diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-01 10:34:52 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-01 10:34:52 -0700 |
commit | 835d31d319d9c8c4eb6cac074643360ba0ecab10 (patch) | |
tree | 824dc6286c3f34357de0a0c12d0311eca9a6da8d | |
parent | 0d290223a6c77107b1c3988959e49279a8dafaba (diff) | |
parent | 9c3a0f285248899dfa81585bc5d5bc9ebdb8fead (diff) |
Merge tag 'media/v5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- new sensor drivers: imx335, imx412, ov9282
- new IR transmitter driver: meson-ir-tx
- handro driver gained support for H.264 for Rockchip VDPU2
- imx gained support for i.MX8MQ
- ti-vpe has gained support for other SoC variants
- lots of cleanups, fixes, board additions and doc improvements
* tag 'media/v5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (195 commits)
media: venus: venc: add support for V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM control
media: venus: venc: Add support for intra-refresh period
media: v4l2-ctrls: Add intra-refresh period control
media: docs: ext-ctrls-codec: Document cyclic intra-refresh zero control value
media: venus: helper: do not set constrained parameters for UBWC
media: venus: venc: Fix potential null pointer dereference on pointer fmt
media: venus: hfi: fix return value check in sys_get_prop_image_version()
media: tegra-cec: Handle errors of clk_prepare_enable()
media: cec-pin: rename timer overrun variables
media: TDA1997x: report -ENOLINK after disconnecting HDMI source
media: TDA1997x: fix tda1997x_query_dv_timings() return value
media: Fix cosmetic error in TDA1997x driver
media: v4l2-dv-timings.c: fix wrong condition in two for-loops
media: imx: add a driver for i.MX8MQ mipi csi rx phy and controller
media: dt-bindings: media: document the nxp,imx8mq-mipi-csi2 receiver phy and controller
media: imx: imx7_mipi_csis: convert some switch cases to the default
media: imx: imx7-media-csi: Fix buffer return upon stream start failure
media: imx: imx7-media-csi: Don't set PIXEL_BIT in CSICR1
media: imx: imx7-media-csi: Set TWO_8BIT_SENSOR for >= 10-bit formats
media: dt-bindings: media: nxp,imx7-csi: Add i.MX8MM support
...
150 files changed, 7973 insertions, 1339 deletions
diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml b/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml new file mode 100644 index 000000000000..4432fea32650 --- /dev/null +++ b/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/amlogic,meson-ir-tx.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson IR transmitter + +maintainers: + - Viktor Prutyanov <viktor.prutyanov@phystech.edu> + +description: | + Some Amlogic SoCs such as A311D and T950D4 have IR transmitter + (also called blaster) controller onboard. It is capable of + sending IR signals with arbitrary carrier frequency and duty cycle. + +properties: + compatible: + oneOf: + - const: amlogic,meson-ir-tx + - items: + - const: amlogic,meson-g12a-ir-tx + - const: amlogic,meson-ir-tx + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: sysclk + - const: xtal + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + #include <dt-bindings/clock/g12a-clkc.h> + + ir@ff80014c { + compatible = "amlogic,meson-g12a-ir-tx", "amlogic,meson-ir-tx"; + reg = <0xff80014c 0x10>; + interrupts = <0 198 IRQ_TYPE_EDGE_RISING>; + clocks = <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "sysclk", "xtal"; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index 3ce4af143a3a..c8d887eee3bb 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -35,6 +35,14 @@ properties: powerdown-gpios: maxItems: 1 + reset-gpios: + maxItems: 1 + + adv,force-bt656-4: + description: + Indicates that the output is a BT.656-4 compatible stream. + type: boolean + port: $ref: /schemas/graph.yaml#/$defs/port-base unevaluatedProperties: false diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml new file mode 100644 index 000000000000..ad42992c6da3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov9282.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV9282 Sensor + +maintainers: + - Paul J. Murphy <paul.j.murphy@intel.com> + - Daniele Alessandrelli <daniele.alessandrelli@intel.com> + +description: + OV9282 sensor is an OmniVision black & white CMOS active pixel digital image + sensor with an active array size of 1296H x 816V. It is programmable through + I2C interface. The I2C client address is fixed to 0x60/0x70 as per sensor data + sheet. Image data is sent through MIPI CSI-2. + +properties: + compatible: + const: ovti,ov9282 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency from 6 to 27MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@60 { + compatible = "ovti,ov9282"; + reg = <0x60>; + clocks = <&ov9282_clk>; + + assigned-clocks = <&ov9282_clk>; + assigned-clock-parents = <&ov9282_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + ov9282: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml new file mode 100644 index 000000000000..881f79532501 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx335.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX335 Sensor + +maintainers: + - Paul J. Murphy <paul.j.murphy@intel.com> + - Daniele Alessandrelli <daniele.alessandrelli@intel.com> + +description: + IMX335 sensor is a Sony CMOS active pixel digital image sensor with an active + array size of 2592H x 1944V. It is programmable through I2C interface. The + I2C client address is fixed to 0x1a as per sensor data sheet. Image data is + sent through MIPI CSI-2. + +properties: + compatible: + const: sony,imx335 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx335"; + reg = <0x1a>; + clocks = <&imx335_clk>; + + assigned-clocks = <&imx335_clk>; + assigned-clock-parents = <&imx335_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + imx335: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <594000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml new file mode 100644 index 000000000000..1edeabf39e6a --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx412.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX412 Sensor + +maintainers: + - Paul J. Murphy <paul.j.murphy@intel.com> + - Daniele Alessandrelli <daniele.alessandrelli@intel.com> + +description: + IMX412 sensor is a Sony CMOS active pixel digital image sensor with an active + array size of 4072H x 3176V. It is programmable through I2C interface. The + I2C client address is fixed to 0x1a as per sensor data sheet. Image data is + sent through MIPI CSI-2. + +properties: + compatible: + const: sony,imx412 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx412"; + reg = <0x1a>; + clocks = <&imx412_clk>; + + assigned-clocks = <&imx412_clk>; + assigned-clock-parents = <&imx412_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + imx412: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <600000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml index d91575b8ebb9..5922a2795167 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/media/nxp,imx7-csi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: i.MX7 CMOS Sensor Interface +title: i.MX7 and i.MX8 CSI bridge (CMOS Sensor Interface) maintainers: - Rui Miguel Silva <rmfrfs@gmail.com> @@ -15,9 +15,13 @@ description: | properties: compatible: - enum: - - fsl,imx7-csi - - fsl,imx6ul-csi + oneOf: + - enum: + - fsl,imx7-csi + - fsl,imx6ul-csi + - items: + - const: fsl,imx8mm-csi + - const: fsl,imx7-csi reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml new file mode 100644 index 000000000000..9c04fa85ee5c --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml @@ -0,0 +1,174 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,imx8mq-mipi-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8MQ MIPI CSI-2 receiver + +maintainers: + - Martin Kepplinger <martin.kepplinger@puri.sm> + +description: |- + This binding covers the CSI-2 RX PHY and host controller included in the + NXP i.MX8MQ SoC. It handles the sensor/image input and process for all the + input imaging devices. + +properties: + compatible: + enum: + - fsl,imx8mq-mipi-csi2 + + reg: + maxItems: 1 + + clocks: + items: + - description: core is the RX Controller Core Clock input. This clock + must be exactly equal to or faster than the receive + byteclock from the RX DPHY. + - description: esc is the Rx Escape Clock. This must be the same escape + clock that the RX DPHY receives. + - description: ui is the pixel clock (phy_ref up to 333Mhz). + See the reference manual for details. + + clock-names: + items: + - const: core + - const: esc + - const: ui + + power-domains: + maxItems: 1 + + resets: + items: + - description: CORE_RESET reset register bit definition + - description: PHY_REF_RESET reset register bit definition + - description: ESC_RESET reset register bit definition + + fsl,mipi-phy-gpr: + description: | + The phandle to the imx8mq syscon iomux-gpr with the register + for setting RX_ENABLE for the mipi receiver. + + The format should be as follows: + <gpr req_gpr> + gpr is the phandle to general purpose register node. + req_gpr is the gpr register offset of RX_ENABLE for the mipi phy. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: The 'gpr' is the phandle to general purpose register node. + - description: The 'req_gpr' is the gpr register offset containing + CSI2_1_RX_ENABLE or CSI2_2_RX_ENABLE respectively. + maximum: 0xff + + interconnects: + maxItems: 1 + + interconnect-names: + const: dram + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Input port node, single endpoint describing the CSI-2 transmitter. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + items: + minItems: 1 + maxItems: 4 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Output port node + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - resets + - fsl,mipi-phy-gpr + - ports + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mq-clock.h> + #include <dt-bindings/interconnect/imx8mq.h> + #include <dt-bindings/reset/imx8mq-reset.h> + + csi@30a70000 { + compatible = "fsl,imx8mq-mipi-csi2"; + reg = <0x30a70000 0x1000>; + clocks = <&clk IMX8MQ_CLK_CSI1_CORE>, + <&clk IMX8MQ_CLK_CSI1_ESC>, + <&clk IMX8MQ_CLK_CSI1_PHY_REF>; + clock-names = "core", "esc", "ui"; + assigned-clocks = <&clk IMX8MQ_CLK_CSI1_CORE>, + <&clk IMX8MQ_CLK_CSI1_PHY_REF>, + <&clk IMX8MQ_CLK_CSI1_ESC>; + assigned-clock-rates = <266000000>, <200000000>, <66000000>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_266M>, + <&clk IMX8MQ_SYS2_PLL_1000M>, + <&clk IMX8MQ_SYS1_PLL_800M>; + power-domains = <&pgc_mipi_csi1>; + resets = <&src IMX8MQ_RESET_MIPI_CSI1_CORE_RESET>, + <&src IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET>, + <&src IMX8MQ_RESET_MIPI_CSI1_ESC_RESET>; + fsl,mipi-phy-gpr = <&iomuxc_gpr 0x88>; + interconnects = <&noc IMX8MQ_ICM_CSI1 &noc IMX8MQ_ICS_DRAM>; + interconnect-names = "dram"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + imx8mm_mipi_csi_in: endpoint { + remote-endpoint = <&imx477_out>; + data-lanes = <1 2 3 4>; + }; + }; + + port@1 { + reg = <1>; + + imx8mm_mipi_csi_out: endpoint { + remote-endpoint = <&csi_in>; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml index b88172a59de7..bacb60a34989 100644 --- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml @@ -22,6 +22,7 @@ properties: - rockchip,rk3288-vpu - rockchip,rk3328-vpu - rockchip,rk3399-vpu + - rockchip,px30-vpu - items: - const: rockchip,rk3188-vpu - const: rockchip,rk3066-vpu diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 7160336aa475..c7d4891bd24e 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -3,10 +3,10 @@ Writing camera sensor drivers ============================= -CSI-2 ------ +CSI-2 and parallel (BT.601 and BT.656) busses +--------------------------------------------- -Please see what is written on :ref:`MIPI_CSI_2`. +Please see :ref:`transmitter-receiver`. Handling clocks --------------- @@ -26,15 +26,16 @@ user. ACPI ~~~~ -Read the "clock-frequency" _DSD property to denote the frequency. The driver can -rely on this frequency being used. +Read the ``clock-frequency`` _DSD property to denote the frequency. The driver +can rely on this frequency being used. Devicetree ~~~~~~~~~~ -The currently preferred way to achieve this is using "assigned-clock-rates" -property. See Documentation/devicetree/bindings/clock/clock-bindings.txt for -more information. The driver then gets the frequency using clk_get_rate(). +The currently preferred way to achieve this is using ``assigned-clocks``, +``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See +``Documentation/devicetree/bindings/clock/clock-bindings.txt`` for more +information. The driver then gets the frequency using ``clk_get_rate()``. This approach has the drawback that there's no guarantee that the frequency hasn't been modified directly or indirectly by another driver, or supported by @@ -55,7 +56,7 @@ processing pipeline as one or more sub-devices with different cropping and scaling configurations. The output size of the device is the result of a series of cropping and scaling operations from the device's pixel array's size. -An example of such a driver is the smiapp driver (see drivers/media/i2c/smiapp). +An example of such a driver is the CCS driver (see ``drivers/media/i2c/ccs``). Register list based drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -67,7 +68,7 @@ level are independent. How a driver picks such configuration is based on the format set on a source pad at the end of the device's internal pipeline. Most sensor drivers are implemented this way, see e.g. -drivers/media/i2c/imx319.c for an example. +``drivers/media/i2c/imx319.c`` for an example. Frame interval configuration ---------------------------- @@ -94,9 +95,10 @@ large variety of devices beyond camera sensors. Devices that have no analogue crop, use the full source image size, i.e. pixel array size. Horizontal and vertical blanking are specified by ``V4L2_CID_HBLANK`` and -``V4L2_CID_VBLANK``, respectively. The unit of these controls are lines. The -pixel rate is specified by ``V4L2_CID_PIXEL_RATE`` in the same sub-device. The -unit of that control is Hz. +``V4L2_CID_VBLANK``, respectively. The unit of the ``V4L2_CID_HBLANK`` control +is pixels and the unit of the ``V4L2_CID_VBLANK`` is lines. The pixel rate in +the sensor's **pixel array** is specified by ``V4L2_CID_PIXEL_RATE`` in the same +sub-device. The unit of that control is pixels per second. Register list based drivers need to implement read-only sub-device nodes for the purpose. Devices that are not register list based need these to configure the @@ -125,14 +127,14 @@ general, the device must be powered on at least when its registers are being accessed and when it is streaming. Existing camera sensor drivers may rely on the old -:c:type:`v4l2_subdev_core_ops`->s_power() callback for bridge or ISP drivers to +struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to manage their power state. This is however **deprecated**. If you feel you need to begin calling an s_power from an ISP or a bridge driver, instead please add runtime PM support to the sensor driver you are using. Likewise, new drivers should not use s_power. Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and -``drivers/media/i2c/smiapp/smiapp-core.c``. The two drivers work in both ACPI +``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI and DT based systems. Control framework @@ -149,16 +151,3 @@ used to obtain device's power state after the power state transition: The function returns a non-zero value if it succeeded getting the power count or runtime PM was disabled, in either of which cases the driver may proceed to access the device. - -Controls --------- - -For camera sensors that are connected to a bus where transmitter and receiver -require common configuration set by drivers, such as CSI-2 or parallel (BT.601 -or BT.656) bus, the ``V4L2_CID_LINK_FREQ`` control is mandatory on transmitter -drivers. Receiver drivers can use the ``V4L2_CID_LINK_FREQ`` to query the -frequency used on the bus. - -The transmitter drivers should also implement ``V4L2_CID_PIXEL_RATE`` control in -order to tell the maximum pixel rate to the receiver. This is required on raw -camera sensors. diff --git a/Documentation/driver-api/media/cec-core.rst b/Documentation/driver-api/media/cec-core.rst index 56345eae9a26..c6194ee81c41 100644 --- a/Documentation/driver-api/media/cec-core.rst +++ b/Documentation/driver-api/media/cec-core.rst @@ -130,9 +130,12 @@ To enable/disable the hardware:: int (*adap_enable)(struct cec_adapter *adap, bool enable); This callback enables or disables the CEC hardware. Enabling the CEC hardware -means powering it up in a state where no logical addresses are claimed. This -op assumes that the physical address (adap->phys_addr) is valid when enable is -true and will not change while the CEC adapter remains enabled. The initial +means powering it up in a state where no logical addresses are claimed. The +physical address will always be valid if CEC_CAP_NEEDS_HPD is set. If that +capability is not set, then the physical address can change while the CEC +hardware is enabled. CEC drivers should not set CEC_CAP_NEEDS_HPD unless +the hardware design requires that as this will make it impossible to wake +up displays that pull the HPD low when in standby mode. The initial state of the CEC adapter after calling cec_allocate_adapter() is disabled. Note that adap_enable must return 0 if enable is false. diff --git a/Documentation/driver-api/media/csi2.rst b/Documentation/driver-api/media/csi2.rst deleted file mode 100644 index 11c52b0be8b8..000000000000 --- a/Documentation/driver-api/media/csi2.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. _MIPI_CSI_2: - -MIPI CSI-2 -========== - -CSI-2 is a data bus intended for transferring images from cameras to -the host SoC. It is defined by the `MIPI alliance`_. - -.. _`MIPI alliance`: http://www.mipi.org/ - -Media bus formats ------------------ - -See :ref:`v4l2-mbus-pixelcode` for details on which media bus formats should -be used for CSI-2 interfaces. - -Transmitter drivers -------------------- - -CSI-2 transmitter, such as a sensor or a TV tuner, drivers need to -provide the CSI-2 receiver with information on the CSI-2 bus -configuration. These include the V4L2_CID_LINK_FREQ and -V4L2_CID_PIXEL_RATE controls and -(:c:type:`v4l2_subdev_video_ops`->s_stream() callback). These -interface elements must be present on the sub-device represents the -CSI-2 transmitter. - -The V4L2_CID_LINK_FREQ control is used to tell the receiver driver the -frequency (and not the symbol rate) of the link. The V4L2_CID_PIXEL_RATE -control may be used by the receiver to obtain the pixel rate the transmitter -uses. The :c:type:`v4l2_subdev_video_ops`->s_stream() callback provides an -ability to start and stop the stream. - -The value of the V4L2_CID_PIXEL_RATE is calculated as follows:: - - pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample - -where - -.. list-table:: variables in pixel rate calculation - :header-rows: 1 - - * - variable or constant - - description - * - link_freq - - The value of the V4L2_CID_LINK_FREQ integer64 menu item. - * - nr_of_lanes - - Number of data lanes used on the CSI-2 link. This can - be obtained from the OF endpoint configuration. - * - 2 - - Two bits are transferred per clock cycle per lane. - * - bits_per_sample - - Number of bits per sample. - * - k - - 16 for D-PHY and 7 for C-PHY - -The transmitter drivers must, if possible, configure the CSI-2 -transmitter to *LP-11 mode* whenever the transmitter is powered on but -not active, and maintain *LP-11 mode* until stream on. Only at stream -on should the transmitter activate the clock on the clock lane and -transition to *HS mode*. - -Some transmitters do this automatically but some have to be explicitly -programmed to do so, and some are unable to do so altogether due to -hardware constraints. - -Stopping the transmitter -^^^^^^^^^^^^^^^^^^^^^^^^ - -A transmitter stops sending the stream of images as a result of -calling the ``.s_stream()`` callback. Some transmitters may stop the -stream at a frame boundary whereas others stop immediately, -effectively leaving the current frame unfinished. The receiver driver -should not make assumptions either way, but function properly in both -cases. - -Receiver drivers ----------------- - -Before the receiver driver may enable the CSI-2 transmitter by using -the :c:type:`v4l2_subdev_video_ops`->s_stream(), it must have powered -the transmitter up by using the -:c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take -place either indirectly by using :c:func:`v4l2_pipeline_pm_get` or -directly. - -Formats -------- - -The media bus pixel codes document parallel formats. Should the pixel data be -transported over a serial bus, the media bus pixel code that describes a -parallel format that transfers a sample on a single clock cycle is used. diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst index 813d7db59da7..08e206567408 100644 --- a/Documentation/driver-api/media/index.rst +++ b/Documentation/driver-api/media/index.rst @@ -37,7 +37,7 @@ Documentation/userspace-api/media/index.rst rc-core mc-core cec-core - csi2 + tx-rx camera-sensor drivers/index diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst new file mode 100644 index 000000000000..e1e9258dd862 --- /dev/null +++ b/Documentation/driver-api/media/tx-rx.rst @@ -0,0 +1,133 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _transmitter-receiver: + +Pixel data transmitter and receiver drivers +=========================================== + +V4L2 supports various devices that transmit and receive pixel data. Examples of +these devices include a camera sensor, a TV tuner and a parallel or a CSI-2 +receiver in an SoC. + +Bus types +--------- + +The following busses are the most common. This section discusses these two only. + +MIPI CSI-2 +^^^^^^^^^^ + +CSI-2 is a data bus intended for transferring images from cameras to +the host SoC. It is defined by the `MIPI alliance`_. + +.. _`MIPI alliance`: https://www.mipi.org/ + +Parallel +^^^^^^^^ + +`BT.601`_ and `BT.656`_ are the most common parallel busses. + +.. _`BT.601`: https://en.wikipedia.org/wiki/Rec._601 +.. _`BT.656`: https://en.wikipedia.org/wiki/ITU-R_BT.656 + +Transmitter drivers +------------------- + +Transmitter drivers generally need to provide the receiver drivers with the +configuration of the transmitter. What is required depends on the type of the +bus. These are common for both busses. + +Media bus pixel code +^^^^^^^^^^^^^^^^^^^^ + +See :ref:`v4l2-mbus-pixelcode`. + +Link frequency +^^^^^^^^^^^^^^ + +The :ref:`V4L2_CID_LINK_FREQ <v4l2-cid-link-freq>` control is used to tell the +receiver the frequency of the bus (i.e. it is not the same as the symbol rate). + +``.s_stream()`` callback +^^^^^^^^^^^^^^^^^^^^^^^^ + +The struct struct v4l2_subdev_video_ops->s_stream() callback is used by the +receiver driver to control the transmitter driver's streaming state. + + +CSI-2 transmitter drivers +------------------------- + +Pixel rate +^^^^^^^^^^ + +The pixel rate on the bus is calculated as follows:: + + pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample + +where + +.. list-table:: variables in pixel rate calculation + :header-rows: 1 + + * - variable or constant + - description + * - link_freq + - The value of the ``V4L2_CID_LINK_FREQ`` integer64 menu item. + * - nr_of_lanes + - Number of data lanes used on the CSI-2 link. This can + be obtained from the OF endpoint configuration. + * - 2 + - Data is transferred on both rising and falling edge of the signal. + * - bits_per_sample + - Number of bits per sample. + * - k + - 16 for D-PHY and 7 for C-PHY + +.. note:: + + The pixel rate calculated this way is **not** the same thing as the + pixel rate on the camera sensor's pixel array which is indicated by the + :ref:`V4L2_CID_PIXEL_RATE <v4l2-cid-pixel-rate>` control. + +LP-11 and LP-111 modes +^^^^^^^^^^^^^^^^^^^^^^ + +As part of transitioning to high speed mode, a CSI-2 transmitter typically +briefly sets the bus to LP-11 or LP-111 state, depending on the PHY. This period +may be as short as 100 µs, during which the receiver observes this state and +proceeds its own part of high speed mode transition. + +Most receivers are capable of autonomously handling this once the software has +configured them to do so, but there are receivers which require software +involvement in observing LP-11 or LP-111 state. 100 µs is a brief period to hit +in software, especially when there is no interrupt telling something is +happening. + +One way to address this is to configure the transmitter side explicitly to LP-11 +or LP-111 mode, which requires support from the transmitter hardware. This is +not universally available. Many devices return to this state once streaming is +stopped while the state after power-on is LP-00 or LP-000. + +The ``.pre_streamon()`` callback may be used to prepare a transmitter for +transitioning to streaming state, but not yet start streaming. Similarly, the +``.post_streamoff()`` callback is used to undo what was done by the +``.pre_streamon()`` callback. The caller of ``.pre_streamon()`` is thus required +to call ``.post_streamoff()`` for each successful call of ``.pre_streamon()``. + +In the context of CSI-2, the ``.pre_streamon()`` callback is used to transition +the transmitter to the LP-11 or LP-111 mode. This also requires powering on the +device, so this should be only done when it is needed. + +Receiver drivers that do not need explicit LP-11 or LP-111 mode setup are waived +from calling the two callbacks. + +Stopping the transmitter +^^^^^^^^^^^^^^^^^^^^^^^^ + +A transmitter stops sending the stream of images as a result of +calling the ``.s_stream()`` callback. Some transmitters may stop the +stream at a frame boundary whereas others stop immediately, +effectively leaving the current frame unfinished. The receiver driver +should not make assumptions either way, but function properly in both +cases. diff --git a/Documentation/userspace-api/media/cec.h.rst.exceptions b/Documentation/userspace-api/media/cec.h.rst.exceptions index d83790ccac8e..13de01d9555e 100644 --- a/Documentation/userspace-api/media/cec.h.rst.exceptions +++ b/Documentation/userspace-api/media/cec.h.rst.exceptions @@ -140,7 +140,7 @@ ignore define CEC_OP_REC_SEQ_TUESDAY ignore define CEC_OP_REC_SEQ_WEDNESDAY ignore define CEC_OP_REC_SEQ_THURSDAY ignore define CEC_OP_REC_SEQ_FRIDAY -ignore define CEC_OP_REC_SEQ_SATERDAY +ignore define CEC_OP_REC_SEQ_SATURDAY ignore define CEC_OP_REC_SEQ_ONCE_ONLY ignore define CEC_MSG_CLEAR_DIGITAL_TIMER diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 8c6e2a11ed95..976d34445a24 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1174,7 +1174,24 @@ enum v4l2_mpeg_video_h264_entropy_mode - Cyclic intra macroblock refresh. This is the number of continuous macroblocks refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from - the top of the frame. Applicable to H264, H263 and MPEG4 encoder. + the top of the frame. Setting this control to zero means that + macroblocks will not be refreshed. Note that this control will not + take effect when ``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD`` control + is set to non zero value. + Applicable to H264, H263 and MPEG4 encoder. + +``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (integer)`` + Intra macroblock refresh period. This sets the period to refresh + the whole frame. In other words, this defines the number of frames + for which the whole frame will be intra-refreshed. An example: + setting period to 1 means that the whole frame will be refreshed, + setting period to 2 means that the half of macroblocks will be + intra-refreshed on frameX and the other half of macroblocks + will be refreshed in frameX + 1 and so on. Setting the period to + zero means no period is specified. + Note that if the client sets this control to non zero value the + ``V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB`` control shall be + ignored. Applicable to H264 and HEVC encoders. ``V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (boolean)`` Frame level rate control enable. If this control is disabled then @@ -3000,6 +3017,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``pic_struct`` - + * - __u32 + - ``slice_segment_addr`` + - * - __u8 - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - The list of L0 reference elements as indices in the DPB. diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst index 87698c15c027..b1c2ab2854af 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst @@ -20,25 +20,26 @@ Image Process Control IDs ``V4L2_CID_IMAGE_PROC_CLASS (class)`` The IMAGE_PROC class descriptor. +.. _v4l2-cid-link-freq: + ``V4L2_CID_LINK_FREQ (integer menu)`` - Data bus frequency. Together with the media bus pixel code, bus type - (clock cycles per sample), the data bus frequency defines the pixel - rate (``V4L2_CID_PIXEL_RATE``) in the pixel array (or possibly - elsewhere, if the device is not an image sensor). The frame rate can - be calculated from the pixel clock, image width and height and - horizontal and vertical blanking. While the pixel rate control may - be defined elsewhere than in the subdev containing the pixel array, - the frame rate cannot be obtained from that information. This is - because only on the pixel array it can be assumed that the vertical - and horizontal blanking information is exact: no other blanking is - allowed in the pixel array. The selection of frame rate is performed - by selecting the desired horizontal and vertical blanking. The unit - of this control is Hz. + The frequency of the data bus (e.g. parallel or CSI-2). + +.. _v4l2-cid-pixel-rate: ``V4L2_CID_PIXEL_RATE (64-bit integer)`` - Pixel rate in the source pads of the subdev. This control is + Pixel sampling rate in the device's pixel array. This control is read-only and its unit is pixels / second. + Some devices use horizontal and vertical balanking to configure the frame + rate. The frame rate can be calculated from the pixel rate, analogue crop + rectangle as well as horizontal and vertical blanking. The pixel rate + control may be present in a different sub-device than the blanking controls + and the analogue crop rectangle configuration. + + The configuration of the frame rate is performed by selecting the desired + horizontal and vertical blanking. The unit of this control is Hz. + ``V4L2_CID_TEST_PATTERN (menu)`` Some capture/display/sensor devices have the capability to generate test pattern images. These hardware specific test patterns can be diff --git a/MAINTAINERS b/MAINTAINERS index db76855aa3c4..af0df260c02b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13833,6 +13833,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml F: drivers/media/i2c/ov8856.c +OMNIVISION OV9282 SENSOR DRIVER +M: Paul J. Murphy <paul.j.murphy@intel.com> +M: Daniele Alessandrelli <daniele.alessandrelli@intel.com> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml +F: drivers/media/i2c/ov9282.c + OMNIVISION OV9640 SENSOR DRIVER M: Petr Cvek <petrcvekcz@gmail.com> L: linux-media@vger.kernel.org @@ -17366,6 +17375,15 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c +SONY IMX335 SENSOR DRIVER +M: Paul J. Murphy <paul.j.murphy@intel.com> +M: Daniele Alessandrelli <daniele.alessandrelli@intel.com> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml +F: drivers/media/i2c/imx335.c + SONY IMX355 SENSOR DRIVER M: Tianshu Qiu <tian.shu.qiu@intel.com> L: linux-media@vger.kernel.org @@ -17373,6 +17391,15 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/imx355.c +SONY IMX412 SENSOR DRIVER +M: Paul J. Murphy <paul.j.murphy@intel.com> +M: Daniele Alessandrelli <daniele.alessandrelli@intel.com> +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml +F: drivers/media/i2c/imx412.c + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky <maximlevitsky@gmail.com> M: Alex Dubov <oakad@yahoo.com> diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index f423db8855d9..fb101f15865c 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -209,8 +209,8 @@ struct cec_pin { u32 work_pin_events_dropped_cnt; ktime_t timer_ts; u32 timer_cnt; - u32 timer_100ms_overruns; - u32 timer_300ms_overruns; + u32 timer_100us_overruns; + u32 timer_300us_overruns; u32 timer_max_overrun; u32 timer_sum_overrun; diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index f006bd8eec63..8c613aa649c6 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -854,9 +854,9 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (delta > 100 && pin->state != CEC_ST_IDLE) { /* Keep track of timer overruns */ pin->timer_sum_overrun += delta; - pin->timer_100ms_overruns++; + pin->timer_100us_overruns++; if (delta > 300) - pin->timer_300ms_overruns++; + pin->timer_300us_overruns++; if (delta > pin->timer_max_overrun) pin->timer_max_overrun = delta; } @@ -1207,15 +1207,15 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "cec pin events dropped: %u\n", pin->work_pin_events_dropped_cnt); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); - if (pin->timer_100ms_overruns) { - seq_printf(file, "timer overruns > 100ms: %u of %u\n", - pin->timer_100ms_overruns, pin->timer_cnt); - seq_printf(file, "timer overruns > 300ms: %u of %u\n", - pin->timer_300ms_overruns, pin->timer_cnt); + if (pin->timer_100us_overruns) { + seq_printf(file, "timer overruns > 100us: %u of %u\n", + pin->timer_100us_overruns, pin->timer_cnt); + seq_printf(file, "timer overruns > 300us: %u of %u\n", + pin->timer_300us_overruns, pin->timer_cnt); seq_printf(file, "max timer overrun: %u usecs\n", pin->timer_max_overrun); seq_printf(file, "avg timer overrun: %u usecs\n", - pin->timer_sum_overrun / pin->timer_100ms_overruns); + pin->timer_sum_overrun / pin->timer_100us_overruns); } if (pin->rx_start_bit_low_too_short_cnt) seq_printf(file, @@ -1245,8 +1245,8 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt); pin->work_pin_events_dropped_cnt = 0; pin->timer_cnt = 0; - pin->timer_100ms_overruns = 0; - pin->timer_300ms_overruns = 0; + pin->timer_100us_overruns = 0; + pin->timer_300us_overruns = 0; pin->timer_max_overrun = 0; pin->timer_sum_overrun = 0; pin->rx_start_bit_low_too_short_cnt = 0; diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index ea4b1ebfca99..0ffd89712536 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -305,14 +305,16 @@ static int stm32_cec_probe(struct platform_device *pdev) cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec"); if (IS_ERR(cec->clk_hdmi_cec) && - PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) - return -EPROBE_DEFER; + PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_unprepare_cec_clk; + } if (!IS_ERR(cec->clk_hdmi_cec)) { ret = clk_prepare(cec->clk_hdmi_cec); if (ret) { dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n"); - return ret; + goto err_unprepare_cec_clk; } } @@ -324,19 +326,27 @@ static int stm32_cec_probe(struct platform_device *pdev) CEC_NAME, caps, CEC_MAX_LOG_ADDRS); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) - return ret; + goto err_unprepare_hdmi_cec_clk; ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; - } + if (ret) + goto err_delete_adapter; cec_hw_init(cec); platform_set_drvdata(pdev, cec); return 0; + +err_delete_adapter: + cec_delete_adapter(cec->adap); + +err_unprepare_hdmi_cec_clk: + clk_unprepare(cec->clk_hdmi_cec); + +err_unprepare_cec_clk: + clk_unprepare(cec->clk_cec); + return ret; } static int stm32_cec_remove(struct platform_device *pdev) diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 1ac0c70a5981..5e907395ca2e 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -366,7 +366,11 @@ static int tegra_cec_probe(struct platform_device *pdev) return -ENOENT; } - clk_prepare_enable(cec->clk); + ret = clk_prepare_enable(cec->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare clock for CEC\n"); + return ret; + } /* set context info. */ cec->dev = &pdev->dev; @@ -446,9 +450,7 @@ static int tegra_cec_resume(struct platform_device *pdev) dev_notice(&pdev->dev, "Resuming\n"); - clk_prepare_enable(cec->clk); - - return 0; + return clk_prepare_enable(cec->clk); } #endif diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 9fccc906d85a..ac6e47d81b9e 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -1172,7 +1172,6 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, "%s: Error attaching frontend %d\n", KBUILD_MODNAME, demod); goto error1; - break; case 1: /* new priv instance */ priv->i2c = i2c; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 082796534b0a..bb02354a48b8 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2107,32 +2107,55 @@ static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *an dib8000_write_word(state, 117 + mode, ana_fe[mode]); } -static const u16 lut_prbs_2k[14] = { - 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213 +static const u16 lut_prbs_2k[13] = { + 0x423, 0x009, 0x5C7, + 0x7A6, 0x3D8, 0x527, + 0x7FF, 0x79B, 0x3D6, + 0x3A2, 0x53B, 0x2F4, + 0x213 }; -static const u16 lut_prbs_4k[14] = { - 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E + +static const u16 lut_prbs_4k[13] = { + 0x208, 0x0C3, 0x7B9, + 0x423, 0x5C7, 0x3D8, + 0x7FF, 0x3D6, 0x53B, + 0x213, 0x029, 0x0D0, + 0x48E }; -static const u16 lut_prbs_8k[14] = { - 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684 + +static const u16 lut_prbs_8k[13] = { + 0x740, 0x069, 0x7DD, + 0x208, 0x7B9, 0x5C7, + 0x7FF, 0x53B, 0x029, + 0x48E, 0x4C4, 0x367, + 0x684 }; static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) { int sub_channel_prbs_group = 0; + int prbs_group; - sub_channel_prbs_group = (subchannel / 3) + 1; - dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); + sub_channel_prbs_group = subchannel / 3; + if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k)) + return 0; switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: - return lut_prbs_2k[sub_channel_prbs_group]; + prbs_group = lut_prbs_2k[sub_channel_prbs_group]; + break; case TRANSMISSION_MODE_4K: - return lut_prbs_4k[sub_channel_prbs_group]; + prbs_group = lut_prbs_4k[sub_channel_prbs_group]; + break; default: case TRANSMISSION_MODE_8K: - return lut_prbs_8k[sub_channel_prbs_group]; + prbs_group = lut_prbs_8k[sub_channel_prbs_group]; } + + dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", + sub_channel_prbs_group, subchannel, prbs_group); + + return prbs_group; } static void dib8000_set_13seg_channel(struct dib8000_state *state) @@ -2409,10 +2432,8 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq /* TSB or ISDBT ? apply it now */ if (c->isdbt_sb_mode) { dib8000_set_sb_channel(state); - if (c->isdbt_sb_subchannel < 14) - init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); - else - init_prbs = 0; + init_prbs = dib8000_get_init_prbs(state, + c->isdbt_sb_subchannel); } else { dib8000_set_13seg_channel(state); init_prbs = 0xfff; @@ -3004,6 +3025,7 @@ static int dib8000_tune(struct dvb_frontend *fe) unsigned long *timeout = &state->timeout; unsigned long now = jiffies; + u16 init_prbs; #ifdef DIB8000_AGC_FREEZE u16 agc1, agc2; #endif @@ -3302,8 +3324,10 @@ static int dib8000_tune(struct dvb_frontend *fe) break; case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ - if (state->subchannel <= 41) { - dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); + init_prbs = dib8000_get_init_prbs(state, state->subchannel); + + if (init_prbs) { + dib8000_set_subchannel_prbs(state, init_prbs); *tune_state = CT_DEMOD_STEP_9; } else { *tune_state = CT_DEMOD_STOP; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 588f8eb95984..08feb3e8c1bf 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -842,6 +842,20 @@ config VIDEO_IMX334 To compile this driver as a module, choose M here: the module will be called imx334. +config VIDEO_IMX335 + tristate "Sony IMX335 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX335 camera. + + To compile this driver as a module, choose M here: the + module will be called imx335. + config VIDEO_IMX355 tristate "Sony IMX355 sensor support" depends on I2C && VIDEO_V4L2 @@ -854,6 +868,20 @@ config VIDEO_IMX355 To compile this driver as a module, choose M here: the module will be called imx355. +config VIDEO_IMX412 + tristate "Sony IMX412 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX412 camera. + + To compile this driver as a module, choose M here: the + module will be called imx412. + config VIDEO_OV02A10 tristate "OmniVision OV02A10 sensor support" depends on VIDEO_V4L2 && I2C @@ -1103,6 +1131,20 @@ config VIDEO_OV8865 To compile this driver as a module, choose M here: the module will be called ov8865. +config VIDEO_OV9282 + tristate "OmniVision OV9282 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV9282 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called ov9282. + config VIDEO_OV9640 tristate "OmniVision OV9640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 1168fa6b84ed..83268f20aa3a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV8856) += ov8856.o obj-$(CONFIG_VIDEO_OV8865) += ov8865.o +obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o @@ -124,11 +125,12 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX290) += imx290.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX334) += imx334.o +obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o +obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_MAX9286) += max9286.o obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o - obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index fa5bc55bc944..d9a99fcfacb1 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -94,6 +94,7 @@ #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 #define ADV7180_REG_CTRL_2 0x001d #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 +#define ADV7180_VSYNC_FIELD_CTL_1_NEWAV 0x12 #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f @@ -205,6 +206,7 @@ struct adv7180_state { struct mutex mutex; /* mutual excl. when accessing chip */ int irq; struct gpio_desc *pwdn_gpio; + struct gpio_desc *rst_gpio; v4l2_std_id curr_norm; bool powered; bool streaming; @@ -216,6 +218,7 @@ struct adv7180_state { struct i2c_client *vpp_client; const struct adv7180_chip_info *chip_info; enum v4l2_field field; + bool force_bt656_4; }; #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ struct adv7180_state, \ @@ -484,6 +487,19 @@ static void adv7180_set_power_pin(struct adv7180_state *state, bool on) } } +static void adv7180_set_reset_pin(struct adv7180_state *state, bool on) +{ + if (!state->rst_gpio) + return; + + if (on) { + gpiod_set_value_cansleep(state->rst_gpio, 1); + } else { + gpiod_set_value_cansleep(state->rst_gpio, 0); + usleep_range(5000, 10000); + } +} + static int adv7180_set_power(struct adv7180_state *state, bool on) { u8 val; @@ -963,10 +979,26 @@ static int adv7182_init(struct adv7180_state *state) adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); } else { - if (state->chip_info->flags & ADV7180_FLAG_V2) - adv7180_write(state, - ADV7180_REG_EXTENDED_OUTPUT_CONTROL, - 0x17); + if (state->chip_info->flags & ADV7180_FLAG_V2) { + if (state->force_bt656_4) { + /* ITU-R BT.656-4 compatible */ + adv7180_write(state, + ADV7180_REG_EXTENDED_OUTPUT_CONTROL, + ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); + /* Manually set NEWAVMODE */ + adv7180_write(state, + ADV7180_REG_VSYNC_FIELD_CTL_1, + ADV7180_VSYNC_FIELD_CTL_1_NEWAV); + /* Manually set V bit end position in NTSC mode */ + adv7180_write(state, + ADV7180_REG_NTSC_V_BIT_END, + ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); + } else { + adv7180_write(state, + ADV7180_REG_EXTENDED_OUTPUT_CONTROL, + 0x17); + } + } else adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, @@ -1263,6 +1295,7 @@ static int init_device(struct adv7180_state *state) mutex_lock(&state->mutex); adv7180_set_power_pin(state, true); + adv7180_set_reset_pin(state, false); adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); usleep_range(5000, 10000); @@ -1314,6 +1347,7 @@ out_unlock: static int adv7180_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device_node *np = client->dev.of_node; struct adv7180_state *state; struct v4l2_subdev *sd; int ret; @@ -1338,6 +1372,17 @@ static int adv7180_probe(struct i2c_client *client, return ret; } + state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(state->rst_gpio)) { + ret = PTR_ERR(state->rst_gpio); + v4l_err(client, "request for reset pin failed: %d\n", ret); + return ret; + } + + if (of_property_read_bool(np, "adv,force-bt656-4")) + 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); @@ -1392,11 +1437,19 @@ static int adv7180_probe(struct i2c_client *client, if (ret) goto err_free_irq; - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr, client->adapter->name); + mutex_lock(&state->mutex); + ret = adv7180_read(state, ADV7180_REG_IDENT); + mutex_unlock(&state->mutex); + if (ret < 0) + goto err_v4l2_async_unregister; + + v4l_info(client, "chip id 0x%x found @ 0x%02x (%s)\n", + ret, client->addr, client->adapter->name); return 0; +err_v4l2_async_unregister: + v4l2_async_unregister_subdev(sd); err_free_irq: if (state->irq > 0) free_irq(client->irq, state); @@ -1428,6 +1481,7 @@ static int adv7180_remove(struct i2c_client *client) i2c_unregister_device(state->vpp_client); i2c_unregister_device(state->csi_client); + adv7180_set_reset_pin(state, true); adv7180_set_power_pin(state, false); mutex_destroy(&state->mutex); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index a9403a227c6b..5363f3bcafe3 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1943,6 +1943,51 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) return rval; } +static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) { + switch (sensor->hwcfg.csi_signalling_mode) { + case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: + if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) & + CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY)) + return -EACCES; + break; + case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: + if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) & + CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY)) + return -EACCES; + break; + default: + return -EACCES; + } + } + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; + + if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) { + rval = ccs_write(sensor, MANUAL_LP_CTRL, + CCS_MANUAL_LP_CTRL_ENABLE); + if (rval) + pm_runtime_put(&client->dev); + } + + return rval; +} + +static int ccs_post_streamoff(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + return pm_runtime_put(&client->dev); +} + static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -2673,8 +2718,7 @@ static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) */ static ssize_t -ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, - char *buf) +nvm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); struct i2c_client *client = v4l2_get_subdevdata(subdev); @@ -2704,11 +2748,10 @@ ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, */ return rval; } -static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL); +static DEVICE_ATTR_RO(nvm); static ssize_t -ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, - char *buf) +ident_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); struct ccs_sensor *sensor = to_ccs_sensor(subdev); @@ -2723,8 +2766,7 @@ ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, minfo->smia_manufacturer_id, minfo->model_id, minfo->revision_number) + 1; } - -static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); +static DEVICE_ATTR_RO(ident); /* ----------------------------------------------------------------------------- * V4L2 subdev core operations @@ -3058,6 +3100,8 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_video_ops ccs_video_ops = { .s_stream = ccs_set_stream, + .pre_streamon = ccs_pre_streamon, + .post_streamoff = ccs_post_streamoff, }; static const struct v4l2_subdev_pad_ops ccs_pad_ops = { diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index c7b91c0c03b5..873d614339bb 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1237,8 +1237,7 @@ out_poweroff: * sysfs attributes */ static ssize_t -et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, - char *buf) +priv_mem_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); @@ -1251,7 +1250,7 @@ et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, return ET8EK8_PRIV_MEM_SIZE; } -static DEVICE_ATTR(priv_mem, 0444, et8ek8_priv_mem_read, NULL); +static DEVICE_ATTR_RO(priv_mem); /* -------------------------------------------------------------------------- * V4L2 subdev core operations diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 7ab9e5f9f267..81cdf37216ca 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -23,7 +23,7 @@ #define IMX258_CHIP_ID 0x0258 /* V_TIMING internal */ -#define IMX258_VTS_30FPS 0x0c98 +#define IMX258_VTS_30FPS 0x0c50 #define IMX258_VTS_30FPS_2K 0x0638 #define IMX258_VTS_30FPS_VGA 0x034c #define IMX258_VTS_MAX 0xffff @@ -47,7 +47,7 @@ /* Analog gain control */ #define IMX258_REG_ANALOG_GAIN 0x0204 #define IMX258_ANA_GAIN_MIN 0 -#define IMX258_ANA_GAIN_MAX 0x1fff +#define IMX258_ANA_GAIN_MAX 480 #define IMX258_ANA_GAIN_STEP 1 #define IMX258_ANA_GAIN_DEFAULT 0x0 diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c new file mode 100644 index 000000000000..410d6b86feb5 --- /dev/null +++ b/drivers/media/i2c/imx335.c @@ -0,0 +1,1129 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sony imx335 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include <asm/unaligned.h> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +/* Streaming Mode */ +#define IMX335_REG_MODE_SELECT 0x3000 +#define IMX335_MODE_STANDBY 0x01 +#define IMX335_MODE_STREAMING 0x00 + +/* Lines per frame */ +#define IMX335_REG_LPFR 0x3030 + +/* Chip ID */ +#define IMX335_REG_ID 0x3912 +#define IMX335_ID 0x00 + +/* Exposure control */ +#define IMX335_REG_SHUTTER 0x3058 +#define IMX335_EXPOSURE_MIN 1 +#define IMX335_EXPOSURE_OFFSET 9 +#define IMX335_EXPOSURE_STEP 1 +#define IMX335_EXPOSURE_DEFAULT 0x0648 + +/* Analog gain control */ +#define IMX335_REG_AGAIN 0x30e8 +#define IMX335_AGAIN_MIN 0 +#define IMX335_AGAIN_MAX 240 +#define IMX335_AGAIN_STEP 1 +#define IMX335_AGAIN_DEFAULT 0 + +/* Group hold register */ +#define IMX335_REG_HOLD 0x3001 + +/* Input clock rate */ +#define IMX335_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define IMX335_LINK_FREQ 594000000 +#define IMX335_NUM_DATA_LANES 4 + +#define IMX335_REG_MIN 0x00 +#define IMX335_REG_MAX 0xfffff + +/** + * struct imx335_reg - imx335 sensor register + * @address: Register address + * @val: Register value + */ +struct imx335_reg { + u16 address; + u8 val; +}; + +/** + * struct imx335_reg_list - imx335 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct imx335_reg_list { + u32 num_of_regs; + const struct imx335_reg *regs; +}; + +/** + * struct imx335_mode - imx335 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct imx335_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct imx335_reg_list reg_list; +}; + +/** + * struct imx335 - imx335 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct imx335 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct imx335_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + IMX335_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct imx335_reg mode_2592x1940_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x00}, + {0x300c, 0x3b}, + {0x300d, 0x2a}, + {0x3018, 0x04}, + {0x302c, 0x3c}, + {0x302e, 0x20}, + {0x3056, 0x94}, + {0x3074, 0xc8}, + {0x3076, 0x28}, + {0x304c, 0x00}, + {0x314c, 0xc6}, + {0x315a, 0x02}, + {0x3168, 0xa0}, + {0x316a, 0x7e}, + {0x31a1, 0x00}, + {0x3288, 0x21}, + {0x328a, 0x02}, + {0x3414, 0x05}, + {0x3416, 0x18}, + {0x3648, 0x01}, + {0x364a, 0x04}, + {0x364c, 0x04}, + {0x3678, 0x01}, + {0x367c, 0x31}, + {0x367e, 0x31}, + {0x3706, 0x10}, + {0x3708, 0x03}, + {0x3714, 0x02}, + {0x3715, 0x02}, + {0x3716, 0x01}, + {0x3717, 0x03}, + {0x371c, 0x3d}, + {0x371d, 0x3f}, + {0x372c, 0x00}, + {0x372d, 0x00}, + {0x372e, 0x46}, + {0x372f, 0x00}, + {0x3730, 0x89}, + {0x3731, 0x00}, + {0x3732, 0x08}, + {0x3733, 0x01}, + {0x3734, 0xfe}, + {0x3735, 0x05}, + {0x3740, 0x02}, + {0x375d, 0x00}, + {0x375e, 0x00}, + {0x375f, 0x11}, + {0x3760, 0x01}, + {0x3768, 0x1b}, + {0x3769, 0x1b}, + {0x376a, 0x1b}, + {0x376b, 0x1b}, + {0x376c, 0x1a}, + {0x376d, 0x17}, + {0x376e, 0x0f}, + {0x3776, 0x00}, + {0x3777, 0x00}, + {0x3778, 0x46}, + {0x3779, 0x00}, + {0x377a, 0x89}, + {0x377b, 0x00}, + {0x377c, 0x08}, + {0x377d, 0x01}, + {0x377e, 0x23}, + {0x377f, 0x02}, + {0x3780, 0xd9}, + {0x3781, 0x03}, + {0x3782, 0xf5}, + {0x3783, 0x06}, + {0x3784, 0xa5}, + {0x3788, 0x0f}, + {0x378a, 0xd9}, + {0x378b, 0x03}, + {0x378c, 0xeb}, + {0x378d, 0x05}, + {0x378e, 0x87}, + {0x378f, 0x06}, + {0x3790, 0xf5}, + {0x3792, 0x43}, + {0x3794, 0x7a}, + {0x3796, 0xa1}, + {0x37b0, 0x36}, + {0x3a00, 0x01}, +}; + +/* Supported sensor mode configurations */ +static const struct imx335_mode supported_mode = { + .width = 2592, + .height = 1940, + .hblank = 342, + .vblank = 2560, + .vblank_min = 2560, + .vblank_max = 133060, + .pclk = 396000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), + .regs = mode_2592x1940_regs, + }, +}; + +/** + * to_imx335() - imx335 V4L2 sub-device to imx335 device. + * @subdev: pointer to imx335 V4L2 sub-device + * + * Return: pointer to imx335 device + */ +static inline struct imx335 *to_imx335(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct imx335, sd); +} + +/** + * imx335_read_reg() - Read registers. + * @imx335: pointer to imx335 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Big endian register addresses with little endian values. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_read_reg(struct imx335 *imx335, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_le32(data_buf); + + return 0; +} + +/** + * imx335_write_reg() - Write register + * @imx335: pointer to imx335 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Big endian register addresses with little endian values. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_write_reg(struct imx335 *imx335, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_le32(val, buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * imx335_write_regs() - Write a list of registers + * @imx335: pointer to imx335 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful. error code otherwise. + */ +static int imx335_write_regs(struct imx335 *imx335, + const struct imx335_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = imx335_write_reg(imx335, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * imx335_update_controls() - Update control ranges based on streaming mode + * @imx335: pointer to imx335 device + * @mode: pointer to imx335_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_update_controls(struct imx335 *imx335, + const struct imx335_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(imx335->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(imx335->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * imx335_update_exp_gain() - Set updated exposure and gain + * @imx335: pointer to imx335 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) +{ + u32 lpfr, shutter; + int ret; + + lpfr = imx335->vblank + imx335->cur_mode->height; + shutter = lpfr - exposure; + + dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", + exposure, gain, shutter, lpfr); + + ret = imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = imx335_write_reg(imx335, IMX335_REG_LPFR, 3, lpfr); + if (ret) + goto error_release_group_hold; + + ret = imx335_write_reg(imx335, IMX335_REG_SHUTTER, 3, shutter); + if (ret) + goto error_release_group_hold; + + ret = imx335_write_reg(imx335, IMX335_REG_AGAIN, 2, gain); + +error_release_group_hold: + imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 0); + + return ret; +} + +/** + * imx335_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx335 *imx335 = + container_of(ctrl->handler, struct imx335, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + imx335->vblank = imx335->vblank_ctrl->val; + + dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u", + imx335->vblank, + imx335->vblank + imx335->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl, + IMX335_EXPOSURE_MIN, + imx335->vblank + + imx335->cur_mode->height - + IMX335_EXPOSURE_OFFSET, + 1, IMX335_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(imx335->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = imx335->again_ctrl->val; + + dev_dbg(imx335->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = imx335_update_exp_gain(imx335, exposure, analog_gain); + + pm_runtime_put(imx335->dev); + + break; + default: + dev_err(imx335->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops imx335_ctrl_ops = { + .s_ctrl = imx335_set_ctrl, +}; + +/** + * imx335_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * imx335_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * imx335_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @imx335: pointer to imx335 device + * @mode: pointer to imx335_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void imx335_fill_pad_format(struct imx335 *imx335, + const struct imx335_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * imx335_get_pad_format() - Get subdevice pad format + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx335 *imx335 = to_imx335(sd); + + mutex_lock(&imx335->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + imx335_fill_pad_format(imx335, imx335->cur_mode, fmt); + } + + mutex_unlock(&imx335->mutex); + + return 0; +} + +/** + * imx335_set_pad_format() - Set subdevice pad format + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx335 *imx335 = to_imx335(sd); + const struct imx335_mode *mode; + int ret = 0; + + mutex_lock(&imx335->mutex); + + mode = &supported_mode; + imx335_fill_pad_format(imx335, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = imx335_update_controls(imx335, mode); + if (!ret) + imx335->cur_mode = mode; + } + + mutex_unlock(&imx335->mutex); + + return ret; +} + +/** + * imx335_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct imx335 *imx335 = to_imx335(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + imx335_fill_pad_format(imx335, &supported_mode, &fmt); + + return imx335_set_pad_format(sd, sd_state, &fmt); +} + +/** + * imx335_start_streaming() - Start sensor stream + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_start_streaming(struct imx335 *imx335) +{ + const struct imx335_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &imx335->cur_mode->reg_list; + ret = imx335_write_regs(imx335, reg_list->regs, + reg_list->num_of_regs); + if (ret) { + dev_err(imx335->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler); + if (ret) { + dev_err(imx335->dev, "fail to setup handler"); + return ret; + } + + /* Start streaming */ + ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, + 1, IMX335_MODE_STREAMING); + if (ret) { + dev_err(imx335->dev, "fail to start streaming"); + return ret; + } + + /* Initial regulator stabilization period */ + usleep_range(18000, 20000); + + return 0; +} + +/** + * imx335_stop_streaming() - Stop sensor stream + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_stop_streaming(struct imx335 *imx335) +{ + return imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, + 1, IMX335_MODE_STANDBY); +} + +/** + * imx335_set_stream() - Enable sensor streaming + * @sd: pointer to imx335 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx335 *imx335 = to_imx335(sd); + int ret; + + mutex_lock(&imx335->mutex); + + if (imx335->streaming == enable) { + mutex_unlock(&imx335->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(imx335->dev); + if (ret) + goto error_unlock; + + ret = imx335_start_streaming(imx335); + if (ret) + goto error_power_off; + } else { + imx335_stop_streaming(imx335); + pm_runtime_put(imx335->dev); + } + + imx335->streaming = enable; + + mutex_unlock(&imx335->mutex); + + return 0; + +error_power_off: + pm_runtime_put(imx335->dev); +error_unlock: + mutex_unlock(&imx335->mutex); + + return ret; +} + +/** + * imx335_detect() - Detect imx335 sensor + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int imx335_detect(struct imx335 *imx335) +{ + int ret; + u32 val; + + ret = imx335_read_reg(imx335, IMX335_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX335_ID) { + dev_err(imx335->dev, "chip id mismatch: %x!=%x", + IMX335_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * imx335_parse_hw_config() - Parse HW configuration and check if supported + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_parse_hw_config(struct imx335 *imx335) +{ + struct fwnode_handle *fwnode = dev_fwnode(imx335->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + imx335->reset_gpio = devm_gpiod_get_optional(imx335->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(imx335->reset_gpio)) { + dev_err(imx335->dev, "failed to get reset gpio %ld", + PTR_ERR(imx335->reset_gpio)); + return PTR_ERR(imx335->reset_gpio); + } + + /* Get sensor input clock */ + imx335->inclk = devm_clk_get(imx335->dev, NULL); + if (IS_ERR(imx335->inclk)) { + dev_err(imx335->dev, "could not get inclk"); + return PTR_ERR(imx335->inclk); + } + + rate = clk_get_rate(imx335->inclk); + if (rate != IMX335_INCLK_RATE) { + dev_err(imx335->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) { + dev_err(imx335->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(imx335->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == IMX335_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops imx335_video_ops = { + .s_stream = imx335_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx335_pad_ops = { + .init_cfg = imx335_init_pad_cfg, + .enum_mbus_code = imx335_enum_mbus_code, + .enum_frame_size = imx335_enum_frame_size, + .get_fmt = imx335_get_pad_format, + .set_fmt = imx335_set_pad_format, +}; + +static const struct v4l2_subdev_ops imx335_subdev_ops = { + .video = &imx335_video_ops, + .pad = &imx335_pad_ops, +}; + +/** + * imx335_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx335 *imx335 = to_imx335(sd); + int ret; + + gpiod_set_value_cansleep(imx335->reset_gpio, 1); + + ret = clk_prepare_enable(imx335->inclk); + if (ret) { + dev_err(imx335->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(20, 22); + + return 0; + +error_reset: + gpiod_set_value_cansleep(imx335->reset_gpio, 0); + + return ret; +} + +/** + * imx335_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx335 *imx335 = to_imx335(sd); + + gpiod_set_value_cansleep(imx335->reset_gpio, 0); + + clk_disable_unprepare(imx335->inclk); + + return 0; +} + +/** + * imx335_init_controls() - Initialize sensor subdevice controls + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_init_controls(struct imx335 *imx335) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler; + const struct imx335_mode *mode = imx335->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &imx335->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + imx335->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX335_EXPOSURE_MIN, + lpfr - IMX335_EXPOSURE_OFFSET, + IMX335_EXPOSURE_STEP, + IMX335_EXPOSURE_DEFAULT); + + imx335->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + IMX335_AGAIN_MIN, + IMX335_AGAIN_MAX, + IMX335_AGAIN_STEP, + IMX335_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &imx335->exp_ctrl); + + imx335->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + imx335->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + imx335->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (imx335->link_freq_ctrl) + imx335->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx335->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_HBLANK, + IMX335_REG_MIN, + IMX335_REG_MAX, + 1, mode->hblank); + if (imx335->hblank_ctrl) + imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(imx335->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + imx335->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * imx335_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_probe(struct i2c_client *client) +{ + struct imx335 *imx335; + int ret; + + imx335 = devm_kzalloc(&client->dev, sizeof(*imx335), GFP_KERNEL); + if (!imx335) + return -ENOMEM; + + imx335->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops); + + ret = imx335_parse_hw_config(imx335); + if (ret) { + dev_err(imx335->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&imx335->mutex); + + ret = imx335_power_on(imx335->dev); + if (ret) { + dev_err(imx335->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = imx335_detect(imx335); + if (ret) { + dev_err(imx335->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + imx335->cur_mode = &supported_mode; + imx335->vblank = imx335->cur_mode->vblank; + + ret = imx335_init_controls(imx335); + if (ret) { + dev_err(imx335->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + imx335->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx335->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx335->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx335->sd.entity, 1, &imx335->pad); + if (ret) { + dev_err(imx335->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&imx335->sd); + if (ret < 0) { + dev_err(imx335->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(imx335->dev); + pm_runtime_enable(imx335->dev); + pm_runtime_idle(imx335->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx335->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(imx335->sd.ctrl_handler); +error_power_off: + imx335_power_off(imx335->dev); +error_mutex_destroy: + mutex_destroy(&imx335->mutex); + + return ret; +} + +/** + * imx335_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx335 *imx335 = to_imx335(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx335_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx335->mutex); + + return 0; +} + +static const struct dev_pm_ops imx335_pm_ops = { + SET_RUNTIME_PM_OPS(imx335_power_off, imx335_power_on, NULL) +}; + +static const struct of_device_id imx335_of_match[] = { + { .compatible = "sony,imx335" }, + { } +}; + +MODULE_DEVICE_TABLE(of, imx335_of_match); + +static struct i2c_driver imx335_driver = { + .probe_new = imx335_probe, + .remove = imx335_remove, + .driver = { + .name = "imx335", + .pm = &imx335_pm_ops, + .of_match_table = imx335_of_match, + }, +}; + +module_i2c_driver(imx335_driver); + +MODULE_DESCRIPTION("Sony imx335 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c new file mode 100644 index 000000000000..be3f6ea55559 --- /dev/null +++ b/drivers/media/i2c/imx412.c @@ -0,0 +1,1272 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sony imx412 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include <asm/unaligned.h> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +/* Streaming Mode */ +#define IMX412_REG_MODE_SELECT 0x0100 +#define IMX412_MODE_STANDBY 0x00 +#define IMX412_MODE_STREAMING 0x01 + +/* Lines per frame */ +#define IMX412_REG_LPFR 0x0340 + +/* Chip ID */ +#define IMX412_REG_ID 0x0016 +#define IMX412_ID 0x577 + +/* Exposure control */ +#define IMX412_REG_EXPOSURE_CIT 0x0202 +#define IMX412_EXPOSURE_MIN 8 +#define IMX412_EXPOSURE_OFFSET 22 +#define IMX412_EXPOSURE_STEP 1 +#define IMX412_EXPOSURE_DEFAULT 0x0648 + +/* Analog gain control */ +#define IMX412_REG_AGAIN 0x0204 +#define IMX412_AGAIN_MIN 0 +#define IMX412_AGAIN_MAX 978 +#define IMX412_AGAIN_STEP 1 +#define IMX412_AGAIN_DEFAULT 0 + +/* Group hold register */ +#define IMX412_REG_HOLD 0x0104 + +/* Input clock rate */ +#define IMX412_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define IMX412_LINK_FREQ 600000000 +#define IMX412_NUM_DATA_LANES 4 + +#define IMX412_REG_MIN 0x00 +#define IMX412_REG_MAX 0xffff + +/** + * struct imx412_reg - imx412 sensor register + * @address: Register address + * @val: Register value + */ +struct imx412_reg { + u16 address; + u8 val; +}; + +/** + * struct imx412_reg_list - imx412 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct imx412_reg_list { + u32 num_of_regs; + const struct imx412_reg *regs; +}; + +/** + * struct imx412_mode - imx412 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct imx412_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct imx412_reg_list reg_list; +}; + +/** + * struct imx412 - imx412 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct imx412 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct imx412_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + IMX412_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct imx412_reg mode_4056x3040_regs[] = { + {0x0136, 0x18}, + {0x0137, 0x00}, + {0x3c7e, 0x08}, + {0x3c7f, 0x02}, + {0x38a8, 0x1f}, + {0x38a9, 0xff}, + {0x38aa, 0x1f}, + {0x38ab, 0xff}, + {0x55d4, 0x00}, + {0x55d5, 0x00}, + {0x55d6, 0x07}, + {0x55d7, 0xff}, + {0x55e8, 0x07}, + {0x55e9, 0xff}, + {0x55ea, 0x00}, + {0x55eb, 0x00}, + {0x575c, 0x07}, + {0x575d, 0xff}, + {0x575e, 0x00}, + {0x575f, 0x00}, + {0x5764, 0x00}, + {0x5765, 0x00}, + {0x5766, 0x07}, + {0x5767, 0xff}, + {0x5974, 0x04}, + {0x5975, 0x01}, + {0x5f10, 0x09}, + {0x5f11, 0x92}, + {0x5f12, 0x32}, + {0x5f13, 0x72}, + {0x5f14, 0x16}, + {0x5f15, 0xba}, + {0x5f17, 0x13}, + {0x5f18, 0x24}, + {0x5f19, 0x60}, + {0x5f1a, 0xe3}, + {0x5f1b, 0xad}, + {0x5f1c, 0x74}, + {0x5f2d, 0x25}, + {0x5f5c, 0xd0}, + {0x6a22, 0x00}, + {0x6a23, 0x1d}, + {0x7ba8, 0x00}, + {0x7ba9, 0x00}, + {0x886b, 0x00}, + {0x9002, 0x0a}, + {0x9004, 0x1a}, + {0x9214, 0x93}, + {0x9215, 0x69}, + {0x9216, 0x93}, + {0x9217, 0x6b}, + {0x9218, 0x93}, + {0x9219, 0x6d}, + {0x921a, 0x57}, + {0x921b, 0x58}, + {0x921c, 0x57}, + {0x921d, 0x59}, + {0x921e, 0x57}, + {0x921f, 0x5a}, + {0x9220, 0x57}, + {0x9221, 0x5b}, + {0x9222, 0x93}, + {0x9223, 0x02}, + {0x9224, 0x93}, + {0x9225, 0x03}, + {0x9226, 0x93}, + {0x9227, 0x04}, + {0x9228, 0x93}, + {0x9229, 0x05}, + {0x922a, 0x98}, + {0x922b, 0x21}, + {0x922c, 0xb2}, + {0x922d, 0xdb}, + {0x922e, 0xb2}, + {0x922f, 0xdc}, + {0x9230, 0xb2}, + {0x9231, 0xdd}, + {0x9232, 0xe2}, + {0x9233, 0xe1}, + {0x9234, 0xb2}, + {0x9235, 0xe2}, + {0x9236, 0xb2}, + {0x9237, 0xe3}, + {0x9238, 0xb7}, + {0x9239, 0xb9}, + {0x923a, 0xb7}, + {0x923b, 0xbb}, + {0x923c, 0xb7}, + {0x923d, 0xbc}, + {0x923e, 0xb7}, + {0x923f, 0xc5}, + {0x9240, 0xb7}, + {0x9241, 0xc7}, + {0x9242, 0xb7}, + {0x9243, 0xc9}, + {0x9244, 0x98}, + {0x9245, 0x56}, + {0x9246, 0x98}, + {0x9247, 0x55}, + {0x9380, 0x00}, + {0x9381, 0x62}, + {0x9382, 0x00}, + {0x9383, 0x56}, + {0x9384, 0x00}, + {0x9385, 0x52}, + {0x9388, 0x00}, + {0x9389, 0x55}, + {0x938a, 0x00}, + {0x938b, 0x55}, + {0x938c, 0x00}, + {0x938d, 0x41}, + {0x5078, 0x01}, + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x03}, + {0x0342, 0x11}, + {0x0343, 0xa0}, + {0x0340, 0x0d}, + {0x0341, 0xda}, + {0x3210, 0x00}, + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0346, 0x00}, + {0x0347, 0x00}, + {0x0348, 0x0f}, + {0x0349, 0xd7}, + {0x034a, 0x0b}, + {0x034b, 0xdf}, + {0x00e3, 0x00}, + {0x00e4, 0x00}, + {0x00e5, 0x01}, + {0x00fc, 0x0a}, + {0x00fd, 0x0a}, + {0x00fe, 0x0a}, + {0x00ff, 0x0a}, + {0xe013, 0x00}, + {0x0220, 0x00}, + {0x0221, 0x11}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x00}, + {0x0901, 0x11}, + {0x0902, 0x00}, + {0x3140, 0x02}, + {0x3241, 0x11}, + {0x3250, 0x03}, + {0x3e10, 0x00}, + {0x3e11, 0x00}, + {0x3f0d, 0x00}, + {0x3f42, 0x00}, + {0x3f43, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x0408, 0x00}, + {0x0409, 0x00}, + {0x040a, 0x00}, + {0x040b, 0x00}, + {0x040c, 0x0f}, + {0x040d, 0xd8}, + {0x040e, 0x0b}, + {0x040f, 0xe0}, + {0x034c, 0x0f}, + {0x034d, 0xd8}, + {0x034e, 0x0b}, + {0x034f, 0xe0}, + {0x0301, 0x05}, + {0x0303, 0x02}, + {0x0305, 0x04}, + {0x0306, 0x00}, + {0x0307, 0xc8}, + {0x0309, 0x0a}, + {0x030b, 0x01}, + {0x030d, 0x02}, + {0x030e, 0x01}, + {0x030f, 0x5e}, + {0x0310, 0x00}, + {0x0820, 0x12}, + {0x0821, 0xc0}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, + {0x3e37, 0x00}, + {0x3f50, 0x00}, + {0x3f56, 0x00}, + {0x3f57, 0xe2}, + {0x3c0a, 0x5a}, + {0x3c0b, 0x55}, + {0x3c0c, 0x28}, + {0x3c0d, 0x07}, + {0x3c0e, 0xff}, + {0x3c0f, 0x00}, + {0x3c10, 0x00}, + {0x3c11, 0x02}, + {0x3c12, 0x00}, + {0x3c13, 0x03}, + {0x3c14, 0x00}, + {0x3c15, 0x00}, + {0x3c16, 0x0c}, + {0x3c17, 0x0c}, + {0x3c18, 0x0c}, + {0x3c19, 0x0a}, + {0x3c1a, 0x0a}, + {0x3c1b, 0x0a}, + {0x3c1c, 0x00}, + {0x3c1d, 0x00}, + {0x3c1e, 0x00}, + {0x3c1f, 0x00}, + {0x3c20, 0x00}, + {0x3c21, 0x00}, + {0x3c22, 0x3f}, + {0x3c23, 0x0a}, + {0x3e35, 0x01}, + {0x3f4a, 0x03}, + {0x3f4b, 0xbf}, + {0x3f26, 0x00}, + {0x0202, 0x0d}, + {0x0203, 0xc4}, + {0x0204, 0x00}, + {0x0205, 0x00}, + {0x020e, 0x01}, + {0x020f, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + {0xbcf1, 0x00}, +}; + +/* Supported sensor mode configurations */ +static const struct imx412_mode supported_mode = { + .width = 4056, + .height = 3040, + .hblank = 456, + .vblank = 506, + .vblank_min = 506, + .vblank_max = 32420, + .pclk = 480000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), + .regs = mode_4056x3040_regs, + }, +}; + +/** + * to_imx412() - imx412 V4L2 sub-device to imx412 device. + * @subdev: pointer to imx412 V4L2 sub-device + * + * Return: pointer to imx412 device + */ +static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct imx412, sd); +} + +/** + * imx412_read_reg() - Read registers. + * @imx412: pointer to imx412 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_read_reg(struct imx412 *imx412, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/** + * imx412_write_reg() - Write register + * @imx412: pointer to imx412 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_write_reg(struct imx412 *imx412, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * imx412_write_regs() - Write a list of registers + * @imx412: pointer to imx412 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_write_regs(struct imx412 *imx412, + const struct imx412_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = imx412_write_reg(imx412, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * imx412_update_controls() - Update control ranges based on streaming mode + * @imx412: pointer to imx412 device + * @mode: pointer to imx412_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_update_controls(struct imx412 *imx412, + const struct imx412_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(imx412->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(imx412->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(imx412->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * imx412_update_exp_gain() - Set updated exposure and gain + * @imx412: pointer to imx412 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) +{ + u32 lpfr, shutter; + int ret; + + lpfr = imx412->vblank + imx412->cur_mode->height; + shutter = lpfr - exposure; + + dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", + exposure, gain, shutter, lpfr); + + ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr); + if (ret) + goto error_release_group_hold; + + ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter); + if (ret) + goto error_release_group_hold; + + ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain); + +error_release_group_hold: + imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0); + + return ret; +} + +/** + * imx412_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx412 *imx412 = + container_of(ctrl->handler, struct imx412, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + imx412->vblank = imx412->vblank_ctrl->val; + + dev_dbg(imx412->dev, "Received vblank %u, new lpfr %u", + imx412->vblank, + imx412->vblank + imx412->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(imx412->exp_ctrl, + IMX412_EXPOSURE_MIN, + imx412->vblank + + imx412->cur_mode->height - + IMX412_EXPOSURE_OFFSET, + 1, IMX412_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(imx412->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = imx412->again_ctrl->val; + + dev_dbg(imx412->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = imx412_update_exp_gain(imx412, exposure, analog_gain); + + pm_runtime_put(imx412->dev); + + break; + default: + dev_err(imx412->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops imx412_ctrl_ops = { + .s_ctrl = imx412_set_ctrl, +}; + +/** + * imx412_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * imx412_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * imx412_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @imx412: pointer to imx412 device + * @mode: pointer to imx412_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void imx412_fill_pad_format(struct imx412 *imx412, + const struct imx412_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * imx412_get_pad_format() - Get subdevice pad format + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx412 *imx412 = to_imx412(sd); + + mutex_lock(&imx412->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + imx412_fill_pad_format(imx412, imx412->cur_mode, fmt); + } + + mutex_unlock(&imx412->mutex); + + return 0; +} + +/** + * imx412_set_pad_format() - Set subdevice pad format + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx412 *imx412 = to_imx412(sd); + const struct imx412_mode *mode; + int ret = 0; + + mutex_lock(&imx412->mutex); + + mode = &supported_mode; + imx412_fill_pad_format(imx412, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = imx412_update_controls(imx412, mode); + if (!ret) + imx412->cur_mode = mode; + } + + mutex_unlock(&imx412->mutex); + + return ret; +} + +/** + * imx412_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct imx412 *imx412 = to_imx412(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + imx412_fill_pad_format(imx412, &supported_mode, &fmt); + + return imx412_set_pad_format(sd, sd_state, &fmt); +} + +/** + * imx412_start_streaming() - Start sensor stream + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_start_streaming(struct imx412 *imx412) +{ + const struct imx412_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &imx412->cur_mode->reg_list; + ret = imx412_write_regs(imx412, reg_list->regs, + reg_list->num_of_regs); + if (ret) { + dev_err(imx412->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(imx412->sd.ctrl_handler); + if (ret) { + dev_err(imx412->dev, "fail to setup handler"); + return ret; + } + + /* Delay is required before streaming*/ + usleep_range(7400, 8000); + + /* Start streaming */ + ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, + 1, IMX412_MODE_STREAMING); + if (ret) { + dev_err(imx412->dev, "fail to start streaming"); + return ret; + } + + return 0; +} + +/** + * imx412_stop_streaming() - Stop sensor stream + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_stop_streaming(struct imx412 *imx412) +{ + return imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, + 1, IMX412_MODE_STANDBY); +} + +/** + * imx412_set_stream() - Enable sensor streaming + * @sd: pointer to imx412 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx412 *imx412 = to_imx412(sd); + int ret; + + mutex_lock(&imx412->mutex); + + if (imx412->streaming == enable) { + mutex_unlock(&imx412->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(imx412->dev); + if (ret) + goto error_unlock; + + ret = imx412_start_streaming(imx412); + if (ret) + goto error_power_off; + } else { + imx412_stop_streaming(imx412); + pm_runtime_put(imx412->dev); + } + + imx412->streaming = enable; + + mutex_unlock(&imx412->mutex); + + return 0; + +error_power_off: + pm_runtime_put(imx412->dev); +error_unlock: + mutex_unlock(&imx412->mutex); + + return ret; +} + +/** + * imx412_detect() - Detect imx412 sensor + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int imx412_detect(struct imx412 *imx412) +{ + int ret; + u32 val; + + ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX412_ID) { + dev_err(imx412->dev, "chip id mismatch: %x!=%x", + IMX412_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * imx412_parse_hw_config() - Parse HW configuration and check if supported + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_parse_hw_config(struct imx412 *imx412) +{ + struct fwnode_handle *fwnode = dev_fwnode(imx412->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(imx412->reset_gpio)) { + dev_err(imx412->dev, "failed to get reset gpio %ld", + PTR_ERR(imx412->reset_gpio)); + return PTR_ERR(imx412->reset_gpio); + } + + /* Get sensor input clock */ + imx412->inclk = devm_clk_get(imx412->dev, NULL); + if (IS_ERR(imx412->inclk)) { + dev_err(imx412->dev, "could not get inclk"); + return PTR_ERR(imx412->inclk); + } + + rate = clk_get_rate(imx412->inclk); + if (rate != IMX412_INCLK_RATE) { + dev_err(imx412->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX412_NUM_DATA_LANES) { + dev_err(imx412->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(imx412->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == IMX412_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops imx412_video_ops = { + .s_stream = imx412_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx412_pad_ops = { + .init_cfg = imx412_init_pad_cfg, + .enum_mbus_code = imx412_enum_mbus_code, + .enum_frame_size = imx412_enum_frame_size, + .get_fmt = imx412_get_pad_format, + .set_fmt = imx412_set_pad_format, +}; + +static const struct v4l2_subdev_ops imx412_subdev_ops = { + .video = &imx412_video_ops, + .pad = &imx412_pad_ops, +}; + +/** + * imx412_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx412 *imx412 = to_imx412(sd); + int ret; + + gpiod_set_value_cansleep(imx412->reset_gpio, 1); + + ret = clk_prepare_enable(imx412->inclk); + if (ret) { + dev_err(imx412->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(1000, 1200); + + return 0; + +error_reset: + gpiod_set_value_cansleep(imx412->reset_gpio, 0); + + return ret; +} + +/** + * imx412_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx412 *imx412 = to_imx412(sd); + + gpiod_set_value_cansleep(imx412->reset_gpio, 0); + + clk_disable_unprepare(imx412->inclk); + + return 0; +} + +/** + * imx412_init_controls() - Initialize sensor subdevice controls + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_init_controls(struct imx412 *imx412) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &imx412->ctrl_handler; + const struct imx412_mode *mode = imx412->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &imx412->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + imx412->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX412_EXPOSURE_MIN, + lpfr - IMX412_EXPOSURE_OFFSET, + IMX412_EXPOSURE_STEP, + IMX412_EXPOSURE_DEFAULT); + + imx412->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + IMX412_AGAIN_MIN, + IMX412_AGAIN_MAX, + IMX412_AGAIN_STEP, + IMX412_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &imx412->exp_ctrl); + + imx412->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + imx412->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + imx412->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (imx412->link_freq_ctrl) + imx412->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx412->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_HBLANK, + IMX412_REG_MIN, + IMX412_REG_MAX, + 1, mode->hblank); + if (imx412->hblank_ctrl) + imx412->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(imx412->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + imx412->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * imx412_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_probe(struct i2c_client *client) +{ + struct imx412 *imx412; + int ret; + + imx412 = devm_kzalloc(&client->dev, sizeof(*imx412), GFP_KERNEL); + if (!imx412) + return -ENOMEM; + + imx412->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops); + + ret = imx412_parse_hw_config(imx412); + if (ret) { + dev_err(imx412->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&imx412->mutex); + + ret = imx412_power_on(imx412->dev); + if (ret) { + dev_err(imx412->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = imx412_detect(imx412); + if (ret) { + dev_err(imx412->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + imx412->cur_mode = &supported_mode; + imx412->vblank = imx412->cur_mode->vblank; + + ret = imx412_init_controls(imx412); + if (ret) { + dev_err(imx412->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + imx412->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx412->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx412->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx412->sd.entity, 1, &imx412->pad); + if (ret) { + dev_err(imx412->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&imx412->sd); + if (ret < 0) { + dev_err(imx412->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(imx412->dev); + pm_runtime_enable(imx412->dev); + pm_runtime_idle(imx412->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx412->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(imx412->sd.ctrl_handler); +error_power_off: + imx412_power_off(imx412->dev); +error_mutex_destroy: + mutex_destroy(&imx412->mutex); + + return ret; +} + +/** + * imx412_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx412 *imx412 = to_imx412(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx412_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx412->mutex); + + return 0; +} + +static const struct dev_pm_ops imx412_pm_ops = { + SET_RUNTIME_PM_OPS(imx412_power_off, imx412_power_on, NULL) +}; + +static const struct of_device_id imx412_of_match[] = { + { .compatible = "sony,imx412" }, + { } +}; + +MODULE_DEVICE_TABLE(of, imx412_of_match); + +static struct i2c_driver imx412_driver = { + .probe_new = imx412_probe, + .remove = imx412_remove, + .driver = { + .name = "imx412", + .pm = &imx412_pm_ops, + .of_match_table = imx412_of_match, + }, +}; + +module_i2c_driver(imx412_driver); + +MODULE_DESCRIPTION("Sony imx412 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 599369a3d192..934c9d65cb09 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -51,7 +51,7 @@ #define OV2740_REG_MWB_R_GAIN 0x500a #define OV2740_REG_MWB_G_GAIN 0x500c #define OV2740_REG_MWB_B_GAIN 0x500e -#define OV2740_DGTL_GAIN_MIN 0 +#define OV2740_DGTL_GAIN_MIN 1024 #define OV2740_DGTL_GAIN_MAX 4095 #define OV2740_DGTL_GAIN_STEP 1 #define OV2740_DGTL_GAIN_DEFAULT 1024 @@ -61,6 +61,12 @@ #define OV2740_TEST_PATTERN_ENABLE BIT(7) #define OV2740_TEST_PATTERN_BAR_SHIFT 2 +/* Group Access */ +#define OV2740_REG_GROUP_ACCESS 0x3208 +#define OV2740_GROUP_HOLD_START 0x0 +#define OV2740_GROUP_HOLD_END 0x10 +#define OV2740_GROUP_HOLD_LAUNCH 0xa0 + /* ISP CTRL00 */ #define OV2740_REG_ISP_CTRL00 0x5000 /* ISP CTRL01 */ @@ -438,6 +444,11 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain) { int ret = 0; + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_START); + if (ret) + return ret; + ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_R_GAIN, 2, d_gain); if (ret) return ret; @@ -446,7 +457,18 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain) if (ret) return ret; - return ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain); + ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain); + if (ret) + return ret; + + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_END); + if (ret) + return ret; + + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_LAUNCH); + return ret; } static int ov2740_test_pattern(struct ov2740 *ov2740, u32 pattern) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index f6e1e51e0375..ddbd71394db3 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -135,7 +135,9 @@ struct ov5640_pixfmt { static const struct ov5640_pixfmt ov5640_formats[] = { { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, @@ -2338,11 +2340,13 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, u8 fmt, mux; switch (format->code) { + case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422, UYVY */ fmt = 0x3f; mux = OV5640_FMT_MUX_YUV422; break; + case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: /* YUV422, YUYV */ fmt = 0x30; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 88e19f30d376..aa74744b91c7 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2304,25 +2304,26 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) clk_set_rate(ov8856->xvclk, xvclk_rate); xvclk_rate = clk_get_rate(ov8856->xvclk); + + ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov8856->reset_gpio)) + return PTR_ERR(ov8856->reset_gpio); + + for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) + ov8856->supplies[i].supply = ov8856_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(ov8856_supply_names), + ov8856->supplies); + if (ret) + return ret; } if (xvclk_rate != OV8856_XVCLK_19_2) dev_warn(dev, "external clock rate %u is unsupported", xvclk_rate); - ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ov8856->reset_gpio)) - return PTR_ERR(ov8856->reset_gpio); - - for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) - ov8856->supplies[i].supply = ov8856_supply_names[i]; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov8856_supply_names), - ov8856->supplies); - if (ret) - return ret; - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c new file mode 100644 index 000000000000..2e0b315801e5 --- /dev/null +++ b/drivers/media/i2c/ov9282.c @@ -0,0 +1,1137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OmniVision ov9282 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include <asm/unaligned.h> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +/* Streaming Mode */ +#define OV9282_REG_MODE_SELECT 0x0100 +#define OV9282_MODE_STANDBY 0x00 +#define OV9282_MODE_STREAMING 0x01 + +/* Lines per frame */ +#define OV9282_REG_LPFR 0x380e + +/* Chip ID */ +#define OV9282_REG_ID 0x300a +#define OV9282_ID 0x9281 + +/* Exposure control */ +#define OV9282_REG_EXPOSURE 0x3500 +#define OV9282_EXPOSURE_MIN 1 +#define OV9282_EXPOSURE_OFFSET 12 +#define OV9282_EXPOSURE_STEP 1 +#define OV9282_EXPOSURE_DEFAULT 0x0282 + +/* Analog gain control */ +#define OV9282_REG_AGAIN 0x3509 +#define OV9282_AGAIN_MIN 0x10 +#define OV9282_AGAIN_MAX 0xff +#define OV9282_AGAIN_STEP 1 +#define OV9282_AGAIN_DEFAULT 0x10 + +/* Group hold register */ +#define OV9282_REG_HOLD 0x3308 + +/* Input clock rate */ +#define OV9282_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define OV9282_LINK_FREQ 400000000 +#define OV9282_NUM_DATA_LANES 2 + +#define OV9282_REG_MIN 0x00 +#define OV9282_REG_MAX 0xfffff + +/** + * struct ov9282_reg - ov9282 sensor register + * @address: Register address + * @val: Register value + */ +struct ov9282_reg { + u16 address; + u8 val; +}; + +/** + * struct ov9282_reg_list - ov9282 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct ov9282_reg_list { + u32 num_of_regs; + const struct ov9282_reg *regs; +}; + +/** + * struct ov9282_mode - ov9282 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct ov9282_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct ov9282_reg_list reg_list; +}; + +/** + * struct ov9282 - ov9282 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct ov9282 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct ov9282_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + OV9282_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct ov9282_reg mode_1280x720_regs[] = { + {0x0302, 0x32}, + {0x030d, 0x50}, + {0x030e, 0x02}, + {0x3001, 0x00}, + {0x3004, 0x00}, + {0x3005, 0x00}, + {0x3006, 0x04}, + {0x3011, 0x0a}, + {0x3013, 0x18}, + {0x301c, 0xf0}, + {0x3022, 0x01}, + {0x3030, 0x10}, + {0x3039, 0x32}, + {0x303a, 0x00}, + {0x3500, 0x00}, + {0x3501, 0x5f}, + {0x3502, 0x1e}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x3610, 0x80}, + {0x3611, 0xa0}, + {0x3620, 0x6e}, + {0x3632, 0x56}, + {0x3633, 0x78}, + {0x3666, 0x00}, + {0x366f, 0x5a}, + {0x3680, 0x84}, + {0x3712, 0x80}, + {0x372d, 0x22}, + {0x3731, 0x80}, + {0x3732, 0x30}, + {0x3778, 0x00}, + {0x377d, 0x22}, + {0x3788, 0x02}, + {0x3789, 0xa4}, + {0x378a, 0x00}, + {0x378b, 0x4a}, + {0x3799, 0x20}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x05}, + {0x3805, 0x0f}, + {0x3806, 0x02}, + {0x3807, 0xdf}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x05}, + {0x380d, 0xfa}, + {0x380e, 0x06}, + {0x380f, 0xce}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3820, 0x3c}, + {0x3821, 0x84}, + {0x3881, 0x42}, + {0x38a8, 0x02}, + {0x38a9, 0x80}, + {0x38b1, 0x00}, + {0x38c4, 0x00}, + {0x38c5, 0xc0}, + {0x38c6, 0x04}, + {0x38c7, 0x80}, + {0x3920, 0xff}, + {0x4003, 0x40}, + {0x4008, 0x02}, + {0x4009, 0x05}, + {0x400c, 0x00}, + {0x400d, 0x03}, + {0x4010, 0x40}, + {0x4043, 0x40}, + {0x4307, 0x30}, + {0x4317, 0x00}, + {0x4501, 0x00}, + {0x4507, 0x00}, + {0x4509, 0x80}, + {0x450a, 0x08}, + {0x4601, 0x04}, + {0x470f, 0x00}, + {0x4f07, 0x00}, + {0x4800, 0x20}, + {0x5000, 0x9f}, + {0x5001, 0x00}, + {0x5e00, 0x00}, + {0x5d00, 0x07}, + {0x5d01, 0x00}, + {0x0101, 0x01}, + {0x1000, 0x03}, + {0x5a08, 0x84}, +}; + +/* Supported sensor mode configurations */ +static const struct ov9282_mode supported_mode = { + .width = 1280, + .height = 720, + .hblank = 250, + .vblank = 1022, + .vblank_min = 151, + .vblank_max = 51540, + .pclk = 160000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_Y10_1X10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), + .regs = mode_1280x720_regs, + }, +}; + +/** + * to_ov9282() - ov9282 V4L2 sub-device to ov9282 device. + * @subdev: pointer to ov9282 V4L2 sub-device + * + * Return: pointer to ov9282 device + */ +static inline struct ov9282 *to_ov9282(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct ov9282, sd); +} + +/** + * ov9282_read_reg() - Read registers. + * @ov9282: pointer to ov9282 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_read_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/** + * ov9282_write_reg() - Write register + * @ov9282: pointer to ov9282 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_write_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * ov9282_write_regs() - Write a list of registers + * @ov9282: pointer to ov9282 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_write_regs(struct ov9282 *ov9282, + const struct ov9282_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = ov9282_write_reg(ov9282, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * ov9282_update_controls() - Update control ranges based on streaming mode + * @ov9282: pointer to ov9282 device + * @mode: pointer to ov9282_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_update_controls(struct ov9282 *ov9282, + const struct ov9282_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(ov9282->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(ov9282->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(ov9282->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * ov9282_update_exp_gain() - Set updated exposure and gain + * @ov9282: pointer to ov9282 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain) +{ + u32 lpfr; + int ret; + + lpfr = ov9282->vblank + ov9282->cur_mode->height; + + dev_dbg(ov9282->dev, "Set exp %u, analog gain %u, lpfr %u", + exposure, gain, lpfr); + + ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr); + if (ret) + goto error_release_group_hold; + + ret = ov9282_write_reg(ov9282, OV9282_REG_EXPOSURE, 3, exposure << 4); + if (ret) + goto error_release_group_hold; + + ret = ov9282_write_reg(ov9282, OV9282_REG_AGAIN, 1, gain); + +error_release_group_hold: + ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 0); + + return ret; +} + +/** + * ov9282_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov9282 *ov9282 = + container_of(ctrl->handler, struct ov9282, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + ov9282->vblank = ov9282->vblank_ctrl->val; + + dev_dbg(ov9282->dev, "Received vblank %u, new lpfr %u", + ov9282->vblank, + ov9282->vblank + ov9282->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(ov9282->exp_ctrl, + OV9282_EXPOSURE_MIN, + ov9282->vblank + + ov9282->cur_mode->height - + OV9282_EXPOSURE_OFFSET, + 1, OV9282_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(ov9282->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = ov9282->again_ctrl->val; + + dev_dbg(ov9282->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = ov9282_update_exp_gain(ov9282, exposure, analog_gain); + + pm_runtime_put(ov9282->dev); + + break; + default: + dev_err(ov9282->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops ov9282_ctrl_ops = { + .s_ctrl = ov9282_set_ctrl, +}; + +/** + * ov9282_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * ov9282_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * ov9282_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @ov9282: pointer to ov9282 device + * @mode: pointer to ov9282_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void ov9282_fill_pad_format(struct ov9282 *ov9282, + const struct ov9282_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * ov9282_get_pad_format() - Get subdevice pad format + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + + mutex_lock(&ov9282->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + ov9282_fill_pad_format(ov9282, ov9282->cur_mode, fmt); + } + + mutex_unlock(&ov9282->mutex); + + return 0; +} + +/** + * ov9282_set_pad_format() - Set subdevice pad format + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + const struct ov9282_mode *mode; + int ret = 0; + + mutex_lock(&ov9282->mutex); + + mode = &supported_mode; + ov9282_fill_pad_format(ov9282, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = ov9282_update_controls(ov9282, mode); + if (!ret) + ov9282->cur_mode = mode; + } + + mutex_unlock(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + ov9282_fill_pad_format(ov9282, &supported_mode, &fmt); + + return ov9282_set_pad_format(sd, sd_state, &fmt); +} + +/** + * ov9282_start_streaming() - Start sensor stream + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_start_streaming(struct ov9282 *ov9282) +{ + const struct ov9282_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &ov9282->cur_mode->reg_list; + ret = ov9282_write_regs(ov9282, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(ov9282->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(ov9282->sd.ctrl_handler); + if (ret) { + dev_err(ov9282->dev, "fail to setup handler"); + return ret; + } + + /* Start streaming */ + ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, + 1, OV9282_MODE_STREAMING); + if (ret) { + dev_err(ov9282->dev, "fail to start streaming"); + return ret; + } + + return 0; +} + +/** + * ov9282_stop_streaming() - Stop sensor stream + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_stop_streaming(struct ov9282 *ov9282) +{ + return ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, + 1, OV9282_MODE_STANDBY); +} + +/** + * ov9282_set_stream() - Enable sensor streaming + * @sd: pointer to ov9282 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + int ret; + + mutex_lock(&ov9282->mutex); + + if (ov9282->streaming == enable) { + mutex_unlock(&ov9282->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ov9282->dev); + if (ret) + goto error_unlock; + + ret = ov9282_start_streaming(ov9282); + if (ret) + goto error_power_off; + } else { + ov9282_stop_streaming(ov9282); + pm_runtime_put(ov9282->dev); + } + + ov9282->streaming = enable; + + mutex_unlock(&ov9282->mutex); + + return 0; + +error_power_off: + pm_runtime_put(ov9282->dev); +error_unlock: + mutex_unlock(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_detect() - Detect ov9282 sensor + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int ov9282_detect(struct ov9282 *ov9282) +{ + int ret; + u32 val; + + ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != OV9282_ID) { + dev_err(ov9282->dev, "chip id mismatch: %x!=%x", + OV9282_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * ov9282_parse_hw_config() - Parse HW configuration and check if supported + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_parse_hw_config(struct ov9282 *ov9282) +{ + struct fwnode_handle *fwnode = dev_fwnode(ov9282->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + ov9282->reset_gpio = devm_gpiod_get_optional(ov9282->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov9282->reset_gpio)) { + dev_err(ov9282->dev, "failed to get reset gpio %ld", + PTR_ERR(ov9282->reset_gpio)); + return PTR_ERR(ov9282->reset_gpio); + } + + /* Get sensor input clock */ + ov9282->inclk = devm_clk_get(ov9282->dev, NULL); + if (IS_ERR(ov9282->inclk)) { + dev_err(ov9282->dev, "could not get inclk"); + return PTR_ERR(ov9282->inclk); + } + + rate = clk_get_rate(ov9282->inclk); + if (rate != OV9282_INCLK_RATE) { + dev_err(ov9282->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV9282_NUM_DATA_LANES) { + dev_err(ov9282->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(ov9282->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == OV9282_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops ov9282_video_ops = { + .s_stream = ov9282_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov9282_pad_ops = { + .init_cfg = ov9282_init_pad_cfg, + .enum_mbus_code = ov9282_enum_mbus_code, + .enum_frame_size = ov9282_enum_frame_size, + .get_fmt = ov9282_get_pad_format, + .set_fmt = ov9282_set_pad_format, +}; + +static const struct v4l2_subdev_ops ov9282_subdev_ops = { + .video = &ov9282_video_ops, + .pad = &ov9282_pad_ops, +}; + +/** + * ov9282_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov9282 *ov9282 = to_ov9282(sd); + int ret; + + usleep_range(400, 600); + + gpiod_set_value_cansleep(ov9282->reset_gpio, 1); + + ret = clk_prepare_enable(ov9282->inclk); + if (ret) { + dev_err(ov9282->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(400, 600); + + return 0; + +error_reset: + gpiod_set_value_cansleep(ov9282->reset_gpio, 0); + + return ret; +} + +/** + * ov9282_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov9282 *ov9282 = to_ov9282(sd); + + gpiod_set_value_cansleep(ov9282->reset_gpio, 0); + + clk_disable_unprepare(ov9282->inclk); + + return 0; +} + +/** + * ov9282_init_controls() - Initialize sensor subdevice controls + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_init_controls(struct ov9282 *ov9282) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &ov9282->ctrl_handler; + const struct ov9282_mode *mode = ov9282->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &ov9282->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + ov9282->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_EXPOSURE, + OV9282_EXPOSURE_MIN, + lpfr - OV9282_EXPOSURE_OFFSET, + OV9282_EXPOSURE_STEP, + OV9282_EXPOSURE_DEFAULT); + + ov9282->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + OV9282_AGAIN_MIN, + OV9282_AGAIN_MAX, + OV9282_AGAIN_STEP, + OV9282_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &ov9282->exp_ctrl); + + ov9282->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + ov9282->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + ov9282->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (ov9282->link_freq_ctrl) + ov9282->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov9282->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_HBLANK, + OV9282_REG_MIN, + OV9282_REG_MAX, + 1, mode->hblank); + if (ov9282->hblank_ctrl) + ov9282->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(ov9282->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + ov9282->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * ov9282_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_probe(struct i2c_client *client) +{ + struct ov9282 *ov9282; + int ret; + + ov9282 = devm_kzalloc(&client->dev, sizeof(*ov9282), GFP_KERNEL); + if (!ov9282) + return -ENOMEM; + + ov9282->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops); + + ret = ov9282_parse_hw_config(ov9282); + if (ret) { + dev_err(ov9282->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&ov9282->mutex); + + ret = ov9282_power_on(ov9282->dev); + if (ret) { + dev_err(ov9282->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = ov9282_detect(ov9282); + if (ret) { + dev_err(ov9282->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + ov9282->cur_mode = &supported_mode; + ov9282->vblank = ov9282->cur_mode->vblank; + + ret = ov9282_init_controls(ov9282); + if (ret) { + dev_err(ov9282->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov9282->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + ov9282->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov9282->sd.entity, 1, &ov9282->pad); + if (ret) { + dev_err(ov9282->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&ov9282->sd); + if (ret < 0) { + dev_err(ov9282->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(ov9282->dev); + pm_runtime_enable(ov9282->dev); + pm_runtime_idle(ov9282->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&ov9282->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(ov9282->sd.ctrl_handler); +error_power_off: + ov9282_power_off(ov9282->dev); +error_mutex_destroy: + mutex_destroy(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9282 *ov9282 = to_ov9282(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov9282_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&ov9282->mutex); + + return 0; +} + +static const struct dev_pm_ops ov9282_pm_ops = { + SET_RUNTIME_PM_OPS(ov9282_power_off, ov9282_power_on, NULL) +}; + +static const struct of_device_id ov9282_of_match[] = { + { .compatible = "ovti,ov9282" }, + { } +}; + +MODULE_DEVICE_TABLE(of, ov9282_of_match); + +static struct i2c_driver ov9282_driver = { + .probe_new = ov9282_probe, + .remove = ov9282_remove, + .driver = { + .name = "ov9282", + .pm = &ov9282_pm_ops, + .of_match_table = ov9282_of_match, + }, +}; + +module_i2c_driver(ov9282_driver); + +MODULE_DESCRIPTION("OmniVision ov9282 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index af50c66cf5ce..df538ceb71c3 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -60,6 +60,12 @@ #define OV9734_TEST_PATTERN_ENABLE BIT(7) #define OV9734_TEST_PATTERN_BAR_SHIFT 2 +/* Group Access */ +#define OV9734_REG_GROUP_ACCESS 0x3208 +#define OV9734_GROUP_HOLD_START 0x0 +#define OV9734_GROUP_HOLD_END 0x10 +#define OV9734_GROUP_HOLD_LAUNCH 0xa0 + enum { OV9734_LINK_FREQ_180MHZ_INDEX, }; @@ -433,6 +439,11 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain) { int ret; + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_START); + if (ret) + return ret; + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_R_GAIN, 2, d_gain); if (ret) return ret; @@ -441,7 +452,18 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain) if (ret) return ret; - return ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain); + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_END); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_LAUNCH); + return ret; } static int ov9734_test_pattern(struct ov9734 *ov9734, u32 pattern) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 91e6db847bb5..6070aaf0b32e 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -563,7 +563,7 @@ static void tda1997x_delayed_work_enable_hpd(struct work_struct *work) delayed_work_enable_hpd); struct v4l2_subdev *sd = &state->sd; - v4l2_dbg(2, debug, sd, "%s:\n", __func__); + v4l2_dbg(2, debug, sd, "%s\n", __func__); /* Set HPD high */ tda1997x_manual_hpd(sd, HPD_HIGH_OTHER); @@ -1107,7 +1107,8 @@ tda1997x_detect_std(struct tda1997x_state *state, hper = io_read16(sd, REG_H_PER) & MASK_HPER; hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper); - if (!vper || !hper || !hsper) + + if (!state->input_detect[0] && !state->input_detect[1]) return -ENOLINK; for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { @@ -1695,14 +1696,15 @@ static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { struct tda1997x_state *state = to_state(sd); + int ret; v4l_dbg(1, debug, state->client, "%s\n", __func__); memset(timings, 0, sizeof(struct v4l2_dv_timings)); mutex_lock(&state->lock); - tda1997x_detect_std(state, timings); + ret = tda1997x_detect_std(state, timings); mutex_unlock(&state->lock); - return 0; + return ret; } static const struct v4l2_subdev_video_ops tda1997x_video_ops = { @@ -2233,6 +2235,7 @@ static int tda1997x_core_init(struct v4l2_subdev *sd) /* get initial HDMI status */ state->hdmi_status = io_read(sd, REG_HDMI_FLAGS); + io_write(sd, REG_EDID_ENABLE, EDID_ENABLE_A_EN | EDID_ENABLE_B_EN); return 0; } diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 30c63552556d..4b16ffcaef98 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -964,7 +964,7 @@ static int tvp5150_enable(struct v4l2_subdev *sd) /* * Enable the YCbCr and clock outputs. In discrete sync mode - * (non-BT.656) additionally enable the the sync outputs. + * (non-BT.656) additionally enable the sync outputs. */ switch (decoder->mbus_type) { case V4L2_MBUS_PARALLEL: diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 9e56d2ad6b94..cf5e459b1d96 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -556,7 +556,7 @@ static const struct media_file_operations media_device_fops = { * sysfs */ -static ssize_t show_model(struct device *cd, +static ssize_t model_show(struct device *cd, struct device_attribute *attr, char *buf) { struct media_devnode *devnode = to_media_devnode(cd); @@ -565,7 +565,7 @@ static ssize_t show_model(struct device *cd, return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); } -static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR_RO(model); /* ----------------------------------------------------------------------------- * Registration/unregistration diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h index f3e2c5634962..c252733df340 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.h +++ b/drivers/media/pci/ivtv/ivtv-cards.h @@ -78,27 +78,53 @@ #define IVTV_PCI_ID_SONY 0x104d /* hardware flags, no gaps allowed */ -#define IVTV_HW_CX25840 (1 << 0) -#define IVTV_HW_SAA7115 (1 << 1) -#define IVTV_HW_SAA7127 (1 << 2) -#define IVTV_HW_MSP34XX (1 << 3) -#define IVTV_HW_TUNER (1 << 4) -#define IVTV_HW_WM8775 (1 << 5) -#define IVTV_HW_CS53L32A (1 << 6) -#define IVTV_HW_TVEEPROM (1 << 7) -#define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_UPD64031A (1 << 9) -#define IVTV_HW_UPD6408X (1 << 10) -#define IVTV_HW_SAA717X (1 << 11) -#define IVTV_HW_WM8739 (1 << 12) -#define IVTV_HW_VP27SMPX (1 << 13) -#define IVTV_HW_M52790 (1 << 14) -#define IVTV_HW_GPIO (1 << 15) -#define IVTV_HW_I2C_IR_RX_AVER (1 << 16) -#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17) /* External before internal */ -#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18) -#define IVTV_HW_Z8F0811_IR_HAUP (1 << 19) -#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 20) +enum ivtv_hw_bits { + IVTV_HW_BIT_CX25840, + IVTV_HW_BIT_SAA7115, + IVTV_HW_BIT_SAA7127, + IVTV_HW_BIT_MSP34XX, + IVTV_HW_BIT_TUNER, + IVTV_HW_BIT_WM8775, + IVTV_HW_BIT_CS53L32A, + IVTV_HW_BIT_TVEEPROM, + IVTV_HW_BIT_SAA7114, + IVTV_HW_BIT_UPD64031A, + IVTV_HW_BIT_UPD6408X, + IVTV_HW_BIT_SAA717X, + IVTV_HW_BIT_WM8739, + IVTV_HW_BIT_VP27SMPX, + IVTV_HW_BIT_M52790, + IVTV_HW_BIT_GPIO, + IVTV_HW_BIT_I2C_IR_RX_AVER, + IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT, /* External before internal */ + IVTV_HW_BIT_I2C_IR_RX_HAUP_INT, + IVTV_HW_BIT_Z8F0811_IR_HAUP, + IVTV_HW_BIT_I2C_IR_RX_ADAPTEC, + + IVTV_HW_MAX_BITS /* Should be the last one */ +}; + +#define IVTV_HW_CX25840 BIT(IVTV_HW_BIT_CX25840) +#define IVTV_HW_SAA7115 BIT(IVTV_HW_BIT_SAA7115) +#define IVTV_HW_SAA7127 BIT(IVTV_HW_BIT_SAA7127) +#define IVTV_HW_MSP34XX BIT(IVTV_HW_BIT_MSP34XX) +#define IVTV_HW_TUNER BIT(IVTV_HW_BIT_TUNER) +#define IVTV_HW_WM8775 BIT(IVTV_HW_BIT_WM8775) +#define IVTV_HW_CS53L32A BIT(IVTV_HW_BIT_CS53L32A) +#define IVTV_HW_TVEEPROM BIT(IVTV_HW_BIT_TVEEPROM) +#define IVTV_HW_SAA7114 BIT(IVTV_HW_BIT_SAA7114) +#define IVTV_HW_UPD64031A BIT(IVTV_HW_BIT_UPD64031A) +#define IVTV_HW_UPD6408X BIT(IVTV_HW_BIT_UPD6408X) +#define IVTV_HW_SAA717X BIT(IVTV_HW_BIT_SAA717X) +#define IVTV_HW_WM8739 BIT(IVTV_HW_BIT_WM8739) +#define IVTV_HW_VP27SMPX BIT(IVTV_HW_BIT_VP27SMPX) +#define IVTV_HW_M52790 BIT(IVTV_HW_BIT_M52790) +#define IVTV_HW_GPIO BIT(IVTV_HW_BIT_GPIO) +#define IVTV_HW_I2C_IR_RX_AVER BIT(IVTV_HW_BIT_I2C_IR_RX_AVER) +#define IVTV_HW_I2C_IR_RX_HAUP_EXT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT) +#define IVTV_HW_I2C_IR_RX_HAUP_INT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_INT) +#define IVTV_HW_Z8F0811_IR_HAUP BIT(IVTV_HW_BIT_Z8F0811_IR_HAUP) +#define IVTV_HW_I2C_IR_RX_ADAPTEC BIT(IVTV_HW_BIT_I2C_IR_RX_ADAPTEC) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index 982045c4eea8..c052c57c6dce 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -85,7 +85,7 @@ #define IVTV_ADAPTEC_IR_ADDR 0x6b /* This array should match the IVTV_HW_ defines */ -static const u8 hw_addrs[] = { +static const u8 hw_addrs[IVTV_HW_MAX_BITS] = { IVTV_CX25840_I2C_ADDR, IVTV_SAA7115_I2C_ADDR, IVTV_SAA7127_I2C_ADDR, @@ -110,7 +110,7 @@ static const u8 hw_addrs[] = { }; /* This array should match the IVTV_HW_ defines */ -static const char * const hw_devicenames[] = { +static const char * const hw_devicenames[IVTV_HW_MAX_BITS] = { "cx25840", "saa7115", "saa7127_auto", /* saa7127 or saa7129 */ @@ -240,10 +240,16 @@ void ivtv_i2c_new_ir_legacy(struct ivtv *itv) int ivtv_i2c_register(struct ivtv *itv, unsigned idx) { - struct v4l2_subdev *sd; struct i2c_adapter *adap = &itv->i2c_adap; - const char *type = hw_devicenames[idx]; - u32 hw = 1 << idx; + struct v4l2_subdev *sd; + const char *type; + u32 hw; + + if (idx >= IVTV_HW_MAX_BITS) + return -ENODEV; + + type = hw_devicenames[idx]; + hw = 1 << idx; if (hw == IVTV_HW_TUNER) { /* special tuner handling */ diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 7a1fb067b0e0..fb24d2ed3621 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1215,15 +1215,13 @@ static int alsa_device_exit(struct saa7134_dev *dev) static int saa7134_alsa_init(void) { struct saa7134_dev *dev = NULL; - struct list_head *list; saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; pr_info("saa7134 ALSA driver for DMA sound loaded\n"); - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) { if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 47158ab3956b..96328b0af164 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -223,7 +223,8 @@ int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) __le32 *cpu; dma_addr_t dma_addr = 0; - cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); + cpu = dma_alloc_coherent(&pci->dev, SAA7134_PGTABLE_SIZE, &dma_addr, + GFP_KERNEL); if (NULL == cpu) return -ENOMEM; pt->size = SAA7134_PGTABLE_SIZE; @@ -254,7 +255,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) { if (NULL == pt->cpu) return; - pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); + dma_free_coherent(&pci->dev, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; } @@ -1092,7 +1093,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name); goto err_v4l2_unregister; diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index 716162055fb7..a65d810ce212 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -549,9 +549,6 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, /* See of other commands are on the bus */ if (saa7164_cmd_dequeue(dev) != SAA_OK) printk(KERN_ERR "dequeue(3) failed\n"); - - continue; - } /* (loop) */ /* Release the sequence number allocation */ diff --git a/drivers/media/pci/tw5864/tw5864-reg.h b/drivers/media/pci/tw5864/tw5864-reg.h index a26a439c4dc0..25d4a9a6cc6b 100644 --- a/drivers/media/pci/tw5864/tw5864-reg.h +++ b/drivers/media/pci/tw5864/tw5864-reg.h @@ -663,7 +663,7 @@ #define TW5864_SYNC 0x8008 /* Define controls in register TW5864_SYNC */ /* - * 0 vlc stream to syncrous port + * 0 vlc stream to synchronous port * 1 vlc stream to ddr buffers */ #define TW5864_SYNC_CFG BIT(7) diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 925aa80a139b..b66f1d174e9d 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -255,6 +255,23 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc) struct regmap *regmap = isc->regmap; u32 rlp_mode = isc->config.rlp_cfg_mode; + /* + * In sama5d2, the YUV planar modes and the YUYV modes are treated + * in the same way in RLP register. + * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n) + * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n) + * but in sama5d2, the YCYC mode does not exist, and YYCC must be + * selected for both planar and interleaved modes, as in fact + * both modes are supported. + * + * Thus, if the YCYC mode is selected, replace it with the + * sama5d2-compliant mode which is YYCC . + */ + if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) { + rlp_mode &= ~ISC_RLP_CFG_MODE_MASK; + rlp_mode |= ISC_RLP_CFG_MODE_YYCC; + } + regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp, ISC_RLP_CFG_MODE_MASK, rlp_mode); } diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 2f42808c43a4..c484c008ab02 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2053,17 +2053,25 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 src_fourcc, dst_fourcc; int ret; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + if (!ctx->initialized) { ret = __coda_decoder_seq_init(ctx); if (ret < 0) return ret; + } else { + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); + if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | + ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); } - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - src_fourcc = q_data_src->fourcc; - dst_fourcc = q_data_dst->fourcc; - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index f9f7dd17c57c..0a2226b321d7 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -189,7 +189,7 @@ int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) if (!ccdc_cfg) { /* * TODO. Will this ever happen? if so, we need to fix it. - * Proabably we need to add the request to a linked list and + * Probably we need to add the request to a linked list and * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 3b8a24bb724c..fa648721eaab 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1238,8 +1238,8 @@ static const struct media_device_ops fimc_md_ops = { .link_notify = fimc_md_link_notify, }; -static ssize_t fimc_md_sysfs_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t subdev_conf_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fimc_md *fmd = dev_get_drvdata(dev); @@ -1249,9 +1249,9 @@ static ssize_t fimc_md_sysfs_show(struct device *dev, return strscpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); } -static ssize_t fimc_md_sysfs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t subdev_conf_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct fimc_md *fmd = dev_get_drvdata(dev); bool subdev_api; @@ -1278,8 +1278,7 @@ static ssize_t fimc_md_sysfs_store(struct device *dev, * sub-dev - for media controller API, subdevs must be configured in user * space before starting streaming. */ -static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, - fimc_md_sysfs_show, fimc_md_sysfs_store); +static DEVICE_ATTR_RW(subdev_conf_mode); static int cam_clk_prepare(struct clk_hw *hw) { diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 070a0f3fc337..58f9463f3b8c 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -692,7 +692,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) * Scatter/gather mode requires stopping the controller between * frames so we can put in a new DMA descriptor array. If no new * buffer exists at frame completion, the controller is left stopped; - * this function is charged with gettig things going again. + * this function is charged with getting things going again. */ static void mcam_sg_restart(struct mcam_camera *cam) { diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 53025c8c7531..20f59c59ff8a 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2037,8 +2037,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) mutex_lock(&isp->media_dev.graph_mutex); ret = media_entity_enum_init(&isp->crashed, &isp->media_dev); - if (ret) + if (ret) { + mutex_unlock(&isp->media_dev.graph_mutex); return ret; + } list_for_each_entry(sd, &v4l2_dev->subdevs, list) { if (sd->notifier != &isp->notifier) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 8df2d497d706..5ec851115eca 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -234,6 +234,7 @@ struct venc_controls { u32 h264_loop_filter_mode; s32 h264_loop_filter_alpha; s32 h264_loop_filter_beta; + u32 h264_8x8_transform; u32 hevc_i_qp; u32 hevc_p_qp; @@ -256,6 +257,7 @@ struct venc_controls { u32 header_mode; bool aud_enable; + u32 intra_refresh_period; struct { u32 h264; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 1fe6d463dc99..8012f5c7bf34 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1137,6 +1137,9 @@ int venus_helper_set_format_constraints(struct venus_inst *inst) if (!IS_V6(inst->core)) return 0; + if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC) + return 0; + pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; pconstraint.num_planes = 2; pconstraint.plane_format[0].stride_multiples = 128; diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index f51024786991..60f4b8e4b8d0 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1239,6 +1239,14 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, break; } + case HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8: { + struct hfi_h264_8x8_transform *in = pdata, *tm = prop_data; + + tm->enable_type = in->enable_type; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*tm); + break; + } + case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index b0a9beb4163c..bec4feb63ceb 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -507,6 +507,7 @@ #define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020 #define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC 0x2005021 #define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY 0x2005023 +#define HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8 0x2005025 #define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026 #define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP 0x2005027 #define HFI_PROPERTY_PARAM_VENC_INITIAL_QP 0x2005028 @@ -562,6 +563,10 @@ struct hfi_bitrate { u32 layer_id; }; +struct hfi_h264_8x8_transform { + u32 enable_type; +}; + #define HFI_CAPABILITY_FRAME_WIDTH 0x01 #define HFI_CAPABILITY_FRAME_HEIGHT 0x02 #define HFI_CAPABILITY_MBS_PER_FRAME 0x03 diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index d9fde66f6fa8..9a2bdb002edc 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -261,7 +261,7 @@ sys_get_prop_image_version(struct device *dev, smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMG_VER_TBL, &smem_blk_sz); - if (smem_tbl_ptr && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) + if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS, img_ver, VER_STR_SZ); } diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 8dd49d4f124c..bc1c42dd53c0 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -183,6 +183,8 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) else return NULL; fmt = find_format(inst, pixmp->pixelformat, f->type); + if (!fmt) + return NULL; } pixmp->width = clamp(pixmp->width, frame_width_min(inst), @@ -547,6 +549,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_quantization_range quant_range; struct hfi_enable en; struct hfi_ltr_mode ltr_mode; + struct hfi_intra_refresh intra_refresh = {}; u32 ptype, rate_control, bitrate; u32 profile, level; int ret; @@ -567,6 +570,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_h264_vui_timing_info info; struct hfi_h264_entropy_control entropy; struct hfi_h264_db_control deblock; + struct hfi_h264_8x8_transform h264_transform; ptype = HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO; info.enable = 1; @@ -597,6 +601,17 @@ static int venc_set_properties(struct venus_inst *inst) ret = hfi_session_set_property(inst, ptype, &deblock); if (ret) return ret; + + ptype = HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8; + h264_transform.enable_type = 0; + if (ctr->profile.h264 == HFI_H264_PROFILE_HIGH || + ctr->profile.h264 == HFI_H264_PROFILE_CONSTRAINED_HIGH) + h264_transform.enable_type = ctr->h264_8x8_transform; + + ret = hfi_session_set_property(inst, ptype, &h264_transform); + if (ret) + return ret; + } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || @@ -802,6 +817,31 @@ static int venc_set_properties(struct venus_inst *inst) en.enable = 1; ret = hfi_session_set_property(inst, ptype, &en); + } + + if ((inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || + inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) && + (rate_control == HFI_RATE_CONTROL_CBR_VFR || + rate_control == HFI_RATE_CONTROL_CBR_CFR)) { + intra_refresh.mode = HFI_INTRA_REFRESH_NONE; + intra_refresh.cir_mbs = 0; + + if (ctr->intra_refresh_period) { + u32 mbs; + + mbs = ALIGN(inst->width, 16) * ALIGN(inst->height, 16); + mbs /= 16 * 16; + if (mbs % ctr->intra_refresh_period) + mbs++; + mbs /= ctr->intra_refresh_period; + + intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; + intra_refresh.cir_mbs = mbs; + } + + ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; + + ret = hfi_session_set_property(inst, ptype, &intra_refresh); if (ret) return ret; } diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 637c92f6c5be..1ada42df314d 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -17,7 +17,6 @@ #define SLICE_BYTE_SIZE_MAX 1024 #define SLICE_BYTE_SIZE_MIN 1024 #define SLICE_MB_SIZE_MAX 300 -#define INTRA_REFRESH_MBS_MAX 300 #define AT_SLICE_BOUNDARY \ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY #define MAX_LTR_FRAME_COUNT 4 @@ -227,8 +226,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) } mutex_unlock(&inst->lock); break; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: - break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ret = venc_calc_bpframes(ctrl->val, ctr->num_b_frames, &bframes, &ctr->num_p_frames); @@ -319,6 +316,28 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: ctr->mastering = *ctrl->p_new.p_hdr10_mastering; break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: + ctr->intra_refresh_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + if (ctr->profile.h264 != HFI_H264_PROFILE_HIGH && + ctr->profile.h264 != HFI_H264_PROFILE_CONSTRAINED_HIGH) + return -EINVAL; + + /* + * In video firmware, 8x8 transform is supported only for + * high profile(HP) and constrained high profile(CHP). + * If client wants to disable 8x8 transform for HP/CHP, + * it is better to set profile as main profile(MP). + * Because there is no difference between HP and MP + * if we disable 8x8 transform for HP. + */ + + if (ctrl->val == 0) + return -EINVAL; + + ctr->h264_8x8_transform = ctrl->val; + break; default: return -EINVAL; } @@ -334,7 +353,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 57); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58); if (ret) return ret; @@ -438,6 +457,9 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP, 1, 51, 1, 1); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP, 1, 51, 1, 1); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, @@ -503,10 +525,6 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, - 0, INTRA_REFRESH_MBS_MAX, 1, 0); - - v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, @@ -564,6 +582,10 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, + ((4096 * 2304) >> 8), 1, 0); + ret = inst->ctrl_handler.error; if (ret) goto err; diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index cca15a10c0b3..0d141155f0e3 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -253,8 +253,8 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, int ret; sd_state = v4l2_subdev_alloc_state(sd); - if (sd_state == NULL) - return -ENOMEM; + if (IS_ERR(sd_state)) + return PTR_ERR(sd_state); if (!rvin_format_from_pixel(vin, pix->pixelformat)) pix->pixelformat = RVIN_DEFAULT_FORMAT; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index bf3fd71ec3af..6759091b15e0 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -863,12 +863,12 @@ static int rga_probe(struct platform_device *pdev) if (IS_ERR(rga->m2m_dev)) { v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(rga->m2m_dev); - goto unreg_video_dev; + goto rel_vdev; } ret = pm_runtime_resume_and_get(rga->dev); if (ret < 0) - goto unreg_video_dev; + goto rel_vdev; rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; @@ -882,11 +882,23 @@ static int rga_probe(struct platform_device *pdev) rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_phy, GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); + if (!rga->cmdbuf_virt) { + ret = -ENOMEM; + goto rel_vdev; + } rga->src_mmu_pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + if (!rga->src_mmu_pages) { + ret = -ENOMEM; + goto free_dma; + } rga->dst_mmu_pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + if (rga->dst_mmu_pages) { + ret = -ENOMEM; + goto free_src_pages; + } def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; def_frame.size = def_frame.stride * def_frame.height; @@ -894,7 +906,7 @@ static int rga_probe(struct platform_device *pdev) ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); - goto rel_vdev; + goto free_dst_pages; } v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n", @@ -902,10 +914,15 @@ static int rga_probe(struct platform_device *pdev) return 0; +free_dst_pages: + free_pages((unsigned long)rga->dst_mmu_pages, 3); +free_src_pages: + free_pages((unsigned long)rga->src_mmu_pages, 3); +free_dma: + dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, + rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); rel_vdev: video_device_release(vfd); -unreg_video_dev: - video_unregister_device(rga->vfd); unreg_v4l2_dev: v4l2_device_unregister(&rga->v4l2_dev); err_put_clk: diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 60cd2200e7ae..41988eb0ec0a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -750,7 +750,7 @@ static int rkisp1_vb2_queue_setup(struct vb2_queue *queue, return 0; } -static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +static int rkisp1_vb2_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct rkisp1_buffer *ispbuf = @@ -780,6 +780,15 @@ static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap) swap(ispbuf->buff_addr[RKISP1_PLANE_CR], ispbuf->buff_addr[RKISP1_PLANE_CB]); + return 0; +} + +static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *ispbuf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; spin_lock_irq(&cap->buf.lock); list_add_tail(&ispbuf->queue, &cap->buf.queue); @@ -1039,6 +1048,7 @@ err_ret_buffers: static const struct vb2_ops rkisp1_vb2_ops = { .queue_setup = rkisp1_vb2_queue_setup, + .buf_init = rkisp1_vb2_buf_init, .buf_queue = rkisp1_vb2_buf_queue, .buf_prepare = rkisp1_vb2_buf_prepare, .wait_prepare = vb2_ops_wait_prepare, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 038c303a8aed..bb73f4e17b66 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -156,15 +156,11 @@ struct rkisp1_vdev_node { * @vb: vb2 buffer * @queue: entry of the buffer in the queue * @buff_addr: dma addresses of each plane, used only by the capture devices: selfpath, mainpath - * @vaddr: virtual address for buffers used by params and stats devices */ struct rkisp1_buffer { struct vb2_v4l2_buffer vb; struct list_head queue; - union { - u32 buff_addr[VIDEO_MAX_PLANES]; - void *vaddr; - }; + u32 buff_addr[VIDEO_MAX_PLANES]; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 529c6e21815f..8fa5b0abf1f9 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1143,7 +1143,7 @@ static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, cur_buf = list_first_entry(¶ms->params, struct rkisp1_buffer, queue); - new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr); + new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); rkisp1_isp_isr_other_config(params, new_params); rkisp1_isp_isr_meas_config(params, new_params); @@ -1382,7 +1382,6 @@ static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) struct vb2_queue *vq = vb->vb2_queue; struct rkisp1_params *params = vq->drv_priv; - params_buf->vaddr = vb2_plane_vaddr(vb, 0); spin_lock_irq(¶ms->config_lock); list_add_tail(¶ms_buf->queue, ¶ms->params); spin_unlock_irq(¶ms->config_lock); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index c1d07a2e8839..e88bdd612d71 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -112,7 +112,6 @@ static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb) struct vb2_queue *vq = vb->vb2_queue; struct rkisp1_stats *stats_dev = vq->drv_priv; - stats_buf->vaddr = vb2_plane_vaddr(vb, 0); spin_lock_irq(&stats_dev->lock); list_add_tail(&stats_buf->queue, &stats_dev->stat); @@ -305,9 +304,8 @@ rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) if (!cur_buf) return; - cur_stat_buf = - (struct rkisp1_stat_buffer *)(cur_buf->vaddr); - + cur_stat_buf = (struct rkisp1_stat_buffer *) + vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) rkisp1_stats_get_awb_meas(stats, cur_stat_buf); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 49503c20d320..28a06dc343fd 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1418,7 +1418,7 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) if (test_and_clear_bit(0, &dev->hw_lock) == 0) mfc_err("Failed to unlock hardware\n"); - /* This is in deed imporant, as no operation has been + /* This is indeed important, as no operation has been * scheduled, reduce the clock count as no one will * ever do this, because no interrupt related to this try_run * will ever come from hardware. */ diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c index 186d88f02ecd..21d3e08e259a 100644 --- a/drivers/media/platform/sti/delta/delta-ipc.c +++ b/drivers/media/platform/sti/delta/delta-ipc.c @@ -175,8 +175,7 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name, msg.ipc_buf_size = ipc_buf_size; msg.ipc_buf_paddr = ctx->ipc_buf->paddr; - memcpy(msg.name, name, sizeof(msg.name)); - msg.name[sizeof(msg.name) - 1] = 0; + strscpy(msg.name, name, sizeof(msg.name)); msg.param_size = param->size; memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size); diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 124a4e2bdefe..4bf7a8c2e711 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -45,22 +45,30 @@ static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) * ------------------------------------------------------------------ */ -static s64 cal_camerarx_get_external_rate(struct cal_camerarx *phy) +static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) { - struct v4l2_ctrl *ctrl; - s64 rate; - - ctrl = v4l2_ctrl_find(phy->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE); - if (!ctrl) { - phy_err(phy, "no pixel rate control in subdev: %s\n", - phy->sensor->name); - return -EPIPE; + struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; + u32 num_lanes = mipi_csi2->num_data_lanes; + const struct cal_format_info *fmtinfo; + u32 bpp; + s64 freq; + + fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code); + if (!fmtinfo) + return -EINVAL; + + bpp = fmtinfo->bpp; + + freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes); + if (freq < 0) { + phy_err(phy, "failed to get link freq for subdev '%s'\n", + phy->source->name); + return freq; } - rate = v4l2_ctrl_g_ctrl_int64(ctrl); - phy_dbg(3, phy, "sensor Pixel Rate: %llu\n", rate); + phy_dbg(3, phy, "Source Link Freq: %llu\n", freq); - return rate; + return freq; } static void cal_camerarx_lane_config(struct cal_camerarx *phy) @@ -116,34 +124,19 @@ void cal_camerarx_disable(struct cal_camerarx *phy) #define TCLK_MISS 1 #define TCLK_SETTLE 14 -static void cal_camerarx_config(struct cal_camerarx *phy, s64 external_rate) +static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq) { unsigned int reg0, reg1; unsigned int ths_term, ths_settle; - unsigned int csi2_ddrclk_khz; - struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = - &phy->endpoint.bus.mipi_csi2; - u32 num_lanes = mipi_csi2->num_data_lanes; /* DPHY timing configuration */ - /* - * CSI-2 is DDR and we only count used lanes. - * - * csi2_ddrclk_khz = external_rate / 1000 - * / (2 * num_lanes) * phy->fmtinfo->bpp; - */ - csi2_ddrclk_khz = div_s64(external_rate * phy->fmtinfo->bpp, - 2 * num_lanes * 1000); - - phy_dbg(1, phy, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz); - /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ - ths_term = 20 * csi2_ddrclk_khz / 1000000; + ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000); phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term); /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ - ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4; + ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4; phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0); @@ -240,25 +233,42 @@ static void cal_camerarx_enable_irqs(struct cal_camerarx *phy) CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; - - /* Enable CIO error IRQs. */ + const u32 vc_err_mask = + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3); + + /* Enable CIO & VC error IRQs. */ cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), - CAL_HL_IRQ_CIO_MASK(phy->instance)); + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), cio_err_mask); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), + vc_err_mask); } static void cal_camerarx_disable_irqs(struct cal_camerarx *phy) { /* Disable CIO error irqs */ cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0), - CAL_HL_IRQ_CIO_MASK(phy->instance)); + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0); } static void cal_camerarx_ppi_enable(struct cal_camerarx *phy) { cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), + 1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK); + + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); } @@ -270,16 +280,21 @@ static void cal_camerarx_ppi_disable(struct cal_camerarx *phy) static int cal_camerarx_start(struct cal_camerarx *phy) { - s64 external_rate; + s64 link_freq; u32 sscounter; u32 val; int ret; - external_rate = cal_camerarx_get_external_rate(phy); - if (external_rate < 0) - return external_rate; + if (phy->enable_count > 0) { + phy->enable_count++; + return 0; + } + + link_freq = cal_camerarx_get_ext_link_freq(phy); + if (link_freq < 0) + return link_freq; - ret = v4l2_subdev_call(phy->sensor, core, s_power, 1); + ret = v4l2_subdev_call(phy->source, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { phy_err(phy, "power on failed in subdev\n"); return ret; @@ -311,7 +326,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) * 2. CSI PHY and link initialization sequence. * * a. Deassert the CSI-2 PHY reset. Do not wait for reset completion - * at this point, as it requires the external sensor to send the + * at this point, as it requires the external source to send the * CSI-2 HS clock. */ cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), @@ -325,7 +340,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) camerarx_read(phy, CAL_CSI2_PHY_REG0); /* Program the PHY timing parameters. */ - cal_camerarx_config(phy, external_rate); + cal_camerarx_config(phy, link_freq); /* * b. Assert the FORCERXMODE signal. @@ -370,12 +385,12 @@ static int cal_camerarx_start(struct cal_camerarx *phy) cal_camerarx_power(phy, true); /* - * Start the sensor to enable the CSI-2 HS clock. We can now wait for + * Start the source to enable the CSI-2 HS clock. We can now wait for * CSI-2 PHY reset to complete. */ - ret = v4l2_subdev_call(phy->sensor, video, s_stream, 1); + ret = v4l2_subdev_call(phy->source, video, s_stream, 1); if (ret) { - v4l2_subdev_call(phy->sensor, core, s_power, 0); + v4l2_subdev_call(phy->source, core, s_power, 0); cal_camerarx_disable_irqs(phy); phy_err(phy, "stream on failed in subdev\n"); return ret; @@ -399,14 +414,18 @@ static int cal_camerarx_start(struct cal_camerarx *phy) /* Finally, enable the PHY Protocol Interface (PPI). */ cal_camerarx_ppi_enable(phy); + phy->enable_count++; + return 0; } static void cal_camerarx_stop(struct cal_camerarx *phy) { - unsigned int i; int ret; + if (--phy->enable_count > 0) + return; + cal_camerarx_ppi_disable(phy); cal_camerarx_disable_irqs(phy); @@ -418,27 +437,17 @@ static void cal_camerarx_stop(struct cal_camerarx *phy) CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); - /* Wait for power down completion */ - for (i = 0; i < 10; i++) { - if (cal_read_field(phy->cal, - CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING) - break; - usleep_range(1000, 1100); - } - phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n", + phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n", phy->instance, - cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)), i, - (i >= 10) ? "(timeout)" : ""); + cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); /* Disable the phy */ cal_camerarx_disable(phy); - if (v4l2_subdev_call(phy->sensor, video, s_stream, 0)) + if (v4l2_subdev_call(phy->source, video, s_stream, 0)) phy_err(phy, "stream off failed in subdev\n"); - ret = v4l2_subdev_call(phy->sensor, core, s_power, 0); + ret = v4l2_subdev_call(phy->source, core, s_power, 0); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) phy_err(phy, "power off failed in subdev\n"); } @@ -558,16 +567,16 @@ static int cal_camerarx_parse_dt(struct cal_camerarx *phy) endpoint->bus.mipi_csi2.flags); /* Retrieve the connected device and store it for later use. */ - phy->sensor_ep_node = of_graph_get_remote_endpoint(ep_node); - phy->sensor_node = of_graph_get_port_parent(phy->sensor_ep_node); - if (!phy->sensor_node) { + phy->source_ep_node = of_graph_get_remote_endpoint(ep_node); + phy->source_node = of_graph_get_port_parent(phy->source_ep_node); + if (!phy->source_node) { phy_dbg(3, phy, "Can't get remote parent\n"); - of_node_put(phy->sensor_ep_node); + of_node_put(phy->source_ep_node); ret = -EINVAL; goto done; } - phy_dbg(1, phy, "Found connected device %pOFn\n", phy->sensor_node); + phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node); done: of_node_put(ep_node); @@ -602,12 +611,18 @@ cal_camerarx_get_pad_format(struct cal_camerarx *phy, static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable) { struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); if (enable) - return cal_camerarx_start(phy); + ret = cal_camerarx_start(phy); + else + cal_camerarx_stop(phy); - cal_camerarx_stop(phy); - return 0; + mutex_unlock(&phy->mutex); + + return ret; } static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, @@ -615,27 +630,36 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_mbus_code_enum *code) { struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); /* No transcoding, source and sink codes must match. */ - if (code->pad == CAL_CAMERARX_PAD_SOURCE) { + if (cal_rx_pad_is_source(code->pad)) { struct v4l2_mbus_framefmt *fmt; - if (code->index > 0) - return -EINVAL; + if (code->index > 0) { + ret = -EINVAL; + goto out; + } fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, code->which); code->code = fmt->code; - return 0; - } + } else { + if (code->index >= cal_num_formats) { + ret = -EINVAL; + goto out; + } - if (code->index >= cal_num_formats) - return -EINVAL; + code->code = cal_formats[code->index].code; + } - code->code = cal_formats[code->index].code; +out: + mutex_unlock(&phy->mutex); - return 0; + return ret; } static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, @@ -644,38 +668,46 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, { struct cal_camerarx *phy = to_cal_camerarx(sd); const struct cal_format_info *fmtinfo; + int ret = 0; if (fse->index > 0) return -EINVAL; + mutex_lock(&phy->mutex); + /* No transcoding, source and sink formats must match. */ - if (fse->pad == CAL_CAMERARX_PAD_SOURCE) { + if (cal_rx_pad_is_source(fse->pad)) { struct v4l2_mbus_framefmt *fmt; fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, fse->which); - if (fse->code != fmt->code) - return -EINVAL; + if (fse->code != fmt->code) { + ret = -EINVAL; + goto out; + } fse->min_width = fmt->width; fse->max_width = fmt->width; fse->min_height = fmt->height; fse->max_height = fmt->height; + } else { + fmtinfo = cal_format_by_code(fse->code); + if (!fmtinfo) { + ret = -EINVAL; + goto out; + } - return 0; + fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->min_height = CAL_MIN_HEIGHT_LINES; + fse->max_height = CAL_MAX_HEIGHT_LINES; } - fmtinfo = cal_format_by_code(fse->code); - if (!fmtinfo) - return -EINVAL; - - fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->min_height = CAL_MIN_HEIGHT_LINES; - fse->max_height = CAL_MAX_HEIGHT_LINES; +out: + mutex_unlock(&phy->mutex); - return 0; + return ret; } static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, @@ -685,10 +717,14 @@ static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, struct cal_camerarx *phy = to_cal_camerarx(sd); struct v4l2_mbus_framefmt *fmt; + mutex_lock(&phy->mutex); + fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad, format->which); format->format = *fmt; + mutex_unlock(&phy->mutex); + return 0; } @@ -702,21 +738,18 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, unsigned int bpp; /* No transcoding, source and sink formats must match. */ - if (format->pad == CAL_CAMERARX_PAD_SOURCE) + if (cal_rx_pad_is_source(format->pad)) return cal_camerarx_sd_get_fmt(sd, sd_state, format); /* - * Default to the first format is the requested media bus code isn't + * Default to the first format if the requested media bus code isn't * supported. */ fmtinfo = cal_format_by_code(format->format.code); if (!fmtinfo) fmtinfo = &cal_formats[0]; - /* - * Clamp the size, update the code. The field and colorspace are - * accepted as-is. - */ + /* Clamp the size, update the code. The colorspace is accepted as-is. */ bpp = ALIGN(fmtinfo->bpp, 8); format->format.width = clamp_t(unsigned int, format->format.width, @@ -726,20 +759,23 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES); format->format.code = fmtinfo->code; + format->format.field = V4L2_FIELD_NONE; /* Store the format and propagate it to the source pad. */ + + mutex_lock(&phy->mutex); + fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, format->which); *fmt = format->format; fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_SOURCE, + CAL_CAMERARX_PAD_FIRST_SOURCE, format->which); *fmt = format->format; - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - phy->fmtinfo = fmtinfo; + mutex_unlock(&phy->mutex); return 0; } @@ -798,6 +834,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, struct platform_device *pdev = to_platform_device(cal->dev); struct cal_camerarx *phy; struct v4l2_subdev *sd; + unsigned int i; int ret; phy = kzalloc(sizeof(*phy), GFP_KERNEL); @@ -807,6 +844,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, phy->cal = cal; phy->instance = instance; + mutex_init(&phy->mutex); + phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, (instance == 0) ? "cal_rx_core0" : @@ -838,14 +877,17 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, sd->dev = cal->dev; phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - phy->pads[CAL_CAMERARX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i) + phy->pads[i].flags = MEDIA_PAD_FL_SOURCE; sd->entity.ops = &cal_camerarx_media_ops; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads), phy->pads); if (ret) goto error; - cal_camerarx_sd_init_cfg(sd, NULL); + ret = cal_camerarx_sd_init_cfg(sd, NULL); + if (ret) + goto error; ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd); if (ret) @@ -866,7 +908,8 @@ void cal_camerarx_destroy(struct cal_camerarx *phy) v4l2_device_unregister_subdev(&phy->subdev); media_entity_cleanup(&phy->subdev.entity); - of_node_put(phy->sensor_ep_node); - of_node_put(phy->sensor_node); + of_node_put(phy->source_ep_node); + of_node_put(phy->source_node); + mutex_destroy(&phy->mutex); kfree(phy); } diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 15fb5360cf13..7799da1cc261 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -102,8 +102,8 @@ static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx, return NULL; } -static int cal_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -128,7 +128,7 @@ static int __subdev_get_format(struct cal_ctx *ctx, sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; sd_fmt.pad = 0; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt); + ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; @@ -151,7 +151,7 @@ static int __subdev_set_format(struct cal_ctx *ctx, sd_fmt.pad = 0; *mbus_fmt = *fmt; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt); + ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt); if (ret) return ret; @@ -189,8 +189,8 @@ static void cal_calc_format_size(struct cal_ctx *ctx, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); } -static int cal_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -216,7 +216,7 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv, fse.code = fmtinfo->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; for (fse.index = 0; ; fse.index++) { - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, &fse); if (ret) break; @@ -249,8 +249,8 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int cal_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct cal_ctx *ctx = video_drvdata(file); struct vb2_queue *q = &ctx->vb_vidq; @@ -266,7 +266,7 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv, return -EBUSY; } - ret = cal_try_fmt_vid_cap(file, priv, f); + ret = cal_legacy_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; @@ -300,8 +300,8 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int cal_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) +static int cal_legacy_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -321,7 +321,7 @@ static int cal_enum_framesizes(struct file *file, void *fh, fse.code = fmtinfo->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, &fse); if (ret) return ret; @@ -337,8 +337,8 @@ static int cal_enum_framesizes(struct file *file, void *fh, return 0; } -static int cal_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) +static int cal_legacy_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) { if (inp->index > 0) return -EINVAL; @@ -348,20 +348,20 @@ static int cal_enum_input(struct file *file, void *priv, return 0; } -static int cal_g_input(struct file *file, void *priv, unsigned int *i) +static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int cal_s_input(struct file *file, void *priv, unsigned int i) +static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i) { return i > 0 ? -EINVAL : 0; } /* timeperframe is arbitrary and continuous */ -static int cal_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) +static int cal_legacy_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -378,7 +378,7 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return -EINVAL; fie.code = fmtinfo->code; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; @@ -388,13 +388,27 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return 0; } -static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { +static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a); +} + +static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a); +} + +static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = { .vidioc_querycap = cal_querycap, - .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = cal_legacy_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap, - .vidioc_enum_framesizes = cal_enum_framesizes, + .vidioc_try_fmt_vid_cap = cal_legacy_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cal_legacy_s_fmt_vid_cap, + .vidioc_enum_framesizes = cal_legacy_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, @@ -402,15 +416,17 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_enum_input = cal_enum_input, - .vidioc_g_input = cal_g_input, - .vidioc_s_input = cal_s_input, - .vidioc_enum_frameintervals = cal_enum_frameintervals, + .vidioc_enum_input = cal_legacy_enum_input, + .vidioc_g_input = cal_legacy_g_input, + .vidioc_s_input = cal_legacy_s_input, + .vidioc_enum_frameintervals = cal_legacy_enum_frameintervals, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_parm = cal_legacy_g_parm, + .vidioc_s_parm = cal_legacy_s_parm, }; /* ------------------------------------------------------------------ @@ -421,13 +437,28 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + unsigned int i; + unsigned int idx; + if (f->index >= cal_num_formats) return -EINVAL; - f->pixelformat = cal_formats[f->index].fourcc; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + idx = 0; - return 0; + for (i = 0; i < cal_num_formats; ++i) { + if (f->mbus_code && cal_formats[i].code != f->mbus_code) + continue; + + if (idx == f->index) { + f->pixelformat = cal_formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + + idx++; + } + + return -EINVAL; } static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f, @@ -656,8 +687,13 @@ static void cal_release_buffers(struct cal_ctx *ctx, static int cal_video_check_format(struct cal_ctx *ctx) { const struct v4l2_mbus_framefmt *format; + struct media_pad *remote_pad; + + remote_pad = media_entity_remote_pad(&ctx->pad); + if (!remote_pad) + return -ENODEV; - format = &ctx->phy->formats[CAL_CAMERARX_PAD_SOURCE]; + format = &ctx->phy->formats[remote_pad->index]; if (ctx->fmtinfo->code != format->code || ctx->v_fmt.fmt.pix.height != format->height || @@ -692,9 +728,15 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) goto error_pipeline; } + ret = cal_ctx_prepare(ctx); + if (ret) { + ctx_err(ctx, "Failed to prepare context: %d\n", ret); + goto error_pipeline; + } + spin_lock_irq(&ctx->dma.lock); buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); - ctx->dma.pending = buf; + ctx->dma.active = buf; list_del(&buf->list); spin_unlock_irq(&ctx->dma.lock); @@ -719,6 +761,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) error_stop: cal_ctx_stop(ctx); pm_runtime_put_sync(ctx->cal->dev); + cal_ctx_unprepare(ctx); error_pipeline: media_pipeline_stop(&ctx->vdev.entity); @@ -738,6 +781,8 @@ static void cal_stop_streaming(struct vb2_queue *vq) pm_runtime_put_sync(ctx->cal->dev); + cal_ctx_unprepare(ctx); + cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); media_pipeline_stop(&ctx->vdev.entity); @@ -785,20 +830,20 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) memset(&mbus_code, 0, sizeof(mbus_code)); mbus_code.index = j; mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code, NULL, &mbus_code); if (ret == -EINVAL) break; if (ret) { ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n", - ctx->phy->sensor->name, ret); + ctx->phy->source->name, ret); return ret; } ctx_dbg(2, ctx, "subdev %s: code: %04x idx: %u\n", - ctx->phy->sensor->name, mbus_code.code, j); + ctx->phy->source->name, mbus_code.code, j); for (k = 0; k < cal_num_formats; k++) { fmtinfo = &cal_formats[k]; @@ -816,7 +861,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) if (i == 0) { ctx_err(ctx, "No suitable format reported by subdev %s\n", - ctx->phy->sensor->name); + ctx->phy->source->name); return -EINVAL; } @@ -841,22 +886,57 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) return 0; } +static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx) +{ + const struct cal_format_info *fmtinfo; + struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; + + fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8); + if (!fmtinfo) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_fmt->pixelformat = fmtinfo->fourcc; + + ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* Save current format */ + cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); + ctx->fmtinfo = fmtinfo; + + return 0; +} + int cal_ctx_v4l2_register(struct cal_ctx *ctx) { struct video_device *vfd = &ctx->vdev; int ret; - ret = cal_ctx_v4l2_init_formats(ctx); - if (ret) - return ret; - if (!cal_mc_api) { struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; - ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, + ret = cal_ctx_v4l2_init_formats(ctx); + if (ret) { + ctx_err(ctx, "Failed to init formats: %d\n", ret); + return ret; + } + + ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler, NULL, true); if (ret < 0) { - ctx_err(ctx, "Failed to add sensor ctrl handler\n"); + ctx_err(ctx, "Failed to add source ctrl handler\n"); + return ret; + } + } else { + ret = cal_ctx_v4l2_init_mc_format(ctx); + if (ret) { + ctx_err(ctx, "Failed to init format: %d\n", ret); return ret; } } @@ -868,13 +948,13 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx) } ret = media_create_pad_link(&ctx->phy->subdev.entity, - CAL_CAMERARX_PAD_SOURCE, + CAL_CAMERARX_PAD_FIRST_SOURCE, &vfd->entity, 0, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); if (ret) { ctx_err(ctx, "Failed to create media link for context %u\n", - ctx->index); + ctx->dma_ctx); video_unregister_device(vfd); return ret; } @@ -926,9 +1006,9 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx) | (cal_mc_api ? V4L2_CAP_IO_MC : 0); vfd->v4l2_dev = &ctx->cal->v4l2_dev; vfd->queue = q; - snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index); + snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx); vfd->release = video_device_release_empty; - vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops; + vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops; vfd->lock = &ctx->mutex; video_set_drvdata(vfd, ctx); diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 76fe7a8b33f6..8e469d518a74 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -290,11 +290,42 @@ void cal_quickdump_regs(struct cal_dev *cal) * ------------------------------------------------------------------ */ +#define CAL_MAX_PIX_PROC 4 + +static int cal_reserve_pix_proc(struct cal_dev *cal) +{ + unsigned long ret; + + spin_lock(&cal->v4l2_dev.lock); + + ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC); + + if (ret == CAL_MAX_PIX_PROC) { + spin_unlock(&cal->v4l2_dev.lock); + return -ENOSPC; + } + + cal->reserved_pix_proc_mask |= BIT(ret); + + spin_unlock(&cal->v4l2_dev.lock); + + return ret; +} + +static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num) +{ + spin_lock(&cal->v4l2_dev.lock); + + cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num); + + spin_unlock(&cal->v4l2_dev.lock); +} + static void cal_ctx_csi2_config(struct cal_ctx *ctx) { u32 val; - val = cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)); + val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)); cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); /* * DT type: MIPI CSI-2 Specs @@ -304,15 +335,16 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx) * 0x2A: RAW8 1 pixel = 1 byte * 0x1E: YUV422 2 pixels = 4 bytes */ - cal_set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK); - cal_set_field(&val, 0, CAL_CSI2_CTX_VC_MASK); + cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK); + cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, CAL_CSI2_CTX_PACK_MODE_MASK); - cal_write(ctx->cal, CAL_CSI2_CTX0(ctx->index), val); - ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index))); + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val); + ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n", + ctx->phy->instance, ctx->csi2_ctx, + cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx))); } static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) @@ -354,16 +386,16 @@ static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) break; } - val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)); + val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)); cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); - cal_write(ctx->cal, CAL_PIX_PROC(ctx->index), val); - ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_PIX_PROC(ctx->index))); + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val); + ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc, + cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc))); } static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) @@ -371,27 +403,25 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline; u32 val; - val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_WR_DMA_CTRL_YSIZE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, CAL_WR_DMA_CTRL_DTAG_MASK); - cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, - CAL_WR_DMA_CTRL_MODE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, CAL_WR_DMA_CTRL_PATTERN_MASK); cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index))); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx))); - cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->index), + cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx), stride / 16, CAL_WR_DMA_OFST_MASK); - ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index))); + ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx))); - val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)); /* 64 bit word means no skipping */ cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); /* @@ -400,34 +430,32 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) * written per line. */ cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index))); - - val = cal_read(ctx->cal, CAL_CTRL); - cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, - CAL_CTRL_BURSTSIZE_MASK); - cal_set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK); - cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, - CAL_CTRL_POSTED_WRITES_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK); - cal_write(ctx->cal, CAL_CTRL, val); - ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL)); + cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx))); } void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) { - cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), addr); + cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); +} + +static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx) +{ + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + + cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, + CAL_WR_DMA_CTRL_MODE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); } static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) { - u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS, CAL_WR_DMA_CTRL_MODE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); } static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) @@ -441,6 +469,31 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) return stopped; } +int cal_ctx_prepare(struct cal_ctx *ctx) +{ + int ret; + + ctx->use_pix_proc = !ctx->fmtinfo->meta; + + if (ctx->use_pix_proc) { + ret = cal_reserve_pix_proc(ctx->cal); + if (ret < 0) { + ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); + return ret; + } + + ctx->pix_proc = ret; + } + + return 0; +} + +void cal_ctx_unprepare(struct cal_ctx *ctx) +{ + if (ctx->use_pix_proc) + cal_release_pix_proc(ctx->cal, ctx->pix_proc); +} + void cal_ctx_start(struct cal_ctx *ctx) { ctx->sequence = 0; @@ -448,14 +501,17 @@ void cal_ctx_start(struct cal_ctx *ctx) /* Configure the CSI-2, pixel processing and write DMA contexts. */ cal_ctx_csi2_config(ctx); - cal_ctx_pix_proc_config(ctx); + if (ctx->use_pix_proc) + cal_ctx_pix_proc_config(ctx); cal_ctx_wr_dma_config(ctx); /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); + + cal_ctx_wr_dma_enable(ctx); } void cal_ctx_stop(struct cal_ctx *ctx) @@ -479,11 +535,18 @@ void cal_ctx_stop(struct cal_ctx *ctx) /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); ctx->dma.state = CAL_DMA_STOPPED; + + /* Disable CSI2 context */ + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); + + /* Disable pix proc */ + if (ctx->use_pix_proc) + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); } /* ------------------------------------------------------------------ @@ -577,6 +640,16 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), cio_stat); } + + if (status & CAL_HL_IRQ_VC_MASK(i)) { + u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); + + dev_err_ratelimited(cal->dev, + "CIO%u VC error: %#08x\n", + i, vc_stat); + + cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat); + } } } @@ -588,8 +661,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(1), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) cal_irq_wdma_end(cal->ctx[i]); } } @@ -602,8 +675,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(2), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + for (i = 0; i < cal->num_contexts; ++i) { + if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) cal_irq_wdma_start(cal->ctx[i]); } } @@ -635,20 +708,20 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, int pad; int ret; - if (phy->sensor) { + if (phy->source) { phy_info(phy, "Rejecting subdev %s (Already set!!)", subdev->name); return 0; } - phy->sensor = subdev; - phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name); + phy->source = subdev; + phy_dbg(1, phy, "Using source %s for capture\n", subdev->name); pad = media_entity_get_fwnode_pad(&subdev->entity, - of_fwnode_handle(phy->sensor_ep_node), + of_fwnode_handle(phy->source_ep_node), MEDIA_PAD_FL_SOURCE); if (pad < 0) { - phy_err(phy, "Sensor %s has no connected source pad\n", + phy_err(phy, "Source %s has no connected source pad\n", subdev->name); return pad; } @@ -658,7 +731,7 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); if (ret) { - phy_err(phy, "Failed to create media link for sensor %s\n", + phy_err(phy, "Failed to create media link for source %s\n", subdev->name); return ret; } @@ -670,15 +743,30 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) { struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); unsigned int i; - int ret = 0; + int ret; - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (cal->ctx[i]) - cal_ctx_v4l2_register(cal->ctx[i]); + for (i = 0; i < cal->num_contexts; ++i) { + ret = cal_ctx_v4l2_register(cal->ctx[i]); + if (ret) + goto err_ctx_unreg; } - if (cal_mc_api) - ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (!cal_mc_api) + return 0; + + ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (ret) + goto err_ctx_unreg; + + return 0; + +err_ctx_unreg: + for (; i > 0; --i) { + if (!cal->ctx[i - 1]) + continue; + + cal_ctx_v4l2_unregister(cal->ctx[i - 1]); + } return ret; } @@ -701,10 +789,10 @@ static int cal_async_notifier_register(struct cal_dev *cal) struct cal_v4l2_async_subdev *casd; struct fwnode_handle *fwnode; - if (!phy->sensor_node) + if (!phy->source_node) continue; - fwnode = of_fwnode_handle(phy->sensor_node); + fwnode = of_fwnode_handle(phy->source_node); casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier, fwnode, struct cal_v4l2_async_subdev); @@ -777,10 +865,8 @@ static void cal_media_unregister(struct cal_dev *cal) unsigned int i; /* Unregister all the V4L2 video devices. */ - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_unregister(cal->ctx[i]); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_unregister(cal->ctx[i]); cal_async_notifier_unregister(cal); media_device_unregister(&cal->mdev); @@ -825,13 +911,6 @@ static int cal_media_init(struct cal_dev *cal) */ static void cal_media_cleanup(struct cal_dev *cal) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_cleanup(cal->ctx[i]); - } - v4l2_device_unregister(&cal->v4l2_dev); media_device_cleanup(&cal->mdev); @@ -848,14 +927,17 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) struct cal_ctx *ctx; int ret; - ctx = devm_kzalloc(cal->dev, sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL; ctx->cal = cal; ctx->phy = cal->phy[inst]; - ctx->index = inst; + ctx->dma_ctx = inst; + ctx->csi2_ctx = inst; ctx->cport = inst; + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; ret = cal_ctx_v4l2_init(ctx); if (ret) @@ -864,6 +946,13 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) return ctx; } +static void cal_ctx_destroy(struct cal_ctx *ctx) +{ + cal_ctx_v4l2_cleanup(ctx); + + kfree(ctx); +} + static const struct of_device_id cal_of_match[] = { { .compatible = "ti,dra72-cal", @@ -976,7 +1065,6 @@ static int cal_init_camerarx_regmap(struct cal_dev *cal) static int cal_probe(struct platform_device *pdev) { struct cal_dev *cal; - struct cal_ctx *ctx; bool connected = false; unsigned int i; int ret; @@ -1045,7 +1133,7 @@ static int cal_probe(struct platform_device *pdev) goto error_camerarx; } - if (cal->phy[i]->sensor_node) + if (cal->phy[i]->source_node) connected = true; } @@ -1057,15 +1145,17 @@ static int cal_probe(struct platform_device *pdev) /* Create contexts. */ for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (!cal->phy[i]->sensor_node) + if (!cal->phy[i]->source_node) continue; - cal->ctx[i] = cal_ctx_create(cal, i); - if (!cal->ctx[i]) { - cal_err(cal, "Failed to create context %u\n", i); + cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i); + if (!cal->ctx[cal->num_contexts]) { + cal_err(cal, "Failed to create context %u\n", cal->num_contexts); ret = -ENODEV; goto error_context; } + + cal->num_contexts++; } /* Register the media device. */ @@ -1076,11 +1166,8 @@ static int cal_probe(struct platform_device *pdev) return 0; error_context: - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - ctx = cal->ctx[i]; - if (ctx) - cal_ctx_v4l2_cleanup(ctx); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); error_camerarx: for (i = 0; i < cal->data->num_csi2_phy; i++) @@ -1106,16 +1193,17 @@ static int cal_remove(struct platform_device *pdev) cal_media_unregister(cal); - for (i = 0; i < ARRAY_SIZE(cal->phy); i++) { - if (cal->phy[i]) - cal_camerarx_disable(cal->phy[i]); - } + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_disable(cal->phy[i]); - cal_media_cleanup(cal); + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); for (i = 0; i < cal->data->num_csi2_phy; i++) cal_camerarx_destroy(cal->phy[i]); + cal_media_cleanup(cal); + if (ret >= 0) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -1127,6 +1215,7 @@ static int cal_runtime_resume(struct device *dev) { struct cal_dev *cal = dev_get_drvdata(dev); unsigned int i; + u32 val; if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { /* @@ -1143,6 +1232,17 @@ static int cal_runtime_resume(struct device *dev) */ cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); + val = cal_read(cal, CAL_CTRL); + cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, + CAL_CTRL_BURSTSIZE_MASK); + cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK); + cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, + CAL_CTRL_POSTED_WRITES_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK); + cal_write(cal, CAL_CTRL, val); + cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL)); + return 0; } diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index db0e408eaa94..527e22d022f3 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -29,7 +29,7 @@ #include <media/videobuf2-v4l2.h> #define CAL_MODULE_NAME "cal" -#define CAL_NUM_CONTEXT 2 +#define CAL_MAX_NUM_CONTEXT 8 #define CAL_NUM_CSI2_PORTS 2 /* @@ -44,7 +44,22 @@ #define CAL_MAX_HEIGHT_LINES 16383 #define CAL_CAMERARX_PAD_SINK 0 -#define CAL_CAMERARX_PAD_SOURCE 1 +#define CAL_CAMERARX_PAD_FIRST_SOURCE 1 +#define CAL_CAMERARX_NUM_SOURCE_PADS 1 +#define CAL_CAMERARX_NUM_PADS (1 + CAL_CAMERARX_NUM_SOURCE_PADS) + +static inline bool cal_rx_pad_is_sink(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad == 0; +} + +static inline bool cal_rx_pad_is_source(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad >= CAL_CAMERARX_PAD_FIRST_SOURCE && + pad <= CAL_CAMERARX_NUM_SOURCE_PADS; +} struct device; struct device_node; @@ -73,6 +88,7 @@ struct cal_format_info { u32 code; /* Bits per pixel */ u8 bpp; + bool meta; }; /* buffer for one video frame */ @@ -149,22 +165,29 @@ struct cal_data { struct cal_camerarx { void __iomem *base; struct resource *res; - struct device *dev; struct regmap_field *fields[F_MAX_FIELDS]; struct cal_dev *cal; unsigned int instance; struct v4l2_fwnode_endpoint endpoint; - struct device_node *sensor_ep_node; - struct device_node *sensor_node; - struct v4l2_subdev *sensor; + struct device_node *source_ep_node; + struct device_node *source_node; + struct v4l2_subdev *source; struct media_pipeline pipe; struct v4l2_subdev subdev; - struct media_pad pads[2]; - struct v4l2_mbus_framefmt formats[2]; - const struct cal_format_info *fmtinfo; + struct media_pad pads[CAL_CAMERARX_NUM_PADS]; + struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS]; + + /* + * Lock for camerarx ops. Protects: + * - formats + * - enable_count + */ + struct mutex mutex; + + unsigned int enable_count; }; struct cal_dev { @@ -184,11 +207,14 @@ struct cal_dev { /* Camera Core Module handle */ struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS]; - struct cal_ctx *ctx[CAL_NUM_CONTEXT]; + u32 num_contexts; + struct cal_ctx *ctx[CAL_MAX_NUM_CONTEXT]; struct media_device mdev; struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; + + unsigned long reserved_pix_proc_mask; }; /* @@ -212,14 +238,20 @@ struct cal_ctx { /* Used to store current pixel format */ struct v4l2_format v_fmt; - /* Current subdev enumerated format */ + /* Current subdev enumerated format (legacy) */ const struct cal_format_info **active_fmt; unsigned int num_active_fmt; unsigned int sequence; struct vb2_queue vb_vidq; - unsigned int index; - unsigned int cport; + u8 dma_ctx; + u8 cport; + u8 csi2_ctx; + u8 pix_proc; + u8 vc; + u8 datatype; + + bool use_pix_proc; }; extern unsigned int cal_debug; @@ -237,11 +269,11 @@ extern bool cal_mc_api; dev_err((cal)->dev, fmt, ##arg) #define ctx_dbg(level, ctx, fmt, arg...) \ - cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define ctx_info(ctx, fmt, arg...) \ - cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define ctx_err(ctx, fmt, arg...) \ - cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define phy_dbg(level, phy, fmt, arg...) \ cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) @@ -297,6 +329,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, unsigned int instance); void cal_camerarx_destroy(struct cal_camerarx *phy); +int cal_ctx_prepare(struct cal_ctx *ctx); +void cal_ctx_unprepare(struct cal_ctx *ctx); void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr); void cal_ctx_start(struct cal_ctx *ctx); void cal_ctx_stop(struct cal_ctx *ctx); diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index f752096dcf7f..40e4f972fcb7 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -72,22 +72,8 @@ #define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U) #define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U) #define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U) -#define CAL_CSI2_CTX0(m) (0x330U + (m) * 0x80U) -#define CAL_CSI2_CTX1(m) (0x334U + (m) * 0x80U) -#define CAL_CSI2_CTX2(m) (0x338U + (m) * 0x80U) -#define CAL_CSI2_CTX3(m) (0x33cU + (m) * 0x80U) -#define CAL_CSI2_CTX4(m) (0x340U + (m) * 0x80U) -#define CAL_CSI2_CTX5(m) (0x344U + (m) * 0x80U) -#define CAL_CSI2_CTX6(m) (0x348U + (m) * 0x80U) -#define CAL_CSI2_CTX7(m) (0x34cU + (m) * 0x80U) -#define CAL_CSI2_STATUS0(m) (0x350U + (m) * 0x80U) -#define CAL_CSI2_STATUS1(m) (0x354U + (m) * 0x80U) -#define CAL_CSI2_STATUS2(m) (0x358U + (m) * 0x80U) -#define CAL_CSI2_STATUS3(m) (0x35cU + (m) * 0x80U) -#define CAL_CSI2_STATUS4(m) (0x360U + (m) * 0x80U) -#define CAL_CSI2_STATUS5(m) (0x364U + (m) * 0x80U) -#define CAL_CSI2_STATUS6(m) (0x368U + (m) * 0x80U) -#define CAL_CSI2_STATUS7(m) (0x36cU + (m) * 0x80U) +#define CAL_CSI2_CTX(phy, csi2_ctx) (0x330U + (phy) * 0x80U + (csi2_ctx) * 4) +#define CAL_CSI2_STATUS(phy, csi2_ctx) (0x350U + (phy) * 0x80U + (csi2_ctx) * 4) /* CAL CSI2 PHY register offsets */ #define CAL_CSI2_PHY_REG0 0x000 @@ -139,7 +125,8 @@ #define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 #define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 -#define CAL_HL_IRQ_MASK(m) BIT(m) +#define CAL_HL_IRQ_WDMA_END_MASK(m) BIT(m) +#define CAL_HL_IRQ_WDMA_START_MASK(m) BIT(m) #define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) @@ -419,32 +406,16 @@ #define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14) #define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15) -#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT(0) -#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT(1) -#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT(2) -#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT(3) -#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT(4) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT(5) -#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT(8) -#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT(9) -#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT(10) -#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT(11) -#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT(12) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT(13) -#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT(16) -#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT(17) -#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT(18) -#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT(19) -#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT(20) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT(21) -#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT(24) -#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT(25) -#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT(26) -#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT(27) -#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT(28) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT(29) +#define CAL_CSI2_VC_IRQ_FS_IRQ_MASK(n) BIT(0 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_FE_IRQ_MASK(n) BIT(1 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LS_IRQ_MASK(n) BIT(2 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LE_IRQ_MASK(n) BIT(3 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_CS_IRQ_MASK(n) BIT(4 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8)) #define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0) +#define CAL_CSI2_CTX_DT_DISABLED 0 +#define CAL_CSI2_CTX_DT_ANY 1 #define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6) #define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8) #define CAL_CSI2_CTX_ATT_MASK BIT(13) diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 6f51e5c75543..823c15facd1b 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -676,9 +676,9 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, * rectangles. */ entity->config = v4l2_subdev_alloc_state(&entity->subdev); - if (entity->config == NULL) { + if (IS_ERR(entity->config)) { media_entity_cleanup(&entity->subdev.entity); - return -ENOMEM; + return PTR_ERR(entity->config); } return 0; diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index d0a8326b75c2..fd5a7a058714 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -246,6 +246,16 @@ config IR_MESON To compile this driver as a module, choose M here: the module will be called meson-ir. +config IR_MESON_TX + tristate "Amlogic Meson IR TX" + depends on ARCH_MESON || COMPILE_TEST + help + Say Y if you want to use the IR transmitter available on + Amlogic Meson SoCs. + + To compile this driver as a module, choose M here: the + module will be called meson-ir-tx. + config IR_MTK tristate "Mediatek IR remote receiver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 692e9b6b203f..0db51fad27d6 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_FINTEK) += fintek-cir.o obj-$(CONFIG_IR_MESON) += meson-ir.o +obj-$(CONFIG_IR_MESON_TX) += meson-ir-tx.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_ENE) += ene_ir.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 6049e5c95394..e09270916fbc 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1052,7 +1052,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->device_name = "ENE eHome Infrared Remote Receiver"; if (dev->hw_learning_and_tx_capable) { - rdev->s_learning_mode = ene_set_learning_mode; + rdev->s_wideband_receiver = ene_set_learning_mode; init_completion(&dev->tx_complete); rdev->tx_ir = ene_transmit; rdev->s_tx_mask = ene_set_tx_mask; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 116daf90c858..7f591ff5269d 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -412,7 +412,7 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) val |= LIRC_CAN_SET_REC_CARRIER | LIRC_CAN_SET_REC_CARRIER_RANGE; - if (dev->s_learning_mode) + if (dev->s_wideband_receiver) val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; if (dev->s_carrier_report) @@ -519,10 +519,10 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case LIRC_SET_WIDEBAND_RECEIVER: - if (!dev->s_learning_mode) + if (!dev->s_wideband_receiver) ret = -ENOTTY; else - ret = dev->s_learning_mode(dev, !!val); + ret = dev->s_wideband_receiver(dev, !!val); break; case LIRC_SET_MEASURE_CARRIER_MODE: diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5642595a057e..e03dd1f0144f 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1630,7 +1630,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->tx_ir = mceusb_tx_ir; } if (ir->flags.rx2 > 0) { - rc->s_learning_mode = mceusb_set_rx_wideband; + rc->s_wideband_receiver = mceusb_set_rx_wideband; rc->s_carrier_report = mceusb_set_rx_carrier_report; } rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c new file mode 100644 index 000000000000..3055f8e1b6ff --- /dev/null +++ b/drivers/media/rc/meson-ir-tx.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0-only +/** + * meson-ir-tx.c - Amlogic Meson IR TX driver + * + * Copyright (c) 2021, SberDevices. All Rights Reserved. + * + * Author: Viktor Prutyanov <viktor.prutyanov@phystech.edu> + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/of_irq.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <media/rc-core.h> + +#define DEVICE_NAME "Meson IR TX" +#define DRIVER_NAME "meson-ir-tx" + +#define MIRTX_DEFAULT_CARRIER 38000 +#define MIRTX_DEFAULT_DUTY_CYCLE 50 +#define MIRTX_FIFO_THD 32 + +#define IRB_MOD_1US_CLK_RATE 1000000 + +#define IRB_FIFO_LEN 128 + +#define IRB_ADDR0 0x0 +#define IRB_ADDR1 0x4 +#define IRB_ADDR2 0x8 +#define IRB_ADDR3 0xc + +#define IRB_MAX_DELAY (1 << 10) +#define IRB_DELAY_MASK (IRB_MAX_DELAY - 1) + +/* IRCTRL_IR_BLASTER_ADDR0 */ +#define IRB_MOD_CLK(x) ((x) << 12) +#define IRB_MOD_SYS_CLK 0 +#define IRB_MOD_XTAL3_CLK 1 +#define IRB_MOD_1US_CLK 2 +#define IRB_MOD_10US_CLK 3 +#define IRB_INIT_HIGH BIT(2) +#define IRB_ENABLE BIT(0) + +/* IRCTRL_IR_BLASTER_ADDR2 */ +#define IRB_MOD_COUNT(lo, hi) ((((lo) - 1) << 16) | ((hi) - 1)) + +/* IRCTRL_IR_BLASTER_ADDR2 */ +#define IRB_WRITE_FIFO BIT(16) +#define IRB_MOD_ENABLE BIT(12) +#define IRB_TB_1US (0x0 << 10) +#define IRB_TB_10US (0x1 << 10) +#define IRB_TB_100US (0x2 << 10) +#define IRB_TB_MOD_CLK (0x3 << 10) + +/* IRCTRL_IR_BLASTER_ADDR3 */ +#define IRB_FIFO_THD_PENDING BIT(16) +#define IRB_FIFO_IRQ_ENABLE BIT(8) + +struct meson_irtx { + struct device *dev; + void __iomem *reg_base; + u32 *buf; + unsigned int buf_len; + unsigned int buf_head; + unsigned int carrier; + unsigned int duty_cycle; + /* Locks buf */ + spinlock_t lock; + struct completion completion; + unsigned long clk_rate; +}; + +static void meson_irtx_set_mod(struct meson_irtx *ir) +{ + unsigned int cnt = DIV_ROUND_CLOSEST(ir->clk_rate, ir->carrier); + unsigned int pulse_cnt = DIV_ROUND_CLOSEST(cnt * ir->duty_cycle, 100); + unsigned int space_cnt = cnt - pulse_cnt; + + dev_dbg(ir->dev, "F_mod = %uHz, T_mod = %luns, duty_cycle = %u%%\n", + ir->carrier, NSEC_PER_SEC / ir->clk_rate * cnt, + 100 * pulse_cnt / cnt); + + writel(IRB_MOD_COUNT(pulse_cnt, space_cnt), + ir->reg_base + IRB_ADDR1); +} + +static void meson_irtx_setup(struct meson_irtx *ir, unsigned int clk_nr) +{ + /* + * Disable the TX, set modulator clock tick and set initialize + * output to be high. Set up carrier frequency and duty cycle. Then + * unset initialize output. Enable FIFO interrupt, set FIFO interrupt + * threshold. Finally, enable the transmitter back. + */ + writel(~IRB_ENABLE & (IRB_MOD_CLK(clk_nr) | IRB_INIT_HIGH), + ir->reg_base + IRB_ADDR0); + meson_irtx_set_mod(ir); + writel(readl(ir->reg_base + IRB_ADDR0) & ~IRB_INIT_HIGH, + ir->reg_base + IRB_ADDR0); + writel(IRB_FIFO_IRQ_ENABLE | MIRTX_FIFO_THD, + ir->reg_base + IRB_ADDR3); + writel(readl(ir->reg_base + IRB_ADDR0) | IRB_ENABLE, + ir->reg_base + IRB_ADDR0); +} + +static u32 meson_irtx_prepare_pulse(struct meson_irtx *ir, unsigned int time) +{ + unsigned int delay; + unsigned int tb = IRB_TB_MOD_CLK; + unsigned int tb_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, ir->carrier); + + delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK; + + return ((IRB_WRITE_FIFO | IRB_MOD_ENABLE) | tb | delay); +} + +static u32 meson_irtx_prepare_space(struct meson_irtx *ir, unsigned int time) +{ + unsigned int delay; + unsigned int tb = IRB_TB_100US; + unsigned int tb_us = 100; + + if (time <= IRB_MAX_DELAY) { + tb = IRB_TB_1US; + tb_us = 1; + } else if (time <= 10 * IRB_MAX_DELAY) { + tb = IRB_TB_10US; + tb_us = 10; + } else if (time <= 100 * IRB_MAX_DELAY) { + tb = IRB_TB_100US; + tb_us = 100; + } + + delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK; + + return ((IRB_WRITE_FIFO & ~IRB_MOD_ENABLE) | tb | delay); +} + +static void meson_irtx_send_buffer(struct meson_irtx *ir) +{ + unsigned int nr = 0; + unsigned int max_fifo_level = IRB_FIFO_LEN - MIRTX_FIFO_THD; + + while (ir->buf_head < ir->buf_len && nr < max_fifo_level) { + writel(ir->buf[ir->buf_head], ir->reg_base + IRB_ADDR2); + + ir->buf_head++; + nr++; + } +} + +static bool meson_irtx_check_buf(struct meson_irtx *ir, + unsigned int *buf, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + unsigned int max_tb_us; + /* + * Max space timebase is 100 us. + * Pulse timebase equals to carrier period. + */ + if (i % 2 == 0) + max_tb_us = USEC_PER_SEC / ir->carrier; + else + max_tb_us = 100; + + if (buf[i] >= max_tb_us * IRB_MAX_DELAY) + return false; + } + + return true; +} + +static void meson_irtx_fill_buf(struct meson_irtx *ir, u32 *dst_buf, + unsigned int *src_buf, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + if (i % 2 == 0) + dst_buf[i] = meson_irtx_prepare_pulse(ir, src_buf[i]); + else + dst_buf[i] = meson_irtx_prepare_space(ir, src_buf[i]); + } +} + +static irqreturn_t meson_irtx_irqhandler(int irq, void *data) +{ + unsigned long flags; + struct meson_irtx *ir = data; + + writel(readl(ir->reg_base + IRB_ADDR3) & ~IRB_FIFO_THD_PENDING, + ir->reg_base + IRB_ADDR3); + + if (completion_done(&ir->completion)) + return IRQ_HANDLED; + + spin_lock_irqsave(&ir->lock, flags); + if (ir->buf_head < ir->buf_len) + meson_irtx_send_buffer(ir); + else + complete(&ir->completion); + spin_unlock_irqrestore(&ir->lock, flags); + + return IRQ_HANDLED; +} + +static int meson_irtx_set_carrier(struct rc_dev *rc, u32 carrier) +{ + struct meson_irtx *ir = rc->priv; + + if (carrier == 0) + return -EINVAL; + + ir->carrier = carrier; + meson_irtx_set_mod(ir); + + return 0; +} + +static int meson_irtx_set_duty_cycle(struct rc_dev *rc, u32 duty_cycle) +{ + struct meson_irtx *ir = rc->priv; + + ir->duty_cycle = duty_cycle; + meson_irtx_set_mod(ir); + + return 0; +} + +static void meson_irtx_update_buf(struct meson_irtx *ir, u32 *buf, + unsigned int len, unsigned int head) +{ + ir->buf = buf; + ir->buf_len = len; + ir->buf_head = head; +} + +static int meson_irtx_transmit(struct rc_dev *rc, unsigned int *buf, + unsigned int len) +{ + unsigned long flags; + struct meson_irtx *ir = rc->priv; + u32 *tx_buf; + int ret = len; + + if (!meson_irtx_check_buf(ir, buf, len)) + return -EINVAL; + + tx_buf = kmalloc_array(len, sizeof(u32), GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + meson_irtx_fill_buf(ir, tx_buf, buf, len); + dev_dbg(ir->dev, "TX buffer filled, length = %u\n", len); + + spin_lock_irqsave(&ir->lock, flags); + meson_irtx_update_buf(ir, tx_buf, len, 0); + reinit_completion(&ir->completion); + meson_irtx_send_buffer(ir); + spin_unlock_irqrestore(&ir->lock, flags); + + if (!wait_for_completion_timeout(&ir->completion, + usecs_to_jiffies(IR_MAX_DURATION))) + ret = -ETIMEDOUT; + + spin_lock_irqsave(&ir->lock, flags); + kfree(ir->buf); + meson_irtx_update_buf(ir, NULL, 0, 0); + spin_unlock_irqrestore(&ir->lock, flags); + + return ret; +} + +static int meson_irtx_mod_clock_probe(struct meson_irtx *ir, + unsigned int *clk_nr) +{ + struct device_node *np = ir->dev->of_node; + struct clk *clock; + + if (!np) + return -ENODEV; + + clock = devm_clk_get(ir->dev, "xtal"); + if (IS_ERR(clock) || clk_prepare_enable(clock)) + return -ENODEV; + + *clk_nr = IRB_MOD_XTAL3_CLK; + ir->clk_rate = clk_get_rate(clock) / 3; + + if (ir->clk_rate < IRB_MOD_1US_CLK_RATE) { + *clk_nr = IRB_MOD_1US_CLK; + ir->clk_rate = IRB_MOD_1US_CLK_RATE; + } + + dev_info(ir->dev, "F_clk = %luHz\n", ir->clk_rate); + + return 0; +} + +static int __init meson_irtx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct meson_irtx *ir; + struct rc_dev *rc; + int irq; + unsigned int clk_nr; + int ret; + + ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + ir->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ir->reg_base)) + return PTR_ERR(ir->reg_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq resource found\n"); + return -ENODEV; + } + + ir->dev = dev; + ir->carrier = MIRTX_DEFAULT_CARRIER; + ir->duty_cycle = MIRTX_DEFAULT_DUTY_CYCLE; + init_completion(&ir->completion); + spin_lock_init(&ir->lock); + + ret = meson_irtx_mod_clock_probe(ir, &clk_nr); + if (ret) { + dev_err(dev, "modulator clock setup failed\n"); + return ret; + } + meson_irtx_setup(ir, clk_nr); + + ret = devm_request_irq(dev, irq, + meson_irtx_irqhandler, + IRQF_TRIGGER_RISING, + DRIVER_NAME, ir); + if (ret) { + dev_err(dev, "irq request failed\n"); + return ret; + } + + rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX); + if (!rc) + return -ENOMEM; + + rc->driver_name = DRIVER_NAME; + rc->device_name = DEVICE_NAME; + rc->priv = ir; + + rc->tx_ir = meson_irtx_transmit; + rc->s_tx_carrier = meson_irtx_set_carrier; + rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle; + + ret = rc_register_device(rc); + if (ret < 0) { + dev_err(dev, "rc_dev registration failed\n"); + rc_free_device(rc); + return ret; + } + + platform_set_drvdata(pdev, rc); + + return 0; +} + +static int meson_irtx_remove(struct platform_device *pdev) +{ + struct rc_dev *rc = platform_get_drvdata(pdev); + + rc_unregister_device(rc); + + return 0; +} + +static const struct of_device_id meson_irtx_dt_match[] = { + { + .compatible = "amlogic,meson-g12a-ir-tx", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_irtx_dt_match); + +static struct platform_driver meson_irtx_pd = { + .remove = meson_irtx_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = meson_irtx_dt_match, + }, +}; + +module_platform_driver_probe(meson_irtx_pd, meson_irtx_probe); + +MODULE_DESCRIPTION("Meson IR TX driver"); +MODULE_AUTHOR("Viktor Prutyanov <viktor.prutyanov@phystech.edu>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 1ba3f96ffa7d..6441879fcba1 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -15,12 +15,9 @@ #include <linux/slab.h> #include <media/rc-core.h> -#define DRIVER_NAME "rc-loopback" -#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x) -#define RXMASK_REGULAR 0x1 -#define RXMASK_LEARNING 0x2 - -static bool debug; +#define DRIVER_NAME "rc-loopback" +#define RXMASK_NARROWBAND 0x1 +#define RXMASK_WIDEBAND 0x2 struct loopback_dev { struct rc_dev *dev; @@ -28,7 +25,7 @@ struct loopback_dev { u32 txcarrier; u32 txduty; bool idle; - bool learning; + bool wideband; bool carrierreport; u32 rxcarriermin; u32 rxcarriermax; @@ -40,12 +37,12 @@ static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) { struct loopback_dev *lodev = dev->priv; - if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { - dprintk("invalid tx mask: %u\n", mask); - return -EINVAL; + if ((mask & (RXMASK_NARROWBAND | RXMASK_WIDEBAND)) != mask) { + dev_dbg(&dev->dev, "invalid tx mask: %u\n", mask); + return 2; } - dprintk("setting tx mask: %u\n", mask); + dev_dbg(&dev->dev, "setting tx mask: %u\n", mask); lodev->txmask = mask; return 0; } @@ -54,7 +51,7 @@ static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier) { struct loopback_dev *lodev = dev->priv; - dprintk("setting tx carrier: %u\n", carrier); + dev_dbg(&dev->dev, "setting tx carrier: %u\n", carrier); lodev->txcarrier = carrier; return 0; } @@ -64,11 +61,11 @@ static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) struct loopback_dev *lodev = dev->priv; if (duty_cycle < 1 || duty_cycle > 99) { - dprintk("invalid duty cycle: %u\n", duty_cycle); + dev_dbg(&dev->dev, "invalid duty cycle: %u\n", duty_cycle); return -EINVAL; } - dprintk("setting duty cycle: %u\n", duty_cycle); + dev_dbg(&dev->dev, "setting duty cycle: %u\n", duty_cycle); lodev->txduty = duty_cycle; return 0; } @@ -78,11 +75,11 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) struct loopback_dev *lodev = dev->priv; if (min < 1 || min > max) { - dprintk("invalid rx carrier range %u to %u\n", min, max); + dev_dbg(&dev->dev, "invalid rx carrier range %u to %u\n", min, max); return -EINVAL; } - dprintk("setting rx carrier range %u to %u\n", min, max); + dev_dbg(&dev->dev, "setting rx carrier range %u to %u\n", min, max); lodev->rxcarriermin = min; lodev->rxcarriermax = max; return 0; @@ -97,25 +94,33 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) if (lodev->txcarrier < lodev->rxcarriermin || lodev->txcarrier > lodev->rxcarriermax) { - dprintk("ignoring tx, carrier out of range\n"); + dev_dbg(&dev->dev, "ignoring tx, carrier out of range\n"); goto out; } - if (lodev->learning) - rxmask = RXMASK_LEARNING; + if (lodev->wideband) + rxmask = RXMASK_WIDEBAND; else - rxmask = RXMASK_REGULAR; + rxmask = RXMASK_NARROWBAND; if (!(rxmask & lodev->txmask)) { - dprintk("ignoring tx, rx mask mismatch\n"); + dev_dbg(&dev->dev, "ignoring tx, rx mask mismatch\n"); goto out; } for (i = 0; i < count; i++) { rawir.pulse = i % 2 ? false : true; rawir.duration = txbuf[i]; - if (rawir.duration) - ir_raw_event_store_with_filter(dev, &rawir); + + ir_raw_event_store_with_filter(dev, &rawir); + } + + if (lodev->carrierreport) { + rawir.pulse = false; + rawir.carrier_report = true; + rawir.carrier = lodev->txcarrier; + + ir_raw_event_store(dev, &rawir); } /* Fake a silence long enough to cause us to go idle */ @@ -134,18 +139,18 @@ static void loop_set_idle(struct rc_dev *dev, bool enable) struct loopback_dev *lodev = dev->priv; if (lodev->idle != enable) { - dprintk("%sing idle mode\n", enable ? "enter" : "exit"); + dev_dbg(&dev->dev, "%sing idle mode\n", enable ? "enter" : "exit"); lodev->idle = enable; } } -static int loop_set_learning_mode(struct rc_dev *dev, int enable) +static int loop_set_wideband_receiver(struct rc_dev *dev, int enable) { struct loopback_dev *lodev = dev->priv; - if (lodev->learning != enable) { - dprintk("%sing learning mode\n", enable ? "enter" : "exit"); - lodev->learning = !!enable; + if (lodev->wideband != enable) { + dev_dbg(&dev->dev, "using %sband receiver\n", enable ? "wide" : "narrow"); + lodev->wideband = !!enable; } return 0; @@ -156,7 +161,7 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable) struct loopback_dev *lodev = dev->priv; if (lodev->carrierreport != enable) { - dprintk("%sabling carrier reports\n", enable ? "en" : "dis"); + dev_dbg(&dev->dev, "%sabling carrier reports\n", enable ? "en" : "dis"); lodev->carrierreport = !!enable; } @@ -204,10 +209,8 @@ static int __init loop_init(void) int ret; rc = rc_allocate_device(RC_DRIVER_IR_RAW); - if (!rc) { - printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); + if (!rc) return -ENOMEM; - } rc->device_name = "rc-core loopback device"; rc->input_phys = "rc-core/virtual"; @@ -219,9 +222,9 @@ static int __init loop_init(void) rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER; rc->encode_wakeup = true; - rc->timeout = MS_TO_US(100); /* 100 ms */ + rc->timeout = IR_DEFAULT_TIMEOUT; rc->min_timeout = 1; - rc->max_timeout = UINT_MAX; + rc->max_timeout = IR_MAX_TIMEOUT; rc->rx_resolution = 1; rc->tx_resolution = 1; rc->s_tx_mask = loop_set_tx_mask; @@ -230,22 +233,22 @@ static int __init loop_init(void) rc->s_rx_carrier_range = loop_set_rx_carrier_range; rc->tx_ir = loop_tx_ir; rc->s_idle = loop_set_idle; - rc->s_learning_mode = loop_set_learning_mode; + rc->s_wideband_receiver = loop_set_wideband_receiver; rc->s_carrier_report = loop_set_carrier_report; rc->s_wakeup_filter = loop_set_wakeup_filter; - loopdev.txmask = RXMASK_REGULAR; + loopdev.txmask = RXMASK_NARROWBAND; loopdev.txcarrier = 36000; loopdev.txduty = 50; loopdev.rxcarriermin = 1; loopdev.rxcarriermax = ~0; loopdev.idle = true; - loopdev.learning = false; + loopdev.wideband = false; loopdev.carrierreport = false; ret = rc_register_device(rc); if (ret < 0) { - printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n"); + dev_err(&rc->dev, "rc_dev registration failed\n"); rc_free_device(rc); return ret; } @@ -262,9 +265,6 @@ static void __exit loop_exit(void) module_init(loop_init); module_exit(loop_exit); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug messages"); - MODULE_DESCRIPTION("Loopback device for rc-core debugging"); MODULE_AUTHOR("David Härdeman <david@hardeman.nu>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8e88dc8ea6c5..b90438a71c80 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1940,7 +1940,7 @@ int rc_register_device(struct rc_dev *dev) kfree(path); /* - * once the the input device is registered in rc_setup_rx_device, + * once the input device is registered in rc_setup_rx_device, * userspace can open the input device and rc_open() will be called * as a result. This results in driver code being allowed to submit * keycodes with rc_keydown, so lirc must be registered first. diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 2cf3377ec63a..ac85464864b9 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -6,7 +6,7 @@ * based heavily on the work of Stephen Cox, with additional * help from RedRat Ltd. * - * This driver began life based an an old version of the first-generation + * This driver began life based on an old version of the first-generation * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's * Chris Dodge. diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 9f3cd9fb6b6e..9cd765e31c49 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -265,8 +265,6 @@ static void streamzap_callback(struct urb *urb) ir_raw_event_handle(sz->rdev); usb_submit_urb(urb, GFP_ATOMIC); - - return; } static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index e5094fff04c5..b91a1e845b97 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -524,13 +524,13 @@ cxd2880_spi_probe(struct spi_device *spi) if (IS_ERR(dvb_spi->vcc_supply)) { if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto fail_adapter; + goto fail_regulator; } dvb_spi->vcc_supply = NULL; } else { ret = regulator_enable(dvb_spi->vcc_supply); if (ret) - goto fail_adapter; + goto fail_regulator; } dvb_spi->spi = spi; @@ -618,6 +618,9 @@ fail_frontend: fail_attach: dvb_unregister_adapter(&dvb_spi->adapter); fail_adapter: + if (!dvb_spi->vcc_supply) + regulator_disable(dvb_spi->vcc_supply); +fail_regulator: kfree(dvb_spi); return ret; } diff --git a/drivers/media/test-drivers/vivid/vivid-cec.c b/drivers/media/test-drivers/vivid/vivid-cec.c index 4d2413e87730..55ea039fe5b2 100644 --- a/drivers/media/test-drivers/vivid/vivid-cec.c +++ b/drivers/media/test-drivers/vivid/vivid-cec.c @@ -282,5 +282,5 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", dev->inst, is_source ? "out" : "cap", idx); return cec_allocate_adapter(&vivid_cec_adap_ops, dev, - name, caps, 1); + name, caps, CEC_MAX_LOG_ADDRS); } diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 5c75303fba9d..60ca8b9d070b 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -34,6 +34,8 @@ config DVB_USB_AF9035 tristate "Afatech AF9035 DVB-T USB2.0 support" depends on DVB_USB_V2 select DVB_AF9033 + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index b1f69c11c839..5eef37b00a52 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -210,6 +210,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type, /* register I2C device */ client = i2c_new_client_device(adapter, &board_info); if (!i2c_client_has_driver(client)) { + dev_err(&intf->dev, "failed to bind i2c device to %s driver\n", type); ret = -ENODEV; goto err; } diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 689829f1b52a..1221c924312a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -541,7 +541,9 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; - if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2) + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2 || + le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2_LITE || + le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL; si2168_config.ts_clock_inv = 1; @@ -577,15 +579,24 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name) { - dvbsky_gpio_ctrl(d, 0x04, 1); - msleep(20); - dvbsky_gpio_ctrl(d, 0x83, 0); - dvbsky_gpio_ctrl(d, 0xc0, 1); - msleep(100); - dvbsky_gpio_ctrl(d, 0x83, 1); - dvbsky_gpio_ctrl(d, 0xc0, 0); - msleep(50); - + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) { + dvbsky_gpio_ctrl(d, 0x87, 0); + msleep(20); + dvbsky_gpio_ctrl(d, 0x86, 1); + dvbsky_gpio_ctrl(d, 0x80, 0); + msleep(100); + dvbsky_gpio_ctrl(d, 0x80, 1); + msleep(50); + } else { + dvbsky_gpio_ctrl(d, 0x04, 1); + msleep(20); + dvbsky_gpio_ctrl(d, 0x83, 0); + dvbsky_gpio_ctrl(d, 0xc0, 1); + msleep(100); + dvbsky_gpio_ctrl(d, 0x83, 1); + dvbsky_gpio_ctrl(d, 0xc0, 0); + msleep(50); + } return WARM; } @@ -789,6 +800,12 @@ static const struct usb_device_id dvbsky_id_table[] = { { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2_LITE, + &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2 Lite", + NULL) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230A, + &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230A", + NULL) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c index 2e07106f4680..bc4b2abdde1a 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c @@ -17,7 +17,8 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) if (d->props.i2c_algo == NULL) { err("no i2c algorithm specified"); - return -EINVAL; + ret = -EINVAL; + goto err; } strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); @@ -27,11 +28,15 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) i2c_set_adapdata(&d->i2c_adap, d); - if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) { err("could not add i2c adapter"); + goto err; + } d->state |= DVB_USB_STATE_I2C; +err: return ret; } diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index 28e1fd64dd3c..61439c8f33ca 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -194,8 +194,8 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) err_adapter_init: dvb_usb_adapter_exit(d); -err_i2c_init: dvb_usb_i2c_exit(d); +err_i2c_init: if (d->priv && d->props.priv_destroy) d->props.priv_destroy(d); err_priv_init: diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c index e7b290552b66..9c0eb0d40822 100644 --- a/drivers/media/usb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c @@ -130,7 +130,7 @@ ret: static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) { - int i; + int i, ret; u8 b; mac[0] = 0x00; @@ -139,7 +139,9 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) /* this is a complete guess, but works for my box */ for (i = 136; i < 139; i++) { - dibusb_read_eeprom_byte(d,i, &b); + ret = dibusb_read_eeprom_byte(d, i, &b); + if (ret) + return ret; mac[5 - (i - 136)] = b; } diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index bf54747e2e01..a1d9e4801a2b 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -291,16 +291,22 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { u8 i, *buf; + int ret; struct vp702x_device_state *st = d->priv; mutex_lock(&st->buf_mutex); buf = st->buf; - for (i = 6; i < 12; i++) - vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1); + for (i = 6; i < 12; i++) { + ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, + &buf[i - 6], 1); + if (ret < 0) + goto err; + } memcpy(mac, buf, 6); +err: mutex_unlock(&st->buf_mutex); - return 0; + return ret; } static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 59529cbf9cd0..0b6d77c3bec8 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -842,7 +842,6 @@ error: kfree(ir); ref_put: em28xx_shutdown_buttons(dev); - kref_put(&dev->ref, em28xx_free_device); return err; } diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index f1767be9d868..6650eab913d8 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -691,49 +691,23 @@ struct go7007 *go7007_alloc(const struct go7007_board_info *board, struct device *dev) { struct go7007 *go; - int i; go = kzalloc(sizeof(struct go7007), GFP_KERNEL); if (go == NULL) return NULL; go->dev = dev; go->board_info = board; - go->board_id = 0; go->tuner_type = -1; - go->channel_number = 0; - go->name[0] = 0; mutex_init(&go->hw_lock); init_waitqueue_head(&go->frame_waitq); spin_lock_init(&go->spinlock); go->status = STATUS_INIT; - memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); - go->i2c_adapter_online = 0; - go->interrupt_available = 0; init_waitqueue_head(&go->interrupt_waitq); - go->input = 0; go7007_update_board(go); - go->encoder_h_halve = 0; - go->encoder_v_halve = 0; - go->encoder_subsample = 0; go->format = V4L2_PIX_FMT_MJPEG; go->bitrate = 1500000; go->fps_scale = 1; - go->pali = 0; go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = 0; - go->ipb = 0; - go->closed_gop = 0; - go->repeat_seqhead = 0; - go->seq_header_enable = 0; - go->gop_header_enable = 0; - go->dvd_mode = 0; - go->interlace_coding = 0; - for (i = 0; i < 4; ++i) - go->modet[i].enable = 0; - for (i = 0; i < 1624; ++i) - go->modet_map[i] = 0; - go->audio_deliver = NULL; - go->audio_enabled = 0; return go; } diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index dbf0455d5d50..eeb85981e02b 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1134,7 +1134,7 @@ static int go7007_usb_probe(struct usb_interface *intf, ep = usb->usbdev->ep_in[4]; if (!ep) - return -ENODEV; + goto allocfail; /* Allocate the URB and buffer for receiving incoming interrupts */ usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 0283e3b908e4..dca4e16ed133 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -4,7 +4,6 @@ menuconfig USB_GSPCA depends on VIDEO_V4L2 depends on INPUT || INPUT=n select VIDEOBUF2_VMALLOC - default m help Say Y here if you want to enable selecting webcams based on the GSPCA framework. diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index 4cb7c92ea132..e7a534be061d 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -1796,7 +1796,7 @@ static const u8 ov7660_60HZ[][4] = { {} }; -static const u8 ov7660_NoFliker[][4] = { +static const u8 ov7660_NoFlicker[][4] = { {0x00, 0x13, 0x87, 0xaa}, {} }; @@ -3319,8 +3319,8 @@ static void sethvflip(struct gspca_dev *gspca_dev, bool hflip, bool vflip) static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - static const u8 (*ov7660_freq_tb[3])[4] = - {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ}; + static const u8 (*ov7660_freq_tb[3])[4] = { + ov7660_NoFlicker, ov7660_50HZ, ov7660_60HZ}; if (sd->sensor != SENSOR_OV7660) return; diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index aa285d5d6c0d..5bcbf0d40147 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -323,7 +323,7 @@ static const struct usb_action adcm2700_60HZ[] = { {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ {} }; -static const struct usb_action adcm2700_NoFliker[] = { +static const struct usb_action adcm2700_NoFlicker[] = { {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ @@ -525,7 +525,7 @@ static const struct usb_action cs2102_60HZ[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action cs2102_NoFlikerScale[] = { +static const struct usb_action cs2102_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x23, 0x0001}, {0xaa, 0x24, 0x005f}, @@ -547,7 +547,7 @@ static const struct usb_action cs2102_NoFlikerScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action cs2102_NoFliker[] = { +static const struct usb_action cs2102_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x23, 0x0000}, {0xaa, 0x24, 0x00af}, @@ -1385,7 +1385,7 @@ static const struct usb_action gc0305_60HZ[] = { {} }; -static const struct usb_action gc0305_NoFliker[] = { +static const struct usb_action gc0305_NoFlicker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -1710,7 +1710,7 @@ static const struct usb_action hdcs2020_60HZ[] = { {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ {} }; -static const struct usb_action hdcs2020_NoFliker[] = { +static const struct usb_action hdcs2020_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ @@ -1925,7 +1925,7 @@ static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ {} }; -static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ +static const struct usb_action hv7131b_NoFlicker[] = { /* 640x480*/ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ @@ -1950,7 +1950,7 @@ static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ {} }; -static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ +static const struct usb_action hv7131b_NoFlickerScale[] = { /* 320x240 */ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ @@ -2141,7 +2141,7 @@ static const struct usb_action hv7131r_60HZScale[] = { {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action hv7131r_NoFliker[] = { +static const struct usb_action hv7131r_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, @@ -2159,7 +2159,7 @@ static const struct usb_action hv7131r_NoFliker[] = { {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action hv7131r_NoFlikerScale[] = { +static const struct usb_action hv7131r_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, @@ -2662,7 +2662,7 @@ static const struct usb_action icm105a_60HZ[] = { {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ {} }; -static const struct usb_action icm105a_NoFlikerScale[] = { +static const struct usb_action icm105a_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ @@ -2693,7 +2693,7 @@ static const struct usb_action icm105a_NoFlikerScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ {} }; -static const struct usb_action icm105a_NoFliker[] = { +static const struct usb_action icm105a_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ @@ -3009,7 +3009,7 @@ static const struct usb_action mc501cb_60HZScale[] = { {} }; -static const struct usb_action mc501cb_NoFliker[] = { +static const struct usb_action mc501cb_NoFlicker[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ @@ -3021,7 +3021,7 @@ static const struct usb_action mc501cb_NoFliker[] = { {} }; -static const struct usb_action mc501cb_NoFlikerScale[] = { +static const struct usb_action mc501cb_NoFlickerScale[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ @@ -3211,7 +3211,7 @@ static const struct usb_action ov7620_60HZ[] = { {0xa1, 0x01, 0x0037}, */ {} }; -static const struct usb_action ov7620_NoFliker[] = { +static const struct usb_action ov7620_NoFlicker[] = { {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ /* disable 1/120s & 1/100s exposures for banding filter */ @@ -3827,7 +3827,7 @@ static const struct usb_action pas106b_60HZ[] = { {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ {} }; -static const struct usb_action pas106b_NoFliker[] = { +static const struct usb_action pas106b_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */ @@ -4051,7 +4051,7 @@ static const struct usb_action pas202b_60HZScale[] = { {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ {} }; -static const struct usb_action pas202b_NoFliker[] = { +static const struct usb_action pas202b_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ @@ -4080,7 +4080,7 @@ static const struct usb_action pas202b_NoFliker[] = { {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ {} }; -static const struct usb_action pas202b_NoFlikerScale[] = { +static const struct usb_action pas202b_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ @@ -4309,7 +4309,7 @@ static const struct usb_action mt9v111_1_AE60HZScale[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_1_AENoFliker[] = { +static const struct usb_action mt9v111_1_AENoFlicker[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0509}, @@ -4332,7 +4332,7 @@ static const struct usb_action mt9v111_1_AENoFliker[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_1_AENoFlikerScale[] = { +static const struct usb_action mt9v111_1_AENoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0534}, @@ -4554,7 +4554,7 @@ static const struct usb_action mt9v111_3_AE60HZScale[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_3_AENoFliker[] = { +static const struct usb_action mt9v111_3_AENoFlicker[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x05, 0x0034}, @@ -4577,7 +4577,7 @@ static const struct usb_action mt9v111_3_AENoFliker[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_3_AENoFlikerScale[] = { +static const struct usb_action mt9v111_3_AENoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x05, 0x0034}, @@ -4787,7 +4787,7 @@ static const struct usb_action pb0330_60HZScale[] = { {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action pb0330_NoFliker[] = { +static const struct usb_action pb0330_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0509}, {0xbb, 0x02, 0x0940}, @@ -4809,7 +4809,7 @@ static const struct usb_action pb0330_NoFliker[] = { {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action pb0330_NoFlikerScale[] = { +static const struct usb_action pb0330_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0535}, {0xbb, 0x01, 0x0980}, @@ -5031,7 +5031,7 @@ static const struct usb_action po2030_60HZ[] = { {} }; -static const struct usb_action po2030_NoFliker[] = { +static const struct usb_action po2030_NoFlicker[] = { {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ @@ -5215,7 +5215,7 @@ static const struct usb_action tas5130c_60HZScale[] = { {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, {} }; -static const struct usb_action tas5130c_NoFliker[] = { +static const struct usb_action tas5130c_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */ @@ -5241,7 +5241,7 @@ static const struct usb_action tas5130c_NoFliker[] = { {} }; -static const struct usb_action tas5130c_NoFlikerScale[] = { +static const struct usb_action tas5130c_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */ @@ -5482,7 +5482,7 @@ static const struct usb_action gc0303_60HZScale[] = { {} }; -static const struct usb_action gc0303_NoFliker[] = { +static const struct usb_action gc0303_NoFlicker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -5504,7 +5504,7 @@ static const struct usb_action gc0303_NoFliker[] = { {} }; -static const struct usb_action gc0303_NoFlikerScale[] = { +static const struct usb_action gc0303_NoFlickerScale[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -5806,7 +5806,7 @@ static void setquality(struct gspca_dev *gspca_dev) * Valid frequencies are: * 50Hz, for European and Asian lighting (default) * 60Hz, for American lighting - * 0 = No Fliker (for outdoore usage) + * 0 = No Flicker (for outdoor usage) */ static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { @@ -5814,80 +5814,80 @@ static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) int i, mode; const struct usb_action *zc3_freq; static const struct usb_action *freq_tb[SENSOR_MAX][6] = { - [SENSOR_ADCM2700] = - {adcm2700_NoFliker, adcm2700_NoFliker, + [SENSOR_ADCM2700] = { + adcm2700_NoFlicker, adcm2700_NoFlicker, adcm2700_50HZ, adcm2700_50HZ, adcm2700_60HZ, adcm2700_60HZ}, - [SENSOR_CS2102] = - {cs2102_NoFliker, cs2102_NoFlikerScale, + [SENSOR_CS2102] = { + cs2102_NoFlicker, cs2102_NoFlickerScale, cs2102_50HZ, cs2102_50HZScale, cs2102_60HZ, cs2102_60HZScale}, - [SENSOR_CS2102K] = - {cs2102_NoFliker, cs2102_NoFlikerScale, + [SENSOR_CS2102K] = { + cs2102_NoFlicker, cs2102_NoFlickerScale, NULL, NULL, /* currently disabled */ NULL, NULL}, - [SENSOR_GC0303] = - {gc0303_NoFliker, gc0303_NoFlikerScale, + [SENSOR_GC0303] = { + gc0303_NoFlicker, gc0303_NoFlickerScale, gc0303_50HZ, gc0303_50HZScale, gc0303_60HZ, gc0303_60HZScale}, - [SENSOR_GC0305] = - {gc0305_NoFliker, gc0305_NoFliker, + [SENSOR_GC0305] = { + gc0305_NoFlicker, gc0305_NoFlicker, gc0305_50HZ, gc0305_50HZ, gc0305_60HZ, gc0305_60HZ}, - [SENSOR_HDCS2020] = - {hdcs2020_NoFliker, hdcs2020_NoFliker, + [SENSOR_HDCS2020] = { + hdcs2020_NoFlicker, hdcs2020_NoFlicker, hdcs2020_50HZ, hdcs2020_50HZ, hdcs2020_60HZ, hdcs2020_60HZ}, - [SENSOR_HV7131B] = - {hv7131b_NoFliker, hv7131b_NoFlikerScale, + [SENSOR_HV7131B] = { + hv7131b_NoFlicker, hv7131b_NoFlickerScale, hv7131b_50HZ, hv7131b_50HZScale, hv7131b_60HZ, hv7131b_60HZScale}, - [SENSOR_HV7131R] = - {hv7131r_NoFliker, hv7131r_NoFlikerScale, + [SENSOR_HV7131R] = { + hv7131r_NoFlicker, hv7131r_NoFlickerScale, hv7131r_50HZ, hv7131r_50HZScale, hv7131r_60HZ, hv7131r_60HZScale}, - [SENSOR_ICM105A] = - {icm105a_NoFliker, icm105a_NoFlikerScale, + [SENSOR_ICM105A] = { + icm105a_NoFlicker, icm105a_NoFlickerScale, icm105a_50HZ, icm105a_50HZScale, icm105a_60HZ, icm105a_60HZScale}, - [SENSOR_MC501CB] = - {mc501cb_NoFliker, mc501cb_NoFlikerScale, + [SENSOR_MC501CB] = { + mc501cb_NoFlicker, mc501cb_NoFlickerScale, mc501cb_50HZ, mc501cb_50HZScale, mc501cb_60HZ, mc501cb_60HZScale}, - [SENSOR_MT9V111_1] = - {mt9v111_1_AENoFliker, mt9v111_1_AENoFlikerScale, + [SENSOR_MT9V111_1] = { + mt9v111_1_AENoFlicker, mt9v111_1_AENoFlickerScale, mt9v111_1_AE50HZ, mt9v111_1_AE50HZScale, mt9v111_1_AE60HZ, mt9v111_1_AE60HZScale}, - [SENSOR_MT9V111_3] = - {mt9v111_3_AENoFliker, mt9v111_3_AENoFlikerScale, + [SENSOR_MT9V111_3] = { + mt9v111_3_AENoFlicker, mt9v111_3_AENoFlickerScale, mt9v111_3_AE50HZ, mt9v111_3_AE50HZScale, mt9v111_3_AE60HZ, mt9v111_3_AE60HZScale}, - [SENSOR_OV7620] = - {ov7620_NoFliker, ov7620_NoFliker, + [SENSOR_OV7620] = { + ov7620_NoFlicker, ov7620_NoFlicker, ov7620_50HZ, ov7620_50HZ, ov7620_60HZ, ov7620_60HZ}, - [SENSOR_OV7630C] = - {NULL, NULL, + [SENSOR_OV7630C] = { + NULL, NULL, NULL, NULL, NULL, NULL}, - [SENSOR_PAS106] = - {pas106b_NoFliker, pas106b_NoFliker, + [SENSOR_PAS106] = { + pas106b_NoFlicker, pas106b_NoFlicker, pas106b_50HZ, pas106b_50HZ, pas106b_60HZ, pas106b_60HZ}, - [SENSOR_PAS202B] = - {pas202b_NoFliker, pas202b_NoFlikerScale, + [SENSOR_PAS202B] = { + pas202b_NoFlicker, pas202b_NoFlickerScale, pas202b_50HZ, pas202b_50HZScale, pas202b_60HZ, pas202b_60HZScale}, - [SENSOR_PB0330] = - {pb0330_NoFliker, pb0330_NoFlikerScale, + [SENSOR_PB0330] = { + pb0330_NoFlicker, pb0330_NoFlickerScale, pb0330_50HZ, pb0330_50HZScale, pb0330_60HZ, pb0330_60HZScale}, - [SENSOR_PO2030] = - {po2030_NoFliker, po2030_NoFliker, + [SENSOR_PO2030] = { + po2030_NoFlicker, po2030_NoFlicker, po2030_50HZ, po2030_50HZ, po2030_60HZ, po2030_60HZ}, - [SENSOR_TAS5130C] = - {tas5130c_NoFliker, tas5130c_NoFlikerScale, + [SENSOR_TAS5130C] = { + tas5130c_NoFlicker, tas5130c_NoFlickerScale, tas5130c_50HZ, tas5130c_50HZScale, tas5130c_60HZ, tas5130c_60HZScale}, }; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a45d464427c4..0e231e576dc3 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1346,7 +1346,7 @@ static int stk_camera_probe(struct usb_interface *interface, if (!dev->isoc_ep) { pr_err("Could not find isoc-in endpoint\n"); err = -ENODEV; - goto error; + goto error_put; } dev->vsettings.palette = V4L2_PIX_FMT_RGB565; dev->vsettings.mode = MODE_VGA; @@ -1359,10 +1359,12 @@ static int stk_camera_probe(struct usb_interface *interface, err = stk_register_video_device(dev); if (err) - goto error; + goto error_put; return 0; +error_put: + usb_put_intf(interface); error: v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 252136cc885c..6acb8013de08 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -899,8 +899,8 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) { struct uvc_fh *handle = fh; struct uvc_video_chain *chain = handle->chain; + u8 *buf; int ret; - u8 i; if (chain->selector == NULL || (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { @@ -908,22 +908,27 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return 0; } + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, chain->selector->id, chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, - &i, 1); - if (ret < 0) - return ret; + buf, 1); + if (!ret) + *input = *buf - 1; - *input = i - 1; - return 0; + kfree(buf); + + return ret; } static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) { struct uvc_fh *handle = fh; struct uvc_video_chain *chain = handle->chain; + u8 *buf; int ret; - u32 i; ret = uvc_acquire_privileges(handle); if (ret < 0) @@ -939,10 +944,17 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) if (input >= chain->selector->bNrInPins) return -EINVAL; - i = input + 1; - return uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id, - chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, - &i, 1); + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *buf = input + 1; + ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id, + chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, + buf, 1); + kfree(buf); + + return ret; } static int uvc_ioctl_queryctrl(struct file *file, void *fh, diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index b6344bbf1e00..421300e13a41 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -833,6 +833,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: return "Intra Refresh Period"; case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; @@ -1258,6 +1259,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: *type = V4L2_CTRL_TYPE_INTEGER; break; case V4L2_CID_MPEG_VIDEO_LTR_COUNT: diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 230d65a64217..af48705c704f 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -196,7 +196,7 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, if (!v4l2_valid_dv_timings(t, cap, fnc, fnc_handle)) return false; - for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, fnc, fnc_handle) && v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, @@ -218,7 +218,7 @@ bool v4l2_find_dv_timings_cea861_vic(struct v4l2_dv_timings *t, u8 vic) { unsigned int i; - for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 10ddcc48aa17..e70e128ccc9c 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -76,10 +76,11 @@ static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl, return (brightness * ctrl->step) + ctrl->minimum; } -static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, - struct v4l2_ctrl *ctrl) +static int v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, + struct v4l2_ctrl *ctrl) { struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; + struct led_classdev *led_cdev; enum led_brightness brightness; if (has_flash_op(v4l2_flash, intensity_to_led_brightness)) @@ -102,14 +103,20 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, if (ctrl == ctrls[TORCH_INTENSITY]) { if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) - return; + return 0; - led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev, - brightness); + if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) + return -EINVAL; + + led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { - led_set_brightness_sync(v4l2_flash->iled_cdev, - brightness); + if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) + return -EINVAL; + + led_cdev = v4l2_flash->iled_cdev; } + + return led_set_brightness_sync(led_cdev, brightness); } static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, @@ -128,8 +135,15 @@ static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, */ if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) return 0; + + if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) + return -EINVAL; + led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { + if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) + return -EINVAL; + led_cdev = v4l2_flash->iled_cdev; } @@ -159,6 +173,12 @@ static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c) case V4L2_CID_FLASH_TORCH_INTENSITY: case V4L2_CID_FLASH_INDICATOR_INTENSITY: return v4l2_flash_update_led_brightness(v4l2_flash, c); + } + + if (!fled_cdev) + return -EINVAL; + + switch (c->id) { case V4L2_CID_FLASH_INTENSITY: ret = led_update_flash_brightness(fled_cdev); if (ret < 0) @@ -194,12 +214,23 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) { struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c); struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; + struct led_classdev *led_cdev; struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; bool external_strobe; int ret = 0; switch (c->id) { + case V4L2_CID_FLASH_TORCH_INTENSITY: + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + return v4l2_flash_set_led_brightness(v4l2_flash, c); + } + + if (!fled_cdev) + return -EINVAL; + + led_cdev = &fled_cdev->led_cdev; + + switch (c->id) { case V4L2_CID_FLASH_LED_MODE: switch (c->val) { case V4L2_FLASH_LED_MODE_NONE: @@ -230,9 +261,8 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) if (ret < 0) return ret; - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[TORCH_INTENSITY]); - return 0; + return v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[TORCH_INTENSITY]); } break; case V4L2_CID_FLASH_STROBE_SOURCE: @@ -268,10 +298,6 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) * microamperes for flash intensity units. */ return led_set_flash_brightness(fled_cdev, c->val); - case V4L2_CID_FLASH_TORCH_INTENSITY: - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - v4l2_flash_set_led_brightness(v4l2_flash, c); - return 0; } return -EINVAL; @@ -483,15 +509,24 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; int ret = 0; - if (ctrls[TORCH_INTENSITY]) - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[TORCH_INTENSITY]); + if (ctrls[TORCH_INTENSITY]) { + ret = v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[TORCH_INTENSITY]); + if (ret < 0) + return ret; + } - if (ctrls[INDICATOR_INTENSITY]) - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[INDICATOR_INTENSITY]); + if (ctrls[INDICATOR_INTENSITY]) { + ret = v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[INDICATOR_INTENSITY]); + if (ret < 0) + return ret; + } if (ctrls[FLASH_TIMEOUT]) { + if (WARN_ON_ONCE(!fled_cdev)) + return -EINVAL; + ret = led_set_flash_timeout(fled_cdev, ctrls[FLASH_TIMEOUT]->val); if (ret < 0) @@ -499,6 +534,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) } if (ctrls[FLASH_INTENSITY]) { + if (WARN_ON_ONCE(!fled_cdev)) + return -EINVAL; + ret = led_set_flash_brightness(fled_cdev, ctrls[FLASH_INTENSITY]->val); if (ret < 0) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 9363c1a52ae9..4d769590f2d3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -849,21 +849,14 @@ static int gc2235_get_fmt(struct v4l2_subdev *sd, static int gc2235_detect(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; + u16 high = 0, low = 0; u16 id; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_L, &low); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_H, &high); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_L, &low); id = ((high << 8) | low); if (id != GC2235_ID) { diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 11196180a206..49f4090856d3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -570,14 +570,13 @@ static int power_down(struct v4l2_subdev *sd) static int mt9m114_s_power(struct v4l2_subdev *sd, int power) { - if (power == 0) { + if (power == 0) return power_down(sd); - } else { - if (power_up(sd)) - return -EINVAL; - return mt9m114_init_common(sd); - } + if (power_up(sd)) + return -EINVAL; + + return mt9m114_init_common(sd); } /* @@ -1545,16 +1544,19 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u32 retvalue; + u32 model; + int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c error", __func__); return -ENODEV; } - mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); - dev->real_model_id = retvalue; + ret = mt9m114_read_reg(client, MISENSOR_16BIT, MT9M114_PID, &model); + if (ret) + return ret; + dev->real_model_id = model; - if (retvalue != MT9M114_MOD_ID) { + if (model != MT9M114_MOD_ID) { dev_err(&client->dev, "%s: failed: client->addr = %x\n", __func__, client->addr); return -ENODEV; diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 4d43b45915e5..874115f35fca 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -627,7 +627,7 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = { {0x5706, 0x0c}, {0x5707, 0x78}, {0x3820, 0xc0}, - {0x3821, 0x00}, //miror/flip + {0x3821, 0x00}, //mirror/flip // {0x5090, 0x0c}, {} }; diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 0828ca9ab6f2..5e3670c4fc29 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -932,7 +932,7 @@ err: static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -EINVAL; + int ret; u8 vcm_code; ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index a60551450c45..c16eaf3d126f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -83,8 +83,6 @@ int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd, void ia_css_mmu_invalidate_cache(void); -void ia_css_mmu_invalidate_cache(void); - int atomisp_css_start(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id, bool in_reset); diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index f60198bb8a1a..99a632f33d2d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -2102,9 +2102,6 @@ void atomisp_css_stop(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id, bool in_reset) { struct atomisp_device *isp = asd->isp; - struct atomisp_s3a_buf *s3a_buf; - struct atomisp_dis_buf *dis_buf; - struct atomisp_metadata_buf *md_buf; unsigned long irqflags; unsigned int i; @@ -2144,42 +2141,17 @@ void atomisp_css_stop(struct atomisp_sub_device *asd, } /* move stats buffers to free queue list */ - while (!list_empty(&asd->s3a_stats_in_css)) { - s3a_buf = list_entry(asd->s3a_stats_in_css.next, - struct atomisp_s3a_buf, list); - list_del(&s3a_buf->list); - list_add_tail(&s3a_buf->list, &asd->s3a_stats); - } - while (!list_empty(&asd->s3a_stats_ready)) { - s3a_buf = list_entry(asd->s3a_stats_ready.next, - struct atomisp_s3a_buf, list); - list_del(&s3a_buf->list); - list_add_tail(&s3a_buf->list, &asd->s3a_stats); - } + list_splice_init(&asd->s3a_stats_in_css, &asd->s3a_stats); + list_splice_init(&asd->s3a_stats_ready, &asd->s3a_stats); spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - while (!list_empty(&asd->dis_stats_in_css)) { - dis_buf = list_entry(asd->dis_stats_in_css.next, - struct atomisp_dis_buf, list); - list_del(&dis_buf->list); - list_add_tail(&dis_buf->list, &asd->dis_stats); - } + list_splice_init(&asd->dis_stats_in_css, &asd->dis_stats); asd->params.dis_proj_data_valid = false; spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { - while (!list_empty(&asd->metadata_in_css[i])) { - md_buf = list_entry(asd->metadata_in_css[i].next, - struct atomisp_metadata_buf, list); - list_del(&md_buf->list); - list_add_tail(&md_buf->list, &asd->metadata[i]); - } - while (!list_empty(&asd->metadata_ready[i])) { - md_buf = list_entry(asd->metadata_ready[i].next, - struct atomisp_metadata_buf, list); - list_del(&md_buf->list); - list_add_tail(&md_buf->list, &asd->metadata[i]); - } + list_splice_init(&asd->metadata_in_css[i], &asd->metadata[i]); + list_splice_init(&asd->metadata_ready[i], &asd->metadata[i]); } atomisp_flush_params_queue(&asd->video_out_capture); diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 56456e59bf89..11b6b1216473 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -28,7 +28,8 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence - which, unsigned int pad) { + which, unsigned int pad) +{ if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, pad); diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c index f670faf978e6..dcb571f515a7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c @@ -96,7 +96,7 @@ opt_err: static ssize_t iunit_dbglvl_show(struct device_driver *drv, char *buf) { iunit_debug.dbglvl = dbg_level; - return sprintf(buf, "dtrace level:%u\n", iunit_debug.dbglvl); + return sysfs_emit(buf, "dtrace level:%u\n", iunit_debug.dbglvl); } static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, @@ -115,7 +115,7 @@ static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgfun_show(struct device_driver *drv, char *buf) { iunit_debug.dbgfun = atomisp_get_css_dbgfunc(); - return sprintf(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); + return sysfs_emit(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); } static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, @@ -139,7 +139,7 @@ static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgopt_show(struct device_driver *drv, char *buf) { - return sprintf(buf, "option:0x%x\n", iunit_debug.dbgopt); + return sysfs_emit(buf, "option:0x%x\n", iunit_debug.dbgopt); } static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf, diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 135994d44802..d8c9e31314b2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1040,10 +1040,10 @@ static struct camera_sensor_platform_data acpi_gmin_plat = { .get_vcm_ctrl = gmin_get_vcm_ctrl, }; -struct camera_sensor_platform_data *gmin_camera_platform_data( - struct v4l2_subdev *subdev, - enum atomisp_input_format csi_format, - enum atomisp_bayer_order csi_bayer) +struct camera_sensor_platform_data * +gmin_camera_platform_data(struct v4l2_subdev *subdev, + enum atomisp_input_format csi_format, + enum atomisp_bayer_order csi_bayer) { u8 pmic_i2c_addr = gmin_detect_pmic(subdev); struct gmin_subdev *gs; diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 948769ca6539..1e324f1f656e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1763,7 +1763,8 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i if (err < 0) goto register_entities_fail; /* init atomisp wdts */ - if (init_atomisp_wdts(isp) != 0) + err = init_atomisp_wdts(isp); + if (err != 0) goto wdt_work_queue_fail; /* save the iunit context only once after all the values are init'ed. */ @@ -1815,6 +1816,7 @@ request_irq_fail: hmm_cleanup(); hmm_pool_unregister(HMM_POOL_TYPE_RESERVED); hmm_pool_fail: + pm_runtime_get_noresume(&pdev->dev); destroy_workqueue(isp->wdt_work_queue); wdt_work_queue_fail: atomisp_acc_cleanup(isp); diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 0f5a231672a8..8e085dda0c18 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -174,8 +174,6 @@ void input_system_get_state( ctrl_unit_get_state(ID, sub_id, &state->ctrl_unit_state[sub_id - CTRL_UNIT0_ID]); } - - return; } void receiver_get_state( @@ -246,8 +244,6 @@ void receiver_get_state( _HRT_CSS_RECEIVER_BE_IRQ_STATUS_REG_IDX); state->be_irq_clear = receiver_reg_load(ID, _HRT_CSS_RECEIVER_BE_IRQ_CLEAR_REG_IDX); - - return; } bool is_mipi_format_yuv420( @@ -310,8 +306,6 @@ void receiver_set_compression( reg = ((field_id < 6) ? (val << (field_id * 5)) : (val << (( field_id - 6) * 5))); receiver_reg_store(ID, addr, reg); - - return; } void receiver_port_enable( @@ -330,7 +324,6 @@ void receiver_port_enable( receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX, reg); - return; } bool is_receiver_port_enabled( @@ -349,7 +342,6 @@ void receiver_irq_enable( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX, irq_info); - return; } rx_irq_info_t receiver_get_irq_info( @@ -367,7 +359,6 @@ void receiver_irq_clear( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX, irq_info); - return; } static inline void capture_unit_get_state( @@ -428,8 +419,6 @@ static inline void capture_unit_get_state( state->FSM_State_Info = input_system_sub_system_reg_load(ID, sub_id, CAPT_FSM_STATE_INFO_REG_ID); - - return; } static inline void acquisition_unit_get_state( @@ -478,8 +467,6 @@ static inline void acquisition_unit_get_state( state->Int_Cntr_Info = input_system_sub_system_reg_load(ID, sub_id, ACQ_INT_CNTR_INFO_REG_ID); - - return; } static inline void ctrl_unit_get_state( @@ -561,8 +548,6 @@ static inline void ctrl_unit_get_state( state->capt_reserve_one_mem_region = input_system_sub_system_reg_load(ID, sub_id, ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID); - - return; } static inline void mipi_port_get_state( @@ -597,8 +582,6 @@ static inline void mipi_port_get_state( state->lane_sync_count[i] = (uint8_t)((state->sync_count) >> (i * 8)); state->lane_rx_count[i] = (uint8_t)((state->rx_count) >> (i * 8)); } - - return; } static inline void rx_channel_get_state( @@ -652,8 +635,6 @@ static inline void rx_channel_get_state( state->comp[i] = (mipi_compressor_t)(val & 0x07); state->pred[i] = (mipi_predictor_t)((val & 0x18) >> 3); } - - return; } // MW: "2400" in the name is not good, but this is to avoid a naming conflict @@ -672,8 +653,6 @@ static void receiver_rst( } // AM: Additional actions for stopping receiver? - - return; } //Single function to reset all the devices mapped via GP_DEVICE. @@ -722,8 +701,6 @@ static void gp_device_rst(const gp_device_ID_t ID) // gp_device_reg_store(ID, _REG_GP_SYNCGEN_FRAME_CNT_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_SOFT_RESET_ADDR, ZERO); // AM: Maybe this soft reset is not safe. - - return; } static void input_selector_cfg_for_sensor(const gp_device_ID_t ID) @@ -740,8 +717,6 @@ static void input_selector_cfg_for_sensor(const gp_device_ID_t ID) gp_device_reg_store(ID, _REG_GP_ISEL_SBAND_SEL_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_ISEL_SYNC_SEL_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_SOFT_RESET_ADDR, ZERO); - - return; } static void input_switch_rst(const gp_device_ID_t ID) @@ -760,8 +735,6 @@ static void input_switch_rst(const gp_device_ID_t ID) gp_device_reg_store(ID, _REG_GP_IFMT_input_switch_fsync_lut, ZERO); - - return; } static void input_switch_cfg( @@ -786,8 +759,6 @@ static void input_switch_cfg( gp_device_reg_store(ID, _REG_GP_IFMT_input_switch_fsync_lut, cfg->vsync_data_reg); - - return; } static void input_system_network_rst(const input_system_ID_t ID) @@ -843,8 +814,6 @@ static void input_system_network_rst(const input_system_ID_t ID) ISYS_CTRL_INIT_REG_ID, 1U); //AM: Is there any named constant? } - - return; } // Function that resets current configuration. @@ -903,17 +872,10 @@ static input_system_err_t input_system_configure_channel( error = input_system_configure_channel_sensor(channel); break; case INPUT_SYSTEM_SOURCE_TPG: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_SOURCE_PRBS: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_SOURCE_FIFO: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } if (error != INPUT_SYSTEM_ERR_NO_ERROR) return error; @@ -995,7 +957,6 @@ static input_system_err_t input_buffer_configuration(void) default: config.csi_buffer_flags[port] |= INPUT_SYSTEM_CFG_FLAG_CONFLICT; return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } // Check acquisition buffer specified but set it later since it has to be unique. @@ -1032,7 +993,6 @@ static input_system_err_t input_buffer_configuration(void) default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } } else { config.csi_buffer_flags[port] = INPUT_SYSTEM_CFG_FLAG_BLOCKED; @@ -1081,8 +1041,6 @@ static void capture_unit_configure( sub_id, CAPT_NUM_MEM_REGIONS_REG_ID, cfg->nof_mem_regs); - - return; } static void acquisition_unit_configure( @@ -1106,8 +1064,6 @@ static void acquisition_unit_configure( sub_id, ACQ_MEM_REGION_SIZE_REG_ID, cfg->mem_reg_size); - - return; } static void ctrl_unit_configure( @@ -1174,7 +1130,6 @@ static void ctrl_unit_configure( sub_id, ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID, 0); - return; } static void input_system_network_configure( @@ -1232,8 +1187,6 @@ static void input_system_network_configure( sub_id, &cfg->ctrl_unit_cfg[sub_id - CTRL_UNIT0_ID]); } - - return; } static input_system_err_t configuration_to_registers(void) @@ -1307,19 +1260,12 @@ static input_system_err_t configuration_to_registers(void) break; case INPUT_SYSTEM_SOURCE_TPG: - - break; - case INPUT_SYSTEM_SOURCE_PRBS: - - break; - case INPUT_SYSTEM_SOURCE_FIFO: break; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } // end of switch (source_type) @@ -1695,19 +1641,11 @@ static input_system_err_t input_system_configure_channel_sensor( break; case INPUT_SYSTEM_FIFO_CAPTURE_WITH_COUNTING: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_XMEM_CAPTURE: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_XMEM_ACQUIRE: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } - return INPUT_SYSTEM_ERR_NO_ERROR; } // Test flags and set structure. diff --git a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h index c801ddd71192..b2076a96987c 100644 --- a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h +++ b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h @@ -27,7 +27,7 @@ // Number of registers #define ISYS_CTRL_NOF_REGS 23 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define ISYS_CTRL_CAPT_START_ADDR_A_REG_ID 0 #define ISYS_CTRL_CAPT_START_ADDR_B_REG_ID 1 #define ISYS_CTRL_CAPT_START_ADDR_C_REG_ID 2 diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h index be3534e46c15..9b22f2da45d5 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h @@ -17,8 +17,8 @@ #define __IA_CSS_ANR_TYPES_H /* @file -* CSS-API header file for Advanced Noise Reduction kernel v1 -*/ + * CSS-API header file for Advanced Noise Reduction kernel v1 + */ /* Application specific DMA settings */ #define ANR_BPP 10 diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 072a92199e05..2614b89b8e34 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -356,41 +356,13 @@ struct rx_cfg_s { }; /* NOTE: The base has already an offset of 0x0100 */ -static const hrt_address MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { +static const hrt_address __maybe_unused MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000000UL, 0x00000100UL, 0x00000200UL }; -static const mipi_lane_cfg_t MIPI_PORT_MAXLANES[N_MIPI_PORT_ID] = { - MIPI_4LANE_CFG, - MIPI_1LANE_CFG, - MIPI_2LANE_CFG -}; - -static const bool MIPI_PORT_ACTIVE[N_RX_MODE][N_MIPI_PORT_ID] = { - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, true}, - {true, true, true}, - {true, true, true}, - {true, true, true} -}; - -static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { - {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} -}; - -static const hrt_address SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { +static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x00001000UL, 0x00002000UL, 0x00003000UL, diff --git a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h index 8e4bddc3790d..7e8f6f2178aa 100644 --- a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h @@ -35,7 +35,7 @@ #define NOF_ACQ_REGS 12 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define ACQ_START_ADDR_REG_ID 0 #define ACQ_MEM_REGION_SIZE_REG_ID 1 #define ACQ_NUM_MEM_REGIONS_REG_ID 2 diff --git a/drivers/staging/media/atomisp/pci/isp_capture_defs.h b/drivers/staging/media/atomisp/pci/isp_capture_defs.h index 14cbb6390d3e..b9e5ed932702 100644 --- a/drivers/staging/media/atomisp/pci/isp_capture_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_capture_defs.h @@ -33,7 +33,7 @@ // Number of registers #define CAPT_NOF_REGS 16 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define CAPT_START_MODE_REG_ID 0 #define CAPT_START_ADDR_REG_ID 1 #define CAPT_MEM_REGION_SIZE_REG_ID 2 diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index 4a18da6bf0c1..af153c3fb86d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -476,10 +476,20 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( #endif #if !defined(ISP2401) +static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { + {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} +}; + void ia_css_isys_rx_configure(const rx_cfg_t *config, const enum ia_css_input_mode input_mode) { - bool port_enabled[N_MIPI_PORT_ID]; bool any_port_enabled = false; enum mipi_port_id port; @@ -516,8 +526,6 @@ void ia_css_isys_rx_configure(const rx_cfg_t *config, _HRT_CSS_RECEIVER_2400_RX_COUNT_REG_IDX, config->rxcount); - port_enabled[port] = true; - if (input_mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { /* MW: A bit of a hack, straight wiring of the capture * units,assuming they are linearly enumerated. */ diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index d26b1301eeb7..c4b35cbab373 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -3224,24 +3224,22 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, #ifdef ISP2401 static unsigned int -get_crop_lines_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; } static unsigned int -get_crop_columns_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; @@ -5170,7 +5168,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, if (binary) { err = ia_css_binary_3a_grid_info(binary, info, pipe); if (err) - goto ERR; + goto err; } else { memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); } @@ -5181,10 +5179,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, ia_css_binary_dvs_grid_info(binary, info, pipe); ia_css_binary_dvs_stat_grid_info(binary, info, pipe); } else { - memset(&info->dvs_grid.dvs_grid_info, 0, - sizeof(info->dvs_grid.dvs_grid_info)); - memset(&info->dvs_grid.dvs_stat_grid_info, 0, - sizeof(info->dvs_grid.dvs_stat_grid_info)); + memset(&info->dvs_grid, 0, sizeof(info->dvs_grid)); } if (binary) { @@ -5195,7 +5190,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, info->vamem_type = IA_CSS_VAMEM_TYPE_2; -ERR : +err: IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } @@ -5328,14 +5323,15 @@ static int load_video_binaries(struct ia_css_pipe *pipe) if (err) return err; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage - * sizeof(bool), GFP_KERNEL); + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, + sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; return err; @@ -5938,14 +5934,15 @@ static int load_primary_binaries( return err; } mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -6989,14 +6986,14 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) goto ERR; mycs->num_output = cas_scaler_descr.num_output_stage; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; goto ERR; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -7097,7 +7094,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) mycs->num_vf_pp = 1; } - mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * + mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->vf_pp_binary) { @@ -10162,7 +10159,7 @@ ia_css_stop_sp(void) timeout--; udelay(1); } - if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)) + if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED) IA_CSS_WARNING("SP has not terminated (SW)"); if (timeout == 0) { diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index f4ce8ace9d50..e1a16a50e588 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -363,10 +363,8 @@ void sh_css_unload_firmware(void) unsigned int i = 0; for (i = 0; i < sh_css_num_binaries; i++) { - if (fw_minibuffer[i].name) - kfree((void *)fw_minibuffer[i].name); - if (fw_minibuffer[i].buffer) - kvfree(fw_minibuffer[i].buffer); + kfree(fw_minibuffer[i].name); + kvfree(fw_minibuffer[i].buffer); } kfree(fw_minibuffer); fw_minibuffer = NULL; diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 3f34cc81be87..75489f7d75ee 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -91,7 +91,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, const enum atomisp_input_format format, const bool hasSOLandEOL, const unsigned int embedded_data_size_words, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ int err = 0; unsigned int bits_per_pixel = 0; @@ -118,8 +119,7 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n", width_padded, height, format, hasSOLandEOL, embedded_data_size_words); - switch (format) - { + switch (format) { case ATOMISP_INPUT_FORMAT_RAW_6: /* 4p, 3B, 24bits */ bits_per_pixel = 6; break; @@ -178,12 +178,10 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 || format == ATOMISP_INPUT_FORMAT_YUV420_10 - || format == ATOMISP_INPUT_FORMAT_YUV420_16) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_16) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -236,7 +234,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, #if !defined(ISP2401) int ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, - const unsigned int size_mem_words) { + const unsigned int size_mem_words) +{ u32 idx; int err = -EBUSY; @@ -246,11 +245,9 @@ ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT && my_css.mipi_sizes_for_check[port][idx] != 0; - idx++) /* do nothing */ - { + idx++) { /* do nothing */ } - if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) - { + if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) { my_css.mipi_sizes_for_check[port][idx] = size_mem_words; err = 0; } @@ -271,7 +268,8 @@ mipi_init(void) int calculate_mipi_buff_size( struct ia_css_stream_config *stream_cfg, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ #if !defined(ISP2401) int err = -EINVAL; (void)stream_cfg; @@ -346,12 +344,10 @@ calculate_mipi_buff_size( /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 - || format == ATOMISP_INPUT_FORMAT_YUV420_10) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_10) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -393,7 +389,8 @@ static bool buffers_needed(struct ia_css_pipe *pipe) int allocate_mipi_frames(struct ia_css_pipe *pipe, - struct ia_css_stream_info *info) { + struct ia_css_stream_info *info) +{ int err = -EINVAL; unsigned int port; @@ -402,8 +399,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, assert(pipe); assert(pipe->stream); - if ((!pipe) || (!pipe->stream)) - { + if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: pipe or stream is null.\n", pipe); @@ -411,8 +407,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } #ifdef ISP2401 - if (pipe->stream->config.online) - { + if (pipe->stream->config.online) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n", pipe); @@ -449,8 +444,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, #endif #if !defined(ISP2401) - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n", pipe, port); @@ -462,8 +456,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, * TODO AM: Once that is changed (removed) this code should be removed as well. * In that case only 2400 related code should remain. */ - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ref_count_mipi_allocation[port]++; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n", @@ -481,8 +474,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, { /* limit the scope of i,j */ unsigned int i, j; - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* free previous frame */ if (my_css.mipi_frames[port][i]) { ia_css_frame_free(my_css.mipi_frames[port][i]); @@ -535,7 +527,8 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } int -free_mipi_frames(struct ia_css_pipe *pipe) { +free_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int port; @@ -543,8 +536,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { "free_mipi_frames(%p) enter:\n", pipe); /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */ - if (pipe) - { + if (pipe) { assert(pipe->stream); if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, @@ -620,8 +612,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } #endif } - } else /* pipe ==NULL */ - { + } else { /* pipe ==NULL */ /* AM TEMP: free-ing all mipi buffers just like a legacy code. */ for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) { unsigned int i; @@ -645,7 +636,8 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } int -send_mipi_frames(struct ia_css_pipe *pipe) { +send_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int i; #ifndef ISP2401 @@ -658,8 +650,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { assert(pipe); assert(pipe->stream); - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("pipe or stream is null"); return -EINVAL; } @@ -686,8 +677,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { } /* Hand-over the SP-internal mipi buffers */ - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* Need to include the ofset for port. */ sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i, my_css.mipi_frames[port][i]); @@ -700,8 +690,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { * Send an event to inform the SP * that all MIPI frames are passed. **********************************/ - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { /* SP is not running. The queues are not valid */ IA_CSS_ERROR("sp is not running"); return err; diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 644e14575987..dbd3bfe3d343 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -813,15 +813,15 @@ convert_allocate_fpntbl(struct ia_css_isp_parameters *params) } static int -store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) { +store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) +{ struct ia_css_host_data *isp_data; assert(params); assert(ptr != mmgr_NULL); isp_data = convert_allocate_fpntbl(params); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -894,7 +894,8 @@ ia_css_process_kernel(struct ia_css_stream *stream, static int sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, - bool *is_dp_10bpp) { + bool *is_dp_10bpp) +{ int err = 0; /* Currently we check if 10bpp DPC configuration is required based * on the use case,i.e. if BDS and DPC is both enabled. The more cleaner @@ -903,12 +904,10 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, * implementation. (This is because the configuration is set before a * binary is selected, and the binary info is not available) */ - if ((!pipe) || (!is_dp_10bpp)) - { + if ((!pipe) || (!is_dp_10bpp)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); err = -EINVAL; - } else - { + } else { *is_dp_10bpp = false; /* check if DPC is enabled from the host */ @@ -936,7 +935,8 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, int sh_css_set_black_frame(struct ia_css_stream *stream, - const struct ia_css_frame *raw_black_frame) { + const struct ia_css_frame *raw_black_frame) +{ struct ia_css_isp_parameters *params; /* this function desperately needs to be moved to the ISP or SP such * that it can use the DMA. @@ -957,13 +957,11 @@ sh_css_set_black_frame(struct ia_css_stream *stream, IA_CSS_ENTER_PRIVATE("black_frame=%p", raw_black_frame); if (params->fpn_config.data && - (params->fpn_config.width != width || params->fpn_config.height != height)) - { + (params->fpn_config.width != width || params->fpn_config.height != height)) { kvfree(params->fpn_config.data); params->fpn_config.data = NULL; } - if (!params->fpn_config.data) - { + if (!params->fpn_config.data) { params->fpn_config.data = kvmalloc(height * width * sizeof(short), GFP_KERNEL); if (!params->fpn_config.data) { @@ -977,8 +975,7 @@ sh_css_set_black_frame(struct ia_css_stream *stream, } /* store raw to fpntbl */ - for (y = 0; y < height; y++) - { + for (y = 0; y < height; y++) { for (x = 0; x < width; x += (ISP_VEC_NELEMS * 2)) { int ofs = y * width + x; @@ -1181,7 +1178,8 @@ sh_css_enable_pipeline(const struct ia_css_binary *binary) static int ia_css_process_zoom_and_motion( struct ia_css_isp_parameters *params, - const struct ia_css_pipeline_stage *first_stage) { + const struct ia_css_pipeline_stage *first_stage) +{ /* first_stage can be NULL */ const struct ia_css_pipeline_stage *stage; int err = 0; @@ -1195,8 +1193,7 @@ ia_css_process_zoom_and_motion( IA_CSS_ENTER_PRIVATE(""); /* Go through all stages to udate uds and cropping */ - for (stage = first_stage; stage; stage = stage->next) - { + for (stage = first_stage; stage; stage = stage->next) { struct ia_css_binary *binary; /* note: the var below is made static as it is quite large; if it is not static it ends up on the stack which could @@ -1581,7 +1578,8 @@ err: int ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, - const struct ia_css_isp_3a_statistics *isp_stats) { + const struct ia_css_isp_3a_statistics *isp_stats) +{ struct ia_css_isp_3a_statistics_map *map; int ret = 0; @@ -1591,13 +1589,11 @@ ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, assert(isp_stats); map = ia_css_isp_3a_statistics_map_allocate(isp_stats, NULL); - if (map) - { + if (map) { hmm_load(isp_stats->data_ptr, map->data_ptr, isp_stats->size); ia_css_translate_3a_statistics(host_stats, map); ia_css_isp_3a_statistics_map_free(map); - } else - { + } else { IA_CSS_ERROR("out of memory"); ret = -ENOMEM; } @@ -1894,7 +1890,8 @@ sh_css_pipe_isp_config_get(struct ia_css_pipe *pipe) int ia_css_stream_set_isp_config( struct ia_css_stream *stream, - const struct ia_css_isp_config *config) { + const struct ia_css_isp_config *config) +{ return ia_css_stream_set_isp_config_on_pipe(stream, config, NULL); } @@ -1902,7 +1899,8 @@ int ia_css_stream_set_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; if ((!stream) || (!config)) @@ -1923,7 +1921,8 @@ ia_css_stream_set_isp_config_on_pipe( int ia_css_pipe_set_isp_config(struct ia_css_pipe *pipe, - struct ia_css_isp_config *config) { + struct ia_css_isp_config *config) +{ struct ia_css_pipe *pipe_in = pipe; int err = 0; @@ -1948,7 +1947,8 @@ static int sh_css_set_global_isp_config_on_pipe( struct ia_css_pipe *curr_pipe, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; int err1 = 0; int err2 = 0; @@ -1977,7 +1977,8 @@ static int sh_css_set_per_frame_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ unsigned int i; bool per_frame_config_created = false; int err = 0; @@ -1991,8 +1992,7 @@ sh_css_set_per_frame_isp_config_on_pipe( IA_CSS_ENTER_PRIVATE("stream=%p, config=%p, pipe=%p", stream, config, pipe); - if (!pipe) - { + if (!pipe) { err = -EINVAL; goto exit; } @@ -2000,8 +2000,7 @@ sh_css_set_per_frame_isp_config_on_pipe( /* create per-frame ISP params object with default values * from stream->isp_params_configs if one doesn't already exist */ - if (!stream->per_frame_isp_params_configs) - { + if (!stream->per_frame_isp_params_configs) { err = sh_css_create_isp_params(stream, &stream->per_frame_isp_params_configs); if (err) @@ -2012,15 +2011,13 @@ sh_css_set_per_frame_isp_config_on_pipe( params = stream->per_frame_isp_params_configs; /* update new ISP params object with the new config */ - if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) - { + if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) { err1 = -EINVAL; } err2 = sh_css_init_isp_params_from_config(stream->pipes[0], params, config, pipe); - if (per_frame_config_created) - { + if (per_frame_config_created) { ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ @@ -2051,7 +2048,8 @@ static int sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, struct ia_css_isp_parameters *params, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; bool is_dp_10bpp = true; @@ -2096,8 +2094,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, } if (0 == - sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) - { + sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) { /* return an error when both DPC and BDS is enabled by the * user. */ /* we do not exit from this point immediately to allow internal @@ -2105,8 +2102,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, if (is_dp_10bpp) { err = -EINVAL; } - } else - { + } else { err = -EINVAL; goto exit; } @@ -2359,7 +2355,8 @@ static unsigned int g_param_buffer_dequeue_count; static unsigned int g_param_buffer_enqueue_count; int -ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { +ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) +{ int err = 0; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2369,8 +2366,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { assert(stream); IA_CSS_ENTER_PRIVATE("void"); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -2385,8 +2381,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { goto ERR; params = stream->isp_params_configs; - if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) - { + if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) { /* we do not return the error immediately to enable internal * firmware feature testing */ err = -EINVAL; @@ -2396,8 +2391,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { ref_sh_css_ddr_address_map(ddr_ptrs, ¶ms->pipe_ddr_ptrs[i]); params->pipe_ddr_ptrs_size[i] = *ddr_ptrs_size; } @@ -2431,7 +2425,8 @@ ia_css_set_sdis2_config( static int sh_css_create_isp_params(struct ia_css_stream *stream, - struct ia_css_isp_parameters **isp_params_out) { + struct ia_css_isp_parameters **isp_params_out) +{ bool succ = true; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2441,23 +2436,20 @@ sh_css_create_isp_params(struct ia_css_stream *stream, struct ia_css_isp_parameters *params = kvmalloc(sizeof(struct ia_css_isp_parameters), GFP_KERNEL); - if (!params) - { + if (!params) { *isp_params_out = NULL; err = -ENOMEM; IA_CSS_ERROR("%s:%d error: cannot allocate memory", __FILE__, __LINE__); IA_CSS_LEAVE_ERR_PRIVATE(err); return err; - } else - { + } else { memset(params, 0, sizeof(struct ia_css_isp_parameters)); } ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { memset(¶ms->pipe_ddr_ptrs[i], 0, sizeof(params->pipe_ddr_ptrs[i])); memset(¶ms->pipe_ddr_ptrs_size[i], 0, @@ -2714,7 +2706,8 @@ exit: } int -sh_css_params_init(void) { +sh_css_params_init(void) +{ int i, p; IA_CSS_ENTER_PRIVATE("void"); @@ -2723,8 +2716,7 @@ sh_css_params_init(void) { g_param_buffer_dequeue_count = 0; g_param_buffer_enqueue_count = 0; - for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) - { + for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) { for (i = 0; i < SH_CSS_MAX_STAGES; i++) { xmem_sp_stage_ptrs[p][i] = ia_css_refcount_increment(-1, @@ -2762,8 +2754,7 @@ sh_css_params_init(void) { ATOMISP_MAP_FLAG_CLEARED)); if ((sp_ddr_ptrs == mmgr_NULL) || - (xmem_sp_group_ptrs == mmgr_NULL)) - { + (xmem_sp_group_ptrs == mmgr_NULL)) { ia_css_uninit(); IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; @@ -3094,14 +3085,14 @@ store_morph_plane( unsigned int width, unsigned int height, ia_css_ptr dest, - unsigned int aligned_width) { + unsigned int aligned_width) +{ struct ia_css_host_data *isp_data; assert(dest != mmgr_NULL); isp_data = convert_allocate_morph_plane(data, width, height, aligned_width); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -3221,7 +3212,8 @@ int sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, struct ia_css_isp_parameters *params, bool commit, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; ia_css_ptr cpy; int i; @@ -3238,15 +3230,13 @@ sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, raw_bit_depth = ia_css_stream_input_format_bits_per_pixel(curr_pipe->stream); /* now make the map available to the sp */ - if (!commit) - { + if (!commit) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } /* enqueue a copies of the mem_map to the designated pipelines */ - for (i = 0; i < curr_pipe->stream->num_pipes; i++) - { + for (i = 0; i < curr_pipe->stream->num_pipes; i++) { struct ia_css_pipe *pipe; struct sh_css_ddr_address_map *cur_map; struct sh_css_ddr_address_map_size *cur_map_size; @@ -3430,7 +3420,8 @@ sh_css_params_write_to_ddr_internal( struct ia_css_isp_parameters *params, const struct ia_css_pipeline_stage *stage, struct sh_css_ddr_address_map *ddr_map, - struct sh_css_ddr_address_map_size *ddr_map_size) { + struct sh_css_ddr_address_map_size *ddr_map_size) +{ int err; const struct ia_css_binary *binary; @@ -3452,8 +3443,7 @@ sh_css_params_write_to_ddr_internal( stage_num = stage->stage_num; - if (binary->info->sp.enable.fpnr) - { + if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, (size_t)(FPNTBL_BYTES(binary)), @@ -3474,8 +3464,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.sc) - { + if (binary->info->sp.enable.sc) { u32 enable_conv; size_t bytes; @@ -3577,8 +3566,7 @@ sh_css_params_write_to_ddr_internal( * DPC kernel. The code below sets the pipe specific configuration to * individual binaries. */ if (IS_ISP2401 && - params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) - { + params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) { unsigned int size = stage->binary->info->mem_offsets.offsets.param->dmem.dp.size; @@ -3596,8 +3584,7 @@ sh_css_params_write_to_ddr_internal( } } - if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) - { + if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) { unsigned int i, j, idx; unsigned int idx_map[] = { 0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8 @@ -3646,8 +3633,7 @@ sh_css_params_write_to_ddr_internal( sizeof(converted_macc_table.data)); } - if (binary->info->sp.enable.dvs_6axis) - { + if (binary->info->sp.enable.dvs_6axis) { /* because UV is packed into the Y plane, calc total * YYU size = /2 gives size of UV-only, * total YYU size = UV-only * 3. @@ -3705,8 +3691,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.ca_gdc) - { + if (binary->info->sp.enable.ca_gdc) { unsigned int i; ia_css_ptr *virt_addr_tetra_x[ @@ -3811,8 +3796,7 @@ sh_css_params_write_to_ddr_internal( } /* After special cases like SC, FPN since they may change parameters */ - for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) - { + for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) { const struct ia_css_isp_data *isp_data = ia_css_isp_param_get_isp_mem_init(&binary->info->sp.mem_initializers, IA_CSS_PARAM_CLASS_PARAM, mem); @@ -4025,7 +4009,8 @@ static int write_ia_css_isp_parameter_set_info_to_ddr( static int free_ia_css_isp_parameter_set_info( - ia_css_ptr ptr) { + ia_css_ptr ptr) +{ int err = 0; struct ia_css_isp_parameter_set_info isp_params_info; unsigned int i; @@ -4034,8 +4019,7 @@ free_ia_css_isp_parameter_set_info( IA_CSS_ENTER_PRIVATE("ptr = %u", ptr); /* sanity check - ptr must be valid */ - if (!ia_css_refcount_is_valid(ptr)) - { + if (!ia_css_refcount_is_valid(ptr)) { IA_CSS_ERROR("%s: IA_CSS_REFCOUNT_PARAM_SET_POOL(0x%x) invalid arg", __func__, ptr); err = -EINVAL; @@ -4046,8 +4030,7 @@ free_ia_css_isp_parameter_set_info( hmm_load(ptr, &isp_params_info.mem_map, sizeof(struct sh_css_ddr_address_map)); /* copy map using size info */ for (i = 0; i < (sizeof(struct sh_css_ddr_address_map_size) / - sizeof(size_t)); i++) - { + sizeof(size_t)); i++) { if (addrs[i] == mmgr_NULL) continue; @@ -4254,7 +4237,8 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( struct sh_css_uds_info *uds, /* out */ struct sh_css_crop_pos *sp_out_crop_pos, /* out */ struct ia_css_resolution pipe_in_res, - bool enable_zoom) { + bool enable_zoom) +{ unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int err = 0; /* Note: @@ -4285,19 +4269,16 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( if ((x0 > x1) || (y0 > y1) || (x1 > pipe_in_res.width) || (y1 > pipe_in_res.height)) return -EINVAL; - if (!enable_zoom) - { + if (!enable_zoom) { uds->curr_dx = HRT_GDC_N; uds->curr_dy = HRT_GDC_N; } - if (info->enable.dvs_envelope) - { + if (info->enable.dvs_envelope) { /* Zoom region is only supported by the UDS module on ISP * 2 and higher. It is not supported in video mode on ISP 1 */ return -EINVAL; - } else - { + } else { if (enable_zoom) { /* A. Calculate dx/dy based on crop region using in_frame_info * Scale the crop region if in_frame_info to the stage is not same as diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index 02f5a73b4096..a73e8ca1e225 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -535,12 +535,12 @@ sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out, } static int -set_input_frame_buffer(const struct ia_css_frame *frame) { +set_input_frame_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_QPLANE6: case IA_CSS_FRAME_FORMAT_YUV420_16: case IA_CSS_FRAME_FORMAT_RAW_PACKED: @@ -566,12 +566,12 @@ set_input_frame_buffer(const struct ia_css_frame *frame) { static int set_output_frame_buffer(const struct ia_css_frame *frame, - unsigned int idx) { + unsigned int idx) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_YUV420: case IA_CSS_FRAME_FORMAT_YUV422: case IA_CSS_FRAME_FORMAT_YUV444: @@ -607,12 +607,12 @@ set_output_frame_buffer(const struct ia_css_frame *frame, } static int -set_view_finder_buffer(const struct ia_css_frame *frame) { +set_view_finder_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { /* the dual output pin */ case IA_CSS_FRAME_FORMAT_NV12: case IA_CSS_FRAME_FORMAT_NV12_16: @@ -732,7 +732,8 @@ sh_css_sp_set_disable_continuous_viewfinder(bool flag) } static int -sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { +sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) +{ int err = 0; int i; @@ -742,8 +743,7 @@ sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { err = set_input_frame_buffer(args->in_frame); if (!err && args->out_vf_frame) err = set_view_finder_buffer(args->out_vf_frame); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { if (!err && args->out_frame[i]) err = set_output_frame_buffer(args->out_frame[i], i); } @@ -786,7 +786,8 @@ sh_css_stage_write_binary_info(struct ia_css_binary_info *info) } static int -copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) { +copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) +{ int err; err = ia_css_isp_param_copy_isp_mem_if_to_ddr( @@ -817,7 +818,8 @@ configure_isp_from_args( const struct ia_css_binary *binary, const struct sh_css_binary_args *args, bool two_ppc, - bool deinterleaved) { + bool deinterleaved) +{ ia_css_fpn_configure(binary, &binary->in_frame_info); ia_css_crop_configure(binary, &args->delay_frames[0]->info); ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info); @@ -896,7 +898,8 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, bool xnr, const struct ia_css_isp_param_css_segments *isp_mem_if, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ const struct ia_css_binary_xinfo *xinfo; const struct ia_css_binary_info *info; int err = 0; @@ -928,8 +931,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); - if (!info) - { + if (!info) { sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = mmgr_NULL; return 0; } @@ -961,8 +963,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.in.info, &binary->in_frame_info); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.out[i].info, &binary->out_frame_info[i]); } @@ -996,16 +997,14 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, err = sh_css_sp_write_frame_pointers(args); /* TODO: move it to a better place */ - if (binary->info->sp.enable.s3a) - { + if (binary->info->sp.enable.s3a) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_3A_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.s3a_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_3A_STATISTICS); } - if (binary->info->sp.enable.dis) - { + if (binary->info->sp.enable.dis) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_DIS_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.dvs_buf, queue_id, @@ -1046,8 +1045,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, * the original out res. for video pipe, it has two output pins --- out and * vf_out, so it can keep these two resolutions already. */ if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW && - (binary->vf_downscale_log2 > 0)) - { + (binary->vf_downscale_log2 > 0)) { /* TODO: Remove this after preview output decimation is fixed * by configuring out&vf info fiels properly */ sh_css_sp_stage.frames.out[0].info.padded_width @@ -1069,7 +1067,8 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, unsigned int pipe_num, bool xnr, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ struct ia_css_binary *binary; const struct ia_css_fw_info *firmware; const struct sh_css_binary_args *args; @@ -1105,14 +1104,12 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, args = &stage->args; stage_num = stage->stage_num; - if (binary) - { + if (binary) { info = binary->info; binary_name = (const char *)(info->blob->name); blob_info = &info->blob->header.blob; ia_css_init_memory_interface(mem_if, &binary->mem_params, &binary->css_params); - } else if (firmware) - { + } else if (firmware) { const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL}; if (args->out_frame[0]) @@ -1133,8 +1130,7 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, binary_name = IA_CSS_EXT_ISP_PROG_NAME(firmware); blob_info = &firmware->blob; mem_if = (struct ia_css_isp_param_css_segments *)&firmware->mem_initializers; - } else - { + } else { /* SP stage */ assert(stage->sp_func != IA_CSS_PIPELINE_NO_FUNC); /* binary and blob_info are now NULL. @@ -1205,7 +1201,8 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, *internal_frame_origin_bqs_on_sctbl, /* Origin of internal frame positioned on shading table at shading correction in ISP. */ const struct ia_css_isp_parameters *params - ) { + ) +{ /* Get first stage */ struct ia_css_pipeline_stage *stage = NULL; struct ia_css_binary *first_binary = NULL; @@ -1223,17 +1220,14 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, first_binary = me->stages->binary; if (input_mode == IA_CSS_INPUT_MODE_SENSOR || - input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - { + input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { assert(port_id < N_MIPI_PORT_ID); if (port_id >= N_MIPI_PORT_ID) /* should not happen but KW does not know */ return; /* we should be able to return an error */ if_config_index = (uint8_t)(port_id - MIPI_PORT0_ID); - } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) - { + } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) { if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; - } else - { + } else { if_config_index = 0x0; } @@ -1241,15 +1235,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline)); /* Count stages */ - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { stage->stage_num = num; ia_css_debug_pipe_graph_dump_stage(stage, id); } me->num_stages = num; - if (first_binary) - { + if (first_binary) { /* Init pipeline data */ sh_css_sp_init_group(two_ppc, first_binary->input_format, offline, if_config_index); @@ -1277,8 +1269,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, /* TODO: next indicates from which queues parameters need to be sampled, needs checking/improvement */ - if (ia_css_pipeline_uses_params(me)) - { + if (ia_css_pipeline_uses_params(me)) { sh_css_sp_group.pipe[thread_id].pipe_config = SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id; } @@ -1292,15 +1283,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, pipe = find_pipe_by_num(pipe_num); assert(pipe); - if (!pipe) - { + if (!pipe) { return; } sh_css_sp_group.pipe[thread_id].scaler_pp_lut = sh_css_pipe_get_pp_gdc_lut(pipe); #if defined(SH_CSS_ENABLE_METADATA) - if (md_info && md_info->size > 0) - { + if (md_info && md_info->size > 0) { sh_css_sp_group.pipe[thread_id].metadata.width = md_info->resolution.width; sh_css_sp_group.pipe[thread_id].metadata.height = md_info->resolution.height; sh_css_sp_group.pipe[thread_id].metadata.stride = md_info->stride; @@ -1316,8 +1305,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) sh_css_sp_group.pipe[thread_id].output_frame_queue_id = (uint32_t)SH_CSS_INVALID_QUEUE_ID; - if (pipe_id != IA_CSS_PIPE_ID_COPY) - { + if (pipe_id != IA_CSS_PIPE_ID_COPY) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, (enum sh_css_queue_id *)( &sh_css_sp_group.pipe[thread_id].output_frame_queue_id)); @@ -1329,14 +1317,12 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, * the parameters are passed to the isp for the shading table centering. */ if (internal_frame_origin_bqs_on_sctbl && - params && params->shading_settings.enable_shading_table_conversion == 0) - { + params && params->shading_settings.enable_shading_table_conversion == 0) { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->x; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->y; - } else - { + } else { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = 0; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = @@ -1347,8 +1333,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, IA_CSS_LOG("pipe_id %d port_config %08x", pipe_id, sh_css_sp_group.pipe[thread_id].inout_port_config); - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { sh_css_sp_group.pipe[thread_id].num_stages++; if (is_sp_stage(stage)) { sp_init_sp_stage(stage, pipe_num, two_ppc, @@ -1400,7 +1385,8 @@ bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command) } enum host2sp_commands -sh_css_read_host2sp_command(void) { +sh_css_read_host2sp_command(void) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command) / sizeof(int); @@ -1586,7 +1572,8 @@ sh_css_event_init_irq_mask(void) int ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, unsigned int or_mask, - unsigned int and_mask) { + unsigned int and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; @@ -1625,7 +1612,8 @@ ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, int ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe, unsigned int *or_mask, - unsigned int *and_mask) { + unsigned int *and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; diff --git a/drivers/staging/media/atomisp/pci/sh_css_version.c b/drivers/staging/media/atomisp/pci/sh_css_version.c index fa6de61e4995..f5ff8ca66b50 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_version.c +++ b/drivers/staging/media/atomisp/pci/sh_css_version.c @@ -21,7 +21,8 @@ #include "sh_css_firmware.h" int -ia_css_get_version(char *version, int max_size) { +ia_css_get_version(char *version, int max_size) +{ char *css_version; if (!IS_ISP2401) diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 287370188d2a..90036831fec4 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -13,6 +13,7 @@ hantro-vpu-y += \ hantro_g2_hevc_dec.o \ hantro_g1_vp8_dec.o \ rockchip_vpu2_hw_jpeg_enc.o \ + rockchip_vpu2_hw_h264_dec.o \ rockchip_vpu2_hw_mpeg2_dec.o \ rockchip_vpu2_hw_vp8_dec.o \ hantro_jpeg.o \ diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index a70c386de6f1..c2e2dca38628 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -61,8 +61,8 @@ struct hantro_irq { * @num_postproc_fmts: Number of post-processor formats. * @codec: Supported codecs * @codec_ops: Codec ops. - * @init: Initialize hardware. - * @runtime_resume: reenable hardware after power gating + * @init: Initialize hardware, optional. + * @runtime_resume: reenable hardware after power gating, optional. * @irqs: array of irq names and interrupt handlers * @num_irqs: number of irqs in the array * @clk_names: array of clock names diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 31d8449ca1d2..8a2edd67f2c6 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -582,6 +582,7 @@ static const struct v4l2_file_operations hantro_fops = { static const struct of_device_id of_hantro_match[] = { #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP + { .compatible = "rockchip,px30-vpu", .data = &px30_vpu_variant, }, { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, }, { .compatible = "rockchip,rk3066-vpu", .data = &rk3066_vpu_variant, }, { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, @@ -942,10 +943,12 @@ static int hantro_probe(struct platform_device *pdev) } } - ret = vpu->variant->init(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to init VPU hardware\n"); - return ret; + if (vpu->variant->init) { + ret = vpu->variant->init(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to init VPU hardware\n"); + return ret; + } } pm_runtime_set_autosuspend_delay(vpu->dev, 100); diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 5c792b7bcb79..236ce24ca00c 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -19,13 +19,12 @@ #include "hantro_hw.h" #include "hantro_v4l2.h" -static void set_params(struct hantro_ctx *ctx) +static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; - struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); struct hantro_dev *vpu = ctx->dev; u32 reg; @@ -127,28 +126,14 @@ static void set_params(struct hantro_ctx *ctx) static void set_ref(struct hantro_ctx *ctx) { - struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; const u8 *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; - u32 dpb_longterm = 0; - u32 dpb_valid = 0; int reg_num; u32 reg; int i; - /* - * Set up bit maps of valid and long term DPBs. - * NOTE: The bits are reversed, i.e. MSb is DPB 0. - */ - for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - } - vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); - vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); + vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); + vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); /* * Set up reference frame picture numbers. @@ -157,17 +142,8 @@ static void set_ref(struct hantro_ctx *ctx) * subsequential reference pictures. */ for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) { - reg = 0; - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); - else - reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); - - if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); - else - reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num); - + reg = G1_REG_REF_PIC_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, i)) | + G1_REG_REF_PIC_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, i + 1)); vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2)); } @@ -226,22 +202,20 @@ static void set_ref(struct hantro_ctx *ctx) } } -static void set_buffers(struct hantro_ctx *ctx) +static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; - struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *dst_buf; struct hantro_dev *vpu = ctx->dev; dma_addr_t src_dma, dst_dma; size_t offset = 0; - src_buf = hantro_get_src_buf(ctx); - dst_buf = hantro_get_dst_buf(ctx); - /* Source (stream) buffer. */ src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR); /* Destination (decoded frame) buffer. */ + dst_buf = hantro_get_dst_buf(ctx); dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); /* Adjust dma addr to start at second line for bottom field */ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) @@ -276,6 +250,7 @@ static void set_buffers(struct hantro_ctx *ctx) int hantro_g1_h264_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf; int ret; /* Prepare the H264 decoder context. */ @@ -284,9 +259,10 @@ int hantro_g1_h264_dec_run(struct hantro_ctx *ctx) return ret; /* Configure hardware registers. */ - set_params(ctx); + src_buf = hantro_get_src_buf(ctx); + set_params(ctx, src_buf); set_ref(ctx); - set_buffers(ctx); + set_buffers(ctx, src_buf); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 96622a7f8279..6180b23e7d94 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -367,21 +367,25 @@ static void cfg_tap(struct hantro_ctx *ctx, } static void cfg_ref(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; - vb2_dst = hantro_get_dst_buf(ctx); ref = hantro_get_ref(ctx, hdr->last_frame_ts); - if (!ref) + if (!ref) { + vpu_debug(0, "failed to find last frame ts=%llu\n", + hdr->last_frame_ts); ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + } vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0)); ref = hantro_get_ref(ctx, hdr->golden_frame_ts); - WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref && hdr->golden_frame_ts) + vpu_debug(0, "failed to find golden frame ts=%llu\n", + hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN) @@ -389,7 +393,9 @@ static void cfg_ref(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4)); ref = hantro_get_ref(ctx, hdr->alt_frame_ts); - WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref && hdr->alt_frame_ts) + vpu_debug(0, "failed to find alt frame ts=%llu\n", + hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT) @@ -398,16 +404,14 @@ static void cfg_ref(struct hantro_ctx *ctx, } static void cfg_buffers(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { const struct v4l2_vp8_segment *seg = &hdr->segment; struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t dst_dma; u32 reg; - vb2_dst = hantro_get_dst_buf(ctx); - /* Set probability table buffer address */ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, G1_REG_ADDR_QTABLE); @@ -429,6 +433,7 @@ int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; size_t height = ctx->dst_fmt.height; size_t width = ctx->dst_fmt.width; u32 mb_width, mb_height; @@ -492,8 +497,10 @@ int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) cfg_qp(ctx, hdr); cfg_parts(ctx, hdr); cfg_tap(ctx, hdr); - cfg_ref(ctx, hdr); - cfg_buffers(ctx, hdr); + + vb2_dst = hantro_get_dst_buf(ctx); + cfg_ref(ctx, hdr, vb2_dst); + cfg_buffers(ctx, hdr, vb2_dst); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index ed6eaf11d96f..0b4d2491be3b 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -229,12 +229,25 @@ static void prepare_table(struct hantro_ctx *ctx) const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + u32 dpb_longterm = 0; + u32 dpb_valid = 0; int i; for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { tbl->poc[i * 2] = dpb[i].top_field_order_cnt; tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); } + ctx->h264_dec.dpb_valid = dpb_valid << 16; + ctx->h264_dec.dpb_longterm = dpb_longterm << 16; tbl->poc[32] = dec_param->top_field_order_cnt; tbl->poc[33] = dec_param->bottom_field_order_cnt; @@ -335,6 +348,17 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, return dma_addr; } +u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx) +{ + const struct v4l2_h264_dpb_entry *dpb = &ctx->h264_dec.dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + return 0; + if (dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return dpb->pic_num; + return dpb->frame_num; +} + int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) { struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 5dcf65805396..df7b5e3a57b9 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -89,12 +89,16 @@ struct hantro_h264_dec_reflists { * @dpb: DPB * @reflists: P/B0/B1 reflists * @ctrls: V4L2 controls attached to a run + * @dpb_longterm: DPB long-term + * @dpb_valid: DPB valid */ struct hantro_h264_dec_hw_ctx { struct hantro_aux_buf priv; struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; struct hantro_h264_dec_reflists reflists; struct hantro_h264_dec_ctrls ctrls; + u32 dpb_longterm; + u32 dpb_valid; }; /** @@ -205,6 +209,7 @@ enum hantro_enc_fmt { extern const struct hantro_variant imx8mq_vpu_g2_variant; extern const struct hantro_variant imx8mq_vpu_variant; +extern const struct hantro_variant px30_vpu_variant; extern const struct hantro_variant rk3036_vpu_variant; extern const struct hantro_variant rk3066_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; @@ -234,7 +239,10 @@ void hantro_jpeg_enc_done(struct hantro_ctx *ctx); dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, unsigned int dpb_idx); +u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, + unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); +int rockchip_vpu2_h264_dec_run(struct hantro_ctx *ctx); int hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); void hantro_h264_dec_exit(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c new file mode 100644 index 000000000000..64a6330475eb --- /dev/null +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong <hertz.wong@rock-chips.com> + * Herman Chen <herman.chen@rock-chips.com> + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa <tfiga@chromium.org> + */ + +#include <linux/types.h> +#include <linux/sort.h> + +#include <media/v4l2-mem2mem.h> + +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +#define VDPU_SWREG(nr) ((nr) * 4) + +#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) +#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) +#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) +#define VDPU_REG_DIR_MV_BASE VDPU_SWREG(62) +#define VDPU_REG_REFER_BASE(i) (VDPU_SWREG(84 + (i))) +#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) +#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_PIC_FIXED_QUANT(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) + +#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) +#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) +#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) + +#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) +#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_START_CODE_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_CH_8PIX_ILEAV_E(v) ((v) ? BIT(21) : 0) +#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) +#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) +#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) +#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) +#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_SEQ_MBAFF_E(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_PICORD_COUNT_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) + +#define VDPU_REG_PRED_BC_TAP_0_0(v) (((v) << 22) & GENMASK(31, 22)) +#define VDPU_REG_PRED_BC_TAP_0_1(v) (((v) << 12) & GENMASK(21, 12)) +#define VDPU_REG_PRED_BC_TAP_0_2(v) (((v) << 2) & GENMASK(11, 2)) + +#define VDPU_REG_REFBU_E(v) ((v) ? BIT(31) : 0) + +#define VDPU_REG_PINIT_RLIST_F9(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_PINIT_RLIST_F8(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_PINIT_RLIST_F7(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F6(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F5(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F4(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_PINIT_RLIST_F15(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_PINIT_RLIST_F14(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_PINIT_RLIST_F13(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F12(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F11(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F10(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_REFER1_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER0_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER3_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER2_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER5_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER4_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER7_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER6_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER9_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER8_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER11_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER10_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER13_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER12_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER15_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER14_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_BINIT_RLIST_F5(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_F4(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_F11(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_F10(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_F9(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F8(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F7(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F6(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_F15(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F14(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F13(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F12(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B5(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_B4(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_B3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B11(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_B10(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_B9(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B8(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B7(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B6(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B15(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B14(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B13(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B12(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_PINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_REFER_LTERM_E(v) (((v) << 0) & GENMASK(31, 0)) + +#define VDPU_REG_REFER_VALID_E(v) (((v) << 0) & GENMASK(31, 0)) + +#define VDPU_REG_STRM_START_BIT(v) (((v) << 0) & GENMASK(5, 0)) + +#define VDPU_REG_CH_QP_OFFSET2(v) (((v) << 22) & GENMASK(26, 22)) +#define VDPU_REG_CH_QP_OFFSET(v) (((v) << 17) & GENMASK(21, 17)) +#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 9) & GENMASK(16, 9)) +#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 0) & GENMASK(8, 0)) + +#define VDPU_REG_WEIGHT_BIPR_IDC(v) (((v) << 16) & GENMASK(17, 16)) +#define VDPU_REG_REF_FRAMES(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_FILT_CTRL_PRES(v) ((v) ? BIT(31) : 0) +#define VDPU_REG_RDPIC_CNT_PRES(v) ((v) ? BIT(30) : 0) +#define VDPU_REG_FRAMENUM_LEN(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_FRAMENUM(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFPIC_MK_LEN(v) (((v) << 16) & GENMASK(26, 16)) +#define VDPU_REG_IDR_PIC_ID(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_PPS_ID(v) (((v) << 24) & GENMASK(31, 24)) +#define VDPU_REG_REFIDX1_ACTIVE(v) (((v) << 19) & GENMASK(23, 19)) +#define VDPU_REG_REFIDX0_ACTIVE(v) (((v) << 14) & GENMASK(18, 14)) +#define VDPU_REG_POC_LENGTH(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_IDR_PIC_E(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_DIR_8X8_INFER_E(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_BLACKWHITE_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_CABAC_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_WEIGHT_PRED_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_CONST_INTRA_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_8X8TRANS_FLAG_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_TYPE1_QUANT_E(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_FIELDPIC_FLAG_E(v) ((v) ? BIT(0) : 0) + +static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct hantro_dev *vpu = ctx->dev; + u32 reg; + + reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | + VDPU_REG_DEC_SCMD_DIS(0) | + VDPU_REG_FILTERING_DIS(0) | + VDPU_REG_PIC_FIXED_QUANT(0) | + VDPU_REG_DEC_LATENCY(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); + + reg = VDPU_REG_INIT_QP(pps->pic_init_qp_minus26 + 26) | + VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); + + reg = VDPU_REG_APF_THRESHOLD(8) | + VDPU_REG_STARTMB_X(0) | + VDPU_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); + + reg = VDPU_REG_DEC_MODE(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); + + reg = VDPU_REG_DEC_STRENDIAN_E(1) | + VDPU_REG_DEC_STRSWAP32_E(1) | + VDPU_REG_DEC_OUTSWAP32_E(1) | + VDPU_REG_DEC_INSWAP32_E(1) | + VDPU_REG_DEC_OUT_ENDIAN(1) | + VDPU_REG_DEC_IN_ENDIAN(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); + + reg = VDPU_REG_DEC_DATA_DISC_E(0) | + VDPU_REG_DEC_MAX_BURST(16) | + VDPU_REG_DEC_AXI_WR_ID(0) | + VDPU_REG_DEC_AXI_RD_ID(0xff); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); + + reg = VDPU_REG_START_CODE_E(1) | + VDPU_REG_CH_8PIX_ILEAV_E(0) | + VDPU_REG_RLC_MODE_E(0) | + VDPU_REG_PIC_INTERLACE_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || + dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) | + VDPU_REG_PIC_FIELDMODE_E(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) | + VDPU_REG_PIC_TOPFIELD_E(!(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)) | + VDPU_REG_WRITE_MVS_E((sps->profile_idc > 66) && dec_param->nal_ref_idc) | + VDPU_REG_SEQ_MBAFF_E(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) | + VDPU_REG_PICORD_COUNT_E(sps->profile_idc > 66) | + VDPU_REG_DEC_TIMEOUT_E(1) | + VDPU_REG_DEC_CLK_GATE_E(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); + + reg = VDPU_REG_PRED_BC_TAP_0_0(1) | + VDPU_REG_PRED_BC_TAP_0_1((u32)-5) | + VDPU_REG_PRED_BC_TAP_0_2(20); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(59)); + + reg = VDPU_REG_REFBU_E(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(65)); + + reg = VDPU_REG_STRM_START_BIT(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(109)); + + reg = VDPU_REG_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset) | + VDPU_REG_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | + VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(110)); + + reg = VDPU_REG_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc) | + VDPU_REG_REF_FRAMES(sps->max_num_ref_frames); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(111)); + + reg = VDPU_REG_FILT_CTRL_PRES(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) | + VDPU_REG_RDPIC_CNT_PRES(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) | + VDPU_REG_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | + VDPU_REG_FRAMENUM(dec_param->frame_num); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(112)); + + reg = VDPU_REG_REFPIC_MK_LEN(dec_param->dec_ref_pic_marking_bit_size) | + VDPU_REG_IDR_PIC_ID(dec_param->idr_pic_id); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(113)); + + reg = VDPU_REG_PPS_ID(pps->pic_parameter_set_id) | + VDPU_REG_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | + VDPU_REG_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + VDPU_REG_POC_LENGTH(dec_param->pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(114)); + + reg = VDPU_REG_IDR_PIC_E(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) | + VDPU_REG_DIR_8X8_INFER_E(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) | + VDPU_REG_BLACKWHITE_E(sps->profile_idc >= 100 && sps->chroma_format_idc == 0) | + VDPU_REG_CABAC_E(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) | + VDPU_REG_WEIGHT_PRED_E(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) | + VDPU_REG_CONST_INTRA_E(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) | + VDPU_REG_8X8TRANS_FLAG_E(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) | + VDPU_REG_TYPE1_QUANT_E(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) | + VDPU_REG_FIELDPIC_FLAG_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(115)); +} + +static void set_ref(struct hantro_ctx *ctx) +{ + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; + u32 reg; + int i; + + b0_reflist = ctx->h264_dec.reflists.b0; + b1_reflist = ctx->h264_dec.reflists.b1; + p_reflist = ctx->h264_dec.reflists.p; + + reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9]) | + VDPU_REG_PINIT_RLIST_F8(p_reflist[8]) | + VDPU_REG_PINIT_RLIST_F7(p_reflist[7]) | + VDPU_REG_PINIT_RLIST_F6(p_reflist[6]) | + VDPU_REG_PINIT_RLIST_F5(p_reflist[5]) | + VDPU_REG_PINIT_RLIST_F4(p_reflist[4]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(74)); + + reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15]) | + VDPU_REG_PINIT_RLIST_F14(p_reflist[14]) | + VDPU_REG_PINIT_RLIST_F13(p_reflist[13]) | + VDPU_REG_PINIT_RLIST_F12(p_reflist[12]) | + VDPU_REG_PINIT_RLIST_F11(p_reflist[11]) | + VDPU_REG_PINIT_RLIST_F10(p_reflist[10]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(75)); + + reg = VDPU_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | + VDPU_REG_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, 0)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(76)); + + reg = VDPU_REG_REFER3_NBR(hantro_h264_get_ref_nbr(ctx, 3)) | + VDPU_REG_REFER2_NBR(hantro_h264_get_ref_nbr(ctx, 2)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(77)); + + reg = VDPU_REG_REFER5_NBR(hantro_h264_get_ref_nbr(ctx, 5)) | + VDPU_REG_REFER4_NBR(hantro_h264_get_ref_nbr(ctx, 4)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(78)); + + reg = VDPU_REG_REFER7_NBR(hantro_h264_get_ref_nbr(ctx, 7)) | + VDPU_REG_REFER6_NBR(hantro_h264_get_ref_nbr(ctx, 6)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(79)); + + reg = VDPU_REG_REFER9_NBR(hantro_h264_get_ref_nbr(ctx, 9)) | + VDPU_REG_REFER8_NBR(hantro_h264_get_ref_nbr(ctx, 8)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(80)); + + reg = VDPU_REG_REFER11_NBR(hantro_h264_get_ref_nbr(ctx, 11)) | + VDPU_REG_REFER10_NBR(hantro_h264_get_ref_nbr(ctx, 10)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(81)); + + reg = VDPU_REG_REFER13_NBR(hantro_h264_get_ref_nbr(ctx, 13)) | + VDPU_REG_REFER12_NBR(hantro_h264_get_ref_nbr(ctx, 12)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(82)); + + reg = VDPU_REG_REFER15_NBR(hantro_h264_get_ref_nbr(ctx, 15)) | + VDPU_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(83)); + + reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5]) | + VDPU_REG_BINIT_RLIST_F4(b0_reflist[4]) | + VDPU_REG_BINIT_RLIST_F3(b0_reflist[3]) | + VDPU_REG_BINIT_RLIST_F2(b0_reflist[2]) | + VDPU_REG_BINIT_RLIST_F1(b0_reflist[1]) | + VDPU_REG_BINIT_RLIST_F0(b0_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(100)); + + reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11]) | + VDPU_REG_BINIT_RLIST_F10(b0_reflist[10]) | + VDPU_REG_BINIT_RLIST_F9(b0_reflist[9]) | + VDPU_REG_BINIT_RLIST_F8(b0_reflist[8]) | + VDPU_REG_BINIT_RLIST_F7(b0_reflist[7]) | + VDPU_REG_BINIT_RLIST_F6(b0_reflist[6]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(101)); + + reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15]) | + VDPU_REG_BINIT_RLIST_F14(b0_reflist[14]) | + VDPU_REG_BINIT_RLIST_F13(b0_reflist[13]) | + VDPU_REG_BINIT_RLIST_F12(b0_reflist[12]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(102)); + + reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5]) | + VDPU_REG_BINIT_RLIST_B4(b1_reflist[4]) | + VDPU_REG_BINIT_RLIST_B3(b1_reflist[3]) | + VDPU_REG_BINIT_RLIST_B2(b1_reflist[2]) | + VDPU_REG_BINIT_RLIST_B1(b1_reflist[1]) | + VDPU_REG_BINIT_RLIST_B0(b1_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(103)); + + reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11]) | + VDPU_REG_BINIT_RLIST_B10(b1_reflist[10]) | + VDPU_REG_BINIT_RLIST_B9(b1_reflist[9]) | + VDPU_REG_BINIT_RLIST_B8(b1_reflist[8]) | + VDPU_REG_BINIT_RLIST_B7(b1_reflist[7]) | + VDPU_REG_BINIT_RLIST_B6(b1_reflist[6]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(104)); + + reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15]) | + VDPU_REG_BINIT_RLIST_B14(b1_reflist[14]) | + VDPU_REG_BINIT_RLIST_B13(b1_reflist[13]) | + VDPU_REG_BINIT_RLIST_B12(b1_reflist[12]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(105)); + + reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3]) | + VDPU_REG_PINIT_RLIST_F2(p_reflist[2]) | + VDPU_REG_PINIT_RLIST_F1(p_reflist[1]) | + VDPU_REG_PINIT_RLIST_F0(p_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(106)); + + reg = VDPU_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(107)); + + reg = VDPU_REG_REFER_VALID_E(ctx->h264_dec.dpb_valid); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(108)); + + /* Set up addresses of DPB buffers. */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { + dma_addr_t dma_addr = hantro_h264_get_ref_buf(ctx, i); + + vdpu_write_relaxed(vpu, dma_addr, VDPU_REG_REFER_BASE(i)); + } +} + +static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + struct vb2_v4l2_buffer *dst_buf; + struct hantro_dev *vpu = ctx->dev; + dma_addr_t src_dma, dst_dma; + size_t offset = 0; + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, src_dma, VDPU_REG_RLC_VLC_BASE); + + /* Destination (decoded frame) buffer. */ + dst_buf = hantro_get_dst_buf(ctx); + dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); + /* Adjust dma addr to start at second line for bottom field */ + if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset = ALIGN(ctx->src_fmt.width, MB_DIM); + vdpu_write_relaxed(vpu, dst_dma + offset, VDPU_REG_DEC_OUT_BASE); + + /* Higher profiles require DMV buffer appended to reference frames. */ + if (ctrls->sps->profile_idc > 66 && ctrls->decode->nal_ref_idc) { + unsigned int bytes_per_mb = 384; + + /* DMV buffer for monochrome start directly after Y-plane */ + if (ctrls->sps->profile_idc >= 100 && + ctrls->sps->chroma_format_idc == 0) + bytes_per_mb = 256; + offset = bytes_per_mb * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + + /* + * DMV buffer is split in two for field encoded frames, + * adjust offset for bottom field + */ + if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset += 32 * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + vdpu_write_relaxed(vpu, dst_dma + offset, VDPU_REG_DIR_MV_BASE); + } + + /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, VDPU_REG_QTABLE_BASE); +} + +int rockchip_vpu2_h264_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf; + u32 reg; + int ret; + + /* Prepare the H264 decoder context. */ + ret = hantro_h264_dec_prepare_run(ctx); + if (ret) + return ret; + + src_buf = hantro_get_src_buf(ctx); + set_params(ctx, src_buf); + set_ref(ctx); + set_buffers(ctx, src_buf); + + hantro_end_prepare_run(ctx); + + /* Start decoding! */ + reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); + vdpu_write(vpu, reg, VDPU_SWREG(57)); + + return 0; +} diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c index 951b55f58a61..d079075448c9 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c @@ -444,21 +444,24 @@ static void cfg_tap(struct hantro_ctx *ctx, } static void cfg_ref(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; - vb2_dst = hantro_get_dst_buf(ctx); - ref = hantro_get_ref(ctx, hdr->last_frame_ts); - if (!ref) + if (!ref) { + vpu_debug(0, "failed to find last frame ts=%llu\n", + hdr->last_frame_ts); ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + } vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0); ref = hantro_get_ref(ctx, hdr->golden_frame_ts); - WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref && hdr->golden_frame_ts) + vpu_debug(0, "failed to find golden frame ts=%llu\n", + hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN) @@ -466,7 +469,9 @@ static void cfg_ref(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2)); ref = hantro_get_ref(ctx, hdr->alt_frame_ts); - WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref && hdr->alt_frame_ts) + vpu_debug(0, "failed to find alt frame ts=%llu\n", + hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT) @@ -475,16 +480,14 @@ static void cfg_ref(struct hantro_ctx *ctx, } static void cfg_buffers(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { const struct v4l2_vp8_segment *seg = &hdr->segment; struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t dst_dma; u32 reg; - vb2_dst = hantro_get_dst_buf(ctx); - /* Set probability table buffer address */ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, VDPU_REG_ADDR_QTABLE); @@ -507,6 +510,7 @@ int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; size_t height = ctx->dst_fmt.height; size_t width = ctx->dst_fmt.width; u32 mb_width, mb_height; @@ -583,8 +587,10 @@ int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx) cfg_qp(ctx, hdr); cfg_parts(ctx, hdr); cfg_tap(ctx, hdr); - cfg_ref(ctx, hdr); - cfg_buffers(ctx, hdr); + + vb2_dst = hantro_get_dst_buf(ctx); + cfg_ref(ctx, hdr, vb2_dst); + cfg_buffers(ctx, hdr, vb2_dst); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index 3ccc16413f42..d4f52957cc53 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -163,6 +163,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .codec_mode = HANTRO_MODE_NONE, }, { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, + { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, .max_depth = 2, @@ -388,6 +401,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { .init = hantro_jpeg_enc_init, .exit = hantro_jpeg_enc_exit, }, + [HANTRO_MODE_H264_DEC] = { + .run = rockchip_vpu2_h264_dec_run, + .reset = rockchip_vpu2_dec_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, [HANTRO_MODE_MPEG2_DEC] = { .run = rockchip_vpu2_mpeg2_dec_run, .reset = rockchip_vpu2_dec_reset, @@ -433,6 +452,8 @@ static const char * const rockchip_vpu_clk_names[] = { "aclk", "hclk" }; +/* VDPU1/VEPU1 */ + const struct hantro_variant rk3036_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3066_vpu_dec_fmts, @@ -495,11 +516,14 @@ const struct hantro_variant rk3288_vpu_variant = { .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; +/* VDPU2/VEPU2 */ + const struct hantro_variant rk3328_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3399_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, .codec_ops = rk3399_vpu_codec_ops, .irqs = rockchip_vdpu2_irqs, .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs), @@ -524,3 +548,20 @@ const struct hantro_variant rk3399_vpu_variant = { .clk_names = rockchip_vpu_clk_names, .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; + +const struct hantro_variant px30_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rockchip_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rockchip_vpu2_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vpu2_irqs), + .init = rk3036_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c index 58ae72c2b723..9c3b8cd0b239 100644 --- a/drivers/staging/media/hantro/sama5d4_vdec_hw.c +++ b/drivers/staging/media/hantro/sama5d4_vdec_hw.c @@ -64,11 +64,6 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = { }, }; -static int sama5d4_hw_init(struct hantro_dev *vpu) -{ - return 0; -} - /* * Supported codec ops. */ @@ -109,7 +104,6 @@ const struct hantro_variant sama5d4_vdec_variant = { .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = sama5d4_vdec_codec_ops, - .init = sama5d4_hw_init, .irqs = sama5d4_irqs, .num_irqs = ARRAY_SIZE(sama5d4_irqs), .clk_names = sama5d4_clk_names, diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index 6ac33275cc97..19c2fc54d424 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-mipi-csis.o +obj-$(CONFIG_VIDEO_IMX7_CSI) += imx8mq-mipi-csi2.o diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 894c4de31790..127183732912 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -361,6 +361,7 @@ static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, vb->timestamp = ktime_get_ns(); vb2_buffer_done(vb, return_status); + csi->active_vb2_buf[i] = NULL; } } } @@ -386,9 +387,10 @@ static int imx7_csi_dma_setup(struct imx7_csi *csi) return 0; } -static void imx7_csi_dma_cleanup(struct imx7_csi *csi) +static void imx7_csi_dma_cleanup(struct imx7_csi *csi, + enum vb2_buffer_state return_status) { - imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR); + imx7_csi_dma_unsetup_vb2_buf(csi, return_status); imx_media_free_dma_buf(csi->dev, &csi->underrun_buf); } @@ -421,6 +423,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) struct v4l2_pix_format *out_pix = &vdev->fmt; int width = out_pix->width; u32 stride = 0; + u32 cr3 = BIT_FRMCNT_RST; u32 cr1, cr18; cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); @@ -464,6 +467,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW10; break; case MEDIA_BUS_FMT_Y12_1X12: @@ -471,6 +475,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW12; break; case MEDIA_BUS_FMT_Y14_1X14: @@ -478,6 +483,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG14_1X14: case MEDIA_BUS_FMT_SGRBG14_1X14: case MEDIA_BUS_FMT_SRGGB14_1X14: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW14; break; /* @@ -491,26 +497,11 @@ static void imx7_csi_configure(struct imx7_csi *csi) cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B; break; } - - switch (out_pix->pixelformat) { - case V4L2_PIX_FMT_Y10: - case V4L2_PIX_FMT_Y12: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR16: - case V4L2_PIX_FMT_SGBRG16: - case V4L2_PIX_FMT_SGRBG16: - case V4L2_PIX_FMT_SRGGB16: - cr1 |= BIT_PIXEL_BIT; - break; - } } imx7_csi_reg_write(csi, cr1, CSI_CSICR1); imx7_csi_reg_write(csi, BIT_DMA_BURST_TYPE_RFF_INCR16, CSI_CSICR2); - imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3); + imx7_csi_reg_write(csi, cr3, CSI_CSICR3); imx7_csi_reg_write(csi, cr18, CSI_CSICR18); imx7_csi_reg_write(csi, (width * out_pix->height) >> 2, CSI_CSIRXCNT); @@ -537,9 +528,10 @@ static int imx7_csi_init(struct imx7_csi *csi) return 0; } -static void imx7_csi_deinit(struct imx7_csi *csi) +static void imx7_csi_deinit(struct imx7_csi *csi, + enum vb2_buffer_state return_status) { - imx7_csi_dma_cleanup(csi); + imx7_csi_dma_cleanup(csi, return_status); imx7_csi_init_default(csi); imx7_csi_dmareq_rff_disable(csi); clk_disable_unprepare(csi->mclk); @@ -702,7 +694,7 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1); if (ret < 0) { - imx7_csi_deinit(csi); + imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED); goto out_unlock; } @@ -712,7 +704,7 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) v4l2_subdev_call(csi->src_sd, video, s_stream, 0); - imx7_csi_deinit(csi); + imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR); } csi->is_streaming = !!enable; diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index ead696eb4610..41e33535de55 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -1019,10 +1019,8 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, case 6: align = 2; break; - case 1: - case 3: - case 5: - case 7: + default: + /* 1, 3, 5, 7 */ align = 3; break; } diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c new file mode 100644 index 000000000000..a6f562009b9a --- /dev/null +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -0,0 +1,991 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP i.MX8MQ SoC series MIPI-CSI2 receiver driver + * + * Copyright (C) 2021 Purism SPC + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/interconnect.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/spinlock.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> + +#define MIPI_CSI2_DRIVER_NAME "imx8mq-mipi-csi2" +#define MIPI_CSI2_SUBDEV_NAME MIPI_CSI2_DRIVER_NAME + +#define MIPI_CSI2_PAD_SINK 0 +#define MIPI_CSI2_PAD_SOURCE 1 +#define MIPI_CSI2_PADS_NUM 2 + +#define MIPI_CSI2_DEF_PIX_WIDTH 640 +#define MIPI_CSI2_DEF_PIX_HEIGHT 480 + +/* Register map definition */ + +/* i.MX8MQ CSI-2 controller CSR */ +#define CSI2RX_CFG_NUM_LANES 0x100 +#define CSI2RX_CFG_DISABLE_DATA_LANES 0x104 +#define CSI2RX_BIT_ERR 0x108 +#define CSI2RX_IRQ_STATUS 0x10c +#define CSI2RX_IRQ_MASK 0x110 +#define CSI2RX_IRQ_MASK_ALL 0x1ff +#define CSI2RX_IRQ_MASK_ULPS_STATUS_CHANGE 0x8 +#define CSI2RX_ULPS_STATUS 0x114 +#define CSI2RX_PPI_ERRSOT_HS 0x118 +#define CSI2RX_PPI_ERRSOTSYNC_HS 0x11c +#define CSI2RX_PPI_ERRESC 0x120 +#define CSI2RX_PPI_ERRSYNCESC 0x124 +#define CSI2RX_PPI_ERRCONTROL 0x128 +#define CSI2RX_CFG_DISABLE_PAYLOAD_0 0x12c +#define CSI2RX_CFG_VID_VC_IGNORE 0x180 +#define CSI2RX_CFG_VID_VC 0x184 +#define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 +#define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 + +enum { + ST_POWERED = 1, + ST_STREAMING = 2, + ST_SUSPENDED = 4, +}; + +enum imx8mq_mipi_csi_clk { + CSI2_CLK_CORE, + CSI2_CLK_ESC, + CSI2_CLK_UI, + CSI2_NUM_CLKS, +}; + +static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { + [CSI2_CLK_CORE] = "core", + [CSI2_CLK_ESC] = "esc", + [CSI2_CLK_UI] = "ui", +}; + +#define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) + +#define GPR_CSI2_1_RX_ENABLE BIT(13) +#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) +#define GPR_CSI2_1_HSEL BIT(10) +#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) +#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) + +/* + * The send level configures the number of entries that must accumulate in + * the Pixel FIFO before the data will be transferred to the video output. + * The exact value needed for this configuration is dependent on the rate at + * which the sensor transfers data to the CSI-2 Controller and the user + * video clock. + * + * The calculation is the classical rate-in rate-out type of problem: If the + * video bandwidth is 10% faster than the incoming mipi data and the video + * line length is 500 pixels, then the fifo should be allowed to fill + * 10% of the line length or 50 pixels. If the gap data is ok, then the level + * can be set to 16 and ignored. + */ +#define CSI2RX_SEND_LEVEL 64 + +struct csi_state { + struct device *dev; + void __iomem *regs; + struct clk_bulk_data clks[CSI2_NUM_CLKS]; + struct reset_control *rst; + struct regulator *mipi_phy_regulator; + + struct v4l2_subdev sd; + struct media_pad pads[MIPI_CSI2_PADS_NUM]; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *src_sd; + + struct v4l2_fwnode_bus_mipi_csi2 bus; + + struct mutex lock; /* Protect csi2_fmt, format_mbus, state, hs_settle */ + const struct csi2_pix_format *csi2_fmt; + struct v4l2_mbus_framefmt format_mbus[MIPI_CSI2_PADS_NUM]; + u32 state; + u32 hs_settle; + + struct regmap *phy_gpr; + u8 phy_gpr_reg; + + struct icc_path *icc_path; + s32 icc_path_bw; +}; + +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +struct csi2_pix_format { + u32 code; + u8 width; +}; + +static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { + /* RAW (Bayer and greyscale) formats. */ + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_Y10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_Y12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .width = 14, + }, { + /* YUV formats */ + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .width = 16, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .width = 16, + } +}; + +static const struct csi2_pix_format *find_csi2_format(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx8mq_mipi_csi_formats); i++) + if (code == imx8mq_mipi_csi_formats[i].code) + return &imx8mq_mipi_csi_formats[i]; + return NULL; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static inline void imx8mq_mipi_csi_write(struct csi_state *state, u32 reg, u32 val) +{ + writel(val, state->regs + reg); +} + +static int imx8mq_mipi_csi_sw_reset(struct csi_state *state) +{ + int ret; + + /* + * these are most likely self-clearing reset bits. to make it + * more clear, the reset-imx7 driver should implement the + * .reset() operation. + */ + ret = reset_control_assert(state->rst); + if (ret < 0) { + dev_err(state->dev, "Failed to assert resets: %d\n", ret); + return ret; + } + + return 0; +} + +static void imx8mq_mipi_csi_system_enable(struct csi_state *state, int on) +{ + if (!on) { + imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, 0xf); + return; + } + + regmap_update_bits(state->phy_gpr, + state->phy_gpr_reg, + 0x3fff, + GPR_CSI2_1_RX_ENABLE | + GPR_CSI2_1_VID_INTFC_ENB | + GPR_CSI2_1_HSEL | + GPR_CSI2_1_CONT_CLK_MODE | + GPR_CSI2_1_S_PRG_RXHS_SETTLE(state->hs_settle)); +} + +static void imx8mq_mipi_csi_set_params(struct csi_state *state) +{ + int lanes = state->bus.num_data_lanes; + + imx8mq_mipi_csi_write(state, CSI2RX_CFG_NUM_LANES, lanes - 1); + imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, + (0xf << lanes) & 0xf); + imx8mq_mipi_csi_write(state, CSI2RX_IRQ_MASK, CSI2RX_IRQ_MASK_ALL); + /* + * 0x180 bit 0 controls the Virtual Channel behaviour: when set the + * interface ignores the Virtual Channel (VC) field in received packets; + * when cleared it causes the interface to only accept packets whose VC + * matches the value to which VC is set at offset 0x184. + */ + imx8mq_mipi_csi_write(state, CSI2RX_CFG_VID_VC_IGNORE, 1); + imx8mq_mipi_csi_write(state, CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL, + CSI2RX_SEND_LEVEL); +} + +static int imx8mq_mipi_csi_clk_enable(struct csi_state *state) +{ + return clk_bulk_prepare_enable(CSI2_NUM_CLKS, state->clks); +} + +static void imx8mq_mipi_csi_clk_disable(struct csi_state *state) +{ + clk_bulk_disable_unprepare(CSI2_NUM_CLKS, state->clks); +} + +static int imx8mq_mipi_csi_clk_get(struct csi_state *state) +{ + unsigned int i; + + for (i = 0; i < CSI2_NUM_CLKS; i++) + state->clks[i].id = imx8mq_mipi_csi_clk_id[i]; + + return devm_clk_bulk_get(state->dev, CSI2_NUM_CLKS, state->clks); +} + +static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state) +{ + s64 link_freq; + u32 lane_rate; + unsigned long esc_clk_rate; + u32 min_ths_settle, max_ths_settle, ths_settle_ns, esc_clk_period_ns; + + /* Calculate the line rate from the pixel rate. */ + link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, + state->csi2_fmt->width, + state->bus.num_data_lanes * 2); + if (link_freq < 0) { + dev_err(state->dev, "Unable to obtain link frequency: %d\n", + (int)link_freq); + return link_freq; + } + + lane_rate = link_freq * 2; + if (lane_rate < 80000000 || lane_rate > 1500000000) { + dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate); + return -EINVAL; + } + + /* + * The D-PHY specification requires Ths-settle to be in the range + * 85ns + 6*UI to 140ns + 10*UI, with the unit interval UI being half + * the clock period. + * + * The Ths-settle value is expressed in the hardware as a multiple of + * the Esc clock period: + * + * Ths-settle = (PRG_RXHS_SETTLE + 1) * Tperiod of RxClkInEsc + * + * Due to the one cycle inaccuracy introduced by rounding, the + * documentation recommends picking a value away from the boundaries. + * Let's pick the average. + */ + esc_clk_rate = clk_get_rate(state->clks[CSI2_CLK_ESC].clk); + if (!esc_clk_rate) { + dev_err(state->dev, "Could not get esc clock rate.\n"); + return -EINVAL; + } + + dev_dbg(state->dev, "esc clk rate: %lu\n", esc_clk_rate); + esc_clk_period_ns = 1000000000 / esc_clk_rate; + + min_ths_settle = 85 + 6 * 1000000 / (lane_rate / 1000); + max_ths_settle = 140 + 10 * 1000000 / (lane_rate / 1000); + ths_settle_ns = (min_ths_settle + max_ths_settle) / 2; + + state->hs_settle = ths_settle_ns / esc_clk_period_ns - 1; + + dev_dbg(state->dev, "lane rate %u Ths_settle %u hs_settle %u\n", + lane_rate, ths_settle_ns, state->hs_settle); + + return 0; +} + +static int imx8mq_mipi_csi_start_stream(struct csi_state *state) +{ + int ret; + + ret = imx8mq_mipi_csi_sw_reset(state); + if (ret) + return ret; + + imx8mq_mipi_csi_set_params(state); + ret = imx8mq_mipi_csi_calc_hs_settle(state); + if (ret) + return ret; + + imx8mq_mipi_csi_system_enable(state, true); + + return 0; +} + +static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) +{ + imx8mq_mipi_csi_system_enable(state, false); +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static struct csi_state *mipi_sd_to_csi2_state(struct v4l2_subdev *sdev) +{ + return container_of(sdev, struct csi_state, sd); +} + +static int imx8mq_mipi_csi_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + imx8mq_mipi_csi_write(state, CSI2RX_IRQ_MASK, + CSI2RX_IRQ_MASK_ULPS_STATUS_CHANGE); + + if (enable) { + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; + } + + mutex_lock(&state->lock); + + if (enable) { + if (state->state & ST_SUSPENDED) { + ret = -EBUSY; + goto unlock; + } + + ret = imx8mq_mipi_csi_start_stream(state); + if (ret < 0) + goto unlock; + + ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); + if (ret < 0) + goto unlock; + + state->state |= ST_STREAMING; + } else { + v4l2_subdev_call(state->src_sd, video, s_stream, 0); + imx8mq_mipi_csi_stop_stream(state); + state->state &= ~ST_STREAMING; + } + +unlock: + mutex_unlock(&state->lock); + + if (!enable || ret < 0) + pm_runtime_put(state->dev); + + return ret; +} + +static struct v4l2_mbus_framefmt * +imx8mq_mipi_csi_get_format(struct csi_state *state, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which, + unsigned int pad) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&state->sd, sd_state, pad); + + return &state->format_mbus[pad]; +} + +static int imx8mq_mipi_csi_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct v4l2_mbus_framefmt *fmt_sink; + struct v4l2_mbus_framefmt *fmt_source; + enum v4l2_subdev_format_whence which; + + which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt_sink = imx8mq_mipi_csi_get_format(state, sd_state, which, + MIPI_CSI2_PAD_SINK); + + fmt_sink->code = MEDIA_BUS_FMT_SGBRG10_1X10; + fmt_sink->width = MIPI_CSI2_DEF_PIX_WIDTH; + fmt_sink->height = MIPI_CSI2_DEF_PIX_HEIGHT; + fmt_sink->field = V4L2_FIELD_NONE; + + fmt_sink->colorspace = V4L2_COLORSPACE_RAW; + fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); + fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); + fmt_sink->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, + fmt_sink->ycbcr_enc); + + fmt_source = imx8mq_mipi_csi_get_format(state, sd_state, which, + MIPI_CSI2_PAD_SOURCE); + *fmt_source = *fmt_sink; + + return 0; +} + +static int imx8mq_mipi_csi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct v4l2_mbus_framefmt *fmt; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + sdformat->format = *fmt; + + mutex_unlock(&state->lock); + + return 0; +} + +static int imx8mq_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + /* + * We can't transcode in any way, the source format is identical + * to the sink format. + */ + if (code->pad == MIPI_CSI2_PAD_SOURCE) { + struct v4l2_mbus_framefmt *fmt; + + if (code->index > 0) + return -EINVAL; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, code->which, + code->pad); + code->code = fmt->code; + return 0; + } + + if (code->pad != MIPI_CSI2_PAD_SINK) + return -EINVAL; + + if (code->index >= ARRAY_SIZE(imx8mq_mipi_csi_formats)) + return -EINVAL; + + code->code = imx8mq_mipi_csi_formats[code->index].code; + + return 0; +} + +static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct csi2_pix_format const *csi2_fmt; + struct v4l2_mbus_framefmt *fmt; + + /* + * The device can't transcode in any way, the source format can't be + * modified. + */ + if (sdformat->pad == MIPI_CSI2_PAD_SOURCE) + return imx8mq_mipi_csi_get_fmt(sd, sd_state, sdformat); + + if (sdformat->pad != MIPI_CSI2_PAD_SINK) + return -EINVAL; + + csi2_fmt = find_csi2_format(sdformat->format.code); + if (!csi2_fmt) + csi2_fmt = &imx8mq_mipi_csi_formats[0]; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + fmt->code = csi2_fmt->code; + fmt->width = sdformat->format.width; + fmt->height = sdformat->format.height; + + sdformat->format = *fmt; + + /* Propagate the format from sink to source. */ + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + MIPI_CSI2_PAD_SOURCE); + *fmt = sdformat->format; + + /* Store the CSI2 format descriptor for active formats. */ + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + state->csi2_fmt = csi2_fmt; + + mutex_unlock(&state->lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx8mq_mipi_csi_video_ops = { + .s_stream = imx8mq_mipi_csi_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx8mq_mipi_csi_pad_ops = { + .init_cfg = imx8mq_mipi_csi_init_cfg, + .enum_mbus_code = imx8mq_mipi_csi_enum_mbus_code, + .get_fmt = imx8mq_mipi_csi_get_fmt, + .set_fmt = imx8mq_mipi_csi_set_fmt, +}; + +static const struct v4l2_subdev_ops imx8mq_mipi_csi_subdev_ops = { + .video = &imx8mq_mipi_csi_video_ops, + .pad = &imx8mq_mipi_csi_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static const struct media_entity_operations imx8mq_mipi_csi_entity_ops = { + .link_validate = v4l2_subdev_link_validate, + .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, +}; + +/* ----------------------------------------------------------------------------- + * Async subdev notifier + */ + +static struct csi_state * +mipi_notifier_to_csi2_state(struct v4l2_async_notifier *n) +{ + return container_of(n, struct csi_state, notifier); +} + +static int imx8mq_mipi_csi_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct csi_state *state = mipi_notifier_to_csi2_state(notifier); + struct media_pad *sink = &state->sd.entity.pads[MIPI_CSI2_PAD_SINK]; + + state->src_sd = sd; + + return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static const struct v4l2_async_notifier_operations imx8mq_mipi_csi_notify_ops = { + .bound = imx8mq_mipi_csi_notify_bound, +}; + +static int imx8mq_mipi_csi_async_register(struct csi_state *state) +{ + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct v4l2_async_subdev *asd; + struct fwnode_handle *ep; + unsigned int i; + int ret; + + v4l2_async_notifier_init(&state->notifier); + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + return -ENOTCONN; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; + + for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) { + if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) { + dev_err(state->dev, + "data lanes reordering is not supported"); + ret = -EINVAL; + goto err_parse; + } + } + + state->bus = vep.bus.mipi_csi2; + + dev_dbg(state->dev, "data lanes: %d flags: 0x%08x\n", + state->bus.num_data_lanes, + state->bus.flags); + + asd = v4l2_async_notifier_add_fwnode_remote_subdev(&state->notifier, + ep, struct v4l2_async_subdev); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto err_parse; + } + + fwnode_handle_put(ep); + + state->notifier.ops = &imx8mq_mipi_csi_notify_ops; + + ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier); + if (ret) + return ret; + + return v4l2_async_register_subdev(&state->sd); + +err_parse: + fwnode_handle_put(ep); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Suspend/resume + */ + +static int imx8mq_mipi_csi_pm_suspend(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + mutex_lock(&state->lock); + + if (state->state & ST_POWERED) { + imx8mq_mipi_csi_stop_stream(state); + imx8mq_mipi_csi_clk_disable(state); + state->state &= ~ST_POWERED; + if (!runtime) + state->state |= ST_SUSPENDED; + } + + mutex_unlock(&state->lock); + + ret = icc_set_bw(state->icc_path, 0, 0); + if (ret) + dev_err(dev, "icc_set_bw failed with %d\n", ret); + + return ret ? -EAGAIN : 0; +} + +static int imx8mq_mipi_csi_pm_resume(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + ret = icc_set_bw(state->icc_path, 0, state->icc_path_bw); + if (ret) { + dev_err(dev, "icc_set_bw failed with %d\n", ret); + return ret; + } + + mutex_lock(&state->lock); + + if (!runtime && !(state->state & ST_SUSPENDED)) + goto unlock; + + if (!(state->state & ST_POWERED)) { + state->state |= ST_POWERED; + ret = imx8mq_mipi_csi_clk_enable(state); + } + if (state->state & ST_STREAMING) { + ret = imx8mq_mipi_csi_start_stream(state); + if (ret) + goto unlock; + } + + state->state &= ~ST_SUSPENDED; + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; +} + +static int __maybe_unused imx8mq_mipi_csi_suspend(struct device *dev) +{ + return imx8mq_mipi_csi_pm_suspend(dev, false); +} + +static int __maybe_unused imx8mq_mipi_csi_resume(struct device *dev) +{ + return imx8mq_mipi_csi_pm_resume(dev, false); +} + +static int __maybe_unused imx8mq_mipi_csi_runtime_suspend(struct device *dev) +{ + return imx8mq_mipi_csi_pm_suspend(dev, true); +} + +static int __maybe_unused imx8mq_mipi_csi_runtime_resume(struct device *dev) +{ + return imx8mq_mipi_csi_pm_resume(dev, true); +} + +static const struct dev_pm_ops imx8mq_mipi_csi_pm_ops = { + SET_RUNTIME_PM_OPS(imx8mq_mipi_csi_runtime_suspend, + imx8mq_mipi_csi_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(imx8mq_mipi_csi_suspend, imx8mq_mipi_csi_resume) +}; + +/* ----------------------------------------------------------------------------- + * Probe/remove & platform driver + */ + +static int imx8mq_mipi_csi_subdev_init(struct csi_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + v4l2_subdev_init(sd, &imx8mq_mipi_csi_subdev_ops); + sd->owner = THIS_MODULE; + snprintf(sd->name, sizeof(sd->name), "%s %s", + MIPI_CSI2_SUBDEV_NAME, dev_name(state->dev)); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &imx8mq_mipi_csi_entity_ops; + + sd->dev = state->dev; + + state->csi2_fmt = &imx8mq_mipi_csi_formats[0]; + imx8mq_mipi_csi_init_cfg(sd, NULL); + + state->pads[MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK + | MEDIA_PAD_FL_MUST_CONNECT; + state->pads[MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + | MEDIA_PAD_FL_MUST_CONNECT; + return media_entity_pads_init(&sd->entity, MIPI_CSI2_PADS_NUM, + state->pads); +} + +static void imx8mq_mipi_csi_release_icc(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + icc_put(state->icc_path); +} + +static int imx8mq_mipi_csi_init_icc(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + /* Optional interconnect request */ + state->icc_path = of_icc_get(&pdev->dev, "dram"); + if (IS_ERR_OR_NULL(state->icc_path)) + return PTR_ERR_OR_ZERO(state->icc_path); + + state->icc_path_bw = MBps_to_icc(700); + + return 0; +} + +static int imx8mq_mipi_csi_parse_dt(struct csi_state *state) +{ + struct device *dev = state->dev; + struct device_node *np = state->dev->of_node; + struct device_node *node; + phandle ph; + u32 out_val[2]; + int ret = 0; + + state->rst = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(state->rst)) { + dev_err(dev, "Failed to get reset: %pe\n", state->rst); + return PTR_ERR(state->rst); + } + + ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, + ARRAY_SIZE(out_val)); + if (ret) { + dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret); + return ret; + } + + ph = *out_val; + + node = of_find_node_by_phandle(ph); + if (!node) { + dev_err(dev, "Error finding node by phandle\n"); + return -ENODEV; + } + state->phy_gpr = syscon_node_to_regmap(node); + of_node_put(node); + if (IS_ERR(state->phy_gpr)) { + dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr); + return PTR_ERR(state->phy_gpr); + } + + state->phy_gpr_reg = out_val[1]; + dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg); + + return ret; +} + +static int imx8mq_mipi_csi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct csi_state *state; + int ret; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->dev = dev; + + ret = imx8mq_mipi_csi_parse_dt(state); + if (ret < 0) { + dev_err(dev, "Failed to parse device tree: %d\n", ret); + return ret; + } + + /* Acquire resources. */ + state->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(state->regs)) + return PTR_ERR(state->regs); + + ret = imx8mq_mipi_csi_clk_get(state); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, &state->sd); + + mutex_init(&state->lock); + + ret = imx8mq_mipi_csi_subdev_init(state); + if (ret < 0) + goto mutex; + + ret = imx8mq_mipi_csi_init_icc(pdev); + if (ret) + goto mutex; + + /* Enable runtime PM. */ + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = imx8mq_mipi_csi_pm_resume(dev, true); + if (ret < 0) + goto icc; + } + + ret = imx8mq_mipi_csi_async_register(state); + if (ret < 0) + goto cleanup; + + return 0; + +cleanup: + pm_runtime_disable(&pdev->dev); + imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + + media_entity_cleanup(&state->sd.entity); + v4l2_async_notifier_unregister(&state->notifier); + v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); +icc: + imx8mq_mipi_csi_release_icc(pdev); +mutex: + mutex_destroy(&state->lock); + + return ret; +} + +static int imx8mq_mipi_csi_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + v4l2_async_notifier_unregister(&state->notifier); + v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); + + pm_runtime_disable(&pdev->dev); + imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + media_entity_cleanup(&state->sd.entity); + mutex_destroy(&state->lock); + pm_runtime_set_suspended(&pdev->dev); + imx8mq_mipi_csi_release_icc(pdev); + + return 0; +} + +static const struct of_device_id imx8mq_mipi_csi_of_match[] = { + { .compatible = "fsl,imx8mq-mipi-csi2", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); + +static struct platform_driver imx8mq_mipi_csi_driver = { + .probe = imx8mq_mipi_csi_probe, + .remove = imx8mq_mipi_csi_remove, + .driver = { + .of_match_table = imx8mq_mipi_csi_of_match, + .name = MIPI_CSI2_DRIVER_NAME, + .pm = &imx8mq_mipi_csi_pm_ops, + }, +}; + +module_platform_driver(imx8mq_mipi_csi_driver); + +MODULE_DESCRIPTION("i.MX8MQ MIPI CSI-2 receiver driver"); +MODULE_AUTHOR("Martin Kepplinger <martin.kepplinger@puri.sm>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx8mq-mipi-csi2"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 6821e3d05d34..ef0311a16d01 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -247,6 +247,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, const struct v4l2_ctrl_hevc_slice_params *slice_params; const struct v4l2_ctrl_hevc_decode_params *decode_params; const struct v4l2_hevc_pred_weight_table *pred_weight_table; + unsigned int width_in_ctb_luma, ctb_size_luma; + unsigned int log2_max_luma_coding_block_size; dma_addr_t src_buf_addr; dma_addr_t src_buf_end_addr; u32 chroma_log2_weight_denom; @@ -260,15 +262,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, decode_params = run->h265.decode_params; pred_weight_table = &slice_params->pred_weight_table; + log2_max_luma_coding_block_size = + sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_luma = 1UL << log2_max_luma_coding_block_size; + width_in_ctb_luma = + DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma); + /* MV column buffer size and allocation. */ if (!ctx->codec.h265.mv_col_buf_size) { unsigned int num_buffers = run->dst->vb2_buf.vb2_queue->num_buffers; - unsigned int log2_max_luma_coding_block_size = - sps->log2_min_luma_coding_block_size_minus3 + 3 + - sps->log2_diff_max_min_luma_coding_block_size; - unsigned int ctb_size_luma = - 1UL << log2_max_luma_coding_block_size; /* * Each CTB requires a MV col buffer with a specific unit size. @@ -322,15 +326,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr); cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg); - /* Coding tree block address: start at the beginning. */ - reg = VE_DEC_H265_DEC_CTB_ADDR_X(0) | VE_DEC_H265_DEC_CTB_ADDR_Y(0); + /* Coding tree block address */ + reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma); + reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma); cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg); cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0); cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0); /* Clear the number of correctly-decoded coding tree blocks. */ - cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0); + if (ctx->fh.m2m_ctx->new_frame) + cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0); /* Initialize bitstream access. */ cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); @@ -482,8 +488,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, slice_params->flags); - /* FIXME: For multi-slice support. */ - reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; + if (ctx->fh.m2m_ctx->new_frame) + reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO0, reg); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 32c13ecb22d8..c589fe9dae70 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -340,6 +340,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv, switch (ctx->src_fmt.pixelformat) { case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_HEVC_SLICE: vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; break; diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 89709cd06d4d..d321790b07d9 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -508,8 +508,8 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, return -ENODEV; sd_state = v4l2_subdev_alloc_state(subdev); - if (!sd_state) - return -ENOMEM; + if (IS_ERR(sd_state)) + return PTR_ERR(sd_state); /* * Retrieve the format information and if requested format isn't * supported, keep the current format. diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index d37cb74b769c..b0a535d6893a 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -394,6 +394,8 @@ #define USB_PID_MYGICA_T230C 0xc689 #define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_MYGICA_T230C_LITE 0xc699 +#define USB_PID_MYGICA_T230C2_LITE 0xc69a +#define USB_PID_MYGICA_T230A 0x689a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 53c0038c792b..781371bff2ad 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -196,10 +196,11 @@ struct v4l2_ctrl_hevc_slice_params { __u8 pic_struct; /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u32 slice_segment_addr; __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __u8 padding[5]; + __u8 padding; /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ struct v4l2_hevc_pred_weight_table pred_weight_table; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index a1019c4ab5e8..8c5b7978e1d9 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -151,7 +151,7 @@ struct lirc_fh { * @tx_ir: transmit IR * @s_idle: enable/disable hardware idle mode, upon which, * device doesn't interrupt host until it sees IR pulses - * @s_learning_mode: enable wide band receiver used for learning + * @s_wideband_receiver: enable wide band receiver used for learning * @s_carrier_report: enable carrier reports * @s_filter: set the scancode filter * @s_wakeup_filter: set the wakeup scancode filter. If the mask is zero @@ -218,7 +218,7 @@ struct rc_dev { int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max); int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n); void (*s_idle)(struct rc_dev *dev, bool enable); - int (*s_learning_mode)(struct rc_dev *dev, int enable); + int (*s_wideband_receiver)(struct rc_dev *dev, int enable); int (*s_carrier_report) (struct rc_dev *dev, int enable); int (*s_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); @@ -313,6 +313,7 @@ struct ir_raw_event { #define MS_TO_US(msec) ((msec) * 1000) #define IR_MAX_DURATION MS_TO_US(500) #define IR_DEFAULT_TIMEOUT MS_TO_US(125) +#define IR_MAX_TIMEOUT LIRC_VALUE_MASK void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 5b275a845c20..fa4901162663 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -129,11 +129,11 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir); * * This function initializes the notifier @asd_list. It must be called * before adding a subdevice to a notifier, using one of: - * @v4l2_async_notifier_add_fwnode_remote_subdev, - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_i2c_subdev, - * @__v4l2_async_notifier_add_subdev or - * @v4l2_async_notifier_parse_fwnode_endpoints. + * v4l2_async_notifier_add_fwnode_remote_subdev(), + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_i2c_subdev(), + * __v4l2_async_notifier_add_subdev() or + * v4l2_async_notifier_parse_fwnode_endpoints(). */ void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier); @@ -145,9 +145,9 @@ void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier); * @asd: pointer to &struct v4l2_async_subdev * * \warning: Drivers should avoid using this function and instead use one of: - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_fwnode_remote_subdev or - * @v4l2_async_notifier_add_i2c_subdev. + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_fwnode_remote_subdev() or + * v4l2_async_notifier_add_i2c_subdev(). * * Call this function before registering a notifier to link the provided @asd to * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as @@ -200,7 +200,7 @@ __v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif * function also gets a reference of the fwnode which is released later at * notifier cleanup time. * - * This is just like @v4l2_async_notifier_add_fwnode_subdev, but with the + * This is just like v4l2_async_notifier_add_fwnode_subdev(), but with the * exception that the fwnode refers to a local endpoint, not the remote one. */ #define v4l2_async_notifier_add_fwnode_remote_subdev(notifier, ep, type) \ @@ -265,13 +265,13 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); * sub-devices allocated for the purposes of the notifier but not the notifier * itself. The user is responsible for calling this function to clean up the * notifier after calling - * @v4l2_async_notifier_add_fwnode_remote_subdev, - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_i2c_subdev, - * @__v4l2_async_notifier_add_subdev or - * @v4l2_async_notifier_parse_fwnode_endpoints. + * v4l2_async_notifier_add_fwnode_remote_subdev(), + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_i2c_subdev(), + * __v4l2_async_notifier_add_subdev() or + * v4l2_async_notifier_parse_fwnode_endpoints(). * - * There is no harm from calling v4l2_async_notifier_cleanup in other + * There is no harm from calling v4l2_async_notifier_cleanup() in other * cases as long as its memory has been zeroed after it has been * allocated. */ diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 95f8bfd63273..95ec18c2f49c 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -355,6 +355,16 @@ struct v4l2_mbus_frame_desc { }; /** + * enum v4l2_subdev_pre_streamon_flags - Flags for pre_streamon subdev core op + * + * @V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP: Set the transmitter to either LP-11 + * or LP-111 mode before call to s_stream(). + */ +enum v4l2_subdev_pre_streamon_flags { + V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP = BIT(0), +}; + +/** * struct v4l2_subdev_video_ops - Callbacks used when v4l device was opened * in video mode. * @@ -409,6 +419,19 @@ struct v4l2_mbus_frame_desc { * @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev * can adjust @size to a lower value and must not write more data to the * buffer starting at @data than the original value of @size. + * + * @pre_streamon: May be called before streaming is actually started, to help + * initialising the bus. Current usage is to set a CSI-2 transmitter to + * LP-11 or LP-111 mode before streaming. See &enum + * v4l2_subdev_pre_streamon_flags. + * + * pre_streamon shall return error if it cannot perform the operation as + * indicated by the flags argument. In particular, -EACCES indicates lack + * of support for the operation. The caller shall call post_streamoff for + * each successful call of pre_streamon. + * + * @post_streamoff: Called after streaming is stopped, but if and only if + * pre_streamon was called earlier. */ struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); @@ -435,6 +458,8 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, unsigned int *size); + int (*pre_streamon)(struct v4l2_subdev *sd, u32 flags); + int (*post_streamoff)(struct v4l2_subdev *sd); }; /** @@ -871,7 +896,7 @@ struct v4l2_subdev_platform_data { * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. * @subdev_notifier: A sub-device notifier implicitly registered for the sub- - * device using v4l2_device_register_sensor_subdev(). + * device using v4l2_async_register_subdev_sensor(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index dc8879d179fd..de936f5e446d 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -642,7 +642,7 @@ struct cec_event { #define CEC_OP_REC_SEQ_WEDNESDAY 0x08 #define CEC_OP_REC_SEQ_THURSDAY 0x10 #define CEC_OP_REC_SEQ_FRIDAY 0x20 -#define CEC_OP_REC_SEQ_SATERDAY 0x40 +#define CEC_OP_REC_SEQ_SATURDAY 0x40 #define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 #define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index fdf97a6d7d18..5532b5f68493 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -435,6 +435,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX (V4L2_CID_CODEC_BASE+233) #define V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES (V4L2_CID_CODEC_BASE+234) #define V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR (V4L2_CID_CODEC_BASE+235) +#define V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (V4L2_CID_CODEC_BASE+236) /* CIDs for the MPEG-2 Part 2 (H.262) codec */ #define V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL (V4L2_CID_CODEC_BASE+270) |