mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-21 23:16:50 +08:00
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:
@@ -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.
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
103
Documentation/devicetree/bindings/media/i2c/ovti,os05b10.yaml
Normal file
103
Documentation/devicetree/bindings/media/i2c/ovti,os05b10.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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:
|
||||
- |
|
||||
|
||||
103
Documentation/devicetree/bindings/media/i2c/samsung,s5k3m5.yaml
Normal file
103
Documentation/devicetree/bindings/media/i2c/samsung,s5k3m5.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
103
Documentation/devicetree/bindings/media/i2c/samsung,s5kjn1.yaml
Normal file
103
Documentation/devicetree/bindings/media/i2c/samsung,s5kjn1.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
439
Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml
Normal file
439
Documentation/devicetree/bindings/media/qcom,sm6150-camss.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -77,6 +77,7 @@ allOf:
|
||||
- renesas,r9a07g043u-fcpvd
|
||||
- renesas,r9a07g044-fcpvd
|
||||
- renesas,r9a07g054-fcpvd
|
||||
- renesas,r9a09g056-fcpvd
|
||||
- renesas,r9a09g057-fcpvd
|
||||
then:
|
||||
properties:
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
189
Documentation/devicetree/bindings/media/ti,omap3isp.yaml
Normal file
189
Documentation/devicetree/bindings/media/ti,omap3isp.yaml
Normal 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 = <¶llel>;
|
||||
};
|
||||
};
|
||||
|
||||
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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
152
Documentation/devicetree/bindings/media/ti,vip.yaml
Normal file
152
Documentation/devicetree/bindings/media/ti,vip.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
...
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)``
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
39
MAINTAINERS
39
MAINTAINERS
@@ -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/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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, ¤t_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
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
1487
drivers/media/i2c/s5kjn1.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_*() */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user