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:
commit
827060261c
@ -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]
|
||||
}
|
||||
|
@ -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
|
@ -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>;
|
||||
};
|
||||
};
|
||||
...
|
@ -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
|
||||
|
@ -63,6 +63,9 @@ properties:
|
||||
description:
|
||||
Describes point to scp.
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -47,7 +47,9 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mediatek,mt8192-vcodec-dec
|
||||
enum:
|
||||
- mediatek,mt8192-vcodec-dec
|
||||
- mediatek,mt8186-vcodec-dec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -93,6 +93,7 @@ properties:
|
||||
- 4 # MIPI CSI-2 D-PHY
|
||||
- 5 # Parallel
|
||||
- 6 # BT.656
|
||||
- 7 # DPI
|
||||
description:
|
||||
Data bus type.
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
^^^^^^^^
|
||||
|
@ -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
|
||||
---------------------------------------------
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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>`
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
12
MAINTAINERS
12
MAINTAINERS
@ -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/
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user