[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
Linus Torvalds 2025-07-31 13:16:09 -07:00
commit 0cdee263bc
314 changed files with 23149 additions and 4618 deletions

View File

@ -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>

View File

@ -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

View File

@ -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>;
};

View File

@ -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>;
};
};
};
};
...

View File

@ -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>;
};
};
};
};
...

View File

@ -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>;
};

View File

@ -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:

View File

@ -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

View File

@ -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:
- |

View File

@ -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>;
};
};
};
};
...

View File

@ -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:
- |

View File

@ -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:

View File

@ -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:

View File

@ -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>;
};

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -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>`

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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[];

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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;
}

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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,
};

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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,
};

View File

@ -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,
};
/* -----------------------------------------------------------------------------

View File

@ -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,
};
/* -----------------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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);
}

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -600,7 +600,7 @@ static int lt6911uxe_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&lt6911uxe->sd, client, &lt6911uxe_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");

View File

@ -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;

View File

@ -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)

View File

@ -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++)

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}
/* -----------------------------------------------------------------------------

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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

View File

@ -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");

View File

@ -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");

View File

@ -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,

View File

@ -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)
*/

View File

@ -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)
{

View File

@ -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(

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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 {

View File

@ -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));
}

View File

@ -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

View File

@ -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;

View File

@ -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)
{
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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 */ },

View File

@ -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