Merge tag 'media/v7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - Add support for GMSL1 and GMSL‑coax modules (PCI mgb4)

 - Add driver for TI VIP

 - AV1 – first kernel support (pixel‑format, decoder, transcoder)

 - Three new camera‑sensor drivers (os05b10, s5k3m5, s5kjn1)

 - Synopsys CSI‑2 receiver driver

 - Verisilicon & rkvdec – major fixes and enhancements

 - IPU6 (and 7) fixes and preparation for metadata

 - omap3isp: v4l2-compliance updates

 - Fix DVB streaming, drop wait_prepare/finish (dvb/vb2)

* tag 'media/v7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (307 commits)
  media: uvcvideo: Pass allocation size directly to uvc_alloc_urb_buffer
  media: uvcvideo: Fix allocation for small frame sizes
  media: uvcvideo: Return queued buffers on start_streaming() failure
  media: uvcvideo: Create an ID namespace for streaming output terminals
  media: rkvdec: Add HEVC support for the VDPU383 variant
  media: rkvdec: Add HEVC support for the VDPU381 variant
  media: rkvdec: Add H264 support for the VDPU383 variant
  media: rkvdec: Add H264 support for the VDPU381 variant
  media: rkvdec: Disable multicore support
  media: rkvdec: Enable all clocks without naming them
  media: rkvdec: Support per-variant interrupt handler
  media: rkvdec: Add RCB and SRAM support
  media: rkvdec: Add variant specific coded formats list
  media: rkvdec: Move hevc functions to common file
  media: rkvdec: Move h264 functions to common file
  media: rkvdec: Use structs to represent the HW RPS
  media: rkvdec: Move cabac tables to their own source file
  media: rkvdec: Switch to using structs instead of writel
  media: visl: Add HEVC short and long term RPS sets
  media: v4l2-ctrls: Add hevc_ext_sps_[ls]t_rps controls
  ...
This commit is contained in:
Linus Torvalds
2026-02-11 12:20:25 -08:00
265 changed files with 23552 additions and 4743 deletions

View File

@@ -31,9 +31,11 @@ Global (PCI card) parameters
| 0 - No module present
| 1 - FPDL3
| 2 - GMSL (one serializer, two daisy chained deserializers)
| 3 - GMSL (one serializer, two deserializers)
| 4 - GMSL (two deserializers with two daisy chain outputs)
| 2 - GMSL3 (one serializer, two daisy chained deserializers)
| 3 - GMSL3 (one serializer, two deserializers)
| 4 - GMSL3 (two deserializers with two daisy chain outputs)
| 6 - GMSL1
| 8 - GMSL3 coax
**module_version** (R):
Module version number. Zero in case of a missing module.
@@ -42,7 +44,8 @@ Global (PCI card) parameters
Firmware type.
| 1 - FPDL3
| 2 - GMSL
| 2 - GMSL3
| 3 - GMSL1
**fw_version** (R):
Firmware version number.

View File

@@ -30,7 +30,27 @@ properties:
- adi,adv7282-m
reg:
maxItems: 1
minItems: 1
items:
- description: main register map
- description: VPP or CSI register map
- description: CSI register map
description:
The ADV7180 family may have up to three register maps. All chips have
the main register map. The availability of the CSI and VPP register maps
depends on the chip variant.
The addresses of the CSI and VPP register maps are programmable by
software. They depend on the board layout and other devices on the I2C
bus and are determined by the hardware designer to avoid address
conflicts on the I2C bus.
reg-names:
minItems: 1
items:
- const: main
- enum: [ csi, vpp ]
- const: csi
powerdown-gpios:
maxItems: 1
@@ -138,6 +158,62 @@ allOf:
required:
- ports
- if:
properties:
compatible:
contains:
enum:
- adi,adv7180
- adi,adv7180cp
- adi,adv7180st
- adi,adv7182
then:
properties:
reg:
maxItems: 1
reg-names:
maxItems: 1
- if:
properties:
compatible:
contains:
enum:
- adi,adv7281
- adi,adv7281-m
- adi,adv7281-ma
then:
properties:
reg:
minItems: 1
maxItems: 2
reg-names:
minItems: 1
items:
- const: main
- const: csi
- if:
properties:
compatible:
contains:
enum:
- adi,adv7280
- adi,adv7282
then:
properties:
reg:
minItems: 1
maxItems: 2
reg-names:
minItems: 1
items:
- const: main
- const: vpp
examples:
- |
i2c {
@@ -187,3 +263,22 @@ examples:
};
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
composite-in@20 {
compatible = "adi,adv7280-m";
reg = <0x20>, <0x42>, <0x44>;
reg-names = "main", "vpp", "csi";
port {
adv7280_out: endpoint {
bus-width = <8>;
remote-endpoint = <&vin1ep>;
};
};
};
};

View File

@@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/ovti,os05b10.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: OmniVision OS05B10 Image Sensor
maintainers:
- Elgin Perumbilly <elgin.perumbilly@siliconsignals.io>
description:
The OmniVision OS05B10 is a 5MP (2592x1944) color CMOS image sensor controlled
through an I2C-compatible SCCB bus. it outputs RAW10/RAW12 format and uses a
1/2.78" optical format.
properties:
compatible:
const: ovti,os05b10
reg:
maxItems: 1
clocks:
items:
- description: XCLK clock
avdd-supply:
description: Analog Domain Power Supply (2.8v)
dovdd-supply:
description: I/O Domain Power Supply (1.8v)
dvdd-supply:
description: Digital Domain Power Supply (1.2v)
reset-gpios:
maxItems: 1
description: Reset Pin GPIO Control (active low)
port:
description: MIPI CSI-2 transmitter port
$ref: /schemas/graph.yaml#/$defs/port-base
additionalProperties: false
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
oneOf:
- items:
- const: 1
- const: 2
- const: 3
- const: 4
- items:
- const: 1
- const: 2
required:
- data-lanes
- link-frequencies
required:
- compatible
- reg
- clocks
- avdd-supply
- dovdd-supply
- dvdd-supply
- port
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
camera-sensor@36 {
compatible = "ovti,os05b10";
reg = <0x36>;
clocks = <&os05b10_clk>;
reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
avdd-supply = <&os05b10_avdd_2v8>;
dvdd-supply = <&os05b10_dvdd_1v2>;
dovdd-supply = <&os05b10_dovdd_1v8>;
port {
cam_out: endpoint {
remote-endpoint = <&mipi_in_cam>;
data-lanes = <1 2 3 4>;
link-frequencies = /bits/ 64 <600000000>;
};
};
};
};

View File

@@ -14,6 +14,9 @@ description: |-
The OV5647 is a raw image sensor with MIPI CSI-2 and CCP2 image data
interfaces and CCI (I2C compatible) control bus.
allOf:
- $ref: /schemas/media/video-interface-devices.yaml#
properties:
compatible:
const: ovti,ov5647
@@ -30,6 +33,15 @@ properties:
description: Reference to the GPIO connected to the pwdn pin. Active high.
maxItems: 1
avdd-supply:
description: Analog voltage supply, 2.8 volts
dvdd-supply:
description: Digital core voltage supply, 1.5 volts
dovdd-supply:
description: Digital I/O voltage supply, 1.7 - 3.0 volts
port:
$ref: /schemas/graph.yaml#/$defs/port-base
additionalProperties: false
@@ -48,7 +60,7 @@ required:
- clocks
- port
additionalProperties: false
unevaluatedProperties: false
examples:
- |

View File

@@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/samsung,s5k3m5.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S5K3M5 Image Sensor
description:
Samsung S5K3M5 (ISOCELL 3M5) image sensor is a 13MP image sensor.
The sensor is controlled over a serial camera control bus protocol,
the widest supported output image frame size is 4208x3120 at 30 frames
per second, data output format is RAW10 transferred over 4-lane
MIPI D-PHY interface.
maintainers:
- Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
allOf:
- $ref: /schemas/media/video-interface-devices.yaml#
properties:
compatible:
const: samsung,s5k3m5
reg:
maxItems: 1
clocks:
description: MCLK supply clock.
maxItems: 1
reset-gpios:
description: Active low GPIO connected to RESET pad of the sensor.
maxItems: 1
afvdd-supply:
description: Autofocus actuator voltage supply, 2.8-3.0 volts.
vdda-supply:
description: Analogue voltage supply, 2.8 volts.
vddd-supply:
description: Digital core voltage supply, 1.05 volts.
vddio-supply:
description: Digital I/O voltage supply, 2.8 or 1.8 volts.
port:
$ref: /schemas/graph.yaml#/$defs/port-base
additionalProperties: false
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
items:
- const: 1
- const: 2
- const: 3
- const: 4
required:
- link-frequencies
required:
- compatible
- reg
- port
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
camera@10 {
compatible = "samsung,s5k3m5";
reg = <0x10>;
clocks = <&camera_mclk 0>;
assigned-clocks = <&camera_mclk 0>;
assigned-clock-rates = <24000000>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
vdda-supply = <&vreg_2p8>;
vddd-supply = <&vreg_1p05>;
vddio-supply = <&vreg_1p8>;
port {
endpoint {
link-frequencies = /bits/ 64 <602500000>;
remote-endpoint = <&mipi_csi2_ep>;
};
};
};
};
...

View File

@@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/samsung,s5kjn1.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung S5KJN1 Image Sensor
description:
Samsung S5KJN1 (ISOCELL JN1) image sensor is a 50MP image sensor.
The sensor is controlled over a serial camera control bus protocol,
the widest supported output image frame size is 8160x6144 at 10 frames
per second, data output format is RAW10 transferred over 4-lane
MIPI D-PHY interface.
maintainers:
- Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
allOf:
- $ref: /schemas/media/video-interface-devices.yaml#
properties:
compatible:
const: samsung,s5kjn1
reg:
maxItems: 1
clocks:
description: MCLK supply clock.
maxItems: 1
reset-gpios:
description: Active low GPIO connected to RESET pad of the sensor.
maxItems: 1
afvdd-supply:
description: Autofocus actuator voltage supply, 2.8-3.0 volts.
vdda-supply:
description: Analogue voltage supply, 2.8 volts.
vddd-supply:
description: Digital core voltage supply, 1.05 volts.
vddio-supply:
description: Digital I/O voltage supply, 1.8 volts.
port:
$ref: /schemas/graph.yaml#/$defs/port-base
additionalProperties: false
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
items:
- const: 1
- const: 2
- const: 3
- const: 4
required:
- link-frequencies
required:
- compatible
- reg
- port
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
camera@56 {
compatible = "samsung,s5kjn1";
reg = <0x56>;
clocks = <&camera_mclk 0>;
assigned-clocks = <&camera_mclk 0>;
assigned-clock-rates = <24000000>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
vdda-supply = <&vreg_2p8>;
vddd-supply = <&vreg_1p05>;
vddio-supply = <&vreg_1p8>;
port {
endpoint {
link-frequencies = /bits/ 64 <700000000>;
remote-endpoint = <&mipi_csi2_ep>;
};
};
};
};
...

View File

@@ -1,55 +0,0 @@
Toshiba et8ek8 5MP sensor
Toshiba et8ek8 5MP sensor is an image sensor found in Nokia N900 device
More detailed documentation can be found in
Documentation/devicetree/bindings/media/video-interfaces.txt .
Mandatory properties
--------------------
- compatible: "toshiba,et8ek8"
- reg: I2C address (0x3e, or an alternative address)
- vana-supply: Analogue voltage supply (VANA), 2.8 volts
- clocks: External clock to the sensor
- reset-gpios: XSHUTDOWN GPIO. The XSHUTDOWN signal is active low. The sensor
is in hardware standby mode when the signal is in the low state.
Optional properties
-------------------
- flash-leds: See ../video-interfaces.txt
- lens-focus: See ../video-interfaces.txt
Endpoint node mandatory properties
----------------------------------
- remote-endpoint: A phandle to the bus receiver's endpoint node.
Example
-------
&i2c3 {
clock-frequency = <400000>;
cam1: camera@3e {
compatible = "toshiba,et8ek8";
reg = <0x3e>;
vana-supply = <&vaux4>;
clocks = <&isp 0>;
assigned-clocks = <&isp 0>;
assigned-clock-rates = <9600000>;
reset-gpio = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */
port {
csi_cam1: endpoint {
remote-endpoint = <&csi_out1>;
};
};
};
};

View File

@@ -0,0 +1,87 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/i2c/toshiba,et8ek8.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Toshiba et8ek8 5MP sensor
maintainers:
- Pavel Machek <pavel@ucw.cz>
- Sakari Ailus <sakari.ailus@iki.fi>
description:
Toshiba et8ek8 5MP sensor is an image sensor found in Nokia N900 device
allOf:
- $ref: /schemas/media/video-interface-devices.yaml#
properties:
compatible:
const: toshiba,et8ek8
reg:
description:
I2C address (0x3e, or an alternative address)
maxItems: 1
vana-supply:
description:
Analogue voltage supply (VANA), 2.8 volts
clocks:
maxItems: 1
reset-gpios:
description:
XSHUTDOWN GPIO. The XSHUTDOWN signal is active low. The sensor
is in hardware standby mode when the signal is in the low state.
maxItems: 1
flash-leds:
maxItems: 1
port:
$ref: /schemas/graph.yaml#/$defs/port-base
additionalProperties: false
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
- vana-supply
- clocks
- reset-gpios
- port
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
camera@3e {
compatible = "toshiba,et8ek8";
reg = <0x3e>;
vana-supply = <&vaux4>;
clocks = <&isp 0>;
assigned-clocks = <&isp 0>;
assigned-clock-rates = <9600000>;
reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
flash-leds = <&led>;
port {
csi_cam1: endpoint {
remote-endpoint = <&csi_out1>;
};
};
};
};

View File

@@ -55,6 +55,12 @@ properties:
minItems: 1 # Wrapper and all slots
maxItems: 5 # Wrapper and 4 slots
sram:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Optional phandle to a reserved on-chip SRAM regions. The SRAM can
be used for descriptor storage, which may improve bus utilization.
required:
- compatible
- reg

View File

@@ -120,6 +120,14 @@ properties:
items:
- const: top
vdda-phy-supply:
description:
Phandle to a 0.88V regulator supply to CSI PHYs.
vdda-pll-supply:
description:
Phandle to 1.2V regulator supply to CSI PHYs pll block.
ports:
$ref: /schemas/graph.yaml#/properties/ports
@@ -160,6 +168,8 @@ required:
- power-domains
- power-domain-names
- ports
- vdda-phy-supply
- vdda-pll-supply
additionalProperties: false
@@ -328,6 +338,9 @@ examples:
power-domains = <&camcc CAM_CC_TITAN_TOP_GDSC>;
power-domain-names = "top";
vdda-phy-supply = <&vreg_l4a_0p88>;
vdda-pll-supply = <&vreg_l1c_1p2>;
ports {
#address-cells = <1>;
#size-cells = <0>;

View File

@@ -126,11 +126,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@@ -125,11 +125,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@@ -264,11 +264,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
required:
- clock-names

View File

@@ -91,11 +91,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@@ -207,11 +207,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
required:
- clock-names

View File

@@ -0,0 +1,439 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/qcom,sm6150-camss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm SM6150 Camera Subsystem (CAMSS)
maintainers:
- Wenmeng Liu <wenmeng.liu@oss.qualcomm.com>
description:
This binding describes the camera subsystem hardware found on SM6150
Qualcomm SoCs. It includes submodules such as CSIPHY (CSI Physical layer)
and CSID (CSI Decoder), which comply with the MIPI CSI2 protocol.
The subsystem also integrates a set of real-time image processing engines
and their associated configuration modules, as well as non-real-time engines.
properties:
compatible:
const: qcom,sm6150-camss
reg:
items:
- description: Registers for CSID 0
- description: Registers for CSID 1
- description: Registers for CSID Lite
- description: Registers for CSIPHY 0
- description: Registers for CSIPHY 1
- description: Registers for CSIPHY 2
- description: Registers for VFE 0
- description: Registers for VFE 1
- description: Registers for VFE Lite
- description: Registers for BPS (Bayer Processing Segment)
- description: Registers for CAMNOC
- description: Registers for CPAS CDM
- description: Registers for CPAS TOP
- description: Registers for ICP (Imaging Control Processor) CSR (Control and Status Registers)
- description: Registers for ICP QGIC (Qualcomm Generic Interrupt Controller)
- description: Registers for ICP SIERRA ((A5 subsystem communication))
- description: Registers for IPE (Image Postprocessing Engine) 0
- description: Registers for JPEG DMA
- description: Registers for JPEG ENC
- description: Registers for LRME (Low Resolution Motion Estimation)
reg-names:
items:
- const: csid0
- const: csid1
- const: csid_lite
- const: csiphy0
- const: csiphy1
- const: csiphy2
- const: vfe0
- const: vfe1
- const: vfe_lite
- const: bps
- const: camnoc
- const: cpas_cdm
- const: cpas_top
- const: icp_csr
- const: icp_qgic
- const: icp_sierra
- const: ipe0
- const: jpeg_dma
- const: jpeg_enc
- const: lrme
clocks:
maxItems: 33
clock-names:
items:
- const: gcc_ahb
- const: gcc_axi_hf
- const: camnoc_axi
- const: cpas_ahb
- const: csiphy0
- const: csiphy0_timer
- const: csiphy1
- const: csiphy1_timer
- const: csiphy2
- const: csiphy2_timer
- const: soc_ahb
- const: vfe0
- const: vfe0_axi
- const: vfe0_cphy_rx
- const: vfe0_csid
- const: vfe1
- const: vfe1_axi
- const: vfe1_cphy_rx
- const: vfe1_csid
- const: vfe_lite
- const: vfe_lite_cphy_rx
- const: vfe_lite_csid
- const: bps
- const: bps_ahb
- const: bps_axi
- const: bps_areg
- const: icp
- const: ipe0
- const: ipe0_ahb
- const: ipe0_areg
- const: ipe0_axi
- const: jpeg
- const: lrme
interrupts:
maxItems: 15
interrupt-names:
items:
- const: csid0
- const: csid1
- const: csid_lite
- const: csiphy0
- const: csiphy1
- const: csiphy2
- const: vfe0
- const: vfe1
- const: vfe_lite
- const: camnoc
- const: cdm
- const: icp
- const: jpeg_dma
- const: jpeg_enc
- const: lrme
interconnects:
maxItems: 4
interconnect-names:
items:
- const: ahb
- const: hf_0
- const: hf_1
- const: sf_mnoc
iommus:
items:
- description: Camera IFE 0 non-protected stream
- description: Camera IFE 1 non-protected stream
- description: Camera IFE 3 non-protected stream
- description: Camera CDM non-protected stream
- description: Camera LRME read non-protected stream
- description: Camera IPE 0 read non-protected stream
- description: Camera BPS read non-protected stream
- description: Camera IPE 0 write non-protected stream
- description: Camera BPS write non-protected stream
- description: Camera LRME write non-protected stream
- description: Camera JPEG read non-protected stream
- description: Camera JPEG write non-protected stream
- description: Camera ICP stream
power-domains:
items:
- description:
IFE0 GDSC - Image Front End, Global Distributed Switch Controller.
- description:
IFE1 GDSC - Image Front End, Global Distributed Switch Controller.
- description:
Titan GDSC - Titan ISP Block, Global Distributed Switch Controller.
- description:
Titan BPS - Bayer Processing Segment, Global Distributed Switch Controller.
- description:
IPE GDSC - Image Postprocessing Engine, Global Distributed Switch Controller.
power-domain-names:
items:
- const: ife0
- const: ife1
- const: top
- const: bps
- const: ipe
vdd-csiphy-1p2-supply:
description:
Phandle to a 1.2V regulator supply to CSI PHYs.
vdd-csiphy-1p8-supply:
description:
Phandle to 1.8V regulator supply to CSI PHYs pll block.
ports:
$ref: /schemas/graph.yaml#/properties/ports
description:
CSI input ports.
patternProperties:
"^port@[0-2]$":
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description:
Input port for receiving CSI data from a CSIPHY.
properties:
endpoint:
$ref: video-interfaces.yaml#
unevaluatedProperties: false
properties:
data-lanes:
minItems: 1
maxItems: 4
required:
- data-lanes
required:
- compatible
- reg
- reg-names
- clocks
- clock-names
- interrupts
- interrupt-names
- interconnects
- interconnect-names
- iommus
- power-domains
- power-domain-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,qcs615-camcc.h>
#include <dt-bindings/clock/qcom,qcs615-gcc.h>
#include <dt-bindings/clock/qcom,rpmh.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include <dt-bindings/interconnect/qcom,qcs615-rpmh.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/power/qcom-rpmpd.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
camss: isp@acb3000 {
compatible = "qcom,sm6150-camss";
reg = <0x0 0x0acb3000 0x0 0x1000>,
<0x0 0x0acba000 0x0 0x1000>,
<0x0 0x0acc8000 0x0 0x1000>,
<0x0 0x0ac65000 0x0 0x1000>,
<0x0 0x0ac66000 0x0 0x1000>,
<0x0 0x0ac67000 0x0 0x1000>,
<0x0 0x0acaf000 0x0 0x4000>,
<0x0 0x0acb6000 0x0 0x4000>,
<0x0 0x0acc4000 0x0 0x4000>,
<0x0 0x0ac6f000 0x0 0x3000>,
<0x0 0x0ac42000 0x0 0x5000>,
<0x0 0x0ac48000 0x0 0x1000>,
<0x0 0x0ac40000 0x0 0x1000>,
<0x0 0x0ac18000 0x0 0x3000>,
<0x0 0x0ac00000 0x0 0x6000>,
<0x0 0x0ac10000 0x0 0x8000>,
<0x0 0x0ac87000 0x0 0x3000>,
<0x0 0x0ac52000 0x0 0x4000>,
<0x0 0x0ac4e000 0x0 0x4000>,
<0x0 0x0ac6b000 0x0 0x0a00>;
reg-names = "csid0",
"csid1",
"csid_lite",
"csiphy0",
"csiphy1",
"csiphy2",
"vfe0",
"vfe1",
"vfe_lite",
"bps",
"camnoc",
"cpas_cdm",
"cpas_top",
"icp_csr",
"icp_qgic",
"icp_sierra",
"ipe0",
"jpeg_dma",
"jpeg_enc",
"lrme";
clocks = <&gcc GCC_CAMERA_AHB_CLK>,
<&gcc GCC_CAMERA_HF_AXI_CLK>,
<&camcc CAM_CC_CAMNOC_AXI_CLK>,
<&camcc CAM_CC_CPAS_AHB_CLK>,
<&camcc CAM_CC_CSIPHY0_CLK>,
<&camcc CAM_CC_CSI0PHYTIMER_CLK>,
<&camcc CAM_CC_CSIPHY1_CLK>,
<&camcc CAM_CC_CSI1PHYTIMER_CLK>,
<&camcc CAM_CC_CSIPHY2_CLK>,
<&camcc CAM_CC_CSI2PHYTIMER_CLK>,
<&camcc CAM_CC_SOC_AHB_CLK>,
<&camcc CAM_CC_IFE_0_CLK>,
<&camcc CAM_CC_IFE_0_AXI_CLK>,
<&camcc CAM_CC_IFE_0_CPHY_RX_CLK>,
<&camcc CAM_CC_IFE_0_CSID_CLK>,
<&camcc CAM_CC_IFE_1_CLK>,
<&camcc CAM_CC_IFE_1_AXI_CLK>,
<&camcc CAM_CC_IFE_1_CPHY_RX_CLK>,
<&camcc CAM_CC_IFE_1_CSID_CLK>,
<&camcc CAM_CC_IFE_LITE_CLK>,
<&camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>,
<&camcc CAM_CC_IFE_LITE_CSID_CLK>,
<&camcc CAM_CC_BPS_CLK>,
<&camcc CAM_CC_BPS_AHB_CLK>,
<&camcc CAM_CC_BPS_AXI_CLK>,
<&camcc CAM_CC_BPS_AREG_CLK>,
<&camcc CAM_CC_ICP_CLK>,
<&camcc CAM_CC_IPE_0_CLK>,
<&camcc CAM_CC_IPE_0_AHB_CLK>,
<&camcc CAM_CC_IPE_0_AREG_CLK>,
<&camcc CAM_CC_IPE_0_AXI_CLK>,
<&camcc CAM_CC_JPEG_CLK>,
<&camcc CAM_CC_LRME_CLK>;
clock-names = "gcc_ahb",
"gcc_axi_hf",
"camnoc_axi",
"cpas_ahb",
"csiphy0",
"csiphy0_timer",
"csiphy1",
"csiphy1_timer",
"csiphy2",
"csiphy2_timer",
"soc_ahb",
"vfe0",
"vfe0_axi",
"vfe0_cphy_rx",
"vfe0_csid",
"vfe1",
"vfe1_axi",
"vfe1_cphy_rx",
"vfe1_csid",
"vfe_lite",
"vfe_lite_cphy_rx",
"vfe_lite_csid",
"bps",
"bps_ahb",
"bps_axi",
"bps_areg",
"icp",
"ipe0",
"ipe0_ahb",
"ipe0_areg",
"ipe0_axi",
"jpeg",
"lrme";
interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY
&config_noc SLAVE_CAMERA_CFG QCOM_ICC_TAG_ACTIVE_ONLY>,
<&mmss_noc MASTER_CAMNOC_HF0 QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
<&mmss_noc MASTER_CAMNOC_HF1 QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
<&mmss_noc MASTER_CAMNOC_SF QCOM_ICC_TAG_ALWAYS
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
interconnect-names = "ahb",
"hf_0",
"hf_1",
"sf_mnoc";
interrupts = <GIC_SPI 464 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 466 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 468 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 477 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 478 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 479 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 465 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 467 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 469 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 459 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 461 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 463 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 475 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 474 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 476 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "csid0",
"csid1",
"csid_lite",
"csiphy0",
"csiphy1",
"csiphy2",
"vfe0",
"vfe1",
"vfe_lite",
"camnoc",
"cdm",
"icp",
"jpeg_dma",
"jpeg_enc",
"lrme";
iommus = <&apps_smmu 0x0820 0x40>,
<&apps_smmu 0x0840 0x00>,
<&apps_smmu 0x0860 0x40>,
<&apps_smmu 0x0c00 0x00>,
<&apps_smmu 0x0cc0 0x00>,
<&apps_smmu 0x0c80 0x00>,
<&apps_smmu 0x0ca0 0x00>,
<&apps_smmu 0x0d00 0x00>,
<&apps_smmu 0x0d20 0x00>,
<&apps_smmu 0x0d40 0x00>,
<&apps_smmu 0x0d80 0x20>,
<&apps_smmu 0x0da0 0x20>,
<&apps_smmu 0x0de2 0x00>;
power-domains = <&camcc IFE_0_GDSC>,
<&camcc IFE_1_GDSC>,
<&camcc TITAN_TOP_GDSC>,
<&camcc BPS_GDSC>,
<&camcc IPE_0_GDSC>;
power-domain-names = "ife0",
"ife1",
"top",
"bps",
"ipe";
vdd-csiphy-1p2-supply = <&vreg_l11a_1p2>;
vdd-csiphy-1p8-supply = <&vreg_l12a_1p8>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
csiphy_ep0: endpoint {
data-lanes = <0 1>;
remote-endpoint = <&sensor_ep>;
};
};
};
};
};

View File

@@ -296,11 +296,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.8V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
required:
- clock-names

View File

@@ -134,11 +134,11 @@ properties:
vdda-phy-supply:
description:
Phandle to a regulator supply to PHY core block.
0.88V supply to CSIPHY IP blocks.
vdda-pll-supply:
description:
Phandle to 1.2V regulator supply to PHY refclk pll block.
1.2V supply to CSIPHY IP blocks.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@@ -120,11 +120,11 @@ properties:
vdd-csiphy-0p8-supply:
description:
Phandle to a 0.8V regulator supply to a PHY.
0.8V supply to a PHY.
vdd-csiphy-1p2-supply:
description:
Phandle to 1.2V regulator supply to a PHY.
1.2V supply to a PHY.
ports:
$ref: /schemas/graph.yaml#/properties/ports

View File

@@ -77,6 +77,7 @@ allOf:
- renesas,r9a07g043u-fcpvd
- renesas,r9a07g044-fcpvd
- renesas,r9a07g054-fcpvd
- renesas,r9a09g056-fcpvd
- renesas,r9a09g057-fcpvd
then:
properties:

View File

@@ -0,0 +1,141 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/rockchip,rk3568-mipi-csi2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Rockchip MIPI CSI-2 Receiver
maintainers:
- Michael Riesch <michael.riesch@collabora.com>
description:
The Rockchip MIPI CSI-2 Receiver is a CSI-2 bridge with one input port and
one output port. It receives the data with the help of an external MIPI PHY
(C-PHY or D-PHY) and passes it to the Rockchip Video Capture (VICAP) block.
properties:
compatible:
enum:
- rockchip,rk3568-mipi-csi2
reg:
maxItems: 1
interrupts:
items:
- description: Interrupt that signals changes in CSI2HOST_ERR1.
- description: Interrupt that signals changes in CSI2HOST_ERR2.
interrupt-names:
items:
- const: err1
- const: err2
clocks:
maxItems: 1
phys:
maxItems: 1
description: MIPI C-PHY or D-PHY.
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: Input port node. Connect to e.g., a MIPI CSI-2 image sensor.
properties:
endpoint:
$ref: video-interfaces.yaml#
unevaluatedProperties: false
properties:
bus-type:
enum:
- 1 # MEDIA_BUS_TYPE_CSI2_CPHY
- 4 # MEDIA_BUS_TYPE_CSI2_DPHY
data-lanes:
minItems: 1
maxItems: 4
required:
- bus-type
- data-lanes
port@1:
$ref: /schemas/graph.yaml#/properties/port
description: Output port connected to a Rockchip VICAP port.
required:
- port@0
- port@1
power-domains:
maxItems: 1
resets:
maxItems: 1
required:
- compatible
- reg
- clocks
- phys
- ports
- power-domains
- resets
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/rk3568-cru.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/media/video-interfaces.h>
#include <dt-bindings/power/rk3568-power.h>
soc {
interrupt-parent = <&gic>;
#address-cells = <2>;
#size-cells = <2>;
csi: csi@fdfb0000 {
compatible = "rockchip,rk3568-mipi-csi2";
reg = <0x0 0xfdfb0000 0x0 0x10000>;
interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "err1", "err2";
clocks = <&cru PCLK_CSI2HOST1>;
phys = <&csi_dphy>;
power-domains = <&power RK3568_PD_VI>;
resets = <&cru SRST_P_CSI2HOST1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
csi_in: port@0 {
reg = <0>;
csi_input: endpoint {
bus-type = <MEDIA_BUS_TYPE_CSI2_DPHY>;
data-lanes = <1 2 3 4>;
remote-endpoint = <&imx415_output>;
};
};
csi_out: port@1 {
reg = <1>;
csi_output: endpoint {
remote-endpoint = <&vicap_mipi_input>;
};
};
};
};
};

View File

@@ -1,71 +0,0 @@
OMAP 3 ISP Device Tree bindings
===============================
The DT definitions can be found in include/dt-bindings/media/omap3-isp.h.
Required properties
===================
compatible : must contain "ti,omap3-isp"
reg : the two registers sets (physical address and length) for the
ISP. The first set contains the core ISP registers up to
the end of the SBL block. The second set contains the
CSI PHYs and receivers registers.
interrupts : the ISP interrupt specifier
iommus : phandle and IOMMU specifier for the IOMMU that serves the ISP
syscon : the phandle and register offset to the Complex I/O or CSI-PHY
register
ti,phy-type : 0 -- OMAP3ISP_PHY_TYPE_COMPLEX_IO (e.g. 3430)
1 -- OMAP3ISP_PHY_TYPE_CSIPHY (e.g. 3630)
#clock-cells : Must be 1 --- the ISP provides two external clocks,
cam_xclka and cam_xclkb, at indices 0 and 1,
respectively. Please find more information on common
clock bindings in ../clock/clock-bindings.txt.
Port nodes (optional)
---------------------
More documentation on these bindings is available in
video-interfaces.txt in the same directory.
reg : The interface:
0 - parallel (CCDC)
1 - CSIPHY1 -- CSI2C / CCP2B on 3630;
CSI1 -- CSIb on 3430
2 - CSIPHY2 -- CSI2A / CCP2B on 3630;
CSI2 -- CSIa on 3430
Optional properties
===================
vdd-csiphy1-supply : voltage supply of the CSI-2 PHY 1
vdd-csiphy2-supply : voltage supply of the CSI-2 PHY 2
Endpoint nodes
--------------
lane-polarities : lane polarity (required on CSI-2)
0 -- not inverted; 1 -- inverted
data-lanes : an array of data lanes from 1 to 3. The length can
be either 1 or 2. (required on CSI-2)
clock-lanes : the clock lane (from 1 to 3). (required on CSI-2)
Example
=======
isp@480bc000 {
compatible = "ti,omap3-isp";
reg = <0x480bc000 0x12fc
0x480bd800 0x0600>;
interrupts = <24>;
iommus = <&mmu_isp>;
syscon = <&scm_conf 0x2f0>;
ti,phy-type = <OMAP3ISP_PHY_TYPE_CSIPHY>;
#clock-cells = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
};
};

View File

@@ -0,0 +1,189 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/ti,omap3isp.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments OMAP 3 Image Signal Processor (ISP)
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- Sakari Ailus <sakari.ailus@iki.fi>
description:
The OMAP 3 ISP is an image signal processor present in OMAP 3 SoCs.
properties:
compatible:
const: ti,omap3-isp
reg:
items:
- description: Core ISP registers up to the end of the SBL block
- description: CSI PHYs and receivers registers
interrupts:
maxItems: 1
iommus:
maxItems: 1
syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: phandle to System Control Module
- description: register offset to Complex I/O or CSI-PHY register
description:
Phandle and register offset to the Complex I/O or CSI-PHY register
ti,phy-type:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1]
description:
0 - OMAP3ISP_PHY_TYPE_COMPLEX_IO (e.g. OMAP 3430)
1 - OMAP3ISP_PHY_TYPE_CSIPHY (e.g. OMAP 3630)
'#clock-cells':
const: 1
description:
The ISP provides two external clocks, cam_xclka and cam_xclkb,
at indices 0 and 1 respectively.
vdd-csiphy1-supply:
description: Voltage supply of the CSI-2 PHY 1
vdd-csiphy2-supply:
description: Voltage supply of the CSI-2 PHY 2
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port@0:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: Parallel (CCDC) interface
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
port@1:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: |
CSIPHY1 interface:
OMAP 3630: CSI2C / CCP2B
OMAP 3430: CSI1 (CSIb)
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
lane-polarities:
minItems: 2
maxItems: 3
data-lanes:
minItems: 1
maxItems: 2
items:
minimum: 1
maximum: 3
clock-lanes:
minimum: 1
maximum: 3
port@2:
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: |
CSIPHY2 interface:
OMAP 3630: CSI2A / CCP2B
OMAP 3430: CSI2 (CSIa)
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
lane-polarities:
minItems: 2
maxItems: 3
data-lanes:
minItems: 1
maxItems: 2
items:
minimum: 1
maximum: 3
clock-lanes:
minimum: 1
maximum: 3
required:
- compatible
- reg
- interrupts
- iommus
- syscon
- ti,phy-type
- '#clock-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/media/omap3-isp.h>
isp@480bc000 {
compatible = "ti,omap3-isp";
reg = <0x480bc000 0x12fc>,
<0x480bd800 0x0600>;
interrupts = <24>;
iommus = <&mmu_isp>;
syscon = <&scm_conf 0x2f0>;
ti,phy-type = <OMAP3ISP_PHY_TYPE_CSIPHY>;
#clock-cells = <1>;
vdd-csiphy1-supply = <&vaux2>;
vdd-csiphy2-supply = <&vaux2>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
parallel_ep: endpoint {
remote-endpoint = <&parallel>;
};
};
port@1 {
reg = <1>;
csi1_ep: endpoint {
remote-endpoint = <&smia_1>;
clock-lanes = <1>;
data-lanes = <2>;
lane-polarities = <0 0>;
};
};
port@2 {
reg = <2>;
csi2a_ep: endpoint {
remote-endpoint = <&smia_2>;
clock-lanes = <2>;
data-lanes = <1 3>;
lane-polarities = <1 1 1>;
};
};
};
};

View File

@@ -0,0 +1,152 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) 2025 Texas Instruments Incorporated - http://www.ti.com/
%YAML 1.2
---
$id: http://devicetree.org/schemas/media/ti,vip.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments DRA7x Video Input Port (VIP)
maintainers:
- Yemike Abhilash Chandra <y-abhilashchandra@ti.com>
description: |-
Video Input Port (VIP) can be found on devices such as DRA7xx and
provides the system interface and the processing capability to
connect parallel image-sensor as well as BT.656/1120 capable encoder
chip to DRA7x device.
Each VIP instance supports 2 independently configurable external
video input capture slices (Slice 0 and Slice 1) each providing
up to two video input ports (Port A and Port B).
properties:
compatible:
enum:
- ti,dra7-vip
reg:
maxItems: 1
interrupts:
items:
- description: IRQ index 0 is used for Slice0 interrupts
- description: IRQ index 1 is used for Slice1 interrupts
ti,ctrl-module:
description:
Reference to the device control module that provides clock-edge
inversion control for VIP ports. These controls allow the
VIP to sample pixel data on the correct clock edge.
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
items:
- description: phandle to device control module
- description: offset to the CTRL_CORE_SMA_SW_1 register
- description: Bit field to slice 0 port A
- description: Bit field to slice 0 port B
- description: Bit field to slice 1 port A
- description: Bit field to slice 1 port B
maxItems: 1
ports:
$ref: /schemas/graph.yaml#/properties/ports
patternProperties:
'^port@[0-3]$':
$ref: /schemas/graph.yaml#/$defs/port-base
unevaluatedProperties: false
description: |
Each VIP instance supports 2 independently configurable external video
input capture slices (Slice 0 and Slice 1) each providing up to two video
input ports (Port A and Port B). These ports represent the following
port@0 -> Slice 0 Port A
port@1 -> Slice 0 Port B
port@2 -> Slice 1 Port A
port@3 -> Slice 1 Port B
properties:
endpoint:
$ref: /schemas/media/video-interfaces.yaml#
unevaluatedProperties: false
properties:
bus-width:
enum: [8, 16, 24]
default: 8
required:
- compatible
- reg
- interrupts
- ti,ctrl-module
- ports
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
video@48970000 {
compatible = "ti,dra7-vip";
reg = <0x48970000 0x1000>;
interrupts = <GIC_SPI 351 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 392 IRQ_TYPE_LEVEL_HIGH>;
ti,ctrl-module = <&scm_conf 0x534 0x0 0x2 0x1 0x3>;
ports {
#address-cells = <1>;
#size-cells = <0>;
vin1a: port@0 {
reg = <0>;
vin1a_ep: endpoint {
remote-endpoint = <&camera1>;
hsync-active = <1>;
vsync-active = <1>;
pclk-sample = <0>;
bus-width = <8>;
};
};
vin1b: port@1 {
reg = <1>;
vin1b_ep: endpoint {
remote-endpoint = <&camera2>;
hsync-active = <1>;
vsync-active = <1>;
pclk-sample = <0>;
bus-width = <8>;
};
};
vin2a: port@2 {
reg = <2>;
vin2a_ep: endpoint {
remote-endpoint = <&camera3>;
hsync-active = <1>;
vsync-active = <1>;
pclk-sample = <0>;
bus-width = <16>;
};
};
vin2b: port@3 {
reg = <3>;
vin2b_ep: endpoint {
remote-endpoint = <&camera4>;
hsync-active = <1>;
vsync-active = <1>;
pclk-sample = <0>;
bus-width = <8>;
};
};
};
};
...

View File

@@ -157,10 +157,10 @@ changing the e.g. exposure of the webcam.
Of course, you can always do all the locking yourself by leaving both lock
pointers at ``NULL``.
In the case of :ref:`videobuf2 <vb2_framework>` you will need to implement the
``wait_prepare()`` and ``wait_finish()`` callbacks to unlock/lock if applicable.
If you use the ``queue->lock`` pointer, then you can use the helper functions
:c:func:`vb2_ops_wait_prepare` and :c:func:`vb2_ops_wait_finish`.
In the case of :ref:`videobuf2 <vb2_framework>` you must set the ``queue->lock``
pointer to the lock you use to serialize the queuing ioctls. This ensures that
that lock is released while waiting in ``VIDIOC_DQBUF`` for a buffer to arrive,
and it is retaken afterwards.
The implementation of a hotplug disconnect should also take the lock from
:c:type:`video_device` before calling v4l2_device_disconnect. If you are also

View File

@@ -42,8 +42,6 @@ nitpick_ignore = [
("c:func", "struct fd_set"),
("c:func", "struct pollfd"),
("c:func", "usb_make_path"),
("c:func", "wait_finish"),
("c:func", "wait_prepare"),
("c:func", "write"),
("c:type", "atomic_t"),

View File

@@ -933,7 +933,10 @@ reflected by corresponding queries):
* the minimum number of buffers needed for decoding,
* bit-depth of the bitstream has been changed.
* bit-depth of the bitstream has been changed,
* colorspace of the bitstream has been changed, but it doesn't require
buffer reallocation.
Whenever that happens, the decoder must proceed as follows:

View File

@@ -221,7 +221,7 @@ and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` does
:alt: vbi_hsync.svg
:align: center
**Figure 4.1. Line synchronization**
Line synchronization
.. _vbi-525:
@@ -229,7 +229,7 @@ and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` does
:alt: vbi_525.svg
:align: center
**Figure 4.2. ITU-R 525 line numbering (M/NTSC and M/PAL)**
ITU-R 525 line numbering (M/NTSC and M/PAL)
.. _vbi-625:
@@ -237,7 +237,7 @@ and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` does
:alt: vbi_625.svg
:align: center
**Figure 4.3. ITU-R 625 line numbering**
ITU-R 625 line numbering
Remember the VBI image format depends on the selected video standard,
therefore the application must choose a new standard or query the

View File

@@ -460,7 +460,7 @@ selection will refer to the sink pad format dimensions instead.
:alt: subdev-image-processing-crop.svg
:align: center
**Figure 4.5. Image processing in subdevs: simple crop example**
Image processing in subdevs: simple crop example
In the above example, the subdev supports cropping on its sink pad. To
configure it, the user sets the media bus format on the subdev's sink
@@ -477,7 +477,7 @@ pad.
:alt: subdev-image-processing-scaling-multi-source.svg
:align: center
**Figure 4.6. Image processing in subdevs: scaling with multiple sources**
Image processing in subdevs: scaling with multiple sources
In this example, the subdev is capable of first cropping, then scaling
and finally cropping for two source pads individually from the resulting
@@ -493,7 +493,7 @@ an area at location specified by the source crop rectangle from it.
:alt: subdev-image-processing-full.svg
:align: center
**Figure 4.7. Image processing in subdevs: scaling and composition with multiple sinks and sources**
Image processing in subdevs: scaling and composition with multiple sinks and sources
The subdev driver supports two sink pads and two source pads. The images
from both of the sink pads are individually cropped, then scaled and
@@ -578,15 +578,14 @@ Device types and routing setup
Different kinds of sub-devices have differing behaviour for route activation,
depending on the hardware. In all cases, however, only routes that have the
``V4L2_SUBDEV_STREAM_FL_ACTIVE`` flag set are active.
``V4L2_SUBDEV_ROUTE_FL_ACTIVE`` flag set are active.
Devices generating the streams may allow enabling and disabling some of the
routes or have a fixed routing configuration. If the routes can be disabled, not
declaring the routes (or declaring them without
``V4L2_SUBDEV_STREAM_FL_ACTIVE`` flag set) in ``VIDIOC_SUBDEV_S_ROUTING`` will
disable the routes. ``VIDIOC_SUBDEV_S_ROUTING`` will still return such routes
back to the user in the routes array, with the ``V4L2_SUBDEV_STREAM_FL_ACTIVE``
flag unset.
declaring the routes (or declaring them without ``V4L2_SUBDEV_ROUTE_FL_ACTIVE``
flag set) in ``VIDIOC_SUBDEV_S_ROUTING`` will disable the routes.
``VIDIOC_SUBDEV_S_ROUTING`` will still return such routes back to the user in
the routes array, with the ``V4L2_SUBDEV_ROUTE_FL_ACTIVE`` flag unset.
Devices transporting the streams almost always have more configurability with
respect to routing. Typically any route between the sub-device's sink and source

View File

@@ -2959,6 +2959,126 @@ This structure contains all loop filter related parameters. See sections
- 0x00000004
-
``V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS (struct)``
Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
It extends it with the list of Long-term reference sets parameters.
These parameters are defined according to :ref:`hevc`.
They are described in section 7.4.3.2.1 "General sequence parameter set
RBSP semantics" of the specification.
This control is a dynamically sized 1-dimensional array.
The values in the array should be ignored when either
num_long_term_ref_pics_sps is 0 or the
V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT flag is not set in
:c:type:`v4l2_ctrl_hevc_sps`.
.. c:type:: v4l2_ctrl_hevc_ext_sps_lt_rps
.. cssclass:: longtable
.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_lt_rps
:header-rows: 0
:stub-columns: 0
:widths: 1 1 2
* - __u16
- ``lt_ref_pic_poc_lsb_sps``
- Long term reference picture order count as described in section 7.4.3.2.1
"General sequence parameter set RBSP semantics" of the specification.
* - __u16
- ``flags``
- See :ref:`Extended Long-Term RPS Flags <hevc_ext_sps_lt_rps_flags>`
.. _hevc_ext_sps_lt_rps_flags:
``Extended SPS Long-Term RPS Flags``
.. cssclass:: longtable
.. flat-table::
:header-rows: 0
:stub-columns: 0
:widths: 1 1 2
* - ``V4L2_HEVC_EXT_SPS_LT_RPS_FLAG_USED_LT``
- 0x00000001
- Specifies if the long-term reference picture is used 7.4.3.2.1 "General sequence parameter
set RBSP semantics" of the specification.
``V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS (struct)``
Subset of the :c:type:`v4l2_ctrl_hevc_sps` control.
It extends it with the list of Short-term reference sets parameters.
These parameters are defined according to :ref:`hevc`.
They are described in section 7.4.8 "Short-term reference picture set
semantics" of the specification.
This control is a dynamically sized 1-dimensional array.
The values in the array should be ignored when
num_short_term_ref_pic_sets is 0.
.. c:type:: v4l2_ctrl_hevc_ext_sps_st_rps
.. cssclass:: longtable
.. flat-table:: struct v4l2_ctrl_hevc_ext_sps_st_rps
:header-rows: 0
:stub-columns: 0
:widths: 1 1 2
* - __u8
- ``delta_idx_minus1``
- Specifies the delta compare to the index. See details in section 7.4.8 "Short-term
reference picture set semantics" of the specification.
* - __u8
- ``delta_rps_sign``
- Sign of the delta as specified in section 7.4.8 "Short-term reference picture set
semantics" of the specification.
* - __u8
- ``num_negative_pics``
- Number of short-term RPS entries that have picture order count values less than the
picture order count value of the current picture.
* - __u8
- ``num_positive_pics``
- Number of short-term RPS entries that have picture order count values greater than the
picture order count value of the current picture.
* - __u32
- ``used_by_curr_pic``
- Bit i specifies if short-term RPS i is used by the current picture.
* - __u32
- ``use_delta_flag``
- Bit i specifies if short-term RPS i is included in the short-term RPS entries.
* - __u16
- ``abs_delta_rps_minus1``
- Absolute delta RPS as specified in section 7.4.8 "Short-term reference picture set
semantics" of the specification.
* - __u16
- ``delta_poc_s0_minus1[16]``
- Specifies the negative picture order count delta for the i-th entry in the short-term RPS.
See details in section 7.4.8 "Short-term reference picture set semantics" of the
specification.
* - __u16
- ``delta_poc_s1_minus1[16]``
- Specifies the positive picture order count delta for the i-th entry in the short-term RPS.
See details in section 7.4.8 "Short-term reference picture set semantics" of the
specification.
* - __u16
- ``flags``
- See :ref:`Extended Short-Term RPS Flags <hevc_ext_sps_st_rps_flags>`
.. _hevc_ext_sps_st_rps_flags:
``Extended SPS Short-Term RPS Flags``
.. cssclass:: longtable
.. flat-table::
:header-rows: 0
:stub-columns: 0
:widths: 1 1 2
* - ``V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED``
- 0x00000001
- Specifies if the short-term RPS is predicted from another short term RPS. See details in
section 7.4.8 "Short-term reference picture set semantics" of the specification.
.. _v4l2-codec-stateless-av1:
``V4L2_CID_STATELESS_AV1_SEQUENCE (struct)``

View File

@@ -58,6 +58,8 @@ Flash Control IDs
``V4L2_CID_FLASH_CLASS (class)``
The FLASH class descriptor.
.. _v4l2-cid-flash-led-mode:
``V4L2_CID_FLASH_LED_MODE (menu)``
Defines the mode of the flash LED, the high-power white LED attached
to the flash controller. Setting this control may not be possible in
@@ -81,6 +83,8 @@ Flash Control IDs
.. _v4l2-cid-flash-strobe-source:
``V4L2_CID_FLASH_STROBE_SOURCE (menu)``
Defines the source of the flash LED strobe.
@@ -97,6 +101,12 @@ Flash Control IDs
- The flash strobe is triggered by an external source. Typically
this is a sensor, which makes it possible to synchronise the
flash strobe start to exposure start.
This method of controlling flash LED strobe has two additional
prerequisites: the strobe source's :ref:`strobe output
<v4l2-cid-flash-strobe-oe>` must be enabled (if available)
and the flash controller's :ref:`flash LED mode
<v4l2-cid-flash-led-mode>` must be set to
``V4L2_FLASH_LED_MODE_FLASH``.
@@ -187,3 +197,35 @@ Flash Control IDs
charged before strobing. LED flashes often require a cooldown period
after strobe during which another strobe will not be possible. This
is a read-only control.
.. _v4l2-cid-flash-duration:
``V4L2_CID_FLASH_DURATION (integer)``
Duration of the flash strobe pulse generated by the strobe source, when
using external strobe. This control shall be implemented by the device
generating the hardware flash strobe signal, typically a camera sensor,
connected to a flash controller.
The flash controllers :ref:`strobe source <v4l2-cid-flash-strobe-source>`
must be configured to ``V4L2_FLASH_STROBE_SOURCE_EXTERNAL`` for this
mode of operation. For more details please also take a look at the
documentation there.
The unit should be microseconds (µs) if possible.
.. _v4l2-cid-flash-strobe-oe:
``V4L2_CID_FLASH_STROBE_OE (boolean)``
Enables the output of a hardware strobe signal from the strobe source,
when using external strobe. This control shall be implemented by the device
generating the hardware flash strobe signal, typically a camera sensor,
connected to a flash controller.
Provided the signal generating device driver supports it, the length of the
strobe signal can be configured by adjusting its
:ref:`flash duration <v4l2-cid-flash-duration>`.
The flash controllers :ref:`strobe source <v4l2-cid-flash-strobe-source>`
must be configured to ``V4L2_FLASH_STROBE_SOURCE_EXTERNAL`` for this
mode of operation. For more details please also take a look at the
documentation there.

View File

@@ -275,6 +275,14 @@ Compressed Formats
of macroblocks to decode a full corresponding frame to the matching
capture buffer.
* .. _V4L2-PIX-FMT-AV1:
- ``V4L2_PIX_FMT_AV1``
- 'AV01'
- AV1 compressed video frame. This format is adapted for implementing AV1
pipeline. The decoder implements stateful video decoder and expects one
temporal unit per buffer in OBU stream format.
The encoder generates one Temporal Unit per buffer.
.. raw:: latex
\normalsize

View File

@@ -2800,7 +2800,7 @@ be named ``MEDIA_BUS_FMT_SRGGB10_2X8_PADHI_LE``.
:alt: bayer.svg
:align: center
**Figure 4.8 Bayer Patterns**
Bayer Patterns
The following table lists existing packed Bayer formats. The data
organization is given as an example for the first pixel only.

View File

@@ -150,6 +150,8 @@ replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_H264_PRED_WEIGHTS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`V4L.v4l2_ctrl_type`
replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`V4L.v4l2_ctrl_type`

View File

@@ -531,6 +531,18 @@ See also the examples in :ref:`control`.
- n/a
- A struct :c:type:`v4l2_ctrl_hevc_decode_params`, containing HEVC
decoding parameters for stateless video decoders.
* - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS``
- n/a
- n/a
- n/a
- A struct :c:type:`v4l2_ctrl_hevc_ext_sps_lt_rps`, containing HEVC
extended Long-Term RPS for stateless video decoders.
* - ``V4L2_CTRL_TYPE_HEVC_EXT_SPS_ST_RPS``
- n/a
- n/a
- n/a
- A struct :c:type:`v4l2_ctrl_hevc_ext_sps_st_rps`, containing HEVC
extended Short-Term RPS for stateless video decoders.
* - ``V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR``
- n/a
- n/a

View File

@@ -157,7 +157,14 @@ appropriately. The generic error codes are described at the
EINVAL
The sink or source pad identifiers reference a non-existing pad or reference
pads of different types (ie. the sink_pad identifiers refers to a source
pad), or the ``which`` field has an unsupported value.
pad), the ``which`` field has an unsupported value, or, for
``VIDIOC_SUBDEV_S_ROUTING``, the num_routes field set by the application is
larger than the len_routes field value.
ENXIO
The application requested routes cannot be created or the state of
the specified routes cannot be modified. Only returned for
``VIDIOC_SUBDEV_S_ROUTING``.
E2BIG
The application provided ``num_routes`` for ``VIDIOC_SUBDEV_S_ROUTING`` is

View File

@@ -15832,11 +15832,11 @@ F: include/linux/imx-media.h
F: include/media/imx.h
MEDIA DRIVERS FOR FREESCALE IMX7/8
M: Rui Miguel Silva <rmfrfs@gmail.com>
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
M: Frank Li <Frank.Li@nxp.com>
M: Martin Kepplinger-Novakovic <martink@posteo.de>
R: Rui Miguel Silva <rmfrfs@gmail.com>
R: Purism Kernel Team <kernel@puri.sm>
R: Frank Li <Frank.Li@nxp.com>
L: imx@lists.linux.dev
L: linux-media@vger.kernel.org
S: Maintained
@@ -16113,7 +16113,7 @@ M: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
M: Houlong Wei <houlong.wei@mediatek.com>
M: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
S: Supported
F: Documentation/devicetree/bindings/media/mediatek-mdp.txt
F: Documentation/devicetree/bindings/media/mediatek,mt8173-mdp.yaml
F: drivers/media/platform/mediatek/mdp/
F: drivers/media/platform/mediatek/vpu/
@@ -18672,6 +18672,7 @@ M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/adi,ad5820.yaml
F: Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.yaml
F: drivers/media/i2c/ad5820.c
F: drivers/media/i2c/et8ek8
@@ -19329,6 +19330,14 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/ovti,og0ve1b.yaml
F: drivers/media/i2c/og0ve1b.c
OMNIVISION OS05B10 SENSOR DRIVER
M: Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>
M: Elgin Perumbilly <elgin.perumbilly@siliconsignals.io>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/ovti,os05b10.yaml
F: drivers/media/i2c/os05b10.c
OMNIVISION OV01A10 SENSOR DRIVER
M: Bingbu Cao <bingbu.cao@intel.com>
L: linux-media@vger.kernel.org
@@ -23393,6 +23402,14 @@ S: Supported
F: Documentation/devicetree/bindings/media/samsung,s5c73m3.yaml
F: drivers/media/i2c/s5c73m3/*
SAMSUNG S5K3M5 CAMERA DRIVER
M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/samsung,s5k3m5.yaml
F: drivers/media/i2c/s5k3m5.c
SAMSUNG S5K5BAF CAMERA DRIVER
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
M: Andrzej Hajda <andrzej.hajda@intel.com>
@@ -23400,6 +23417,14 @@ L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/i2c/s5k5baf.c
SAMSUNG S5KJN1 CAMERA DRIVER
M: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/samsung,s5kjn1.yaml
F: drivers/media/i2c/s5kjn1.c
SAMSUNG S5P Security SubSystem (SSS) DRIVER
M: Krzysztof Kozlowski <krzk@kernel.org>
M: Vladimir Zapolskiy <vz@mleia.com>
@@ -25477,6 +25502,13 @@ S: Maintained
F: drivers/i2c/busses/i2c-designware-amdisp.c
F: include/linux/soc/amd/isp4_misc.h
SYNOPSYS DESIGNWARE MIPI CSI-2 RECEIVER DRIVER
M: Michael Riesch <michael.riesch@collabora.com>
L: linux-media@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/media/rockchip,rk3568-mipi-csi2.yaml
F: drivers/media/platform/synopsys/dw-mipi-csi2rx.c
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
M: Jaehoon Chung <jh80.chung@samsung.com>
M: Shawn Lin <shawn.lin@rock-chips.com>
@@ -26390,6 +26422,7 @@ S: Maintained
W: http://linuxtv.org/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
F: Documentation/devicetree/bindings/media/ti,cal.yaml
F: Documentation/devicetree/bindings/media/ti,vip.yaml
F: Documentation/devicetree/bindings/media/ti,vpe.yaml
F: drivers/media/platform/ti/cal/
F: drivers/media/platform/ti/vpe/

View File

@@ -605,8 +605,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int start, unsigned i
*/
if (vb2_get_num_buffers(q)) {
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||
q->cnt_wait_prepare != q->cnt_wait_finish;
q->cnt_prepare_streaming != q->cnt_unprepare_streaming;
if (unbalanced) {
pr_info("unbalanced counters for queue %p:\n", q);
@@ -617,13 +616,8 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int start, unsigned i
if (q->cnt_prepare_streaming != q->cnt_unprepare_streaming)
pr_info(" prepare_streaming: %u unprepare_streaming: %u\n",
q->cnt_prepare_streaming, q->cnt_unprepare_streaming);
if (q->cnt_wait_prepare != q->cnt_wait_finish)
pr_info(" wait_prepare: %u wait_finish: %u\n",
q->cnt_wait_prepare, q->cnt_wait_finish);
}
q->cnt_queue_setup = 0;
q->cnt_wait_prepare = 0;
q->cnt_wait_finish = 0;
q->cnt_prepare_streaming = 0;
q->cnt_start_streaming = 0;
q->cnt_stop_streaming = 0;
@@ -2037,10 +2031,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
* become ready or for streamoff. Driver's lock is released to
* allow streamoff or qbuf to be called while waiting.
*/
if (q->ops->wait_prepare)
call_void_qop(q, wait_prepare, q);
else if (q->lock)
mutex_unlock(q->lock);
mutex_unlock(q->lock);
/*
* All locks have been released, it is safe to sleep now.
@@ -2050,10 +2041,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
!list_empty(&q->done_list) || !q->streaming ||
q->error);
if (q->ops->wait_finish)
call_void_qop(q, wait_finish, q);
else if (q->lock)
mutex_lock(q->lock);
mutex_lock(q->lock);
q->waiting_in_dqbuf = 0;
/*
@@ -2653,12 +2641,8 @@ int vb2_core_queue_init(struct vb2_queue *q)
if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers))
return -EINVAL;
/* Either both or none are set */
if (WARN_ON(!q->ops->wait_prepare ^ !q->ops->wait_finish))
return -EINVAL;
/* Warn if q->lock is NULL and no custom wait_prepare is provided */
if (WARN_ON(!q->lock && !q->ops->wait_prepare))
/* Warn if q->lock is NULL */
if (WARN_ON(!q->lock))
return -EINVAL;
INIT_LIST_HEAD(&q->queued_list);
@@ -3220,17 +3204,10 @@ static int vb2_thread(void *data)
continue;
prequeue--;
} else {
if (!threadio->stop) {
if (q->ops->wait_finish)
call_void_qop(q, wait_finish, q);
else if (q->lock)
mutex_lock(q->lock);
mutex_lock(q->lock);
if (!threadio->stop)
ret = vb2_core_dqbuf(q, &index, NULL, 0);
if (q->ops->wait_prepare)
call_void_qop(q, wait_prepare, q);
else if (q->lock)
mutex_unlock(q->lock);
}
mutex_unlock(q->lock);
dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
if (!ret)
vb = vb2_get_buffer(q, index);
@@ -3245,15 +3222,9 @@ static int vb2_thread(void *data)
if (copy_timestamp)
vb->timestamp = ktime_get_ns();
if (!threadio->stop) {
if (q->ops->wait_finish)
call_void_qop(q, wait_finish, q);
else if (q->lock)
mutex_lock(q->lock);
mutex_lock(q->lock);
ret = vb2_core_qbuf(q, vb, NULL, NULL);
if (q->ops->wait_prepare)
call_void_qop(q, wait_prepare, q);
else if (q->lock)
mutex_unlock(q->lock);
mutex_unlock(q->lock);
}
if (ret || threadio->stop)
break;

View File

@@ -1302,20 +1302,6 @@ void vb2_video_unregister_device(struct video_device *vdev)
}
EXPORT_SYMBOL_GPL(vb2_video_unregister_device);
/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
void vb2_ops_wait_prepare(struct vb2_queue *vq)
{
mutex_unlock(vq->lock);
}
EXPORT_SYMBOL_GPL(vb2_ops_wait_prepare);
void vb2_ops_wait_finish(struct vb2_queue *vq)
{
mutex_lock(vq->lock);
}
EXPORT_SYMBOL_GPL(vb2_ops_wait_finish);
/*
* Note that this function is called during validation time and
* thus the req_queue_mutex is held to ensure no request objects

View File

@@ -171,6 +171,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
&dmxdev->mutex,
file->f_flags & O_NONBLOCK);
dvbdev->readers--;
}
@@ -397,11 +398,11 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer1, buffer1_len,
buffer_flags);
buffer_flags, true);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer2, buffer2_len,
buffer_flags);
buffer_flags, true);
} else {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer1, buffer1_len);
@@ -452,10 +453,10 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
if (dvb_vb2_is_streaming(ctx)) {
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
buffer_flags);
buffer_flags, false);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
buffer_flags);
buffer_flags, false);
} else {
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
@@ -815,9 +816,21 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
dmxdev->may_do_mmap = 0;
#endif
/*
* The mutex passed to dvb_vb2_init is unlocked when a buffer
* is in a blocking wait. However, dmxdevfilter has two mutexes:
* dmxdevfilter->mutex and dmxdev->mutex. So this will not work.
* The solution would be to support unlocking two mutexes in vb2,
* but since this problem has been here since the beginning and
* nobody ever complained, we leave it as-is rather than adding
* that second mutex pointer to vb2.
*
* In the unlikely event that someone complains about this, then
* this comment will hopefully help.
*/
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
file->f_flags & O_NONBLOCK);
&dmxdevfilter->mutex, file->f_flags & O_NONBLOCK);
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0);
@@ -1217,24 +1230,11 @@ static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return ret;
return dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
}
#endif
@@ -1367,7 +1367,6 @@ static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
@@ -1375,12 +1374,7 @@ static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
if (dmxdev->exit)
return -ENODEV;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
mutex_unlock(&dmxdev->mutex);
return ret;
return dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
}
#endif

View File

@@ -103,31 +103,12 @@ static void _stop_streaming(struct vb2_queue *vq)
spin_unlock_irqrestore(&ctx->slock, flags);
}
static void _dmxdev_lock(struct vb2_queue *vq)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
mutex_lock(&ctx->mutex);
dprintk(3, "[%s]\n", ctx->name);
}
static void _dmxdev_unlock(struct vb2_queue *vq)
{
struct dvb_vb2_ctx *ctx = vb2_get_drv_priv(vq);
if (mutex_is_locked(&ctx->mutex))
mutex_unlock(&ctx->mutex);
dprintk(3, "[%s]\n", ctx->name);
}
static const struct vb2_ops dvb_vb2_qops = {
.queue_setup = _queue_setup,
.buf_prepare = _buffer_prepare,
.buf_queue = _buffer_queue,
.start_streaming = _start_streaming,
.stop_streaming = _stop_streaming,
.wait_prepare = _dmxdev_unlock,
.wait_finish = _dmxdev_lock,
};
static void _fill_dmx_buffer(struct vb2_buffer *vb, void *pb)
@@ -158,9 +139,10 @@ static const struct vb2_buf_ops dvb_vb2_buf_ops = {
};
/*
* Videobuf operations
* vb2 operations
*/
int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name,
struct mutex *mutex, int nonblocking)
{
struct vb2_queue *q = &ctx->vb_q;
int ret;
@@ -175,14 +157,7 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
q->ops = &dvb_vb2_qops;
q->mem_ops = &vb2_vmalloc_memops;
q->buf_ops = &dvb_vb2_buf_ops;
ret = vb2_core_queue_init(q);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
mutex_init(&ctx->mutex);
q->lock = mutex;
spin_lock_init(&ctx->slock);
INIT_LIST_HEAD(&ctx->dvb_q);
@@ -190,6 +165,13 @@ int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int nonblocking)
ctx->nonblocking = nonblocking;
ctx->state = DVB_VB2_STATE_INIT;
ret = vb2_core_queue_init(q);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
return ret;
}
dprintk(3, "[%s]\n", ctx->name);
return 0;
@@ -249,7 +231,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx)
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
const unsigned char *src, int len,
enum dmx_buffer_flags *buffer_flags)
enum dmx_buffer_flags *buffer_flags,
bool flush)
{
unsigned long flags = 0;
void *vbuf = NULL;
@@ -306,7 +289,7 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
}
}
if (ctx->nonblocking && ctx->buf) {
if (flush && ctx->buf) {
vb2_set_plane_payload(&ctx->buf->vb, 0, ll);
vb2_buffer_done(&ctx->buf->vb, VB2_BUF_STATE_DONE);
list_del(&ctx->buf->list);

View File

@@ -305,6 +305,7 @@ config VIDEO_MT9M111
config VIDEO_MT9M114
tristate "onsemi MT9M114 sensor support"
select V4L2_CCI_I2C
select VIDEO_APTINA_PLL
help
This is a Video4Linux2 sensor-level driver for the onsemi MT9M114
camera.
@@ -371,8 +372,19 @@ config VIDEO_OG0VE1B
To compile this driver as a module, choose M here: the
module will be called og0ve1b.
config VIDEO_OS05B10
tristate "OmniVision OS05B10 sensor support"
select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for Omnivision
OS05B10 camera sensor.
To compile this driver as a module, choose M here: the
module will be called os05b10.
config VIDEO_OV01A10
tristate "OmniVision OV01A10 sensor support"
select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the OmniVision
OV01A10 camera.
@@ -529,6 +541,7 @@ config VIDEO_OV5645
config VIDEO_OV5647
tristate "OmniVision OV5647 sensor support"
select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the OmniVision
OV5647 camera.
@@ -743,6 +756,16 @@ config VIDEO_S5C73M3
This is a V4L2 sensor driver for Samsung S5C73M3
8 Mpixel camera.
config VIDEO_S5K3M5
tristate "Samsung S5K3M5 sensor support"
select V4L2_CCI_I2C
help
This is a V4L2 sensor driver for Samsung S5K3M5 13MP raw
camera sensor.
To compile this driver as a module, choose M here: the
module will be called s5k3m5.
config VIDEO_S5K5BAF
tristate "Samsung S5K5BAF sensor support"
help
@@ -755,6 +778,16 @@ config VIDEO_S5K6A3
This is a V4L2 sensor driver for Samsung S5K6A3 raw
camera sensor.
config VIDEO_S5KJN1
tristate "Samsung S5KJN1 sensor support"
select V4L2_CCI_I2C
help
This is a V4L2 sensor driver for Samsung S5KJN1 50MP raw
camera sensor.
To compile this driver as a module, choose M here: the
module will be called s5kjn1.
config VIDEO_VD55G1
tristate "ST VD55G1 sensor support"
select V4L2_CCI_I2C

View File

@@ -84,6 +84,7 @@ obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o
obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o
obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o
obj-$(CONFIG_VIDEO_OS05B10) += os05b10.o
obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o
obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o
obj-$(CONFIG_VIDEO_OV02C10) += ov02c10.o
@@ -125,8 +126,10 @@ obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o
obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o
obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
obj-$(CONFIG_VIDEO_S5K3M5) += s5k3m5.o
obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o
obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o
obj-$(CONFIG_VIDEO_S5KJN1) += s5kjn1.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o
obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o

View File

@@ -507,6 +507,13 @@ static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
fi->interval.denominator = 25;
}
/*
* If the de-interlacer is active, the chip produces full video frames
* at the field rate.
*/
if (state->field == V4L2_FIELD_NONE)
fi->interval.denominator *= 2;
return 0;
}
@@ -969,6 +976,32 @@ static int adv7180_subscribe_event(struct v4l2_subdev *sd,
}
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int adv7180_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct adv7180_state *state = to_state(sd);
int ret;
ret = adv7180_read(state, reg->reg);
if (ret < 0)
return ret;
reg->val = ret;
reg->size = 1;
return 0;
}
static int adv7180_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
struct adv7180_state *state = to_state(sd);
return adv7180_write(state, reg->reg, reg->val);
}
#endif
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.s_std = adv7180_s_std,
.g_std = adv7180_g_std,
@@ -982,6 +1015,10 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.subscribe_event = adv7180_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7180_g_register,
.s_register = adv7180_s_register,
#endif
};
static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
@@ -1066,13 +1103,13 @@ static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
static int adv7182_init(struct adv7180_state *state)
{
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
if (state->csi_client)
adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
state->csi_client->addr << 1);
if (state->chip_info->flags & ADV7180_FLAG_I2P)
if (state->vpp_client)
adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
state->vpp_client->addr << 1);
if (state->chip_info->flags & ADV7180_FLAG_V2) {
/* ADI recommended writes for improved video quality */
@@ -1443,15 +1480,17 @@ static int adv7180_probe(struct i2c_client *client)
state->force_bt656_4 = true;
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
state->csi_client = i2c_new_dummy_device(client->adapter,
ADV7180_DEFAULT_CSI_I2C_ADDR);
state->csi_client =
i2c_new_ancillary_device(client, "csi",
ADV7180_DEFAULT_CSI_I2C_ADDR);
if (IS_ERR(state->csi_client))
return PTR_ERR(state->csi_client);
}
if (state->chip_info->flags & ADV7180_FLAG_I2P) {
state->vpp_client = i2c_new_dummy_device(client->adapter,
ADV7180_DEFAULT_VPP_I2C_ADDR);
state->vpp_client =
i2c_new_ancillary_device(client, "vpp",
ADV7180_DEFAULT_VPP_I2C_ADDR);
if (IS_ERR(state->vpp_client)) {
ret = PTR_ERR(state->vpp_client);
goto err_unregister_csi_client;

View File

@@ -3453,7 +3453,13 @@ static int configure_regmaps(struct adv76xx_state *state)
static void adv76xx_reset(struct adv76xx_state *state)
{
if (state->reset_gpio) {
/* ADV76XX can be reset by a low reset pulse of minimum 5 ms. */
/*
* Note: Misinterpretation of reset assertion - do not re-use
* this code. The reset pin is using incorrect (for a reset
* signal) logical level.
*
* ADV76XX can be reset by a low reset pulse of minimum 5 ms.
*/
gpiod_set_value_cansleep(state->reset_gpio, 0);
usleep_range(5000, 10000);
gpiod_set_value_cansleep(state->reset_gpio, 1);

View File

@@ -129,6 +129,8 @@ int aptina_pll_calculate(struct device *dev,
p1_max = min(limits->p1_max, limits->out_clock_max * div /
(pll->ext_clock * pll->m));
dev_dbg(dev, "pll: p1 min %u max %u\n", p1_min, p1_max);
for (p1 = p1_max & ~1; p1 >= p1_min; p1 -= 2) {
unsigned int mf_inc = p1 / gcd(div, p1);
unsigned int mf_high;

File diff suppressed because it is too large Load Diff

View File

@@ -48,6 +48,8 @@
#define CCS_COLOUR_COMPONENTS 4
#define CCS_DEFAULT_COMPRESSED_DT MIPI_CSI2_DT_USER_DEFINED(0)
#define SMIAPP_NAME "smiapp"
#define CCS_NAME "ccs"
@@ -177,6 +179,8 @@ struct ccs_csi_data_format {
#define CCS_PAD_SRC 1
#define CCS_PADS 2
#define CCS_STREAM_PIXEL 0
struct ccs_binning_subtype {
u8 horizontal:4;
u8 vertical:4;
@@ -218,27 +222,20 @@ struct ccs_sensor {
void *ccs_limits;
u8 nbinning_subtypes;
struct ccs_binning_subtype binning_subtypes[CCS_LIM_BINNING_SUB_TYPE_MAX_N + 1];
u32 mbus_frame_fmts;
u64 mbus_frame_fmts;
const struct ccs_csi_data_format *csi_format;
const struct ccs_csi_data_format *internal_csi_format;
struct v4l2_rect pa_src, scaler_sink, src_src;
u32 default_mbus_frame_fmts;
u64 default_mbus_frame_fmts;
int default_pixel_order;
struct ccs_data_container sdata, mdata;
u8 binning_horizontal;
u8 binning_vertical;
u8 scale_m;
u8 scaling_mode;
u8 frame_skip;
u16 embedded_start; /* embedded data start line */
u16 embedded_end;
u16 image_start; /* image data start line */
u16 visible_pixel_start; /* start pixel of the visible image */
bool streaming;
u8 streaming;
bool dev_init_done;
bool handler_setup_needed;
u8 compressed_min_bpp;

View File

@@ -149,7 +149,7 @@ static int dw9714_power_up(struct dw9714_device *dw9714_dev)
gpiod_set_value_cansleep(dw9714_dev->powerdown_gpio, 0);
usleep_range(1000, 2000);
usleep_range(12000, 14000);
return 0;
}

View File

@@ -835,6 +835,10 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor)
udelay(10); /* I wish this is a good value */
/*
* Note: Misinterpretation of reset assertion - do not re-use this code.
* The reset pin is using incorrect (for a reset signal) logical level.
*/
gpiod_set_value(sensor->reset, 1);
msleep(5000 * 1000 / sensor->xclk_freq + 1); /* Wait 5000 cycles */

View File

@@ -792,21 +792,6 @@ static int imx219_disable_streams(struct v4l2_subdev *sd,
return ret;
}
static void imx219_update_pad_format(struct imx219 *imx219,
const struct imx219_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
{
/* Bayer order varies with flips */
fmt->code = imx219_get_format_code(imx219, code);
fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_RAW;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
}
static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -858,12 +843,24 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
format = v4l2_subdev_state_get_format(state, 0);
prev_line_len = format->width + imx219->hblank->val;
/*
* Adjust the requested format to match the closest mode. The Bayer
* order varies with flips.
*/
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes),
width, height,
fmt->format.width, fmt->format.height);
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
fmt->format.code = imx219_get_format_code(imx219, fmt->format.code);
fmt->format.width = mode->width;
fmt->format.height = mode->height;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
*format = fmt->format;
/*

View File

@@ -32,6 +32,8 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
#include "aptina-pll.h"
/* Sysctl registers */
#define MT9M114_CHIP_ID CCI_REG16(0x0000)
#define MT9M114_COMMAND_REGISTER CCI_REG16(0x0080)
@@ -267,9 +269,9 @@
#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_VALUE(m, n) ((((n) - 1) << 8) | (m))
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982)
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(p) ((p) << 8)
#define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(p) (((p) - 1) << 8)
#define MT9M114_CAM_PORT_OUTPUT_CONTROL CCI_REG16(0xc984)
#define MT9M114_CAM_PORT_PORT_SELECT_PARALLEL (0 << 0)
#define MT9M114_CAM_PORT_PORT_SELECT_MIPI (1 << 0)
@@ -327,19 +329,22 @@
/*
* The minimum amount of horizontal and vertical blanking is undocumented. The
* minimum values that have been seen in register lists are 303 and 38, use
* minimum values that have been seen in register lists are 303 and 21, use
* them.
*
* Set the default to achieve 1280x960 at 30fps.
* Set the default to achieve full resolution (1296x976 analog crop
* rectangle, 1280x960 output size) at 30fps with a 48 MHz pixclock.
*/
#define MT9M114_MIN_HBLANK 303
#define MT9M114_MIN_VBLANK 38
#define MT9M114_DEF_HBLANK 323
#define MT9M114_DEF_VBLANK 39
#define MT9M114_MIN_VBLANK 21
#define MT9M114_DEF_HBLANK 308
#define MT9M114_DEF_VBLANK 21
#define MT9M114_DEF_FRAME_RATE 30
#define MT9M114_MAX_FRAME_RATE 120
#define MT9M114_DEF_PIXCLOCK 48000000
#define MT9M114_PIXEL_ARRAY_WIDTH 1296U
#define MT9M114_PIXEL_ARRAY_HEIGHT 976U
@@ -384,11 +389,7 @@ struct mt9m114 {
struct v4l2_fwnode_endpoint bus_cfg;
bool bypass_pll;
struct {
unsigned int m;
unsigned int n;
unsigned int p;
} pll;
struct aptina_pll pll;
unsigned int pixrate;
bool streaming;
@@ -758,7 +759,7 @@ static int mt9m114_initialize(struct mt9m114 *sensor)
sensor->pll.n),
&ret);
cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P,
MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p),
MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p1),
&ret);
}
@@ -788,14 +789,6 @@ static int mt9m114_initialize(struct mt9m114 *sensor)
if (ret < 0)
return ret;
ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE);
if (ret < 0)
return ret;
ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND);
if (ret < 0)
return ret;
return 0;
}
@@ -850,6 +843,18 @@ static int mt9m114_configure_pa(struct mt9m114 *sensor,
return ret;
}
/*
* For source pad formats other then RAW10 the IFP removes a 4 pixel border from
* its sink pad format size for demosaicing.
*/
static int mt9m114_ifp_get_border(struct v4l2_subdev_state *state)
{
const struct v4l2_mbus_framefmt *format =
v4l2_subdev_state_get_format(state, 1);
return format->code == MEDIA_BUS_FMT_SGRBG10_1X10 ? 0 : 4;
}
static int mt9m114_configure_ifp(struct mt9m114 *sensor,
struct v4l2_subdev_state *state)
{
@@ -857,6 +862,7 @@ static int mt9m114_configure_ifp(struct mt9m114 *sensor,
const struct v4l2_mbus_framefmt *format;
const struct v4l2_rect *crop;
const struct v4l2_rect *compose;
unsigned int border;
u64 output_format;
int ret = 0;
@@ -871,15 +877,18 @@ static int mt9m114_configure_ifp(struct mt9m114 *sensor,
return ret;
/*
* Color pipeline (IFP) cropping and scaling. Subtract 4 from the left
* and top coordinates to compensate for the lines and columns removed
* by demosaicing that are taken into account in the crop rectangle but
* not in the hardware.
* Color pipeline (IFP) cropping and scaling. The crop window registers
* apply cropping after demosaicing, which itself consumes 4 pixels on
* each side of the image. The crop rectangle exposed to userspace
* includes that demosaicing border, subtract it from the left and top
* coordinates to configure the crop window.
*/
border = mt9m114_ifp_get_border(state);
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET,
crop->left - 4, &ret);
crop->left - border, &ret);
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET,
crop->top - 4, &ret);
crop->top - border, &ret);
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH,
crop->width, &ret);
cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT,
@@ -950,6 +959,10 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor,
if (ret)
return ret;
ret = mt9m114_initialize(sensor);
if (ret)
goto error;
ret = mt9m114_configure_ifp(sensor, ifp_state);
if (ret)
goto error;
@@ -1823,6 +1836,41 @@ static int mt9m114_ifp_enum_frameintervals(struct v4l2_subdev *sd,
return 0;
}
/*
* Helper function to update IFP crop, compose rectangles and source format
* when the pixel border size changes, which requires resetting these.
*/
static void mt9m114_ifp_update_sel_and_src_fmt(struct v4l2_subdev_state *state)
{
struct v4l2_mbus_framefmt *src_format, *sink_format;
struct v4l2_rect *crop;
unsigned int border;
sink_format = v4l2_subdev_state_get_format(state, 0);
src_format = v4l2_subdev_state_get_format(state, 1);
crop = v4l2_subdev_state_get_crop(state, 0);
border = mt9m114_ifp_get_border(state);
crop->left = border;
crop->top = border;
crop->width = sink_format->width - 2 * border;
crop->height = sink_format->height - 2 * border;
*v4l2_subdev_state_get_compose(state, 0) = *crop;
src_format->width = crop->width;
src_format->height = crop->height;
if (src_format->code == MEDIA_BUS_FMT_SGRBG10_1X10) {
src_format->colorspace = V4L2_COLORSPACE_RAW;
src_format->ycbcr_enc = V4L2_YCBCR_ENC_601;
src_format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
} else {
src_format->colorspace = V4L2_COLORSPACE_SRGB;
src_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
src_format->quantization = V4L2_QUANTIZATION_DEFAULT;
}
}
static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt)
@@ -1840,17 +1888,28 @@ static int mt9m114_ifp_set_fmt(struct v4l2_subdev *sd,
format->height = clamp(ALIGN(fmt->format.height, 8),
MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT,
MT9M114_PIXEL_ARRAY_HEIGHT);
/* Propagate changes downstream. */
mt9m114_ifp_update_sel_and_src_fmt(state);
} else {
const struct mt9m114_format_info *info;
/* Only the media bus code can be changed on the source pad. */
info = mt9m114_format_info(sensor, 1, fmt->format.code);
format->code = info->code;
/* If the output format is RAW10, bypass the scaler. */
if (format->code == MEDIA_BUS_FMT_SGRBG10_1X10)
*format = *v4l2_subdev_state_get_format(state, 0);
/*
* If the output format changes from/to RAW10 then the crop
* rectangle needs to be adjusted to add / remove the 4 pixel
* border used for demosaicing. And these changes then need to
* be propagated to the compose rectangle and source format.
*/
if ((format->code == MEDIA_BUS_FMT_SGRBG10_1X10) !=
(info->code == MEDIA_BUS_FMT_SGRBG10_1X10)) {
format->code = info->code;
mt9m114_ifp_update_sel_and_src_fmt(state);
} else {
format->code = info->code;
}
}
fmt->format = *format;
@@ -1864,6 +1923,7 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
{
const struct v4l2_mbus_framefmt *format;
const struct v4l2_rect *crop;
unsigned int border;
int ret = 0;
/* Crop and compose are only supported on the sink pad. */
@@ -1878,15 +1938,17 @@ static int mt9m114_ifp_get_selection(struct v4l2_subdev *sd,
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
/*
* The crop default and bounds are equal to the sink
* format size minus 4 pixels on each side for demosaicing.
* Crop defaults and bounds are equal to the sink format size.
* For source pad formats other then RAW10 this gets reduced
* by 4 pixels on each side for demosaicing.
*/
format = v4l2_subdev_state_get_format(state, 0);
border = mt9m114_ifp_get_border(state);
sel->r.left = 4;
sel->r.top = 4;
sel->r.width = format->width - 8;
sel->r.height = format->height - 8;
sel->r.left = border;
sel->r.top = border;
sel->r.width = format->width - 2 * border;
sel->r.height = format->height - 2 * border;
break;
case V4L2_SEL_TGT_COMPOSE:
@@ -1918,9 +1980,10 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
struct v4l2_mbus_framefmt *format;
struct v4l2_mbus_framefmt *format, *src_format;
struct v4l2_rect *crop;
struct v4l2_rect *compose;
unsigned int border;
if (sel->target != V4L2_SEL_TGT_CROP &&
sel->target != V4L2_SEL_TGT_COMPOSE)
@@ -1930,27 +1993,37 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd,
if (sel->pad != 0)
return -EINVAL;
format = v4l2_subdev_state_get_format(state, 0);
crop = v4l2_subdev_state_get_crop(state, 0);
/* Crop and compose cannot be changed when bypassing the scaler. */
src_format = v4l2_subdev_state_get_format(state, 1);
if (src_format->code == MEDIA_BUS_FMT_SGRBG10_1X10) {
sel->r = *crop;
return 0;
}
format = v4l2_subdev_state_get_format(state, 0);
compose = v4l2_subdev_state_get_compose(state, 0);
if (sel->target == V4L2_SEL_TGT_CROP) {
/*
* Clamp the crop rectangle. Demosaicing removes 4 pixels on
* each side of the image.
* Clamp the crop rectangle. For source pad formats other then
* RAW10 demosaicing removes 4 pixels on each side of the image.
*/
crop->left = clamp_t(unsigned int, ALIGN(sel->r.left, 2), 4,
format->width - 4 -
border = mt9m114_ifp_get_border(state);
crop->left = clamp_t(unsigned int, ALIGN(sel->r.left, 2), border,
format->width - border -
MT9M114_SCALER_CROPPED_INPUT_WIDTH);
crop->top = clamp_t(unsigned int, ALIGN(sel->r.top, 2), 4,
format->height - 4 -
crop->top = clamp_t(unsigned int, ALIGN(sel->r.top, 2), border,
format->height - border -
MT9M114_SCALER_CROPPED_INPUT_HEIGHT);
crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
MT9M114_SCALER_CROPPED_INPUT_WIDTH,
format->width - 4 - crop->left);
format->width - border - crop->left);
crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
MT9M114_SCALER_CROPPED_INPUT_HEIGHT,
format->height - 4 - crop->top);
format->height - border - crop->top);
sel->r = *crop;
@@ -1974,9 +2047,8 @@ static int mt9m114_ifp_set_selection(struct v4l2_subdev *sd,
}
/* Propagate the compose rectangle to the source format. */
format = v4l2_subdev_state_get_format(state, 1);
format->width = compose->width;
format->height = compose->height;
src_format->width = compose->width;
src_format->height = compose->height;
return 0;
}
@@ -2227,6 +2299,13 @@ error_regulator:
static void mt9m114_power_off(struct mt9m114 *sensor)
{
unsigned int duration;
gpiod_set_value(sensor->reset, 1);
/* Power off takes 10 clock cycles. Double it to be safe. */
duration = DIV_ROUND_UP(2 * 10 * 1000000, clk_get_rate(sensor->clk));
fsleep(duration);
clk_disable_unprepare(sensor->clk);
regulator_bulk_disable(ARRAY_SIZE(sensor->supplies), sensor->supplies);
}
@@ -2235,19 +2314,8 @@ static int __maybe_unused mt9m114_runtime_resume(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct mt9m114 *sensor = ifp_to_mt9m114(sd);
int ret;
ret = mt9m114_power_on(sensor);
if (ret)
return ret;
ret = mt9m114_initialize(sensor);
if (ret) {
mt9m114_power_off(sensor);
return ret;
}
return 0;
return mt9m114_power_on(sensor);
}
static int __maybe_unused mt9m114_runtime_suspend(struct device *dev)
@@ -2281,14 +2349,39 @@ static int mt9m114_verify_link_frequency(struct mt9m114 *sensor,
return 0;
}
/*
* Based on the docs the PLL is believed to have the following setup:
*
* +-----+ +-----+ +-----+ +-----+ +-----+
* Fin --> | / N | --> | x M | --> | x 2 | --> | / P | --> | / 2 | -->
* +-----+ +-----+ +-----+ +-----+ +-----+
* fBit fWord fSensor
* ext_clock int_clock out_clock pix_clock
*
* The MT9M114 docs give a max fBit rate of 768 MHz which translates to
* an out_clock_max of 384 MHz.
*/
static int mt9m114_clk_init(struct mt9m114 *sensor)
{
static const struct aptina_pll_limits limits = {
.ext_clock_min = 6000000,
.ext_clock_max = 54000000,
/* int_clock_* limits are not documented taken from mt9p031.c */
.int_clock_min = 2000000,
.int_clock_max = 13500000,
/* out_clock_min is not documented, taken from mt9p031.c */
.out_clock_min = 180000000,
.out_clock_max = 384000000,
.pix_clock_max = 48000000,
.n_min = 1,
.n_max = 64,
.m_min = 16,
.m_max = 192,
.p1_min = 8,
.p1_max = 8,
};
unsigned int pixrate;
/* Hardcode the PLL multiplier and dividers to default settings. */
sensor->pll.m = 32;
sensor->pll.n = 1;
sensor->pll.p = 7;
int ret;
/*
* Calculate the pixel rate and link frequency. The CSI-2 bus is clocked
@@ -2308,8 +2401,15 @@ static int mt9m114_clk_init(struct mt9m114 *sensor)
}
/* 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));
sensor->pll.ext_clock = clk_get_rate(sensor->clk);
sensor->pll.pix_clock = MT9M114_DEF_PIXCLOCK;
ret = aptina_pll_calculate(&sensor->client->dev, &limits, &sensor->pll);
if (ret)
return ret;
pixrate = sensor->pll.ext_clock * sensor->pll.m
/ (sensor->pll.n * sensor->pll.p1);
if (mt9m114_verify_link_frequency(sensor, pixrate) == 0) {
sensor->pixrate = pixrate;
sensor->bypass_pll = false;
@@ -2360,11 +2460,17 @@ static int mt9m114_parse_dt(struct mt9m114 *sensor)
struct fwnode_handle *ep;
int ret;
/*
* On ACPI systems the fwnode graph can be initialized by a bridge
* driver, which may not have probed yet. Wait for this.
*
* TODO: Return an error once bridge driver code will have moved
* to the ACPI core.
*/
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep) {
dev_err(&sensor->client->dev, "No endpoint found\n");
return -EINVAL;
}
if (!ep)
return dev_err_probe(&sensor->client->dev, -EPROBE_DEFER,
"waiting for fwnode graph endpoint\n");
sensor->bus_cfg.bus_type = V4L2_MBUS_UNKNOWN;
ret = v4l2_fwnode_endpoint_alloc_parse(ep, &sensor->bus_cfg);
@@ -2434,7 +2540,7 @@ static int mt9m114_probe(struct i2c_client *client)
goto error_ep_free;
}
sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(sensor->reset)) {
ret = PTR_ERR(sensor->reset);
dev_err_probe(dev, ret, "Failed to get reset GPIO\n");
@@ -2459,8 +2565,8 @@ static int mt9m114_probe(struct i2c_client *client)
/*
* Identify the sensor. The driver supports runtime PM, but needs to
* work when runtime PM is disabled in the kernel. To that end, power
* the sensor on manually here, and initialize it after identification
* to reach the same state as if resumed through runtime PM.
* the sensor on manually here to reach the same state as if resumed
* through runtime PM.
*/
ret = mt9m114_power_on(sensor);
if (ret < 0) {
@@ -2472,10 +2578,6 @@ static int mt9m114_probe(struct i2c_client *client)
if (ret < 0)
goto error_power_off;
ret = mt9m114_initialize(sensor);
if (ret < 0)
goto error_power_off;
/*
* Enable runtime PM with autosuspend. As the device has been powered
* manually, mark it as active, and increase the usage count without
@@ -2550,11 +2652,18 @@ static const struct of_device_id mt9m114_of_ids[] = {
};
MODULE_DEVICE_TABLE(of, mt9m114_of_ids);
static const struct acpi_device_id mt9m114_acpi_ids[] = {
{ "INT33F0" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_ids);
static struct i2c_driver mt9m114_driver = {
.driver = {
.name = "mt9m114",
.pm = &mt9m114_pm_ops,
.of_match_table = mt9m114_of_ids,
.acpi_match_table = mt9m114_acpi_ids,
},
.probe = mt9m114_probe,
.remove = mt9m114_remove,

View File

@@ -41,6 +41,10 @@
#define OG0VE1B_ANALOGUE_GAIN_STEP 1
#define OG0VE1B_ANALOGUE_GAIN_DEFAULT 16
/* Vertical timing size */
#define OG0VE1B_REG_VTS CCI_REG16(0x380e)
#define OG0VE1B_VTS_MAX 0xffff
/* Test pattern */
#define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00)
#define OG0VE1B_TEST_PATTERN_ENABLE BIT(7)
@@ -89,6 +93,8 @@ struct og0ve1b {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl_handler ctrl_handler;
/* Saved register value */
@@ -140,8 +146,6 @@ static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = {
{ CCI_REG8(0x380b), 0xe0 },
{ CCI_REG8(0x380c), 0x03 }, /* horizontal timing size */
{ CCI_REG8(0x380d), 0x18 },
{ CCI_REG8(0x380e), 0x02 }, /* vertical timing size */
{ CCI_REG8(0x380f), 0x38 },
{ CCI_REG8(0x3811), 0x04 },
{ CCI_REG8(0x3813), 0x04 },
{ CCI_REG8(0x3814), 0x11 },
@@ -273,8 +277,25 @@ static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b,
ctrl_handler);
const struct og0ve1b_mode *mode = &supported_modes[0];
s64 exposure_max;
int ret;
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
exposure_max = ctrl->val + mode->height -
OG0VE1B_EXPOSURE_MAX_MARGIN;
ret = __v4l2_ctrl_modify_range(og0ve1b->exposure,
og0ve1b->exposure->minimum,
exposure_max,
og0ve1b->exposure->step,
og0ve1b->exposure->default_value);
if (ret)
return ret;
}
/* V4L2 controls are applied, when sensor is powered up for streaming */
if (!pm_runtime_get_if_active(og0ve1b->dev))
return 0;
@@ -288,6 +309,10 @@ static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl)
ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_EXPOSURE,
ctrl->val << 4, NULL);
break;
case V4L2_CID_VBLANK:
ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_VTS,
ctrl->val + mode->height, NULL);
break;
case V4L2_CID_TEST_PATTERN:
ret = og0ve1b_enable_test_pattern(og0ve1b, ctrl->val);
break;
@@ -309,8 +334,8 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b)
{
struct v4l2_ctrl_handler *ctrl_hdlr = &og0ve1b->ctrl_handler;
const struct og0ve1b_mode *mode = &supported_modes[0];
s64 exposure_max, pixel_rate, h_blank, v_blank;
struct v4l2_fwnode_device_properties props;
s64 exposure_max, pixel_rate, h_blank;
struct v4l2_ctrl *ctrl;
int ret;
@@ -333,24 +358,24 @@ static int og0ve1b_init_controls(struct og0ve1b *og0ve1b)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_VBLANK,
mode->vts - mode->height,
mode->vts - mode->height, 1,
mode->vts - mode->height);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
v_blank = mode->vts - mode->height;
og0ve1b->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops,
V4L2_CID_VBLANK, v_blank,
OG0VE1B_VTS_MAX - mode->height, 1,
v_blank);
v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
OG0VE1B_ANALOGUE_GAIN_MIN, OG0VE1B_ANALOGUE_GAIN_MAX,
OG0VE1B_ANALOGUE_GAIN_STEP,
OG0VE1B_ANALOGUE_GAIN_DEFAULT);
exposure_max = (mode->vts - OG0VE1B_EXPOSURE_MAX_MARGIN);
v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops,
V4L2_CID_EXPOSURE,
OG0VE1B_EXPOSURE_MIN, exposure_max,
OG0VE1B_EXPOSURE_STEP,
OG0VE1B_EXPOSURE_DEFAULT);
exposure_max = mode->vts - OG0VE1B_EXPOSURE_MAX_MARGIN;
og0ve1b->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops,
V4L2_CID_EXPOSURE,
OG0VE1B_EXPOSURE_MIN,
exposure_max,
OG0VE1B_EXPOSURE_STEP,
OG0VE1B_EXPOSURE_DEFAULT);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og0ve1b_ctrl_ops,
V4L2_CID_TEST_PATTERN,

1130
drivers/media/i2c/os05b10.c Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -993,7 +993,7 @@ static int ov2735_probe(struct i2c_client *client)
"failed to parse endpoint configuration\n");
ov2735->reset_gpio = devm_gpiod_get_optional(ov2735->dev,
"reset", GPIOD_OUT_LOW);
"reset", GPIOD_OUT_HIGH);
if (IS_ERR(ov2735->reset_gpio))
return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->reset_gpio),
"failed to get reset GPIO\n");

File diff suppressed because it is too large Load Diff

View File

@@ -41,6 +41,10 @@
#define OV6211_ANALOGUE_GAIN_STEP 1
#define OV6211_ANALOGUE_GAIN_DEFAULT 160
/* Vertical timing size */
#define OV6211_REG_VTS CCI_REG16(0x380e)
#define OV6211_VTS_MAX 0xffff
/* Test pattern */
#define OV6211_REG_PRE_ISP CCI_REG8(0x5e00)
#define OV6211_TEST_PATTERN_ENABLE BIT(7)
@@ -89,6 +93,8 @@ struct ov6211 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl_handler ctrl_handler;
/* Saved register values */
@@ -167,8 +173,6 @@ static const struct cci_reg_sequence ov6211_400x400_120fps_mode[] = {
{ CCI_REG8(0x380b), 0x90 },
{ CCI_REG8(0x380c), 0x05 }, /* horizontal timing size */
{ CCI_REG8(0x380d), 0xf2 },
{ CCI_REG8(0x380e), 0x01 }, /* vertical timing size */
{ CCI_REG8(0x380f), 0xb6 },
{ CCI_REG8(0x3810), 0x00 },
{ CCI_REG8(0x3811), 0x04 },
{ CCI_REG8(0x3812), 0x00 },
@@ -251,8 +255,25 @@ static int ov6211_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov6211 *ov6211 = container_of(ctrl->handler, struct ov6211,
ctrl_handler);
const struct ov6211_mode *mode = &supported_modes[0];
s64 exposure_max;
int ret;
/* Propagate change of current control to all related controls */
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
exposure_max = ctrl->val + mode->height -
OV6211_EXPOSURE_MAX_MARGIN;
ret = __v4l2_ctrl_modify_range(ov6211->exposure,
ov6211->exposure->minimum,
exposure_max,
ov6211->exposure->step,
ov6211->exposure->default_value);
if (ret)
return ret;
}
/* V4L2 controls are applied, when sensor is powered up for streaming */
if (!pm_runtime_get_if_active(ov6211->dev))
return 0;
@@ -266,6 +287,10 @@ static int ov6211_set_ctrl(struct v4l2_ctrl *ctrl)
ret = cci_write(ov6211->regmap, OV6211_REG_EXPOSURE,
ctrl->val << 4, NULL);
break;
case V4L2_CID_VBLANK:
ret = cci_write(ov6211->regmap, OV6211_REG_VTS,
ctrl->val + mode->height, NULL);
break;
case V4L2_CID_TEST_PATTERN:
ret = ov6211_set_test_pattern(ov6211, ctrl->val);
break;
@@ -287,8 +312,8 @@ static int ov6211_init_controls(struct ov6211 *ov6211)
{
struct v4l2_ctrl_handler *ctrl_hdlr = &ov6211->ctrl_handler;
const struct ov6211_mode *mode = &supported_modes[0];
s64 exposure_max, pixel_rate, h_blank, v_blank;
struct v4l2_fwnode_device_properties props;
s64 exposure_max, pixel_rate, h_blank;
struct v4l2_ctrl *ctrl;
int ret;
@@ -311,24 +336,24 @@ static int ov6211_init_controls(struct ov6211 *ov6211)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_VBLANK,
mode->vts - mode->height,
mode->vts - mode->height, 1,
mode->vts - mode->height);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
v_blank = mode->vts - mode->height;
ov6211->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops,
V4L2_CID_VBLANK, v_blank,
OV6211_VTS_MAX - mode->height, 1,
v_blank);
v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
OV6211_ANALOGUE_GAIN_MIN, OV6211_ANALOGUE_GAIN_MAX,
OV6211_ANALOGUE_GAIN_STEP,
OV6211_ANALOGUE_GAIN_DEFAULT);
exposure_max = (mode->vts - OV6211_EXPOSURE_MAX_MARGIN);
v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops,
V4L2_CID_EXPOSURE,
OV6211_EXPOSURE_MIN, exposure_max,
OV6211_EXPOSURE_STEP,
OV6211_EXPOSURE_DEFAULT);
exposure_max = mode->vts - OV6211_EXPOSURE_MAX_MARGIN;
ov6211->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops,
V4L2_CID_EXPOSURE,
OV6211_EXPOSURE_MIN,
exposure_max,
OV6211_EXPOSURE_STEP,
OV6211_EXPOSURE_DEFAULT);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov6211_ctrl_ops,
V4L2_CID_TEST_PATTERN,

View File

@@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -37,6 +38,29 @@
#define OV9282_REG_ID 0x300a
#define OV9282_ID 0x9281
/* Output enable registers */
#define OV9282_REG_OUTPUT_ENABLE4 0x3004
#define OV9282_OUTPUT_ENABLE4_GPIO2 BIT(1)
#define OV9282_OUTPUT_ENABLE4_D9 BIT(0)
#define OV9282_REG_OUTPUT_ENABLE5 0x3005
#define OV9282_OUTPUT_ENABLE5_D8 BIT(7)
#define OV9282_OUTPUT_ENABLE5_D7 BIT(6)
#define OV9282_OUTPUT_ENABLE5_D6 BIT(5)
#define OV9282_OUTPUT_ENABLE5_D5 BIT(4)
#define OV9282_OUTPUT_ENABLE5_D4 BIT(3)
#define OV9282_OUTPUT_ENABLE5_D3 BIT(2)
#define OV9282_OUTPUT_ENABLE5_D2 BIT(1)
#define OV9282_OUTPUT_ENABLE5_D1 BIT(0)
#define OV9282_REG_OUTPUT_ENABLE6 0x3006
#define OV9282_OUTPUT_ENABLE6_D0 BIT(7)
#define OV9282_OUTPUT_ENABLE6_PCLK BIT(6)
#define OV9282_OUTPUT_ENABLE6_HREF BIT(5)
#define OV9282_OUTPUT_ENABLE6_STROBE BIT(3)
#define OV9282_OUTPUT_ENABLE6_ILPWM BIT(2)
#define OV9282_OUTPUT_ENABLE6_VSYNC BIT(1)
/* Exposure control */
#define OV9282_REG_EXPOSURE 0x3500
#define OV9282_EXPOSURE_MIN 1
@@ -74,6 +98,10 @@
#define OV9282_REG_MIPI_CTRL00 0x4800
#define OV9282_GATED_CLOCK BIT(5)
/* Flash/Strobe control registers */
#define OV9282_REG_STROBE_FRAME_SPAN 0x3925
#define OV9282_STROBE_FRAME_SPAN_DEFAULT 0x0000001a
/* Input clock rate */
#define OV9282_INCLK_RATE 24000000
@@ -101,6 +129,8 @@
#define OV9282_REG_MIN 0x00
#define OV9282_REG_MAX 0xfffff
#define OV9282_STROBE_SPAN_FACTOR 192
static const char * const ov9282_supply_names[] = {
"avdd", /* Analog power */
"dovdd", /* Digital I/O power */
@@ -169,6 +199,7 @@ struct ov9282_mode {
* @exp_ctrl: Pointer to exposure control
* @again_ctrl: Pointer to analog gain control
* @pixel_rate: Pointer to pixel rate control
* @flash_duration: Pointer to flash duration control
* @vblank: Vertical blanking in lines
* @noncontinuous_clock: Selection of CSI2 noncontinuous clock mode
* @cur_mode: Pointer to current selected sensor mode
@@ -191,6 +222,7 @@ struct ov9282 {
struct v4l2_ctrl *again_ctrl;
};
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *flash_duration;
u32 vblank;
bool noncontinuous_clock;
const struct ov9282_mode *cur_mode;
@@ -213,9 +245,9 @@ static const struct ov9282_reg common_regs[] = {
{0x0302, 0x32},
{0x030e, 0x02},
{0x3001, 0x00},
{0x3004, 0x00},
{0x3005, 0x00},
{0x3006, 0x04},
{OV9282_REG_OUTPUT_ENABLE4, 0x00},
{OV9282_REG_OUTPUT_ENABLE5, 0x00},
{OV9282_REG_OUTPUT_ENABLE6, OV9282_OUTPUT_ENABLE6_ILPWM},
{0x3011, 0x0a},
{0x3013, 0x18},
{0x301c, 0xf0},
@@ -582,6 +614,15 @@ static int ov9282_update_controls(struct ov9282 *ov9282,
mode->vblank_max, 1, mode->vblank);
}
static u32 ov9282_exposure_to_us(struct ov9282 *ov9282, u32 exposure)
{
/* calculate exposure time in µs */
u32 frame_width = ov9282->cur_mode->width + ov9282->hblank_ctrl->val;
u32 trow_us = frame_width / (ov9282->pixel_rate->val / 1000000UL);
return exposure * trow_us;
}
/**
* ov9282_update_exp_gain() - Set updated exposure and gain
* @ov9282: pointer to ov9282 device
@@ -593,9 +634,10 @@ static int ov9282_update_controls(struct ov9282 *ov9282,
static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain)
{
int ret;
u32 exposure_us = ov9282_exposure_to_us(ov9282, exposure);
dev_dbg(ov9282->dev, "Set exp %u, analog gain %u",
exposure, gain);
dev_dbg(ov9282->dev, "Set exp %u (~%u us), analog gain %u",
exposure, exposure_us, gain);
ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1);
if (ret)
@@ -606,6 +648,12 @@ static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain)
goto error_release_group_hold;
ret = ov9282_write_reg(ov9282, OV9282_REG_AGAIN, 1, gain);
if (ret)
goto error_release_group_hold;
ret = __v4l2_ctrl_modify_range(ov9282->flash_duration,
0, exposure_us, 1,
OV9282_STROBE_FRAME_SPAN_DEFAULT);
error_release_group_hold:
ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 0);
@@ -647,6 +695,75 @@ static int ov9282_set_ctrl_vflip(struct ov9282 *ov9282, int value)
current_val);
}
static int ov9282_set_ctrl_flash_strobe_oe(struct ov9282 *ov9282, bool enable)
{
u32 current_val;
int ret;
ret = ov9282_read_reg(ov9282, OV9282_REG_OUTPUT_ENABLE6, 1, &current_val);
if (ret)
return ret;
if (enable)
current_val |= OV9282_OUTPUT_ENABLE6_STROBE;
else
current_val &= ~OV9282_OUTPUT_ENABLE6_STROBE;
return ov9282_write_reg(ov9282, OV9282_REG_OUTPUT_ENABLE6, 1, current_val);
}
static u32 ov9282_us_to_flash_duration(struct ov9282 *ov9282, u32 value)
{
/*
* Calculate "strobe_frame_span" increments from a given value (µs).
* This is quite tricky as "The step width of shift and span is
* programmable under system clock domain.", but it's not documented
* how to program this step width (at least in the datasheet available
* to the author at time of writing).
* The formula below is interpolated from different modes/framerates
* and should work quite well for most settings.
*/
u32 frame_width = ov9282->cur_mode->width + ov9282->hblank_ctrl->val;
return value * OV9282_STROBE_SPAN_FACTOR / frame_width;
}
static u32 ov9282_flash_duration_to_us(struct ov9282 *ov9282, u32 value)
{
/*
* Calculate back to microseconds from "strobe_frame_span" increments.
* As the calculation in ov9282_us_to_flash_duration uses an integer
* divison round up here.
*/
u32 frame_width = ov9282->cur_mode->width + ov9282->hblank_ctrl->val;
return DIV_ROUND_UP(value * frame_width, OV9282_STROBE_SPAN_FACTOR);
}
static int ov9282_set_ctrl_flash_duration(struct ov9282 *ov9282, u32 value)
{
u32 val = ov9282_us_to_flash_duration(ov9282, value);
int ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_STROBE_FRAME_SPAN, 1,
(val >> 24) & 0xff);
if (ret)
return ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_STROBE_FRAME_SPAN + 1, 1,
(val >> 16) & 0xff);
if (ret)
return ret;
ret = ov9282_write_reg(ov9282, OV9282_REG_STROBE_FRAME_SPAN + 2, 1,
(val >> 8) & 0xff);
if (ret)
return ret;
return ov9282_write_reg(ov9282, OV9282_REG_STROBE_FRAME_SPAN + 3, 1,
val & 0xff);
}
/**
* ov9282_set_ctrl() - Set subdevice control
* @ctrl: pointer to v4l2_ctrl structure
@@ -713,6 +830,12 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
ret = ov9282_write_reg(ov9282, OV9282_REG_TIMING_HTS, 2,
(ctrl->val + ov9282->cur_mode->width) >> 1);
break;
case V4L2_CID_FLASH_STROBE_OE:
ret = ov9282_set_ctrl_flash_strobe_oe(ov9282, ctrl->val);
break;
case V4L2_CID_FLASH_DURATION:
ret = ov9282_set_ctrl_flash_duration(ov9282, ctrl->val);
break;
default:
dev_err(ov9282->dev, "Invalid control %d", ctrl->id);
ret = -EINVAL;
@@ -723,9 +846,36 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl)
return ret;
}
static int ov9282_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov9282 *ov9282 =
container_of_const(ctrl->handler, struct ov9282, ctrl_handler);
if (ctrl->id == V4L2_CID_FLASH_DURATION) {
u32 us = ctrl->val;
u32 fd = ov9282_us_to_flash_duration(ov9282, us);
/* get nearest strobe_duration value */
u32 us0 = ov9282_flash_duration_to_us(ov9282, fd);
u32 us1 = ov9282_flash_duration_to_us(ov9282, fd + 1);
if (abs(us1 - us) < abs(us - us0))
ctrl->val = us1;
else
ctrl->val = us0;
if (us != ctrl->val)
dev_dbg(ov9282->dev, "using next valid strobe_duration %u instead of %u\n",
ctrl->val, us);
}
return 0;
}
/* V4l2 subdevice control ops*/
static const struct v4l2_ctrl_ops ov9282_ctrl_ops = {
.s_ctrl = ov9282_set_ctrl,
.try_ctrl = ov9282_try_ctrl,
};
/**
@@ -1299,10 +1449,11 @@ static int ov9282_init_controls(struct ov9282 *ov9282)
const struct ov9282_mode *mode = ov9282->cur_mode;
struct v4l2_fwnode_device_properties props;
u32 hblank_min;
u32 exposure_us;
u32 lpfr;
int ret;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10);
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
if (ret)
return ret;
@@ -1367,6 +1518,16 @@ static int ov9282_init_controls(struct ov9282 *ov9282)
OV9282_TIMING_HTS_MAX - mode->width,
1, hblank_min);
/* Flash/Strobe controls */
v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops,
V4L2_CID_FLASH_STROBE_OE, 0, 1, 1, 0);
exposure_us = ov9282_exposure_to_us(ov9282, OV9282_EXPOSURE_DEFAULT);
ov9282->flash_duration =
v4l2_ctrl_new_std(ctrl_hdlr, &ov9282_ctrl_ops,
V4L2_CID_FLASH_DURATION, 0, exposure_us, 1,
OV9282_STROBE_FRAME_SPAN_DEFAULT);
ret = v4l2_fwnode_device_parse(ov9282->dev, &props);
if (!ret) {
/* Failure sets ctrl_hdlr->error, which we check afterwards anyway */

1377
drivers/media/i2c/s5k3m5.c Normal file

File diff suppressed because it is too large Load Diff

1487
drivers/media/i2c/s5kjn1.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -49,8 +49,6 @@ MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
#define PREFIX "saa6588: "
#define dprintk if (debug) printk
struct saa6588 {
struct v4l2_subdev sd;
@@ -144,14 +142,14 @@ static bool block_from_buf(struct saa6588 *s, unsigned char *buf)
if (s->rd_index == s->wr_index) {
if (debug > 2)
dprintk(PREFIX "Read: buffer empty.\n");
v4l2_info(&s->sd, "Read: buffer empty.\n");
return false;
}
if (debug > 2) {
dprintk(PREFIX "Read: ");
v4l2_info(&s->sd, "Read: ");
for (i = s->rd_index; i < s->rd_index + 3; i++)
dprintk("0x%02x ", s->buffer[i]);
v4l2_info(&s->sd, "0x%02x ", s->buffer[i]);
}
memcpy(buf, &s->buffer[s->rd_index], 3);
@@ -162,7 +160,7 @@ static bool block_from_buf(struct saa6588 *s, unsigned char *buf)
s->block_count--;
if (debug > 2)
dprintk("%d blocks total.\n", s->block_count);
v4l2_info(&s->sd, "%d blocks total.\n", s->block_count);
return true;
}
@@ -222,11 +220,11 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
unsigned int i;
if (debug > 3)
dprintk(PREFIX "New block: ");
v4l2_info(&s->sd, "New block: ");
for (i = 0; i < 3; ++i) {
if (debug > 3)
dprintk("0x%02x ", blockbuf[i]);
v4l2_info(&s->sd, "0x%02x ", blockbuf[i]);
s->buffer[s->wr_index] = blockbuf[i];
s->wr_index++;
}
@@ -242,7 +240,7 @@ static void block_to_buf(struct saa6588 *s, unsigned char *blockbuf)
s->block_count++;
if (debug > 3)
dprintk("%d blocks total.\n", s->block_count);
v4l2_info(&s->sd, "%d blocks total.\n", s->block_count);
}
static void saa6588_i2c_poll(struct saa6588 *s)
@@ -257,7 +255,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
SAA6588 returns garbage otherwise. */
if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1)
dprintk(PREFIX "read error!\n");
v4l2_info(&s->sd, "read error!\n");
return;
}
@@ -267,7 +265,7 @@ static void saa6588_i2c_poll(struct saa6588 *s)
blocknum = tmpbuf[0] >> 5;
if (blocknum == s->last_blocknum) {
if (debug > 3)
dprintk("Saw block %d again.\n", blocknum);
v4l2_info(&s->sd, "Saw block %d again.\n", blocknum);
return;
}
@@ -370,12 +368,13 @@ static void saa6588_configure(struct saa6588 *s)
break;
}
dprintk(PREFIX "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
buf[0], buf[1], buf[2]);
if (debug)
v4l2_info(&s->sd, "writing: 0w=0x%02x 1w=0x%02x 2w=0x%02x\n",
buf[0], buf[1], buf[2]);
rc = i2c_master_send(client, buf, 3);
if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
v4l2_info(&s->sd, "i2c i/o error: rc == %d (should be 3)\n", rc);
}
/* ---------------------------------------------------------------------- */

View File

@@ -228,6 +228,7 @@ static int tw9903_probe(struct i2c_client *client)
if (write_regs(sd, initial_registers) < 0) {
v4l2_err(client, "error initializing TW9903\n");
v4l2_ctrl_handler_free(hdl);
return -EINVAL;
}

View File

@@ -196,6 +196,7 @@ static int tw9906_probe(struct i2c_client *client)
if (write_regs(sd, initial_registers) < 0) {
v4l2_err(client, "error initializing TW9906\n");
v4l2_ctrl_handler_free(hdl);
return -EINVAL;
}

View File

@@ -679,6 +679,23 @@ void media_device_unregister_entity(struct media_entity *entity)
}
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
#ifdef CONFIG_DEBUG_FS
/*
* Log the state of media requests. Very useful for debugging.
*/
static int media_device_requests(struct seq_file *file, void *priv)
{
struct media_device *dev = dev_get_drvdata(file->private);
seq_printf(file, "number of requests: %d\n",
atomic_read(&dev->num_requests));
seq_printf(file, "number of request objects: %d\n",
atomic_read(&dev->num_request_objects));
return 0;
}
#endif
void media_device_init(struct media_device *mdev)
{
INIT_LIST_HEAD(&mdev->entities);
@@ -697,6 +714,9 @@ void media_device_init(struct media_device *mdev)
media_set_bus_info(mdev->bus_info, sizeof(mdev->bus_info),
mdev->dev);
atomic_set(&mdev->num_requests, 0);
atomic_set(&mdev->num_request_objects, 0);
dev_dbg(mdev->dev, "Media device initialized\n");
}
EXPORT_SYMBOL_GPL(media_device_init);
@@ -748,6 +768,15 @@ int __must_check __media_device_register(struct media_device *mdev,
dev_dbg(mdev->dev, "Media device registered\n");
#ifdef CONFIG_DEBUG_FS
if (!media_debugfs_root)
media_debugfs_root = debugfs_create_dir("media", NULL);
mdev->media_dir = debugfs_create_dir(dev_name(&devnode->dev),
media_debugfs_root);
debugfs_create_devm_seqfile(&devnode->dev, "requests",
mdev->media_dir, media_device_requests);
#endif
return 0;
}
EXPORT_SYMBOL_GPL(__media_device_register);
@@ -824,6 +853,7 @@ void media_device_unregister(struct media_device *mdev)
dev_dbg(mdev->dev, "Media device unregistered\n");
debugfs_remove_recursive(mdev->media_dir);
device_remove_file(&mdev->devnode->dev, &dev_attr_model);
media_devnode_unregister(mdev->devnode);
/* devnode free is handled in media_devnode_*() */

View File

@@ -45,6 +45,9 @@ static dev_t media_dev_t;
static DEFINE_MUTEX(media_devnode_lock);
static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
/* debugfs */
struct dentry *media_debugfs_root;
/* Called when the last user of the media device exits. */
static void media_devnode_release(struct device *cd)
{
@@ -231,6 +234,7 @@ int __must_check media_devnode_register(struct media_device *mdev,
if (devnode->parent)
devnode->dev.parent = devnode->parent;
dev_set_name(&devnode->dev, "media%d", devnode->minor);
dev_set_drvdata(&devnode->dev, mdev);
device_initialize(&devnode->dev);
/* Part 2: Initialize the character device */
@@ -309,6 +313,7 @@ static int __init media_devnode_init(void)
static void __exit media_devnode_exit(void)
{
debugfs_remove_recursive(media_debugfs_root);
bus_unregister(&media_bus_type);
unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
}

View File

@@ -54,6 +54,7 @@ static void media_request_clean(struct media_request *req)
req->access_count = 0;
WARN_ON(req->num_incomplete_objects);
req->num_incomplete_objects = 0;
req->manual_completion = false;
wake_up_interruptible_all(&req->poll_wait);
}
@@ -74,6 +75,7 @@ static void media_request_release(struct kref *kref)
mdev->ops->req_free(req);
else
kfree(req);
atomic_dec(&mdev->num_requests);
}
void media_request_put(struct media_request *req)
@@ -298,6 +300,7 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
req->mdev = mdev;
req->state = MEDIA_REQUEST_STATE_IDLE;
req->num_incomplete_objects = 0;
req->manual_completion = false;
kref_init(&req->kref);
INIT_LIST_HEAD(&req->objects);
spin_lock_init(&req->lock);
@@ -317,6 +320,7 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd)
snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
atomic_inc_return(&mdev->request_id), fd_prepare_fd(fdf));
atomic_inc(&mdev->num_requests);
dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
*alloc_fd = fd_publish(fdf);
@@ -337,10 +341,12 @@ static void media_request_object_release(struct kref *kref)
struct media_request_object *obj =
container_of(kref, struct media_request_object, kref);
struct media_request *req = obj->req;
struct media_device *mdev = obj->mdev;
if (WARN_ON(req))
media_request_object_unbind(obj);
obj->ops->release(obj);
atomic_dec(&mdev->num_request_objects);
}
struct media_request_object *
@@ -405,6 +411,7 @@ int media_request_object_bind(struct media_request *req,
obj->req = req;
obj->ops = ops;
obj->priv = priv;
obj->mdev = req->mdev;
if (is_buffer)
list_add_tail(&obj->list, &req->objects);
@@ -412,6 +419,7 @@ int media_request_object_bind(struct media_request *req,
list_add(&obj->list, &req->objects);
req->num_incomplete_objects++;
ret = 0;
atomic_inc(&obj->mdev->num_request_objects);
unlock:
spin_unlock_irqrestore(&req->lock, flags);
@@ -449,7 +457,7 @@ void media_request_object_unbind(struct media_request_object *obj)
req->num_incomplete_objects--;
if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
!req->num_incomplete_objects) {
!req->num_incomplete_objects && !req->manual_completion) {
req->state = MEDIA_REQUEST_STATE_COMPLETE;
completed = true;
wake_up_interruptible_all(&req->poll_wait);
@@ -478,7 +486,7 @@ void media_request_object_complete(struct media_request_object *obj)
WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
goto unlock;
if (!--req->num_incomplete_objects) {
if (!--req->num_incomplete_objects && !req->manual_completion) {
req->state = MEDIA_REQUEST_STATE_COMPLETE;
wake_up_interruptible_all(&req->poll_wait);
completed = true;
@@ -489,3 +497,38 @@ unlock:
media_request_put(req);
}
EXPORT_SYMBOL_GPL(media_request_object_complete);
void media_request_manual_complete(struct media_request *req)
{
bool completed = false;
unsigned long flags;
if (WARN_ON_ONCE(!req))
return;
spin_lock_irqsave(&req->lock, flags);
if (WARN_ON_ONCE(!req->manual_completion))
goto unlock;
if (WARN_ON_ONCE(req->state != MEDIA_REQUEST_STATE_QUEUED))
goto unlock;
req->manual_completion = false;
/*
* It is expected that all other objects in this request are
* completed when this function is called. WARN if that is
* not the case.
*/
if (!WARN_ON(req->num_incomplete_objects)) {
req->state = MEDIA_REQUEST_STATE_COMPLETE;
wake_up_interruptible_all(&req->poll_wait);
completed = true;
}
unlock:
spin_unlock_irqrestore(&req->lock, flags);
if (completed)
media_request_put(req);
}
EXPORT_SYMBOL_GPL(media_request_manual_complete);

View File

@@ -392,8 +392,10 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream,
ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0)
if (ret < 0) {
cx23885_alsa_dma_unmap(chip);
goto error;
}
/* Loop back to start of program */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);

View File

@@ -535,6 +535,7 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
chip->period_size, chip->num_periods, 1);
if (ret < 0) {
pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
cx25821_alsa_dma_unmap(chip);
goto error;
}

View File

@@ -908,6 +908,7 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
if (!dev->lmmio) {
CX25821_ERR("ioremap failed, maybe increasing __VMALLOC_RESERVE in page.h\n");
release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
cx25821_iounmap(dev);
return -ENOMEM;
}

View File

@@ -483,8 +483,10 @@ static int snd_cx88_hw_params(struct snd_pcm_substream *substream,
ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0)
if (ret < 0) {
cx88_alsa_dma_unmap(chip);
goto error;
}
/* Loop back to start of program */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);

View File

@@ -88,7 +88,7 @@ s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2)
if (!csi2)
return -EINVAL;
src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
src_pad = media_pad_remote_pad_unique(&csi2->asd.sd.entity.pads[CSI2_PAD_SINK]);
if (IS_ERR(src_pad)) {
dev_err(&csi2->isys->adev->auxdev.dev,
"can't get source pad of %s (%pe)\n",

View File

@@ -3,6 +3,7 @@
* Copyright (C) 2013--2024 Intel Corporation
*/
#include <linux/atomic.h>
#include <linux/cleanup.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/list.h>
@@ -131,9 +132,6 @@ void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
list_add_tail(&ib->head, &aq->incoming);
spin_unlock_irqrestore(&aq->lock, flags);
if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)
vb2_buffer_done(vb, state);
if (first) {
dev_dbg(dev,
"queue buf list %p flags %lx, s %d, %d bufs\n",
@@ -201,6 +199,8 @@ static int buffer_list_get(struct ipu6_isys_stream *stream,
unsigned long flags;
unsigned long buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;
lockdep_assert_held(&stream->mutex);
bl->nbufs = 0;
INIT_LIST_HEAD(&bl->head);
@@ -287,16 +287,15 @@ ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
/* Start streaming for real. The buffer list must be available. */
static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
struct ipu6_isys_buffer_list *bl, bool error)
struct ipu6_isys_buffer_list *bl)
{
struct ipu6_isys_stream *stream = av->stream;
struct device *dev = &stream->isys->adev->auxdev.dev;
struct ipu6_isys_buffer_list __bl;
int ret;
mutex_lock(&stream->isys->stream_mutex);
guard(mutex)(&stream->isys->stream_mutex);
ret = ipu6_isys_video_set_streaming(av, 1, bl);
mutex_unlock(&stream->isys->stream_mutex);
if (ret)
goto out_requeue;
@@ -334,10 +333,7 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
out_requeue:
if (bl && bl->nbufs)
ipu6_isys_buffer_list_queue(bl,
IPU6_ISYS_BUFFER_LIST_FL_INCOMING |
(error ?
IPU6_ISYS_BUFFER_LIST_FL_SET_STATE :
0), error ? VB2_BUF_STATE_ERROR :
IPU6_ISYS_BUFFER_LIST_FL_INCOMING,
VB2_BUF_STATE_QUEUED);
flush_firmware_streamon_fail(stream);
@@ -353,8 +349,6 @@ static void buf_queue(struct vb2_buffer *vb)
vb2_buffer_to_ipu6_isys_video_buffer(vvb);
struct ipu6_isys_buffer *ib = &ivb->ib;
struct device *dev = &av->isys->adev->auxdev.dev;
struct media_pipeline *media_pipe =
media_entity_pipeline(&av->vdev.entity);
struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
struct ipu6_isys_stream *stream = av->stream;
struct ipu6_isys_buffer_list bl;
@@ -372,8 +366,8 @@ static void buf_queue(struct vb2_buffer *vb)
list_add(&ib->head, &aq->incoming);
spin_unlock_irqrestore(&aq->lock, flags);
if (!media_pipe || !vb->vb2_queue->start_streaming_called) {
dev_dbg(dev, "media pipeline is not ready for %s\n",
if (!vb2_start_streaming_called(vb->vb2_queue)) {
dev_dbg(dev, "start_streaming hasn't been called yet on %s\n",
av->vdev.name);
return;
}
@@ -406,13 +400,6 @@ static void buf_queue(struct vb2_buffer *vb)
ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
if (!stream->streaming) {
ret = ipu6_isys_stream_start(av, &bl, true);
if (ret)
dev_err(dev, "stream start failed.\n");
goto out;
}
/*
* We must queue the buffers in the buffer list to the
* appropriate video buffer queues BEFORE passing them to the
@@ -433,14 +420,13 @@ out:
static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
{
struct v4l2_mbus_framefmt format;
struct v4l2_mbus_framefmt format, *__format;
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
struct device *dev = &av->isys->adev->auxdev.dev;
struct media_pad *remote_pad =
media_pad_remote_pad_first(av->vdev.entity.pads);
struct v4l2_subdev *sd;
u32 r_stream, code;
int ret;
if (!remote_pad)
return -ENOTCONN;
@@ -448,13 +434,20 @@ static int ipu6_isys_link_fmt_validate(struct ipu6_isys_queue *aq)
sd = media_entity_to_v4l2_subdev(remote_pad->entity);
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, remote_pad->index);
ret = ipu6_isys_get_stream_pad_fmt(sd, remote_pad->index, r_stream,
&format);
struct v4l2_subdev_state *state =
v4l2_subdev_lock_and_get_active_state(sd);
if (ret) {
__format = v4l2_subdev_state_get_format(state, remote_pad->index,
r_stream);
if (__format)
format = *__format;
v4l2_subdev_unlock_state(state);
if (!__format) {
dev_dbg(dev, "failed to get %s: pad %d, stream:%d format\n",
sd->entity.name, remote_pad->index, r_stream);
return ret;
return -EPIPE;
}
if (format.width != ipu6_isys_get_frame_width(av) ||
@@ -545,14 +538,28 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
struct ipu6_isys_buffer_list __bl, *bl = NULL;
struct ipu6_isys_stream *stream;
struct media_entity *source_entity = NULL;
struct media_pad *source_pad, *remote_pad;
int nr_queues, ret;
dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
av->vdev.name, ipu6_isys_get_frame_width(av),
ipu6_isys_get_frame_height(av), pfmt->css_pixelformat);
ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues);
remote_pad = media_pad_remote_pad_unique(&av->pad);
if (IS_ERR(remote_pad)) {
dev_dbg(dev, "failed to get remote pad\n");
ret = PTR_ERR(remote_pad);
goto out_return_buffers;
}
source_pad = media_pad_remote_pad_unique(&remote_pad->entity->pads[0]);
if (IS_ERR(source_pad)) {
dev_dbg(dev, "No external source entity\n");
ret = PTR_ERR(source_pad);
goto out_return_buffers;
}
ret = ipu6_isys_setup_video(av, remote_pad, source_pad, &nr_queues);
if (ret < 0) {
dev_dbg(dev, "failed to setup video\n");
goto out_return_buffers;
@@ -573,7 +580,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
stream = av->stream;
mutex_lock(&stream->mutex);
if (!stream->nr_streaming) {
ret = ipu6_isys_video_prepare_stream(av, source_entity,
ret = ipu6_isys_video_prepare_stream(av, source_pad->entity,
nr_queues);
if (ret)
goto out_fw_close;
@@ -584,7 +591,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
stream->nr_queues);
list_add(&aq->node, &stream->queues);
ipu6_isys_configure_stream_watermark(av, true);
ipu6_isys_configure_stream_watermark(av, source_pad->entity);
ipu6_isys_update_stream_watermark(av, true);
if (stream->nr_streaming != stream->nr_queues)
@@ -597,7 +604,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
goto out;
}
ret = ipu6_isys_stream_start(av, bl, false);
ret = ipu6_isys_stream_start(av, bl);
if (ret)
goto out_stream_start;
@@ -637,10 +644,10 @@ static void stop_streaming(struct vb2_queue *q)
mutex_lock(&av->isys->stream_mutex);
if (stream->nr_streaming == stream->nr_queues && stream->streaming)
ipu6_isys_video_set_streaming(av, 0, NULL);
list_del(&aq->node);
mutex_unlock(&av->isys->stream_mutex);
stream->nr_streaming--;
list_del(&aq->node);
stream->streaming = 0;
mutex_unlock(&stream->mutex);

View File

@@ -39,7 +39,6 @@ struct ipu6_isys_video_buffer {
#define IPU6_ISYS_BUFFER_LIST_FL_INCOMING BIT(0)
#define IPU6_ISYS_BUFFER_LIST_FL_ACTIVE BIT(1)
#define IPU6_ISYS_BUFFER_LIST_FL_SET_STATE BIT(2)
struct ipu6_isys_buffer_list {
struct list_head head;

View File

@@ -265,42 +265,6 @@ static int subdev_set_routing(struct v4l2_subdev *sd,
return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
}
int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_mbus_framefmt *format)
{
struct v4l2_mbus_framefmt *fmt;
struct v4l2_subdev_state *state;
if (!sd || !format)
return -EINVAL;
state = v4l2_subdev_lock_and_get_active_state(sd);
fmt = v4l2_subdev_state_get_format(state, pad, stream);
if (fmt)
*format = *fmt;
v4l2_subdev_unlock_state(state);
return fmt ? 0 : -EINVAL;
}
int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_rect *crop)
{
struct v4l2_subdev_state *state;
struct v4l2_rect *rect;
if (!sd || !crop)
return -EINVAL;
state = v4l2_subdev_lock_and_get_active_state(sd);
rect = v4l2_subdev_state_get_crop(state, pad, stream);
if (rect)
*crop = *rect;
v4l2_subdev_unlock_state(state);
return rect ? 0 : -EINVAL;
}
u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
{
struct v4l2_subdev_state *state;

View File

@@ -38,10 +38,6 @@ int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_mbus_code_enum
*code);
u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad);
int ipu6_isys_get_stream_pad_fmt(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_mbus_framefmt *format);
int ipu6_isys_get_stream_pad_crop(struct v4l2_subdev *sd, u32 pad, u32 stream,
struct v4l2_rect *crop);
int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
enum v4l2_subdev_format_whence which,

View File

@@ -455,6 +455,7 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
{
struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
struct v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
struct ipu6_fw_isys_input_pin_info_abi *input_pin;
struct ipu6_fw_isys_output_pin_info_abi *output_pin;
struct ipu6_isys_stream *stream = av->stream;
@@ -464,26 +465,13 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
struct v4l2_rect v4l2_crop;
struct ipu6_isys *isys = av->isys;
struct device *dev = &isys->adev->auxdev.dev;
int input_pins = cfg->nof_input_pins++;
int output_pins;
u32 src_stream;
int ret;
src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
ret = ipu6_isys_get_stream_pad_fmt(sd, src_pad->index, src_stream,
&fmt);
if (ret < 0) {
dev_err(dev, "can't get stream format (%d)\n", ret);
return ret;
}
ret = ipu6_isys_get_stream_pad_crop(sd, src_pad->index, src_stream,
&v4l2_crop);
if (ret < 0) {
dev_err(dev, "can't get stream crop (%d)\n", ret);
return ret;
}
fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
v4l2_crop = *v4l2_subdev_state_get_crop(state, src_pad->index, src_stream);
input_pin = &cfg->input_pins[input_pins];
input_pin->input_res.width = fmt.width;
@@ -745,17 +733,16 @@ int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
stream->stream_source = stream->asd->source;
csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
csi2->receiver_errors = 0;
stream->source_entity = source_entity;
dev_dbg(&av->isys->adev->auxdev.dev,
"prepare stream: external entity %s\n",
stream->source_entity->name);
source_entity->name);
return 0;
}
void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
bool state)
struct media_entity *source)
{
struct ipu6_isys *isys = av->isys;
struct ipu6_isys_csi2 *csi2 = NULL;
@@ -769,10 +756,7 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
u64 pixel_rate = 0;
int ret;
if (!state)
return;
esd = media_entity_to_v4l2_subdev(av->stream->source_entity);
esd = media_entity_to_v4l2_subdev(source);
av->watermark.width = ipu6_isys_get_frame_width(av);
av->watermark.height = ipu6_isys_get_frame_height(av);
@@ -788,13 +772,16 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
link_freq = ipu6_isys_csi2_get_link_freq(csi2);
if (link_freq > 0) {
struct v4l2_subdev_state *state =
v4l2_subdev_lock_and_get_active_state(&csi2->asd.sd);
lanes = csi2->nlanes;
ret = ipu6_isys_get_stream_pad_fmt(&csi2->asd.sd, 0,
av->source_stream, &format);
if (!ret) {
bpp = ipu6_isys_mbus_code_to_bpp(format.code);
pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
}
format = *v4l2_subdev_state_get_format(state, 0,
av->source_stream);
bpp = ipu6_isys_mbus_code_to_bpp(format.code);
pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
v4l2_subdev_unlock_state(state);
}
av->watermark.pixel_rate = pixel_rate;
@@ -804,7 +791,7 @@ void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
iwake_watermark->force_iwake_disable = true;
mutex_unlock(&iwake_watermark->mutex);
dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
av->stream->source_entity->name);
source->name);
}
}
@@ -1011,9 +998,6 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
dev_dbg(dev, "set stream: %d\n", state);
if (WARN(!stream->source_entity, "No source entity for stream\n"))
return -ENODEV;
sd = &stream->asd->sd;
r_pad = media_pad_remote_pad_first(&av->pad);
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
@@ -1036,11 +1020,10 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
sd->name, r_pad->index, stream_mask);
ret = v4l2_subdev_disable_streams(sd, r_pad->index,
stream_mask);
if (ret) {
if (ret)
dev_err(dev, "stream off %s failed with %d\n", sd->name,
ret);
return ret;
}
close_streaming_firmware(av);
} else {
ret = start_stream_firmware(av, bl);
@@ -1066,6 +1049,7 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
out_media_entity_stop_streaming_firmware:
stop_streaming_firmware(av);
close_streaming_firmware(av);
return ret;
}
@@ -1179,7 +1163,8 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
}
int ipu6_isys_setup_video(struct ipu6_isys_video *av,
struct media_entity **source_entity, int *nr_queues)
struct media_pad *remote_pad,
struct media_pad *source_pad, int *nr_queues)
{
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
@@ -1188,30 +1173,13 @@ int ipu6_isys_setup_video(struct ipu6_isys_video *av,
struct v4l2_subdev_route *route = NULL;
struct v4l2_subdev_route *r;
struct v4l2_subdev_state *state;
struct ipu6_isys_subdev *asd;
struct v4l2_subdev *remote_sd;
struct media_pipeline *pipeline;
struct media_pad *source_pad, *remote_pad;
struct v4l2_subdev *remote_sd =
media_entity_to_v4l2_subdev(remote_pad->entity);
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(remote_sd);
int ret = -EINVAL;
*nr_queues = 0;
remote_pad = media_pad_remote_pad_unique(&av->pad);
if (IS_ERR(remote_pad)) {
dev_dbg(dev, "failed to get remote pad\n");
return PTR_ERR(remote_pad);
}
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
asd = to_ipu6_isys_subdev(remote_sd);
source_pad = media_pad_remote_pad_first(&remote_pad->entity->pads[0]);
if (!source_pad) {
dev_dbg(dev, "No external source entity\n");
return -ENODEV;
}
*source_entity = source_pad->entity;
/* Find the root */
state = v4l2_subdev_lock_and_get_active_state(remote_sd);
for_each_active_route(&state->routing, r) {
@@ -1231,7 +1199,7 @@ int ipu6_isys_setup_video(struct ipu6_isys_video *av,
ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
to_ipu6_isys_csi2(asd),
*source_entity, &entry);
source_pad->entity, &entry);
if (ret == -ENOIOCTLCMD) {
av->vc = 0;
av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
@@ -1247,11 +1215,7 @@ int ipu6_isys_setup_video(struct ipu6_isys_video *av,
return ret;
}
pipeline = media_entity_pipeline(&av->vdev.entity);
if (!pipeline)
ret = video_device_pipeline_alloc_start(&av->vdev);
else
ret = video_device_pipeline_start(&av->vdev, pipeline);
ret = video_device_pipeline_alloc_start(&av->vdev);
if (ret < 0) {
dev_dbg(dev, "media pipeline start failed\n");
return ret;

View File

@@ -43,7 +43,6 @@ struct sequence_info {
*/
struct ipu6_isys_stream {
struct mutex mutex;
struct media_entity *source_entity;
atomic_t sequence;
unsigned int seq_index;
struct sequence_info seq[IPU6_ISYS_MAX_PARALLEL_SOF];
@@ -113,7 +112,8 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
int ipu6_isys_fw_open(struct ipu6_isys *isys);
void ipu6_isys_fw_close(struct ipu6_isys *isys);
int ipu6_isys_setup_video(struct ipu6_isys_video *av,
struct media_entity **source_entity, int *nr_queues);
struct media_pad *remote_pad,
struct media_pad *source_pad, int *nr_queues);
int ipu6_isys_video_init(struct ipu6_isys_video *av);
void ipu6_isys_video_cleanup(struct ipu6_isys_video *av);
void ipu6_isys_put_stream(struct ipu6_isys_stream *stream);
@@ -123,7 +123,7 @@ struct ipu6_isys_stream *
ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc);
void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
bool state);
struct media_entity *source);
void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state);
u32 ipu6_isys_get_format(struct ipu6_isys_video *av);

View File

@@ -269,7 +269,7 @@ fail:
return ret;
}
void isys_setup_hw(struct ipu6_isys *isys)
static void isys_setup_hw(struct ipu6_isys *isys)
{
void __iomem *base = isys->pdata->base;
const u8 *thd = isys->pdata->ipdata->hw_variant.cdc_fifo_threshold;
@@ -341,7 +341,7 @@ static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
}
}
irqreturn_t isys_isr(struct ipu6_bus_device *adev)
static irqreturn_t isys_isr(struct ipu6_bus_device *adev)
{
struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
void __iomem *base = isys->pdata->base;
@@ -857,9 +857,6 @@ static int isys_runtime_pm_resume(struct device *dev)
unsigned long flags;
int ret;
if (!isys)
return 0;
ret = ipu6_mmu_hw_init(adev->mmu);
if (ret)
return ret;
@@ -884,13 +881,9 @@ static int isys_runtime_pm_resume(struct device *dev)
static int isys_runtime_pm_suspend(struct device *dev)
{
struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
struct ipu6_isys *isys;
struct ipu6_isys *isys = dev_get_drvdata(dev);
unsigned long flags;
isys = dev_get_drvdata(dev);
if (!isys)
return 0;
spin_lock_irqsave(&isys->power_lock, flags);
isys->power = 0;
spin_unlock_irqrestore(&isys->power_lock, flags);
@@ -1070,10 +1063,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
if (!isys->csi2)
return -ENOMEM;
ret = ipu6_mmu_hw_init(adev->mmu);
if (ret)
return ret;
/* initial sensor type */
isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
@@ -1125,8 +1114,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
if (ret)
goto free_fw_msg_bufs;
ipu6_mmu_hw_cleanup(adev->mmu);
return 0;
free_fw_msg_bufs:
@@ -1148,8 +1135,6 @@ release_firmware:
mutex_destroy(&isys->mutex);
mutex_destroy(&isys->stream_mutex);
ipu6_mmu_hw_cleanup(adev->mmu);
return ret;
}
@@ -1373,7 +1358,7 @@ MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
MODULE_AUTHOR("Yunliang Ding <yunliang.ding@intel.com>");
MODULE_AUTHOR("Hongju Wang <hongju.wang@intel.com>");
MODULE_AUTHOR("Hongju Wang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel IPU6 input system driver");
MODULE_IMPORT_NS("INTEL_IPU6");

View File

@@ -181,8 +181,6 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops;
void isys_setup_hw(struct ipu6_isys *isys);
irqreturn_t isys_isr(struct ipu6_bus_device *adev);
void update_watermark_setting(struct ipu6_isys *isys);
int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys,

View File

@@ -102,7 +102,7 @@ static void page_table_dump(struct ipu6_mmu_info *mmu_info)
if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval)
continue;
l2_phys = TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx];)
l2_phys = TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx]);
dev_dbg(mmu_info->dev,
"l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pap\n",
l1_idx, iova, iova + ISP_PAGE_SIZE, &l2_phys);
@@ -248,7 +248,7 @@ static u32 *alloc_l2_pt(struct ipu6_mmu_info *mmu_info)
dev_dbg(mmu_info->dev, "alloc_l2: get_zeroed_page() = %p\n", pt);
for (i = 0; i < ISP_L1PT_PTES; i++)
for (i = 0; i < ISP_L2PT_PTES; i++)
pt[i] = mmu_info->dummy_page_pteval;
return pt;

View File

@@ -630,21 +630,21 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (ret) {
dev_err_probe(&isp->pdev->dev, ret,
"Failed to set MMU hardware\n");
goto out_ipu6_bus_del_devices;
goto out_ipu6_rpm_put;
}
ret = ipu6_buttress_map_fw_image(isp->psys, isp->cpd_fw,
&isp->psys->fw_sgt);
if (ret) {
dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
goto out_ipu6_bus_del_devices;
goto out_ipu6_rpm_put;
}
ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
if (ret) {
dev_err_probe(&isp->pdev->dev, ret,
"failed to create pkg dir\n");
goto out_ipu6_bus_del_devices;
goto out_ipu6_rpm_put;
}
ret = devm_request_threaded_irq(dev, pdev->irq, ipu6_buttress_isr,
@@ -652,7 +652,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
IRQF_SHARED, IPU6_NAME, isp);
if (ret) {
dev_err_probe(dev, ret, "Requesting irq failed\n");
goto out_ipu6_bus_del_devices;
goto out_ipu6_rpm_put;
}
ret = ipu6_buttress_authenticate(isp);
@@ -683,6 +683,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_free_irq:
devm_free_irq(dev, pdev->irq, isp);
out_ipu6_rpm_put:
pm_runtime_put_sync(&isp->psys->auxdev.dev);
out_ipu6_bus_del_devices:
if (isp->psys) {
ipu6_cpd_free_pkg_dir(isp->psys);
@@ -841,6 +843,6 @@ MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");
MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@intel.com>");
MODULE_AUTHOR("Yunliang Ding <yunliang.ding@intel.com>");
MODULE_AUTHOR("Hongju Wang <hongju.wang@intel.com>");
MODULE_AUTHOR("Hongju Wang");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Intel IPU6 PCI driver");

View File

@@ -381,6 +381,18 @@ static int get_serial_number(struct mgb4_dev *mgbdev)
return 0;
}
static const char *module_type_str(struct mgb4_dev *mgbdev)
{
if (MGB4_IS_FPDL3(mgbdev))
return "FPDL3";
else if (MGB4_IS_GMSL3(mgbdev))
return "GMSL3";
else if (MGB4_IS_GMSL1(mgbdev))
return "GMSL1";
else
return "UNKNOWN";
}
static int get_module_version(struct mgb4_dev *mgbdev)
{
struct device *dev = &mgbdev->pdev->dev;
@@ -402,19 +414,21 @@ static int get_module_version(struct mgb4_dev *mgbdev)
}
mgbdev->module_version = ~((u32)version) & 0xff;
if (!(MGB4_IS_FPDL3(mgbdev) || MGB4_IS_GMSL(mgbdev))) {
if (!(MGB4_IS_FPDL3(mgbdev) ||
MGB4_IS_GMSL3(mgbdev) ||
MGB4_IS_GMSL1(mgbdev))) {
dev_err(dev, "unknown module type\n");
return -EINVAL;
}
fw_version = mgb4_read_reg(&mgbdev->video, 0xC4) >> 24;
if ((MGB4_IS_FPDL3(mgbdev) && fw_version != 1) ||
(MGB4_IS_GMSL(mgbdev) && fw_version != 2)) {
(MGB4_IS_GMSL3(mgbdev) && fw_version != 2) ||
(MGB4_IS_GMSL1(mgbdev) && fw_version != 3)) {
dev_err(dev, "module/firmware type mismatch\n");
return -EINVAL;
}
dev_info(dev, "%s module detected\n",
MGB4_IS_FPDL3(mgbdev) ? "FPDL3" : "GMSL");
dev_info(dev, "%s module detected\n", module_type_str(mgbdev));
return 0;
}

View File

@@ -18,14 +18,20 @@
#define MGB4_VIN_DEVICES 2
#define MGB4_VOUT_DEVICES 2
#define MGB4_IS_GMSL(mgbdev) \
((((mgbdev)->module_version >> 4) >= 2) && \
(((mgbdev)->module_version >> 4) <= 4))
#define MGB4_IS_GMSL1(mgbdev) \
(((mgbdev)->module_version >> 4) == 6)
#define MGB4_IS_GMSL3(mgbdev) \
(((((mgbdev)->module_version >> 4) >= 2) && \
(((mgbdev)->module_version >> 4) <= 4)) || \
(((mgbdev)->module_version >> 4) == 8))
#define MGB4_IS_GMSL3C(mgbdev) \
(((mgbdev)->module_version >> 4) == 8)
#define MGB4_IS_FPDL3(mgbdev) \
(((mgbdev)->module_version >> 4) == 1)
#define MGB4_HAS_VOUT(mgbdev) \
((((mgbdev)->module_version >> 4) >= 1) && \
(((mgbdev)->module_version >> 4) <= 3))
(((((mgbdev)->module_version >> 4) >= 1) && \
(((mgbdev)->module_version >> 4) <= 3)) || \
((((mgbdev)->module_version >> 4) == 6)))
struct mgb4_dma_channel {
struct dma_chan *chan;

View File

@@ -11,8 +11,10 @@
extern struct attribute *mgb4_pci_attrs[];
extern struct attribute *mgb4_fpdl3_in_attrs[];
extern struct attribute *mgb4_gmsl_in_attrs[];
extern struct attribute *mgb4_gmsl3_in_attrs[];
extern struct attribute *mgb4_gmsl1_in_attrs[];
extern struct attribute *mgb4_fpdl3_out_attrs[];
extern struct attribute *mgb4_gmsl_out_attrs[];
extern struct attribute *mgb4_gmsl3_out_attrs[];
extern struct attribute *mgb4_gmsl1_out_attrs[];
#endif

View File

@@ -36,10 +36,13 @@ static ssize_t oldi_lane_width_show(struct device *dev,
u32 config;
int ret;
i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49;
i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03;
i2c_single_val = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02;
i2c_dual_val = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00;
if (MGB4_IS_GMSL1(mgbdev))
return sprintf(buf, "0\n");
i2c_reg = MGB4_IS_GMSL3(mgbdev) ? 0x1CE : 0x49;
i2c_mask = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x03;
i2c_single_val = MGB4_IS_GMSL3(mgbdev) ? 0x00 : 0x02;
i2c_dual_val = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x00;
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_read_byte(&vindev->deser, i2c_reg);
@@ -79,21 +82,24 @@ static ssize_t oldi_lane_width_store(struct device *dev,
if (ret)
return ret;
if (MGB4_IS_GMSL1(mgbdev))
return val ? -EINVAL : count;
switch (val) {
case 0: /* single */
fpga_data = 0;
i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x00 : 0x02;
i2c_data = MGB4_IS_GMSL3(mgbdev) ? 0x00 : 0x02;
break;
case 1: /* dual */
fpga_data = 1U << 9;
i2c_data = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x00;
i2c_data = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x00;
break;
default:
return -EINVAL;
}
i2c_reg = MGB4_IS_GMSL(mgbdev) ? 0x1CE : 0x49;
i2c_mask = MGB4_IS_GMSL(mgbdev) ? 0x0E : 0x03;
i2c_reg = MGB4_IS_GMSL3(mgbdev) ? 0x1CE : 0x49;
i2c_mask = MGB4_IS_GMSL3(mgbdev) ? 0x0E : 0x03;
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&vindev->deser, i2c_reg, i2c_mask, i2c_data);
@@ -102,7 +108,7 @@ static ssize_t oldi_lane_width_store(struct device *dev,
return -EIO;
mgb4_mask_reg(&mgbdev->video, vindev->config->regs.config, 1U << 9,
fpga_data);
if (MGB4_IS_GMSL(mgbdev)) {
if (MGB4_IS_GMSL3(mgbdev)) {
/* reset input link */
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&vindev->deser, 0x10, 1U << 5, 1U << 5);
@@ -745,7 +751,7 @@ struct attribute *mgb4_fpdl3_in_attrs[] = {
NULL
};
struct attribute *mgb4_gmsl_in_attrs[] = {
struct attribute *mgb4_gmsl3_in_attrs[] = {
&dev_attr_input_id.attr,
&dev_attr_link_status.attr,
&dev_attr_stream_status.attr,
@@ -770,3 +776,26 @@ struct attribute *mgb4_gmsl_in_attrs[] = {
&dev_attr_gmsl_fec.attr,
NULL
};
struct attribute *mgb4_gmsl1_in_attrs[] = {
&dev_attr_input_id.attr,
&dev_attr_link_status.attr,
&dev_attr_stream_status.attr,
&dev_attr_video_width.attr,
&dev_attr_video_height.attr,
&dev_attr_hsync_status.attr,
&dev_attr_vsync_status.attr,
&dev_attr_oldi_lane_width.attr,
&dev_attr_color_mapping.attr,
&dev_attr_hsync_gap_length.attr,
&dev_attr_vsync_gap_length.attr,
&dev_attr_pclk_frequency.attr,
&dev_attr_hsync_width.attr,
&dev_attr_vsync_width.attr,
&dev_attr_hback_porch.attr,
&dev_attr_hfront_porch.attr,
&dev_attr_vback_porch.attr,
&dev_attr_vfront_porch.attr,
&dev_attr_frequency_range.attr,
NULL
};

View File

@@ -665,6 +665,7 @@ static ssize_t pclk_frequency_store(struct device *dev,
{
struct video_device *vdev = to_video_device(dev);
struct mgb4_vout_dev *voutdev = video_get_drvdata(vdev);
struct mgb4_dev *mgbdev = voutdev->mgbdev;
unsigned long val;
int ret;
unsigned int dp;
@@ -679,14 +680,16 @@ static ssize_t pclk_frequency_store(struct device *dev,
return -EBUSY;
}
dp = (val > 50000) ? 1 : 0;
dp = (MGB4_IS_FPDL3(mgbdev) && val > 50000) ? 1 : 0;
voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, val >> dp) << dp;
mgb4_mask_reg(&voutdev->mgbdev->video, voutdev->config->regs.config,
0x10, dp << 4);
mutex_lock(&voutdev->mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6, ((~dp) & 1) << 6);
mutex_unlock(&voutdev->mgbdev->i2c_lock);
mgb4_mask_reg(&mgbdev->video, voutdev->config->regs.config, 0x10,
dp << 4);
if (MGB4_IS_FPDL3(mgbdev)) {
mutex_lock(&mgbdev->i2c_lock);
ret = mgb4_i2c_mask_byte(&voutdev->ser, 0x4F, 1 << 6,
((~dp) & 1) << 6);
mutex_unlock(&mgbdev->i2c_lock);
}
mutex_unlock(voutdev->vdev.lock);
@@ -731,7 +734,7 @@ struct attribute *mgb4_fpdl3_out_attrs[] = {
NULL
};
struct attribute *mgb4_gmsl_out_attrs[] = {
struct attribute *mgb4_gmsl3_out_attrs[] = {
&dev_attr_output_id.attr,
&dev_attr_video_source.attr,
&dev_attr_display_width.attr,
@@ -739,3 +742,22 @@ struct attribute *mgb4_gmsl_out_attrs[] = {
&dev_attr_frame_rate.attr,
NULL
};
struct attribute *mgb4_gmsl1_out_attrs[] = {
&dev_attr_output_id.attr,
&dev_attr_video_source.attr,
&dev_attr_display_width.attr,
&dev_attr_display_height.attr,
&dev_attr_frame_rate.attr,
&dev_attr_hsync_polarity.attr,
&dev_attr_vsync_polarity.attr,
&dev_attr_de_polarity.attr,
&dev_attr_pclk_frequency.attr,
&dev_attr_hsync_width.attr,
&dev_attr_vsync_width.attr,
&dev_attr_hback_porch.attr,
&dev_attr_hfront_porch.attr,
&dev_attr_vback_porch.attr,
&dev_attr_vfront_porch.attr,
NULL
};

View File

@@ -32,7 +32,8 @@
#include "mgb4_vin.h"
ATTRIBUTE_GROUPS(mgb4_fpdl3_in);
ATTRIBUTE_GROUPS(mgb4_gmsl_in);
ATTRIBUTE_GROUPS(mgb4_gmsl3_in);
ATTRIBUTE_GROUPS(mgb4_gmsl1_in);
static const struct mgb4_vin_config vin_cfg[] = {
{0, 0, 0, 6, {0x10, 0x00, 0x04, 0x08, 0x1C, 0x14, 0x18, 0x20, 0x24, 0x28, 0xE8}},
@@ -44,23 +45,43 @@ static const struct i2c_board_info fpdl3_deser_info[] = {
{I2C_BOARD_INFO("deserializer2", 0x36)},
};
static const struct i2c_board_info gmsl_deser_info[] = {
static const struct i2c_board_info gmsl3_deser_info[] = {
{I2C_BOARD_INFO("deserializer1", 0x4C)},
{I2C_BOARD_INFO("deserializer2", 0x2A)},
};
static const struct i2c_board_info gmsl3c_deser_info[] = {
{I2C_BOARD_INFO("deserializer1", 0x6A)},
{I2C_BOARD_INFO("deserializer2", 0x6C)},
};
static const struct i2c_board_info gmsl1_deser_info[] = {
{I2C_BOARD_INFO("deserializer1", 0x2C)},
{I2C_BOARD_INFO("deserializer2", 0x6C)},
};
static const struct mgb4_i2c_kv fpdl3_i2c[] = {
{0x06, 0xFF, 0x04}, {0x07, 0xFF, 0x01}, {0x45, 0xFF, 0xE8},
{0x49, 0xFF, 0x00}, {0x34, 0xFF, 0x00}, {0x23, 0xFF, 0x00}
};
static const struct mgb4_i2c_kv gmsl_i2c[] = {
static const struct mgb4_i2c_kv gmsl3_i2c[] = {
{0x01, 0x03, 0x03}, {0x300, 0x0C, 0x0C}, {0x03, 0xC0, 0xC0},
{0x1CE, 0x0E, 0x0E}, {0x11, 0x05, 0x00}, {0x05, 0xC0, 0x40},
{0x307, 0x0F, 0x00}, {0xA0, 0x03, 0x00}, {0x3E0, 0x07, 0x07},
{0x308, 0x01, 0x01}, {0x10, 0x20, 0x20}, {0x300, 0x40, 0x40}
};
static const struct mgb4_i2c_kv gmsl3c_i2c[] = {
{0x01, 0x03, 0x02}, {0x300, 0x0C, 0x08}, {0x03, 0xC0, 0x00},
{0x1CE, 0x0E, 0x0E}, {0x11, 0x05, 0x05}, {0x05, 0xC0, 0x40},
{0x307, 0x0F, 0x00}, {0xA0, 0x03, 0x00}, {0x3E0, 0x07, 0x00},
{0x308, 0x01, 0x00}, {0x10, 0x20, 0x20}, {0x300, 0x40, 0x40}
};
static const struct mgb4_i2c_kv gmsl1_i2c[] = {
};
static const struct v4l2_dv_timings_cap video_timings_cap = {
.type = V4L2_DV_BT_656_1120,
.bt = {
@@ -796,22 +817,36 @@ static irqreturn_t err_handler(int irq, void *ctx)
static int deser_init(struct mgb4_vin_dev *vindev, int id)
{
int rv, addr_size;
size_t values_count;
const struct mgb4_i2c_kv *values;
const struct i2c_board_info *info;
int rv, addr_size = 0;
size_t count = 0;
const struct mgb4_i2c_kv *values = NULL;
const struct i2c_board_info *info = NULL;
struct device *dev = &vindev->mgbdev->pdev->dev;
if (MGB4_IS_GMSL(vindev->mgbdev)) {
info = &gmsl_deser_info[id];
addr_size = 16;
values = gmsl_i2c;
values_count = ARRAY_SIZE(gmsl_i2c);
} else {
if (MGB4_IS_GMSL3(vindev->mgbdev)) {
if (MGB4_IS_GMSL3C(vindev->mgbdev)) {
info = &gmsl3c_deser_info[id];
addr_size = 16;
values = gmsl3c_i2c;
count = ARRAY_SIZE(gmsl3c_i2c);
} else {
info = &gmsl3_deser_info[id];
addr_size = 16;
values = gmsl3_i2c;
count = ARRAY_SIZE(gmsl3_i2c);
}
} else if (MGB4_IS_FPDL3(vindev->mgbdev)) {
info = &fpdl3_deser_info[id];
addr_size = 8;
values = fpdl3_i2c;
values_count = ARRAY_SIZE(fpdl3_i2c);
count = ARRAY_SIZE(fpdl3_i2c);
} else if (MGB4_IS_GMSL1(vindev->mgbdev)) {
info = &gmsl1_deser_info[id];
addr_size = 8;
values = gmsl1_i2c;
count = ARRAY_SIZE(gmsl1_i2c);
} else {
return -EINVAL;
}
rv = mgb4_i2c_init(&vindev->deser, vindev->mgbdev->i2c_adap, info,
@@ -820,7 +855,7 @@ static int deser_init(struct mgb4_vin_dev *vindev, int id)
dev_err(dev, "failed to create deserializer\n");
return rv;
}
rv = mgb4_i2c_configure(&vindev->deser, values, values_count);
rv = mgb4_i2c_configure(&vindev->deser, values, count);
if (rv < 0) {
dev_err(dev, "failed to configure deserializer\n");
goto err_i2c_dev;
@@ -838,11 +873,12 @@ static void fpga_init(struct mgb4_vin_dev *vindev)
{
struct mgb4_regs *video = &vindev->mgbdev->video;
const struct mgb4_vin_regs *regs = &vindev->config->regs;
int dp = MGB4_IS_GMSL1(vindev->mgbdev) ? 0 : 1;
mgb4_write_reg(video, regs->config, 0x00000001);
mgb4_write_reg(video, regs->sync, 0x03E80002);
mgb4_write_reg(video, regs->padding, 0x00000000);
mgb4_write_reg(video, regs->config, 1U << 9);
mgb4_write_reg(video, regs->config, dp << 9);
}
static void create_debugfs(struct mgb4_vin_dev *vindev)
@@ -890,10 +926,21 @@ static void create_debugfs(struct mgb4_vin_dev *vindev)
#endif
}
static const struct attribute_group **module_groups(struct mgb4_dev *mgbdev)
{
if (MGB4_IS_FPDL3(mgbdev))
return mgb4_fpdl3_in_groups;
else if (MGB4_IS_GMSL3(mgbdev))
return mgb4_gmsl3_in_groups;
else if (MGB4_IS_GMSL1(mgbdev))
return mgb4_gmsl1_in_groups;
else
return NULL;
}
struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
{
int rv;
const struct attribute_group **groups;
struct mgb4_vin_dev *vindev;
struct pci_dev *pdev = mgbdev->pdev;
struct device *dev = &pdev->dev;
@@ -914,14 +961,13 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
INIT_WORK(&vindev->dma_work, dma_transfer);
INIT_WORK(&vindev->err_work, signal_change);
/* IRQ callback */
/* IRQ callbacks */
vin_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->vin_irq);
rv = request_irq(vin_irq, vin_handler, 0, "mgb4-vin", vindev);
if (rv) {
dev_err(dev, "failed to register vin irq handler\n");
goto err_alloc;
}
/* Error IRQ callback */
err_irq = xdma_get_user_irq(mgbdev->xdev, vindev->config->err_irq);
rv = request_irq(err_irq, err_handler, 0, "mgb4-err", vindev);
if (rv) {
@@ -986,9 +1032,7 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
}
/* Module sysfs attributes */
groups = MGB4_IS_GMSL(mgbdev)
? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups;
rv = device_add_groups(&vindev->vdev.dev, groups);
rv = device_add_groups(&vindev->vdev.dev, module_groups(mgbdev));
if (rv) {
dev_err(dev, "failed to create sysfs attributes\n");
goto err_video_dev;
@@ -1014,7 +1058,6 @@ err_alloc:
void mgb4_vin_free(struct mgb4_vin_dev *vindev)
{
const struct attribute_group **groups;
int vin_irq = xdma_get_user_irq(vindev->mgbdev->xdev,
vindev->config->vin_irq);
int err_irq = xdma_get_user_irq(vindev->mgbdev->xdev,
@@ -1025,9 +1068,7 @@ void mgb4_vin_free(struct mgb4_vin_dev *vindev)
free_irq(vin_irq, vindev);
free_irq(err_irq, vindev);
groups = MGB4_IS_GMSL(vindev->mgbdev)
? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups;
device_remove_groups(&vindev->vdev.dev, groups);
device_remove_groups(&vindev->vdev.dev, module_groups(vindev->mgbdev));
mgb4_i2c_free(&vindev->deser);
video_unregister_device(&vindev->vdev);

View File

@@ -25,7 +25,8 @@
#include "mgb4_vout.h"
ATTRIBUTE_GROUPS(mgb4_fpdl3_out);
ATTRIBUTE_GROUPS(mgb4_gmsl_out);
ATTRIBUTE_GROUPS(mgb4_gmsl3_out);
ATTRIBUTE_GROUPS(mgb4_gmsl1_out);
static const struct mgb4_vout_config vout_cfg[] = {
{0, 0, 8, {0x78, 0x60, 0x64, 0x68, 0x74, 0x6C, 0x70, 0x7C, 0xE0}},
@@ -37,10 +38,18 @@ static const struct i2c_board_info fpdl3_ser_info[] = {
{I2C_BOARD_INFO("serializer2", 0x16)},
};
static const struct i2c_board_info gmsl1_ser_info[] = {
{I2C_BOARD_INFO("serializer1", 0x24)},
{I2C_BOARD_INFO("serializer2", 0x22)},
};
static const struct mgb4_i2c_kv fpdl3_i2c[] = {
{0x05, 0xFF, 0x04}, {0x06, 0xFF, 0x01}, {0xC2, 0xFF, 0x80}
};
static const struct mgb4_i2c_kv gmsl1_i2c[] = {
};
static const struct v4l2_dv_timings_cap video_timings_cap = {
.type = V4L2_DV_BT_656_1120,
.bt = {
@@ -634,12 +643,24 @@ static irqreturn_t handler(int irq, void *ctx)
static int ser_init(struct mgb4_vout_dev *voutdev, int id)
{
int rv;
const struct i2c_board_info *info = &fpdl3_ser_info[id];
struct mgb4_i2c_client *ser = &voutdev->ser;
struct device *dev = &voutdev->mgbdev->pdev->dev;
const struct i2c_board_info *info = NULL;
const struct mgb4_i2c_kv *values = NULL;
size_t count = 0;
int rv;
if (MGB4_IS_GMSL(voutdev->mgbdev))
if (MGB4_IS_FPDL3(voutdev->mgbdev)) {
info = &fpdl3_ser_info[id];
values = fpdl3_i2c;
count = ARRAY_SIZE(fpdl3_i2c);
} else if (MGB4_IS_GMSL1(voutdev->mgbdev)) {
info = &gmsl1_ser_info[id];
values = gmsl1_i2c;
count = ARRAY_SIZE(gmsl1_i2c);
}
if (!info)
return 0;
rv = mgb4_i2c_init(ser, voutdev->mgbdev->i2c_adap, info, 8);
@@ -647,7 +668,7 @@ static int ser_init(struct mgb4_vout_dev *voutdev, int id)
dev_err(dev, "failed to create serializer\n");
return rv;
}
rv = mgb4_i2c_configure(ser, fpdl3_i2c, ARRAY_SIZE(fpdl3_i2c));
rv = mgb4_i2c_configure(ser, values, count);
if (rv < 0) {
dev_err(dev, "failed to configure serializer\n");
goto err_i2c_dev;
@@ -665,18 +686,19 @@ static void fpga_init(struct mgb4_vout_dev *voutdev)
{
struct mgb4_regs *video = &voutdev->mgbdev->video;
const struct mgb4_vout_regs *regs = &voutdev->config->regs;
int dp = MGB4_IS_GMSL1(voutdev->mgbdev) ? 0 : 1;
u32 source = (voutdev->config->id + MGB4_VIN_DEVICES) << 2;
mgb4_write_reg(video, regs->config, 0x00000011);
mgb4_write_reg(video, regs->config, 0x00000001);
mgb4_write_reg(video, regs->resolution, (1280 << 16) | 640);
mgb4_write_reg(video, regs->hsync, 0x00283232);
mgb4_write_reg(video, regs->vsync, 0x40141F1E);
mgb4_write_reg(video, regs->frame_limit, MGB4_HW_FREQ / 60);
mgb4_write_reg(video, regs->padding, 0x00000000);
voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> 1) << 1;
voutdev->freq = mgb4_cmt_set_vout_freq(voutdev, 61150 >> dp) << dp;
mgb4_write_reg(video, regs->config,
(voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4);
mgb4_write_reg(video, regs->config, source | dp << 4);
}
static void create_debugfs(struct mgb4_vout_dev *voutdev)
@@ -720,10 +742,21 @@ static void create_debugfs(struct mgb4_vout_dev *voutdev)
#endif
}
static const struct attribute_group **module_groups(struct mgb4_dev *mgbdev)
{
if (MGB4_IS_FPDL3(mgbdev))
return mgb4_fpdl3_out_groups;
else if (MGB4_IS_GMSL3(mgbdev))
return mgb4_gmsl3_out_groups;
else if (MGB4_IS_GMSL1(mgbdev))
return mgb4_gmsl1_out_groups;
else
return NULL;
}
struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
{
int rv, irq;
const struct attribute_group **groups;
struct mgb4_vout_dev *voutdev;
struct pci_dev *pdev = mgbdev->pdev;
struct device *dev = &pdev->dev;
@@ -804,9 +837,7 @@ struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
}
/* Module sysfs attributes */
groups = MGB4_IS_GMSL(mgbdev)
? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups;
rv = device_add_groups(&voutdev->vdev.dev, groups);
rv = device_add_groups(&voutdev->vdev.dev, module_groups(mgbdev));
if (rv) {
dev_err(dev, "failed to create sysfs attributes\n");
goto err_video_dev;
@@ -830,15 +861,10 @@ err_alloc:
void mgb4_vout_free(struct mgb4_vout_dev *voutdev)
{
const struct attribute_group **groups;
int irq = xdma_get_user_irq(voutdev->mgbdev->xdev, voutdev->config->irq);
free_irq(irq, voutdev);
groups = MGB4_IS_GMSL(voutdev->mgbdev)
? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups;
device_remove_groups(&voutdev->vdev.dev, groups);
device_remove_groups(&voutdev->vdev.dev, module_groups(voutdev->mgbdev));
mgb4_i2c_free(&voutdev->ser);
video_unregister_device(&voutdev->vdev);
v4l2_device_unregister(&voutdev->v4l2dev);

View File

@@ -166,7 +166,7 @@ static const u8 tbl_tw2865_pal_template[] = {
0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
};
#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
#define is_tw286x(__solo, __id) (!((__solo)->tw2815 & (1U << (__id))))
static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
u8 tw_off)
@@ -686,6 +686,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
chip_num = ch / 4;
ch %= 4;
if (chip_num >= TW_NUM_CHIP)
return -EINVAL;
if (val > 255 || val < 0)
return -ERANGE;
@@ -758,6 +761,9 @@ int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
chip_num = ch / 4;
ch %= 4;
if (chip_num >= TW_NUM_CHIP)
return -EINVAL;
switch (ctrl) {
case V4L2_CID_SHARPNESS:
/* Only 286x has sharpness */

View File

@@ -9,7 +9,6 @@
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
@@ -17,7 +16,6 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-vmalloc.h>
#include "vpu.h"
#include "vpu_defs.h"
#include "vpu_core.h"
@@ -724,6 +722,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd
switch (cmd->cmd) {
case V4L2_DEC_CMD_START:
vdec_cmd_start(inst);
vb2_clear_last_buffer_dequeued(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
break;
case V4L2_DEC_CMD_STOP:
vdec_cmd_stop(inst);
@@ -949,7 +948,7 @@ static void vdec_stop_done(struct vpu_inst *inst)
vpu_inst_unlock(inst);
}
static bool vdec_check_source_change(struct vpu_inst *inst)
static bool vdec_check_source_change(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr)
{
struct vdec_t *vdec = inst->priv;
const struct vpu_format *sibling;
@@ -961,26 +960,35 @@ static bool vdec_check_source_change(struct vpu_inst *inst)
return false;
sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt);
if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt)
vdec->codec_info.pixfmt = inst->cap_format.pixfmt;
if (sibling && hdr->pixfmt == sibling->pixfmt)
hdr->pixfmt = inst->cap_format.pixfmt;
if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx)))
return true;
if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt)
if (inst->cap_format.pixfmt != hdr->pixfmt)
return true;
if (inst->cap_format.width != vdec->codec_info.decoded_width)
if (inst->cap_format.width != hdr->decoded_width)
return true;
if (inst->cap_format.height != vdec->codec_info.decoded_height)
if (inst->cap_format.height != hdr->decoded_height)
return true;
if (vpu_get_num_buffers(inst, inst->cap_format.type) < inst->min_buffer_cap)
return true;
if (inst->crop.left != vdec->codec_info.offset_x)
if (inst->crop.left != hdr->offset_x)
return true;
if (inst->crop.top != vdec->codec_info.offset_y)
if (inst->crop.top != hdr->offset_y)
return true;
if (inst->crop.width != vdec->codec_info.width)
if (inst->crop.width != hdr->width)
return true;
if (inst->crop.height != vdec->codec_info.height)
if (inst->crop.height != hdr->height)
return true;
if (!hdr->progressive)
return true;
if (vdec->seq_hdr_found &&
(hdr->color_primaries != vdec->codec_info.color_primaries ||
hdr->transfer_chars != vdec->codec_info.transfer_chars ||
hdr->matrix_coeffs != vdec->codec_info.matrix_coeffs ||
hdr->full_range != vdec->codec_info.full_range))
return true;
return false;
@@ -1332,20 +1340,25 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info
struct vdec_t *vdec = inst->priv;
vpu_inst_lock(inst);
memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
vpu_trace(inst->dev, "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d\n",
vpu_trace(inst->dev,
"[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d, colorspace: %d, %d, %d, %d\n",
inst->id,
vdec->codec_info.decoded_width,
vdec->codec_info.decoded_height,
vdec->codec_info.offset_x,
vdec->codec_info.offset_y,
vdec->codec_info.width,
vdec->codec_info.height,
hdr->decoded_width,
hdr->decoded_height,
hdr->offset_x,
hdr->offset_y,
hdr->width,
hdr->height,
hdr->num_ref_frms,
hdr->num_dpb_frms);
hdr->num_dpb_frms,
hdr->color_primaries,
hdr->transfer_chars,
hdr->matrix_coeffs,
hdr->full_range);
inst->min_buffer_cap = hdr->num_ref_frms + hdr->num_dpb_frms;
vdec->is_source_changed = vdec_check_source_change(inst);
vdec->is_source_changed = vdec_check_source_change(inst, hdr);
memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info));
vdec_init_fmt(inst);
vdec_init_crop(inst);
vdec_init_mbi(inst);
@@ -1374,7 +1387,12 @@ static void vdec_event_resolution_change(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
vpu_trace(inst->dev, "[%d]\n", inst->id);
vpu_trace(inst->dev, "[%d] input : %d, decoded : %d, display : %d, sequence : %d\n",
inst->id,
vdec->params.frame_count,
vdec->decoded_frame_count,
vdec->display_frame_count,
vdec->sequence);
vpu_inst_lock(inst);
vdec->seq_tag = vdec->codec_info.tag;
vdec_clear_fs(&vdec->mbi);
@@ -1642,9 +1660,9 @@ static void vdec_cleanup(struct vpu_inst *inst)
vdec->slots = NULL;
vdec->slot_count = 0;
}
vfree(vdec);
kfree(vdec);
inst->priv = NULL;
vfree(inst);
kfree(inst);
}
static void vdec_init_params(struct vdec_t *vdec)
@@ -1909,13 +1927,13 @@ static int vdec_open(struct file *file)
struct vdec_t *vdec;
int ret;
inst = vzalloc(sizeof(*inst));
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst)
return -ENOMEM;
vdec = vzalloc(sizeof(*vdec));
vdec = kzalloc(sizeof(*vdec), GFP_KERNEL);
if (!vdec) {
vfree(inst);
kfree(inst);
return -ENOMEM;
}
@@ -1923,8 +1941,8 @@ static int vdec_open(struct file *file)
sizeof(*vdec->slots),
GFP_KERNEL | __GFP_ZERO);
if (!vdec->slots) {
vfree(vdec);
vfree(inst);
kfree(vdec);
kfree(inst);
return -ENOMEM;
}
vdec->slot_count = VDEC_SLOT_CNT_DFT;

View File

@@ -13,14 +13,12 @@
#include <linux/videodev2.h>
#include <linux/ktime.h>
#include <linux/rational.h>
#include <linux/vmalloc.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-vmalloc.h>
#include "vpu.h"
#include "vpu_defs.h"
#include "vpu_core.h"
@@ -844,7 +842,7 @@ static int venc_get_encoded_frames(struct vpu_inst *inst)
v4l2_m2m_dst_buf_remove(inst->fh.m2m_ctx)))
break;
list_del_init(&frame->list);
vfree(frame);
kfree(frame);
}
return 0;
@@ -860,7 +858,7 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg)
if (!info)
return -EINVAL;
venc = inst->priv;
frame = vzalloc(sizeof(*frame));
frame = kzalloc(sizeof(*frame), GFP_KERNEL);
if (!frame)
return -ENOMEM;
@@ -912,9 +910,9 @@ static void venc_cleanup(struct vpu_inst *inst)
return;
venc = inst->priv;
vfree(venc);
kfree(venc);
inst->priv = NULL;
vfree(inst);
kfree(inst);
}
static int venc_start_session(struct vpu_inst *inst, u32 type)
@@ -1067,7 +1065,7 @@ static void venc_cleanup_frames(struct venc_t *venc)
list_for_each_entry_safe(frame, tmp, &venc->frames, list) {
list_del_init(&frame->list);
vfree(frame);
kfree(frame);
}
}
@@ -1151,7 +1149,7 @@ static int venc_process_capture(struct vpu_inst *inst, struct vb2_buffer *vb)
return ret;
list_del_init(&frame->list);
vfree(frame);
kfree(frame);
return 0;
}
@@ -1309,13 +1307,13 @@ static int venc_open(struct file *file)
struct venc_t *venc;
int ret;
inst = vzalloc(sizeof(*inst));
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
if (!inst)
return -ENOMEM;
venc = vzalloc(sizeof(*venc));
venc = kzalloc(sizeof(*venc), GFP_KERNEL);
if (!venc) {
vfree(inst);
kfree(inst);
return -ENOMEM;
}

View File

@@ -13,7 +13,6 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/vmalloc.h>
#include "vpu.h"
#include "vpu_defs.h"
#include "vpu_cmds.h"
@@ -84,13 +83,13 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
int i;
int ret;
cmd = vzalloc(sizeof(*cmd));
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
return NULL;
cmd->pkt = vzalloc(sizeof(*cmd->pkt));
cmd->pkt = kzalloc(sizeof(*cmd->pkt), GFP_KERNEL);
if (!cmd->pkt) {
vfree(cmd);
kfree(cmd);
return NULL;
}
@@ -98,8 +97,8 @@ static struct vpu_cmd_t *vpu_alloc_cmd(struct vpu_inst *inst, u32 id, void *data
ret = vpu_iface_pack_cmd(inst->core, cmd->pkt, inst->id, id, data);
if (ret) {
dev_err(inst->dev, "iface pack cmd %s fail\n", vpu_id_name(id));
vfree(cmd->pkt);
vfree(cmd);
kfree(cmd->pkt);
kfree(cmd);
return NULL;
}
for (i = 0; i < ARRAY_SIZE(vpu_cmd_requests); i++) {
@@ -118,8 +117,8 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
return;
if (cmd->last_response_cmd)
atomic_long_set(cmd->last_response_cmd, cmd->key);
vfree(cmd->pkt);
vfree(cmd);
kfree(cmd->pkt);
kfree(cmd);
}
static int vpu_session_process_cmd(struct vpu_inst *inst, struct vpu_cmd_t *cmd)

View File

@@ -17,7 +17,6 @@
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include "vpu.h"
#include "vpu_defs.h"
#include "vpu_core.h"
@@ -265,7 +264,7 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
INIT_WORK(&core->msg_work, vpu_msg_run_work);
INIT_DELAYED_WORK(&core->msg_delayed_work, vpu_msg_delayed_work);
buffer_size = roundup_pow_of_two(VPU_MSG_BUFFER_SIZE);
core->msg_buffer = vzalloc(buffer_size);
core->msg_buffer = kzalloc(buffer_size, GFP_KERNEL);
if (!core->msg_buffer) {
dev_err(core->dev, "failed allocate buffer for fifo\n");
ret = -ENOMEM;
@@ -282,10 +281,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
return 0;
error:
if (core->msg_buffer) {
vfree(core->msg_buffer);
core->msg_buffer = NULL;
}
kfree(core->msg_buffer);
core->msg_buffer = NULL;
if (core->workqueue) {
destroy_workqueue(core->workqueue);
core->workqueue = NULL;
@@ -308,7 +305,7 @@ static int vpu_core_unregister(struct device *dev, struct vpu_core *core)
vpu_core_put_vpu(core);
core->vpu = NULL;
vfree(core->msg_buffer);
kfree(core->msg_buffer);
core->msg_buffer = NULL;
if (core->workqueue) {

View File

@@ -102,7 +102,6 @@ static int vpu_notify_eos(struct vpu_inst *inst)
int vpu_notify_source_change(struct vpu_inst *inst)
{
static const struct v4l2_event ev = {
.id = 0,
.type = V4L2_EVENT_SOURCE_CHANGE,
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION
};
@@ -670,7 +669,6 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
src_vq->min_queued_buffers = 1;
src_vq->dev = inst->vpu->dev;
src_vq->lock = &inst->lock;
ret = vb2_queue_init(src_vq);
@@ -687,7 +685,6 @@ static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_q
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct vpu_vb2_buffer);
dst_vq->min_queued_buffers = 1;
dst_vq->dev = inst->vpu->dev;
dst_vq->lock = &inst->lock;
ret = vb2_queue_init(dst_vq);

View File

@@ -26,6 +26,7 @@
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/ktime.h>
#include <linux/reset.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
#include <media/v4l2-ctrls.h>
@@ -310,6 +311,7 @@ struct aspeed_video {
void __iomem *base;
struct clk *eclk;
struct clk *vclk;
struct reset_control *reset;
struct device *dev;
struct v4l2_ctrl_handler ctrl_handler;
@@ -720,6 +722,13 @@ static void aspeed_video_on(struct aspeed_video *video)
set_bit(VIDEO_CLOCKS_ON, &video->flags);
}
static void aspeed_video_reset(struct aspeed_video *v)
{
reset_control_assert(v->reset);
usleep_range(100, 150);
reset_control_deassert(v->reset);
}
static void aspeed_video_bufs_done(struct aspeed_video *video,
enum vb2_buffer_state state)
{
@@ -742,7 +751,9 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay)
video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL;
aspeed_video_off(video);
aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff);
aspeed_video_reset(video);
aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR);
schedule_delayed_work(&video->res_work, delay);
@@ -1984,8 +1995,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q)
* Need to force stop any DMA and try and get HW into a good
* state for future calls to start streaming again.
*/
aspeed_video_off(video);
aspeed_video_on(video);
aspeed_video_reset(video);
aspeed_video_init_regs(video);
@@ -2230,6 +2240,12 @@ static int aspeed_video_init(struct aspeed_video *video)
}
dev_info(video->dev, "irq %d\n", irq);
video->reset = devm_reset_control_get(dev, NULL);
if (IS_ERR(video->reset)) {
dev_err(dev, "Unable to get reset\n");
return PTR_ERR(video->reset);
}
video->eclk = devm_clk_get(dev, "eclk");
if (IS_ERR(video->eclk)) {
dev_err(dev, "Unable to get ECLK\n");

View File

@@ -27,6 +27,11 @@ const char *state_to_str(enum vpu_instance_state state)
}
}
int wave5_kfifo_alloc(struct vpu_instance *inst)
{
return kfifo_alloc(&inst->irq_status, 16 * sizeof(int), GFP_KERNEL);
}
void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp)
{
int i;
@@ -49,7 +54,7 @@ void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp)
v4l2_fh_del(&inst->v4l2_fh, filp);
v4l2_fh_exit(&inst->v4l2_fh);
}
list_del_init(&inst->list);
kfifo_free(&inst->irq_status);
ida_free(&inst->dev->inst_ida, inst->id);
kfree(inst->codec_info);
kfree(inst);
@@ -61,8 +66,29 @@ int wave5_vpu_release_device(struct file *filp,
{
struct vpu_instance *inst = file_to_vpu_inst(filp);
int ret = 0;
unsigned long flags;
v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
/*
* To prevent Null reference exception, the existing irq handler were
* separated to two modules.
* One is to queue interrupt reason into the irq handler,
* the other is irq_thread to call the wave5_vpu_dec_finish_decode
* to get decoded frame.
* The list of instances should be protected between all flow of the
* decoding process, but to protect the list in the irq_handler, spin lock
* should be used, and mutex should be used in the irq_thread because spin lock
* is not able to be used because mutex is already being used
* in the wave5_vpu_dec_finish_decode.
* So the spin lock and mutex were used to protect the list in the release function.
*/
ret = mutex_lock_interruptible(&inst->dev->irq_lock);
if (ret)
return ret;
spin_lock_irqsave(&inst->dev->irq_spinlock, flags);
list_del_init(&inst->list);
spin_unlock_irqrestore(&inst->dev->irq_spinlock, flags);
mutex_unlock(&inst->dev->irq_lock);
if (inst->state != VPU_INST_STATE_NONE) {
u32 fail_res;

View File

@@ -33,4 +33,5 @@ void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
unsigned int width,
unsigned int height,
const struct v4l2_frmsize_stepwise *frmsize);
int wave5_kfifo_alloc(struct vpu_instance *inst);
#endif

View File

@@ -102,7 +102,7 @@ static void _wave5_print_reg_err(struct vpu_device *vpu_dev, u32 reg_fail_reason
dev_dbg(dev, "%s: queueing failure: 0x%x\n", func, reg_val);
break;
case WAVE5_SYSERR_RESULT_NOT_READY:
dev_err(dev, "%s: result not ready: 0x%x\n", func, reg_fail_reason);
dev_dbg(dev, "%s: result not ready: 0x%x\n", func, reg_fail_reason);
break;
case WAVE5_SYSERR_ACCESS_VIOLATION_HW:
dev_err(dev, "%s: access violation: 0x%x\n", func, reg_fail_reason);

View File

@@ -136,6 +136,18 @@ valid_state_switch:
return 0;
}
static int set_instance_state(struct vpu_instance *inst, enum vpu_instance_state state)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&inst->state_spinlock, flags);
ret = switch_state(inst, state);
spin_unlock_irqrestore(&inst->state_spinlock, flags);
return ret;
}
static int wave5_vpu_dec_set_eos_on_firmware(struct vpu_instance *inst)
{
int ret;
@@ -227,7 +239,7 @@ static int start_decode(struct vpu_instance *inst, u32 *fail_res)
src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
if (src_buf)
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
switch_state(inst, VPU_INST_STATE_STOP);
set_instance_state(inst, VPU_INST_STATE_STOP);
dev_dbg(inst->dev->dev, "%s: pic run failed / finish job", __func__);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
@@ -268,6 +280,7 @@ static void send_eos_event(struct vpu_instance *inst)
v4l2_event_queue_fh(&inst->v4l2_fh, &vpu_event_eos);
inst->eos = false;
inst->sent_eos = true;
}
static int handle_dynamic_resolution_change(struct vpu_instance *inst)
@@ -347,13 +360,12 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
struct vb2_v4l2_buffer *dec_buf = NULL;
struct vb2_v4l2_buffer *disp_buf = NULL;
struct vb2_queue *dst_vq = v4l2_m2m_get_dst_vq(m2m_ctx);
struct queue_status_info q_status;
dev_dbg(inst->dev->dev, "%s: Fetch output info from firmware.", __func__);
ret = wave5_vpu_dec_get_output_info(inst, &dec_info);
if (ret) {
dev_warn(inst->dev->dev, "%s: could not get output info.", __func__);
dev_dbg(inst->dev->dev, "%s: could not get output info.", __func__);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
return;
}
@@ -442,18 +454,17 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
spin_unlock_irqrestore(&inst->state_spinlock, flags);
}
/*
* During a resolution change and while draining, the firmware may flush
* the reorder queue regardless of having a matching decoding operation
* pending. Only terminate the job if there are no more IRQ coming.
*/
wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
if (q_status.report_queue_count == 0 &&
(q_status.instance_queue_count == 0 || dec_info.sequence_changed)) {
dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__);
pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
if (inst->sent_eos &&
v4l2_m2m_get_curr_priv(inst->v4l2_m2m_dev)) {
struct queue_status_info q_status;
wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
if (q_status.report_queue_count == 0 &&
q_status.instance_queue_count == 0)
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
inst->queuing_fail = false;
}
static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
@@ -1142,11 +1153,30 @@ static int write_to_ringbuffer(struct vpu_instance *inst, void *buffer, size_t b
return 0;
}
static struct vpu_src_buffer *inst_src_buf_remove(struct vpu_instance *inst)
{
struct vpu_src_buffer *b;
int ret;
ret = mutex_lock_interruptible(&inst->feed_lock);
if (ret)
return NULL;
if (list_empty(&inst->avail_src_bufs)) {
mutex_unlock(&inst->feed_lock);
return NULL;
}
b = list_first_entry(&inst->avail_src_bufs, struct vpu_src_buffer, list);
list_del_init(&b->list);
mutex_unlock(&inst->feed_lock);
return b;
}
static int fill_ringbuffer(struct vpu_instance *inst)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
struct v4l2_m2m_buffer *buf, *n;
int ret;
struct vpu_src_buffer *vpu_buf;
int ret = 0;
if (m2m_ctx->last_src_buf) {
struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(m2m_ctx->last_src_buf);
@@ -1157,9 +1187,8 @@ static int fill_ringbuffer(struct vpu_instance *inst)
}
}
v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
struct vb2_v4l2_buffer *vbuf = &buf->vb;
struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf);
while ((vpu_buf = inst_src_buf_remove(inst)) != NULL) {
struct vb2_v4l2_buffer *vbuf = &vpu_buf->v4l2_m2m_buf.vb;
struct vpu_buf *ring_buffer = &inst->bitstream_vbuf;
size_t src_size = vb2_get_plane_payload(&vbuf->vb2_buf, 0);
void *src_buf = vb2_plane_vaddr(&vbuf->vb2_buf, 0);
@@ -1219,9 +1248,12 @@ static int fill_ringbuffer(struct vpu_instance *inst)
dev_dbg(inst->dev->dev, "last src buffer written to the ring buffer\n");
break;
}
inst->queuing_num++;
break;
}
return 0;
return ret;
}
static void wave5_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
@@ -1230,10 +1262,16 @@ static void wave5_vpu_dec_buf_queue_src(struct vb2_buffer *vb)
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vpu_src_buffer *vpu_buf = wave5_to_vpu_src_buf(vbuf);
int ret;
vpu_buf->consumed = false;
vbuf->sequence = inst->queued_src_buf_num++;
ret = mutex_lock_interruptible(&inst->feed_lock);
if (ret)
return;
INIT_LIST_HEAD(&vpu_buf->list);
list_add_tail(&vpu_buf->list, &inst->avail_src_bufs);
mutex_unlock(&inst->feed_lock);
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
}
@@ -1243,6 +1281,7 @@ static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
struct vpu_instance *inst = vb2_get_drv_priv(vb->vb2_queue);
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
pm_runtime_resume_and_get(inst->dev->dev);
vbuf->sequence = inst->queued_dst_buf_num++;
if (inst->state == VPU_INST_STATE_PIC_RUN) {
@@ -1275,6 +1314,7 @@ static void wave5_vpu_dec_buf_queue_dst(struct vb2_buffer *vb)
} else {
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
}
pm_runtime_put_autosuspend(inst->dev->dev);
}
static void wave5_vpu_dec_buf_queue(struct vb2_buffer *vb)
@@ -1286,10 +1326,13 @@ static void wave5_vpu_dec_buf_queue(struct vb2_buffer *vb)
__func__, vb->type, vb->index, vb2_plane_size(&vbuf->vb2_buf, 0),
vb2_plane_size(&vbuf->vb2_buf, 1), vb2_plane_size(&vbuf->vb2_buf, 2));
if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
wave5_vpu_dec_buf_queue_src(vb);
else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
if (inst->empty_queue)
inst->empty_queue = false;
} else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
wave5_vpu_dec_buf_queue_dst(vb);
}
}
static int wave5_vpu_dec_allocate_ring_buffer(struct vpu_instance *inst)
@@ -1383,6 +1426,12 @@ static int streamoff_output(struct vb2_queue *q)
dma_addr_t new_rd_ptr;
struct dec_output_info dec_info;
unsigned int i;
struct vpu_src_buffer *vpu_buf;
inst->retry = false;
inst->queuing_num = 0;
while ((vpu_buf = inst_src_buf_remove(inst)) != NULL)
;
for (i = 0; i < v4l2_m2m_num_dst_bufs_ready(m2m_ctx); i++) {
ret = wave5_vpu_dec_set_disp_flag(inst, i);
@@ -1468,21 +1517,21 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
{
struct vpu_instance *inst = vb2_get_drv_priv(q);
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
bool check_cmd = TRUE;
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
pm_runtime_resume_and_get(inst->dev->dev);
inst->empty_queue = true;
while (check_cmd) {
struct queue_status_info q_status;
struct dec_output_info dec_output_info;
wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status);
if (q_status.report_queue_count == 0)
break;
if (wave5_vpu_wait_interrupt(inst, VPU_DEC_TIMEOUT) < 0)
if ((inst->state == VPU_INST_STATE_STOP ||
inst->state == VPU_INST_STATE_INIT_SEQ ||
q_status.instance_queue_count == 0) &&
q_status.report_queue_count == 0)
break;
if (wave5_vpu_dec_get_output_info(inst, &dec_output_info))
@@ -1496,6 +1545,8 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
else
streamoff_capture(q);
inst->empty_queue = false;
inst->sent_eos = false;
pm_runtime_put_autosuspend(inst->dev->dev);
}
@@ -1577,10 +1628,18 @@ static void wave5_vpu_dec_device_run(void *priv)
dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__);
pm_runtime_resume_and_get(inst->dev->dev);
ret = fill_ringbuffer(inst);
if (ret) {
dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
goto finish_job_and_return;
if (!inst->retry) {
ret = fill_ringbuffer(inst);
if (ret < 0) {
dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
goto finish_job_and_return;
} else if (!inst->eos &&
inst->queuing_num == 0 &&
inst->state == VPU_INST_STATE_PIC_RUN) {
dev_dbg(inst->dev->dev, "%s: no bitstream for feeding, so skip ", __func__);
inst->empty_queue = true;
goto finish_job_and_return;
}
}
switch (inst->state) {
@@ -1605,7 +1664,7 @@ static void wave5_vpu_dec_device_run(void *priv)
}
spin_unlock_irqrestore(&inst->state_spinlock, flags);
} else {
switch_state(inst, VPU_INST_STATE_INIT_SEQ);
set_instance_state(inst, VPU_INST_STATE_INIT_SEQ);
}
break;
@@ -1616,8 +1675,7 @@ static void wave5_vpu_dec_device_run(void *priv)
* we had a chance to switch, which leads to an invalid state
* change.
*/
switch_state(inst, VPU_INST_STATE_PIC_RUN);
set_instance_state(inst, VPU_INST_STATE_PIC_RUN);
/*
* During DRC, the picture decoding remains pending, so just leave the job
* active until this decode operation completes.
@@ -1631,14 +1689,12 @@ static void wave5_vpu_dec_device_run(void *priv)
ret = wave5_prepare_fb(inst);
if (ret) {
dev_warn(inst->dev->dev, "Framebuffer preparation, fail: %d\n", ret);
switch_state(inst, VPU_INST_STATE_STOP);
set_instance_state(inst, VPU_INST_STATE_STOP);
break;
}
if (q_status.instance_queue_count) {
dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
return;
}
if (q_status.instance_queue_count)
goto finish_job_and_return;
fallthrough;
case VPU_INST_STATE_PIC_RUN:
@@ -1647,28 +1703,45 @@ static void wave5_vpu_dec_device_run(void *priv)
dev_err(inst->dev->dev,
"Frame decoding on m2m context (%p), fail: %d (result: %d)\n",
m2m_ctx, ret, fail_res);
break;
goto finish_job_and_return;
}
if (fail_res == WAVE5_SYSERR_QUEUEING_FAIL) {
inst->retry = true;
inst->queuing_fail = true;
} else {
inst->retry = false;
if (!inst->eos)
inst->queuing_num--;
}
/* Return so that we leave this job active */
dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
return;
default:
WARN(1, "Execution of a job in state %s illegal.\n", state_to_str(inst->state));
break;
default:
dev_dbg(inst->dev->dev, "Execution of a job in state %s illegal.\n",
state_to_str(inst->state));
}
finish_job_and_return:
dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
/*
* After receiving CMD_STOP, there is no input, but we have to run device_run
* to send DEC_PIC command until display index == -1, so job_finish was always
* called in the device_run to archive it, the logic was very wasteful
* in power and CPU time.
* If EOS is passed, device_run will not call job_finish no more, it is called
* only if HW is idle status in order to reduce overhead.
*/
if (!inst->sent_eos)
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
static void wave5_vpu_dec_job_abort(void *priv)
{
struct vpu_instance *inst = priv;
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
int ret;
ret = switch_state(inst, VPU_INST_STATE_STOP);
ret = set_instance_state(inst, VPU_INST_STATE_STOP);
if (ret)
return;
@@ -1676,6 +1749,8 @@ static void wave5_vpu_dec_job_abort(void *priv)
if (ret)
dev_warn(inst->dev->dev,
"Setting EOS for the bitstream, fail: %d\n", ret);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
static int wave5_vpu_dec_job_ready(void *priv)
@@ -1711,10 +1786,15 @@ static int wave5_vpu_dec_job_ready(void *priv)
"No capture buffer ready to decode!\n");
break;
} else if (!wave5_is_draining_or_eos(inst) &&
!v4l2_m2m_num_src_bufs_ready(m2m_ctx)) {
(!v4l2_m2m_num_src_bufs_ready(m2m_ctx) ||
inst->empty_queue)) {
dev_dbg(inst->dev->dev,
"No bitstream data to decode!\n");
break;
} else if (inst->state == VPU_INST_STATE_PIC_RUN &&
!wave5_is_draining_or_eos(inst) &&
inst->queuing_fail) {
break;
}
ret = 1;
break;
@@ -1751,10 +1831,14 @@ static int wave5_vpu_open_dec(struct file *filp)
inst->ops = &wave5_vpu_dec_inst_ops;
spin_lock_init(&inst->state_spinlock);
mutex_init(&inst->feed_lock);
INIT_LIST_HEAD(&inst->avail_src_bufs);
inst->codec_info = kzalloc(sizeof(*inst->codec_info), GFP_KERNEL);
if (!inst->codec_info)
if (!inst->codec_info) {
kfree(inst);
return -ENOMEM;
}
v4l2_fh_init(&inst->v4l2_fh, vdev);
v4l2_fh_add(&inst->v4l2_fh, filp);
@@ -1806,6 +1890,11 @@ static int wave5_vpu_open_dec(struct file *filp)
inst->xfer_func = V4L2_XFER_FUNC_DEFAULT;
init_completion(&inst->irq_done);
ret = wave5_kfifo_alloc(inst);
if (ret) {
dev_err(inst->dev->dev, "failed to allocate fifo\n");
goto cleanup_inst;
}
inst->id = ida_alloc(&inst->dev->inst_ida, GFP_KERNEL);
if (inst->id < 0) {
@@ -1825,9 +1914,6 @@ static int wave5_vpu_open_dec(struct file *filp)
if (ret)
goto cleanup_inst;
if (list_empty(&dev->instances))
pm_runtime_use_autosuspend(inst->dev->dev);
list_add_tail(&inst->list, &dev->instances);
mutex_unlock(&dev->dev_lock);

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