[GIT PULL for v6.17] media updates
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmiLgnwACgkQCF8+vY7k
4RULug/9Hro6lyA8ZtKjPd0nAhML5XC4Cdds4CUE8C0jkdUs5UEXdZMkvq+FA8iT
O0lMZpo3ssCyqTEPCUyDxu9X9Z+meGCzFg2imPWMgcGRGtkNH+WxBfWBECrWJIbA
jnBgvYM+EDP+GRacW4yLVK/O4l9+8E1mDhYdouf7T3uy1leEM6GFGjZTtYkEM74+
7mJh+4+fXfRrBvoZZ2HYQa8OCn18zs7YYpVdTBHBncd6qvhRm7/g3xHhkpyh/iR4
M2BEM1FEeVPj7SGKR4ojKrltz5EYAhtdI5p9hJ/SCCXyk9H55jpdSfwEMw1UaHdm
HdC5G4Cen4aI7aVHU9CdwW2fRsLfU1b7Lhb8IMGaBGvUoJlg94q5qNt9KS2SFnpk
U/IwoMOxQVDNIGjr/cZ81QHLnjR2Tcb1RQ4vJKDxLu2flCNO8pDG8TGEbcSq0UKb
TFEsmykP5s6LEMCKO3htpq4lx+MTCF/pUS99TkgM//WOFcuM505scIbBio1tutpk
CXVn5KoT5ecNgt3xSGaWN6KtBWr12mnuY5oqVBRfoFKrAvl0xbexbToBvE3uSCWc
tcUJ+3bMlZZvZsYdF2HvHQTXfx4glrWAP9tfusjstvKie+z8JfixVktNGSLCMU+4
qvidvLM99t/9bw+Bt0O4BbvryRnGi2+RA1Afo6zGRnRpxYMkagY=
=oX7n
-----END PGP SIGNATURE-----
Merge tag 'media/v6.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- v4l2 core:
- sub-device framework routing improvements
- NV12M tiled variants added to v4l2_format_info
- some fixes at control handler freeing logic
- fixed H264 SEPARATE_COLOUR_PLANE check
- new staging driver: Intel IPU7 PCI
- Rockchip video decoder driver got promoted from staging
- iris: added HEVC/VP9 encoder/decoder support
- vsp1: driver has gained Renesas VSPX support
- uvc:
- switched to vb2 ioctl helpers
- added MSXU 1.5 metadata support
- atomisp: GC0310 sensor driver cleanups in preparation for moving it
out of staging
- Lots of cleanup, fixes and improvements
* tag 'media/v6.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (310 commits)
media: rkvdec: Unstage the driver
media: rkvdec: Remove TODO file
media: dt-bindings: rockchip: Add RK3576 Video Decoder bindings
media: dt-bindings: rockchip: Document RK3588 Video Decoder bindings
media: amphion: Support dmabuf and v4l2 buffer without binding
media: verisilicon: postproc: 4K support
media: v4l2: Add support for NV12M tiled variants to v4l2_format_info()
media: uvcvideo: Use a count variable for meta_formats instead of 0 terminating
media: uvcvideo: Auto-set UVC_QUIRK_MSXU_META
media: uvcvideo: Introduce V4L2_META_FMT_UVC_MSXU_1_5
media: uvcvideo: Introduce dev->meta_formats
media: Documentation: Add note about UVCH length field
media: uvcvideo: Do not mark valid metadata as invalid
media: uvcvideo: uvc_v4l2_unlocked_ioctl: Invert PM logic
media: core: export v4l2_translate_cmd
media: uvcvideo: Turn on the camera if V4L2_EVENT_SUB_FL_SEND_INITIAL
media: uvcvideo: Remove stream->is_streaming field
media: uvcvideo: Split uvc_stop_streaming()
media: uvcvideo: Handle locks in uvc_queue_return_buffers
media: uvcvideo: Use vb2 ioctl and fop helpers
...
pull/1311/head
commit
0cdee263bc
5
.mailmap
5
.mailmap
|
|
@ -287,8 +287,9 @@ Gustavo Padovan <padovan@profusion.mobi>
|
|||
Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com>
|
||||
Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org>
|
||||
Hans de Goede <hansg@kernel.org> <hdegoede@redhat.com>
|
||||
Hans Verkuil <hverkuil@xs4all.nl> <hansverk@cisco.com>
|
||||
Hans Verkuil <hverkuil@xs4all.nl> <hverkuil-cisco@xs4all.nl>
|
||||
Hans Verkuil <hverkuil@kernel.org> <hverkuil@xs4all.nl>
|
||||
Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl>
|
||||
Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com>
|
||||
Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
|
||||
Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
|
||||
Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ properties:
|
|||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: error_irq
|
||||
- const: irq
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: CSI2Rx system clock
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/fsl,imx6q-vdoa.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Freescale Video Data Order Adapter
|
||||
|
||||
description:
|
||||
The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose
|
||||
is to reorder video data from the macroblock tiled order produced by the CODA
|
||||
960 VPU to the conventional raster-scan order for scanout.
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: "fsl,imx6q-vdoa"
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/imx6qdl-clock.h>
|
||||
|
||||
vdoa@21e4000 {
|
||||
compatible = "fsl,imx6q-vdoa";
|
||||
reg = <0x021e4000 0x4000>;
|
||||
interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_VDOA>;
|
||||
};
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/fsl,imx8qm-isi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: i.MX8QM Image Sensing Interface
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
description:
|
||||
The Image Sensing Interface (ISI) combines image processing pipelines with
|
||||
DMA engines to process and capture frames originating from a variety of
|
||||
sources. The inputs to the ISI go through Pixel Link interfaces, and their
|
||||
number and nature is SoC-dependent. They cover both capture interfaces (MIPI
|
||||
CSI-2 RX, HDMI RX, ...) and display engine outputs for writeback support.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8qm-isi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 8
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: per0
|
||||
- const: per1
|
||||
- const: per2
|
||||
- const: per3
|
||||
- const: per4
|
||||
- const: per5
|
||||
- const: per6
|
||||
- const: per7
|
||||
|
||||
interrupts:
|
||||
maxItems: 8
|
||||
|
||||
power-domains:
|
||||
maxItems: 8
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: MIPI CSI-2 RX 0
|
||||
port@3:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: MIPI CSI-2 RX 1
|
||||
port@4:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: HDMI RX
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- power-domains
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/imx8-clock.h>
|
||||
#include <dt-bindings/clock/imx8-lpcg.h>
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
image-controller@58100000 {
|
||||
compatible = "fsl,imx8qm-isi";
|
||||
reg = <0x58100000 0x80000>;
|
||||
interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pdma0_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma1_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma2_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma3_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma4_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma5_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma6_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma7_lpcg IMX_LPCG_CLK_0>;
|
||||
clock-names = "per0", "per1", "per2", "per3",
|
||||
"per4", "per5", "per6", "per7";
|
||||
power-domains = <&pd IMX_SC_R_ISI_CH0>, <&pd IMX_SC_R_ISI_CH1>,
|
||||
<&pd IMX_SC_R_ISI_CH2>, <&pd IMX_SC_R_ISI_CH3>,
|
||||
<&pd IMX_SC_R_ISI_CH4>, <&pd IMX_SC_R_ISI_CH5>,
|
||||
<&pd IMX_SC_R_ISI_CH6>, <&pd IMX_SC_R_ISI_CH7>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
endpoint {
|
||||
remote-endpoint = <&mipi_csi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/media/fsl,imx8qxp-isi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: i.MX8QXP Image Sensing Interface
|
||||
|
||||
maintainers:
|
||||
- Frank Li <Frank.Li@nxp.com>
|
||||
|
||||
description:
|
||||
The Image Sensing Interface (ISI) combines image processing pipelines with
|
||||
DMA engines to process and capture frames originating from a variety of
|
||||
sources. The inputs to the ISI go through Pixel Link interfaces, and their
|
||||
number and nature is SoC-dependent. They cover both capture interfaces (MIPI
|
||||
CSI-2 RX, HDMI RX, ...) and display engine outputs for writeback support.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8qxp-isi
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 6
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: per0
|
||||
- const: per1
|
||||
- const: per2
|
||||
- const: per3
|
||||
- const: per4
|
||||
- const: per5
|
||||
|
||||
interrupts:
|
||||
maxItems: 6
|
||||
|
||||
power-domains:
|
||||
maxItems: 6
|
||||
|
||||
ports:
|
||||
$ref: /schemas/graph.yaml#/properties/ports
|
||||
properties:
|
||||
port@2:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: MIPI CSI-2 RX 0
|
||||
port@6:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description: CSI-2 Parallel RX
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
- power-domains
|
||||
- ports
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/imx8-clock.h>
|
||||
#include <dt-bindings/clock/imx8-lpcg.h>
|
||||
#include <dt-bindings/firmware/imx/rsrc.h>
|
||||
|
||||
image-controller@58100000 {
|
||||
compatible = "fsl,imx8qxp-isi";
|
||||
reg = <0x58100000 0x60000>;
|
||||
interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&pdma0_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma1_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma2_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma3_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma4_lpcg IMX_LPCG_CLK_0>,
|
||||
<&pdma5_lpcg IMX_LPCG_CLK_0>;
|
||||
clock-names = "per0", "per1", "per2", "per3", "per4", "per5";
|
||||
power-domains = <&pd IMX_SC_R_ISI_CH0>, <&pd IMX_SC_R_ISI_CH1>,
|
||||
<&pd IMX_SC_R_ISI_CH2>, <&pd IMX_SC_R_ISI_CH3>,
|
||||
<&pd IMX_SC_R_ISI_CH4>, <&pd IMX_SC_R_ISI_CH5>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@2 {
|
||||
reg = <2>;
|
||||
endpoint {
|
||||
remote-endpoint = <&mipi_csi0_out>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
Freescale Video Data Order Adapter
|
||||
==================================
|
||||
|
||||
The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose
|
||||
is to reorder video data from the macroblock tiled order produced by the CODA
|
||||
960 VPU to the conventional raster-scan order for scanout.
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "fsl,imx6q-vdoa"
|
||||
- reg: the register base and size for the device registers
|
||||
- interrupts: the VDOA interrupt
|
||||
- clocks: the vdoa clock
|
||||
|
||||
Example:
|
||||
|
||||
vdoa@21e4000 {
|
||||
compatible = "fsl,imx6q-vdoa";
|
||||
reg = <0x021e4000 0x4000>;
|
||||
interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clks IMX6QDL_CLK_VDOA>;
|
||||
};
|
||||
|
|
@ -23,6 +23,9 @@ description:
|
|||
More detailed documentation can be found in
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt .
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/media/video-interface-devices.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
|
|
@ -58,16 +61,10 @@ properties:
|
|||
documentation.
|
||||
maxItems: 1
|
||||
|
||||
flash-leds:
|
||||
description: Flash LED phandles. See ../video-interfaces.txt for details.
|
||||
|
||||
lens-focus:
|
||||
description: Lens focus controller phandles. See ../video-interfaces.txt
|
||||
for details.
|
||||
flash-leds: true
|
||||
lens-focus: true
|
||||
|
||||
rotation:
|
||||
description: Rotation of the sensor. See ../video-interfaces.txt for
|
||||
details.
|
||||
enum: [ 0, 180 ]
|
||||
|
||||
port:
|
||||
|
|
|
|||
|
|
@ -70,6 +70,15 @@ properties:
|
|||
- bus-type
|
||||
- link-frequencies
|
||||
|
||||
slew-rate:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Slew rate ot the output pads DOUT[7:0], LINE_VALID, FRAME_VALID and
|
||||
PIXCLK. Higher values imply steeper voltage-flanks on the pads.
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
default: 7
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ description: |
|
|||
controlled through an I2C-compatible SCCB bus. The sensor transmits images
|
||||
on a MIPI CSI-2 output interface with up to 4 data lanes.
|
||||
|
||||
$ref: /schemas/media/video-interface-devices.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: ovti,ov8858
|
||||
|
|
@ -69,7 +71,7 @@ required:
|
|||
- clocks
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
|||
|
|
@ -33,20 +33,21 @@ properties:
|
|||
|
||||
clock-frequency:
|
||||
description: Frequency of the xclk clock in Hz.
|
||||
deprecated: true
|
||||
|
||||
enable-gpios:
|
||||
description: GPIO descriptor for the enable pin.
|
||||
maxItems: 1
|
||||
|
||||
vdddo-supply:
|
||||
description: Chip digital IO regulator (1.8V).
|
||||
|
||||
vdda-supply:
|
||||
description: Chip analog regulator (2.7V).
|
||||
|
||||
vddd-supply:
|
||||
description: Chip digital core regulator (1.12V).
|
||||
|
||||
vdddo-supply:
|
||||
description: Chip digital IO regulator (1.8V).
|
||||
|
||||
flash-leds: true
|
||||
lens-focus: true
|
||||
|
||||
|
|
@ -84,11 +85,10 @@ required:
|
|||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-frequency
|
||||
- enable-gpios
|
||||
- vdddo-supply
|
||||
- vdda-supply
|
||||
- vddd-supply
|
||||
- vdddo-supply
|
||||
- port
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
|
@ -104,22 +104,25 @@ examples:
|
|||
camera-sensor@1a {
|
||||
compatible = "sony,imx214";
|
||||
reg = <0x1a>;
|
||||
vdddo-supply = <&pm8994_lvs1>;
|
||||
vddd-supply = <&camera_vddd_1v12>;
|
||||
vdda-supply = <&pm8994_l17>;
|
||||
lens-focus = <&ad5820>;
|
||||
enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
clocks = <&camera_clk>;
|
||||
clock-frequency = <24000000>;
|
||||
assigned-clocks = <&camera_clk>;
|
||||
assigned-clock-rates = <24000000>;
|
||||
|
||||
enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
vdda-supply = <&pm8994_l17>;
|
||||
vddd-supply = <&camera_vddd_1v12>;
|
||||
vdddo-supply = <&pm8994_lvs1>;
|
||||
|
||||
lens-focus = <&ad5820>;
|
||||
|
||||
port {
|
||||
imx214_ep: endpoint {
|
||||
data-lanes = <1 2 3 4>;
|
||||
link-frequencies = /bits/ 64 <480000000>;
|
||||
link-frequencies = /bits/ 64 <600000000>;
|
||||
remote-endpoint = <&csiphy0_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ description: |-
|
|||
The camera module does not expose the model through registers, so the
|
||||
exact model needs to be specified.
|
||||
|
||||
$ref: /schemas/media/video-interface-devices.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
|
|
@ -81,7 +83,7 @@ required:
|
|||
- reg
|
||||
- port
|
||||
|
||||
additionalProperties: false
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
|
|
|
|||
|
|
@ -22,10 +22,14 @@ properties:
|
|||
- nxp,imx8qxp-jpgdec
|
||||
- nxp,imx8qxp-jpgenc
|
||||
- items:
|
||||
- const: nxp,imx8qm-jpgdec
|
||||
- enum:
|
||||
- nxp,imx8qm-jpgdec
|
||||
- nxp,imx95-jpgdec
|
||||
- const: nxp,imx8qxp-jpgdec
|
||||
- items:
|
||||
- const: nxp,imx8qm-jpgenc
|
||||
- enum:
|
||||
- nxp,imx8qm-jpgenc
|
||||
- nxp,imx95-jpgenc
|
||||
- const: nxp,imx8qxp-jpgenc
|
||||
|
||||
reg:
|
||||
|
|
@ -48,7 +52,7 @@ properties:
|
|||
description:
|
||||
List of phandle and PM domain specifier as documented in
|
||||
Documentation/devicetree/bindings/power/power_domain.txt
|
||||
minItems: 2 # Wrapper and 1 slot
|
||||
minItems: 1 # Wrapper and all slots
|
||||
maxItems: 5 # Wrapper and 4 slots
|
||||
|
||||
required:
|
||||
|
|
@ -58,6 +62,24 @@ required:
|
|||
- interrupts
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nxp,imx95-jpgenc
|
||||
- nxp,imx95-jpgdec
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
else:
|
||||
properties:
|
||||
power-domains:
|
||||
minItems: 2 # Wrapper and 1 slot
|
||||
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -16,11 +16,19 @@ description: |-
|
|||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx8mq-mipi-csi2
|
||||
oneOf:
|
||||
- enum:
|
||||
- fsl,imx8mq-mipi-csi2
|
||||
- fsl,imx8qxp-mipi-csi2
|
||||
- items:
|
||||
- const: fsl,imx8qm-mipi-csi2
|
||||
- const: fsl,imx8qxp-mipi-csi2
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
items:
|
||||
- description: MIPI CSI-2 RX host controller register.
|
||||
- description: MIPI CSI-2 control and status register (csr).
|
||||
minItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
|
|
@ -46,6 +54,7 @@ properties:
|
|||
- description: CORE_RESET reset register bit definition
|
||||
- description: PHY_REF_RESET reset register bit definition
|
||||
- description: ESC_RESET reset register bit definition
|
||||
minItems: 1
|
||||
|
||||
fsl,mipi-phy-gpr:
|
||||
description: |
|
||||
|
|
@ -113,9 +122,30 @@ required:
|
|||
- clock-names
|
||||
- power-domains
|
||||
- resets
|
||||
- fsl,mipi-phy-gpr
|
||||
- ports
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8qxp-mipi-csi2
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 2
|
||||
resets:
|
||||
maxItems: 1
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
resets:
|
||||
minItems: 3
|
||||
required:
|
||||
- fsl,mipi-phy-gpr
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ properties:
|
|||
CSI input ports.
|
||||
|
||||
patternProperties:
|
||||
"^port@[0-3]+$":
|
||||
"^port@[0-3]$":
|
||||
$ref: /schemas/graph.yaml#/$defs/port-base
|
||||
unevaluatedProperties: false
|
||||
|
||||
|
|
@ -146,15 +146,16 @@ properties:
|
|||
unevaluatedProperties: false
|
||||
|
||||
properties:
|
||||
clock-lanes:
|
||||
maxItems: 1
|
||||
|
||||
data-lanes:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
|
||||
bus-type:
|
||||
enum:
|
||||
- 1 # MEDIA_BUS_TYPE_CSI2_CPHY
|
||||
- 4 # MEDIA_BUS_TYPE_CSI2_DPHY
|
||||
|
||||
required:
|
||||
- clock-lanes
|
||||
- data-lanes
|
||||
|
||||
required:
|
||||
|
|
@ -189,7 +190,7 @@ examples:
|
|||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
camss: isp@acb6000 {
|
||||
camss: isp@acb7000 {
|
||||
compatible = "qcom,x1e80100-camss";
|
||||
|
||||
reg = <0 0x0acb7000 0 0x2000>,
|
||||
|
|
@ -357,7 +358,6 @@ examples:
|
|||
port@0 {
|
||||
reg = <0>;
|
||||
csiphy_ep0: endpoint {
|
||||
clock-lanes = <7>;
|
||||
data-lanes = <0 1>;
|
||||
remote-endpoint = <&sensor_ep>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ properties:
|
|||
- renesas,r9a07g043u-fcpvd # RZ/G2UL
|
||||
- renesas,r9a07g044-fcpvd # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-fcpvd # RZ/V2L
|
||||
- renesas,r9a09g056-fcpvd # RZ/V2N
|
||||
- renesas,r9a09g057-fcpvd # RZ/V2H(P)
|
||||
- const: renesas,fcpv # Generic FCP for VSP fallback
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ properties:
|
|||
- enum:
|
||||
- renesas,r9a07g043u-vsp2 # RZ/G2UL
|
||||
- renesas,r9a07g054-vsp2 # RZ/V2L
|
||||
- renesas,r9a09g056-vsp2 # RZ/V2N
|
||||
- renesas,r9a09g057-vsp2 # RZ/V2H(P)
|
||||
- const: renesas,r9a07g044-vsp2 # RZ/G2L fallback
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ maintainers:
|
|||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
description: |-
|
||||
The Rockchip rk3399 has a stateless Video Decoder that can decodes H.264,
|
||||
HEVC an VP9 streams.
|
||||
Rockchip SoCs have variants of the same stateless Video Decoder that can
|
||||
decodes H.264, HEVC, VP9 and AV1 streams, depending on the variant.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: rockchip,rk3399-vdec
|
||||
- const: rockchip,rk3576-vdec
|
||||
- const: rockchip,rk3588-vdec
|
||||
- items:
|
||||
- enum:
|
||||
- rockchip,rk3228-vdec
|
||||
|
|
@ -24,35 +26,72 @@ properties:
|
|||
- const: rockchip,rk3399-vdec
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
minItems: 1
|
||||
items:
|
||||
- description: The function configuration registers base
|
||||
- description: The link table configuration registers base
|
||||
- description: The cache configuration registers base
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: function
|
||||
- const: link
|
||||
- const: cache
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 4
|
||||
items:
|
||||
- description: The Video Decoder AXI interface clock
|
||||
- description: The Video Decoder AHB interface clock
|
||||
- description: The Video Decoded CABAC clock
|
||||
- description: The Video Decoder core clock
|
||||
- description: The Video decoder HEVC CABAC clock
|
||||
|
||||
clock-names:
|
||||
minItems: 4
|
||||
items:
|
||||
- const: axi
|
||||
- const: ahb
|
||||
- const: cabac
|
||||
- const: core
|
||||
- const: hevc_cabac
|
||||
|
||||
assigned-clocks: true
|
||||
|
||||
assigned-clock-rates: true
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: The Video Decoder AXI interface reset
|
||||
- description: The Video Decoder AHB interface reset
|
||||
- description: The Video Decoded CABAC reset
|
||||
- description: The Video Decoder core reset
|
||||
- description: The Video decoder HEVC CABAC reset
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: axi
|
||||
- const: ahb
|
||||
- const: cabac
|
||||
- const: core
|
||||
- const: hevc_cabac
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
iommus:
|
||||
maxItems: 1
|
||||
|
||||
sram:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: |
|
||||
phandle to a reserved on-chip SRAM regions.
|
||||
Some SoCs, like rk3588 provide on-chip SRAM to store temporary
|
||||
buffers during decoding.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
|
@ -61,6 +100,41 @@ required:
|
|||
- clock-names
|
||||
- power-domains
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- rockchip,rk3576-vdec
|
||||
- rockchip,rk3588-vdec
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
minItems: 3
|
||||
reg-names:
|
||||
minItems: 3
|
||||
clocks:
|
||||
minItems: 5
|
||||
clock-names:
|
||||
minItems: 5
|
||||
resets:
|
||||
minItems: 5
|
||||
reset-names:
|
||||
minItems: 5
|
||||
else:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 1
|
||||
reg-names: false
|
||||
clocks:
|
||||
maxItems: 4
|
||||
clock-names:
|
||||
maxItems: 4
|
||||
resets: false
|
||||
reset-names: false
|
||||
sram: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ For sub-device drivers:
|
|||
|
||||
v4l2_ctrl_handler_free(&foo->ctrl_handler);
|
||||
|
||||
:c:func:`v4l2_ctrl_handler_free` does not touch the handler's ``error`` field.
|
||||
|
||||
2) Add controls:
|
||||
|
||||
|
|
@ -191,12 +192,8 @@ These functions are typically called right after the
|
|||
V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0,
|
||||
0, test_pattern);
|
||||
...
|
||||
if (foo->ctrl_handler.error) {
|
||||
int err = foo->ctrl_handler.error;
|
||||
|
||||
v4l2_ctrl_handler_free(&foo->ctrl_handler);
|
||||
return err;
|
||||
}
|
||||
if (foo->ctrl_handler.error)
|
||||
return v4l2_ctrl_handler_free(&foo->ctrl_handler);
|
||||
|
||||
The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to
|
||||
the new control, but if you do not need to access the pointer outside the
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ error injection status::
|
|||
# <op> rx-clear clear all rx error injections for <op>
|
||||
# <op> tx-clear clear all tx error injections for <op>
|
||||
#
|
||||
# RX error injection settings:
|
||||
# rx-no-low-drive do not generate low-drive pulses
|
||||
#
|
||||
# RX error injection:
|
||||
# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK
|
||||
# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position
|
||||
|
|
@ -53,6 +56,10 @@ error injection status::
|
|||
# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse
|
||||
# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse
|
||||
# tx-custom-pulse transmit the custom pulse once the bus is idle
|
||||
# tx-glitch-low-usecs <usecs> define the 'low' time for the glitch pulse
|
||||
# tx-glitch-high-usecs <usecs> define the 'high' time for the glitch pulse
|
||||
# tx-glitch-falling-edge send the glitch pulse after every falling edge
|
||||
# tx-glitch-rising-edge send the glitch pulse after every rising edge
|
||||
#
|
||||
# TX error injection:
|
||||
# <op>[,<mode>] tx-no-eom don't set the EOM bit
|
||||
|
|
@ -193,6 +200,14 @@ Receive Messages
|
|||
This does not work if the remote CEC transmitter has logical address
|
||||
0 ('TV') since that will always win.
|
||||
|
||||
``rx-no-low-drive``
|
||||
The receiver will ignore situations that would normally generate a
|
||||
Low Drive pulse (3.6 ms). This is typically done if a spurious pulse is
|
||||
detected when receiving a message, and it indicates to the transmitter that
|
||||
the message has to be retransmitted since the receiver got confused.
|
||||
Disabling this is useful to test how other CEC devices handle glitches
|
||||
by ensuring we will not be the one that generates a Low Drive.
|
||||
|
||||
Transmit Messages
|
||||
-----------------
|
||||
|
||||
|
|
@ -327,3 +342,30 @@ Custom Pulses
|
|||
|
||||
``tx-custom-pulse``
|
||||
Transmit a single custom pulse as soon as the CEC bus is idle.
|
||||
|
||||
Glitch Pulses
|
||||
-------------
|
||||
|
||||
This emulates what happens if the signal on the CEC line is seeing spurious
|
||||
pulses. Typically this happens after the falling or rising edge where there
|
||||
is a short voltage fluctuation that, if the CEC hardware doesn't do
|
||||
deglitching, can be seen as a spurious pulse and can cause a Low Drive
|
||||
condition or corrupt data.
|
||||
|
||||
``tx-glitch-low-usecs <usecs>``
|
||||
This defines the duration in microseconds that the glitch pulse pulls
|
||||
the CEC line low. The default is 1 microsecond. The range is 0-100
|
||||
microseconds. If 0, then no glitch pulse will be generated.
|
||||
|
||||
``tx-glitch-high-usecs <usecs>``
|
||||
This defines the duration in microseconds that the glitch pulse keeps the
|
||||
CEC line high (unless another CEC adapter pulls it low in that time).
|
||||
The default is 1 microseconds. The range is 0-100 microseconds. If 0, then
|
||||
no glitch pulse will be generated.The total period of the glitch pulse is
|
||||
``tx-custom-low-usecs + tx-custom-high-usecs``.
|
||||
|
||||
``tx-glitch-falling-edge``
|
||||
Send the glitch pulse right after the falling edge.
|
||||
|
||||
``tx-glitch-rising-edge``
|
||||
Send the glitch pulse right after the rising edge.
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ ITU-T.81
|
|||
========
|
||||
|
||||
|
||||
:title: ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continous-Tone Still Images --- Requirements and Guidelines"
|
||||
:title: ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continuous-Tone Still Images --- Requirements and Guidelines"
|
||||
|
||||
:author: International Telecommunication Union (http://www.itu.int)
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ capabilities, and they may support :ref:`control` ioctls.
|
|||
The :ref:`video standard <standard>` ioctls provide information vital
|
||||
to program a sliced VBI device, therefore must be supported.
|
||||
|
||||
.. _sliced-vbi-format-negotitation:
|
||||
.. _sliced-vbi-format-negotiation:
|
||||
|
||||
Sliced VBI Format Negotiation
|
||||
=============================
|
||||
|
|
@ -377,7 +377,7 @@ Sliced VBI Data in MPEG Streams
|
|||
|
||||
If a device can produce an MPEG output stream, it may be capable of
|
||||
providing
|
||||
:ref:`negotiated sliced VBI services <sliced-vbi-format-negotitation>`
|
||||
:ref:`negotiated sliced VBI services <sliced-vbi-format-negotiation>`
|
||||
as data embedded in the MPEG stream. Users or applications control this
|
||||
sliced VBI data insertion with the
|
||||
:ref:`V4L2_CID_MPEG_STREAM_VBI_FMT <v4l2-mpeg-stream-vbi-fmt>`
|
||||
|
|
|
|||
|
|
@ -64,17 +64,12 @@ FM_RX Control IDs
|
|||
broadcasts speech. If the transmitter doesn't make this distinction,
|
||||
then it will be set.
|
||||
|
||||
``V4L2_CID_TUNE_DEEMPHASIS``
|
||||
(enum)
|
||||
|
||||
enum v4l2_deemphasis -
|
||||
``V4L2_CID_TUNE_DEEMPHASIS (enum)``
|
||||
Configures the de-emphasis value for reception. A de-emphasis filter
|
||||
is applied to the broadcast to accentuate the high audio
|
||||
frequencies. Depending on the region, a time constant of either 50
|
||||
or 75 useconds is used. The enum v4l2_deemphasis defines possible
|
||||
values for de-emphasis. Here they are:
|
||||
|
||||
|
||||
or 75 microseconds is used. The enum v4l2_deemphasis defines possible
|
||||
values for de-emphasis. They are:
|
||||
|
||||
.. flat-table::
|
||||
:header-rows: 0
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ FM_TX Control IDs
|
|||
|
||||
``V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (integer)``
|
||||
Sets the audio deviation limiter feature release time. Unit is in
|
||||
useconds. Step and range are driver-specific.
|
||||
microseconds. Step and range are driver-specific.
|
||||
|
||||
``V4L2_CID_AUDIO_LIMITER_DEVIATION (integer)``
|
||||
Configures audio frequency deviation level in Hz. The range and step
|
||||
|
|
@ -121,16 +121,16 @@ FM_TX Control IDs
|
|||
range and step are driver-specific.
|
||||
|
||||
``V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (integer)``
|
||||
Sets the threshold level for audio compression freature. It is a dB
|
||||
Sets the threshold level for audio compression feature. It is a dB
|
||||
value. The range and step are driver-specific.
|
||||
|
||||
``V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (integer)``
|
||||
Sets the attack time for audio compression feature. It is a useconds
|
||||
Sets the attack time for audio compression feature. It is a microseconds
|
||||
value. The range and step are driver-specific.
|
||||
|
||||
``V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (integer)``
|
||||
Sets the release time for audio compression feature. It is a
|
||||
useconds value. The range and step are driver-specific.
|
||||
microseconds value. The range and step are driver-specific.
|
||||
|
||||
``V4L2_CID_PILOT_TONE_ENABLED (boolean)``
|
||||
Enables or disables the pilot tone generation feature.
|
||||
|
|
@ -143,17 +143,12 @@ FM_TX Control IDs
|
|||
Configures pilot tone frequency value. Unit is in Hz. The range and
|
||||
step are driver-specific.
|
||||
|
||||
``V4L2_CID_TUNE_PREEMPHASIS``
|
||||
(enum)
|
||||
|
||||
enum v4l2_preemphasis -
|
||||
``V4L2_CID_TUNE_PREEMPHASIS (enum)``
|
||||
Configures the pre-emphasis value for broadcasting. A pre-emphasis
|
||||
filter is applied to the broadcast to accentuate the high audio
|
||||
frequencies. Depending on the region, a time constant of either 50
|
||||
or 75 useconds is used. The enum v4l2_preemphasis defines possible
|
||||
values for pre-emphasis. Here they are:
|
||||
|
||||
|
||||
or 75 microseconds is used. The enum v4l2_preemphasis defines possible
|
||||
values for pre-emphasis. They are:
|
||||
|
||||
.. flat-table::
|
||||
:header-rows: 0
|
||||
|
|
@ -166,8 +161,6 @@ enum v4l2_preemphasis -
|
|||
* - ``V4L2_PREEMPHASIS_75_uS``
|
||||
- A pre-emphasis of 75 uS is used.
|
||||
|
||||
|
||||
|
||||
``V4L2_CID_TUNE_POWER_LEVEL (integer)``
|
||||
Sets the output power level for signal transmission. Unit is in
|
||||
dBuV. Range and step are driver-specific.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ These formats are used for the :ref:`metadata` interface only.
|
|||
metafmt-pisp-fe
|
||||
metafmt-rkisp1
|
||||
metafmt-uvc
|
||||
metafmt-uvc-msxu-1-5
|
||||
metafmt-vivid
|
||||
metafmt-vsp1-hgo
|
||||
metafmt-vsp1-hgt
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
|
||||
|
||||
.. _v4l2-meta-fmt-uvc-msxu-1-5:
|
||||
|
||||
***********************************
|
||||
V4L2_META_FMT_UVC_MSXU_1_5 ('UVCM')
|
||||
***********************************
|
||||
|
||||
Microsoft(R)'s UVC Payload Metadata.
|
||||
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
V4L2_META_FMT_UVC_MSXU_1_5 buffers follow the metadata buffer layout of
|
||||
V4L2_META_FMT_UVC with the only difference that it includes all the UVC
|
||||
metadata in the `buffer[]` field, not just the first 2-12 bytes.
|
||||
|
||||
The metadata format follows the specification from Microsoft(R) [1].
|
||||
|
||||
.. _1:
|
||||
|
||||
[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5
|
||||
|
|
@ -44,7 +44,9 @@ Each individual block contains the following fields:
|
|||
them
|
||||
* - :cspan:`1` *The rest is an exact copy of the UVC payload header:*
|
||||
* - __u8 length;
|
||||
- length of the rest of the block, including this field
|
||||
- length of the rest of the block, including this field. Please note that
|
||||
regardless of this value, for V4L2_META_FMT_UVC the kernel will never
|
||||
copy more than 2-12 bytes.
|
||||
* - __u8 flags;
|
||||
- Flags, indicating presence of other standard UVC fields
|
||||
* - __u8 buf[];
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ orders. See also `the Wikipedia article on Bayer filter
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
pixfmt-rawnn-cru
|
||||
pixfmt-srggb8
|
||||
pixfmt-srggb8-pisp-comp
|
||||
pixfmt-srggb10
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
|
||||
|
||||
.. _v4l2-pix-fmt-raw-cru10:
|
||||
.. _v4l2-pix-fmt-raw-cru12:
|
||||
.. _v4l2-pix-fmt-raw-cru14:
|
||||
.. _v4l2-pix-fmt-raw-cru20:
|
||||
|
||||
**********************************************************************************************************************************
|
||||
V4L2_PIX_FMT_RAW_CRU10 ('CR10'), V4L2_PIX_FMT_RAW_CRU12 ('CR12'), V4L2_PIX_FMT_RAW_CRU14 ('CR14'), V4L2_PIX_FMT_RAW_CRU20 ('CR20')
|
||||
**********************************************************************************************************************************
|
||||
|
||||
===============================================================
|
||||
Renesas RZ/V2H Camera Receiver Unit 64-bit packed pixel formats
|
||||
===============================================================
|
||||
|
||||
| V4L2_PIX_FMT_RAW_CRU10 (CR10)
|
||||
| V4L2_PIX_FMT_RAW_CRU12 (CR12)
|
||||
| V4L2_PIX_FMT_RAW_CRU14 (CR14)
|
||||
| V4L2_PIX_FMT_RAW_CRU20 (CR20)
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
These pixel formats are some of the RAW outputs for the Camera Receiver Unit in
|
||||
the Renesas RZ/V2H SoC. They are raw formats which pack pixels contiguously into
|
||||
64-bit units, with the 4 or 8 most significant bits padded.
|
||||
|
||||
**Byte Order**
|
||||
|
||||
.. flat-table:: RAW formats
|
||||
:header-rows: 2
|
||||
:stub-columns: 0
|
||||
:widths: 36 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
|
||||
:fill-cells:
|
||||
|
||||
* - :rspan:`1` Pixel Format Code
|
||||
- :cspan:`63` Data organization
|
||||
* - 63
|
||||
- 62
|
||||
- 61
|
||||
- 60
|
||||
- 59
|
||||
- 58
|
||||
- 57
|
||||
- 56
|
||||
- 55
|
||||
- 54
|
||||
- 53
|
||||
- 52
|
||||
- 51
|
||||
- 50
|
||||
- 49
|
||||
- 48
|
||||
- 47
|
||||
- 46
|
||||
- 45
|
||||
- 44
|
||||
- 43
|
||||
- 42
|
||||
- 41
|
||||
- 40
|
||||
- 39
|
||||
- 38
|
||||
- 37
|
||||
- 36
|
||||
- 35
|
||||
- 34
|
||||
- 33
|
||||
- 32
|
||||
- 31
|
||||
- 30
|
||||
- 29
|
||||
- 28
|
||||
- 27
|
||||
- 26
|
||||
- 25
|
||||
- 24
|
||||
- 23
|
||||
- 22
|
||||
- 21
|
||||
- 20
|
||||
- 19
|
||||
- 18
|
||||
- 17
|
||||
- 16
|
||||
- 15
|
||||
- 14
|
||||
- 13
|
||||
- 12
|
||||
- 11
|
||||
- 10
|
||||
- 9
|
||||
- 8
|
||||
- 7
|
||||
- 6
|
||||
- 5
|
||||
- 4
|
||||
- 3
|
||||
- 2
|
||||
- 1
|
||||
- 0
|
||||
* - V4L2_PIX_FMT_RAW_CRU10
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- :cspan:`9` P5
|
||||
- :cspan:`9` P4
|
||||
- :cspan:`9` P3
|
||||
- :cspan:`9` P2
|
||||
- :cspan:`9` P1
|
||||
- :cspan:`9` P0
|
||||
* - V4L2_PIX_FMT_RAW_CRU12
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- :cspan:`11` P4
|
||||
- :cspan:`11` P3
|
||||
- :cspan:`11` P2
|
||||
- :cspan:`11` P1
|
||||
- :cspan:`11` P0
|
||||
* - V4L2_PIX_FMT_RAW_CRU14
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- :cspan:`13` P3
|
||||
- :cspan:`13` P2
|
||||
- :cspan:`13` P1
|
||||
- :cspan:`13` P0
|
||||
* - V4L2_PIX_FMT_RAW_CRU20
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- :cspan:`19` P2
|
||||
- :cspan:`19` P1
|
||||
- :cspan:`19` P0
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
.. _v4l2-pix-fmt-sgrbg12p:
|
||||
|
||||
*******************************************************************************************************************************
|
||||
V4L2_PIX_FMT_SRGGB12P ('pRCC'), V4L2_PIX_FMT_SGRBG12P ('pgCC'), V4L2_PIX_FMT_SGBRG12P ('pGCC'), V4L2_PIX_FMT_SBGGR12P ('pBCC'),
|
||||
V4L2_PIX_FMT_SRGGB12P ('pRCC'), V4L2_PIX_FMT_SGRBG12P ('pgCC'), V4L2_PIX_FMT_SGBRG12P ('pGCC'), V4L2_PIX_FMT_SBGGR12P ('pBCC')
|
||||
*******************************************************************************************************************************
|
||||
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ Description
|
|||
These four pixel formats are packed raw sRGB / Bayer formats with 12
|
||||
bits per colour. Every two consecutive samples are packed into three
|
||||
bytes. Each of the first two bytes contain the 8 high order bits of
|
||||
the pixels, and the third byte contains the four least significants
|
||||
the pixels, and the third byte contains the four least significant
|
||||
bits of each pixel, in the same order.
|
||||
|
||||
Each n-pixel row contains n/2 green samples and n/2 blue or red
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ These four pixel formats are packed raw sRGB / Bayer formats with 14
|
|||
bits per colour. Every four consecutive samples are packed into seven
|
||||
bytes. Each of the first four bytes contain the eight high order bits
|
||||
of the pixels, and the three following bytes contains the six least
|
||||
significants bits of each pixel, in the same order.
|
||||
significant bits of each pixel, in the same order.
|
||||
|
||||
Each n-pixel row contains n/2 green samples and n/2 blue or red samples,
|
||||
with alternating green-red and green-blue rows. They are conventionally
|
||||
|
|
|
|||
32
MAINTAINERS
32
MAINTAINERS
|
|
@ -824,7 +824,7 @@ F: drivers/media/platform/allegro-dvt/
|
|||
|
||||
ALLIED VISION ALVIUM CAMERA DRIVER
|
||||
M: Tommaso Merciai <tomm.merciai@gmail.com>
|
||||
M: Martin Hecht <martin.hecht@avnet.eu>
|
||||
M: Martin Hecht <mhecht73@gmail.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml
|
||||
|
|
@ -12397,6 +12397,15 @@ T: git git://linuxtv.org/media.git
|
|||
F: Documentation/admin-guide/media/ipu6-isys.rst
|
||||
F: drivers/media/pci/intel/ipu6/
|
||||
|
||||
INTEL IPU7 INPUT SYSTEM DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
R: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
F: drivers/staging/media/ipu7/
|
||||
|
||||
INTEL ISHTP ECLITE DRIVER
|
||||
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
|
|
@ -12684,6 +12693,16 @@ W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
|
|||
T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/
|
||||
F: drivers/net/wireless/intel/iwlwifi/
|
||||
|
||||
INTEL VISION SENSING CONTROLLER DRIVER
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
R: Bingbu Cao <bingbu.cao@intel.com>
|
||||
R: Lixu Zhang <lixu.zhang@intel.com>
|
||||
R: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://linuxtv.org/media.git
|
||||
F: drivers/media/pci/intel/ivsc/
|
||||
|
||||
INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
|
||||
S: Orphan
|
||||
W: https://slimbootloader.github.io/security/firmware-update.html
|
||||
|
|
@ -18134,6 +18153,7 @@ NXP i.MX 8M ISI DRIVER
|
|||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/fsl,imx8*-isi.yaml
|
||||
F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml
|
||||
F: drivers/media/platform/nxp/imx8-isi/
|
||||
|
||||
|
|
@ -20548,6 +20568,7 @@ QUALCOMM CAMERA SUBSYSTEM DRIVER
|
|||
M: Robert Foss <rfoss@kernel.org>
|
||||
M: Todor Tomov <todor.too@gmail.com>
|
||||
M: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
|
||||
R: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/admin-guide/media/qcom_camss.rst
|
||||
|
|
@ -21693,6 +21714,14 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/media/rockchip-rga.yaml
|
||||
F: drivers/media/platform/rockchip/rga/
|
||||
|
||||
ROCKCHIP RKVDEC VIDEO DECODER DRIVER
|
||||
M: Detlev Casanova <detlev.casanova@collabora.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
L: linux-rockchip@lists.infradead.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/media/rockchip,vdec.yaml
|
||||
F: drivers/media/platform/rockchip/rkvdec/
|
||||
|
||||
ROCKCHIP RK3308 INTERNAL AUDIO CODEC
|
||||
M: Luca Ceresoli <luca.ceresoli@bootlin.com>
|
||||
S: Maintained
|
||||
|
|
@ -26081,6 +26110,7 @@ S: Maintained
|
|||
W: http://www.ideasonboard.org/uvc/
|
||||
T: git git://linuxtv.org/media.git
|
||||
F: Documentation/userspace-api/media/drivers/uvcvideo.rst
|
||||
F: Documentation/userspace-api/media/v4l/metafmt-uvc-msxu-1-5.rst
|
||||
F: Documentation/userspace-api/media/v4l/metafmt-uvc.rst
|
||||
F: drivers/media/common/uvc.c
|
||||
F: drivers/media/usb/uvc/
|
||||
|
|
|
|||
|
|
@ -91,16 +91,22 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
|
|||
if (!strcmp(token, "clear")) {
|
||||
memset(pin->error_inj, 0, sizeof(pin->error_inj));
|
||||
pin->rx_toggle = pin->tx_toggle = false;
|
||||
pin->rx_no_low_drive = false;
|
||||
pin->tx_ignore_nack_until_eom = false;
|
||||
pin->tx_custom_pulse = false;
|
||||
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
pin->tx_glitch_falling_edge = false;
|
||||
pin->tx_glitch_rising_edge = false;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "rx-clear")) {
|
||||
for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++)
|
||||
pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK;
|
||||
pin->rx_toggle = false;
|
||||
pin->rx_no_low_drive = false;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-clear")) {
|
||||
|
|
@ -111,6 +117,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
|
|||
pin->tx_custom_pulse = false;
|
||||
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
pin->tx_glitch_falling_edge = false;
|
||||
pin->tx_glitch_rising_edge = false;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "rx-no-low-drive")) {
|
||||
pin->rx_no_low_drive = true;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-ignore-nack-until-eom")) {
|
||||
|
|
@ -122,6 +136,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
|
|||
cec_pin_start_timer(pin);
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-glitch-falling-edge")) {
|
||||
pin->tx_glitch_falling_edge = true;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-glitch-rising-edge")) {
|
||||
pin->tx_glitch_rising_edge = true;
|
||||
return true;
|
||||
}
|
||||
if (!p)
|
||||
return false;
|
||||
|
||||
|
|
@ -139,7 +161,23 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line)
|
|||
|
||||
if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
|
||||
return false;
|
||||
pin->tx_custom_high_usecs = usecs;
|
||||
pin->tx_glitch_high_usecs = usecs;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-glitch-low-usecs")) {
|
||||
u32 usecs;
|
||||
|
||||
if (kstrtou32(p, 0, &usecs) || usecs > 100)
|
||||
return false;
|
||||
pin->tx_glitch_low_usecs = usecs;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(token, "tx-glitch-high-usecs")) {
|
||||
u32 usecs;
|
||||
|
||||
if (kstrtou32(p, 0, &usecs) || usecs > 100)
|
||||
return false;
|
||||
pin->tx_glitch_high_usecs = usecs;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -273,6 +311,9 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
|
|||
seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n");
|
||||
seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# RX error injection settings:\n");
|
||||
seq_puts(sf, "# rx-no-low-drive do not generate low-drive pulses\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# RX error injection:\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n");
|
||||
|
|
@ -285,6 +326,10 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
|
|||
seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n");
|
||||
seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n");
|
||||
seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n");
|
||||
seq_puts(sf, "# tx-glitch-low-usecs <usecs> define the 'low' time for the glitch pulse\n");
|
||||
seq_puts(sf, "# tx-glitch-high-usecs <usecs> define the 'high' time for the glitch pulse\n");
|
||||
seq_puts(sf, "# tx-glitch-falling-edge send the glitch pulse after every falling edge\n");
|
||||
seq_puts(sf, "# tx-glitch-rising-edge send the glitch pulse after every rising edge\n");
|
||||
seq_puts(sf, "#\n");
|
||||
seq_puts(sf, "# TX error injection:\n");
|
||||
seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n");
|
||||
|
|
@ -332,8 +377,14 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
|
|||
}
|
||||
}
|
||||
|
||||
if (pin->rx_no_low_drive)
|
||||
seq_puts(sf, "rx-no-low-drive\n");
|
||||
if (pin->tx_ignore_nack_until_eom)
|
||||
seq_puts(sf, "tx-ignore-nack-until-eom\n");
|
||||
if (pin->tx_glitch_falling_edge)
|
||||
seq_puts(sf, "tx-glitch-falling-edge\n");
|
||||
if (pin->tx_glitch_rising_edge)
|
||||
seq_puts(sf, "tx-glitch-rising-edge\n");
|
||||
if (pin->tx_custom_pulse)
|
||||
seq_puts(sf, "tx-custom-pulse\n");
|
||||
if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT)
|
||||
|
|
@ -342,5 +393,11 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf)
|
|||
if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT)
|
||||
seq_printf(sf, "tx-custom-high-usecs %u\n",
|
||||
pin->tx_custom_high_usecs);
|
||||
if (pin->tx_glitch_low_usecs != CEC_TIM_GLITCH_DEFAULT)
|
||||
seq_printf(sf, "tx-glitch-low-usecs %u\n",
|
||||
pin->tx_glitch_low_usecs);
|
||||
if (pin->tx_glitch_high_usecs != CEC_TIM_GLITCH_DEFAULT)
|
||||
seq_printf(sf, "tx-glitch-high-usecs %u\n",
|
||||
pin->tx_glitch_high_usecs);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -164,6 +164,9 @@ enum cec_pin_state {
|
|||
/* The default for the low/high time of the custom pulse */
|
||||
#define CEC_TIM_CUSTOM_DEFAULT 1000
|
||||
|
||||
/* The default for the low/high time of the glitch pulse */
|
||||
#define CEC_TIM_GLITCH_DEFAULT 1
|
||||
|
||||
#define CEC_NUM_PIN_EVENTS 128
|
||||
#define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0)
|
||||
#define CEC_PIN_EVENT_FL_DROPPED (1 << 1)
|
||||
|
|
@ -225,12 +228,17 @@ struct cec_pin {
|
|||
u32 timer_max_overrun;
|
||||
u32 timer_sum_overrun;
|
||||
|
||||
bool rx_no_low_drive;
|
||||
u32 tx_custom_low_usecs;
|
||||
u32 tx_custom_high_usecs;
|
||||
u32 tx_glitch_low_usecs;
|
||||
u32 tx_glitch_high_usecs;
|
||||
bool tx_ignore_nack_until_eom;
|
||||
bool tx_custom_pulse;
|
||||
bool tx_generated_poll;
|
||||
bool tx_post_eom;
|
||||
bool tx_glitch_falling_edge;
|
||||
bool tx_glitch_rising_edge;
|
||||
u8 tx_extra_bytes;
|
||||
u32 tx_low_drive_cnt;
|
||||
#ifdef CONFIG_CEC_PIN_ERROR_INJ
|
||||
|
|
|
|||
|
|
@ -142,15 +142,42 @@ static bool cec_pin_read(struct cec_pin *pin)
|
|||
return v;
|
||||
}
|
||||
|
||||
static void cec_pin_insert_glitch(struct cec_pin *pin, bool rising_edge)
|
||||
{
|
||||
/*
|
||||
* Insert a short glitch after the falling or rising edge to
|
||||
* simulate reflections on the CEC line. This can be used to
|
||||
* test deglitch filters, which should be present in CEC devices
|
||||
* to deal with noise on the line.
|
||||
*/
|
||||
if (!pin->tx_glitch_high_usecs || !pin->tx_glitch_low_usecs)
|
||||
return;
|
||||
if (rising_edge) {
|
||||
udelay(pin->tx_glitch_high_usecs);
|
||||
call_void_pin_op(pin, low);
|
||||
udelay(pin->tx_glitch_low_usecs);
|
||||
call_void_pin_op(pin, high);
|
||||
} else {
|
||||
udelay(pin->tx_glitch_low_usecs);
|
||||
call_void_pin_op(pin, high);
|
||||
udelay(pin->tx_glitch_high_usecs);
|
||||
call_void_pin_op(pin, low);
|
||||
}
|
||||
}
|
||||
|
||||
static void cec_pin_low(struct cec_pin *pin)
|
||||
{
|
||||
call_void_pin_op(pin, low);
|
||||
if (pin->tx_glitch_falling_edge && pin->adap->cec_pin_is_high)
|
||||
cec_pin_insert_glitch(pin, false);
|
||||
cec_pin_update(pin, false, false);
|
||||
}
|
||||
|
||||
static bool cec_pin_high(struct cec_pin *pin)
|
||||
{
|
||||
call_void_pin_op(pin, high);
|
||||
if (pin->tx_glitch_rising_edge && !pin->adap->cec_pin_is_high)
|
||||
cec_pin_insert_glitch(pin, true);
|
||||
return cec_pin_read(pin);
|
||||
}
|
||||
|
||||
|
|
@ -770,7 +797,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
|
|||
* Go to low drive state when the total bit time is
|
||||
* too short.
|
||||
*/
|
||||
if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) {
|
||||
if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN && !pin->rx_no_low_drive) {
|
||||
if (!pin->rx_data_bit_too_short_cnt++) {
|
||||
pin->rx_data_bit_too_short_ts = ktime_to_ns(pin->ts);
|
||||
pin->rx_data_bit_too_short_delta = delta;
|
||||
|
|
@ -1350,6 +1377,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
|
|||
init_waitqueue_head(&pin->kthread_waitq);
|
||||
pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
|
||||
pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
|
||||
|
||||
adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name,
|
||||
caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN,
|
||||
|
|
|
|||
|
|
@ -61,49 +61,51 @@ static void cec_gpio_low(struct cec_adapter *adap)
|
|||
gpiod_set_value(cec->cec_gpio, 0);
|
||||
}
|
||||
|
||||
static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv)
|
||||
static irqreturn_t cec_gpio_5v_irq_handler_thread(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
|
||||
cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_5v_gpio_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
int val = gpiod_get_value(cec->v5_gpio);
|
||||
int val = gpiod_get_value_cansleep(cec->v5_gpio);
|
||||
bool is_high = val > 0;
|
||||
|
||||
if (val < 0 || is_high == cec->v5_is_high)
|
||||
return IRQ_HANDLED;
|
||||
cec->v5_ts = ktime_get();
|
||||
|
||||
cec->v5_is_high = is_high;
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_5v_gpio_irq_handler_thread(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
|
||||
cec_queue_pin_5v_event(cec->adap, cec->v5_is_high, cec->v5_ts);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv)
|
||||
static irqreturn_t cec_gpio_5v_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
int val = gpiod_get_value(cec->hpd_gpio);
|
||||
|
||||
cec->v5_ts = ktime_get();
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_gpio_hpd_irq_handler_thread(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
int val = gpiod_get_value_cansleep(cec->hpd_gpio);
|
||||
bool is_high = val > 0;
|
||||
|
||||
if (val < 0 || is_high == cec->hpd_is_high)
|
||||
return IRQ_HANDLED;
|
||||
cec->hpd_ts = ktime_get();
|
||||
|
||||
cec->hpd_is_high = is_high;
|
||||
cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_gpio_hpd_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
|
||||
cec->hpd_ts = ktime_get();
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t cec_gpio_irq_handler(int irq, void *priv)
|
||||
static irqreturn_t cec_gpio_cec_irq_handler(int irq, void *priv)
|
||||
{
|
||||
struct cec_gpio *cec = priv;
|
||||
int val = gpiod_get_value(cec->cec_gpio);
|
||||
|
|
@ -113,7 +115,7 @@ static irqreturn_t cec_gpio_irq_handler(int irq, void *priv)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static bool cec_gpio_enable_irq(struct cec_adapter *adap)
|
||||
static bool cec_gpio_cec_enable_irq(struct cec_adapter *adap)
|
||||
{
|
||||
struct cec_gpio *cec = cec_get_drvdata(adap);
|
||||
|
||||
|
|
@ -121,7 +123,7 @@ static bool cec_gpio_enable_irq(struct cec_adapter *adap)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void cec_gpio_disable_irq(struct cec_adapter *adap)
|
||||
static void cec_gpio_cec_disable_irq(struct cec_adapter *adap)
|
||||
{
|
||||
struct cec_gpio *cec = cec_get_drvdata(adap);
|
||||
|
||||
|
|
@ -148,7 +150,7 @@ static int cec_gpio_read_hpd(struct cec_adapter *adap)
|
|||
|
||||
if (!cec->hpd_gpio)
|
||||
return -ENOTTY;
|
||||
return gpiod_get_value(cec->hpd_gpio);
|
||||
return gpiod_get_value_cansleep(cec->hpd_gpio);
|
||||
}
|
||||
|
||||
static int cec_gpio_read_5v(struct cec_adapter *adap)
|
||||
|
|
@ -157,15 +159,15 @@ static int cec_gpio_read_5v(struct cec_adapter *adap)
|
|||
|
||||
if (!cec->v5_gpio)
|
||||
return -ENOTTY;
|
||||
return gpiod_get_value(cec->v5_gpio);
|
||||
return gpiod_get_value_cansleep(cec->v5_gpio);
|
||||
}
|
||||
|
||||
static const struct cec_pin_ops cec_gpio_pin_ops = {
|
||||
.read = cec_gpio_read,
|
||||
.low = cec_gpio_low,
|
||||
.high = cec_gpio_high,
|
||||
.enable_irq = cec_gpio_enable_irq,
|
||||
.disable_irq = cec_gpio_disable_irq,
|
||||
.enable_irq = cec_gpio_cec_enable_irq,
|
||||
.disable_irq = cec_gpio_cec_disable_irq,
|
||||
.status = cec_gpio_status,
|
||||
.read_hpd = cec_gpio_read_hpd,
|
||||
.read_5v = cec_gpio_read_5v,
|
||||
|
|
@ -209,7 +211,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(cec->adap))
|
||||
return PTR_ERR(cec->adap);
|
||||
|
||||
ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler,
|
||||
ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_cec_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
|
||||
cec->adap->name, cec);
|
||||
if (ret)
|
||||
|
|
@ -218,8 +220,8 @@ static int cec_gpio_probe(struct platform_device *pdev)
|
|||
if (cec->hpd_gpio) {
|
||||
cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio);
|
||||
ret = devm_request_threaded_irq(dev, cec->hpd_irq,
|
||||
cec_hpd_gpio_irq_handler,
|
||||
cec_hpd_gpio_irq_handler_thread,
|
||||
cec_gpio_hpd_irq_handler,
|
||||
cec_gpio_hpd_irq_handler_thread,
|
||||
IRQF_ONESHOT |
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"hpd-gpio", cec);
|
||||
|
|
@ -230,8 +232,8 @@ static int cec_gpio_probe(struct platform_device *pdev)
|
|||
if (cec->v5_gpio) {
|
||||
cec->v5_irq = gpiod_to_irq(cec->v5_gpio);
|
||||
ret = devm_request_threaded_irq(dev, cec->v5_irq,
|
||||
cec_5v_gpio_irq_handler,
|
||||
cec_5v_gpio_irq_handler_thread,
|
||||
cec_gpio_5v_irq_handler,
|
||||
cec_gpio_5v_irq_handler_thread,
|
||||
IRQF_ONESHOT |
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"v5-gpio", cec);
|
||||
|
|
|
|||
|
|
@ -171,11 +171,12 @@ static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data,
|
|||
{
|
||||
struct rain *rain = serio_get_drvdata(serio);
|
||||
|
||||
spin_lock(&rain->buf_lock);
|
||||
if (rain->buf_len == DATA_SIZE) {
|
||||
spin_unlock(&rain->buf_lock);
|
||||
dev_warn_once(rain->dev, "buffer overflow\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
spin_lock(&rain->buf_lock);
|
||||
rain->buf_len++;
|
||||
rain->buf[rain->buf_wr_idx] = data;
|
||||
rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff;
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
|
|||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm flexcop_algo = {
|
||||
static const struct i2c_algorithm flexcop_algo = {
|
||||
.master_xfer = flexcop_master_xfer,
|
||||
.functionality = flexcop_i2c_func,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -433,7 +433,7 @@ static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr,
|
|||
return cxd2820r_gpio(&priv->fe, gpio);
|
||||
}
|
||||
|
||||
static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
|
||||
static int cxd2820r_gpio_set(struct gpio_chip *chip, unsigned int nr, int val)
|
||||
{
|
||||
struct cxd2820r_priv *priv = gpiochip_get_data(chip);
|
||||
struct i2c_client *client = priv->client[0];
|
||||
|
|
@ -446,7 +446,7 @@ static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
|
|||
|
||||
(void) cxd2820r_gpio(&priv->fe, gpio);
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr)
|
||||
|
|
@ -651,7 +651,7 @@ static int cxd2820r_probe(struct i2c_client *client)
|
|||
priv->gpio_chip.parent = &client->dev;
|
||||
priv->gpio_chip.owner = THIS_MODULE;
|
||||
priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output;
|
||||
priv->gpio_chip.set = cxd2820r_gpio_set;
|
||||
priv->gpio_chip.set_rv = cxd2820r_gpio_set;
|
||||
priv->gpio_chip.get = cxd2820r_gpio_get;
|
||||
priv->gpio_chip.base = -1; /* Dynamic allocation */
|
||||
priv->gpio_chip.ngpio = GPIO_COUNT;
|
||||
|
|
|
|||
|
|
@ -2193,6 +2193,8 @@ static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_ms
|
|||
struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
|
||||
u8 n_overflow = 1;
|
||||
u16 i = 1000;
|
||||
if (msg[0].len < 3)
|
||||
return -EOPNOTSUPP;
|
||||
u16 serpar_num = msg[0].buf[0];
|
||||
|
||||
while (n_overflow == 1 && i) {
|
||||
|
|
@ -2212,6 +2214,8 @@ static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg
|
|||
struct dib7000p_state *state = i2c_get_adapdata(i2c_adap);
|
||||
u8 n_overflow = 1, n_empty = 1;
|
||||
u16 i = 1000;
|
||||
if (msg[0].len < 1 || msg[1].len < 2)
|
||||
return -EOPNOTSUPP;
|
||||
u16 serpar_num = msg[0].buf[0];
|
||||
u16 read_word;
|
||||
|
||||
|
|
@ -2256,8 +2260,12 @@ static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap,
|
|||
u16 word;
|
||||
|
||||
if (num == 1) { /* write */
|
||||
if (msg[0].len < 3)
|
||||
return -EOPNOTSUPP;
|
||||
dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2])));
|
||||
} else {
|
||||
if (msg[1].len < 2)
|
||||
return -EOPNOTSUPP;
|
||||
word = dib7000p_read_word(state, apb_address);
|
||||
msg[1].buf[0] = (word >> 8) & 0xff;
|
||||
msg[1].buf[1] = (word) & 0xff;
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ config VIDEO_IMX214
|
|||
depends on GPIOLIB
|
||||
select REGMAP_I2C
|
||||
select V4L2_CCI_I2C
|
||||
select VIDEO_CCS_PLL
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX214 camera.
|
||||
|
|
@ -765,24 +766,25 @@ config VIDEO_THP7312
|
|||
|
||||
endmenu
|
||||
|
||||
menu "Lens drivers"
|
||||
visible if MEDIA_CAMERA_SUPPORT
|
||||
menuconfig VIDEO_CAMERA_LENS
|
||||
bool "Lens drivers"
|
||||
depends on MEDIA_CAMERA_SUPPORT && I2C
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_FWNODE
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
default y
|
||||
|
||||
if VIDEO_CAMERA_LENS
|
||||
|
||||
config VIDEO_AD5820
|
||||
tristate "AD5820 lens voice coil support"
|
||||
depends on GPIOLIB && I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select V4L2_ASYNC
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This is a driver for the AD5820 camera lens voice coil.
|
||||
It is used for example in Nokia N900 (RX-51).
|
||||
|
||||
config VIDEO_AK7375
|
||||
tristate "AK7375 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_ASYNC
|
||||
help
|
||||
This is a driver for the AK7375 camera lens voice coil.
|
||||
AK7375 is a 12 bit DAC with 120mA output current sink
|
||||
|
|
@ -791,10 +793,7 @@ config VIDEO_AK7375
|
|||
|
||||
config VIDEO_DW9714
|
||||
tristate "DW9714 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_ASYNC
|
||||
depends on GPIOLIB
|
||||
help
|
||||
This is a driver for the DW9714 camera lens voice coil.
|
||||
DW9714 is a 10 bit DAC with 120mA output current sink
|
||||
|
|
@ -803,10 +802,6 @@ config VIDEO_DW9714
|
|||
|
||||
config VIDEO_DW9719
|
||||
tristate "DW9719 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_ASYNC
|
||||
select V4L2_CCI_I2C
|
||||
help
|
||||
This is a driver for the DW9719 camera lens voice coil.
|
||||
|
|
@ -815,10 +810,6 @@ config VIDEO_DW9719
|
|||
|
||||
config VIDEO_DW9768
|
||||
tristate "DW9768 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This is a driver for the DW9768 camera lens voice coil.
|
||||
DW9768 is a 10 bit DAC with 100mA output current sink
|
||||
|
|
@ -827,17 +818,13 @@ config VIDEO_DW9768
|
|||
|
||||
config VIDEO_DW9807_VCM
|
||||
tristate "DW9807 lens voice coil support"
|
||||
depends on I2C && VIDEO_DEV
|
||||
select MEDIA_CONTROLLER
|
||||
select VIDEO_V4L2_SUBDEV_API
|
||||
select V4L2_ASYNC
|
||||
help
|
||||
This is a driver for the DW9807 camera lens voice coil.
|
||||
DW9807 is a 10 bit DAC with 100mA output current sink
|
||||
capability. This is designed for linear control of
|
||||
voice coil motors, controlled via I2C serial interface.
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
menu "Flash devices"
|
||||
visible if MEDIA_CAMERA_SUPPORT
|
||||
|
|
@ -1684,7 +1671,7 @@ config VIDEO_MAX96714
|
|||
|
||||
config VIDEO_MAX96717
|
||||
tristate "Maxim MAX96717 GMSL2 Serializer support"
|
||||
depends on OF && I2C && VIDEO_DEV && COMMON_CLK
|
||||
depends on I2C && VIDEO_DEV && COMMON_CLK
|
||||
select I2C_MUX
|
||||
select MEDIA_CONTROLLER
|
||||
select GPIOLIB
|
||||
|
|
|
|||
|
|
@ -868,21 +868,6 @@ static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
if (state->curr_norm & V4L2_STD_525_60) {
|
||||
aspect->numerator = 11;
|
||||
aspect->denominator = 10;
|
||||
} else {
|
||||
aspect->numerator = 54;
|
||||
aspect->denominator = 59;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
|
||||
{
|
||||
*norm = V4L2_STD_ALL;
|
||||
|
|
@ -929,7 +914,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
|||
.querystd = adv7180_querystd,
|
||||
.g_input_status = adv7180_g_input_status,
|
||||
.s_routing = adv7180_s_routing,
|
||||
.g_pixelaspect = adv7180_g_pixelaspect,
|
||||
.g_tvnorms = adv7180_g_tvnorms,
|
||||
.s_stream = adv7180_s_stream,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -161,22 +161,6 @@ int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input)
|
|||
return sdp_write(state, ADV748X_SDP_INSEL, input);
|
||||
}
|
||||
|
||||
static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd,
|
||||
struct v4l2_fract *aspect)
|
||||
{
|
||||
struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
|
||||
|
||||
if (afe->curr_norm & V4L2_STD_525_60) {
|
||||
aspect->numerator = 11;
|
||||
aspect->denominator = 10;
|
||||
} else {
|
||||
aspect->numerator = 54;
|
||||
aspect->denominator = 59;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* v4l2_subdev_video_ops
|
||||
*/
|
||||
|
|
@ -307,7 +291,6 @@ static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = {
|
|||
.g_tvnorms = adv748x_afe_g_tvnorms,
|
||||
.g_input_status = adv748x_afe_g_input_status,
|
||||
.s_stream = adv748x_afe_s_stream,
|
||||
.g_pixelaspect = adv748x_afe_g_pixelaspect,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -382,19 +382,9 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd,
|
||||
struct v4l2_fract *aspect)
|
||||
{
|
||||
aspect->numerator = 1;
|
||||
aspect->denominator = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = {
|
||||
.g_input_status = adv748x_hdmi_g_input_status,
|
||||
.s_stream = adv748x_hdmi_s_stream,
|
||||
.g_pixelaspect = adv748x_hdmi_g_pixelaspect,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2448,8 +2448,8 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
|||
}
|
||||
cec_s_phys_addr(state->cec_adap, parent_pa, false);
|
||||
|
||||
/* enable hotplug after 100 ms */
|
||||
schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10);
|
||||
/* enable hotplug after 143 ms */
|
||||
schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 7);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -203,9 +203,9 @@ static int ub913_gpio_direction_out(struct gpio_chip *gc, unsigned int offset,
|
|||
0));
|
||||
}
|
||||
|
||||
static void ub913_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
static int ub913_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
ub913_gpio_direction_out(gc, offset, value);
|
||||
return ub913_gpio_direction_out(gc, offset, value);
|
||||
}
|
||||
|
||||
static int ub913_gpio_of_xlate(struct gpio_chip *gc,
|
||||
|
|
@ -235,7 +235,7 @@ static int ub913_gpiochip_probe(struct ub913_data *priv)
|
|||
gc->ngpio = UB913_NUM_GPIOS;
|
||||
gc->get_direction = ub913_gpio_get_direction;
|
||||
gc->direction_output = ub913_gpio_direction_out;
|
||||
gc->set = ub913_gpio_set;
|
||||
gc->set_rv = ub913_gpio_set;
|
||||
gc->of_xlate = ub913_gpio_of_xlate;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
|
|
@ -337,14 +337,6 @@ static int _ub913_set_routing(struct v4l2_subdev *sd,
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
|
||||
* frame desc is made dynamically allocated.
|
||||
*/
|
||||
|
||||
if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -317,14 +317,13 @@ static int ub953_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
|||
return !!(v & UB953_REG_GPIO_PIN_STS_GPIO_STS(offset));
|
||||
}
|
||||
|
||||
static void ub953_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
static int ub953_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
struct ub953_data *priv = gpiochip_get_data(gc);
|
||||
|
||||
regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA,
|
||||
UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset),
|
||||
value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) :
|
||||
0);
|
||||
return regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA,
|
||||
UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset),
|
||||
value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : 0);
|
||||
}
|
||||
|
||||
static int ub953_gpio_of_xlate(struct gpio_chip *gc,
|
||||
|
|
@ -362,7 +361,7 @@ static int ub953_gpiochip_probe(struct ub953_data *priv)
|
|||
gc->direction_input = ub953_gpio_direction_in;
|
||||
gc->direction_output = ub953_gpio_direction_out;
|
||||
gc->get = ub953_gpio_get;
|
||||
gc->set = ub953_gpio_set;
|
||||
gc->set_rv = ub953_gpio_set;
|
||||
gc->of_xlate = ub953_gpio_of_xlate;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
|
|
@ -400,14 +399,6 @@ static int _ub953_set_routing(struct v4l2_subdev *sd,
|
|||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
|
||||
* frame desc is made dynamically allocated.
|
||||
*/
|
||||
|
||||
if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -3861,14 +3861,6 @@ static int _ub960_set_routing(struct v4l2_subdev *sd,
|
|||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
|
||||
* frame desc is made dynamically allocated.
|
||||
*/
|
||||
|
||||
if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 |
|
||||
V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Copyright (c) 2015--2017 Intel Corporation.
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
|
@ -38,6 +39,7 @@ struct dw9714_device {
|
|||
struct v4l2_subdev sd;
|
||||
u16 current_val;
|
||||
struct regulator *vcc;
|
||||
struct gpio_desc *powerdown_gpio;
|
||||
};
|
||||
|
||||
static inline struct dw9714_device *to_dw9714_vcm(struct v4l2_ctrl *ctrl)
|
||||
|
|
@ -137,6 +139,28 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm)
|
|||
return hdl->error;
|
||||
}
|
||||
|
||||
static int dw9714_power_up(struct dw9714_device *dw9714_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regulator_enable(dw9714_dev->vcc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpiod_set_value_cansleep(dw9714_dev->powerdown_gpio, 0);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw9714_power_down(struct dw9714_device *dw9714_dev)
|
||||
{
|
||||
gpiod_set_value_cansleep(dw9714_dev->powerdown_gpio, 1);
|
||||
|
||||
return regulator_disable(dw9714_dev->vcc);
|
||||
}
|
||||
|
||||
static int dw9714_probe(struct i2c_client *client)
|
||||
{
|
||||
struct dw9714_device *dw9714_dev;
|
||||
|
|
@ -144,20 +168,25 @@ static int dw9714_probe(struct i2c_client *client)
|
|||
|
||||
dw9714_dev = devm_kzalloc(&client->dev, sizeof(*dw9714_dev),
|
||||
GFP_KERNEL);
|
||||
if (dw9714_dev == NULL)
|
||||
if (!dw9714_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dw9714_dev->vcc = devm_regulator_get(&client->dev, "vcc");
|
||||
if (IS_ERR(dw9714_dev->vcc))
|
||||
return PTR_ERR(dw9714_dev->vcc);
|
||||
|
||||
rval = regulator_enable(dw9714_dev->vcc);
|
||||
if (rval < 0) {
|
||||
dev_err(&client->dev, "failed to enable vcc: %d\n", rval);
|
||||
return rval;
|
||||
}
|
||||
dw9714_dev->powerdown_gpio = devm_gpiod_get_optional(&client->dev,
|
||||
"powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(dw9714_dev->powerdown_gpio))
|
||||
return dev_err_probe(&client->dev,
|
||||
PTR_ERR(dw9714_dev->powerdown_gpio),
|
||||
"could not get powerdown gpio\n");
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
rval = dw9714_power_up(dw9714_dev);
|
||||
if (rval)
|
||||
return dev_err_probe(&client->dev, rval,
|
||||
"failed to power up: %d\n", rval);
|
||||
|
||||
v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops);
|
||||
dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
|
|
@ -185,7 +214,7 @@ static int dw9714_probe(struct i2c_client *client)
|
|||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
regulator_disable(dw9714_dev->vcc);
|
||||
dw9714_power_down(dw9714_dev);
|
||||
v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm);
|
||||
media_entity_cleanup(&dw9714_dev->sd.entity);
|
||||
|
||||
|
|
@ -200,10 +229,10 @@ static void dw9714_remove(struct i2c_client *client)
|
|||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev)) {
|
||||
ret = regulator_disable(dw9714_dev->vcc);
|
||||
ret = dw9714_power_down(dw9714_dev);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to disable vcc: %d\n", ret);
|
||||
"Failed to power down: %d\n", ret);
|
||||
}
|
||||
}
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
|
|
@ -234,9 +263,9 @@ static int __maybe_unused dw9714_vcm_suspend(struct device *dev)
|
|||
usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10);
|
||||
}
|
||||
|
||||
ret = regulator_disable(dw9714_dev->vcc);
|
||||
ret = dw9714_power_down(dw9714_dev);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to disable vcc: %d\n", ret);
|
||||
dev_err(dev, "Failed to power down: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -247,7 +276,7 @@ static int __maybe_unused dw9714_vcm_suspend(struct device *dev)
|
|||
* The lens position is gradually moved in units of DW9714_CTRL_STEPS,
|
||||
* to make the movements smoothly.
|
||||
*/
|
||||
static int __maybe_unused dw9714_vcm_resume(struct device *dev)
|
||||
static int __maybe_unused dw9714_vcm_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct v4l2_subdev *sd = i2c_get_clientdata(client);
|
||||
|
|
@ -257,12 +286,11 @@ static int __maybe_unused dw9714_vcm_resume(struct device *dev)
|
|||
if (pm_runtime_suspended(&client->dev))
|
||||
return 0;
|
||||
|
||||
ret = regulator_enable(dw9714_dev->vcc);
|
||||
ret = dw9714_power_up(dw9714_dev);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable vcc: %d\n", ret);
|
||||
dev_err(dev, "Failed to power up: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
for (val = dw9714_dev->current_val % DW9714_CTRL_STEPS;
|
||||
val < dw9714_dev->current_val + DW9714_CTRL_STEPS - 1;
|
||||
|
|
@ -271,7 +299,7 @@ static int __maybe_unused dw9714_vcm_resume(struct device *dev)
|
|||
DW9714_VAL(val, DW9714_DEFAULT_S));
|
||||
if (ret)
|
||||
dev_err_ratelimited(dev, "%s I2C failure: %d",
|
||||
__func__, ret);
|
||||
__func__, ret);
|
||||
usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -624,6 +624,12 @@ static const struct hi556_mode supported_modes[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const char * const hi556_supply_names[] = {
|
||||
"dovdd", /* Digital I/O power */
|
||||
"avdd", /* Analog power */
|
||||
"dvdd", /* Digital core power */
|
||||
};
|
||||
|
||||
struct hi556 {
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
|
@ -639,7 +645,7 @@ struct hi556 {
|
|||
/* GPIOs, clocks, etc. */
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct clk *clk;
|
||||
struct regulator *avdd;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(hi556_supply_names)];
|
||||
|
||||
/* Current mode */
|
||||
const struct hi556_mode *cur_mode;
|
||||
|
|
@ -756,21 +762,23 @@ static int hi556_test_pattern(struct hi556 *hi556, u32 pattern)
|
|||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pattern) {
|
||||
ret = hi556_read_reg(hi556, HI556_REG_ISP,
|
||||
HI556_REG_VALUE_08BIT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = hi556_read_reg(hi556, HI556_REG_ISP,
|
||||
HI556_REG_VALUE_08BIT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hi556_write_reg(hi556, HI556_REG_ISP,
|
||||
HI556_REG_VALUE_08BIT,
|
||||
val | HI556_REG_ISP_TPG_EN);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
val = pattern ? (val | HI556_REG_ISP_TPG_EN) :
|
||||
(val & ~HI556_REG_ISP_TPG_EN);
|
||||
|
||||
ret = hi556_write_reg(hi556, HI556_REG_ISP,
|
||||
HI556_REG_VALUE_08BIT, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = pattern ? BIT(pattern - 1) : 0;
|
||||
|
||||
return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN,
|
||||
HI556_REG_VALUE_08BIT, pattern);
|
||||
HI556_REG_VALUE_08BIT, val);
|
||||
}
|
||||
|
||||
static int hi556_set_ctrl(struct v4l2_ctrl *ctrl)
|
||||
|
|
@ -1289,17 +1297,10 @@ static int hi556_suspend(struct device *dev)
|
|||
{
|
||||
struct v4l2_subdev *sd = dev_get_drvdata(dev);
|
||||
struct hi556 *hi556 = to_hi556(sd);
|
||||
int ret;
|
||||
|
||||
gpiod_set_value_cansleep(hi556->reset_gpio, 1);
|
||||
|
||||
ret = regulator_disable(hi556->avdd);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to disable avdd: %d\n", ret);
|
||||
gpiod_set_value_cansleep(hi556->reset_gpio, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(hi556_supply_names),
|
||||
hi556->supplies);
|
||||
clk_disable_unprepare(hi556->clk);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1314,14 +1315,20 @@ static int hi556_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regulator_enable(hi556->avdd);
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(hi556_supply_names),
|
||||
hi556->supplies);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable avdd: %d\n", ret);
|
||||
dev_err(dev, "failed to enable regulators: %d", ret);
|
||||
clk_disable_unprepare(hi556->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(hi556->reset_gpio, 0);
|
||||
if (hi556->reset_gpio) {
|
||||
/* Assert reset for at least 2ms on back to back off-on */
|
||||
usleep_range(2000, 2200);
|
||||
gpiod_set_value_cansleep(hi556->reset_gpio, 0);
|
||||
}
|
||||
|
||||
usleep_range(5000, 5500);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1330,7 +1337,7 @@ static int hi556_probe(struct i2c_client *client)
|
|||
{
|
||||
struct hi556 *hi556;
|
||||
bool full_power;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
ret = hi556_check_hwcfg(&client->dev);
|
||||
if (ret)
|
||||
|
|
@ -1353,11 +1360,15 @@ static int hi556_probe(struct i2c_client *client)
|
|||
return dev_err_probe(&client->dev, PTR_ERR(hi556->clk),
|
||||
"failed to get clock\n");
|
||||
|
||||
/* The regulator core will provide a "dummy" regulator if necessary */
|
||||
hi556->avdd = devm_regulator_get(&client->dev, "avdd");
|
||||
if (IS_ERR(hi556->avdd))
|
||||
return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd),
|
||||
"failed to get avdd regulator\n");
|
||||
for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++)
|
||||
hi556->supplies[i].supply = hi556_supply_names[i];
|
||||
|
||||
ret = devm_regulator_bulk_get(&client->dev,
|
||||
ARRAY_SIZE(hi556_supply_names),
|
||||
hi556->supplies);
|
||||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret,
|
||||
"failed to get regulators\n");
|
||||
|
||||
full_power = acpi_dev_state_d0(&client->dev);
|
||||
if (full_power) {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
#include "ccs-pll.h"
|
||||
|
||||
/* Chip ID */
|
||||
#define IMX214_REG_CHIP_ID CCI_REG16(0x0016)
|
||||
#define IMX214_CHIP_ID 0x0214
|
||||
|
|
@ -30,11 +32,9 @@
|
|||
|
||||
#define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106)
|
||||
|
||||
#define IMX214_DEFAULT_CLK_FREQ 24000000
|
||||
#define IMX214_DEFAULT_LINK_FREQ 600000000
|
||||
/* Keep wrong link frequency for backward compatibility */
|
||||
#define IMX214_DEFAULT_LINK_FREQ_LEGACY 480000000
|
||||
#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
|
||||
#define IMX214_FPS 30
|
||||
|
||||
/* V-TIMING internal */
|
||||
|
|
@ -84,6 +84,7 @@
|
|||
#define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A
|
||||
#define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06
|
||||
#define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08
|
||||
#define IMX214_BITS_PER_PIXEL_MASK 0xFF
|
||||
|
||||
#define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114)
|
||||
#define IMX214_CSI_2_LANE_MODE 1
|
||||
|
|
@ -249,6 +250,10 @@ struct imx214 {
|
|||
struct clk *xclk;
|
||||
struct regmap *regmap;
|
||||
|
||||
struct ccs_pll pll;
|
||||
|
||||
struct v4l2_fwnode_endpoint bus_cfg;
|
||||
|
||||
struct v4l2_subdev sd;
|
||||
struct media_pad pad;
|
||||
|
||||
|
|
@ -299,16 +304,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
|
|||
{ IMX214_REG_DIG_CROP_WIDTH, 4096 },
|
||||
{ IMX214_REG_DIG_CROP_HEIGHT, 2304 },
|
||||
|
||||
{ IMX214_REG_VTPXCK_DIV, 5 },
|
||||
{ IMX214_REG_VTSYCK_DIV, 2 },
|
||||
{ IMX214_REG_PREPLLCK_VT_DIV, 3 },
|
||||
{ IMX214_REG_PLL_VT_MPY, 150 },
|
||||
{ IMX214_REG_OPPXCK_DIV, 10 },
|
||||
{ IMX214_REG_OPSYCK_DIV, 1 },
|
||||
{ IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
|
||||
|
||||
{ IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
|
||||
|
||||
{ CCI_REG8(0x3A03), 0x09 },
|
||||
{ CCI_REG8(0x3A04), 0x50 },
|
||||
{ CCI_REG8(0x3A05), 0x01 },
|
||||
|
|
@ -362,16 +357,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
|
|||
{ IMX214_REG_DIG_CROP_WIDTH, 1920 },
|
||||
{ IMX214_REG_DIG_CROP_HEIGHT, 1080 },
|
||||
|
||||
{ IMX214_REG_VTPXCK_DIV, 5 },
|
||||
{ IMX214_REG_VTSYCK_DIV, 2 },
|
||||
{ IMX214_REG_PREPLLCK_VT_DIV, 3 },
|
||||
{ IMX214_REG_PLL_VT_MPY, 150 },
|
||||
{ IMX214_REG_OPPXCK_DIV, 10 },
|
||||
{ IMX214_REG_OPSYCK_DIV, 1 },
|
||||
{ IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
|
||||
|
||||
{ IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
|
||||
|
||||
{ CCI_REG8(0x3A03), 0x04 },
|
||||
{ CCI_REG8(0x3A04), 0xF8 },
|
||||
{ CCI_REG8(0x3A05), 0x02 },
|
||||
|
|
@ -405,9 +390,6 @@ static const struct cci_reg_sequence mode_table_common[] = {
|
|||
/* ATR setting */
|
||||
{ IMX214_REG_ATR_FAST_MOVE, 2 },
|
||||
|
||||
/* external clock setting */
|
||||
{ IMX214_REG_EXCK_FREQ, IMX214_EXCK_FREQ(IMX214_DEFAULT_CLK_FREQ / 1000000) },
|
||||
|
||||
/* global setting */
|
||||
/* basic config */
|
||||
{ IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
|
||||
|
|
@ -777,6 +759,30 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int imx214_configure_pll(struct imx214 *imx214)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
cci_write(imx214->regmap, IMX214_REG_VTPXCK_DIV,
|
||||
imx214->pll.vt_bk.pix_clk_div, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_VTSYCK_DIV,
|
||||
imx214->pll.vt_bk.sys_clk_div, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_PREPLLCK_VT_DIV,
|
||||
imx214->pll.vt_fr.pre_pll_clk_div, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_PLL_VT_MPY,
|
||||
imx214->pll.vt_fr.pll_multiplier, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV,
|
||||
imx214->pll.op_bk.pix_clk_div, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_OPSYCK_DIV,
|
||||
imx214->pll.op_bk.sys_clk_div, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_PLL_MULT_DRIV,
|
||||
IMX214_PLL_SINGLE, &ret);
|
||||
cci_write(imx214->regmap, IMX214_REG_EXCK_FREQ,
|
||||
IMX214_EXCK_FREQ(imx214->pll.ext_clk_freq_hz / 1000000), &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx214_update_digital_gain(struct imx214 *imx214, u32 val)
|
||||
{
|
||||
int ret = 0;
|
||||
|
|
@ -877,9 +883,6 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = {
|
|||
|
||||
static int imx214_ctrls_init(struct imx214 *imx214)
|
||||
{
|
||||
static const s64 link_freq[] = {
|
||||
IMX214_DEFAULT_LINK_FREQ
|
||||
};
|
||||
static const struct v4l2_area unit_size = {
|
||||
.width = 1120,
|
||||
.height = 1120,
|
||||
|
|
@ -900,15 +903,14 @@ static int imx214_ctrls_init(struct imx214 *imx214)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
imx214->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL,
|
||||
V4L2_CID_PIXEL_RATE, 0,
|
||||
IMX214_DEFAULT_PIXEL_RATE, 1,
|
||||
IMX214_DEFAULT_PIXEL_RATE);
|
||||
imx214->pixel_rate =
|
||||
v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_PIXEL_RATE, 1,
|
||||
INT_MAX, 1, 1);
|
||||
|
||||
imx214->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL,
|
||||
V4L2_CID_LINK_FREQ,
|
||||
ARRAY_SIZE(link_freq) - 1,
|
||||
0, link_freq);
|
||||
imx214->bus_cfg.nr_of_link_frequencies - 1,
|
||||
0, imx214->bus_cfg.link_frequencies);
|
||||
if (imx214->link_freq)
|
||||
imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
|
|
@ -1011,6 +1013,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
|
|||
const struct v4l2_mbus_framefmt *fmt;
|
||||
struct v4l2_subdev_state *state;
|
||||
const struct imx214_mode *mode;
|
||||
int bit_rate_mbps;
|
||||
int ret;
|
||||
|
||||
ret = cci_multi_reg_write(imx214->regmap, mode_table_common,
|
||||
|
|
@ -1020,6 +1023,21 @@ static int imx214_start_streaming(struct imx214 *imx214)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = imx214_configure_pll(imx214);
|
||||
if (ret) {
|
||||
dev_err(imx214->dev, "failed to configure PLL: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bit_rate_mbps = (imx214->pll.pixel_rate_csi / 1000000)
|
||||
* imx214->pll.bits_per_pixel;
|
||||
ret = cci_write(imx214->regmap, IMX214_REG_REQ_LINK_BIT_RATE,
|
||||
IMX214_LINK_BIT_RATE_MBPS(bit_rate_mbps), NULL);
|
||||
if (ret) {
|
||||
dev_err(imx214->dev, "failed to configure link bit rate\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
|
||||
IMX214_CSI_4_LANE_MODE, NULL);
|
||||
if (ret) {
|
||||
|
|
@ -1097,6 +1115,109 @@ err_rpm_put:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll,
|
||||
unsigned int link_freq)
|
||||
{
|
||||
struct ccs_pll_limits limits = {
|
||||
.min_ext_clk_freq_hz = 6000000,
|
||||
.max_ext_clk_freq_hz = 27000000,
|
||||
|
||||
.vt_fr = {
|
||||
.min_pre_pll_clk_div = 1,
|
||||
.max_pre_pll_clk_div = 15,
|
||||
/* Value is educated guess as we don't have a spec */
|
||||
.min_pll_ip_clk_freq_hz = 6000000,
|
||||
/* Value is educated guess as we don't have a spec */
|
||||
.max_pll_ip_clk_freq_hz = 12000000,
|
||||
.min_pll_multiplier = 12,
|
||||
.max_pll_multiplier = 1200,
|
||||
.min_pll_op_clk_freq_hz = 338000000,
|
||||
.max_pll_op_clk_freq_hz = 1200000000,
|
||||
},
|
||||
.vt_bk = {
|
||||
.min_sys_clk_div = 2,
|
||||
.max_sys_clk_div = 4,
|
||||
.min_pix_clk_div = 5,
|
||||
.max_pix_clk_div = 10,
|
||||
.min_pix_clk_freq_hz = 30000000,
|
||||
.max_pix_clk_freq_hz = 120000000,
|
||||
},
|
||||
.op_bk = {
|
||||
.min_sys_clk_div = 1,
|
||||
.max_sys_clk_div = 2,
|
||||
.min_pix_clk_div = 6,
|
||||
.max_pix_clk_div = 10,
|
||||
.min_pix_clk_freq_hz = 30000000,
|
||||
.max_pix_clk_freq_hz = 120000000,
|
||||
},
|
||||
|
||||
.min_line_length_pck_bin = IMX214_PPL_DEFAULT,
|
||||
.min_line_length_pck = IMX214_PPL_DEFAULT,
|
||||
};
|
||||
unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes;
|
||||
|
||||
/*
|
||||
* There are no documented constraints on the sys clock frequency, for
|
||||
* either branch. Recover them based on the PLL output clock frequency
|
||||
* and sys_clk_div limits on one hand, and the pix clock frequency and
|
||||
* the pix_clk_div limits on the other hand.
|
||||
*/
|
||||
limits.vt_bk.min_sys_clk_freq_hz =
|
||||
max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div,
|
||||
limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div);
|
||||
limits.vt_bk.max_sys_clk_freq_hz =
|
||||
min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div,
|
||||
limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div);
|
||||
|
||||
limits.op_bk.min_sys_clk_freq_hz =
|
||||
max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div,
|
||||
limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div);
|
||||
limits.op_bk.max_sys_clk_freq_hz =
|
||||
min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div,
|
||||
limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div);
|
||||
|
||||
memset(pll, 0, sizeof(*pll));
|
||||
|
||||
pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY;
|
||||
pll->op_lanes = num_lanes;
|
||||
pll->vt_lanes = num_lanes;
|
||||
pll->csi2.lanes = num_lanes;
|
||||
|
||||
pll->binning_horizontal = 1;
|
||||
pll->binning_vertical = 1;
|
||||
pll->scale_m = 1;
|
||||
pll->scale_n = 1;
|
||||
pll->bits_per_pixel =
|
||||
IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK;
|
||||
pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL;
|
||||
pll->link_freq = link_freq;
|
||||
pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk);
|
||||
|
||||
return ccs_pll_calculate(imx214->dev, &limits, pll);
|
||||
}
|
||||
|
||||
static int imx214_pll_update(struct imx214 *imx214)
|
||||
{
|
||||
u64 link_freq;
|
||||
int ret;
|
||||
|
||||
link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val];
|
||||
ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq);
|
||||
if (ret) {
|
||||
dev_err(imx214->dev, "PLL calculations failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate,
|
||||
imx214->pll.pixel_rate_pixel_array);
|
||||
if (ret) {
|
||||
dev_err(imx214->dev, "failed to set pixel rate\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx214_get_frame_interval(struct v4l2_subdev *subdev,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_frame_interval *fival)
|
||||
|
|
@ -1203,12 +1324,10 @@ static int imx214_identify_module(struct imx214 *imx214)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int imx214_parse_fwnode(struct device *dev)
|
||||
static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214)
|
||||
{
|
||||
struct v4l2_fwnode_endpoint *bus_cfg = &imx214->bus_cfg;
|
||||
struct fwnode_handle *endpoint;
|
||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||
.bus_type = V4L2_MBUS_CSI2_DPHY,
|
||||
};
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1216,42 +1335,52 @@ static int imx214_parse_fwnode(struct device *dev)
|
|||
if (!endpoint)
|
||||
return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
|
||||
bus_cfg->bus_type = V4L2_MBUS_CSI2_DPHY;
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, bus_cfg);
|
||||
fwnode_handle_put(endpoint);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "parsing endpoint node failed\n");
|
||||
goto done;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check the number of MIPI CSI2 data lanes */
|
||||
if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
|
||||
if (bus_cfg->bus.mipi_csi2.num_data_lanes != 4) {
|
||||
ret = dev_err_probe(dev, -EINVAL,
|
||||
"only 4 data lanes are currently supported\n");
|
||||
goto done;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bus_cfg.nr_of_link_frequencies != 1)
|
||||
if (bus_cfg->nr_of_link_frequencies != 1)
|
||||
dev_warn(dev, "Only one link-frequency supported, please review your DT. Continuing anyway\n");
|
||||
|
||||
for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
|
||||
if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ)
|
||||
for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) {
|
||||
u64 freq = bus_cfg->link_frequencies[i];
|
||||
struct ccs_pll pll;
|
||||
|
||||
if (!imx214_pll_calculate(imx214, &pll, freq))
|
||||
break;
|
||||
if (bus_cfg.link_frequencies[i] ==
|
||||
IMX214_DEFAULT_LINK_FREQ_LEGACY) {
|
||||
if (freq == IMX214_DEFAULT_LINK_FREQ_LEGACY) {
|
||||
dev_warn(dev,
|
||||
"link-frequencies %d not supported, please review your DT. Continuing anyway\n",
|
||||
IMX214_DEFAULT_LINK_FREQ);
|
||||
freq = IMX214_DEFAULT_LINK_FREQ;
|
||||
if (imx214_pll_calculate(imx214, &pll, freq))
|
||||
continue;
|
||||
bus_cfg->link_frequencies[i] = freq;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == bus_cfg.nr_of_link_frequencies)
|
||||
if (i == bus_cfg->nr_of_link_frequencies)
|
||||
ret = dev_err_probe(dev, -EINVAL,
|
||||
"link-frequencies %d not supported, please review your DT\n",
|
||||
IMX214_DEFAULT_LINK_FREQ);
|
||||
"link-frequencies %lld not supported, please review your DT\n",
|
||||
bus_cfg->nr_of_link_frequencies ?
|
||||
bus_cfg->link_frequencies[0] : 0);
|
||||
|
||||
done:
|
||||
v4l2_fwnode_endpoint_free(&bus_cfg);
|
||||
fwnode_handle_put(endpoint);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
v4l2_fwnode_endpoint_free(&imx214->bus_cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1261,10 +1390,6 @@ static int imx214_probe(struct i2c_client *client)
|
|||
struct imx214 *imx214;
|
||||
int ret;
|
||||
|
||||
ret = imx214_parse_fwnode(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL);
|
||||
if (!imx214)
|
||||
return -ENOMEM;
|
||||
|
|
@ -1276,11 +1401,6 @@ static int imx214_probe(struct i2c_client *client)
|
|||
return dev_err_probe(dev, PTR_ERR(imx214->xclk),
|
||||
"failed to get xclk\n");
|
||||
|
||||
ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to set xclk frequency\n");
|
||||
|
||||
ret = imx214_get_regulators(dev, imx214);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(dev, ret, "failed to get regulators\n");
|
||||
|
|
@ -1295,6 +1415,10 @@ static int imx214_probe(struct i2c_client *client)
|
|||
return dev_err_probe(dev, PTR_ERR(imx214->regmap),
|
||||
"failed to initialize CCI\n");
|
||||
|
||||
ret = imx214_parse_fwnode(dev, imx214);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
|
||||
imx214->sd.internal_ops = &imx214_internal_ops;
|
||||
|
||||
|
|
@ -1302,7 +1426,9 @@ static int imx214_probe(struct i2c_client *client)
|
|||
* Enable power initially, to avoid warnings
|
||||
* from clk_disable on power_off
|
||||
*/
|
||||
imx214_power_on(imx214->dev);
|
||||
ret = imx214_power_on(imx214->dev);
|
||||
if (ret < 0)
|
||||
goto error_fwnode;
|
||||
|
||||
ret = imx214_identify_module(imx214);
|
||||
if (ret)
|
||||
|
|
@ -1333,6 +1459,12 @@ static int imx214_probe(struct i2c_client *client)
|
|||
pm_runtime_set_active(imx214->dev);
|
||||
pm_runtime_enable(imx214->dev);
|
||||
|
||||
ret = imx214_pll_update(imx214);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(dev, ret, "failed to update PLL\n");
|
||||
goto error_subdev_cleanup;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev_sensor(&imx214->sd);
|
||||
if (ret < 0) {
|
||||
dev_err_probe(dev, ret,
|
||||
|
|
@ -1358,6 +1490,9 @@ free_ctrl:
|
|||
error_power_off:
|
||||
imx214_power_off(imx214->dev);
|
||||
|
||||
error_fwnode:
|
||||
v4l2_fwnode_endpoint_free(&imx214->bus_cfg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1370,6 +1505,8 @@ static void imx214_remove(struct i2c_client *client)
|
|||
v4l2_subdev_cleanup(sd);
|
||||
media_entity_cleanup(&imx214->sd.entity);
|
||||
v4l2_ctrl_handler_free(&imx214->ctrls);
|
||||
v4l2_fwnode_endpoint_free(&imx214->bus_cfg);
|
||||
|
||||
pm_runtime_disable(&client->dev);
|
||||
if (!pm_runtime_status_suspended(&client->dev)) {
|
||||
imx214_power_off(imx214->dev);
|
||||
|
|
|
|||
|
|
@ -1294,7 +1294,6 @@ static int imx290_subdev_init(struct imx290 *imx290)
|
|||
* will already be prevented even before the delay.
|
||||
*/
|
||||
v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
|
||||
imx290->sd.dev = imx290->dev;
|
||||
pm_runtime_mark_last_busy(imx290->dev);
|
||||
pm_runtime_put_autosuspend(imx290->dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -1251,7 +1251,7 @@ static int imx415_parse_hw_config(struct imx415 *sensor)
|
|||
return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset),
|
||||
"failed to get reset GPIO\n");
|
||||
|
||||
sensor->clk = devm_clk_get(sensor->dev, "inck");
|
||||
sensor->clk = devm_clk_get(sensor->dev, NULL);
|
||||
if (IS_ERR(sensor->clk))
|
||||
return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk),
|
||||
"failed to get clock\n");
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ static int lt6911uxe_probe(struct i2c_client *client)
|
|||
|
||||
v4l2_i2c_subdev_init(<6911uxe->sd, client, <6911uxe_subdev_ops);
|
||||
|
||||
lt6911uxe->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_IN);
|
||||
lt6911uxe->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(lt6911uxe->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio),
|
||||
"failed to get reset gpio\n");
|
||||
|
|
|
|||
|
|
@ -1193,12 +1193,12 @@ static int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset,
|
|||
MAX9286_0X0F_RESERVED | priv->gpio_state);
|
||||
}
|
||||
|
||||
static void max9286_gpiochip_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
static int max9286_gpiochip_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max9286_priv *priv = gpiochip_get_data(chip);
|
||||
|
||||
max9286_gpio_set(priv, offset, value);
|
||||
return max9286_gpio_set(priv, offset, value);
|
||||
}
|
||||
|
||||
static int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset)
|
||||
|
|
@ -1220,7 +1220,7 @@ static int max9286_register_gpio(struct max9286_priv *priv)
|
|||
gpio->owner = THIS_MODULE;
|
||||
gpio->ngpio = 2;
|
||||
gpio->base = -1;
|
||||
gpio->set = max9286_gpiochip_set;
|
||||
gpio->set_rv = max9286_gpiochip_set;
|
||||
gpio->get = max9286_gpiochip_get;
|
||||
gpio->can_sleep = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -370,13 +370,6 @@ static int _max96714_set_routing(struct v4l2_subdev *sd,
|
|||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
|
||||
* frame desc is made dynamically allocated.
|
||||
*/
|
||||
if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_subdev_routing_validate(sd, routing,
|
||||
V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -297,13 +297,13 @@ static int max96717_gpiochip_get(struct gpio_chip *gpiochip,
|
|||
return !!(val & MAX96717_GPIO_OUT);
|
||||
}
|
||||
|
||||
static void max96717_gpiochip_set(struct gpio_chip *gpiochip,
|
||||
unsigned int offset, int value)
|
||||
static int max96717_gpiochip_set(struct gpio_chip *gpiochip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max96717_priv *priv = gpiochip_get_data(gpiochip);
|
||||
|
||||
cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL);
|
||||
return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
|
||||
MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL);
|
||||
}
|
||||
|
||||
static int max96717_gpio_get_direction(struct gpio_chip *gpiochip,
|
||||
|
|
@ -355,9 +355,8 @@ static int max96717_gpiochip_probe(struct max96717_priv *priv)
|
|||
gc->get_direction = max96717_gpio_get_direction;
|
||||
gc->direction_input = max96717_gpio_direction_in;
|
||||
gc->direction_output = max96717_gpio_direction_out;
|
||||
gc->set = max96717_gpiochip_set;
|
||||
gc->set_rv = max96717_gpiochip_set;
|
||||
gc->get = max96717_gpiochip_get;
|
||||
gc->of_gpio_n_cells = 2;
|
||||
|
||||
/* Disable GPIO forwarding */
|
||||
for (i = 0; i < gc->ngpio; i++)
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@
|
|||
#define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e)
|
||||
#define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e)
|
||||
#define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0)
|
||||
#define MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE 0x00
|
||||
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980)
|
||||
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m))
|
||||
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982)
|
||||
|
|
@ -377,6 +378,7 @@ struct mt9m114 {
|
|||
struct gpio_desc *reset;
|
||||
struct regulator_bulk_data supplies[3];
|
||||
struct v4l2_fwnode_endpoint bus_cfg;
|
||||
bool bypass_pll;
|
||||
|
||||
struct {
|
||||
unsigned int m;
|
||||
|
|
@ -743,14 +745,21 @@ static int mt9m114_initialize(struct mt9m114 *sensor)
|
|||
}
|
||||
|
||||
/* Configure the PLL. */
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE,
|
||||
MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N,
|
||||
MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m,
|
||||
sensor->pll.n),
|
||||
&ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P,
|
||||
MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), &ret);
|
||||
if (sensor->bypass_pll) {
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE,
|
||||
MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE, &ret);
|
||||
} else {
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE,
|
||||
MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N,
|
||||
MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m,
|
||||
sensor->pll.n),
|
||||
&ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P,
|
||||
MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p),
|
||||
&ret);
|
||||
}
|
||||
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK,
|
||||
sensor->pixrate, &ret);
|
||||
|
||||
|
|
@ -781,41 +790,25 @@ static int mt9m114_initialize(struct mt9m114 *sensor)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m114_configure(struct mt9m114 *sensor,
|
||||
struct v4l2_subdev_state *pa_state,
|
||||
struct v4l2_subdev_state *ifp_state)
|
||||
static int mt9m114_configure_pa(struct mt9m114 *sensor,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
const struct v4l2_mbus_framefmt *pa_format;
|
||||
const struct v4l2_rect *pa_crop;
|
||||
const struct mt9m114_format_info *ifp_info;
|
||||
const struct v4l2_mbus_framefmt *ifp_format;
|
||||
const struct v4l2_rect *ifp_crop;
|
||||
const struct v4l2_rect *ifp_compose;
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
const struct v4l2_rect *crop;
|
||||
unsigned int hratio, vratio;
|
||||
u64 output_format;
|
||||
u64 read_mode;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
pa_format = v4l2_subdev_state_get_format(pa_state, 0);
|
||||
pa_crop = v4l2_subdev_state_get_crop(pa_state, 0);
|
||||
|
||||
ifp_format = v4l2_subdev_state_get_format(ifp_state, 1);
|
||||
ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code);
|
||||
ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0);
|
||||
ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0);
|
||||
format = v4l2_subdev_state_get_format(state, 0);
|
||||
crop = v4l2_subdev_state_get_crop(state, 0);
|
||||
|
||||
ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE,
|
||||
&read_mode, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT,
|
||||
&output_format, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hratio = pa_crop->width / pa_format->width;
|
||||
vratio = pa_crop->height / pa_format->height;
|
||||
hratio = crop->width / format->width;
|
||||
vratio = crop->height / format->height;
|
||||
|
||||
/*
|
||||
* Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW
|
||||
|
|
@ -824,15 +817,15 @@ static int mt9m114_configure(struct mt9m114 *sensor,
|
|||
* example sensor modes.
|
||||
*/
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START,
|
||||
pa_crop->left, &ret);
|
||||
crop->left, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START,
|
||||
pa_crop->top, &ret);
|
||||
crop->top, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END,
|
||||
pa_crop->width + pa_crop->left - 1, &ret);
|
||||
crop->width + crop->left - 1, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END,
|
||||
pa_crop->height + pa_crop->top - 1, &ret);
|
||||
crop->height + crop->top - 1, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW,
|
||||
(pa_crop->height - 4) / vratio - 1, &ret);
|
||||
(crop->height - 4) / vratio - 1, &ret);
|
||||
|
||||
read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK |
|
||||
MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK);
|
||||
|
|
@ -845,6 +838,29 @@ static int mt9m114_configure(struct mt9m114 *sensor,
|
|||
cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE,
|
||||
read_mode, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m114_configure_ifp(struct mt9m114 *sensor,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
const struct mt9m114_format_info *info;
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
const struct v4l2_rect *crop;
|
||||
const struct v4l2_rect *compose;
|
||||
u64 output_format;
|
||||
int ret = 0;
|
||||
|
||||
format = v4l2_subdev_state_get_format(state, 1);
|
||||
info = mt9m114_format_info(sensor, 1, format->code);
|
||||
crop = v4l2_subdev_state_get_crop(state, 0);
|
||||
compose = v4l2_subdev_state_get_compose(state, 0);
|
||||
|
||||
ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT,
|
||||
&output_format, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Color pipeline (IFP) cropping and scaling. Subtract 4 from the left
|
||||
* and top coordinates to compensate for the lines and columns removed
|
||||
|
|
@ -852,18 +868,18 @@ static int mt9m114_configure(struct mt9m114 *sensor,
|
|||
* not in the hardware.
|
||||
*/
|
||||
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET,
|
||||
ifp_crop->left - 4, &ret);
|
||||
crop->left - 4, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET,
|
||||
ifp_crop->top - 4, &ret);
|
||||
crop->top - 4, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH,
|
||||
ifp_crop->width, &ret);
|
||||
crop->width, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT,
|
||||
ifp_crop->height, &ret);
|
||||
crop->height, &ret);
|
||||
|
||||
cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH,
|
||||
ifp_compose->width, &ret);
|
||||
compose->width, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT,
|
||||
ifp_compose->height, &ret);
|
||||
compose->height, &ret);
|
||||
|
||||
/* AWB and AE windows, use the full frame. */
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART,
|
||||
|
|
@ -871,18 +887,18 @@ static int mt9m114_configure(struct mt9m114 *sensor,
|
|||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART,
|
||||
0, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND,
|
||||
ifp_compose->width - 1, &ret);
|
||||
compose->width - 1, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND,
|
||||
ifp_compose->height - 1, &ret);
|
||||
compose->height - 1, &ret);
|
||||
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART,
|
||||
0, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART,
|
||||
0, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND,
|
||||
ifp_compose->width / 5 - 1, &ret);
|
||||
compose->width / 5 - 1, &ret);
|
||||
cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND,
|
||||
ifp_compose->height / 5 - 1, &ret);
|
||||
compose->height / 5 - 1, &ret);
|
||||
|
||||
cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE,
|
||||
MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN |
|
||||
|
|
@ -894,7 +910,7 @@ static int mt9m114_configure(struct mt9m114 *sensor,
|
|||
MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK |
|
||||
MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES |
|
||||
MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE);
|
||||
output_format |= ifp_info->output_format;
|
||||
output_format |= info->output_format;
|
||||
|
||||
cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT,
|
||||
output_format, &ret);
|
||||
|
|
@ -925,7 +941,11 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = mt9m114_configure(sensor, pa_state, ifp_state);
|
||||
ret = mt9m114_configure_ifp(sensor, ifp_state);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
ret = mt9m114_configure_pa(sensor, pa_state);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
|
|
@ -1599,13 +1619,9 @@ static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd,
|
|||
if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(sensor->ifp.hdl.lock);
|
||||
|
||||
ival->numerator = 1;
|
||||
ival->denominator = sensor->ifp.frame_rate;
|
||||
|
||||
mutex_unlock(sensor->ifp.hdl.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1624,8 +1640,6 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
|
|||
if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(sensor->ifp.hdl.lock);
|
||||
|
||||
if (ival->numerator != 0 && ival->denominator != 0)
|
||||
sensor->ifp.frame_rate = min_t(unsigned int,
|
||||
ival->denominator / ival->numerator,
|
||||
|
|
@ -1639,8 +1653,6 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd,
|
|||
if (sensor->streaming)
|
||||
ret = mt9m114_set_frame_rate(sensor);
|
||||
|
||||
mutex_unlock(sensor->ifp.hdl.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -2235,9 +2247,22 @@ static const struct dev_pm_ops mt9m114_pm_ops = {
|
|||
* Probe & Remove
|
||||
*/
|
||||
|
||||
static int mt9m114_verify_link_frequency(struct mt9m114 *sensor,
|
||||
unsigned int pixrate)
|
||||
{
|
||||
unsigned int link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY
|
||||
? pixrate * 8 : pixrate * 2;
|
||||
|
||||
if (sensor->bus_cfg.nr_of_link_frequencies != 1 ||
|
||||
sensor->bus_cfg.link_frequencies[0] != link_freq)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m114_clk_init(struct mt9m114 *sensor)
|
||||
{
|
||||
unsigned int link_freq;
|
||||
unsigned int pixrate;
|
||||
|
||||
/* Hardcode the PLL multiplier and dividers to default settings. */
|
||||
sensor->pll.m = 32;
|
||||
|
|
@ -2249,19 +2274,29 @@ static int mt9m114_clk_init(struct mt9m114 *sensor)
|
|||
* for 16-bit per pixel, transmitted in DDR over a single lane. For
|
||||
* parallel mode, the sensor ouputs one pixel in two PIXCLK cycles.
|
||||
*/
|
||||
sensor->pixrate = clk_get_rate(sensor->clk) * sensor->pll.m
|
||||
/ ((sensor->pll.n + 1) * (sensor->pll.p + 1));
|
||||
|
||||
link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY
|
||||
? sensor->pixrate * 8 : sensor->pixrate * 2;
|
||||
|
||||
if (sensor->bus_cfg.nr_of_link_frequencies != 1 ||
|
||||
sensor->bus_cfg.link_frequencies[0] != link_freq) {
|
||||
dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n");
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Check if EXTCLK fits the configured link frequency. Bypass the PLL
|
||||
* in this case.
|
||||
*/
|
||||
pixrate = clk_get_rate(sensor->clk) / 2;
|
||||
if (mt9m114_verify_link_frequency(sensor, pixrate) == 0) {
|
||||
sensor->pixrate = pixrate;
|
||||
sensor->bypass_pll = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Check if the PLL configuration fits the configured link frequency. */
|
||||
pixrate = clk_get_rate(sensor->clk) * sensor->pll.m
|
||||
/ ((sensor->pll.n + 1) * (sensor->pll.p + 1));
|
||||
if (mt9m114_verify_link_frequency(sensor, pixrate) == 0) {
|
||||
sensor->pixrate = pixrate;
|
||||
sensor->bypass_pll = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mt9m114_identify(struct mt9m114 *sensor)
|
||||
|
|
|
|||
|
|
@ -1469,14 +1469,15 @@ static int ov2659_probe(struct i2c_client *client)
|
|||
V4L2_CID_TEST_PATTERN,
|
||||
ARRAY_SIZE(ov2659_test_pattern_menu) - 1,
|
||||
0, 0, ov2659_test_pattern_menu);
|
||||
ov2659->sd.ctrl_handler = &ov2659->ctrls;
|
||||
|
||||
if (ov2659->ctrls.error) {
|
||||
dev_err(&client->dev, "%s: control initialization error %d\n",
|
||||
__func__, ov2659->ctrls.error);
|
||||
v4l2_ctrl_handler_free(&ov2659->ctrls);
|
||||
return ov2659->ctrls.error;
|
||||
}
|
||||
|
||||
ov2659->sd.ctrl_handler = &ov2659->ctrls;
|
||||
sd = &ov2659->sd;
|
||||
client->flags |= I2C_CLIENT_SCCB;
|
||||
|
||||
|
|
|
|||
|
|
@ -766,11 +766,9 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
|
|||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd);
|
||||
struct v4l2_ctrl_handler *ctrl_hdlr;
|
||||
const struct ov2740_mode *cur_mode;
|
||||
s64 exposure_max, h_blank, pixel_rate;
|
||||
u32 vblank_min, vblank_max, vblank_default;
|
||||
struct v4l2_fwnode_device_properties props;
|
||||
int size;
|
||||
int ret;
|
||||
|
||||
ctrl_hdlr = &ov2740->ctrl_handler;
|
||||
|
|
@ -778,12 +776,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
cur_mode = ov2740->cur_mode;
|
||||
size = ARRAY_SIZE(link_freq_menu_items);
|
||||
|
||||
ov2740->link_freq =
|
||||
v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops,
|
||||
V4L2_CID_LINK_FREQ, size - 1,
|
||||
V4L2_CID_LINK_FREQ,
|
||||
ARRAY_SIZE(link_freq_menu_items) - 1,
|
||||
ov2740->supported_modes->link_freq_index,
|
||||
link_freq_menu_items);
|
||||
if (ov2740->link_freq)
|
||||
|
|
@ -794,14 +790,14 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
|
|||
V4L2_CID_PIXEL_RATE, 0,
|
||||
pixel_rate, 1, pixel_rate);
|
||||
|
||||
vblank_min = cur_mode->vts_min - cur_mode->height;
|
||||
vblank_max = cur_mode->vts_max - cur_mode->height;
|
||||
vblank_default = cur_mode->vts_def - cur_mode->height;
|
||||
vblank_min = ov2740->cur_mode->vts_min - ov2740->cur_mode->height;
|
||||
vblank_max = ov2740->cur_mode->vts_max - ov2740->cur_mode->height;
|
||||
vblank_default = ov2740->cur_mode->vts_def - ov2740->cur_mode->height;
|
||||
ov2740->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
|
||||
V4L2_CID_VBLANK, vblank_min,
|
||||
vblank_max, 1, vblank_default);
|
||||
|
||||
h_blank = cur_mode->hts - cur_mode->width;
|
||||
h_blank = ov2740->cur_mode->hts - ov2740->cur_mode->width;
|
||||
ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
|
||||
V4L2_CID_HBLANK, h_blank, h_blank, 1,
|
||||
h_blank);
|
||||
|
|
@ -814,7 +810,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740)
|
|||
v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
|
||||
OV2740_DGTL_GAIN_MIN, OV2740_DGTL_GAIN_MAX,
|
||||
OV2740_DGTL_GAIN_STEP, OV2740_DGTL_GAIN_DEFAULT);
|
||||
exposure_max = cur_mode->vts_def - OV2740_EXPOSURE_MAX_MARGIN;
|
||||
exposure_max = ov2740->cur_mode->vts_def - OV2740_EXPOSURE_MAX_MARGIN;
|
||||
ov2740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE,
|
||||
OV2740_EXPOSURE_MIN, exposure_max,
|
||||
|
|
|
|||
|
|
@ -2688,10 +2688,15 @@ static int ov5670_probe(struct i2c_client *client)
|
|||
if (ret)
|
||||
return dev_err_probe(&client->dev, ret, "GPIO probe failed\n");
|
||||
|
||||
/* Graph Endpoint */
|
||||
/*
|
||||
* Graph Endpoint. If it's missing we defer rather than fail, as this
|
||||
* sensor is known to co-exist on systems with the IPU3 and so it might
|
||||
* be created by the ipu-bridge.
|
||||
*/
|
||||
handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
|
||||
if (!handle)
|
||||
return dev_err_probe(&client->dev, -ENXIO, "Endpoint for node get failed\n");
|
||||
return dev_err_probe(&client->dev, -EPROBE_DEFER,
|
||||
"Endpoint for node get failed\n");
|
||||
|
||||
ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY;
|
||||
ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2;
|
||||
|
|
|
|||
|
|
@ -1222,9 +1222,14 @@ static int ov5693_check_hwcfg(struct ov5693_device *ov5693)
|
|||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Sometimes the fwnode graph is initialized by the bridge driver
|
||||
* Bridge drivers doing this may also add GPIO mappings, wait for this.
|
||||
*/
|
||||
endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||
if (!endpoint)
|
||||
return -EPROBE_DEFER; /* Could be provided by cio2-bridge */
|
||||
return dev_err_probe(ov5693->dev, -EPROBE_DEFER,
|
||||
"waiting for fwnode graph endpoint\n");
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
|
||||
fwnode_handle_put(endpoint);
|
||||
|
|
|
|||
|
|
@ -1486,9 +1486,14 @@ static int ov7251_check_hwcfg(struct ov7251 *ov7251)
|
|||
unsigned int i, j;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Sometimes the fwnode graph is initialized by the bridge driver
|
||||
* Bridge drivers doing this may also add GPIO mappings, wait for this.
|
||||
*/
|
||||
endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
||||
if (!endpoint)
|
||||
return -EPROBE_DEFER; /* could be provided by cio2-bridge */
|
||||
return dev_err_probe(ov7251->dev, -EPROBE_DEFER,
|
||||
"waiting for fwnode graph endpoint\n");
|
||||
|
||||
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
|
||||
fwnode_handle_put(endpoint);
|
||||
|
|
|
|||
|
|
@ -2991,7 +2991,8 @@ static int ov8865_probe(struct i2c_client *client)
|
|||
|
||||
handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
|
||||
if (!handle)
|
||||
return -EPROBE_DEFER;
|
||||
return dev_err_probe(dev, -EPROBE_DEFER,
|
||||
"waiting for fwnode graph endpoint\n");
|
||||
|
||||
sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "saa711x_regs.h"
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -664,15 +665,6 @@ static const unsigned char saa7115_init_misc[] = {
|
|||
0x00, 0x00
|
||||
};
|
||||
|
||||
static int saa711x_odd_parity(u8 c)
|
||||
{
|
||||
c ^= (c >> 4);
|
||||
c ^= (c >> 2);
|
||||
c ^= (c >> 1);
|
||||
|
||||
return c & 1;
|
||||
}
|
||||
|
||||
static int saa711x_decode_vps(u8 *dst, u8 *p)
|
||||
{
|
||||
static const u8 biphase_tbl[] = {
|
||||
|
|
@ -1227,7 +1219,7 @@ static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vb
|
|||
vbi->type = V4L2_SLICED_TELETEXT_B;
|
||||
break;
|
||||
case 4:
|
||||
if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
|
||||
if (!parity8(p[0]) || !parity8(p[1]))
|
||||
return 0;
|
||||
vbi->type = V4L2_SLICED_CAPTION_525;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ static inline struct tc358743_state *to_state(struct v4l2_subdev *sd)
|
|||
|
||||
/* --------------- I2C --------------- */
|
||||
|
||||
static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
||||
static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
||||
{
|
||||
struct tc358743_state *state = to_state(sd);
|
||||
struct i2c_client *client = state->i2c_client;
|
||||
|
|
@ -140,6 +140,7 @@ static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
|||
v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n",
|
||||
__func__, reg, client->addr, err);
|
||||
}
|
||||
return err != ARRAY_SIZE(msgs);
|
||||
}
|
||||
|
||||
static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
||||
|
|
@ -196,15 +197,24 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n)
|
|||
}
|
||||
}
|
||||
|
||||
static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
|
||||
static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n,
|
||||
int *err)
|
||||
{
|
||||
int error;
|
||||
__le32 val = 0;
|
||||
|
||||
i2c_rd(sd, reg, (u8 __force *)&val, n);
|
||||
error = i2c_rd(sd, reg, (u8 __force *)&val, n);
|
||||
if (err)
|
||||
*err = error;
|
||||
|
||||
return le32_to_cpu(val);
|
||||
}
|
||||
|
||||
static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n)
|
||||
{
|
||||
return i2c_rdreg_err(sd, reg, n, NULL);
|
||||
}
|
||||
|
||||
static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n)
|
||||
{
|
||||
__le32 raw = cpu_to_le32(val);
|
||||
|
|
@ -233,6 +243,13 @@ static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg)
|
|||
return i2c_rdreg(sd, reg, 2);
|
||||
}
|
||||
|
||||
static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value)
|
||||
{
|
||||
int err;
|
||||
*value = i2c_rdreg_err(sd, reg, 2, &err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val)
|
||||
{
|
||||
i2c_wrreg(sd, reg, val, 2);
|
||||
|
|
@ -420,9 +437,9 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd)
|
|||
|
||||
v4l2_dbg(2, debug, sd, "%s:\n", __func__);
|
||||
|
||||
/* Enable hotplug after 100 ms. DDC access to EDID is also enabled when
|
||||
/* Enable hotplug after 143 ms. DDC access to EDID is also enabled when
|
||||
* hotplug is enabled. See register DDC_CTL */
|
||||
schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10);
|
||||
schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 7);
|
||||
|
||||
tc358743_enable_interrupts(sd, true);
|
||||
tc358743_s_ctrl_detect_tx_5v(sd);
|
||||
|
|
@ -1691,12 +1708,23 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static u32 tc358743_g_colorspace(u32 code)
|
||||
{
|
||||
switch (code) {
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
return V4L2_COLORSPACE_SRGB;
|
||||
case MEDIA_BUS_FMT_UYVY8_1X16:
|
||||
return V4L2_COLORSPACE_SMPTE170M;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int tc358743_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct tc358743_state *state = to_state(sd);
|
||||
u8 vi_rep = i2c_rd8(sd, VI_REP);
|
||||
|
||||
if (format->pad != 0)
|
||||
return -EINVAL;
|
||||
|
|
@ -1706,23 +1734,7 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd,
|
|||
format->format.height = state->timings.bt.height;
|
||||
format->format.field = V4L2_FIELD_NONE;
|
||||
|
||||
switch (vi_rep & MASK_VOUT_COLOR_SEL) {
|
||||
case MASK_VOUT_COLOR_RGB_FULL:
|
||||
case MASK_VOUT_COLOR_RGB_LIMITED:
|
||||
format->format.colorspace = V4L2_COLORSPACE_SRGB;
|
||||
break;
|
||||
case MASK_VOUT_COLOR_601_YCBCR_LIMITED:
|
||||
case MASK_VOUT_COLOR_601_YCBCR_FULL:
|
||||
format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
break;
|
||||
case MASK_VOUT_COLOR_709_YCBCR_FULL:
|
||||
case MASK_VOUT_COLOR_709_YCBCR_LIMITED:
|
||||
format->format.colorspace = V4L2_COLORSPACE_REC709;
|
||||
break;
|
||||
default:
|
||||
format->format.colorspace = 0;
|
||||
break;
|
||||
}
|
||||
format->format.colorspace = tc358743_g_colorspace(format->format.code);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1736,19 +1748,14 @@ static int tc358743_set_fmt(struct v4l2_subdev *sd,
|
|||
u32 code = format->format.code; /* is overwritten by get_fmt */
|
||||
int ret = tc358743_get_fmt(sd, sd_state, format);
|
||||
|
||||
format->format.code = code;
|
||||
if (code == MEDIA_BUS_FMT_RGB888_1X24 ||
|
||||
code == MEDIA_BUS_FMT_UYVY8_1X16)
|
||||
format->format.code = code;
|
||||
format->format.colorspace = tc358743_g_colorspace(format->format.code);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (code) {
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
case MEDIA_BUS_FMT_UYVY8_1X16:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
return 0;
|
||||
|
||||
|
|
@ -1972,8 +1979,19 @@ static int tc358743_probe_of(struct tc358743_state *state)
|
|||
state->pdata.refclk_hz = clk_get_rate(refclk);
|
||||
state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS;
|
||||
state->pdata.enable_hdcp = false;
|
||||
/* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */
|
||||
state->pdata.fifo_level = 16;
|
||||
/*
|
||||
* Ideally the FIFO trigger level should be set based on the input and
|
||||
* output data rates, but the calculations required are buried in
|
||||
* Toshiba's register settings spreadsheet.
|
||||
* A value of 16 works with a 594Mbps data rate for 720p60 (using 2
|
||||
* lanes) and 1080p60 (using 4 lanes), but fails when the data rate
|
||||
* is increased, or a lower pixel clock is used that result in CSI
|
||||
* reading out faster than the data is arriving.
|
||||
*
|
||||
* A value of 374 works with both those modes at 594Mbps, and with most
|
||||
* modes on 972Mbps.
|
||||
*/
|
||||
state->pdata.fifo_level = 374;
|
||||
/*
|
||||
* The PLL input clock is obtained by dividing refclk by pll_prd.
|
||||
* It must be between 6 MHz and 40 MHz, lower frequency is better.
|
||||
|
|
@ -1993,6 +2011,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
|
|||
/*
|
||||
* The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
|
||||
* The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
|
||||
* 972 Mbps allows 1080P50 UYVY over 2-lane.
|
||||
*/
|
||||
bps_pr_lane = 2 * endpoint.link_frequencies[0];
|
||||
if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
|
||||
|
|
@ -2006,23 +2025,42 @@ static int tc358743_probe_of(struct tc358743_state *state)
|
|||
state->pdata.refclk_hz * state->pdata.pll_prd;
|
||||
|
||||
/*
|
||||
* FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz
|
||||
* link frequency). In principle it should be possible to calculate
|
||||
* FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane
|
||||
* (297 MHz or 486 MHz link frequency).
|
||||
* In principle it should be possible to calculate
|
||||
* them based on link frequency and resolution.
|
||||
*/
|
||||
if (bps_pr_lane != 594000000U)
|
||||
switch (bps_pr_lane) {
|
||||
default:
|
||||
dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane);
|
||||
state->pdata.lineinitcnt = 0xe80;
|
||||
state->pdata.lptxtimecnt = 0x003;
|
||||
/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
|
||||
state->pdata.tclk_headercnt = 0x1403;
|
||||
state->pdata.tclk_trailcnt = 0x00;
|
||||
/* ths-preparecnt: 3, ths-zerocnt: 1 */
|
||||
state->pdata.ths_headercnt = 0x0103;
|
||||
state->pdata.twakeup = 0x4882;
|
||||
state->pdata.tclk_postcnt = 0x008;
|
||||
state->pdata.ths_trailcnt = 0x2;
|
||||
state->pdata.hstxvregcnt = 0;
|
||||
fallthrough;
|
||||
case 594000000U:
|
||||
state->pdata.lineinitcnt = 0xe80;
|
||||
state->pdata.lptxtimecnt = 0x003;
|
||||
/* tclk-preparecnt: 3, tclk-zerocnt: 20 */
|
||||
state->pdata.tclk_headercnt = 0x1403;
|
||||
state->pdata.tclk_trailcnt = 0x00;
|
||||
/* ths-preparecnt: 3, ths-zerocnt: 1 */
|
||||
state->pdata.ths_headercnt = 0x0103;
|
||||
state->pdata.twakeup = 0x4882;
|
||||
state->pdata.tclk_postcnt = 0x008;
|
||||
state->pdata.ths_trailcnt = 0x2;
|
||||
state->pdata.hstxvregcnt = 0;
|
||||
break;
|
||||
case 972000000U:
|
||||
state->pdata.lineinitcnt = 0x1b58;
|
||||
state->pdata.lptxtimecnt = 0x007;
|
||||
/* tclk-preparecnt: 6, tclk-zerocnt: 40 */
|
||||
state->pdata.tclk_headercnt = 0x2806;
|
||||
state->pdata.tclk_trailcnt = 0x00;
|
||||
/* ths-preparecnt: 6, ths-zerocnt: 8 */
|
||||
state->pdata.ths_headercnt = 0x0806;
|
||||
state->pdata.twakeup = 0x4268;
|
||||
state->pdata.tclk_postcnt = 0x008;
|
||||
state->pdata.ths_trailcnt = 0x5;
|
||||
state->pdata.hstxvregcnt = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
state->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
|
|
@ -2061,6 +2099,7 @@ static int tc358743_probe(struct i2c_client *client)
|
|||
struct tc358743_platform_data *pdata = client->dev.platform_data;
|
||||
struct v4l2_subdev *sd;
|
||||
u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK;
|
||||
u16 chipid;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
|
|
@ -2092,7 +2131,8 @@ static int tc358743_probe(struct i2c_client *client)
|
|||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
|
||||
/* i2c access */
|
||||
if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) {
|
||||
if (i2c_rd16_err(sd, CHIPID, &chipid) ||
|
||||
(chipid & MASK_CHIPID) != 0) {
|
||||
v4l2_info(sd, "not a TC358743 on address 0x%x\n",
|
||||
client->addr << 1);
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -589,8 +589,8 @@ static void tda1997x_enable_edid(struct v4l2_subdev *sd)
|
|||
|
||||
v4l2_dbg(1, debug, sd, "%s\n", __func__);
|
||||
|
||||
/* Enable hotplug after 100ms */
|
||||
schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10);
|
||||
/* Enable hotplug after 143ms */
|
||||
schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 7);
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -111,9 +111,9 @@
|
|||
|
||||
#define VD55G1_WIDTH 804
|
||||
#define VD55G1_HEIGHT 704
|
||||
#define VD55G1_DEFAULT_MODE 0
|
||||
#define VD55G1_MODE_DEF 0
|
||||
#define VD55G1_NB_GPIOS 4
|
||||
#define VD55G1_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8
|
||||
#define VD55G1_MBUS_CODE_DEF 0
|
||||
#define VD55G1_DGAIN_DEF 256
|
||||
#define VD55G1_AGAIN_DEF 19
|
||||
#define VD55G1_EXPO_MAX_TERM 64
|
||||
|
|
@ -129,8 +129,8 @@
|
|||
#define VD55G1_FWPATCH_REVISION_MINOR 9
|
||||
#define VD55G1_XCLK_FREQ_MIN (6 * HZ_PER_MHZ)
|
||||
#define VD55G1_XCLK_FREQ_MAX (27 * HZ_PER_MHZ)
|
||||
#define VD55G1_MIPI_RATE_MIN (250 * HZ_PER_MHZ)
|
||||
#define VD55G1_MIPI_RATE_MAX (1200 * HZ_PER_MHZ)
|
||||
#define VD55G1_MIPI_RATE_MIN (250 * MEGA)
|
||||
#define VD55G1_MIPI_RATE_MAX (1200 * MEGA)
|
||||
|
||||
static const u8 patch_array[] = {
|
||||
0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00,
|
||||
|
|
@ -883,10 +883,9 @@ static int vd55g1_apply_cold_start(struct vd55g1 *sensor,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void vd55g1_update_img_pad_format(struct vd55g1 *sensor,
|
||||
const struct vd55g1_mode *mode,
|
||||
u32 code,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
static void vd55g1_update_pad_fmt(struct vd55g1 *sensor,
|
||||
const struct vd55g1_mode *mode, u32 code,
|
||||
struct v4l2_mbus_framefmt *fmt)
|
||||
{
|
||||
fmt->code = code;
|
||||
fmt->width = mode->width;
|
||||
|
|
@ -1038,8 +1037,6 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret);
|
||||
|
||||
/* Configure output */
|
||||
vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE,
|
||||
sensor->mipi_rate, &ret);
|
||||
|
|
@ -1084,7 +1081,7 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd,
|
|||
|
||||
err_rpm_put:
|
||||
pm_runtime_put(sensor->dev);
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vd55g1_disable_streams(struct v4l2_subdev *sd,
|
||||
|
|
@ -1231,8 +1228,8 @@ static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd,
|
|||
width, height, sd_fmt->format.width,
|
||||
sd_fmt->format.height);
|
||||
|
||||
vd55g1_update_img_pad_format(sensor, new_mode, sd_fmt->format.code,
|
||||
&sd_fmt->format);
|
||||
vd55g1_update_pad_fmt(sensor, new_mode, sd_fmt->format.code,
|
||||
&sd_fmt->format);
|
||||
|
||||
/*
|
||||
* Use binning to maximize the crop rectangle size, and centre it in the
|
||||
|
|
@ -1262,7 +1259,6 @@ static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd,
|
|||
static int vd55g1_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state)
|
||||
{
|
||||
unsigned int def_mode = VD55G1_DEFAULT_MODE;
|
||||
struct vd55g1 *sensor = to_vd55g1(sd);
|
||||
struct v4l2_subdev_format fmt = { 0 };
|
||||
struct v4l2_subdev_route routes[] = {
|
||||
|
|
@ -1279,8 +1275,9 @@ static int vd55g1_init_state(struct v4l2_subdev *sd,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
vd55g1_update_img_pad_format(sensor, &vd55g1_supported_modes[def_mode],
|
||||
VD55G1_MEDIA_BUS_FMT_DEF, &fmt.format);
|
||||
vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF],
|
||||
vd55g1_mbus_codes[VD55G1_MBUS_CODE_DEF].code,
|
||||
&fmt.format);
|
||||
|
||||
return vd55g1_set_pad_fmt(sd, sd_state, &fmt);
|
||||
}
|
||||
|
|
@ -1613,6 +1610,9 @@ static int vd55g1_power_on(struct device *dev)
|
|||
goto disable_clock;
|
||||
}
|
||||
|
||||
/* Setup clock now to advance through system FSM states */
|
||||
vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret);
|
||||
|
||||
ret = vd55g1_patch(sensor);
|
||||
if (ret) {
|
||||
dev_err(dev, "Sensor patch failed %d\n", ret);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include "cx18-driver.h"
|
||||
|
||||
/*
|
||||
|
|
@ -56,15 +57,6 @@ struct vbi_anc_data {
|
|||
/* u8 fill[]; Variable number of fill bytes */
|
||||
};
|
||||
|
||||
static int odd_parity(u8 c)
|
||||
{
|
||||
c ^= (c >> 4);
|
||||
c ^= (c >> 2);
|
||||
c ^= (c >> 1);
|
||||
|
||||
return c & 1;
|
||||
}
|
||||
|
||||
static int decode_vps(u8 *dst, u8 *p)
|
||||
{
|
||||
static const u8 biphase_tbl[] = {
|
||||
|
|
@ -278,7 +270,7 @@ int cx18_av_decode_vbi_line(struct v4l2_subdev *sd,
|
|||
break;
|
||||
case 6:
|
||||
sdid = V4L2_SLICED_CAPTION_525;
|
||||
err = !odd_parity(p[0]) || !odd_parity(p[1]);
|
||||
err = !parity8(p[0]) || !parity8(p[1]);
|
||||
break;
|
||||
case 9:
|
||||
sdid = V4L2_SLICED_VPS;
|
||||
|
|
|
|||
|
|
@ -271,18 +271,6 @@ struct cx18_options {
|
|||
#define CX18_SLICED_TYPE_WSS_625 (5)
|
||||
#define CX18_SLICED_TYPE_VPS (7)
|
||||
|
||||
/**
|
||||
* list_entry_is_past_end - check if a previous loop cursor is off list end
|
||||
* @pos: the type * previously used as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Check if the entry's list_head is the head of the list, thus it's not a
|
||||
* real entry but was the loop cursor that walked past the end
|
||||
*/
|
||||
#define list_entry_is_past_end(pos, head, member) \
|
||||
(&pos->member == (head))
|
||||
|
||||
struct cx18_vb2_buffer {
|
||||
/* Common video buffer sub-system struct */
|
||||
struct vb2_v4l2_buffer vb;
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ static size_t cx18_copy_mdl_to_user(struct cx18_stream *s,
|
|||
mdl->curr_buf = list_first_entry(&mdl->buf_list,
|
||||
struct cx18_buffer, list);
|
||||
|
||||
if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
|
||||
if (list_entry_is_head(mdl->curr_buf, &mdl->buf_list, list)) {
|
||||
/*
|
||||
* For some reason we've exhausted the buffers, but the MDL
|
||||
* object still said some data was unread.
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl,
|
|||
mdl->curr_buf = list_first_entry(&mdl->buf_list,
|
||||
struct cx18_buffer, list);
|
||||
|
||||
if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) {
|
||||
if (list_entry_is_head(mdl->curr_buf, &mdl->buf_list, list)) {
|
||||
/*
|
||||
* For some reason we've exhausted the buffers, but the MDL
|
||||
* object still said some data was unread.
|
||||
|
|
|
|||
|
|
@ -55,11 +55,15 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
|||
/* Himax HM2172 */
|
||||
IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000),
|
||||
/* GalaxyCore GC0310 */
|
||||
IPU_SENSOR_CONFIG("INT0310", 0),
|
||||
IPU_SENSOR_CONFIG("INT0310", 1, 55692000),
|
||||
/* Omnivision OV5693 */
|
||||
IPU_SENSOR_CONFIG("INT33BE", 1, 419200000),
|
||||
/* Onsemi MT9M114 */
|
||||
IPU_SENSOR_CONFIG("INT33F0", 1, 384000000),
|
||||
/* Omnivision OV2740 */
|
||||
IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
|
||||
/* Omnivision OV5670 */
|
||||
IPU_SENSOR_CONFIG("INT3479", 1, 422400000),
|
||||
/* Omnivision OV8865 */
|
||||
IPU_SENSOR_CONFIG("INT347A", 1, 360000000),
|
||||
/* Omnivision OV7251 */
|
||||
|
|
@ -78,7 +82,7 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
|||
/* Omnivision OV08A10 */
|
||||
IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000),
|
||||
/* Omnivision OV08x40 */
|
||||
IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000),
|
||||
IPU_SENSOR_CONFIG("OVTI08F4", 3, 400000000, 749000000, 800000000),
|
||||
/* Omnivision OV13B10 */
|
||||
IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000),
|
||||
IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
|
||||
|
|
@ -86,6 +90,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
|
|||
IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000),
|
||||
/* Omnivision OV8856 */
|
||||
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
|
||||
/* Toshiba T4KA3 */
|
||||
IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000),
|
||||
};
|
||||
|
||||
static const struct ipu_property_names prop_names = {
|
||||
|
|
@ -809,7 +815,8 @@ int ipu_bridge_init(struct device *dev,
|
|||
return 0;
|
||||
|
||||
if (!ipu_bridge_ivsc_is_ready())
|
||||
return -EPROBE_DEFER;
|
||||
return dev_err_probe(dev, -EPROBE_DEFER,
|
||||
"waiting for IVSC to become ready\n");
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge)
|
||||
|
|
|
|||
|
|
@ -358,6 +358,8 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|||
static const int FBPT_WIDTH = DIV_ROUND_UP(CIO2_MAX_LOPS,
|
||||
CIO2_FBPT_SUBENTRY_UNIT);
|
||||
const u32 num_buffers1 = CIO2_MAX_BUFFERS - 1;
|
||||
struct v4l2_subdev_state *state;
|
||||
const struct v4l2_mbus_framefmt *format;
|
||||
const struct ipu3_cio2_fmt *fmt;
|
||||
void __iomem *const base = cio2->base;
|
||||
u8 lanes, csi2bus = q->csi2.port;
|
||||
|
|
@ -365,7 +367,13 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|||
struct cio2_csi2_timing timing = { 0 };
|
||||
int i, r;
|
||||
|
||||
fmt = cio2_find_format(NULL, &q->subdev_fmt.code);
|
||||
state = v4l2_subdev_lock_and_get_active_state(&q->subdev);
|
||||
format = v4l2_subdev_state_get_format(state, CIO2_PAD_SINK);
|
||||
|
||||
fmt = cio2_find_format(NULL, &format->code);
|
||||
|
||||
v4l2_subdev_unlock_state(state);
|
||||
|
||||
if (!fmt)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -1194,9 +1202,9 @@ static int cio2_subdev_subscribe_event(struct v4l2_subdev *sd,
|
|||
return v4l2_event_subscribe(fh, sub, 0, NULL);
|
||||
}
|
||||
|
||||
static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
static int cio2_subdev_init_state(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *state)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
const struct v4l2_mbus_framefmt fmt_default = {
|
||||
.width = 1936,
|
||||
.height = 1096,
|
||||
|
|
@ -1207,42 +1215,23 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||
.quantization = V4L2_QUANTIZATION_DEFAULT,
|
||||
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
|
||||
};
|
||||
struct v4l2_mbus_framefmt *format;
|
||||
|
||||
/* Initialize try_fmt */
|
||||
format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SINK);
|
||||
/* Initialize the format on the sink and source pads. */
|
||||
format = v4l2_subdev_state_get_format(state, CIO2_PAD_SINK);
|
||||
*format = fmt_default;
|
||||
|
||||
/* same as sink */
|
||||
format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SOURCE);
|
||||
format = v4l2_subdev_state_get_format(state, CIO2_PAD_SOURCE);
|
||||
*format = fmt_default;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
|
||||
|
||||
mutex_lock(&q->subdev_lock);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
fmt->format = *v4l2_subdev_state_get_format(sd_state,
|
||||
fmt->pad);
|
||||
else
|
||||
fmt->format = q->subdev_fmt;
|
||||
|
||||
mutex_unlock(&q->subdev_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
struct v4l2_subdev_format *fmt)
|
||||
{
|
||||
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
|
||||
struct v4l2_mbus_framefmt *mbus;
|
||||
u32 mbus_code = fmt->format.code;
|
||||
unsigned int i;
|
||||
|
|
@ -1252,12 +1241,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|||
* source always propagates from sink
|
||||
*/
|
||||
if (fmt->pad == CIO2_PAD_SOURCE)
|
||||
return cio2_subdev_get_fmt(sd, sd_state, fmt);
|
||||
|
||||
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
mbus = v4l2_subdev_state_get_format(sd_state, fmt->pad);
|
||||
else
|
||||
mbus = &q->subdev_fmt;
|
||||
return v4l2_subdev_get_fmt(sd, sd_state, fmt);
|
||||
|
||||
fmt->format.code = formats[0].mbus_code;
|
||||
|
||||
|
|
@ -1272,9 +1256,12 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|||
fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT);
|
||||
fmt->format.field = V4L2_FIELD_NONE;
|
||||
|
||||
mutex_lock(&q->subdev_lock);
|
||||
mbus = v4l2_subdev_state_get_format(sd_state, CIO2_PAD_SINK);
|
||||
*mbus = fmt->format;
|
||||
|
||||
/* Propagate the format to the source pad. */
|
||||
mbus = v4l2_subdev_state_get_format(sd_state, CIO2_PAD_SOURCE);
|
||||
*mbus = fmt->format;
|
||||
mutex_unlock(&q->subdev_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1345,12 +1332,12 @@ static const struct v4l2_subdev_core_ops cio2_subdev_core_ops = {
|
|||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops cio2_subdev_internal_ops = {
|
||||
.open = cio2_subdev_open,
|
||||
.init_state = cio2_subdev_init_state,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops cio2_subdev_pad_ops = {
|
||||
.link_validate = v4l2_subdev_link_validate_default,
|
||||
.get_fmt = cio2_subdev_get_fmt,
|
||||
.get_fmt = v4l2_subdev_get_fmt,
|
||||
.set_fmt = cio2_subdev_set_fmt,
|
||||
.enum_mbus_code = cio2_subdev_enum_mbus_code,
|
||||
};
|
||||
|
|
@ -1502,28 +1489,18 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|||
{
|
||||
static const u32 default_width = 1936;
|
||||
static const u32 default_height = 1096;
|
||||
const struct ipu3_cio2_fmt dflt_fmt = formats[0];
|
||||
struct device *dev = &cio2->pci_dev->dev;
|
||||
struct video_device *vdev = &q->vdev;
|
||||
struct vb2_queue *vbq = &q->vbq;
|
||||
struct v4l2_subdev *subdev = &q->subdev;
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
int r;
|
||||
|
||||
/* Initialize miscellaneous variables */
|
||||
mutex_init(&q->lock);
|
||||
mutex_init(&q->subdev_lock);
|
||||
|
||||
/* Initialize formats to default values */
|
||||
fmt = &q->subdev_fmt;
|
||||
fmt->width = default_width;
|
||||
fmt->height = default_height;
|
||||
fmt->code = dflt_fmt.mbus_code;
|
||||
fmt->field = V4L2_FIELD_NONE;
|
||||
|
||||
q->format.width = default_width;
|
||||
q->format.height = default_height;
|
||||
q->format.pixelformat = dflt_fmt.fourcc;
|
||||
q->format.pixelformat = formats[0].fourcc;
|
||||
q->format.colorspace = V4L2_COLORSPACE_RAW;
|
||||
q->format.field = V4L2_FIELD_NONE;
|
||||
q->format.num_planes = 1;
|
||||
|
|
@ -1567,9 +1544,16 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|||
CIO2_ENTITY_NAME " %td", q - cio2->queue);
|
||||
subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
|
||||
v4l2_set_subdevdata(subdev, cio2);
|
||||
|
||||
r = v4l2_subdev_init_finalize(subdev);
|
||||
if (r) {
|
||||
dev_err(dev, "failed to initialize subdev (%d)\n", r);
|
||||
goto fail_subdev;
|
||||
}
|
||||
|
||||
r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev);
|
||||
if (r) {
|
||||
dev_err(dev, "failed initialize subdev (%d)\n", r);
|
||||
dev_err(dev, "failed to register subdev (%d)\n", r);
|
||||
goto fail_subdev;
|
||||
}
|
||||
|
||||
|
|
@ -1626,7 +1610,6 @@ fail_vdev_media_entity:
|
|||
fail_subdev_media_entity:
|
||||
cio2_fbpt_exit(q, dev);
|
||||
fail_fbpt:
|
||||
mutex_destroy(&q->subdev_lock);
|
||||
mutex_destroy(&q->lock);
|
||||
|
||||
return r;
|
||||
|
|
@ -1639,7 +1622,6 @@ static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q)
|
|||
v4l2_device_unregister_subdev(&q->subdev);
|
||||
media_entity_cleanup(&q->subdev.entity);
|
||||
cio2_fbpt_exit(q, &cio2->pci_dev->dev);
|
||||
mutex_destroy(&q->subdev_lock);
|
||||
mutex_destroy(&q->lock);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -351,9 +351,7 @@ struct cio2_queue {
|
|||
|
||||
/* Subdev, /dev/v4l-subdevX */
|
||||
struct v4l2_subdev subdev;
|
||||
struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */
|
||||
struct media_pad subdev_pads[CIO2_PADS];
|
||||
struct v4l2_mbus_framefmt subdev_fmt;
|
||||
atomic_t frame_sequence;
|
||||
|
||||
/* Video device, /dev/videoX */
|
||||
|
|
|
|||
|
|
@ -354,9 +354,9 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
|
|||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
sink_streams =
|
||||
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
|
||||
if (ret)
|
||||
|
|
@ -384,9 +384,9 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
|
|||
struct media_pad *remote_pad;
|
||||
u64 sink_streams;
|
||||
|
||||
sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
|
||||
CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
sink_streams =
|
||||
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
|
||||
&streams_mask);
|
||||
|
||||
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
|
||||
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct ipu6_bus_device;
|
|||
#define IPU6_ISYS_NUM_RECV_QUEUE 1
|
||||
|
||||
#define IPU6_ISYS_MIN_WIDTH 2U
|
||||
#define IPU6_ISYS_MIN_HEIGHT 2U
|
||||
#define IPU6_ISYS_MIN_HEIGHT 1U
|
||||
#define IPU6_ISYS_MAX_WIDTH 4672U
|
||||
#define IPU6_ISYS_MAX_HEIGHT 3416U
|
||||
|
||||
|
|
|
|||
|
|
@ -529,6 +529,8 @@ static void mei_ace_remove(struct mei_cl_device *cldev)
|
|||
|
||||
ace_set_camera_owner(ace, ACE_CAMERA_IVSC);
|
||||
|
||||
mei_cldev_disable(cldev);
|
||||
|
||||
mutex_destroy(&ace->lock);
|
||||
}
|
||||
|
||||
|
|
@ -574,7 +576,7 @@ static struct mei_cl_driver mei_ace_driver = {
|
|||
|
||||
module_mei_cl_driver(mei_ace_driver);
|
||||
|
||||
MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
|
||||
MODULE_AUTHOR("Wentong Wu");
|
||||
MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
|
||||
MODULE_DESCRIPTION("Device driver for IVSC ACE");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -760,6 +760,8 @@ static void mei_csi_remove(struct mei_cl_device *cldev)
|
|||
|
||||
pm_runtime_disable(&cldev->dev);
|
||||
|
||||
mei_cldev_disable(cldev);
|
||||
|
||||
mutex_destroy(&csi->lock);
|
||||
}
|
||||
|
||||
|
|
@ -783,7 +785,7 @@ static struct mei_cl_driver mei_csi_driver = {
|
|||
module_mei_cl_driver(mei_csi_driver);
|
||||
|
||||
MODULE_IMPORT_NS("INTEL_IPU_BRIDGE");
|
||||
MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
|
||||
MODULE_AUTHOR("Wentong Wu");
|
||||
MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
|
||||
MODULE_DESCRIPTION("Device driver for IVSC CSI");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -492,7 +492,14 @@ static int vidioc_s_dv_timings(struct file *file, void *fh,
|
|||
static int vidioc_enum_dv_timings(struct file *file, void *fh,
|
||||
struct v4l2_enum_dv_timings *timings)
|
||||
{
|
||||
return v4l2_enum_dv_timings_cap(timings, &video_timings_cap, NULL, NULL);
|
||||
struct mgb4_vout_dev *voutdev = video_drvdata(file);
|
||||
|
||||
if (timings->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
get_timings(voutdev, &timings->timings);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_dv_timings_cap(struct file *file, void *fh,
|
||||
|
|
|
|||
|
|
@ -52,26 +52,6 @@
|
|||
* | etc
|
||||
*/
|
||||
|
||||
void saa7164_buffer_display(struct saa7164_buffer *buf)
|
||||
{
|
||||
struct saa7164_dev *dev = buf->port->dev;
|
||||
int i;
|
||||
|
||||
dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n",
|
||||
__func__, buf, buf->idx);
|
||||
dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n",
|
||||
buf->cpu, (long long)buf->dma, buf->pci_size);
|
||||
dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
|
||||
buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
|
||||
|
||||
/* Format the Page Table Entries to point into the data buffer */
|
||||
for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
|
||||
|
||||
dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n",
|
||||
i, buf->pt_cpu, (u64)*(buf->pt_cpu));
|
||||
|
||||
}
|
||||
}
|
||||
/* Allocate a new buffer structure and associated PCI space in bytes.
|
||||
* len must be a multiple of sizeof(u64)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -295,34 +295,6 @@ static int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno)
|
||||
{
|
||||
int i;
|
||||
dprintk(DBGLVL_CMD, "%s()\n", __func__);
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
|
||||
if (dev->cmds[i].inuse == 1) {
|
||||
dprintk(DBGLVL_CMD,
|
||||
"seqno %d inuse, sig = %d, t/out = %d\n",
|
||||
dev->cmds[i].seqno,
|
||||
dev->cmds[i].signalled,
|
||||
dev->cmds[i].timeout);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
|
||||
if ((dev->cmds[i].inuse == 1) && ((i == 0) ||
|
||||
(dev->cmds[i].signalled) || (dev->cmds[i].timeout))) {
|
||||
dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n",
|
||||
__func__, i);
|
||||
dev->cmds[i].signalled = 1;
|
||||
wake_up(&dev->cmds[i].wait);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->lock);
|
||||
}
|
||||
|
||||
int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
|
||||
u16 controlselector, u16 size, void *buf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -508,7 +508,6 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
|
|||
int saa7164_cmd_send(struct saa7164_dev *dev,
|
||||
u8 id, enum tmComResCmd command, u16 controlselector,
|
||||
u16 size, void *buf);
|
||||
void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
|
||||
int saa7164_irq_dequeue(struct saa7164_dev *dev);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
|
|
@ -570,7 +569,6 @@ extern int saa7164_dvb_unregister(struct saa7164_port *port);
|
|||
extern struct saa7164_buffer *saa7164_buffer_alloc(
|
||||
struct saa7164_port *port, u32 len);
|
||||
extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
|
||||
extern void saa7164_buffer_display(struct saa7164_buffer *buf);
|
||||
extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
|
||||
extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
|
||||
extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
|
||||
|
|
|
|||
|
|
@ -116,18 +116,6 @@ static int solo_gpiochip_get_direction(struct gpio_chip *chip,
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int solo_gpiochip_direction_input(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int solo_gpiochip_direction_output(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int solo_gpiochip_get(struct gpio_chip *chip,
|
||||
unsigned int offset)
|
||||
{
|
||||
|
|
@ -139,8 +127,8 @@ static int solo_gpiochip_get(struct gpio_chip *chip,
|
|||
return 1 & (ret >> (offset + 8));
|
||||
}
|
||||
|
||||
static void solo_gpiochip_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
static int solo_gpiochip_set(struct gpio_chip *chip,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct solo_dev *solo_dev = gpiochip_get_data(chip);
|
||||
|
||||
|
|
@ -148,6 +136,8 @@ static void solo_gpiochip_set(struct gpio_chip *chip,
|
|||
solo_gpio_set(solo_dev, 1 << (offset + 8));
|
||||
else
|
||||
solo_gpio_clear(solo_dev, 1 << (offset + 8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -167,10 +157,8 @@ int solo_gpio_init(struct solo_dev *solo_dev)
|
|||
solo_dev->gpio_dev.can_sleep = 0;
|
||||
|
||||
solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction;
|
||||
solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input;
|
||||
solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output;
|
||||
solo_dev->gpio_dev.get = solo_gpiochip_get;
|
||||
solo_dev->gpio_dev.set = solo_gpiochip_set;
|
||||
solo_dev->gpio_dev.set_rv = solo_gpiochip_set;
|
||||
|
||||
ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "vpu_cmds.h"
|
||||
#include "vpu_rpc.h"
|
||||
|
||||
#define VDEC_SLOT_CNT_DFT 32
|
||||
#define VDEC_MIN_BUFFER_CAP 8
|
||||
#define VDEC_MIN_BUFFER_OUT 8
|
||||
|
||||
|
|
@ -41,6 +42,14 @@ struct vdec_fs_info {
|
|||
u32 tag;
|
||||
};
|
||||
|
||||
struct vdec_frame_store_t {
|
||||
struct vpu_vb2_buffer *curr;
|
||||
struct vpu_vb2_buffer *pend;
|
||||
dma_addr_t addr;
|
||||
unsigned int state;
|
||||
u32 tag;
|
||||
};
|
||||
|
||||
struct vdec_t {
|
||||
u32 seq_hdr_found;
|
||||
struct vpu_buffer udata;
|
||||
|
|
@ -48,7 +57,8 @@ struct vdec_t {
|
|||
struct vpu_dec_codec_info codec_info;
|
||||
enum vpu_codec_state state;
|
||||
|
||||
struct vpu_vb2_buffer *slots[VB2_MAX_FRAME];
|
||||
struct vdec_frame_store_t *slots;
|
||||
u32 slot_count;
|
||||
u32 req_frame_count;
|
||||
struct vdec_fs_info mbi;
|
||||
struct vdec_fs_info dcp;
|
||||
|
|
@ -232,6 +242,35 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
|
|||
V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
|
||||
0, 1, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
|
||||
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
||||
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_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_EXTENDED) |
|
||||
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
|
||||
V4L2_MPEG_VIDEO_H264_PROFILE_MAIN);
|
||||
|
||||
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
|
||||
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
|
||||
V4L2_MPEG_VIDEO_H264_LEVEL_6_2,
|
||||
0,
|
||||
V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
|
||||
|
||||
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
|
||||
V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
|
||||
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
|
||||
~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
|
||||
(1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)),
|
||||
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
|
||||
|
||||
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL,
|
||||
V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
|
||||
V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
|
||||
0,
|
||||
V4L2_MPEG_VIDEO_HEVC_LEVEL_4);
|
||||
|
||||
ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
|
||||
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2);
|
||||
if (ctrl)
|
||||
|
|
@ -258,6 +297,63 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void vdec_attach_frame_store(struct vpu_inst *inst, struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
struct vdec_frame_store_t *new_slots = NULL;
|
||||
dma_addr_t addr;
|
||||
int i;
|
||||
|
||||
addr = vpu_get_vb_phy_addr(vb, 0);
|
||||
for (i = 0; i < vdec->slot_count; i++) {
|
||||
if (addr == vdec->slots[i].addr) {
|
||||
if (vdec->slots[i].curr && vdec->slots[i].curr != vpu_buf) {
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED);
|
||||
vdec->slots[i].pend = vpu_buf;
|
||||
} else {
|
||||
vpu_set_buffer_state(vbuf, vdec->slots[i].state);
|
||||
}
|
||||
vpu_buf->fs_id = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < vdec->slot_count; i++) {
|
||||
if (!vdec->slots[i].addr) {
|
||||
vdec->slots[i].addr = addr;
|
||||
vpu_buf->fs_id = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
new_slots = krealloc_array(vdec->slots, vdec->slot_count * 2,
|
||||
sizeof(*vdec->slots),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!new_slots) {
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
vdec->slots = new_slots;
|
||||
vdec->slot_count *= 2;
|
||||
|
||||
vdec->slots[i].addr = addr;
|
||||
vpu_buf->fs_id = i;
|
||||
}
|
||||
|
||||
static void vdec_reset_frame_store(struct vpu_inst *inst)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
|
||||
if (!vdec->slots || !vdec->slot_count)
|
||||
return;
|
||||
|
||||
vpu_trace(inst->dev, "inst[%d] reset slots\n", inst->id);
|
||||
memset(vdec->slots, 0, sizeof(*vdec->slots) * vdec->slot_count);
|
||||
}
|
||||
|
||||
static void vdec_handle_resolution_change(struct vpu_inst *inst)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
|
|
@ -714,11 +810,11 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
|
|||
struct vb2_v4l2_buffer *src_buf;
|
||||
int ret = 0;
|
||||
|
||||
if (!info || info->id >= ARRAY_SIZE(vdec->slots))
|
||||
if (!info || info->id >= vdec->slot_count)
|
||||
return -EINVAL;
|
||||
|
||||
vpu_inst_lock(inst);
|
||||
vpu_buf = vdec->slots[info->id];
|
||||
vpu_buf = vdec->slots[info->id].curr;
|
||||
if (!vpu_buf) {
|
||||
dev_err(inst->dev, "[%d] decoded invalid frame[%d]\n", inst->id, info->id);
|
||||
ret = -EINVAL;
|
||||
|
|
@ -739,11 +835,13 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg)
|
|||
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->slots[info->id].state = VPU_BUF_STATE_DECODED;
|
||||
vdec->decoded_frame_count++;
|
||||
if (vdec->params.display_delay_enable) {
|
||||
struct vpu_format *cur_fmt;
|
||||
|
||||
cur_fmt = vpu_get_format(inst, inst->cap_format.type);
|
||||
vdec->slots[info->id].state = VPU_BUF_STATE_READY;
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY);
|
||||
for (int i = 0; i < vbuf->vb2_buf.num_planes; i++)
|
||||
vb2_set_plane_payload(&vbuf->vb2_buf,
|
||||
|
|
@ -766,11 +864,11 @@ static struct vpu_vb2_buffer *vdec_find_buffer(struct vpu_inst *inst, u32 luma)
|
|||
struct vdec_t *vdec = inst->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) {
|
||||
if (!vdec->slots[i])
|
||||
for (i = 0; i < vdec->slot_count; i++) {
|
||||
if (!vdec->slots[i].curr)
|
||||
continue;
|
||||
if (luma == vdec->slots[i]->luma)
|
||||
return vdec->slots[i];
|
||||
if (luma == vdec->slots[i].addr)
|
||||
return vdec->slots[i].curr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -804,11 +902,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
|
|||
|
||||
cur_fmt = vpu_get_format(inst, inst->cap_format.type);
|
||||
vbuf = &vpu_buf->m2m_buf.vb;
|
||||
if (vbuf->vb2_buf.index != frame->id)
|
||||
dev_err(inst->dev, "[%d] buffer id(%d, %d) mismatch\n",
|
||||
inst->id, vbuf->vb2_buf.index, frame->id);
|
||||
if (vpu_buf->fs_id != frame->id)
|
||||
dev_err(inst->dev, "[%d] buffer id(%d(%d), %d) mismatch\n",
|
||||
inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index, frame->id);
|
||||
|
||||
if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_READY && vdec->params.display_delay_enable)
|
||||
if (vdec->params.display_delay_enable)
|
||||
return;
|
||||
|
||||
if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED)
|
||||
|
|
@ -821,10 +919,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame)
|
|||
vbuf->sequence = vdec->sequence;
|
||||
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);
|
||||
vdec->slots[vpu_buf->fs_id].state = VPU_BUF_STATE_READY;
|
||||
vdec->display_frame_count++;
|
||||
vpu_inst_unlock(inst);
|
||||
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
|
||||
dev_dbg(inst->dev, "[%d] decoded : %d, display : %d, sequence : %d\n",
|
||||
inst->id, vdec->decoded_frame_count, vdec->display_frame_count, vdec->sequence);
|
||||
}
|
||||
|
|
@ -1052,18 +1151,30 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb
|
|||
if (!vbuf)
|
||||
return -EINVAL;
|
||||
|
||||
if (vdec->slots[vbuf->vb2_buf.index]) {
|
||||
dev_err(inst->dev, "[%d] repeat alloc fs %d\n",
|
||||
inst->id, vbuf->vb2_buf.index);
|
||||
vpu_buf = to_vpu_vb2_buffer(vbuf);
|
||||
if (vpu_buf->fs_id < 0 || vpu_buf->fs_id >= vdec->slot_count) {
|
||||
dev_err(inst->dev, "invalid fs %d for v4l2 buffer %d\n",
|
||||
vpu_buf->fs_id, vbuf->vb2_buf.index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (vdec->slots[vpu_buf->fs_id].curr) {
|
||||
if (vdec->slots[vpu_buf->fs_id].curr != vpu_buf) {
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED);
|
||||
vdec->slots[vpu_buf->fs_id].pend = vpu_buf;
|
||||
} else {
|
||||
vpu_set_buffer_state(vbuf, vdec->slots[vpu_buf->fs_id].state);
|
||||
}
|
||||
dev_err(inst->dev, "[%d] repeat alloc fs %d (v4l2 index %d)\n",
|
||||
inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n",
|
||||
inst->id, vpu_codec_state_name(inst->state), vbuf->vb2_buf.index, vdec->seq_tag);
|
||||
vpu_buf = to_vpu_vb2_buffer(vbuf);
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.id = vbuf->vb2_buf.index;
|
||||
info.id = vpu_buf->fs_id;
|
||||
info.type = MEM_RES_FRAME;
|
||||
info.tag = vdec->seq_tag;
|
||||
info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0);
|
||||
|
|
@ -1078,12 +1189,13 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
vpu_buf->tag = info.tag;
|
||||
vpu_buf->luma = info.luma_addr;
|
||||
vpu_buf->chroma_u = info.chroma_addr;
|
||||
vpu_buf->chroma_v = 0;
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE);
|
||||
vdec->slots[info.id] = vpu_buf;
|
||||
vdec->slots[info.id].tag = info.tag;
|
||||
vdec->slots[info.id].curr = vpu_buf;
|
||||
vdec->slots[info.id].state = VPU_BUF_STATE_INUSE;
|
||||
vdec->req_frame_count--;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1144,25 +1256,76 @@ static void vdec_recycle_buffer(struct vpu_inst *inst, struct vb2_v4l2_buffer *v
|
|||
v4l2_m2m_buf_queue(inst->fh.m2m_ctx, vbuf);
|
||||
}
|
||||
|
||||
static void vdec_clear_slots(struct vpu_inst *inst)
|
||||
static void vdec_release_curr_frame_store(struct vpu_inst *inst, u32 id)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
struct vpu_vb2_buffer *vpu_buf;
|
||||
struct vb2_v4l2_buffer *vbuf;
|
||||
|
||||
if (id >= vdec->slot_count)
|
||||
return;
|
||||
if (!vdec->slots[id].curr)
|
||||
return;
|
||||
|
||||
vpu_buf = vdec->slots[id].curr;
|
||||
vbuf = &vpu_buf->m2m_buf.vb;
|
||||
|
||||
vdec_response_fs_release(inst, id, vdec->slots[id].tag);
|
||||
if (vpu_buf->fs_id == id) {
|
||||
if (vpu_buf->state != VPU_BUF_STATE_READY)
|
||||
vdec_recycle_buffer(inst, vbuf);
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
|
||||
}
|
||||
|
||||
vdec->slots[id].curr = NULL;
|
||||
vdec->slots[id].state = VPU_BUF_STATE_IDLE;
|
||||
|
||||
if (vdec->slots[id].pend) {
|
||||
vpu_set_buffer_state(&vdec->slots[id].pend->m2m_buf.vb, VPU_BUF_STATE_IDLE);
|
||||
vdec->slots[id].pend = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void vdec_clear_slots(struct vpu_inst *inst)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) {
|
||||
if (!vdec->slots[i])
|
||||
for (i = 0; i < vdec->slot_count; i++) {
|
||||
if (!vdec->slots[i].curr)
|
||||
continue;
|
||||
|
||||
vpu_buf = vdec->slots[i];
|
||||
vbuf = &vpu_buf->m2m_buf.vb;
|
||||
|
||||
vpu_trace(inst->dev, "clear slot %d\n", i);
|
||||
vdec_response_fs_release(inst, i, vpu_buf->tag);
|
||||
vdec_recycle_buffer(inst, vbuf);
|
||||
vdec->slots[i]->state = VPU_BUF_STATE_IDLE;
|
||||
vdec->slots[i] = NULL;
|
||||
vdec_release_curr_frame_store(inst, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void vdec_update_v4l2_ctrl(struct vpu_inst *inst, u32 id, u32 val)
|
||||
{
|
||||
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id);
|
||||
|
||||
if (ctrl)
|
||||
v4l2_ctrl_s_ctrl(ctrl, val);
|
||||
}
|
||||
|
||||
static void vdec_update_v4l2_profile_level(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
|
||||
{
|
||||
switch (inst->out_format.pixfmt) {
|
||||
case V4L2_PIX_FMT_H264:
|
||||
case V4L2_PIX_FMT_H264_MVC:
|
||||
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
||||
vpu_get_h264_v4l2_profile(hdr));
|
||||
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
|
||||
vpu_get_h264_v4l2_level(hdr));
|
||||
break;
|
||||
case V4L2_PIX_FMT_HEVC:
|
||||
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
|
||||
vpu_get_hevc_v4l2_profile(hdr));
|
||||
vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
|
||||
vpu_get_hevc_v4l2_level(hdr));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1189,6 +1352,7 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
|
|||
vdec_init_crop(inst);
|
||||
vdec_init_mbi(inst);
|
||||
vdec_init_dcp(inst);
|
||||
vdec_update_v4l2_profile_level(inst, hdr);
|
||||
if (!vdec->seq_hdr_found) {
|
||||
vdec->seq_tag = vdec->codec_info.tag;
|
||||
if (vdec->is_source_changed) {
|
||||
|
|
@ -1263,39 +1427,29 @@ static void vdec_event_req_fs(struct vpu_inst *inst, struct vpu_fs_info *fs)
|
|||
static void vdec_evnet_rel_fs(struct vpu_inst *inst, struct vpu_fs_info *fs)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
struct vpu_vb2_buffer *vpu_buf;
|
||||
struct vb2_v4l2_buffer *vbuf;
|
||||
|
||||
if (!fs || fs->id >= ARRAY_SIZE(vdec->slots))
|
||||
if (!fs || fs->id >= vdec->slot_count)
|
||||
return;
|
||||
if (fs->type != MEM_RES_FRAME)
|
||||
return;
|
||||
|
||||
if (fs->id >= vpu_get_num_buffers(inst, inst->cap_format.type)) {
|
||||
if (fs->id >= vdec->slot_count) {
|
||||
dev_err(inst->dev, "[%d] invalid fs(%d) to release\n", inst->id, fs->id);
|
||||
return;
|
||||
}
|
||||
|
||||
vpu_inst_lock(inst);
|
||||
vpu_buf = vdec->slots[fs->id];
|
||||
vdec->slots[fs->id] = NULL;
|
||||
|
||||
if (!vpu_buf) {
|
||||
if (!vdec->slots[fs->id].curr) {
|
||||
dev_dbg(inst->dev, "[%d] fs[%d] has bee released\n", inst->id, fs->id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
vbuf = &vpu_buf->m2m_buf.vb;
|
||||
if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) {
|
||||
if (vdec->slots[fs->id].state == VPU_BUF_STATE_DECODED) {
|
||||
dev_dbg(inst->dev, "[%d] frame skip\n", inst->id);
|
||||
vdec->sequence++;
|
||||
}
|
||||
|
||||
vdec_response_fs_release(inst, fs->id, vpu_buf->tag);
|
||||
if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_READY)
|
||||
vdec_recycle_buffer(inst, vbuf);
|
||||
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
|
||||
vdec_release_curr_frame_store(inst, fs->id);
|
||||
vpu_process_capture_buffer(inst);
|
||||
|
||||
exit:
|
||||
|
|
@ -1485,6 +1639,11 @@ static void vdec_cleanup(struct vpu_inst *inst)
|
|||
return;
|
||||
|
||||
vdec = inst->priv;
|
||||
if (vdec) {
|
||||
kfree(vdec->slots);
|
||||
vdec->slots = NULL;
|
||||
vdec->slot_count = 0;
|
||||
}
|
||||
vfree(vdec);
|
||||
inst->priv = NULL;
|
||||
vfree(inst);
|
||||
|
|
@ -1606,10 +1765,42 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vdec_get_slot_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
struct vpu_vb2_buffer *vpu_buf;
|
||||
int num = -1;
|
||||
|
||||
vpu_inst_lock(inst);
|
||||
if (i >= vdec->slot_count || !vdec->slots[i].addr)
|
||||
goto exit;
|
||||
|
||||
vpu_buf = vdec->slots[i].curr;
|
||||
|
||||
num = scnprintf(str, size, "slot[%2d] :", i);
|
||||
if (vpu_buf) {
|
||||
num += scnprintf(str + num, size - num, " %2d",
|
||||
vpu_buf->m2m_buf.vb.vb2_buf.index);
|
||||
num += scnprintf(str + num, size - num, "; state = %d", vdec->slots[i].state);
|
||||
} else {
|
||||
num += scnprintf(str + num, size - num, " -1");
|
||||
}
|
||||
|
||||
if (vdec->slots[i].pend)
|
||||
num += scnprintf(str + num, size - num, "; %d",
|
||||
vdec->slots[i].pend->m2m_buf.vb.vb2_buf.index);
|
||||
|
||||
num += scnprintf(str + num, size - num, "\n");
|
||||
exit:
|
||||
vpu_inst_unlock(inst);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i)
|
||||
{
|
||||
struct vdec_t *vdec = inst->priv;
|
||||
int num = -1;
|
||||
int num;
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
|
|
@ -1664,6 +1855,7 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i
|
|||
vdec->codec_info.vui_present);
|
||||
break;
|
||||
default:
|
||||
num = vdec_get_slot_debug_info(inst, str, size, i - 10);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1687,6 +1879,8 @@ static struct vpu_inst_ops vdec_inst_ops = {
|
|||
.get_debug_info = vdec_get_debug_info,
|
||||
.wait_prepare = vpu_inst_unlock,
|
||||
.wait_finish = vpu_inst_lock,
|
||||
.attach_frame_store = vdec_attach_frame_store,
|
||||
.reset_frame_store = vdec_reset_frame_store,
|
||||
};
|
||||
|
||||
static void vdec_init(struct file *file)
|
||||
|
|
@ -1727,6 +1921,16 @@ static int vdec_open(struct file *file)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vdec->slots = kmalloc_array(VDEC_SLOT_CNT_DFT,
|
||||
sizeof(*vdec->slots),
|
||||
GFP_KERNEL | __GFP_ZERO);
|
||||
if (!vdec->slots) {
|
||||
vfree(vdec);
|
||||
vfree(inst);
|
||||
return -ENOMEM;
|
||||
}
|
||||
vdec->slot_count = VDEC_SLOT_CNT_DFT;
|
||||
|
||||
inst->ops = &vdec_inst_ops;
|
||||
inst->formats = vdec_formats;
|
||||
inst->type = VPU_CORE_TYPE_DEC;
|
||||
|
|
|
|||
|
|
@ -222,6 +222,8 @@ struct vpu_inst_ops {
|
|||
int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i);
|
||||
void (*wait_prepare)(struct vpu_inst *inst);
|
||||
void (*wait_finish)(struct vpu_inst *inst);
|
||||
void (*attach_frame_store)(struct vpu_inst *inst, struct vb2_buffer *vb);
|
||||
void (*reset_frame_store)(struct vpu_inst *inst);
|
||||
};
|
||||
|
||||
struct vpu_inst {
|
||||
|
|
@ -295,7 +297,8 @@ enum {
|
|||
VPU_BUF_STATE_DECODED,
|
||||
VPU_BUF_STATE_READY,
|
||||
VPU_BUF_STATE_SKIP,
|
||||
VPU_BUF_STATE_ERROR
|
||||
VPU_BUF_STATE_ERROR,
|
||||
VPU_BUF_STATE_CHANGED
|
||||
};
|
||||
|
||||
struct vpu_vb2_buffer {
|
||||
|
|
@ -304,8 +307,8 @@ struct vpu_vb2_buffer {
|
|||
dma_addr_t chroma_u;
|
||||
dma_addr_t chroma_v;
|
||||
unsigned int state;
|
||||
u32 tag;
|
||||
u32 average_qp;
|
||||
s32 fs_id;
|
||||
};
|
||||
|
||||
void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val);
|
||||
|
|
|
|||
|
|
@ -108,76 +108,3 @@ u32 vpu_color_cvrt_full_range_i2v(u32 full_range)
|
|||
|
||||
return V4L2_QUANTIZATION_LIM_RANGE;
|
||||
}
|
||||
|
||||
int vpu_color_check_primaries(u32 primaries)
|
||||
{
|
||||
return vpu_color_cvrt_primaries_v2i(primaries) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int vpu_color_check_transfers(u32 transfers)
|
||||
{
|
||||
return vpu_color_cvrt_transfers_v2i(transfers) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int vpu_color_check_matrix(u32 matrix)
|
||||
{
|
||||
return vpu_color_cvrt_matrix_v2i(matrix) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
int vpu_color_check_full_range(u32 full_range)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
switch (full_range) {
|
||||
case V4L2_QUANTIZATION_FULL_RANGE:
|
||||
case V4L2_QUANTIZATION_LIM_RANGE:
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range)
|
||||
{
|
||||
u32 transfers;
|
||||
u32 matrix;
|
||||
u32 full_range;
|
||||
|
||||
switch (primaries) {
|
||||
case V4L2_COLORSPACE_REC709:
|
||||
transfers = V4L2_XFER_FUNC_709;
|
||||
matrix = V4L2_YCBCR_ENC_709;
|
||||
break;
|
||||
case V4L2_COLORSPACE_470_SYSTEM_M:
|
||||
case V4L2_COLORSPACE_470_SYSTEM_BG:
|
||||
case V4L2_COLORSPACE_SMPTE170M:
|
||||
transfers = V4L2_XFER_FUNC_709;
|
||||
matrix = V4L2_YCBCR_ENC_601;
|
||||
break;
|
||||
case V4L2_COLORSPACE_SMPTE240M:
|
||||
transfers = V4L2_XFER_FUNC_SMPTE240M;
|
||||
matrix = V4L2_YCBCR_ENC_SMPTE240M;
|
||||
break;
|
||||
case V4L2_COLORSPACE_BT2020:
|
||||
transfers = V4L2_XFER_FUNC_709;
|
||||
matrix = V4L2_YCBCR_ENC_BT2020;
|
||||
break;
|
||||
default:
|
||||
transfers = V4L2_XFER_FUNC_DEFAULT;
|
||||
matrix = V4L2_YCBCR_ENC_DEFAULT;
|
||||
break;
|
||||
}
|
||||
full_range = V4L2_QUANTIZATION_LIM_RANGE;
|
||||
|
||||
if (ptransfers)
|
||||
*ptransfers = transfers;
|
||||
if (pmatrix)
|
||||
*pmatrix = matrix;
|
||||
if (pfull_range)
|
||||
*pfull_range = full_range;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ static char *vpu_stat_name[] = {
|
|||
[VPU_BUF_STATE_READY] = "ready",
|
||||
[VPU_BUF_STATE_SKIP] = "skip",
|
||||
[VPU_BUF_STATE_ERROR] = "error",
|
||||
[VPU_BUF_STATE_CHANGED] = "changed",
|
||||
};
|
||||
|
||||
static inline const char *to_vpu_stat_name(int state)
|
||||
|
|
@ -164,6 +165,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
|
|||
for (i = 0; i < vb2_get_num_buffers(vq); i++) {
|
||||
struct vb2_buffer *vb;
|
||||
struct vb2_v4l2_buffer *vbuf;
|
||||
struct vpu_vb2_buffer *vpu_buf;
|
||||
|
||||
vb = vb2_get_buffer(vq, i);
|
||||
if (!vb)
|
||||
|
|
@ -173,13 +175,24 @@ static int vpu_dbg_instance(struct seq_file *s, void *data)
|
|||
continue;
|
||||
|
||||
vbuf = to_vb2_v4l2_buffer(vb);
|
||||
vpu_buf = to_vpu_vb2_buffer(vbuf);
|
||||
|
||||
num = scnprintf(str, sizeof(str),
|
||||
"capture[%2d] state = %10s, %8s\n",
|
||||
"capture[%2d] state = %10s, %8s",
|
||||
i, vb2_stat_name[vb->state],
|
||||
to_vpu_stat_name(vpu_get_buffer_state(vbuf)));
|
||||
if (seq_write(s, str, num))
|
||||
return 0;
|
||||
|
||||
if (vpu_buf->fs_id >= 0) {
|
||||
num = scnprintf(str, sizeof(str), "; fs %d", vpu_buf->fs_id);
|
||||
if (seq_write(s, str, num))
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = scnprintf(str, sizeof(str), "\n");
|
||||
if (seq_write(s, str, num))
|
||||
return 0;
|
||||
}
|
||||
|
||||
num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ struct vpu_dec_codec_info {
|
|||
u32 decoded_height;
|
||||
struct v4l2_fract frame_rate;
|
||||
u32 dsp_asp_ratio;
|
||||
u32 profile_idc;
|
||||
u32 level_idc;
|
||||
u32 bit_depth_luma;
|
||||
u32 bit_depth_chroma;
|
||||
|
|
@ -147,6 +148,17 @@ struct vpu_dec_codec_info {
|
|||
u32 mbi_size;
|
||||
u32 dcp_size;
|
||||
u32 stride;
|
||||
union {
|
||||
struct {
|
||||
u32 constraint_set5_flag : 1;
|
||||
u32 constraint_set4_flag : 1;
|
||||
u32 constraint_set3_flag : 1;
|
||||
u32 constraint_set2_flag : 1;
|
||||
u32 constraint_set1_flag : 1;
|
||||
u32 constraint_set0_flag : 1;
|
||||
};
|
||||
u32 constraint_set_flags;
|
||||
};
|
||||
};
|
||||
|
||||
struct vpu_dec_pic_info {
|
||||
|
|
|
|||
|
|
@ -509,3 +509,126 @@ const char *vpu_codec_state_name(enum vpu_codec_state state)
|
|||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
struct codec_id_mapping {
|
||||
u32 id;
|
||||
u32 v4l2_id;
|
||||
};
|
||||
|
||||
static struct codec_id_mapping h264_profiles[] = {
|
||||
{66, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE},
|
||||
{77, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN},
|
||||
{88, V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED},
|
||||
{100, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH}
|
||||
};
|
||||
|
||||
static struct codec_id_mapping h264_levels[] = {
|
||||
{10, V4L2_MPEG_VIDEO_H264_LEVEL_1_0},
|
||||
{9, V4L2_MPEG_VIDEO_H264_LEVEL_1B},
|
||||
{11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1},
|
||||
{12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2},
|
||||
{13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3},
|
||||
{20, V4L2_MPEG_VIDEO_H264_LEVEL_2_0},
|
||||
{21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1},
|
||||
{22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2},
|
||||
{30, V4L2_MPEG_VIDEO_H264_LEVEL_3_0},
|
||||
{31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1},
|
||||
{32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2},
|
||||
{40, V4L2_MPEG_VIDEO_H264_LEVEL_4_0},
|
||||
{41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1},
|
||||
{42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2},
|
||||
{50, V4L2_MPEG_VIDEO_H264_LEVEL_5_0},
|
||||
{51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1},
|
||||
{52, V4L2_MPEG_VIDEO_H264_LEVEL_5_2},
|
||||
{60, V4L2_MPEG_VIDEO_H264_LEVEL_6_0},
|
||||
{61, V4L2_MPEG_VIDEO_H264_LEVEL_6_1},
|
||||
{62, V4L2_MPEG_VIDEO_H264_LEVEL_6_2}
|
||||
};
|
||||
|
||||
static struct codec_id_mapping hevc_profiles[] = {
|
||||
{1, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN},
|
||||
{2, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10}
|
||||
};
|
||||
|
||||
static struct codec_id_mapping hevc_levels[] = {
|
||||
{30, V4L2_MPEG_VIDEO_HEVC_LEVEL_1},
|
||||
{60, V4L2_MPEG_VIDEO_HEVC_LEVEL_2},
|
||||
{63, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1},
|
||||
{90, V4L2_MPEG_VIDEO_HEVC_LEVEL_3},
|
||||
{93, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1},
|
||||
{120, V4L2_MPEG_VIDEO_HEVC_LEVEL_4},
|
||||
{123, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1},
|
||||
{150, V4L2_MPEG_VIDEO_HEVC_LEVEL_5},
|
||||
{153, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1},
|
||||
{156, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2},
|
||||
{180, V4L2_MPEG_VIDEO_HEVC_LEVEL_6},
|
||||
{183, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1},
|
||||
{186, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2}
|
||||
};
|
||||
|
||||
static u32 vpu_find_v4l2_id(u32 id, struct codec_id_mapping *array, u32 array_sz)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (!array || !array_sz)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < array_sz; i++) {
|
||||
if (id == array[i].id)
|
||||
return array[i].v4l2_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr)
|
||||
{
|
||||
if (!hdr)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In H.264 Document section A.2.1.1 Constrained Baseline profile
|
||||
* Conformance of a bitstream to the Constrained Baseline profile is indicated by
|
||||
* profile_idc being equal to 66 with constraint_set1_flag being equal to 1.
|
||||
*/
|
||||
if (hdr->profile_idc == 66 && hdr->constraint_set1_flag)
|
||||
return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
|
||||
|
||||
return vpu_find_v4l2_id(hdr->profile_idc, h264_profiles, ARRAY_SIZE(h264_profiles));
|
||||
}
|
||||
|
||||
u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr)
|
||||
{
|
||||
if (!hdr)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In H.264 Document section 7.4.2.1.1 Sequence parameter set data semantics
|
||||
* If profile_idc is equal to 66, 77, or 88 and level_idc is equal to 11,
|
||||
* constraint_set3_flag equal to 1 indicates that the coded video sequence
|
||||
* obeys all constraints specified in Annex A for level 1b
|
||||
* and constraint_set3_flag equal to 0 indicates that the coded video sequence
|
||||
* obeys all constraints specified in Annex A for level 1.1.
|
||||
*/
|
||||
if (hdr->level_idc == 11 && hdr->constraint_set3_flag &&
|
||||
(hdr->profile_idc == 66 || hdr->profile_idc == 77 || hdr->profile_idc == 88))
|
||||
return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
|
||||
|
||||
return vpu_find_v4l2_id(hdr->level_idc, h264_levels, ARRAY_SIZE(h264_levels));
|
||||
}
|
||||
|
||||
u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr)
|
||||
{
|
||||
if (!hdr)
|
||||
return 0;
|
||||
|
||||
return vpu_find_v4l2_id(hdr->profile_idc, hevc_profiles, ARRAY_SIZE(hevc_profiles));
|
||||
}
|
||||
|
||||
u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr)
|
||||
{
|
||||
if (!hdr)
|
||||
return 0;
|
||||
|
||||
return vpu_find_v4l2_id(hdr->level_idc, hevc_levels, ARRAY_SIZE(hevc_levels));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#ifndef _AMPHION_VPU_HELPERS_H
|
||||
#define _AMPHION_VPU_HELPERS_H
|
||||
|
||||
#include "vpu_defs.h"
|
||||
|
||||
struct vpu_pair {
|
||||
u32 src;
|
||||
u32 dst;
|
||||
|
|
@ -54,10 +56,6 @@ static inline u8 vpu_helper_read_byte(struct vpu_buffer *stream_buffer, u32 pos)
|
|||
return pdata[pos % stream_buffer->length];
|
||||
}
|
||||
|
||||
int vpu_color_check_primaries(u32 primaries);
|
||||
int vpu_color_check_transfers(u32 transfers);
|
||||
int vpu_color_check_matrix(u32 matrix);
|
||||
int vpu_color_check_full_range(u32 full_range);
|
||||
u32 vpu_color_cvrt_primaries_v2i(u32 primaries);
|
||||
u32 vpu_color_cvrt_primaries_i2v(u32 primaries);
|
||||
u32 vpu_color_cvrt_transfers_v2i(u32 transfers);
|
||||
|
|
@ -66,8 +64,12 @@ u32 vpu_color_cvrt_matrix_v2i(u32 matrix);
|
|||
u32 vpu_color_cvrt_matrix_i2v(u32 matrix);
|
||||
u32 vpu_color_cvrt_full_range_v2i(u32 full_range);
|
||||
u32 vpu_color_cvrt_full_range_i2v(u32 full_range);
|
||||
int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range);
|
||||
|
||||
int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src);
|
||||
int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst);
|
||||
|
||||
u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr);
|
||||
u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr);
|
||||
u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr);
|
||||
u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -908,7 +908,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt,
|
|||
info->frame_rate.numerator = 1000;
|
||||
info->frame_rate.denominator = pkt->data[8];
|
||||
info->dsp_asp_ratio = pkt->data[9];
|
||||
info->level_idc = pkt->data[10];
|
||||
info->profile_idc = (pkt->data[10] >> 8) & 0xff;
|
||||
info->level_idc = pkt->data[10] & 0xff;
|
||||
info->bit_depth_luma = pkt->data[13];
|
||||
info->bit_depth_chroma = pkt->data[14];
|
||||
info->chroma_fmt = pkt->data[15];
|
||||
|
|
@ -925,6 +926,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt,
|
|||
info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128;
|
||||
else
|
||||
info->pixfmt = V4L2_PIX_FMT_NV12M_8L128;
|
||||
if (pkt->hdr.num > 28)
|
||||
info->constraint_set_flags = pkt->data[28];
|
||||
if (info->frame_rate.numerator && info->frame_rate.denominator) {
|
||||
unsigned long n, d;
|
||||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,3 @@ void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data)
|
|||
mbox_send_message(core->tx_data.ch, &data);
|
||||
mbox_send_message(core->tx_type.ch, &type);
|
||||
}
|
||||
|
||||
void vpu_mbox_enable_rx(struct vpu_dev *dev)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,5 @@ int vpu_mbox_request(struct vpu_core *core);
|
|||
void vpu_mbox_free(struct vpu_core *core);
|
||||
void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data);
|
||||
void vpu_mbox_send_type(struct vpu_core *core, u32 type);
|
||||
void vpu_mbox_enable_rx(struct vpu_dev *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -501,14 +501,25 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq,
|
|||
call_void_vop(inst, release);
|
||||
}
|
||||
|
||||
if (V4L2_TYPE_IS_CAPTURE(vq->type))
|
||||
call_void_vop(inst, reset_frame_store);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vpu_vb2_buf_init(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
|
||||
struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
|
||||
|
||||
vpu_buf->fs_id = -1;
|
||||
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
|
||||
|
||||
if (!inst->ops->attach_frame_store || V4L2_TYPE_IS_OUTPUT(vb->type))
|
||||
return 0;
|
||||
|
||||
call_void_vop(inst, attach_frame_store, vb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,6 +57,25 @@
|
|||
#define CSI2RX_LANES_MAX 4
|
||||
#define CSI2RX_STREAMS_MAX 4
|
||||
|
||||
#define CSI2RX_ERROR_IRQS_REG 0x28
|
||||
#define CSI2RX_ERROR_IRQS_MASK_REG 0x2C
|
||||
|
||||
#define CSI2RX_STREAM3_FIFO_OVERFLOW_IRQ BIT(19)
|
||||
#define CSI2RX_STREAM2_FIFO_OVERFLOW_IRQ BIT(18)
|
||||
#define CSI2RX_STREAM1_FIFO_OVERFLOW_IRQ BIT(17)
|
||||
#define CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ BIT(16)
|
||||
#define CSI2RX_FRONT_TRUNC_HDR_IRQ BIT(12)
|
||||
#define CSI2RX_PROT_TRUNCATED_PACKET_IRQ BIT(11)
|
||||
#define CSI2RX_FRONT_LP_NO_PAYLOAD_IRQ BIT(10)
|
||||
#define CSI2RX_SP_INVALID_RCVD_IRQ BIT(9)
|
||||
#define CSI2RX_DATA_ID_IRQ BIT(7)
|
||||
#define CSI2RX_HEADER_CORRECTED_ECC_IRQ BIT(6)
|
||||
#define CSI2RX_HEADER_ECC_IRQ BIT(5)
|
||||
#define CSI2RX_PAYLOAD_CRC_IRQ BIT(4)
|
||||
|
||||
#define CSI2RX_ECC_ERRORS GENMASK(7, 4)
|
||||
#define CSI2RX_PACKET_ERRORS GENMASK(12, 9)
|
||||
|
||||
enum csi2rx_pads {
|
||||
CSI2RX_PAD_SINK,
|
||||
CSI2RX_PAD_SOURCE_STREAM0,
|
||||
|
|
@ -71,9 +90,32 @@ struct csi2rx_fmt {
|
|||
u8 bpp;
|
||||
};
|
||||
|
||||
struct csi2rx_event {
|
||||
u32 mask;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct csi2rx_event csi2rx_events[] = {
|
||||
{ CSI2RX_STREAM3_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 3 FIFO detected" },
|
||||
{ CSI2RX_STREAM2_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 2 FIFO detected" },
|
||||
{ CSI2RX_STREAM1_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 1 FIFO detected" },
|
||||
{ CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 0 FIFO detected" },
|
||||
{ CSI2RX_FRONT_TRUNC_HDR_IRQ, "A truncated header [short or long] has been received" },
|
||||
{ CSI2RX_PROT_TRUNCATED_PACKET_IRQ, "A truncated long packet has been received" },
|
||||
{ CSI2RX_FRONT_LP_NO_PAYLOAD_IRQ, "A truncated long packet has been received. No payload" },
|
||||
{ CSI2RX_SP_INVALID_RCVD_IRQ, "A reserved or invalid short packet has been received" },
|
||||
{ CSI2RX_DATA_ID_IRQ, "Data ID error in the header packet" },
|
||||
{ CSI2RX_HEADER_CORRECTED_ECC_IRQ, "ECC error detected and corrected" },
|
||||
{ CSI2RX_HEADER_ECC_IRQ, "Unrecoverable ECC error" },
|
||||
{ CSI2RX_PAYLOAD_CRC_IRQ, "CRC error" },
|
||||
};
|
||||
|
||||
#define CSI2RX_NUM_EVENTS ARRAY_SIZE(csi2rx_events)
|
||||
|
||||
struct csi2rx_priv {
|
||||
struct device *dev;
|
||||
unsigned int count;
|
||||
int error_irq;
|
||||
|
||||
/*
|
||||
* Used to prevent race conditions between multiple,
|
||||
|
|
@ -95,6 +137,7 @@ struct csi2rx_priv {
|
|||
u8 max_lanes;
|
||||
u8 max_streams;
|
||||
bool has_internal_dphy;
|
||||
u32 events[CSI2RX_NUM_EVENTS];
|
||||
|
||||
struct v4l2_subdev subdev;
|
||||
struct v4l2_async_notifier notifier;
|
||||
|
|
@ -124,6 +167,54 @@ static const struct csi2rx_fmt formats[] = {
|
|||
{ .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, },
|
||||
};
|
||||
|
||||
static void csi2rx_configure_error_irq_mask(void __iomem *base,
|
||||
struct csi2rx_priv *csi2rx)
|
||||
{
|
||||
u32 error_irq_mask = 0;
|
||||
|
||||
error_irq_mask |= CSI2RX_ECC_ERRORS;
|
||||
error_irq_mask |= CSI2RX_PACKET_ERRORS;
|
||||
|
||||
/*
|
||||
* Iterate through all source pads and check if they are linked
|
||||
* to an active remote pad. If an active remote pad is found,
|
||||
* calculate the corresponding bit position and set it in
|
||||
* mask, enabling the stream overflow error in the mask.
|
||||
*/
|
||||
for (int i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) {
|
||||
struct media_pad *remote_pad;
|
||||
|
||||
remote_pad = media_pad_remote_pad_first(&csi2rx->pads[i]);
|
||||
if (remote_pad) {
|
||||
int pad = i - CSI2RX_PAD_SOURCE_STREAM0;
|
||||
u32 bit_mask = CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ << pad;
|
||||
|
||||
error_irq_mask |= bit_mask;
|
||||
}
|
||||
}
|
||||
|
||||
writel(error_irq_mask, base + CSI2RX_ERROR_IRQS_MASK_REG);
|
||||
}
|
||||
|
||||
static irqreturn_t csi2rx_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct csi2rx_priv *csi2rx = dev_id;
|
||||
int i;
|
||||
u32 error_status, error_mask;
|
||||
|
||||
error_status = readl(csi2rx->base + CSI2RX_ERROR_IRQS_REG);
|
||||
error_mask = readl(csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG);
|
||||
|
||||
for (i = 0; i < CSI2RX_NUM_EVENTS; i++)
|
||||
if ((error_status & csi2rx_events[i].mask) &&
|
||||
(error_mask & csi2rx_events[i].mask))
|
||||
csi2rx->events[i]++;
|
||||
|
||||
writel(error_status, csi2rx->base + CSI2RX_ERROR_IRQS_REG);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
|
@ -220,6 +311,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
|
|||
reset_control_deassert(csi2rx->p_rst);
|
||||
csi2rx_reset(csi2rx);
|
||||
|
||||
if (csi2rx->error_irq >= 0)
|
||||
csi2rx_configure_error_irq_mask(csi2rx->base, csi2rx);
|
||||
|
||||
reg = csi2rx->num_lanes << 8;
|
||||
for (i = 0; i < csi2rx->num_lanes; i++) {
|
||||
reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csi2rx->lanes[i]);
|
||||
|
|
@ -332,6 +426,8 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx)
|
|||
reset_control_assert(csi2rx->sys_rst);
|
||||
clk_disable_unprepare(csi2rx->sys_clk);
|
||||
|
||||
writel(0, csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG);
|
||||
|
||||
for (i = 0; i < csi2rx->max_streams; i++) {
|
||||
writel(CSI2RX_STREAM_CTRL_STOP,
|
||||
csi2rx->base + CSI2RX_STREAM_CTRL_REG(i));
|
||||
|
|
@ -363,6 +459,21 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx)
|
|||
}
|
||||
}
|
||||
|
||||
static int csi2rx_log_status(struct v4l2_subdev *sd)
|
||||
{
|
||||
struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(sd);
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < CSI2RX_NUM_EVENTS; i++) {
|
||||
if (csi2rx->events[i])
|
||||
dev_info(csi2rx->dev, "%s events: %d\n",
|
||||
csi2rx_events[i].name,
|
||||
csi2rx->events[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev);
|
||||
|
|
@ -468,7 +579,12 @@ static const struct v4l2_subdev_video_ops csi2rx_video_ops = {
|
|||
.s_stream = csi2rx_s_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops csi2rx_core_ops = {
|
||||
.log_status = csi2rx_log_status,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops csi2rx_subdev_ops = {
|
||||
.core = &csi2rx_core_ops,
|
||||
.video = &csi2rx_video_ops,
|
||||
.pad = &csi2rx_pad_ops,
|
||||
};
|
||||
|
|
@ -705,6 +821,21 @@ static int csi2rx_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
||||
csi2rx->error_irq = platform_get_irq_byname_optional(pdev, "error_irq");
|
||||
|
||||
if (csi2rx->error_irq < 0) {
|
||||
dev_dbg(csi2rx->dev, "Optional interrupt not defined, proceeding without it\n");
|
||||
} else {
|
||||
ret = devm_request_irq(csi2rx->dev, csi2rx->error_irq,
|
||||
csi2rx_irq_handler, 0,
|
||||
dev_name(&pdev->dev), csi2rx);
|
||||
if (ret) {
|
||||
dev_err(csi2rx->dev,
|
||||
"Unable to request interrupt: %d\n", ret);
|
||||
goto err_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
ret = v4l2_subdev_init_finalize(&csi2rx->subdev);
|
||||
if (ret)
|
||||
goto err_cleanup;
|
||||
|
|
|
|||
|
|
@ -598,6 +598,27 @@ static void _bswap16(u16 *a)
|
|||
*a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8);
|
||||
}
|
||||
|
||||
static dma_addr_t mxc_jpeg_get_plane_dma_addr(struct vb2_buffer *buf, unsigned int plane_no)
|
||||
{
|
||||
if (plane_no >= buf->num_planes)
|
||||
return 0;
|
||||
return vb2_dma_contig_plane_dma_addr(buf, plane_no) + buf->planes[plane_no].data_offset;
|
||||
}
|
||||
|
||||
static void *mxc_jpeg_get_plane_vaddr(struct vb2_buffer *buf, unsigned int plane_no)
|
||||
{
|
||||
if (plane_no >= buf->num_planes)
|
||||
return NULL;
|
||||
return vb2_plane_vaddr(buf, plane_no) + buf->planes[plane_no].data_offset;
|
||||
}
|
||||
|
||||
static unsigned long mxc_jpeg_get_plane_payload(struct vb2_buffer *buf, unsigned int plane_no)
|
||||
{
|
||||
if (plane_no >= buf->num_planes)
|
||||
return 0;
|
||||
return vb2_get_plane_payload(buf, plane_no) - buf->planes[plane_no].data_offset;
|
||||
}
|
||||
|
||||
static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf,
|
||||
unsigned long len)
|
||||
{
|
||||
|
|
@ -610,11 +631,11 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf,
|
|||
return;
|
||||
|
||||
for (plane_no = 0; plane_no < buf->num_planes; plane_no++) {
|
||||
payload = vb2_get_plane_payload(buf, plane_no);
|
||||
payload = mxc_jpeg_get_plane_payload(buf, plane_no);
|
||||
if (len == 0)
|
||||
len = payload;
|
||||
dma_addr = vb2_dma_contig_plane_dma_addr(buf, plane_no);
|
||||
vaddr = vb2_plane_vaddr(buf, plane_no);
|
||||
dma_addr = mxc_jpeg_get_plane_dma_addr(buf, plane_no);
|
||||
vaddr = mxc_jpeg_get_plane_vaddr(buf, plane_no);
|
||||
v4l2_dbg(3, debug, &jpeg->v4l2_dev,
|
||||
"plane %d (vaddr=%p dma_addr=%x payload=%ld):",
|
||||
plane_no, vaddr, dma_addr, payload);
|
||||
|
|
@ -712,16 +733,15 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
|
|||
struct mxc_jpeg_q_data *q_data;
|
||||
|
||||
q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type);
|
||||
desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0);
|
||||
desc->buf_base0 = mxc_jpeg_get_plane_dma_addr(raw_buf, 0);
|
||||
desc->buf_base1 = 0;
|
||||
if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
|
||||
if (raw_buf->num_planes == 2)
|
||||
desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1);
|
||||
desc->buf_base1 = mxc_jpeg_get_plane_dma_addr(raw_buf, 1);
|
||||
else
|
||||
desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0];
|
||||
}
|
||||
desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) +
|
||||
offset;
|
||||
desc->stm_bufbase = mxc_jpeg_get_plane_dma_addr(jpeg_buf, 0) + offset;
|
||||
}
|
||||
|
||||
static bool mxc_jpeg_is_extended_sequential(const struct mxc_jpeg_fmt *fmt)
|
||||
|
|
@ -1029,8 +1049,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
|
|||
vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload);
|
||||
}
|
||||
dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n",
|
||||
vb2_get_plane_payload(&dst_buf->vb2_buf, 0),
|
||||
vb2_get_plane_payload(&dst_buf->vb2_buf, 1));
|
||||
mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 0),
|
||||
mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 1));
|
||||
}
|
||||
|
||||
/* short preview of the results */
|
||||
|
|
@ -1889,8 +1909,8 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
|
|||
struct mxc_jpeg_sof *psof = NULL;
|
||||
struct mxc_jpeg_sos *psos = NULL;
|
||||
struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb);
|
||||
u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0);
|
||||
u32 size = vb2_get_plane_payload(vb, 0);
|
||||
u8 *src_addr = (u8 *)mxc_jpeg_get_plane_vaddr(vb, 0);
|
||||
u32 size = mxc_jpeg_get_plane_payload(vb, 0);
|
||||
int ret;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
|
@ -2027,6 +2047,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
|
|||
i, vb2_plane_size(vb, i), sizeimage);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!IS_ALIGNED(mxc_jpeg_get_plane_dma_addr(vb, i), MXC_JPEG_ADDR_ALIGNMENT)) {
|
||||
dev_err(dev, "planes[%d] address is not %d aligned\n",
|
||||
i, MXC_JPEG_ADDR_ALIGNMENT);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) {
|
||||
vb2_set_plane_payload(vb, 0, 0);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#define MXC_JPEG_MAX_PLANES 2
|
||||
#define MXC_JPEG_PATTERN_WIDTH 128
|
||||
#define MXC_JPEG_PATTERN_HEIGHT 64
|
||||
#define MXC_JPEG_ADDR_ALIGNMENT 16
|
||||
|
||||
enum mxc_jpeg_enc_state {
|
||||
MXC_JPEG_ENCODING = 0, /* jpeg encode phase */
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/reset.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <media/mipi-csi2.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
|
|
@ -229,25 +230,6 @@
|
|||
|
||||
#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
|
||||
|
||||
/* MIPI CSI-2 Data Types */
|
||||
#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18
|
||||
#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19
|
||||
#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a
|
||||
#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c
|
||||
#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d
|
||||
#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e
|
||||
#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f
|
||||
#define MIPI_CSI2_DATA_TYPE_RGB565 0x22
|
||||
#define MIPI_CSI2_DATA_TYPE_RGB666 0x23
|
||||
#define MIPI_CSI2_DATA_TYPE_RGB888 0x24
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW6 0x28
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW7 0x29
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c
|
||||
#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d
|
||||
#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x))
|
||||
|
||||
struct mipi_csis_event {
|
||||
bool debug;
|
||||
u32 mask;
|
||||
|
|
@ -357,116 +339,116 @@ static const struct csis_pix_format mipi_csis_formats[] = {
|
|||
{
|
||||
.code = MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
.output = MEDIA_BUS_FMT_UYVY8_1X16,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_YUV422_8,
|
||||
.data_type = MIPI_CSI2_DT_YUV422_8B,
|
||||
.width = 16,
|
||||
},
|
||||
/* RGB formats. */
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_RGB565_1X16,
|
||||
.output = MEDIA_BUS_FMT_RGB565_1X16,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RGB565,
|
||||
.data_type = MIPI_CSI2_DT_RGB565,
|
||||
.width = 16,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_BGR888_1X24,
|
||||
.output = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RGB888,
|
||||
.data_type = MIPI_CSI2_DT_RGB888,
|
||||
.width = 24,
|
||||
},
|
||||
/* RAW (Bayer and greyscale) formats. */
|
||||
{
|
||||
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
|
||||
.output = MEDIA_BUS_FMT_SBGGR8_1X8,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
|
||||
.output = MEDIA_BUS_FMT_SGBRG8_1X8,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
|
||||
.output = MEDIA_BUS_FMT_SGRBG8_1X8,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
|
||||
.output = MEDIA_BUS_FMT_SRGGB8_1X8,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_Y8_1X8,
|
||||
.output = MEDIA_BUS_FMT_Y8_1X8,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
.output = MEDIA_BUS_FMT_SBGGR10_1X10,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW10,
|
||||
.data_type = MIPI_CSI2_DT_RAW10,
|
||||
.width = 10,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
.output = MEDIA_BUS_FMT_SGBRG10_1X10,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW10,
|
||||
.data_type = MIPI_CSI2_DT_RAW10,
|
||||
.width = 10,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
.output = MEDIA_BUS_FMT_SGRBG10_1X10,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW10,
|
||||
.data_type = MIPI_CSI2_DT_RAW10,
|
||||
.width = 10,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
.output = MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW10,
|
||||
.data_type = MIPI_CSI2_DT_RAW10,
|
||||
.width = 10,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_Y10_1X10,
|
||||
.output = MEDIA_BUS_FMT_Y10_1X10,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW10,
|
||||
.data_type = MIPI_CSI2_DT_RAW10,
|
||||
.width = 10,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
|
||||
.output = MEDIA_BUS_FMT_SBGGR12_1X12,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW12,
|
||||
.data_type = MIPI_CSI2_DT_RAW12,
|
||||
.width = 12,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
|
||||
.output = MEDIA_BUS_FMT_SGBRG12_1X12,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW12,
|
||||
.data_type = MIPI_CSI2_DT_RAW12,
|
||||
.width = 12,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
|
||||
.output = MEDIA_BUS_FMT_SGRBG12_1X12,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW12,
|
||||
.data_type = MIPI_CSI2_DT_RAW12,
|
||||
.width = 12,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
|
||||
.output = MEDIA_BUS_FMT_SRGGB12_1X12,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW12,
|
||||
.data_type = MIPI_CSI2_DT_RAW12,
|
||||
.width = 12,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_Y12_1X12,
|
||||
.output = MEDIA_BUS_FMT_Y12_1X12,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW12,
|
||||
.data_type = MIPI_CSI2_DT_RAW12,
|
||||
.width = 12,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SBGGR14_1X14,
|
||||
.output = MEDIA_BUS_FMT_SBGGR14_1X14,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW14,
|
||||
.data_type = MIPI_CSI2_DT_RAW14,
|
||||
.width = 14,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGBRG14_1X14,
|
||||
.output = MEDIA_BUS_FMT_SGBRG14_1X14,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW14,
|
||||
.data_type = MIPI_CSI2_DT_RAW14,
|
||||
.width = 14,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SGRBG14_1X14,
|
||||
.output = MEDIA_BUS_FMT_SGRBG14_1X14,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW14,
|
||||
.data_type = MIPI_CSI2_DT_RAW14,
|
||||
.width = 14,
|
||||
}, {
|
||||
.code = MEDIA_BUS_FMT_SRGGB14_1X14,
|
||||
.output = MEDIA_BUS_FMT_SRGGB14_1X14,
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW14,
|
||||
.data_type = MIPI_CSI2_DT_RAW14,
|
||||
.width = 14,
|
||||
},
|
||||
/* JPEG */
|
||||
|
|
@ -494,7 +476,7 @@ static const struct csis_pix_format mipi_csis_formats[] = {
|
|||
* SoC that can support quad pixel mode, this will have to be
|
||||
* revisited.
|
||||
*/
|
||||
.data_type = MIPI_CSI2_DATA_TYPE_RAW8,
|
||||
.data_type = MIPI_CSI2_DT_RAW8,
|
||||
.width = 8,
|
||||
}
|
||||
};
|
||||
|
|
@ -583,7 +565,7 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis,
|
|||
*
|
||||
* TODO: Verify which other formats require DUAL (or QUAD) modes.
|
||||
*/
|
||||
if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8)
|
||||
if (csis_fmt->data_type == MIPI_CSI2_DT_YUV422_8B)
|
||||
val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL;
|
||||
|
||||
val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright 2019-2020 NXP
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
|
|
@ -245,26 +246,41 @@ static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi)
|
|||
|
||||
/* Panic will assert when the buffers are 50% full */
|
||||
|
||||
/* For i.MX8QXP C0 and i.MX8MN ISI IER version */
|
||||
/* For i.MX8MN ISI IER version */
|
||||
static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = {
|
||||
.oflw_y_buf_en = { .offset = 19, .mask = 0x80000 },
|
||||
.oflw_u_buf_en = { .offset = 21, .mask = 0x200000 },
|
||||
.oflw_v_buf_en = { .offset = 23, .mask = 0x800000 },
|
||||
.oflw_y_buf_en = { .mask = BIT(19) },
|
||||
.oflw_u_buf_en = { .mask = BIT(21) },
|
||||
.oflw_v_buf_en = { .mask = BIT(23) },
|
||||
|
||||
.panic_y_buf_en = {.offset = 20, .mask = 0x100000 },
|
||||
.panic_u_buf_en = {.offset = 22, .mask = 0x400000 },
|
||||
.panic_v_buf_en = {.offset = 24, .mask = 0x1000000 },
|
||||
.panic_y_buf_en = { .mask = BIT(20) },
|
||||
.panic_u_buf_en = { .mask = BIT(22) },
|
||||
.panic_v_buf_en = { .mask = BIT(24) },
|
||||
};
|
||||
|
||||
/* For i.MX8MP ISI IER version */
|
||||
/* For i.MX8QXP C0 and i.MX8MP ISI IER version */
|
||||
static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = {
|
||||
.oflw_y_buf_en = { .offset = 18, .mask = 0x40000 },
|
||||
.oflw_u_buf_en = { .offset = 20, .mask = 0x100000 },
|
||||
.oflw_v_buf_en = { .offset = 22, .mask = 0x400000 },
|
||||
.oflw_y_buf_en = { .mask = BIT(18) },
|
||||
.oflw_u_buf_en = { .mask = BIT(20) },
|
||||
.oflw_v_buf_en = { .mask = BIT(22) },
|
||||
|
||||
.panic_y_buf_en = {.offset = 19, .mask = 0x80000 },
|
||||
.panic_u_buf_en = {.offset = 21, .mask = 0x200000 },
|
||||
.panic_v_buf_en = {.offset = 23, .mask = 0x800000 },
|
||||
.panic_y_buf_en = { .mask = BIT(19) },
|
||||
.panic_u_buf_en = { .mask = BIT(21) },
|
||||
.panic_v_buf_en = { .mask = BIT(23) },
|
||||
};
|
||||
|
||||
/* For i.MX8QM ISI IER version */
|
||||
static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_qm = {
|
||||
.oflw_y_buf_en = { .mask = BIT(16) },
|
||||
.oflw_u_buf_en = { .mask = BIT(19) },
|
||||
.oflw_v_buf_en = { .mask = BIT(22) },
|
||||
|
||||
.excs_oflw_y_buf_en = { .mask = BIT(17) },
|
||||
.excs_oflw_u_buf_en = { .mask = BIT(20) },
|
||||
.excs_oflw_v_buf_en = { .mask = BIT(23) },
|
||||
|
||||
.panic_y_buf_en = { .mask = BIT(18) },
|
||||
.panic_u_buf_en = { .mask = BIT(21) },
|
||||
.panic_v_buf_en = { .mask = BIT(24) },
|
||||
};
|
||||
|
||||
/* Panic will assert when the buffers are 50% full */
|
||||
|
|
@ -274,11 +290,6 @@ static const struct mxc_isi_set_thd mxc_imx8_isi_thd_v1 = {
|
|||
.panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 },
|
||||
};
|
||||
|
||||
static const struct clk_bulk_data mxc_imx8mn_clks[] = {
|
||||
{ .id = "axi" },
|
||||
{ .id = "apb" },
|
||||
};
|
||||
|
||||
static const struct mxc_isi_plat_data mxc_imx8mn_data = {
|
||||
.model = MXC_ISI_IMX8MN,
|
||||
.num_ports = 1,
|
||||
|
|
@ -286,8 +297,6 @@ static const struct mxc_isi_plat_data mxc_imx8mn_data = {
|
|||
.reg_offset = 0,
|
||||
.ier_reg = &mxc_imx8_isi_ier_v1,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.clks = mxc_imx8mn_clks,
|
||||
.num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
|
||||
.buf_active_reverse = false,
|
||||
.gasket_ops = &mxc_imx8_gasket_ops,
|
||||
.has_36bit_dma = false,
|
||||
|
|
@ -300,8 +309,6 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = {
|
|||
.reg_offset = 0x2000,
|
||||
.ier_reg = &mxc_imx8_isi_ier_v2,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.clks = mxc_imx8mn_clks,
|
||||
.num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
|
||||
.buf_active_reverse = true,
|
||||
.gasket_ops = &mxc_imx8_gasket_ops,
|
||||
.has_36bit_dma = true,
|
||||
|
|
@ -314,8 +321,6 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = {
|
|||
.reg_offset = 0x0,
|
||||
.ier_reg = &mxc_imx8_isi_ier_v2,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.clks = mxc_imx8mn_clks,
|
||||
.num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
|
||||
.buf_active_reverse = true,
|
||||
.has_36bit_dma = false,
|
||||
};
|
||||
|
|
@ -327,13 +332,33 @@ static const struct mxc_isi_plat_data mxc_imx93_data = {
|
|||
.reg_offset = 0,
|
||||
.ier_reg = &mxc_imx8_isi_ier_v2,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.clks = mxc_imx8mn_clks,
|
||||
.num_clks = ARRAY_SIZE(mxc_imx8mn_clks),
|
||||
.buf_active_reverse = true,
|
||||
.gasket_ops = &mxc_imx93_gasket_ops,
|
||||
.has_36bit_dma = false,
|
||||
};
|
||||
|
||||
static const struct mxc_isi_plat_data mxc_imx8qm_data = {
|
||||
.model = MXC_ISI_IMX8QM,
|
||||
.num_ports = 5,
|
||||
.num_channels = 8,
|
||||
.reg_offset = 0x10000,
|
||||
.ier_reg = &mxc_imx8_isi_ier_qm,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.buf_active_reverse = true,
|
||||
.has_36bit_dma = false,
|
||||
};
|
||||
|
||||
static const struct mxc_isi_plat_data mxc_imx8qxp_data = {
|
||||
.model = MXC_ISI_IMX8QXP,
|
||||
.num_ports = 5,
|
||||
.num_channels = 6,
|
||||
.reg_offset = 0x10000,
|
||||
.ier_reg = &mxc_imx8_isi_ier_v2,
|
||||
.set_thd = &mxc_imx8_isi_thd_v1,
|
||||
.buf_active_reverse = true,
|
||||
.has_36bit_dma = false,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Power management
|
||||
*/
|
||||
|
|
@ -385,7 +410,7 @@ static int mxc_isi_runtime_suspend(struct device *dev)
|
|||
{
|
||||
struct mxc_isi_dev *isi = dev_get_drvdata(dev);
|
||||
|
||||
clk_bulk_disable_unprepare(isi->pdata->num_clks, isi->clks);
|
||||
clk_bulk_disable_unprepare(isi->num_clks, isi->clks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -395,7 +420,7 @@ static int mxc_isi_runtime_resume(struct device *dev)
|
|||
struct mxc_isi_dev *isi = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(isi->pdata->num_clks, isi->clks);
|
||||
ret = clk_bulk_prepare_enable(isi->num_clks, isi->clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable clocks (%d)\n", ret);
|
||||
return ret;
|
||||
|
|
@ -413,27 +438,6 @@ static const struct dev_pm_ops mxc_isi_pm_ops = {
|
|||
* Probe, remove & driver
|
||||
*/
|
||||
|
||||
static int mxc_isi_clk_get(struct mxc_isi_dev *isi)
|
||||
{
|
||||
unsigned int size = isi->pdata->num_clks
|
||||
* sizeof(*isi->clks);
|
||||
int ret;
|
||||
|
||||
isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL);
|
||||
if (!isi->clks)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks,
|
||||
isi->clks);
|
||||
if (ret < 0) {
|
||||
dev_err(isi->dev, "Failed to acquire clocks: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxc_isi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -456,34 +460,25 @@ static int mxc_isi_probe(struct platform_device *pdev)
|
|||
if (!isi->pipes)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mxc_isi_clk_get(isi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to get clocks\n");
|
||||
return ret;
|
||||
}
|
||||
isi->num_clks = devm_clk_bulk_get_all(dev, &isi->clks);
|
||||
if (isi->num_clks < 0)
|
||||
return dev_err_probe(dev, isi->num_clks, "Failed to get clocks\n");
|
||||
|
||||
isi->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(isi->regs)) {
|
||||
dev_err(dev, "Failed to get ISI register map\n");
|
||||
return PTR_ERR(isi->regs);
|
||||
}
|
||||
if (IS_ERR(isi->regs))
|
||||
return dev_err_probe(dev, PTR_ERR(isi->regs),
|
||||
"Failed to get ISI register map\n");
|
||||
|
||||
if (isi->pdata->gasket_ops) {
|
||||
isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"fsl,blk-ctrl");
|
||||
if (IS_ERR(isi->gasket)) {
|
||||
ret = PTR_ERR(isi->gasket);
|
||||
dev_err(dev, "failed to get gasket: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(isi->gasket))
|
||||
return dev_err_probe(dev, PTR_ERR(isi->gasket),
|
||||
"failed to get gasket\n");
|
||||
}
|
||||
|
||||
dma_size = isi->pdata->has_36bit_dma ? 36 : 32;
|
||||
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to set DMA mask\n");
|
||||
return ret;
|
||||
}
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size));
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
|
|
@ -541,6 +536,8 @@ static void mxc_isi_remove(struct platform_device *pdev)
|
|||
static const struct of_device_id mxc_isi_of_match[] = {
|
||||
{ .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data },
|
||||
{ .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data },
|
||||
{ .compatible = "fsl,imx8qm-isi", .data = &mxc_imx8qm_data },
|
||||
{ .compatible = "fsl,imx8qxp-isi", .data = &mxc_imx8qxp_data },
|
||||
{ .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data },
|
||||
{ .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data },
|
||||
{ /* sentinel */ },
|
||||
|
|
|
|||
|
|
@ -114,7 +114,6 @@ struct mxc_isi_buffer {
|
|||
};
|
||||
|
||||
struct mxc_isi_reg {
|
||||
u32 offset;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
|
|
@ -158,6 +157,8 @@ struct mxc_gasket_ops {
|
|||
enum model {
|
||||
MXC_ISI_IMX8MN,
|
||||
MXC_ISI_IMX8MP,
|
||||
MXC_ISI_IMX8QM,
|
||||
MXC_ISI_IMX8QXP,
|
||||
MXC_ISI_IMX8ULP,
|
||||
MXC_ISI_IMX93,
|
||||
};
|
||||
|
|
@ -170,8 +171,6 @@ struct mxc_isi_plat_data {
|
|||
const struct mxc_isi_ier_reg *ier_reg;
|
||||
const struct mxc_isi_set_thd *set_thd;
|
||||
const struct mxc_gasket_ops *gasket_ops;
|
||||
const struct clk_bulk_data *clks;
|
||||
unsigned int num_clks;
|
||||
bool buf_active_reverse;
|
||||
bool has_36bit_dma;
|
||||
};
|
||||
|
|
@ -283,6 +282,7 @@ struct mxc_isi_dev {
|
|||
|
||||
void __iomem *regs;
|
||||
struct clk_bulk_data *clks;
|
||||
int num_clks;
|
||||
struct regmap *gasket;
|
||||
|
||||
struct mxc_isi_crossbar crossbar;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue