diff options
256 files changed, 10126 insertions, 3687 deletions
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index c6ae4c9d0e0c..4fdf6b562d1c 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2582,6 +2582,10 @@ ioctls.</para> <listitem> <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para> </listitem> + <listitem> + <para>Vendor and device specific media bus pixel formats. + <xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para> + </listitem> </itemizedlist> </section> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 272a5f718509..7fe5be1d3bbb 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -1586,7 +1586,6 @@ frame counter of the frame that is currently displayed (decoded). This value is the decoder is started.</entry> </row> - <row><entry></entry></row> <row> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant> </entry> @@ -2270,6 +2269,14 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry> </row> <row><entry></entry></row> + <row id="v4l2-mpeg-video-vbv-delay"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_DELAY</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Sets the initial delay in milliseconds for +VBV buffer control.</entry> + </row> + + <row><entry></entry></row> <row> <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant> </entry> <entry>integer</entry> @@ -2334,6 +2341,265 @@ Applicable to the MPEG4 decoder.</entry> </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry> </row> + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enable generation of frame packing supplemental enhancement information in the encoded bitstream. +The frame packing SEI message contains the arrangement of L and R planes for 3D viewing. Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Sets current frame as frame0 in frame packing SEI. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-sei-fp-arrangement-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_sei_fp_arrangement_type</entry> + </row> + <row><entry spanname="descr">Frame packing arrangement type for H264 SEI. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHEKERBOARD</constant> </entry> + <entry>Pixels are alternatively from L and R.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN</constant> </entry> + <entry>L and R are interlaced by column.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW</constant> </entry> + <entry>L and R are interlaced by row.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE</constant> </entry> + <entry>L is on the left, R on the right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM</constant> </entry> + <entry>L is on top, R on bottom.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL</constant> </entry> + <entry>One view per frame.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables flexible macroblock ordering in the encoded bitstream. It is a technique +used for restructuring the ordering of macroblocks in pictures. Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-fmo-map-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_fmo_map_type</entry> + </row> + <row><entry spanname="descr">When using FMO, the map type divides the image in different scan patterns of macroblocks. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES</constant> </entry> + <entry>Slices are interleaved one after other with macroblocks in run length order.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES</constant> </entry> + <entry>Scatters the macroblocks based on a mathematical function known to both encoder and decoder.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER</constant> </entry> + <entry>Macroblocks arranged in rectangular areas or regions of interest.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT</constant> </entry> + <entry>Slice groups grow in a cyclic way from centre to outwards.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN</constant> </entry> + <entry>Slice groups grow in raster scan pattern from left to right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN</constant> </entry> + <entry>Slice groups grow in wipe scan pattern from top to bottom.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT</constant> </entry> + <entry>User defined map type.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Number of slice groups in FMO. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-fmo-change-direction"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_fmo_change_dir</entry> + </row> + <row><entry spanname="descr">Specifies a direction of the slice group change for raster and wipe maps. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT</constant> </entry> + <entry>Raster scan or wipe right.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT</constant> </entry> + <entry>Reverse raster scan or wipe left.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the size of the first slice group for raster and wipe map. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the number of consecutive macroblocks for the interleaved map. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables arbitrary slice ordering in encoded bitstream. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Specifies the slice order in ASO. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit):</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry>Bit 0:15</entry> + <entry>Slice ID</entry> + </row> + <row> + <entry>Bit 16:32</entry> + <entry>Slice position or order</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING</constant> </entry> + <entry>boolean</entry> + </row> + <row><entry spanname="descr">Enables H264 hierarchical coding. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row id="v4l2-mpeg-video-h264-hierarchical-coding-type"> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE</constant> </entry> + <entry>enum v4l2_mpeg_video_h264_hierarchical_coding_type</entry> + </row> + <row><entry spanname="descr">Specifies the hierarchical coding type. +Applicable to the H264 encoder. +Possible values are:</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B</constant> </entry> + <entry>Hierarchical B coding.</entry> + </row> + <row> + <entry><constant>V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P</constant> </entry> + <entry>Hierarchical P coding.</entry> + </row> + </tbody> + </entrytbl> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER</constant> </entry> + <entry>integer</entry> + </row> + <row><entry spanname="descr">Specifies the number of hierarchical coding layers. +Applicable to the H264 encoder.</entry> + </row> + + <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">Specifies a user defined QP for each layer. Applicable to the H264 encoder. +The supplied 32-bit integer is interpreted as follows (bit +0 = least significant bit):</entry> + </row> + <row> + <entrytbl spanname="descr" cols="2"> + <tbody valign="top"> + <row> + <entry>Bit 0:15</entry> + <entry>QP value</entry> + </row> + <row> + <entry>Bit 16:32</entry> + <entry>Layer number</entry> + </row> + </tbody> + </entrytbl> + </row> + </tbody> </tgroup> </table> @@ -4267,6 +4533,16 @@ interface and may change in the future.</para> pixels / second. </entry> </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN</constant></entry> + <entry>menu</entry> + </row> + <row id="v4l2-test-pattern"> + <entry spanname="descr"> Some capture/display/sensor devices have + the capability to generate test pattern images. These hardware + specific test patterns can be used to test if a device is working + properly.</entry> + </row> <row><entry></entry></row> </tbody> </tgroup> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index 97f785add841..b5d1cbdc558b 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -677,8 +677,10 @@ memory, set by the application. See <xref linkend="userp" /> for details. <entry><structfield>length</structfield></entry> <entry></entry> <entry>Size of the buffer (not the payload) in bytes for the - single-planar API. For the multi-planar API should contain the - number of elements in the <structfield>planes</structfield> array. + single-planar API. For the multi-planar API the application sets + this to the number of elements in the <structfield>planes</structfield> + array. The driver will fill in the actual number of valid elements in + that array. </entry> </row> <row> diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml index 5274c24d11e0..a990b34d911a 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-nv12m.xml @@ -1,11 +1,13 @@ - <refentry id="V4L2-PIX-FMT-NV12M"> + <refentry> <refmeta> - <refentrytitle>V4L2_PIX_FMT_NV12M ('NM12')</refentrytitle> + <refentrytitle>V4L2_PIX_FMT_NV12M ('NM12'), V4L2_PIX_FMT_NV21M ('NM21'), V4L2_PIX_FMT_NV12MT_16X16</refentrytitle> &manvol; </refmeta> <refnamediv> - <refname> <constant>V4L2_PIX_FMT_NV12M</constant></refname> - <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> with planes + <refname id="V4L2-PIX-FMT-NV12M"><constant>V4L2_PIX_FMT_NV12M</constant></refname> + <refname id="V4L2-PIX-FMT-NV21M"><constant>V4L2_PIX_FMT_NV21M</constant></refname> + <refname id="V4L2-PIX-FMT-NV12MT_16X16"><constant>V4L2_PIX_FMT_NV12MT_16X16</constant></refname> + <refpurpose>Variation of <constant>V4L2_PIX_FMT_NV12</constant> and <constant>V4L2_PIX_FMT_NV21</constant> with planes non contiguous in memory. </refpurpose> </refnamediv> <refsect1> @@ -22,7 +24,12 @@ The CbCr plane is the same width, in bytes, as the Y plane (and of the image), but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example, Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to Y'<subscript>00</subscript>, Y'<subscript>01</subscript>, -Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. </para> +Y'<subscript>10</subscript>, Y'<subscript>11</subscript>. +<constant>V4L2_PIX_FMT_NV12MT_16X16</constant> is the tiled version of +<constant>V4L2_PIX_FMT_NV12M</constant> with 16x16 macroblock tiles. Here pixels +are arranged in 16x16 2D tiles and tiles are arranged in linear order in memory. +<constant>V4L2_PIX_FMT_NV21M</constant> is the same as <constant>V4L2_PIX_FMT_NV12M</constant> +except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.</para> <para><constant>V4L2_PIX_FMT_NV12M</constant> is intended to be used only in drivers and applications that support the multi-planar API, diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 1ddbfabe3195..bf94f417592c 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml @@ -758,6 +758,11 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see <entry>'AVC1'</entry> <entry>H264 video elementary stream without start codes.</entry> </row> + <row id="V4L2-PIX-FMT-H264-MVC"> + <entry><constant>V4L2_PIX_FMT_H264_MVC</constant></entry> + <entry>'MVC'</entry> + <entry>H264 MVC video elementary stream.</entry> + </row> <row id="V4L2-PIX-FMT-H263"> <entry><constant>V4L2_PIX_FMT_H263</constant></entry> <entry>'H263'</entry> @@ -793,6 +798,11 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see <entry>'VC1L'</entry> <entry>VC1, SMPTE 421M Annex L compliant stream.</entry> </row> + <row id="V4L2-PIX-FMT-VP8"> + <entry><constant>V4L2_PIX_FMT_VP8</constant></entry> + <entry>'VP8'</entry> + <entry>VP8 video elementary stream.</entry> + </row> </tbody> </tgroup> </table> @@ -996,6 +1006,34 @@ the other bits are set to 0.</entry> <entry>Old 6-bit greyscale format. Only the most significant 6 bits of each byte are used, the other bits are set to 0.</entry> </row> + <row id="V4L2-PIX-FMT-S5C-UYVY-JPG"> + <entry><constant>V4L2_PIX_FMT_S5C_UYVY_JPG</constant></entry> + <entry>'S5CI'</entry> + <entry>Two-planar format used by Samsung S5C73MX cameras. The +first plane contains interleaved JPEG and UYVY image data, followed by meta data +in form of an array of offsets to the UYVY data blocks. The actual pointer array +follows immediately the interleaved JPEG/UYVY data, the number of entries in +this array equals the height of the UYVY image. Each entry is a 4-byte unsigned +integer in big endian order and it's an offset to a single pixel line of the +UYVY image. The first plane can start either with JPEG or UYVY data chunk. The +size of a single UYVY block equals the UYVY image's width multiplied by 2. The +size of a JPEG chunk depends on the image and can vary with each line. +<para>The second plane, at an offset of 4084 bytes, contains a 4-byte offset to +the pointer array in the first plane. This offset is followed by a 4-byte value +indicating size of the pointer array. All numbers in the second plane are also +in big endian order. Remaining data in the second plane is undefined. The +information in the second plane allows to easily find location of the pointer +array, which can be different for each frame. The size of the pointer array is +constant for given UYVY image height.</para> +<para>In order to extract UYVY and JPEG frames an application can initially set +a data pointer to the start of first plane and then add an offset from the first +entry of the pointers table. Such a pointer indicates start of an UYVY image +pixel line. Whole UYVY line can be copied to a separate buffer. These steps +should be repeated for each line, i.e. the number of entries in the pointer +array. Anything what's in between the UYVY lines is JPEG data and should be +concatenated to form the JPEG stream. </para> +</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index 49c532ebbbbe..a0a936455fae 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -2565,5 +2565,49 @@ </tgroup> </table> </section> + + <section id="v4l2-mbus-vendor-spec-fmts"> + <title>Vendor and Device Specific Formats</title> + + <note> + <title>Experimental</title> + <para>This is an <link linkend="experimental">experimental</link> +interface and may change in the future.</para> + </note> + + <para>This section lists complex data formats that are either vendor or + device specific. + </para> + + <para>The following table lists the existing vendor and device specific + formats.</para> + + <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-vendor-specific"> + <title>Vendor and device specific formats</title> + <tgroup cols="3"> + <colspec colname="id" align="left" /> + <colspec colname="code" align="left"/> + <colspec colname="remarks" align="left"/> + <thead> + <row> + <entry>Identifier</entry> + <entry>Code</entry> + <entry>Comments</entry> + </row> + </thead> + <tbody valign="top"> + <row id="V4L2-MBUS-FMT-S5C-UYVY-JPEG-1X8"> + <entry>V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8</entry> + <entry>0x5001</entry> + <entry> + Interleaved raw UYVY and JPEG image format with embedded + meta-data used by Samsung S3C73MX camera sensors. + </entry> + </row> + </tbody> + </tgroup> + </table> + </section> + </section> </section> diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml index 6a821a65a5ae..2d37abefce13 100644 --- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -121,8 +121,7 @@ remaining fields or returns an error code. The driver may also set field. It indicates a non-critical (recoverable) streaming error. In such case the application may continue as normal, but should be aware that data in the dequeued buffer might be corrupted. When using the multi-planar API, the -planes array does not have to be passed; the <structfield>m.planes</structfield> -member must be set to NULL in that case.</para> +planes array must be passed in as well.</para> <para>By default <constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the outgoing queue. When the diff --git a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml index 6e414d7b6df7..a597155c052d 100644 --- a/Documentation/DocBook/media/v4l/vidioc-querybuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-querybuf.xml @@ -48,8 +48,8 @@ <refsect1> <title>Description</title> - <para>This ioctl is part of the <link linkend="mmap">memory -mapping</link> I/O method. It can be used to query the status of a + <para>This ioctl is part of the <link linkend="mmap">streaming +</link> I/O method. It can be used to query the status of a buffer at any time after buffers have been allocated with the &VIDIOC-REQBUFS; ioctl.</para> @@ -71,6 +71,7 @@ the structure.</para> <para>In the <structfield>flags</structfield> field the <constant>V4L2_BUF_FLAG_MAPPED</constant>, +<constant>V4L2_BUF_FLAG_PREPARED</constant>, <constant>V4L2_BUF_FLAG_QUEUED</constant> and <constant>V4L2_BUF_FLAG_DONE</constant> flags will be valid. The <structfield>memory</structfield> field will be set to the current @@ -79,8 +80,10 @@ contains the offset of the buffer from the start of the device memory, the <structfield>length</structfield> field its size. For the multi-planar API, fields <structfield>m.mem_offset</structfield> and <structfield>length</structfield> in the <structfield>m.planes</structfield> -array elements will be used instead. The driver may or may not set the remaining -fields and flags, they are meaningless in this context.</para> +array elements will be used instead and the <structfield>length</structfield> +field of &v4l2-buffer; is set to the number of filled-in array elements. +The driver may or may not set the remaining fields and flags, they are +meaningless in this context.</para> <para>The <structname>v4l2_buffer</structname> structure is specified in <xref linkend="buffer" />.</para> diff --git a/Documentation/arm/Booting b/Documentation/arm/Booting index a341d87d276e..0c1f475fdf36 100644 --- a/Documentation/arm/Booting +++ b/Documentation/arm/Booting @@ -154,13 +154,33 @@ In either case, the following conditions must be met: - CPU mode All forms of interrupts must be disabled (IRQs and FIQs) - The CPU must be in SVC mode. (A special exception exists for Angel) + + For CPUs which do not include the ARM virtualization extensions, the + CPU must be in SVC mode. (A special exception exists for Angel) + + CPUs which include support for the virtualization extensions can be + entered in HYP mode in order to enable the kernel to make full use of + these extensions. This is the recommended boot method for such CPUs, + unless the virtualisations are already in use by a pre-installed + hypervisor. + + If the kernel is not entered in HYP mode for any reason, it must be + entered in SVC mode. - Caches, MMUs The MMU must be off. Instruction cache may be on or off. Data cache must be off. + If the kernel is entered in HYP mode, the above requirements apply to + the HYP mode configuration in addition to the ordinary PL1 (privileged + kernel modes) configuration. In addition, all traps into the + hypervisor must be disabled, and PL1 access must be granted for all + peripherals and CPU resources for which this is architecturally + possible. Except for entering in HYP mode, the system configuration + should be such that a kernel which does not include support for the + virtualization extensions can boot correctly without extra help. + - The boot loader is expected to call the kernel image by jumping directly to the first instruction of the kernel image. diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt index 54270df99d5c..cfe52c798d74 100644 --- a/Documentation/video4linux/v4l2-controls.txt +++ b/Documentation/video4linux/v4l2-controls.txt @@ -136,11 +136,25 @@ Or alternatively for integer menu controls, by calling v4l2_ctrl_new_int_menu: const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 def, const s64 *qmenu_int); +Standard menu controls with a driver specific menu are added by calling +v4l2_ctrl_new_std_menu_items: + + struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items( + struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 skip_mask, s32 def, const char * const *qmenu); + These functions are typically called right after the v4l2_ctrl_handler_init: static const s64 exp_bias_qmenu[] = { -2, -1, 0, 1, 2 }; + static const char * const test_pattern[] = { + "Disabled", + "Vertical Bars", + "Solid Black", + "Solid White", + }; v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls); v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops, @@ -156,6 +170,9 @@ These functions are typically called right after the v4l2_ctrl_handler_init: ARRAY_SIZE(exp_bias_qmenu) - 1, ARRAY_SIZE(exp_bias_qmenu) / 2 - 1, exp_bias_qmenu); + v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops, + V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, + 0, test_pattern); ... if (foo->ctrl_handler.error) { int err = foo->ctrl_handler.error; @@ -185,6 +202,13 @@ v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and takes as the last argument an array of signed 64-bit integers that form an exact menu item list. +The v4l2_ctrl_new_std_menu_items function is very similar to +v4l2_ctrl_new_std_menu but takes an extra parameter qmenu, which is the driver +specific menu for an otherwise standard menu control. A good example for this +control is the test pattern control for capture/display/sensors devices that +have the capability to generate test patterns. These test patterns are hardware +specific, so the contents of the menu will vary from device to device. + Note that if something fails, the function will return NULL or an error and set ctrl_handler->error to the error code. If ctrl_handler->error was already set, then it will just return and do nothing. This is also true for diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index d0d441c429ae..f79a08efe000 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore @@ -1,6 +1,7 @@ ashldi3.S font.c lib1funcs.S +hyp-stub.S piggy.gzip piggy.lzo piggy.lzma diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index bb267562e7ed..a517153a13ea 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -30,6 +30,10 @@ FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c OBJS += string.o CFLAGS_string.o := -Os +ifeq ($(CONFIG_ARM_VIRT_EXT),y) +OBJS += hyp-stub.o +endif + # # Architecture dependencies # @@ -126,7 +130,7 @@ KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) endif ccflags-y := -fpic -fno-builtin -I$(obj) -asflags-y := -Wa,-march=all +asflags-y := -Wa,-march=all -DZIMAGE # Supply kernel BSS size to the decompressor via a linker symbol. KBSS_SZ = $(shell $(CROSS_COMPILE)size $(obj)/../../../../vmlinux | \ @@ -198,3 +202,6 @@ $(obj)/font.c: $(FONTC) $(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) @sed "$(SEDFLAGS)" < $< > $@ + +$(obj)/hyp-stub.S: $(srctree)/arch/$(SRCARCH)/kernel/hyp-stub.S + $(call cmd,shipped) diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index bc67cbff3944..90275f036cd1 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include <linux/linkage.h> +#include <asm/assembler.h> /* * Debugging stuff @@ -132,7 +133,12 @@ start: .word start @ absolute load/run zImage address .word _edata @ zImage end address THUMB( .thumb ) -1: mov r7, r1 @ save architecture ID +1: + mrs r9, cpsr +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install @ get into SVC mode, reversibly +#endif + mov r7, r1 @ save architecture ID mov r8, r2 @ save atags pointer #ifndef __ARM_ARCH_2__ @@ -148,9 +154,9 @@ start: ARM( swi 0x123456 ) @ angel_SWI_ARM THUMB( svc 0xab ) @ angel_SWI_THUMB not_angel: - mrs r2, cpsr @ turn off interrupts to - orr r2, r2, #0xc0 @ prevent angel from running - msr cpsr_c, r2 + safe_svcmode_maskall r0 + msr spsr_cxsf, r9 @ Save the CPU boot mode in + @ SPSR #else teqp pc, #0x0c000003 @ turn off interrupts #endif @@ -350,6 +356,20 @@ dtb_check_done: adr r5, restart bic r5, r5, #31 +/* Relocate the hyp vector base if necessary */ +#ifdef CONFIG_ARM_VIRT_EXT + mrs r0, spsr + and r0, r0, #MODE_MASK + cmp r0, #HYP_MODE + bne 1f + + bl __hyp_get_vectors + sub r0, r0, r5 + add r0, r0, r10 + bl __hyp_set_vectors +1: +#endif + sub r9, r6, r5 @ size to copy add r9, r9, #31 @ rounded up to a multiple bic r9, r9, #31 @ ... of 32 bytes @@ -458,11 +478,29 @@ not_relocated: mov r0, #0 bl decompress_kernel bl cache_clean_flush bl cache_off - mov r0, #0 @ must be zero mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer - ARM( mov pc, r4 ) @ call kernel - THUMB( bx r4 ) @ entry point is always ARM + +#ifdef CONFIG_ARM_VIRT_EXT + mrs r0, spsr @ Get saved CPU boot mode + and r0, r0, #MODE_MASK + cmp r0, #HYP_MODE @ if not booted in HYP mode... + bne __enter_kernel @ boot kernel directly + + adr r12, .L__hyp_reentry_vectors_offset + ldr r0, [r12] + add r0, r0, r12 + + bl __hyp_set_vectors + __HVC(0) @ otherwise bounce to hyp mode + + b . @ should never be reached + + .align 2 +.L__hyp_reentry_vectors_offset: .long __hyp_reentry_vectors - . +#else + b __enter_kernel +#endif .align 2 .type LC0, #object @@ -1196,6 +1234,25 @@ memdump: mov r12, r0 #endif .ltorg + +#ifdef CONFIG_ARM_VIRT_EXT +.align 5 +__hyp_reentry_vectors: + W(b) . @ reset + W(b) . @ undef + W(b) . @ svc + W(b) . @ pabort + W(b) . @ dabort + W(b) __enter_kernel @ hyp + W(b) . @ irq + W(b) . @ fiq +#endif /* CONFIG_ARM_VIRT_EXT */ + +__enter_kernel: + mov r0, #0 @ must be 0 + ARM( mov pc, r4 ) @ call kernel + THUMB( bx r4 ) @ entry point is always ARM + reloc_code_end: .align diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 5c8b3bf4d825..2ef95813fce0 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -22,6 +22,7 @@ #include <asm/ptrace.h> #include <asm/domain.h> +#include <asm/opcodes-virt.h> #define IOMEM(x) (x) @@ -240,6 +241,34 @@ #endif /* + * Helper macro to enter SVC mode cleanly and mask interrupts. reg is + * a scratch register for the macro to overwrite. + * + * This macro is intended for forcing the CPU into SVC mode at boot time. + * you cannot return to the original mode. + * + * Beware, it also clobers LR. + */ +.macro safe_svcmode_maskall reg:req + mrs \reg , cpsr + mov lr , \reg + and lr , lr , #MODE_MASK + cmp lr , #HYP_MODE + orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT + bic \reg , \reg , #MODE_MASK + orr \reg , \reg , #SVC_MODE +THUMB( orr \reg , \reg , #PSR_T_BIT ) + bne 1f + orr \reg, \reg, #PSR_A_BIT + adr lr, BSYM(2f) + msr spsr_cxsf, \reg + __MSR_ELR_HYP(14) + __ERET +1: msr cpsr_c, \reg +2: +.endm + +/* * STRT/LDRT access macros with ARM and Thumb-2 variants */ #ifdef CONFIG_THUMB2_KERNEL diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index e4448e16046d..e1489c54cd12 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -49,6 +49,13 @@ * * Unconditionally clean and invalidate the entire cache. * + * flush_kern_louis() + * + * Flush data cache levels up to the level of unification + * inner shareable and invalidate the I-cache. + * Only needed from v7 onwards, falls back to flush_cache_all() + * for all other processor versions. + * * flush_user_all() * * Clean and invalidate all user space cache entries @@ -97,6 +104,7 @@ struct cpu_cache_fns { void (*flush_icache_all)(void); void (*flush_kern_all)(void); + void (*flush_kern_louis)(void); void (*flush_user_all)(void); void (*flush_user_range)(unsigned long, unsigned long, unsigned int); @@ -119,6 +127,7 @@ extern struct cpu_cache_fns cpu_cache; #define __cpuc_flush_icache_all cpu_cache.flush_icache_all #define __cpuc_flush_kern_all cpu_cache.flush_kern_all +#define __cpuc_flush_kern_louis cpu_cache.flush_kern_louis #define __cpuc_flush_user_all cpu_cache.flush_user_all #define __cpuc_flush_user_range cpu_cache.flush_user_range #define __cpuc_coherent_kern_range cpu_cache.coherent_kern_range @@ -139,6 +148,7 @@ extern struct cpu_cache_fns cpu_cache; extern void __cpuc_flush_icache_all(void); extern void __cpuc_flush_kern_all(void); +extern void __cpuc_flush_kern_louis(void); extern void __cpuc_flush_user_all(void); extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int); extern void __cpuc_coherent_kern_range(unsigned long, unsigned long); @@ -204,6 +214,11 @@ static inline void __flush_icache_all(void) __flush_icache_preferred(); } +/* + * Flush caches up to Level of Unification Inner Shareable + */ +#define flush_cache_louis() __cpuc_flush_kern_louis() + #define flush_cache_all() __cpuc_flush_kern_all() static inline void vivt_flush_cache_mm(struct mm_struct *mm) diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h index 4f8d2c0dc441..cca9f15704ed 100644 --- a/arch/arm/include/asm/glue-cache.h +++ b/arch/arm/include/asm/glue-cache.h @@ -132,6 +132,7 @@ #ifndef MULTI_CACHE #define __cpuc_flush_icache_all __glue(_CACHE,_flush_icache_all) #define __cpuc_flush_kern_all __glue(_CACHE,_flush_kern_cache_all) +#define __cpuc_flush_kern_louis __glue(_CACHE,_flush_kern_cache_louis) #define __cpuc_flush_user_all __glue(_CACHE,_flush_user_cache_all) #define __cpuc_flush_user_range __glue(_CACHE,_flush_user_cache_range) #define __cpuc_coherent_kern_range __glue(_CACHE,_coherent_kern_range) diff --git a/arch/arm/include/asm/opcodes-virt.h b/arch/arm/include/asm/opcodes-virt.h index b85665a96f8e..efcfdf92d9d5 100644 --- a/arch/arm/include/asm/opcodes-virt.h +++ b/arch/arm/include/asm/opcodes-virt.h @@ -26,4 +26,14 @@ 0xF7E08000 | (((imm16) & 0xF000) << 4) | ((imm16) & 0x0FFF) \ ) +#define __ERET __inst_arm_thumb32( \ + 0xE160006E, \ + 0xF3DE8F00 \ +) + +#define __MSR_ELR_HYP(regnum) __inst_arm_thumb32( \ + 0xE12EF300 | regnum, \ + 0xF3808E30 | (regnum << 16) \ +) + #endif /* ! __ASM_ARM_OPCODES_VIRT_H */ diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 44fe998269d9..142d6ae41231 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h @@ -44,6 +44,7 @@ #define IRQ_MODE 0x00000012 #define SVC_MODE 0x00000013 #define ABT_MODE 0x00000017 +#define HYP_MODE 0x0000001a #define UND_MODE 0x0000001b #define SYSTEM_MODE 0x0000001f #define MODE32_BIT 0x00000010 diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h index a7aadbd9a6dd..6a6f1e485f41 100644 --- a/arch/arm/include/asm/vfpmacros.h +++ b/arch/arm/include/asm/vfpmacros.h @@ -28,7 +28,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - ldceq p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} + ldceql p11, cr0, [\base],#32*4 @ FLDMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 @@ -52,7 +52,7 @@ ldr \tmp, =elf_hwcap @ may not have MVFR regs ldr \tmp, [\tmp, #0] tst \tmp, #HWCAP_VFPv3D16 - stceq p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} + stceql p11, cr0, [\base],#32*4 @ FSTMIAD \base!, {d16-d31} addne \base, \base, #32*4 @ step over unused register space #else VFPFMRX \tmp, MVFR0 @ Media and VFP Feature Register 0 diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h new file mode 100644 index 000000000000..86164df86cb4 --- /dev/null +++ b/arch/arm/include/asm/virt.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef VIRT_H +#define VIRT_H + +#include <asm/ptrace.h> + +/* + * Flag indicating that the kernel was not entered in the same mode on every + * CPU. The zImage loader stashes this value in an SPSR, so we need an + * architecturally defined flag bit here (the N flag, as it happens) + */ +#define BOOT_CPU_MODE_MISMATCH (1<<31) + +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_ARM_VIRT_EXT +/* + * __boot_cpu_mode records what mode the primary CPU was booted in. + * A correctly-implemented bootloader must start all CPUs in the same mode: + * if it fails to do this, the flag BOOT_CPU_MODE_MISMATCH is set to indicate + * that some CPU(s) were booted in a different mode. + * + * This allows the kernel to flag an error when the secondaries have come up. + */ +extern int __boot_cpu_mode; + +void __hyp_set_vectors(unsigned long phys_vector_base); +unsigned long __hyp_get_vectors(void); +#else +#define __boot_cpu_mode (SVC_MODE) +#endif + +#ifndef ZIMAGE +void hyp_mode_check(void); + +/* Reports the availability of HYP mode */ +static inline bool is_hyp_mode_available(void) +{ + return ((__boot_cpu_mode & MODE_MASK) == HYP_MODE && + !(__boot_cpu_mode & BOOT_CPU_MODE_MISMATCH)); +} + +/* Check if the bootloader has booted CPUs in different modes */ +static inline bool is_hyp_mode_mismatched(void) +{ + return !!(__boot_cpu_mode & BOOT_CPU_MODE_MISMATCH); +} +#endif + +#endif /* __ASSEMBLY__ */ + +#endif /* ! VIRT_H */ diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5dfef9d97ed9..5bbec7b8183e 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -81,4 +81,6 @@ head-y := head$(MMUEXT).o obj-$(CONFIG_DEBUG_LL) += debug.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o +obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o + extra-y := $(head-y) vmlinux.lds diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 9874d0741191..4eee351f4668 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -83,8 +83,12 @@ ENTRY(stext) THUMB( .thumb ) @ switch to Thumb now. THUMB(1: ) - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode - @ and irqs disabled +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install +#endif + @ ensure svc mode and all interrupts masked + safe_svcmode_maskall r9 + mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type @ r5=procinfo r9=cpuid movs r10, r5 @ invalid processor (r5=0)? @@ -326,7 +330,11 @@ ENTRY(secondary_startup) * the processor type - there is no need to check the machine type * as it has already been validated by the primary processor. */ - setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 +#ifdef CONFIG_ARM_VIRT_EXT + bl __hyp_stub_install +#endif + safe_svcmode_maskall r9 + mrc p15, 0, r9, c0, c0 @ get processor id bl __lookup_processor_type movs r10, r5 @ invalid processor? diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S new file mode 100644 index 000000000000..65b2417aebce --- /dev/null +++ b/arch/arm/kernel/hyp-stub.S @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2012 Linaro Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/virt.h> + +#ifndef ZIMAGE +/* + * For the kernel proper, we need to find out the CPU boot mode long after + * boot, so we need to store it in a writable variable. + * + * This is not in .bss, because we set it sufficiently early that the boot-time + * zeroing of .bss would clobber it. + */ +.data +ENTRY(__boot_cpu_mode) + .long 0 +.text + + /* + * Save the primary CPU boot mode. Requires 3 scratch registers. + */ + .macro store_primary_cpu_mode reg1, reg2, reg3 + mrs \reg1, cpsr + and \reg1, \reg1, #MODE_MASK + adr \reg2, .L__boot_cpu_mode_offset + ldr \reg3, [\reg2] + str \reg1, [\reg2, \reg3] + .endm + + /* + * Compare the current mode with the one saved on the primary CPU. + * If they don't match, record that fact. The Z bit indicates + * if there's a match or not. + * Requires 3 additionnal scratch registers. + */ + .macro compare_cpu_mode_with_primary mode, reg1, reg2, reg3 + adr \reg2, .L__boot_cpu_mode_offset + ldr \reg3, [\reg2] + ldr \reg1, [\reg2, \reg3] + cmp \mode, \reg1 @ matches primary CPU boot mode? + orrne r7, r7, #BOOT_CPU_MODE_MISMATCH + strne r7, [r5, r6] @ record what happened and give up + .endm + +#else /* ZIMAGE */ + + .macro store_primary_cpu_mode reg1:req, reg2:req, reg3:req + .endm + +/* + * The zImage loader only runs on one CPU, so we don't bother with mult-CPU + * consistency checking: + */ + .macro compare_cpu_mode_with_primary mode, reg1, reg2, reg3 + cmp \mode, \mode + .endm + +#endif /* ZIMAGE */ + +/* + * Hypervisor stub installation functions. + * + * These must be called with the MMU and D-cache off. + * They are not ABI compliant and are only intended to be called from the kernel + * entry points in head.S. + */ +@ Call this from the primary CPU +ENTRY(__hyp_stub_install) + store_primary_cpu_mode r4, r5, r6 +ENDPROC(__hyp_stub_install) + + @ fall through... + +@ Secondary CPUs should call here +ENTRY(__hyp_stub_install_secondary) + mrs r4, cpsr + and r4, r4, #MODE_MASK + + /* + * If the secondary has booted with a different mode, give up + * immediately. + */ + compare_cpu_mode_with_primary r4, r5, r6, r7 + bxne lr + + /* + * Once we have given up on one CPU, we do not try to install the + * stub hypervisor on the remaining ones: because the saved boot mode + * is modified, it can't compare equal to the CPSR mode field any + * more. + * + * Otherwise... + */ + + cmp r4, #HYP_MODE + bxne lr @ give up if the CPU is not in HYP mode + +/* + * Configure HSCTLR to set correct exception endianness/instruction set + * state etc. + * Turn off all traps + * Eventually, CPU-specific code might be needed -- assume not for now + * + * This code relies on the "eret" instruction to synchronize the + * various coprocessor accesses. + */ + @ Now install the hypervisor stub: + adr r7, __hyp_stub_vectors + mcr p15, 4, r7, c12, c0, 0 @ set hypervisor vector base (HVBAR) + + @ Disable all traps, so we don't get any nasty surprise + mov r7, #0 + mcr p15, 4, r7, c1, c1, 0 @ HCR + mcr p15, 4, r7, c1, c1, 2 @ HCPTR + mcr p15, 4, r7, c1, c1, 3 @ HSTR + +THUMB( orr r7, #(1 << 30) ) @ HSCTLR.TE +#ifdef CONFIG_CPU_BIG_ENDIAN + orr r7, #(1 << 9) @ HSCTLR.EE +#endif + mcr p15, 4, r7, c1, c0, 0 @ HSCTLR + + mrc p15, 4, r7, c1, c1, 1 @ HDCR + and r7, #0x1f @ Preserve HPMN + mcr p15, 4, r7, c1, c1, 1 @ HDCR + +#if !defined(ZIMAGE) && defined(CONFIG_ARM_ARCH_TIMER) + @ make CNTP_* and CNTPCT accessible from PL1 + mrc p15, 0, r7, c0, c1, 1 @ ID_PFR1 + lsr r7, #16 + and r7, #0xf + cmp r7, #1 + bne 1f + mrc p15, 4, r7, c14, c1, 0 @ CNTHCTL + orr r7, r7, #3 @ PL1PCEN | PL1PCTEN + mcr p15, 4, r7, c14, c1, 0 @ CNTHCTL +1: +#endif + + bic r7, r4, #MODE_MASK + orr r7, r7, #SVC_MODE +THUMB( orr r7, r7, #PSR_T_BIT ) + msr spsr_cxsf, r7 @ This is SPSR_hyp. + + __MSR_ELR_HYP(14) @ msr elr_hyp, lr + __ERET @ return, switching to SVC mode + @ The boot CPU mode is left in r4. +ENDPROC(__hyp_stub_install_secondary) + +__hyp_stub_do_trap: + cmp r0, #-1 + mrceq p15, 4, r0, c12, c0, 0 @ get HVBAR + mcrne p15, 4, r0, c12, c0, 0 @ set HVBAR + __ERET +ENDPROC(__hyp_stub_do_trap) + +/* + * __hyp_set_vectors: Call this after boot to set the initial hypervisor + * vectors as part of hypervisor installation. On an SMP system, this should + * be called on each CPU. + * + * r0 must be the physical address of the new vector table (which must lie in + * the bottom 4GB of physical address space. + * + * r0 must be 32-byte aligned. + * + * Before calling this, you must check that the stub hypervisor is installed + * everywhere, by waiting for any secondary CPUs to be brought up and then + * checking that BOOT_CPU_MODE_HAVE_HYP(__boot_cpu_mode) is true. + * + * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or + * something else went wrong... in such cases, trying to install a new + * hypervisor is unlikely to work as desired. + * + * When you call into your shiny new hypervisor, sp_hyp will contain junk, + * so you will need to set that to something sensible at the new hypervisor's + * initialisation entry point. + */ +ENTRY(__hyp_get_vectors) + mov r0, #-1 +ENDPROC(__hyp_get_vectors) + @ fall through +ENTRY(__hyp_set_vectors) + __HVC(0) + bx lr +ENDPROC(__hyp_set_vectors) + +#ifndef ZIMAGE +.align 2 +.L__boot_cpu_mode_offset: + .long __boot_cpu_mode - . +#endif + +.align 5 +__hyp_stub_vectors: +__hyp_stub_reset: W(b) . +__hyp_stub_und: W(b) . +__hyp_stub_svc: W(b) . +__hyp_stub_pabort: W(b) . +__hyp_stub_dabort: W(b) . +__hyp_stub_trap: W(b) __hyp_stub_do_trap +__hyp_stub_irq: W(b) . +__hyp_stub_fiq: W(b) . +ENDPROC(__hyp_stub_vectors) + diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index febafa0f552d..da1d1aa20ad9 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -53,6 +53,7 @@ #include <asm/traps.h> #include <asm/unwind.h> #include <asm/memblock.h> +#include <asm/virt.h> #include "atags.h" #include "tcm.h" @@ -703,6 +704,21 @@ static int __init meminfo_cmp(const void *_a, const void *_b) return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } +void __init hyp_mode_check(void) +{ +#ifdef CONFIG_ARM_VIRT_EXT + if (is_hyp_mode_available()) { + pr_info("CPU: All CPU(s) started in HYP mode.\n"); + pr_info("CPU: Virtualization extensions available.\n"); + } else if (is_hyp_mode_mismatched()) { + pr_warn("CPU: WARNING: CPU(s) started in wrong/inconsistent modes (primary CPU mode 0x%x)\n", + __boot_cpu_mode & MODE_MASK); + pr_warn("CPU: This may indicate a broken bootloader or firmware.\n"); + } else + pr_info("CPU: All CPU(s) started in SVC mode.\n"); +#endif +} + void __init setup_arch(char **cmdline_p) { struct machine_desc *mdesc; @@ -748,6 +764,10 @@ void __init setup_arch(char **cmdline_p) smp_init_cpus(); } #endif + + if (!is_smp()) + hyp_mode_check(); + reserve_crashkernel(); tcm_init(); diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index d100eacdb798..8e20754dd31d 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -43,6 +43,7 @@ #include <asm/ptrace.h> #include <asm/localtimer.h> #include <asm/smp_plat.h> +#include <asm/virt.h> #include <asm/mach/arch.h> /* @@ -202,8 +203,11 @@ int __cpuinit __cpu_disable(void) /* * Flush user cache and TLB mappings, and then remove this CPU * from the vm mask set of all processes. + * + * Caches are flushed to the Level of Unification Inner Shareable + * to write-back dirty lines to unified caches shared by all CPUs. */ - flush_cache_all(); + flush_cache_louis(); local_flush_tlb_all(); clear_tasks_mm_cpumask(cpu); @@ -355,6 +359,8 @@ void __init smp_cpus_done(unsigned int max_cpus) num_online_cpus(), bogosum / (500000/HZ), (bogosum / (5000/HZ)) % 100); + + hyp_mode_check(); } void __init smp_prepare_boot_cpu(void) diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c index 1794cc3b0f18..358bca3a995e 100644 --- a/arch/arm/kernel/suspend.c +++ b/arch/arm/kernel/suspend.c @@ -17,6 +17,8 @@ extern void cpu_resume_mmu(void); */ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) { + u32 *ctx = ptr; + *save_ptr = virt_to_phys(ptr); /* This must correspond to the LDM in cpu_resume() assembly */ @@ -26,7 +28,20 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr) cpu_do_suspend(ptr); - flush_cache_all(); + flush_cache_louis(); + + /* + * flush_cache_louis does not guarantee that + * save_ptr and ptr are cleaned to main memory, + * just up to the Level of Unification Inner Shareable. + * Since the context pointer and context itself + * are to be retrieved with the MMU off that + * data must be cleaned from all cache levels + * to main memory using "area" cache primitives. + */ + __cpuc_flush_dcache_area(ctx, ptrsz); + __cpuc_flush_dcache_area(save_ptr, sizeof(*save_ptr)); + outer_clean_range(*save_ptr, *save_ptr + ptrsz); outer_clean_range(virt_to_phys(save_ptr), virt_to_phys(save_ptr) + sizeof(*save_ptr)); diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index ab99c3c3b752..026b4b277ae5 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig @@ -186,6 +186,13 @@ config DA850_UI_RMII NOTE: Please take care while choosing this option, MII PHY will not be functional if RMII mode is selected. +config DA850_UI_SD_VIDEO_PORT + bool "Video Port Interface" + help + Say Y if you want to use Video Port Interface (VPIF) on the + DA850/OMAP-L138 EVM. The Video decoders/encoders are found on the + UI daughter card that is supplied with the EVM. + endchoice config DA850_WL12XX diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 1295e616ceee..32ee3f895967 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -45,6 +45,9 @@ #include <linux/platform_data/mtd-davinci-aemif.h> #include <linux/platform_data/spi-davinci.h> +#include <media/tvp514x.h> +#include <media/adv7343.h> + #define DA850_EVM_PHY_ID "davinci_mdio-0:00" #define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8) #define DA850_LCD_BL_PIN GPIO_TO_PIN(2, 15) @@ -452,6 +455,15 @@ static void da850_evm_ui_keys_init(unsigned gpio) } } +#ifdef CONFIG_DA850_UI_SD_VIDEO_PORT +static inline void da850_evm_setup_video_port(int video_sel) +{ + gpio_set_value_cansleep(video_sel, 0); +} +#else +static inline void da850_evm_setup_video_port(int video_sel) { } +#endif + static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, unsigned ngpio, void *c) { @@ -497,6 +509,8 @@ static int da850_evm_ui_expander_setup(struct i2c_client *client, unsigned gpio, da850_evm_setup_emac_rmii(sel_a); + da850_evm_setup_video_port(sel_c); + return 0; exp_setup_keys_fail: @@ -1149,6 +1163,169 @@ static __init int da850_evm_init_cpufreq(void) static __init int da850_evm_init_cpufreq(void) { return 0; } #endif +#if defined(CONFIG_DA850_UI_SD_VIDEO_PORT) + +#define TVP5147_CH0 "tvp514x-0" +#define TVP5147_CH1 "tvp514x-1" + +/* VPIF capture configuration */ +static struct tvp514x_platform_data tvp5146_pdata = { + .clk_polarity = 0, + .hs_polarity = 1, + .vs_polarity = 1, +}; + +#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +static const struct vpif_input da850_ch0_inputs[] = { + { + .input = { + .index = 0, + .name = "Composite", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH0, + }, +}; + +static const struct vpif_input da850_ch1_inputs[] = { + { + .input = { + .index = 0, + .name = "S-Video", + .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, + .std = TVP514X_STD_ALL, + }, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, + .subdev_name = TVP5147_CH1, + }, +}; + +static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = { + { + .name = TVP5147_CH0, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5d), + .platform_data = &tvp5146_pdata, + }, + }, + { + .name = TVP5147_CH1, + .board_info = { + I2C_BOARD_INFO("tvp5146", 0x5c), + .platform_data = &tvp5146_pdata, + }, + }, +}; + +static struct vpif_capture_config da850_vpif_capture_config = { + .subdev_info = da850_vpif_capture_sdev_info, + .subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info), + .chan_config[0] = { + .inputs = da850_ch0_inputs, + .input_count = ARRAY_SIZE(da850_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .chan_config[1] = { + .inputs = da850_ch1_inputs, + .input_count = ARRAY_SIZE(da850_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, + }, + .card_name = "DA850/OMAP-L138 Video Capture", +}; + +/* VPIF display configuration */ +static struct vpif_subdev_info da850_vpif_subdev[] = { + { + .name = "adv7343", + .board_info = { + I2C_BOARD_INFO("adv7343", 0x2a), + }, + }, +}; + +static const struct vpif_output da850_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, +}; + +static struct vpif_display_config da850_vpif_display_config = { + .subdevinfo = da850_vpif_subdev, + .subdev_count = ARRAY_SIZE(da850_vpif_subdev), + .chan_config[0] = { + .outputs = da850_ch0_outputs, + .output_count = ARRAY_SIZE(da850_ch0_outputs), + }, + .card_name = "DA850/OMAP-L138 Video Display", +}; + +static __init void da850_vpif_init(void) +{ + int ret; + + ret = da850_register_vpif(); + if (ret) + pr_warn("da850_evm_init: VPIF setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_capture_pins); + if (ret) + pr_warn("da850_evm_init: VPIF capture mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_capture(&da850_vpif_capture_config); + if (ret) + pr_warn("da850_evm_init: VPIF capture setup failed: %d\n", ret); + + ret = davinci_cfg_reg_list(da850_vpif_display_pins); + if (ret) + pr_warn("da850_evm_init: VPIF display mux setup failed: %d\n", + ret); + + ret = da850_register_vpif_display(&da850_vpif_display_config); + if (ret) + pr_warn("da850_evm_init: VPIF display setup failed: %d\n", ret); +} + +#else +static __init void da850_vpif_init(void) {} +#endif + #ifdef CONFIG_DA850_WL12XX static void wl12xx_set_power(int index, bool power_on) @@ -1375,6 +1552,8 @@ static __init void da850_evm_init(void) pr_warning("da850_evm_init: suspend registration failed: %d\n", ret); + da850_vpif_init(); + ret = da8xx_register_spi(1, da850evm_spi_info, ARRAY_SIZE(da850evm_spi_info)); if (ret) diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index ca72fc4b8cca..f22572cee49d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -23,6 +23,7 @@ #include <linux/phy.h> #include <linux/clk.h> #include <linux/videodev2.h> +#include <linux/v4l2-dv-timings.h> #include <linux/export.h> #include <media/tvp514x.h> @@ -620,7 +621,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_525_60}, + .std_id = V4L2_STD_525_60, .interlaced = 1, .xres = 720, .yres = 480, @@ -632,7 +633,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .timings = {V4L2_STD_625_50}, + .std_id = V4L2_STD_625_50, .interlaced = 1, .xres = 720, .yres = 576, @@ -647,8 +648,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { { .name = "480p59_94", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_480P59_94}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, .interlaced = 0, .xres = 720, .yres = 480, @@ -659,8 +660,8 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { }, { .name = "576p50", - .timings_type = VPBE_ENC_DV_PRESET, - .timings = {V4L2_DV_576P50}, + .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X576P50, .interlaced = 0, .xres = 720, .yres = 576, @@ -698,7 +699,7 @@ static struct vpbe_output dm644xevm_vpbe_outputs[] = { .index = 1, .name = "Component", .type = V4L2_OUTPUT_TYPE_ANALOG, - .capabilities = V4L2_OUT_CAP_PRESETS, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, }, .subdev_name = VPBE_VENC_SUBDEV_NAME, .default_mode = "480p59_94", diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 9944367b4931..1dbf85beed1b 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -26,6 +26,7 @@ #include <linux/i2c/pcf857x.h> #include <media/tvp514x.h> +#include <media/adv7343.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -496,18 +497,49 @@ static struct vpif_subdev_info dm646x_vpif_subdev[] = { }, }; -static const char *output[] = { - "Composite", - "Component", - "S-Video", +static const struct vpif_output dm6467_ch0_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPOSITE_ID, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_COMPONENT_ID, + }, + { + .output = { + .index = 2, + .name = "S-Video", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_STD, + .std = V4L2_STD_ALL, + }, + .subdev_name = "adv7343", + .output_route = ADV7343_SVIDEO_ID, + }, }; static struct vpif_display_config dm646x_vpif_display_config = { .set_clock = set_vpif_clock, .subdevinfo = dm646x_vpif_subdev, .subdev_count = ARRAY_SIZE(dm646x_vpif_subdev), - .output = output, - .output_count = ARRAY_SIZE(output), + .chan_config[0] = { + .outputs = dm6467_ch0_outputs, + .output_count = ARRAY_SIZE(dm6467_ch0_outputs), + }, .card_name = "DM646x EVM", }; @@ -601,15 +633,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5d), .platform_data = &tvp5146_pdata, }, - .input = INPUT_CVBS_VI2B, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, { .name = TVP5147_CH1, @@ -617,15 +640,6 @@ static struct vpif_subdev_info vpif_capture_sdev_info[] = { I2C_BOARD_INFO("tvp5146", 0x5c), .platform_data = &tvp5146_pdata, }, - .input = INPUT_SVIDEO_VI2C_VI1C, - .output = OUTPUT_10BIT_422_EMBEDDED_SYNC, - .can_route = 1, - .vpif_if = { - .if_type = VPIF_IF_BT656, - .hd_pol = 1, - .vd_pol = 1, - .fid_pol = 0, - }, }, }; @@ -635,9 +649,12 @@ static const struct vpif_input dm6467_ch0_inputs[] = { .index = 0, .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH0, + .input_route = INPUT_CVBS_VI2B, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; @@ -647,9 +664,12 @@ static const struct vpif_input dm6467_ch1_inputs[] = { .index = 0, .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .capabilities = V4L2_IN_CAP_STD, .std = TVP514X_STD_ALL, }, .subdev_name = TVP5147_CH1, + .input_route = INPUT_SVIDEO_VI2C_VI1C, + .output_route = OUTPUT_10BIT_422_EMBEDDED_SYNC, }, }; @@ -661,10 +681,22 @@ static struct vpif_capture_config dm646x_vpif_capture_cfg = { .chan_config[0] = { .inputs = dm6467_ch0_inputs, .input_count = ARRAY_SIZE(dm6467_ch0_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, .chan_config[1] = { .inputs = dm6467_ch1_inputs, .input_count = ARRAY_SIZE(dm6467_ch1_inputs), + .vpif_if = { + .if_type = VPIF_IF_BT656, + .hd_pol = 1, + .vd_pol = 1, + .fid_pol = 0, + }, }, }; diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index e517e1036b09..b90c172d5541 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -347,6 +347,13 @@ static struct clk spi1_clk = { .flags = DA850_CLK_ASYNC3, }; +static struct clk vpif_clk = { + .name = "vpif", + .parent = &pll0_sysclk2, + .lpsc = DA850_LPSC1_VPIF, + .gpsc = 1, +}; + static struct clk sata_clk = { .name = "sata", .parent = &pll0_sysclk2, @@ -397,6 +404,7 @@ static struct clk_lookup da850_clks[] = { CLK(NULL, "usb20", &usb20_clk), CLK("spi_davinci.0", NULL, &spi0_clk), CLK("spi_davinci.1", NULL, &spi1_clk), + CLK("vpif", NULL, &vpif_clk), CLK("ahci", NULL, &sata_clk), CLK(NULL, NULL, NULL), }; @@ -573,6 +581,46 @@ static const struct mux_config da850_pins[] = { MUX_CFG(DA850, GPIO6_10, 13, 20, 15, 8, false) MUX_CFG(DA850, GPIO6_13, 13, 8, 15, 8, false) MUX_CFG(DA850, RTC_ALARM, 0, 28, 15, 2, false) + /* VPIF Capture */ + MUX_CFG(DA850, VPIF_DIN0, 15, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN1, 15, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN2, 14, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN3, 14, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN4, 14, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN5, 14, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN6, 14, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN7, 14, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN8, 16, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN9, 16, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN10, 15, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN11, 15, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN12, 15, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN13, 15, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN14, 15, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DIN15, 15, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN0, 14, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN1, 14, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN2, 19, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKIN3, 19, 16, 15, 1, false) + /* VPIF Display */ + MUX_CFG(DA850, VPIF_DOUT0, 17, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT1, 17, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT2, 16, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT3, 16, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT4, 16, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT5, 16, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT6, 16, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT7, 16, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT8, 18, 4, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT9, 18, 0, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT10, 17, 28, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT11, 17, 24, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT12, 17, 20, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT13, 17, 16, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT14, 17, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_DOUT15, 17, 8, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO2, 19, 12, 15, 1, false) + MUX_CFG(DA850, VPIF_CLKO3, 19, 20, 15, 1, false) #endif }; @@ -595,6 +643,26 @@ const short da850_lcdcntl_pins[] __initconst = { -1 }; +const short da850_vpif_capture_pins[] __initdata = { + DA850_VPIF_DIN0, DA850_VPIF_DIN1, DA850_VPIF_DIN2, DA850_VPIF_DIN3, + DA850_VPIF_DIN4, DA850_VPIF_DIN5, DA850_VPIF_DIN6, DA850_VPIF_DIN7, + DA850_VPIF_DIN8, DA850_VPIF_DIN9, DA850_VPIF_DIN10, DA850_VPIF_DIN11, + DA850_VPIF_DIN12, DA850_VPIF_DIN13, DA850_VPIF_DIN14, DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, DA850_VPIF_CLKIN1, DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + -1 +}; + +const short da850_vpif_display_pins[] __initdata = { + DA850_VPIF_DOUT0, DA850_VPIF_DOUT1, DA850_VPIF_DOUT2, DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, DA850_VPIF_DOUT5, DA850_VPIF_DOUT6, DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, DA850_VPIF_DOUT9, DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, DA850_VPIF_DOUT12, DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, DA850_VPIF_DOUT15, DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, + -1 +}; + /* FIQ are pri 0-1; otherwise 2-7, with 7 lowest priority */ static u8 da850_default_priorities[DA850_N_CP_INTC_IRQ] = { [IRQ_DA8XX_COMMTX] = 7, @@ -1064,6 +1132,90 @@ no_ddrpll_mem: return ret; } +/* VPIF resource, platform data */ +static u64 da850_vpif_dma_mask = DMA_BIT_MASK(32); + +static struct resource da850_vpif_resource[] = { + { + .start = DA8XX_VPIF_BASE, + .end = DA8XX_VPIF_BASE + 0xfff, + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device da850_vpif_dev = { + .name = "vpif", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_resource, + .num_resources = ARRAY_SIZE(da850_vpif_resource), +}; + +static struct resource da850_vpif_display_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_display_dev = { + .name = "vpif_display", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_display_resource, + .num_resources = ARRAY_SIZE(da850_vpif_display_resource), +}; + +static struct resource da850_vpif_capture_resource[] = { + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, + { + .start = IRQ_DA850_VPIFINT, + .end = IRQ_DA850_VPIFINT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device da850_vpif_capture_dev = { + .name = "vpif_capture", + .id = -1, + .dev = { + .dma_mask = &da850_vpif_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = da850_vpif_capture_resource, + .num_resources = ARRAY_SIZE(da850_vpif_capture_resource), +}; + +int __init da850_register_vpif(void) +{ + return platform_device_register(&da850_vpif_dev); +} + +int __init da850_register_vpif_display(struct vpif_display_config + *display_config) +{ + da850_vpif_display_dev.dev.platform_data = display_config; + return platform_device_register(&da850_vpif_display_dev); +} + +int __init da850_register_vpif_capture(struct vpif_capture_config + *capture_config) +{ + da850_vpif_capture_dev.dev.platform_data = capture_config; + return platform_device_register(&da850_vpif_capture_dev); +} + static struct davinci_soc_info davinci_soc_info_da850 = { .io_desc = da850_io_desc, .io_desc_num = ARRAY_SIZE(da850_io_desc), diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 0755d466221a..cd0c8b1e1ecf 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -701,7 +701,7 @@ static struct resource dm644x_venc_resources[] = { #define DM644X_VPSS_DACCLKEN BIT(4) static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, - unsigned int mode) + unsigned int pclock) { int ret = 0; u32 v = DM644X_VPSS_VENCLKEN; @@ -711,27 +711,18 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); break; - case VPBE_ENC_DV_PRESET: - switch (mode) { - case V4L2_DV_480P59_94: - case V4L2_DV_576P50: + case VPBE_ENC_CUSTOM_TIMINGS: + if (pclock <= 27000000) { v |= DM644X_VPSS_MUXSEL_PLL2_MODE | DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - case V4L2_DV_720P60: - case V4L2_DV_1080I60: - case V4L2_DV_1080P30: + } else { /* * For HD, use external clock source since * HD requires higher clock rate */ v |= DM644X_VPSS_MUXSEL_VPBECLK_MODE; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); - break; - default: - ret = -EINVAL; - break; } break; default: diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index c9ee723c56f3..aaccdc4528fc 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -17,6 +17,7 @@ #include <linux/davinci_emac.h> #include <linux/spi/spi.h> #include <linux/platform_data/davinci_asp.h> +#include <linux/videodev2.h> #include <mach/serial.h> #include <mach/edma.h> @@ -26,6 +27,8 @@ #include <linux/platform_data/usb-davinci.h> #include <linux/platform_data/spi-davinci.h> +#include <media/davinci/vpif_types.h> + extern void __iomem *da8xx_syscfg0_base; extern void __iomem *da8xx_syscfg1_base; @@ -63,6 +66,7 @@ extern unsigned int da850_max_speed; #define DA8XX_PLL0_BASE 0x01c11000 #define DA8XX_TIMER64P0_BASE 0x01c20000 #define DA8XX_TIMER64P1_BASE 0x01c21000 +#define DA8XX_VPIF_BASE 0x01e17000 #define DA8XX_GPIO_BASE 0x01e26000 #define DA8XX_PSC1_BASE 0x01e27000 #define DA8XX_AEMIF_CS2_BASE 0x60000000 @@ -92,6 +96,11 @@ int da8xx_register_cpuidle(void); void __iomem * __init da8xx_get_mem_ctlr(void); int da850_register_pm(struct platform_device *pdev); int __init da850_register_sata(unsigned long refclkpn); +int __init da850_register_vpif(void); +int __init da850_register_vpif_display + (struct vpif_display_config *display_config); +int __init da850_register_vpif_capture + (struct vpif_capture_config *capture_config); void da8xx_restart(char mode, const char *cmd); extern struct platform_device da8xx_serial_device; @@ -126,6 +135,8 @@ extern const short da830_ecap1_pins[]; extern const short da830_ecap2_pins[]; extern const short da830_eqep0_pins[]; extern const short da830_eqep1_pins[]; +extern const short da850_vpif_capture_pins[]; +extern const short da850_vpif_display_pins[]; extern const short da850_i2c0_pins[]; extern const short da850_i2c1_pins[]; diff --git a/arch/arm/mach-davinci/include/mach/mux.h b/arch/arm/mach-davinci/include/mach/mux.h index a7e92fca32e6..9e95b8a1edb6 100644 --- a/arch/arm/mach-davinci/include/mach/mux.h +++ b/arch/arm/mach-davinci/include/mach/mux.h @@ -928,6 +928,48 @@ enum davinci_da850_index { DA850_GPIO6_10, DA850_GPIO6_13, DA850_RTC_ALARM, + + /* VPIF Capture */ + DA850_VPIF_DIN0, + DA850_VPIF_DIN1, + DA850_VPIF_DIN2, + DA850_VPIF_DIN3, + DA850_VPIF_DIN4, + DA850_VPIF_DIN5, + DA850_VPIF_DIN6, + DA850_VPIF_DIN7, + DA850_VPIF_DIN8, + DA850_VPIF_DIN9, + DA850_VPIF_DIN10, + DA850_VPIF_DIN11, + DA850_VPIF_DIN12, + DA850_VPIF_DIN13, + DA850_VPIF_DIN14, + DA850_VPIF_DIN15, + DA850_VPIF_CLKIN0, + DA850_VPIF_CLKIN1, + DA850_VPIF_CLKIN2, + DA850_VPIF_CLKIN3, + + /* VPIF Display */ + DA850_VPIF_DOUT0, + DA850_VPIF_DOUT1, + DA850_VPIF_DOUT2, + DA850_VPIF_DOUT3, + DA850_VPIF_DOUT4, + DA850_VPIF_DOUT5, + DA850_VPIF_DOUT6, + DA850_VPIF_DOUT7, + DA850_VPIF_DOUT8, + DA850_VPIF_DOUT9, + DA850_VPIF_DOUT10, + DA850_VPIF_DOUT11, + DA850_VPIF_DOUT12, + DA850_VPIF_DOUT13, + DA850_VPIF_DOUT14, + DA850_VPIF_DOUT15, + DA850_VPIF_CLKO2, + DA850_VPIF_CLKO3, }; enum davinci_tnetv107x_index { diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h index 405318e35bf6..40a0027838e8 100644 --- a/arch/arm/mach-davinci/include/mach/psc.h +++ b/arch/arm/mach-davinci/include/mach/psc.h @@ -166,6 +166,7 @@ #define DA830_LPSC1_McASP1 8 #define DA850_LPSC1_SATA 8 #define DA830_LPSC1_McASP2 9 +#define DA850_LPSC1_VPIF 9 #define DA8XX_LPSC1_SPI1 10 #define DA8XX_LPSC1_I2C 11 #define DA8XX_LPSC1_UART1 12 diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 85fc2feb0af0..c05d7aa84031 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -378,10 +378,10 @@ static struct regulator_consumer_supply __initdata max8997_ldo1_[] = { }; static struct regulator_consumer_supply __initdata max8997_ldo3_[] = { REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"), /* USB */ - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo4_[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata max8997_ldo5_[] = { REGULATOR_SUPPLY("vhsic", "modemctl"), /* MODEM */ @@ -1180,9 +1180,7 @@ static struct platform_device cam_8m_12v_fixed_rdev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_MEGA_RST EXYNOS4_GPY3(7) /* ISP_RESET */ @@ -1226,7 +1224,6 @@ static struct s5p_fimc_isp_info nuri_camera_sensors[] = { .bus_type = FIMC_MIPI_CSI2, .board_info = &m5mols_board_info, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index c11a62e23dcc..9adf491674ea 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -97,12 +97,12 @@ static struct s3c2410_uartcfg origen_uartcfgs[] __initdata = { }; static struct regulator_consumer_supply __initdata ldo3_consumer[] = { - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), /* MIPI */ REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), /* HDMI */ REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), /* HDMI */ }; static struct regulator_consumer_supply __initdata ldo6_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), /* MIPI */ + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), /* MIPI */ }; static struct regulator_consumer_supply __initdata ldo7_consumer[] = { REGULATOR_SUPPLY("avdd", "alc5625"), /* Realtek ALC5625 */ diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 08b81fd99505..ebc9dd339a38 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -209,7 +209,7 @@ static struct regulator_consumer_supply lp3974_ldo3_consumer[] = { REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"), REGULATOR_SUPPLY("vdd", "exynos4-hdmi"), REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"), - REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddcore", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo3_data = { @@ -273,7 +273,7 @@ static struct regulator_init_data lp3974_ldo6_data = { }; static struct regulator_consumer_supply lp3974_ldo7_consumer[] = { - REGULATOR_SUPPLY("vdd18", "s5p-mipi-csis.0"), + REGULATOR_SUPPLY("vddio", "s5p-mipi-csis.0"), }; static struct regulator_init_data lp3974_ldo7_data = { @@ -942,9 +942,7 @@ static struct platform_device cam_s_if_fixed_reg_dev = { static struct s5p_platform_mipi_csis mipi_csis_platdata = { .clk_rate = 166000000UL, .lanes = 2, - .alignment = 32, .hs_settle = 12, - .phy_enable = s5p_csis_phy_enable, }; #define GPIO_CAM_LEVEL_EN(n) EXYNOS4_GPE4(n + 3) @@ -1008,7 +1006,6 @@ static struct s5p_fimc_isp_info universal_camera_sensors[] = { .board_info = &m5mols_board_info, .i2c_bus_num = 0, .clk_frequency = 24000000UL, - .csi_data_align = 32, }, }; diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 101b9681c08c..c9a4963b5c3d 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -624,6 +624,23 @@ config ARM_THUMBEE Say Y here if you have a CPU with the ThumbEE extension and code to make use of it. Say N for code that can run on CPUs without ThumbEE. +config ARM_VIRT_EXT + bool "Native support for the ARM Virtualization Extensions" + depends on MMU && CPU_V7 + help + Enable the kernel to make use of the ARM Virtualization + Extensions to install hypervisors without run-time firmware + assistance. + + A compliant bootloader is required in order to make maximum + use of this feature. Refer to Documentation/arm/Booting for + details. + + It is safe to enable this option even if the kernel may not be + booted in HYP mode, may not have support for the + virtualization extensions, or may be booted with a + non-compliant bootloader. + config SWP_EMULATE bool "Emulate SWP/SWPB instructions" depends on !CPU_USE_DOMAINS && CPU_V7 diff --git a/arch/arm/mm/cache-fa.S b/arch/arm/mm/cache-fa.S index 072016371093..e505befe51b5 100644 --- a/arch/arm/mm/cache-fa.S +++ b/arch/arm/mm/cache-fa.S @@ -240,6 +240,9 @@ ENTRY(fa_dma_unmap_area) mov pc, lr ENDPROC(fa_dma_unmap_area) + .globl fa_flush_kern_cache_louis + .equ fa_flush_kern_cache_louis, fa_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v3.S b/arch/arm/mm/cache-v3.S index 52e35f32eefb..8a3fadece8d3 100644 --- a/arch/arm/mm/cache-v3.S +++ b/arch/arm/mm/cache-v3.S @@ -128,6 +128,9 @@ ENTRY(v3_dma_map_area) ENDPROC(v3_dma_unmap_area) ENDPROC(v3_dma_map_area) + .globl v3_flush_kern_cache_louis + .equ v3_flush_kern_cache_louis, v3_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S index 022135d2b7e4..43e5d77be677 100644 --- a/arch/arm/mm/cache-v4.S +++ b/arch/arm/mm/cache-v4.S @@ -140,6 +140,9 @@ ENTRY(v4_dma_map_area) ENDPROC(v4_dma_unmap_area) ENDPROC(v4_dma_map_area) + .globl v4_flush_kern_cache_louis + .equ v4_flush_kern_cache_louis, v4_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4wb.S b/arch/arm/mm/cache-v4wb.S index 8f1eeae340c8..cd4945321407 100644 --- a/arch/arm/mm/cache-v4wb.S +++ b/arch/arm/mm/cache-v4wb.S @@ -251,6 +251,9 @@ ENTRY(v4wb_dma_unmap_area) mov pc, lr ENDPROC(v4wb_dma_unmap_area) + .globl v4wb_flush_kern_cache_louis + .equ v4wb_flush_kern_cache_louis, v4wb_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v4wt.S b/arch/arm/mm/cache-v4wt.S index b34a5f908a82..11e5e5838bc5 100644 --- a/arch/arm/mm/cache-v4wt.S +++ b/arch/arm/mm/cache-v4wt.S @@ -196,6 +196,9 @@ ENTRY(v4wt_dma_map_area) ENDPROC(v4wt_dma_unmap_area) ENDPROC(v4wt_dma_map_area) + .globl v4wt_flush_kern_cache_louis + .equ v4wt_flush_kern_cache_louis, v4wt_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S index 4b10760c56d6..d8fd4d4bd3d4 100644 --- a/arch/arm/mm/cache-v6.S +++ b/arch/arm/mm/cache-v6.S @@ -326,6 +326,9 @@ ENTRY(v6_dma_unmap_area) mov pc, lr ENDPROC(v6_dma_unmap_area) + .globl v6_flush_kern_cache_louis + .equ v6_flush_kern_cache_louis, v6_flush_kern_cache_all + __INITDATA @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 3b172275262e..cd956647c21a 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -33,6 +33,24 @@ ENTRY(v7_flush_icache_all) mov pc, lr ENDPROC(v7_flush_icache_all) + /* + * v7_flush_dcache_louis() + * + * Flush the D-cache up to the Level of Unification Inner Shareable + * + * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) + */ + +ENTRY(v7_flush_dcache_louis) + dmb @ ensure ordering with previous memory accesses + mrc p15, 1, r0, c0, c0, 1 @ read clidr, r0 = clidr + ands r3, r0, #0xe00000 @ extract LoUIS from clidr + mov r3, r3, lsr #20 @ r3 = LoUIS * 2 + moveq pc, lr @ return if level == 0 + mov r10, #0 @ r10 (starting level) = 0 + b flush_levels @ start flushing cache levels +ENDPROC(v7_flush_dcache_louis) + /* * v7_flush_dcache_all() * @@ -49,7 +67,7 @@ ENTRY(v7_flush_dcache_all) mov r3, r3, lsr #23 @ left align loc bit field beq finished @ if loc is 0, then no need to clean mov r10, #0 @ start clean at cache level 0 -loop1: +flush_levels: add r2, r10, r10, lsr #1 @ work out 3x current cache level mov r1, r0, lsr r2 @ extract cache type bits from clidr and r1, r1, #7 @ mask of the bits for current cache only @@ -71,9 +89,9 @@ loop1: clz r5, r4 @ find bit position of way size increment ldr r7, =0x7fff ands r7, r7, r1, lsr #13 @ extract max number of the index size -loop2: +loop1: mov r9, r4 @ create working copy of max way size -loop3: +loop2: ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11 THUMB( lsl r6, r9, r5 ) THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 @@ -82,13 +100,13 @@ loop3: THUMB( orr r11, r11, r6 ) @ factor index number into r11 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way subs r9, r9, #1 @ decrement the way - bge loop3 - subs r7, r7, #1 @ decrement the index bge loop2 + subs r7, r7, #1 @ decrement the index + bge loop1 skip: add r10, r10, #2 @ increment cache number cmp r3, r10 - bgt loop1 + bgt flush_levels finished: mov r10, #0 @ swith back to cache level 0 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr @@ -120,6 +138,24 @@ ENTRY(v7_flush_kern_cache_all) mov pc, lr ENDPROC(v7_flush_kern_cache_all) + /* + * v7_flush_kern_cache_louis(void) + * + * Flush the data cache up to Level of Unification Inner Shareable. + * Invalidate the I-cache to the point of unification. + */ +ENTRY(v7_flush_kern_cache_louis) + ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) + THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) + bl v7_flush_dcache_louis + mov r0, #0 + ALT_SMP(mcr p15, 0, r0, c7, c1, 0) @ invalidate I-cache inner shareable + ALT_UP(mcr p15, 0, r0, c7, c5, 0) @ I+BTB cache invalidate + ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) + THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) + mov pc, lr +ENDPROC(v7_flush_kern_cache_louis) + /* * v7_flush_cache_all() * diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 0650bb87c1e3..2bb61e703d6c 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -368,6 +368,9 @@ ENTRY(arm1020_dma_unmap_area) mov pc, lr ENDPROC(arm1020_dma_unmap_area) + .globl arm1020_flush_kern_cache_louis + .equ arm1020_flush_kern_cache_louis, arm1020_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1020 diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 4188478325a6..8f96aa40f510 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -354,6 +354,9 @@ ENTRY(arm1020e_dma_unmap_area) mov pc, lr ENDPROC(arm1020e_dma_unmap_area) + .globl arm1020e_flush_kern_cache_louis + .equ arm1020e_flush_kern_cache_louis, arm1020e_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1020e diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 33c68824bff0..8ebe4a469a22 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -343,6 +343,9 @@ ENTRY(arm1022_dma_unmap_area) mov pc, lr ENDPROC(arm1022_dma_unmap_area) + .globl arm1022_flush_kern_cache_louis + .equ arm1022_flush_kern_cache_louis, arm1022_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1022 diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index fbc1d5fc24dc..093fc7e520c3 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -337,6 +337,9 @@ ENTRY(arm1026_dma_unmap_area) mov pc, lr ENDPROC(arm1026_dma_unmap_area) + .globl arm1026_flush_kern_cache_louis + .equ arm1026_flush_kern_cache_louis, arm1026_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm1026 diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 1a8c138eb897..2c3b9421ab5e 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -319,6 +319,9 @@ ENTRY(arm920_dma_unmap_area) mov pc, lr ENDPROC(arm920_dma_unmap_area) + .globl arm920_flush_kern_cache_louis + .equ arm920_flush_kern_cache_louis, arm920_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm920 #endif diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 4c44d7e1c3ca..4464c49d7449 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -321,6 +321,9 @@ ENTRY(arm922_dma_unmap_area) mov pc, lr ENDPROC(arm922_dma_unmap_area) + .globl arm922_flush_kern_cache_louis + .equ arm922_flush_kern_cache_louis, arm922_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm922 #endif diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index ec5b1180994f..281eb9b9c1d6 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -376,6 +376,9 @@ ENTRY(arm925_dma_unmap_area) mov pc, lr ENDPROC(arm925_dma_unmap_area) + .globl arm925_flush_kern_cache_louis + .equ arm925_flush_kern_cache_louis, arm925_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm925 diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index c31e62c606c0..f1803f7e2972 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -339,6 +339,9 @@ ENTRY(arm926_dma_unmap_area) mov pc, lr ENDPROC(arm926_dma_unmap_area) + .globl arm926_flush_kern_cache_louis + .equ arm926_flush_kern_cache_louis, arm926_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm926 diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S index a613a7dd7146..8da189d4a402 100644 --- a/arch/arm/mm/proc-arm940.S +++ b/arch/arm/mm/proc-arm940.S @@ -267,6 +267,9 @@ ENTRY(arm940_dma_unmap_area) mov pc, lr ENDPROC(arm940_dma_unmap_area) + .globl arm940_flush_kern_cache_louis + .equ arm940_flush_kern_cache_louis, arm940_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm940 diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S index 9f4f2999fdd0..f666cf34075a 100644 --- a/arch/arm/mm/proc-arm946.S +++ b/arch/arm/mm/proc-arm946.S @@ -310,6 +310,9 @@ ENTRY(arm946_dma_unmap_area) mov pc, lr ENDPROC(arm946_dma_unmap_area) + .globl arm946_flush_kern_cache_louis + .equ arm946_flush_kern_cache_louis, arm946_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions arm946 diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S index 23a8e4c7f2bd..4106b09e0c29 100644 --- a/arch/arm/mm/proc-feroceon.S +++ b/arch/arm/mm/proc-feroceon.S @@ -415,6 +415,9 @@ ENTRY(feroceon_dma_unmap_area) mov pc, lr ENDPROC(feroceon_dma_unmap_area) + .globl feroceon_flush_kern_cache_louis + .equ feroceon_flush_kern_cache_louis, feroceon_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions feroceon @@ -431,6 +434,7 @@ ENDPROC(feroceon_dma_unmap_area) range_alias flush_icache_all range_alias flush_user_cache_all range_alias flush_kern_cache_all + range_alias flush_kern_cache_louis range_alias flush_user_cache_range range_alias coherent_kern_range range_alias coherent_user_range diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S index 2d8ff3ad86d3..b29a2265af01 100644 --- a/arch/arm/mm/proc-macros.S +++ b/arch/arm/mm/proc-macros.S @@ -299,6 +299,7 @@ ENTRY(\name\()_processor_functions) ENTRY(\name\()_cache_fns) .long \name\()_flush_icache_all .long \name\()_flush_kern_cache_all + .long \name\()_flush_kern_cache_louis .long \name\()_flush_user_cache_all .long \name\()_flush_user_cache_range .long \name\()_coherent_kern_range diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S index fbb2124a547d..82f9cdc751d6 100644 --- a/arch/arm/mm/proc-mohawk.S +++ b/arch/arm/mm/proc-mohawk.S @@ -303,6 +303,9 @@ ENTRY(mohawk_dma_unmap_area) mov pc, lr ENDPROC(mohawk_dma_unmap_area) + .globl mohawk_flush_kern_cache_louis + .equ mohawk_flush_kern_cache_louis, mohawk_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions mohawk diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index c2e2b66f72b5..846d279f3176 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -172,7 +172,7 @@ __v7_ca15mp_setup: __v7_setup: adr r12, __v7_setup_stack @ the local stack stmia r12, {r0-r5, r7, r9, r11, lr} - bl v7_flush_dcache_all + bl v7_flush_dcache_louis ldmia r12, {r0-r5, r7, r9, r11, lr} mrc p15, 0, r0, c0, c0, 0 @ read main ID register diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S index b0d57869da2d..eb93d6487f35 100644 --- a/arch/arm/mm/proc-xsc3.S +++ b/arch/arm/mm/proc-xsc3.S @@ -337,6 +337,9 @@ ENTRY(xsc3_dma_unmap_area) mov pc, lr ENDPROC(xsc3_dma_unmap_area) + .globl xsc3_flush_kern_cache_louis + .equ xsc3_flush_kern_cache_louis, xsc3_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions xsc3 diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 4ffebaa595ee..25510361aa18 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -410,6 +410,9 @@ ENTRY(xscale_dma_unmap_area) mov pc, lr ENDPROC(xscale_dma_unmap_area) + .globl xscale_flush_kern_cache_louis + .equ xscale_flush_kern_cache_louis, xscale_flush_kern_cache_all + @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S) define_cache_functions xscale @@ -439,6 +442,7 @@ ENDPROC(xscale_dma_unmap_area) a0_alias flush_icache_all a0_alias flush_user_cache_all a0_alias flush_kern_cache_all + a0_alias flush_kern_cache_louis a0_alias flush_user_cache_range a0_alias coherent_kern_range a0_alias coherent_user_range diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h index 826de74bfdd1..c08a54d9d889 100644 --- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h +++ b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h @@ -45,6 +45,12 @@ #define NMK_GPIO_ALT_B 2 #define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) +#define NMK_GPIO_ALT_CX_SHIFT 2 +#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) +#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C) + /* Pull up/down values */ enum nmk_gpio_pull { NMK_GPIO_PULL_NONE, diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h index 9c949c7c98a7..3b8ec60af351 100644 --- a/arch/arm/plat-nomadik/include/plat/pincfg.h +++ b/arch/arm/plat-nomadik/include/plat/pincfg.h @@ -25,6 +25,8 @@ * bit 19..20 - SLPM direction * bit 21..22 - SLPM Value (if output) * bit 23..25 - PDIS value (if input) + * bit 26 - Gpio mode + * bit 27 - Sleep mode * * to facilitate the definition, the following macros are provided * diff --git a/arch/arm/plat-samsung/setup-mipiphy.c b/arch/arm/plat-samsung/setup-mipiphy.c index 683c466c0e6a..147459327601 100644 --- a/arch/arm/plat-samsung/setup-mipiphy.c +++ b/arch/arm/plat-samsung/setup-mipiphy.c @@ -14,24 +14,18 @@ #include <linux/spinlock.h> #include <mach/regs-clock.h> -static int __s5p_mipi_phy_control(struct platform_device *pdev, - bool on, u32 reset) +static int __s5p_mipi_phy_control(int id, bool on, u32 reset) { static DEFINE_SPINLOCK(lock); void __iomem *addr; unsigned long flags; - int pid; u32 cfg; - if (!pdev) + id = max(0, id); + if (id > 1) return -EINVAL; - pid = (pdev->id == -1) ? 0 : pdev->id; - - if (pid != 0 && pid != 1) - return -EINVAL; - - addr = S5P_MIPI_DPHY_CONTROL(pid); + addr = S5P_MIPI_DPHY_CONTROL(id); spin_lock_irqsave(&lock, flags); @@ -52,12 +46,12 @@ static int __s5p_mipi_phy_control(struct platform_device *pdev, return 0; } -int s5p_csis_phy_enable(struct platform_device *pdev, bool on) +int s5p_csis_phy_enable(int id, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_SRESETN); + return __s5p_mipi_phy_control(id, on, S5P_MIPI_DPHY_SRESETN); } int s5p_dsim_phy_enable(struct platform_device *pdev, bool on) { - return __s5p_mipi_phy_control(pdev, on, S5P_MIPI_DPHY_MRESETN); + return __s5p_mipi_phy_control(pdev->id, on, S5P_MIPI_DPHY_MRESETN); } diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 3c720ef6c32d..4c10e607c908 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -39,7 +39,7 @@ config IA64 select ARCH_TASK_STRUCT_ALLOCATOR select ARCH_THREAD_INFO_ALLOCATOR select ARCH_CLOCKSOURCE_DATA - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD default y help The Itanium Processor Family is Intel's 64-bit successor to diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c index 80ff9acc5edf..f6388216080d 100644 --- a/arch/ia64/kernel/time.c +++ b/arch/ia64/kernel/time.c @@ -19,7 +19,7 @@ #include <linux/interrupt.h> #include <linux/efi.h> #include <linux/timex.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/platform_device.h> #include <asm/machvec.h> @@ -454,7 +454,7 @@ void update_vsyscall_tz(void) { } -void update_vsyscall(struct timespec *wall, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall, struct timespec *wtm, struct clocksource *c, u32 mult) { write_seqcount_begin(&fsyscall_gtod_data.seq); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 78d6588b6e86..969f3d9ded91 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -137,7 +137,7 @@ config PPC select ARCH_HAVE_NMI_SAFE_CMPXCHG select GENERIC_SMP_IDLE_THREAD select GENERIC_CMOS_UPDATE - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD select GENERIC_CLOCKEVENTS select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index c9986fd400d8..ce4cb772dc78 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -73,7 +73,7 @@ /* powerpc clocksource/clockevent code */ #include <linux/clockchips.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> static cycle_t rtc_read(struct clocksource *); static struct clocksource clocksource_rtc = { @@ -727,7 +727,7 @@ static cycle_t timebase_read(struct clocksource *cs) return (cycle_t)get_tb(); } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, struct clocksource *clock, u32 mult) { u64 new_tb_to_xs, new_stamp_xsec; diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 99d2d790d152..e5dac1236185 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -131,7 +131,7 @@ config S390 select HAVE_UID16 if 32BIT select ARCH_WANT_IPC_PARSE_VERSION select GENERIC_SMP_IDLE_THREAD - select GENERIC_TIME_VSYSCALL + select GENERIC_TIME_VSYSCALL_OLD select GENERIC_CLOCKEVENTS select KTIME_SCALAR if 32BIT select HAVE_ARCH_SECCOMP_FILTER diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 2db1011b8b19..7fcd690d42c7 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -34,7 +34,7 @@ #include <linux/profile.h> #include <linux/timex.h> #include <linux/notifier.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/clockchips.h> #include <linux/gfp.h> #include <linux/kprobes.h> @@ -219,7 +219,7 @@ struct clocksource * __init clocksource_default_clock(void) return &clocksource_tod; } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, +void update_vsyscall_old(struct timespec *wall_time, struct timespec *wtm, struct clocksource *clock, u32 mult) { if (clock != &clocksource_tod) diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h index 8b38be2de9e1..46e24d36b7da 100644 --- a/arch/x86/include/asm/vgtod.h +++ b/arch/x86/include/asm/vgtod.h @@ -17,8 +17,8 @@ struct vsyscall_gtod_data { /* open coded 'struct timespec' */ time_t wall_time_sec; - u32 wall_time_nsec; - u32 monotonic_time_nsec; + u64 wall_time_snsec; + u64 monotonic_time_snsec; time_t monotonic_time_sec; struct timezone sys_tz; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d609be046b57..a2bb18e02839 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -68,6 +68,7 @@ #include <linux/percpu.h> #include <linux/crash_dump.h> #include <linux/tboot.h> +#include <linux/jiffies.h> #include <video/edid.h> @@ -1032,6 +1033,8 @@ void __init setup_arch(char **cmdline_p) mcheck_init(); arch_init_ideal_nops(); + + register_refined_jiffies(CLOCK_TICK_RATE); } #ifdef CONFIG_X86_32 diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c index 8d141b309046..3a3e8c9e280d 100644 --- a/arch/x86/kernel/vsyscall_64.c +++ b/arch/x86/kernel/vsyscall_64.c @@ -28,7 +28,7 @@ #include <linux/jiffies.h> #include <linux/sysctl.h> #include <linux/topology.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/getcpu.h> #include <linux/cpu.h> #include <linux/smp.h> @@ -82,32 +82,41 @@ void update_vsyscall_tz(void) vsyscall_gtod_data.sys_tz = sys_tz; } -void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, - struct clocksource *clock, u32 mult) +void update_vsyscall(struct timekeeper *tk) { - struct timespec monotonic; + struct vsyscall_gtod_data *vdata = &vsyscall_gtod_data; - write_seqcount_begin(&vsyscall_gtod_data.seq); + write_seqcount_begin(&vdata->seq); /* copy vsyscall data */ - vsyscall_gtod_data.clock.vclock_mode = clock->archdata.vclock_mode; - vsyscall_gtod_data.clock.cycle_last = clock->cycle_last; - vsyscall_gtod_data.clock.mask = clock->mask; - vsyscall_gtod_data.clock.mult = mult; - vsyscall_gtod_data.clock.shift = clock->shift; - - vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec; - vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec; + vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode; + vdata->clock.cycle_last = tk->clock->cycle_last; + vdata->clock.mask = tk->clock->mask; + vdata->clock.mult = tk->mult; + vdata->clock.shift = tk->shift; + + vdata->wall_time_sec = tk->xtime_sec; + vdata->wall_time_snsec = tk->xtime_nsec; + + vdata->monotonic_time_sec = tk->xtime_sec + + tk->wall_to_monotonic.tv_sec; + vdata->monotonic_time_snsec = tk->xtime_nsec + + (tk->wall_to_monotonic.tv_nsec + << tk->shift); + while (vdata->monotonic_time_snsec >= + (((u64)NSEC_PER_SEC) << tk->shift)) { + vdata->monotonic_time_snsec -= + ((u64)NSEC_PER_SEC) << tk->shift; + vdata->monotonic_time_sec++; + } - monotonic = timespec_add(*wall_time, *wtm); - vsyscall_gtod_data.monotonic_time_sec = monotonic.tv_sec; - vsyscall_gtod_data.monotonic_time_nsec = monotonic.tv_nsec; + vdata->wall_time_coarse.tv_sec = tk->xtime_sec; + vdata->wall_time_coarse.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); - vsyscall_gtod_data.wall_time_coarse = __current_kernel_time(); - vsyscall_gtod_data.monotonic_time_coarse = - timespec_add(vsyscall_gtod_data.wall_time_coarse, *wtm); + vdata->monotonic_time_coarse = timespec_add(vdata->wall_time_coarse, + tk->wall_to_monotonic); - write_seqcount_end(&vsyscall_gtod_data.seq); + write_seqcount_end(&vdata->seq); } static void warn_bad_vsyscall(const char *level, struct pt_regs *regs, diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c index 885eff49d6ab..4df6c373421a 100644 --- a/arch/x86/vdso/vclock_gettime.c +++ b/arch/x86/vdso/vclock_gettime.c @@ -80,7 +80,7 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz) } -notrace static inline long vgetns(void) +notrace static inline u64 vgetsns(void) { long v; cycles_t cycles; @@ -91,21 +91,24 @@ notrace static inline long vgetns(void) else return 0; v = (cycles - gtod->clock.cycle_last) & gtod->clock.mask; - return (v * gtod->clock.mult) >> gtod->clock.shift; + return v * gtod->clock.mult; } /* Code size doesn't matter (vdso is 4k anyway) and this is faster. */ notrace static int __always_inline do_realtime(struct timespec *ts) { - unsigned long seq, ns; + unsigned long seq; + u64 ns; int mode; + ts->tv_nsec = 0; do { seq = read_seqcount_begin(>od->seq); mode = gtod->clock.vclock_mode; ts->tv_sec = gtod->wall_time_sec; - ts->tv_nsec = gtod->wall_time_nsec; - ns = vgetns(); + ns = gtod->wall_time_snsec; + ns += vgetsns(); + ns >>= gtod->clock.shift; } while (unlikely(read_seqcount_retry(>od->seq, seq))); timespec_add_ns(ts, ns); @@ -114,15 +117,18 @@ notrace static int __always_inline do_realtime(struct timespec *ts) notrace static int do_monotonic(struct timespec *ts) { - unsigned long seq, ns; + unsigned long seq; + u64 ns; int mode; + ts->tv_nsec = 0; do { seq = read_seqcount_begin(>od->seq); mode = gtod->clock.vclock_mode; ts->tv_sec = gtod->monotonic_time_sec; - ts->tv_nsec = gtod->monotonic_time_nsec; - ns = vgetns(); + ns = gtod->monotonic_time_snsec; + ns += vgetsns(); + ns >>= gtod->clock.shift; } while (unlikely(read_seqcount_retry(>od->seq, seq))); timespec_add_ns(ts, ns); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index bf788d34530d..e3497f240eab 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -987,7 +987,16 @@ static void xen_write_cr4(unsigned long cr4) native_write_cr4(cr4); } - +#ifdef CONFIG_X86_64 +static inline unsigned long xen_read_cr8(void) +{ + return 0; +} +static inline void xen_write_cr8(unsigned long val) +{ + BUG_ON(val); +} +#endif static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high) { int ret; @@ -1156,6 +1165,11 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_cr4_safe = native_read_cr4_safe, .write_cr4 = xen_write_cr4, +#ifdef CONFIG_X86_64 + .read_cr8 = xen_read_cr8, + .write_cr8 = xen_write_cr8, +#endif + .wbinvd = native_wbinvd, .read_msr = native_read_msr_safe, @@ -1164,6 +1178,8 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = { .read_tsc = native_read_tsc, .read_pmc = native_read_pmc, + .read_tscp = native_read_tscp, + .iret = xen_iret, .irq_enable_sysexit = xen_sysexit, #ifdef CONFIG_X86_64 diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index fd28d86fe3d2..6226c99729b9 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -47,6 +47,7 @@ #include <linux/gfp.h> #include <linux/memblock.h> #include <linux/seq_file.h> +#include <linux/crash_dump.h> #include <trace/events/xen.h> @@ -2381,6 +2382,43 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order) EXPORT_SYMBOL_GPL(xen_destroy_contiguous_region); #ifdef CONFIG_XEN_PVHVM +#ifdef CONFIG_PROC_VMCORE +/* + * This function is used in two contexts: + * - the kdump kernel has to check whether a pfn of the crashed kernel + * was a ballooned page. vmcore is using this function to decide + * whether to access a pfn of the crashed kernel. + * - the kexec kernel has to check whether a pfn was ballooned by the + * previous kernel. If the pfn is ballooned, handle it properly. + * Returns 0 if the pfn is not backed by a RAM page, the caller may + * handle the pfn special in this case. + */ +static int xen_oldmem_pfn_is_ram(unsigned long pfn) +{ + struct xen_hvm_get_mem_type a = { + .domid = DOMID_SELF, + .pfn = pfn, + }; + int ram; + + if (HYPERVISOR_hvm_op(HVMOP_get_mem_type, &a)) + return -ENXIO; + + switch (a.mem_type) { + case HVMMEM_mmio_dm: + ram = 0; + break; + case HVMMEM_ram_rw: + case HVMMEM_ram_ro: + default: + ram = 1; + break; + } + + return ram; +} +#endif + static void xen_hvm_exit_mmap(struct mm_struct *mm) { struct xen_hvm_pagetable_dying a; @@ -2411,6 +2449,9 @@ void __init xen_hvm_init_mmu_ops(void) { if (is_pagetable_dying_supported()) pv_mmu_ops.exit_mmap = xen_hvm_exit_mmap; +#ifdef CONFIG_PROC_VMCORE + register_oldmem_pfn_is_ram(&xen_oldmem_pfn_is_ram); +#endif } #endif diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 8f58f241c10d..7e92793260f0 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -966,6 +966,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) break; } + c->lna = LNA_AUTO; + return 0; } @@ -1054,6 +1056,8 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), + + _DTV_CMD(DTV_LNA, 0, 0), }; static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) @@ -1440,6 +1444,10 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d; break; + case DTV_LNA: + tvp->u.data = c->lna; + break; + default: return -EINVAL; } @@ -1731,10 +1739,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, case DTV_INTERLEAVING: c->interleaving = tvp->u.data; break; - case DTV_LNA: - if (fe->ops.set_lna) - r = fe->ops.set_lna(fe, tvp->u.data); - break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: @@ -1806,6 +1810,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; break; + case DTV_LNA: + c->lna = tvp->u.data; + if (fe->ops.set_lna) + r = fe->ops.set_lna(fe); + break; + default: return -EINVAL; } @@ -2309,7 +2319,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, fepriv->tune_mode_flags = (unsigned long) parg; err = 0; break; - }; + } return err; } diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 44a445cee74f..97112cd88a17 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -303,7 +303,7 @@ struct dvb_frontend_ops { int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); - int (*set_lna)(struct dvb_frontend *, int); + int (*set_lna)(struct dvb_frontend *); /* These callbacks are for devices that implement their own * tuning algorithms, rather than a simple swzigzag @@ -391,6 +391,8 @@ struct dtv_frontend_properties { u8 atscmh_sccc_code_mode_b; u8 atscmh_sccc_code_mode_c; u8 atscmh_sccc_code_mode_d; + + u32 lna; }; struct dvb_frontend { diff --git a/drivers/media/dvb-frontends/a8293.c b/drivers/media/dvb-frontends/a8293.c index cff44a389b40..74fbb5d58bed 100644 --- a/drivers/media/dvb-frontends/a8293.c +++ b/drivers/media/dvb-frontends/a8293.c @@ -90,7 +90,7 @@ static int a8293_set_voltage(struct dvb_frontend *fe, default: ret = -EINVAL; goto err; - }; + } ret = a8293_wr(priv, &priv->reg[0], 1); if (ret) diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index e9f04a36577b..a204f2828820 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -241,7 +241,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) KBUILD_MODNAME, gpio); ret = -EINVAL; goto err; - }; + } switch (gpio) { case 0: @@ -253,7 +253,7 @@ static int af9013_set_gpio(struct af9013_state *state, u8 gpio, u8 gpioval) default: pos = 4; break; - }; + } ret = af9013_wr_reg_bits(state, addr, pos, 4, gpioval); if (ret) @@ -726,7 +726,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__); auto_mode = 1; - }; + } switch (c->modulation) { case QAM_AUTO: diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 8162d939c4b2..464ad878490b 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -408,7 +408,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) { struct af9033_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i, spec_inv; + int ret, i, spec_inv, sampling_freq; u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; @@ -465,18 +465,20 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else if_frequency = 0; - while (if_frequency > (adc_freq / 2)) - if_frequency -= adc_freq; + sampling_freq = if_frequency; - if (if_frequency >= 0) + while (sampling_freq > (adc_freq / 2)) + sampling_freq -= adc_freq; + + if (sampling_freq >= 0) spec_inv *= -1; else - if_frequency *= -1; + sampling_freq *= -1; - freq_cw = af9033_div(state, if_frequency, adc_freq, 23ul); + freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul); if (spec_inv == -1) - freq_cw *= -1; + freq_cw = 0x800000 - freq_cw; /* get adc multiplies */ ret = af9033_rd_reg(state, 0x800045, &tmp); diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 033cd7ad3ca2..1b77909c0c71 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -527,7 +527,7 @@ static int bcm3510_set_frontend(struct dvb_frontend *fe) cmd.ACQUIRE1.IF_FREQ = 0x0; default: return -EINVAL; - }; + } cmd.ACQUIRE0.OFFSET = 0; cmd.ACQUIRE0.NTSCSWEEP = 1; cmd.ACQUIRE0.FA = 1; diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 3180f5b2a6a6..0cd6927e654c 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -218,7 +218,7 @@ static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec) } else return -EOPNOTSUPP; /* fixme (low): which is the correct return code? */ - }; + } return 0; } @@ -275,7 +275,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) cx24110_writereg(state,0x07,tmp|0x3); cx24110_writereg(state,0x06,0x78); fclk=90999000UL; - }; + } dprintk("cx24110 debug: fclk %d Hz\n",fclk); /* we need to divide two integers with approx. 27 bits in 32 bit arithmetic giving a 25 bit result */ @@ -362,7 +362,7 @@ static int cx24110_initfe(struct dvb_frontend* fe) for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) { cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); - }; + } return 0; } diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 42648643693e..9b658c1cf39a 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -688,7 +688,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, { struct cxd2820r_priv *priv; int ret; - u8 tmp, gpio[GPIO_COUNT]; + u8 tmp; priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL); if (!priv) { @@ -735,6 +735,7 @@ struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg, * Use static GPIO configuration if GPIOLIB is undefined. * This is fallback condition. */ + u8 gpio[GPIO_COUNT]; gpio[0] = (*gpio_chip_base >> 0) & 0x07; gpio[1] = (*gpio_chip_base >> 3) & 0x07; gpio[2] = 0; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index f380eb43e9d5..6d9853750d2b 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -991,7 +991,7 @@ static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult) if (nrRetries > DRXD_MAX_RETRIES) { status = -1; break; - }; + } status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0); } while (waitCmd != 0); diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 4c8ac2657c4a..5b639087ce45 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -30,6 +30,7 @@ #include "ds3000.h" static int debug; +static int force_fw_upload; #define dprintk(args...) \ do { \ @@ -392,11 +393,13 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) dprintk("%s()\n", __func__); - if (ds3000_readreg(state, 0xb2) <= 0) + ret = ds3000_readreg(state, 0xb2); + if (ret < 0) return ret; - if (state->skip_fw_load) - return 0; + if (state->skip_fw_load || !force_fw_upload) + return 0; /* Firmware already uploaded, skipping */ + /* Load firmware */ /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, @@ -1306,6 +1309,9 @@ static struct dvb_frontend_ops ds3000_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +module_param(force_fw_upload, int, 0644); +MODULE_PARM_DESC(force_fw_upload, "Force firmware upload (default:0)"); + MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " "DS3000/TS2020 hardware"); MODULE_AUTHOR("Konstantin Dimitrov"); diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c index dcfc902c8678..d5acc304786b 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c @@ -121,16 +121,13 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; @@ -141,16 +138,13 @@ struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; @@ -161,16 +155,13 @@ struct dvb_frontend *dvb_dummy_fe_qam_attach(void) /* allocate memory for the internal state */ state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); - if (state == NULL) goto error; + if (!state) + return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c index 33d33f4d8867..0c642a5bf823 100644 --- a/drivers/media/dvb-frontends/isl6405.c +++ b/drivers/media/dvb-frontends/isl6405.c @@ -77,7 +77,7 @@ static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } } isl6405->config |= isl6405->override_or; isl6405->config &= isl6405->override_and; diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 684c8ec166cb..0cb3f0f74c9c 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -63,7 +63,7 @@ static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage break; default: return -EINVAL; - }; + } isl6421->config |= isl6421->override_or; isl6421->config &= isl6421->override_and; diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index 316457584fe7..c1c3400b2173 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -231,7 +231,7 @@ static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz) state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF; itd_dbg("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d\n", freq_khz, state->frequency, pllf, plln); - itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */; + itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */ itd1000_write_reg(state, PLLNL, plln & 0xff); itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f)); itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff); diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index cc11260e99df..5fd14f840ab0 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1421,8 +1421,8 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, config ? config->i2c_addr : 0); state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL); - if (state == NULL) - goto fail; + if (!state) + return NULL; state->cfg = config; state->i2c_adap = i2c_adap; @@ -1449,10 +1449,6 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, state->frontend.dtv_property_cache.atscmh_parade_id = 1; return &state->frontend; -fail: - lg_warn("unable to detect LG216x hardware\n"); - kfree(state); - return NULL; } EXPORT_SYMBOL(lg2160_attach); diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c index 13437259eeac..f3ba7b5faa2e 100644 --- a/drivers/media/dvb-frontends/lnbp21.c +++ b/drivers/media/dvb-frontends/lnbp21.c @@ -65,7 +65,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; @@ -108,7 +108,7 @@ static int lnbp21_set_tone(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } lnbp21->config |= lnbp21->override_or; lnbp21->config &= lnbp21->override_and; diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c index 84ad0390a4a1..c463da7f6dcc 100644 --- a/drivers/media/dvb-frontends/lnbp22.c +++ b/drivers/media/dvb-frontends/lnbp22.c @@ -73,7 +73,7 @@ static int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) break; default: return -EINVAL; - }; + } dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]); return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO; diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 8352ce1c9556..6ec16a243741 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -351,8 +351,8 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n"); /* allocate memory for the internal state */ state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; /* setup the state */ state->config = config; @@ -367,10 +367,6 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL(s5h1432_attach); diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index cd2288c07147..a271ac3eaec0 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -487,9 +487,9 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, kzalloc(sizeof(struct s921_state), GFP_KERNEL); dprintk("\n"); - if (state == NULL) { + if (!state) { rc("Unable to kzalloc\n"); - goto rcor; + return NULL; } /* setup the state */ @@ -502,11 +502,6 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, state->frontend.demodulator_priv = state; return &state->frontend; - -rcor: - kfree(state); - - return NULL; } EXPORT_SYMBOL(s921_attach); diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index a68a64800df7..73b47cc6a13b 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -343,7 +343,7 @@ static int si21xx_wait_diseqc_idle(struct si21xx_state *state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -472,7 +472,7 @@ static int si21xx_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt) break; default: return -EINVAL; - }; + } } static int si21xx_init(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index e37274c8f14e..2aa8ef76eba2 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -188,7 +188,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -207,7 +207,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -229,7 +229,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index f4096ccb226e..1bb81b5ae6e0 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -229,7 +229,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->hierarchy) { case HIERARCHY_NONE: @@ -248,7 +248,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } switch (p->code_rate_HP) { case FEC_1_2: @@ -270,7 +270,7 @@ static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05) break; default: return -EINVAL; - }; + } if (known_parameters) *reg0xc05 |= (2 << 1); /* use specified parameters */ diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 2e93e65d2cdb..45f9523f968f 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -575,8 +575,8 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, struct stb6100_state *state = NULL; state = kzalloc(sizeof (struct stb6100_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -587,10 +587,6 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, printk("%s: Attaching STB6100 \n", __func__); return fe; - -error: - kfree(state); - return NULL; } static int stb6100_release(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index 057b5f8effc0..92a6075cd82f 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -199,7 +199,7 @@ static int stv0299_wait_diseqc_fifo (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -216,7 +216,7 @@ static int stv0299_wait_diseqc_idle (struct stv0299_state* state, int timeout) return -ETIMEDOUT; } msleep(10); - }; + } return 0; } @@ -387,7 +387,7 @@ static int stv0299_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag break; default: return -EINVAL; - }; + } if (state->config->op0_off) reg0x0c &= ~0x10; diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 7f1badaf0d03..262dfa503c2a 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1552,8 +1552,8 @@ static int stv0900_status(struct stv0900_internal *intp, bitrate = (stv0900_get_mclk_freq(intp, intp->quartz)/1000000) * (tsbitrate1_val << 8 | tsbitrate0_val); bitrate /= 16384; - dprintk("TS bitrate = %d Mbit/sec \n", bitrate); - }; + dprintk("TS bitrate = %d Mbit/sec\n", bitrate); + } return locked; } diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 2c1c759a4f42..63cc12378d9a 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -228,8 +228,8 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, struct dvb_tuner_info *info; state = kzalloc(sizeof(struct tda665x_state), GFP_KERNEL); - if (state == NULL) - goto exit; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -246,10 +246,6 @@ struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, printk(KERN_DEBUG "%s: Attaching TDA665x (%s) tuner\n", __func__, info->name); return fe; - -exit: - kfree(state); - return NULL; } EXPORT_SYMBOL(tda665x_attach); diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c index 15912c96926a..9d08350fe4b0 100644 --- a/drivers/media/dvb-frontends/tda8083.c +++ b/drivers/media/dvb-frontends/tda8083.c @@ -175,7 +175,7 @@ static void tda8083_wait_diseqc_fifo (struct tda8083_state* state, int timeout) !(tda8083_readreg(state, 0x02) & 0x80)) { msleep(50); - }; + } } static int tda8083_set_tone (struct tda8083_state* state, fe_sec_tone_mode_t tone) @@ -215,7 +215,7 @@ static int tda8083_send_diseqc_burst (struct tda8083_state* state, fe_sec_mini_c break; default: return -EINVAL; - }; + } tda8083_wait_diseqc_fifo (state, 100); diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index d8eac3e30a7e..2cee69e34184 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -599,7 +599,7 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write4(client, 0x114, 0x01bf0c9e); cx25840_write4(client, 0x110, 0x000a030c); break; - }; + } /* ADC2 input select */ cx25840_write(client, 0x102, 0x10); diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 86c815be348c..90a6c520f115 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -16,9 +16,17 @@ #ifndef M5MOLS_H #define M5MOLS_H +#include <linux/sizes.h> #include <media/v4l2-subdev.h> #include "m5mols_reg.h" + +/* An amount of data transmitted in addition to the value + * determined by CAPP_JPEG_SIZE_MAX register. + */ +#define M5MOLS_JPEG_TAGS_SIZE 0x20000 +#define M5MOLS_MAIN_JPEG_SIZE_MAX (5 * SZ_1M) + extern int m5mols_debug; enum m5mols_restype { @@ -67,12 +75,14 @@ struct m5mols_exif { /** * struct m5mols_capture - Structure for the capture capability * @exif: EXIF information + * @buf_size: internal JPEG frame buffer size, in bytes * @main: size in bytes of the main image * @thumb: size in bytes of the thumb image, if it was accompanied * @total: total size in bytes of the produced image */ struct m5mols_capture { struct m5mols_exif exif; + unsigned int buf_size; u32 main; u32 thumb; u32 total; diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c index cb243bd278ce..ab34ccedf31e 100644 --- a/drivers/media/i2c/m5mols/m5mols_capture.c +++ b/drivers/media/i2c/m5mols/m5mols_capture.c @@ -105,6 +105,7 @@ static int m5mols_capture_info(struct m5mols_info *info) int m5mols_start_capture(struct m5mols_info *info) { + unsigned int framesize = info->cap.buf_size - M5MOLS_JPEG_TAGS_SIZE; struct v4l2_subdev *sd = &info->sd; int ret; @@ -121,6 +122,8 @@ int m5mols_start_capture(struct m5mols_info *info) if (!ret) ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution); if (!ret) + ret = m5mols_write(sd, CAPP_JPEG_SIZE_MAX, framesize); + if (!ret) ret = m5mols_set_mode(info, REG_CAPTURE); if (!ret) /* Wait until a frame is captured to ISP internal memory */ diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c index 2f490ef26c38..8131d651de9e 100644 --- a/drivers/media/i2c/m5mols/m5mols_core.c +++ b/drivers/media/i2c/m5mols/m5mols_core.c @@ -599,6 +599,51 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return ret; } +static int m5mols_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + + if (pad != 0 || fd == NULL) + return -EINVAL; + + mutex_lock(&info->lock); + /* + * .get_frame_desc is only used for compressed formats, + * thus we always return the capture frame parameters here. + */ + fd->entry[0].length = info->cap.buf_size; + fd->entry[0].pixelcode = info->ffmt[M5MOLS_RESTYPE_CAPTURE].code; + mutex_unlock(&info->lock); + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + + return 0; +} + +static int m5mols_set_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct m5mols_info *info = to_m5mols(sd); + struct v4l2_mbus_framefmt *mf = &info->ffmt[M5MOLS_RESTYPE_CAPTURE]; + + if (pad != 0 || fd == NULL) + return -EINVAL; + + fd->entry[0].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->num_entries = 1; + fd->entry[0].length = clamp_t(u32, fd->entry[0].length, + mf->width * mf->height, + M5MOLS_MAIN_JPEG_SIZE_MAX); + mutex_lock(&info->lock); + info->cap.buf_size = fd->entry[0].length; + mutex_unlock(&info->lock); + + return 0; +} + + static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code) @@ -615,6 +660,8 @@ static struct v4l2_subdev_pad_ops m5mols_pad_ops = { .enum_mbus_code = m5mols_enum_mbus_code, .get_fmt = m5mols_get_fmt, .set_fmt = m5mols_set_fmt, + .get_frame_desc = m5mols_get_frame_desc, + .set_frame_desc = m5mols_set_frame_desc, }; /** diff --git a/drivers/media/i2c/m5mols/m5mols_reg.h b/drivers/media/i2c/m5mols/m5mols_reg.h index 14d4be72aeff..58d8027508df 100644 --- a/drivers/media/i2c/m5mols/m5mols_reg.h +++ b/drivers/media/i2c/m5mols/m5mols_reg.h @@ -310,6 +310,7 @@ #define REG_JPEG 0x10 #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1) +#define CAPP_JPEG_SIZE_MAX I2C_REG(CAT_CAPT_PARM, 0x0f, 4) #define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1) #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1) diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 2c0f4077c491..e32833262d32 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -574,7 +574,6 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004) @@ -740,18 +739,6 @@ static const char * const mt9p031_test_pattern_menu[] = { static const struct v4l2_ctrl_config mt9p031_ctrls[] = { { .ops = &mt9p031_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Test Pattern", - .min = 0, - .max = ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, - .step = 0, - .def = 0, - .flags = 0, - .menu_skip_mask = 0, - .qmenu = mt9p031_test_pattern_menu, - }, { - .ops = &mt9p031_ctrl_ops, .id = V4L2_CID_BLC_AUTO, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "BLC, Auto", @@ -950,7 +937,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->model = did->driver_data; mt9p031->reset = -1; - v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 5); + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_EXPOSURE, MT9P031_SHUTTER_WIDTH_MIN, @@ -966,6 +953,10 @@ static int mt9p031_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->target_freq, pdata->target_freq, 1, pdata->target_freq); + v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0, + 0, mt9p031_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9p031_ctrls); ++i) v4l2_ctrl_new_custom(&mt9p031->ctrls, &mt9p031_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 6d343adf891d..2e189d8b71bb 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -371,7 +371,7 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) #define V4L2_CID_BLACK_LEVEL_AUTO (V4L2_CID_USER_BASE | 0x1002) #define V4L2_CID_BLACK_LEVEL_OFFSET (V4L2_CID_USER_BASE | 0x1003) #define V4L2_CID_BLACK_LEVEL_CALIBRATE (V4L2_CID_USER_BASE | 0x1004) @@ -487,12 +487,11 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl) ctrl->val >> 16); case V4L2_CID_TEST_PATTERN: - ret = mt9t001_set_output_control(mt9t001, + return mt9t001_set_output_control(mt9t001, ctrl->val ? 0 : MT9T001_OUTPUT_CONTROL_TEST_DATA, ctrl->val ? MT9T001_OUTPUT_CONTROL_TEST_DATA : 0); - if (ret < 0) - return ret; + case V4L2_CID_TEST_PATTERN_COLOR: return mt9t001_write(client, MT9T001_TEST_DATA, ctrl->val << 2); case V4L2_CID_BLACK_LEVEL_AUTO: @@ -533,12 +532,17 @@ static struct v4l2_ctrl_ops mt9t001_ctrl_ops = { .s_ctrl = mt9t001_s_ctrl, }; +static const char * const mt9t001_test_pattern_menu[] = { + "Disabled", + "Enabled", +}; + static const struct v4l2_ctrl_config mt9t001_ctrls[] = { { .ops = &mt9t001_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, + .id = V4L2_CID_TEST_PATTERN_COLOR, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", + .name = "Test Pattern Color", .min = 0, .max = 1023, .step = 1, @@ -741,7 +745,7 @@ static int mt9t001_probe(struct i2c_client *client, return -ENOMEM; v4l2_ctrl_handler_init(&mt9t001->ctrls, ARRAY_SIZE(mt9t001_ctrls) + - ARRAY_SIZE(mt9t001_gains) + 3); + ARRAY_SIZE(mt9t001_gains) + 4); v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_EXPOSURE, MT9T001_SHUTTER_WIDTH_MIN, @@ -752,6 +756,10 @@ static int mt9t001_probe(struct i2c_client *client, v4l2_ctrl_new_std(&mt9t001->ctrls, &mt9t001_ctrl_ops, V4L2_CID_PIXEL_RATE, pdata->ext_clk, pdata->ext_clk, 1, pdata->ext_clk); + v4l2_ctrl_new_std_menu_items(&mt9t001->ctrls, &mt9t001_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9t001_test_pattern_menu) - 1, 0, + 0, mt9t001_test_pattern_menu); for (i = 0; i < ARRAY_SIZE(mt9t001_ctrls); ++i) v4l2_ctrl_new_custom(&mt9t001->ctrls, &mt9t001_ctrls[i], NULL); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index e2177405dad2..3f356cb28256 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -141,6 +141,10 @@ struct mt9v032 { u16 chip_control; u16 aec_agc; u16 hblank; + struct { + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *test_pattern_color; + }; }; static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd) @@ -500,7 +504,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev, * V4L2 subdev control operations */ -#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001) +#define V4L2_CID_TEST_PATTERN_COLOR (V4L2_CID_USER_BASE | 0x1001) static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) { @@ -545,7 +549,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_TEST_PATTERN: - switch (ctrl->val) { + switch (mt9v032->test_pattern->val) { case 0: data = 0; break; @@ -562,13 +566,13 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) | MT9V032_TEST_PATTERN_ENABLE; break; default: - data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT) + data = (mt9v032->test_pattern_color->val << + MT9V032_TEST_PATTERN_DATA_SHIFT) | MT9V032_TEST_PATTERN_USE_DATA | MT9V032_TEST_PATTERN_ENABLE | MT9V032_TEST_PATTERN_FLIP; break; } - return mt9v032_write(client, MT9V032_TEST_PATTERN, data); } @@ -579,18 +583,24 @@ static struct v4l2_ctrl_ops mt9v032_ctrl_ops = { .s_ctrl = mt9v032_s_ctrl, }; -static const struct v4l2_ctrl_config mt9v032_ctrls[] = { - { - .ops = &mt9v032_ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", - .min = 0, - .max = 1023, - .step = 1, - .def = 0, - .flags = 0, - } +static const char * const mt9v032_test_pattern_menu[] = { + "Disabled", + "Gray Vertical Shade", + "Gray Horizontal Shade", + "Gray Diagonal Shade", + "Plain", +}; + +static const struct v4l2_ctrl_config mt9v032_test_pattern_color = { + .ops = &mt9v032_ctrl_ops, + .id = V4L2_CID_TEST_PATTERN_COLOR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Test Pattern Color", + .min = 0, + .max = 1023, + .step = 1, + .def = 0, + .flags = 0, }; /* ----------------------------------------------------------------------------- @@ -741,7 +751,7 @@ static int mt9v032_probe(struct i2c_client *client, mutex_init(&mt9v032->power_lock); mt9v032->pdata = pdata; - v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 8); + v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); @@ -763,6 +773,14 @@ static int mt9v032_probe(struct i2c_client *client, V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN, MT9V032_VERTICAL_BLANKING_MAX, 1, MT9V032_VERTICAL_BLANKING_DEF); + mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls, + &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9v032_test_pattern_menu) - 1, 0, 0, + mt9v032_test_pattern_menu); + mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls, + &mt9v032_test_pattern_color, NULL); + + v4l2_ctrl_cluster(2, &mt9v032->test_pattern); mt9v032->pixel_rate = v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, @@ -784,8 +802,6 @@ static int mt9v032_probe(struct i2c_client *client, v4l2_ctrl_cluster(2, &mt9v032->link_freq); } - for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i) - v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL); mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 78ac5744cb5d..d2d298b6354e 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -684,6 +684,11 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); u8 val; + int ret; + + ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS); + if (ret < 0) + return ret; switch (ctrl->id) { case V4L2_CID_VFLIP: diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index e5c0eedebc58..c31cc04fffd2 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -28,6 +28,18 @@ #include <media/v4l2-subdev.h> #include <media/v4l2-chip-ident.h> +#define THS7303_CHANNEL_1 1 +#define THS7303_CHANNEL_2 2 +#define THS7303_CHANNEL_3 3 + +enum ths7303_filter_mode { + THS7303_FILTER_MODE_480I_576I, + THS7303_FILTER_MODE_480P_576P, + THS7303_FILTER_MODE_720P_1080I, + THS7303_FILTER_MODE_1080P, + THS7303_FILTER_MODE_DISABLE +}; + MODULE_DESCRIPTION("TI THS7303 video amplifier driver"); MODULE_AUTHOR("Chaithrika U S"); MODULE_LICENSE("GPL"); @@ -37,35 +49,96 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-1"); /* following function is used to set ths7303 */ -static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std) +int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode) { + u8 input_bias_chroma = 3; + u8 input_bias_luma = 3; + int disable = 0; int err = 0; - u8 val; - struct i2c_client *client; + u8 val = 0; + u8 temp; - client = v4l2_get_subdevdata(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); - if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { - val = 0x02; - v4l2_dbg(1, debug, sd, "setting value for SDTV format\n"); - } else { - val = 0x00; - v4l2_dbg(1, debug, sd, "disabling all channels\n"); + if (!client) + return -EINVAL; + + switch (mode) { + case THS7303_FILTER_MODE_1080P: + val = (3 << 6); + val |= (3 << 3); + break; + case THS7303_FILTER_MODE_720P_1080I: + val = (2 << 6); + val |= (2 << 3); + break; + case THS7303_FILTER_MODE_480P_576P: + val = (1 << 6); + val |= (1 << 3); + break; + case THS7303_FILTER_MODE_480I_576I: + break; + case THS7303_FILTER_MODE_DISABLE: + pr_info("mode disabled\n"); + /* disable all channels */ + disable = 1; + default: + /* disable all channels */ + disable = 1; } + /* Setup channel 2 - Luma - Green */ + temp = val; + if (!disable) + val |= input_bias_luma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val); + if (err) + goto out; - err |= i2c_smbus_write_byte_data(client, 0x01, val); - err |= i2c_smbus_write_byte_data(client, 0x02, val); - err |= i2c_smbus_write_byte_data(client, 0x03, val); + /* setup two chroma channels */ + if (!disable) + temp |= input_bias_chroma; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp); if (err) - v4l2_err(sd, "write failed\n"); + goto out; + err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp); + if (err) + goto out; + return err; +out: + pr_info("write byte data failed\n"); return err; } static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { - return ths7303_setvalue(sd, norm); + if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) + return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); + else + return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); +} + +/* for setting filter for HD output */ +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) +{ + u32 height = dv_timings->bt.height; + int interlaced = dv_timings->bt.interlaced; + int res = 0; + + if (height == 1080 && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P); + else if ((height == 720 && !interlaced) || + (height == 1080 && interlaced)) + res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I); + else if ((height == 480 || height == 576) && !interlaced) + res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P); + else + /* disable all channels */ + res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); + + return res; } static int ths7303_g_chip_ident(struct v4l2_subdev *sd, @@ -78,6 +151,7 @@ static int ths7303_g_chip_ident(struct v4l2_subdev *sd, static const struct v4l2_subdev_video_ops ths7303_video_ops = { .s_std_output = ths7303_s_std_output, + .s_dv_timings = ths7303_s_dv_timings, }; static const struct v4l2_subdev_core_ops ths7303_core_ops = { @@ -107,7 +181,7 @@ static int ths7303_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - return ths7303_setvalue(sd, std_id); + return ths7303_s_std_output(sd, std_id); } static int ths7303_remove(struct i2c_client *client) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1f3943bb87d5..d5e10215a28f 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -519,6 +519,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id) *std_id = V4L2_STD_UNKNOWN; + /* To query the standard the TVP514x must power on the ADCs. */ + if (!decoder->streaming) { + tvp514x_s_stream(sd, 1); + msleep(LOCK_RETRY_DELAY); + } + /* query the current standard */ current_std = tvp514x_query_current_std(sd); if (current_std == STD_INVALID) @@ -625,25 +631,12 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, int err; enum tvp514x_input input_sel; enum tvp514x_output output_sel; - u8 sync_lock_status, lock_mask; - int try_count = LOCK_RETRY_COUNT; if ((input >= INPUT_INVALID) || (output >= OUTPUT_INVALID)) /* Index out of bound */ return -EINVAL; - /* - * For the sequence streamon -> streamoff and again s_input - * it fails to lock the signal, since streamoff puts TVP514x - * into power off state which leads to failure in sub-sequent s_input. - * - * So power up the TVP514x device here, since it is important to lock - * the signal at this stage. - */ - if (!decoder->streaming) - tvp514x_s_stream(sd, 1); - input_sel = input; output_sel = output; @@ -660,64 +653,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd, decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel; decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel; - - /* Clear status */ - msleep(LOCK_RETRY_DELAY); - err = - tvp514x_write_reg(sd, REG_CLEAR_LOST_LOCK, 0x01); - if (err) - return err; - - switch (input_sel) { - case INPUT_CVBS_VI1A: - case INPUT_CVBS_VI1B: - case INPUT_CVBS_VI1C: - case INPUT_CVBS_VI2A: - case INPUT_CVBS_VI2B: - case INPUT_CVBS_VI2C: - case INPUT_CVBS_VI3A: - case INPUT_CVBS_VI3B: - case INPUT_CVBS_VI3C: - case INPUT_CVBS_VI4A: - lock_mask = STATUS_CLR_SUBCAR_LOCK_BIT | - STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - - case INPUT_SVIDEO_VI2A_VI1A: - case INPUT_SVIDEO_VI2B_VI1B: - case INPUT_SVIDEO_VI2C_VI1C: - case INPUT_SVIDEO_VI2A_VI3A: - case INPUT_SVIDEO_VI2B_VI3B: - case INPUT_SVIDEO_VI2C_VI3C: - case INPUT_SVIDEO_VI4A_VI1A: - case INPUT_SVIDEO_VI4A_VI1B: - case INPUT_SVIDEO_VI4A_VI1C: - case INPUT_SVIDEO_VI4A_VI3A: - case INPUT_SVIDEO_VI4A_VI3B: - case INPUT_SVIDEO_VI4A_VI3C: - lock_mask = STATUS_HORZ_SYNC_LOCK_BIT | - STATUS_VIRT_SYNC_LOCK_BIT; - break; - /* Need to add other interfaces*/ - default: - return -EINVAL; - } - - while (try_count-- > 0) { - /* Allow decoder to sync up with new input */ - msleep(LOCK_RETRY_DELAY); - - sync_lock_status = tvp514x_read_reg(sd, - REG_STATUS1); - if (lock_mask == (sync_lock_status & lock_mask)) - /* Input detected */ - break; - } - - if (try_count < 0) - return -EINVAL; - decoder->input = input; decoder->output = output; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b68918c97f66..56c6c77793d7 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -668,6 +668,12 @@ static const struct v4l2_queryctrl bttv_ctls[] = { .default_value = 32768, .type = V4L2_CTRL_TYPE_INTEGER, },{ + .id = V4L2_CID_COLOR_KILLER, + .name = "Color killer", + .minimum = 0, + .maximum = 1, + .type = V4L2_CTRL_TYPE_BOOLEAN, + }, { .id = V4L2_CID_HUE, .name = "Hue", .minimum = 0, @@ -1474,6 +1480,9 @@ static int bttv_g_ctrl(struct file *file, void *priv, case V4L2_CID_SATURATION: c->value = btv->saturation; break; + case V4L2_CID_COLOR_KILLER: + c->value = btv->opt_color_killer; + break; case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: @@ -1526,7 +1535,6 @@ static int bttv_s_ctrl(struct file *file, void *f, struct v4l2_control *c) { int err; - int val; struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1547,6 +1555,16 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_SATURATION: bt848_sat(btv, c->value); break; + case V4L2_CID_COLOR_KILLER: + btv->opt_color_killer = c->value; + if (btv->opt_color_killer) { + btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CKILL, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CKILL, BT848_O_SCLOOP); + } + break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ @@ -1564,9 +1582,13 @@ static int bttv_s_ctrl(struct file *file, void *f, case V4L2_CID_PRIVATE_CHROMA_AGC: btv->opt_chroma_agc = c->value; - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); + if (btv->opt_chroma_agc) { + btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } else { + btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP); + btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP); + } break; case V4L2_CID_PRIVATE_COMBFILTER: btv->opt_combfilter = c->value; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 70fd4f23f605..9ec0adba236c 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -429,6 +429,7 @@ struct bttv { int opt_lumafilter; int opt_automute; int opt_chroma_agc; + int opt_color_killer; int opt_adc_crush; int opt_vcr_hack; int opt_whitecrush_upper; diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index ee3884fbc9ce..7d96fab7d246 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -646,7 +646,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct dprintk(verbose, DST_CA_INFO, 1, " -->CA_SET_PID Success !"); default: result = -EOPNOTSUPP; - }; + } free_mem_and_exit: kfree (p_ca_message); kfree (p_ca_slot_info); diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index aee7f0dacff1..495781ee4711 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -416,7 +416,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[1] status = 0x%x\n", __func__, inter->state[1]->status); - }; + } if (inter->state[0] != NULL) { inter->state[0]->status = @@ -425,7 +425,7 @@ static void netup_read_ci_status(struct work_struct *work) DVB_CA_EN50221_POLL_CAM_READY : 0); ci_dbg_print("%s: setting CI[0] status = 0x%x\n", __func__, inter->state[0]->status); - }; + } } /* CI irq handler */ diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index c9f15d6dec40..6617774a326a 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -193,7 +193,7 @@ int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, 0, &store, 1); if (ret != 0) return ret; - }; + } state->current_ci_flag = flag; mutex_lock(&dev->gpio_lock); diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 39a4a4b9ed7e..5acdf954ff6b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -542,11 +542,13 @@ struct cx23885_board cx23885_boards[] = { { .type = CX23885_VMUX_COMPOSITE1, .vmux = CX25840_COMPOSITE8, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_SVIDEO, .vmux = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4, + .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_COMPONENT, @@ -554,6 +556,7 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN1_CH1 | CX25840_VIN6_CH2 | CX25840_VIN7_CH3, + .amux = CX25840_AUDIO7, }, }, }, diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 8c4a9a5f9a50..1a21926ca412 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -508,7 +508,8 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) || (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) || - (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850)) { + (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) || + (dev->board == CX23885_BOARD_MYGICA_X8507)) { /* Configure audio routing */ v4l2_subdev_call(dev->sd_cx25840, audio, s_routing, INPUT(input)->amux, 0, 0); diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c index c8c94fbf5d8d..d33fc1a23030 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -761,7 +761,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename_ch2, "") == 0) { + if (strcmp(dev->_filename_ch2, "") == 0) { if (dev->_isNTSC_ch2) { dev->_filename_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? "/root/vid411.yuv" : diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 52c13e0b6492..6759fff8eb64 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -808,7 +808,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, } /* Default if filename is empty string */ - if (strcmp(dev->input_filename, "") == 0) { + if (strcmp(dev->_filename, "") == 0) { if (dev->_isNTSC) { dev->_filename = (dev->_pixel_format == PIXEL_FRMT_411) ? diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index def363fb71c0..62184eb919e5 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -721,7 +721,7 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -739,7 +739,7 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); @@ -755,7 +755,7 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index d803bba09525..666f83b2f3c0 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -896,7 +896,7 @@ static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, break; default: return -EINVAL; - }; + } return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO; } diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index c04fb618e10b..d154bc197356 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -450,7 +450,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); - }; + } if (MAX_IRQ_LOOP == loop) { dprintk( 0, "clearing mask\n" ); printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 770ec05b5e9b..424fd97495dc 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -373,7 +373,7 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) set_audio_registers(core, nicam_bgdki_common); set_audio_registers(core, nicam_default); break; - }; + } mode |= EN_DMTRX_LR | EN_DMTRX_BYPASS; set_audio_finish(core, mode); @@ -639,7 +639,7 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode) dprintk("%s Warning: wrong value\n", __func__); return; break; - }; + } mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; set_audio_finish(core, mode); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index a146d50d7795..05171457bf28 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1535,7 +1535,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) cx88_core_irq(core,status); if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); - }; + } if (10 == loop) { printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", core->name); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 22f8758d047f..4a77124ee70e 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1204,7 +1204,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str break; default: /* nothing */; - }; + } switch (c->id) { case V4L2_CID_BRIGHTNESS: dev->ctl_bright = c->value; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f588d6296c76..181c7686e412 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -165,12 +165,12 @@ config VIDEO_SAMSUNG_S5P_JPEG This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec config VIDEO_SAMSUNG_S5P_MFC - tristate "Samsung S5P MFC 5.1 Video Codec" + tristate "Samsung S5P MFC Video Codec" depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P select VIDEOBUF2_DMA_CONTIG default n help - MFC 5.1 driver for V4L2. + MFC 5.1 and 6.x driver for V4L2 config VIDEO_MX2_EMMAPRP tristate "MX2 eMMa-PrP support" diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index c4a82a1a8a97..69d7a58c92c3 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -174,26 +174,6 @@ static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, return 0; } -static int vpbe_get_dv_preset_info(struct vpbe_device *vpbe_dev, - unsigned int dv_preset) -{ - struct vpbe_config *cfg = vpbe_dev->cfg; - struct vpbe_enc_mode_info var; - int curr_output = vpbe_dev->current_out_index; - int i; - - for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { - var = cfg->outputs[curr_output].modes[i]; - if ((var.timings_type & VPBE_ENC_DV_PRESET) && - (var.timings.dv_preset == dv_preset)) { - vpbe_dev->current_timings = var; - return 0; - } - } - - return -EINVAL; -} - /* Get std by std id */ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) @@ -206,7 +186,7 @@ static int vpbe_get_std_info(struct vpbe_device *vpbe_dev, for (i = 0; i < vpbe_dev->cfg->outputs[curr_output].num_modes; i++) { var = cfg->outputs[curr_output].modes[i]; if ((var.timings_type & VPBE_ENC_STD) && - (var.timings.std_id & std_id)) { + (var.std_id & std_id)) { vpbe_dev->current_timings = var; return 0; } @@ -344,38 +324,42 @@ static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) } /** - * vpbe_s_dv_preset - Set the given preset timings in the encoder + * vpbe_s_dv_timings - Set the given preset timings in the encoder * - * Sets the preset if supported by the current encoder. Return the status. + * Sets the timings if supported by the current encoder. Return the status. * 0 - success & -EINVAL on error */ -static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; + struct vpbe_output *output = &cfg->outputs[out_index]; int sd_index = vpbe_dev->current_sd_index; - int ret; + int ret, i; if (!(cfg->outputs[out_index].output.capabilities & - V4L2_OUT_CAP_PRESETS)) + V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; - ret = vpbe_get_dv_preset_info(vpbe_dev, dv_preset->preset); - - if (ret) - return ret; - + for (i = 0; i < output->num_modes; i++) { + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS && + !memcmp(&output->modes[i].dv_timings, + dv_timings, sizeof(*dv_timings))) + break; + } + if (i >= output->num_modes) + return -EINVAL; + vpbe_dev->current_timings = output->modes[i]; mutex_lock(&vpbe_dev->lock); - ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); if (!ret && (vpbe_dev->amp != NULL)) { /* Call amplifier subdevice */ ret = v4l2_subdev_call(vpbe_dev->amp, video, - s_dv_preset, dv_preset); + s_dv_timings, dv_timings); } /* set the lcd controller output for the given mode */ if (!ret) { @@ -392,17 +376,17 @@ static int vpbe_s_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_g_dv_preset - Get the preset in the current encoder + * vpbe_g_dv_timings - Get the timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset) +static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings) { if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; return 0; } @@ -410,13 +394,13 @@ static int vpbe_g_dv_preset(struct vpbe_device *vpbe_dev, } /** - * vpbe_enum_dv_presets - Enumerate the dv presets in the current encoder + * vpbe_enum_dv_timings - Enumerate the dv timings in the current encoder * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ -static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info) +static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; @@ -424,12 +408,12 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, int j = 0; int i; - if (!(output->output.capabilities & V4L2_OUT_CAP_PRESETS)) + if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS)) return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_DV_PRESET) { - if (j == preset_info->index) + if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) { + if (j == timings->index) break; j++; } @@ -437,9 +421,8 @@ static int vpbe_enum_dv_presets(struct vpbe_device *vpbe_dev, if (i == output->num_modes) return -EINVAL; - - return v4l_fill_dv_preset_info(output->modes[i].timings.dv_preset, - preset_info); + timings->timings = output->modes[i].dv_timings; + return 0; } /** @@ -489,10 +472,10 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) */ static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) { - struct vpbe_enc_mode_info cur_timings = vpbe_dev->current_timings; + struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings; - if (cur_timings.timings_type & VPBE_ENC_STD) { - *std_id = cur_timings.timings.std_id; + if (cur_timings->timings_type & VPBE_ENC_STD) { + *std_id = cur_timings->std_id; return 0; } @@ -511,7 +494,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, { struct vpbe_enc_mode_info *preset_mode = NULL; struct vpbe_config *cfg = vpbe_dev->cfg; - struct v4l2_dv_preset dv_preset; + struct v4l2_dv_timings dv_timings; struct osd_state *osd_device; int out_index = vpbe_dev->current_out_index; int ret = 0; @@ -530,11 +513,12 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, */ if (preset_mode->timings_type & VPBE_ENC_STD) return vpbe_s_std(vpbe_dev, - &preset_mode->timings.std_id); - if (preset_mode->timings_type & VPBE_ENC_DV_PRESET) { - dv_preset.preset = - preset_mode->timings.dv_preset; - return vpbe_s_dv_preset(vpbe_dev, &dv_preset); + &preset_mode->std_id); + if (preset_mode->timings_type & + VPBE_ENC_CUSTOM_TIMINGS) { + dv_timings = + preset_mode->dv_timings; + return vpbe_s_dv_timings(vpbe_dev, &dv_timings); } } } @@ -626,11 +610,11 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) vpbe_dev->dac_clk = clk_get(vpbe_dev->pdev, "vpss_dac"); if (IS_ERR(vpbe_dev->dac_clk)) { ret = PTR_ERR(vpbe_dev->dac_clk); - goto vpbe_unlock; + goto fail_mutex_unlock; } if (clk_enable(vpbe_dev->dac_clk)) { ret = -ENODEV; - goto vpbe_unlock; + goto fail_mutex_unlock; } } @@ -642,7 +626,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) if (ret) { v4l2_err(dev->driver, "Unable to register v4l2 device.\n"); - goto vpbe_fail_clock; + goto fail_clk_put; } v4l2_info(&vpbe_dev->v4l2_dev, "vpbe v4l2 device registered\n"); @@ -658,7 +642,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "vpbe unable to init venc sub device\n"); ret = -ENODEV; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } /* initialize osd device */ osd_device = vpbe_dev->osd_device; @@ -669,7 +653,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to initialize the OSD device"); err = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } } @@ -685,7 +669,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) v4l2_err(&vpbe_dev->v4l2_dev, "unable to allocate memory for encoders sub devices"); ret = -ENOMEM; - goto vpbe_fail_v4l2_device; + goto fail_dev_unregister; } i2c_adap = i2c_get_adapter(vpbe_dev->cfg->i2c_adapter_id); @@ -711,7 +695,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) " failed to register", enc_info->module_name); ret = -ENODEV; - goto vpbe_fail_sd_register; + goto fail_kfree_encoders; } } else v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" @@ -730,7 +714,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) "amplifier %s failed to register", amp_info->module_name); ret = -ENODEV; - goto vpbe_fail_amp_register; + goto fail_kfree_encoders; } v4l2_info(&vpbe_dev->v4l2_dev, "v4l2 sub device %s registered\n", @@ -770,16 +754,14 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) /* TBD handling of bootargs for default output and mode */ return 0; -vpbe_fail_amp_register: - kfree(vpbe_dev->amp); -vpbe_fail_sd_register: +fail_kfree_encoders: kfree(vpbe_dev->encoders); -vpbe_fail_v4l2_device: +fail_dev_unregister: v4l2_device_unregister(&vpbe_dev->v4l2_dev); -vpbe_fail_clock: +fail_clk_put: if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) clk_put(vpbe_dev->dac_clk); -vpbe_unlock: +fail_mutex_unlock: mutex_unlock(&vpbe_dev->lock); return ret; } @@ -810,9 +792,9 @@ static struct vpbe_device_ops vpbe_dev_ops = { .enum_outputs = vpbe_enum_outputs, .set_output = vpbe_set_output, .get_output = vpbe_get_output, - .s_dv_preset = vpbe_s_dv_preset, - .g_dv_preset = vpbe_g_dv_preset, - .enum_dv_presets = vpbe_enum_dv_presets, + .s_dv_timings = vpbe_s_dv_timings, + .g_dv_timings = vpbe_g_dv_timings, + .enum_dv_timings = vpbe_enum_dv_timings, .s_std = vpbe_s_std, .g_std = vpbe_g_std, .initialize = vpbe_initialize, diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 239f37bfa313..161c77650e2f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -393,7 +393,7 @@ vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, int h_scale; int v_scale; - v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; + v4l2_std_id standard_id = vpbe_dev->current_timings.std_id; /* * Application initially set the image format. Current display @@ -637,7 +637,7 @@ static int vpbe_display_s_crop(struct file *file, void *priv, struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; struct osd_layer_config *cfg = &layer->layer_info.config; struct osd_state *osd_device = disp_dev->osd_device; - struct v4l2_rect *rect = &crop->c; + struct v4l2_rect rect = crop->c; int ret; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, @@ -648,21 +648,21 @@ static int vpbe_display_s_crop(struct file *file, void *priv, return -EINVAL; } - if (rect->top < 0) - rect->top = 0; - if (rect->left < 0) - rect->left = 0; + if (rect.top < 0) + rect.top = 0; + if (rect.left < 0) + rect.left = 0; - vpbe_disp_check_window_params(disp_dev, rect); + vpbe_disp_check_window_params(disp_dev, &rect); osd_device->ops.get_layer_config(osd_device, layer->layer_info.id, cfg); vpbe_disp_calculate_scale_factor(disp_dev, layer, - rect->width, - rect->height); - vpbe_disp_adj_position(disp_dev, layer, rect->top, - rect->left); + rect.width, + rect.height); + vpbe_disp_adj_position(disp_dev, layer, rect.top, + rect.left); ret = osd_device->ops.set_layer_config(osd_device, layer->layer_info.id, cfg); if (ret < 0) { @@ -943,7 +943,7 @@ static int vpbe_display_g_std(struct file *file, void *priv, /* Get the standard from the current encoder */ if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { - *std_id = vpbe_dev->current_timings.timings.std_id; + *std_id = vpbe_dev->current_timings.std_id; return 0; } @@ -1029,29 +1029,29 @@ static int vpbe_display_g_output(struct file *file, void *priv, } /** - * vpbe_display_enum_dv_presets - Enumerate the dv presets + * vpbe_display_enum_dv_timings - Enumerate the dv timings * - * enum the preset in the current encoder. Return the status. 0 - success + * enum the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_enum_dv_presets(struct file *file, void *priv, - struct v4l2_dv_enum_preset *preset) +vpbe_display_enum_dv_timings(struct file *file, void *priv, + struct v4l2_enum_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); /* Enumerate outputs */ - if (NULL == vpbe_dev->ops.enum_dv_presets) + if (NULL == vpbe_dev->ops.enum_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); + ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to enumerate dv presets info\n"); + "Failed to enumerate dv timings info\n"); return -EINVAL; } @@ -1059,21 +1059,21 @@ vpbe_display_enum_dv_presets(struct file *file, void *priv, } /** - * vpbe_display_s_dv_preset - Set the dv presets + * vpbe_display_s_dv_timings - Set the dv timings * - * Set the preset in the current encoder. Return the status. 0 - success + * Set the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_s_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *preset) +vpbe_display_s_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *timings) { struct vpbe_fh *fh = priv; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n"); /* If streaming is started, return error */ @@ -1083,13 +1083,13 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /* Set the given standard in the encoder */ - if (!vpbe_dev->ops.s_dv_preset) + if (!vpbe_dev->ops.s_dv_timings) return -EINVAL; - ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); + ret = vpbe_dev->ops.s_dv_timings(vpbe_dev, timings); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "Failed to set the dv presets info\n"); + "Failed to set the dv timings info\n"); return -EINVAL; } /* set the current norm to zero to be consistent. If STD is used @@ -1101,26 +1101,25 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /** - * vpbe_display_g_dv_preset - Set the dv presets + * vpbe_display_g_dv_timings - Set the dv timings * - * Get the preset in the current encoder. Return the status. 0 - success + * Get the timings in the current encoder. Return the status. 0 - success * -EINVAL on error */ static int -vpbe_display_g_dv_preset(struct file *file, void *priv, - struct v4l2_dv_preset *dv_preset) +vpbe_display_g_dv_timings(struct file *file, void *priv, + struct v4l2_dv_timings *dv_timings) { struct vpbe_fh *fh = priv; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); + v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n"); /* Get the given standard in the encoder */ if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_DV_PRESET) { - dv_preset->preset = - vpbe_dev->current_timings.timings.dv_preset; + VPBE_ENC_CUSTOM_TIMINGS) { + *dv_timings = vpbe_dev->current_timings.dv_timings; } else { return -EINVAL; } @@ -1572,9 +1571,9 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { .vidioc_enum_output = vpbe_display_enum_output, .vidioc_s_output = vpbe_display_s_output, .vidioc_g_output = vpbe_display_g_output, - .vidioc_s_dv_preset = vpbe_display_s_dv_preset, - .vidioc_g_dv_preset = vpbe_display_g_dv_preset, - .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, + .vidioc_s_dv_timings = vpbe_display_s_dv_timings, + .vidioc_g_dv_timings = vpbe_display_g_dv_timings, + .vidioc_enum_dv_timings = vpbe_display_enum_dv_timings, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vpbe_display_g_register, .vidioc_s_register = vpbe_display_s_register, @@ -1639,8 +1638,7 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, VPBE_ENC_STD) { vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); vbd->current_norm = - disp_dev->vpbe_dev-> - current_timings.timings.std_id; + disp_dev->vpbe_dev->current_timings.std_id; } else vbd->current_norm = 0; diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 0302669622d6..aed7369b962a 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -298,7 +298,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_480P59_94) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -345,7 +345,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) (pdata->venc_type != VPBE_VERSION_2)) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_576P50) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -385,7 +385,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_720P60) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -413,7 +413,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_DV_PRESET, V4L2_DV_1080P30) < 0) + if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -446,26 +446,27 @@ static int venc_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) return -EINVAL; } -static int venc_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *dv_preset) +static int venc_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) { struct venc_state *venc = to_state(sd); + u32 height = dv_timings->bt.height; int ret; - v4l2_dbg(debug, 1, sd, "venc_s_dv_preset\n"); + v4l2_dbg(debug, 1, sd, "venc_s_dv_timings\n"); - if (dv_preset->preset == V4L2_DV_576P50) + if (height == 576) return venc_set_576p50(sd); - else if (dv_preset->preset == V4L2_DV_480P59_94) + else if (height == 480) return venc_set_480p59_94(sd); - else if ((dv_preset->preset == V4L2_DV_720P60) && + else if ((height == 720) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 720p mode here */ ret = venc_set_720p60_internal(sd); /* for DM365 VPBE, there is DAC inside */ vdaccfg_write(sd, VDAC_CONFIG_HD_V2); return ret; - } else if ((dv_preset->preset == V4L2_DV_1080I30) && + } else if ((height == 1080) && (venc->pdata->venc_type == VPBE_VERSION_2)) { /* TBD setup internal 1080i mode here */ ret = venc_set_1080i30_internal(sd); @@ -518,7 +519,7 @@ static const struct v4l2_subdev_core_ops venc_core_ops = { static const struct v4l2_subdev_video_ops venc_video_ops = { .s_routing = venc_s_routing, .s_std_output = venc_s_std_output, - .s_dv_preset = venc_s_dv_preset, + .s_dv_timings = venc_s_dv_timings, }; static const struct v4l2_subdev_ops venc_ops = { diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 48052cbffc2b..8be492cd8ed4 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1669,6 +1669,7 @@ static int vpfe_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct vpfe_device *vpfe_dev = video_drvdata(file); + struct v4l2_rect rect = crop->c; int ret = 0; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_crop\n"); @@ -1684,7 +1685,7 @@ static int vpfe_s_crop(struct file *file, void *priv, if (ret) return ret; - if (crop->c.top < 0 || crop->c.left < 0) { + if (rect.top < 0 || rect.left < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "doesn't support negative values for top & left\n"); ret = -EINVAL; @@ -1692,26 +1693,26 @@ static int vpfe_s_crop(struct file *file, void *priv, } /* adjust the width to 16 pixel boundary */ - crop->c.width = ((crop->c.width + 15) & ~0xf); + rect.width = ((rect.width + 15) & ~0xf); /* make sure parameters are valid */ - if ((crop->c.left + crop->c.width > + if ((rect.left + rect.width > vpfe_dev->std_info.active_pixels) || - (crop->c.top + crop->c.height > + (rect.top + rect.height > vpfe_dev->std_info.active_lines)) { v4l2_err(&vpfe_dev->v4l2_dev, "Error in S_CROP params\n"); ret = -EINVAL; goto unlock_out; } - ccdc_dev->hw_ops.set_image_window(&crop->c); - vpfe_dev->fmt.fmt.pix.width = crop->c.width; - vpfe_dev->fmt.fmt.pix.height = crop->c.height; + ccdc_dev->hw_ops.set_image_window(&rect); + vpfe_dev->fmt.fmt.pix.width = rect.width; + vpfe_dev->fmt.fmt.pix.height = rect.height; vpfe_dev->fmt.fmt.pix.bytesperline = ccdc_dev->hw_ops.get_line_length(); vpfe_dev->fmt.fmt.pix.sizeimage = vpfe_dev->fmt.fmt.pix.bytesperline * vpfe_dev->fmt.fmt.pix.height; - vpfe_dev->crop = crop->c; + vpfe_dev->crop = rect; unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0bafecac4923..fcabc023885d 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -311,12 +311,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* configure 1 or 2 channel mode */ - ret = vpif_config_data->setup_input_channel_mode - (vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - return ret; + if (vpif_config_data->setup_input_channel_mode) { + ret = vpif_config_data-> + setup_input_channel_mode(vpif->std_info.ycmux_mode); + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + return ret; + } } /* Call vpif_set_params function to set the parameters and addresses */ @@ -863,13 +864,11 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait) */ static int vpif_open(struct file *filep) { - struct vpif_capture_config *config = vpif_dev->platform_data; struct video_device *vdev = video_devdata(filep); struct common_obj *common; struct video_obj *vid_ch; struct channel_obj *ch; struct vpif_fh *fh; - int i; vpif_dbg(2, debug, "vpif_open\n"); @@ -878,26 +877,6 @@ static int vpif_open(struct file *filep) vid_ch = &ch->video; common = &ch->common[VPIF_VIDEO_INDEX]; - if (NULL == ch->curr_subdev_info) { - /** - * search through the sub device to see a registered - * sub device and make it as current sub device - */ - for (i = 0; i < config->subdev_count; i++) { - if (vpif_obj.sd[i]) { - /* the sub device is registered */ - ch->curr_subdev_info = &config->subdev_info[i]; - /* make first input as the current input */ - vid_ch->input_idx = 0; - break; - } - } - if (i == config->subdev_count) { - vpif_err("No sub device registered\n"); - return -ENOENT; - } - } - /* Allocate memory for the file handle object */ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL); if (NULL == fh) { @@ -997,6 +976,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct common_obj *common; u8 index = 0; struct vb2_queue *q; + int ret; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -1036,8 +1016,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_capture: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ @@ -1175,10 +1159,9 @@ static int vpif_streamon(struct file *file, void *priv, return ret; /* Enable streamon on the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 1); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 1); - if (ret && (ret != -ENOIOCTLCMD)) { + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "stream on failed in subdev\n"); return ret; } @@ -1238,73 +1221,105 @@ static int vpif_streamoff(struct file *file, void *priv, common->started = 0; - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - s_stream, 0); + ret = v4l2_subdev_call(ch->sd, video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) vpif_dbg(1, debug, "stream off failed in subdev\n"); return vb2_streamoff(&common->buffer_queue, buftype); } /** - * vpif_map_sub_device_to_input() - Maps sub device to input - * @ch - ptr to channel - * @config - ptr to capture configuration + * vpif_input_to_subdev() - Maps input to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr * @input_index - Given input index from application - * @sub_device_index - index into sd table * * lookup the sub device information for a given input index. * we report all the inputs to application. inputs table also * has sub device name for the each input */ -static struct vpif_subdev_info *vpif_map_sub_device_to_input( - struct channel_obj *ch, - struct vpif_capture_config *vpif_cfg, - int input_index, - int *sub_device_index) +static int vpif_input_to_subdev( + struct vpif_capture_config *vpif_cfg, + struct vpif_capture_chan_config *chan_cfg, + int input_index) { - struct vpif_capture_chan_config *chan_cfg; - struct vpif_subdev_info *subdev_info = NULL; - const char *subdev_name = NULL; + struct vpif_subdev_info *subdev_info; + const char *subdev_name; int i; - vpif_dbg(2, debug, "vpif_map_sub_device_to_input\n"); + vpif_dbg(2, debug, "vpif_input_to_subdev\n"); - chan_cfg = &vpif_cfg->chan_config[ch->channel_id]; - - /** - * search through the inputs to find the sub device supporting - * the input - */ - for (i = 0; i < chan_cfg->input_count; i++) { - /* For each sub device, loop through input */ - if (i == input_index) { - subdev_name = chan_cfg->inputs[i].subdev_name; - break; - } - } - - /* if reached maximum. return null */ - if (i == chan_cfg->input_count || (NULL == subdev_name)) - return subdev_info; + subdev_name = chan_cfg->inputs[input_index].subdev_name; + if (subdev_name == NULL) + return -1; /* loop through the sub device list to get the sub device info */ for (i = 0; i < vpif_cfg->subdev_count; i++) { subdev_info = &vpif_cfg->subdev_info[i]; if (!strcmp(subdev_info->name, subdev_name)) - break; + return i; + } + return -1; +} + +/** + * vpif_set_input() - Select an input + * @vpif_cfg - global config ptr + * @ch - channel + * @_index - Given input index from application + * + * Select the given input. + */ +static int vpif_set_input( + struct vpif_capture_config *vpif_cfg, + struct channel_obj *ch, + int index) +{ + struct vpif_capture_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; + + sd_index = vpif_input_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdev_info[sd_index]; } - if (i == vpif_cfg->subdev_count) - return subdev_info; + /* first setup input path from sub device to vpif */ + if (sd && vpif_cfg->setup_input_path) { + ret = vpif_cfg->setup_input_path(ch->channel_id, + subdev_info->name); + if (ret < 0) { + vpif_dbg(1, debug, "couldn't setup input path for the" \ + " sub device %s, for input index %d\n", + subdev_info->name, index); + return ret; + } + } - /* check if the sub device is registered */ - if (NULL == vpif_obj.sd[i]) - return NULL; + if (sd) { + input = chan_cfg->inputs[index].input_route; + output = chan_cfg->inputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, + input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_dbg(1, debug, "Failed to set input\n"); + return ret; + } + } + ch->input_idx = index; + ch->sd = sd; + /* copy interface parameters to vpif */ + ch->vpifparams.iface = chan_cfg->vpif_if; - *sub_device_index = i; - return subdev_info; + /* update tvnorms from the sub device input info */ + ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; + return 0; } /** @@ -1324,12 +1339,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) vpif_dbg(2, debug, "vpif_querystd\n"); /* Call querystd function of decoder device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video, - querystd, std_id); - if (ret < 0) - vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); + ret = v4l2_subdev_call(ch->sd, video, querystd, std_id); - return ret; + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + return -ENODATA; + if (ret) { + vpif_dbg(1, debug, "Failed to query standard for sub devices\n"); + return ret; + } + + return 0; } /** @@ -1397,11 +1416,12 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); /* set standard in the sub device */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_std, *std_id); - if (ret < 0) + ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); + if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); - return ret; + return ret; + } + return 0; } /** @@ -1441,10 +1461,8 @@ static int vpif_g_input(struct file *file, void *priv, unsigned int *index) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - - *index = vid_ch->input_idx; + *index = ch->input_idx; return 0; } @@ -1461,13 +1479,13 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - struct video_obj *vid_ch = &ch->video; - struct vpif_subdev_info *subdev_info; - int ret = 0, sd_index = 0; - u32 input = 0, output = 0; + int ret; chan_cfg = &config->chan_config[ch->channel_id]; + if (index >= chan_cfg->input_count) + return -EINVAL; + if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; @@ -1486,45 +1504,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index) return ret; fh->initialized = 1; - subdev_info = vpif_map_sub_device_to_input(ch, config, index, - &sd_index); - if (NULL == subdev_info) { - vpif_dbg(1, debug, - "couldn't lookup sub device for the input index\n"); - return -EINVAL; - } - - /* first setup input path from sub device to vpif */ - if (config->setup_input_path) { - ret = config->setup_input_path(ch->channel_id, - subdev_info->name); - if (ret < 0) { - vpif_dbg(1, debug, "couldn't setup input path for the" - " sub device %s, for input index %d\n", - subdev_info->name, index); - return ret; - } - } - - if (subdev_info->can_route) { - input = subdev_info->input; - output = subdev_info->output; - ret = v4l2_subdev_call(vpif_obj.sd[sd_index], video, s_routing, - input, output, 0); - if (ret < 0) { - vpif_dbg(1, debug, "Failed to set input\n"); - return ret; - } - } - vid_ch->input_idx = index; - ch->curr_subdev_info = subdev_info; - ch->curr_sd_index = sd_index; - /* copy interface parameters to vpif */ - ch->vpifparams.iface = subdev_info->vpif_if; - - /* update tvnorms from the sub device input info */ - ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std; - return ret; + return vpif_set_input(config, ch, index); } /** @@ -1655,9 +1635,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_capture_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -1730,9 +1712,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1747,9 +1732,12 @@ vpif_query_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; + int ret; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, query_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -ENODATA; + return ret; } /** @@ -1775,13 +1763,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; @@ -1906,8 +1890,7 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1924,8 +1907,7 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -2063,7 +2045,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_capture_config *config; - int i, j, k, m, q, err; + int i, j, k, err; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct channel_obj *ch; struct common_obj *common; @@ -2086,18 +2069,19 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Capture", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Capture", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; - i--; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { @@ -2111,7 +2095,7 @@ static __init int vpif_probe(struct platform_device *pdev) video_device_release(ch->video_dev); } err = -ENOMEM; - goto vpif_dev_alloc_err; + goto vpif_int_err; } /* Initialize field of video device */ @@ -2142,24 +2126,6 @@ static __init int vpif_probe(struct platform_device *pdev) } } - for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { - ch = vpif_obj.dev[j]; - ch->channel_id = j; - common = &(ch->common[VPIF_VIDEO_INDEX]); - spin_lock_init(&common->irqlock); - mutex_init(&common->lock); - ch->video_dev->lock = &common->lock; - /* Initialize prio member of channel object */ - v4l2_prio_init(&ch->prio); - err = video_register_device(ch->video_dev, - VFL_TYPE_GRABBER, (j ? 1 : 0)); - if (err) - goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - - } - i2c_adap = i2c_get_adapter(1); config = pdev->dev.platform_data; @@ -2169,7 +2135,7 @@ static __init int vpif_probe(struct platform_device *pdev) if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; - goto probe_out; + goto vpif_sd_error; } for (i = 0; i < subdev_count; i++) { @@ -2186,19 +2152,32 @@ static __init int vpif_probe(struct platform_device *pdev) } v4l2_info(&vpif_obj.v4l2_dev, "registered sub device %s\n", subdevdata->name); - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + common = &(ch->common[VPIF_VIDEO_INDEX]); + spin_lock_init(&common->irqlock); + mutex_init(&common->lock); + ch->video_dev->lock = &common->lock; + /* Initialize prio member of channel object */ + v4l2_prio_init(&ch->prio); + video_set_drvdata(ch->video_dev, ch); + + /* select input 0 */ + err = vpif_set_input(config, ch, 0); + if (err) + goto probe_out; + + err = video_register_device(ch->video_dev, + VFL_TYPE_GRABBER, (j ? 1 : 0)); + if (err) + goto probe_out; + } v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n"); return 0; -probe_subdev_out: - /* free sub devices memory */ - kfree(vpif_obj.sd); - - j = VPIF_CAPTURE_MAX_DEVICES; probe_out: for (k = 0; k < j; k++) { /* Get the pointer to the channel object */ @@ -2206,22 +2185,23 @@ probe_out: /* Unregister video device */ video_unregister_device(ch->video_dev); } +probe_subdev_out: + /* free sub devices memory */ + kfree(vpif_obj.sd); -vpif_dev_alloc_err: - k = VPIF_CAPTURE_MAX_DEVICES-1; - res = platform_get_resource(pdev, IORESOURCE_IRQ, k); - i = res->end; - -vpif_int_err: - for (q = k; q >= 0; q--) { - for (m = i; m >= (int)res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[q]->channel_id)); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, q-1); - if (res) - i = res->end; +vpif_sd_error: + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); } +vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); + } return err; } diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h index d24efc17e4c8..3d3c1e5cd5d4 100644 --- a/drivers/media/platform/davinci/vpif_capture.h +++ b/drivers/media/platform/davinci/vpif_capture.h @@ -54,8 +54,6 @@ struct video_obj { /* Currently selected or default standard */ v4l2_std_id stdid; struct v4l2_dv_timings dv_timings; - /* This is to track the last input that is passed to application */ - u32 input_idx; }; struct vpif_cap_buffer { @@ -119,10 +117,10 @@ struct channel_obj { u8 initialized; /* Identifies channel */ enum vpif_channel_id channel_id; - /* index into sd table */ - int curr_sd_index; - /* ptr to current sub device information */ - struct vpif_subdev_info *curr_subdev_info; + /* Current input */ + u32 input_idx; + /* subdev corresponding to the current input, may be NULL */ + struct v4l2_subdev *sd; /* vpif configuration params */ struct vpif_params vpifparams; /* common object array */ @@ -159,10 +157,6 @@ struct vpif_config_params { u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS]; u8 max_device_type; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; -}; + #endif /* End of __KERNEL__ */ #endif /* VPIF_CAPTURE_H */ diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index a5b88689abad..b716fbd4241f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -280,12 +280,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) } /* clock settings */ - ret = - vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode, - ch->vpifparams.std_info.hd_sd); - if (ret < 0) { - vpif_err("can't set clock\n"); - return ret; + if (vpif_config_data->set_clock) { + ret = vpif_config_data->set_clock(ch->vpifparams.std_info. + ycmux_mode, ch->vpifparams.std_info.hd_sd); + if (ret < 0) { + vpif_err("can't set clock\n"); + return ret; + } } /* set the parameters and addresses */ @@ -307,7 +308,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel2_intr_assert(); channel2_intr_enable(1); enable_channel2(1); - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(1); } @@ -316,7 +317,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) channel3_intr_assert(); channel3_intr_enable(1); enable_channel3(1); - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data->chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(1); } @@ -826,9 +827,11 @@ static int vpif_querycap(struct file *file, void *priv, { struct vpif_display_config *config = vpif_dev->platform_data; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, "vpif display", sizeof(cap->driver)); - strlcpy(cap->bus_info, "Platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpif_dev)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -935,6 +938,7 @@ static int vpif_reqbufs(struct file *file, void *priv, enum v4l2_field field; struct vb2_queue *q; u8 index = 0; + int ret; /* This file handle has not initialized the channel, It is not allowed to do settings */ @@ -980,8 +984,12 @@ static int vpif_reqbufs(struct file *file, void *priv, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); - vb2_queue_init(q); - + ret = vb2_queue_init(q); + if (ret) { + vpif_err("vpif_display: vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(common->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; /* Increment io usrs member of channel object to 1 */ @@ -1173,14 +1181,16 @@ static int vpif_streamoff(struct file *file, void *priv, if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { - if (vpif_config_data->ch2_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL2_VIDEO].clip_en) channel2_clipping_enable(0); enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { - if (vpif_config_data->ch3_clip_en) + if (vpif_config_data-> + chan_config[VPIF_CHANNEL3_VIDEO].clip_en) channel3_clipping_enable(0); enable_channel3(0); channel3_intr_enable(0); @@ -1213,49 +1223,126 @@ static int vpif_enum_output(struct file *file, void *fh, { struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; + struct vpif_fh *vpif_handler = fh; + struct channel_obj *ch = vpif_handler->channel; - if (output->index >= config->output_count) { + chan_cfg = &config->chan_config[ch->channel_id]; + if (output->index >= chan_cfg->output_count) { vpif_dbg(1, debug, "Invalid output index\n"); return -EINVAL; } - strcpy(output->name, config->output[output->index]); - output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = VPIF_V4L2_STD; + *output = chan_cfg->outputs[output->index].output; + return 0; +} + +/** + * vpif_output_to_subdev() - Maps output to sub device + * @vpif_cfg - global config ptr + * @chan_cfg - channel config ptr + * @index - Given output index from application + * + * lookup the sub device information for a given output index. + * we report all the output to application. output table also + * has sub device name for the each output + */ +static int +vpif_output_to_subdev(struct vpif_display_config *vpif_cfg, + struct vpif_display_chan_config *chan_cfg, int index) +{ + struct vpif_subdev_info *subdev_info; + const char *subdev_name; + int i; + + vpif_dbg(2, debug, "vpif_output_to_subdev\n"); + + if (chan_cfg->outputs == NULL) + return -1; + + subdev_name = chan_cfg->outputs[index].subdev_name; + if (subdev_name == NULL) + return -1; + + /* loop through the sub device list to get the sub device info */ + for (i = 0; i < vpif_cfg->subdev_count; i++) { + subdev_info = &vpif_cfg->subdevinfo[i]; + if (!strcmp(subdev_info->name, subdev_name)) + return i; + } + return -1; +} + +/** + * vpif_set_output() - Select an output + * @vpif_cfg - global config ptr + * @ch - channel + * @index - Given output index from application + * + * Select the given output. + */ +static int vpif_set_output(struct vpif_display_config *vpif_cfg, + struct channel_obj *ch, int index) +{ + struct vpif_display_chan_config *chan_cfg = + &vpif_cfg->chan_config[ch->channel_id]; + struct vpif_subdev_info *subdev_info = NULL; + struct v4l2_subdev *sd = NULL; + u32 input = 0, output = 0; + int sd_index; + int ret; + + sd_index = vpif_output_to_subdev(vpif_cfg, chan_cfg, index); + if (sd_index >= 0) { + sd = vpif_obj.sd[sd_index]; + subdev_info = &vpif_cfg->subdevinfo[sd_index]; + } + + if (sd) { + input = chan_cfg->outputs[index].input_route; + output = chan_cfg->outputs[index].output_route; + ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); + if (ret < 0 && ret != -ENOIOCTLCMD) { + vpif_err("Failed to set output\n"); + return ret; + } + } + ch->output_idx = index; + ch->sd = sd; + if (chan_cfg->outputs != NULL) + /* update tvnorms from the sub device output info */ + ch->video_dev->tvnorms = chan_cfg->outputs[index].output.std; return 0; } static int vpif_s_output(struct file *file, void *priv, unsigned int i) { + struct vpif_display_config *config = vpif_dev->platform_data; + struct vpif_display_chan_config *chan_cfg; struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; - int ret = 0; + + chan_cfg = &config->chan_config[ch->channel_id]; + + if (i >= chan_cfg->output_count) + return -EINVAL; if (common->started) { vpif_err("Streaming in progress\n"); return -EBUSY; } - ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_routing, 0, i, 0); - - if (ret < 0) - vpif_err("Failed to set output standard\n"); - - vid_ch->output_id = i; - return ret; + return vpif_set_output(config, ch, i); } static int vpif_g_output(struct file *file, void *priv, unsigned int *i) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - *i = vid_ch->output_id; + *i = ch->output_idx; return 0; } @@ -1290,10 +1377,12 @@ vpif_enum_dv_timings(struct file *file, void *priv, { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; + int ret; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, enum_dv_timings, timings); + ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); + if (ret == -ENOIOCTLCMD && ret == -ENODEV) + return -EINVAL; + return ret; } /** @@ -1319,13 +1408,9 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } /* Configure subdevice timings, if any */ - ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], - video, s_dv_timings, timings); - if (ret == -ENOIOCTLCMD) { - vpif_dbg(2, debug, "Custom DV timings not supported by " - "subdevice\n"); - return -EINVAL; - } + ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings); + if (ret == -ENOIOCTLCMD || ret == -ENODEV) + ret = 0; if (ret < 0) { vpif_dbg(2, debug, "Error setting custom DV timings\n"); return ret; @@ -1450,10 +1535,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - g_register, reg); + return v4l2_subdev_call(ch->sd, core, g_register, reg); } /* @@ -1469,10 +1552,8 @@ static int vpif_dbg_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg){ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; - struct video_obj *vid_ch = &ch->video; - return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core, - s_register, reg); + return v4l2_subdev_call(ch->sd, core, s_register, reg); } #endif @@ -1536,9 +1617,6 @@ static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = VPIF_V4L2_STD, - .current_norm = V4L2_STD_625_50, - }; /*Configure the channels, buffer sizei, request irq */ @@ -1611,7 +1689,8 @@ static __init int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct vpif_display_config *config; - int i, j = 0, k, q, m, err = 0; + int i, j = 0, k, err = 0; + int res_idx = 0; struct i2c_adapter *i2c_adap; struct common_obj *common; struct channel_obj *ch; @@ -1634,21 +1713,22 @@ static __init int vpif_probe(struct platform_device *pdev) return err; } - k = 0; - while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { + while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, vpif_channel_isr, IRQF_SHARED, - "VPIF_Display", - (void *)(&vpif_obj.dev[k]->channel_id))) { + "VPIF_Display", (void *) + (&vpif_obj.dev[res_idx]->channel_id))) { err = -EBUSY; + for (j = 0; j < i; j++) + free_irq(j, (void *) + (&vpif_obj.dev[res_idx]->channel_id)); goto vpif_int_err; } } - k++; + res_idx++; } for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { - /* Get the pointer to the channel object */ ch = vpif_obj.dev[i]; @@ -1694,6 +1774,32 @@ static __init int vpif_probe(struct platform_device *pdev) } } + i2c_adap = i2c_get_adapter(1); + config = pdev->dev.platform_data; + subdev_count = config->subdev_count; + subdevdata = config->subdevinfo; + vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, + GFP_KERNEL); + if (vpif_obj.sd == NULL) { + vpif_err("unable to allocate memory for subdevice pointers\n"); + err = -ENOMEM; + goto vpif_sd_error; + } + + for (i = 0; i < subdev_count; i++) { + vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, + i2c_adap, + &subdevdata[i].board_info, + NULL); + if (!vpif_obj.sd[i]) { + vpif_err("Error registering v4l2 subdevice\n"); + goto probe_subdev_out; + } + + if (vpif_obj.sd[i]) + vpif_obj.sd[i]->grp_id = 1 << i; + } + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; /* Initialize field of the channel objects */ @@ -1715,6 +1821,8 @@ static __init int vpif_probe(struct platform_device *pdev) } ch->initialized = 0; + if (subdev_count) + ch->sd = vpif_obj.sd[0]; ch->channel_id = j; if (j < 2) ch->common[VPIF_VIDEO_INDEX].numbuffers = @@ -1729,6 +1837,12 @@ static __init int vpif_probe(struct platform_device *pdev) ch->common[VPIF_VIDEO_INDEX].fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; ch->video_dev->lock = &common->lock; + video_set_drvdata(ch->video_dev, ch); + + /* select output 0 */ + err = vpif_set_output(config, ch, 0); + if (err) + goto probe_out; /* register video device */ vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n", @@ -1738,42 +1852,12 @@ static __init int vpif_probe(struct platform_device *pdev) VFL_TYPE_GRABBER, (j ? 3 : 2)); if (err < 0) goto probe_out; - - video_set_drvdata(ch->video_dev, ch); - } - - i2c_adap = i2c_get_adapter(1); - config = pdev->dev.platform_data; - subdev_count = config->subdev_count; - subdevdata = config->subdevinfo; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); - if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); - err = -ENOMEM; - goto probe_out; - } - - for (i = 0; i < subdev_count; i++) { - vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev, - i2c_adap, - &subdevdata[i].board_info, - NULL); - if (!vpif_obj.sd[i]) { - vpif_err("Error registering v4l2 subdevice\n"); - goto probe_subdev_out; - } - - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; } v4l2_info(&vpif_obj.v4l2_dev, " VPIF display driver initialized\n"); return 0; -probe_subdev_out: - kfree(vpif_obj.sd); probe_out: for (k = 0; k < j; k++) { ch = vpif_obj.dev[k]; @@ -1781,14 +1865,21 @@ probe_out: video_device_release(ch->video_dev); ch->video_dev = NULL; } +probe_subdev_out: + kfree(vpif_obj.sd); +vpif_sd_error: + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + ch = vpif_obj.dev[i]; + /* Note: does nothing if ch->video_dev == NULL */ + video_device_release(ch->video_dev); + } vpif_int_err: v4l2_device_unregister(&vpif_obj.v4l2_dev); vpif_err("VPIF IRQ request failed\n"); - for (q = k; k >= 0; k--) { - for (m = i; m >= res->start; m--) - free_irq(m, (void *)(&vpif_obj.dev[k]->channel_id)); - res = platform_get_resource(pdev, IORESOURCE_IRQ, k-1); - m = res->end; + for (i = 0; i < res_idx; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + for (j = res->start; j <= res->end; j++) + free_irq(j, (void *)(&vpif_obj.dev[i]->channel_id)); } return err; diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h index f628ebcf3674..a5a18f74395c 100644 --- a/drivers/media/platform/davinci/vpif_display.h +++ b/drivers/media/platform/davinci/vpif_display.h @@ -62,13 +62,6 @@ struct video_obj { v4l2_std_id stdid; /* Currently selected or default * standard */ struct v4l2_dv_timings dv_timings; - u32 output_id; /* Current output id */ -}; - -struct vbi_obj { - int num_services; - struct vpif_vbi_params vbiparams; /* vpif parameters for the raw - * vbi data */ }; struct vpif_disp_buffer { @@ -131,12 +124,13 @@ struct channel_obj { * which is being displayed */ u8 initialized; /* flag to indicate whether * encoder is initialized */ + u32 output_idx; /* Current output index */ + struct v4l2_subdev *sd; /* Current output subdev(may be NULL) */ enum vpif_channel_id channel_id;/* Identifies channel */ struct vpif_params vpifparams; struct common_obj common[VPIF_NUMOBJECTS]; struct video_obj video; - struct vbi_obj vbi; }; /* File handle structure */ @@ -168,12 +162,4 @@ struct vpif_config_params { u8 min_numbuffers; }; -/* Struct which keeps track of the line numbers for the sliced vbi service */ -struct vpif_service_line { - u16 service_id; - u16 service_line[2]; - u16 enc_service_id; - u8 bytestowrite; -}; - #endif /* DAVINCIHD_DISPLAY_H */ diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index 0d8625f03a32..0146b354dc22 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -212,7 +212,7 @@ void gsc_hw_set_in_image_format(struct gsc_ctx *ctx) else cfg |= GSC_IN_YUV422_3P; break; - }; + } writel(cfg, dev->regs + GSC_IN_CON); } @@ -332,7 +332,7 @@ void gsc_hw_set_out_image_format(struct gsc_ctx *ctx) case 3: cfg |= GSC_OUT_YUV420_3P; break; - }; + } end_set: writel(cfg, dev->regs + GSC_OUT_CON); diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 897250b88647..31ac4dc69247 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -864,7 +864,7 @@ int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer * { struct viu_fh *fh = priv; struct viu_dev *dev = fh->dev; - struct v4l2_framebuffer *fb = arg; + const struct v4l2_framebuffer *fb = arg; struct viu_fmt *fmt; if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index d03637537118..2e2121e98133 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -397,8 +397,7 @@ static void device_isr(unsigned long priv) curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev); if (NULL == curr_ctx) { - printk(KERN_ERR - "Instance released before the end of transaction\n"); + pr_err("Instance released before the end of transaction\n"); return; } @@ -894,7 +893,7 @@ static int m2mtest_open(struct file *file) if (mutex_lock_interruptible(&dev->dev_mutex)) return -ERESTARTSYS; - ctx = kzalloc(sizeof *ctx, GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) { rc = -ENOMEM; goto open_unlock; @@ -1020,7 +1019,7 @@ static int m2mtest_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = kzalloc(sizeof *dev, GFP_KERNEL); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1028,7 +1027,7 @@ static int m2mtest_probe(struct platform_device *pdev) ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - goto free_dev; + return ret; atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -1067,15 +1066,13 @@ static int m2mtest_probe(struct platform_device *pdev) return 0; - v4l2_m2m_release(dev->m2m_dev); err_m2m: + v4l2_m2m_release(dev->m2m_dev); video_unregister_device(dev->vfd); rel_vdev: video_device_release(vfd); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); return ret; } @@ -1090,7 +1087,6 @@ static int m2mtest_remove(struct platform_device *pdev) del_timer_sync(&dev->timer); video_unregister_device(dev->vfd); v4l2_device_unregister(&dev->v4l2_dev); - kfree(dev); return 0; } diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index 084ea77d65a7..e2c57f334c5d 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -27,13 +27,13 @@ #ifndef OMAP3_ISP_REG_H #define OMAP3_ISP_REG_H -#include <plat/omap34xx.h> - - #define CM_CAM_MCLK_HZ 172800000 /* Hz */ /* ISP Submodules offset */ +#define L4_34XX_BASE 0x48000000 +#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) + #define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE #define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index dded98815220..367efd164d0f 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -177,7 +177,9 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) { + struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; struct timeval *tv; struct timespec ts; @@ -216,6 +218,25 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } + /* + * Set up a buffer at MIPI-CSIS if current image format + * requires the frame embedded data capture. + */ + if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { + unsigned int plane = ffs(f->fmt->mdataplanes) - 1; + unsigned int size = f->payload[plane]; + s32 index = fimc_hw_get_frame_index(fimc); + void *vaddr; + + list_for_each_entry(v_buf, &cap->active_buf_q, list) { + if (v_buf->index != index) + continue; + vaddr = vb2_plane_vaddr(&v_buf->vb, plane); + v4l2_subdev_call(csis, video, s_rx_buffer, + vaddr, &size); + break; + } + } if (cap->active_buf_cnt == 0) { if (deq_buf) @@ -351,6 +372,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, unsigned int size = (wh * fmt->depth[i]) / 8; if (pixm) sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else if (fimc_fmt_is_user_defined(fmt->color)) + sizes[i] = frame->payload[i]; else sizes[i] = max_t(u32, size, frame->payload[i]); @@ -611,10 +634,10 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, u32 mask = FMT_FLAGS_CAM; struct fimc_fmt *ffmt; - /* Color conversion from/to JPEG is not supported */ + /* Conversion from/to JPEG or User Defined format is not supported */ if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && - fimc_fmt_is_jpeg(ctx->s_frame.fmt->color)) - *code = V4L2_MBUS_FMT_JPEG_1X8; + fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) + *code = ctx->s_frame.fmt->mbus_code; if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) mask |= FMT_FLAGS_M2M; @@ -628,18 +651,19 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, *fourcc = ffmt->fourcc; if (pad == FIMC_SD_PAD_SINK) { - max_w = fimc_fmt_is_jpeg(ffmt->color) ? + max_w = fimc_fmt_is_user_defined(ffmt->color) ? pl->scaler_dis_w : pl->scaler_en_w; /* Apply the camera input interface pixel constraints */ v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, height, max_t(u32, *height, 32), FIMC_CAMIF_MAX_HEIGHT, - fimc_fmt_is_jpeg(ffmt->color) ? 3 : 1, + fimc_fmt_is_user_defined(ffmt->color) ? + 3 : 1, 0); return ffmt; } /* Can't scale or crop in transparent (JPEG) transfer mode */ - if (fimc_fmt_is_jpeg(ffmt->color)) { + if (fimc_fmt_is_user_defined(ffmt->color)) { *width = ctx->s_frame.f_width; *height = ctx->s_frame.f_height; return ffmt; @@ -684,7 +708,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, u32 max_sc_h, max_sc_v; /* In JPEG transparent transfer mode cropping is not supported */ - if (fimc_fmt_is_jpeg(ctx->d_frame.fmt->color)) { + if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { r->width = sink->f_width; r->height = sink->f_height; r->left = r->top = 0; @@ -847,6 +871,48 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, return 0; } +/** + * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters + * @sensor: pointer to the sensor subdev + * @plane_fmt: provides plane sizes corresponding to the frame layout entries + * @try: true to set the frame parameters, false to query only + * + * This function is used by this driver only for compressed/blob data formats. + */ +static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, + struct v4l2_plane_pix_format *plane_fmt, + unsigned int num_planes, bool try) +{ + struct v4l2_mbus_frame_desc fd; + int i, ret; + + for (i = 0; i < num_planes; i++) + fd.entry[i].length = plane_fmt[i].sizeimage; + + if (try) + ret = v4l2_subdev_call(sensor, pad, set_frame_desc, 0, &fd); + else + ret = v4l2_subdev_call(sensor, pad, get_frame_desc, 0, &fd); + + if (ret < 0) + return ret; + + if (num_planes != fd.num_entries) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + plane_fmt[i].sizeimage = fd.entry[i].length; + + if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { + v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", + fd.entry[0].length); + + return -EINVAL; + } + + return 0; +} + static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { @@ -865,7 +931,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_mbus_framefmt mf; struct fimc_fmt *ffmt = NULL; - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -879,25 +945,32 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, return -EINVAL; if (!fimc->vid_cap.user_subdev_api) { - mf.width = pix->width; + mf.width = pix->width; mf.height = pix->height; - mf.code = ffmt->mbus_code; + mf.code = ffmt->mbus_code; fimc_md_graph_lock(fimc); fimc_pipeline_try_format(ctx, &mf, &ffmt, false); fimc_md_graph_unlock(fimc); - - pix->width = mf.width; - pix->height = mf.height; + pix->width = mf.width; + pix->height = mf.height; if (ffmt) pix->pixelformat = ffmt->fourcc; } fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); + + if (ffmt->flags & FMT_FLAGS_COMPRESSED) + fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ffmt->memplanes, true); + return 0; } -static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, bool jpeg) +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, + enum fimc_color_fmt color) { + bool jpeg = fimc_fmt_is_user_defined(color); + ctx->scaler.enabled = !jpeg; fimc_ctrls_activate(ctx, !jpeg); @@ -920,7 +993,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) return -EBUSY; /* Pre-configure format at camera interface input, for JPEG only */ - if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, FIMC_SD_PAD_SINK); @@ -953,7 +1026,16 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) } fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); - for (i = 0; i < ff->fmt->colplanes; i++) + + if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { + ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ff->fmt->memplanes, + true); + if (ret < 0) + return ret; + } + + for (i = 0; i < ff->fmt->memplanes; i++) ff->payload[i] = pix->plane_fmt[i].sizeimage; set_frame_bounds(ff, pix->width, pix->height); @@ -961,7 +1043,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f) if (!(ctx->state & FIMC_COMPOSE)) set_frame_crop(ff, 0, 0, pix->width, pix->height); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); /* Reset cropping and set format at the camera interface input */ if (!fimc->vid_cap.user_subdev_api) { @@ -1063,6 +1145,23 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) src_fmt.format.height != sink_fmt.format.height || src_fmt.format.code != sink_fmt.format.code) return -EPIPE; + + if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + fimc_user_defined_mbus_fmt(src_fmt.format.code)) { + struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; + struct fimc_frame *frame = &vid_cap->ctx->d_frame; + unsigned int i; + + ret = fimc_get_sensor_frame_desc(sd, plane_fmt, + frame->fmt->memplanes, + false); + if (ret < 0) + return -EPIPE; + + for (i = 0; i < frame->fmt->memplanes; i++) + if (frame->payload[i] < plane_fmt[i].sizeimage) + return -EPIPE; + } } return 0; } @@ -1424,7 +1523,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, /* Update RGB Alpha control state and value range */ fimc_alpha_ctrl_update(ctx); - fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ffmt->color)); + fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 1a445404e73d..8d0d2b94a135 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -184,7 +184,17 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 1, .colplanes = 1, .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, - .flags = FMT_FLAGS_CAM, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, + }, { + .name = "S5C73MX interleaved UYVY/JPEG", + .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, + .color = FIMC_FMT_YUYV_JPEG, + .depth = { 8 }, + .memplanes = 2, + .colplanes = 1, + .mdataplanes = 0x2, /* plane 1 holds frame meta data */ + .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, }, }; @@ -371,7 +381,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, default: return -EINVAL; } - } else { + } else if (!frame->fmt->mdataplanes) { if (frame->fmt->memplanes >= 2) paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); @@ -698,6 +708,11 @@ int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f) if (frame->fmt->colplanes == 1) /* packed formats */ bpl = (bpl * frame->fmt->depth[0]) / 8; pixm->plane_fmt[i].bytesperline = bpl; + + if (frame->fmt->flags & FMT_FLAGS_COMPRESSED) { + pixm->plane_fmt[i].sizeimage = frame->payload[i]; + continue; + } pixm->plane_fmt[i].sizeimage = (frame->o_width * frame->o_height * frame->fmt->depth[i]) / 8; } diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index cd716ba6015f..c0040d792499 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -40,6 +40,8 @@ #define SCALER_MAX_VRATIO 64 #define DMA_MIN_SIZE 8 #define FIMC_CAMIF_MAX_HEIGHT 0x2000 +#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) +#define FIMC_MAX_PLANES 3 /* indices to the clocks array */ enum { @@ -83,7 +85,7 @@ enum fimc_datapath { }; enum fimc_color_fmt { - FIMC_FMT_RGB444 = 0x10, + FIMC_FMT_RGB444 = 0x10, FIMC_FMT_RGB555, FIMC_FMT_RGB565, FIMC_FMT_RGB666, @@ -95,14 +97,15 @@ enum fimc_color_fmt { FIMC_FMT_CBYCRY422, FIMC_FMT_CRYCBY422, FIMC_FMT_YCBCR444_LOCAL, - FIMC_FMT_JPEG = 0x40, - FIMC_FMT_RAW8 = 0x80, + FIMC_FMT_RAW8 = 0x40, FIMC_FMT_RAW10, FIMC_FMT_RAW12, + FIMC_FMT_JPEG = 0x80, + FIMC_FMT_YUYV_JPEG = 0x100, }; +#define fimc_fmt_is_user_defined(x) (!!((x) & 0x180)) #define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) -#define fimc_fmt_is_jpeg(x) (!!((x) & 0x40)) #define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -139,6 +142,7 @@ enum fimc_color_fmt { * @memplanes: number of physically non-contiguous data planes * @colplanes: number of physically contiguous data planes * @depth: per plane driver's private 'number of bits per pixel' + * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) * @flags: flags indicating which operation mode format applies to */ struct fimc_fmt { @@ -149,12 +153,14 @@ struct fimc_fmt { u16 memplanes; u16 colplanes; u8 depth[VIDEO_MAX_PLANES]; + u16 mdataplanes; u16 flags; #define FMT_FLAGS_CAM (1 << 0) #define FMT_FLAGS_M2M_IN (1 << 1) #define FMT_FLAGS_M2M_OUT (1 << 2) #define FMT_FLAGS_M2M (1 << 1 | 1 << 2) #define FMT_HAS_ALPHA (1 << 3) +#define FMT_FLAGS_COMPRESSED (1 << 4) }; /** @@ -272,7 +278,7 @@ struct fimc_frame { u32 offs_v; u32 width; u32 height; - unsigned long payload[VIDEO_MAX_PLANES]; + unsigned int payload[VIDEO_MAX_PLANES]; struct fimc_addr paddr; struct fimc_dma_offset dma_offset; struct fimc_fmt *fmt; @@ -577,6 +583,18 @@ static inline int tiled_fmt(struct fimc_fmt *fmt) return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } +static inline bool fimc_jpeg_fourcc(u32 pixelformat) +{ + return (pixelformat == V4L2_PIX_FMT_JPEG || + pixelformat == V4L2_PIX_FMT_S5C_UYVY_JPG); +} + +static inline bool fimc_user_defined_mbus_fmt(u32 code) +{ + return (code == V4L2_MBUS_FMT_JPEG_1X8 || + code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); +} + /* Return the alpha component bit mask */ static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) { diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 6b71d953fd15..4500e44f6857 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -551,30 +551,31 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) return 0; } -static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *cr) +static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_crop cr = *crop; struct fimc_frame *f; int ret; - ret = fimc_m2m_try_crop(ctx, cr); + ret = fimc_m2m_try_crop(ctx, &cr); if (ret) return ret; - f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? + f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->s_frame : &ctx->d_frame; /* Check to see if scaling ratio is within supported range */ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) { - if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(ctx, cr->c.width, - cr->c.height, ctx->d_frame.width, + if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = fimc_check_scaler_ratio(ctx, cr.c.width, + cr.c.height, ctx->d_frame.width, ctx->d_frame.height, ctx->rotation); } else { ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, - ctx->s_frame.height, cr->c.width, - cr->c.height, ctx->rotation); + ctx->s_frame.height, cr.c.width, + cr.c.height, ctx->rotation); } if (ret) { v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); @@ -582,10 +583,10 @@ static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop * } } - f->offs_h = cr->c.left; - f->offs_v = cr->c.top; - f->width = cr->c.width; - f->height = cr->c.height; + f->offs_h = cr.c.left; + f->offs_v = cr.c.top; + f->width = cr.c.width; + f->height = cr.c.height; fimc_ctx_state_set(FIMC_PARAMS, ctx); diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c index 783408fd7d56..2c9d0c06c9e8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-reg.c @@ -625,7 +625,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; } /* else defaults to ITU-R BT.656 8-bit */ } else if (cam->bus_type == FIMC_MIPI_CSI2) { - if (fimc_fmt_is_jpeg(f->fmt->color)) + if (fimc_fmt_is_user_defined(f->fmt->color)) cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; } @@ -680,6 +680,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; break; case V4L2_MBUS_FMT_JPEG_1X8: + case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: tmp = FIMC_REG_CSIIMGFMT_USER(1); cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; break; @@ -744,13 +745,13 @@ void fimc_hw_dis_capture(struct fimc_dev *dev) } /* Return an index to the buffer actually being written. */ -u32 fimc_hw_get_frame_index(struct fimc_dev *dev) +s32 fimc_hw_get_frame_index(struct fimc_dev *dev) { - u32 reg; + s32 reg; if (dev->variant->has_cistatus2) { - reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F; - return reg > 0 ? --reg : reg; + reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; + return reg - 1; } reg = readl(dev->regs + FIMC_REG_CISTATUS); @@ -759,6 +760,18 @@ u32 fimc_hw_get_frame_index(struct fimc_dev *dev) FIMC_REG_CISTATUS_FRAMECNT_SHIFT; } +/* Return an index to the buffer being written previously. */ +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) +{ + s32 reg; + + if (!dev->variant->has_cistatus2) + return -1; + + reg = readl(dev->regs + FIMC_REG_CISTATUS2); + return ((reg >> 7) & 0x3f) - 1; +} + /* Locking: the caller holds fimc->slock */ void fimc_activate_capture(struct fimc_ctx *ctx) { diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h index 579ac8ac03de..b6abfc7b72ac 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.h +++ b/drivers/media/platform/s5p-fimc/fimc-reg.h @@ -307,7 +307,8 @@ void fimc_hw_clear_irq(struct fimc_dev *dev); void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); void fimc_hw_dis_capture(struct fimc_dev *dev); -u32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); void fimc_activate_capture(struct fimc_ctx *ctx); void fimc_deactivate_capture(struct fimc_dev *fimc); diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index e92236ac5cfe..4c961b1b68e6 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -2,7 +2,7 @@ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver * * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki, <s.nawrocki@samsung.com> + * Sylwester Nawrocki <s.nawrocki@samsung.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); #define CSIS_MAX_PIX_WIDTH 0xffff #define CSIS_MAX_PIX_HEIGHT 0xffff +/* Non-image packet data buffers */ +#define S5PCSIS_PKTDATA_ODD 0x2000 +#define S5PCSIS_PKTDATA_EVEN 0x3000 +#define S5PCSIS_PKTDATA_SIZE SZ_4K + enum { CSIS_CLK_MUX, CSIS_CLK_GATE, @@ -110,8 +115,8 @@ static char *csi_clock_name[] = { #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) static const char * const csis_supply_name[] = { - "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ - "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddio", /* CSIS I/O and PLL (1.8V) supply */ }; #define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) @@ -144,12 +149,18 @@ static const struct s5pcsis_event s5pcsis_events[] = { }; #define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) +struct csis_pktbuf { + u32 *data; + unsigned int len; +}; + /** * struct csis_state - the driver's internal state data structure * @lock: mutex serializing the subdev and power management operations, * protecting @format and @flags members * @pads: CSIS pads array * @sd: v4l2_subdev associated with CSIS device instance + * @index: the hardware instance index * @pdev: CSIS platform device * @regs: mmaped I/O registers memory * @supplies: CSIS regulator supplies @@ -159,12 +170,14 @@ static const struct s5pcsis_event s5pcsis_events[] = { * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below + * @pkt_buf: the frame embedded (non-image) data buffer * @events: MIPI-CSIS event (error) counters */ struct csis_state { struct mutex lock; struct media_pad pads[CSIS_PADS_NUM]; struct v4l2_subdev sd; + u8 index; struct platform_device *pdev; void __iomem *regs; struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; @@ -175,6 +188,7 @@ struct csis_state { struct v4l2_mbus_framefmt format; struct spinlock slock; + struct csis_pktbuf pkt_buf; struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; }; @@ -202,7 +216,11 @@ static const struct csis_pix_format s5pcsis_formats[] = { .code = V4L2_MBUS_FMT_JPEG_1X8, .fmt_reg = S5PCSIS_CFG_FMT_USER(1), .data_alignment = 32, - }, + }, { + .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_USER(1), + .data_alignment = 32, + } }; #define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) @@ -266,7 +284,7 @@ static void __s5pcsis_set_format(struct csis_state *state) struct v4l2_mbus_framefmt *mf = &state->format; u32 val; - v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n", + v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", mf->code, mf->width, mf->height); /* Color format */ @@ -304,8 +322,10 @@ static void s5pcsis_set_params(struct csis_state *state) val |= S5PCSIS_CTRL_ALIGN_32BIT; else /* 24-bits */ val &= ~S5PCSIS_CTRL_ALIGN_32BIT; - /* Not using external clock. */ + val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; + if (pdata->wclk_source) + val |= S5PCSIS_CTRL_WCLK_EXTCLK; s5pcsis_write(state, S5PCSIS_CTRL, val); /* Update the shadow register. */ @@ -529,6 +549,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, return 0; } +static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, + unsigned int *size) +{ + struct csis_state *state = sd_to_csis_state(sd); + unsigned long flags; + + *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); + + spin_lock_irqsave(&state->slock, flags); + state->pkt_buf.data = buf; + state->pkt_buf.len = *size; + spin_unlock_irqrestore(&state->slock, flags); + + return 0; +} + static int s5pcsis_log_status(struct v4l2_subdev *sd) { struct csis_state *state = sd_to_csis_state(sd); @@ -566,6 +602,7 @@ static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { }; static struct v4l2_subdev_video_ops s5pcsis_video_ops = { + .s_rx_buffer = s5pcsis_s_rx_buffer, .s_stream = s5pcsis_s_stream, }; @@ -578,13 +615,26 @@ static struct v4l2_subdev_ops s5pcsis_subdev_ops = { static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) { struct csis_state *state = dev_id; + struct csis_pktbuf *pktbuf = &state->pkt_buf; unsigned long flags; u32 status; status = s5pcsis_read(state, S5PCSIS_INTSRC); - spin_lock_irqsave(&state->slock, flags); + if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { + u32 offset; + + if (status & S5PCSIS_INTSRC_EVEN) + offset = S5PCSIS_PKTDATA_EVEN; + else + offset = S5PCSIS_PKTDATA_ODD; + + memcpy(pktbuf->data, state->regs + offset, pktbuf->len); + pktbuf->data = NULL; + rmb(); + } + /* Update the event/error counters */ if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { int i; @@ -620,14 +670,15 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev) spin_lock_init(&state->slock); state->pdev = pdev; + state->index = max(0, pdev->id); pdata = pdev->dev.platform_data; - if (pdata == NULL || pdata->phy_enable == NULL) { + if (pdata == NULL) { dev_err(&pdev->dev, "Platform data not fully specified\n"); return -EINVAL; } - if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || + if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || pdata->lanes > CSIS0_MAX_LANES) { dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", pdata->lanes); @@ -710,7 +761,6 @@ e_clkput: static int s5pcsis_pm_suspend(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -722,7 +772,7 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) mutex_lock(&state->lock); if (state->flags & ST_POWERED) { s5pcsis_stop_stream(state); - ret = pdata->phy_enable(state->pdev, false); + ret = s5p_csis_phy_enable(state->index, false); if (ret) goto unlock; ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, @@ -741,7 +791,6 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime) static int s5pcsis_pm_resume(struct device *dev, bool runtime) { - struct s5p_platform_mipi_csis *pdata = dev->platform_data; struct platform_device *pdev = to_platform_device(dev); struct v4l2_subdev *sd = platform_get_drvdata(pdev); struct csis_state *state = sd_to_csis_state(sd); @@ -759,7 +808,7 @@ static int s5pcsis_pm_resume(struct device *dev, bool runtime) state->supplies); if (ret) goto unlock; - ret = pdata->phy_enable(state->pdev, true); + ret = s5p_csis_phy_enable(state->index, true); if (!ret) { state->flags |= ST_POWERED; } else { diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 1e3b9dd014c0..1bfbc325836b 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -507,7 +507,7 @@ static int vidioc_g_crop(struct file *file, void *prv, struct v4l2_crop *cr) return 0; } -static int vidioc_try_crop(struct file *file, void *prv, struct v4l2_crop *cr) +static int vidioc_try_crop(struct file *file, void *prv, const struct v4l2_crop *cr) { struct g2d_ctx *ctx = prv; struct g2d_dev *dev = ctx->dev; diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 394775ae5774..17983c4c9a9a 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1353,7 +1353,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) return ret; } dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk); - clk_enable(jpeg->clk); + clk_prepare_enable(jpeg->clk); /* v4l2 device */ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev); @@ -1460,7 +1460,7 @@ device_register_rollback: v4l2_device_unregister(&jpeg->v4l2_dev); clk_get_rollback: - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return ret; @@ -1480,7 +1480,7 @@ static int s5p_jpeg_remove(struct platform_device *pdev) v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); - clk_disable(jpeg->clk); + clk_disable_unprepare(jpeg->clk); clk_put(jpeg->clk); return 0; diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index d0663409af00..379008c6d09a 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o -s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o +s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o +s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h new file mode 100644 index 000000000000..363a97cc7681 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -0,0 +1,408 @@ +/* + * Register definition file for Samsung MFC V6.x Interface (FIMV) driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _REGS_FIMV_V6_H +#define _REGS_FIMV_V6_H + +#include <linux/kernel.h> +#include <linux/sizes.h> + +#define S5P_FIMV_REG_SIZE_V6 (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) +#define S5P_FIMV_REG_COUNT_V6 ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) + +/* Number of bits that the buffer address should be shifted for particular + * MFC buffers. */ +#define S5P_FIMV_MEM_OFFSET_V6 0 + +#define S5P_FIMV_START_ADDR_V6 0x0000 +#define S5P_FIMV_END_ADDR_V6 0xfd80 + +#define S5P_FIMV_REG_CLEAR_BEGIN_V6 0xf000 +#define S5P_FIMV_REG_CLEAR_COUNT_V6 1024 + +/* Codec Common Registers */ +#define S5P_FIMV_RISC_ON_V6 0x0000 +#define S5P_FIMV_RISC2HOST_INT_V6 0x003C +#define S5P_FIMV_HOST2RISC_INT_V6 0x0044 +#define S5P_FIMV_RISC_BASE_ADDRESS_V6 0x0054 + +#define S5P_FIMV_MFC_RESET_V6 0x1070 + +#define S5P_FIMV_HOST2RISC_CMD_V6 0x1100 +#define S5P_FIMV_H2R_CMD_EMPTY_V6 0 +#define S5P_FIMV_H2R_CMD_SYS_INIT_V6 1 +#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6 2 +#define S5P_FIMV_CH_SEQ_HEADER_V6 3 +#define S5P_FIMV_CH_INIT_BUFS_V6 4 +#define S5P_FIMV_CH_FRAME_START_V6 5 +#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6 6 +#define S5P_FIMV_H2R_CMD_SLEEP_V6 7 +#define S5P_FIMV_H2R_CMD_WAKEUP_V6 8 +#define S5P_FIMV_CH_LAST_FRAME_V6 9 +#define S5P_FIMV_H2R_CMD_FLUSH_V6 10 +/* RMVME: REALLOC used? */ +#define S5P_FIMV_CH_FRAME_START_REALLOC_V6 5 + +#define S5P_FIMV_RISC2HOST_CMD_V6 0x1104 +#define S5P_FIMV_R2H_CMD_EMPTY_V6 0 +#define S5P_FIMV_R2H_CMD_SYS_INIT_RET_V6 1 +#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET_V6 2 +#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET_V6 3 +#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET_V6 4 + +#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET_V6 6 +#define S5P_FIMV_R2H_CMD_SLEEP_RET_V6 7 +#define S5P_FIMV_R2H_CMD_WAKEUP_RET_V6 8 +#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET_V6 9 +#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET_V6 10 +#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET_V6 11 +#define S5P_FIMV_R2H_CMD_FW_STATUS_RET_V6 12 +#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET_V6 13 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET_V6 14 +#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET_V6 15 +#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 +#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 + +#define S5P_FIMV_FW_VERSION_V6 0xf000 + +#define S5P_FIMV_INSTANCE_ID_V6 0xf008 +#define S5P_FIMV_CODEC_TYPE_V6 0xf00c +#define S5P_FIMV_CONTEXT_MEM_ADDR_V6 0xf014 +#define S5P_FIMV_CONTEXT_MEM_SIZE_V6 0xf018 +#define S5P_FIMV_PIXEL_FORMAT_V6 0xf020 + +#define S5P_FIMV_METADATA_ENABLE_V6 0xf024 +#define S5P_FIMV_DBG_BUFFER_ADDR_V6 0xf030 +#define S5P_FIMV_DBG_BUFFER_SIZE_V6 0xf034 +#define S5P_FIMV_RET_INSTANCE_ID_V6 0xf070 + +#define S5P_FIMV_ERROR_CODE_V6 0xf074 +#define S5P_FIMV_ERR_WARNINGS_START_V6 160 +#define S5P_FIMV_ERR_DEC_MASK_V6 0xffff +#define S5P_FIMV_ERR_DEC_SHIFT_V6 0 +#define S5P_FIMV_ERR_DSPL_MASK_V6 0xffff0000 +#define S5P_FIMV_ERR_DSPL_SHIFT_V6 16 + +#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE_V6 0xf078 +#define S5P_FIMV_METADATA_STATUS_V6 0xf07C +#define S5P_FIMV_METADATA_ADDR_MB_INFO_V6 0xf080 +#define S5P_FIMV_METADATA_SIZE_MB_INFO_V6 0xf084 + +/* Decoder Registers */ +#define S5P_FIMV_D_CRC_CTRL_V6 0xf0b0 +#define S5P_FIMV_D_DEC_OPTIONS_V6 0xf0b4 +#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6 4 +#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6 3 +#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6 1 +#define S5P_FIMV_D_OPT_LF_CTRL_MASK_V6 0x3 +#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6 0 + +#define S5P_FIMV_D_DISPLAY_DELAY_V6 0xf0b8 + +#define S5P_FIMV_D_SET_FRAME_WIDTH_V6 0xf0bc +#define S5P_FIMV_D_SET_FRAME_HEIGHT_V6 0xf0c0 + +#define S5P_FIMV_D_SEI_ENABLE_V6 0xf0c4 + +/* Buffer setting registers */ +#define S5P_FIMV_D_MIN_NUM_DPB_V6 0xf0f0 +#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE_V6 0xf0f4 +#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE_V6 0xf0f8 +#define S5P_FIMV_D_MVC_NUM_VIEWS_V6 0xf0fc +#define S5P_FIMV_D_MIN_NUM_MV_V6 0xf100 +#define S5P_FIMV_D_NUM_DPB_V6 0xf130 +#define S5P_FIMV_D_LUMA_DPB_SIZE_V6 0xf134 +#define S5P_FIMV_D_CHROMA_DPB_SIZE_V6 0xf138 +#define S5P_FIMV_D_MV_BUFFER_SIZE_V6 0xf13c + +#define S5P_FIMV_D_LUMA_DPB_V6 0xf140 +#define S5P_FIMV_D_CHROMA_DPB_V6 0xf240 +#define S5P_FIMV_D_MV_BUFFER_V6 0xf340 + +#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6 0xf440 +#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6 0xf444 +#define S5P_FIMV_D_METADATA_BUFFER_ADDR_V6 0xf448 +#define S5P_FIMV_D_METADATA_BUFFER_SIZE_V6 0xf44c +#define S5P_FIMV_D_NUM_MV_V6 0xf478 +#define S5P_FIMV_D_CPB_BUFFER_ADDR_V6 0xf4b0 +#define S5P_FIMV_D_CPB_BUFFER_SIZE_V6 0xf4b4 + +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER_V6 0xf4b8 +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6 0xf4bc +#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V6 0xf4c0 +#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4 +#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8 +#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0 + +/* Display information register */ +#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500 +#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6 0xf504 + +/* Display status */ +#define S5P_FIMV_D_DISPLAY_STATUS_V6 0xf508 + +#define S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6 0xf50c +#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6 0xf510 + +#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6 0xf514 + +#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 0xf518 +#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 0xf51c +#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V6 0xf520 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP_V6 0xf524 +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP_V6 0xf528 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT_V6 0xf52c +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT_V6 0xf530 +#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6 0xf534 +#define S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6 0xf538 + +/* Decoded picture information register */ +#define S5P_FIMV_D_DECODED_FRAME_WIDTH_V6 0xf53c +#define S5P_FIMV_D_DECODED_FRAME_HEIGHT_V6 0xf540 +#define S5P_FIMV_D_DECODED_STATUS_V6 0xf544 +#define S5P_FIMV_DEC_CRC_GEN_MASK_V6 0x1 +#define S5P_FIMV_DEC_CRC_GEN_SHIFT_V6 6 + +#define S5P_FIMV_D_DECODED_LUMA_ADDR_V6 0xf548 +#define S5P_FIMV_D_DECODED_CHROMA_ADDR_V6 0xf54c + +#define S5P_FIMV_D_DECODED_FRAME_TYPE_V6 0xf550 +#define S5P_FIMV_DECODE_FRAME_MASK_V6 7 + +#define S5P_FIMV_D_DECODED_CROP_INFO1_V6 0xf554 +#define S5P_FIMV_D_DECODED_CROP_INFO2_V6 0xf558 +#define S5P_FIMV_D_DECODED_PICTURE_PROFILE_V6 0xf55c +#define S5P_FIMV_D_DECODED_NAL_SIZE_V6 0xf560 +#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP_V6 0xf564 +#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP_V6 0xf568 +#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT_V6 0xf56c +#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT_V6 0xf570 + +/* Returned value register for specific setting */ +#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 0xf574 +#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 0xf578 +#define S5P_FIMV_D_RET_PICTURE_TIME_TOP_V6 0xf57c +#define S5P_FIMV_D_RET_PICTURE_TIME_BOT_V6 0xf580 +#define S5P_FIMV_D_CHROMA_FORMAT_V6 0xf588 +#define S5P_FIMV_D_MPEG4_INFO_V6 0xf58c +#define S5P_FIMV_D_H264_INFO_V6 0xf590 + +#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB_V6 0xf594 +#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB_V6 0xf598 +#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM_V6 0xf59c +#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM_V6 0xf5a0 +#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL_V6 0xf5a4 +#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL_V6 0xf5a8 +#define S5P_FIMV_D_METADATA_ADDR_VUI_V6 0xf5ac +#define S5P_FIMV_D_METADATA_SIZE_VUI_V6 0xf5b0 + +#define S5P_FIMV_D_MVC_VIEW_ID_V6 0xf5b4 + +/* SEI related information */ +#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6 0xf5f0 +#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID_V6 0xf5f4 +#define S5P_FIMV_D_FRAME_PACK_SEI_INFO_V6 0xf5f8 +#define S5P_FIMV_D_FRAME_PACK_GRID_POS_V6 0xf5fc + +/* Encoder Registers */ +#define S5P_FIMV_E_FRAME_WIDTH_V6 0xf770 +#define S5P_FIMV_E_FRAME_HEIGHT_V6 0xf774 +#define S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6 0xf778 +#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6 0xf77c +#define S5P_FIMV_E_FRAME_CROP_OFFSET_V6 0xf780 +#define S5P_FIMV_E_ENC_OPTIONS_V6 0xf784 +#define S5P_FIMV_E_PICTURE_PROFILE_V6 0xf788 +#define S5P_FIMV_E_FIXED_PICTURE_QP_V6 0xf790 + +#define S5P_FIMV_E_RC_CONFIG_V6 0xf794 +#define S5P_FIMV_E_RC_QP_BOUND_V6 0xf798 +#define S5P_FIMV_E_RC_RPARAM_V6 0xf79c +#define S5P_FIMV_E_MB_RC_CONFIG_V6 0xf7a0 +#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4 +#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac +#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0 + +#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c +#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850 +#define S5P_FIMV_E_NUM_DPB_V6 0xf890 +#define S5P_FIMV_E_LUMA_DPB_V6 0xf8c0 +#define S5P_FIMV_E_CHROMA_DPB_V6 0xf904 +#define S5P_FIMV_E_ME_BUFFER_V6 0xf948 + +#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6 0xf98c +#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6 0xf990 +#define S5P_FIMV_E_TMV_BUFFER0_V6 0xf994 +#define S5P_FIMV_E_TMV_BUFFER1_V6 0xf998 +#define S5P_FIMV_E_SOURCE_LUMA_ADDR_V6 0xf9f0 +#define S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6 0xf9f4 +#define S5P_FIMV_E_STREAM_BUFFER_ADDR_V6 0xf9f8 +#define S5P_FIMV_E_STREAM_BUFFER_SIZE_V6 0xf9fc +#define S5P_FIMV_E_ROI_BUFFER_ADDR_V6 0xfA00 + +#define S5P_FIMV_E_PARAM_CHANGE_V6 0xfa04 +#define S5P_FIMV_E_IR_SIZE_V6 0xfa08 +#define S5P_FIMV_E_GOP_CONFIG_V6 0xfa0c +#define S5P_FIMV_E_MSLICE_MODE_V6 0xfa10 +#define S5P_FIMV_E_MSLICE_SIZE_MB_V6 0xfa14 +#define S5P_FIMV_E_MSLICE_SIZE_BITS_V6 0xfa18 +#define S5P_FIMV_E_FRAME_INSERTION_V6 0xfa1c + +#define S5P_FIMV_E_RC_FRAME_RATE_V6 0xfa20 +#define S5P_FIMV_E_RC_BIT_RATE_V6 0xfa24 +#define S5P_FIMV_E_RC_QP_OFFSET_V6 0xfa28 +#define S5P_FIMV_E_RC_ROI_CTRL_V6 0xfa2c +#define S5P_FIMV_E_PICTURE_TAG_V6 0xfa30 +#define S5P_FIMV_E_BIT_COUNT_ENABLE_V6 0xfa34 +#define S5P_FIMV_E_MAX_BIT_COUNT_V6 0xfa38 +#define S5P_FIMV_E_MIN_BIT_COUNT_V6 0xfa3c + +#define S5P_FIMV_E_METADATA_BUFFER_ADDR_V6 0xfa40 +#define S5P_FIMV_E_METADATA_BUFFER_SIZE_V6 0xfa44 +#define S5P_FIMV_E_STREAM_SIZE_V6 0xfa80 +#define S5P_FIMV_E_SLICE_TYPE_V6 0xfa84 +#define S5P_FIMV_E_PICTURE_COUNT_V6 0xfa88 +#define S5P_FIMV_E_RET_PICTURE_TAG_V6 0xfa8c +#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER_V6 0xfa90 + +#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6 0xfa94 +#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6 0xfa98 +#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6 0xfa9c +#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6 0xfaa0 +#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE_V6 0xfaa4 +#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE_V6 0xfaa8 + +#define S5P_FIMV_E_MPEG4_OPTIONS_V6 0xfb10 +#define S5P_FIMV_E_MPEG4_HEC_PERIOD_V6 0xfb14 +#define S5P_FIMV_E_ASPECT_RATIO_V6 0xfb50 +#define S5P_FIMV_E_EXTENDED_SAR_V6 0xfb54 + +#define S5P_FIMV_E_H264_OPTIONS_V6 0xfb58 +#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6 0xfb5c +#define S5P_FIMV_E_H264_LF_BETA_OFFSET_V6 0xfb60 +#define S5P_FIMV_E_H264_I_PERIOD_V6 0xfb64 + +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6 0xfb68 +#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6 0xfb6c +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6 0xfb70 +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6 0xfb74 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 0xfb78 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1_V6 0xfb7c +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2_V6 0xfb80 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3_V6 0xfb84 + +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 0xfb88 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1_V6 0xfb8c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2_V6 0xfb90 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3_V6 0xfb94 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4_V6 0xfb98 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5_V6 0xfb9c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6_V6 0xfba0 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7_V6 0xfba4 + +#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET_V6 0xfba8 +#define S5P_FIMV_E_H264_NUM_T_LAYER_V6 0xfbac + +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 0xfbb0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1_V6 0xfbb4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2_V6 0xfbb8 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3_V6 0xfbbc +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4_V6 0xfbc0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5_V6 0xfbc4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6_V6 0xfbc8 + +#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6 0xfc4c +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE_V6 0 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TOP_BOTTOM_V6 1 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TEMPORAL_V6 2 + +#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1_V6 0xfd40 +#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1_V6 0xfd44 +#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1_V6 0xfd48 +#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1_V6 0xfd4c +#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50 +#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80 + +/* Codec numbers */ +#define S5P_FIMV_CODEC_NONE_V6 -1 + + +#define S5P_FIMV_CODEC_H264_DEC_V6 0 +#define S5P_FIMV_CODEC_H264_MVC_DEC_V6 1 + +#define S5P_FIMV_CODEC_MPEG4_DEC_V6 3 +#define S5P_FIMV_CODEC_FIMV1_DEC_V6 4 +#define S5P_FIMV_CODEC_FIMV2_DEC_V6 5 +#define S5P_FIMV_CODEC_FIMV3_DEC_V6 6 +#define S5P_FIMV_CODEC_FIMV4_DEC_V6 7 +#define S5P_FIMV_CODEC_H263_DEC_V6 8 +#define S5P_FIMV_CODEC_VC1RCV_DEC_V6 9 +#define S5P_FIMV_CODEC_VC1_DEC_V6 10 +/* FIXME: Add 11~12 */ +#define S5P_FIMV_CODEC_MPEG2_DEC_V6 13 +#define S5P_FIMV_CODEC_VP8_DEC_V6 14 +/* FIXME: Add 15~16 */ +#define S5P_FIMV_CODEC_H264_ENC_V6 20 +#define S5P_FIMV_CODEC_H264_MVC_ENC_V6 21 + +#define S5P_FIMV_CODEC_MPEG4_ENC_V6 23 +#define S5P_FIMV_CODEC_H263_ENC_V6 24 + +#define S5P_FIMV_NV12M_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_VALIGN_V6 16 + +#define S5P_FIMV_TMV_BUFFER_ALIGN_V6 16 +#define S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_ME_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6 256 + +#define S5P_FIMV_LUMA_MB_TO_PIXEL_V6 256 +#define S5P_FIMV_CHROMA_MB_TO_PIXEL_V6 128 +#define S5P_FIMV_NUM_TMV_BUFFERS_V6 2 + +#define S5P_FIMV_MAX_FRAME_SIZE_V6 (2 * SZ_1M) +#define S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6 16 +#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16 + +/* Buffer size requirements defined by hardware */ +#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 1) * 8) +#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \ + ((DIV_ROUND_UP(imw, 64) * DIV_ROUND_UP(imh, 64) * 256) + \ + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \ + ((w) * ((h) * 64 + 144) + (2048/16 * (h) * 64) + \ + (2048/16 * 256 + 8320)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ + (2096 * ((w) + (h) + 1)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ + ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ + (((w) * 64) + (((w) + 1) * 16) + (4096 * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(w, h) \ + (((w) * 16) + (((w) + 1) * 16)) + +/* MFC Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V6 (28 * SZ_1K) /* 28KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V6 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V6 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V6 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ + +/* MFCv6 variant defines */ +#define MAX_FW_SIZE_V6 (SZ_1M) /* 1MB */ +#define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V6 0x61 +#define MFC_NUM_PORTS_V6 1 + +#endif /* _REGS_FIMV_V6_H */ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index a19bece41ba9..9319e93599ae 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -12,6 +12,9 @@ #ifndef _REGS_FIMV_H #define _REGS_FIMV_H +#include <linux/kernel.h> +#include <linux/sizes.h> + #define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) #define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) @@ -144,6 +147,7 @@ #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 +#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ @@ -213,6 +217,7 @@ #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 /* Decode frame address */ #define S5P_FIMV_DECODE_Y_ADR 0x2024 @@ -377,6 +382,16 @@ #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 #define S5P_FIMV_R2H_CMD_ERR_RET 32 +/* Dummy definition for MFCv6 compatibilty */ +#define S5P_FIMV_CODEC_H264_MVC_DEC -1 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 +#define S5P_FIMV_MFC_RESET -1 +#define S5P_FIMV_RISC_ON -1 +#define S5P_FIMV_RISC_BASE_ADDRESS -1 +#define S5P_FIMV_CODEC_VP8_DEC -1 +#define S5P_FIMV_REG_CLEAR_BEGIN 0 +#define S5P_FIMV_REG_CLEAR_COUNT 0 + /* Error handling defines */ #define S5P_FIMV_ERR_WARNINGS_START 145 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF @@ -414,5 +429,31 @@ #define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 #define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C #define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 +#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2 + +/* Offset used by the hardware to store addresses */ +#define MFC_OFFSET_SHIFT 11 + +#define FIRMWARE_ALIGN (128 * SZ_1K) /* 128KB */ +#define MFC_H264_CTX_BUF_SIZE (600 * SZ_1K) /* 600KB per H264 instance */ +#define MFC_CTX_BUF_SIZE (10 * SZ_1K) /* 10KB per instance */ +#define DESC_BUF_SIZE (128 * SZ_1K) /* 128KB for DESC buffer */ +#define SHARED_BUF_SIZE (8 * SZ_1K) /* 8KB for shared buffer */ + +#define DEF_CPB_SIZE (256 * SZ_1K) /* 256KB */ +#define MAX_CPB_SIZE (4 * SZ_1M) /* 4MB */ +#define MAX_FW_SIZE (384 * SZ_1K) + +#define MFC_VERSION 0x51 +#define MFC_NUM_PORTS 2 + +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C +#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 +#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 + +/* Values for resolution change in display status */ +#define S5P_FIMV_RES_INCREASE 1 +#define S5P_FIMV_RES_DECREASE 2 #endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 5587ef15ca4f..130f4ac8649e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,15 +22,15 @@ #include <media/v4l2-event.h> #include <linux/workqueue.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" +#include "s5p_mfc_common.h" #include "s5p_mfc_ctrl.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" #define S5P_MFC_NAME "s5p-mfc" #define S5P_MFC_DEC_NAME "s5p-mfc-dec" @@ -149,10 +149,12 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) if (!ctx) continue; ctx->state = MFCINST_ERROR; - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); clear_work_bit(ctx); - wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0); + wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); } clear_bit(0, &dev->hw_lock); spin_unlock_irqrestore(&dev->irqlock, flags); @@ -199,6 +201,7 @@ static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_buf *dst_buf; + struct s5p_mfc_dev *dev = ctx->dev; ctx->state = MFCINST_FINISHED; ctx->sequence++; @@ -213,8 +216,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; @@ -228,8 +231,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf, *src_buf; - size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dec_y_addr; + unsigned int frame_type; + + dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); /* Copy timestamp / timecode from decoded src to dst and set appropraite flags */ @@ -265,10 +271,13 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *dst_buf; - size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dspl_y_addr; + unsigned int frame_type; unsigned int index; + dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + /* If frame is same as previous then skip and do not dequeue */ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { if (!ctx->after_packed_pb) @@ -285,8 +294,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) list_del(&dst_buf->list); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == - s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) + if (s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_bot, ctx)) dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = @@ -317,21 +328,23 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, unsigned int index; - dst_frame_status = s5p_mfc_get_dspl_status() + dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - res_change = s5p_mfc_get_dspl_status() - & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; + res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) + >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; mfc_debug(2, "Frame Status: %x\n", dst_frame_status); if (ctx->state == MFCINST_RES_CHANGE_INIT) ctx->state = MFCINST_RES_CHANGE_FLUSH; - if (res_change) { + if (res_change == S5P_FIMV_RES_INCREASE || + res_change == S5P_FIMV_RES_DECREASE) { ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } if (ctx->dpb_flush_flag) @@ -365,9 +378,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, && !list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - ctx->consumed_stream += s5p_mfc_get_consumed_stream(); - if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && - s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME + ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, + get_consumed_stream, dev); + if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && + s5p_mfc_hw_call(dev->mfc_ops, + get_dec_frame_type, dev) == + S5P_FIMV_DECODE_FRAME_P_FRAME && ctx->consumed_stream + STUFF_BYTE < src_buf->b->v4l2_planes[0].bytesused) { /* Run MFC again on the same buffer */ @@ -379,7 +395,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, ctx->consumed_stream = 0; list_del(&src_buf->list); ctx->src_queue_cnt--; - if (s5p_mfc_err_dec(err) > 0) + if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR); else vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); @@ -390,12 +406,12 @@ leave_handle_frame: if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->dpb_count) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ @@ -412,7 +428,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, dev = ctx->dev; mfc_err("Interrupt Error: %08x\n", err); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); /* Error recovery is dependent on the state of context */ @@ -441,9 +457,11 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, ctx->state = MFCINST_ERROR; /* Mark all dst buffers as having an error */ spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); /* Mark all src buffers as having an error */ - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); spin_unlock_irqrestore(&dev->irqlock, flags); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -461,7 +479,6 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) { struct s5p_mfc_dev *dev; - unsigned int guard_width, guard_height; if (ctx == NULL) return; @@ -470,55 +487,44 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, if (ctx->c_ops->post_seq_start(ctx)) mfc_err("post_seq_start() failed\n"); } else { - ctx->img_width = s5p_mfc_get_img_width(); - ctx->img_height = s5p_mfc_get_img_height(); - - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->buf_height = ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, " - "buffer dimensions: %dx%d\n", ctx->img_width, - ctx->img_height, ctx->buf_width, - ctx->buf_height); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - ctx->luma_size = ALIGN(ctx->buf_width * - ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->chroma_size = ALIGN(ctx->buf_width * - ALIGN((ctx->img_height >> 1), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = ALIGN(ctx->buf_width * - ALIGN((ctx->buf_height >> 2), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 24, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN(ctx->img_height + 16, - S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(guard_width * - guard_height, S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = 0; - } - ctx->dpb_count = s5p_mfc_get_dpb_count(); + ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width, + dev); + ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, + dev); + + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); + + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, + dev); + ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, + dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else ctx->state = MFCINST_HEAD_PARSED; + + if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && + !list_empty(&ctx->src_queue)) { + struct s5p_mfc_buf *src_buf; + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, + dev) < + src_buf->b->v4l2_planes[0].bytesused) + ctx->head_processed = 0; + else + ctx->head_processed = 1; + } else { + ctx->head_processed = 1; + } } - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -533,14 +539,14 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (ctx == NULL) return; dev = ctx->dev; - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; clear_work_bit(ctx); if (err == 0) { ctx->state = MFCINST_RUNNING; - if (!ctx->dpb_flush_flag) { + if (!ctx->dpb_flush_flag && ctx->head_processed) { spin_lock_irqsave(&dev->irqlock, flags); if (!list_empty(&ctx->src_queue)) { src_buf = list_entry(ctx->src_queue.next, @@ -560,7 +566,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -602,7 +608,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -618,81 +624,83 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) atomic_set(&dev->watchdog_cnt, 0); ctx = dev->ctx[dev->curr_ctx]; /* Get the reason of interrupt and the error code */ - reason = s5p_mfc_get_int_reason(); - err = s5p_mfc_get_int_err(); + reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); + err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev); mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); switch (reason) { - case S5P_FIMV_R2H_CMD_ERR_RET: + case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occured */ if (ctx->state == MFCINST_RUNNING && - s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START) + s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start) s5p_mfc_handle_frame(ctx, reason, err); else s5p_mfc_handle_error(ctx, reason, err); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: - case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + case S5P_MFC_R2H_CMD_SLICE_DONE_RET: + case S5P_MFC_R2H_CMD_FIELD_DONE_RET: + case S5P_MFC_R2H_CMD_FRAME_DONE_RET: if (ctx->c_ops->post_frame_start) { if (ctx->c_ops->post_frame_start(ctx)) mfc_err("post_frame_start() failed\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } break; - case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + case S5P_MFC_R2H_CMD_SEQ_DONE_RET: s5p_mfc_handle_seq_done(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: - ctx->inst_no = s5p_mfc_get_inst_no(); + case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: + ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); ctx->state = MFCINST_GOT_INST; clear_work_bit(ctx); wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: clear_work_bit(ctx); ctx->state = MFCINST_FREE; wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_SYS_INIT_RET: - case S5P_FIMV_R2H_CMD_FW_STATUS_RET: - case S5P_FIMV_R2H_CMD_SLEEP_RET: - case S5P_FIMV_R2H_CMD_WAKEUP_RET: + case S5P_MFC_R2H_CMD_SYS_INIT_RET: + case S5P_MFC_R2H_CMD_FW_STATUS_RET: + case S5P_MFC_R2H_CMD_SLEEP_RET: + case S5P_MFC_R2H_CMD_WAKEUP_RET: if (ctx) clear_work_bit(ctx); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: s5p_mfc_handle_init_buffers(ctx, reason, err); break; - case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: s5p_mfc_handle_stream_complete(ctx, reason, err); break; default: mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); } mfc_debug_leave(); return IRQ_HANDLED; irq_cleanup_hw: - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); ctx->int_type = reason; ctx->int_err = err; ctx->int_cond = 1; @@ -701,7 +709,7 @@ irq_cleanup_hw: s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); mfc_debug(2, "Exit via irq_cleanup_hw\n"); return IRQ_HANDLED; } @@ -749,6 +757,7 @@ static int s5p_mfc_open(struct file *file) if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { ctx->type = MFCINST_DECODER; ctx->c_ops = get_dec_codec_ops(); + s5p_mfc_dec_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_dec_ctrls_setup(ctx); if (ret) { @@ -761,6 +770,7 @@ static int s5p_mfc_open(struct file *file) /* only for encoder */ INIT_LIST_HEAD(&ctx->ref_queue); ctx->ref_queue_cnt = 0; + s5p_mfc_enc_init(ctx); /* Setup ctrl handler */ ret = s5p_mfc_enc_ctrls_setup(ctx); if (ret) { @@ -886,19 +896,20 @@ static int s5p_mfc_release(struct file *file) ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); /* Wait until instance is returned or timeout occured */ if (s5p_mfc_wait_for_done_ctx - (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { + (ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { s5p_mfc_clock_off(); mfc_err("Err returning instance\n"); } mfc_debug(2, "After free instance\n"); /* Free resources */ - s5p_mfc_release_codec_buffers(ctx); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); if (ctx->type == MFCINST_DECODER) - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, + ctx); ctx->inst_no = MFC_NO_INSTANCE_SET; } @@ -910,6 +921,7 @@ static int s5p_mfc_release(struct file *file) mfc_debug(2, "Last instance - release firmware\n"); /* reset <-> F/W release */ s5p_mfc_reset(dev); + s5p_mfc_deinit_hw(dev); s5p_mfc_release_firmware(dev); del_timer_sync(&dev->watchdog_timer); if (s5p_mfc_power_off() < 0) @@ -1041,6 +1053,9 @@ static int s5p_mfc_probe(struct platform_device *pdev) return -ENODEV; } + dev->variant = (struct s5p_mfc_variant *) + platform_get_device_id(pdev)->driver_data; + ret = s5p_mfc_init_pm(dev); if (ret < 0) { dev_err(&pdev->dev, "failed to get mfc clock source\n"); @@ -1076,6 +1091,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) ret = -ENODEV; goto err_res; } + dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", match_child); if (!dev->mem_dev_r) { @@ -1139,6 +1155,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->release = video_device_release, vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); dev->vfd_enc = vfd; ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); @@ -1160,6 +1177,10 @@ static int s5p_mfc_probe(struct platform_device *pdev) dev->watchdog_timer.data = (unsigned long)dev; dev->watchdog_timer.function = s5p_mfc_watchdog; + /* Initialize HW ops and commands based on MFC version */ + s5p_mfc_init_hw_ops(dev); + s5p_mfc_init_hw_cmds(dev); + pr_debug("%s--\n", __func__); return 0; @@ -1280,9 +1301,78 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { NULL) }; +struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { + .h264_ctx = MFC_H264_CTX_BUF_SIZE, + .non_h264_ctx = MFC_CTX_BUF_SIZE, + .dsc = DESC_BUF_SIZE, + .shm = SHARED_BUF_SIZE, +}; + +struct s5p_mfc_buf_size buf_size_v5 = { + .fw = MAX_FW_SIZE, + .cpb = MAX_CPB_SIZE, + .priv = &mfc_buf_size_v5, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v5 = { + .base = MFC_BASE_ALIGN_ORDER, +}; + +static struct s5p_mfc_variant mfc_drvdata_v5 = { + .version = MFC_VERSION, + .port_num = MFC_NUM_PORTS, + .buf_size = &buf_size_v5, + .buf_align = &mfc_buf_align_v5, + .mclk_name = "sclk_mfc", + .fw_name = "s5p-mfc.fw", +}; + +struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V6, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, +}; + +struct s5p_mfc_buf_size buf_size_v6 = { + .fw = MAX_FW_SIZE_V6, + .cpb = MAX_CPB_SIZE_V6, + .priv = &mfc_buf_size_v6, +}; + +struct s5p_mfc_buf_align mfc_buf_align_v6 = { + .base = 0, +}; + +static struct s5p_mfc_variant mfc_drvdata_v6 = { + .version = MFC_VERSION_V6, + .port_num = MFC_NUM_PORTS_V6, + .buf_size = &buf_size_v6, + .buf_align = &mfc_buf_align_v6, + .mclk_name = "aclk_333", + .fw_name = "s5p-mfc-v6.fw", +}; + +static struct platform_device_id mfc_driver_ids[] = { + { + .name = "s5p-mfc", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v5", + .driver_data = (unsigned long)&mfc_drvdata_v5, + }, { + .name = "s5p-mfc-v6", + .driver_data = (unsigned long)&mfc_drvdata_v6, + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, mfc_driver_ids); + static struct platform_driver s5p_mfc_driver = { - .probe = s5p_mfc_probe, - .remove = __devexit_p(s5p_mfc_remove), + .probe = s5p_mfc_probe, + .remove = __devexit_p(s5p_mfc_remove), + .id_table = mfc_driver_ids, .driver = { .name = S5P_MFC_NAME, .owner = THIS_MODULE, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c index 91a415573bd2..f0a41c95df84 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c @@ -1,7 +1,7 @@ /* * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -10,111 +10,20 @@ * (at your option) any later version. */ -#include "regs-mfc.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd_v6.h" -/* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) -{ - int cur_cmd; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while waiting for hardware\n"); - return -EIO; - } - cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); - } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); - mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); - mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); - mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); - mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); - /* Issue the command */ - mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); - return 0; -} - -/* Initialize the MFC */ -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_size; - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); -} - -/* Suspend the MFC hardware */ -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); -} +static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; -/* Wake up the MFC hardware */ -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) { - struct s5p_mfc_cmd_args h2r_args; + if (IS_MFCV6(dev)) + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); + else + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); + dev->mfc_cmds = s5p_mfc_cmds; } - - -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - /* Preparing decoding - getting instance number */ - mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->codec_mode; - h2r_args.arg[1] = 0; /* no crc & no pixelcache */ - h2r_args.arg[2] = ctx->ctx_ofs; - h2r_args.arg[3] = ctx->ctx_size; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to create a new instance\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - if (ctx->state == MFCINST_FREE) { - mfc_err("Instance already returned\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - /* Closing decoding instance */ - mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->inst_no; - ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to return an instance\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - return 0; -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h index 8b090d3723e7..282e6c780702 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h @@ -1,7 +1,7 @@ /* * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -21,10 +21,15 @@ struct s5p_mfc_cmd_args { unsigned int arg[MAX_H2R_ARG]; }; -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); +struct s5p_mfc_hw_cmds { + int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args); + int (*sys_init_cmd)(struct s5p_mfc_dev *dev); + int (*sleep_cmd)(struct s5p_mfc_dev *dev); + int (*wakeup_cmd)(struct s5p_mfc_dev *dev); + int (*open_inst_cmd)(struct s5p_mfc_ctx *ctx); + int (*close_inst_cmd)(struct s5p_mfc_ctx *ctx); +}; +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c new file mode 100644 index 000000000000..138778083c63 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -0,0 +1,166 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "regs-mfc.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" + +/* This function is used to send a command to the MFC */ +int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + int cur_cmd; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while waiting for hardware\n"); + return -EIO; + } + cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); + } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); + mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); + mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); + mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); + mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); + return 0; +} + +/* Initialize the MFC */ +int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = dev->fw_size; + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, + &h2r_args); +} + +/* Suspend the MFC hardware */ +int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); +} + +/* Wake up the MFC hardware */ +int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, + &h2r_args); +} + + +int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + /* Preparing decoding - getting instance number */ + mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; + break; + case S5P_MFC_CODEC_VC1_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; + break; + case S5P_MFC_CODEC_H263_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; + break; + case S5P_MFC_CODEC_H264_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; + break; + case S5P_MFC_CODEC_H263_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; + break; + default: + h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; + }; + h2r_args.arg[1] = 0; /* no crc & no pixelcache */ + h2r_args.arg[2] = ctx->ctx.ofs; + h2r_args.arg[3] = ctx->ctx.size; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to create a new instance\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + if (ctx->state == MFCINST_FREE) { + mfc_err("Instance already returned\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + /* Closing decoding instance */ + mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = ctx->inst_no; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to return an instance\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + return 0; +} + +/* Initialize cmd function pointers for MFC v5 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, + .sleep_cmd = s5p_mfc_sleep_cmd_v5, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) +{ + return &s5p_mfc_cmds_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h new file mode 100644 index 000000000000..6928a5514c1b --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h @@ -0,0 +1,20 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_V5_H_ +#define S5P_MFC_CMD_V5_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c new file mode 100644 index 000000000000..754bfbcb1c43 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -0,0 +1,156 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include "s5p_mfc_common.h" + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" + +int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + mfc_debug(2, "Issue the command: %d\n", cmd); + + /* Reset RISC2HOST command */ + mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); + + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); + + return 0; +} + +int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); + mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, + &h2r_args); +} + +int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, + &h2r_args); +} + +int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, + &h2r_args); +} + +/* Open a new instance and get its number */ +int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int codec_type; + + mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + codec_type = S5P_FIMV_CODEC_H264_DEC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_DEC: + codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; + break; + case S5P_MFC_CODEC_VC1_DEC: + codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; + break; + case S5P_MFC_CODEC_H263_DEC: + codec_type = S5P_FIMV_CODEC_H263_DEC_V6; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; + break; + case S5P_MFC_CODEC_VP8_DEC: + codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; + break; + case S5P_MFC_CODEC_H264_ENC: + codec_type = S5P_FIMV_CODEC_H264_ENC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_ENC: + codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; + break; + case S5P_MFC_CODEC_H263_ENC: + codec_type = S5P_FIMV_CODEC_H263_ENC_V6; + break; + default: + codec_type = S5P_FIMV_CODEC_NONE_V6; + }; + mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); + mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ + + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, + &h2r_args); +} + +/* Close instance */ +int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret = 0; + + dev->curr_ctx = ctx->num; + if (ctx->state != MFCINST_FREE) { + mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + ret = s5p_mfc_cmd_host2risc_v6(dev, + S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, + &h2r_args); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* Initialize cmd function pointers for MFC v6 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, + .sleep_cmd = s5p_mfc_sleep_cmd_v6, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) +{ + return &s5p_mfc_cmds_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h new file mode 100644 index 000000000000..b7a8e57837b5 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h @@ -0,0 +1,20 @@ +/* + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef S5P_MFC_CMD_V6_H_ +#define S5P_MFC_CMD_V6_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 519b0d66d8d1..f02e0497ca98 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -16,13 +16,14 @@ #ifndef S5P_MFC_COMMON_H_ #define S5P_MFC_COMMON_H_ -#include "regs-mfc.h" #include <linux/platform_device.h> #include <linux/videodev2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> +#include "regs-mfc.h" +#include "regs-mfc-v6.h" /* Definitions related to MFC memory */ @@ -30,17 +31,6 @@ * while mmaping */ #define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) -/* Offset used by the hardware to store addresses */ -#define MFC_OFFSET_SHIFT 11 - -#define FIRMWARE_ALIGN 0x20000 /* 128KB */ -#define MFC_H264_CTX_BUF_SIZE 0x96000 /* 600KB per H264 instance */ -#define MFC_CTX_BUF_SIZE 0x2800 /* 10KB per instance */ -#define DESC_BUF_SIZE 0x20000 /* 128KB for DESC buffer */ -#define SHARED_BUF_SIZE 0x2000 /* 8KB for shared buffer */ - -#define DEF_CPB_SIZE 0x40000 /* 512KB */ - #define MFC_BANK1_ALLOC_CTX 0 #define MFC_BANK2_ALLOC_CTX 1 @@ -74,7 +64,40 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 64 +#define MFC_MAX_CTRLS 70 + +#define S5P_MFC_CODEC_NONE -1 +#define S5P_MFC_CODEC_H264_DEC 0 +#define S5P_MFC_CODEC_H264_MVC_DEC 1 +#define S5P_MFC_CODEC_VC1_DEC 2 +#define S5P_MFC_CODEC_MPEG4_DEC 3 +#define S5P_MFC_CODEC_MPEG2_DEC 4 +#define S5P_MFC_CODEC_H263_DEC 5 +#define S5P_MFC_CODEC_VC1RCV_DEC 6 +#define S5P_MFC_CODEC_VP8_DEC 7 + +#define S5P_MFC_CODEC_H264_ENC 20 +#define S5P_MFC_CODEC_H264_MVC_ENC 21 +#define S5P_MFC_CODEC_MPEG4_ENC 22 +#define S5P_MFC_CODEC_H263_ENC 23 + +#define S5P_MFC_R2H_CMD_EMPTY 0 +#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 +#define S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET 2 +#define S5P_MFC_R2H_CMD_SEQ_DONE_RET 3 +#define S5P_MFC_R2H_CMD_INIT_BUFFERS_RET 4 +#define S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET 6 +#define S5P_MFC_R2H_CMD_SLEEP_RET 7 +#define S5P_MFC_R2H_CMD_WAKEUP_RET 8 +#define S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET 9 +#define S5P_MFC_R2H_CMD_DPB_FLUSH_RET 10 +#define S5P_MFC_R2H_CMD_NAL_ABORT_RET 11 +#define S5P_MFC_R2H_CMD_FW_STATUS_RET 12 +#define S5P_MFC_R2H_CMD_FRAME_DONE_RET 13 +#define S5P_MFC_R2H_CMD_FIELD_DONE_RET 14 +#define S5P_MFC_R2H_CMD_SLICE_DONE_RET 15 +#define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 +#define S5P_MFC_R2H_CMD_ERR_RET 32 #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ @@ -177,6 +200,58 @@ struct s5p_mfc_pm { struct device *device; }; +struct s5p_mfc_buf_size_v5 { + unsigned int h264_ctx; + unsigned int non_h264_ctx; + unsigned int dsc; + unsigned int shm; +}; + +struct s5p_mfc_buf_size_v6 { + unsigned int dev_ctx; + unsigned int h264_dec_ctx; + unsigned int other_dec_ctx; + unsigned int h264_enc_ctx; + unsigned int other_enc_ctx; +}; + +struct s5p_mfc_buf_size { + unsigned int fw; + unsigned int cpb; + void *priv; +}; + +struct s5p_mfc_buf_align { + unsigned int base; +}; + +struct s5p_mfc_variant { + unsigned int version; + unsigned int port_num; + struct s5p_mfc_buf_size *buf_size; + struct s5p_mfc_buf_align *buf_align; + char *mclk_name; + char *fw_name; +}; + +/** + * struct s5p_mfc_priv_buf - represents internal used buffer + * @alloc: allocation-specific context for each buffer + * (videobuf2 allocator) + * @ofs: offset of each buffer, will be used for MFC + * @virt: kernel virtual address, only valid when the + * buffer accessed by driver + * @dma: DMA address, only valid when kernel DMA API used + * @size: size of the buffer + */ +struct s5p_mfc_priv_buf { + void *alloc; + unsigned long ofs; + void *virt; + dma_addr_t dma; + size_t size; +}; + /** * struct s5p_mfc_dev - The struct containing driver internal parameters. * @@ -191,6 +266,7 @@ struct s5p_mfc_pm { * @dec_ctrl_handler: control framework handler for decoding * @enc_ctrl_handler: control framework handler for encoding * @pm: power management control + * @variant: MFC hardware variant information * @num_inst: couter of active MFC instances * @irqlock: lock for operations on videobuf2 queues * @condlock: lock for changing/checking if a context is ready to be @@ -212,6 +288,10 @@ struct s5p_mfc_pm { * @watchdog_work: worker for the watchdog * @alloc_ctx: videobuf2 allocator contexts for two memory banks * @enter_suspend: flag set when entering suspend + * @ctx_buf: common context memory (MFCv6) + * @warn_start: hardware error code from which warnings start + * @mfc_ops: ops structure holding HW operation function pointers + * @mfc_cmds: cmd structure holding HW commands function pointers * */ struct s5p_mfc_dev { @@ -226,6 +306,7 @@ struct s5p_mfc_dev { struct v4l2_ctrl_handler dec_ctrl_handler; struct v4l2_ctrl_handler enc_ctrl_handler; struct s5p_mfc_pm pm; + struct s5p_mfc_variant *variant; int num_inst; spinlock_t irqlock; /* lock when operating on videobuf2 queues */ spinlock_t condlock; /* lock when changing/checking if a context is @@ -248,6 +329,11 @@ struct s5p_mfc_dev { struct work_struct watchdog_work; void *alloc_ctx[2]; unsigned long enter_suspend; + + struct s5p_mfc_priv_buf ctx_buf; + int warn_start; + struct s5p_mfc_hw_ops *mfc_ops; + struct s5p_mfc_hw_cmds *mfc_cmds; }; /** @@ -262,7 +348,6 @@ struct s5p_mfc_h264_enc_params { u8 max_ref_pic; u8 num_ref_pic_4p; int _8x8_transform; - int rc_mb; int rc_mb_dark; int rc_mb_smooth; int rc_mb_static; @@ -281,6 +366,23 @@ struct s5p_mfc_h264_enc_params { enum v4l2_mpeg_video_h264_level level_v4l2; int level; u16 cpb_size; + int interlace; + u8 hier_qp; + u8 hier_qp_type; + u8 hier_qp_layer; + u8 hier_qp_layer_qp[7]; + u8 sei_frame_packing; + u8 sei_fp_curr_frame_0; + u8 sei_fp_arrangement_type; + + u8 fmo; + u8 fmo_map_type; + u8 fmo_slice_grp; + u8 fmo_chg_dir; + u32 fmo_chg_rate; + u32 fmo_run_len[4]; + u8 aso; + u32 aso_slice_order[8]; }; /** @@ -319,9 +421,11 @@ struct s5p_mfc_enc_params { u8 pad_cb; u8 pad_cr; int rc_frame; + int rc_mb; u32 rc_bitrate; u16 rc_reaction_coeff; u16 vbv_size; + u32 vbv_delay; enum v4l2_mpeg_video_header_mode seq_hdr_mode; enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; @@ -330,7 +434,6 @@ struct s5p_mfc_enc_params { u8 num_b_frame; u32 rc_framerate_num; u32 rc_framerate_denom; - int interlace; union { struct s5p_mfc_h264_enc_params h264; @@ -388,6 +491,8 @@ struct s5p_mfc_codec_ops { * decoding buffer * @dpb_flush_flag: flag used to indicate that a DPB buffers are being * flushed + * @head_processed: flag mentioning whether the header data is processed + * completely or not * @bank1_buf: handle to memory allocated for temporary buffers from * memory bank 1 * @bank1_phys: address of the temporary buffers from memory bank 1 @@ -412,19 +517,20 @@ struct s5p_mfc_codec_ops { * @display_delay_enable: display delay for H264 enable flag * @after_packed_pb: flag used to track buffer when stream is in * Packed PB format + * @sei_fp_parse: enable/disable parsing of frame packing SEI information * @dpb_count: count of the DPB buffers required by MFC hw * @total_dpb_count: count of DPB buffers with additional buffers * requested by the application - * @ctx_buf: handle to the memory associated with this context - * @ctx_phys: address of the memory associated with this context - * @ctx_size: size of the memory associated with this context - * @desc_buf: description buffer for decoding handle - * @desc_phys: description buffer for decoding address - * @shm_alloc: handle for the shared memory buffer - * @shm: virtual address for the shared memory buffer - * @shm_ofs: address offset for shared memory + * @ctx: context buffer information + * @dsc: descriptor buffer information + * @shm: shared memory buffer information + * @mv_count: number of MV buffers allocated for decoding * @enc_params: encoding parameters for MFC * @enc_dst_buf_size: size of the buffers for encoder output + * @luma_dpb_size: dpb buffer size for luma + * @chroma_dpb_size: dpb buffer size for chroma + * @me_buffer_size: size of the motion estimation buffer + * @tmv_buffer_size: size of temporal predictor motion vector buffer * @frame_type: used to force the type of the next encoded frame * @ref_queue: list of the reference buffers for encoding * @ref_queue_cnt: number of the buffers in the reference list @@ -473,6 +579,7 @@ struct s5p_mfc_ctx { unsigned long consumed_stream; unsigned int dpb_flush_flag; + unsigned int head_processed; /* Buffers */ void *bank1_buf; @@ -502,37 +609,41 @@ struct s5p_mfc_ctx { int display_delay; int display_delay_enable; int after_packed_pb; + int sei_fp_parse; int dpb_count; int total_dpb_count; - + int mv_count; /* Buffers */ - void *ctx_buf; - size_t ctx_phys; - size_t ctx_ofs; - size_t ctx_size; - - void *desc_buf; - size_t desc_phys; - - - void *shm_alloc; - void *shm; - size_t shm_ofs; + struct s5p_mfc_priv_buf ctx; + struct s5p_mfc_priv_buf dsc; + struct s5p_mfc_priv_buf shm; struct s5p_mfc_enc_params enc_params; size_t enc_dst_buf_size; + size_t luma_dpb_size; + size_t chroma_dpb_size; + size_t me_buffer_size; + size_t tmv_buffer_size; enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; struct list_head ref_queue; unsigned int ref_queue_cnt; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + union { + unsigned int mb; + unsigned int bits; + } slice_size; + struct s5p_mfc_codec_ops *c_ops; struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; struct v4l2_ctrl_handler ctrl_handler; + unsigned int frame_tag; + size_t scratch_buf_size; }; /* @@ -565,6 +676,9 @@ struct mfc_control { __u8 is_volatile; }; +/* Macro for making hardware specific calls */ +#define s5p_mfc_hw_call(f, op, args...) \ + ((f && f->op) ? f->op(args) : -ENODEV) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ @@ -575,4 +689,9 @@ void set_work_bit(struct s5p_mfc_ctx *ctx); void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ + (dev->variant->port_num ? 1 : 0) : 0) : 0) +#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) +#define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0) + #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 0deba6bc687c..585b7b0ed8ec 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -15,11 +15,11 @@ #include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/sched.h> -#include "regs-mfc.h" #include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" static void *s5p_mfc_bitproc_buf; @@ -37,13 +37,19 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; } - dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); + dev->fw_size = dev->variant->buf_size->fw; + if (fw_blob->size > dev->fw_size) { + mfc_err("MFC firmware is too big to be loaded\n"); + release_firmware(fw_blob); + return -ENOMEM; + } if (s5p_mfc_bitproc_buf) { mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); release_firmware(fw_blob); @@ -77,32 +83,37 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) return -EIO; } dev->bank1 = s5p_mfc_bitproc_phys; - b_base = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BASE_ALIGN_ORDER); - if (IS_ERR(b_base)) { - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - mfc_err("Allocating bank2 base failed\n"); - release_firmware(fw_blob); - return -ENOMEM; - } - bank2_base_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); - vb2_dma_contig_memops.put(b_base); - if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { - mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); - vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); - s5p_mfc_bitproc_phys = 0; - s5p_mfc_bitproc_buf = NULL; - release_firmware(fw_blob); - return -EIO; + if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { + b_base = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], + 1 << MFC_BASE_ALIGN_ORDER); + if (IS_ERR(b_base)) { + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + mfc_err("Allocating bank2 base failed\n"); + release_firmware(fw_blob); + return -ENOMEM; + } + bank2_base_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); + vb2_dma_contig_memops.put(b_base); + if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { + mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); + vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); + s5p_mfc_bitproc_phys = 0; + s5p_mfc_bitproc_buf = NULL; + release_firmware(fw_blob); + return -EIO; + } + /* Valid buffers passed to MFC encoder with LAST_FRAME command + * should not have address of bank2 - MFC will treat it as a null frame. + * To avoid such situation we set bank2 address below the pool address. + */ + dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); + } else { + dev->bank2 = dev->bank1; } - /* Valid buffers passed to MFC encoder with LAST_FRAME command - * should not have address of bank2 - MFC will treat it as a null frame. - * To avoid such situation we set bank2 address below the pool address. - */ - dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); wmb(); release_firmware(fw_blob); @@ -119,8 +130,9 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) /* Firmare has to be present as a separate file or compiled * into kernel. */ mfc_debug_enter(); + err = request_firmware((const struct firmware **)&fw_blob, - "s5p-mfc.fw", dev->v4l2_dev.dev); + dev->variant->fw_name, dev->v4l2_dev.dev); if (err != 0) { mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); return -EINVAL; @@ -161,46 +173,81 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) { unsigned int mc_status; unsigned long timeout; + int i; mfc_debug_enter(); - /* Stop procedure */ - /* reset RISC */ - mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); - /* All reset except for MC */ - mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); - mdelay(10); - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* Check MC status */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while resetting MFC\n"); - return -EIO; - } - mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + if (IS_MFCV6(dev)) { + /* Reset IP */ + /* except RISC, reset */ + mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); + /* reset release */ + mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); + + /* Zero Initialization of MFC registers */ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); + + for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) + mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); - } while (mc_status & 0x3); + /* Reset */ + mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); + mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); + } else { + /* Stop procedure */ + /* reset RISC */ + mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); + /* All reset except for MC */ + mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); + mdelay(10); + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check MC status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC\n"); + return -EIO; + } + + mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + + } while (mc_status & 0x3); + + mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); + mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); + } - mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); - mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); mfc_debug_leave(); return 0; } static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) { - mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); - mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); - mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); + if (IS_MFCV6(dev)) { + mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); + mfc_debug(2, "Base Address : %08x\n", dev->bank1); + } else { + mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); + mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); + mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", + dev->bank1, dev->bank2); + } } static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) { - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); - mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + if (IS_MFCV6(dev)) { + /* Zero initialization should be done before RESET. + * Nothing to do here. */ + } else { + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + } } /* Initialize hardware */ @@ -228,9 +275,12 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); /* 3. Release reset signal to the RISC */ s5p_mfc_clean_dev_int_flags(dev); - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Will now wait for completion of firmware transfer\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -238,7 +288,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ - ret = s5p_mfc_sys_init_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); s5p_mfc_reset(dev); @@ -246,7 +296,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) return ret; } mfc_debug(2, "Ok, now will write a command to init the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -254,7 +304,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SYS_INIT_RET) { + S5P_MFC_R2H_CMD_SYS_INIT_RET) { /* Failure. */ mfc_err("Failed to init firmware - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -262,7 +312,11 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clock_off(); return -EIO; } - ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + if (IS_MFCV6(dev)) + ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); + else + ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); s5p_mfc_clock_off(); @@ -271,6 +325,17 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } +/* Deinitialize hardware */ +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) +{ + s5p_mfc_clock_on(); + + s5p_mfc_reset(dev); + s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); + + s5p_mfc_clock_off(); +} + int s5p_mfc_sleep(struct s5p_mfc_dev *dev) { int ret; @@ -278,19 +343,19 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_debug_enter(); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); - ret = s5p_mfc_sleep_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { mfc_err("Failed to sleep\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SLEEP_RET) { + S5P_MFC_R2H_CMD_SLEEP_RET) { /* Failure. */ mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, dev->int_type); @@ -320,22 +385,25 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Initialize firmware */ - ret = s5p_mfc_wakeup_cmd(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); return ret; } /* 4. Release reset signal to the RISC */ - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + if (IS_MFCV6(dev)) + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { mfc_err("Failed to load firmware\n"); return -EIO; } s5p_mfc_clock_off(); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_WAKEUP_RET) { + S5P_MFC_R2H_CMD_WAKEUP_RET) { /* Failure. */ mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, dev->int_type); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h index e1e0c544b6a2..90aa9b9886d5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h @@ -20,6 +20,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev); int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); int s5p_mfc_sleep(struct s5p_mfc_dev *dev); int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 6ee21bb71398..eb6a70b0f821 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -23,85 +23,114 @@ #include <linux/workqueue.h> #include <media/v4l2-ctrls.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_dec.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" + +#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 +#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16 static struct s5p_mfc_fmt formats[] = { { + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { .name = "4:2:0 2 Planes 64x32 Tiles", .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, + .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - }, + }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H264/MVC Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264_MVC, + .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG1, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG2 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG2, - .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG1, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG2 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG2, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "XviD Encoded Stream", - .fourcc = V4L2_PIX_FMT_XVID, - .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, - .codec_mode = S5P_FIMV_CODEC_VC1_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "XviD Encoded Stream", + .fourcc = V4L2_PIX_FMT_XVID, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, { - .name = "VC1 RCV Encoded Stream", - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, - .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, + .name = "VC1 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, + .codec_mode = S5P_MFC_CODEC_VC1_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + }, + { + .name = "VC1 RCV Encoded Stream", + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, + .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + }, + { + .name = "VP8 Encoded Stream", + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = S5P_MFC_CODEC_VP8_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, }, }; @@ -297,7 +326,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* If the MFC is parsing the header, * so wait until it is finished */ s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); } if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && @@ -342,21 +371,36 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) /* Try format */ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_fmt *fmt; - if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_err("This node supports decoding only\n"); - return -EINVAL; - } - fmt = find_format(f, MFC_FMT_DEC); - if (!fmt) { - mfc_err("Unsupported format\n"); - return -EINVAL; - } - if (fmt->type != MFC_FMT_DEC) { - mfc_err("\n"); - return -EINVAL; + mfc_debug(2, "Type is %d\n", f->type); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = find_format(f, MFC_FMT_DEC); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for destination.\n"); + return -EINVAL; + } + if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (!IS_MFCV6(dev) && + (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } } + return 0; } @@ -379,8 +423,29 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EBUSY; goto out; } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + ctx->dst_fmt = fmt; + mfc_debug_leave(); + return ret; + } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_err("Wrong type error for S_FMT : %d", f->type); + return -EINVAL; + } fmt = find_format(f, MFC_FMT_DEC); - if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { + if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { mfc_err("Unknown codec\n"); ret = -EINVAL; goto out; @@ -391,6 +456,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) ret = -EINVAL; goto out; } + if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } ctx->src_fmt = fmt; ctx->codec_mode = fmt->codec_mode; mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); @@ -476,7 +545,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, return -ENOMEM; } ctx->total_dpb_count = reqbufs->count; - ret = s5p_mfc_alloc_codec_buffers(ctx); + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); if (ret) { mfc_err("Failed to allocate decoding buffers\n"); reqbufs->count = 0; @@ -492,15 +561,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, reqbufs->count = 0; s5p_mfc_clock_on(); ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - s5p_mfc_release_codec_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, + ctx); s5p_mfc_clock_off(); return -ENOMEM; } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); + S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0); } return ret; } @@ -582,18 +652,22 @@ static int vidioc_streamon(struct file *file, void *priv, ctx->src_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; ctx->output_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); - s5p_mfc_alloc_dec_temp_buffers(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, + ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_dec_temp_buffers, + ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); - s5p_mfc_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_instance_buffer, ctx); + s5p_mfc_hw_call(dev->mfc_ops, + release_dec_desc_buffer, ctx); return -EIO; } mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); @@ -662,7 +736,7 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) /* Should wait for the header to be parsed */ s5p_mfc_clean_ctx_int_flags(ctx); s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); if (ctx->state >= MFCINST_HEAD_PARSED && ctx->state < MFCINST_ABORT) { ctrl->val = ctx->dpb_count; @@ -686,6 +760,7 @@ static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *cr) { struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; if (ctx->state != MFCINST_HEAD_PARSED && @@ -695,10 +770,10 @@ static int vidioc_g_crop(struct file *file, void *priv, return -EINVAL; } if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { - left = s5p_mfc_read_shm(ctx, CROP_INFO_H); + left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; - top = s5p_mfc_read_shm(ctx, CROP_INFO_V); + top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; cr->c.left = left; @@ -749,6 +824,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; /* Video output for decoding (source) * this can be set after getting an instance */ @@ -784,7 +860,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + + if (IS_MFCV6(dev)) + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + else + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && ctx->state == MFCINST_INIT) { @@ -876,7 +958,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -892,19 +974,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; s5p_mfc_wait_for_done_ctx(ctx, - S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); + S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); aborted = 1; } spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; ctx->dpb_flush_flag = 1; ctx->dec_dst_flag = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -944,7 +1028,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_dec_qops = { @@ -1028,3 +1112,13 @@ void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) ctx->ctrls[i] = NULL; } +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_DEC; + ctx->src_fmt = find_format(&f, MFC_FMT_DEC); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_DEC; + ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); + mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", + (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h index fdf1d99a9d15..d06a7cab5eb1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_dec_def_fmt(bool src); int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_DEC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 179e4db60b15..2af6d522f4ac 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -25,48 +25,64 @@ #include <linux/workqueue.h> #include <media/v4l2-ctrls.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_enc.h" #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12MT +#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 + static struct s5p_mfc_fmt formats[] = { { - .name = "4:2:0 2 Planes 64x32 Tiles", - .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes 16x16 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes 64x32 Tiles", + .fourcc = V4L2_PIX_FMT_NV12MT, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + }, + { + .name = "4:2:0 2 Planes Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "4:2:0 2 Planes", - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_FIMV_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, + .name = "4:2:0 2 Planes Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, }, { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_FIMV_CODEC_H264_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "H264 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "MPEG4 Encoded Stream", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, { - .name = "H263 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_FIMV_CODEC_H263_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, + .name = "H263 Encoded Stream", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, }, }; @@ -574,7 +590,8 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode a frame */ - if (ctx->state == MFCINST_RUNNING && + if ((ctx->state == MFCINST_RUNNING || + ctx->state == MFCINST_HEAD_PARSED) && ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) return 1; /* context is ready to encode remaining frames */ @@ -619,7 +636,8 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; } @@ -638,14 +656,23 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) list_del(&dst_mb->list); ctx->dst_queue_cnt--; vb2_set_plane_payload(dst_mb->b, 0, - s5p_mfc_get_enc_strm_size()); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev)); vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); spin_unlock_irqrestore(&dev->irqlock, flags); } - ctx->state = MFCINST_RUNNING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + if (IS_MFCV6(dev)) { + ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */ + } else { + ctx->state = MFCINST_RUNNING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } + + if (IS_MFCV6(dev)) + ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, + get_enc_dpb_count, dev); + return 0; } @@ -662,14 +689,16 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, src_y_addr, + src_c_addr); spin_unlock_irqrestore(&dev->irqlock, flags); spin_lock_irqsave(&dev->irqlock, flags); dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); spin_unlock_irqrestore(&dev->irqlock, flags); return 0; @@ -685,15 +714,16 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) unsigned int strm_size; unsigned long flags; - slice_type = s5p_mfc_get_enc_slice_type(); - strm_size = s5p_mfc_get_enc_strm_size(); + slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); + strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); mfc_debug(2, "Encoded slice type: %d", slice_type); mfc_debug(2, "Encoded stream size: %d", strm_size); mfc_debug(2, "Display order: %d", mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); spin_lock_irqsave(&dev->irqlock, flags); if (slice_type >= 0) { - s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr); + s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, + &enc_y_addr, &enc_c_addr); list_for_each_entry(mb_entry, &ctx->src_queue, list) { mb_y_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 0); mb_c_addr = vb2_dma_contig_plane_dma_addr(mb_entry->b, 1); @@ -939,15 +969,16 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) pix_fmt_mp->plane_fmt[0].bytesperline = 0; ctx->dst_bufs_cnt = 0; ctx->capture_state = QUEUE_FREE; - s5p_mfc_alloc_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); set_work_bit_irqsave(ctx); s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); if (s5p_mfc_wait_for_done_ctx(ctx, \ - S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) { + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 1)) { /* Error or timeout */ mfc_err("Error getting instance from hardware\n"); - s5p_mfc_release_instance_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, + ctx); ret = -EIO; goto out; } @@ -958,6 +989,17 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_err("failed to set output format\n"); return -EINVAL; } + + if (!IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } else if (IS_MFCV6(dev) && + (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { + mfc_err("Not supported format.\n"); + return -EINVAL; + } + if (fmt->num_planes != pix_fmt_mp->num_planes) { mfc_err("failed to set output format\n"); ret = -EINVAL; @@ -970,45 +1012,13 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", pix_fmt_mp->width, pix_fmt_mp->height, ctx->img_width, ctx->img_height); - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12M_LVALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12M_CVALIGN); - - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12M_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12M_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { - ctx->buf_width = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN); - ctx->luma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height - >> 1), S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(ctx->luma_size, - S5P_FIMV_NV12MT_SALIGN); - ctx->chroma_size = ALIGN(ctx->chroma_size, - S5P_FIMV_NV12MT_SALIGN); - - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - } + + s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + ctx->src_bufs_cnt = 0; ctx->output_state = QUEUE_FREE; } else { @@ -1023,6 +1033,7 @@ out: static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { + struct s5p_mfc_dev *dev = video_drvdata(file); struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; @@ -1042,12 +1053,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, return ret; } ctx->capture_state = QUEUE_BUFS_REQUESTED; - ret = s5p_mfc_alloc_codec_buffers(ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; + + if (!IS_MFCV6(dev)) { + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, + alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers\n"); + reqbufs->count = 0; + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } } } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (ctx->output_state != QUEUE_FREE) { @@ -1310,6 +1325,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264.profile = S5P_FIMV_ENC_PROFILE_H264_BASELINE; break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + if (IS_MFCV6(dev)) + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; + else + ret = -EINVAL; + break; default: ret = -EINVAL; } @@ -1349,7 +1371,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) p->codec.h264._8x8_transform = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - p->codec.h264.rc_mb = ctrl->val; + p->rc_mb = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: p->codec.h264.rc_frame_qp = ctrl->val; @@ -1500,7 +1522,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv, mfc_debug(2, "EOS: empty src queue, entering finishing state"); ctx->state = MFCINST_FINISHING; spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { mfc_debug(2, "EOS: marking last buffer of stream"); buf = list_entry(ctx->src_queue.prev, @@ -1583,6 +1605,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int psize[], void *allocators[]) { struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; if (ctx->state != MFCINST_GOT_INST) { mfc_err("inavlid state: %d\n", ctx->state); @@ -1611,8 +1634,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, *buf_count = MFC_MAX_BUFFERS; psize[0] = ctx->luma_size; psize[1] = ctx->chroma_size; - allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; - allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + if (IS_MFCV6(dev)) { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; + } else { + allocators[0] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + allocators[1] = + ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; + } } else { mfc_err("inavlid queue type: %d\n", vq->type); return -EINVAL; @@ -1715,7 +1747,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) /* If context is ready then dev = work->data;schedule it to run */ if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return 0; } @@ -1729,19 +1761,21 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q) ctx->state == MFCINST_RUNNING) && dev->curr_ctx == ctx->num && dev->hw_lock) { ctx->state = MFCINST_ABORT; - s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET, + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); } ctx->state = MFCINST_FINISHED; spin_lock_irqsave(&dev->irqlock, flags); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); INIT_LIST_HEAD(&ctx->dst_queue); ctx->dst_queue_cnt = 0; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { cleanup_ref_queue(ctx); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); INIT_LIST_HEAD(&ctx->src_queue); ctx->src_queue_cnt = 0; } @@ -1782,7 +1816,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) } if (s5p_mfc_ctx_ready(ctx)) set_work_bit_irqsave(ctx); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } static struct vb2_ops s5p_mfc_enc_qops = { @@ -1880,3 +1914,13 @@ void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) for (i = 0; i < NUM_CTRLS; i++) ctx->ctrls[i] = NULL; } + +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC; + ctx->src_fmt = find_format(&f, MFC_FMT_RAW); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC; + ctx->dst_fmt = find_format(&f, MFC_FMT_ENC); +} + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h index ca9fd66bd310..5118d46b3a9e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h @@ -19,5 +19,6 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); struct s5p_mfc_fmt *get_enc_def_fmt(bool src); int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); #endif /* S5P_MFC_ENC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c index 37860e299021..5b8f0e085e6d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c @@ -17,7 +17,6 @@ #include <linux/io.h> #include <linux/sched.h> #include <linux/wait.h> -#include "regs-mfc.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" #include "s5p_mfc_intr.h" @@ -28,7 +27,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) ret = wait_event_interruptible_timeout(dev->queue, (dev->int_cond && (dev->int_type == command - || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || dev->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); if (ret == 0) { mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", @@ -40,7 +39,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) } mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", dev->int_type, command); - if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (dev->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } @@ -60,12 +59,12 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, if (interrupt) { ret = wait_event_interruptible_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } else { ret = wait_event_timeout(ctx->queue, (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), msecs_to_jiffies(MFC_INT_TIMEOUT)); } if (ret == 0) { @@ -78,7 +77,7 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, } mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", ctx->int_type, command); - if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET) + if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) return 1; return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 767a51271dc2..6932e90d4065 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -1,10 +1,10 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.c + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.c * * Samsung MFC (Multi Function Codec - FIMV) driver * This file contains hw related functions. * - * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -12,1414 +12,20 @@ * published by the Free Software Foundation. */ -#include "regs-mfc.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_shm.h" -#include <asm/cacheflush.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <linux/err.h> -#include <linux/firmware.h> -#include <linux/io.h> -#include <linux/jiffies.h> -#include <linux/mm.h> -#include <linux/sched.h> +#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr_v6.h" -#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) -#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) +static struct s5p_mfc_hw_ops *s5p_mfc_ops; -/* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) { - void *desc_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - ctx->desc_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); - if (IS_ERR_VALUE((int)ctx->desc_buf)) { - ctx->desc_buf = NULL; - mfc_err("Allocating DESC buffer failed\n"); - return -ENOMEM; - } - ctx->desc_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); - BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); - if (desc_virt == NULL) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - mfc_err("Remapping DESC buffer failed\n"); - return -ENOMEM; - } - memset(desc_virt, 0, DESC_BUF_SIZE); - wmb(); - return 0; -} - -/* Release temporary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->desc_phys) { - vb2_dma_contig_memops.put(ctx->desc_buf); - ctx->desc_phys = 0; - ctx->desc_buf = NULL; - } -} - -/* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int enc_ref_y_size = 0; - unsigned int enc_ref_c_size = 0; - unsigned int guard_width, guard_height; - - if (ctx->type == MFCINST_DECODER) { - mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", - ctx->luma_size, ctx->chroma_size, ctx->mv_size); - mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); - } else if (ctx->type == MFCINST_ENCODER) { - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height >> 1, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, - S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "recon luma size: %d chroma size: %d\n", - enc_ref_y_size, enc_ref_c_size); + if (IS_MFCV6(dev)) { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; } else { - return -EINVAL; - } - /* Codecs have different memory requirements */ - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + - S5P_FIMV_DEC_VERT_NB_MV_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_STX_PARSER_SIZE + - S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_VC1RCV_DEC: - case S5P_FIMV_CODEC_VC1_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE + - 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - ctx->bank1_size = 0; - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H263_DEC: - ctx->bank1_size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2_size = 0; - break; - case S5P_FIMV_CODEC_H264_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_INTRAMD_SIZE + - S5P_FIMV_ENC_NBORINFO_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4) + - S5P_FIMV_ENC_INTRAPRED_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - case S5P_FIMV_CODEC_H263_ENC: - ctx->bank1_size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2_size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - default: - break; - } - /* Allocate only if memory from bank 1 is necessary */ - if (ctx->bank1_size > 0) { - ctx->bank1_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); - if (IS_ERR(ctx->bank1_buf)) { - ctx->bank1_buf = NULL; - printk(KERN_ERR - "Buf alloc for decoding failed (port A)\n"); - return -ENOMEM; - } - ctx->bank1_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); - BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - } - /* Allocate only if memory from bank 2 is necessary */ - if (ctx->bank2_size > 0) { - ctx->bank2_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); - if (IS_ERR(ctx->bank2_buf)) { - ctx->bank2_buf = NULL; - mfc_err("Buf alloc for decoding failed (port B)\n"); - return -ENOMEM; - } - ctx->bank2_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); - BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); - } - return 0; -} - -/* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) -{ - if (ctx->bank1_buf) { - vb2_dma_contig_memops.put(ctx->bank1_buf); - ctx->bank1_buf = NULL; - ctx->bank1_phys = 0; - ctx->bank1_size = 0; - } - if (ctx->bank2_buf) { - vb2_dma_contig_memops.put(ctx->bank2_buf); - ctx->bank2_buf = NULL; - ctx->bank2_phys = 0; - ctx->bank2_size = 0; + s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; } + dev->mfc_ops = s5p_mfc_ops; } - -/* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - void *context_virt; - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; - else - ctx->ctx_size = MFC_CTX_BUF_SIZE; - ctx->ctx_buf = vb2_dma_contig_memops.alloc( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); - if (IS_ERR(ctx->ctx_buf)) { - mfc_err("Allocating context buffer failed\n"); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - ctx->ctx_phys = s5p_mfc_mem_cookie( - dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); - BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); - context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); - if (context_virt == NULL) { - mfc_err("Remapping instance buffer failed\n"); - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - /* Zero content of the allocated memory */ - memset(context_virt, 0, ctx->ctx_size); - wmb(); - if (s5p_mfc_init_shm(ctx) < 0) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - return -ENOMEM; - } - return 0; -} - -/* Release instance buffer */ -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) -{ - if (ctx->ctx_buf) { - vb2_dma_contig_memops.put(ctx->ctx_buf); - ctx->ctx_phys = 0; - ctx->ctx_buf = NULL; - } - if (ctx->shm_alloc) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_alloc = NULL; - ctx->shm = NULL; - } -} - -/* Set registers for decoding temporary buffers */ -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); - mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); -} - -/* Set registers for shared buffer */ -static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); -} - -/* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, unsigned int buf_size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); - mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); - mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); - s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM); - return 0; -} - -/* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) -{ - unsigned int frame_size, i; - unsigned int frame_size_ch, frame_size_mv; - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - size_t buf_addr1, buf_addr2; - int buf_size1, buf_size2; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~S5P_FIMV_DPB_COUNT_MASK; - mfc_write(dev, ctx->total_dpb_count | dpb, - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - s5p_mfc_set_shared_buffer(ctx); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_DEC: - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_VERT_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; - break; - case S5P_FIMV_CODEC_MPEG4_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); - buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; - buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - break; - case S5P_FIMV_CODEC_H263_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - break; - case S5P_FIMV_CODEC_VC1_DEC: - case S5P_FIMV_CODEC_VC1RCV_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - break; - case S5P_FIMV_CODEC_MPEG2_DEC: - break; - default: - mfc_err("Unknown codec for decoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - break; - } - frame_size = ctx->luma_size; - frame_size_ch = ctx->chroma_size; - frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, - frame_size_mv); - for (i = 0; i < ctx->total_dpb_count; i++) { - /* Bank2 */ - mfc_debug(2, "Luma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.luma); - mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), - S5P_FIMV_DEC_LUMA_ADR + i * 4); - mfc_debug(2, "\tChroma %d: %x\n", i, - ctx->dst_bufs[i].cookie.raw.chroma); - mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), - S5P_FIMV_DEC_CHROMA_ADR + i * 4); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { - mfc_debug(2, "\tBuf2: %x, size: %d\n", - buf_addr2, buf_size2); - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_MV_ADR + i * 4); - buf_addr2 += frame_size_mv; - buf_size2 -= frame_size_mv; - } - } - mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); - mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", - buf_size1, buf_size2, ctx->total_dpb_count); - if (buf_size1 < 0 || buf_size2 < 0) { - mfc_debug(2, "Not enough memory has been allocated\n"); - return -ENOMEM; - } - s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); - s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) - s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE); - mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) - << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); - mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); - return 0; -} - -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); - mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); -} - -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) - << MFC_OFFSET_SHIFT); - *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) - << MFC_OFFSET_SHIFT); -} - -/* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - size_t buf_addr1, buf_addr2; - size_t buf_size1, buf_size2; - unsigned int enc_ref_y_size, enc_ref_c_size; - unsigned int guard_width, guard_height; - int i; - - buf_addr1 = ctx->bank1_phys; - buf_size1 = ctx->bank1_size; - buf_addr2 = ctx->bank2_phys; - buf_size2 = ctx->bank2_size; - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); - switch (ctx->codec_mode) { - case S5P_FIMV_CODEC_H264_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_UP_INTRA_MD_ADR); - buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; - buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_UP_INTRA_PRED_ADR); - buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; - buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_NBOR_INFO_ADR); - buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; - buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_MPEG4_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - case S5P_FIMV_CODEC_H263_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", - buf_size1, buf_size2); - break; - default: - mfc_err("Unknown codec set for encoding: %d\n", - ctx->codec_mode); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - unsigned int reg; - unsigned int shm; - - /* width */ - mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); - /* height */ - mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); - /* pictype : enable, IDR period */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - reg |= (1 << 18); - reg &= ~(0xFFFF); - reg |= p->gop_size; - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); - /* multi-slice control */ - /* multi-slice MB number or bit size */ - mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { - mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { - mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); - } - /* cyclic intra refresh */ - mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - /* padding control & value */ - reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); - if (p->pad) { - /** enable */ - reg |= (1 << 31); - /** cr value */ - reg &= ~(0xFF << 16); - reg |= (p->pad_cr << 16); - /** cb value */ - reg &= ~(0xFF << 8); - reg |= (p->pad_cb << 8); - /** y value */ - reg &= ~(0xFF); - reg |= (p->pad_luma); - } else { - /** disable & all value clear */ - reg = 0; - } - mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /** frame-level rate control */ - reg &= ~(0x1 << 9); - reg |= (p->rc_frame << 9); - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* bit rate */ - if (p->rc_frame) - mfc_write(dev, p->rc_bitrate, - S5P_FIMV_ENC_RC_BIT_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); - /* reaction coefficient */ - if (p->rc_frame) - mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* seq header ctrl */ - shm &= ~(0x1 << 3); - shm |= (p->seq_hdr_mode << 3); - /* frame skip mode */ - shm &= ~(0x3 << 1); - shm |= (p->frame_skip_mode << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - /* fixed target bit */ - s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); - return 0; -} - -static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_264->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_264->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* interlace */ - mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); - /* height */ - if (p->interlace) - mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); - /* loopfilter ctrl */ - mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); - /* loopfilter alpha offset */ - if (p_264->loop_filter_alpha < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_alpha) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_alpha & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); - /* loopfilter beta offset */ - if (p_264->loop_filter_beta < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_beta) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_beta & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); - /* entropy coding mode */ - if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) - mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); - /* number of ref. picture */ - reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* num of ref. pictures of P */ - reg &= ~(0x3 << 5); - reg |= (p_264->num_ref_pic_4p << 5); - /* max number of ref. pictures */ - reg &= ~(0x1F); - reg |= p_264->max_ref_pic; - mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* 8x8 transform enable */ - mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= (p_264->rc_mb << 8); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_264->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_264->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_264->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* macroblock adaptive scaling features */ - if (p_264->rc_mb) { - reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); - /* dark region */ - reg &= ~(0x1 << 3); - reg |= (p_264->rc_mb_dark << 3); - /* smooth region */ - reg &= ~(0x1 << 2); - reg |= (p_264->rc_mb_smooth << 2); - /* static region */ - reg &= ~(0x1 << 1); - reg |= (p_264->rc_mb_static << 1); - /* high activity region */ - reg &= ~(0x1); - reg |= p_264->rc_mb_activity; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); - } - if (!p->rc_frame && - !p_264->rc_mb) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_264->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* AR VUI control */ - shm &= ~(0x1 << 15); - shm |= (p_264->vui_sar << 1); - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - if (p_264->vui_sar) { - /* aspect ration IDC */ - shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC); - shm &= ~(0xFF); - shm |= p_264->vui_sar_idc; - s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); - if (p_264->vui_sar_idc == 0xFF) { - /* sample AR info */ - shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR); - shm &= ~(0xFFFFFFFF); - shm |= p_264->vui_ext_sar_width << 16; - shm |= p_264->vui_ext_sar_height; - s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR); - } - } - /* intra picture period for H.264 */ - shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD); - /* control */ - shm &= ~(0x1 << 16); - shm |= (p_264->open_gop << 16); - /* value */ - if (p_264->open_gop) { - shm &= ~(0xFFFF); - shm |= p_264->open_gop_size; - } - s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p_264->cpb_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - unsigned int framerate; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_mpeg4->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_mpeg4->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* quarter_pixel */ - mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame) { - if (p->rc_framerate_denom > 0) { - framerate = p->rc_framerate_num * 1000 / - p->rc_framerate_denom; - mfc_write(dev, framerate, - S5P_FIMV_ENC_RC_FRAME_RATE); - shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING); - shm &= ~(0xFFFFFFFF); - shm |= (1 << 31); - shm |= ((p->rc_framerate_num & 0x7FFF) << 16); - shm |= (p->rc_framerate_denom & 0xFFFF); - s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING); - } - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - } - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_mpeg4->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= (p_h263->rc_p_frame_qp & 0x3F); - s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_h263->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -/* Initialize decoding */ -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_shared_buffer(ctx); - /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) - mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); - else - mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); - mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << - S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << - S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & - S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - mfc_write(dev, - ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - - if (flush) - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( - S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - else - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); -} - -/* Decode a single frame */ -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); - s5p_mfc_set_shared_buffer(ctx); - s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); - /* Issue different commands to instance basing on whether it - * is the last frame or not. */ - switch (last_frame) { - case MFC_DEC_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_LAST_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_RES_CHANGE: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & - S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - break; - } - mfc_debug(2, "Decoding a usual frame\n"); - return 0; -} - -int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) - s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) - s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) - s5p_mfc_set_enc_params_h263(ctx); - else { - mfc_err("Unknown codec for encoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - } - s5p_mfc_set_shared_buffer(ctx); - mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | - (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Encode a single frame */ -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int cmd; - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - s5p_mfc_set_shared_buffer(ctx); - - if (ctx->state == MFCINST_FINISHING) - cmd = S5P_FIMV_CH_LAST_FRAME; - else - cmd = S5P_FIMV_CH_FRAME_START; - mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - - return 0; -} - -static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int new_ctx; - int cnt; - - spin_lock_irqsave(&dev->condlock, flags); - new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; - cnt = 0; - while (!test_bit(new_ctx, &dev->ctx_work_bits)) { - new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; - if (++cnt > MFC_NUM_CONTEXTS) { - /* No contexts to run */ - spin_unlock_irqrestore(&dev->condlock, flags); - return -EAGAIN; - } - } - spin_unlock_irqrestore(&dev->condlock, flags); - return new_ctx; -} - -static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); -} - -static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - unsigned long flags; - unsigned int index; - - spin_lock_irqsave(&dev->irqlock, flags); - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), ctx->consumed_stream, - temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - index = temp_vb->b->v4l2_buf.index; - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - if (temp_vb->b->v4l2_planes[0].bytesused == 0) { - last_frame = MFC_DEC_LAST_FRAME; - mfc_debug(2, "Setting ctx->state to FINISHING\n"); - ctx->state = MFCINST_FINISHING; - } - s5p_mfc_decode_one_frame(ctx, last_frame); - return 0; -} - -static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - unsigned int dst_size; - - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { - mfc_debug(2, "no src buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->dst_queue)) { - mfc_debug(2, "no dst buffers\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EAGAIN; - } - if (list_empty(&ctx->src_queue)) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, dev->bank2); - src_mb = NULL; - } else { - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - src_mb->flags |= MFC_BUF_FLAG_USED; - if (src_mb->b->v4l2_planes[0].bytesused == 0) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer(ctx, dev->bank2, - dev->bank2); - ctx->state = MFCINST_FINISHING; - } else { - src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 0); - src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, - 1); - s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, - src_c_addr); - if (src_mb->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - } - } - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_mb->flags |= MFC_BUF_FLAG_USED; - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - mfc_debug(2, "encoding buffer with index=%d state=%d", - src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); - s5p_mfc_encode_one_frame(ctx); - return 0; -} - -static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - - /* Initializing decoding - parsing header */ - spin_lock_irqsave(&dev->irqlock, flags); - mfc_debug(2, "Preparing to init decoding\n"); - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - s5p_mfc_set_dec_desc_buffer(ctx); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_decode(ctx); -} - -static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - s5p_mfc_set_enc_ref_buffer(ctx); - spin_lock_irqsave(&dev->irqlock, flags); - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); - dst_size = vb2_plane_size(dst_mb->b, 0); - s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_init_encode(ctx); -} - -static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *temp_vb; - int ret; - - /* - * Header was parsed now starting processing - * First set the output frame buffers - */ - if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destionation buffers were " - "mmaped\nMFC requires that all destination are mmaped " - "before starting processing\n"); - return -EAGAIN; - } - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of" - " initialization\n"); - spin_unlock_irqrestore(&dev->irqlock, flags); - return -EIO; - } - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer(ctx, - vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), - 0, temp_vb->b->v4l2_planes[0].bytesused); - spin_unlock_irqrestore(&dev->irqlock, flags); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_set_dec_frame_buffer(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -/* Try running an operation on hardware */ -void s5p_mfc_try_run(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_ctx *ctx; - int new_ctx; - unsigned int ret = 0; - - if (test_bit(0, &dev->enter_suspend)) { - mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); - return; - } - /* Check whether hardware is not running */ - if (test_and_set_bit(0, &dev->hw_lock) != 0) { - /* This is perfectly ok, the scheduled ctx should wait */ - mfc_debug(1, "Couldn't lock HW\n"); - return; - } - /* Choose the context to run */ - new_ctx = s5p_mfc_get_new_ctx(dev); - if (new_ctx < 0) { - /* No contexts to run */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) { - mfc_err("Failed to unlock hardware\n"); - return; - } - mfc_debug(1, "No ctx is scheduled to be run\n"); - return; - } - ctx = dev->ctx[new_ctx]; - /* Got context to run in ctx */ - /* - * Last frame has already been sent to MFC. - * Now obtaining frames from MFC buffer - */ - s5p_mfc_clock_on(); - if (ctx->type == MFCINST_DECODER) { - s5p_mfc_set_dec_desc_buffer(ctx); - switch (ctx->state) { - case MFCINST_FINISHING: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); - break; - case MFCINST_RUNNING: - ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_dec(ctx); - break; - case MFCINST_HEAD_PARSED: - ret = s5p_mfc_run_init_dec_buffers(ctx); - mfc_debug(1, "head parsed\n"); - break; - case MFCINST_RES_CHANGE_INIT: - s5p_mfc_run_res_change(ctx); - break; - case MFCINST_RES_CHANGE_FLUSH: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_RES_CHANGE_END: - mfc_debug(2, "Finished remaining frames after resolution change\n"); - ctx->capture_state = QUEUE_FREE; - mfc_debug(2, "Will re-init the codec\n"); - s5p_mfc_run_init_dec(ctx); - break; - default: - ret = -EAGAIN; - } - } else if (ctx->type == MFCINST_ENCODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - case MFCINST_RUNNING: - ret = s5p_mfc_run_enc_frame(ctx); - break; - case MFCINST_INIT: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_open_inst_cmd(ctx); - break; - case MFCINST_RETURN_INST: - s5p_mfc_clean_ctx_int_flags(ctx); - ret = s5p_mfc_close_inst_cmd(ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_enc(ctx); - break; - default: - ret = -EAGAIN; - } - } else { - mfc_err("Invalid context type: %d\n", ctx->type); - ret = -EAGAIN; - } - - if (ret) { - /* Free hardware lock */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hardware\n"); - - /* This is in deed imporant, as no operation has been - * scheduled, reduce the clock count as no one will - * ever do this, because no interrupt related to this try_run - * will ever come from hardware. */ - s5p_mfc_clock_off(); - } -} - - -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->num_planes; i++) - vb2_set_plane_payload(b->b, i, 0); - vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 2ad3def052f8..420abecafec0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -1,10 +1,10 @@ /* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr.h + * drivers/media/platform/s5p-mfc/s5p_mfc_opr.h * * Header file for Samsung MFC (Multi Function Codec - FIMV) driver * Contains declarations of hw related functions. * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify @@ -17,77 +17,68 @@ #include "s5p_mfc_common.h" -int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); -int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); +struct s5p_mfc_hw_ops { + int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_codec_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_codec_buffers)(struct s5p_mfc_ctx *ctx); + int (*alloc_instance_buffer)(struct s5p_mfc_ctx *ctx); + void (*release_instance_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); + void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); + int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int buf_size); + int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx); + int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size); + void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr); + void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr); + int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx); + int (*init_decode)(struct s5p_mfc_ctx *ctx); + int (*init_encode)(struct s5p_mfc_ctx *ctx); + int (*encode_one_frame)(struct s5p_mfc_ctx *ctx); + void (*try_run)(struct s5p_mfc_dev *dev); + void (*cleanup_queue)(struct list_head *lh, + struct vb2_queue *vq); + void (*clear_int_flags)(struct s5p_mfc_dev *dev); + void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs); + unsigned int (*read_info)(struct s5p_mfc_ctx *ctx, + unsigned int ofs); + int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dspl_status)(struct s5p_mfc_dev *dev); + int (*get_dec_status)(struct s5p_mfc_dev *dev); + int (*get_dec_frame_type)(struct s5p_mfc_dev *dev); + int (*get_disp_frame_type)(struct s5p_mfc_ctx *ctx); + int (*get_consumed_stream)(struct s5p_mfc_dev *dev); + int (*get_int_reason)(struct s5p_mfc_dev *dev); + int (*get_int_err)(struct s5p_mfc_dev *dev); + int (*err_dec)(unsigned int err); + int (*err_dspl)(unsigned int err); + int (*get_img_width)(struct s5p_mfc_dev *dev); + int (*get_img_height)(struct s5p_mfc_dev *dev); + int (*get_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_mv_count)(struct s5p_mfc_dev *dev); + int (*get_inst_no)(struct s5p_mfc_dev *dev); + int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); + int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); + int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_enc_pic_count)(struct s5p_mfc_dev *dev); + int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx); + int (*get_mvc_num_views)(struct s5p_mfc_dev *dev); + int (*get_mvc_view_id)(struct s5p_mfc_dev *dev); + unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); +}; -/* Decoding functions */ -int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); -int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, - unsigned int buf_size); - -/* Encoding functions */ -void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr); -int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size); -void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr); -int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); - -int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame); -int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); - -/* Memory allocation */ -int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); - -int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); -void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); - -void s5p_mfc_try_run(struct s5p_mfc_dev *dev); -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); - -#define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_Y_ADR) << \ - MFC_OFFSET_SHIFT) -#define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DISPLAY_STATUS) -#define s5p_mfc_get_dec_status() readl(dev->regs_base + \ - S5P_FIMV_SI_DECODE_STATUS) -#define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ - S5P_FIMV_DECODE_FRAME_TYPE) \ - & S5P_FIMV_DECODE_FRAME_MASK) -#define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ - S5P_FIMV_SI_CONSUMED_BYTES) -#define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_CMD) & \ - S5P_FIMV_RISC2HOST_CMD_MASK) -#define s5p_mfc_get_int_err() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG2) -#define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ - S5P_FIMV_ERR_DEC_SHIFT) -#define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ - S5P_FIMV_ERR_DSPL_SHIFT) -#define s5p_mfc_get_img_width() readl(dev->regs_base + \ - S5P_FIMV_SI_HRESOL) -#define s5p_mfc_get_img_height() readl(dev->regs_base + \ - S5P_FIMV_SI_VRESOL) -#define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ - S5P_FIMV_SI_BUF_NUMBER) -#define s5p_mfc_get_inst_no() readl(dev->regs_base + \ - S5P_FIMV_RISC2HOST_ARG1) -#define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_STRM_SIZE) -#define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ - S5P_FIMV_ENC_SI_SLICE_TYPE) +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c new file mode 100644 index 000000000000..bf7d010a4107 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -0,0 +1,1794 @@ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" +#include <asm/cacheflush.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/firmware.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/mm.h> +#include <linux/sched.h> + +#define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) +#define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + ctx->dsc.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + buf_size->dsc); + if (IS_ERR_VALUE((int)ctx->dsc.alloc)) { + ctx->dsc.alloc = NULL; + mfc_err("Allocating DESC buffer failed\n"); + return -ENOMEM; + } + ctx->dsc.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->dsc.alloc); + BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->dsc.virt = vb2_dma_contig_memops.vaddr(ctx->dsc.alloc); + if (ctx->dsc.virt == NULL) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.dma = 0; + ctx->dsc.alloc = NULL; + mfc_err("Remapping DESC buffer failed\n"); + return -ENOMEM; + } + memset(ctx->dsc.virt, 0, buf_size->dsc); + wmb(); + return 0; +} + +/* Release temporary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->dsc.dma) { + vb2_dma_contig_memops.put(ctx->dsc.alloc); + ctx->dsc.alloc = NULL; + ctx->dsc.dma = 0; + } +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int enc_ref_y_size = 0; + unsigned int enc_ref_c_size = 0; + unsigned int guard_width, guard_height; + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, + S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height >> 1, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, + S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + enc_ref_y_size, enc_ref_c_size); + } else { + return -EINVAL; + } + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + + S5P_FIMV_DEC_VERT_NB_MV_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_STX_PARSER_SIZE + + S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE + + 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->bank1_size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_INTRAMD_SIZE + + S5P_FIMV_ENC_NBORINFO_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4) + + S5P_FIMV_ENC_INTRAPRED_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + case S5P_MFC_CODEC_H263_ENC: + ctx->bank1_size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2_size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + default: + break; + } + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = NULL; + printk(KERN_ERR + "Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + /* Allocate only if memory from bank 2 is necessary */ + if (ctx->bank2_size > 0) { + ctx->bank2_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); + if (IS_ERR(ctx->bank2_buf)) { + ctx->bank2_buf = NULL; + mfc_err("Buf alloc for decoding failed (port B)\n"); + return -ENOMEM; + } + ctx->bank2_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); + BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); + } + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = NULL; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } + if (ctx->bank2_buf) { + vb2_dma_contig_memops.put(ctx->bank2_buf); + ctx->bank2_buf = NULL; + ctx->bank2_phys = 0; + ctx->bank2_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + ctx->ctx.size = buf_size->h264_ctx; + else + ctx->ctx.size = buf_size->non_h264_ctx; + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { + mfc_err("Allocating context buffer failed\n"); + ctx->ctx.alloc = NULL; + return -ENOMEM; + } + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + BUG_ON(ctx->ctx.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + ctx->ctx.ofs = OFFSETA(ctx->ctx.dma); + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { + mfc_err("Remapping instance buffer failed\n"); + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.dma = 0; + return -ENOMEM; + } + /* Zero content of the allocated memory */ + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + /* Initialize shared memory */ + ctx->shm.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->shm); + if (IS_ERR(ctx->shm.alloc)) { + mfc_err("failed to allocate shared memory\n"); + return PTR_ERR(ctx->shm.alloc); + } + /* shared memory offset only keeps the offset from base (port a) */ + ctx->shm.ofs = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->shm.alloc) + - dev->bank1; + BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + + ctx->shm.virt = vb2_dma_contig_memops.vaddr(ctx->shm.alloc); + if (!ctx->shm.virt) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; + mfc_err("failed to virt addr of shared memory\n"); + return -ENOMEM; + } + memset((void *)ctx->shm.virt, 0, buf_size->shm); + wmb(); + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.ofs = 0; + ctx->ctx.virt = NULL; + ctx->ctx.dma = 0; + } + if (ctx->shm.alloc) { + vb2_dma_contig_memops.put(ctx->shm.alloc); + ctx->shm.alloc = NULL; + ctx->shm.ofs = 0; + ctx->shm.virt = NULL; + } +} + +int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + + return 0; +} + +void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ +} + +static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + writel(data, (ctx->shm.virt + ofs)); + wmb(); +} + +static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, + unsigned int ofs) +{ + rmb(); + return readl(ctx->shm.virt + ofs); +} + +void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int guard_width, guard_height; + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + mfc_debug(2, + "SEQ Done: Movie dimensions %dx%d, buffer dimensions: %dx%d\n", + ctx->img_width, ctx->img_height, ctx->buf_width, + ctx->buf_height); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->chroma_size = ALIGN(ctx->buf_width * + ALIGN((ctx->img_height >> 1), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + ctx->mv_size = ALIGN(ctx->buf_width * + ALIGN((ctx->buf_height >> 2), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + } else { + guard_width = + ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); + ctx->luma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + guard_width = + ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + ctx->mv_size = 0; + } +} + +void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN); + ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = + ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN); + } +} + +/* Set registers for decoding temporary buffers */ +static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); + mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); +} + +/* Set registers for shared buffer */ +static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + mfc_write(dev, ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int buf_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); + mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); + mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); + s5p_mfc_write_info_v5(ctx, start_num_byte, START_BYTE_NUM); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + size_t buf_addr1, buf_addr2; + int buf_size1, buf_size2; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~S5P_FIMV_DPB_COUNT_MASK; + mfc_write(dev, ctx->total_dpb_count | dpb, + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + s5p_mfc_set_shared_buffer(ctx); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_VERT_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); + buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; + buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + break; + case S5P_MFC_CODEC_H263_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + break; + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + break; + default: + mfc_err("Unknown codec for decoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + break; + } + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, + frame_size_mv); + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), + S5P_FIMV_DEC_LUMA_ADR + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), + S5P_FIMV_DEC_CHROMA_ADR + i * 4); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + mfc_debug(2, "\tBuf2: %x, size: %d\n", + buf_addr2, buf_size2); + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_MV_ADR + i * 4); + buf_addr2 += frame_size_mv; + buf_size2 -= frame_size_mv; + } + } + mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); + mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", + buf_size1, buf_size2, ctx->total_dpb_count); + if (buf_size1 < 0 || buf_size2 < 0) { + mfc_debug(2, "Not enough memory has been allocated\n"); + return -ENOMEM; + } + s5p_mfc_write_info_v5(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) + s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); + mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) + << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); + mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); + return 0; +} + +void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); + mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); +} + +void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) + << MFC_OFFSET_SHIFT); + *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) + << MFC_OFFSET_SHIFT); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_addr2; + size_t buf_size1, buf_size2; + unsigned int enc_ref_y_size, enc_ref_c_size; + unsigned int guard_width, guard_height; + int i; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + buf_addr2 = ctx->bank2_phys; + buf_size2 = ctx->bank2_size; + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_UP_INTRA_MD_ADR); + buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; + buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_UP_INTRA_PRED_ADR); + buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; + buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_NBOR_INFO_ADR); + buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; + buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_MPEG4_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_H263_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", + buf_size1, buf_size2); + break; + default: + mfc_err("Unknown codec set for encoding: %d\n", + ctx->codec_mode); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg; + unsigned int shm; + + /* width */ + mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); + /* height */ + mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); + /* pictype : enable, IDR period */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + reg |= (1 << 18); + reg &= ~(0xFFFF); + reg |= p->gop_size; + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); + /* multi-slice control */ + /* multi-slice MB number or bit size */ + mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); + } + /* cyclic intra refresh */ + mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + /* padding control & value */ + reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); + if (p->pad) { + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg &= ~(0xFF << 16); + reg |= (p->pad_cr << 16); + /** cb value */ + reg &= ~(0xFF << 8); + reg |= (p->pad_cb << 8); + /** y value */ + reg &= ~(0xFF); + reg |= (p->pad_luma); + } else { + /** disable & all value clear */ + reg = 0; + } + mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /** frame-level rate control */ + reg &= ~(0x1 << 9); + reg |= (p->rc_frame << 9); + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* bit rate */ + if (p->rc_frame) + mfc_write(dev, p->rc_bitrate, + S5P_FIMV_ENC_RC_BIT_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); + /* reaction coefficient */ + if (p->rc_frame) + mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* seq header ctrl */ + shm &= ~(0x1 << 3); + shm |= (p->seq_hdr_mode << 3); + /* frame skip mode */ + shm &= ~(0x3 << 1); + shm |= (p->frame_skip_mode << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + /* fixed target bit */ + s5p_mfc_write_info_v5(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_264->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_264->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* interlace */ + mfc_write(dev, p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT); + /* height */ + if (p_264->interlace) + mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); + /* loopfilter ctrl */ + mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); + /* loopfilter alpha offset */ + if (p_264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_alpha & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); + /* loopfilter beta offset */ + if (p_264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_beta & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); + /* entropy coding mode */ + if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); + /* number of ref. picture */ + reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* num of ref. pictures of P */ + reg &= ~(0x3 << 5); + reg |= (p_264->num_ref_pic_4p << 5); + /* max number of ref. pictures */ + reg &= ~(0x1F); + reg |= p_264->max_ref_pic; + mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* 8x8 transform enable */ + mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_264->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_264->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_264->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* macroblock adaptive scaling features */ + if (p->rc_mb) { + reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); + /* dark region */ + reg &= ~(0x1 << 3); + reg |= (p_264->rc_mb_dark << 3); + /* smooth region */ + reg &= ~(0x1 << 2); + reg |= (p_264->rc_mb_smooth << 2); + /* static region */ + reg &= ~(0x1 << 1); + reg |= (p_264->rc_mb_static << 1); + /* high activity region */ + reg &= ~(0x1); + reg |= p_264->rc_mb_activity; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); + } + if (!p->rc_frame && !p->rc_mb) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_264->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* AR VUI control */ + shm &= ~(0x1 << 15); + shm |= (p_264->vui_sar << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + if (p_264->vui_sar) { + /* aspect ration IDC */ + shm = s5p_mfc_read_info_v5(ctx, SAMPLE_ASPECT_RATIO_IDC); + shm &= ~(0xFF); + shm |= p_264->vui_sar_idc; + s5p_mfc_write_info_v5(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); + if (p_264->vui_sar_idc == 0xFF) { + /* sample AR info */ + shm = s5p_mfc_read_info_v5(ctx, EXTENDED_SAR); + shm &= ~(0xFFFFFFFF); + shm |= p_264->vui_ext_sar_width << 16; + shm |= p_264->vui_ext_sar_height; + s5p_mfc_write_info_v5(ctx, shm, EXTENDED_SAR); + } + } + /* intra picture period for H.264 */ + shm = s5p_mfc_read_info_v5(ctx, H264_I_PERIOD); + /* control */ + shm &= ~(0x1 << 16); + shm |= (p_264->open_gop << 16); + /* value */ + if (p_264->open_gop) { + shm &= ~(0xFFFF); + shm |= p_264->open_gop_size; + } + s5p_mfc_write_info_v5(ctx, shm, H264_I_PERIOD); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p_264->cpb_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + unsigned int framerate; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_mpeg4->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_mpeg4->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* quarter_pixel */ + mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame) { + if (p->rc_framerate_denom > 0) { + framerate = p->rc_framerate_num * 1000 / + p->rc_framerate_denom; + mfc_write(dev, framerate, + S5P_FIMV_ENC_RC_FRAME_RATE); + shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); + shm &= ~(0xFFFFFFFF); + shm |= (1 << 31); + shm |= ((p->rc_framerate_num & 0x7FFF) << 16); + shm |= (p->rc_framerate_denom & 0xFFFF); + s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); + } + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + } + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_mpeg4->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= (p_h263->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_h263->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_shared_buffer(ctx); + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) + mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); + else + mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); + mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << + S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << + S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & + S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + mfc_write(dev, + ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + + if (flush) + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( + S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + else + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); + s5p_mfc_set_shared_buffer(ctx); + s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case MFC_DEC_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_LAST_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_RES_CHANGE: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & + S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + break; + } + mfc_debug(2, "Decoding a usual frame\n"); + return 0; +} + +int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + } + s5p_mfc_set_shared_buffer(ctx); + mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | + (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int cmd; + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + s5p_mfc_set_shared_buffer(ctx); + + if (ctx->state == MFCINST_FINISHING) + cmd = S5P_FIMV_CH_LAST_FRAME; + else + cmd = S5P_FIMV_CH_FRAME_START; + mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + + return 0; +} + +static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + if (++cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); +} + +static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + index = temp_vb->b->v4l2_buf.index; + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = MFC_DEC_LAST_FRAME; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v5(ctx, last_frame); + return 0; +} + +static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { + mfc_debug(2, "no src buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + if (list_empty(&ctx->src_queue)) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, dev->bank2); + src_mb = NULL; + } else { + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + src_mb->flags |= MFC_BUF_FLAG_USED; + if (src_mb->b->v4l2_planes[0].bytesused == 0) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->bank2, + dev->bank2); + ctx->state = MFCINST_FINISHING; + } else { + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, + 1); + s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr, + src_c_addr); + if (src_mb->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + } + } + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + mfc_debug(2, "encoding buffer with index=%d state=%d", + src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state); + s5p_mfc_encode_one_frame_v5(ctx); + return 0; +} + +static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + s5p_mfc_set_dec_desc_buffer(ctx); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode_v5(ctx); +} + +static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + s5p_mfc_set_enc_ref_buffer_v5(ctx); + spin_lock_irqsave(&dev->irqlock, flags); + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode_v5(ctx); +} + +static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + int ret; + + /* + * Header was parsed now starting processing + * First set the output frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were " + "mmaped\nMFC requires that all destination are mmaped " + "before starting processing\n"); + return -EAGAIN; + } + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_err("Header has been deallocated in the middle of" + " initialization\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EIO; + } + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + 0, temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + if (test_bit(0, &dev->enter_suspend)) { + mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); + return; + } + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW\n"); + return; + } + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware\n"); + return; + } + mfc_debug(1, "No ctx is scheduled to be run\n"); + return; + } + ctx = dev->ctx[new_ctx]; + /* Got context to run in ctx */ + /* + * Last frame has already been sent to MFC. + * Now obtaining frames from MFC buffer + */ + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + s5p_mfc_set_dec_desc_buffer(ctx); + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + mfc_debug(1, "head parsed\n"); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_res_change(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("Invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); +} + +int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; +} + +int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); +} + +int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); +} + +int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) +{ + return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> + S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); +} + +int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) +{ + int reason; + reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & + S5P_FIMV_RISC2HOST_CMD_MASK; + switch (reason) { + case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + reason = S5P_MFC_R2H_CMD_SEQ_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + reason = S5P_MFC_R2H_CMD_FRAME_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: + reason = S5P_MFC_R2H_CMD_SLICE_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SYS_INIT_RET: + reason = S5P_MFC_R2H_CMD_SYS_INIT_RET; + break; + case S5P_FIMV_R2H_CMD_FW_STATUS_RET: + reason = S5P_MFC_R2H_CMD_FW_STATUS_RET; + break; + case S5P_FIMV_R2H_CMD_SLEEP_RET: + reason = S5P_MFC_R2H_CMD_SLEEP_RET; + break; + case S5P_FIMV_R2H_CMD_WAKEUP_RET: + reason = S5P_MFC_R2H_CMD_WAKEUP_RET; + break; + case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + reason = S5P_MFC_R2H_CMD_INIT_BUFFERS_RET; + break; + case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + reason = S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET; + break; + case S5P_FIMV_R2H_CMD_ERR_RET: + reason = S5P_MFC_R2H_CMD_ERR_RET; + break; + default: + reason = S5P_MFC_R2H_CMD_EMPTY; + }; + return reason; +} + +int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); +} + +int s5p_mfc_err_dec_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; +} + +int s5p_mfc_err_dspl_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT; +} + +int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_HRESOL); +} + +int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_VRESOL); +} + +int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); +} + +int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); +} + +int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); +} + +int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); +} + +int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT); +} + +int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL); +} + +int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); +} + +unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); +} + +unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); +} + +unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); +} + +/* Initialize opr function pointers for MFC v5 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v5, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v5, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v5, + .alloc_dev_context_buffer = s5p_mfc_alloc_dev_context_buffer_v5, + .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5, + .init_decode = s5p_mfc_init_decode_v5, + .init_encode = s5p_mfc_init_encode_v5, + .encode_one_frame = s5p_mfc_encode_one_frame_v5, + .try_run = s5p_mfc_try_run_v5, + .cleanup_queue = s5p_mfc_cleanup_queue_v5, + .clear_int_flags = s5p_mfc_clear_int_flags_v5, + .write_info = s5p_mfc_write_info_v5, + .read_info = s5p_mfc_read_info_v5, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, + .get_dspl_status = s5p_mfc_get_dspl_status_v5, + .get_dec_status = s5p_mfc_get_dec_status_v5, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v5, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v5, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v5, + .get_int_reason = s5p_mfc_get_int_reason_v5, + .get_int_err = s5p_mfc_get_int_err_v5, + .err_dec = s5p_mfc_err_dec_v5, + .err_dspl = s5p_mfc_err_dspl_v5, + .get_img_width = s5p_mfc_get_img_width_v5, + .get_img_height = s5p_mfc_get_img_height_v5, + .get_dpb_count = s5p_mfc_get_dpb_count_v5, + .get_mv_count = s5p_mfc_get_mv_count_v5, + .get_inst_no = s5p_mfc_get_inst_no_v5, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) +{ + return &s5p_mfc_ops_v5; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h index 416ebd7ba35a..ffee39a127d5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h @@ -1,17 +1,22 @@ /* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.h + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * http://www.samsung.com/ * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ -#ifndef S5P_MFC_SHM_H_ -#define S5P_MFC_SHM_H_ +#ifndef S5P_MFC_OPR_V5_H_ +#define S5P_MFC_OPR_V5_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" enum MFC_SHM_OFS { EXTENEDED_DECODE_STATUS = 0x00, /* D */ @@ -71,20 +76,10 @@ enum MFC_SHM_OFS { DBG_HISTORY_INPUT1 = 0xD4, /* C */ DBG_HISTORY_OUTPUT = 0xD8, /* C */ HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ + FRAME_PACK_SEI_ENABLE = 0x168, /* C */ + FRAME_PACK_SEI_AVAIL = 0x16c, /* D */ + FRAME_PACK_SEI_INFO = 0x17c, /* E */ }; -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx); - -#define s5p_mfc_write_shm(ctx, x, ofs) \ - do { \ - writel(x, (ctx->shm + ofs)); \ - wmb(); \ - } while (0) - -static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs) -{ - rmb(); - return readl(ctx->shm + ofs); -} - -#endif /* S5P_MFC_SHM_H_ */ +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c new file mode 100644 index 000000000000..50b5bee3c44e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -0,0 +1,1956 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#undef DEBUG + +#include <linux/delay.h> +#include <linux/mm.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/firmware.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/dma-mapping.h> + +#include <asm/cacheflush.h> + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v6.h" + +/* #define S5P_MFC_DEBUG_REGWRITE */ +#ifdef S5P_MFC_DEBUG_REGWRITE +#undef writel +#define writel(v, r) \ + do { \ + pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ + __raw_writel(v, r); \ + } while (0) +#endif /* S5P_MFC_DEBUG_REGWRITE */ + +#define READL(offset) readl(dev->regs_base + (offset)) +#define WRITEL(data, offset) writel((data), dev->regs_base + (offset)) +#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET) +#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET) + +/* Allocate temporary buffers for decoding */ +int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ + + return 0; +} + +/* Release temproary buffers for decoding */ +void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + +int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +/* Allocate codec buffers */ +int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * + ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), + S5P_FIMV_TMV_BUFFER_ALIGN_V6); + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( + ctx->img_width, ctx->img_height, + mb_width, mb_height), + S5P_FIMV_ME_BUFFER_ALIGN_V6); + + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + ctx->luma_dpb_size, ctx->chroma_dpb_size); + } else { + return -EINVAL; + } + + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1_size = 0; + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VP8_DEC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1_size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->dpb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2_size = 0; + break; + default: + break; + } + + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1_size > 0) { + ctx->bank1_buf = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); + if (IS_ERR(ctx->bank1_buf)) { + ctx->bank1_buf = 0; + pr_err("Buf alloc for decoding failed (port A)\n"); + return -ENOMEM; + } + ctx->bank1_phys = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); + BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + + return 0; +} + +/* Release buffers allocated for codec */ +void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + if (ctx->bank1_buf) { + vb2_dma_contig_memops.put(ctx->bank1_buf); + ctx->bank1_buf = 0; + ctx->bank1_phys = 0; + ctx->bank1_size = 0; + } +} + +/* Allocate memory for instance data buffer */ +int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + ctx->ctx.size = buf_size->h264_dec_ctx; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_H263_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_VP8_DEC: + ctx->ctx.size = buf_size->other_dec_ctx; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->ctx.size = buf_size->h264_enc_ctx; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + ctx->ctx.size = buf_size->other_enc_ctx; + break; + default: + ctx->ctx.size = 0; + mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); + break; + } + + ctx->ctx.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); + if (IS_ERR(ctx->ctx.alloc)) { + mfc_err("Allocating context buffer failed.\n"); + return PTR_ERR(ctx->ctx.alloc); + } + + ctx->ctx.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); + + ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); + if (!ctx->ctx.virt) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + + mfc_err("Remapping context buffer failed.\n"); + return -ENOMEM; + } + + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release instance buffer */ +void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + mfc_debug_enter(); + + if (ctx->ctx.alloc) { + vb2_dma_contig_memops.put(ctx->ctx.alloc); + ctx->ctx.alloc = NULL; + ctx->ctx.dma = 0; + ctx->ctx.virt = NULL; + } + + mfc_debug_leave(); +} + +/* Allocate context buffers for SYS_INIT */ +int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + + mfc_debug_enter(); + + dev->ctx_buf.alloc = vb2_dma_contig_memops.alloc( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->dev_ctx); + if (IS_ERR(dev->ctx_buf.alloc)) { + mfc_err("Allocating DESC buffer failed.\n"); + return PTR_ERR(dev->ctx_buf.alloc); + } + + dev->ctx_buf.dma = s5p_mfc_mem_cookie( + dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], + dev->ctx_buf.alloc); + + dev->ctx_buf.virt = vb2_dma_contig_memops.vaddr(dev->ctx_buf.alloc); + if (!dev->ctx_buf.virt) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + + mfc_err("Remapping DESC buffer failed.\n"); + return -ENOMEM; + } + + memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release context buffers for SYS_INIT */ +void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + if (dev->ctx_buf.alloc) { + vb2_dma_contig_memops.put(dev->ctx_buf.alloc); + dev->ctx_buf.alloc = NULL; + dev->ctx_buf.dma = 0; + dev->ctx_buf.virt = NULL; + } +} + +static int calc_plane(int width, int height) +{ + int mbX, mbY; + + mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); + mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); + + if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) + mbY = (mbY + 1) / 2 * 2; + + return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * + (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); +} + +void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) +{ + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); + mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" + "buffer dimensions: %dx%d\n", ctx->img_width, + ctx->img_height, ctx->buf_width, ctx->buf_height); + + ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); + ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + ctx->mv_size = ALIGN(ctx->mv_size, 16); + } else { + ctx->mv_size = 0; + } +} + +void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); + ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); + ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); +} + +/* Set registers for decoding stream buffer */ +int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, + unsigned int start_num_byte, unsigned int strm_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + + mfc_debug_enter(); + mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" + "buf_size: 0x%08x (%d)\n", + ctx->inst_no, buf_addr, strm_size, strm_size); + WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); + WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); + WRITEL(buf_size->cpb, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); + WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); + + mfc_debug_leave(); + return 0; +} + +/* Set decoding frame buffer */ +int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1; + int buf_size1; + int align_gap; + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); + mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); + + WRITEL(ctx->total_dpb_count, S5P_FIMV_D_NUM_DPB_V6); + WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); + WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); + + WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); + WRITEL(ctx->mv_count, S5P_FIMV_D_NUM_MV_V6); + } + + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", + frame_size, frame_size_ch, frame_size_mv); + + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + WRITEL(ctx->dst_bufs[i].cookie.raw.luma, + S5P_FIMV_D_LUMA_DPB_V6 + i * 4); + mfc_debug(2, "\tChroma %d: %x\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + WRITEL(ctx->dst_bufs[i].cookie.raw.chroma, + S5P_FIMV_D_CHROMA_DPB_V6 + i * 4); + } + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + for (i = 0; i < ctx->mv_count; i++) { + /* To test alignment */ + align_gap = buf_addr1; + buf_addr1 = ALIGN(buf_addr1, 16); + align_gap = buf_addr1 - align_gap; + buf_size1 -= align_gap; + + mfc_debug(2, "\tBuf1: %x, size: %d\n", + buf_addr1, buf_size1); + WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER_V6 + i * 4); + buf_addr1 += frame_size_mv; + buf_size1 -= frame_size_mv; + } + } + + mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", + buf_addr1, buf_size1, ctx->total_dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug(2, "After setting buffers.\n"); + return 0; +} + +/* Set registers for encoding stream buffer */ +int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */ + WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); + + mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d", + addr, size); + + return 0; +} + +void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */ + WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); + + mfc_debug(2, "enc src y buf addr: 0x%08lx", y_addr); + mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); +} + +void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long enc_recon_y_addr, enc_recon_c_addr; + + *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); + *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); + + enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); + enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); + + mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr); + mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr); +} + +/* Set encoding ref & codec buffer */ +int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_size1; + int i; + + mfc_debug_enter(); + + buf_addr1 = ctx->bank1_phys; + buf_size1 = ctx->bank1_size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + + for (i = 0; i < ctx->dpb_count; i++) { + WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } + + WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); + WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1_V6); + buf_addr1 += ctx->tmv_buffer_size >> 1; + buf_size1 -= ctx->tmv_buffer_size; + + mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", + buf_addr1, buf_size1, ctx->dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + WRITEL(ctx->slice_mode, S5P_FIMV_E_MSLICE_MODE_V6); + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + WRITEL(ctx->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + } else if (ctx->slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + WRITEL(ctx->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } else { + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + } + + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg = 0; + + mfc_debug_enter(); + + /* width */ + WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH_V6); /* 16 align */ + /* height */ + WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT_V6); /* 16 align */ + + /* cropped width */ + WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); + /* cropped height */ + WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + /* cropped offset */ + WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); + + /* pictype : IDR period */ + reg = 0; + reg |= p->gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + ctx->slice_mode = p->slice_mode; + reg = 0; + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.mb = p->slice_mb; + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + reg |= (0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + ctx->slice_size.bits = p->slice_bit; + } else { + reg &= ~(0x1 << 3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + } + + s5p_mfc_set_slice_mode(ctx); + + /* cyclic intra refresh */ + WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE_V6); + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + if (p->intra_refresh_mb == 0) + reg &= ~(0x1 << 4); + else + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 9); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { + /* 0: Linear, 1: 2D tiled*/ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 7); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + } + + /* memory structure recon. frame */ + /* 0: Linear, 1: 2D tiled */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg |= (0x1 << 8); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* padding control & value */ + WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL_V6); + if (p->pad) { + reg = 0; + /** enable */ + reg |= (1 << 31); + /** cr value */ + reg |= ((p->pad_cr & 0xFF) << 16); + /** cb value */ + reg |= ((p->pad_cb & 0xFF) << 8); + /** y value */ + reg |= p->pad_luma & 0xFF; + WRITEL(reg, S5P_FIMV_E_PADDING_CTRL_V6); + } + + /* rate control config. */ + reg = 0; + /* frame-level rate control */ + reg |= ((p->rc_frame & 0x1) << 9); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* bit rate */ + if (p->rc_frame) + WRITEL(p->rc_bitrate, + S5P_FIMV_E_RC_BIT_RATE_V6); + else + WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6); + + /* reaction coefficient */ + if (p->rc_frame) { + if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ + WRITEL(1, S5P_FIMV_E_RC_RPARAM_V6); + else /* loose CBR */ + WRITEL(2, S5P_FIMV_E_RC_RPARAM_V6); + } + + /* seq header ctrl */ + reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); + reg &= ~(0x1 << 2); + reg |= ((p->seq_hdr_mode & 0x1) << 2); + + /* frame skip mode */ + reg &= ~(0x3); + reg |= (p->frame_skip_mode & 0x3); + WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); + + /* 'DROP_CONTROL_ENABLE', disable */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + reg &= ~(0x1 << 10); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* setting for MV range [16, 256] */ + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6); + + reg = 0; + reg &= ~(0x3FFF); + reg = 256; + WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6); + + WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6); + WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE_V6); + WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL_V6); + WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG_V6); + + WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); + WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT_V6); + WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT_V6); + + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); + WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_h264->level & 0xFF) << 8); + /** profile - 0 ~ 3 */ + reg |= p_h264->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h264->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h264->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h264->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p_h264->cpb_size & 0xFFFF, + S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* interlace */ + reg = 0; + reg |= ((p_h264->interlace & 0x1) << 3); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* height */ + if (p_h264->interlace) { + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_FRAME_HEIGHT_V6); /* 32 align */ + /* cropped height */ + WRITEL(ctx->img_height >> 1, + S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + } + + /* loop filter ctrl */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 1); + reg |= ((p_h264->loop_filter_mode & 0x3) << 1); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* loopfilter alpha offset */ + if (p_h264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_alpha & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); + + /* loopfilter beta offset */ + if (p_h264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_beta & 0xF); + } + WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); + + /* entropy coding mode */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1); + reg |= p_h264->entropy_mode & 0x1; + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* number of ref. picture */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 7); + reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 8x8 transform enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 12); + reg |= ((p_h264->_8x8_transform & 0x3) << 12); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* macroblock adaptive scaling features */ + WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG_V6); + if (p->rc_mb) { + reg = 0; + /** dark region */ + reg |= ((p_h264->rc_mb_dark & 0x1) << 3); + /** smooth region */ + reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); + /** static region */ + reg |= ((p_h264->rc_mb_static & 0x1) << 1); + /** high activity region */ + reg |= p_h264->rc_mb_activity & 0x1; + WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG_V6); + } + + /* aspect ratio VUI */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 5); + reg |= ((p_h264->vui_sar & 0x1) << 5); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO_V6); + WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR_V6); + if (p_h264->vui_sar) { + /* aspect ration IDC */ + reg = 0; + reg |= p_h264->vui_sar_idc & 0xFF; + WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO_V6); + if (p_h264->vui_sar_idc == 0xFF) { + /* extended SAR */ + reg = 0; + reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; + reg |= p_h264->vui_ext_sar_height & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR_V6); + } + } + + /* intra picture period for H.264 open GOP */ + /* control */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 4); + reg |= ((p_h264->open_gop & 0x1) << 4); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + /* value */ + WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD_V6); + if (p_h264->open_gop) { + reg = 0; + reg |= p_h264->open_gop_size & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD_V6); + } + + /* 'WEIGHTED_BI_PREDICTION' for B is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x3 << 9); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 14); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* ASO */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 6); + reg |= ((p_h264->aso & 0x1) << 6); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + + /* hier qp enable */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 8); + reg |= ((p_h264->open_gop & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + reg = 0; + if (p_h264->hier_qp && p_h264->hier_qp_layer) { + reg |= (p_h264->hier_qp_type & 0x1) << 0x3; + reg |= p_h264->hier_qp_layer & 0x7; + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + /* QP value for each layer */ + for (i = 0; i < (p_h264->hier_qp_layer & 0x7); i++) + WRITEL(p_h264->hier_qp_layer_qp[i], + S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 + + i * 4); + } + /* number of coding layer should be zero when hierarchical is disable */ + WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + + /* frame packing SEI generation */ + reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); + reg &= ~(0x1 << 25); + reg |= ((p_h264->sei_frame_packing & 0x1) << 25); + WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); + if (p_h264->sei_frame_packing) { + reg = 0; + /** current frame0 flag */ + reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); + /** arrangement type */ + reg |= p_h264->sei_fp_arrangement_type & 0x3; + WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); + } + + if (p_h264->fmo) { + switch (p_h264->fmo_map_type) { + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) + WRITEL(p_h264->fmo_run_len[i] - 1, + S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 + + i * 4); + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: + if (p_h264->fmo_slice_grp > 2) + p_h264->fmo_slice_grp = 2; + WRITEL(p_h264->fmo_chg_dir & 0x1, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); + /* the valid range is 0 ~ number of macroblocks -1 */ + WRITEL(p_h264->fmo_chg_rate, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); + break; + default: + mfc_err("Unsupported map type for FMO: %d\n", + p_h264->fmo_map_type); + p_h264->fmo_map_type = 0; + p_h264->fmo_slice_grp = 1; + break; + } + + WRITEL(p_h264->fmo_map_type, + S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); + WRITEL(p_h264->fmo_slice_grp - 1, + S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } else { + WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + } + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_mpeg4->level & 0xFF) << 8); + /** profile - 0 ~ 1 */ + reg |= p_mpeg4->profile & 0x3F; + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_mpeg4->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + /* Disable HEC */ + WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS_V6); + WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* profile & level */ + reg = 0; + /** profile */ + reg |= (0x1 << 4); + WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); + + /* rate control config. */ + reg = READL(S5P_FIMV_E_RC_CONFIG_V6); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h263->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h263->rc_min_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); + + /* other QPs */ + WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h263->rc_frame_qp & 0x3F; + WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + + if (p->rc_frame) + WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + } + + mfc_debug_leave(); + + return 0; +} + +/* Initialize decoding */ +int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int reg = 0; + int fmo_aso_ctrl = 0; + + mfc_debug_enter(); + mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, + S5P_FIMV_CH_SEQ_HEADER_V6); + mfc_debug(2, "BUFs: %08x %08x %08x\n", + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), + READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6)); + + /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ + reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); + + /* When user sets desplay_delay to 0, + * It works as "display_delay enable" and delay set to 0. + * If user wants display_delay disable, It should be + * set to negative value. */ + if (ctx->display_delay >= 0) { + reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); + WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); + } + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { + mfc_debug(2, "Set loop filter to: %d\n", + ctx->loop_filter_mpeg4); + reg |= (ctx->loop_filter_mpeg4 << + S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); + } + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) + reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); + + WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6); + + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) + WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); + else + WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); + + /* sei parse */ + WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + mfc_debug_leave(); + return 0; +} + +static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + if (flush) + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14); + else + dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14); + WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + WRITEL(ctx->dec_dst_flag, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); + WRITEL(ctx->slice_interface & 0x1, S5P_FIMV_D_SLICE_IF_ENABLE_V6); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case 0: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + break; + case 1: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_LAST_FRAME_V6, NULL); + break; + default: + mfc_err("Unsupported last frame arg.\n"); + return -EINVAL; + } + + mfc_debug(2, "Decoding a usual frame.\n"); + return 0; +} + +int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x).\n", + ctx->codec_mode); + return -EINVAL; + } + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + return 0; +} + +int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + int i; + + if (p_h264->aso) { + for (i = 0; i < 8; i++) + WRITEL(p_h264->aso_slice_order[i], + S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 + i * 4); + } + return 0; +} + +/* Encode a single frame */ +int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_debug(2, "++\n"); + + /* memory structure cur. frame */ + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_h264_set_aso_slice_order_v6(ctx); + + s5p_mfc_set_slice_mode(ctx); + + WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + + mfc_debug(2, "--\n"); + + return 0; +} + +static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int new_ctx; + int cnt; + + spin_lock_irqsave(&dev->condlock, flags); + mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx, + dev->ctx_work_bits); + new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; + cnt = 0; + while (!test_bit(new_ctx, &dev->ctx_work_bits)) { + new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; + cnt++; + if (cnt > MFC_NUM_CONTEXTS) { + /* No contexts to run */ + spin_unlock_irqrestore(&dev->condlock, flags); + return -EAGAIN; + } + } + spin_unlock_irqrestore(&dev->condlock, flags); + return new_ctx; +} + +static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0); + spin_unlock_irqrestore(&dev->irqlock, flags); + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v6(ctx, 1); +} + +static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + unsigned long flags; + int last_frame = 0; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), + ctx->consumed_stream, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = temp_vb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + if (temp_vb->b->v4l2_planes[0].bytesused == 0) { + last_frame = 1; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + + return 0; +} + +static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + /* + unsigned int src_y_size, src_c_size; + */ + unsigned int dst_size; + unsigned int index; + + spin_lock_irqsave(&dev->irqlock, flags); + + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "no src buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers.\n"); + spin_unlock_irqrestore(&dev->irqlock, flags); + return -EAGAIN; + } + + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + src_mb->flags |= MFC_BUF_FLAG_USED; + src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); + + mfc_debug(2, "enc src y addr: 0x%08lx", src_y_addr); + mfc_debug(2, "enc src c addr: 0x%08lx", src_c_addr); + + s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + + spin_unlock_irqrestore(&dev->irqlock, flags); + + index = src_mb->b->v4l2_buf.index; + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_encode_one_frame_v6(ctx); + + return 0; +} + +static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + spin_lock_irqsave(&dev->irqlock, flags); + mfc_debug(2, "Preparing to init decoding.\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, + temp_vb->b->v4l2_planes[0].bytesused); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_decode_v6(ctx); +} + +static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + spin_lock_irqsave(&dev->irqlock, flags); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); + dst_size = vb2_plane_size(dst_mb->b, 0); + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + spin_unlock_irqrestore(&dev->irqlock, flags); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_init_encode_v6(ctx); +} + +static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + /* Header was parsed now start processing + * First set the output frame buffers + * s5p_mfc_alloc_dec_buffers(ctx); */ + + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destionation buffers were\n" + "mmaped.MFC requires that all destination are mmaped\n" + "before starting processing.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + ret = s5p_mfc_alloc_codec_buffers_v6(ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers.\n"); + return -ENOMEM; + } + + /* Header was generated now starting processing + * First set the reference frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_REQUESTED) { + mfc_err("It seems that destionation buffers were not\n" + "requested.MFC requires that header should be generated\n" + "before allocating codec buffer.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + mfc_debug(1, "Try run dev: %p\n", dev); + + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW.\n"); + return; + } + + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware.\n"); + return; + } + + mfc_debug(1, "No ctx is scheduled to be run.\n"); + return; + } + + mfc_debug(1, "New context: %d\n", new_ctx); + ctx = dev->ctx[new_ctx]; + mfc_debug(1, "Seting new context to %p\n", ctx); + /* Got context to run in ctx */ + mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", + ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt); + mfc_debug(1, "ctx->state=%d\n", ctx->state); + /* Last frame has already been sent to MFC + * Now obtaining frames from MFC buffer */ + + s5p_mfc_clock_on(); + if (ctx->type == MFCINST_DECODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx); + break; + case MFCINST_INIT: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + s5p_mfc_clean_ctx_int_flags(ctx); + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change.\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec`.\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + case MFCINST_HEAD_PARSED: /* Only for MFC6.x */ + ret = s5p_mfc_run_init_enc_buffers(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware.\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + + +void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->num_planes; i++) + vb2_set_plane_payload(b->b, i, 0); + vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6); +} + +void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_clock_on(); + WRITEL(data, ofs); + s5p_mfc_clock_off(); +} + +unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + s5p_mfc_clock_on(); + ret = READL(ofs); + s5p_mfc_clock_off(); + + return ret; +} + +int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); +} + +int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); +} + +int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); +} + +int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6); +} + +int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) & + S5P_FIMV_RISC2HOST_CMD_MASK; +} + +int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6); +} + +int s5p_mfc_err_dec_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; +} + +int s5p_mfc_err_dspl_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; +} + +int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); +} + +int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); +} + +int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6); +} + +int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6); +} + +int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6); +} + +int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6); +} + +int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6); +} + +int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6); +} + +int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6); +} + +int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) +{ + return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); +} + +int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6); +} + +int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6); +} + +unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6); +} + +unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6); +} + +unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6); +} + +unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6); +} + +/* Initialize opr function pointers for MFC v6 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, + .alloc_dev_context_buffer = + s5p_mfc_alloc_dev_context_buffer_v6, + .release_dev_context_buffer = + s5p_mfc_release_dev_context_buffer_v6, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, + .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6, + .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, + .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6, + .init_decode = s5p_mfc_init_decode_v6, + .init_encode = s5p_mfc_init_encode_v6, + .encode_one_frame = s5p_mfc_encode_one_frame_v6, + .try_run = s5p_mfc_try_run_v6, + .cleanup_queue = s5p_mfc_cleanup_queue_v6, + .clear_int_flags = s5p_mfc_clear_int_flags_v6, + .write_info = s5p_mfc_write_info_v6, + .read_info = s5p_mfc_read_info_v6, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, + .get_dspl_status = s5p_mfc_get_dspl_status_v6, + .get_dec_status = s5p_mfc_get_dec_status_v6, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, + .get_int_reason = s5p_mfc_get_int_reason_v6, + .get_int_err = s5p_mfc_get_int_err_v6, + .err_dec = s5p_mfc_err_dec_v6, + .err_dspl = s5p_mfc_err_dspl_v6, + .get_img_width = s5p_mfc_get_img_width_v6, + .get_img_height = s5p_mfc_get_img_height_v6, + .get_dpb_count = s5p_mfc_get_dpb_count_v6, + .get_mv_count = s5p_mfc_get_mv_count_v6, + .get_inst_no = s5p_mfc_get_inst_no_v6, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, + .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6, + .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6, + .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6, + .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) +{ + return &s5p_mfc_ops_v6; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h new file mode 100644 index 000000000000..ab164efa127e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -0,0 +1,50 @@ +/* + * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef S5P_MFC_OPR_V6_H_ +#define S5P_MFC_OPR_V6_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" + +#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR + +#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) +#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) +#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) + +/* Definition */ +#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) +#define ENC_MULTI_SLICE_BIT_MIN 2800 +#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) +#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) +#define ENC_H264_LOOP_FILTER_AB_MIN -12 +#define ENC_H264_LOOP_FILTER_AB_MAX 12 +#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H264_PROFILE_MAX 3 +#define ENC_H264_LEVEL_MAX 42 +#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) +#define FRAME_DELTA_H264_H263 1 +#define TIGHT_CBR_MAX 10 + +/* Definitions for shared memory compatibility */ +#define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 +#define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 +#define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 +#define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); +#endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 0503d14ac94e..367db7552289 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -20,7 +20,6 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -#define MFC_CLKNAME "sclk_mfc" #define MFC_GATE_CLK_NAME "mfc" #define CLK_DEBUG @@ -51,7 +50,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) goto err_p_ip_clk; } - pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); + pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name); if (IS_ERR(pm->clock)) { mfc_err("Failed to get MFC clock\n"); ret = PTR_ERR(pm->clock); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c deleted file mode 100644 index b5933d233a4b..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_shm.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifdef CONFIG_ARCH_EXYNOS4 -#include <linux/dma-mapping.h> -#endif -#include <linux/io.h> -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" - -int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; - - ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx, - SHARED_BUF_SIZE); - if (IS_ERR(ctx->shm_alloc)) { - mfc_err("failed to allocate shared memory\n"); - return PTR_ERR(ctx->shm_alloc); - } - /* shm_ofs only keeps the offset from base (port a) */ - ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc) - - dev->bank1; - BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); - if (!ctx->shm) { - vb2_dma_contig_memops.put(ctx->shm_alloc); - ctx->shm_ofs = 0; - ctx->shm_alloc = NULL; - mfc_err("failed to virt addr of shared memory\n"); - return -ENOMEM; - } - memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); - wmb(); - return 0; -} - diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 403d7f17bfab..9fd9d1c5b218 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1376,6 +1376,7 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __u32 pixfmt = pix->pixelformat; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; + struct mx2_fmt_cfg *emma_prp; unsigned int width_limit; int ret; @@ -1438,12 +1439,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, __func__, pcdev->s_width, pcdev->s_height); /* If the sensor does not support image size try PrP resizing */ - pcdev->emma_prp = mx27_emma_prp_get_format(xlate->code, + emma_prp = mx27_emma_prp_get_format(xlate->code, xlate->host_fmt->fourcc); - memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); if ((mf.width != pix->width || mf.height != pix->height) && - pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { + emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } @@ -1655,6 +1655,7 @@ static int __devinit mx27_camera_emma_init(struct platform_device *pdev) irq_emma = platform_get_irq(pdev, 1); if (!res_emma || !irq_emma) { dev_err(pcdev->dev, "no EMMA resources\n"); + err = -ENODEV; goto out; } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 3be92944f8e7..d3f0b84e2d70 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -950,11 +950,11 @@ static int soc_camera_s_selection(struct file *file, void *fh, /* In all these cases cropping emulation will not help */ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - (s->target != V4L2_SEL_TGT_COMPOSE_ACTIVE && - s->target != V4L2_SEL_TGT_CROP_ACTIVE)) + (s->target != V4L2_SEL_TGT_COMPOSE && + s->target != V4L2_SEL_TGT_CROP)) return -EINVAL; - if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + if (s->target == V4L2_SEL_TGT_COMPOSE) { /* No output size change during a running capture! */ if (is_streaming(ici, icd) && (icd->user_width != s->r.width || @@ -974,7 +974,7 @@ static int soc_camera_s_selection(struct file *file, void *fh, ret = ici->ops->set_selection(icd, s); if (!ret && - s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE) { + s->target == V4L2_SEL_TGT_COMPOSE) { icd->user_width = s->r.width; icd->user_height = s->r.height; if (!icd->streamer) @@ -1184,7 +1184,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) sd->grp_id = soc_camera_grp_id(icd); v4l2_set_subdev_hostdata(sd, icd); - if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL)) + ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL); + if (ret < 0) goto ectrl; /* At this point client .probe() should have run already */ @@ -1529,12 +1530,11 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) { struct soc_camera_link *icl = pdev->dev.platform_data; struct soc_camera_device *icd; - int ret; if (!icl) return -EINVAL; - icd = kzalloc(sizeof(*icd), GFP_KERNEL); + icd = devm_kzalloc(&pdev->dev, sizeof(*icd), GFP_KERNEL); if (!icd) return -ENOMEM; @@ -1543,19 +1543,10 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev) icd->pdev = &pdev->dev; platform_set_drvdata(pdev, icd); - ret = soc_camera_device_register(icd); - if (ret < 0) - goto escdevreg; - icd->user_width = DEFAULT_WIDTH; icd->user_height = DEFAULT_HEIGHT; - return 0; - -escdevreg: - kfree(icd); - - return ret; + return soc_camera_device_register(icd); } /* @@ -1572,8 +1563,6 @@ static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev) list_del(&icd->list); - kfree(icd); - return 0; } @@ -1586,18 +1575,7 @@ static struct platform_driver __refdata soc_camera_pdrv = { }, }; -static int __init soc_camera_init(void) -{ - return platform_driver_register(&soc_camera_pdrv); -} - -static void __exit soc_camera_exit(void) -{ - platform_driver_unregister(&soc_camera_pdrv); -} - -module_init(soc_camera_init); -module_exit(soc_camera_exit); +module_platform_driver(soc_camera_pdrv); MODULE_DESCRIPTION("Image capture bus driver"); MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index e5024cfd27a7..4ef55ec8045e 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -308,7 +308,7 @@ static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index be076f7181e7..62f3edec39bc 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -446,7 +446,7 @@ static void si470x_int_in_callback(struct urb *urb) READCHAN_BLERD) >> 10; rds = radio->registers[RDSD]; break; - }; + } /* Fill the V4L2 RDS buffer */ put_unaligned_le16(rds, &tmpbuf); diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index a9e6d17015ef..e3079c142c5f 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1009,7 +1009,7 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, default: rval = -EINVAL; - }; + } return rval; } @@ -1081,7 +1081,7 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1130,7 +1130,7 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, default: rval = -EINVAL; goto unlock; - }; + } if (sdev->power_state) rval = si4713_tx_tune_power(sdev, power, antcap); @@ -1420,7 +1420,7 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev, default: rval = -EINVAL; break; - }; + } exit: return rval; @@ -1473,7 +1473,7 @@ static int si4713_read_econtrol_tune(struct si4713_device *sdev, break; default: rval = -EINVAL; - }; + } unlock: mutex_unlock(&sdev->mutex); @@ -1698,7 +1698,7 @@ static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) default: rval = -EINVAL; break; - }; + } return rval; } diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 647dd951b0e8..d05ac15b5de4 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -881,10 +881,13 @@ static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask) static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier) { struct ene_device *dev = rdev->priv; - u32 period = 2000000 / carrier; + u32 period; dbg("TX: attempt to set tx carrier to %d kHz", carrier); + if (carrier == 0) + return -EINVAL; + period = 2000000 / carrier; if (period && (period > ENE_CIRMOD_PRD_MAX || period < ENE_CIRMOD_PRD_MIN)) { diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 1e4c68a5cecf..51d7057aca04 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -28,6 +28,7 @@ #include <media/rc-core.h> #define DRIVER_NAME "iguanair" +#define BUF_SIZE 152 struct iguanair { struct rc_dev *rc; @@ -35,26 +36,23 @@ struct iguanair { struct device *dev; struct usb_device *udev; - int pipe_out; uint16_t version; uint8_t bufsize; + uint8_t cycle_overhead; struct mutex lock; /* receiver support */ bool receiver_on; - dma_addr_t dma_in; + dma_addr_t dma_in, dma_out; uint8_t *buf_in; - struct urb *urb_in; + struct urb *urb_in, *urb_out; struct completion completion; /* transmit support */ bool tx_overflow; uint32_t carrier; - uint8_t cycle_overhead; - uint8_t channels; - uint8_t busy4; - uint8_t busy7; + struct send_packet *packet; char name[64]; char phys[64]; @@ -73,7 +71,8 @@ struct iguanair { #define DIR_IN 0xdc #define DIR_OUT 0xcd -#define MAX_PACKET_SIZE 8u +#define MAX_IN_PACKET 8u +#define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE) #define TIMEOUT 1000 #define RX_RESOLUTION 21333 @@ -191,20 +190,25 @@ static void iguanair_rx(struct urb *urb) dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc); } -static int iguanair_send(struct iguanair *ir, void *data, unsigned size) +static void iguanair_irq_out(struct urb *urb) { - int rc, transferred; + struct iguanair *ir = urb->context; + + if (urb->status) + dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status); +} + +static int iguanair_send(struct iguanair *ir, unsigned size) +{ + int rc; INIT_COMPLETION(ir->completion); - rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size, - &transferred, TIMEOUT); + ir->urb_out->transfer_buffer_length = size; + rc = usb_submit_urb(ir->urb_out, GFP_KERNEL); if (rc) return rc; - if (transferred != size) - return -EIO; - if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) return -ETIMEDOUT; @@ -213,14 +217,13 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size) static int iguanair_get_features(struct iguanair *ir) { - struct packet packet; int rc; - packet.start = 0; - packet.direction = DIR_OUT; - packet.cmd = CMD_GET_VERSION; + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_GET_VERSION; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get version\n"); goto out; @@ -235,17 +238,23 @@ static int iguanair_get_features(struct iguanair *ir) ir->bufsize = 150; ir->cycle_overhead = 65; - packet.cmd = CMD_GET_BUFSIZE; + ir->packet->header.cmd = CMD_GET_BUFSIZE; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get buffer size\n"); goto out; } - packet.cmd = CMD_GET_FEATURES; + if (ir->bufsize > BUF_SIZE) { + dev_info(ir->dev, "buffer size %u larger than expected\n", + ir->bufsize); + ir->bufsize = BUF_SIZE; + } + + ir->packet->header.cmd = CMD_GET_FEATURES; - rc = iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); if (rc) { dev_info(ir->dev, "failed to get features\n"); goto out; @@ -257,13 +266,18 @@ out: static int iguanair_receiver(struct iguanair *ir, bool enable) { - struct packet packet = { 0, DIR_OUT, enable ? - CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; + int rc; + + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; if (enable) ir_raw_event_reset(ir->rc); - return iguanair_send(ir, &packet, sizeof(packet)); + rc = iguanair_send(ir, sizeof(ir->packet->header)); + + return rc; } /* @@ -308,8 +322,8 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) fours = (cycles - sevens * 7) / 4; /* magic happens here */ - ir->busy7 = (4 - sevens) * 2; - ir->busy4 = 110 - fours; + ir->packet->busy7 = (4 - sevens) * 2; + ir->packet->busy4 = 110 - fours; } mutex_unlock(&ir->lock); @@ -325,7 +339,7 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask) return 4; mutex_lock(&ir->lock); - ir->channels = mask; + ir->packet->channels = mask << 4; mutex_unlock(&ir->lock); return 0; @@ -337,16 +351,9 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) uint8_t space; unsigned i, size, periods, bytes; int rc; - struct send_packet *packet; mutex_lock(&ir->lock); - packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL); - if (!packet) { - rc = -ENOMEM; - goto out; - } - /* convert from us to carrier periods */ for (i = space = size = 0; i < count; i++) { periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); @@ -356,11 +363,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) break; } while (periods > 127) { - packet->payload[size++] = 127 | space; + ir->packet->payload[size++] = 127 | space; periods -= 127; } - packet->payload[size++] = periods | space; + ir->packet->payload[size++] = periods | space; space ^= 0x80; } @@ -369,36 +376,19 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) goto out; } - packet->header.start = 0; - packet->header.direction = DIR_OUT; - packet->header.cmd = CMD_SEND; - packet->length = size; - packet->channels = ir->channels << 4; - packet->busy7 = ir->busy7; - packet->busy4 = ir->busy4; - - if (ir->receiver_on) { - rc = iguanair_receiver(ir, false); - if (rc) { - dev_warn(ir->dev, "disable receiver before transmit failed\n"); - goto out; - } - } + ir->packet->header.start = 0; + ir->packet->header.direction = DIR_OUT; + ir->packet->header.cmd = CMD_SEND; + ir->packet->length = size; ir->tx_overflow = false; - rc = iguanair_send(ir, packet, size + 8); + rc = iguanair_send(ir, sizeof(*ir->packet) + size); if (rc == 0 && ir->tx_overflow) rc = -EOVERFLOW; - if (ir->receiver_on) { - if (iguanair_receiver(ir, true)) - dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); - } - out: - kfree(packet); mutex_unlock(&ir->lock); return rc ? rc : count; @@ -411,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev) mutex_lock(&ir->lock); - BUG_ON(ir->receiver_on); - rc = iguanair_receiver(ir, true); if (rc == 0) ir->receiver_on = true; @@ -443,7 +431,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf, struct usb_device *udev = interface_to_usbdev(intf); struct iguanair *ir; struct rc_dev *rc; - int ret, pipein; + int ret, pipein, pipeout; struct usb_host_interface *idesc; ir = kzalloc(sizeof(*ir), GFP_KERNEL); @@ -453,11 +441,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, goto out; } - ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL, + ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL, &ir->dma_in); + ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL, + &ir->dma_out); ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); + ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); - if (!ir->buf_in || !ir->urb_in) { + if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { ret = -ENOMEM; goto out; } @@ -472,13 +463,18 @@ static int __devinit iguanair_probe(struct usb_interface *intf, ir->rc = rc; ir->dev = &intf->dev; ir->udev = udev; - ir->pipe_out = usb_sndintpipe(udev, - idesc->endpoint[1].desc.bEndpointAddress); mutex_init(&ir->lock); + init_completion(&ir->completion); + pipeout = usb_sndintpipe(udev, + idesc->endpoint[1].desc.bEndpointAddress); + usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET, + iguanair_irq_out, ir, 1); + ir->urb_out->transfer_dma = ir->dma_out; + ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress); - usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE, + usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET, iguanair_rx, ir, 1); ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -528,11 +524,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, return 0; out2: usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); out: if (ir) { usb_free_urb(ir->urb_in); - usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in, - ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet, + ir->dma_out); } rc_free_device(rc); kfree(ir); @@ -546,8 +545,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf) rc_unregister_device(ir->rc); usb_set_intfdata(intf, NULL); usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); usb_free_urb(ir->urb_in); - usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in); + usb_free_urb(ir->urb_out); + usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); + usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out); kfree(ir); } @@ -565,6 +567,7 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message) } usb_kill_urb(ir->urb_in); + usb_kill_urb(ir->urb_out); mutex_unlock(&ir->lock); diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 569124b03de3..870c93052fd0 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -203,13 +203,13 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, /* TX settings */ case LIRC_SET_TRANSMITTER_MASK: if (!dev->s_tx_mask) - return -EINVAL; + return -ENOSYS; return dev->s_tx_mask(dev, val); case LIRC_SET_SEND_CARRIER: if (!dev->s_tx_carrier) - return -EINVAL; + return -ENOSYS; return dev->s_tx_carrier(dev, val); diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index c64e9e30045d..2fa71d0d72d7 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -22,24 +22,24 @@ #include <linux/module.h> static struct rc_map_table msi_digivox_ii[] = { - { 0x0002, KEY_2 }, - { 0x0003, KEY_UP }, /* up */ - { 0x0004, KEY_3 }, - { 0x0005, KEY_CHANNELDOWN }, - { 0x0008, KEY_5 }, - { 0x0009, KEY_0 }, - { 0x000b, KEY_8 }, - { 0x000d, KEY_DOWN }, /* down */ - { 0x0010, KEY_9 }, - { 0x0011, KEY_7 }, - { 0x0014, KEY_VOLUMEUP }, - { 0x0015, KEY_CHANNELUP }, - { 0x0016, KEY_OK }, - { 0x0017, KEY_POWER2 }, - { 0x001a, KEY_1 }, - { 0x001c, KEY_4 }, - { 0x001d, KEY_6 }, - { 0x001f, KEY_VOLUMEDOWN }, + { 0x0302, KEY_2 }, + { 0x0303, KEY_UP }, /* up */ + { 0x0304, KEY_3 }, + { 0x0305, KEY_CHANNELDOWN }, + { 0x0308, KEY_5 }, + { 0x0309, KEY_0 }, + { 0x030b, KEY_8 }, + { 0x030d, KEY_DOWN }, /* down */ + { 0x0310, KEY_9 }, + { 0x0311, KEY_7 }, + { 0x0314, KEY_VOLUMEUP }, + { 0x0315, KEY_CHANNELUP }, + { 0x0316, KEY_OK }, + { 0x0317, KEY_POWER2 }, + { 0x031a, KEY_1 }, + { 0x031c, KEY_4 }, + { 0x031d, KEY_6 }, + { 0x031f, KEY_VOLUMEDOWN }, }; static struct rc_map_list msi_digivox_ii_map = { diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 699eef39128b..2ea913a44ae8 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -517,6 +517,9 @@ static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier) struct nvt_dev *nvt = dev->priv; u16 val; + if (carrier == 0) + return -EINVAL; + nvt_cir_reg_write(nvt, 1, CIR_CP); val = 3000000 / (carrier) - 1; nvt_cir_reg_write(nvt, val & 0xff, CIR_CC); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 49731b1a9c57..9f5a17bb5ef5 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -890,6 +890,9 @@ static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) struct device *dev = rr3->dev; rr3_dbg(dev, "Setting modulation frequency to %u", carrier); + if (carrier == 0) + return -EINVAL; + rr3->carrier = carrier; return carrier; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 30ae1f24abc3..7c9b5f33113b 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -184,7 +184,7 @@ enum wbcir_txstate { }; /* Misc */ -#define WBCIR_NAME "Winbond CIR" +#define WBCIR_NAME "winbond-cir" #define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ #define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ #define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index 0ed9091ff48e..2e1a02e360ff 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -245,7 +245,7 @@ struct mt2063_state { /* * mt2063_write - Write data into the I2C bus */ -static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) +static int mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) { struct dvb_frontend *fe = state->frontend; int ret; @@ -277,9 +277,9 @@ static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) /* * mt2063_write - Write register data into the I2C bus, caching the value */ -static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) +static int mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) { - u32 status; + int status; dprintk(2, "\n"); @@ -298,10 +298,10 @@ static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) /* * mt2063_read - Read data from the I2C bus */ -static u32 mt2063_read(struct mt2063_state *state, +static int mt2063_read(struct mt2063_state *state, u8 subAddress, u8 *pData, u32 cnt) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ struct dvb_frontend *fe = state->frontend; u32 i = 0; @@ -816,7 +816,7 @@ static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, */ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) { - u32 status = 0; + int status = 0; u32 fm, fp; /* restricted range on LO's */ pAS_Info->bSpurAvoided = 0; pAS_Info->nSpursFound = 0; @@ -935,14 +935,14 @@ static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) * * This function returns 0, if no lock, 1 if locked and a value < 1 if error */ -static unsigned int mt2063_lockStatus(struct mt2063_state *state) +static int mt2063_lockStatus(struct mt2063_state *state) { const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ const u32 nPollRate = 2; /* poll status bits every 2 ms */ const u32 nMaxLoops = nMaxWait / nPollRate; const u8 LO1LK = 0x80; u8 LO2LK = 0x08; - u32 status; + int status; u32 nDelays = 0; dprintk(2, "\n"); @@ -1069,7 +1069,7 @@ static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, enum MT2063_DNC_Output_Enable nValue) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val = 0; dprintk(2, "\n"); @@ -1203,7 +1203,7 @@ static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, static u32 MT2063_SetReceiverMode(struct mt2063_state *state, enum mt2063_delivery_sys Mode) { - u32 status = 0; /* Status to be returned */ + int status = 0; /* Status to be returned */ u8 val; u32 longval; @@ -1345,7 +1345,7 @@ static u32 MT2063_SetReceiverMode(struct mt2063_state *state, static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, enum MT2063_Mask_Bits Bits) { - u32 status = 0; + int status = 0; dprintk(2, "\n"); Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ @@ -1374,7 +1374,7 @@ static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, */ static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) { - u32 status; + int status; dprintk(2, "\n"); if (Shutdown == 1) @@ -1540,7 +1540,7 @@ static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) { /* RF input center frequency */ - u32 status = 0; + int status = 0; u32 LO1; /* 1st LO register value */ u32 Num1; /* Numerator for LO1 reg. value */ u32 f_IF1; /* 1st IF requested */ @@ -1803,7 +1803,7 @@ static const u8 MT2063B3_defaults[] = { static int mt2063_init(struct dvb_frontend *fe) { - u32 status; + int status; struct mt2063_state *state = fe->tuner_priv; u8 all_resets = 0xF0; /* reset/load bits */ const u8 *def = NULL; @@ -2249,8 +2249,8 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, dprintk(2, "\n"); state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); - if (state == NULL) - goto error; + if (!state) + return NULL; state->config = config; state->i2c = i2c; @@ -2261,18 +2261,15 @@ struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, printk(KERN_INFO "%s: Attaching MT2063\n", __func__); return fe; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL_GPL(mt2063_attach); +#if 0 /* * Ancillary routines visible outside mt2063 * FIXME: Remove them in favor of using standard tuner callbacks */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) +static int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2285,9 +2282,8 @@ unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) +static int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; int err = 0; @@ -2300,7 +2296,7 @@ unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) return err; } -EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); +#endif MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); MODULE_DESCRIPTION("MT2063 Silicon tuner"); diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h index 3f5cfd93713f..ab24170c1571 100644 --- a/drivers/media/tuners/mt2063.h +++ b/drivers/media/tuners/mt2063.h @@ -23,10 +23,6 @@ static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, return NULL; } -/* FIXME: Should use the standard DVB attachment interfaces */ -unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); -unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); - #endif /* CONFIG_DVB_MT2063 */ #endif /* __MT2063_H__ */ diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index 221171eeb0c3..18c77afe2e4f 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -187,7 +187,8 @@ int tda18271_read_extended(struct dvb_frontend *fe) return (ret == 2 ? 0 : ret); } -int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -198,7 +199,6 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) BUG_ON((len == 0) || (idx + len > sizeof(buf))); - switch (priv->small_i2c) { case TDA18271_03_BYTE_CHUNK_INIT: max = 3; @@ -214,7 +214,19 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) max = 39; } - tda18271_i2c_gate_ctrl(fe, 1); + + /* + * If lock_i2c is true, it will take the I2C bus for tda18271 private + * usage during the entire write ops, as otherwise, bad things could + * happen. + * During device init, several write operations will happen. So, + * tda18271_init_regs controls the I2C lock directly, + * disabling lock_i2c here. + */ + if (lock_i2c) { + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + } while (len) { if (max > len) max = len; @@ -226,14 +238,17 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) msg.len = max + 1; /* write registers */ - ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); + ret = __i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) break; idx += max; len -= max; } - tda18271_i2c_gate_ctrl(fe, 0); + if (lock_i2c) { + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); + } if (ret != 1) tda_err("ERROR: idx = 0x%x, len = %d, " @@ -242,10 +257,16 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) return (ret == 1 ? 0 : ret); } +int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) +{ + return __tda18271_write_regs(fe, idx, len, true); +} + /*---------------------------------------------------------------------*/ -int tda18271_charge_pump_source(struct dvb_frontend *fe, - enum tda18271_pll pll, int force) +static int __tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force, + bool lock_i2c) { struct tda18271_priv *priv = fe->tuner_priv; unsigned char *regs = priv->tda18271_regs; @@ -255,9 +276,16 @@ int tda18271_charge_pump_source(struct dvb_frontend *fe, regs[r_cp] &= ~0x20; regs[r_cp] |= ((force & 1) << 5); - return tda18271_write_regs(fe, r_cp, 1); + return __tda18271_write_regs(fe, r_cp, 1, lock_i2c); +} + +int tda18271_charge_pump_source(struct dvb_frontend *fe, + enum tda18271_pll pll, int force) +{ + return __tda18271_charge_pump_source(fe, pll, force, true); } + int tda18271_init_regs(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -267,6 +295,13 @@ int tda18271_init_regs(struct dvb_frontend *fe) i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); + /* + * Don't let any other I2C transfer to happen at adapter during init, + * as those could cause bad things + */ + tda18271_i2c_gate_ctrl(fe, 1); + i2c_lock_adapter(priv->i2c_props.adap); + /* initialize registers */ switch (priv->id) { case TDA18271HDC1: @@ -352,28 +387,28 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_EB22] = 0x48; regs[R_EB23] = 0xb0; - tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); + __tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS, false); /* setup agc1 gain */ regs[R_EB17] = 0x00; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x03; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x43; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); regs[R_EB17] = 0x4c; - tda18271_write_regs(fe, R_EB17, 1); + __tda18271_write_regs(fe, R_EB17, 1, false); /* setup agc2 gain */ if ((priv->id) == TDA18271HDC1) { regs[R_EB20] = 0xa0; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xa7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xe7; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); regs[R_EB20] = 0xec; - tda18271_write_regs(fe, R_EB20, 1); + __tda18271_write_regs(fe, R_EB20, 1, false); } /* image rejection calibration */ @@ -391,21 +426,21 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD2] = 0x08; regs[R_MD3] = 0x00; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); if ((priv->id) == TDA18271HDC2) { /* main pll cp source on */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1, false); msleep(1); /* main pll cp source off */ - tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); + __tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0, false); } msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted low measurement */ regs[R_EP5] = 0x85; @@ -413,11 +448,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0x70; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image low optimization completion */ /* mid-band */ @@ -428,11 +463,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x73; regs[R_MD2] = 0x1a; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted mid measurement */ regs[R_EP5] = 0x86; @@ -440,11 +475,11 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_CD1] = 0x66; regs[R_CD2] = 0xa0; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image mid optimization completion */ /* high-band */ @@ -456,30 +491,33 @@ int tda18271_init_regs(struct dvb_frontend *fe) regs[R_MD1] = 0x71; regs[R_MD2] = 0xcd; - tda18271_write_regs(fe, R_EP3, 11); + __tda18271_write_regs(fe, R_EP3, 11, false); msleep(5); /* pll locking */ /* launch detector */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); msleep(5); /* wanted high measurement */ regs[R_EP5] = 0x87; regs[R_CD1] = 0x65; regs[R_CD2] = 0x50; - tda18271_write_regs(fe, R_EP3, 7); + __tda18271_write_regs(fe, R_EP3, 7, false); msleep(5); /* pll locking */ /* launch optimization algorithm */ - tda18271_write_regs(fe, R_EP2, 1); + __tda18271_write_regs(fe, R_EP2, 1, false); msleep(30); /* image high optimization completion */ /* return to normal mode */ regs[R_EP4] = 0x64; - tda18271_write_regs(fe, R_EP4, 1); + __tda18271_write_regs(fe, R_EP4, 1, false); /* synchronize */ - tda18271_write_regs(fe, R_EP1, 1); + __tda18271_write_regs(fe, R_EP1, 1, false); + + i2c_unlock_adapter(priv->i2c_props.adap); + tda18271_i2c_gate_ctrl(fe, 0); return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 824f1911ee21..3d7526e28d42 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -500,7 +500,7 @@ static int af9015_read_config(struct dvb_usb_device *d) case 3: state->af9013_config[i].clock = 25000000; break; - }; + } dev_dbg(&d->udev->dev, "%s: [%d] xtal=%d set clock=%d\n", __func__, i, val, state->af9013_config[i].clock); @@ -568,7 +568,7 @@ static int af9015_read_config(struct dvb_usb_device *d) "supported, please report!\n", KBUILD_MODNAME, val); return -ENODEV; - }; + } state->af9013_config[i].tuner = val; dev_dbg(&d->udev->dev, "%s: [%d] tuner id=%d\n", diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index aabd3fc03ea7..ea27eaff4e34 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -520,7 +520,7 @@ static int af9035_read_config(struct dvb_usb_device *d) dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \ "supported, please report!", KBUILD_MODNAME, tmp); - }; + } /* tuner IF frequency */ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 8d7fef84afd8..83684ed023cd 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -93,7 +93,7 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) /* call the universal NEC remote processor, to find out the key's state and event */ dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); ret = 0; out: kfree(key); diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 0a98548ecd17..9fd1527494eb 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -172,8 +172,7 @@ static int cinergyt2_rc_query(struct dvb_usb_device *d, u32 *event, int *state) if (*event != d->last_event) st->rc_counter = 0; - deb_rc("key: %x %x %x %x %x\n", - key[0], key[1], key[2], key[3], key[4]); + deb_rc("key: %*ph\n", 5, key); } return 0; } diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index a76bbb29ca36..af0d4321845b 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -473,7 +473,7 @@ int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } EXPORT_SYMBOL(dibusb_rc_query); diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index ff34419a4c88..772bde3c5020 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -253,7 +253,7 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state) } if (key[0] != 0) - deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_rc("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index 66f205c112b2..c357fb3b0a88 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -84,7 +84,7 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state) dvb_usb_generic_rw(d,&cmd,1,key,5,0); dvb_usb_nec_rc_key_to_event(d,key,event,state); if (key[0] != 0) - deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]); + deb_info("key: %*ph\n", 5, key); return 0; } diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 288af29a8bb7..661bb75be955 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -358,7 +358,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0) goto done; - deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]); + deb("%*ph\n", 4, read); if ((ret = m920x_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0) goto done; diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index acefaa89cc53..7a8c8c18590f 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -677,6 +677,7 @@ static struct usb_device_id technisat_usb2_id_table[] = { { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, { 0 } /* Terminating entry */ }; +MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table); /* device description */ static struct dvb_usb_device_properties technisat_usb2_devices = { diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index f7297ae76b48..16a84f9f46d8 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2203,7 +2203,7 @@ EXPORT_SYMBOL_GPL(em28xx_tuner_callback); static inline void em28xx_set_model(struct em28xx *dev) { - memcpy(&dev->board, &em28xx_boards[dev->model], sizeof(dev->board)); + dev->board = em28xx_boards[dev->model]; /* Those are the default values for the majority of boards Use those values if not specified otherwise at boards entry diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 913e5227897a..13ae821949e9 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -574,18 +574,19 @@ static void pctv_520e_init(struct em28xx *dev) i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); }; -static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) +static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx *dev = fe->dvb->priv; #ifdef CONFIG_GPIOLIB struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; - if (val) - flags = GPIOF_OUT_INIT_LOW; + if (c->lna == 1) + flags = GPIOF_OUT_INIT_HIGH; /* enable LNA */ else - flags = GPIOF_OUT_INIT_HIGH; + flags = GPIOF_OUT_INIT_LOW; /* disable LNA */ ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) @@ -595,8 +596,8 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe, int val) return ret; #else - dev_warn(&dev->udev->dev, "%s: LNA control is disabled\n", - KBUILD_MODNAME); + dev_warn(&dev->udev->dev, "%s: LNA control is disabled (lna=%u)\n", + KBUILD_MODNAME, c->lna); return 0; #endif } diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index b62740846061..34a26e0cfe77 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -100,12 +100,21 @@ int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value) void stk1160_select_input(struct stk1160 *dev) { + int route; static const u8 gctrl[] = { - 0x98, 0x90, 0x88, 0x80 + 0x98, 0x90, 0x88, 0x80, 0x98 }; - if (dev->ctl_input < ARRAY_SIZE(gctrl)) + if (dev->ctl_input == STK1160_SVIDEO_INPUT) + route = SAA7115_SVIDEO3; + else + route = SAA7115_COMPOSITE0; + + if (dev->ctl_input < ARRAY_SIZE(gctrl)) { + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, + route, 0, 0); stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]); + } } /* TODO: We should break this into pieces */ @@ -351,8 +360,6 @@ static int stk1160_probe(struct usb_interface *interface, /* i2c reset saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing, - 0, 0, 0); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); /* reset stk1160 to default values */ diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index fe6e857969ca..6694f9e2ca57 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -419,7 +419,12 @@ static int vidioc_enum_input(struct file *file, void *priv, if (i->index > STK1160_MAX_INPUT) return -EINVAL; - sprintf(i->name, "Composite%d", i->index); + /* S-Video special handling */ + if (i->index == STK1160_SVIDEO_INPUT) + sprintf(i->name, "S-Video"); + else + sprintf(i->name, "Composite%d", i->index); + i->type = V4L2_INPUT_TYPE_CAMERA; i->std = dev->vdev.tvnorms; return 0; diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 3feba0033f98..68c8707d36ab 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -46,7 +46,8 @@ #define STK1160_MIN_PKT_SIZE 3072 -#define STK1160_MAX_INPUT 3 +#define STK1160_MAX_INPUT 4 +#define STK1160_SVIDEO_INPUT 4 #define STK1160_I2C_TIMEOUT 100 diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 5577381b5bf0..18a91fae6bc1 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -122,21 +122,27 @@ static struct vb2_ops uvc_queue_qops = { .buf_finish = uvc_buffer_finish, }; -void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, +int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted) { + int ret; + queue->queue.type = type; queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; queue->queue.drv_priv = queue; queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; - vb2_queue_init(&queue->queue); + ret = vb2_queue_init(&queue->queue); + if (ret) + return ret; mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->irqqueue); queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0; + + return 0; } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 1c15b4227bdb..57c3076a4625 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1755,7 +1755,9 @@ int uvc_video_init(struct uvc_streaming *stream) atomic_set(&stream->active, 0); /* Initialize the video buffers queue. */ - uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); + if (ret) + return ret; /* Alternate setting 0 should be the default, yet the XBox Live Vision * Cam (and possibly other devices) crash or otherwise misbehave if diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 3764040475bb..af216ec45e39 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -600,7 +600,7 @@ extern struct uvc_driver uvc_driver; extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); /* Video buffers queue management. */ -extern void uvc_queue_init(struct uvc_video_queue *queue, +extern int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int drop_corrupted); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, struct v4l2_requestbuffers *rb); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 631cdc0e0bda..f6ee201d9347 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -384,6 +384,25 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Extended SAR", NULL, }; + static const char * const h264_fp_arrangement_type[] = { + "Checkerboard", + "Column", + "Row", + "Side by Side", + "Top Bottom", + "Temporal", + NULL, + }; + static const char * const h264_fmo_map_type[] = { + "Interleaved Slices", + "Scattered Slices", + "Foreground with Leftover", + "Box Out", + "Raster Scan", + "Wipe Scan", + "Explicit", + NULL, + }; static const char * const mpeg_mpeg4_level[] = { "0", "0b", @@ -508,6 +527,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_profile; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return vui_sar_idc; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + return h264_fp_arrangement_type; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + return h264_fmo_map_type; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return mpeg_mpeg4_level; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: @@ -643,6 +666,22 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: return "Horizontal Size of SAR"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: return "Aspect Ratio VUI Enable"; case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: return "VUI Aspect Ratio IDC"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: return "H264 Enable Frame Packing SEI"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: return "H264 Set Curr. Frame as Frame0"; + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: return "H264 FP Arrangement Type"; + case V4L2_CID_MPEG_VIDEO_H264_FMO: return "H264 Flexible MB Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return "H264 Map Type for FMO"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: return "H264 FMO Number of Slice Groups"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: return "H264 FMO Direction of Change"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: return "H264 FMO Size of 1st Slice Grp"; + case V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: return "H264 FMO No. of Consecutive MBs"; + case V4L2_CID_MPEG_VIDEO_H264_ASO: return "H264 Arbitrary Slice Ordering"; + case V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: return "H264 ASO Slice Order"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: return "Enable H264 Hierarchical Coding"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: return "H264 Hierarchical Coding Type"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:return "H264 Number of HC Layers"; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: + return "H264 Set QP Value for HC Layers"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -657,6 +696,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -749,6 +789,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls"; case V4L2_CID_LINK_FREQ: return "Link Frequency"; case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; + case V4L2_CID_TEST_PATTERN: return "Test Pattern"; /* DV controls */ case V4L2_CID_DV_CLASS: return "Digital Video Controls"; @@ -853,6 +894,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: case V4L2_CID_MPEG_VIDEO_H264_PROFILE: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: @@ -862,6 +905,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_TX_MODE: case V4L2_CID_DV_TX_RGB_RANGE: case V4L2_CID_DV_RX_RGB_RANGE: + case V4L2_CID_TEST_PATTERN: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -1648,6 +1692,36 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, } EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); +/* Helper function for standard menu controls with driver defined menu */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu) +{ + enum v4l2_ctrl_type type; + const char *name; + u32 flags; + s32 step; + s32 min; + + /* v4l2_ctrl_new_std_menu_items() should only be called for + * standard controls without a standard menu. + */ + if (v4l2_ctrl_get_menu(id)) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, id, name, type, 0, max, mask, def, + flags, qmenu, NULL, NULL); + +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); + /* Helper function for standard integer menu controls */ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 9d3e46c446ad..8f388ff31ebb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -157,8 +157,7 @@ static const char *v4l2_memory_names[] = { [V4L2_MEMORY_OVERLAY] = "overlay", }; -#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ - arr[a] : "unknown") +#define prt_names(a, arr) (((unsigned)(a)) < ARRAY_SIZE(arr) ? arr[a] : "unknown") /* ------------------------------------------------------------------ */ /* debug help functions */ @@ -2188,6 +2187,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, int ret = 0; switch (cmd) { + case VIDIOC_PREPARE_BUF: case VIDIOC_QUERYBUF: case VIDIOC_QBUF: case VIDIOC_DQBUF: { @@ -2211,6 +2211,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_subdev_edid *edid = parg; if (edid->blocks) { + if (edid->blocks > 256) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)edid->edid; *kernel_ptr = (void *)&edid->edid; *array_size = edid->blocks * 128; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index e6a26b433e87..432df119af27 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -276,6 +276,9 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) */ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer *b) { + if (!V4L2_TYPE_IS_MULTIPLANAR(b->type)) + return 0; + /* Is memory for copying plane information present? */ if (NULL == b->m.planes) { dprintk(1, "Multi-planar buffer passed but " @@ -331,10 +334,9 @@ static bool __buffers_in_use(struct vb2_queue *q) * __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be * returned to userspace */ -static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) +static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) { struct vb2_queue *q = vb->vb2_queue; - int ret; /* Copy back data such as timestamp, flags, etc. */ memcpy(b, &vb->v4l2_buf, offsetof(struct v4l2_buffer, m)); @@ -342,14 +344,11 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->reserved = vb->v4l2_buf.reserved; if (V4L2_TYPE_IS_MULTIPLANAR(q->type)) { - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* * Fill in plane-related data if userspace provided an array - * for it. The memory and size is verified above. + * for it. The caller has already verified memory and size. */ + b->length = vb->num_planes; memcpy(b->m.planes, vb->v4l2_planes, b->length * sizeof(struct v4l2_plane)); } else { @@ -391,8 +390,6 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) if (__buffer_in_use(q, vb)) b->flags |= V4L2_BUF_FLAG_MAPPED; - - return 0; } /** @@ -411,6 +408,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; + int ret; if (b->type != q->type) { dprintk(1, "querybuf: wrong buffer type\n"); @@ -422,8 +420,10 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) return -EINVAL; } vb = q->bufs[b->index]; - - return __fill_v4l2_buffer(vb, b); + ret = __verify_planes_array(vb, b); + if (!ret) + __fill_v4l2_buffer(vb, b); + return ret; } EXPORT_SYMBOL(vb2_querybuf); @@ -813,24 +813,16 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) EXPORT_SYMBOL_GPL(vb2_buffer_done); /** - * __fill_vb2_buffer() - fill a vb2_buffer with information provided in - * a v4l2_buffer by the userspace + * __fill_vb2_buffer() - fill a vb2_buffer with information provided in a + * v4l2_buffer by the userspace. The caller has already verified that struct + * v4l2_buffer has a valid number of planes. */ -static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, +static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, struct v4l2_plane *v4l2_planes) { unsigned int plane; - int ret; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { - /* - * Verify that the userspace gave us a valid array for - * plane information. - */ - ret = __verify_planes_array(vb, b); - if (ret) - return ret; - /* Fill in driver-provided information for OUTPUT types */ if (V4L2_TYPE_IS_OUTPUT(b->type)) { /* @@ -872,8 +864,6 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b, vb->v4l2_buf.field = b->field; vb->v4l2_buf.timestamp = b->timestamp; vb->v4l2_buf.flags = b->flags & ~V4L2_BUFFER_STATE_FLAGS; - - return 0; } /** @@ -888,10 +878,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b) int ret; int write = !V4L2_TYPE_IS_OUTPUT(q->type); - /* Verify and copy relevant information provided by the userspace */ - ret = __fill_vb2_buffer(vb, b, planes); - if (ret) - return ret; + /* Copy relevant information provided by the userspace */ + __fill_vb2_buffer(vb, b, planes); for (plane = 0; plane < vb->num_planes; ++plane) { /* Skip the plane if already verified */ @@ -966,7 +954,8 @@ err: */ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) { - return __fill_vb2_buffer(vb, b, vb->v4l2_planes); + __fill_vb2_buffer(vb, b, vb->v4l2_planes); + return 0; } /** @@ -1059,7 +1048,9 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b) dprintk(1, "%s(): invalid buffer state %d\n", __func__, vb->state); return -EINVAL; } - + ret = __verify_planes_array(vb, b); + if (ret < 0) + return ret; ret = __buf_prepare(vb, b); if (ret < 0) return ret; @@ -1147,6 +1138,9 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) ret = -EINVAL; goto unlock; } + ret = __verify_planes_array(vb, b); + if (ret) + goto unlock; switch (vb->state) { case VB2_BUF_STATE_DEQUEUED: @@ -1243,8 +1237,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * the locks or return an error if one occurred. */ call_qop(q, wait_finish, q); - if (ret) + if (ret) { + dprintk(1, "Sleep was interrupted\n"); return ret; + } } return 0; } @@ -1255,7 +1251,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * Will sleep if required for nonblocking == false. */ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, - int nonblocking) + struct v4l2_buffer *b, int nonblocking) { unsigned long flags; int ret; @@ -1273,10 +1269,16 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb, */ spin_lock_irqsave(&q->done_lock, flags); *vb = list_first_entry(&q->done_list, struct vb2_buffer, done_entry); - list_del(&(*vb)->done_entry); + /* + * Only remove the buffer from done_list if v4l2_buffer can handle all + * the planes. + */ + ret = __verify_planes_array(*vb, b); + if (!ret) + list_del(&(*vb)->done_entry); spin_unlock_irqrestore(&q->done_lock, flags); - return 0; + return ret; } /** @@ -1335,12 +1337,9 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) dprintk(1, "dqbuf: invalid buffer type\n"); return -EINVAL; } - - ret = __vb2_get_done_vb(q, &vb, nonblocking); - if (ret < 0) { - dprintk(1, "dqbuf: error getting next done buffer\n"); + ret = __vb2_get_done_vb(q, &vb, b, nonblocking); + if (ret < 0) return ret; - } ret = call_qop(q, buf_finish, vb); if (ret) { diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index ec6209dd7c39..debaa75b0552 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -725,10 +725,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), - /* Other alt C1 column, these are still configured as alt C */ - DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C), + /* Other alt C1 column */ + DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1), }; /* We use this macro to define the groups applicable to a function */ @@ -860,6 +860,284 @@ static const struct nmk_function nmk_db8500_functions[] = { FUNCTION(spi2), }; +static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = { + PRCM_GPIOCR_ALTCX(23, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_CLK_a */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_CLK_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(24, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE or U2_RXD ??? */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_VAL_a */ + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(25, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[0] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[0] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(26, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[1] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[1] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(27, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[2] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[2] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(28, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[3] */ + true, PRCM_IDX_GPIOCR1, 7, /* SBAG_D_a[3] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(29, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(30, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(31, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(32, false, 0, 0, + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 10, /* STM_MOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(68, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(69, true, PRCM_IDX_GPIOCR1, 18, /* REMAP_SELECT_ON */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(70, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D23 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_CLK */ + ), + PRCM_GPIOCR_ALTCX(71, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D22 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D3 */ + ), + PRCM_GPIOCR_ALTCX(72, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D21 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D2 */ + ), + PRCM_GPIOCR_ALTCX(73, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D20 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D1 */ + ), + PRCM_GPIOCR_ALTCX(74, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D19 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 11, /* STM_MOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_D0 */ + ), + PRCM_GPIOCR_ALTCX(75, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D18 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(76, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D17 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + true, PRCM_IDX_GPIOCR1, 0, /* DBG_UARTMOD_CMD0 */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(77, true, PRCM_IDX_GPIOCR1, 5, /* PTM_A9_D16 */ + true, PRCM_IDX_GPIOCR2, 2, /* DBG_ETM_R4_CMD0 */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 8 /* SBAG_VAL */ + ), + PRCM_GPIOCR_ALTCX(86, true, PRCM_IDX_GPIOCR1, 12, /* KP_O3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(87, true, PRCM_IDX_GPIOCR1, 12, /* KP_O2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(88, true, PRCM_IDX_GPIOCR1, 12, /* KP_I3 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(89, true, PRCM_IDX_GPIOCR1, 12, /* KP_I2 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(90, true, PRCM_IDX_GPIOCR1, 12, /* KP_O1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(91, true, PRCM_IDX_GPIOCR1, 12, /* KP_O0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(92, true, PRCM_IDX_GPIOCR1, 12, /* KP_I1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(93, true, PRCM_IDX_GPIOCR1, 12, /* KP_I0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(96, true, PRCM_IDX_GPIOCR2, 3, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(97, true, PRCM_IDX_GPIOCR2, 1, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(151, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CTL */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS17 */ + ), + PRCM_GPIOCR_ALTCX(152, true, PRCM_IDX_GPIOCR1, 4, /* Hx_CLK */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_CLK */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS16 */ + ), + PRCM_GPIOCR_ALTCX(153, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D15 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS15 */ + ), + PRCM_GPIOCR_ALTCX(154, true, PRCM_IDX_GPIOCR1, 1, /* UARTMOD_CMD1 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D14 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS14 */ + ), + PRCM_GPIOCR_ALTCX(155, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D13 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS13 */ + ), + PRCM_GPIOCR_ALTCX(156, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D12 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS12 */ + ), + PRCM_GPIOCR_ALTCX(157, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D11 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS11 */ + ), + PRCM_GPIOCR_ALTCX(158, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D10 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS10 */ + ), + PRCM_GPIOCR_ALTCX(159, true, PRCM_IDX_GPIOCR1, 13, /* STM_MOD_CMD2 */ + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D9 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS9 */ + ), + PRCM_GPIOCR_ALTCX(160, false, 0, 0, + true, PRCM_IDX_GPIOCR1, 14, /* PTM_A9_D8 */ + true, PRCM_IDX_GPIOCR1, 19, /* DBG_ETM_R4_CMD2 */ + true, PRCM_IDX_GPIOCR1, 25 /* HW_OBS8 */ + ), + PRCM_GPIOCR_ALTCX(161, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO7 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D7 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS7 */ + ), + PRCM_GPIOCR_ALTCX(162, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO6 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D6 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS6 */ + ), + PRCM_GPIOCR_ALTCX(163, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO5 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D5 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS5 */ + ), + PRCM_GPIOCR_ALTCX(164, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO4 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D4 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS4 */ + ), + PRCM_GPIOCR_ALTCX(165, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO3 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D3 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS3 */ + ), + PRCM_GPIOCR_ALTCX(166, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO2 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D2 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS2 */ + ), + PRCM_GPIOCR_ALTCX(167, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO1 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D1 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS1 */ + ), + PRCM_GPIOCR_ALTCX(168, true, PRCM_IDX_GPIOCR1, 4, /* Hx_GPIO0 */ + true, PRCM_IDX_GPIOCR1, 6, /* PTM_A9_D0 */ + true, PRCM_IDX_GPIOCR1, 15, /* DBG_ETM_R4_CMD1*/ + true, PRCM_IDX_GPIOCR1, 24 /* HW_OBS0 */ + ), + PRCM_GPIOCR_ALTCX(170, true, PRCM_IDX_GPIOCR2, 2, /* RF_INT */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(171, true, PRCM_IDX_GPIOCR2, 0, /* RF_CTRL */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(215, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_TXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(216, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_FRM */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(217, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_CLK */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(218, true, PRCM_IDX_GPIOCR1, 23, /* SPI2_RXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), +}; + +static const u16 db8500_prcm_gpiocr_regs[] = { + [PRCM_IDX_GPIOCR1] = 0x138, + [PRCM_IDX_GPIOCR2] = 0x574, +}; + static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { .gpio_ranges = nmk_db8500_ranges, .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges), @@ -869,6 +1147,9 @@ static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { .nfunctions = ARRAY_SIZE(nmk_db8500_functions), .groups = nmk_db8500_groups, .ngroups = ARRAY_SIZE(nmk_db8500_groups), + .altcx_pins = db8500_altcx_pins, + .npins_altcx = ARRAY_SIZE(db8500_altcx_pins), + .prcm_gpiocr_registers = db8500_prcm_gpiocr_regs, }; void __devinit diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c index 3daf665c84c3..52fc30181f7e 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c @@ -778,50 +778,50 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8540_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), - /* Other alt C1 column, these are still configured as alt C */ - DB8540_PIN_GROUP(spi3_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsrefclk_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobspwrctrl_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsclkout_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modprcmudbg_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsresout_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccgpo_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modxmip_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(i2c6_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2txrx_oc1_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2ctsrts_oc1_1, NMK_GPIO_ALT_C), + /* Other alt C1 column */ + DB8540_PIN_GROUP(spi3_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsrefclk_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobspwrctrl_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsclkout_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(moduart1_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modprcmudbg_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modobsresout_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modaccgpo_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(modxmip_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(i2c6_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2txrx_oc1_1, NMK_GPIO_ALT_C1), + DB8540_PIN_GROUP(u2ctsrts_oc1_1, NMK_GPIO_ALT_C1), - /* Other alt C2 column, these are still configured as alt C */ - DB8540_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(hxclk_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuart_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmmod_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduartstmmux_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(hxgpio_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(sbag_oc2_2, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modobsservice_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart0_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmape_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(u2_oc2_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modxmip_oc2_1, NMK_GPIO_ALT_C), + /* Other alt C2 column */ + DB8540_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(hxclk_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modaccuart_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(stmmod_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(moduartstmmux_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(hxgpio_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(sbag_oc2_2, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modobsservice_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(moduart0_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(stmape_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(u2_oc2_1, NMK_GPIO_ALT_C2), + DB8540_PIN_GROUP(modxmip_oc2_1, NMK_GPIO_ALT_C2), - /* Other alt C3 column, these are still configured as alt C */ - DB8540_PIN_GROUP(modaccgpo_oc3_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(tpui_oc3_1, NMK_GPIO_ALT_C), + /* Other alt C3 column */ + DB8540_PIN_GROUP(modaccgpo_oc3_1, NMK_GPIO_ALT_C3), + DB8540_PIN_GROUP(tpui_oc3_1, NMK_GPIO_ALT_C3), - /* Other alt C4 column, these are still configured as alt C */ - DB8540_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1txrx_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(moduart1rtscts_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C), - DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C), + /* Other alt C4 column */ + DB8540_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduart1txrx_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduart1rtscts_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4), }; @@ -981,6 +981,265 @@ static const struct nmk_function nmk_db8540_functions[] = { FUNCTION(usb) }; +static const struct prcm_gpiocr_altcx_pin_desc db8540_altcx_pins[] = { + PRCM_GPIOCR_ALTCX(8, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_CLK */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(9, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_RXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(10, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_FRM */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(11, true, PRCM_IDX_GPIOCR1, 20, /* SPI3_TXD */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(23, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_CLK_a */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_CLK_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(24, true, PRCM_IDX_GPIOCR3, 30, /* U2_RXD_g */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_VAL_a */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(25, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[0] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[0] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(26, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[1] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[1] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(27, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[2] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[2] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(28, true, PRCM_IDX_GPIOCR1, 9, /* STMAPE_DAT_a[3] */ + true, PRCM_IDX_GPIOCR2, 10, /* SBAG_D_a[3] */ + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(64, true, PRCM_IDX_GPIOCR1, 15, /* MODOBS_REFCLK_REQ */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_CTL */ + true, PRCM_IDX_GPIOCR2, 23 /* HW_OBS_APE_PRCMU[17] */ + ), + PRCM_GPIOCR_ALTCX(65, true, PRCM_IDX_GPIOCR1, 19, /* MODOBS_PWRCTRL0 */ + true, PRCM_IDX_GPIOCR1, 24, /* Hx_CLK */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_CLK */ + true, PRCM_IDX_GPIOCR2, 24 /* HW_OBS_APE_PRCMU[16] */ + ), + PRCM_GPIOCR_ALTCX(66, true, PRCM_IDX_GPIOCR1, 15, /* MODOBS_CLKOUT1 */ + false, 0, 0, + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[15] */ + true, PRCM_IDX_GPIOCR2, 25 /* HW_OBS_APE_PRCMU[15] */ + ), + PRCM_GPIOCR_ALTCX(67, true, PRCM_IDX_GPIOCR1, 1, /* MODUART1_TXD_a */ + true, PRCM_IDX_GPIOCR1, 6, /* MODACCUART_TXD_a */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[14] */ + true, PRCM_IDX_GPIOCR2, 26 /* HW_OBS_APE_PRCMU[14] */ + ), + PRCM_GPIOCR_ALTCX(70, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[17] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_CLK_b */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[13] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[13] */ + ), + PRCM_GPIOCR_ALTCX(71, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[16] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[3] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[12] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[12] */ + ), + PRCM_GPIOCR_ALTCX(72, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[15] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[2] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[11] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[11] */ + ), + PRCM_GPIOCR_ALTCX(73, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[14] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[1] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[10] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[10] */ + ), + PRCM_GPIOCR_ALTCX(74, true, PRCM_IDX_GPIOCR3, 6, /* MOD_PRCMU_DEBUG[13] */ + true, PRCM_IDX_GPIOCR1, 10, /* STMMOD_DAT_b[0] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[9] */ + true, PRCM_IDX_GPIOCR2, 27 /* HW_OBS_APE_PRCMU[9] */ + ), + PRCM_GPIOCR_ALTCX(75, true, PRCM_IDX_GPIOCR1, 12, /* MODOBS_RESOUT0_N */ + true, PRCM_IDX_GPIOCR2, 1, /* MODUART_STMMUX_RXD_b */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[8] */ + true, PRCM_IDX_GPIOCR2, 28 /* HW_OBS_APE_PRCMU[8] */ + ), + PRCM_GPIOCR_ALTCX(76, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[12] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[7] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[7] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[7] */ + ), + PRCM_GPIOCR_ALTCX(77, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[11] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[6] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[6] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[6] */ + ), + PRCM_GPIOCR_ALTCX(78, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[10] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[5] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[5] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[5] */ + ), + PRCM_GPIOCR_ALTCX(79, true, PRCM_IDX_GPIOCR3, 7, /* MOD_PRCMU_DEBUG[9] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[4] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[4] */ + true, PRCM_IDX_GPIOCR2, 29 /* HW_OBS_APE_PRCMU[4] */ + ), + PRCM_GPIOCR_ALTCX(80, true, PRCM_IDX_GPIOCR1, 26, /* MODACC_GPO[0] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[3] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[3] */ + true, PRCM_IDX_GPIOCR2, 30 /* HW_OBS_APE_PRCMU[3] */ + ), + PRCM_GPIOCR_ALTCX(81, true, PRCM_IDX_GPIOCR2, 17, /* MODACC_GPO[1] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[2] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[2] */ + true, PRCM_IDX_GPIOCR2, 30 /* HW_OBS_APE_PRCMU[2] */ + ), + PRCM_GPIOCR_ALTCX(82, true, PRCM_IDX_GPIOCR3, 8, /* MOD_PRCMU_DEBUG[8] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[1] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[1] */ + true, PRCM_IDX_GPIOCR2, 31 /* HW_OBS_APE_PRCMU[1] */ + ), + PRCM_GPIOCR_ALTCX(83, true, PRCM_IDX_GPIOCR3, 8, /* MOD_PRCMU_DEBUG[7] */ + true, PRCM_IDX_GPIOCR1, 25, /* Hx_GPIO[0] */ + true, PRCM_IDX_GPIOCR1, 2, /* TPIU_D[0] */ + true, PRCM_IDX_GPIOCR2, 31 /* HW_OBS_APE_PRCMU[0] */ + ), + PRCM_GPIOCR_ALTCX(84, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_CLK_b */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[23] */ + true, PRCM_IDX_GPIOCR1, 16 /* MODUART1_RXD_b */ + ), + PRCM_GPIOCR_ALTCX(85, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[5] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[3] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[22] */ + true, PRCM_IDX_GPIOCR1, 16 /* MODUART1_TXD_b */ + ), + PRCM_GPIOCR_ALTCX(86, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[0] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[0] */ + true, PRCM_IDX_GPIOCR1, 14, /* TPIU_D[25] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[0] */ + ), + PRCM_GPIOCR_ALTCX(87, true, PRCM_IDX_GPIOCR3, 0, /* MODACC_GPO_a[5] */ + true, PRCM_IDX_GPIOCR2, 3, /* U2_RXD_c */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[24] */ + true, PRCM_IDX_GPIOCR1, 21 /* MODUART_STMMUX_RXD_c */ + ), + PRCM_GPIOCR_ALTCX(151, true, PRCM_IDX_GPIOCR1, 18, /* REMAP0 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(152, true, PRCM_IDX_GPIOCR1, 18, /* REMAP1 */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(153, true, PRCM_IDX_GPIOCR3, 2, /* KP_O_b[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[2] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[21] */ + true, PRCM_IDX_GPIOCR1, 0 /* MODUART1_RTS */ + ), + PRCM_GPIOCR_ALTCX(154, true, PRCM_IDX_GPIOCR3, 2, /* KP_I_b[6] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[1] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[20] */ + true, PRCM_IDX_GPIOCR1, 0 /* MODUART1_CTS */ + ), + PRCM_GPIOCR_ALTCX(155, true, PRCM_IDX_GPIOCR3, 3, /* KP_O_b[5] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_D_b[0] */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[19] */ + true, PRCM_IDX_GPIOCR1, 5 /* MODACCUART_RXD_c */ + ), + PRCM_GPIOCR_ALTCX(156, true, PRCM_IDX_GPIOCR3, 3, /* KP_O_b[4] */ + true, PRCM_IDX_GPIOCR1, 8, /* SBAG_VAL_b */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[18] */ + true, PRCM_IDX_GPIOCR1, 5 /* MODACCUART_TXD_b */ + ), + PRCM_GPIOCR_ALTCX(157, true, PRCM_IDX_GPIOCR3, 4, /* KP_I_b[5] */ + true, PRCM_IDX_GPIOCR1, 23, /* MODOBS_SERVICE_N */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[17] */ + true, PRCM_IDX_GPIOCR1, 14 /* MODACCUART_RTS */ + ), + PRCM_GPIOCR_ALTCX(158, true, PRCM_IDX_GPIOCR3, 4, /* KP_I_b[4] */ + true, PRCM_IDX_GPIOCR2, 0, /* U2_TXD_c */ + true, PRCM_IDX_GPIOCR1, 3, /* TPIU_D[16] */ + true, PRCM_IDX_GPIOCR1, 14 /* MODACCUART_CTS */ + ), + PRCM_GPIOCR_ALTCX(159, true, PRCM_IDX_GPIOCR3, 5, /* KP_O_b[3] */ + true, PRCM_IDX_GPIOCR3, 10, /* MODUART0_RXD */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[31] */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(160, true, PRCM_IDX_GPIOCR3, 5, /* KP_I_b[3] */ + true, PRCM_IDX_GPIOCR3, 10, /* MODUART0_TXD */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[30] */ + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(161, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[4] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_CLK_b */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[29] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_CLK_c */ + ), + PRCM_GPIOCR_ALTCX(162, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[3] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[3] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[28] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[3] */ + ), + PRCM_GPIOCR_ALTCX(163, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[2] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[2] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[27] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[2] */ + ), + PRCM_GPIOCR_ALTCX(164, true, PRCM_IDX_GPIOCR3, 9, /* MOD_PRCMU_DEBUG[1] */ + true, PRCM_IDX_GPIOCR2, 18, /* STMAPE_DAT_b[1] */ + true, PRCM_IDX_GPIOCR1, 4, /* TPIU_D[26] */ + true, PRCM_IDX_GPIOCR1, 11 /* STMMOD_DAT_c[1] */ + ), + PRCM_GPIOCR_ALTCX(204, true, PRCM_IDX_GPIOCR2, 2, /* U2_RXD_f */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(205, true, PRCM_IDX_GPIOCR2, 2, /* U2_TXD_f */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(206, true, PRCM_IDX_GPIOCR2, 2, /* U2_CTSn_b */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), + PRCM_GPIOCR_ALTCX(207, true, PRCM_IDX_GPIOCR2, 2, /* U2_RTSn_b */ + false, 0, 0, + false, 0, 0, + false, 0, 0 + ), +}; + +static const u16 db8540_prcm_gpiocr_regs[] = { + [PRCM_IDX_GPIOCR1] = 0x138, + [PRCM_IDX_GPIOCR2] = 0x574, + [PRCM_IDX_GPIOCR3] = 0x2bc, +}; + static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { .gpio_ranges = nmk_db8540_ranges, .gpio_num_ranges = ARRAY_SIZE(nmk_db8540_ranges), @@ -990,6 +1249,9 @@ static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { .nfunctions = ARRAY_SIZE(nmk_db8540_functions), .groups = nmk_db8540_groups, .ngroups = ARRAY_SIZE(nmk_db8540_groups), + .altcx_pins = db8540_altcx_pins, + .npins_altcx = ARRAY_SIZE(db8540_altcx_pins), + .prcm_gpiocr_registers = db8540_prcm_gpiocr_regs, }; void __devinit diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 6030a513f3c4..fec9c30133d4 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -30,6 +30,7 @@ #include <linux/pinctrl/pinconf.h> /* Since we request GPIOs from ourself */ #include <linux/pinctrl/consumer.h> +#include <linux/mfd/dbx500-prcmu.h> #include <asm/mach/irq.h> @@ -237,6 +238,89 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); } +static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, + unsigned offset, unsigned alt_num) +{ + int i; + u16 reg; + u8 bit; + u8 alt_index; + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + if (alt_num > PRCM_IDX_GPIOCR_ALTC_MAX) { + dev_err(npct->dev, "PRCM GPIOCR: alternate-C%i is invalid\n", + alt_num); + return; + } + + for (i = 0 ; i < npct->soc->npins_altcx ; i++) { + if (npct->soc->altcx_pins[i].pin == offset) + break; + } + if (i == npct->soc->npins_altcx) { + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i is not found\n", + offset); + return; + } + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + + /* + * If alt_num is NULL, just clear current ALTCx selection + * to make sure we come back to a pure ALTC selection + */ + if (!alt_num) { + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (prcmu_read(reg) & BIT(bit)) { + prcmu_write_masked(reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + return; + } + + alt_index = alt_num - 1; + if (pin_desc->altcx[alt_index].used == false) { + dev_warn(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i does not exist\n", + offset, alt_num); + return; + } + + /* + * Check if any other ALTCx functions are activated on this pin + * and disable it first. + */ + for (i = 0 ; i < PRCM_IDX_GPIOCR_ALTC_MAX ; i++) { + if (i == alt_index) + continue; + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (prcmu_read(reg) & BIT(bit)) { + prcmu_write_masked(reg, BIT(bit), 0); + dev_dbg(npct->dev, + "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", + offset, i+1); + } + } + } + + reg = gpiocr_regs[pin_desc->altcx[alt_index].reg_index]; + bit = pin_desc->altcx[alt_index].control_bit; + dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", + offset, alt_index+1); + prcmu_write_masked(reg, BIT(bit), BIT(bit)); +} + static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, pin_cfg_t cfg, bool sleep, unsigned int *slpmregs) { @@ -1287,9 +1371,19 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) platform_set_drvdata(dev, nmk_chip); - nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP, - NOMADIK_GPIO_TO_IRQ(pdata->first_gpio), - 0, &nmk_gpio_irq_simple_ops, nmk_chip); + if (np) { + /* The DT case will just grab a set of IRQ numbers */ + nmk_chip->domain = irq_domain_add_linear(np, NMK_GPIO_PER_CHIP, + &nmk_gpio_irq_simple_ops, nmk_chip); + } else { + /* Non-DT legacy mode, use hardwired IRQ numbers */ + int irq_start; + + irq_start = NOMADIK_GPIO_TO_IRQ(pdata->first_gpio); + nmk_chip->domain = irq_domain_add_simple(NULL, + NMK_GPIO_PER_CHIP, irq_start, + &nmk_gpio_irq_simple_ops, nmk_chip); + } if (!nmk_chip->domain) { dev_err(&dev->dev, "failed to create irqdomain\n"); ret = -ENOSYS; @@ -1441,7 +1535,7 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, * IOFORCE will switch *all* ports to their sleepmode setting to as * to avoid glitches. (Not just one port!) */ - glitch = (g->altsetting == NMK_GPIO_ALT_C); + glitch = ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C); if (glitch) { spin_lock_irqsave(&nmk_gpio_slpm_lock, flags); @@ -1491,8 +1585,21 @@ static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function, */ nmk_gpio_disable_lazy_irq(nmk_chip, bit); - __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch); + __nmk_gpio_set_mode_safe(nmk_chip, bit, + (g->altsetting & NMK_GPIO_ALT_C), glitch); clk_disable(nmk_chip->clk); + + /* + * Call PRCM GPIOCR config function in case ALTC + * has been selected: + * - If selection is a ALTCx, some bits in PRCM GPIOCR registers + * must be set. + * - If selection is pure ALTC and previous selection was ALTCx, + * then some bits in PRCM GPIOCR registers must be cleared. + */ + if ((g->altsetting & NMK_GPIO_ALT_C) == NMK_GPIO_ALT_C) + nmk_prcm_altcx_set_mode(npct, g->pins[i], + g->altsetting >> NMK_GPIO_ALT_CX_SHIFT); } /* When all pins are successfully reconfigured we get here */ diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h index 5c99f1c62dfd..eef316e979a0 100644 --- a/drivers/pinctrl/pinctrl-nomadik.h +++ b/drivers/pinctrl/pinctrl-nomadik.h @@ -8,6 +8,78 @@ #define PINCTRL_NMK_DB8500 1 #define PINCTRL_NMK_DB8540 2 +#define PRCM_GPIOCR_ALTCX(pin_num,\ + altc1_used, altc1_ri, altc1_cb,\ + altc2_used, altc2_ri, altc2_cb,\ + altc3_used, altc3_ri, altc3_cb,\ + altc4_used, altc4_ri, altc4_cb)\ +{\ + .pin = pin_num,\ + .altcx[PRCM_IDX_GPIOCR_ALTC1] = {\ + .used = altc1_used,\ + .reg_index = altc1_ri,\ + .control_bit = altc1_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC2] = {\ + .used = altc2_used,\ + .reg_index = altc2_ri,\ + .control_bit = altc2_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC3] = {\ + .used = altc3_used,\ + .reg_index = altc3_ri,\ + .control_bit = altc3_cb\ + },\ + .altcx[PRCM_IDX_GPIOCR_ALTC4] = {\ + .used = altc4_used,\ + .reg_index = altc4_ri,\ + .control_bit = altc4_cb\ + },\ +} + +/** + * enum prcm_gpiocr_reg_index + * Used to reference an PRCM GPIOCR register address. + */ +enum prcm_gpiocr_reg_index { + PRCM_IDX_GPIOCR1, + PRCM_IDX_GPIOCR2, + PRCM_IDX_GPIOCR3 +}; +/** + * enum prcm_gpiocr_altcx_index + * Used to reference an Other alternate-C function. + */ +enum prcm_gpiocr_altcx_index { + PRCM_IDX_GPIOCR_ALTC1, + PRCM_IDX_GPIOCR_ALTC2, + PRCM_IDX_GPIOCR_ALTC3, + PRCM_IDX_GPIOCR_ALTC4, + PRCM_IDX_GPIOCR_ALTC_MAX, +}; + +/** + * struct prcm_gpio_altcx - Other alternate-C function + * @used: other alternate-C function availability + * @reg_index: PRCM GPIOCR register index used to control the function + * @control_bit: PRCM GPIOCR bit used to control the function + */ +struct prcm_gpiocr_altcx { + bool used:1; + u8 reg_index:2; + u8 control_bit:5; +} __packed; + +/** + * struct prcm_gpio_altcx_pin_desc - Other alternate-C pin + * @pin: The pin number + * @altcx: array of other alternate-C[1-4] functions + */ +struct prcm_gpiocr_altcx_pin_desc { + unsigned short pin; + struct prcm_gpiocr_altcx altcx[PRCM_IDX_GPIOCR_ALTC_MAX]; +}; + /** * struct nmk_function - Nomadik pinctrl mux function * @name: The name of the function, exported to pinctrl core. @@ -50,6 +122,9 @@ struct nmk_pingroup { * @nfunction: The number of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The number of entries in @groups. + * @altcx_pins: The pins that support Other alternate-C function on this SoC + * @npins_altcx: The number of Other alternate-C pins + * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC */ struct nmk_pinctrl_soc_data { struct pinctrl_gpio_range *gpio_ranges; @@ -60,6 +135,9 @@ struct nmk_pinctrl_soc_data { unsigned nfunctions; const struct nmk_pingroup *groups; unsigned ngroups; + const struct prcm_gpiocr_altcx_pin_desc *altcx_pins; + unsigned npins_altcx; + const u16 *prcm_gpiocr_registers; }; #ifdef CONFIG_PINCTRL_STN8815 diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 2944ff88fdc0..f4abfe238f98 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -478,7 +478,6 @@ static void xencons_backend_changed(struct xenbus_device *dev, case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -488,6 +487,10 @@ static void xencons_backend_changed(struct xenbus_device *dev, xenbus_switch_state(dev, XenbusStateConnected); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 131dec04794e..48220e129f85 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -48,6 +48,7 @@ #include <xen/xenbus.h> #include <xen/xen.h> #include "xenbus_comms.h" +#include <asm/xen/hypervisor.h> struct xs_stored_msg { struct list_head list; @@ -618,7 +619,24 @@ static struct xenbus_watch *find_watch(const char *token) return NULL; } +/* + * Certain older XenBus toolstack cannot handle reading values that are + * not populated. Some Xen 3.4 installation are incapable of doing this + * so if we are running on anything older than 4 do not attempt to read + * control/platform-feature-xs_reset_watches. + */ +static bool xen_strict_xenbus_quirk() +{ + uint32_t eax, ebx, ecx, edx, base; + + base = xen_cpuid_base(); + cpuid(base + 1, &eax, &ebx, &ecx, &edx); + if ((eax >> 16) < 4) + return true; + return false; + +} static void xs_reset_watches(void) { int err, supported = 0; @@ -626,6 +644,9 @@ static void xs_reset_watches(void) if (!xen_hvm_domain() || xen_initial_domain()) return; + if (xen_strict_xenbus_quirk()) + return; + err = xenbus_scanf(XBT_NIL, "control", "platform-feature-xs_reset_watches", "%d", &supported); if (err != 1 || !supported) diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h index 96c5c249b086..9069694e70eb 100644 --- a/include/linux/alarmtimer.h +++ b/include/linux/alarmtimer.h @@ -21,7 +21,6 @@ enum alarmtimer_restart { #define ALARMTIMER_STATE_INACTIVE 0x00 #define ALARMTIMER_STATE_ENQUEUED 0x01 -#define ALARMTIMER_STATE_CALLBACK 0x02 /** * struct alarm - Alarm timer structure @@ -35,6 +34,7 @@ enum alarmtimer_restart { */ struct alarm { struct timerqueue_node node; + struct hrtimer timer; enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); enum alarmtimer_type type; int state; @@ -43,39 +43,12 @@ struct alarm { void alarm_init(struct alarm *alarm, enum alarmtimer_type type, enum alarmtimer_restart (*function)(struct alarm *, ktime_t)); -void alarm_start(struct alarm *alarm, ktime_t start); +int alarm_start(struct alarm *alarm, ktime_t start); int alarm_try_to_cancel(struct alarm *alarm); int alarm_cancel(struct alarm *alarm); u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); -/* - * A alarmtimer is active, when it is enqueued into timerqueue or the - * callback function is running. - */ -static inline int alarmtimer_active(const struct alarm *timer) -{ - return timer->state != ALARMTIMER_STATE_INACTIVE; -} - -/* - * Helper function to check, whether the timer is on one of the queues - */ -static inline int alarmtimer_is_queued(struct alarm *timer) -{ - return timer->state & ALARMTIMER_STATE_ENQUEUED; -} - -/* - * Helper function to check, whether the timer is running the callback - * function - */ -static inline int alarmtimer_callback_running(struct alarm *timer) -{ - return timer->state & ALARMTIMER_STATE_CALLBACK; -} - - /* Provide way to access the rtc device being used by alarmtimers */ struct rtc_device *alarmtimer_get_rtcdev(void); diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h index fbe89e17124e..4dceaf8ae152 100644 --- a/include/linux/clocksource.h +++ b/include/linux/clocksource.h @@ -319,22 +319,6 @@ static inline void __clocksource_updatefreq_khz(struct clocksource *cs, u32 khz) __clocksource_updatefreq_scale(cs, 1000, khz); } -#ifdef CONFIG_GENERIC_TIME_VSYSCALL -extern void -update_vsyscall(struct timespec *ts, struct timespec *wtm, - struct clocksource *c, u32 mult); -extern void update_vsyscall_tz(void); -#else -static inline void -update_vsyscall(struct timespec *ts, struct timespec *wtm, - struct clocksource *c, u32 mult) -{ -} - -static inline void update_vsyscall_tz(void) -{ -} -#endif extern void timekeeping_notify(struct clocksource *clock); diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h index 20e5eac2ffd3..827cce7e33e3 100644 --- a/include/linux/dvb/version.h +++ b/include/linux/dvb/version.h @@ -24,6 +24,6 @@ #define _DVBVERSION_H_ #define DVB_API_VERSION 5 -#define DVB_API_VERSION_MINOR 8 +#define DVB_API_VERSION_MINOR 9 #endif /*_DVBVERSION_H_*/ diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 05e3c2c7a8cf..6b87413da9d6 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -51,31 +51,17 @@ #define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \ + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN)) -#ifdef CLOCK_TICK_RATE /* LATCH is used in the interval timer and ftape setup. */ -# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ +#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ -/* - * HZ is the requested value. However the CLOCK_TICK_RATE may not allow - * for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy) - */ -# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8)) -#else -# define SHIFTED_HZ (HZ << 8) -#endif +extern int register_refined_jiffies(long clock_tick_rate); /* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ -#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8)) +#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) -/* - * TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and - * a value TUSEC for TICK_USEC (can be set bij adjtimex) - */ -#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8)) - /* some arch's have a small-data section that can be accessed register-relative * but that can only take up to, say, 4-byte variables. jiffies being part of * an 8-byte variable may not be correctly accessed unless we force the issue diff --git a/include/linux/platform_data/mipi-csis.h b/include/linux/platform_data/mipi-csis.h index c45b1e8d4c2e..bf34e17cee7f 100644 --- a/include/linux/platform_data/mipi-csis.h +++ b/include/linux/platform_data/mipi-csis.h @@ -1,7 +1,7 @@ /* - * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. * - * S5P series MIPI CSI slave device support + * Samsung S5P/Exynos SoC series MIPI CSIS device support * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -11,33 +11,27 @@ #ifndef __PLAT_SAMSUNG_MIPI_CSIS_H_ #define __PLAT_SAMSUNG_MIPI_CSIS_H_ __FILE__ -struct platform_device; - /** * struct s5p_platform_mipi_csis - platform data for S5P MIPI-CSIS driver - * @clk_rate: bus clock frequency - * @lanes: number of data lanes used - * @alignment: data alignment in bits - * @hs_settle: HS-RX settle time - * @fixed_phy_vdd: false to enable external D-PHY regulator management in the - * driver or true in case this regulator has no enable function - * @phy_enable: pointer to a callback controlling D-PHY enable/reset + * @clk_rate: bus clock frequency + * @wclk_source: CSI wrapper clock selection: 0 - bus clock, 1 - ext. SCLK_CAM + * @lanes: number of data lanes used + * @hs_settle: HS-RX settle time */ struct s5p_platform_mipi_csis { unsigned long clk_rate; + u8 wclk_source; u8 lanes; - u8 alignment; u8 hs_settle; - bool fixed_phy_vdd; - int (*phy_enable)(struct platform_device *pdev, bool on); }; /** * s5p_csis_phy_enable - global MIPI-CSI receiver D-PHY control - * @pdev: MIPI-CSIS platform device - * @on: true to enable D-PHY and deassert its reset - * false to disable D-PHY + * @id: MIPI-CSIS harware instance index (0...1) + * @on: true to enable D-PHY and deassert its reset + * false to disable D-PHY + * @return: 0 on success, or negative error code on failure */ -int s5p_csis_phy_enable(struct platform_device *pdev, bool on); +int s5p_csis_phy_enable(int id, bool on); #endif /* __PLAT_SAMSUNG_MIPI_CSIS_H_ */ diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h new file mode 100644 index 000000000000..e1d558e237ec --- /dev/null +++ b/include/linux/timekeeper_internal.h @@ -0,0 +1,108 @@ +/* + * You SHOULD NOT be including this unless you're vsyscall + * handling code or timekeeping internal code! + */ + +#ifndef _LINUX_TIMEKEEPER_INTERNAL_H +#define _LINUX_TIMEKEEPER_INTERNAL_H + +#include <linux/clocksource.h> +#include <linux/jiffies.h> +#include <linux/time.h> + +/* Structure holding internal timekeeping values. */ +struct timekeeper { + /* Current clocksource used for timekeeping. */ + struct clocksource *clock; + /* NTP adjusted clock multiplier */ + u32 mult; + /* The shift value of the current clocksource. */ + u32 shift; + /* Number of clock cycles in one NTP interval. */ + cycle_t cycle_interval; + /* Number of clock shifted nano seconds in one NTP interval. */ + u64 xtime_interval; + /* shifted nano seconds left over when rounding cycle_interval */ + s64 xtime_remainder; + /* Raw nano seconds accumulated per NTP interval. */ + u32 raw_interval; + + /* Current CLOCK_REALTIME time in seconds */ + u64 xtime_sec; + /* Clock shifted nano seconds */ + u64 xtime_nsec; + + /* Difference between accumulated time and NTP time in ntp + * shifted nano seconds. */ + s64 ntp_error; + /* Shift conversion between clock shifted nano seconds and + * ntp shifted nano seconds. */ + u32 ntp_error_shift; + + /* + * wall_to_monotonic is what we need to add to xtime (or xtime corrected + * for sub jiffie times) to get to monotonic time. Monotonic is pegged + * at zero at system boot time, so wall_to_monotonic will be negative, + * however, we will ALWAYS keep the tv_nsec part positive so we can use + * the usual normalization. + * + * wall_to_monotonic is moved after resume from suspend for the + * monotonic time not to jump. We need to add total_sleep_time to + * wall_to_monotonic to get the real boot based time offset. + * + * - wall_to_monotonic is no longer the boot time, getboottime must be + * used instead. + */ + struct timespec wall_to_monotonic; + /* Offset clock monotonic -> clock realtime */ + ktime_t offs_real; + /* time spent in suspend */ + struct timespec total_sleep_time; + /* Offset clock monotonic -> clock boottime */ + ktime_t offs_boot; + /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ + struct timespec raw_time; + /* Seqlock for all timekeeper values */ + seqlock_t lock; +}; + +static inline struct timespec tk_xtime(struct timekeeper *tk) +{ + struct timespec ts; + + ts.tv_sec = tk->xtime_sec; + ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); + return ts; +} + + +#ifdef CONFIG_GENERIC_TIME_VSYSCALL + +extern void update_vsyscall(struct timekeeper *tk); +extern void update_vsyscall_tz(void); + +#elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD) + +extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm, + struct clocksource *c, u32 mult); +extern void update_vsyscall_tz(void); + +static inline void update_vsyscall(struct timekeeper *tk) +{ + struct timespec xt; + + xt = tk_xtime(tk); + update_vsyscall_old(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); +} + +#else + +static inline void update_vsyscall(struct timekeeper *tk) +{ +} +static inline void update_vsyscall_tz(void) +{ +} +#endif + +#endif /* _LINUX_TIMEKEEPER_INTERNAL_H */ diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h index 421d24c7f686..f56c945cecd4 100644 --- a/include/linux/v4l2-controls.h +++ b/include/linux/v4l2-controls.h @@ -349,6 +349,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) +#define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) @@ -439,6 +440,46 @@ enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, }; +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING (V4L2_CID_MPEG_BASE+368) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0 (V4L2_CID_MPEG_BASE+369) +#define V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE (V4L2_CID_MPEG_BASE+370) +enum v4l2_mpeg_video_h264_sei_fp_arrangement_type { + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD = 0, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN = 1, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW = 2, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE = 3, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM = 4, + V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL = 5, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO (V4L2_CID_MPEG_BASE+371) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE (V4L2_CID_MPEG_BASE+372) +enum v4l2_mpeg_video_h264_fmo_map_type { + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES = 0, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES = 1, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER = 2, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT = 3, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN = 4, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN = 5, + V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT = 6, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (V4L2_CID_MPEG_BASE+373) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION (V4L2_CID_MPEG_BASE+374) +enum v4l2_mpeg_video_h264_fmo_change_dir { + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT = 0, + V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE (V4L2_CID_MPEG_BASE+375) +#define V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH (V4L2_CID_MPEG_BASE+376) +#define V4L2_CID_MPEG_VIDEO_H264_ASO (V4L2_CID_MPEG_BASE+377) +#define V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER (V4L2_CID_MPEG_BASE+378) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING (V4L2_CID_MPEG_BASE+379) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE (V4L2_CID_MPEG_BASE+380) +enum v4l2_mpeg_video_h264_hierarchical_coding_type { + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B = 0, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P = 1, +}; +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER (V4L2_CID_MPEG_BASE+381) +#define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_MPEG_BASE+382) #define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) #define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) #define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) @@ -757,5 +798,6 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) #define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) +#define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #endif diff --git a/include/linux/v4l2-mediabus.h b/include/linux/v4l2-mediabus.h index 5ea7f753a348..7d64e0e1a18b 100644 --- a/include/linux/v4l2-mediabus.h +++ b/include/linux/v4l2-mediabus.h @@ -92,6 +92,11 @@ enum v4l2_mbus_pixelcode { /* JPEG compressed formats - next is 0x4002 */ V4L2_MBUS_FMT_JPEG_1X8 = 0x4001, + + /* Vendor specific formats - next is 0x5002 */ + + /* S5C73M3 sensor specific interleaved UYVY and JPEG */ + V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001, }; /** diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 61395ef85a00..873adbe82988 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -366,7 +366,9 @@ struct v4l2_pix_format { /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21M v4l2_fourcc('N', 'M', '2', '1') /* 21 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ +#define V4L2_PIX_FMT_NV12MT_16X16 v4l2_fourcc('V', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 16x16 macroblocks */ /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ @@ -403,6 +405,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ #define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ #define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ +#define V4L2_PIX_FMT_H264_MVC v4l2_fourcc('M', '2', '6', '4') /* H264 MVC */ #define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ #define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ #define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ @@ -410,6 +413,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ +#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ @@ -437,6 +441,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ #define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ #define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ +#define V4L2_PIX_FMT_S5C_UYVY_JPG v4l2_fourcc('S', '5', 'C', 'I') /* S5C73M3 interleaved UYVY/JPEG */ /* * F O R M A T E N U M E R A T I O N diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index 8bc1b3c0e679..a7ca4884c46c 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -35,7 +35,7 @@ struct osd_config_info { struct vpbe_output { struct v4l2_output output; /* - * If output capabilities include dv_preset, list supported presets + * If output capabilities include dv_timings, list supported timings * below */ char *subdev_name; @@ -120,16 +120,16 @@ struct vpbe_device_ops { unsigned int (*get_output)(struct vpbe_device *vpbe_dev); /* Set DV preset at current output */ - int (*s_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*s_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Get DV presets supported at the output */ - int (*g_dv_preset)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_preset *dv_preset); + int (*g_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_dv_timings *dv_timings); /* Enumerate the DV Presets supported at the output */ - int (*enum_dv_presets)(struct vpbe_device *vpbe_dev, - struct v4l2_dv_enum_preset *preset_info); + int (*enum_dv_timings)(struct vpbe_device *vpbe_dev, + struct v4l2_enum_dv_timings *timings_info); /* Set std at the output */ int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h index 727f55170e41..9b85396514be 100644 --- a/include/media/davinci/vpbe_types.h +++ b/include/media/davinci/vpbe_types.h @@ -32,11 +32,6 @@ enum vpbe_enc_timings_type { VPBE_ENC_TIMINGS_INVALID = 0x8, }; -union vpbe_timings { - v4l2_std_id std_id; - unsigned int dv_preset; -}; - /* * struct vpbe_enc_mode_info * @name: ptr to name string of the standard, "NTSC", "PAL" etc @@ -73,7 +68,8 @@ union vpbe_timings { struct vpbe_enc_mode_info { unsigned char *name; enum vpbe_enc_timings_type timings_type; - union vpbe_timings timings; + v4l2_std_id std_id; + struct v4l2_dv_timings dv_timings; unsigned int interlaced; unsigned int xres; unsigned int yres; diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h index 6b57334f4029..cc78c2eb16da 100644 --- a/include/media/davinci/vpbe_venc.h +++ b/include/media/davinci/vpbe_venc.h @@ -32,7 +32,7 @@ struct venc_platform_data { int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type, int field); int (*setup_clock)(enum vpbe_enc_timings_type type, - unsigned int mode); + unsigned int pixclock); int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode); /* Number of LCD outputs supported */ int num_lcd_outputs; diff --git a/include/media/davinci/vpif_types.h b/include/media/davinci/vpif_types.h index d8f6ab1943e4..3882e0675ccf 100644 --- a/include/media/davinci/vpif_types.h +++ b/include/media/davinci/vpif_types.h @@ -20,6 +20,7 @@ #include <linux/i2c.h> #define VPIF_CAPTURE_MAX_CHANNELS 2 +#define VPIF_DISPLAY_MAX_CHANNELS 2 enum vpif_if_type { VPIF_IF_BT656, @@ -37,29 +38,38 @@ struct vpif_interface { struct vpif_subdev_info { const char *name; struct i2c_board_info board_info; - u32 input; - u32 output; - unsigned can_route:1; - struct vpif_interface vpif_if; +}; + +struct vpif_output { + struct v4l2_output output; + const char *subdev_name; + u32 input_route; + u32 output_route; +}; + +struct vpif_display_chan_config { + const struct vpif_output *outputs; + int output_count; + bool clip_en; }; struct vpif_display_config { int (*set_clock)(int, int); struct vpif_subdev_info *subdevinfo; int subdev_count; - const char **output; - int output_count; + struct vpif_display_chan_config chan_config[VPIF_DISPLAY_MAX_CHANNELS]; const char *card_name; - bool ch2_clip_en; - bool ch3_clip_en; }; struct vpif_input { struct v4l2_input input; const char *subdev_name; + u32 input_route; + u32 output_route; }; struct vpif_capture_chan_config { + struct vpif_interface vpif_if; const struct vpif_input *inputs; int input_count; }; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 09421a611d73..eaea62a382f8 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -30,7 +30,6 @@ struct i2c_board_info; * @board_info: pointer to I2C subdevice's board info * @clk_frequency: frequency of the clock the host interface provides to sensor * @bus_type: determines bus type, MIPI, ITU-R BT.601 etc. - * @csi_data_align: MIPI-CSI interface data alignment in bits * @i2c_bus_num: i2c control bus id the sensor is attached to * @mux_id: FIMC camera interface multiplexer index (separate for MIPI and ITU) * @clk_id: index of the SoC peripheral clock for sensors @@ -40,7 +39,6 @@ struct s5p_fimc_isp_info { struct i2c_board_info *board_info; unsigned long clk_frequency; enum cam_bus_type bus_type; - u16 csi_data_align; u16 i2c_bus_num; u16 mux_id; u16 flags; diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 801adb466bd2..96509119f28f 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -351,6 +351,29 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 mask, s32 def); +/** v4l2_ctrl_new_std_menu_items() - Create a new standard V4L2 menu control + * with driver specific menu. + * @hdl: The control handler. + * @ops: The control ops. + * @id: The control ID. + * @max: The control's maximum value. + * @mask: The control's skip mask for menu controls. This makes it + * easy to skip menu items that are not valid. If bit X is set, + * then menu item X is skipped. Of course, this only works for + * menus with <= 32 menu items. There are no menus that come + * close to that number, so this is OK. Should we ever need more, + * then this will have to be extended to a u64 or a bit array. + * @def: The control's default value. + * @qmenu: The new menu. + * + * Same as v4l2_ctrl_new_std_menu(), but @qmenu will be the driver specific + * menu of this control. + * + */ +struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, s32 max, + s32 mask, s32 def, const char * const *qmenu); + /** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control. * @hdl: The control handler. * @ops: The control ops. diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2ecd7377153b..b137a5e1151a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -21,6 +21,7 @@ #ifndef _V4L2_SUBDEV_H #define _V4L2_SUBDEV_H +#include <linux/types.h> #include <linux/v4l2-subdev.h> #include <media/media-entity.h> #include <media/v4l2-common.h> @@ -45,6 +46,7 @@ struct v4l2_fh; struct v4l2_subdev; struct v4l2_subdev_fh; struct tuner_setup; +struct v4l2_mbus_frame_desc; /* decode_vbi_line */ struct v4l2_decode_vbi_line { @@ -226,6 +228,36 @@ struct v4l2_subdev_audio_ops { int (*s_stream)(struct v4l2_subdev *sd, int enable); }; +/* Indicates the @length field specifies maximum data length. */ +#define V4L2_MBUS_FRAME_DESC_FL_LEN_MAX (1U << 0) +/* Indicates user defined data format, i.e. non standard frame format. */ +#define V4L2_MBUS_FRAME_DESC_FL_BLOB (1U << 1) + +/** + * struct v4l2_mbus_frame_desc_entry - media bus frame description structure + * @flags: V4L2_MBUS_FRAME_DESC_FL_* flags + * @pixelcode: media bus pixel code, valid if FRAME_DESC_FL_BLOB is not set + * @length: number of octets per frame, valid for compressed or unspecified + * formats + */ +struct v4l2_mbus_frame_desc_entry { + u16 flags; + u32 pixelcode; + u32 length; +}; + +#define V4L2_FRAME_DESC_ENTRY_MAX 4 + +/** + * struct v4l2_mbus_frame_desc - media bus data frame description + * @entry: frame descriptors array + * @num_entries: number of entries in @entry array + */ +struct v4l2_mbus_frame_desc { + struct v4l2_mbus_frame_desc_entry entry[V4L2_FRAME_DESC_ENTRY_MAX]; + unsigned short num_entries; +}; + /* s_std_output: set v4l2_std_id for video OUTPUT devices. This is ignored by video input devices. @@ -274,6 +306,10 @@ struct v4l2_subdev_audio_ops { s_mbus_config: set a certain mediabus configuration. This operation is added for compatibility with soc-camera drivers and should not be used by new software. + + s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev + can adjust @size to a lower value and must not write more data to the + buffer starting at @data than the original value of @size. */ struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); @@ -327,6 +363,8 @@ struct v4l2_subdev_video_ops { struct v4l2_mbus_config *cfg); int (*s_mbus_config)(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg); + int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, + unsigned int *size); }; /* @@ -455,6 +493,12 @@ struct v4l2_subdev_ir_ops { struct v4l2_subdev_ir_parameters *params); }; +/** + * struct v4l2_subdev_pad_ops - v4l2-subdev pad level operations + * @get_frame_desc: get the current low level media bus frame parameters. + * @get_frame_desc: set the low level media bus frame parameters, @fd array + * may be adjusted by the subdev driver to device capabilities. + */ struct v4l2_subdev_pad_ops { int (*enum_mbus_code)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct v4l2_subdev_mbus_code_enum *code); @@ -483,6 +527,10 @@ struct v4l2_subdev_pad_ops { struct v4l2_subdev_format *source_fmt, struct v4l2_subdev_format *sink_fmt); #endif /* CONFIG_MEDIA_CONTROLLER */ + int (*get_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); + int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd); }; struct v4l2_subdev_ops { diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h index a4827f46ee97..956a04682865 100644 --- a/include/xen/interface/hvm/hvm_op.h +++ b/include/xen/interface/hvm/hvm_op.h @@ -43,4 +43,23 @@ struct xen_hvm_pagetable_dying { typedef struct xen_hvm_pagetable_dying xen_hvm_pagetable_dying_t; DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_pagetable_dying_t); +enum hvmmem_type_t { + HVMMEM_ram_rw, /* Normal read/write guest RAM */ + HVMMEM_ram_ro, /* Read-only; writes are discarded */ + HVMMEM_mmio_dm, /* Reads and write go to the device model */ +}; + +#define HVMOP_get_mem_type 15 +/* Return hvmmem_type_t for the specified pfn. */ +struct xen_hvm_get_mem_type { + /* Domain to be queried. */ + domid_t domid; + /* OUT variable. */ + uint16_t mem_type; + uint16_t pad[2]; /* align next field on 8-byte boundary */ + /* IN variable. */ + uint64_t pfn; +}; +DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_get_mem_type); + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ diff --git a/init/Kconfig b/init/Kconfig index 4c93533da42c..89e4cf672dfe 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -496,6 +496,12 @@ config RCU_USER_QS excluded from the global RCU state machine and thus doesn't to keep the timer tick on for RCU. + Unless you want to hack and help the development of the full + tickless feature, you shouldn't enable this option. It adds + unnecessary overhead. + + If unsure say N + config RCU_USER_QS_FORCE bool "Force userspace extended QS by default" depends on RCU_USER_QS @@ -504,6 +510,12 @@ config RCU_USER_QS_FORCE test this feature that treats userspace as an extended quiescent state until we have a real user like a full adaptive nohz option. + Unless you want to hack and help the development of the full + tickless feature, you shouldn't enable this option. It adds + unnecessary overhead. + + If unsure say N + config RCU_FANOUT int "Tree-based hierarchical RCU fanout value" range 2 64 if 64BIT diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index 49a77727db42..4e69e24d3d7d 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -148,7 +148,8 @@ static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, * @host_data: Controller private data pointer * * Allocates a legacy irq_domain if irq_base is positive or a linear - * domain otherwise. + * domain otherwise. For the legacy domain, IRQ descriptors will also + * be allocated. * * This is intended to implement the expected behaviour for most * interrupt controllers which is that a linear mapping should @@ -162,11 +163,33 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node, const struct irq_domain_ops *ops, void *host_data) { - if (first_irq > 0) - return irq_domain_add_legacy(of_node, size, first_irq, 0, + if (first_irq > 0) { + int irq_base; + + if (IS_ENABLED(CONFIG_SPARSE_IRQ)) { + /* + * Set the descriptor allocator to search for a + * 1-to-1 mapping, such as irq_alloc_desc_at(). + * Use of_node_to_nid() which is defined to + * numa_node_id() on platforms that have no custom + * implementation. + */ + irq_base = irq_alloc_descs(first_irq, first_irq, size, + of_node_to_nid(of_node)); + if (irq_base < 0) { + WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n", + first_irq); + irq_base = first_irq; + } + } else + irq_base = first_irq; + + return irq_domain_add_legacy(of_node, size, irq_base, 0, ops, host_data); - else - return irq_domain_add_linear(of_node, size, ops, host_data); + } + + /* A linear domain is the default */ + return irq_domain_add_linear(of_node, size, ops, host_data); } /** diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 4fb2376ddf06..74df86bd9204 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -74,6 +74,7 @@ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS]; .orphan_nxttail = &sname##_state.orphan_nxtlist, \ .orphan_donetail = &sname##_state.orphan_donelist, \ .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \ + .onoff_mutex = __MUTEX_INITIALIZER(sname##_state.onoff_mutex), \ .name = #sname, \ } @@ -1197,7 +1198,7 @@ static int rcu_gp_init(struct rcu_state *rsp) raw_spin_unlock_irq(&rnp->lock); /* Exclude any concurrent CPU-hotplug operations. */ - get_online_cpus(); + mutex_lock(&rsp->onoff_mutex); /* * Set the quiescent-state-needed bits in all the rcu_node @@ -1234,7 +1235,7 @@ static int rcu_gp_init(struct rcu_state *rsp) cond_resched(); } - put_online_cpus(); + mutex_unlock(&rsp->onoff_mutex); return 1; } @@ -1700,6 +1701,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) /* Remove the dead CPU from the bitmasks in the rcu_node hierarchy. */ /* Exclude any attempts to start a new grace period. */ + mutex_lock(&rsp->onoff_mutex); raw_spin_lock_irqsave(&rsp->onofflock, flags); /* Orphan the dead CPU's callbacks, and adopt them if appropriate. */ @@ -1744,6 +1746,7 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp) init_callback_list(rdp); /* Disallow further callbacks on this CPU. */ rdp->nxttail[RCU_NEXT_TAIL] = NULL; + mutex_unlock(&rsp->onoff_mutex); } #else /* #ifdef CONFIG_HOTPLUG_CPU */ @@ -2648,6 +2651,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu); struct rcu_node *rnp = rcu_get_root(rsp); + /* Exclude new grace periods. */ + mutex_lock(&rsp->onoff_mutex); + /* Set up local state, ensuring consistent view of global state. */ raw_spin_lock_irqsave(&rnp->lock, flags); rdp->beenonline = 1; /* We have now been online. */ @@ -2662,14 +2668,6 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) rcu_prepare_for_idle_init(cpu); raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */ - /* - * A new grace period might start here. If so, we won't be part - * of it, but that is OK, as we are currently in a quiescent state. - */ - - /* Exclude any attempts to start a new GP on large systems. */ - raw_spin_lock(&rsp->onofflock); /* irqs already disabled. */ - /* Add CPU to rcu_node bitmasks. */ rnp = rdp->mynode; mask = rdp->grpmask; @@ -2693,8 +2691,9 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible) raw_spin_unlock(&rnp->lock); /* irqs already disabled. */ rnp = rnp->parent; } while (rnp != NULL && !(rnp->qsmaskinit & mask)); + local_irq_restore(flags); - raw_spin_unlock_irqrestore(&rsp->onofflock, flags); + mutex_unlock(&rsp->onoff_mutex); } static void __cpuinit rcu_prepare_cpu(int cpu) diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 5faf05d68326..a240f032848e 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -394,11 +394,17 @@ struct rcu_state { struct rcu_head **orphan_donetail; /* Tail of above. */ long qlen_lazy; /* Number of lazy callbacks. */ long qlen; /* Total number of callbacks. */ + /* End of fields guarded by onofflock. */ + + struct mutex onoff_mutex; /* Coordinate hotplug & GPs. */ + struct mutex barrier_mutex; /* Guards barrier fields. */ atomic_t barrier_cpu_count; /* # CPUs waiting on. */ struct completion barrier_completion; /* Wake at barrier end. */ unsigned long n_barrier_done; /* ++ at start and end of */ /* _rcu_barrier(). */ + /* End of fields guarded by barrier_mutex. */ + unsigned long jiffies_force_qs; /* Time at which to invoke */ /* force_quiescent_state(). */ unsigned long n_force_qs; /* Number of calls to */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index bd7c39450b1b..2d8927fda712 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6122,6 +6122,17 @@ static void sched_init_numa(void) * numbers. */ + /* + * Here, we should temporarily reset sched_domains_numa_levels to 0. + * If it fails to allocate memory for array sched_domains_numa_masks[][], + * the array will contain less then 'level' members. This could be + * dangerous when we use it to iterate array sched_domains_numa_masks[][] + * in other functions. + * + * We reset it to 'level' at the end of this function. + */ + sched_domains_numa_levels = 0; + sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL); if (!sched_domains_numa_masks) return; @@ -6176,11 +6187,68 @@ static void sched_init_numa(void) } sched_domain_topology = tl; + + sched_domains_numa_levels = level; +} + +static void sched_domains_numa_masks_set(int cpu) +{ + int i, j; + int node = cpu_to_node(cpu); + + for (i = 0; i < sched_domains_numa_levels; i++) { + for (j = 0; j < nr_node_ids; j++) { + if (node_distance(j, node) <= sched_domains_numa_distance[i]) + cpumask_set_cpu(cpu, sched_domains_numa_masks[i][j]); + } + } +} + +static void sched_domains_numa_masks_clear(int cpu) +{ + int i, j; + for (i = 0; i < sched_domains_numa_levels; i++) { + for (j = 0; j < nr_node_ids; j++) + cpumask_clear_cpu(cpu, sched_domains_numa_masks[i][j]); + } +} + +/* + * Update sched_domains_numa_masks[level][node] array when new cpus + * are onlined. + */ +static int sched_domains_numa_masks_update(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + int cpu = (long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_ONLINE: + sched_domains_numa_masks_set(cpu); + break; + + case CPU_DEAD: + sched_domains_numa_masks_clear(cpu); + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; } #else static inline void sched_init_numa(void) { } + +static int sched_domains_numa_masks_update(struct notifier_block *nfb, + unsigned long action, + void *hcpu) +{ + return 0; +} #endif /* CONFIG_NUMA */ static int __sdt_alloc(const struct cpumask *cpu_map) @@ -6629,6 +6697,7 @@ void __init sched_init_smp(void) mutex_unlock(&sched_domains_mutex); put_online_cpus(); + hotcpu_notifier(sched_domains_numa_masks_update, CPU_PRI_SCHED_ACTIVE); hotcpu_notifier(cpuset_cpu_active, CPU_PRI_CPUSET_ACTIVE); hotcpu_notifier(cpuset_cpu_inactive, CPU_PRI_CPUSET_INACTIVE); diff --git a/kernel/time.c b/kernel/time.c index ba744cf80696..d226c6a3fd28 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -30,7 +30,7 @@ #include <linux/export.h> #include <linux/timex.h> #include <linux/capability.h> -#include <linux/clocksource.h> +#include <linux/timekeeper_internal.h> #include <linux/errno.h> #include <linux/syscalls.h> #include <linux/security.h> diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index fd42bd452b75..8601f0db1261 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -16,6 +16,10 @@ config ARCH_CLOCKSOURCE_DATA config GENERIC_TIME_VSYSCALL bool +# Timekeeping vsyscall support +config GENERIC_TIME_VSYSCALL_OLD + bool + # ktime_t scalar 64bit nsec representation config KTIME_SCALAR bool diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index aa27d391bfc8..f11d83b12949 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -37,7 +37,6 @@ static struct alarm_base { spinlock_t lock; struct timerqueue_head timerqueue; - struct hrtimer timer; ktime_t (*gettime)(void); clockid_t base_clockid; } alarm_bases[ALARM_NUMTYPE]; @@ -46,6 +45,8 @@ static struct alarm_base { static ktime_t freezer_delta; static DEFINE_SPINLOCK(freezer_delta_lock); +static struct wakeup_source *ws; + #ifdef CONFIG_RTC_CLASS /* rtc timer and device for setting alarm wakeups at suspend */ static struct rtc_timer rtctimer; @@ -130,50 +131,35 @@ static inline void alarmtimer_rtc_timer_init(void) { } * @base: pointer to the base where the timer is being run * @alarm: pointer to alarm being enqueued. * - * Adds alarm to a alarm_base timerqueue and if necessary sets - * an hrtimer to run. + * Adds alarm to a alarm_base timerqueue * * Must hold base->lock when calling. */ static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) { + if (alarm->state & ALARMTIMER_STATE_ENQUEUED) + timerqueue_del(&base->timerqueue, &alarm->node); + timerqueue_add(&base->timerqueue, &alarm->node); alarm->state |= ALARMTIMER_STATE_ENQUEUED; - - if (&alarm->node == timerqueue_getnext(&base->timerqueue)) { - hrtimer_try_to_cancel(&base->timer); - hrtimer_start(&base->timer, alarm->node.expires, - HRTIMER_MODE_ABS); - } } /** - * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue + * alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue * @base: pointer to the base where the timer is running * @alarm: pointer to alarm being removed * - * Removes alarm to a alarm_base timerqueue and if necessary sets - * a new timer to run. + * Removes alarm to a alarm_base timerqueue * * Must hold base->lock when calling. */ -static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) +static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm) { - struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue); - if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED)) return; timerqueue_del(&base->timerqueue, &alarm->node); alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; - - if (next == &alarm->node) { - hrtimer_try_to_cancel(&base->timer); - next = timerqueue_getnext(&base->timerqueue); - if (!next) - return; - hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS); - } } @@ -188,42 +174,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm) */ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) { - struct alarm_base *base = container_of(timer, struct alarm_base, timer); - struct timerqueue_node *next; + struct alarm *alarm = container_of(timer, struct alarm, timer); + struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; - ktime_t now; int ret = HRTIMER_NORESTART; int restart = ALARMTIMER_NORESTART; spin_lock_irqsave(&base->lock, flags); - now = base->gettime(); - while ((next = timerqueue_getnext(&base->timerqueue))) { - struct alarm *alarm; - ktime_t expired = next->expires; - - if (expired.tv64 > now.tv64) - break; - - alarm = container_of(next, struct alarm, node); - - timerqueue_del(&base->timerqueue, &alarm->node); - alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; - - alarm->state |= ALARMTIMER_STATE_CALLBACK; - spin_unlock_irqrestore(&base->lock, flags); - if (alarm->function) - restart = alarm->function(alarm, now); - spin_lock_irqsave(&base->lock, flags); - alarm->state &= ~ALARMTIMER_STATE_CALLBACK; + alarmtimer_dequeue(base, alarm); + spin_unlock_irqrestore(&base->lock, flags); - if (restart != ALARMTIMER_NORESTART) { - timerqueue_add(&base->timerqueue, &alarm->node); - alarm->state |= ALARMTIMER_STATE_ENQUEUED; - } - } + if (alarm->function) + restart = alarm->function(alarm, base->gettime()); - if (next) { - hrtimer_set_expires(&base->timer, next->expires); + spin_lock_irqsave(&base->lock, flags); + if (restart != ALARMTIMER_NORESTART) { + hrtimer_set_expires(&alarm->timer, alarm->node.expires); + alarmtimer_enqueue(base, alarm); ret = HRTIMER_RESTART; } spin_unlock_irqrestore(&base->lock, flags); @@ -250,6 +217,7 @@ static int alarmtimer_suspend(struct device *dev) unsigned long flags; struct rtc_device *rtc; int i; + int ret; spin_lock_irqsave(&freezer_delta_lock, flags); min = freezer_delta; @@ -279,8 +247,10 @@ static int alarmtimer_suspend(struct device *dev) if (min.tv64 == 0) return 0; - /* XXX - Should we enforce a minimum sleep time? */ - WARN_ON(min.tv64 < NSEC_PER_SEC); + if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { + __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); + return -EBUSY; + } /* Setup an rtc timer to fire that far in the future */ rtc_timer_cancel(rtc, &rtctimer); @@ -288,9 +258,11 @@ static int alarmtimer_suspend(struct device *dev) now = rtc_tm_to_ktime(tm); now = ktime_add(now, min); - rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); - - return 0; + /* Set alarm, if in the past reject suspend briefly to handle */ + ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); + if (ret < 0) + __pm_wakeup_event(ws, MSEC_PER_SEC); + return ret; } #else static int alarmtimer_suspend(struct device *dev) @@ -324,6 +296,9 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) { timerqueue_init(&alarm->node); + hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid, + HRTIMER_MODE_ABS); + alarm->timer.function = alarmtimer_fired; alarm->function = function; alarm->type = type; alarm->state = ALARMTIMER_STATE_INACTIVE; @@ -334,17 +309,19 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type, * @alarm: ptr to alarm to set * @start: time to run the alarm */ -void alarm_start(struct alarm *alarm, ktime_t start) +int alarm_start(struct alarm *alarm, ktime_t start) { struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; + int ret; spin_lock_irqsave(&base->lock, flags); - if (alarmtimer_active(alarm)) - alarmtimer_remove(base, alarm); alarm->node.expires = start; alarmtimer_enqueue(base, alarm); + ret = hrtimer_start(&alarm->timer, alarm->node.expires, + HRTIMER_MODE_ABS); spin_unlock_irqrestore(&base->lock, flags); + return ret; } /** @@ -358,18 +335,12 @@ int alarm_try_to_cancel(struct alarm *alarm) { struct alarm_base *base = &alarm_bases[alarm->type]; unsigned long flags; - int ret = -1; - spin_lock_irqsave(&base->lock, flags); - - if (alarmtimer_callback_running(alarm)) - goto out; + int ret; - if (alarmtimer_is_queued(alarm)) { - alarmtimer_remove(base, alarm); - ret = 1; - } else - ret = 0; -out: + spin_lock_irqsave(&base->lock, flags); + ret = hrtimer_try_to_cancel(&alarm->timer); + if (ret >= 0) + alarmtimer_dequeue(base, alarm); spin_unlock_irqrestore(&base->lock, flags); return ret; } @@ -802,10 +773,6 @@ static int __init alarmtimer_init(void) for (i = 0; i < ALARM_NUMTYPE; i++) { timerqueue_init_head(&alarm_bases[i].timerqueue); spin_lock_init(&alarm_bases[i].lock); - hrtimer_init(&alarm_bases[i].timer, - alarm_bases[i].base_clockid, - HRTIMER_MODE_ABS); - alarm_bases[i].timer.function = alarmtimer_fired; } error = alarmtimer_rtc_interface_setup(); @@ -821,6 +788,7 @@ static int __init alarmtimer_init(void) error = PTR_ERR(pdev); goto out_drv; } + ws = wakeup_source_register("alarmtimer"); return 0; out_drv: diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c index 46da0537c10b..6629bf7b5285 100644 --- a/kernel/time/jiffies.c +++ b/kernel/time/jiffies.c @@ -37,7 +37,7 @@ * requested HZ value. It is also not recommended * for "tick-less" systems. */ -#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ)) +#define NSEC_PER_JIFFY ((NSEC_PER_SEC+HZ/2)/HZ) /* Since jiffies uses a simple NSEC_PER_JIFFY multiplier * conversion, the .shift value could be zero. However @@ -95,3 +95,33 @@ struct clocksource * __init __weak clocksource_default_clock(void) { return &clocksource_jiffies; } + +struct clocksource refined_jiffies; + +int register_refined_jiffies(long cycles_per_second) +{ + u64 nsec_per_tick, shift_hz; + long cycles_per_tick; + + + + refined_jiffies = clocksource_jiffies; + refined_jiffies.name = "refined-jiffies"; + refined_jiffies.rating++; + + /* Calc cycles per tick */ + cycles_per_tick = (cycles_per_second + HZ/2)/HZ; + /* shift_hz stores hz<<8 for extra accuracy */ + shift_hz = (u64)cycles_per_second << 8; + shift_hz += cycles_per_tick/2; + do_div(shift_hz, cycles_per_tick); + /* Calculate nsec_per_tick using shift_hz */ + nsec_per_tick = (u64)NSEC_PER_SEC << 8; + nsec_per_tick += (u32)shift_hz/2; + do_div(nsec_per_tick, (u32)shift_hz); + + refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT; + + clocksource_register(&refined_jiffies); + return 0; +} diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index f423bdd035c2..a40260885265 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -835,7 +835,7 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) */ if (ts->tick_stopped) { touch_softlockup_watchdog(); - if (idle_cpu(cpu)) + if (is_idle_task(current)) ts->idle_jiffies++; } update_process_times(user_mode(regs)); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 5ce06a3fa91e..e424970bb562 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -8,6 +8,7 @@ * */ +#include <linux/timekeeper_internal.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/percpu.h> @@ -21,61 +22,6 @@ #include <linux/tick.h> #include <linux/stop_machine.h> -/* Structure holding internal timekeeping values. */ -struct timekeeper { - /* Current clocksource used for timekeeping. */ - struct clocksource *clock; - /* NTP adjusted clock multiplier */ - u32 mult; - /* The shift value of the current clocksource. */ - u32 shift; - /* Number of clock cycles in one NTP interval. */ - cycle_t cycle_interval; - /* Number of clock shifted nano seconds in one NTP interval. */ - u64 xtime_interval; - /* shifted nano seconds left over when rounding cycle_interval */ - s64 xtime_remainder; - /* Raw nano seconds accumulated per NTP interval. */ - u32 raw_interval; - - /* Current CLOCK_REALTIME time in seconds */ - u64 xtime_sec; - /* Clock shifted nano seconds */ - u64 xtime_nsec; - - /* Difference between accumulated time and NTP time in ntp - * shifted nano seconds. */ - s64 ntp_error; - /* Shift conversion between clock shifted nano seconds and - * ntp shifted nano seconds. */ - u32 ntp_error_shift; - - /* - * wall_to_monotonic is what we need to add to xtime (or xtime corrected - * for sub jiffie times) to get to monotonic time. Monotonic is pegged - * at zero at system boot time, so wall_to_monotonic will be negative, - * however, we will ALWAYS keep the tv_nsec part positive so we can use - * the usual normalization. - * - * wall_to_monotonic is moved after resume from suspend for the - * monotonic time not to jump. We need to add total_sleep_time to - * wall_to_monotonic to get the real boot based time offset. - * - * - wall_to_monotonic is no longer the boot time, getboottime must be - * used instead. - */ - struct timespec wall_to_monotonic; - /* Offset clock monotonic -> clock realtime */ - ktime_t offs_real; - /* time spent in suspend */ - struct timespec total_sleep_time; - /* Offset clock monotonic -> clock boottime */ - ktime_t offs_boot; - /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */ - struct timespec raw_time; - /* Seqlock for all timekeeper values */ - seqlock_t lock; -}; static struct timekeeper timekeeper; @@ -96,15 +42,6 @@ static inline void tk_normalize_xtime(struct timekeeper *tk) } } -static struct timespec tk_xtime(struct timekeeper *tk) -{ - struct timespec ts; - - ts.tv_sec = tk->xtime_sec; - ts.tv_nsec = (long)(tk->xtime_nsec >> tk->shift); - return ts; -} - static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts) { tk->xtime_sec = ts->tv_sec; @@ -246,14 +183,11 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk) /* must hold write on timekeeper.lock */ static void timekeeping_update(struct timekeeper *tk, bool clearntp) { - struct timespec xt; - if (clearntp) { tk->ntp_error = 0; ntp_clear(); } - xt = tk_xtime(tk); - update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult); + update_vsyscall(tk); } /** @@ -1113,7 +1047,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, accumulate_nsecs_to_secs(tk); /* Accumulate raw time */ - raw_nsecs = tk->raw_interval << shift; + raw_nsecs = (u64)tk->raw_interval << shift; raw_nsecs += tk->raw_time.tv_nsec; if (raw_nsecs >= NSEC_PER_SEC) { u64 raw_secs = raw_nsecs; @@ -1130,6 +1064,33 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, return offset; } +#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD +static inline void old_vsyscall_fixup(struct timekeeper *tk) +{ + s64 remainder; + + /* + * Store only full nanoseconds into xtime_nsec after rounding + * it up and add the remainder to the error difference. + * XXX - This is necessary to avoid small 1ns inconsistnecies caused + * by truncating the remainder in vsyscalls. However, it causes + * additional work to be done in timekeeping_adjust(). Once + * the vsyscall implementations are converted to use xtime_nsec + * (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD + * users are removed, this can be killed. + */ + remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); + tk->xtime_nsec -= remainder; + tk->xtime_nsec += 1ULL << tk->shift; + tk->ntp_error += remainder << tk->ntp_error_shift; + +} +#else +#define old_vsyscall_fixup(tk) +#endif + + + /** * update_wall_time - Uses the current clocksource to increment the wall time * @@ -1141,7 +1102,6 @@ static void update_wall_time(void) cycle_t offset; int shift = 0, maxshift; unsigned long flags; - s64 remainder; write_seqlock_irqsave(&tk->lock, flags); @@ -1183,20 +1143,11 @@ static void update_wall_time(void) /* correct the clock when NTP error is too big */ timekeeping_adjust(tk, offset); - /* - * Store only full nanoseconds into xtime_nsec after rounding - * it up and add the remainder to the error difference. - * XXX - This is necessary to avoid small 1ns inconsistnecies caused - * by truncating the remainder in vsyscalls. However, it causes - * additional work to be done in timekeeping_adjust(). Once - * the vsyscall implementations are converted to use xtime_nsec - * (shifted nanoseconds), this can be killed. - */ - remainder = tk->xtime_nsec & ((1ULL << tk->shift) - 1); - tk->xtime_nsec -= remainder; - tk->xtime_nsec += 1ULL << tk->shift; - tk->ntp_error += remainder << tk->ntp_error_shift; + * XXX This can be killed once everyone converts + * to the new update_vsyscall. + */ + old_vsyscall_fixup(tk); /* * Finally, make sure that after the rounding diff --git a/kernel/timer.c b/kernel/timer.c index d5de1b2292aa..367d00858482 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -63,6 +63,7 @@ EXPORT_SYMBOL(jiffies_64); #define TVR_SIZE (1 << TVR_BITS) #define TVN_MASK (TVN_SIZE - 1) #define TVR_MASK (TVR_SIZE - 1) +#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4*TVN_BITS)) - 1)) struct tvec { struct list_head vec[TVN_SIZE]; @@ -359,11 +360,12 @@ __internal_add_timer(struct tvec_base *base, struct timer_list *timer) vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK); } else { int i; - /* If the timeout is larger than 0xffffffff on 64-bit - * architectures then we use the maximum timeout: + /* If the timeout is larger than MAX_TVAL (on 64-bit + * architectures or with CONFIG_BASE_SMALL=1) then we + * use the maximum timeout. */ - if (idx > 0xffffffffUL) { - idx = 0xffffffffUL; + if (idx > MAX_TVAL) { + idx = MAX_TVAL; expires = idx + base->timer_jiffies; } i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; diff --git a/mm/slab_common.c b/mm/slab_common.c index 9c217255ac49..069a24e64403 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -168,6 +168,7 @@ void kmem_cache_destroy(struct kmem_cache *s) list_del(&s->list); if (!__kmem_cache_shutdown(s)) { + mutex_unlock(&slab_mutex); if (s->flags & SLAB_DESTROY_BY_RCU) rcu_barrier(); @@ -175,12 +176,14 @@ void kmem_cache_destroy(struct kmem_cache *s) kmem_cache_free(kmem_cache, s); } else { list_add(&s->list, &slab_caches); + mutex_unlock(&slab_mutex); printk(KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n", s->name); dump_stack(); } + } else { + mutex_unlock(&slab_mutex); } - mutex_unlock(&slab_mutex); put_online_cpus(); } EXPORT_SYMBOL(kmem_cache_destroy); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index c0ab72cbeed1..70d4848b5cd0 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -5168,6 +5168,8 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); */ void *snd_array_new(struct snd_array *array) { + if (snd_BUG_ON(!array->elem_size)) + return NULL; if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; int size = (num + 1) * array->elem_size; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index f09ff6c14041..6833835a218b 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -554,7 +554,6 @@ enum { #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_POSFIX_COMBO (1 << 24) /* Use COMBO as default */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ /* quirks for ATI SB / AMD Hudson */ @@ -2858,10 +2857,6 @@ static int __devinit check_position_fix(struct azx *chip, int fix) snd_printd(SFX "Using LPIB position fix\n"); return POS_FIX_LPIB; } - if (chip->driver_caps & AZX_DCAPS_POSFIX_COMBO) { - snd_printd(SFX "Using COMBO position fix\n"); - return POS_FIX_COMBO; - } return POS_FIX_AUTO; } diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index fcfc9f0a056b..61a71131711c 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -897,7 +897,7 @@ static int build_digital_input(struct hda_codec *codec) * HP/SPK/SPDIF */ -static void cs_automute(struct hda_codec *codec) +static void cs_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -973,7 +973,7 @@ static void cs_automute(struct hda_codec *codec) * Switch max 3 inputs of a single ADC (nid 3) */ -static void cs_automic(struct hda_codec *codec) +static void cs_automic(struct hda_codec *codec, struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -1035,7 +1035,7 @@ static void init_output(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable(codec, nid, HP_EVENT); + snd_hda_jack_detect_enable_callback(codec, nid, HP_EVENT, cs_automute); spec->hp_detect = 1; } } @@ -1046,7 +1046,7 @@ static void init_output(struct hda_codec *codec) /* SPDIF is enabled on presence detect for CS421x */ if (spec->hp_detect || spec->spdif_detect) - cs_automute(codec); + cs_automute(codec, NULL); } static void init_input(struct hda_codec *codec) @@ -1070,13 +1070,13 @@ static void init_input(struct hda_codec *codec) AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(spec->adc_idx[i])); if (spec->mic_detect && spec->automic_idx == i) - snd_hda_jack_detect_enable(codec, pin, MIC_EVENT); + snd_hda_jack_detect_enable_callback(codec, pin, MIC_EVENT, cs_automic); } /* CS420x has multiple ADC, CS421x has single ADC */ if (spec->vendor_nid == CS420X_VENDOR_NID) { change_cur_input(codec, spec->cur_input, 1); if (spec->mic_detect) - cs_automic(codec); + cs_automic(codec, NULL); coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ if (is_active_pin(codec, CS_DMIC2_PIN_NID)) @@ -1089,7 +1089,7 @@ static void init_input(struct hda_codec *codec) cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); } else { if (spec->mic_detect) - cs_automic(codec); + cs_automic(codec, NULL); else { spec->cur_adc = spec->adc_nid[spec->cur_input]; cs_update_input_select(codec); @@ -1243,28 +1243,16 @@ static void cs_free(struct hda_codec *codec) struct cs_spec *spec = codec->spec; kfree(spec->capture_bind[0]); kfree(spec->capture_bind[1]); + snd_hda_gen_free(&spec->gen); kfree(codec->spec); } -static void cs_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (snd_hda_jack_get_action(codec, res >> 26)) { - case HP_EVENT: - cs_automute(codec); - break; - case MIC_EVENT: - cs_automic(codec); - break; - } - snd_hda_jack_report_sync(codec); -} - static const struct hda_codec_ops cs_patch_ops = { .build_controls = cs_build_controls, .build_pcms = cs_build_pcms, .init = cs_init, .free = cs_free, - .unsol_event = cs_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, }; static int cs_parse_auto_config(struct hda_codec *codec) @@ -1439,6 +1427,7 @@ static int patch_cs420x(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS420X_VENDOR_NID; @@ -1457,7 +1446,7 @@ static int patch_cs420x(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -1674,7 +1663,7 @@ static void init_cs421x_digital(struct hda_codec *codec) if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable(codec, nid, SPDIF_EVENT); + snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs_automute); spec->spdif_detect = 1; } } @@ -1889,21 +1878,6 @@ static int cs421x_build_controls(struct hda_codec *codec) return 0; } -static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (snd_hda_jack_get_action(codec, res >> 26)) { - case HP_EVENT: - case SPDIF_EVENT: - cs_automute(codec); - break; - - case MIC_EVENT: - cs_automic(codec); - break; - } - snd_hda_jack_report_sync(codec); -} - static int parse_cs421x_input(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; @@ -1977,7 +1951,7 @@ static struct hda_codec_ops cs421x_patch_ops = { .build_pcms = cs_build_pcms, .init = cs421x_init, .free = cs_free, - .unsol_event = cs421x_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = cs421x_suspend, #endif @@ -1992,6 +1966,7 @@ static int patch_cs4210(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS4210_VENDOR_NID; @@ -2017,7 +1992,7 @@ static int patch_cs4210(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } @@ -2031,6 +2006,7 @@ static int patch_cs4213(struct hda_codec *codec) if (!spec) return -ENOMEM; codec->spec = spec; + snd_hda_gen_init(&spec->gen); spec->vendor_nid = CS4213_VENDOR_NID; @@ -2042,7 +2018,7 @@ static int patch_cs4213(struct hda_codec *codec) return 0; error: - kfree(codec->spec); + cs_free(codec); codec->spec = NULL; return err; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8568aee56e2d..8253b4eeb6a1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -611,6 +611,8 @@ static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack { struct alc_spec *spec = codec->spec; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + return; /* check LO jack only when it's different from HP */ if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) return; @@ -4245,6 +4247,7 @@ static void alc_auto_init_std(struct hda_codec *codec) ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) static const struct snd_pci_quirk beep_white_list[] = { + SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index fe163547f906..770013ff556f 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -104,6 +104,7 @@ enum { STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, + STAC_92HD83XXX_HEADSET_JACK, STAC_92HD83XXX_MODELS }; @@ -204,6 +205,7 @@ struct sigmatel_spec { unsigned int check_volume_offset:1; unsigned int auto_mic:1; unsigned int linear_tone_beep:1; + unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */ /* gpio lines */ unsigned int eapd_mask; @@ -1684,6 +1686,7 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_HP_LED] = "hp-led", [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", + [STAC_92HD83XXX_HEADSET_JACK] = "headset-jack", }; static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1694,6 +1697,24 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD83XXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0532, + "Dell Latitude E6230", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0533, + "Dell Latitude E6330", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0534, + "Dell Latitude E6430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0535, + "Dell Latitude E6530", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053c, + "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053d, + "Dell Latitude E5530", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0549, + "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x057d, + "Dell Latitude E6430s", STAC_92HD83XXX_HEADSET_JACK), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0584, + "Dell Latitude E6430U", STAC_92HD83XXX_HEADSET_JACK), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028, "Dell Vostro 3500", STAC_DELL_VOSTRO_3500), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656, @@ -2855,6 +2876,9 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, char name[22]; if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { + if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf) + != INPUT_PIN_ATTR_DOCK) + return 0; if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD && nid == spec->line_switch) control = STAC_CTL_WIDGET_IO_SWITCH; @@ -5626,6 +5650,9 @@ again: case STAC_92HD83XXX_HP_MIC_LED: spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ break; + case STAC_92HD83XXX_HEADSET_JACK: + spec->headset_jack = 1; + break; } if (find_mute_led_cfg(codec, default_polarity)) diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 5a45a912aedc..72a2f60b087c 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -118,6 +118,8 @@ enum { }; struct via_spec { + struct hda_gen_spec gen; + /* codec parameterization */ const struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; @@ -246,6 +248,7 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) /* VT1708BCE & VT1708S are almost same */ if (spec->codec_type == VT1708BCE) spec->codec_type = VT1708S; + snd_hda_gen_init(&spec->gen); return spec; } @@ -299,7 +302,6 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_JACK_EVENT 0x20 #define VIA_HP_EVENT 0x01 -#define VIA_GPIO_EVENT 0x02 #define VIA_LINE_EVENT 0x03 enum { @@ -1628,6 +1630,7 @@ static void via_free(struct hda_codec *codec) vt1708_stop_hp_work(spec); kfree(spec->bind_cap_vol); kfree(spec->bind_cap_sw); + snd_hda_gen_free(&spec->gen); kfree(spec); } @@ -1685,69 +1688,6 @@ static void via_hp_automute(struct hda_codec *codec) via_line_automute(codec, present); } -static void via_gpio_control(struct hda_codec *codec) -{ - unsigned int gpio_data; - unsigned int vol_counter; - unsigned int vol; - unsigned int master_vol; - - struct via_spec *spec = codec->spec; - - gpio_data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0) & 0x03; - - vol_counter = (snd_hda_codec_read(codec, codec->afg, 0, - 0xF84, 0) & 0x3F0000) >> 16; - - vol = vol_counter & 0x1F; - master_vol = snd_hda_codec_read(codec, 0x1A, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - - if (gpio_data == 0x02) { - /* unmute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], - PIN_OUT); - if (vol_counter & 0x20) { - /* decrease volume */ - if (vol > master_vol) - vol = master_vol; - snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, - 0, HDA_AMP_VOLMASK, - master_vol-vol); - } else { - /* increase volume */ - snd_hda_codec_amp_stereo(codec, 0x1A, HDA_INPUT, 0, - HDA_AMP_VOLMASK, - ((master_vol+vol) > 0x2A) ? 0x2A : - (master_vol+vol)); - } - } else if (!(gpio_data & 0x02)) { - /* mute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0); - } -} - -/* unsolicited event for jack sensing */ -static void via_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - res = snd_hda_jack_get_action(codec, res); - - if (res & VIA_JACK_EVENT) - set_widgets_power_state(codec); - - res &= ~VIA_JACK_EVENT; - - if (res == VIA_HP_EVENT || res == VIA_LINE_EVENT) - via_hp_automute(codec); - else if (res == VIA_GPIO_EVENT) - via_gpio_control(codec); - snd_hda_jack_report_sync(codec); -} - #ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { @@ -1783,7 +1723,7 @@ static const struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, - .unsol_event = via_unsol_event, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .suspend = via_suspend, .check_power_status = via_check_power_status, @@ -2761,6 +2701,17 @@ static void via_auto_init_dig_in(struct hda_codec *codec) snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN); } +static void via_jack_output_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +{ + set_widgets_power_state(codec); + via_hp_automute(codec); +} + +static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +{ + set_widgets_power_state(codec); +} + /* initialize the unsolicited events */ static void via_auto_init_unsol_event(struct hda_codec *codec) { @@ -2768,26 +2719,31 @@ static void via_auto_init_unsol_event(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int ev; int i; + hda_jack_callback cb; if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_jack_detect_enable(codec, cfg->hp_pins[0], - VIA_HP_EVENT | VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->hp_pins[0], + VIA_HP_EVENT | VIA_JACK_EVENT, + via_jack_output_event); if (cfg->speaker_pins[0]) ev = VIA_LINE_EVENT; else ev = 0; + cb = ev ? via_jack_output_event : via_jack_powerstate_event; + for (i = 0; i < cfg->line_outs; i++) { if (cfg->line_out_pins[i] && is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_jack_detect_enable(codec, cfg->line_out_pins[i], - ev | VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->line_out_pins[i], + ev | VIA_JACK_EVENT, cb); } for (i = 0; i < cfg->num_inputs; i++) { if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_jack_detect_enable(codec, cfg->inputs[i].pin, - VIA_JACK_EVENT); + snd_hda_jack_detect_enable_callback(codec, cfg->inputs[i].pin, + VIA_JACK_EVENT, + via_jack_powerstate_event); } } diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index d73ac9bc4272..88d8cebbb244 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2780,6 +2780,52 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +{ + /* Tascam US122 MKII - playback-only support */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = 0x8021, + .bInterfaceClass = USB_CLASS_AUDIO, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "TASCAM", + .product_name = "US122 MKII", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_IGNORE_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 1, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x02, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 44100, + .rate_max = 96000, + .nr_rates = 4, + .rate_table = (unsigned int[]) { + 44100, 48000, 88200, 96000 + } + } + }, + { + .ifnum = -1 + } + } + } +}, /* Microsoft XboxLive Headset/Xbox Communicator */ { |