media updates for v5.19-rc1

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmKLMPAACgkQCF8+vY7k
 4RVupA//Q4U2BV3xKn9H3g/+dbSIbm0YEeWc2xMd3wbDnqokXsKxOuIfG1omIxCf
 hfhfnEfhRo0WHc5AGaHtbodCU3HcCrNdjH59r6nwedQg3qgFwMT4FYDNW33E8PN1
 dj293GEUZ+BZGDoCatGOxlHi/I2/HcS3I6BiU/GlglALgM/8KaBvdMhY8S6lEXIK
 SqdiDDOsXVT+v1BB2PSSaRWU3KIccLzS2QlXQRTs2xKszXuQy6wT6IK//YqvFxQp
 PS9uziJhJNk2nIlZqE8U46iYv9v+HnTW/5cLrUDTj0VIxjWHgMSnpbubOABgBRYj
 gX1wXRqe/bx9frm1ksfBUyNmEmxF3LL2h6fnkc2RQh/T/DKwMFpE9u3P8aEIPtmk
 djACoQbdjJXKtez1Uw5KT1nH8EKfgeA5z/PkFw+zYMiXtNdhIgxFBg38veI+/jsB
 w8nUPydFWy/EpmgTbQTmvbF9c+LczqUgaMSbXKzLByVfxie/SsE/JRyLXQITByVT
 QmmZ3WTKjTJYa1gEz2lvIafhTxXWu7mnBo7ma1wSXVPSkwOr2m73aIfxf1h1vr/N
 +/sCOEeQiVT67arKbdlmf7IDvNzcRmnBTdSE//VkJGonaBAjrpUuRD4Yq61YCVon
 DqVh29LGeFDmkRkcvfZVT2Si/UwDAYhHa8yb0lPZpVXhKbCxLUQ=
 =HllR
 -----END PGP SIGNATURE-----

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

Pull media updates from Mauro Carvalho Chehab:

 - dvb-usb drivers entries got reworked to avoid usage of magic numbers
   to refer to data position inside tables

 - vcodec driver has gained support for MT8186 and for vp8 and vp9
   stateless codecs

 - hantro has gained support for Hantro G1 on RK366x

 - Added more h264 levels on coda960

 - ccs gained support for MIPI CSI-2 28 bits per pixel raw data type

 - venus driver gained support for Qualcomm custom compressed pixel
   formats

 - lots of driver fixes and updates

* tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
  media: hantro: Enable HOLD_CAPTURE_BUF for H.264
  media: hantro: Add H.264 field decoding support
  media: hantro: h264: Make dpb entry management more robust
  media: hantro: Stop using H.264 parameter pic_num
  media: rkvdec: Enable capture buffer holding for H264
  media: rkvdec-h264: Add field decoding support
  media: rkvdec: Ensure decoded resolution fit coded resolution
  media: rkvdec: h264: Fix reference frame_num wrap for second field
  media: rkvdec: h264: Validate and use pic width and height in mbs
  media: rkvdec: Move H264 SPS validation in rkvdec-h264
  media: rkvdec: h264: Fix bit depth wrap in pps packet
  media: rkvdec: h264: Fix dpb_valid implementation
  media: rkvdec: Stop overclocking the decoder
  media: v4l2: Reorder field reflist
  media: h264: Sort p/b reflist using frame_num
  media: v4l2: Trace calculated p/b0/b1 initial reflist
  media: h264: Store all fields into the unordered list
  media: h264: Store current picture fields
  media: h264: Increase reference lists size to 32
  media: h264: Use v4l2_h264_reference for reflist
  ...
This commit is contained in:
Linus Torvalds 2022-05-24 18:09:16 -07:00
commit 827060261c
269 changed files with 9711 additions and 3611 deletions

View File

@ -9,14 +9,14 @@ digraph board {
n00000003:port0 -> n00000008:port0 [style=bold]
n00000003:port0 -> n0000000f [style=bold]
n00000005 [label="{{<port0> 0} | Debayer A\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000005:port1 -> n00000017:port0
n00000005:port1 -> n00000015:port0
n00000008 [label="{{<port0> 0} | Debayer B\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000008:port1 -> n00000017:port0 [style=dashed]
n00000008:port1 -> n00000015:port0 [style=dashed]
n0000000b [label="Raw Capture 0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
n0000000f [label="Raw Capture 1\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
n00000013 [label="RGB/YUV Input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
n00000013 -> n00000017:port0 [style=dashed]
n00000017 [label="{{<port0> 0} | Scaler\n/dev/v4l-subdev4 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000017:port1 -> n0000001a [style=bold]
n0000001a [label="RGB/YUV Capture\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
n00000013 [label="{{} | RGB/YUV Input\n/dev/v4l-subdev4 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
n00000013:port0 -> n00000015:port0 [style=dashed]
n00000015 [label="{{<port0> 0} | Scaler\n/dev/v4l-subdev5 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
n00000015:port1 -> n00000018 [style=bold]
n00000018 [label="RGB/YUV Capture\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
}

View File

@ -1,9 +0,0 @@
Dongwoon Anatech DW9807 voice coil lens driver
DW9807 is a 10-bit DAC with current sink capability. It is intended for
controlling voice coil lenses.
Mandatory properties:
- compatible: "dongwoon,dw9807-vcm"
- reg: I2C slave address

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2018, 2021 Intel Corporation
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9807-vcm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dongwoon Anatech DW9807 voice coil lens driver
maintainers:
- Sakari Ailus <sakari.ailus@linux.intel.com>
description: |
DW9807 is a 10-bit DAC with current sink capability. It is intended for
controlling voice coil lenses.
properties:
compatible:
const: dongwoon,dw9807-vcm
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
lens@e {
compatible = "dongwoon,dw9807-vcm";
reg = <0x0e>;
};
};
...

View File

@ -32,6 +32,15 @@ properties:
description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz
maxItems: 1
dovdd-supply:
description: Interface power supply.
avdd-supply:
description: Analog power supply.
dvdd-supply:
description: Digital power supply.
reset-gpios:
description: Reference to the GPIO connected to the XCLR pin, if any.
maxItems: 1

View File

@ -63,6 +63,9 @@ properties:
description:
Describes point to scp.
power-domains:
maxItems: 1
required:
- compatible
- reg

View File

@ -47,7 +47,9 @@ description: |
properties:
compatible:
const: mediatek,mt8192-vcodec-dec
enum:
- mediatek,mt8192-vcodec-dec
- mediatek,mt8186-vcodec-dec
reg:
maxItems: 1

View File

@ -67,7 +67,7 @@ properties:
remote-endpoint: true
bus-width:
enum: [8, 9, 10, 11, 12]
enum: [8, 9, 10, 11, 12, 14]
default: 12
hsync-active:

View File

@ -18,7 +18,9 @@ properties:
oneOf:
- const: rockchip,rk3399-vdec
- items:
- const: rockchip,rk3228-vdec
- enum:
- rockchip,rk3228-vdec
- rockchip,rk3328-vdec
- const: rockchip,rk3399-vdec
reg:

View File

@ -23,6 +23,7 @@ properties:
- rockchip,rk3328-vpu
- rockchip,rk3399-vpu
- rockchip,px30-vpu
- rockchip,rk3568-vpu
- items:
- const: rockchip,rk3188-vpu
- const: rockchip,rk3066-vpu

View File

@ -93,6 +93,7 @@ properties:
- 4 # MIPI CSI-2 D-PHY
- 5 # Parallel
- 6 # BT.656
- 7 # DPI
description:
Data bus type.

View File

@ -109,6 +109,7 @@ your driver:
int (*adap_monitor_all_enable)(struct cec_adapter *adap, bool enable);
int (*adap_monitor_pin_enable)(struct cec_adapter *adap, bool enable);
int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
void (*adap_configured)(struct cec_adapter *adap, bool configured);
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg);
void (*adap_status)(struct cec_adapter *adap, struct seq_file *file);
@ -117,7 +118,7 @@ your driver:
/* Error injection callbacks */
...
/* High-level callbacks */
/* High-level callback */
...
};
@ -178,6 +179,16 @@ can receive directed messages to that address.
Note that adap_log_addr must return 0 if logical_addr is CEC_LOG_ADDR_INVALID.
Called when the adapter is fully configured or unconfigured::
void (*adap_configured)(struct cec_adapter *adap, bool configured);
If configured == true, then the adapter is fully configured, i.e. all logical
addresses have been successfully claimed. If configured == false, then the
adapter is unconfigured. If the driver has to take specific actions after
(un)configuration, then that can be done through this optional callback.
To transmit a new message::
int (*adap_transmit)(struct cec_adapter *adap, u8 attempts,

View File

@ -42,9 +42,16 @@ Allocation of the structure is handled by the media device driver, usually by
embedding the :c:type:`media_device` instance in a larger driver-specific
structure.
Drivers register media device instances by calling
:c:func:`__media_device_register()` via the macro ``media_device_register()``
and unregistered by calling :c:func:`media_device_unregister()`.
Drivers initialise media device instances by calling
:c:func:`media_device_init()`. After initialising a media device instance, it is
registered by calling :c:func:`__media_device_register()` via the macro
``media_device_register()`` and unregistered by calling
:c:func:`media_device_unregister()`. An initialised media device must be
eventually cleaned up by calling :c:func:`media_device_cleanup()`.
Note that it is not allowed to unregister a media device instance that was not
previously registered, or clean up a media device instance that was not
previously initialised.
Entities
^^^^^^^^

View File

@ -518,6 +518,75 @@ The :c:func:`v4l2_i2c_new_subdev` function will call
:c:type:`i2c_board_info` structure using the ``client_type`` and the
``addr`` to fill it.
Centrally managed subdev active state
-------------------------------------
Traditionally V4L2 subdev drivers maintained internal state for the active
device configuration. This is often implemented as e.g. an array of struct
v4l2_mbus_framefmt, one entry for each pad, and similarly for crop and compose
rectangles.
In addition to the active configuration, each subdev file handle has an array of
struct v4l2_subdev_pad_config, managed by the V4L2 core, which contains the try
configuration.
To simplify the subdev drivers the V4L2 subdev API now optionally supports a
centrally managed active configuration represented by
:c:type:`v4l2_subdev_state`. One instance of state, which contains the active
device configuration, is stored in the sub-device itself as part of
the :c:type:`v4l2_subdev` structure, while the core associates a try state to
each open file handle, to store the try configuration related to that file
handle.
Sub-device drivers can opt-in and use state to manage their active configuration
by initializing the subdevice state with a call to v4l2_subdev_init_finalize()
before registering the sub-device. They must also call v4l2_subdev_cleanup()
to release all the allocated resources before unregistering the sub-device.
The core automatically allocates and initializes a state for each open file
handle to store the try configurations and frees it when closing the file
handle.
V4L2 sub-device operations that use both the :ref:`ACTIVE and TRY formats
<v4l2-subdev-format-whence>` receive the correct state to operate on through
the 'state' parameter. The state must be locked and unlocked by the
caller by calling :c:func:`v4l2_subdev_lock_state()` and
:c:func:`v4l2_subdev_unlock_state()`. The caller can do so by calling the subdev
operation through the :c:func:`v4l2_subdev_call_state_active()` macro.
Operations that do not receive a state parameter implicitly operate on the
subdevice active state, which drivers can exclusively access by
calling :c:func:`v4l2_subdev_lock_and_get_active_state()`. The sub-device active
state must equally be released by calling :c:func:`v4l2_subdev_unlock_state()`.
Drivers must never manually access the state stored in the :c:type:`v4l2_subdev`
or in the file handle without going through the designated helpers.
While the V4L2 core passes the correct try or active state to the subdevice
operations, many existing device drivers pass a NULL state when calling
operations with :c:func:`v4l2_subdev_call()`. This legacy construct causes
issues with subdevice drivers that let the V4L2 core manage the active state,
as they expect to receive the appropriate state as a parameter. To help the
conversion of subdevice drivers to a managed active state without having to
convert all callers at the same time, an additional wrapper layer has been
added to v4l2_subdev_call(), which handles the NULL case by geting and locking
the callee's active state with :c:func:`v4l2_subdev_lock_and_get_active_state()`,
and unlocking the state after the call.
The whole subdev state is in reality split into three parts: the
v4l2_subdev_state, subdev controls and subdev driver's internal state. In the
future these parts should be combined into a single state. For the time being
we need a way to handle the locking for these parts. This can be accomplished
by sharing a lock. The v4l2_ctrl_handler already supports this via its 'lock'
pointer and the same model is used with states. The driver can do the following
before calling v4l2_subdev_init_finalize():
.. code-block:: c
sd->ctrl_handler->lock = &priv->mutex;
sd->state_lock = &priv->mutex;
This shares the driver's private mutex between the controls and the states.
V4L2 sub-device functions and data structures
---------------------------------------------

View File

@ -7,7 +7,7 @@ This file documents some driver-specific aspects of the UVC driver, such as
driver-specific ioctls and implementation notes.
Questions and remarks can be sent to the Linux UVC development mailing list at
linux-uvc-devel@lists.berlios.de.
linux-media@vger.kernel.org.
Extension Unit (XU) support

View File

@ -33,3 +33,9 @@ are:
- An **interface link** is a point-to-point bidirectional control
connection between a Linux Kernel interface and an entity.
- An **ancillary link** is a point-to-point connection denoting that two
entities form a single logical unit. For example this could represent the
fact that a particular camera sensor and lens controller form a single
physical module, meaning this lens controller drives the lens for this
camera sensor.

View File

@ -412,14 +412,21 @@ must be set for every pad.
is set by drivers and is read-only for applications.
* - ``MEDIA_LNK_FL_LINK_TYPE``
- This is a bitmask that defines the type of the link. Currently,
two types of links are supported:
- This is a bitmask that defines the type of the link. The following
link types are currently supported:
.. _MEDIA-LNK-FL-DATA-LINK:
``MEDIA_LNK_FL_DATA_LINK`` if the link is between two pads
``MEDIA_LNK_FL_DATA_LINK`` for links that represent a data connection
between two pads.
.. _MEDIA-LNK-FL-INTERFACE-LINK:
``MEDIA_LNK_FL_INTERFACE_LINK`` if the link is between an
interface and an entity
``MEDIA_LNK_FL_INTERFACE_LINK`` for links that associate an entity to its
interface.
.. _MEDIA-LNK-FL-ANCILLARY-LINK:
``MEDIA_LNK_FL_ANCILLARY_LINK`` for links that represent a physical
relationship between two entities. The link may or may not be
immutable, so applications must not assume either case.

View File

@ -72,6 +72,12 @@ coded resolution
coded width
width for given coded resolution.
coding tree unit
processing unit of the HEVC codec (corresponds to macroblock units in
H.264, VP8, VP9),
can use block structures of up to 64×64 pixels.
Good at sub-partitioning the picture into variable sized structures.
decode order
the order in which frames are decoded; may differ from display order if the
coded format includes a feature of frame reordering; for decoders,
@ -104,7 +110,8 @@ keyframe
macroblock
a processing unit in image and video compression formats based on linear
block transforms (e.g. H.264, VP8, VP9); codec-specific, but for most of
popular codecs the size is 16x16 samples (pixels).
popular codecs the size is 16x16 samples (pixels). The HEVC codec uses a
slightly more flexible processing unit called coding tree unit (CTU).
OUTPUT
the source buffer queue; for decoders, the queue of buffers containing

View File

@ -649,10 +649,16 @@ Stateless Codec Control ID
:c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
* - __u32
- ``pic_num``
-
- For short term references, this must match the derived value PicNum
(8-28) and for long term references it must match the derived value
LongTermPicNum (8-29). When decoding frames (as opposed to fields)
pic_num is the same as FrameNumWrap.
* - __u16
- ``frame_num``
-
- For short term references, this must match the frame_num value from
the slice header syntax (the driver will wrap the value if needed). For
long term references, this must be set to the value of
long_term_frame_idx described in the dec_ref_pic_marking() syntax.
* - __u8
- ``fields``
- Specifies how the DPB entry is referenced. See :ref:`Reference Fields <h264_ref_fields>`

View File

@ -1180,6 +1180,28 @@ enum v4l2_mpeg_video_h264_entropy_mode -
is set to non zero value.
Applicable to H264, H263 and MPEG4 encoder.
``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE (enum)``
enum v4l2_mpeg_video_intra_refresh_period_type -
Sets the type of intra refresh. The period to refresh
the whole frame is specified by V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD.
Note that if this control is not present, then it is undefined what
refresh type is used and it is up to the driver to decide.
Applicable to H264 and HEVC encoders. Possible values are:
.. tabularcolumns:: |p{9.6cm}|p{7.9cm}|
.. flat-table::
:header-rows: 0
:stub-columns: 0
* - ``V4L2_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM``
- The whole frame is completely refreshed randomly
after the specified period.
* - ``V4L2_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC``
- The whole frame MBs are completely refreshed in cyclic order
after the specified period.
``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (integer)``
Intra macroblock refresh period. This sets the period to refresh
the whole frame. In other words, this defines the number of frames

View File

@ -239,6 +239,25 @@ please make a proposal on the linux-media mailing list.
It remains an opaque intermediate format and the MDP hardware must be
used to convert ``V4L2_PIX_FMT_MT21C`` to ``V4L2_PIX_FMT_NV12M``,
``V4L2_PIX_FMT_YUV420M`` or ``V4L2_PIX_FMT_YVU420``.
* .. _V4L2-PIX-FMT-QC08C:
- ``V4L2_PIX_FMT_QC08C``
- 'QC08C'
- Compressed Macro-tile 8-Bit YUV420 format used by Qualcomm platforms.
It is an opaque intermediate format. The used compression is lossless
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video and eight planes for
interlaced video.
* .. _V4L2-PIX-FMT-QC10C:
- ``V4L2_PIX_FMT_QC10C``
- 'QC10C'
- Compressed Macro-tile 10-Bit YUV420 format used by Qualcomm platforms.
It is an opaque intermediate format. The used compression is lossless
and it is used by various multimedia hardware blocks like GPU, display
controllers, ISP and video accelerators.
It contains four planes for progressive video.
.. raw:: latex
\normalsize

View File

@ -48,6 +48,17 @@ are often referred to as greyscale formats.
- ...
- ...
* .. _V4L2-PIX-FMT-IPU3-Y10:
- ``V4L2_PIX_FMT_IPU3_Y10``
- 'ip3y'
- Y'\ :sub:`0`\ [7:0]
- Y'\ :sub:`1`\ [5:0] Y'\ :sub:`0`\ [9:8]
- Y'\ :sub:`2`\ [3:0] Y'\ :sub:`1`\ [9:6]
- Y'\ :sub:`3`\ [1:0] Y'\ :sub:`2`\ [9:4]
- Y'\ :sub:`3`\ [9:2]
* .. _V4L2-PIX-FMT-Y10:
- ``V4L2_PIX_FMT_Y10``
@ -133,4 +144,5 @@ are often referred to as greyscale formats.
For the Y16 and Y16_BE formats, the actual sampling precision may be lower
than 16 bits. For example, 10 bits per pixel uses values in the range 0 to
1023.
1023. For the IPU3_Y10 format 25 pixels are packed into 32 bytes, which
leaves the 6 most significant bits of the last byte padded with 0.

View File

@ -43,8 +43,7 @@ the capture or output process during streaming
Capture hardware is disabled and no input buffers are filled (if there
are any empty buffers in the incoming queue) until ``VIDIOC_STREAMON``
has been called. Output hardware is disabled and no video signal is
produced until ``VIDIOC_STREAMON`` has been called. The ioctl will
succeed when at least one output buffer is in the incoming queue.
produced until ``VIDIOC_STREAMON`` has been called.
Memory-to-memory devices will not start until ``VIDIOC_STREAMON`` has
been called for both the capture and output stream types.

View File

@ -12194,7 +12194,7 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/admin-guide/media/imx7.rst
F: Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml
F: drivers/media/platform/imx/imx-mipi-csis.c
F: drivers/media/platform/nxp/imx-mipi-csis.c
F: drivers/staging/media/imx/imx7-media-csi.c
MEDIA DRIVERS FOR HELENE
@ -12249,7 +12249,7 @@ L: linux-media@vger.kernel.org
L: linux-tegra@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt
F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.yaml
F: drivers/media/platform/nvidia/tegra-vde/
MEDIA DRIVERS FOR RENESAS - CEU
@ -12412,10 +12412,9 @@ F: drivers/iommu/mtk_iommu*
F: include/dt-bindings/memory/mt*-port.h
MEDIATEK JPEG DRIVER
M: Rick Chang <rick.chang@mediatek.com>
M: Bin Liu <bin.liu@mediatek.com>
S: Supported
F: Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
F: Documentation/devicetree/bindings/media/mediatek-jpeg-*.yaml
F: drivers/media/platform/mediatek/jpeg/
MEDIATEK MDP DRIVER
@ -12431,7 +12430,7 @@ MEDIATEK MEDIA DRIVER
M: Tiffany Lin <tiffany.lin@mediatek.com>
M: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
S: Supported
F: Documentation/devicetree/bindings/media/mediatek-vcodec.txt
F: Documentation/devicetree/bindings/media/mediatek,vcodec*.yaml
F: Documentation/devicetree/bindings/media/mediatek-vpu.txt
F: drivers/media/platform/mediatek/vcodec/
F: drivers/media/platform/mediatek/vpu/
@ -14246,7 +14245,7 @@ R: NXP Linux Team <linux-imx@nxp.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
F: drivers/media/platform/imx-jpeg
F: drivers/media/platform/nxp/imx-jpeg
NZXT-KRAKEN2 HARDWARE MONITORING DRIVER
M: Jonas Malaco <jonas@protocubo.io>
@ -20583,7 +20582,6 @@ F: drivers/usb/host/uhci*
USB VIDEO CLASS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-uvc-devel@lists.sourceforge.net (subscribers-only)
L: linux-media@vger.kernel.org
S: Maintained
W: http://www.ideasonboard.org/uvc/

View File

@ -27,27 +27,6 @@ static void cec_fill_msg_report_features(struct cec_adapter *adap,
struct cec_msg *msg,
unsigned int la_idx);
/*
* 400 ms is the time it takes for one 16 byte message to be
* transferred and 5 is the maximum number of retries. Add
* another 100 ms as a margin. So if the transmit doesn't
* finish before that time something is really wrong and we
* have to time out.
*
* This is a sign that something it really wrong and a warning
* will be issued.
*/
#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
#define call_op(adap, op, arg...) \
(adap->ops->op ? adap->ops->op(adap, ## arg) : 0)
#define call_void_op(adap, op, arg...) \
do { \
if (adap->ops->op) \
adap->ops->op(adap, ## arg); \
} while (0)
static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr)
{
int i;
@ -366,38 +345,48 @@ static void cec_data_completed(struct cec_data *data)
/*
* A pending CEC transmit needs to be cancelled, either because the CEC
* adapter is disabled or the transmit takes an impossibly long time to
* finish.
* finish, or the reply timed out.
*
* This function is called with adap->lock held.
*/
static void cec_data_cancel(struct cec_data *data, u8 tx_status)
static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status)
{
struct cec_adapter *adap = data->adap;
/*
* It's either the current transmit, or it is a pending
* transmit. Take the appropriate action to clear it.
*/
if (data->adap->transmitting == data) {
data->adap->transmitting = NULL;
if (adap->transmitting == data) {
adap->transmitting = NULL;
} else {
list_del_init(&data->list);
if (!(data->msg.tx_status & CEC_TX_STATUS_OK))
if (!WARN_ON(!data->adap->transmit_queue_sz))
data->adap->transmit_queue_sz--;
if (!WARN_ON(!adap->transmit_queue_sz))
adap->transmit_queue_sz--;
}
if (data->msg.tx_status & CEC_TX_STATUS_OK) {
data->msg.rx_ts = ktime_get_ns();
data->msg.rx_status = CEC_RX_STATUS_ABORTED;
data->msg.rx_status = rx_status;
if (!data->blocking)
data->msg.tx_status = 0;
} else {
data->msg.tx_ts = ktime_get_ns();
data->msg.tx_status |= tx_status |
CEC_TX_STATUS_MAX_RETRIES;
data->msg.tx_error_cnt++;
data->attempts = 0;
if (!data->blocking)
data->msg.rx_status = 0;
}
/* Queue transmitted message for monitoring purposes */
cec_queue_msg_monitor(data->adap, &data->msg, 1);
cec_queue_msg_monitor(adap, &data->msg, 1);
if (!data->blocking && data->msg.sequence)
/* Allow drivers to process the message first */
call_op(adap, received, &data->msg);
cec_data_completed(data);
}
@ -418,15 +407,15 @@ static void cec_flush(struct cec_adapter *adap)
while (!list_empty(&adap->transmit_queue)) {
data = list_first_entry(&adap->transmit_queue,
struct cec_data, list);
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
}
if (adap->transmitting)
cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED);
adap->transmit_in_progress_aborted = true;
/* Cancel the pending timeout work. */
list_for_each_entry_safe(data, n, &adap->wait_queue, list) {
if (cancel_delayed_work(&data->work))
cec_data_cancel(data, CEC_TX_STATUS_OK);
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED);
/*
* If cancel_delayed_work returned false, then
* the cec_wait_timeout function is running,
@ -482,7 +471,7 @@ int cec_thread_func(void *_adap)
kthread_should_stop() ||
(!adap->transmit_in_progress &&
!list_empty(&adap->transmit_queue)),
msecs_to_jiffies(CEC_XFER_TIMEOUT_MS));
msecs_to_jiffies(adap->xfer_timeout_ms));
timeout = err == 0;
} else {
/* Otherwise we just wait for something to happen. */
@ -508,7 +497,8 @@ int cec_thread_func(void *_adap)
* adapter driver, or the CEC bus is in some weird
* state. On rare occasions it can happen if there is
* so much traffic on the bus that the adapter was
* unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s).
* unable to transmit for xfer_timeout_ms (2.1s by
* default).
*/
if (adap->transmitting) {
pr_warn("cec-%s: message %*ph timed out\n", adap->name,
@ -516,7 +506,7 @@ int cec_thread_func(void *_adap)
adap->transmitting->msg.msg);
/* Just give up on this. */
cec_data_cancel(adap->transmitting,
CEC_TX_STATUS_TIMEOUT);
CEC_TX_STATUS_TIMEOUT, 0);
} else {
pr_warn("cec-%s: transmit timed out\n", adap->name);
}
@ -572,10 +562,11 @@ int cec_thread_func(void *_adap)
if (data->attempts == 0)
data->attempts = attempts;
adap->transmit_in_progress_aborted = false;
/* Tell the adapter to transmit, cancel on error */
if (adap->ops->adap_transmit(adap, data->attempts,
signal_free_time, &data->msg))
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
if (call_op(adap, adap_transmit, data->attempts,
signal_free_time, &data->msg))
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
else
adap->transmit_in_progress = true;
@ -599,6 +590,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
struct cec_msg *msg;
unsigned int attempts_made = arb_lost_cnt + nack_cnt +
low_drive_cnt + error_cnt;
bool done = status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK);
bool aborted = adap->transmit_in_progress_aborted;
dprintk(2, "%s: status 0x%02x\n", __func__, status);
if (attempts_made < 1)
@ -619,6 +612,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
goto wake_thread;
}
adap->transmit_in_progress = false;
adap->transmit_in_progress_aborted = false;
msg = &data->msg;
@ -639,8 +633,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
* the hardware didn't signal that it retried itself (by setting
* CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves.
*/
if (data->attempts > attempts_made &&
!(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) {
if (!aborted && data->attempts > attempts_made && !done) {
/* Retry this message */
data->attempts -= attempts_made;
if (msg->timeout)
@ -655,6 +648,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
goto wake_thread;
}
if (aborted && !done)
status |= CEC_TX_STATUS_ABORTED;
data->attempts = 0;
/* Always set CEC_TX_STATUS_MAX_RETRIES on error */
@ -733,9 +728,7 @@ static void cec_wait_timeout(struct work_struct *work)
/* Mark the message as timed out */
list_del_init(&data->list);
data->msg.rx_ts = ktime_get_ns();
data->msg.rx_status = CEC_RX_STATUS_TIMEOUT;
cec_data_completed(data);
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_TIMEOUT);
unlock:
mutex_unlock(&adap->lock);
}
@ -921,8 +914,12 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
mutex_lock(&adap->lock);
/* Cancel the transmit if it was interrupted */
if (!data->completed)
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
if (!data->completed) {
if (data->msg.tx_status & CEC_TX_STATUS_OK)
cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED);
else
cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0);
}
/* The transmit completed (possibly with an error) */
*msg = data->msg;
@ -1278,17 +1275,22 @@ static int cec_config_log_addr(struct cec_adapter *adap,
* While trying to poll the physical address was reset
* and the adapter was unconfigured, so bail out.
*/
if (!adap->is_configuring)
if (adap->phys_addr == CEC_PHYS_ADDR_INVALID)
return -EINTR;
/* Also bail out if the PA changed while configuring. */
if (adap->must_reconfigure)
return -EINTR;
if (err)
return err;
/*
* The message was aborted due to a disconnect or
* The message was aborted or timed out due to a disconnect or
* unconfigure, just bail out.
*/
if (msg.tx_status & CEC_TX_STATUS_ABORTED)
if (msg.tx_status &
(CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT))
return -EINTR;
if (msg.tx_status & CEC_TX_STATUS_OK)
return 0;
@ -1314,7 +1316,7 @@ static int cec_config_log_addr(struct cec_adapter *adap,
* Message not acknowledged, so this logical
* address is free to use.
*/
err = adap->ops->adap_log_addr(adap, log_addr);
err = call_op(adap, adap_log_addr, log_addr);
if (err)
return err;
@ -1331,15 +1333,14 @@ static int cec_config_log_addr(struct cec_adapter *adap,
*/
static void cec_adap_unconfigure(struct cec_adapter *adap)
{
if (!adap->needs_hpd ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID)
WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
if (!adap->needs_hpd || adap->phys_addr != CEC_PHYS_ADDR_INVALID)
WARN_ON(call_op(adap, adap_log_addr, CEC_LOG_ADDR_INVALID));
adap->log_addrs.log_addr_mask = 0;
adap->is_configuring = false;
adap->is_configured = false;
cec_flush(adap);
wake_up_interruptible(&adap->kthread_waitq);
cec_post_state_event(adap);
call_void_op(adap, adap_configured, false);
}
/*
@ -1408,6 +1409,7 @@ static int cec_config_thread_func(void *arg)
if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED)
goto configured;
reconfigure:
for (i = 0; i < las->num_log_addrs; i++) {
unsigned int type = las->log_addr_type[i];
const u8 *la_list;
@ -1430,6 +1432,13 @@ static int cec_config_thread_func(void *arg)
last_la = la_list[0];
err = cec_config_log_addr(adap, i, last_la);
if (adap->must_reconfigure) {
adap->must_reconfigure = false;
las->log_addr_mask = 0;
goto reconfigure;
}
if (err > 0) /* Reused last LA */
continue;
@ -1475,6 +1484,7 @@ configured:
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
adap->is_configured = true;
adap->is_configuring = false;
adap->must_reconfigure = false;
cec_post_state_event(adap);
/*
@ -1521,15 +1531,18 @@ configured:
adap->kthread_config = NULL;
complete(&adap->config_completion);
mutex_unlock(&adap->lock);
call_void_op(adap, adap_configured, true);
return 0;
unconfigure:
for (i = 0; i < las->num_log_addrs; i++)
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
cec_adap_unconfigure(adap);
adap->is_configuring = false;
adap->must_reconfigure = false;
adap->kthread_config = NULL;
mutex_unlock(&adap->lock);
complete(&adap->config_completion);
mutex_unlock(&adap->lock);
return 0;
}
@ -1552,6 +1565,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
"ceccfg-%s", adap->name);
if (IS_ERR(adap->kthread_config)) {
adap->kthread_config = NULL;
adap->is_configuring = false;
} else if (block) {
mutex_unlock(&adap->lock);
wait_for_completion(&adap->config_completion);
@ -1559,63 +1573,96 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
}
}
/*
* Helper function to enable/disable the CEC adapter.
*
* This function is called with adap->lock held.
*/
static int cec_adap_enable(struct cec_adapter *adap)
{
bool enable;
int ret = 0;
enable = adap->monitor_all_cnt || adap->monitor_pin_cnt ||
adap->log_addrs.num_log_addrs;
if (adap->needs_hpd)
enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID;
if (enable == adap->is_enabled)
return 0;
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
if (enable) {
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
ret = adap->ops->adap_enable(adap, true);
if (!ret) {
/*
* Enable monitor-all/pin modes if needed. We warn, but
* continue if this fails as this is not a critical error.
*/
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, true));
if (adap->monitor_pin_cnt)
WARN_ON(call_op(adap, adap_monitor_pin_enable, true));
}
} else {
/* Disable monitor-all/pin modes if needed (needs_hpd == 1) */
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
if (adap->monitor_pin_cnt)
WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
WARN_ON(adap->ops->adap_enable(adap, false));
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
adap->transmit_in_progress_aborted = false;
if (adap->transmitting)
cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED, 0);
}
if (!ret)
adap->is_enabled = enable;
wake_up_interruptible(&adap->kthread_waitq);
mutex_unlock(&adap->devnode.lock);
return ret;
}
/* Set a new physical address and send an event notifying userspace of this.
*
* This function is called with adap->lock held.
*/
void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
{
bool becomes_invalid = phys_addr == CEC_PHYS_ADDR_INVALID;
bool is_invalid = adap->phys_addr == CEC_PHYS_ADDR_INVALID;
if (phys_addr == adap->phys_addr)
return;
if (phys_addr != CEC_PHYS_ADDR_INVALID && adap->devnode.unregistered)
if (!becomes_invalid && adap->devnode.unregistered)
return;
dprintk(1, "new physical address %x.%x.%x.%x\n",
cec_phys_addr_exp(phys_addr));
if (phys_addr == CEC_PHYS_ADDR_INVALID ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID) {
if (becomes_invalid || !is_invalid) {
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
cec_post_state_event(adap);
cec_adap_unconfigure(adap);
/* Disabling monitor all mode should always succeed */
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) {
WARN_ON(adap->ops->adap_enable(adap, false));
adap->transmit_in_progress = false;
wake_up_interruptible(&adap->kthread_waitq);
}
mutex_unlock(&adap->devnode.lock);
if (phys_addr == CEC_PHYS_ADDR_INVALID)
return;
}
/* serialize adap_enable */
mutex_lock(&adap->devnode.lock);
adap->last_initiator = 0xff;
adap->transmit_in_progress = false;
if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) {
if (adap->ops->adap_enable(adap, true)) {
mutex_unlock(&adap->devnode.lock);
if (becomes_invalid) {
cec_adap_enable(adap);
return;
}
}
if (adap->monitor_all_cnt &&
call_op(adap, adap_monitor_all_enable, true)) {
if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock);
return;
}
mutex_unlock(&adap->devnode.lock);
adap->phys_addr = phys_addr;
if (is_invalid)
cec_adap_enable(adap);
cec_post_state_event(adap);
if (adap->log_addrs.num_log_addrs)
if (!adap->log_addrs.num_log_addrs)
return;
if (adap->is_configuring)
adap->must_reconfigure = true;
else
cec_claim_log_addrs(adap, block);
}
@ -1670,19 +1717,24 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs *log_addrs, bool block)
{
u16 type_mask = 0;
int err;
int i;
if (adap->devnode.unregistered)
return -ENODEV;
if (!log_addrs || log_addrs->num_log_addrs == 0) {
cec_adap_unconfigure(adap);
if (!adap->log_addrs.num_log_addrs)
return 0;
if (adap->is_configuring || adap->is_configured)
cec_adap_unconfigure(adap);
adap->log_addrs.num_log_addrs = 0;
for (i = 0; i < CEC_MAX_LOG_ADDRS; i++)
adap->log_addrs.log_addr[i] = CEC_LOG_ADDR_INVALID;
adap->log_addrs.osd_name[0] = '\0';
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
cec_adap_enable(adap);
return 0;
}
@ -1818,9 +1870,10 @@ int __cec_s_log_addrs(struct cec_adapter *adap,
log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask;
adap->log_addrs = *log_addrs;
if (adap->phys_addr != CEC_PHYS_ADDR_INVALID)
err = cec_adap_enable(adap);
if (!err && adap->phys_addr != CEC_PHYS_ADDR_INVALID)
cec_claim_log_addrs(adap, block);
return 0;
return err;
}
int cec_s_log_addrs(struct cec_adapter *adap,
@ -1922,11 +1975,10 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
msg->msg[1] != CEC_MSG_CDC_MESSAGE)
return 0;
if (adap->ops->received) {
/* Allow drivers to process the message first */
if (adap->ops->received(adap, msg) != -ENOMSG)
return 0;
}
/* Allow drivers to process the message first */
if (adap->ops->received && !adap->devnode.unregistered &&
adap->ops->received(adap, msg) != -ENOMSG)
return 0;
/*
* REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and
@ -2119,20 +2171,25 @@ skip_processing:
*/
int cec_monitor_all_cnt_inc(struct cec_adapter *adap)
{
int ret = 0;
int ret;
if (adap->monitor_all_cnt == 0)
ret = call_op(adap, adap_monitor_all_enable, 1);
if (ret == 0)
adap->monitor_all_cnt++;
if (adap->monitor_all_cnt++)
return 0;
ret = cec_adap_enable(adap);
if (ret)
adap->monitor_all_cnt--;
return ret;
}
void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
{
adap->monitor_all_cnt--;
if (adap->monitor_all_cnt == 0)
WARN_ON(call_op(adap, adap_monitor_all_enable, 0));
if (WARN_ON(!adap->monitor_all_cnt))
return;
if (--adap->monitor_all_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
cec_adap_enable(adap);
}
/*
@ -2142,20 +2199,25 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap)
*/
int cec_monitor_pin_cnt_inc(struct cec_adapter *adap)
{
int ret = 0;
int ret;
if (adap->monitor_pin_cnt == 0)
ret = call_op(adap, adap_monitor_pin_enable, 1);
if (ret == 0)
adap->monitor_pin_cnt++;
if (adap->monitor_pin_cnt++)
return 0;
ret = cec_adap_enable(adap);
if (ret)
adap->monitor_pin_cnt--;
return ret;
}
void cec_monitor_pin_cnt_dec(struct cec_adapter *adap)
{
adap->monitor_pin_cnt--;
if (adap->monitor_pin_cnt == 0)
WARN_ON(call_op(adap, adap_monitor_pin_enable, 0));
if (WARN_ON(!adap->monitor_pin_cnt))
return;
if (--adap->monitor_pin_cnt)
return;
WARN_ON(call_op(adap, adap_monitor_pin_enable, false));
cec_adap_enable(adap);
}
#ifdef CONFIG_DEBUG_FS
@ -2169,6 +2231,7 @@ int cec_adap_status(struct seq_file *file, void *priv)
struct cec_data *data;
mutex_lock(&adap->lock);
seq_printf(file, "enabled: %d\n", adap->is_enabled);
seq_printf(file, "configured: %d\n", adap->is_configured);
seq_printf(file, "configuring: %d\n", adap->is_configuring);
seq_printf(file, "phys_addr: %x.%x.%x.%x\n",
@ -2183,6 +2246,9 @@ int cec_adap_status(struct seq_file *file, void *priv)
if (adap->monitor_all_cnt)
seq_printf(file, "file handles in Monitor All mode: %u\n",
adap->monitor_all_cnt);
if (adap->monitor_pin_cnt)
seq_printf(file, "file handles in Monitor Pin mode: %u\n",
adap->monitor_pin_cnt);
if (adap->tx_timeouts) {
seq_printf(file, "transmit timeouts: %u\n",
adap->tx_timeouts);

View File

@ -586,18 +586,6 @@ static int cec_open(struct inode *inode, struct file *filp)
return err;
}
/* serialize adap_enable */
mutex_lock(&devnode->lock);
if (list_empty(&devnode->fhs) &&
!adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
err = adap->ops->adap_enable(adap, true);
if (err) {
mutex_unlock(&devnode->lock);
kfree(fh);
return err;
}
}
filp->private_data = fh;
/* Queue up initial state events */
@ -607,7 +595,8 @@ static int cec_open(struct inode *inode, struct file *filp)
adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR;
cec_queue_event_fh(fh, &ev, 0);
#ifdef CONFIG_CEC_PIN
if (adap->pin && adap->pin->ops->read_hpd) {
if (adap->pin && adap->pin->ops->read_hpd &&
!adap->devnode.unregistered) {
err = adap->pin->ops->read_hpd(adap);
if (err >= 0) {
ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
@ -615,7 +604,8 @@ static int cec_open(struct inode *inode, struct file *filp)
cec_queue_event_fh(fh, &ev, 0);
}
}
if (adap->pin && adap->pin->ops->read_5v) {
if (adap->pin && adap->pin->ops->read_5v &&
!adap->devnode.unregistered) {
err = adap->pin->ops->read_5v(adap);
if (err >= 0) {
ev.event = err ? CEC_EVENT_PIN_5V_HIGH :
@ -625,6 +615,7 @@ static int cec_open(struct inode *inode, struct file *filp)
}
#endif
mutex_lock(&devnode->lock);
mutex_lock(&devnode->lock_fhs);
list_add(&fh->list, &devnode->fhs);
mutex_unlock(&devnode->lock_fhs);
@ -656,15 +647,10 @@ static int cec_release(struct inode *inode, struct file *filp)
cec_monitor_all_cnt_dec(adap);
mutex_unlock(&adap->lock);
/* serialize adap_enable */
mutex_lock(&devnode->lock);
mutex_lock(&devnode->lock_fhs);
list_del(&fh->list);
mutex_unlock(&devnode->lock_fhs);
if (cec_is_registered(adap) && list_empty(&devnode->fhs) &&
!adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
WARN_ON(adap->ops->adap_enable(adap, false));
}
mutex_unlock(&devnode->lock);
/* Unhook pending transmits from this filehandle. */

View File

@ -20,6 +20,18 @@
#define CEC_NUM_DEVICES 256
#define CEC_NAME "cec"
/*
* 400 ms is the time it takes for one 16 byte message to be
* transferred and 5 is the maximum number of retries. Add
* another 100 ms as a margin. So if the transmit doesn't
* finish before that time something is really wrong and we
* have to time out.
*
* This is a sign that something it really wrong and a warning
* will be issued.
*/
#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
int cec_debug;
module_param_named(debug, cec_debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
@ -204,7 +216,7 @@ static ssize_t cec_error_inj_write(struct file *file,
line = strsep(&p, "\n");
if (!*line || *line == '#')
continue;
if (!adap->ops->error_inj_parse_line(adap, line)) {
if (!call_op(adap, error_inj_parse_line, line)) {
kfree(buf);
return -EINVAL;
}
@ -217,7 +229,7 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused)
{
struct cec_adapter *adap = sf->private;
return adap->ops->error_inj_show(adap, sf);
return call_op(adap, error_inj_show, sf);
}
static int cec_error_inj_open(struct inode *inode, struct file *file)
@ -331,6 +343,8 @@ int cec_register_adapter(struct cec_adapter *adap,
adap->owner = parent->driver->owner;
adap->devnode.dev.parent = parent;
if (!adap->xfer_timeout_ms)
adap->xfer_timeout_ms = CEC_XFER_TIMEOUT_MS;
#ifdef CONFIG_MEDIA_CEC_RC
if (adap->capabilities & CEC_CAP_RC) {

View File

@ -12,6 +12,17 @@
#include <linux/atomic.h>
#include <media/cec-pin.h>
#define call_pin_op(pin, op, arg...) \
((pin && pin->ops->op && !pin->adap->devnode.unregistered) ? \
pin->ops->op(pin->adap, ## arg) : 0)
#define call_void_pin_op(pin, op, arg...) \
do { \
if (pin && pin->ops->op && \
!pin->adap->devnode.unregistered) \
pin->ops->op(pin->adap, ## arg); \
} while (0)
enum cec_pin_state {
/* CEC is off */
CEC_ST_OFF,

View File

@ -135,7 +135,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force)
static bool cec_pin_read(struct cec_pin *pin)
{
bool v = pin->ops->read(pin->adap);
bool v = call_pin_op(pin, read);
cec_pin_update(pin, v, false);
return v;
@ -143,13 +143,13 @@ static bool cec_pin_read(struct cec_pin *pin)
static void cec_pin_low(struct cec_pin *pin)
{
pin->ops->low(pin->adap);
call_void_pin_op(pin, low);
cec_pin_update(pin, false, false);
}
static bool cec_pin_high(struct cec_pin *pin)
{
pin->ops->high(pin->adap);
call_void_pin_op(pin, high);
return cec_pin_read(pin);
}
@ -1037,11 +1037,14 @@ static int cec_pin_thread_func(void *_adap)
for (;;) {
wait_event_interruptible(pin->kthread_waitq,
kthread_should_stop() ||
pin->work_rx_msg.len ||
pin->work_tx_status ||
atomic_read(&pin->work_irq_change) ||
atomic_read(&pin->work_pin_num_events));
kthread_should_stop() ||
pin->work_rx_msg.len ||
pin->work_tx_status ||
atomic_read(&pin->work_irq_change) ||
atomic_read(&pin->work_pin_num_events));
if (kthread_should_stop())
break;
if (pin->work_rx_msg.len) {
struct cec_msg *msg = &pin->work_rx_msg;
@ -1086,10 +1089,12 @@ static int cec_pin_thread_func(void *_adap)
CEC_PIN_IRQ_UNCHANGED)) {
case CEC_PIN_IRQ_DISABLE:
if (irq_enabled) {
pin->ops->disable_irq(adap);
call_void_pin_op(pin, disable_irq);
irq_enabled = false;
}
cec_pin_high(pin);
if (pin->state == CEC_ST_OFF)
break;
cec_pin_to_idle(pin);
hrtimer_start(&pin->timer, ns_to_ktime(0),
HRTIMER_MODE_REL);
@ -1097,7 +1102,7 @@ static int cec_pin_thread_func(void *_adap)
case CEC_PIN_IRQ_ENABLE:
if (irq_enabled)
break;
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
pin->enable_irq_failed = !call_pin_op(pin, enable_irq);
if (pin->enable_irq_failed) {
cec_pin_to_idle(pin);
hrtimer_start(&pin->timer, ns_to_ktime(0),
@ -1109,15 +1114,7 @@ static int cec_pin_thread_func(void *_adap)
default:
break;
}
if (kthread_should_stop())
break;
}
if (pin->ops->disable_irq && irq_enabled)
pin->ops->disable_irq(adap);
hrtimer_cancel(&pin->timer);
cec_pin_read(pin);
cec_pin_to_idle(pin);
pin->state = CEC_ST_OFF;
return 0;
}
@ -1126,24 +1123,32 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
struct cec_pin *pin = adap->pin;
if (enable) {
atomic_set(&pin->work_pin_num_events, 0);
pin->work_pin_events_rd = pin->work_pin_events_wr = 0;
pin->work_pin_events_dropped = false;
cec_pin_read(pin);
cec_pin_to_idle(pin);
pin->tx_msg.len = 0;
pin->timer_ts = ns_to_ktime(0);
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
pin->kthread = kthread_run(cec_pin_thread_func, adap,
"cec-pin");
if (IS_ERR(pin->kthread)) {
pr_err("cec-pin: kernel_thread() failed\n");
return PTR_ERR(pin->kthread);
if (!pin->kthread) {
pin->kthread = kthread_run(cec_pin_thread_func, adap,
"cec-pin");
if (IS_ERR(pin->kthread)) {
int err = PTR_ERR(pin->kthread);
pr_err("cec-pin: kernel_thread() failed\n");
pin->kthread = NULL;
return err;
}
}
hrtimer_start(&pin->timer, ns_to_ktime(0),
HRTIMER_MODE_REL);
} else {
kthread_stop(pin->kthread);
} else if (pin->kthread) {
hrtimer_cancel(&pin->timer);
cec_pin_high(pin);
cec_pin_to_idle(pin);
pin->state = CEC_ST_OFF;
pin->work_tx_status = 0;
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE);
wake_up_interruptible(&pin->kthread_waitq);
}
return 0;
}
@ -1207,7 +1212,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
seq_printf(file, "state: %s\n", states[pin->state].name);
seq_printf(file, "tx_bit: %d\n", pin->tx_bit);
seq_printf(file, "rx_bit: %d\n", pin->rx_bit);
seq_printf(file, "cec pin: %d\n", pin->ops->read(adap));
seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read));
seq_printf(file, "cec pin events dropped: %u\n",
pin->work_pin_events_dropped_cnt);
seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed);
@ -1260,8 +1265,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap,
pin->rx_data_bit_too_long_cnt = 0;
pin->rx_low_drive_cnt = 0;
pin->tx_low_drive_cnt = 0;
if (pin->ops->status)
pin->ops->status(adap, file);
call_void_pin_op(pin, status, file);
}
static int cec_pin_adap_monitor_all_enable(struct cec_adapter *adap,
@ -1277,6 +1281,9 @@ static void cec_pin_adap_free(struct cec_adapter *adap)
{
struct cec_pin *pin = adap->pin;
if (pin->kthread)
kthread_stop(pin->kthread);
pin->kthread = NULL;
if (pin->ops->free)
pin->ops->free(adap);
adap->pin = NULL;
@ -1287,7 +1294,7 @@ static int cec_pin_received(struct cec_adapter *adap, struct cec_msg *msg)
{
struct cec_pin *pin = adap->pin;
if (pin->ops->received)
if (pin->ops->received && !adap->devnode.unregistered)
return pin->ops->received(adap, msg);
return -ENOMSG;
}
@ -1327,6 +1334,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
return ERR_PTR(-ENOMEM);
pin->ops = pin_ops;
hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
atomic_set(&pin->work_pin_num_events, 0);
pin->timer.function = cec_pin_timer;
init_waitqueue_head(&pin->kthread_waitq);
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;

View File

@ -17,6 +17,16 @@
pr_info("cec-%s: " fmt, adap->name, ## arg); \
} while (0)
#define call_op(adap, op, arg...) \
((adap->ops->op && !adap->devnode.unregistered) ? \
adap->ops->op(adap, ## arg) : 0)
#define call_void_op(adap, op, arg...) \
do { \
if (adap->ops->op && !adap->devnode.unregistered) \
adap->ops->op(adap, ## arg); \
} while (0)
/* devnode to cec_adapter */
#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode)

View File

@ -31,29 +31,17 @@ struct secocec_data {
int irq;
};
#define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
cmd, data, SMBUS_WRITE, NULL)
#define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \
#define smb_wr16(cmd, data) smb_word_op(SECOCEC_MICRO_ADDRESS, \
cmd, data, SMBUS_WRITE, NULL)
#define smb_rd16(cmd, res) smb_word_op(SECOCEC_MICRO_ADDRESS, \
cmd, 0, SMBUS_READ, res)
static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
static int smb_word_op(u16 slave_addr, u8 cmd, u16 data,
u8 operation, u16 *result)
{
unsigned int count;
short _data_format;
int status = 0;
switch (data_format) {
case CMD_BYTE_DATA:
_data_format = BRA_SMB_CMD_BYTE_DATA;
break;
case CMD_WORD_DATA:
_data_format = BRA_SMB_CMD_WORD_DATA;
break;
default:
return -EINVAL;
}
/* Active wait until ready */
for (count = 0; count <= SMBTIMEOUT; ++count) {
if (!(inb(HSTS) & BRA_INUSE_STS))
@ -75,7 +63,7 @@ static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data,
outb((u8)(data >> 8), HDAT1);
}
outb(BRA_START + _data_format, HCNT);
outb(BRA_START + BRA_SMB_CMD_WORD_DATA, HCNT);
for (count = 0; count <= SMBTIMEOUT; count++) {
if (!(inb(HSTS) & BRA_HOST_BUSY))

View File

@ -443,7 +443,6 @@ static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *
strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));
strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_DEVICE_CAPS;

View File

@ -126,8 +126,7 @@ static void *vb2_dma_sg_alloc(struct vb2_buffer *vb, struct device *dev,
* there is no memory consistency guarantee, hence dma-sg ignores DMA
* attributes passed from the upper layer.
*/
buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *),
GFP_KERNEL | __GFP_ZERO);
buf->pages = kvcalloc(buf->num_pages, sizeof(struct page *), GFP_KERNEL);
if (!buf->pages)
goto fail_pages_array_alloc;

View File

@ -977,12 +977,6 @@ EXPORT_SYMBOL_GPL(vb2_poll);
* and so they simplify the driver code.
*/
/* The queue is busy if there is a owner and you are not that owner. */
static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file)
{
return vdev->queue->owner && vdev->queue->owner != file->private_data;
}
/* vb2 ioctl helpers */
int vb2_ioctl_reqbufs(struct file *file, void *priv,
@ -997,7 +991,7 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
p->flags = flags;
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count);
/* If count == 0, then the owner has released all buffers and he
@ -1026,7 +1020,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
return res != -EBUSY ? res : 0;
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
res = vb2_create_bufs(vdev->queue, p);
@ -1041,7 +1035,7 @@ int vb2_ioctl_prepare_buf(struct file *file, void *priv,
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_prepare_buf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
@ -1060,7 +1054,7 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_qbuf(vdev->queue, vdev->v4l2_dev->mdev, p);
}
@ -1070,7 +1064,7 @@ int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK);
}
@ -1080,7 +1074,7 @@ int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_streamon(vdev->queue, i);
}
@ -1090,7 +1084,7 @@ int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_streamoff(vdev->queue, i);
}
@ -1100,7 +1094,7 @@ int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p)
{
struct video_device *vdev = video_devdata(file);
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
return -EBUSY;
return vb2_expbuf(vdev->queue, p);
}
@ -1152,7 +1146,7 @@ ssize_t vb2_fop_write(struct file *file, const char __user *buf,
return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
goto exit;
err = vb2_write(vdev->queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);
@ -1176,7 +1170,7 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
return -EINVAL;
if (lock && mutex_lock_interruptible(lock))
return -ERESTARTSYS;
if (vb2_queue_is_busy(vdev, file))
if (vb2_queue_is_busy(vdev->queue, file))
goto exit;
err = vb2_read(vdev->queue, buf, count, ppos,
file->f_flags & O_NONBLOCK);

View File

@ -372,6 +372,7 @@ config VIDEO_OV13B10
config VIDEO_OV2640
tristate "OmniVision OV2640 sensor support"
depends on VIDEO_DEV && I2C
select V4L2_ASYNC
help
This is a Video4Linux2 sensor driver for the OmniVision
OV2640 camera.

View File

@ -66,6 +66,9 @@
#define ADV7180_HUE_DEF 0
#define ADV7180_HUE_MAX 128
#define ADV7180_REG_DEF_VALUE_Y 0x000c
#define ADV7180_DEF_VAL_EN 0x1
#define ADV7180_DEF_VAL_AUTO_EN 0x2
#define ADV7180_REG_CTRL 0x000e
#define ADV7180_CTRL_IRQ_SPACE 0x20
@ -549,6 +552,40 @@ static int adv7180_s_power(struct v4l2_subdev *sd, int on)
return ret;
}
static const char * const test_pattern_menu[] = {
"Single color",
"Color bars",
"Luma ramp",
"Boundary box",
"Disable",
};
static int adv7180_test_pattern(struct adv7180_state *state, int value)
{
unsigned int reg = 0;
/* Map menu value into register value */
if (value < 3)
reg = value;
if (value == 3)
reg = 5;
adv7180_write(state, ADV7180_REG_ANALOG_CLAMP_CTL, reg);
if (value == ARRAY_SIZE(test_pattern_menu) - 1) {
reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
reg &= ~ADV7180_DEF_VAL_EN;
adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
return 0;
}
reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y);
reg |= ADV7180_DEF_VAL_EN | ADV7180_DEF_VAL_AUTO_EN;
adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg);
return 0;
}
static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
@ -592,6 +629,9 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
}
break;
case V4L2_CID_TEST_PATTERN:
ret = adv7180_test_pattern(state, val);
break;
default:
ret = -EINVAL;
}
@ -632,6 +672,12 @@ static int adv7180_init_controls(struct adv7180_state *state)
ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(test_pattern_menu) - 1,
0, ARRAY_SIZE(test_pattern_menu) - 1,
test_pattern_menu);
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
int err = state->ctrl_hdl.error;

View File

@ -121,7 +121,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor,
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n",
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n",
linfo->reg, linfo->name, offset, val, val);
ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val);
@ -288,7 +288,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK;
} else {
dev_dbg(&client->dev,
"invalid frame format model type %d\n",
"invalid frame format model type %u\n",
fmt_model_type);
return -EINVAL;
}
@ -320,7 +320,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
}
dev_dbg(&client->dev,
"%s pixels: %d %s (pixelcode %u)\n",
"%s pixels: %u %s (pixelcode %u)\n",
what, pixels, which, pixelcode);
if (i < ncol_desc) {
@ -353,9 +353,9 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
sensor->image_start = sensor->embedded_end;
}
dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
dev_dbg(&client->dev, "embedded data from lines %u to %u\n",
sensor->embedded_start, sensor->embedded_end);
dev_dbg(&client->dev, "image data starts at line %d\n",
dev_dbg(&client->dev, "image data starts at line %u\n",
sensor->image_start);
return 0;
@ -571,7 +571,7 @@ static u32 ccs_pixel_order(struct ccs_sensor *sensor)
flip ^= sensor->hvflip_inv_mask;
dev_dbg(&client->dev, "flip %d\n", flip);
dev_dbg(&client->dev, "flip %u\n", flip);
return sensor->default_pixel_order ^ flip;
}
@ -1056,18 +1056,18 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor)
type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE);
dev_dbg(&client->dev, "data_format_model_type %d\n", type);
dev_dbg(&client->dev, "data_format_model_type %u\n", type);
rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order);
if (rval)
return rval;
if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
dev_dbg(&client->dev, "bad pixel order %u\n", pixel_order);
return -EINVAL;
}
dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
dev_dbg(&client->dev, "pixel order %u (%s)\n", pixel_order,
pixel_order_str[pixel_order]);
switch (type) {
@ -1105,7 +1105,7 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor)
(fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK))
continue;
dev_dbg(&client->dev, "jolly good! %d\n", j);
dev_dbg(&client->dev, "jolly good! %u\n", j);
sensor->default_mbus_frame_fmts |= 1 << j;
}
@ -1602,8 +1602,11 @@ static int ccs_power_on(struct device *dev)
usleep_range(1000, 2000);
} while (--retry);
if (!reset)
return -EIO;
if (!reset) {
dev_err(dev, "software reset failed\n");
rval = -EIO;
goto out_cci_addr_fail;
}
}
if (sensor->hwcfg.i2c_addr_alt) {
@ -1999,7 +2002,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
mutex_lock(&sensor->mutex);
dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
dev_err(&client->dev, "subdev %s, pad %u, index %u\n",
subdev->name, code->pad, code->index);
if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) {
@ -2017,7 +2020,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev,
if (idx == code->index) {
code->code = ccs_csi_data_formats[i].code;
dev_err(&client->dev, "found index %d, i %d, code %x\n",
dev_err(&client->dev, "found index %u, i %u, code %x\n",
code->index, i, code->code);
rval = 0;
break;
@ -2386,7 +2389,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN),
CCS_LIM(sensor, SCALER_M_MAX));
dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
dev_dbg(&client->dev, "scaling: a %u b %u max_m %u\n", a, b, max_m);
min = min(max_m, min(a, b));
max = min(max_m, max(a, b));
@ -2416,7 +2419,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev,
sel->r.height,
sel->flags);
dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
dev_dbg(&client->dev, "trying factor %u (%u)\n", try[i], i);
if (this > best) {
scale_m = try[i];
@ -3183,7 +3186,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev);
u32 rotation;
int i;
unsigned int i;
int rval;
ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0,
@ -3221,8 +3224,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
goto out_err;
}
dev_dbg(dev, "lanes %u\n", hwcfg->lanes);
rval = fwnode_property_read_u32(fwnode, "rotation", &rotation);
if (!rval) {
switch (rotation) {
@ -3244,7 +3245,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
if (rval)
dev_info(dev, "can't get clock-frequency\n");
dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk,
dev_dbg(dev, "clk %u, mode %u\n", hwcfg->ext_clk,
hwcfg->csi_signalling_mode);
if (!bus_cfg.nr_of_link_frequencies) {
@ -3263,7 +3264,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev)
for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i];
dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]);
dev_dbg(dev, "freq %u: %lld\n", i, hwcfg->op_sys_clock[i]);
}
v4l2_fwnode_endpoint_free(&bus_cfg);

View File

@ -183,6 +183,7 @@ static int dw9714_probe(struct i2c_client *client)
return 0;
err_cleanup:
regulator_disable(dw9714_dev->vcc);
v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm);
media_entity_cleanup(&dw9714_dev->sd.entity);
@ -201,7 +202,6 @@ static int dw9714_remove(struct i2c_client *client)
if (ret) {
dev_err(&client->dev,
"Failed to disable vcc: %d\n", ret);
return ret;
}
}
pm_runtime_set_suspended(&client->dev);

View File

@ -469,11 +469,6 @@ static int dw9768_probe(struct i2c_client *client)
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
/*
* Device is already turned on by i2c-core with ACPI domain PM.
* Attempt to turn off the device to satisfy the privacy LED concerns.
*/
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev)) {
ret = dw9768_runtime_resume(dev);
@ -488,7 +483,6 @@ static int dw9768_probe(struct i2c_client *client)
dev_err(dev, "failed to register V4L2 subdev: %d", ret);
goto err_power_off;
}
pm_runtime_idle(dev);
return 0;

View File

@ -295,6 +295,8 @@ static int __maybe_unused dw9807_vcm_resume(struct device *dev)
static const struct of_device_id dw9807_of_table[] = {
{ .compatible = "dongwoon,dw9807-vcm" },
/* Compatibility for older firmware, NEVER USE THIS IN FIRMWARE! */
{ .compatible = "dongwoon,dw9807" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw9807_of_table);

View File

@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
@ -101,6 +102,12 @@ struct imx412_mode {
struct imx412_reg_list reg_list;
};
static const char * const imx412_supply_names[] = {
"dovdd", /* Digital I/O power */
"avdd", /* Analog power */
"dvdd", /* Digital core power */
};
/**
* struct imx412 - imx412 sensor device structure
* @dev: Pointer to generic device
@ -109,6 +116,7 @@ struct imx412_mode {
* @pad: Media pad. Only one pad supported
* @reset_gpio: Sensor reset gpio
* @inclk: Sensor input clock
* @supplies: Regulator supplies
* @ctrl_handler: V4L2 control handler
* @link_freq_ctrl: Pointer to link frequency control
* @pclk_ctrl: Pointer to pixel clock control
@ -128,6 +136,7 @@ struct imx412 {
struct media_pad pad;
struct gpio_desc *reset_gpio;
struct clk *inclk;
struct regulator_bulk_data supplies[ARRAY_SIZE(imx412_supply_names)];
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *link_freq_ctrl;
struct v4l2_ctrl *pclk_ctrl;
@ -946,6 +955,16 @@ static int imx412_parse_hw_config(struct imx412 *imx412)
return -EINVAL;
}
/* Get optional DT defined regulators */
for (i = 0; i < ARRAY_SIZE(imx412_supply_names); i++)
imx412->supplies[i].supply = imx412_supply_names[i];
ret = devm_regulator_bulk_get(imx412->dev,
ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
if (ret)
return ret;
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
return -ENXIO;
@ -1011,7 +1030,14 @@ static int imx412_power_on(struct device *dev)
struct imx412 *imx412 = to_imx412(sd);
int ret;
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
ret = regulator_bulk_enable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
if (ret < 0) {
dev_err(dev, "failed to enable regulators\n");
return ret;
}
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
ret = clk_prepare_enable(imx412->inclk);
if (ret) {
@ -1024,7 +1050,9 @@ static int imx412_power_on(struct device *dev)
return 0;
error_reset:
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
return ret;
}
@ -1040,10 +1068,13 @@ static int imx412_power_off(struct device *dev)
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx412 *imx412 = to_imx412(sd);
gpiod_set_value_cansleep(imx412->reset_gpio, 0);
clk_disable_unprepare(imx412->inclk);
gpiod_set_value_cansleep(imx412->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names),
imx412->supplies);
return 0;
}

View File

@ -1147,22 +1147,18 @@ static int max9286_poc_enable(struct max9286_priv *priv, bool enable)
return ret;
}
static int max9286_init(struct device *dev)
static int max9286_init(struct max9286_priv *priv)
{
struct max9286_priv *priv;
struct i2c_client *client;
struct i2c_client *client = priv->client;
int ret;
client = to_i2c_client(dev);
priv = i2c_get_clientdata(client);
ret = max9286_poc_enable(priv, true);
if (ret)
return ret;
ret = max9286_setup(priv);
if (ret) {
dev_err(dev, "Unable to setup max9286\n");
dev_err(&client->dev, "Unable to setup max9286\n");
goto err_poc_disable;
}
@ -1172,13 +1168,13 @@ static int max9286_init(struct device *dev)
*/
ret = max9286_v4l2_register(priv);
if (ret) {
dev_err(dev, "Failed to register with V4L2\n");
dev_err(&client->dev, "Failed to register with V4L2\n");
goto err_poc_disable;
}
ret = max9286_i2c_mux_init(priv);
if (ret) {
dev_err(dev, "Unable to initialize I2C multiplexer\n");
dev_err(&client->dev, "Unable to initialize I2C multiplexer\n");
goto err_v4l2_register;
}
@ -1333,7 +1329,6 @@ static int max9286_probe(struct i2c_client *client)
mutex_init(&priv->mutex);
priv->client = client;
i2c_set_clientdata(client, priv);
priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable",
GPIOD_OUT_HIGH);
@ -1369,7 +1364,7 @@ static int max9286_probe(struct i2c_client *client)
if (ret)
goto err_powerdown;
ret = max9286_init(&client->dev);
ret = max9286_init(priv);
if (ret < 0)
goto err_cleanup_dt;
@ -1385,7 +1380,7 @@ err_powerdown:
static int max9286_remove(struct i2c_client *client)
{
struct max9286_priv *priv = i2c_get_clientdata(client);
struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client));
i2c_mux_del_adapters(priv->mux);

View File

@ -843,7 +843,7 @@ static int ov5645_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_UYVY8_2X8;
code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0;
}
@ -852,7 +852,7 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8)
if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16)
return -EINVAL;
if (fse->index >= ARRAY_SIZE(ov5645_mode_info_data))
@ -948,7 +948,7 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
format->which);
__format->width = __crop->width;
__format->height = __crop->height;
__format->code = MEDIA_BUS_FMT_UYVY8_2X8;
__format->code = MEDIA_BUS_FMT_UYVY8_1X16;
__format->field = V4L2_FIELD_NONE;
__format->colorspace = V4L2_COLORSPACE_SRGB;
@ -1283,7 +1283,7 @@ MODULE_DEVICE_TABLE(of, ov5645_of_match);
static struct i2c_driver ov5645_i2c_driver = {
.driver = {
.of_match_table = of_match_ptr(ov5645_of_match),
.of_match_table = ov5645_of_match,
.name = "ov5645",
},
.probe_new = ov5645_probe,

View File

@ -2498,9 +2498,9 @@ static int ov5648_probe(struct i2c_client *client)
/* DOVDD: digital I/O */
sensor->dovdd = devm_regulator_get(dev, "dovdd");
if (IS_ERR(sensor->dvdd)) {
if (IS_ERR(sensor->dovdd)) {
dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n");
ret = PTR_ERR(sensor->dvdd);
ret = PTR_ERR(sensor->dovdd);
goto error_endpoint;
}

View File

@ -1122,7 +1122,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
/* 4 least significant bits of expsoure are fractional part */
/* 4 least significant bits of exposure are fractional part */
ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE,
OV5695_REG_VALUE_24BIT, ctrl->val << 4);
break;

File diff suppressed because it is too large Load Diff

View File

@ -13,23 +13,28 @@
MODULE_DESCRIPTION("OmniVision ov7640 sensor driver");
MODULE_LICENSE("GPL v2");
static const u8 initial_registers[] = {
0x12, 0x80,
0x12, 0x54,
0x14, 0x24,
0x15, 0x01,
0x28, 0x20,
0x75, 0x82,
0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */
struct reg_val {
u8 reg;
u8 val;
};
static int write_regs(struct i2c_client *client, const u8 *regs)
{
int i;
static const struct reg_val regval_init[] = {
{0x12, 0x80},
{0x12, 0x54},
{0x14, 0x24},
{0x15, 0x01},
{0x28, 0x20},
{0x75, 0x82},
};
for (i = 0; regs[i] != 0xFF; i += 2)
if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0)
static int write_regs(struct i2c_client *client,
const struct reg_val *rv, int len)
{
while (--len >= 0) {
if (i2c_smbus_write_byte_data(client, rv->reg, rv->val) < 0)
return -1;
rv++;
}
return 0;
}
@ -56,7 +61,7 @@ static int ov7640_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
if (write_regs(client, initial_registers) < 0) {
if (write_regs(client, regval_init, ARRAY_SIZE(regval_init)) < 0) {
v4l_err(client, "error initializing OV7640\n");
return -ENODEV;
}

View File

@ -2017,7 +2017,6 @@ static int ov7670_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&info->hdl);
media_entity_cleanup(&info->sd.entity);
ov7670_power_off(sd);
return 0;
}

View File

@ -63,6 +63,7 @@
#define OV8856_ANAL_GAIN_STEP 1
/* Digital gain controls from sensor */
#define OV8856_REG_DIGITAL_GAIN 0x350a
#define OV8856_REG_MWB_R_GAIN 0x5019
#define OV8856_REG_MWB_G_GAIN 0x501b
#define OV8856_REG_MWB_B_GAIN 0x501d
@ -351,7 +352,7 @@ static const struct ov8856_reg lane_2_mode_3280x2464[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5795, 0x02},
@ -543,7 +544,7 @@ static const struct ov8856_reg lane_2_mode_1640x1232[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5795, 0x00},
@ -734,7 +735,7 @@ static const struct ov8856_reg lane_4_mode_3280x2464[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5780, 0x14},
@ -925,7 +926,7 @@ static const struct ov8856_reg lane_4_mode_1640x1232[] = {
{0x484b, 0x05},
{0x5000, 0x57},
{0x5001, 0x0a},
{0x5004, 0x04},
{0x5004, 0x06},
{0x502e, 0x03},
{0x5030, 0x41},
{0x5780, 0x14},
@ -1755,19 +1756,7 @@ static int ov8856_identify_module(struct ov8856 *ov8856)
static int ov8856_update_digital_gain(struct ov8856 *ov8856, u32 d_gain)
{
int ret;
ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_R_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_G_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
if (ret)
return ret;
return ov8856_write_reg(ov8856, OV8856_REG_MWB_B_GAIN,
return ov8856_write_reg(ov8856, OV8856_REG_DIGITAL_GAIN,
OV8856_REG_VALUE_16BIT, d_gain);
}

View File

@ -47,11 +47,11 @@
#define OV10635_VTS 933
/*
* As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 format we
* As the drivers supports a single MEDIA_BUS_FMT_UYVY8_1X16 format we
* can harcode the pixel rate.
*
* PCLK is fed through the system clock, programmed @88MHz.
* MEDIA_BUS_FMT_UYVY8_2X8 format = 2 samples per pixel.
* MEDIA_BUS_FMT_UYVY8_1X16 format = 2 samples per pixel.
*
* Pixelrate = PCLK / 2
* FPS = (OV10635_VTS * OV10635_HTS) / PixelRate
@ -409,7 +409,7 @@ static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd,
if (code->pad || code->index > 0)
return -EINVAL;
code->code = MEDIA_BUS_FMT_UYVY8_2X8;
code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0;
}
@ -425,7 +425,7 @@ static int rdacm20_get_fmt(struct v4l2_subdev *sd,
mf->width = OV10635_WIDTH;
mf->height = OV10635_HEIGHT;
mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
mf->colorspace = V4L2_COLORSPACE_RAW;
mf->field = V4L2_FIELD_NONE;
mf->ycbcr_enc = V4L2_YCBCR_ENC_601;
@ -611,7 +611,7 @@ static int rdacm20_probe(struct i2c_client *client)
goto error_free_ctrls;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret < 0)
goto error_free_ctrls;

View File

@ -583,7 +583,7 @@ static int rdacm21_probe(struct i2c_client *client)
goto error_free_ctrls;
dev->pad.flags = MEDIA_PAD_FL_SOURCE;
dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR;
dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
if (ret < 0)
goto error_free_ctrls;

View File

@ -213,7 +213,7 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
for (i++; i < S5K6A3_NUM_SUPPLIES; i++) {
ret = regulator_enable(sensor->supplies[i].consumer);
if (ret < 0)
goto error_reg_dis;
goto error_clk;
}
gpio_set_value(sensor->gpio_reset, 1);
@ -226,6 +226,8 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor)
msleep(20);
return 0;
error_clk:
clk_disable_unprepare(sensor->clock);
error_reg_dis:
for (--i; i >= 0; --i)
regulator_disable(sensor->supplies[i].consumer);

View File

@ -9,6 +9,7 @@
* - Melexis MLX90640 Thermal Cameras
*/
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/hwmon.h>
@ -34,6 +35,37 @@
#define VIDEO_I2C_DRIVER "video-i2c"
/* Power control register */
#define AMG88XX_REG_PCTL 0x00
#define AMG88XX_PCTL_NORMAL 0x00
#define AMG88XX_PCTL_SLEEP 0x10
/* Reset register */
#define AMG88XX_REG_RST 0x01
#define AMG88XX_RST_FLAG 0x30
#define AMG88XX_RST_INIT 0x3f
/* Frame rate register */
#define AMG88XX_REG_FPSC 0x02
#define AMG88XX_FPSC_1FPS BIT(0)
/* Thermistor register */
#define AMG88XX_REG_TTHL 0x0e
/* Temperature register */
#define AMG88XX_REG_T01L 0x80
/* RAM */
#define MLX90640_RAM_START_ADDR 0x0400
/* EEPROM */
#define MLX90640_EEPROM_START_ADDR 0x2400
/* Control register */
#define MLX90640_REG_CTL1 0x800d
#define MLX90640_REG_CTL1_MASK GENMASK(9, 7)
#define MLX90640_REG_CTL1_MASK_SHIFT 7
struct video_i2c_chip;
struct video_i2c_buffer {
@ -124,7 +156,7 @@ static int mlx90640_nvram_read(void *priv, unsigned int offset, void *val,
{
struct video_i2c_data *data = priv;
return regmap_bulk_read(data->regmap, 0x2400 + offset, val, bytes);
return regmap_bulk_read(data->regmap, MLX90640_EEPROM_START_ADDR + offset, val, bytes);
}
static struct nvmem_config mlx90640_nvram_config = {
@ -135,31 +167,6 @@ static struct nvmem_config mlx90640_nvram_config = {
.reg_read = mlx90640_nvram_read,
};
/* Power control register */
#define AMG88XX_REG_PCTL 0x00
#define AMG88XX_PCTL_NORMAL 0x00
#define AMG88XX_PCTL_SLEEP 0x10
/* Reset register */
#define AMG88XX_REG_RST 0x01
#define AMG88XX_RST_FLAG 0x30
#define AMG88XX_RST_INIT 0x3f
/* Frame rate register */
#define AMG88XX_REG_FPSC 0x02
#define AMG88XX_FPSC_1FPS BIT(0)
/* Thermistor register */
#define AMG88XX_REG_TTHL 0x0e
/* Temperature register */
#define AMG88XX_REG_T01L 0x80
/* Control register */
#define MLX90640_REG_CTL1 0x800d
#define MLX90640_REG_CTL1_MASK 0x0380
#define MLX90640_REG_CTL1_MASK_SHIFT 7
static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
{
return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf,
@ -168,7 +175,7 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
static int mlx90640_xfer(struct video_i2c_data *data, char *buf)
{
return regmap_bulk_read(data->regmap, 0x400, buf,
return regmap_bulk_read(data->regmap, MLX90640_RAM_START_ADDR, buf,
data->chip->buffer_size);
}

View File

@ -604,15 +604,8 @@ static void __media_device_unregister_entity(struct media_entity *entity)
media_gobj_destroy(&entity->graph_obj);
/* invoke entity_notify callbacks to handle entity removal?? */
entity->graph_obj.mdev = NULL;
}
/**
* media_device_register_entity - Register an entity with a media device
* @mdev: The media device
* @entity: The entity
*/
int __must_check media_device_register_entity(struct media_device *mdev,
struct media_entity *entity)
{
@ -691,16 +684,6 @@ void media_device_unregister_entity(struct media_entity *entity)
}
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
/**
* media_device_init() - initialize a media device
* @mdev: The media device
*
* The caller is responsible for initializing the media device before
* registration. The following fields must be set:
*
* - dev must point to the parent device
* - model must be filled with the device model name
*/
void media_device_init(struct media_device *mdev)
{
INIT_LIST_HEAD(&mdev->entities);
@ -715,6 +698,10 @@ void media_device_init(struct media_device *mdev)
atomic_set(&mdev->request_id, 0);
if (!*mdev->bus_info)
media_set_bus_info(mdev->bus_info, sizeof(mdev->bus_info),
mdev->dev);
dev_dbg(mdev->dev, "Media device initialized\n");
}
EXPORT_SYMBOL_GPL(media_device_init);

View File

@ -44,6 +44,20 @@ static inline const char *intf_type(struct media_interface *intf)
}
};
static inline const char *link_type_name(struct media_link *link)
{
switch (link->flags & MEDIA_LNK_FL_LINK_TYPE) {
case MEDIA_LNK_FL_DATA_LINK:
return "data";
case MEDIA_LNK_FL_INTERFACE_LINK:
return "interface";
case MEDIA_LNK_FL_ANCILLARY_LINK:
return "ancillary";
default:
return "unknown";
}
}
__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
int idx_max)
{
@ -89,9 +103,7 @@ static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj)
dev_dbg(gobj->mdev->dev,
"%s id %u: %s link id %u ==> id %u\n",
event_name, media_id(gobj),
media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
"data" : "interface",
event_name, media_id(gobj), link_type_name(link),
media_id(link->gobj0),
media_id(link->gobj1));
break;
@ -295,6 +307,12 @@ static void media_graph_walk_iter(struct media_graph *graph)
link = list_entry(link_top(graph), typeof(*link), list);
/* If the link is not a data link, don't follow it */
if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) {
link_top(graph) = link_top(graph)->next;
return;
}
/* The link is not enabled so we do not follow. */
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
link_top(graph) = link_top(graph)->next;
@ -579,26 +597,30 @@ static void __media_entity_remove_link(struct media_entity *entity,
struct media_link *rlink, *tmp;
struct media_entity *remote;
if (link->source->entity == entity)
remote = link->sink->entity;
else
remote = link->source->entity;
list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
if (rlink != link->reverse)
continue;
/* Remove the reverse links for a data link. */
if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) {
if (link->source->entity == entity)
remote->num_backlinks--;
remote = link->sink->entity;
else
remote = link->source->entity;
/* Remove the remote link */
list_del(&rlink->list);
media_gobj_destroy(&rlink->graph_obj);
kfree(rlink);
list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
if (rlink != link->reverse)
continue;
if (--remote->num_links == 0)
break;
if (link->source->entity == entity)
remote->num_backlinks--;
/* Remove the remote link */
list_del(&rlink->list);
media_gobj_destroy(&rlink->graph_obj);
kfree(rlink);
if (--remote->num_links == 0)
break;
}
}
list_del(&link->list);
media_gobj_destroy(&link->graph_obj);
kfree(link);
@ -1007,3 +1029,25 @@ void media_remove_intf_links(struct media_interface *intf)
mutex_unlock(&mdev->graph_mutex);
}
EXPORT_SYMBOL_GPL(media_remove_intf_links);
struct media_link *media_create_ancillary_link(struct media_entity *primary,
struct media_entity *ancillary)
{
struct media_link *link;
link = media_add_link(&primary->links);
if (!link)
return ERR_PTR(-ENOMEM);
link->gobj0 = &primary->graph_obj;
link->gobj1 = &ancillary->graph_obj;
link->flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_ANCILLARY_LINK;
/* Initialize graph object embedded in the new link */
media_gobj_create(primary->graph_obj.mdev, MEDIA_GRAPH_LINK,
&link->graph_obj);
return link;
}
EXPORT_SYMBOL_GPL(media_create_ancillary_link);

View File

@ -2435,8 +2435,6 @@ static int bttv_querycap(struct file *file, void *priv,
strscpy(cap->driver, "bttv", sizeof(cap->driver));
strscpy(cap->card, btv->video_dev.name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(btv->c.pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
if (no_overlay <= 0)

View File

@ -389,8 +389,6 @@ static int cx18_querycap(struct file *file, void *fh,
strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, cx->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCI:%s", pci_name(cx->pci_dev));
vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
return 0;
}

View File

@ -2165,7 +2165,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
err = dma_set_mask(&pci_dev->dev, 0xffffffff);
if (err) {
pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
goto fail_ctrl;
goto fail_dma_set_mask;
}
err = request_irq(pci_dev->irq, cx23885_irq,
@ -2173,7 +2173,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
goto fail_irq;
goto fail_dma_set_mask;
}
switch (dev->board) {
@ -2195,7 +2195,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
return 0;
fail_irq:
fail_dma_set_mask:
cx23885_dev_unregister(dev);
fail_ctrl:
v4l2_ctrl_handler_free(hdl);

View File

@ -728,8 +728,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev)
chip->irq = dev->pci->irq;
err = request_irq(dev->pci->irq, cx25821_irq,
IRQF_SHARED, chip->dev->name, chip);
err = devm_request_irq(&dev->pci->dev, dev->pci->irq, cx25821_irq,
IRQF_SHARED, chip->dev->name, chip);
if (err < 0) {
pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name,

View File

@ -1332,11 +1332,11 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
struct cx25821_dev *dev = get_cx25821(v4l2_dev);
cx25821_shutdown(dev);
pci_disable_device(pci_dev);
/* unregister stuff */
if (pci_dev->irq)
free_irq(pci_dev->irq, dev);
pci_disable_device(pci_dev);
cx25821_dev_unregister(dev);
v4l2_device_unregister(v4l2_dev);

View File

@ -796,7 +796,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx88_core *core = dev->core;
strscpy(cap->driver, "cx88_blackbird", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}

View File

@ -808,7 +808,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct cx88_core *core = dev->core;
strscpy(cap->driver, "cx8800", sizeof(cap->driver));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return cx88_querycap(file, core, cap);
}

View File

@ -292,11 +292,8 @@ static const struct v4l2_file_operations dt3155_fops = {
static int dt3155_querycap(struct file *filp, void *p,
struct v4l2_capability *cap)
{
struct dt3155_priv *pd = video_drvdata(filp);
strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver));
strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
return 0;
}

View File

@ -25,6 +25,8 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = {
CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000),
/* Omnivision OV8865 */
CIO2_SENSOR_CONFIG("INT347A", 1, 360000000),
/* Omnivision OV7251 */
CIO2_SENSOR_CONFIG("INT347E", 1, 319200000),
/* Omnivision OV2680 */
CIO2_SENSOR_CONFIG("OVTI2680", 0),
};

View File

@ -65,6 +65,11 @@ static const struct ipu3_cio2_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_IPU3_SRGGB10,
.mipicode = 0x2b,
.bpp = 10,
}, {
.mbus_code = MEDIA_BUS_FMT_Y10_1X10,
.fourcc = V4L2_PIX_FMT_IPU3_Y10,
.mipicode = 0x2b,
.bpp = 10,
},
};
@ -1046,12 +1051,8 @@ static const struct vb2_ops cio2_vb2_ops = {
static int cio2_v4l2_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct cio2_device *cio2 = video_drvdata(file);
strscpy(cap->driver, CIO2_NAME, sizeof(cap->driver));
strscpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
return 0;
}
@ -1777,8 +1778,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
cio2->media_dev.dev = dev;
strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME,
sizeof(cio2->media_dev.model));
snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info),
"PCI:%s", pci_name(cio2->pci_dev));
cio2->media_dev.hw_revision = 0;
media_device_init(&cio2->media_dev);

View File

@ -732,7 +732,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc
strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strscpy(vcap->card, itv->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev));
vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS;
return 0;
}

View File

@ -1012,7 +1012,6 @@ static int vidioc_querycap(struct file *file, void *fh,
{
strscpy(cap->driver, "meye", sizeof(cap->driver));
strscpy(cap->card, "meye", sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
return 0;
}

View File

@ -1475,7 +1475,6 @@ int saa7134_querycap(struct file *file, void *priv,
strscpy(cap->driver, "saa7134", sizeof(cap->driver));
strscpy(cap->card, saa7134_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS;
@ -1833,8 +1832,7 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
spin_lock_irqsave(&dev->slock, flags);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
if (!on) {
} else {
if (priv != dev->overlay_owner)
return -EINVAL;
spin_lock_irqsave(&dev->slock, flags);

View File

@ -490,7 +490,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, dev->name, sizeof(cap->driver));
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_DEVICE_CAPS;

View File

@ -201,7 +201,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, dev->name, sizeof(cap->driver));
strscpy(cap->card, saa7164_boards[dev->board].name,
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_DEVICE_CAPS;

View File

@ -764,13 +764,10 @@ static int solo_enc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct solo_enc_dev *solo_enc = video_drvdata(file);
struct solo_dev *solo_dev = solo_enc->solo_dev;
strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d",
solo_enc->ch);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
return 0;
}

View File

@ -372,12 +372,8 @@ static const struct vb2_ops solo_video_qops = {
static int solo_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct solo_dev *solo_dev = video_drvdata(file);
strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver));
strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(solo_dev->pdev));
return 0;
}

View File

@ -401,12 +401,8 @@ static const struct v4l2_file_operations vip_fops = {
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct sta2x11_vip *vip = video_drvdata(file);
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
return 0;
}

View File

@ -604,7 +604,6 @@ static int tw5864_querycap(struct file *file, void *priv,
strscpy(cap->driver, "tw5864", sizeof(cap->driver));
snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d",
input->nr);
sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci));
return 0;
}

View File

@ -712,12 +712,9 @@ static int tw68_s_input(struct file *file, void *priv, unsigned int i)
static int tw68_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct tw68_dev *dev = video_drvdata(file);
strscpy(cap->driver, "tw68", sizeof(cap->driver));
strscpy(cap->card, "Techwell Capture Card",
sizeof(cap->card));
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
return 0;
}

View File

@ -762,8 +762,6 @@ static int tw686x_querycap(struct file *file, void *priv,
strscpy(cap->driver, "tw686x", sizeof(cap->driver));
strscpy(cap->card, dev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"PCI:%s", pci_name(dev->pci_dev));
return 0;
}

View File

@ -3249,13 +3249,8 @@ static int allegro_release(struct file *file)
static int allegro_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct allegro_dev *dev = video_get_drvdata(vdev);
strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
return 0;
}

View File

@ -26,8 +26,8 @@
#include "vpu_cmds.h"
#include "vpu_rpc.h"
#define VDEC_FRAME_DEPTH 256
#define VDEC_MIN_BUFFER_CAP 8
#define VDEC_MIN_BUFFER_OUT 8
struct vdec_fs_info {
char name[8];
@ -63,8 +63,6 @@ struct vdec_t {
bool is_source_changed;
u32 source_change;
u32 drain;
u32 ts_pre_count;
u32 frame_depth;
};
static const struct vpu_format vdec_formats[] = {
@ -164,6 +162,12 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
if (ret) {
dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret);
@ -470,7 +474,7 @@ static int vdec_drain(struct vpu_inst *inst)
if (!vdec->drain)
return 0;
if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx))
if (!vpu_is_source_empty(inst))
return 0;
if (!vdec->params.frame_count) {
@ -589,11 +593,8 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type)
{
struct vdec_t *vdec = inst->priv;
if (V4L2_TYPE_IS_OUTPUT(type)) {
if (vdec->ts_pre_count >= vdec->frame_depth)
return false;
if (V4L2_TYPE_IS_OUTPUT(type))
return true;
}
if (vdec->req_frame_count)
return true;
@ -601,12 +602,21 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type)
return false;
}
static struct vb2_v4l2_buffer *vdec_get_src_buffer(struct vpu_inst *inst, u32 count)
{
if (count > 1)
vpu_skip_frame(inst, count - 1);
return vpu_next_src_buf(inst);
}
static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
{
struct vdec_t *vdec = inst->priv;
struct vpu_dec_pic_info *info = arg;
struct vpu_vb2_buffer *vpu_buf;
struct vb2_v4l2_buffer *vbuf;
struct vb2_v4l2_buffer *src_buf;
int ret = 0;
if (!info || info->id >= ARRAY_SIZE(vdec->slots))
@ -620,14 +630,21 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
goto exit;
}
vbuf = &vpu_buf->m2m_buf.vb;
src_buf = vdec_get_src_buffer(inst, info->consumed_count);
if (src_buf) {
v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true);
if (info->consumed_count) {
v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
} else {
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_DECODED);
}
}
if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED)
dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED);
vdec->decoded_frame_count++;
if (vdec->ts_pre_count >= info->consumed_count)
vdec->ts_pre_count -= info->consumed_count;
else
vdec->ts_pre_count = 0;
exit:
vpu_inst_unlock(inst);
@ -683,10 +700,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY);
vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]);
vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]);
vbuf->vb2_buf.timestamp = frame->timestamp;
vbuf->field = inst->cap_format.field;
vbuf->sequence = sequence;
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->timestamp);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
vpu_inst_lock(inst);
@ -708,7 +724,6 @@ static void vdec_stop_done(struct vpu_inst *inst)
vdec->fixed_fmt = false;
vdec->params.end_flag = 0;
vdec->drain = 0;
vdec->ts_pre_count = 0;
vdec->params.frame_count = 0;
vdec->decoded_frame_count = 0;
vdec->display_frame_count = 0;
@ -782,7 +797,7 @@ static void vdec_init_fmt(struct vpu_inst *inst)
if (vdec->codec_info.progressive)
inst->cap_format.field = V4L2_FIELD_NONE;
else
inst->cap_format.field = V4L2_FIELD_SEQ_BT;
inst->cap_format.field = V4L2_FIELD_SEQ_TB;
if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT)
vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709;
if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT)
@ -1244,18 +1259,14 @@ static int vdec_process_output(struct vpu_inst *inst, struct vb2_buffer *vb)
if (free_space < vb2_get_plane_payload(vb, 0) + 0x40000)
return -ENOMEM;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
ret = vpu_iface_input_frame(inst, vb);
if (ret < 0)
return -ENOMEM;
dev_dbg(inst->dev, "[%d][INPUT TS]%32lld\n", inst->id, vb->timestamp);
vdec->ts_pre_count++;
vdec->params.frame_count++;
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
if (vdec->drain)
vdec_drain(inst);
@ -1318,7 +1329,6 @@ static void vdec_abort(struct vpu_inst *inst)
vdec->sequence);
vdec->params.end_flag = 0;
vdec->drain = 0;
vdec->ts_pre_count = 0;
vdec->params.frame_count = 0;
vdec->decoded_frame_count = 0;
vdec->display_frame_count = 0;
@ -1525,10 +1535,6 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i
vdec->drain, vdec->eos_received, vdec->source_change);
break;
case 8:
num = scnprintf(str, size, "ts_pre_count = %d, frame_depth = %d\n",
vdec->ts_pre_count, vdec->frame_depth);
break;
case 9:
num = scnprintf(str, size, "fps = %d/%d\n",
vdec->codec_info.frame_rate.numerator,
vdec->codec_info.frame_rate.denominator);
@ -1562,12 +1568,8 @@ static struct vpu_inst_ops vdec_inst_ops = {
static void vdec_init(struct file *file)
{
struct vpu_inst *inst = to_inst(file);
struct vdec_t *vdec;
struct v4l2_format f;
vdec = inst->priv;
vdec->frame_depth = VDEC_FRAME_DEPTH;
memset(&f, 0, sizeof(f));
f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
@ -1612,36 +1614,18 @@ static int vdec_open(struct file *file)
vdec->fixed_fmt = false;
inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP;
inst->min_buffer_out = VDEC_MIN_BUFFER_OUT;
vdec_init(file);
return 0;
}
static __poll_t vdec_poll(struct file *file, poll_table *wait)
{
struct vpu_inst *inst = to_inst(file);
struct vb2_queue *src_q, *dst_q;
__poll_t ret;
ret = v4l2_m2m_fop_poll(file, wait);
src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
if (vb2_is_streaming(src_q) && !vb2_is_streaming(dst_q))
ret &= (~EPOLLERR);
if (!src_q->error && !dst_q->error &&
(vb2_is_streaming(src_q) && list_empty(&src_q->queued_list)) &&
(vb2_is_streaming(dst_q) && list_empty(&dst_q->queued_list)))
ret &= (~EPOLLERR);
return ret;
}
static const struct v4l2_file_operations vdec_fops = {
.owner = THIS_MODULE,
.open = vdec_open,
.release = vpu_v4l2_close,
.unlocked_ioctl = video_ioctl2,
.poll = vdec_poll,
.poll = v4l2_m2m_fop_poll,
.mmap = v4l2_m2m_fop_mmap,
};

View File

@ -33,6 +33,8 @@
#define VENC_CAPTURE_ENABLE BIT(1)
#define VENC_ENABLE_MASK (VENC_OUTPUT_ENABLE | VENC_CAPTURE_ENABLE)
#define VENC_MAX_BUF_CNT 8
#define VENC_MIN_BUFFER_OUT 6
#define VENC_MIN_BUFFER_CAP 6
struct venc_t {
struct vpu_encode_params params;
@ -281,6 +283,9 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm
if (!parm)
return -EINVAL;
if (!V4L2_TYPE_IS_OUTPUT(parm->type))
return -EINVAL;
if (!vpu_helper_check_type(inst, parm->type))
return -EINVAL;
@ -302,6 +307,9 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm
if (!parm)
return -EINVAL;
if (!V4L2_TYPE_IS_OUTPUT(parm->type))
return -EINVAL;
if (!vpu_helper_check_type(inst, parm->type))
return -EINVAL;
@ -423,7 +431,7 @@ static int venc_drain(struct vpu_inst *inst)
if (inst->state != VPU_CODEC_STATE_DRAIN)
return 0;
if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx))
if (!vpu_is_source_empty(inst))
return 0;
if (!venc->input_ready)
@ -680,6 +688,12 @@ static int venc_ctrl_init(struct vpu_inst *inst)
~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
if (ret) {
dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret);
@ -775,10 +789,20 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst,
struct vb2_v4l2_buffer *vbuf)
{
struct venc_t *venc = inst->priv;
struct vb2_v4l2_buffer *src_buf;
if (!vbuf)
return -EAGAIN;
src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id);
if (src_buf) {
v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
} else {
vbuf->vb2_buf.timestamp = frame->info.timestamp;
}
if (!venc_get_enable(inst->priv, vbuf->vb2_buf.type)) {
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
return 0;
@ -800,11 +824,10 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst,
}
vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->bytesused);
vbuf->sequence = frame->info.frame_id;
vbuf->vb2_buf.timestamp = frame->info.timestamp;
vbuf->field = inst->cap_format.field;
vbuf->flags |= frame->info.pic_type;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->info.timestamp);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
venc->ready_count++;
@ -860,33 +883,6 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
return ret;
}
static void venc_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
{
struct vb2_v4l2_buffer *vbuf;
if (!inst->fh.m2m_ctx)
return;
vpu_inst_lock(inst);
if (!venc_get_enable(inst->priv, frame->type))
goto exit;
vbuf = vpu_find_buf_by_sequence(inst, frame->type, frame->sequence);
if (!vbuf) {
dev_err(inst->dev, "[%d] can't find buf: type %d, sequence %d\n",
inst->id, frame->type, frame->sequence);
goto exit;
}
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
if (V4L2_TYPE_IS_OUTPUT(frame->type))
v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
else
v4l2_m2m_dst_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
exit:
vpu_inst_unlock(inst);
}
static void venc_set_last_buffer_dequeued(struct vpu_inst *inst)
{
struct venc_t *venc = inst->priv;
@ -1252,7 +1248,6 @@ static struct vpu_inst_ops venc_inst_ops = {
.check_ready = venc_check_ready,
.input_done = venc_input_done,
.get_one_frame = venc_frame_encoded,
.buf_done = venc_buf_done,
.stop_done = venc_stop_done,
.event_notify = venc_event_notify,
.release = venc_release,
@ -1333,6 +1328,8 @@ static int venc_open(struct file *file)
if (ret)
return ret;
inst->min_buffer_out = VENC_MIN_BUFFER_OUT;
inst->min_buffer_cap = VENC_MIN_BUFFER_CAP;
venc_init(file);
return 0;

View File

@ -413,10 +413,6 @@ int vpu_inst_create_dbgfs_file(struct vpu_inst *inst)
vpu->debugfs,
inst,
&vpu_dbg_inst_fops);
if (!inst->debugfs) {
dev_err(inst->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
return 0;
}
@ -451,10 +447,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core)
vpu->debugfs,
core,
&vpu_dbg_core_fops);
if (!core->debugfs) {
dev_err(core->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
}
if (!core->debugfs_fwlog) {
scnprintf(name, sizeof(name), "fwlog.%d", core->id);
@ -463,10 +455,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core)
vpu->debugfs,
core,
&vpu_dbg_fwlog_fops);
if (!core->debugfs_fwlog) {
dev_err(core->dev, "vpu create debugfs %s fail\n", name);
return -EINVAL;
}
}
return 0;

View File

@ -69,8 +69,8 @@ enum {
VPU_MSG_ID_BS_ERROR,
VPU_MSG_ID_UNSUPPORTED,
VPU_MSG_ID_TIMESTAMP_INFO,
VPU_MSG_ID_FIRMWARE_XCPT,
VPU_MSG_ID_PIC_SKIPPED,
};
enum VPU_ENC_MEMORY_RESOURSE {

View File

@ -170,6 +170,7 @@ enum {
VID_API_EVENT_DEC_CHECK_RES = 0x24,
VID_API_EVENT_DEC_CFG_INFO = 0x25,
VID_API_EVENT_UNSUPPORTED_STREAM = 0x26,
VID_API_EVENT_PIC_SKIPPED = 0x27,
VID_API_EVENT_STR_SUSPENDED = 0x30,
VID_API_EVENT_SNAPSHOT_DONE = 0x40,
VID_API_EVENT_FW_STATUS = 0xF0,
@ -703,6 +704,7 @@ static struct vpu_pair malone_msgs[] = {
{VPU_MSG_ID_BS_ERROR, VID_API_EVENT_BS_ERROR},
{VPU_MSG_ID_UNSUPPORTED, VID_API_EVENT_UNSUPPORTED_STREAM},
{VPU_MSG_ID_FIRMWARE_XCPT, VID_API_EVENT_FIRMWARE_XCPT},
{VPU_MSG_ID_PIC_SKIPPED, VID_API_EVENT_PIC_SKIPPED},
};
static void vpu_malone_pack_fs_alloc(struct vpu_rpc_event *pkt,
@ -1556,7 +1558,7 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared,
* merge the data to next frame
*/
vbuf = to_vb2_v4l2_buffer(vb);
if (vpu_vb_is_codecconfig(vbuf) && (s64)vb->timestamp < 0) {
if (vpu_vb_is_codecconfig(vbuf)) {
inst->extra_size += size;
return 0;
}

View File

@ -166,6 +166,13 @@ static void vpu_session_handle_firmware_xcpt(struct vpu_inst *inst, struct vpu_r
vpu_v4l2_set_error(inst);
}
static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc_event *pkt)
{
vpu_inst_lock(inst);
vpu_skip_frame(inst, 1);
vpu_inst_unlock(inst);
}
static struct vpu_msg_handler handlers[] = {
{VPU_MSG_ID_START_DONE, vpu_session_handle_start_done},
{VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done},
@ -181,6 +188,7 @@ static struct vpu_msg_handler handlers[] = {
{VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos},
{VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error},
{VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt},
{VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped},
};
static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg)

View File

@ -73,10 +73,10 @@ void vpu_v4l2_set_error(struct vpu_inst *inst)
if (inst->fh.m2m_ctx) {
src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
if (src_q)
src_q->error = 1;
if (dst_q)
dst_q->error = 1;
src_q->error = 1;
dst_q->error = 1;
wake_up(&src_q->done_wq);
wake_up(&dst_q->done_wq);
}
vpu_inst_unlock(inst);
}
@ -127,6 +127,19 @@ int vpu_set_last_buffer_dequeued(struct vpu_inst *inst)
return 0;
}
bool vpu_is_source_empty(struct vpu_inst *inst)
{
struct v4l2_m2m_buffer *buf = NULL;
if (!inst->fh.m2m_ctx)
return true;
v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) {
if (vpu_get_buffer_state(&buf->vb) == VPU_BUF_STATE_IDLE)
return false;
}
return true;
}
const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
@ -234,6 +247,49 @@ int vpu_process_capture_buffer(struct vpu_inst *inst)
return call_vop(inst, process_capture, &vbuf->vb2_buf);
}
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst)
{
struct vb2_v4l2_buffer *src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return NULL;
while (vpu_vb_is_codecconfig(src_buf)) {
v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return NULL;
}
return src_buf;
}
void vpu_skip_frame(struct vpu_inst *inst, int count)
{
struct vb2_v4l2_buffer *src_buf;
enum vb2_buffer_state state;
int i = 0;
if (count <= 0)
return;
while (i < count) {
src_buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx);
if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE)
return;
if (vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_DECODED)
state = VB2_BUF_STATE_DONE;
else
state = VB2_BUF_STATE_ERROR;
i++;
vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE);
v4l2_m2m_buf_done(src_buf, state);
}
}
struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence)
{
struct v4l2_m2m_buffer *buf = NULL;
@ -342,6 +398,10 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq,
return 0;
}
if (V4L2_TYPE_IS_OUTPUT(vq->type))
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out);
else
*buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap);
*plane_count = cur_fmt->num_planes;
for (i = 0; i < cur_fmt->num_planes; i++)
psize[i] = cur_fmt->sizeimage[i];

View File

@ -19,6 +19,8 @@ int vpu_v4l2_close(struct file *file);
const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f);
int vpu_process_output_buffer(struct vpu_inst *inst);
int vpu_process_capture_buffer(struct vpu_inst *inst);
struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst);
void vpu_skip_frame(struct vpu_inst *inst, int count);
struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence);
struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx);
void vpu_v4l2_set_error(struct vpu_inst *inst);
@ -27,6 +29,7 @@ int vpu_notify_source_change(struct vpu_inst *inst);
int vpu_set_last_buffer_dequeued(struct vpu_inst *inst);
void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state);
int vpu_get_num_buffers(struct vpu_inst *inst, u32 type);
bool vpu_is_source_empty(struct vpu_inst *inst);
dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no);
unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no);

View File

@ -1993,6 +1993,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
rc = aspeed_video_setup_video(video);
if (rc) {
aspeed_video_free_buf(video, &video->jpeg);
clk_unprepare(video->vclk);
clk_unprepare(video->eclk);
return rc;
@ -2024,8 +2025,7 @@ static int aspeed_video_remove(struct platform_device *pdev)
v4l2_device_unregister(v4l2_dev);
dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt,
video->jpeg.dma);
aspeed_video_free_buf(video, &video->jpeg);
of_reserved_mem_device_release(dev);

View File

@ -401,6 +401,7 @@ static void isc_stop_streaming(struct vb2_queue *vq)
struct isc_buffer *buf;
int ret;
mutex_lock(&isc->awb_mutex);
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
isc->stop = true;
@ -410,6 +411,8 @@ static void isc_stop_streaming(struct vb2_queue *vq)
v4l2_err(&isc->v4l2_dev,
"Timeout waiting for end of the capture\n");
mutex_unlock(&isc->awb_mutex);
/* Disable DMA interrupt */
regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
@ -442,7 +445,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&isc->dma_queue_lock, flags);
if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
vb2_is_streaming(vb->vb2_queue)) {
vb2_start_streaming_called(vb->vb2_queue)) {
isc->cur_frm = buf;
isc_start_dma(isc);
} else
@ -1029,7 +1032,7 @@ static int isc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct isc_device *isc = video_drvdata(file);
if (vb2_is_streaming(&isc->vb2_vidq))
if (vb2_is_busy(&isc->vb2_vidq))
return -EBUSY;
return isc_set_fmt(isc, f);
@ -1397,10 +1400,6 @@ static void isc_awb_work(struct work_struct *w)
u32 min, max;
int ret;
/* streaming is not active anymore */
if (isc->stop)
return;
if (ctrls->hist_stat != HIST_ENABLED)
return;
@ -1455,7 +1454,24 @@ static void isc_awb_work(struct work_struct *w)
}
regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his,
hist_id | baysel | ISC_HIS_CFG_RAR);
/*
* We have to make sure the streaming has not stopped meanwhile.
* ISC requires a frame to clock the internal profile update.
* To avoid issues, lock the sequence with a mutex
*/
mutex_lock(&isc->awb_mutex);
/* streaming is not active anymore */
if (isc->stop) {
mutex_unlock(&isc->awb_mutex);
return;
};
isc_update_profile(isc);
mutex_unlock(&isc->awb_mutex);
/* if awb has been disabled, we don't need to start another histogram */
if (ctrls->awb)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
@ -1534,6 +1550,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
isc_update_awb_ctrls(isc);
mutex_lock(&isc->awb_mutex);
if (vb2_is_streaming(&isc->vb2_vidq)) {
/*
* If we are streaming, we can update profile to
@ -1548,6 +1565,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
*/
v4l2_ctrl_activate(isc->do_wb_ctrl, false);
}
mutex_unlock(&isc->awb_mutex);
/* if we have autowhitebalance on, start histogram procedure */
if (ctrls->awb == ISC_WB_AUTO &&
@ -1729,6 +1747,7 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier,
{
struct isc_device *isc = container_of(notifier->v4l2_dev,
struct isc_device, v4l2_dev);
mutex_destroy(&isc->awb_mutex);
cancel_work_sync(&isc->awb_work);
video_unregister_device(&isc->video_dev);
v4l2_ctrl_handler_free(&isc->ctrls.handler);
@ -1838,6 +1857,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
isc->current_subdev = container_of(notifier,
struct isc_subdev_entity, notifier);
mutex_init(&isc->lock);
mutex_init(&isc->awb_mutex);
init_completion(&isc->comp);
/* Initialize videobuf2 queue */
@ -1906,6 +1927,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
return 0;
isc_async_complete_err:
mutex_destroy(&isc->awb_mutex);
mutex_destroy(&isc->lock);
return ret;
}

View File

@ -218,6 +218,7 @@ struct isc_reg_offsets {
*
* @lock: lock for serializing userspace file operations
* with ISC operations
* @awb_mutex: serialize access to streaming status from awb work queue
* @awb_lock: lock for serializing awb work queue operations
* with DMA/buffer operations
*
@ -272,7 +273,7 @@ struct isc_device {
struct video_device video_dev;
struct vb2_queue vb2_vidq;
spinlock_t dma_queue_lock; /* serialize access to dma queue */
spinlock_t dma_queue_lock;
struct list_head dma_queue;
struct isc_buffer *cur_frm;
unsigned int sequence;
@ -289,8 +290,9 @@ struct isc_device {
struct isc_ctrls ctrls;
struct work_struct awb_work;
struct mutex lock; /* serialize access to file operations */
spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */
struct mutex lock;
struct mutex awb_mutex;
spinlock_t awb_lock;
struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];

View File

@ -60,56 +60,39 @@
static const struct isc_format sama5d2_controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB444,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ARGB555,
},
{
}, {
.fourcc = V4L2_PIX_FMT_RGB565,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ABGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_XBGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
},
{
}, {
.fourcc = V4L2_PIX_FMT_GREY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
},
};
@ -291,7 +274,7 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc)
* Thus, if the YCYC mode is selected, replace it with the
* sama5d2-compliant mode which is YYCC .
*/
if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) {
if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) {
rlp_mode &= ~ISC_RLP_CFG_MODE_MASK;
rlp_mode |= ISC_RLP_CFG_MODE_YYCC;
}
@ -562,7 +545,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
ret = clk_prepare_enable(isc->ispck);
if (ret) {
dev_err(dev, "failed to enable ispck: %d\n", ret);
goto cleanup_subdev;
goto disable_pm;
}
/* ispck should be greater or equal to hclock */
@ -580,6 +563,9 @@ static int atmel_isc_probe(struct platform_device *pdev)
unprepare_clk:
clk_disable_unprepare(isc->ispck);
disable_pm:
pm_runtime_disable(dev);
cleanup_subdev:
isc_subdev_cleanup(isc);

View File

@ -63,65 +63,45 @@
static const struct isc_format sama7g5_controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_ARGB444,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ARGB555,
},
{
}, {
.fourcc = V4L2_PIX_FMT_RGB565,
},
{
}, {
.fourcc = V4L2_PIX_FMT_ABGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_XBGR32,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV420,
},
{
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUYV,
},
{
}, {
.fourcc = V4L2_PIX_FMT_YUV422P,
},
{
}, {
.fourcc = V4L2_PIX_FMT_GREY,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_Y16,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB8,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
},
{
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
},
};
@ -225,7 +205,6 @@ static struct isc_format sama7g5_formats_list[] = {
.mbus_code = MEDIA_BUS_FMT_Y10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
},
};
static void isc_sama7g5_config_csc(struct isc_device *isc)

View File

@ -454,6 +454,10 @@ static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd,
return 0;
}
static const struct media_entity_operations csi2dc_entity_ops = {
.link_validate = v4l2_subdev_link_validate,
};
static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = {
.enum_mbus_code = csi2dc_enum_mbus_code,
.set_fmt = csi2dc_set_fmt,
@ -683,6 +687,7 @@ static int csi2dc_probe(struct platform_device *pdev)
csi2dc->csi2dc_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
csi2dc->csi2dc_sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
csi2dc->csi2dc_sd.entity.ops = &csi2dc_entity_ops;
platform_set_drvdata(pdev, csi2dc);

View File

@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@ -121,12 +122,12 @@ static const struct csi2tx_fmt csi2tx_formats[] = {
{
.mbus = MEDIA_BUS_FMT_UYVY8_1X16,
.bpp = 2,
.dt = 0x1e,
.dt = MIPI_CSI2_DT_YUV422_8B,
},
{
.mbus = MEDIA_BUS_FMT_RGB888_1X24,
.bpp = 3,
.dt = 0x24,
.dt = MIPI_CSI2_DT_RGB888,
},
};

View File

@ -326,6 +326,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
struct coda_buffer_meta *meta;
u32 start;
lockdep_assert_held(&ctx->bitstream_mutex);
if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
return;
@ -2174,7 +2176,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
(!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
coda_dbg(1, ctx, "bitstream payload: %d, skipping\n",
coda_get_bitstream_payload(ctx));
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
}
@ -2184,7 +2185,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
} else {
ctx->initialized = 1;

View File

@ -657,6 +657,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
const struct coda_q_data *q_data_src;
const struct coda_codec *codec;
struct vb2_queue *src_vq;
int hscale = 0;
int vscale = 0;
int ret;
bool use_vdoa;
@ -673,8 +675,13 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
*/
src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
f->fmt.pix.width = q_data_src->width;
f->fmt.pix.height = q_data_src->height;
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
ctx->dev->devtype->product == CODA_960) {
hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width);
vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height);
}
f->fmt.pix.width = q_data_src->width >> hscale;
f->fmt.pix.height = q_data_src->height >> vscale;
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) {
if (ctx->params.jpeg_chroma_subsampling ==
@ -704,8 +711,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
/* The decoders always write complete macroblocks or MCUs */
if (ctx->inst_type == CODA_INST_DECODER) {
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale);
f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale);
if (codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
@ -850,17 +857,26 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv,
struct coda_q_data *q_data_src;
const struct coda_codec *codec;
struct v4l2_rect r;
int hscale = 0;
int vscale = 0;
int ret;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
ctx->dev->devtype->product == CODA_960) {
hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width);
vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height);
}
ret = coda_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
r.left = 0;
r.top = 0;
r.width = q_data_src->width;
r.height = q_data_src->height;
r.width = q_data_src->width >> hscale;
r.height = q_data_src->height >> vscale;
ret = coda_s_fmt(ctx, f, &r);
if (ret)
@ -1091,17 +1107,6 @@ static int coda_s_selection(struct file *file, void *fh,
}
}
static int coda_try_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *ec)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
if (ctx->inst_type != CODA_INST_ENCODER)
return -ENOTTY;
return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
}
static void coda_wake_up_capture_queue(struct coda_ctx *ctx)
{
struct vb2_queue *dst_vq;
@ -1120,7 +1125,7 @@ static int coda_encoder_cmd(struct file *file, void *fh,
struct vb2_v4l2_buffer *buf;
int ret;
ret = coda_try_encoder_cmd(file, fh, ec);
ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
if (ret < 0)
return ret;
@ -1149,17 +1154,6 @@ static int coda_encoder_cmd(struct file *file, void *fh,
return 0;
}
static int coda_try_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dc)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
if (ctx->inst_type != CODA_INST_DECODER)
return -ENOTTY;
return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
}
static bool coda_mark_last_meta(struct coda_ctx *ctx)
{
struct coda_buffer_meta *meta;
@ -1216,7 +1210,7 @@ static int coda_decoder_cmd(struct file *file, void *fh,
bool wakeup;
int ret;
ret = coda_try_decoder_cmd(file, fh, dc);
ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
if (ret < 0)
return ret;
@ -1291,9 +1285,6 @@ static int coda_enum_framesizes(struct file *file, void *fh,
struct coda_q_data *q_data_dst;
const struct coda_codec *codec;
if (ctx->inst_type != CODA_INST_ENCODER)
return -ENOTTY;
if (fsize->index)
return -EINVAL;
@ -1324,7 +1315,8 @@ static int coda_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *f)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
int i;
struct coda_q_data *q_data;
const struct coda_codec *codec;
if (f->index)
return -EINVAL;
@ -1333,12 +1325,19 @@ static int coda_enum_frameintervals(struct file *file, void *fh,
if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV)
return -EINVAL;
for (i = 0; i < CODA_MAX_FORMATS; i++) {
if (f->pixel_format == ctx->cvd->src_formats[i] ||
f->pixel_format == ctx->cvd->dst_formats[i])
break;
if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) {
q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
codec = coda_find_codec(ctx->dev, f->pixel_format,
q_data->fourcc);
} else {
codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
f->pixel_format);
}
if (i == CODA_MAX_FORMATS)
if (!codec)
return -EINVAL;
if (f->width < MIN_W || f->width > codec->max_w ||
f->height < MIN_H || f->height > codec->max_h)
return -EINVAL;
f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
@ -1498,9 +1497,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_g_selection = coda_g_selection,
.vidioc_s_selection = coda_s_selection,
.vidioc_try_encoder_cmd = coda_try_encoder_cmd,
.vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
.vidioc_encoder_cmd = coda_encoder_cmd,
.vidioc_try_decoder_cmd = coda_try_decoder_cmd,
.vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
.vidioc_decoder_cmd = coda_decoder_cmd,
.vidioc_g_parm = coda_g_parm,
@ -1535,12 +1534,8 @@ static void coda_pic_run_work(struct work_struct *work)
mutex_lock(&dev->coda_mutex);
ret = ctx->ops->prepare_run(ctx);
if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) {
mutex_unlock(&dev->coda_mutex);
mutex_unlock(&ctx->buffer_mutex);
/* job_finish scheduled by prepare_decode */
return;
}
if (ret < 0 && ctx->inst_type == CODA_INST_DECODER)
goto out;
if (!wait_for_completion_timeout(&ctx->completion,
msecs_to_jiffies(1000))) {
@ -1562,6 +1557,7 @@ static void coda_pic_run_work(struct work_struct *work)
ctx->ops->seq_end_work)
queue_work(dev->workqueue, &ctx->seq_end_work);
out:
mutex_unlock(&dev->coda_mutex);
mutex_unlock(&ctx->buffer_mutex);
@ -1665,13 +1661,18 @@ static void set_default_params(struct coda_ctx *ctx)
csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h);
ctx->params.codec_mode = ctx->codec->mode;
if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG)
ctx->colorspace = V4L2_COLORSPACE_JPEG;
else
if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG ||
ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) {
ctx->colorspace = V4L2_COLORSPACE_SRGB;
ctx->xfer_func = V4L2_XFER_FUNC_SRGB;
ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE;
} else {
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
}
ctx->params.framerate = 30;
/* Default formats for output and input queues */
@ -2011,13 +2012,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
*/
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) {
buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
ret = coda_jpeg_decode_header(ctx, &buf->vb2_buf);
if (ret < 0) {
v4l2_err(v4l2_dev,
"failed to decode JPEG header: %d\n",
ret);
goto err;
}
coda_jpeg_decode_header(ctx, &buf->vb2_buf);
/*
* We have to start streaming even if the first buffer
* does not contain a valid JPEG image. The error will
* be caught during device run and will be signalled
* via the capture buffer error flag.
*/
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
q_data_dst->width = round_up(q_data_src->width, 16);
@ -2344,8 +2345,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0,
V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE);
if (ctx->dev->devtype->product == CODA_HX4 ||
ctx->dev->devtype->product == CODA_7541) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@ -2359,12 +2360,15 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
if (ctx->dev->devtype->product == CODA_960) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
}
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@ -2426,7 +2430,7 @@ static void coda_decode_ctrls(struct coda_ctx *ctx)
ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
@ -2901,6 +2905,23 @@ static int coda_register_device(struct coda_dev *dev, int i)
v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) {
v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) {
v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS);
v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
}
} else {
v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES);
v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS);
v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
}
ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
if (!ret)
v4l2_info(&dev->v4l2_dev, "%s registered as %s\n",

View File

@ -283,7 +283,8 @@ int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb)
ret = v4l2_jpeg_parse_header(buf, len, &header);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to parse header\n");
v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n",
ERR_PTR(ret));
return ret;
}
@ -1328,6 +1329,7 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_src, *q_data_dst;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
int chroma_interleave;
int scl_hor_mode, scl_ver_mode;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@ -1335,27 +1337,24 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
dst_fourcc = q_data_dst->fourcc;
scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width);
scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height);
if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0)
vb2_set_plane_payload(&src_buf->vb2_buf, 0,
vb2_plane_size(&src_buf->vb2_buf, 0));
chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc);
if (chroma_format < 0) {
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
if (chroma_format < 0)
return chroma_format;
}
ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to decode JPEG header: %d\n",
ret);
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return ret;
}
@ -1386,7 +1385,11 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO);
coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO);
coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO);
coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO);
if (scl_hor_mode || scl_ver_mode)
val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode;
else
val = 0;
coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO);
coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG);
coda_write(dev, ctx->params.jpeg_restart_interval,
CODA9_REG_JPEG_RST_INTVAL);
@ -1396,7 +1399,6 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"failed to set up Huffman tables: %d\n", ret);
v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return ret;
}
}

View File

@ -380,6 +380,13 @@ u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size);
void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc,
u8 level_idc);
static inline int coda_jpeg_scale(int src, int dst)
{
return (dst <= src / 8) ? 3 :
(dst <= src / 4) ? 2 :
(dst <= src / 2) ? 1 : 0;
}
bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_write_tables(struct coda_ctx *ctx);

View File

@ -497,7 +497,6 @@ static int cafe_pci_probe(struct pci_dev *pdev,
mcam->plat_power_up = cafe_ctlr_power_up;
mcam->plat_power_down = cafe_ctlr_power_down;
mcam->dev = &pdev->dev;
snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev));
/*
* Vmalloc mode for buffers is traditional with this driver.
* We *might* be able to run DMA_contig, especially on a system

View File

@ -137,8 +137,6 @@ static int mtk_jpeg_querycap(struct file *file, void *priv,
strscpy(cap->driver, jpeg->variant->dev_name, sizeof(cap->driver));
strscpy(cap->card, jpeg->variant->dev_name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(jpeg->dev));
return 0;
}

View File

@ -22,6 +22,7 @@ config VIDEO_MEDIATEK_VCODEC
select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU
select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP
select V4L2_H264
select V4L2_VP9
select MEDIA_CONTROLLER
select MEDIA_CONTROLLER_REQUEST_API
help

View File

@ -7,8 +7,12 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \
mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
vdec/vdec_vp8_if.o \
vdec/vdec_vp8_req_if.o \
vdec/vdec_vp9_if.o \
vdec/vdec_vp9_req_lat_if.o \
vdec/vdec_h264_req_if.o \
vdec/vdec_h264_req_common.o \
vdec/vdec_h264_req_multi_if.o \
mtk_vcodec_dec_drv.o \
vdec_drv_if.o \
vdec_vpu_if.o \

View File

@ -26,7 +26,7 @@ mtk_vdec_find_format(struct v4l2_format *f,
const struct mtk_video_fmt *fmt;
unsigned int k;
for (k = 0; k < dec_pdata->num_formats; k++) {
for (k = 0; k < *dec_pdata->num_formats; k++) {
fmt = &dec_pdata->vdec_formats[k];
if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
return fmt;
@ -47,14 +47,7 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
static int vidioc_try_decoder_cmd(struct file *file, void *priv,
struct v4l2_decoder_cmd *cmd)
{
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
/* Use M2M stateless helper if relevant */
if (ctx->dev->vdec_pdata->uses_stateless_api)
return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv,
cmd);
else
return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
}
@ -69,10 +62,6 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
if (ret)
return ret;
/* Use M2M stateless helper if relevant */
if (ctx->dev->vdec_pdata->uses_stateless_api)
return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd);
mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd);
dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
@ -152,13 +141,15 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
q_data->coded_height = DFT_CFG_HEIGHT;
q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt;
q_data->field = V4L2_FIELD_NONE;
ctx->max_width = MTK_VDEC_MAX_W;
ctx->max_height = MTK_VDEC_MAX_H;
v4l_bound_align_image(&q_data->coded_width,
MTK_VDEC_MIN_W,
MTK_VDEC_MAX_W, 4,
ctx->max_width, 4,
&q_data->coded_height,
MTK_VDEC_MIN_H,
MTK_VDEC_MAX_H, 5, 6);
ctx->max_height, 5, 6);
q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
q_data->bytesperline[0] = q_data->coded_width;
@ -217,7 +208,7 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
}
}
static int vidioc_try_fmt(struct v4l2_format *f,
static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
const struct mtk_video_fmt *fmt)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
@ -225,9 +216,9 @@ static int vidioc_try_fmt(struct v4l2_format *f,
pix_fmt_mp->field = V4L2_FIELD_NONE;
pix_fmt_mp->width =
clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W);
clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width);
pix_fmt_mp->height =
clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H);
clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
pix_fmt_mp->num_planes = 1;
@ -245,16 +236,16 @@ static int vidioc_try_fmt(struct v4l2_format *f,
tmp_h = pix_fmt_mp->height;
v4l_bound_align_image(&pix_fmt_mp->width,
MTK_VDEC_MIN_W,
MTK_VDEC_MAX_W, 6,
ctx->max_width, 6,
&pix_fmt_mp->height,
MTK_VDEC_MIN_H,
MTK_VDEC_MAX_H, 6, 9);
ctx->max_height, 6, 9);
if (pix_fmt_mp->width < tmp_w &&
(pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W)
(pix_fmt_mp->width + 64) <= ctx->max_width)
pix_fmt_mp->width += 64;
if (pix_fmt_mp->height < tmp_h &&
(pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H)
(pix_fmt_mp->height + 64) <= ctx->max_height)
pix_fmt_mp->height += 64;
mtk_v4l2_debug(0,
@ -294,7 +285,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
fmt = mtk_vdec_find_format(f, dec_pdata);
}
return vidioc_try_fmt(f, fmt);
return vidioc_try_fmt(ctx, f, fmt);
}
static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
@ -317,7 +308,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
return -EINVAL;
}
return vidioc_try_fmt(f, fmt);
return vidioc_try_fmt(ctx, f, fmt);
}
static int vidioc_vdec_g_selection(struct file *file, void *priv,
@ -444,8 +435,15 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
if (fmt == NULL)
return -EINVAL;
if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) &&
fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) {
mtk_v4l2_debug(3, "4K is enabled");
ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH;
ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT;
}
q_data->fmt = fmt;
vidioc_try_fmt(f, q_data->fmt);
vidioc_try_fmt(ctx, f, q_data->fmt);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage;
q_data->coded_width = pix_mp->width;
@ -466,6 +464,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
}
ctx->state = MTK_STATE_INIT;
}
} else {
ctx->capture_fourcc = fmt->fourcc;
}
/*
@ -476,11 +476,14 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
ctx->picinfo.pic_w = pix_mp->width;
ctx->picinfo.pic_h = pix_mp->height;
/*
* If get pic info fail, need to use the default pic info params, or
* v4l2-compliance will fail
*/
ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo);
if (ret) {
mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail",
ctx->id);
return -EINVAL;
}
ctx->last_decoded_picinfo = ctx->picinfo;
@ -523,20 +526,15 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
if (fsize->index != 0)
return -EINVAL;
for (i = 0; i < dec_pdata->num_framesizes; ++i) {
for (i = 0; i < *dec_pdata->num_framesizes; ++i) {
if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc)
continue;
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise;
if (!(ctx->dev->dec_capability &
VCODEC_CAPABILITY_4K_DISABLED)) {
mtk_v4l2_debug(3, "4K is enabled");
fsize->stepwise.max_width =
VCODEC_DEC_4K_CODED_WIDTH;
fsize->stepwise.max_height =
VCODEC_DEC_4K_CODED_HEIGHT;
}
fsize->stepwise.max_width = ctx->max_width;
fsize->stepwise.max_height = ctx->max_height;
mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
ctx->dev->dec_capability,
fsize->stepwise.min_width,
@ -545,6 +543,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
fsize->stepwise.min_height,
fsize->stepwise.max_height,
fsize->stepwise.step_height);
return 0;
}
@ -559,7 +558,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
const struct mtk_video_fmt *fmt;
int i, j = 0;
for (i = 0; i < dec_pdata->num_formats; i++) {
for (i = 0; i < *dec_pdata->num_formats; i++) {
if (output_queue &&
dec_pdata->vdec_formats[i].type != MTK_FMT_DEC)
continue;
@ -572,7 +571,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
++j;
}
if (i == dec_pdata->num_formats)
if (i == *dec_pdata->num_formats)
return -EINVAL;
fmt = &dec_pdata->vdec_formats[i];
@ -737,6 +736,8 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
i, vb2_plane_size(vb, i),
q_data->sizeimage[i]);
}
if (!V4L2_TYPE_IS_OUTPUT(vb->type))
vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
}
return 0;

Some files were not shown because too many files have changed in this diff Show More