diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
| commit | f4cdf7ca9a1fdcca413157df19753f388a5a224e (patch) | |
| tree | 60a31895b2446cd7fa27514e8c2843534a0de0da | |
| parent | e5c91aac491def6ab3f90c4cc246e3fcb0f8f058 (diff) | |
| parent | 4900cad020c0580dfb1be27776ff10a4ef110cfa (diff) | |
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- v4l2-core: added ISP statistics support and per-block validation
- v4l2-core: Allow unknown HDR10 white point and luminance
- New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor
- New codec: Milos: VPU v2.0 codec support
- isp driver: gained support for Dreamchip RPPX1 ISP framework
- vsp1 driver: gained support for RZ/T2H and RZ/N2H
- Novalake driver: gained CVS support for new NVL hardware
- dvb-core: fix feed leak on failed DMX_ADD_PID
- several driver fixes, cleanups and minor improvements
* tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
media: ipu-bridge: check all DMI entries when overriding sensor rotation
media: v4l2-async: avoid deleting unlinked ASC entry on link error
media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement
media: intel/ipu6: fix async notifier cleanup leak on parse error
media: staging/ipu7: fix async notifier UAF on probe error path
media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path
media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem()
media: rcar-isp: Fix VSPX reference leaks
media: rcar-isp: Release ISPCORE resources
media: i2c: imx415: Release runtime PM reference on VBLANK error
media: i2c: imx415: Return test pattern write errors
media: renesas: vsp1: Declare index variables in for loop statement
media: renesas: vsp1: Make reset control optional to support platforms without a reset line
media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs
media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs
media: nxp: imx8-isi: Add additional 32-bit RGB format support
media: nxp: imx8-isi: Add 16-bit raw Bayer format support
media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams
media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks
media: nxp: imx8-isi: Correct color map between V4L2 and ISI
...
351 files changed, 14578 insertions, 4601 deletions
@@ -640,6 +640,10 @@ S: 25-29 St Giles S: Oxford S: United Kingdom +N: Bingbu Cao +E: bingbu.cao@amd.com +D: Ipu6, ipu7 and camera sensor drivers + N: Luiz Fernando N. Capitulino E: lcapitulino@mandriva.com.br E: lcapitulino@gmail.com @@ -3334,6 +3338,9 @@ E: rpurdie@rpsys.net D: Backlight subsystem maintainer S: United Kingdom +N: Tian Shu Qiu +D: Ipu6, ipu7 and camera sensor drivers + N: Daniel Quinlan E: quinlan@pathname.com W: https://www.pathname.com/~quinlan/ diff --git a/Documentation/admin-guide/media/em28xx-cardlist.rst b/Documentation/admin-guide/media/em28xx-cardlist.rst index 7dac07986d91..741aa7f7c882 100644 --- a/Documentation/admin-guide/media/em28xx-cardlist.rst +++ b/Documentation/admin-guide/media/em28xx-cardlist.rst @@ -446,3 +446,7 @@ EM28xx cards list - MyGica UTV3 Analog USB2.0 TV Box - em2860 - eb1a:2860 + * - 113 + - StarTech SVID2USB232 + - em28281 + - eb1a:8286 diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml index 6050d7e7dcfe..d9cdfda699bf 100644 --- a/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx355.yaml @@ -50,8 +50,15 @@ properties: properties: data-lanes: - minItems: 4 - maxItems: 4 + oneOf: + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + - items: + - const: 1 + - const: 2 required: - link-frequencies diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml new file mode 100644 index 000000000000..098f72544216 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml @@ -0,0 +1,130 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2026 Ideas on Board Oy +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx678.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX678 Sensor + +maintainers: + - Jai Luthra <jai.luthra@ideasonboard.com> + +description: + Sony IMX678 diagonal 8.86 mm (Type 1/1.8) CMOS active pixel type solid-state + image sensor with a square pixel array and 8.40M (3856x2180) effective pixels. + +allOf: + - $ref: /schemas/media/video-interface-devices.yaml# + +properties: + compatible: + items: + - enum: + - sony,imx678-aamr + - sony,imx678-aaqr + - const: sony,imx678 + description: + The IMX678 sensor exists in a colour variant (IMX678-AAQR) and a mono + variant (IMX678-AAMR). The variant-specific compatible describes the + exact sensor variant, with the generic IMX678 compatible as a fallback. + + reg: + maxItems: 1 + + clocks: + description: | + Input clock (INCK). Only the rates listed in the datasheet are supported: + 13.5, 18, 24, 27, 36, 37.125, 72, and 74.25 MHz. + maxItems: 1 + + avdd-supply: + description: Analog power supply (3.3V) + + ovdd-supply: + description: Interface power supply (1.8V) + + dvdd-supply: + description: Digital power supply (1.1V) + + reset-gpios: + description: Sensor RESETN (XCLR) GPIO + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + oneOf: + - items: + - const: 1 + - const: 2 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + - items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + - const: 5 + - const: 6 + - const: 7 + - const: 8 + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - avdd-supply + - ovdd-supply + - dvdd-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx678-aaqr", "sony,imx678"; + reg = <0x1a>; + clocks = <&imx678_clk>; + + avdd-supply = <&camera_avdd_3v3>; + ovdd-supply = <&camera_ovdd_1v8>; + dvdd-supply = <&camera_dvdd_1v1>; + + reset-gpios = <&gpio 0 GPIO_ACTIVE_LOW>; + + port { + imx678: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <720000000>; + }; + }; + }; + }; +... diff --git a/Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml b/Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml index 060ac6829b66..58b1f9e85a9d 100644 --- a/Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml +++ b/Documentation/devicetree/bindings/media/i2c/st,vd55g1.yaml @@ -27,9 +27,10 @@ properties: compatible: enum: - st,vd55g1 + - st,vd55g4 - st,vd65g4 description: - VD55G1 is the monochrome variant, while VD65G4 is the color one. + VD55G1 and VD55G4 are monochrome variants, while VD65G4 is a color one. reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml b/Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml index b59c4ce30b8b..279c9cd3034a 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml @@ -117,7 +117,9 @@ allOf: compatible: not: contains: - const: fsl,imx91-isi + enum: + - fsl,imx8ulp-isi + - fsl,imx91-isi then: required: - fsl,blk-ctrl diff --git a/Documentation/devicetree/bindings/media/qcom,milos-iris.yaml b/Documentation/devicetree/bindings/media/qcom,milos-iris.yaml new file mode 100644 index 000000000000..b0b0355ad52e --- /dev/null +++ b/Documentation/devicetree/bindings/media/qcom,milos-iris.yaml @@ -0,0 +1,166 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/qcom,milos-iris.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Milos SoC Iris video encoder and decoder + +maintainers: + - Alexander Koskovich <akoskovich@pm.me> + +description: + The Iris video processing unit on Qualcomm Milos SoC is a video encode and + decode accelerator. + +properties: + compatible: + enum: + - qcom,milos-iris + + clocks: + maxItems: 3 + + clock-names: + items: + - const: iface + - const: core + - const: vcodec0_core + + dma-coherent: true + + interconnects: + maxItems: 2 + + interconnect-names: + items: + - const: cpu-cfg + - const: video-mem + + iommus: + maxItems: 2 + + operating-points-v2: true + opp-table: + type: object + + power-domains: + maxItems: 4 + + power-domain-names: + items: + - const: venus + - const: vcodec0 + - const: cx + - const: mx + + resets: + maxItems: 2 + + reset-names: + items: + - const: bus + - const: core + +required: + - compatible + - dma-coherent + - interconnects + - interconnect-names + - iommus + - power-domain-names + - resets + - reset-names + +allOf: + - $ref: qcom,venus-common.yaml# + +unevaluatedProperties: false + +examples: + - | + #include <dt-bindings/clock/qcom,rpmh.h> + #include <dt-bindings/clock/qcom,milos-gcc.h> + #include <dt-bindings/clock/qcom,milos-videocc.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interconnect/qcom,icc.h> + #include <dt-bindings/interconnect/qcom,milos-rpmh.h> + #include <dt-bindings/power/qcom-rpmpd.h> + #include <dt-bindings/power/qcom,rpmhpd.h> + + video-codec@aa00000 { + compatible = "qcom,milos-iris"; + reg = <0x0aa00000 0xf0000>; + + clocks = <&gcc GCC_VIDEO_AXI0_CLK>, + <&videocc VIDEO_CC_MVS0C_CLK>, + <&videocc VIDEO_CC_MVS0_CLK>; + clock-names = "iface", + "core", + "vcodec0_core"; + + dma-coherent; + iommus = <&apps_smmu 0x1960 0>, + <&apps_smmu 0x1967 0>; + + interconnects = <&gem_noc MASTER_APPSS_PROC QCOM_ICC_TAG_ACTIVE_ONLY + &cnoc_cfg SLAVE_VENUS_CFG QCOM_ICC_TAG_ACTIVE_ONLY>, + <&mmss_noc MASTER_VIDEO QCOM_ICC_TAG_ALWAYS + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>; + interconnect-names = "cpu-cfg", + "video-mem"; + + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; + + operating-points-v2 = <&iris_opp_table>; + + memory-region = <&video_mem>; + + power-domains = <&videocc VIDEO_CC_MVS0C_GDSC>, + <&videocc VIDEO_CC_MVS0_GDSC>, + <&rpmhpd RPMHPD_CX>, + <&rpmhpd RPMHPD_MX>; + power-domain-names = "venus", + "vcodec0", + "cx", + "mx"; + + resets = <&gcc GCC_VIDEO_AXI0_CLK_ARES>, + <&videocc VIDEO_CC_MVS0C_CLK_ARES>; + reset-names = "bus", + "core"; + + iris_opp_table: opp-table { + compatible = "operating-points-v2"; + + opp-240000000 { + opp-hz = /bits/ 64 <240000000>; + required-opps = <&rpmhpd_opp_low_svs>, + <&rpmhpd_opp_svs>; + }; + + opp-338000000 { + opp-hz = /bits/ 64 <338000000>; + required-opps = <&rpmhpd_opp_svs>, + <&rpmhpd_opp_svs>; + }; + + opp-366000000 { + opp-hz = /bits/ 64 <366000000>; + required-opps = <&rpmhpd_opp_svs_l1>, + <&rpmhpd_opp_svs>; + }; + + opp-444000000 { + opp-hz = /bits/ 64 <444000000>; + required-opps = <&rpmhpd_opp_nom>, + <&rpmhpd_opp_svs_l1>; + }; + + opp-552000000 { + opp-hz = /bits/ 64 <552000000>; + required-opps = <&rpmhpd_opp_turbo>, + <&rpmhpd_opp_nom>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml index 391d0f6f67ef..490a7f3a8c5f 100644 --- a/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml +++ b/Documentation/devicetree/bindings/media/qcom,qcm2290-camss.yaml @@ -14,7 +14,11 @@ description: properties: compatible: - const: qcom,qcm2290-camss + oneOf: + - items: + - const: qcom,shikra-camss + - const: qcom,qcm2290-camss + - const: qcom,qcm2290-camss reg: maxItems: 9 @@ -76,7 +80,14 @@ properties: - const: sf_mnoc iommus: - maxItems: 4 + oneOf: + - items: + - description: S1 HLOS VFE non-protected (VFE only) + - items: + - description: S1 HLOS VFE non-protected + - description: S1 HLOS CDM non-protected + - description: S1 HLOS OPE read non-protected + - description: S1 HLOS OPE write non-protected power-domains: items: diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index dedc5a4b81ec..43d84296e70d 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -122,10 +122,10 @@ properties: - rc-proteus-2309 - rc-purpletv - rc-pv951 - - rc-rc5-tv - rc-rc6-mce - rc-real-audio-220-32-keys - rc-reddo + - rc-siemens-gigaset-rc20 - rc-snapstream-firefly - rc-streamzap - rc-su3000 @@ -147,11 +147,11 @@ properties: - rc-tt-1500 - rc-twinhan-dtv-cab-ci - rc-twinhan1027 + - rc-vega-s9x - rc-videomate-k100 - rc-videomate-s350 - rc-videomate-tv-pvr - rc-videostrong-kii-pro - - rc-vega-s9x - rc-wetek-hub - rc-wetek-play2 - rc-winfast diff --git a/Documentation/devicetree/bindings/media/renesas,fcp.yaml b/Documentation/devicetree/bindings/media/renesas,fcp.yaml index 5e11ae0ee456..cbb16a7a5481 100644 --- a/Documentation/devicetree/bindings/media/renesas,fcp.yaml +++ b/Documentation/devicetree/bindings/media/renesas,fcp.yaml @@ -34,6 +34,8 @@ properties: - renesas,r9a09g047-fcpvd # RZ/G3E - renesas,r9a09g056-fcpvd # RZ/V2N - renesas,r9a09g057-fcpvd # RZ/V2H(P) + - renesas,r9a09g077-fcpvd # RZ/T2H + - renesas,r9a09g087-fcpvd # RZ/N2H - const: renesas,fcpv # Generic FCP for VSP fallback reg: @@ -66,7 +68,6 @@ required: - reg - clocks - power-domains - - resets additionalProperties: false @@ -83,6 +84,8 @@ allOf: - renesas,r9a09g047-fcpvd - renesas,r9a09g056-fcpvd - renesas,r9a09g057-fcpvd + - renesas,r9a09g077-fcpvd + - renesas,r9a09g087-fcpvd then: properties: clocks: @@ -94,6 +97,19 @@ allOf: clocks: maxItems: 1 clock-names: false + - if: + properties: + compatible: + contains: + enum: + - renesas,r9a09g077-fcpvd + - renesas,r9a09g087-fcpvd + then: + properties: + resets: false + else: + required: + - resets examples: # R8A7795 (R-Car H3) FCP for VSP-D1 diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.yaml b/Documentation/devicetree/bindings/media/renesas,vsp1.yaml index 803358780f01..a28632165804 100644 --- a/Documentation/devicetree/bindings/media/renesas,vsp1.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.yaml @@ -29,6 +29,8 @@ properties: - renesas,r9a09g047-vsp2 # RZ/G3E - renesas,r9a09g056-vsp2 # RZ/V2N - renesas,r9a09g057-vsp2 # RZ/V2H(P) + - renesas,r9a09g077-vsp2 # RZ/T2H + - renesas,r9a09g087-vsp2 # RZ/N2H - const: renesas,r9a07g044-vsp2 # RZ/G2L fallback reg: @@ -67,7 +69,6 @@ required: - interrupts - clocks - power-domains - - resets additionalProperties: false @@ -101,6 +102,20 @@ allOf: maxItems: 1 clock-names: false + - if: + properties: + compatible: + contains: + enum: + - renesas,r9a09g077-vsp2 + - renesas,r9a09g087-vsp2 + then: + properties: + resets: false + else: + required: + - resets + examples: # R8A7790 (R-Car H2) VSP1-S - | diff --git a/Documentation/devicetree/bindings/media/ti,am437x-vpfe.yaml b/Documentation/devicetree/bindings/media/ti,am437x-vpfe.yaml new file mode 100644 index 000000000000..983e705ab1e8 --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti,am437x-vpfe.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/ti,am437x-vpfe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments AM437x CAMERA Video Processing Front End (VPFE) + +maintainers: + - Benoit Parrot <bparrot@ti.com> + - Bhargav Joshi <j.bhargav.u@gmail.com> + +description: + The Video Processing Front End (VPFE) is a key component for image capture + applications. The capture module provides the system interface and the + processing capability to connect RAW image-sensor modules and video decoders + to the AM437x device. + +properties: + compatible: + const: ti,am437x-vpfe + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + A single parallel input port connecting to an external image sensor or + video decoder. The VPFE supports only one input port per instance. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + ti,am437x-vpfe-interface: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2, 3, 4] + description: + Selects the VPFE input interface type can be one of following + 0 - Raw Bayer (VPFE_RAW_BAYER) + 1 - BT.656 8-bit (VPFE_BT656) + 2 - BT.656 10-bit (VPFE_BT656_10BIT) + 3 - YCbCr 8-bit sync (VPFE_YCBCR_SYNC_8) + 4 - YCbCr 16-bit sync (VPFE_YCBCR_SYNC_16) + + bus-width: + minimum: 8 + maximum: 16 + + required: + - remote-endpoint + - ti,am437x-vpfe-interface + - bus-width + +required: + - compatible + - reg + - interrupts + - port + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/interrupt-controller/irq.h> + + vpfe@48328000{ + compatible = "ti,am437x-vpfe"; + reg = <0x48328000 0x2000>; + interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&vpfe_pins_default>; + pinctrl-1 = <&vpfe_pins_sleep>; + + port { + vpfe0_ep: endpoint { + remote-endpoint = <&ov2659_1>; + ti,am437x-vpfe-interface = <0>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt b/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt deleted file mode 100644 index 3932e766553a..000000000000 --- a/Documentation/devicetree/bindings/media/ti-am437x-vpfe.txt +++ /dev/null @@ -1,61 +0,0 @@ -Texas Instruments AM437x CAMERA (VPFE) --------------------------------------- - -The Video Processing Front End (VPFE) is a key component for image capture -applications. The capture module provides the system interface and the -processing capability to connect RAW image-sensor modules and video decoders -to the AM437x device. - -Required properties: -- compatible: must be "ti,am437x-vpfe" -- reg: physical base address and length of the registers set for the device; -- interrupts: should contain IRQ line for the VPFE; -- ti,am437x-vpfe-interface: can be one of the following, - 0 - Raw Bayer Interface. - 1 - 8 Bit BT656 Interface. - 2 - 10 Bit BT656 Interface. - 3 - YCbCr 8 Bit Interface. - 4 - YCbCr 16 Bit Interface. - -VPFE supports a single port node with parallel bus. It should contain one -'port' child node with child 'endpoint' node. Please refer to the bindings -defined in Documentation/devicetree/bindings/media/video-interfaces.txt. - -Example: - vpfe: vpfe@f0034000 { - compatible = "ti,am437x-vpfe"; - reg = <0x48328000 0x2000>; - interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>; - - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&vpfe_pins_default>; - pinctrl-1 = <&vpfe_pins_sleep>; - - port { - #address-cells = <1>; - #size-cells = <0>; - - vpfe0_ep: endpoint { - remote-endpoint = <&ov2659_1>; - ti,am437x-vpfe-interface = <0>; - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - }; - }; - }; - - i2c1: i2c@4802a000 { - - ov2659@30 { - compatible = "ti,ov2659"; - reg = <0x30>; - - port { - ov2659_1: endpoint { - remote-endpoint = <&vpfe0_ep>; - bus-width = <8>; - mclk-frequency = <12000000>; - }; - }; - }; diff --git a/Documentation/driver-api/media/maintainer-entry-profile.rst b/Documentation/driver-api/media/maintainer-entry-profile.rst index c5c00c66d85c..7806d83128d4 100644 --- a/Documentation/driver-api/media/maintainer-entry-profile.rst +++ b/Documentation/driver-api/media/maintainer-entry-profile.rst @@ -432,6 +432,10 @@ The Media Driver Maintainers responsible for specific areas are: - Qualcomm drivers + - Ricardo Ribalda <ribalda@chromium.org> + + - Media-CI + Submit Checklist Addendum ------------------------- diff --git a/Documentation/userspace-api/media/cec/cec-ioc-adap-g-log-addrs.rst b/Documentation/userspace-api/media/cec/cec-ioc-adap-g-log-addrs.rst index f3293a589dd6..8397bf573798 100644 --- a/Documentation/userspace-api/media/cec/cec-ioc-adap-g-log-addrs.rst +++ b/Documentation/userspace-api/media/cec/cec-ioc-adap-g-log-addrs.rst @@ -185,6 +185,13 @@ logical address types are already defined will return with error ``EBUSY``. are CEC devices that can only handle CDC messages. All other messages are ignored. + * .. _`CEC-LOG-ADDRS-FL-CONFIG-FAILED`: + + - ``CEC_LOG_ADDRS_FL_CONFIG_FAILED`` + - 8 + - If this flag is set, then the CEC device failed to claim a free logical + address and is in the unconfigured state. This can never happen if + ``CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK`` was set as well. .. tabularcolumns:: |p{7.8cm}|p{1.0cm}|p{8.5cm}| diff --git a/Documentation/userspace-api/media/dvb/legacy_dvb_video.rst b/Documentation/userspace-api/media/dvb/legacy_dvb_video.rst index b9fd5cadae24..71d044605315 100644 --- a/Documentation/userspace-api/media/dvb/legacy_dvb_video.rst +++ b/Documentation/userspace-api/media/dvb/legacy_dvb_video.rst @@ -344,7 +344,7 @@ Variables - .. - - :rspan:`5` ``stuct play`` + - :rspan:`5` ``struct play`` - :rspan:`4` ``__s32 speed`` diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst index 38a4136d7220..0a7da2f16850 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-colorimetry.rst @@ -80,15 +80,25 @@ Colorimetry Control IDs - ``white_point_x`` - Specifies the normalized x chromaticity coordinate of the white point of the mastering display in increments of 0.00002. + When both ``white_point_x`` and ``white_point_y`` are zero, + the white point chromaticity is unknown. If either coordinate is + non-zero, both coordinates shall be within their valid ranges. * - __u16 - ``white_point_y`` - Specifies the normalized y chromaticity coordinate of the white point of the mastering display in increments of 0.00002. + When both ``white_point_x`` and ``white_point_y`` are zero, + the white point chromaticity is unknown. If either coordinate is + non-zero, both coordinates shall be within their valid ranges. * - __u32 - ``max_luminance`` - Specifies the nominal maximum display luminance of the mastering display in units of 0.0001 cd/m\ :sup:`2`. + A value of zero indicates that the nominal maximum display + luminance is unknown. * - __u32 - ``min_luminance`` - - specifies the nominal minimum display luminance of the mastering + - Specifies the nominal minimum display luminance of the mastering display in units of 0.0001 cd/m\ :sup:`2`. + A value of zero indicates that the nominal minimum display + luminance is unknown. diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst index 3e0cab153f0a..b5455229837e 100644 --- a/Documentation/userspace-api/media/v4l/meta-formats.rst +++ b/Documentation/userspace-api/media/v4l/meta-formats.rst @@ -21,6 +21,7 @@ These formats are used for the :ref:`metadata` interface only. metafmt-pisp-be metafmt-pisp-fe metafmt-rkisp1 + metafmt-rppx1 metafmt-uvc metafmt-uvc-msxu-1-5 metafmt-vivid diff --git a/Documentation/userspace-api/media/v4l/metafmt-rppx1.rst b/Documentation/userspace-api/media/v4l/metafmt-rppx1.rst new file mode 100644 index 000000000000..a174e0a3e022 --- /dev/null +++ b/Documentation/userspace-api/media/v4l/metafmt-rppx1.rst @@ -0,0 +1,99 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _v4l2-meta-fmt-rppx1-params: +.. _v4l2-meta-fmt-rppx1-stats: + +************************************************************************* +V4L2_META_FMT_RPPX1_PARAMS ('DR1P'), V4L2_META_FMT_RPPX1_STATS ('DR1S') +************************************************************************* + +Configuration Parameters +======================== + +The configuration parameters are passed to the metadata output video node, using +the :c:type:`v4l2_meta_format` interface. Rather than a single struct containing +sub-structs for each configurable area of the ISP, parameters for the Dreamchip +RPPX1 use the v4l2-isp parameters system, through which groups of parameters are +defined as distinct structs or "blocks" which may be added to the data member of +:c:type:`v4l2_isp_buffer`. Userspace is responsible for populating the data +member with the blocks that need to be configured by the driver. Each +block-specific struct embeds :c:type:`v4l2_isp_block_header` as its first member +and userspace must populate the type member with a value from +:c:type:`rppx1_params_block_type`. + +.. code-block:: c + + struct v4l2_isp_params_buffer *params = + (struct v4l2_isp_params_buffer *)buffer; + + params->version = V4L2_ISP_PARAMS_VERSION_V1; + params->data_size = 0; + + void *data = (void *)params->data; + + struct rppx1_ccor_params *ccor = + (struct rppx1_ccor_params *)data; + + ccor->header.type = RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST; + ccor->header.flags |= V4L2_ISP_PARAMS_FL_BLOCK_ENABLE; + ccor->header.size = sizeof(struct rppx1_ccor_params); + + ccor->coeff[0][0] = 0x1000; + ccor->coeff[0][1] = 0x0000; + ccor->coeff[0][2] = 0x0000; + ccor->coeff[1][0] = 0x0000; + ccor->coeff[1][1] = 0x1000; + ccor->coeff[1][2] = 0x0000; + ccor->coeff[2][0] = 0x0000; + ccor->coeff[2][1] = 0x0000; + ccor->coeff[2][2] = 0x1000; + + ccor->offset[0] = 0x200000; + ccor->offset[1] = 0x200000; + ccor->offset[2] = 0x200000; + + data += sizeof(struct rppx1_ccor_params); + params->data_size += sizeof(struct rppx1_ccor_params); + +3A Statistics +============= + +The ISP device collects different statistics over an input bayer frame. Those +statistics can be obtained by userspace from the metadata capture video node, +using the :c:type:`v4l2_meta_format` interface. Rather than a single struct +containing sub-structs for each statistics area of the ISP, statistics for the +Dreamchip RPPX1 use the v4l2-isp statistics system, through which groups of +statistics are defined as distinct structs or "blocks" which may be added to the +data member of :c:type:`v4l2_isp_buffer`. Userspace is responsible for parsing +the buffer and extracting the blocks of statistics. Each block-specific struct +embeds :c:type:`v4l2_isp_block_header` as its first member and userspace must +interpret the type member with a value from :c:type:`rppx1_stats_block_type`. + +.. code-block:: C + + const struct v4l2_isp_buffer *stats = + (struct v4l2_isp_buffer *)buf; + size_t block_offset = 0; + + while (block_offset < stats->data_size) { + const struct v4l2_isp_stats_block_header *block = + (void*)(stats->data + block_offset); + + block_offset += block->size; + + switch (block->type) { + case RPPX1_STATS_BLOCK_TYPE_HIST_POST: + for (unsigned int i = 0; i < RPPX1_HIST_NUM_BINS; i++) + printf("hist.hist_bins[%u] = 0x%08x\n", + i, hist.hist_bins[%i]); + break; + default: + printf("Unknown block type 0x%04x", block->type); + break; + } + } + +Dreamchip RPPX1 uAPI data types +=============================== + +.. kernel-doc:: include/uapi/linux/media/dreamchip/rppx1-config.h diff --git a/Documentation/userspace-api/media/v4l/v4l2-isp.rst b/Documentation/userspace-api/media/v4l/v4l2-isp.rst index facf6dba1ca7..8a3f05b5e85f 100644 --- a/Documentation/userspace-api/media/v4l/v4l2-isp.rst +++ b/Documentation/userspace-api/media/v4l/v4l2-isp.rst @@ -18,22 +18,22 @@ single C structure that contains a header, followed by a binary buffer where userspace programs a variable number of ISP configuration data block, one for each supported ISP feature. -The :c:type:`v4l2_isp_params_buffer` structure defines the buffer header which -is followed by a binary buffer of ISP configuration data. Userspace shall -correctly populate the buffer header with the generic parameters format version -and with the size (in bytes) of the binary data buffer where it will store the -ISP blocks configuration. +The :c:type:`v4l2_isp_buffer` structure defines the buffer header which is +followed by a binary buffer of ISP configuration data. Userspace shall correctly +populate the buffer header with the serialization format version and with the +size (in bytes) of the binary data buffer where it will store the ISP blocks +configuration. -Each *ISP configuration block* is preceded by an header implemented by the -:c:type:`v4l2_isp_params_block_header` structure, followed by the configuration +Each *ISP configuration block* is preceded by a header implemented by the +:c:type:`v4l2_isp_block_header` structure, followed by the configuration parameters for that specific block, defined by the ISP driver specific data types. Userspace applications are responsible for correctly populating each block's header fields (type, flags and size) and the block-specific parameters. -ISP block enabling, disabling and configuration ------------------------------------------------ +ISP parameters block enabling, disabling and configuration +---------------------------------------------------------- When userspace wants to configure and enable an ISP block it shall fully populate the block configuration and set the V4L2_ISP_PARAMS_FL_BLOCK_ENABLE @@ -59,7 +59,30 @@ definition without invalidating the existing ones. ISP statistics ============== -Support for generic statistics format is not yet implemented in Video4Linux2. +The generic ISP statistics format is identical to the generic ISP configuration +parameters format. It is realized by defining a C structure that contains a +header, followed by binary buffer where the ISP driver copies a variable number +of ISP statistics blocks. + +Extensible statistics buffers have :c:type:`v4l2_isp_buffer` header followed by +a binary buffer of ISP statistics data. ISP drivers populate the buffer header +with the serialization format version and with the size (in bytes) of the binary +data buffer where ISP statistics data are serialized. Applications shall +validate that the serialization format version matches the expected one and that +the buffer size doesn't exceed the maximum size for a statistics buffer as +declared by the driver's uAPI header. + +Each *ISP statistics block* is preceded by a header implemented by the +:c:type:`v4l2_isp_block_header` structure, followed by the statistics data for +that specific block. The driver might optionally report platform-specific flags +associated with each statistics block. + +Applications inspect the statistics block type as reported in the header and +validates the reported size matches the block's expected size before accessing +the ISP statistics data. + +Extension to the statistics format can be implemented by adding new blocks +definition without invalidating the existing ones. V4L2 ISP uAPI data types ======================== diff --git a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst index b8698b85bd80..d78328152b75 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst @@ -72,12 +72,6 @@ partial array, all elements have to be set or retrieved. The total size is calculated as ``elems`` * ``elem_size``. These values can be obtained by calling :ref:`VIDIOC_QUERY_EXT_CTRL <VIDIOC_QUERYCTRL>`. -To change the value of a set of controls applications initialize the -``id``, ``size``, ``reserved2`` and ``value/value64/string/ptr`` fields -of each struct :c:type:`v4l2_ext_control` and call -the :ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` ioctl. The controls will only be set if *all* -control values are valid. - To check if a set of controls have correct values applications initialize the ``id``, ``size``, ``reserved2`` and ``value/value64/string/ptr`` fields of each struct @@ -86,6 +80,15 @@ initialize the ``id``, ``size``, ``reserved2`` and values are automatically adjusted to a valid value or if an error is returned. +To change the value of a set of controls applications initialize the +``id``, ``size``, ``reserved2`` and ``value/value64/string/ptr`` fields +of each struct :c:type:`v4l2_ext_control` and call +the :ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` ioctl. +:ref:`VIDIOC_S_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` will implicitly call +:ref:`VIDIOC_TRY_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` first and return an +error if that fails. So the controls will only be set if *all* +control values are valid. + When the ``id`` or ``which`` is invalid drivers return an ``EINVAL`` error code. When the value is out of bounds drivers can choose to take the closest valid value or return an ``ERANGE`` error code, whatever seems more diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst index 6f66ca38589e..164cf0ad3593 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst @@ -67,7 +67,7 @@ subdevice routing table. This may be smaller or larger than the value of drivers may adjust the requested routing table. The kernel can return a ``num_routes`` value larger than ``len_routes`` from -both ioctls. This indicates thare are more routes in the routing table than fits +both ioctls. This indicates there are more routes in the routing table than fits the ``routes`` array. In this case, the ``routes`` array is filled by the kernel with the first ``len_routes`` entries of the subdevice routing table. This is not considered to be an error, and the ioctl call succeeds. If the applications diff --git a/MAINTAINERS b/MAINTAINERS index a6332a1ec903..096e8608e94a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3936,7 +3936,7 @@ F: Documentation/devicetree/bindings/leds/ams,as3668.yaml F: drivers/leds/leds-as3668.c ASAHI KASEI AK7375 LENS VOICE COIL DRIVER -M: Tianshu Qiu <tian.shu.qiu@intel.com> +M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -7868,6 +7868,16 @@ F: drivers/block/drbd/ F: include/linux/drbd* F: lib/lru_cache.c +DREAMCHIP RPPX1 ISP +M: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com> +M: Jai Luthra <jai.luthra+renesas@ideasonboard.com> +M: Niklas Söderlund <niklas.soderlund@ragnatech.se> +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/userspace-api/media/v4l/metafmt-rppx1.rst +F: drivers/media/platform/dreamchip/rppx1/ +F: include/uapi/linux/media/dreamchip/rppx1-config.h + DRIVER COMPONENT FRAMEWORK L: dri-devel@lists.freedesktop.org F: drivers/base/component.c @@ -13133,9 +13143,7 @@ F: drivers/iommu/intel/ INTEL IPU3 CSI-2 CIO2 DRIVER M: Yong Zhi <yong.zhi@intel.com> M: Sakari Ailus <sakari.ailus@linux.intel.com> -M: Bingbu Cao <bingbu.cao@intel.com> M: Dan Scally <dan.scally@ideasonboard.com> -R: Tianshu Qiu <tian.shu.qiu@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -13144,8 +13152,6 @@ F: drivers/media/pci/intel/ipu3/ INTEL IPU3 CSI-2 IMGU DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> -R: Bingbu Cao <bingbu.cao@intel.com> -R: Tianshu Qiu <tian.shu.qiu@intel.com> L: linux-media@vger.kernel.org S: Maintained F: Documentation/admin-guide/media/ipu3.rst @@ -13155,8 +13161,6 @@ F: drivers/staging/media/ipu3/ INTEL IPU6 INPUT SYSTEM DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> -M: Bingbu Cao <bingbu.cao@intel.com> -R: Tianshu Qiu <tian.shu.qiu@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -13165,7 +13169,6 @@ F: drivers/media/pci/intel/ipu6/ INTEL IPU7 INPUT SYSTEM DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> -R: Bingbu Cao <bingbu.cao@intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -13377,6 +13380,7 @@ INTEL SKYLAKE INT3472 ACPI DEVICE DRIVER M: Daniel Scally <dan.scally@ideasonboard.com> M: Sakari Ailus <sakari.ailus@linux.intel.com> S: Maintained +T: git git://linuxtv.org/media.git F: drivers/platform/x86/intel/int3472/ F: include/linux/platform_data/x86/int3472.h @@ -13467,7 +13471,6 @@ F: drivers/net/wireless/intel/iwlwifi/ INTEL VISION SENSING CONTROLLER DRIVER M: Sakari Ailus <sakari.ailus@linux.intel.com> -R: Bingbu Cao <bingbu.cao@intel.com> R: Lixu Zhang <lixu.zhang@intel.com> L: linux-media@vger.kernel.org S: Maintained @@ -19501,7 +19504,9 @@ F: drivers/iio/adc/vf610_adc.c NXP i.MX 8M ISI DRIVER M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> +R: Frank Li <Frank.Li@nxp.com> L: linux-media@vger.kernel.org +L: imx@lists.linux.dev S: Maintained F: Documentation/devicetree/bindings/media/fsl,imx8*-isi.yaml F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml @@ -19934,7 +19939,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,os05b10.yaml F: drivers/media/i2c/os05b10.c OMNIVISION OV01A10 SENSOR DRIVER -M: Bingbu Cao <bingbu.cao@intel.com> +M: Bingbu Cao <bingbu.cao@amd.com> +M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -20027,9 +20033,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov2735.yaml F: drivers/media/i2c/ov2735.c OMNIVISION OV2740 SENSOR DRIVER -M: Tianshu Qiu <tian.shu.qiu@intel.com> -R: Sakari Ailus <sakari.ailus@linux.intel.com> -R: Bingbu Cao <bingbu.cao@intel.com> +M: Sakari Ailus <sakari.ailus@linux.intel.com> +R: Bingbu Cao <bingbu.cao@amd.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -20171,8 +20176,8 @@ F: Documentation/devicetree/bindings/media/i2c/ovti,ov9650.txt F: drivers/media/i2c/ov9650.c OMNIVISION OV9734 SENSOR DRIVER -M: Tianshu Qiu <tian.shu.qiu@intel.com> -R: Bingbu Cao <bingbu.cao@intel.com> +M: Sakari Ailus <sakari.ailus@linux.intel.com> +R: Bingbu Cao <bingbu.cao@amd.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -25253,7 +25258,8 @@ F: Documentation/devicetree/bindings/media/i2c/sony,imx296.yaml F: drivers/media/i2c/imx296.c SONY IMX319 SENSOR DRIVER -M: Bingbu Cao <bingbu.cao@intel.com> +M: Bingbu Cao <bingbu.cao@amd.com> +M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -25275,7 +25281,9 @@ 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> +M: Sakari Ailus <sakari.ailus@linux.intel.com> +M: Dave Stevenson <dave.stevenson@raspberrypi.com> +R: David Heidelberg <david@ixit.cz> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media.git @@ -25296,6 +25304,19 @@ T: git git://linuxtv.org/media.git F: Documentation/devicetree/bindings/media/i2c/sony,imx415.yaml F: drivers/media/i2c/imx415.c +SONY IMX471 SENSOR DRIVER +M: Kate Hsuan <hpa@redhat.com> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/imx471.c + +SONY IMX678 SENSOR DRIVER +M: Jai Luthra <jai.luthra@ideasonboard.com> +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/i2c/sony,imx678.yaml +F: drivers/media/i2c/imx678.c + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky <maximlevitsky@gmail.com> M: Alex Dubov <oakad@yahoo.com> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fce86b1b2fae..9df1d76fbf2b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -859,6 +859,7 @@ static const char * const acpi_honor_dep_ids[] = { "INTC10DE", /* CVS (LNL) driver must be loaded to allow camera streaming */ "INTC10E0", /* CVS (ARL) driver must be loaded to allow camera streaming */ "INTC10E1", /* CVS (PTL) driver must be loaded to allow camera streaming */ + "INTC10FA", /* CVS (NVL) driver must be loaded to allow camera streaming */ "RSCV0001", /* RISC-V PLIC */ "RSCV0002", /* RISC-V APLIC */ "RSCV0005", /* RISC-V SBI MPXY MBOX */ diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index a90cb84a4b4d..ee8a200b9803 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -80,9 +80,9 @@ void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { static const u16 max_events[CEC_NUM_EVENTS] = { - 1, 1, 800, 800, 8, 8, 8, 8 + 3, 1, 800, 800, 8, 8, 8, 8 }; - struct cec_event_entry *entry; + struct cec_event_entry *new_entry, *entry; unsigned int ev_idx = new_ev->event - 1; if (WARN_ON(ev_idx >= ARRAY_SIZE(fh->events))) @@ -92,36 +92,57 @@ void cec_queue_event_fh(struct cec_fh *fh, ts = ktime_get_ns(); mutex_lock(&fh->lock); - if (ev_idx < CEC_NUM_CORE_EVENTS) - entry = &fh->core_events[ev_idx]; - else - entry = kmalloc_obj(*entry); - if (entry) { + new_entry = kmalloc_obj(*new_entry); + if (new_entry) { if (new_ev->event == CEC_EVENT_LOST_MSGS && fh->queued_events[ev_idx]) { + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); entry->ev.lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs; + kfree(new_entry); goto unlock; } - entry->ev = *new_ev; - entry->ev.ts = ts; + + new_entry->ev = *new_ev; + new_entry->ev.ts = ts; + + /* + * If the physical address becomes invalid (HPD went low), + * then just flush all pending STATE_CHANGE events since + * those are all obsoleted. + * + * This ensures you will not see stale STATE_CHANGE events. + */ + if (new_ev->event == CEC_EVENT_STATE_CHANGE && + new_ev->state_change.phys_addr == CEC_PHYS_ADDR_INVALID && + fh->queued_events[ev_idx]) { + /* drop all events */ + while (!list_empty(&fh->events[ev_idx])) { + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); + list_del(&entry->list); + kfree(entry); + fh->total_queued_events--; + fh->queued_events[ev_idx]--; + } + new_entry->ev.flags |= CEC_EVENT_FL_DROPPED_EVENTS; + } if (fh->queued_events[ev_idx] < max_events[ev_idx]) { /* Add new msg at the end of the queue */ - list_add_tail(&entry->list, &fh->events[ev_idx]); + list_add_tail(&new_entry->list, &fh->events[ev_idx]); fh->queued_events[ev_idx]++; fh->total_queued_events++; goto unlock; } - if (ev_idx >= CEC_NUM_CORE_EVENTS) { - list_add_tail(&entry->list, &fh->events[ev_idx]); - /* drop the oldest event */ - entry = list_first_entry(&fh->events[ev_idx], - struct cec_event_entry, list); - list_del(&entry->list); - kfree(entry); - } + list_add_tail(&new_entry->list, &fh->events[ev_idx]); + /* drop the oldest event */ + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); + list_del(&entry->list); + kfree(entry); } /* Mark that events were lost */ entry = list_first_entry_or_null(&fh->events[ev_idx], @@ -608,6 +629,13 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, attempts_made = 1; mutex_lock(&adap->lock); + if (adap->error_inj_tx_timeouts) { + dprintk(2, "%s: error_inj_tx_timeouts %u\n", + __func__, adap->error_inj_tx_timeouts); + adap->error_inj_tx_timeouts--; + mutex_unlock(&adap->lock); + return; + } data = adap->transmitting; if (!data) { /* @@ -965,7 +993,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, */ mutex_unlock(&adap->lock); err = wait_for_completion_killable(&data->c); - cancel_delayed_work_sync(&data->work); + disable_delayed_work_sync(&data->work); mutex_lock(&adap->lock); if (err) @@ -1317,7 +1345,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, { struct cec_log_addrs *las = &adap->log_addrs; struct cec_msg msg = { }; - const unsigned int max_retries = 2; + const unsigned int max_attempts = 3; unsigned int i; int err; @@ -1328,7 +1356,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, msg.len = 1; msg.msg[0] = (log_addr << 4) | log_addr; - for (i = 0; i < max_retries; i++) { + for (i = 0; i < max_attempts; i++) { err = cec_transmit_msg_fh(adap, &msg, NULL, true); /* @@ -1345,31 +1373,24 @@ static int cec_config_log_addr(struct cec_adapter *adap, if (err) return err; - /* - * The message was aborted or timed out due to a disconnect or - * unconfigure, just bail out. - */ - if (msg.tx_status & - (CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT)) - return -EINTR; if (msg.tx_status & CEC_TX_STATUS_OK) return 0; if (msg.tx_status & CEC_TX_STATUS_NACK) break; /* - * Retry up to max_retries times if the message was neither + * Do up to max_attempts if the message was neither * OKed or NACKed. This can happen due to e.g. a Lost * Arbitration condition. */ } /* - * If we are unable to get an OK or a NACK after max_retries attempts + * If we are unable to get an OK or a NACK after max_attempts * (and note that each attempt already consists of four polls), then * we assume that something is really weird and that it is not a * good idea to try and claim this logical address. */ - if (i == max_retries) { + if (i == max_attempts) { dprintk(0, "polling for LA %u failed with tx_status=0x%04x\n", log_addr, msg.tx_status); return 0; @@ -1468,6 +1489,7 @@ static int cec_config_thread_func(void *arg) dprintk(1, "physical address: %x.%x.%x.%x, claim %d logical addresses\n", cec_phys_addr_exp(adap->phys_addr), las->num_log_addrs); las->log_addr_mask = 0; + las->flags &= ~CEC_LOG_ADDRS_FL_CONFIG_FAILED; if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED) goto configured; @@ -1600,6 +1622,8 @@ configured: unconfigure: for (i = 0; i < las->num_log_addrs; i++) las->log_addr[i] = CEC_LOG_ADDR_INVALID; + if (adap->phys_addr != CEC_PHYS_ADDR_INVALID) + las->flags |= CEC_LOG_ADDRS_FL_CONFIG_FAILED; cec_adap_unconfigure(adap); adap->is_configuring = false; adap->must_reconfigure = false; @@ -1717,7 +1741,6 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) cec_phys_addr_exp(phys_addr)); if (becomes_invalid || !is_invalid) { adap->phys_addr = CEC_PHYS_ADDR_INVALID; - cec_post_state_event(adap); cec_adap_unconfigure(adap); if (becomes_invalid) { cec_adap_enable(adap); @@ -2219,9 +2242,13 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * Unprocessed messages are aborted if userspace isn't doing * any processing either. */ + mutex_lock(&adap->lock); if (!is_broadcast && !is_reply && !adap->follower_cnt && - !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) + !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) { + mutex_unlock(&adap->lock); return cec_feature_abort(adap, msg); + } + mutex_unlock(&adap->lock); break; } @@ -2234,10 +2261,12 @@ skip_processing: * Send to the exclusive follower if there is one, otherwise send * to all followers. */ + mutex_lock(&adap->lock); if (adap->cec_follower) cec_queue_msg_fh(adap->cec_follower, msg); else cec_queue_msg_followers(adap, msg); + mutex_unlock(&adap->lock); return 0; } diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c index 103ded79526f..a491d7fc8a71 100644 --- a/drivers/media/cec/core/cec-api.c +++ b/drivers/media/cec/core/cec-api.c @@ -345,8 +345,7 @@ static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, if (copy_to_user(parg, &ev->ev, sizeof(ev->ev))) err = -EFAULT; - if (ev_idx >= CEC_NUM_CORE_EVENTS) - kfree(ev); + kfree(ev); fh->queued_events[ev_idx]--; fh->total_queued_events--; @@ -673,7 +672,7 @@ static int cec_release(struct inode *inode, struct file *filp) list_del(&entry->list); kfree(entry); } - for (i = CEC_NUM_CORE_EVENTS; i < CEC_NUM_EVENTS; i++) { + for (i = 0; i < CEC_NUM_EVENTS; i++) { while (!list_empty(&fh->events[i])) { struct cec_event_entry *entry = list_first_entry(&fh->events[i], diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 0fcd3b5e60c8..230f8a413e74 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -5,16 +5,33 @@ * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/cdev.h> +#include <linux/container_of.h> #include <linux/debugfs.h> -#include <linux/errno.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/fs.h> #include <linux/init.h> -#include <linux/kernel.h> -#include <linux/kmod.h> -#include <linux/mm.h> +#include <linux/kobject.h> +#include <linux/kthread.h> +#include <linux/list.h> +#include <linux/minmax.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/printk.h> +#include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/sprintf.h> #include <linux/string.h> +#include <linux/time.h> #include <linux/types.h> +#include <linux/wait.h> + +#include <asm/page.h> #include "cec-priv.h" @@ -93,7 +110,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES); if (minor == CEC_NUM_DEVICES) { mutex_unlock(&cec_devnode_lock); - pr_err("could not get a free minor\n"); + pr_err("Could not get a free minor\n"); return -ENFILE; } @@ -104,19 +121,19 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, devnode->dev.bus = &cec_bus_type; devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); devnode->dev.release = cec_devnode_release; - dev_set_name(&devnode->dev, "cec%d", devnode->minor); + dev_set_name(&devnode->dev, "%s%d", CEC_NAME, devnode->minor); device_initialize(&devnode->dev); /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &cec_devnode_fops); devnode->cdev.owner = owner; - kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); + kobject_set_name(&devnode->cdev.kobj, "%s%d", CEC_NAME, devnode->minor); devnode->registered = true; ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { devnode->registered = false; - pr_err("%s: cdev_device_add failed\n", __func__); + pr_err("cdev_device_add() failed\n"); goto clr_bit; } @@ -205,19 +222,35 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused) return call_op(adap, error_inj_show, sf); } +DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj); -static int cec_error_inj_open(struct inode *inode, struct file *file) +static ssize_t cec_error_inj_tx_timeouts_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) { - return single_open(file, cec_error_inj_show, inode->i_private); + struct seq_file *sf = file->private_data; + struct cec_adapter *adap = sf->private; + int ret; + + if (count > 5) + return -EINVAL; + + mutex_lock(&adap->lock); + ret = kstrtou32_from_user(ubuf, count, 0, &adap->error_inj_tx_timeouts); + if (ret) + adap->error_inj_tx_timeouts = 0; + mutex_unlock(&adap->lock); + return ret ? : count; } -static const struct file_operations cec_error_inj_fops = { - .open = cec_error_inj_open, - .write = cec_error_inj_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +static int cec_error_inj_tx_timeouts_show(struct seq_file *sf, void *unused) +{ + struct cec_adapter *adap = sf->private; + + seq_printf(sf, "%u", adap->error_inj_tx_timeouts); + return 0; +} + +DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj_tx_timeouts); #endif struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, @@ -263,12 +296,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, mutex_init(&adap->devnode.lock_fhs); mutex_init(&adap->devnode.lock); - adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); + adap->kthread = kthread_run(cec_thread_func, adap, "%s-%s", CEC_NAME, name); if (IS_ERR(adap->kthread)) { - pr_err("cec-%s: kernel_thread() failed\n", name); + pr_err("%s: kthread_run() failed\n", name); res = PTR_ERR(adap->kthread); - kfree(adap); - return ERR_PTR(res); + goto err_free_adap; } #ifdef CONFIG_MEDIA_CEC_RC @@ -278,11 +310,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, /* Prepare the RC input device */ adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE); if (!adap->rc) { - pr_err("cec-%s: failed to allocate memory for rc_dev\n", - name); + pr_err("%s: failed to allocate memory for rc_dev\n", name); kthread_stop(adap->kthread); - kfree(adap); - return ERR_PTR(-ENOMEM); + res = -ENOMEM; + goto err_free_adap; } snprintf(adap->input_phys, sizeof(adap->input_phys), @@ -298,9 +329,18 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->allowed_protocols = RC_PROTO_BIT_CEC; adap->rc->priv = adap; adap->rc->map_name = RC_MAP_CEC; - adap->rc->timeout = MS_TO_US(550); + adap->rc->timeout = 550 * USEC_PER_MSEC; #endif return adap; + +err_free_adap: + mutex_destroy(&adap->devnode.lock); + mutex_destroy(&adap->devnode.lock_fhs); + + mutex_destroy(&adap->lock); + + kfree(adap); + return ERR_PTR(res); } EXPORT_SYMBOL_GPL(cec_allocate_adapter); @@ -326,8 +366,7 @@ int cec_register_adapter(struct cec_adapter *adap, res = rc_register_device(adap->rc); if (res) { - pr_err("cec-%s: failed to prepare input device\n", - adap->name); + pr_err("%s: failed to prepare input device\n", adap->name); rc_free_device(adap->rc); adap->rc = NULL; return res; @@ -356,6 +395,9 @@ int cec_register_adapter(struct cec_adapter *adap, debugfs_create_devm_seqfile(&adap->devnode.dev, "status", adap->cec_dir, cec_adap_status); + debugfs_create_file("error-inj-tx-timeouts", 0644, adap->cec_dir, adap, + &cec_error_inj_tx_timeouts_fops); + if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line) return 0; debugfs_create_file("error-inj", 0644, adap->cec_dir, adap, @@ -371,9 +413,7 @@ void cec_unregister_adapter(struct cec_adapter *adap) return; #ifdef CONFIG_MEDIA_CEC_RC - /* Note: rc_unregister also calls rc_free */ rc_unregister_device(adap->rc); - adap->rc = NULL; #endif debugfs_remove_recursive(adap->cec_dir); #ifdef CONFIG_CEC_NOTIFIER @@ -387,14 +427,23 @@ void cec_delete_adapter(struct cec_adapter *adap) { if (IS_ERR_OR_NULL(adap)) return; + if (adap->kthread_config) kthread_stop(adap->kthread_config); kthread_stop(adap->kthread); + if (adap->ops->adap_free) adap->ops->adap_free(adap); + #ifdef CONFIG_MEDIA_CEC_RC rc_free_device(adap->rc); #endif + + mutex_destroy(&adap->devnode.lock); + mutex_destroy(&adap->devnode.lock_fhs); + + mutex_destroy(&adap->lock); + kfree(adap); } EXPORT_SYMBOL_GPL(cec_delete_adapter); @@ -407,14 +456,14 @@ static int __init cec_devnode_init(void) int ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, CEC_NAME); if (ret < 0) { - pr_warn("cec: unable to allocate major\n"); + pr_warn("Unable to allocate major\n"); return ret; } #ifdef CONFIG_DEBUG_FS - top_cec_dir = debugfs_create_dir("cec", NULL); + top_cec_dir = debugfs_create_dir(CEC_NAME, NULL); if (IS_ERR_OR_NULL(top_cec_dir)) { - pr_warn("cec: Failed to create debugfs cec dir\n"); + pr_warn("Failed to create debugfs " CEC_NAME " dir\n"); top_cec_dir = NULL; } #endif @@ -423,7 +472,7 @@ static int __init cec_devnode_init(void) if (ret < 0) { debugfs_remove_recursive(top_cec_dir); unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); - pr_warn("cec: bus_register failed\n"); + pr_warn("bus_register() failed\n"); return -EIO; } diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index 6e1c39102832..6a0ee32e8401 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -115,7 +115,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) return; pin->adap->cec_pin_is_high = v; - if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { + if (atomic_read_acquire(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { u8 ev = v; if (pin->work_pin_events_dropped) { @@ -126,7 +126,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); pin->work_pin_events_wr = (pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS; - atomic_inc(&pin->work_pin_num_events); + atomic_inc_return_release(&pin->work_pin_num_events); } else { pin->work_pin_events_dropped = true; pin->work_pin_events_dropped_cnt++; @@ -692,7 +692,6 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) v = cec_pin_read(pin); if (!v) break; - pin->state = CEC_ST_RX_START_BIT_HIGH; delta = ktime_us_delta(ts, pin->ts); /* Start bit low is too short, go back to idle */ if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) { @@ -703,7 +702,16 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) cec_pin_to_idle(pin); break; } + pin->state = CEC_ST_RX_START_BIT_HIGH; if (rx_arb_lost(pin, &poll)) { + /* + * Normally rx_toggle is toggled in cec_pin_to_idle() + * when we're in an RX state, but here we switch to TX + * mode, so cec_pin_to_idle() sees a TX mode and never + * toggles rx_toggle. So toggle it here as a special + * corner case. + */ + pin->rx_toggle ^= 1; cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf); pin->tx_generated_poll = true; pin->tx_extra_bytes = 0; @@ -1101,7 +1109,7 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } - while (atomic_read(&pin->work_pin_num_events)) { + while (atomic_read_acquire(&pin->work_pin_num_events)) { unsigned int idx = pin->work_pin_events_rd; u8 v = pin->work_pin_events[idx]; @@ -1110,7 +1118,7 @@ static int cec_pin_thread_func(void *_adap) v & CEC_PIN_EVENT_FL_DROPPED, pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS; - atomic_dec(&pin->work_pin_num_events); + atomic_dec_return_release(&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change, diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c index 41f5b8669cb0..b175be3f2bf4 100644 --- a/drivers/media/cec/platform/meson/ao-cec-g12a.c +++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c @@ -405,6 +405,7 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr, } static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { + .name = "core", .reg_bits = 8, .val_bits = 8, .reg_read = meson_ao_cec_g12a_read, @@ -688,10 +689,8 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) meson_ao_cec_g12a_irq, meson_ao_cec_g12a_irq_thread, 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); + if (ret) goto out_probe_adapter; - } ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); if (IS_ERR(ao_cec->oscin)) { diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c index 145efd9af6ac..2df0d3743077 100644 --- a/drivers/media/cec/platform/meson/ao-cec.c +++ b/drivers/media/cec/platform/meson/ao-cec.c @@ -636,10 +636,8 @@ static int meson_ao_cec_probe(struct platform_device *pdev) meson_ao_cec_irq, meson_ao_cec_irq_thread, 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); + if (ret) goto out_probe_adapter; - } ao_cec->core = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(ao_cec->core)) { diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c index 97ed9654c78a..12db6dca602b 100644 --- a/drivers/media/cec/platform/seco/seco-cec.c +++ b/drivers/media/cec/platform/seco/seco-cec.c @@ -7,14 +7,15 @@ * Copyright (C) 2018, Aidilab Srl. */ -#include <linux/module.h> #include <linux/acpi.h> #include <linux/delay.h> #include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/time.h> /* CEC Framework */ #include <media/cec-notifier.h> @@ -356,7 +357,7 @@ static int secocec_ir_probe(void *priv) cec->ir->allowed_protocols = RC_PROTO_BIT_RC5; cec->ir->priv = cec; cec->ir->map_name = RC_MAP_HAUPPAUGE; - cec->ir->timeout = MS_TO_US(100); + cec->ir->timeout = 100 * USEC_PER_MSEC; /* Clear the status register */ status = smb_rd16(SECOCEC_STATUS_REG_1, &val); @@ -618,7 +619,6 @@ static int secocec_probe(struct platform_device *pdev) dev_name(&pdev->dev), secocec); if (ret) { - dev_err(dev, "Cannot request IRQ %d\n", secocec->irq); ret = -EIO; goto err; } diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index 1ec0cece0a5b..29418966a98e 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -132,7 +132,8 @@ static void stm32_rx_done(struct stm32_cec *cec, u32 status) u32 val; regmap_read(cec->regmap, CEC_RXDR, &val); - cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF; + if (cec->rx_msg.len < CEC_MAX_MSG_SIZE) + cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF; } if (cec->irq_status & RXEND) { @@ -193,18 +194,24 @@ static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable) static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) { struct stm32_cec *cec = adap->priv; - u32 oar = (1 << logical_addr) << 16; u32 val; + int ret; /* Poll every 100µs the register CEC_CR to wait end of transmission */ - regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), - 100, CEC_XFER_TIMEOUT_MS * 1000); + ret = regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), + 100, CEC_XFER_TIMEOUT_MS * 1000); + if (ret) + return ret; + regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); - if (logical_addr == CEC_LOG_ADDR_INVALID) + if (logical_addr == CEC_LOG_ADDR_INVALID) { regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0); - else + } else { + u32 oar = BIT(logical_addr) << 16; + regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar); + } regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN); diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 3ed50097262f..d64e1662249e 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -24,6 +24,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/clk/tegra.h> #include <media/cec-notifier.h> @@ -47,6 +48,7 @@ struct tegra_cec { u32 tx_buf[CEC_MAX_MSG_SIZE]; u8 tx_buf_cur; u8 tx_buf_cnt; + u32 rx_total_low_drives; }; static inline u32 cec_read(struct tegra_cec *cec, u32 reg) @@ -116,6 +118,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data) return IRQ_WAKE_THREAD; } + if (status & TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED) { + dev_warn_ratelimited(dev, "RX bus error detected, generated low drive\n"); + cec->rx_total_low_drives++; + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED); + } + if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) || (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) { tegra_cec_error_recovery(cec); @@ -241,9 +250,21 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | + TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); - cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); + /* + * TX_NAK_MODE ensures that the whole message is transmitted even + * if each byte is NACKed. Without this flag the retransmit of the + * messages after a NACK can be corrupt. This is a bug in the hardware. + * + * While less efficient, in practice you rarely transmit messages + * that can be NACKed, with the exception of POLL messages which + * are just one byte anyway. + */ + cec_write(cec, TEGRA_CEC_HW_CONTROL, + TEGRA_CEC_HWCTRL_TX_RX_MODE | + TEGRA_CEC_HWCTRL_TX_NAK_MODE); return 0; } @@ -307,11 +328,20 @@ static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, return 0; } +static void tegra_cec_adap_status(struct cec_adapter *adap, struct seq_file *file) +{ + struct tegra_cec *cec = adap->priv; + + seq_printf(file, "receive low drive count: %u\n", + cec->rx_total_low_drives); +} + static const struct cec_adap_ops tegra_cec_ops = { .adap_enable = tegra_cec_adap_enable, .adap_log_addr = tegra_cec_adap_log_addr, .adap_transmit = tegra_cec_adap_transmit, .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, + .adap_status = tegra_cec_adap_status, }; static int tegra_cec_probe(struct platform_device *pdev) @@ -381,11 +411,8 @@ static int tegra_cec_probe(struct platform_device *pdev) tegra_cec_irq_handler, tegra_cec_irq_thread_handler, 0, "cec_irq", &pdev->dev); - if (ret) { - dev_err(&pdev->dev, - "Unable to request interrupt for device\n"); + if (ret) goto err_clk; - } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | @@ -458,6 +485,7 @@ static const struct of_device_id tegra_cec_of_match[] = { { .compatible = "nvidia,tegra210-cec", }, {}, }; +MODULE_DEVICE_TABLE(of, tegra_cec_of_match); static struct platform_driver tegra_cec_driver = { .driver = { diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c index 3381d86096a1..3c6ce6f3d93e 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c @@ -657,7 +657,8 @@ static void extron_process_received(struct extron_port *port, const char *data) if (!port || port->disconnected) return; - if (len < 5 || (len - 2) % 3 || data[len - 2] != '*') + if (len < 5 || ((len - 2) / 3 > sizeof(msg.msg)) || + (len - 2) % 3 || data[len - 2] != '*') goto malformed; while (*data != '*') { diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 931e5dc453b9..e1d5c220f738 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -2346,9 +2346,11 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg, (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); } -static void tpg_fill_plane_extras(const struct tpg_data *tpg, - const struct tpg_draw_params *params, - unsigned p, unsigned h, u8 *vbuf) +/* noinline to work around clang KASAN issues */ +static noinline_for_stack void +tpg_fill_plane_extras(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) { unsigned twopixsize = params->twopixsize; unsigned img_width = params->img_width; @@ -2483,9 +2485,9 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg, } } -static void tpg_fill_plane_pattern(const struct tpg_data *tpg, - const struct tpg_draw_params *params, - unsigned p, unsigned h, u8 *vbuf) +static noinline_for_stack void +tpg_fill_plane_pattern(const struct tpg_data *tpg, const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) { unsigned twopixsize = params->twopixsize; unsigned img_width = params->img_width; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 4baded4fd3b8..5a1ee5eb9c0f 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -635,19 +635,6 @@ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) } EXPORT_SYMBOL_GPL(vb2_find_buffer); -/* - * vb2_querybuf() - query video buffer information - * @q: vb2 queue - * @b: buffer struct passed from userspace to vidioc_querybuf handler - * in driver - * - * Should be called from vidioc_querybuf ioctl handler in driver. - * This function will verify the passed v4l2_buffer structure and fill the - * relevant information for the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_querybuf handler in driver. - */ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 3c8bc75e4d6c..6a825d9bae43 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -884,6 +884,7 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { struct dmxdev_feed *feed; + int ret; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) @@ -901,8 +902,14 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, feed->pid = pid; list_add(&feed->next, &filter->feed.ts); - if (filter->state >= DMXDEV_STATE_GO) - return dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (filter->state >= DMXDEV_STATE_GO) { + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (ret < 0) { + list_del(&feed->next); + kfree(feed); + return ret; + } + } return 0; } diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index d082b6c57c76..0286da57f382 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -30,6 +30,7 @@ #include <linux/kthread.h> #include <linux/ktime.h> #include <linux/compat.h> +#include <linux/lockdep.h> #include <asm/processor.h> #include <media/dvb_frontend.h> @@ -2760,77 +2761,25 @@ static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *w return 0; } -static int dvb_frontend_open(struct inode *inode, struct file *file) +static int __dvb_frontend_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_adapter *adapter = fe->dvb; int ret; - dev_dbg(fe->dvb->device, "%s:\n", __func__); - if (fe->exit == DVB_FE_DEVICE_REMOVED) - return -ENODEV; - - if (adapter->mfe_shared == 2) { - mutex_lock(&adapter->mfe_lock); - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - if (adapter->mfe_dvbdev && - !adapter->mfe_dvbdev->writers) { - mutex_unlock(&adapter->mfe_lock); - return -EBUSY; - } - adapter->mfe_dvbdev = dvbdev; - } - } else if (adapter->mfe_shared) { - mutex_lock(&adapter->mfe_lock); - - if (!adapter->mfe_dvbdev) - adapter->mfe_dvbdev = dvbdev; - - else if (adapter->mfe_dvbdev != dvbdev) { - struct dvb_device - *mfedev = adapter->mfe_dvbdev; - struct dvb_frontend - *mfe = mfedev->priv; - struct dvb_frontend_private - *mfepriv = mfe->frontend_priv; - int mferetry = (dvb_mfe_wait_time << 1); - - mutex_unlock(&adapter->mfe_lock); - while (mferetry-- && (mfedev->users != -1 || - mfepriv->thread)) { - if (msleep_interruptible(500)) { - if (signal_pending(current)) - return -EINTR; - } - } - - mutex_lock(&adapter->mfe_lock); - if (adapter->mfe_dvbdev != dvbdev) { - mfedev = adapter->mfe_dvbdev; - mfe = mfedev->priv; - mfepriv = mfe->frontend_priv; - if (mfedev->users != -1 || - mfepriv->thread) { - mutex_unlock(&adapter->mfe_lock); - return -EBUSY; - } - adapter->mfe_dvbdev = dvbdev; - } - } - } - if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) - goto err0; + return ret; - /* If we took control of the bus, we need to force - reinitialization. This is because many ts_bus_ctrl() - functions strobe the RESET pin on the demod, and if the - frontend thread already exists then the dvb_init() routine - won't get called (which is what usually does initial - register configuration). */ + /* + * If we took control of the bus, we need to force + * reinitialization. This is because many ts_bus_ctrl() + * functions strobe the RESET pin on the demod, and if the + * frontend thread already exists then the dvb_init() routine + * won't get called (which is what usually does initial + * register configuration). + */ fepriv->reinitialise = 1; } @@ -2871,8 +2820,6 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dvb_frontend_get(fe); - if (adapter->mfe_shared) - mutex_unlock(&adapter->mfe_lock); return ret; err3: @@ -2891,12 +2838,88 @@ err2: err1: if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) fe->ops.ts_bus_ctrl(fe, 0); -err0: - if (adapter->mfe_shared) - mutex_unlock(&adapter->mfe_lock); + + return ret; +} + +static int wait_dvb_frontend(struct dvb_adapter *adapter, + struct dvb_device *mfedev) +{ + struct dvb_frontend *mfe = mfedev->priv; + struct dvb_frontend_private *mfepriv = mfe->frontend_priv; + int mferetry = (dvb_mfe_wait_time << 1); + int ret = 0; + + lockdep_assert_held(&adapter->mfe_lock); + + if (mfedev->users == -1 && !mfepriv->thread) + return 0; + + mutex_unlock(&adapter->mfe_lock); + + while (mferetry-- && (mfedev->users != -1 || mfepriv->thread)) { + if (msleep_interruptible(500)) + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + + mutex_lock(&adapter->mfe_lock); + return ret; } +static int dvb_frontend_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_adapter *adapter = fe->dvb; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); + if (fe->exit == DVB_FE_DEVICE_REMOVED) + return -ENODEV; + + if (!adapter->mfe_shared) + return __dvb_frontend_open(inode, file); + + guard(mutex)(&adapter->mfe_lock); + + if (adapter->mfe_shared == 2) { + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (adapter->mfe_dvbdev && + !adapter->mfe_dvbdev->writers) + return -EBUSY; + adapter->mfe_dvbdev = dvbdev; + } + return __dvb_frontend_open(inode, file); + } + + if (!adapter->mfe_dvbdev) { + adapter->mfe_dvbdev = dvbdev; + } else if (adapter->mfe_dvbdev != dvbdev) { + struct dvb_device *mfedev = adapter->mfe_dvbdev; + struct dvb_frontend *mfe = mfedev->priv; + struct dvb_frontend_private *mfepriv = mfe->frontend_priv; + int ret; + + ret = wait_dvb_frontend(adapter, mfedev); + if (ret) + return ret; + + if (adapter->mfe_dvbdev != dvbdev) { + mfedev = adapter->mfe_dvbdev; + mfe = mfedev->priv; + mfepriv = mfe->frontend_priv; + if (mfedev->users != -1 || mfepriv->thread) + return -EBUSY; + adapter->mfe_dvbdev = dvbdev; + } + } + + return __dvb_frontend_open(inode, file); +} + static int dvb_frontend_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c index 993280fefc2c..5fbb466cc8af 100644 --- a/drivers/media/dvb-frontends/helene.c +++ b/drivers/media/dvb-frontends/helene.c @@ -995,22 +995,22 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, const struct helene_config *config, struct i2c_adapter *i2c) { - struct helene_priv *priv = NULL; + struct helene_priv *pr = NULL; - priv = kzalloc_obj(struct helene_priv); - if (priv == NULL) + pr = kzalloc_obj(struct helene_priv); + if (!pr) return NULL; - priv->i2c_address = (config->i2c_address >> 1); - priv->i2c = i2c; - priv->set_tuner_data = config->set_tuner_priv; - priv->set_tuner = config->set_tuner_callback; - priv->xtal = config->xtal; + pr->i2c_address = (config->i2c_address >> 1); + pr->i2c = i2c; + pr->set_tuner_data = config->set_tuner_priv; + pr->set_tuner = config->set_tuner_callback; + pr->xtal = config->xtal; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (helene_x_pon(priv) != 0) { - kfree(priv); + if (helene_x_pon(pr) != 0) { + kfree(pr); return NULL; } @@ -1019,10 +1019,10 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_s, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - dev_info(&priv->i2c->dev, - "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", - priv->i2c_address, priv->i2c); + fe->tuner_priv = pr; + dev_info(&pr->i2c->dev, + "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", + pr->i2c_address, pr->i2c); return fe; } EXPORT_SYMBOL_GPL(helene_attach_s); @@ -1031,22 +1031,22 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, const struct helene_config *config, struct i2c_adapter *i2c) { - struct helene_priv *priv = NULL; + struct helene_priv *pr = NULL; - priv = kzalloc_obj(struct helene_priv); - if (priv == NULL) + pr = kzalloc_obj(struct helene_priv); + if (!pr) return NULL; - priv->i2c_address = (config->i2c_address >> 1); - priv->i2c = i2c; - priv->set_tuner_data = config->set_tuner_priv; - priv->set_tuner = config->set_tuner_callback; - priv->xtal = config->xtal; + pr->i2c_address = (config->i2c_address >> 1); + pr->i2c = i2c; + pr->set_tuner_data = config->set_tuner_priv; + pr->set_tuner = config->set_tuner_callback; + pr->xtal = config->xtal; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (helene_x_pon(priv) != 0) { - kfree(priv); + if (helene_x_pon(pr) != 0) { + kfree(pr); return NULL; } @@ -1055,10 +1055,10 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_t, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - dev_info(&priv->i2c->dev, - "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", - priv->i2c_address, priv->i2c); + fe->tuner_priv = pr; + dev_info(&pr->i2c->dev, + "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", + pr->i2c_address, pr->i2c); return fe; } EXPORT_SYMBOL_GPL(helene_attach); diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index c564485e3bbb..0330e7f0881a 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -906,9 +906,12 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) goto err; mutex_unlock(&dev->v4l2_lock); + return 0; err: + rtl2832_sdr_free_urbs(dev); + rtl2832_sdr_free_stream_bufs(dev); rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); mutex_unlock(&dev->v4l2_lock); @@ -1477,14 +1480,22 @@ static void rtl2832_sdr_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "\n"); - mutex_lock(&dev->vb_queue_lock); + /* + * vb2_video_unregister_device() releases the vb2 queue, which + * triggers rtl2832_sdr_stop_streaming() if streaming is active. + * stop_streaming() uses dev->udev to free URBs and coherent DMA + * stream buffers via usb_free_coherent(), so it must run before + * dev->udev is cleared. vb2_video_unregister_device() locks + * vb_queue_lock internally and stop_streaming() locks v4l2_lock, + * so neither may be held by the caller. + */ + v4l2_device_disconnect(&dev->v4l2_dev); + vb2_video_unregister_device(&dev->vdev); + mutex_lock(&dev->v4l2_lock); - /* No need to keep the urbs around after disconnection */ dev->udev = NULL; - v4l2_device_disconnect(&dev->v4l2_dev); - video_unregister_device(&dev->vdev); mutex_unlock(&dev->v4l2_lock); - mutex_unlock(&dev->vb_queue_lock); + v4l2_device_put(&dev->v4l2_dev); module_put(pdev->dev.parent->driver->owner); } diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 5d173e0ecf42..5c52007f9cbe 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -259,6 +259,7 @@ config VIDEO_IMX335 config VIDEO_IMX355 tristate "Sony IMX355 sensor support" + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX355 camera. @@ -269,6 +270,7 @@ config VIDEO_IMX355 config VIDEO_IMX412 tristate "Sony IMX412 sensor support" depends on OF + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX412 camera. @@ -287,6 +289,27 @@ config VIDEO_IMX415 To compile this driver as a module, choose M here: the module will be called imx415. +config VIDEO_IMX471 + tristate "Sony IMX471 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the Sony + IMX471 camera. + + To compile this driver as a module, choose M here: the + module will be called imx471. + +config VIDEO_IMX678 + tristate "Sony IMX678 sensor support" + depends on GPIOLIB + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the Sony + IMX678 camera. + + To compile this driver as a module, choose M here: the + module will be called imx678. + config VIDEO_MAX9271_LIB tristate diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index e45359efe0e4..d04bd5724552 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -61,6 +61,8 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_IMX415) += imx415.o +obj-$(CONFIG_VIDEO_IMX678) += imx678.o +obj-$(CONFIG_VIDEO_IMX471) += imx471.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index dd991c2ee700..f51f9b987759 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1290,7 +1290,7 @@ static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on) struct device *dev = &alvium->i2c_client->dev; int ret; - ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW, + ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_AUTO_RW, on ? 0x02 : 0x00); if (ret) { dev_err(dev, "Fail to set autoexposure reg\n"); diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c index fe9e59ac311c..d4a3b9c3bab1 100644 --- a/drivers/media/i2c/cvs/core.c +++ b/drivers/media/i2c/cvs/core.c @@ -31,6 +31,7 @@ #define PCI_DEVICE_ID_INTEL_IPU7 0x645d /* MTL / LNL */ #define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d /* ARL / PTL */ +#define PCI_DEVICE_ID_INTEL_IPU8 0xd719 /* NVL */ /* * IPU7 PCI device IDs not covered by ipu6_pci_tbl in ipu6-pci-table.h. @@ -39,6 +40,7 @@ static const struct pci_device_id icvs_ipu7_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU8) }, { } }; @@ -962,6 +964,7 @@ static const struct acpi_device_id intel_cvs_acpi_match[] = { { "INTC10DE" }, /* LNL */ { "INTC10E0" }, /* ARL */ { "INTC10E1" }, /* PTL */ + { "INTC10FA" }, /* NVL */ { } }; MODULE_DEVICE_TABLE(acpi, intel_cvs_acpi_match); diff --git a/drivers/media/i2c/cvs/icvs.h b/drivers/media/i2c/cvs/icvs.h index cfa8ef5d975c..17beb0920dd2 100644 --- a/drivers/media/i2c/cvs/icvs.h +++ b/drivers/media/i2c/cvs/icvs.h @@ -432,7 +432,6 @@ enum icvs_state { * @freq_ctrl: (future) frequency control pointer * @pads: Local media pads (sink/source) * @nr_of_lanes: Active CSI-2 lane count - * @link_freq: Current link frequency (Hz) * @ipu_link: PM runtime device link (IPU consumer, CVS supplier) * @res: Resource capability (light/full) * @caps: Reported device protocol capabilities @@ -458,7 +457,6 @@ struct icvs { struct v4l2_ctrl *freq_ctrl; struct media_pad pads[ICVS_CSI_NUM_PADS]; u32 nr_of_lanes; - u64 link_freq; struct device_link *ipu_link; enum icvs_resources res; struct icvs_dev_capabilities caps; diff --git a/drivers/media/i2c/cvs/v4l2.c b/drivers/media/i2c/cvs/v4l2.c index 3a1ec0059ef7..9fadca7a3bee 100644 --- a/drivers/media/i2c/cvs/v4l2.c +++ b/drivers/media/i2c/cvs/v4l2.c @@ -46,6 +46,7 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { /** * csi_set_link_cfg - Program default CSI-2 link parameters * @ctx: CVS device context + * @link_freq: Link frequency (Hz) * * Populates a HOST_SET_MIPI_CONFIG command using current lane count and * link frequency, then submits it to the device. @@ -53,12 +54,12 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { * * Return: 0 on success or negative errno. */ -static int csi_set_link_cfg(struct icvs *ctx) +static int csi_set_link_cfg(struct icvs *ctx, u64 link_freq) { struct icvs_cmd cmd = { .cmd_id = cpu_to_be16(ICVS_HOST_SET_MIPI_CONFIG), .param.conf.nr_of_lanes = ctx->nr_of_lanes, - .param.conf.link_freq = ctx->link_freq, + .param.conf.link_freq = link_freq, }; size_t cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf); @@ -91,7 +92,7 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev *remote_sd = media_entity_to_v4l2_subdev(ctx->remote->entity); struct device *dev = cvs_dev(ctx); - s64 freq; + s64 link_freq; int ret; /* cvs_set_link_owner(ICVS_CSI_LINK_HOST) */ @@ -99,15 +100,14 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, if (ret < 0) return ret; - freq = v4l2_get_link_freq(ctx->remote, 0, 0); - if (freq < 0) { - ret = freq; + link_freq = v4l2_get_link_freq(ctx->remote, 0, 0); + if (link_freq < 0) { + ret = link_freq; goto err_rpm_put; } - ctx->link_freq = freq; if (ctx->i2c_client) { - ret = csi_set_link_cfg(ctx); + ret = csi_set_link_cfg(ctx, link_freq); if (ret < 0) goto err_rpm_put_sync; } @@ -345,7 +345,6 @@ static int cvs_csi_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, if (freq < 0) return -EINVAL; - ctx->link_freq = freq; cfg->link_freq = freq; return 0; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 8110d40931d9..8b7dd43ed208 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -3962,6 +3962,7 @@ static int cx25840_probe(struct i2c_client *client) int err = state->hdl.error; v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&sd->entity); return err; } if (!is_cx2583x(state)) @@ -3986,6 +3987,7 @@ static void cx25840_remove(struct i2c_client *client) cx25840_ir_remove(sd); v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&sd->entity); } static const struct i2c_device_id cx25840_id[] = { diff --git a/drivers/media/i2c/gc0310.c b/drivers/media/i2c/gc0310.c index 7af4d66f42a0..754e82ad50ae 100644 --- a/drivers/media/i2c/gc0310.c +++ b/drivers/media/i2c/gc0310.c @@ -6,6 +6,7 @@ * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/gpio/consumer.h> @@ -84,6 +85,8 @@ #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) struct gc0310_device { + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -635,7 +638,6 @@ static int gc0310_check_hwcfg(struct device *dev) }; struct fwnode_handle *ep_fwnode; unsigned long link_freq_bitmap; - u32 mclk; int ret; /* @@ -647,21 +649,6 @@ static int gc0310_check_hwcfg(struct device *dev) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &mclk); - if (ret) { - fwnode_handle_put(ep_fwnode); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - - if (mclk != GC0310_MCLK_FREQ) { - fwnode_handle_put(ep_fwnode); - return dev_err_probe(dev, -EINVAL, - "external clock %u is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); fwnode_handle_put(ep_fwnode); if (ret) @@ -685,6 +672,7 @@ static int gc0310_check_hwcfg(struct device *dev) static int gc0310_probe(struct i2c_client *client) { struct gc0310_device *sensor; + unsigned long freq; int ret; ret = gc0310_check_hwcfg(&client->dev); @@ -695,6 +683,16 @@ static int gc0310_probe(struct i2c_client *client) if (!sensor) return -ENOMEM; + sensor->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(sensor->clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + freq = clk_get_rate(sensor->clk); + if (freq != GC0310_MCLK_FREQ) + return dev_err_probe(&client->dev, -EINVAL, + "external clock %lu is not supported\n", freq); + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(sensor->reset)) { return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 223d3753cc93..9571f3622d2d 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -110,11 +110,16 @@ /* Test Pattern Control */ #define IMX219_REG_TEST_PATTERN CCI_REG16(0x0600) -#define IMX219_TEST_PATTERN_DISABLE 0 -#define IMX219_TEST_PATTERN_SOLID_COLOR 1 -#define IMX219_TEST_PATTERN_COLOR_BARS 2 -#define IMX219_TEST_PATTERN_GREY_COLOR 3 -#define IMX219_TEST_PATTERN_PN9 4 +#define IMX219_TEST_PATTERN_DISABLE 0 +#define IMX219_TEST_PATTERN_SOLID_COLOR 1 +#define IMX219_TEST_PATTERN_COLOR_BARS 2 +#define IMX219_TEST_PATTERN_GREY_COLOR 3 +#define IMX219_TEST_PATTERN_PN9 4 +#define IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS 5 +#define IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS 6 +#define IMX219_TEST_PATTERN_COLUMN_COUNTER 7 +#define IMX219_TEST_PATTERN_INV_COLUMN_COUNTER 8 +#define IMX219_TEST_PATTERN_PN31 9 /* Test pattern colour components */ #define IMX219_REG_TESTP_RED CCI_REG16(0x0602) @@ -238,7 +243,12 @@ static const char * const imx219_test_pattern_menu[] = { "Color Bars", "Solid Color", "Grey Color Bars", - "PN9" + "PN9", + "16 Split Color Bars", + "16 Split Inverted Color Bars", + "Column Counter", + "Inverted Column Counter", + "PN31" }; static const int imx219_test_pattern_val[] = { @@ -247,6 +257,11 @@ static const int imx219_test_pattern_val[] = { IMX219_TEST_PATTERN_SOLID_COLOR, IMX219_TEST_PATTERN_GREY_COLOR, IMX219_TEST_PATTERN_PN9, + IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS, + IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS, + IMX219_TEST_PATTERN_COLUMN_COUNTER, + IMX219_TEST_PATTERN_INV_COLUMN_COUNTER, + IMX219_TEST_PATTERN_PN31 }; /* regulator supplies */ diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 27a5c212a527..8eb8588cb71b 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -9,74 +9,97 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/unaligned.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> -#define IMX355_REG_MODE_SELECT 0x0100 +#define IMX355_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX355_MODE_STANDBY 0x00 #define IMX355_MODE_STREAMING 0x01 /* Chip ID */ -#define IMX355_REG_CHIP_ID 0x0016 +#define IMX355_REG_CHIP_ID CCI_REG16(0x0016) #define IMX355_CHIP_ID 0x0355 +#define IMX355_REG_LANE_SEL CCI_REG8(0x0114) + +/* PLL registers that depend on the external clock frequency */ +#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136) +#define IMX355_REG_PLL_OP_PREDIV CCI_REG8(0x030d) +#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e) +#define IMX355_REG_PLL_IVT_PCK_DIV CCI_REG8(0x0301) +#define IMX355_REG_PLL_IVT_SYSCK_DIV CCI_REG8(0x0303) +#define IMX355_PLL_OP_PREDIV 2 +#define IMX355_PLL_IVT_PCK_DIV 5 + /* V_TIMING internal */ -#define IMX355_REG_FLL 0x0340 +#define IMX355_REG_FLL CCI_REG16(0x0340) #define IMX355_FLL_MAX 0xffff +#define IMX355_VBLANK_MIN 20 + +#define IMX355_REG_LLP CCI_REG16(0x0342) +#define IMX355_LLP_MAX 0xffff + +#define IMX355_REG_X_ADD_START CCI_REG16(0x0344) +#define IMX355_REG_Y_ADD_START CCI_REG16(0x0346) +#define IMX355_REG_X_ADD_END CCI_REG16(0x0348) +#define IMX355_REG_Y_ADD_END CCI_REG16(0x034a) +#define IMX355_REG_X_OUT_SIZE CCI_REG16(0x034c) +#define IMX355_REG_Y_OUT_SIZE CCI_REG16(0x034e) /* Exposure control */ -#define IMX355_REG_EXPOSURE 0x0202 +#define IMX355_REG_EXPOSURE CCI_REG16(0x0202) #define IMX355_EXPOSURE_MIN 1 #define IMX355_EXPOSURE_STEP 1 #define IMX355_EXPOSURE_DEFAULT 0x0282 +#define IMX355_EXPOSURE_OFFSET 10 /* Analog gain control */ -#define IMX355_REG_ANALOG_GAIN 0x0204 +#define IMX355_REG_ANALOG_GAIN CCI_REG16(0x0204) #define IMX355_ANA_GAIN_MIN 0 #define IMX355_ANA_GAIN_MAX 960 #define IMX355_ANA_GAIN_STEP 1 #define IMX355_ANA_GAIN_DEFAULT 0 /* Digital gain control */ -#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070 -#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e +#define IMX355_REG_DPGA_USE_GLOBAL_GAIN CCI_REG8(0x3070) +#define IMX355_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) #define IMX355_DGTL_GAIN_MIN 256 #define IMX355_DGTL_GAIN_MAX 4095 #define IMX355_DGTL_GAIN_STEP 1 #define IMX355_DGTL_GAIN_DEFAULT 256 /* Test Pattern Control */ -#define IMX355_REG_TEST_PATTERN 0x0600 +#define IMX355_REG_TEST_PATTERN CCI_REG16(0x0600) #define IMX355_TEST_PATTERN_DISABLED 0 #define IMX355_TEST_PATTERN_SOLID_COLOR 1 #define IMX355_TEST_PATTERN_COLOR_BARS 2 #define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3 #define IMX355_TEST_PATTERN_PN9 4 -/* Flip Control */ -#define IMX355_REG_ORIENTATION 0x0101 +#define IMX355_REG_REQ_LINK_BIT_RATE CCI_REG16(0x0820) -/* default link frequency and external clock */ -#define IMX355_LINK_FREQ_DEFAULT 360000000LL -#define IMX355_EXT_CLK 19200000 -#define IMX355_LINK_FREQ_INDEX 0 +#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900) +#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901) +#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902) -/* number of data lanes */ -#define IMX355_DATA_LANES 4 +/* Flip Control */ +#define IMX355_REG_ORIENTATION CCI_REG8(0x0101) -struct imx355_reg { - u16 address; - u8 val; -}; +#define IMX355_PIXEL_ARRAY_TOP 0 +#define IMX355_PIXEL_ARRAY_LEFT 0 +#define IMX355_PIXEL_ARRAY_WIDTH 3280 +#define IMX355_PIXEL_ARRAY_HEIGHT 2464 struct imx355_reg_list { u32 num_of_regs; - const struct imx355_reg *regs; + const struct cci_reg_sequence *regs; }; /* Mode : resolution and related config&values */ @@ -85,28 +108,58 @@ struct imx355_mode { u32 width; /* Frame height */ u32 height; + struct v4l2_rect crop; /* V-timing */ u32 fll_def; - u32 fll_min; /* H-timing */ u32 llp; - /* index of link frequency */ - u32 link_freq_index; - /* Default register values */ struct imx355_reg_list reg_list; }; +struct imx355_clk_params { + u32 ext_clk; + u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */ + u16 pll_op_mpy[2]; /* OP system PLL multiplier */ + u8 pll_op_prediv[2]; /* OP system pre PLL d */ +}; + +/* + * The clock tree is in single PLL mode, so PREDIV_VT and MPY_IVT do nothing. + * In 4 lane mode the MIPI rate is 360Mhz (720Mbit/s) and pixel rate is + * 288MPix/s. + * In 2 lane mode the MIPI rate is 444MHz (888Mbit/s) and pixel rate + * 177.6MPix/s with a 24MHz clock, and 441.6MHz (883.2Mbit/s) and 176.6MPix/s + * with a 19.2MHz clock. + */ +static const struct imx355_clk_params imx355_clk_params[] = { + { + .ext_clk = 19200000, + .extclk_freq = 0x1333, + .pll_op_mpy = { 75, 92 }, + .pll_op_prediv = { 2, 2 } + }, + { + .ext_clk = 24000000, + .extclk_freq = 0x1800, + .pll_op_mpy = { 60, 111 }, + .pll_op_prediv = { 2, 3 } + }, +}; + struct imx355_hwcfg { + s64 link_freq_menu; unsigned long link_freq_bitmap; + unsigned int num_lanes; }; struct imx355 { struct device *dev; struct clk *clk; + struct regmap *regmap; struct v4l2_subdev sd; struct media_pad pad; @@ -114,24 +167,14 @@ struct imx355 { struct v4l2_ctrl_handler ctrl_handler; /* V4L2 Controls */ struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *vblank; struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; struct v4l2_ctrl *vflip; struct v4l2_ctrl *hflip; - /* Current mode */ - const struct imx355_mode *cur_mode; - struct imx355_hwcfg *hwcfg; - - /* - * Mutex for serialized access: - * Protect sensor set pad format and start/stop streaming safely. - * Protect access to sensor v4l2 controls. - */ - struct mutex mutex; + const struct imx355_clk_params *clk_params; struct gpio_desc *reset_gpio; struct regulator_bulk_data *supplies; @@ -143,750 +186,147 @@ static const struct regulator_bulk_data imx355_supplies[] = { { .supply = "dovdd" }, }; -static const struct imx355_reg imx355_global_regs[] = { - { 0x0136, 0x13 }, - { 0x0137, 0x33 }, - { 0x304e, 0x03 }, - { 0x4348, 0x16 }, - { 0x4350, 0x19 }, - { 0x4408, 0x0a }, - { 0x440c, 0x0b }, - { 0x4411, 0x5f }, - { 0x4412, 0x2c }, - { 0x4623, 0x00 }, - { 0x462c, 0x0f }, - { 0x462d, 0x00 }, - { 0x462e, 0x00 }, - { 0x4684, 0x54 }, - { 0x480a, 0x07 }, - { 0x4908, 0x07 }, - { 0x4909, 0x07 }, - { 0x490d, 0x0a }, - { 0x491e, 0x0f }, - { 0x4921, 0x06 }, - { 0x4923, 0x28 }, - { 0x4924, 0x28 }, - { 0x4925, 0x29 }, - { 0x4926, 0x29 }, - { 0x4927, 0x1f }, - { 0x4928, 0x20 }, - { 0x4929, 0x20 }, - { 0x492a, 0x20 }, - { 0x492c, 0x05 }, - { 0x492d, 0x06 }, - { 0x492e, 0x06 }, - { 0x492f, 0x06 }, - { 0x4930, 0x03 }, - { 0x4931, 0x04 }, - { 0x4932, 0x04 }, - { 0x4933, 0x05 }, - { 0x595e, 0x01 }, - { 0x5963, 0x01 }, - { 0x3030, 0x01 }, - { 0x3031, 0x01 }, - { 0x3045, 0x01 }, - { 0x4010, 0x00 }, - { 0x4011, 0x00 }, - { 0x4012, 0x00 }, - { 0x4013, 0x01 }, - { 0x68a8, 0xfe }, - { 0x68a9, 0xff }, - { 0x6888, 0x00 }, - { 0x6889, 0x00 }, - { 0x68b0, 0x00 }, - { 0x3058, 0x00 }, - { 0x305a, 0x00 }, -}; - -static const struct imx355_reg_list imx355_global_setting = { - .num_of_regs = ARRAY_SIZE(imx355_global_regs), - .regs = imx355_global_regs, +static const struct cci_reg_sequence imx355_global_regs[] = { + { CCI_REG8(0x304e), 0x03 }, + { CCI_REG8(0x4348), 0x16 }, + { CCI_REG8(0x4350), 0x19 }, + { CCI_REG8(0x4408), 0x0a }, + { CCI_REG8(0x440c), 0x0b }, + { CCI_REG8(0x4411), 0x5f }, + { CCI_REG8(0x4412), 0x2c }, + { CCI_REG8(0x4623), 0x00 }, + { CCI_REG8(0x462c), 0x0f }, + { CCI_REG8(0x462d), 0x00 }, + { CCI_REG8(0x462e), 0x00 }, + { CCI_REG8(0x4684), 0x54 }, + { CCI_REG8(0x480a), 0x07 }, + { CCI_REG8(0x4908), 0x07 }, + { CCI_REG8(0x4909), 0x07 }, + { CCI_REG8(0x490d), 0x0a }, + { CCI_REG8(0x491e), 0x0f }, + { CCI_REG8(0x4921), 0x06 }, + { CCI_REG8(0x4923), 0x28 }, + { CCI_REG8(0x4924), 0x28 }, + { CCI_REG8(0x4925), 0x29 }, + { CCI_REG8(0x4926), 0x29 }, + { CCI_REG8(0x4927), 0x1f }, + { CCI_REG8(0x4928), 0x20 }, + { CCI_REG8(0x4929), 0x20 }, + { CCI_REG8(0x492a), 0x20 }, + { CCI_REG8(0x492c), 0x05 }, + { CCI_REG8(0x492d), 0x06 }, + { CCI_REG8(0x492e), 0x06 }, + { CCI_REG8(0x492f), 0x06 }, + { CCI_REG8(0x4930), 0x03 }, + { CCI_REG8(0x4931), 0x04 }, + { CCI_REG8(0x4932), 0x04 }, + { CCI_REG8(0x4933), 0x05 }, + { CCI_REG8(0x595e), 0x01 }, + { CCI_REG8(0x5963), 0x01 }, + { CCI_REG8(0x3030), 0x01 }, + { CCI_REG8(0x3031), 0x01 }, + { CCI_REG8(0x3045), 0x01 }, + { CCI_REG8(0x4010), 0x00 }, + { CCI_REG8(0x4011), 0x00 }, + { CCI_REG8(0x4012), 0x00 }, + { CCI_REG8(0x4013), 0x01 }, + { CCI_REG8(0x68a8), 0xfe }, + { CCI_REG8(0x68a9), 0xff }, + { CCI_REG8(0x6888), 0x00 }, + { CCI_REG8(0x6889), 0x00 }, + { CCI_REG8(0x68b0), 0x00 }, + { CCI_REG8(0x3058), 0x00 }, + { CCI_REG8(0x305a), 0x00 }, + { CCI_REG8(0x0112), 0x0a }, + { CCI_REG8(0x0113), 0x0a }, + { IMX355_REG_PLL_IVT_PCK_DIV, IMX355_PLL_IVT_PCK_DIV }, + { CCI_REG8(0x0303), 0x01 }, + { CCI_REG8(0x0305), 0x02 }, + { CCI_REG8(0x0306), 0x00 }, + { CCI_REG8(0x0307), 0x78 }, + { CCI_REG8(0x030b), 0x01 }, + { IMX355_REG_PLL_OP_PREDIV, IMX355_PLL_OP_PREDIV }, + { CCI_REG8(0x0310), 0x00 }, + { CCI_REG8(0x0220), 0x00 }, + { CCI_REG8(0x0222), 0x01 }, + { CCI_REG8(0x3088), 0x04 }, + { CCI_REG8(0x6813), 0x02 }, + { CCI_REG8(0x6835), 0x07 }, + { CCI_REG8(0x6836), 0x01 }, + { CCI_REG8(0x6837), 0x04 }, + { CCI_REG8(0x684d), 0x07 }, + { CCI_REG8(0x684e), 0x01 }, + { CCI_REG8(0x684f), 0x04 }, }; -static const struct imx355_reg mode_3268x2448_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x08 }, - { 0x0346, 0x00 }, - { 0x0347, 0x08 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcb }, - { 0x034a, 0x09 }, - { 0x034b, 0x97 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xc4 }, - { 0x034e, 0x09 }, - { 0x034f, 0x90 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3268x2448_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_3264x2448_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x08 }, - { 0x0346, 0x00 }, - { 0x0347, 0x08 }, - { 0x0348, 0x0c }, - { 0x0349, 0xc7 }, - { 0x034a, 0x09 }, - { 0x034b, 0x97 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xc0 }, - { 0x034e, 0x09 }, - { 0x034f, 0x90 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3264x2448_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_3280x2464_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xd0 }, - { 0x034e, 0x09 }, - { 0x034f, 0xa0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3280x2464_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1940x1096_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa0 }, - { 0x0346, 0x02 }, - { 0x0347, 0xac }, - { 0x0348, 0x0a }, - { 0x0349, 0x33 }, - { 0x034a, 0x06 }, - { 0x034b, 0xf3 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x94 }, - { 0x034e, 0x04 }, - { 0x034f, 0x48 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1940x1096_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1936x1096_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa0 }, - { 0x0346, 0x02 }, - { 0x0347, 0xac }, - { 0x0348, 0x0a }, - { 0x0349, 0x2f }, - { 0x034a, 0x06 }, - { 0x034b, 0xf3 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x90 }, - { 0x034e, 0x04 }, - { 0x034f, 0x48 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1936x1096_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1924x1080_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa8 }, - { 0x0346, 0x02 }, - { 0x0347, 0xb4 }, - { 0x0348, 0x0a }, - { 0x0349, 0x2b }, - { 0x034a, 0x06 }, - { 0x034b, 0xeb }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x84 }, - { 0x034e, 0x04 }, - { 0x034f, 0x38 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1924x1080_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1920x1080_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa8 }, - { 0x0346, 0x02 }, - { 0x0347, 0xb4 }, - { 0x0348, 0x0a }, - { 0x0349, 0x27 }, - { 0x034a, 0x06 }, - { 0x034b, 0xeb }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x80 }, - { 0x034e, 0x04 }, - { 0x034f, 0x38 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1920x1080_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1640x1232_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x06 }, - { 0x034d, 0x68 }, - { 0x034e, 0x04 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1640x1232_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1640x922_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x01 }, - { 0x0347, 0x30 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x08 }, - { 0x034b, 0x63 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x06 }, - { 0x034d, 0x68 }, - { 0x034e, 0x03 }, - { 0x034f, 0x9a }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1640x922_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1300x736_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x58 }, - { 0x0346, 0x01 }, - { 0x0347, 0xf0 }, - { 0x0348, 0x0b }, - { 0x0349, 0x7f }, - { 0x034a, 0x07 }, - { 0x034b, 0xaf }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x14 }, - { 0x034e, 0x02 }, - { 0x034f, 0xe0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1300x736_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1296x736_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x58 }, - { 0x0346, 0x01 }, - { 0x0347, 0xf0 }, - { 0x0348, 0x0b }, - { 0x0349, 0x77 }, - { 0x034a, 0x07 }, - { 0x034b, 0xaf }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x10 }, - { 0x034e, 0x02 }, - { 0x034f, 0xe0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1296x736_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1284x720_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x68 }, - { 0x0346, 0x02 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0b }, - { 0x0349, 0x6f }, - { 0x034a, 0x07 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x04 }, - { 0x034e, 0x02 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1284x720_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1280x720_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x68 }, - { 0x0346, 0x02 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0b }, - { 0x0349, 0x67 }, - { 0x034a, 0x07 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x00 }, - { 0x034e, 0x02 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1280x720_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_820x616_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x02 }, - { 0x0341, 0x8c }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x44 }, - { 0x0902, 0x00 }, - { 0x034c, 0x03 }, - { 0x034d, 0x34 }, - { 0x034e, 0x02 }, - { 0x034f, 0x68 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x02 }, - { 0x0701, 0x78 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_820x616_regs[] = { + { CCI_REG8(0x0700), 0x02 }, + { CCI_REG8(0x0701), 0x78 }, }; static const char * const imx355_test_pattern_menu[] = { @@ -897,23 +337,19 @@ static const char * const imx355_test_pattern_menu[] = { "Pseudorandom Sequence (PN9)", }; -/* - * When adding more than the one below, make sure the disallowed ones will - * actually be disabled in the LINK_FREQ control. - */ -static const s64 link_freq_menu_items[] = { - IMX355_LINK_FREQ_DEFAULT, -}; - /* Mode configs */ static const struct imx355_mode supported_modes[] = { { .width = 3280, .height = 2464, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), .regs = mode_3280x2464_regs, @@ -922,10 +358,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 3268, .height = 2448, + .crop = { + .width = 3268, + .height = 2448, + .left = 8, + .top = 8, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs), .regs = mode_3268x2448_regs, @@ -934,10 +374,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 3264, .height = 2448, + .crop = { + .width = 3264, + .height = 2448, + .left = 8, + .top = 8, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), .regs = mode_3264x2448_regs, @@ -946,10 +390,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1940, .height = 1096, + .crop = { + .width = 1940, + .height = 1096, + .left = 672, + .top = 684, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs), .regs = mode_1940x1096_regs, @@ -958,10 +406,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1936, .height = 1096, + .crop = { + .width = 1936, + .height = 1096, + .left = 672, + .top = 684, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), .regs = mode_1936x1096_regs, @@ -970,10 +422,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1924, .height = 1080, + .crop = { + .width = 1924, + .height = 1080, + .left = 680, + .top = 692, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs), .regs = mode_1924x1080_regs, @@ -982,10 +438,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1920, .height = 1080, + .crop = { + .width = 1920, + .height = 1080, + .left = 680, + .top = 692, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), .regs = mode_1920x1080_regs, @@ -994,10 +454,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1640, .height = 1232, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), .regs = mode_1640x1232_regs, @@ -1006,10 +470,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1640, .height = 922, + .crop = { + .width = 3280, + .height = 1844, + .left = 0, + .top = 304, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), .regs = mode_1640x922_regs, @@ -1018,10 +486,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1300, .height = 736, + .crop = { + .width = 2600, + .height = 1472, + .left = 344, + .top = 496, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1300x736_regs), .regs = mode_1300x736_regs, @@ -1030,10 +502,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1296, .height = 736, + .crop = { + .width = 2592, + .height = 1472, + .left = 344, + .top = 496, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), .regs = mode_1296x736_regs, @@ -1042,10 +518,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1284, .height = 720, + .crop = { + .width = 2568, + .height = 1440, + .left = 360, + .top = 512, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1284x720_regs), .regs = mode_1284x720_regs, @@ -1054,10 +534,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1280, .height = 720, + .crop = { + .width = 2560, + .height = 1440, + .left = 360, + .top = 512, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), .regs = mode_1280x720_regs, @@ -1066,10 +550,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 820, .height = 616, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 652, - .fll_min = 652, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_820x616_regs), .regs = mode_820x616_regs, @@ -1095,116 +583,28 @@ static u32 imx355_get_format_code(struct imx355 *imx355) { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, }; - lockdep_assert_held(&imx355->mutex); code = codes[imx355->vflip->val][imx355->hflip->val]; return code; } -/* Read registers up to 4 at a time */ -static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); - struct i2c_msg msgs[2]; - u8 addr_buf[2]; - u8 data_buf[4] = { 0 }; - int ret; - - if (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; -} - -/* Write registers up to 4 at a time */ -static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); - u8 buf[6]; - - if (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; -} - -/* Write a list of registers */ -static int imx355_write_regs(struct imx355 *imx355, - const struct imx355_reg *regs, u32 len) -{ - int ret; - u32 i; - - for (i = 0; i < len; i++) { - ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); - if (ret) { - dev_err_ratelimited(imx355->dev, - "write reg 0x%4.4x return err %d", - regs[i].address, ret); - - return ret; - } - } - - return 0; -} - -/* Open sub-device */ -static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct imx355 *imx355 = to_imx355(sd); - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(fh->state, 0); - - mutex_lock(&imx355->mutex); - - /* Initialize try_fmt */ - try_fmt->width = imx355->cur_mode->width; - try_fmt->height = imx355->cur_mode->height; - try_fmt->code = imx355_get_format_code(imx355); - try_fmt->field = V4L2_FIELD_NONE; - - mutex_unlock(&imx355->mutex); - - return 0; -} - static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx355 *imx355 = container_of(ctrl->handler, struct imx355, ctrl_handler); + const struct v4l2_mbus_framefmt *format = NULL; + struct v4l2_subdev_state *state; s64 max; int ret; + state = v4l2_subdev_get_locked_active_state(&imx355->sd); + format = v4l2_subdev_state_get_format(state, 0); + /* Propagate change of current control to all related controls */ switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = imx355->cur_mode->height + ctrl->val - 10; + max = format->height + ctrl->val - IMX355_EXPOSURE_OFFSET; __v4l2_ctrl_modify_range(imx355->exposure, imx355->exposure->minimum, max, imx355->exposure->step, max); @@ -1221,31 +621,31 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: /* Analog gain = 1024/(1024 - ctrl->val) times */ - ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_ANALOG_GAIN, + ctrl->val, NULL); break; case V4L2_CID_DIGITAL_GAIN: - ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_DIG_GAIN_GLOBAL, + ctrl->val, NULL); break; case V4L2_CID_EXPOSURE: - ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_EXPOSURE, + ctrl->val, NULL); break; case V4L2_CID_VBLANK: /* Update FLL that meets expected vertical blanking */ - ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2, - imx355->cur_mode->height + ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_FLL, + format->height + ctrl->val, NULL); break; case V4L2_CID_TEST_PATTERN: - ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN, - 2, ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_TEST_PATTERN, + ctrl->val, NULL); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: - ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1, - imx355->hflip->val | - imx355->vflip->val << 1); + ret = cci_write(imx355->regmap, IMX355_REG_ORIENTATION, + imx355->hflip->val | imx355->vflip->val << 1, + NULL); break; default: ret = -EINVAL; @@ -1272,9 +672,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - mutex_lock(&imx355->mutex); code->code = imx355_get_format_code(imx355); - mutex_unlock(&imx355->mutex); return 0; } @@ -1288,12 +686,9 @@ static int imx355_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - mutex_lock(&imx355->mutex); if (fse->code != imx355_get_format_code(imx355)) { - mutex_unlock(&imx355->mutex); return -EINVAL; } - mutex_unlock(&imx355->mutex); fse->min_width = supported_modes[fse->index].width; fse->max_width = fse->min_width; @@ -1311,36 +706,10 @@ static void imx355_update_pad_format(struct imx355 *imx355, fmt->format.height = mode->height; fmt->format.code = imx355_get_format_code(imx355); fmt->format.field = V4L2_FIELD_NONE; -} - -static int imx355_do_get_pad_format(struct imx355 *imx355, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *framefmt; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - fmt->format = *framefmt; - } else { - imx355_update_pad_format(imx355, imx355->cur_mode, fmt); - } - - return 0; -} - -static int imx355_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx355 *imx355 = to_imx355(sd); - int ret; - - mutex_lock(&imx355->mutex); - ret = imx355_do_get_pad_format(imx355, sd_state, fmt); - mutex_unlock(&imx355->mutex); - - return ret; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; } static int @@ -1351,13 +720,8 @@ imx355_set_pad_format(struct v4l2_subdev *sd, struct imx355 *imx355 = to_imx355(sd); const struct imx355_mode *mode; struct v4l2_mbus_framefmt *framefmt; - s32 vblank_def; - s32 vblank_min; + struct v4l2_rect *crop; s64 h_blank; - u64 pixel_rate; - u32 height; - - mutex_lock(&imx355->mutex); /* * Only one bayer order is supported. @@ -1370,23 +734,25 @@ imx355_set_pad_format(struct v4l2_subdev *sd, width, height, fmt->format.width, fmt->format.height); imx355_update_pad_format(imx355, mode, fmt); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - *framefmt = fmt->format; - } else { - imx355->cur_mode = mode; - pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; - do_div(pixel_rate, 10); - __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); + framefmt = v4l2_subdev_state_get_format(sd_state, 0); + + *framefmt = fmt->format; + + crop = v4l2_subdev_state_get_crop(sd_state, 0); + crop->width = mode->crop.width; + crop->height = mode->crop.height; + crop->left = mode->crop.left; + crop->top = mode->crop.top; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Update limits and set FPS to default */ - height = imx355->cur_mode->height; - vblank_def = imx355->cur_mode->fll_def - height; - vblank_min = imx355->cur_mode->fll_min - height; - height = IMX355_FLL_MAX - height; - __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1, - vblank_def); - __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def); - h_blank = mode->llp - imx355->cur_mode->width; + __v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN, + IMX355_FLL_MAX - mode->height, 1, + mode->fll_def - mode->height); + __v4l2_ctrl_s_ctrl(imx355->vblank, mode->fll_def - mode->height); + + h_blank = mode->llp - mode->width; + /* * Currently hblank is not changeable. * So FPS control is done only by vblank. @@ -1395,7 +761,42 @@ imx355_set_pad_format(struct v4l2_subdev *sd, h_blank, 1, h_blank); } - mutex_unlock(&imx355->mutex); + return 0; +} + +static int imx355_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = IMX355_PIXEL_ARRAY_TOP; + sel->r.left = IMX355_PIXEL_ARRAY_LEFT; + sel->r.width = IMX355_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX355_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +static int imx355_entity_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10; + fmt.format.width = supported_modes[0].width; + fmt.format.height = supported_modes[0].height; + + imx355_set_pad_format(subdev, sd_state, &fmt); return 0; } @@ -1403,52 +804,98 @@ imx355_set_pad_format(struct v4l2_subdev *sd, /* Start streaming */ static int imx355_start_streaming(struct imx355 *imx355) { - const struct imx355_reg_list *reg_list; - int ret; + const struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; + const struct imx355_mode *mode; + int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1; + struct v4l2_rect *crop; + u64 link_bitrate; + u8 binning_mode; + int ret = 0; /* Global Setting */ - reg_list = &imx355_global_setting; - ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); - if (ret) { - dev_err(imx355->dev, "failed to set global settings"); - return ret; - } + cci_multi_reg_write(imx355->regmap, imx355_global_regs, + ARRAY_SIZE(imx355_global_regs), &ret); - /* Apply default values of current mode */ - reg_list = &imx355->cur_mode->reg_list; - ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); - if (ret) { - dev_err(imx355->dev, "failed to set mode"); - return ret; - } + /* Apply values of current mode */ + state = v4l2_subdev_get_locked_active_state(&imx355->sd); + fmt = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, fmt->width, fmt->height); + cci_multi_reg_write(imx355->regmap, mode->reg_list.regs, + mode->reg_list.num_of_regs, &ret); + + /* Set readout crop and size registers */ + cci_write(imx355->regmap, IMX355_REG_X_ADD_START, crop->left, + &ret); + cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, crop->top, &ret); + cci_write(imx355->regmap, IMX355_REG_X_ADD_END, + crop->width + crop->left - 1, &ret); + cci_write(imx355->regmap, IMX355_REG_Y_ADD_END, + crop->height + crop->top - 1, &ret); + cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, fmt->width, &ret); + cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, fmt->height, &ret); + + binning_mode = ((crop->width / fmt->width) << 4) | + (crop->height / fmt->height); + cci_write(imx355->regmap, IMX355_REG_BINNING_MODE, + binning_mode == 0x11 ? 0x00 : 0x01, &ret); + cci_write(imx355->regmap, IMX355_REG_BINNING_TYPE, binning_mode, &ret); + cci_write(imx355->regmap, IMX355_REG_BINNING_WEIGHTING, 0x00, &ret); + + /* Set PLL registers for the external clock frequency */ + cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ, + imx355->clk_params->extclk_freq, &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL, + imx355->clk_params->pll_op_mpy[lane_idx], &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_OP_PREDIV, + imx355->clk_params->pll_op_prediv[lane_idx], &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_IVT_SYSCK_DIV, + lane_idx ? 2 : 1, &ret); + + /* Set MIPI configuration */ + cci_write(imx355->regmap, IMX355_REG_LANE_SEL, + imx355->hwcfg->num_lanes - 1, &ret); + + link_bitrate = imx355->link_freq->qmenu_int[imx355->link_freq->val] * + imx355->hwcfg->num_lanes * 2; + do_div(link_bitrate, 1000000); + cci_write(imx355->regmap, IMX355_REG_REQ_LINK_BIT_RATE, link_bitrate, + &ret); /* set digital gain control to all color mode */ - ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); - if (ret) - return ret; + cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret); + + /* set line length */ + cci_write(imx355->regmap, IMX355_REG_LLP, + imx355->hblank->val + fmt->width, &ret); /* Apply customized values from user */ - ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); - if (ret) - return ret; + if (!ret) + ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); + + cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, IMX355_MODE_STREAMING, + &ret); - return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, - 1, IMX355_MODE_STREAMING); + return ret; } /* Stop streaming */ static int imx355_stop_streaming(struct imx355 *imx355) { - return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, - 1, IMX355_MODE_STANDBY); + return cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, + IMX355_MODE_STANDBY, NULL); } static int imx355_set_stream(struct v4l2_subdev *sd, int enable) { struct imx355 *imx355 = to_imx355(sd); + struct v4l2_subdev_state *state; int ret = 0; - mutex_lock(&imx355->mutex); + state = v4l2_subdev_lock_and_get_active_state(sd); if (enable) { ret = pm_runtime_resume_and_get(imx355->dev); @@ -1464,21 +911,21 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx355_stop_streaming(imx355); - pm_runtime_put(imx355->dev); + pm_runtime_put_autosuspend(imx355->dev); } /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx355->vflip, enable); __v4l2_ctrl_grab(imx355->hflip, enable); - mutex_unlock(&imx355->mutex); + v4l2_subdev_unlock_state(state); return ret; err_rpm_put: - pm_runtime_put(imx355->dev); + pm_runtime_put_autosuspend(imx355->dev); err_unlock: - mutex_unlock(&imx355->mutex); + v4l2_subdev_unlock_state(state); return ret; } @@ -1487,14 +934,14 @@ err_unlock: static int imx355_identify_module(struct imx355 *imx355) { int ret; - u32 val; + u64 val; - ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val); + ret = cci_read(imx355->regmap, IMX355_REG_CHIP_ID, &val, NULL); if (ret) return ret; if (val != IMX355_CHIP_ID) { - dev_err(imx355->dev, "chip id mismatch: %x!=%x", + dev_err(imx355->dev, "chip id mismatch: %x!=%llx", IMX355_CHIP_ID, val); return -EIO; } @@ -1512,9 +959,10 @@ static const struct v4l2_subdev_video_ops imx355_video_ops = { static const struct v4l2_subdev_pad_ops imx355_pad_ops = { .enum_mbus_code = imx355_enum_mbus_code, - .get_fmt = imx355_get_pad_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx355_set_pad_format, .enum_frame_size = imx355_enum_frame_size, + .get_selection = imx355_get_selection, }; static const struct v4l2_subdev_ops imx355_subdev_ops = { @@ -1528,7 +976,7 @@ static const struct media_entity_operations imx355_subdev_entity_ops = { }; static const struct v4l2_subdev_internal_ops imx355_internal_ops = { - .open = imx355_open, + .init_state = imx355_entity_init_state, }; static int imx355_power_off(struct device *dev) @@ -1582,13 +1030,11 @@ static int imx355_init_controls(struct imx355 *imx355) { struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; + const struct imx355_mode *mode = &supported_modes[0]; s64 exposure_max; s64 vblank_def; - s64 vblank_min; s64 hblank; u64 pixel_rate; - const struct imx355_mode *mode; - u32 max; int ret; ctrl_hdlr = &imx355->ctrl_handler; @@ -1596,40 +1042,34 @@ static int imx355_init_controls(struct imx355 *imx355) if (ret) return ret; - ctrl_hdlr->lock = &imx355->mutex; - max = ARRAY_SIZE(link_freq_menu_items) - 1; imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_LINK_FREQ, max, 0, - link_freq_menu_items); + V4L2_CID_LINK_FREQ, 0, 0, + &imx355->hwcfg->link_freq_menu); if (imx355->link_freq) imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; + pixel_rate = imx355->hwcfg->link_freq_menu * 2 * imx355->hwcfg->num_lanes; do_div(pixel_rate, 10); - /* By default, PIXEL_RATE is read only */ - imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_PIXEL_RATE, pixel_rate, - pixel_rate, 1, pixel_rate); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE, + pixel_rate, pixel_rate, 1, pixel_rate); /* Initialize vblank/hblank/exposure parameters based on current mode */ - mode = imx355->cur_mode; vblank_def = mode->fll_def - mode->height; - vblank_min = mode->fll_min - mode->height; imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_VBLANK, vblank_min, + V4L2_CID_VBLANK, IMX355_VBLANK_MIN, IMX355_FLL_MAX - mode->height, 1, vblank_def); hblank = mode->llp - mode->width; - imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_HBLANK, hblank, hblank, - 1, hblank); + imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, + hblank, hblank, 1, hblank); if (imx355->hblank) imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* fll >= exposure time + adjust parameter (default value is 10) */ - exposure_max = mode->fll_def - 10; + exposure_max = mode->fll_def - IMX355_EXPOSURE_OFFSET; imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_EXPOSURE, IMX355_EXPOSURE_MIN, exposure_max, @@ -1683,14 +1123,17 @@ error: return ret; } -static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) +static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355) { + struct device *dev = imx355->dev; struct imx355_hwcfg *cfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + const struct imx355_clk_params *clk = imx355->clk_params; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); + int lane_idx; int ret; if (!fwnode) @@ -1708,13 +1151,18 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES) + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 && + bus_cfg.bus.mipi_csi2.num_data_lanes != 4) goto out_err; + cfg->num_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + + lane_idx = cfg->num_lanes == 4 ? 0 : 1; + cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy[lane_idx]) / + (clk->pll_op_prediv[lane_idx] * 2); ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, - link_freq_menu_items, - ARRAY_SIZE(link_freq_menu_items), + &cfg->link_freq_menu, 1, &cfg->link_freq_bitmap); if (ret) goto out_err; @@ -1741,7 +1189,10 @@ static int imx355_probe(struct i2c_client *client) imx355->dev = &client->dev; - mutex_init(&imx355->mutex); + imx355->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx355->regmap)) + return dev_err_probe(imx355->dev, PTR_ERR(imx355->regmap), + "Unable to initialize I2C\n"); imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); if (IS_ERR(imx355->clk)) @@ -1749,7 +1200,13 @@ static int imx355_probe(struct i2c_client *client) "failed to get clock\n"); freq = clk_get_rate(imx355->clk); - if (freq != IMX355_EXT_CLK) + for (unsigned int i = 0; i < ARRAY_SIZE(imx355_clk_params); i++) { + if (freq == imx355_clk_params[i].ext_clk) { + imx355->clk_params = &imx355_clk_params[i]; + break; + } + } + if (!imx355->clk_params) return dev_err_probe(imx355->dev, -EINVAL, "external clock %lu is not supported\n", freq); @@ -1760,7 +1217,7 @@ static int imx355_probe(struct i2c_client *client) &imx355->supplies); if (ret) { dev_err_probe(imx355->dev, ret, "could not get regulators"); - goto error_probe; + return ret; } imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset", @@ -1768,22 +1225,21 @@ static int imx355_probe(struct i2c_client *client) if (IS_ERR(imx355->reset_gpio)) { ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio), "failed to get gpios"); - goto error_probe; + return ret; } /* Initialize subdev */ v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); - imx355->hwcfg = imx355_get_hwcfg(imx355->dev); + imx355->hwcfg = imx355_get_hwcfg(imx355); if (!imx355->hwcfg) { dev_err(imx355->dev, "failed to get hwcfg"); - ret = -ENODEV; - goto error_probe; + return -ENODEV; } ret = imx355_power_on(imx355->dev); if (ret) - goto error_probe; + return ret; /* Check module identity */ ret = imx355_identify_module(imx355); @@ -1792,9 +1248,6 @@ static int imx355_probe(struct i2c_client *client) goto error_power_off; } - /* Set default mode to max resolution */ - imx355->cur_mode = &supported_modes[0]; - ret = imx355_init_controls(imx355); if (ret) { dev_err(imx355->dev, "failed to init controls: %d", ret); @@ -1816,23 +1269,36 @@ static int imx355_probe(struct i2c_client *client) goto error_handler_free; } + imx355->sd.state_lock = imx355->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx355->sd); + if (ret < 0) { + dev_err_probe(imx355->dev, ret, "subdev init error\n"); + goto error_media_entity_free; + } + /* * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ pm_runtime_set_active(imx355->dev); pm_runtime_enable(imx355->dev); - pm_runtime_idle(imx355->dev); + pm_runtime_set_autosuspend_delay(imx355->dev, 1000); + pm_runtime_use_autosuspend(imx355->dev); ret = v4l2_async_register_subdev_sensor(&imx355->sd); if (ret < 0) - goto error_media_entity_runtime_pm; + goto error_subdev_cleanup_runtime_pm; + + pm_runtime_idle(imx355->dev); return 0; -error_media_entity_runtime_pm: +error_subdev_cleanup_runtime_pm: pm_runtime_disable(imx355->dev); pm_runtime_set_suspended(imx355->dev); + pm_runtime_dont_use_autosuspend(imx355->dev); + v4l2_subdev_cleanup(&imx355->sd); +error_media_entity_free: media_entity_cleanup(&imx355->sd.entity); error_handler_free: @@ -1841,9 +1307,6 @@ error_handler_free: error_power_off: imx355_power_off(imx355->dev); -error_probe: - mutex_destroy(&imx355->mutex); - return ret; } @@ -1853,6 +1316,7 @@ static void imx355_remove(struct i2c_client *client) struct imx355 *imx355 = to_imx355(sd); v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); @@ -1863,7 +1327,7 @@ static void imx355_remove(struct i2c_client *client) pm_runtime_set_suspended(imx355->dev); } - mutex_destroy(&imx355->mutex); + pm_runtime_dont_use_autosuspend(imx355->dev); } static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 2705af2f16c0..d2760e9e6194 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -13,38 +13,39 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <media/v4l2-cci.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_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX412_MODE_STANDBY 0x00 #define IMX412_MODE_STREAMING 0x01 /* Lines per frame */ -#define IMX412_REG_LPFR 0x0340 +#define IMX412_REG_LPFR CCI_REG16(0x0340) /* Chip ID */ -#define IMX412_REG_ID 0x0016 +#define IMX412_REG_ID CCI_REG16(0x0016) #define IMX412_ID 0x577 /* Exposure control */ -#define IMX412_REG_EXPOSURE_CIT 0x0202 +#define IMX412_REG_EXPOSURE_CIT CCI_REG16(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_REG_AGAIN CCI_REG16(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 +#define IMX412_REG_HOLD CCI_REG8(0x0104) /* Input clock rate */ #define IMX412_INCLK_RATE 24000000 @@ -57,23 +58,13 @@ #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; + const struct cci_reg_sequence *regs; }; /** @@ -111,6 +102,7 @@ static const char * const imx412_supply_names[] = { /** * struct imx412 - imx412 sensor device structure * @dev: Pointer to generic device + * @cci: CCI register map * @client: Pointer to i2c client * @sd: V4L2 sub-device * @pad: Media pad. Only one pad supported @@ -126,10 +118,10 @@ static const char * const imx412_supply_names[] = { * @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 */ struct imx412 { struct device *dev; + struct regmap *cci; struct i2c_client *client; struct v4l2_subdev sd; struct media_pad pad; @@ -147,7 +139,6 @@ struct imx412 { }; u32 vblank; const struct imx412_mode *cur_mode; - struct mutex mutex; }; static const s64 link_freq[] = { @@ -155,238 +146,238 @@ static const s64 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}, +static const struct cci_reg_sequence mode_4056x3040_regs[] = { + { CCI_REG8(0x0136), 0x18 }, + { CCI_REG8(0x0137), 0x00 }, + { CCI_REG8(0x3c7e), 0x08 }, + { CCI_REG8(0x3c7f), 0x02 }, + { CCI_REG8(0x38a8), 0x1f }, + { CCI_REG8(0x38a9), 0xff }, + { CCI_REG8(0x38aa), 0x1f }, + { CCI_REG8(0x38ab), 0xff }, + { CCI_REG8(0x55d4), 0x00 }, + { CCI_REG8(0x55d5), 0x00 }, + { CCI_REG8(0x55d6), 0x07 }, + { CCI_REG8(0x55d7), 0xff }, + { CCI_REG8(0x55e8), 0x07 }, + { CCI_REG8(0x55e9), 0xff }, + { CCI_REG8(0x55ea), 0x00 }, + { CCI_REG8(0x55eb), 0x00 }, + { CCI_REG8(0x575c), 0x07 }, + { CCI_REG8(0x575d), 0xff }, + { CCI_REG8(0x575e), 0x00 }, + { CCI_REG8(0x575f), 0x00 }, + { CCI_REG8(0x5764), 0x00 }, + { CCI_REG8(0x5765), 0x00 }, + { CCI_REG8(0x5766), 0x07 }, + { CCI_REG8(0x5767), 0xff }, + { CCI_REG8(0x5974), 0x04 }, + { CCI_REG8(0x5975), 0x01 }, + { CCI_REG8(0x5f10), 0x09 }, + { CCI_REG8(0x5f11), 0x92 }, + { CCI_REG8(0x5f12), 0x32 }, + { CCI_REG8(0x5f13), 0x72 }, + { CCI_REG8(0x5f14), 0x16 }, + { CCI_REG8(0x5f15), 0xba }, + { CCI_REG8(0x5f17), 0x13 }, + { CCI_REG8(0x5f18), 0x24 }, + { CCI_REG8(0x5f19), 0x60 }, + { CCI_REG8(0x5f1a), 0xe3 }, + { CCI_REG8(0x5f1b), 0xad }, + { CCI_REG8(0x5f1c), 0x74 }, + { CCI_REG8(0x5f2d), 0x25 }, + { CCI_REG8(0x5f5c), 0xd0 }, + { CCI_REG8(0x6a22), 0x00 }, + { CCI_REG8(0x6a23), 0x1d }, + { CCI_REG8(0x7ba8), 0x00 }, + { CCI_REG8(0x7ba9), 0x00 }, + { CCI_REG8(0x886b), 0x00 }, + { CCI_REG8(0x9002), 0x0a }, + { CCI_REG8(0x9004), 0x1a }, + { CCI_REG8(0x9214), 0x93 }, + { CCI_REG8(0x9215), 0x69 }, + { CCI_REG8(0x9216), 0x93 }, + { CCI_REG8(0x9217), 0x6b }, + { CCI_REG8(0x9218), 0x93 }, + { CCI_REG8(0x9219), 0x6d }, + { CCI_REG8(0x921a), 0x57 }, + { CCI_REG8(0x921b), 0x58 }, + { CCI_REG8(0x921c), 0x57 }, + { CCI_REG8(0x921d), 0x59 }, + { CCI_REG8(0x921e), 0x57 }, + { CCI_REG8(0x921f), 0x5a }, + { CCI_REG8(0x9220), 0x57 }, + { CCI_REG8(0x9221), 0x5b }, + { CCI_REG8(0x9222), 0x93 }, + { CCI_REG8(0x9223), 0x02 }, + { CCI_REG8(0x9224), 0x93 }, + { CCI_REG8(0x9225), 0x03 }, + { CCI_REG8(0x9226), 0x93 }, + { CCI_REG8(0x9227), 0x04 }, + { CCI_REG8(0x9228), 0x93 }, + { CCI_REG8(0x9229), 0x05 }, + { CCI_REG8(0x922a), 0x98 }, + { CCI_REG8(0x922b), 0x21 }, + { CCI_REG8(0x922c), 0xb2 }, + { CCI_REG8(0x922d), 0xdb }, + { CCI_REG8(0x922e), 0xb2 }, + { CCI_REG8(0x922f), 0xdc }, + { CCI_REG8(0x9230), 0xb2 }, + { CCI_REG8(0x9231), 0xdd }, + { CCI_REG8(0x9232), 0xe2 }, + { CCI_REG8(0x9233), 0xe1 }, + { CCI_REG8(0x9234), 0xb2 }, + { CCI_REG8(0x9235), 0xe2 }, + { CCI_REG8(0x9236), 0xb2 }, + { CCI_REG8(0x9237), 0xe3 }, + { CCI_REG8(0x9238), 0xb7 }, + { CCI_REG8(0x9239), 0xb9 }, + { CCI_REG8(0x923a), 0xb7 }, + { CCI_REG8(0x923b), 0xbb }, + { CCI_REG8(0x923c), 0xb7 }, + { CCI_REG8(0x923d), 0xbc }, + { CCI_REG8(0x923e), 0xb7 }, + { CCI_REG8(0x923f), 0xc5 }, + { CCI_REG8(0x9240), 0xb7 }, + { CCI_REG8(0x9241), 0xc7 }, + { CCI_REG8(0x9242), 0xb7 }, + { CCI_REG8(0x9243), 0xc9 }, + { CCI_REG8(0x9244), 0x98 }, + { CCI_REG8(0x9245), 0x56 }, + { CCI_REG8(0x9246), 0x98 }, + { CCI_REG8(0x9247), 0x55 }, + { CCI_REG8(0x9380), 0x00 }, + { CCI_REG8(0x9381), 0x62 }, + { CCI_REG8(0x9382), 0x00 }, + { CCI_REG8(0x9383), 0x56 }, + { CCI_REG8(0x9384), 0x00 }, + { CCI_REG8(0x9385), 0x52 }, + { CCI_REG8(0x9388), 0x00 }, + { CCI_REG8(0x9389), 0x55 }, + { CCI_REG8(0x938a), 0x00 }, + { CCI_REG8(0x938b), 0x55 }, + { CCI_REG8(0x938c), 0x00 }, + { CCI_REG8(0x938d), 0x41 }, + { CCI_REG8(0x5078), 0x01 }, + { CCI_REG8(0x0112), 0x0a }, + { CCI_REG8(0x0113), 0x0a }, + { CCI_REG8(0x0114), 0x03 }, + { CCI_REG8(0x0342), 0x11 }, + { CCI_REG8(0x0343), 0xa0 }, + { CCI_REG8(0x0340), 0x0d }, + { CCI_REG8(0x0341), 0xda }, + { CCI_REG8(0x3210), 0x00 }, + { CCI_REG8(0x0344), 0x00 }, + { CCI_REG8(0x0345), 0x00 }, + { CCI_REG8(0x0346), 0x00 }, + { CCI_REG8(0x0347), 0x00 }, + { CCI_REG8(0x0348), 0x0f }, + { CCI_REG8(0x0349), 0xd7 }, + { CCI_REG8(0x034a), 0x0b }, + { CCI_REG8(0x034b), 0xdf }, + { CCI_REG8(0x00e3), 0x00 }, + { CCI_REG8(0x00e4), 0x00 }, + { CCI_REG8(0x00e5), 0x01 }, + { CCI_REG8(0x00fc), 0x0a }, + { CCI_REG8(0x00fd), 0x0a }, + { CCI_REG8(0x00fe), 0x0a }, + { CCI_REG8(0x00ff), 0x0a }, + { CCI_REG8(0xe013), 0x00 }, + { CCI_REG8(0x0220), 0x00 }, + { CCI_REG8(0x0221), 0x11 }, + { CCI_REG8(0x0381), 0x01 }, + { CCI_REG8(0x0383), 0x01 }, + { CCI_REG8(0x0385), 0x01 }, + { CCI_REG8(0x0387), 0x01 }, + { CCI_REG8(0x0900), 0x00 }, + { CCI_REG8(0x0901), 0x11 }, + { CCI_REG8(0x0902), 0x00 }, + { CCI_REG8(0x3140), 0x02 }, + { CCI_REG8(0x3241), 0x11 }, + { CCI_REG8(0x3250), 0x03 }, + { CCI_REG8(0x3e10), 0x00 }, + { CCI_REG8(0x3e11), 0x00 }, + { CCI_REG8(0x3f0d), 0x00 }, + { CCI_REG8(0x3f42), 0x00 }, + { CCI_REG8(0x3f43), 0x00 }, + { CCI_REG8(0x0401), 0x00 }, + { CCI_REG8(0x0404), 0x00 }, + { CCI_REG8(0x0405), 0x10 }, + { CCI_REG8(0x0408), 0x00 }, + { CCI_REG8(0x0409), 0x00 }, + { CCI_REG8(0x040a), 0x00 }, + { CCI_REG8(0x040b), 0x00 }, + { CCI_REG8(0x040c), 0x0f }, + { CCI_REG8(0x040d), 0xd8 }, + { CCI_REG8(0x040e), 0x0b }, + { CCI_REG8(0x040f), 0xe0 }, + { CCI_REG8(0x034c), 0x0f }, + { CCI_REG8(0x034d), 0xd8 }, + { CCI_REG8(0x034e), 0x0b }, + { CCI_REG8(0x034f), 0xe0 }, + { CCI_REG8(0x0301), 0x05 }, + { CCI_REG8(0x0303), 0x02 }, + { CCI_REG8(0x0305), 0x04 }, + { CCI_REG8(0x0306), 0x00 }, + { CCI_REG8(0x0307), 0xc8 }, + { CCI_REG8(0x0309), 0x0a }, + { CCI_REG8(0x030b), 0x01 }, + { CCI_REG8(0x030d), 0x02 }, + { CCI_REG8(0x030e), 0x01 }, + { CCI_REG8(0x030f), 0x5e }, + { CCI_REG8(0x0310), 0x00 }, + { CCI_REG8(0x0820), 0x12 }, + { CCI_REG8(0x0821), 0xc0 }, + { CCI_REG8(0x0822), 0x00 }, + { CCI_REG8(0x0823), 0x00 }, + { CCI_REG8(0x3e20), 0x01 }, + { CCI_REG8(0x3e37), 0x00 }, + { CCI_REG8(0x3f50), 0x00 }, + { CCI_REG8(0x3f56), 0x00 }, + { CCI_REG8(0x3f57), 0xe2 }, + { CCI_REG8(0x3c0a), 0x5a }, + { CCI_REG8(0x3c0b), 0x55 }, + { CCI_REG8(0x3c0c), 0x28 }, + { CCI_REG8(0x3c0d), 0x07 }, + { CCI_REG8(0x3c0e), 0xff }, + { CCI_REG8(0x3c0f), 0x00 }, + { CCI_REG8(0x3c10), 0x00 }, + { CCI_REG8(0x3c11), 0x02 }, + { CCI_REG8(0x3c12), 0x00 }, + { CCI_REG8(0x3c13), 0x03 }, + { CCI_REG8(0x3c14), 0x00 }, + { CCI_REG8(0x3c15), 0x00 }, + { CCI_REG8(0x3c16), 0x0c }, + { CCI_REG8(0x3c17), 0x0c }, + { CCI_REG8(0x3c18), 0x0c }, + { CCI_REG8(0x3c19), 0x0a }, + { CCI_REG8(0x3c1a), 0x0a }, + { CCI_REG8(0x3c1b), 0x0a }, + { CCI_REG8(0x3c1c), 0x00 }, + { CCI_REG8(0x3c1d), 0x00 }, + { CCI_REG8(0x3c1e), 0x00 }, + { CCI_REG8(0x3c1f), 0x00 }, + { CCI_REG8(0x3c20), 0x00 }, + { CCI_REG8(0x3c21), 0x00 }, + { CCI_REG8(0x3c22), 0x3f }, + { CCI_REG8(0x3c23), 0x0a }, + { CCI_REG8(0x3e35), 0x01 }, + { CCI_REG8(0x3f4a), 0x03 }, + { CCI_REG8(0x3f4b), 0xbf }, + { CCI_REG8(0x3f26), 0x00 }, + { CCI_REG8(0x0202), 0x0d }, + { CCI_REG8(0x0203), 0xc4 }, + { CCI_REG8(0x0204), 0x00 }, + { CCI_REG8(0x0205), 0x00 }, + { CCI_REG8(0x020e), 0x01 }, + { CCI_REG8(0x020f), 0x00 }, + { CCI_REG8(0x0210), 0x01 }, + { CCI_REG8(0x0211), 0x00 }, + { CCI_REG8(0x0212), 0x01 }, + { CCI_REG8(0x0213), 0x00 }, + { CCI_REG8(0x0214), 0x01 }, + { CCI_REG8(0x0215), 0x00 }, + { CCI_REG8(0xbcf1), 0x00 }, }; /* Supported sensor mode configurations */ @@ -418,97 +409,6 @@ static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev) } /** - * 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 @@ -543,29 +443,25 @@ static int imx412_update_controls(struct imx412 *imx412, static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) { u32 lpfr; - int ret; + int ret = 0; + int ret_hold; lpfr = imx412->vblank + imx412->cur_mode->height; dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u\n", exposure, gain, lpfr); - ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); - if (ret) - return ret; + cci_write(imx412->cci, IMX412_REG_HOLD, 1, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr); - if (ret) - goto error_release_group_hold; + cci_write(imx412->cci, IMX412_REG_LPFR, lpfr, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure); - if (ret) - goto error_release_group_hold; + cci_write(imx412->cci, IMX412_REG_EXPOSURE_CIT, exposure, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain); + cci_write(imx412->cci, IMX412_REG_AGAIN, gain, &ret); -error_release_group_hold: - imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0); + ret_hold = cci_write(imx412->cci, IMX412_REG_HOLD, 0, NULL); + if (ret_hold) + return ret_hold; return ret; } @@ -679,8 +575,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd, { struct imx412 *imx412 = to_imx412(sd); - mutex_lock(&imx412->mutex); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; @@ -690,8 +584,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd, imx412_fill_pad_format(imx412, imx412->cur_mode, fmt); } - mutex_unlock(&imx412->mutex); - return 0; } @@ -703,8 +595,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, const struct imx412_mode *mode; int ret = 0; - mutex_lock(&imx412->mutex); - mode = &supported_mode; imx412_fill_pad_format(imx412, mode, fmt); @@ -719,8 +609,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, imx412->cur_mode = mode; } - mutex_unlock(&imx412->mutex); - return ret; } @@ -737,88 +625,86 @@ static int imx412_init_state(struct v4l2_subdev *sd, } /** - * imx412_start_streaming() - Start sensor stream - * @imx412: pointer to imx412 device + * imx412_enable_streams() - Enable specified streams for the sensor + * @sd: pointer to the V4L2 subdevice + * @state: pointer to the subdevice state + * @pad: pad number for which streams are enabled + * @streams_mask: bitmask specifying the streams to enable * * Return: 0 if successful, error code otherwise. */ -static int imx412_start_streaming(struct imx412 *imx412) +static int imx412_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { const struct imx412_reg_list *reg_list; + struct imx412 *imx412 = to_imx412(sd); int ret; + ret = pm_runtime_resume_and_get(imx412->dev); + if (ret < 0) + return 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); + ret = cci_multi_reg_write(imx412->cci, reg_list->regs, + reg_list->num_of_regs, NULL); if (ret) { dev_err(imx412->dev, "fail to write initial registers\n"); - return ret; + goto err_rpm_put; } /* 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\n"); - return ret; + goto err_rpm_put; } /* Delay is required before streaming*/ usleep_range(7400, 8000); /* Start streaming */ - ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, - 1, IMX412_MODE_STREAMING); + ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT, + IMX412_MODE_STREAMING, NULL); if (ret) { dev_err(imx412->dev, "fail to start streaming\n"); - return ret; + goto err_rpm_put; } return 0; + +err_rpm_put: + pm_runtime_put(imx412->dev); + + return ret; } /** - * imx412_stop_streaming() - Stop sensor stream - * @imx412: pointer to imx412 device + * imx412_disable_streams() - Enable specified streams for the sensor + * @sd: pointer to the V4L2 subdevice + * @state: pointer to the subdevice state + * @pad: pad number for which streams are disabled + * @streams_mask: bitmask specifying the streams to disable * * 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); -} - -static int imx412_set_stream(struct v4l2_subdev *sd, int enable) +static int imx412_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { struct imx412 *imx412 = to_imx412(sd); int ret; - mutex_lock(&imx412->mutex); + ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT, + IMX412_MODE_STANDBY, NULL); - 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); - } - - mutex_unlock(&imx412->mutex); - - return 0; + if (ret) + dev_err(imx412->dev, "failed to set stream off\n"); -error_power_off: pm_runtime_put(imx412->dev); -error_unlock: - mutex_unlock(&imx412->mutex); - return ret; + return 0; } /** @@ -830,16 +716,18 @@ error_unlock: static int imx412_detect(struct imx412 *imx412) { int ret; - u32 val; + u64 val; - ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val); + ret = cci_read(imx412->cci, IMX412_REG_ID, &val, NULL); if (ret) - return ret; + return dev_err_probe(imx412->dev, ret, + "failed to read chip id %x\n", + IMX412_ID); if (val != IMX412_ID) { - dev_err(imx412->dev, "chip id mismatch: %x!=%x\n", - IMX412_ID, val); - return -ENXIO; + return dev_err_probe(imx412->dev, -ENODEV, + "chip id mismatch: %x!=%llx", + IMX412_ID, val); } return 0; @@ -933,7 +821,7 @@ done_endpoint_free: /* V4l2 subdevice ops */ static const struct v4l2_subdev_video_ops imx412_video_ops = { - .s_stream = imx412_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops imx412_pad_ops = { @@ -941,6 +829,8 @@ static const struct v4l2_subdev_pad_ops imx412_pad_ops = { .enum_frame_size = imx412_enum_frame_size, .get_fmt = imx412_get_pad_format, .set_fmt = imx412_set_pad_format, + .enable_streams = imx412_enable_streams, + .disable_streams = imx412_disable_streams, }; static const struct v4l2_subdev_ops imx412_subdev_ops = { @@ -1021,9 +911,6 @@ static int imx412_init_controls(struct imx412 *imx412) 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, @@ -1104,6 +991,11 @@ static int imx412_probe(struct i2c_client *client) if (!name) return -ENODEV; + imx412->cci = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx412->cci)) + return dev_err_probe(imx412->dev, PTR_ERR(imx412->cci), + "Failed to init CCI\n"); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops); imx412->sd.internal_ops = &imx412_internal_ops; @@ -1114,13 +1006,10 @@ static int imx412_probe(struct i2c_client *client) return ret; } - mutex_init(&imx412->mutex); - ret = imx412_power_on(imx412->dev); - if (ret) { - dev_err(imx412->dev, "failed to power-on the sensor\n"); - goto error_mutex_destroy; - } + if (ret) + return dev_err_probe(imx412->dev, ret, + "failed to power-on the sensor\n"); /* Check module identity */ ret = imx412_detect(imx412); @@ -1153,27 +1042,37 @@ static int imx412_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor(&imx412->sd); + imx412->sd.state_lock = imx412->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx412->sd); if (ret < 0) { - dev_err(imx412->dev, - "failed to register async subdev: %d\n", ret); + dev_err_probe(imx412->dev, ret, "subdev init error\n"); goto error_media_entity; } pm_runtime_set_active(imx412->dev); pm_runtime_enable(imx412->dev); + + ret = v4l2_async_register_subdev_sensor(&imx412->sd); + if (ret < 0) { + dev_err_probe(imx412->dev, ret, + "failed to register sub-device\n"); + goto error_subdev_cleanup; + } + pm_runtime_idle(imx412->dev); return 0; +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx412->sd); + pm_runtime_disable(imx412->dev); + pm_runtime_set_suspended(imx412->dev); 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; } @@ -1181,9 +1080,9 @@ error_mutex_destroy: static void 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); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); @@ -1191,8 +1090,6 @@ static void imx412_remove(struct i2c_client *client) if (!pm_runtime_status_suspended(&client->dev)) imx412_power_off(&client->dev); pm_runtime_set_suspended(&client->dev); - - mutex_destroy(&imx412->mutex); } static const struct dev_pm_ops imx412_pm_ops = { diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 0b424c17e880..c3b22b238ea0 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -686,7 +686,7 @@ static int imx415_set_testpattern(struct imx415 *sensor, int val) cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x01, &ret); cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x01, &ret); } - return 0; + return ret; } static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) @@ -720,7 +720,7 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) ret = cci_write(sensor->regmap, IMX415_VMAX, format->height + ctrl->val, NULL); if (ret) - return ret; + break; /* * Exposure is set based on VMAX which has just changed, so * program exposure register as well diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c new file mode 100644 index 000000000000..4053aed84340 --- /dev/null +++ b/drivers/media/i2c/imx471.c @@ -0,0 +1,957 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * imx471.c - imx471 sensor driver + * + * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-fwnode.h> + +#define IMX471_REG_MODE_SELECT CCI_REG8(0x0100) +#define IMX471_MODE_STANDBY 0x00 +#define IMX471_MODE_STREAMING 0x01 + +/* Chip ID */ +#define IMX471_REG_CHIP_ID CCI_REG16(0x0016) +#define IMX471_CHIP_ID 0x0471 + +/* V_TIMING internal */ +#define IMX471_REG_FLL CCI_REG16(0x0340) +#define IMX471_FLL_MAX 0xffff + +/* Exposure control */ +#define IMX471_REG_EXPOSURE CCI_REG16(0x0202) +#define IMX471_EXPOSURE_MIN 1 +#define IMX471_EXPOSURE_STEP 1 +#define IMX471_EXPOSURE_DEFAULT 1270 + +/* Default exposure margin */ +#define IMX471_EXPOSURE_MARGIN 18 + +/* Analog gain control */ +#define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204) +#define IMX471_ANA_GAIN_MIN 0 +#define IMX471_ANA_GAIN_MAX 800 +#define IMX471_ANA_GAIN_STEP 1 +#define IMX471_ANA_GAIN_DEFAULT 0 + +/* Digital gain control */ +#define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9) +#define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) +#define IMX471_DGTL_GAIN_MIN 256 +#define IMX471_DGTL_GAIN_MAX 4095 +#define IMX471_DGTL_GAIN_STEP 1 +#define IMX471_DGTL_GAIN_DEFAULT 256 + +/* HFLIP and VFLIP control */ +#define IMX471_REG_ORIENTATION CCI_REG8(0x0101) + +/* Test Pattern Control */ +#define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600) + +/* default link frequency and external clock */ +#define IMX471_LINK_FREQ_DEFAULT 200000000LL +#define IMX471_EXT_CLK 19200000 + +/* PLL */ +#define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301) +#define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303) +#define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305) +#define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306) +#define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309) +#define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b) +#define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310) +#define IMX471_PLL_SINGLE 0 +#define IMX471_PLL_DUAL 1 + +/* IMX471 native and active pixel array size */ +#define IMX471_NATIVE_WIDTH 4672 +#define IMX471_NATIVE_HEIGHT 3512 +#define IMX471_PIXEL_ARRAY_LEFT 8 +#define IMX471_PIXEL_ARRAY_TOP 8 +#define IMX471_PIXEL_ARRAY_WIDTH 4656 +#define IMX471_PIXEL_ARRAY_HEIGHT 3496 + +#define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136) + +#define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112) +#define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a + +#define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114) +#define IMX471_CSI_2_LANE_MODE 1 +#define IMX471_CSI_4_LANE_MODE 3 + +#define IMX471_REG_X_ADD_STA CCI_REG16(0x0344) +#define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346) +#define IMX471_REG_X_ADD_END CCI_REG16(0x0348) +#define IMX471_REG_Y_ADD_END CCI_REG16(0x034a) +#define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c) +#define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e) +#define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381) +#define IMX471_REG_X_ODD_INC CCI_REG8(0x0383) +#define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385) +#define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387) + +#define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408) +#define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a) +#define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c) +#define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e) + +/* Binning mode */ +#define IMX471_REG_BINNING_MODE CCI_REG8(0x0900) +#define IMX471_BINNING_NONE 0 +#define IMX471_BINNING_ENABLE 1 +#define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901) +#define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902) + +#define to_imx471(_sd) container_of_const(_sd, struct imx471, sd) + +static const char * const imx471_supply_name[] = { + "vana", +}; + +struct imx471_mode { + u32 width; + u32 height; + + /* V-timing */ + u32 fll_def; + u32 fll_min; + + /* H-timing */ + u32 llp; + + const struct cci_reg_sequence *default_mode_regs; + unsigned int default_mode_regs_length; +}; + +struct imx471 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *exposure; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)]; + struct clk *img_clk; + + struct device *dev; + struct regmap *regmap; +}; + +static const struct cci_reg_sequence imx471_global_regs[] = { + { IMX471_REG_EXCK_FREQ, 0x1333 }, + { CCI_REG8(0x3c7e), 0x08 }, + { CCI_REG8(0x3c7f), 0x05 }, + { CCI_REG8(0x3e35), 0x00 }, + { CCI_REG8(0x3e36), 0x00 }, + { CCI_REG8(0x3e37), 0x00 }, + { CCI_REG8(0x3f7f), 0x01 }, + { CCI_REG8(0x4431), 0x04 }, + { CCI_REG8(0x531c), 0x01 }, + { CCI_REG8(0x531d), 0x02 }, + { CCI_REG8(0x531e), 0x04 }, + { CCI_REG8(0x5928), 0x00 }, + { CCI_REG8(0x5929), 0x2f }, + { CCI_REG8(0x592a), 0x00 }, + { CCI_REG8(0x592b), 0x85 }, + { CCI_REG8(0x592c), 0x00 }, + { CCI_REG8(0x592d), 0x32 }, + { CCI_REG8(0x592e), 0x00 }, + { CCI_REG8(0x592f), 0x88 }, + { CCI_REG8(0x5930), 0x00 }, + { CCI_REG8(0x5931), 0x3d }, + { CCI_REG8(0x5932), 0x00 }, + { CCI_REG8(0x5933), 0x93 }, + { CCI_REG8(0x5938), 0x00 }, + { CCI_REG8(0x5939), 0x24 }, + { CCI_REG8(0x593a), 0x00 }, + { CCI_REG8(0x593b), 0x7a }, + { CCI_REG8(0x593c), 0x00 }, + { CCI_REG8(0x593d), 0x24 }, + { CCI_REG8(0x593e), 0x00 }, + { CCI_REG8(0x593f), 0x7a }, + { CCI_REG8(0x5940), 0x00 }, + { CCI_REG8(0x5941), 0x2f }, + { CCI_REG8(0x5942), 0x00 }, + { CCI_REG8(0x5943), 0x85 }, + { CCI_REG8(0x5f0e), 0x6e }, + { CCI_REG8(0x5f11), 0xc6 }, + { CCI_REG8(0x5f17), 0x5e }, + { CCI_REG8(0x7990), 0x01 }, + { CCI_REG8(0x7993), 0x5d }, + { CCI_REG8(0x7994), 0x5d }, + { CCI_REG8(0x7995), 0xa1 }, + { CCI_REG8(0x799a), 0x01 }, + { CCI_REG8(0x799d), 0x00 }, + { CCI_REG8(0x8169), 0x01 }, + { CCI_REG8(0x8359), 0x01 }, + { CCI_REG8(0x9302), 0x1e }, + { CCI_REG8(0x9306), 0x1f }, + { CCI_REG8(0x930a), 0x26 }, + { CCI_REG8(0x930e), 0x23 }, + { CCI_REG8(0x9312), 0x23 }, + { CCI_REG8(0x9316), 0x2c }, + { CCI_REG8(0x9317), 0x19 }, + { CCI_REG8(0xb046), 0x01 }, + { CCI_REG8(0xb048), 0x01 }, +}; + +static const struct cci_reg_sequence mode_1928x1088_regs[] = { + { IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 }, + { IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE }, + { IMX471_REG_X_ADD_STA, 8 }, + { IMX471_REG_Y_ADD_STA, 408 }, + { IMX471_REG_X_ADD_END, 4647 }, + { IMX471_REG_Y_ADD_END, 3051 }, + { IMX471_REG_X_EVEN_INC, 1 }, + { IMX471_REG_X_ODD_INC, 1 }, + { IMX471_REG_Y_EVEN_INC, 1 }, + { IMX471_REG_Y_ODD_INC, 1 }, + { IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE }, + { IMX471_REG_BINNING_TYPE, 0x22 }, + { IMX471_REG_BINNING_WEIGHTING, 0x08 }, + { IMX471_REG_DIG_CROP_X_OFFSET, 208 }, + { IMX471_REG_DIG_CROP_Y_OFFSET, 108 }, + { IMX471_REG_DIG_CROP_WIDTH, 1928 }, + { IMX471_REG_DIG_CROP_HEIGHT, 1088 }, + { IMX471_REG_X_OUTPUT_SIZE, 1928 }, + { IMX471_REG_Y_OUTPUT_SIZE, 1088 }, + { IMX471_REG_VTPXCK_DIV, 0x06 }, + { IMX471_REG_VTSYCK_DIV, 0x02 }, + { IMX471_REG_PREPLLCK_VT_DIV, 0x02 }, + { IMX471_REG_PLL_VT_MPY, 0x0079 }, + { IMX471_REG_OPSYCK_DIV, 0x01 }, + { CCI_REG8(0x030d), 0x02 }, + { CCI_REG8(0x030e), 0x00 }, + { CCI_REG8(0x030f), 0x53 }, + { IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL }, + { CCI_REG8(0x3f4c), 0x81 }, + { CCI_REG8(0x3f4d), 0x81 }, + { CCI_REG8(0x3f78), 0x01 }, + { CCI_REG8(0x3f79), 0x31 }, + { CCI_REG8(0x3ffe), 0x00 }, + { CCI_REG8(0x3fff), 0x8a }, + { CCI_REG8(0x5f0a), 0xb6 }, +}; + +static const char * const imx471_test_pattern_menu[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + +static const s64 link_freq_menu_items[] = { + IMX471_LINK_FREQ_DEFAULT, +}; + +/* + * The Bayer formats for the flipping. + * - no flip + * - h flip + * - v flip + * - h and v flips + */ +static const u32 imx471_hv_flips_bayer_order[] = { + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, +}; + +static const struct imx471_mode imx471_modes[] = { + { + .width = 1928, + .height = 1088, + .fll_def = 1308, + .fll_min = 1308, + .llp = 2328, + .default_mode_regs = mode_1928x1088_regs, + .default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs), + }, +}; + +static int imx471_get_regulators(struct device *dev, struct imx471 *sensor) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++) + sensor->supplies[i].supply = imx471_supply_name[i]; + + return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name), + sensor->supplies); +} + +static int imx471_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx471 *sensor = container_of_const(ctrl->handler, + struct imx471, + ctrl_handler); + struct v4l2_subdev_state *state = + v4l2_subdev_get_locked_active_state(&sensor->sd); + const struct v4l2_mbus_framefmt *format = + v4l2_subdev_state_get_format(state, 0); + int ret; + + if (ctrl->id == V4L2_CID_VBLANK) { + s64 exposure_max = format->height + ctrl->val - + IMX471_EXPOSURE_MARGIN; + ret = __v4l2_ctrl_modify_range(sensor->exposure, + sensor->exposure->minimum, + exposure_max, + sensor->exposure->step, + exposure_max); + if (ret) + return ret; + } + + if (!pm_runtime_get_if_in_use(sensor->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE, + ctrl->val, NULL); + break; + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + ret = cci_write(sensor->regmap, IMX471_REG_FLL, + format->height + ctrl->val, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN, + ctrl->val, NULL); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION, + sensor->hflip->val | sensor->vflip->val << 1, + NULL); + break; + default: + ret = -EINVAL; + dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(sensor->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx471_ctrl_ops = { + .s_ctrl = imx471_set_ctrl, +}; + +static u32 imx471_get_format_code(struct imx471 *sensor) +{ + unsigned int i; + + i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0); + + return imx471_hv_flips_bayer_order[i]; +} + +static int imx471_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx471 *sensor = to_imx471(sd); + + if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4)) + return -EINVAL; + + code->code = imx471_get_format_code(sensor); + + return 0; +} + +static int imx471_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(imx471_modes)) + return -EINVAL; + + fse->min_width = imx471_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = imx471_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static void imx471_update_pad_format(struct imx471 *sensor, + const struct imx471_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.code = imx471_get_format_code(sensor); + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; +} + +static int imx471_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx471 *sensor = to_imx471(sd); + const struct imx471_mode *mode; + int h_blank, ret; + + mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), + width, height, fmt->format.width, + fmt->format.height); + + imx471_update_pad_format(sensor, mode, fmt); + + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + if (media_entity_is_streaming(&sensor->sd.entity)) + return -EBUSY; + + ret = __v4l2_ctrl_modify_range(sensor->vblank, + mode->fll_min - mode->height, + IMX471_FLL_MAX - mode->height, + 1, + mode->fll_def - mode->height); + if (ret) + return ret; + + h_blank = mode->llp - mode->width; + /* + * Currently hblank is not changeable. + * So FPS control is done only by vblank. + */ + return __v4l2_ctrl_modify_range(sensor->hblank, h_blank, + h_blank, 1, h_blank); +} + +static int imx471_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); + break; + + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = IMX471_NATIVE_WIDTH; + sel->r.height = IMX471_NATIVE_HEIGHT; + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX471_PIXEL_ARRAY_TOP; + sel->r.left = IMX471_PIXEL_ARRAY_LEFT; + sel->r.width = IMX471_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT; + return 0; + } + + return -EINVAL; +} + +static int imx471_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = imx471_modes[0].width, + .height = imx471_modes[0].height, + }, + }; + + return imx471_set_pad_format(sd, sd_state, &fmt); +} + +static int imx471_identify_module(struct imx471 *sensor) +{ + int ret; + u64 val; + + ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to read chip id\n"); + + if (val != IMX471_CHIP_ID) + return dev_err_probe(sensor->dev, -EIO, + "chip id mismatch: %x!=%llx\n", + IMX471_CHIP_ID, val); + + return 0; +} + +static int imx471_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx471 *sensor = to_imx471(sd); + + clk_disable_unprepare(sensor->img_clk); + gpiod_set_value_cansleep(sensor->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + + return 0; +} + +static int imx471_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx471 *sensor = to_imx471(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(sensor->img_clk); + if (ret < 0) { + regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + dev_err(dev, "failed to enable imaging clock: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(sensor->reset_gpio, 0); + + usleep_range(10000, 15000); + + return 0; +} + +static int imx471_enable_stream(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct imx471 *sensor = to_imx471(sd); + const struct imx471_mode *mode; + struct v4l2_mbus_framefmt *fmt; + int ret; + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret) + return ret; + + ret = imx471_identify_module(sensor); + if (ret) + goto error_powerdown; + + ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs, + ARRAY_SIZE(imx471_global_regs), NULL); + if (ret) { + dev_err(sensor->dev, "failed to set global settings: %d\n", + ret); + goto error_powerdown; + } + + fmt = v4l2_subdev_state_get_format(state, 0); + mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), + width, height, fmt->width, fmt->height); + + ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs, + mode->default_mode_regs_length, NULL); + if (ret) { + dev_err(sensor->dev, "failed to set mode: %d\n", ret); + goto error_powerdown; + } + + ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1, + NULL); + if (ret) + goto error_powerdown; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); + if (ret) + goto error_powerdown; + + ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, + IMX471_MODE_STREAMING, NULL); + if (ret) + goto error_powerdown; + + __v4l2_ctrl_grab(sensor->vflip, true); + __v4l2_ctrl_grab(sensor->hflip, true); + + return ret; + +error_powerdown: + pm_runtime_put(sensor->dev); + + return ret; +} + +static int imx471_disable_stream(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct imx471 *sensor = to_imx471(sd); + int ret; + + ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, + IMX471_MODE_STANDBY, NULL); + pm_runtime_put(sensor->dev); + + if (ret) + dev_err(sensor->dev, + "failed to disable stream with return value: %d\n", + ret); + + __v4l2_ctrl_grab(sensor->vflip, false); + __v4l2_ctrl_grab(sensor->hflip, false); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx471_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops imx471_pad_ops = { + .enum_mbus_code = imx471_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = imx471_set_pad_format, + .get_selection = imx471_get_selection, + .enum_frame_size = imx471_enum_frame_size, + .enable_streams = imx471_enable_stream, + .disable_streams = imx471_disable_stream, +}; + +static const struct v4l2_subdev_ops imx471_subdev_ops = { + .video = &imx471_video_ops, + .pad = &imx471_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops imx471_internal_ops = { + .init_state = imx471_init_state, +}; + +static int imx471_init_controls(struct imx471 *sensor) +{ + const struct imx471_mode *mode = &imx471_modes[0]; + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_ctrl *link_freq; + s64 exposure_max, hblank; + u64 pixel_rate; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret) { + dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret); + return ret; + } + + ctrl_hdlr = &sensor->ctrl_handler; + v4l2_ctrl_handler_init(ctrl_hdlr, 12); + + v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props); + + link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx471_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, + link_freq_menu_items); + + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr, + &imx471_ctrl_ops, + V4L2_CID_VBLANK, + mode->fll_min - mode->height, + IMX471_FLL_MAX - mode->height, + 1, + mode->fll_def - mode->height); + + hblank = mode->llp - mode->width; + sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + + /* fll >= exposure time + adjust parameter (default value is 18) */ + exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN; + sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX471_EXPOSURE_MIN, exposure_max, + IMX471_EXPOSURE_STEP, + IMX471_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX, + IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX, + IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx471_test_pattern_menu) - 1, + 0, 0, imx471_test_pattern_menu); + + sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (ctrl_hdlr->error) { + dev_err(sensor->dev, "%s control init failed: %d\n", + __func__, ctrl_hdlr->error); + goto error; + } + + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + sensor->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ctrl_hdlr->error; +} + +static int imx471_check_hwcfg(struct imx471 *sensor) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev); + unsigned long link_freq_bitmap; + struct clk *clk; + int ret; + + clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(sensor->dev, PTR_ERR(clk), + "can't get clock frequency\n"); + + if (clk_get_rate(clk) != IMX471_EXT_CLK) + return dev_err_probe(sensor->dev, -EINVAL, + "external clock %lu is not supported\n", + clk_get_rate(clk)); + + ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0); + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return dev_err_probe(sensor->dev, ret, + "parsing endpoint failed\n"); + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "number of CSI2 data lanes %u is not supported\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + goto done_endpoint_free; + } + + ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int imx471_probe(struct i2c_client *client) +{ + struct imx471 *sensor; + int ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return dev_err_probe(&client->dev, -ENOMEM, + "failed to allocate memory\n"); + + sensor->dev = &client->dev; + + ret = imx471_check_hwcfg(sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to check hwcfg: %d\n", ret); + + ret = imx471_get_regulators(sensor->dev, sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get regulators\n"); + + sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset_gpio)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio), + "failed to get reset gpio\n"); + + sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); + if (IS_ERR(sensor->img_clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk), + "failed to get imaging clock\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops); + + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap), + "failed to initialize CCI\n"); + + ret = imx471_power_on(sensor->dev); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to power on\n"); + + ret = imx471_identify_module(sensor); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n", + ret); + goto error_power_off; + } + + ret = imx471_init_controls(sensor); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n", + ret); + goto error_power_off; + } + + sensor->sd.internal_ops = &imx471_internal_ops; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) { + dev_err_probe(sensor->dev, ret, + "failed to init entity pads: %d\n", ret); + goto error_v4l2_ctrl_handler_free; + } + + sensor->sd.state_lock = sensor->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret < 0) { + dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n", + ret); + goto error_media_entity_pm; + } + + pm_runtime_set_active(sensor->dev); + pm_runtime_enable(sensor->dev); + + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret < 0) + goto error_v4l2_subdev_cleanup; + + pm_runtime_idle(sensor->dev); + + return 0; + +error_v4l2_subdev_cleanup: + pm_runtime_disable(sensor->dev); + pm_runtime_set_suspended(sensor->dev); + v4l2_subdev_cleanup(&sensor->sd); + +error_media_entity_pm: + media_entity_cleanup(&sensor->sd.entity); + +error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); + +error_power_off: + imx471_power_off(sensor->dev); + + return ret; +} + +static void imx471_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(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)) { + imx471_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off, + imx471_power_on, NULL); + +static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = { + { "SONY471A" }, + { "TBE20A0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids); + +static struct i2c_driver imx471_i2c_driver = { + .driver = { + .name = "imx471", + .acpi_match_table = ACPI_PTR(imx471_acpi_ids), + .pm = pm_sleep_ptr(&imx471_pm_ops), + }, + .probe = imx471_probe, + .remove = imx471_remove, +}; +module_i2c_driver(imx471_i2c_driver); + +MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>"); +MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>"); +MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>"); +MODULE_DESCRIPTION("Sony imx471 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx678.c b/drivers/media/i2c/imx678.c new file mode 100644 index 000000000000..0efbf43d2fe6 --- /dev/null +++ b/drivers/media/i2c/imx678.c @@ -0,0 +1,1447 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 driver for Sony IMX678 + * + * Diagonal 8.86 mm (Type 1/1.8) CMOS image sensor with 8.40 M effective pixels. + * + * Copyright (C) 2026 Ideas On Board Oy. + * + * Based on Sony IMX678 driver prepared by Will Whang & Soho Enterprise Ltd. + */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-rect.h> +#include <media/v4l2-subdev.h> + +/* Standby or streaming mode */ +#define IMX678_REG_MODE_SELECT CCI_REG8(0x3000) +#define IMX678_MODE_STANDBY 0x01 +#define IMX678_MODE_STREAMING 0x00 +#define IMX678_STREAM_DELAY_US 25000 +#define IMX678_STREAM_DELAY_RANGE_US 1000 + +/* XVS/XHS sync control */ +#define IMX678_REG_XMSTA CCI_REG8(0x3002) +#define IMX678_REG_XXS_DRV CCI_REG8(0x30a6) +#define IMX678_REG_XXS_OUTSEL CCI_REG8(0x30a4) + +/* Clk selection */ +#define IMX678_REG_INCK_SEL CCI_REG8(0x3014) + +/* Link Speed */ +#define IMX678_REG_DATARATE_SEL CCI_REG8(0x3015) + +/* Lane Count */ +#define IMX678_REG_LANEMODE CCI_REG8(0x3040) + +/* + * The internal readout clock runs at 74.25 MHz. In one cycle the AD reads 8 + * pixels, thus giving us a rate of 74.25 * 8 = 594 MPix/s + */ +#define IMX678_PIXEL_RATE 594000000 +#define IMX678_PIX_PER_CLK 8 + +/* VMAX - Frame Length in Lines */ +#define IMX678_REG_VMAX CCI_REG24_LE(0x3028) +#define IMX678_VMAX_MAX 0xfffff +#define IMX678_VMAX_DEFAULT 2250 + +/* HMAX - Line Length in Cycles (8 Pixels) */ +#define IMX678_REG_HMAX CCI_REG16_LE(0x302c) +#define IMX678_HMAX_MAX 0xffff + +/* SHR internal */ +#define IMX678_REG_SHR CCI_REG24_LE(0x3050) +#define IMX678_SHR_MIN 8 + +/* Exposure control */ +#define IMX678_EXPOSURE_MIN 2 +#define IMX678_EXPOSURE_STEP 1 +#define IMX678_EXPOSURE_DEFAULT 1000 + +/* + * Analogue gain control + * Range is from 0 to 100 (0dB - 30dB) with 0.3dB step size + * Values from 101 to 240 are valid but correspond to additional digital gain + * (0.3dB - 42dB) so don't expose it to userspace + */ +#define IMX678_REG_GAIN CCI_REG16_LE(0x3070) +#define IMX678_ANA_GAIN_MIN_NORMAL 0 +#define IMX678_ANA_GAIN_MAX_NORMAL 100 +#define IMX678_ANA_GAIN_STEP 1 +#define IMX678_ANA_GAIN_DEFAULT 0 + +/* Crop */ +#define IMX678_REG_WINMODE CCI_REG8(0x3018) +#define IMX678_REG_PIX_HST CCI_REG16_LE(0x303c) +#define IMX678_REG_PIX_HWIDTH CCI_REG16_LE(0x303e) +#define IMX678_REG_PIX_VST CCI_REG16_LE(0x3044) +#define IMX678_REG_PIX_VWIDTH CCI_REG16_LE(0x3046) + +/* Flip */ +#define IMX678_REG_WINMODEH CCI_REG8(0x3020) +#define IMX678_REG_WINMODEV CCI_REG8(0x3021) + +/* Sensor Identification */ +#define IMX678_REG_MONOCHROME CCI_REG8(0x4d18) +#define IMX678_TYPE BIT(0) +#define IMX678_REG_MODULE_ID CCI_REG16_LE(0x4d1c) +#define IMX678_ID 0x02a6 +#define IMX678_MODULE_ID_DELAY 80000 + +/* Common configuration registers */ +#define IMX678_REG_WDMODE CCI_REG8(0x301a) +#define IMX678_REG_ADDMODE CCI_REG8(0x301b) +#define IMX678_REG_THIN_V_EN CCI_REG8(0x301c) +#define IMX678_REG_VCMODE CCI_REG8(0x301e) +#define IMX678_REG_ADBIT CCI_REG8(0x3022) +#define IMX678_REG_MDBIT CCI_REG8(0x3023) +#define IMX678_REG_GAIN_PGC_FIDMD CCI_REG8(0x3400) + +/* Test pattern generator */ +#define IMX678_REG_TPG_EN_DUOUT CCI_REG8(0x30e0) +#define IMX678_REG_TPG_PATSEL_DUOUT CCI_REG8(0x30e2) +#define IMX678_TPG_ALL_000 0 +#define IMX678_TPG_ALL_FFF 1 +#define IMX678_TPG_ALL_555 2 +#define IMX678_TPG_ALL_AAA 3 +#define IMX678_TPG_TOG_555_AAA 4 +#define IMX678_TPG_TOG_AAA_555 5 +#define IMX678_TPG_TOG_000_555 6 +#define IMX678_TPG_TOG_555_000 7 +#define IMX678_TPG_TOG_000_FFF 8 +#define IMX678_TPG_TOG_FFF_000 9 +#define IMX678_TPG_H_COLOR_BARS 10 +#define IMX678_TPG_V_COLOR_BARS 11 +#define IMX678_REG_TPG_COLORWIDTH CCI_REG8(0x30e4) +#define IMX678_TPG_COLORWIDTH_80PIX 0 +#define IMX678_TPG_COLORWIDTH_160PIX 1 +#define IMX678_TPG_COLORWIDTH_320PIX 2 +#define IMX678_TPG_COLORWIDTH_640PIX 3 + +#define IMX678_REG_INTERFACE_SEL CCI_REG8(0x4e3c) +#define IMX678_INTERFACE_2L_4L 0x07 +#define IMX678_INTERFACE_8L_2x4L 0x7f + +/* Minimum output resolution */ +#define IMX678_PIXEL_ARRAY_MIN_WIDTH 1040 +#define IMX678_PIXEL_ARRAY_MIN_HEIGHT 956 + +/* Sensor windowing register alignment */ +#define IMX678_CROP_HWIDTH_ALIGN 16 +#define IMX678_CROP_VWIDTH_ALIGN 4 +#define IMX678_CROP_HST_ALIGN 4 +#define IMX678_CROP_VST_ALIGN 4 + +/* Subdev pads */ +#define IMX678_SOURCE_PAD 0 + +/* IMX678 native and active pixel array size. */ +static const struct v4l2_rect imx678_native_area = { + .top = 0, + .left = 0, + .width = 3857, + .height = 2201, +}; + +static const struct v4l2_rect imx678_active_area = { + .top = 20, + .left = 0, + .width = 3856, + .height = 2180, +}; + +enum imx678_type { + IMX678_COLOR = 0, + IMX678_MONOCHROME = 1, +}; + +struct imx678_model_info { + enum imx678_type type; + const u32 *codes; + unsigned int num_codes; +}; + +enum imx678_lanemode { + IMX678_LANEMODE_2L = 1, + IMX678_LANEMODE_4L = 3, +}; + +/* Link frequency setup (DDR: lane rate = 2 x link freq) */ +enum { + IMX678_LINK_FREQ_297MHZ, + IMX678_LINK_FREQ_360MHZ, + IMX678_LINK_FREQ_445MHZ, + IMX678_LINK_FREQ_594MHZ, + IMX678_LINK_FREQ_720MHZ, + IMX678_LINK_FREQ_891MHZ, + IMX678_LINK_FREQ_1039MHZ, + IMX678_LINK_FREQ_1188MHZ, +}; + +static const u8 link_freqs_reg_value[] = { + [IMX678_LINK_FREQ_297MHZ] = 0x07, + [IMX678_LINK_FREQ_360MHZ] = 0x06, + [IMX678_LINK_FREQ_445MHZ] = 0x05, + [IMX678_LINK_FREQ_594MHZ] = 0x04, + [IMX678_LINK_FREQ_720MHZ] = 0x03, + [IMX678_LINK_FREQ_891MHZ] = 0x02, + [IMX678_LINK_FREQ_1039MHZ] = 0x01, + [IMX678_LINK_FREQ_1188MHZ] = 0x00, +}; + +static const u64 link_freqs[] = { + [IMX678_LINK_FREQ_297MHZ] = 297000000, + [IMX678_LINK_FREQ_360MHZ] = 360000000, + [IMX678_LINK_FREQ_445MHZ] = 445500000, + [IMX678_LINK_FREQ_594MHZ] = 594000000, + [IMX678_LINK_FREQ_720MHZ] = 720000000, + [IMX678_LINK_FREQ_891MHZ] = 891000000, + [IMX678_LINK_FREQ_1039MHZ] = 1039500000, + [IMX678_LINK_FREQ_1188MHZ] = 1188000000, +}; + +static const u16 min_hmax_4lane[] = { + [IMX678_LINK_FREQ_297MHZ] = 1584, + [IMX678_LINK_FREQ_360MHZ] = 1320, + [IMX678_LINK_FREQ_445MHZ] = 1100, + [IMX678_LINK_FREQ_594MHZ] = 792, + [IMX678_LINK_FREQ_720MHZ] = 660, + [IMX678_LINK_FREQ_891MHZ] = 550, + [IMX678_LINK_FREQ_1039MHZ] = 550, + [IMX678_LINK_FREQ_1188MHZ] = 550, +}; + +struct imx678_inck_cfg { + u32 xclk_hz; /* platform clock rate */ + u8 inck_sel; /* value for reg */ +}; + +static const struct imx678_inck_cfg imx678_inck_table[] = { + { 74250000, 0x00 }, + { 37125000, 0x01 }, + { 72000000, 0x02 }, + { 27000000, 0x03 }, + { 24000000, 0x04 }, + { 36000000, 0x05 }, + { 18000000, 0x06 }, + { 13500000, 0x07 }, +}; + +static const char * const imx678_tpg_menu[] = { + "Disabled", + "All 000h", + "All FFFh", + "All 555h", + "All AAAh", + "Toggle 555/AAAh", + "Toggle AAA/555h", + "Toggle 000/555h", + "Toggle 555/000h", + "Toggle 000/FFFh", + "Toggle FFF/000h", + "Horizontal color bars", + "Vertical color bars", +}; + +static const int imx678_tpg_val[] = { + IMX678_TPG_ALL_000, + IMX678_TPG_ALL_000, + IMX678_TPG_ALL_FFF, + IMX678_TPG_ALL_555, + IMX678_TPG_ALL_AAA, + IMX678_TPG_TOG_555_AAA, + IMX678_TPG_TOG_AAA_555, + IMX678_TPG_TOG_000_555, + IMX678_TPG_TOG_555_000, + IMX678_TPG_TOG_000_FFF, + IMX678_TPG_TOG_FFF_000, + IMX678_TPG_H_COLOR_BARS, + IMX678_TPG_V_COLOR_BARS, +}; + +/* Common configuration */ +static const struct cci_reg_sequence common_regs[] = { + { IMX678_REG_THIN_V_EN, 0x00 }, + { IMX678_REG_VCMODE, 0x01 }, + { CCI_REG8(0x306b), 0x00 }, + { IMX678_REG_GAIN_PGC_FIDMD, 0x01 }, + { CCI_REG8(0x3460), 0x22 }, + { CCI_REG8(0x355a), 0x64 }, + { CCI_REG8(0x3a02), 0x7a }, + { CCI_REG8(0x3a10), 0xec }, + { CCI_REG8(0x3a12), 0x71 }, + { CCI_REG8(0x3a14), 0xde }, + { CCI_REG8(0x3a20), 0x2b }, + { CCI_REG8(0x3a24), 0x22 }, + { CCI_REG8(0x3a25), 0x25 }, + { CCI_REG8(0x3a26), 0x2a }, + { CCI_REG8(0x3a27), 0x2c }, + { CCI_REG8(0x3a28), 0x39 }, + { CCI_REG8(0x3a29), 0x38 }, + { CCI_REG8(0x3a30), 0x04 }, + { CCI_REG8(0x3a31), 0x04 }, + { CCI_REG8(0x3a32), 0x03 }, + { CCI_REG8(0x3a33), 0x03 }, + { CCI_REG8(0x3a34), 0x09 }, + { CCI_REG8(0x3a35), 0x06 }, + { CCI_REG8(0x3a38), 0xcd }, + { CCI_REG8(0x3a3a), 0x4c }, + { CCI_REG8(0x3a3c), 0xb9 }, + { CCI_REG8(0x3a3e), 0x30 }, + { CCI_REG8(0x3a40), 0x2c }, + { CCI_REG8(0x3a42), 0x39 }, + { CCI_REG8(0x3a4e), 0x00 }, + { CCI_REG8(0x3a52), 0x00 }, + { CCI_REG8(0x3a56), 0x00 }, + { CCI_REG8(0x3a5a), 0x00 }, + { CCI_REG8(0x3a5e), 0x00 }, + { CCI_REG8(0x3a62), 0x00 }, + { CCI_REG8(0x3a64), 0x00 }, + { CCI_REG8(0x3a6e), 0xa0 }, + { CCI_REG8(0x3a70), 0x50 }, + { CCI_REG8(0x3a8c), 0x04 }, + { CCI_REG8(0x3a8d), 0x03 }, + { CCI_REG8(0x3a8e), 0x09 }, + { CCI_REG8(0x3a90), 0x38 }, + { CCI_REG8(0x3a91), 0x42 }, + { CCI_REG8(0x3a92), 0x3c }, + { CCI_REG8(0x3b0e), 0xf3 }, + { CCI_REG8(0x3b12), 0xe5 }, + { CCI_REG8(0x3b27), 0xc0 }, + { CCI_REG8(0x3b2e), 0xef }, + { CCI_REG8(0x3b30), 0x6a }, + { CCI_REG8(0x3b32), 0xf6 }, + { CCI_REG8(0x3b36), 0xe1 }, + { CCI_REG8(0x3b3a), 0xe8 }, + { CCI_REG8(0x3b5a), 0x17 }, + { CCI_REG8(0x3b5e), 0xef }, + { CCI_REG8(0x3b60), 0x6a }, + { CCI_REG8(0x3b62), 0xf6 }, + { CCI_REG8(0x3b66), 0xe1 }, + { CCI_REG8(0x3b6a), 0xe8 }, + { CCI_REG8(0x3b88), 0xec }, + { CCI_REG8(0x3b8a), 0xed }, + { CCI_REG8(0x3b94), 0x71 }, + { CCI_REG8(0x3b96), 0x72 }, + { CCI_REG8(0x3b98), 0xde }, + { CCI_REG8(0x3b9a), 0xdf }, + { CCI_REG8(0x3c0f), 0x06 }, + { CCI_REG8(0x3c10), 0x06 }, + { CCI_REG8(0x3c11), 0x06 }, + { CCI_REG8(0x3c12), 0x06 }, + { CCI_REG8(0x3c13), 0x06 }, + { CCI_REG8(0x3c18), 0x20 }, + { CCI_REG8(0x3c37), 0x10 }, + { CCI_REG8(0x3c3a), 0x7a }, + { CCI_REG8(0x3c40), 0xf4 }, + { CCI_REG8(0x3c48), 0xe6 }, + { CCI_REG8(0x3c54), 0xce }, + { CCI_REG8(0x3c56), 0xd0 }, + { CCI_REG8(0x3c6c), 0x53 }, + { CCI_REG8(0x3c6e), 0x55 }, + { CCI_REG8(0x3c70), 0xc0 }, + { CCI_REG8(0x3c72), 0xc2 }, + { CCI_REG8(0x3c7e), 0xce }, + { CCI_REG8(0x3c8c), 0xcf }, + { CCI_REG8(0x3c8e), 0xeb }, + { CCI_REG8(0x3c98), 0x54 }, + { CCI_REG8(0x3c9a), 0x70 }, + { CCI_REG8(0x3c9c), 0xc1 }, + { CCI_REG8(0x3c9e), 0xdd }, + { CCI_REG8(0x3cb0), 0x7a }, + { CCI_REG8(0x3cb2), 0xba }, + { CCI_REG8(0x3cc8), 0xbc }, + { CCI_REG8(0x3cca), 0x7c }, + { CCI_REG8(0x3cd4), 0xea }, + { CCI_REG8(0x3cd5), 0x01 }, + { CCI_REG8(0x3cd6), 0x4a }, + { CCI_REG8(0x3cd8), 0x00 }, + { CCI_REG8(0x3cd9), 0x00 }, + { CCI_REG8(0x3cda), 0xff }, + { CCI_REG8(0x3cdb), 0x03 }, + { CCI_REG8(0x3cdc), 0x00 }, + { CCI_REG8(0x3cdd), 0x00 }, + { CCI_REG8(0x3cde), 0xff }, + { CCI_REG8(0x3cdf), 0x03 }, + { CCI_REG8(0x3ce4), 0x4c }, + { CCI_REG8(0x3ce6), 0xec }, + { CCI_REG8(0x3ce7), 0x01 }, + { CCI_REG8(0x3ce8), 0xff }, + { CCI_REG8(0x3ce9), 0x03 }, + { CCI_REG8(0x3cea), 0x00 }, + { CCI_REG8(0x3ceb), 0x00 }, + { CCI_REG8(0x3cec), 0xff }, + { CCI_REG8(0x3ced), 0x03 }, + { CCI_REG8(0x3cee), 0x00 }, + { CCI_REG8(0x3cef), 0x00 }, + { CCI_REG8(0x3cf2), 0xff }, + { CCI_REG8(0x3cf3), 0x03 }, + { CCI_REG8(0x3cf4), 0x00 }, + { CCI_REG8(0x3e28), 0x82 }, + { CCI_REG8(0x3e2a), 0x80 }, + { CCI_REG8(0x3e30), 0x85 }, + { CCI_REG8(0x3e32), 0x7d }, + { CCI_REG8(0x3e5c), 0xce }, + { CCI_REG8(0x3e5e), 0xd3 }, + { CCI_REG8(0x3e70), 0x53 }, + { CCI_REG8(0x3e72), 0x58 }, + { CCI_REG8(0x3e74), 0xc0 }, + { CCI_REG8(0x3e76), 0xc5 }, + { CCI_REG8(0x3e78), 0xc0 }, + { CCI_REG8(0x3e79), 0x01 }, + { CCI_REG8(0x3e7a), 0xd4 }, + { CCI_REG8(0x3e7b), 0x01 }, + { CCI_REG8(0x3eb4), 0x0b }, + { CCI_REG8(0x3eb5), 0x02 }, + { CCI_REG8(0x3eb6), 0x4d }, + { CCI_REG8(0x3eb7), 0x42 }, + { CCI_REG8(0x3eec), 0xf3 }, + { CCI_REG8(0x3eee), 0xe7 }, + { CCI_REG8(0x3f01), 0x01 }, + { CCI_REG8(0x3f24), 0x10 }, + { CCI_REG8(0x3f28), 0x2d }, + { CCI_REG8(0x3f2a), 0x2d }, + { CCI_REG8(0x3f2c), 0x2d }, + { CCI_REG8(0x3f2e), 0x2d }, + { CCI_REG8(0x3f30), 0x23 }, + { CCI_REG8(0x3f38), 0x2d }, + { CCI_REG8(0x3f3a), 0x2d }, + { CCI_REG8(0x3f3c), 0x2d }, + { CCI_REG8(0x3f3e), 0x28 }, + { CCI_REG8(0x3f40), 0x1e }, + { CCI_REG8(0x3f48), 0x2d }, + { CCI_REG8(0x3f4a), 0x2d }, + { CCI_REG8(0x3f4c), 0x00 }, + { CCI_REG8(0x4004), 0xe4 }, + { CCI_REG8(0x4006), 0xff }, + { CCI_REG8(0x4018), 0x69 }, + { CCI_REG8(0x401a), 0x84 }, + { CCI_REG8(0x401c), 0xd6 }, + { CCI_REG8(0x401e), 0xf1 }, + { CCI_REG8(0x4038), 0xde }, + { CCI_REG8(0x403a), 0x00 }, + { CCI_REG8(0x403b), 0x01 }, + { CCI_REG8(0x404c), 0x63 }, + { CCI_REG8(0x404e), 0x85 }, + { CCI_REG8(0x4050), 0xd0 }, + { CCI_REG8(0x4052), 0xf2 }, + { CCI_REG8(0x4108), 0xdd }, + { CCI_REG8(0x410a), 0xf7 }, + { CCI_REG8(0x411c), 0x62 }, + { CCI_REG8(0x411e), 0x7c }, + { CCI_REG8(0x4120), 0xcf }, + { CCI_REG8(0x4122), 0xe9 }, + { CCI_REG8(0x4138), 0xe6 }, + { CCI_REG8(0x413a), 0xf1 }, + { CCI_REG8(0x414c), 0x6b }, + { CCI_REG8(0x414e), 0x76 }, + { CCI_REG8(0x4150), 0xd8 }, + { CCI_REG8(0x4152), 0xe3 }, + { CCI_REG8(0x417e), 0x03 }, + { CCI_REG8(0x417f), 0x01 }, + { CCI_REG8(0x4186), 0xe0 }, + { CCI_REG8(0x4190), 0xf3 }, + { CCI_REG8(0x4192), 0xf7 }, + { CCI_REG8(0x419c), 0x78 }, + { CCI_REG8(0x419e), 0x7c }, + { CCI_REG8(0x41a0), 0xe5 }, + { CCI_REG8(0x41a2), 0xe9 }, + { CCI_REG8(0x41c8), 0xe2 }, + { CCI_REG8(0x41ca), 0xfd }, + { CCI_REG8(0x41dc), 0x67 }, + { CCI_REG8(0x41de), 0x82 }, + { CCI_REG8(0x41e0), 0xd4 }, + { CCI_REG8(0x41e2), 0xef }, + { CCI_REG8(0x4200), 0xde }, + { CCI_REG8(0x4202), 0xda }, + { CCI_REG8(0x4218), 0x63 }, + { CCI_REG8(0x421a), 0x5f }, + { CCI_REG8(0x421c), 0xd0 }, + { CCI_REG8(0x421e), 0xcc }, + { CCI_REG8(0x425a), 0x82 }, + { CCI_REG8(0x425c), 0xef }, + { CCI_REG8(0x4348), 0xfe }, + { CCI_REG8(0x4349), 0x06 }, + { CCI_REG8(0x4352), 0xce }, + { CCI_REG8(0x4420), 0x0b }, + { CCI_REG8(0x4421), 0x02 }, + { CCI_REG8(0x4422), 0x4d }, + { CCI_REG8(0x4423), 0x0a }, + { CCI_REG8(0x4426), 0xf5 }, + { CCI_REG8(0x442a), 0xe7 }, + { CCI_REG8(0x4432), 0xf5 }, + { CCI_REG8(0x4436), 0xe7 }, + { CCI_REG8(0x4466), 0xb4 }, + { CCI_REG8(0x446e), 0x32 }, + { CCI_REG8(0x449f), 0x1c }, + { CCI_REG8(0x44a4), 0x2c }, + { CCI_REG8(0x44a6), 0x2c }, + { CCI_REG8(0x44a8), 0x2c }, + { CCI_REG8(0x44aa), 0x2c }, + { CCI_REG8(0x44b4), 0x2c }, + { CCI_REG8(0x44b6), 0x2c }, + { CCI_REG8(0x44b8), 0x2c }, + { CCI_REG8(0x44ba), 0x2c }, + { CCI_REG8(0x44c4), 0x2c }, + { CCI_REG8(0x44c6), 0x2c }, + { CCI_REG8(0x44c8), 0x2c }, + { CCI_REG8(0x4506), 0xf3 }, + { CCI_REG8(0x450e), 0xe5 }, + { CCI_REG8(0x4516), 0xf3 }, + { CCI_REG8(0x4522), 0xe5 }, + { CCI_REG8(0x4524), 0xf3 }, + { CCI_REG8(0x452c), 0xe5 }, + { CCI_REG8(0x453c), 0x22 }, + { CCI_REG8(0x453d), 0x1b }, + { CCI_REG8(0x453e), 0x1b }, + { CCI_REG8(0x453f), 0x15 }, + { CCI_REG8(0x4540), 0x15 }, + { CCI_REG8(0x4541), 0x15 }, + { CCI_REG8(0x4542), 0x15 }, + { CCI_REG8(0x4543), 0x15 }, + { CCI_REG8(0x4544), 0x15 }, + { CCI_REG8(0x4548), 0x00 }, + { CCI_REG8(0x4549), 0x01 }, + { CCI_REG8(0x454a), 0x01 }, + { CCI_REG8(0x454b), 0x06 }, + { CCI_REG8(0x454c), 0x06 }, + { CCI_REG8(0x454d), 0x06 }, + { CCI_REG8(0x454e), 0x06 }, + { CCI_REG8(0x454f), 0x06 }, + { CCI_REG8(0x4550), 0x06 }, + { CCI_REG8(0x4554), 0x55 }, + { CCI_REG8(0x4555), 0x02 }, + { CCI_REG8(0x4556), 0x42 }, + { CCI_REG8(0x4557), 0x05 }, + { CCI_REG8(0x4558), 0xfd }, + { CCI_REG8(0x4559), 0x05 }, + { CCI_REG8(0x455a), 0x94 }, + { CCI_REG8(0x455b), 0x06 }, + { CCI_REG8(0x455d), 0x06 }, + { CCI_REG8(0x455e), 0x49 }, + { CCI_REG8(0x455f), 0x07 }, + { CCI_REG8(0x4560), 0x7f }, + { CCI_REG8(0x4561), 0x07 }, + { CCI_REG8(0x4562), 0xa5 }, + { CCI_REG8(0x4564), 0x55 }, + { CCI_REG8(0x4565), 0x02 }, + { CCI_REG8(0x4566), 0x42 }, + { CCI_REG8(0x4567), 0x05 }, + { CCI_REG8(0x4568), 0xfd }, + { CCI_REG8(0x4569), 0x05 }, + { CCI_REG8(0x456a), 0x94 }, + { CCI_REG8(0x456b), 0x06 }, + { CCI_REG8(0x456d), 0x06 }, + { CCI_REG8(0x456e), 0x49 }, + { CCI_REG8(0x456f), 0x07 }, + { CCI_REG8(0x4572), 0xa5 }, + { CCI_REG8(0x460c), 0x7d }, + { CCI_REG8(0x460e), 0xb1 }, + { CCI_REG8(0x4614), 0xa8 }, + { CCI_REG8(0x4616), 0xb2 }, + { CCI_REG8(0x461c), 0x7e }, + { CCI_REG8(0x461e), 0xa7 }, + { CCI_REG8(0x4624), 0xa8 }, + { CCI_REG8(0x4626), 0xb2 }, + { CCI_REG8(0x462c), 0x7e }, + { CCI_REG8(0x462e), 0x8a }, + { CCI_REG8(0x4630), 0x94 }, + { CCI_REG8(0x4632), 0xa7 }, + { CCI_REG8(0x4634), 0xfb }, + { CCI_REG8(0x4636), 0x2f }, + { CCI_REG8(0x4638), 0x81 }, + { CCI_REG8(0x4639), 0x01 }, + { CCI_REG8(0x463a), 0xb5 }, + { CCI_REG8(0x463b), 0x01 }, + { CCI_REG8(0x463c), 0x26 }, + { CCI_REG8(0x463e), 0x30 }, + { CCI_REG8(0x4640), 0xac }, + { CCI_REG8(0x4641), 0x01 }, + { CCI_REG8(0x4642), 0xb6 }, + { CCI_REG8(0x4643), 0x01 }, + { CCI_REG8(0x4644), 0xfc }, + { CCI_REG8(0x4646), 0x25 }, + { CCI_REG8(0x4648), 0x82 }, + { CCI_REG8(0x4649), 0x01 }, + { CCI_REG8(0x464a), 0xab }, + { CCI_REG8(0x464b), 0x01 }, + { CCI_REG8(0x464c), 0x26 }, + { CCI_REG8(0x464e), 0x30 }, + { CCI_REG8(0x4654), 0xfc }, + { CCI_REG8(0x4656), 0x08 }, + { CCI_REG8(0x4658), 0x12 }, + { CCI_REG8(0x465a), 0x25 }, + { CCI_REG8(0x4662), 0xfc }, + { CCI_REG8(0x46a2), 0xfb }, + { CCI_REG8(0x46d6), 0xf3 }, + { CCI_REG8(0x46e6), 0x00 }, + { CCI_REG8(0x46e8), 0xff }, + { CCI_REG8(0x46e9), 0x03 }, + { CCI_REG8(0x46ec), 0x7a }, + { CCI_REG8(0x46ee), 0xe5 }, + { CCI_REG8(0x46f4), 0xee }, + { CCI_REG8(0x46f6), 0xf2 }, + { CCI_REG8(0x470c), 0xff }, + { CCI_REG8(0x470d), 0x03 }, + { CCI_REG8(0x470e), 0x00 }, + { CCI_REG8(0x4714), 0xe0 }, + { CCI_REG8(0x4716), 0xe4 }, + { CCI_REG8(0x471e), 0xed }, + { CCI_REG8(0x472e), 0x00 }, + { CCI_REG8(0x4730), 0xff }, + { CCI_REG8(0x4731), 0x03 }, + { CCI_REG8(0x4734), 0x7b }, + { CCI_REG8(0x4736), 0xdf }, + { CCI_REG8(0x4754), 0x7d }, + { CCI_REG8(0x4756), 0x8b }, + { CCI_REG8(0x4758), 0x93 }, + { CCI_REG8(0x475a), 0xb1 }, + { CCI_REG8(0x475c), 0xfb }, + { CCI_REG8(0x475e), 0x09 }, + { CCI_REG8(0x4760), 0x11 }, + { CCI_REG8(0x4762), 0x2f }, + { CCI_REG8(0x4766), 0xcc }, + { CCI_REG8(0x4776), 0xcb }, + { CCI_REG8(0x477e), 0x4a }, + { CCI_REG8(0x478e), 0x49 }, + { CCI_REG8(0x4794), 0x7c }, + { CCI_REG8(0x4796), 0x8f }, + { CCI_REG8(0x4798), 0xb3 }, + { CCI_REG8(0x4799), 0x00 }, + { CCI_REG8(0x479a), 0xcc }, + { CCI_REG8(0x479c), 0xc1 }, + { CCI_REG8(0x479e), 0xcb }, + { CCI_REG8(0x47a4), 0x7d }, + { CCI_REG8(0x47a6), 0x8e }, + { CCI_REG8(0x47a8), 0xb4 }, + { CCI_REG8(0x47a9), 0x00 }, + { CCI_REG8(0x47aa), 0xc0 }, + { CCI_REG8(0x47ac), 0xfa }, + { CCI_REG8(0x47ae), 0x0d }, + { CCI_REG8(0x47b0), 0x31 }, + { CCI_REG8(0x47b1), 0x01 }, + { CCI_REG8(0x47b2), 0x4a }, + { CCI_REG8(0x47b3), 0x01 }, + { CCI_REG8(0x47b4), 0x3f }, + { CCI_REG8(0x47b6), 0x49 }, + { CCI_REG8(0x47bc), 0xfb }, + { CCI_REG8(0x47be), 0x0c }, + { CCI_REG8(0x47c0), 0x32 }, + { CCI_REG8(0x47c1), 0x01 }, + { CCI_REG8(0x47c2), 0x3e }, + { CCI_REG8(0x47c3), 0x01 }, + { IMX678_REG_WDMODE, 0x00 }, + { IMX678_REG_MDBIT, 0x01 }, + { IMX678_REG_XXS_DRV, 0x00 }, +}; + +static const u32 codes_bayer[] = { + MEDIA_BUS_FMT_SRGGB12_1X12, +}; + +static const u32 codes_monochrome[] = { + MEDIA_BUS_FMT_Y12_1X12, +}; + +static const struct imx678_model_info imx678_aaqr_info = { + .type = IMX678_COLOR, + .codes = codes_bayer, + .num_codes = ARRAY_SIZE(codes_bayer), +}; + +static const struct imx678_model_info imx678_aamr_info = { + .type = IMX678_MONOCHROME, + .codes = codes_monochrome, + .num_codes = ARRAY_SIZE(codes_monochrome), +}; + +static const char * const imx678_supply_name[] = { + "avdd", /* Analog (3.3V) supply */ + "dvdd", /* Digital Core (1.1V) supply */ + "ovdd", /* IF (1.8V) supply */ +}; + +struct imx678 { + struct v4l2_subdev sd; + struct media_pad pad; + struct regmap *cci; + + const struct imx678_model_info *info; + + struct clk *xclk; + u32 xclk_freq; + + /* chosen INCK_SEL register value */ + u8 inck_sel_val; + + /* Link configurations */ + enum imx678_lanemode lane_mode; + unsigned long link_freq_bitmap; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx678_supply_name)]; + + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + + /* Track VMAX for exposure updates */ + u32 vmax; +}; + +static inline struct imx678 *to_imx678(struct v4l2_subdev *_sd) +{ + return container_of_const(_sd, struct imx678, sd); +} + +static u32 imx678_default_mbus_code(struct imx678 *imx678) +{ + return imx678->info->codes[0]; +} + +static bool imx678_mbus_code_supported(struct imx678 *imx678, u32 code) +{ + for (unsigned int i = 0; i < imx678->info->num_codes; i++) { + if (imx678->info->codes[i] == code) + return true; + } + + return false; +} + +static int imx678_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx678 *imx678 = container_of_const(ctrl->handler, struct + imx678, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_get_locked_active_state(&imx678->sd); + format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); + + if (ctrl->id == V4L2_CID_VBLANK) { + u32 current_exposure = imx678->exposure->cur.val; + + imx678->vmax = format->height + ctrl->val; + + current_exposure = clamp_t(u32, current_exposure, + IMX678_EXPOSURE_MIN, + imx678->vmax - IMX678_SHR_MIN); + ret = __v4l2_ctrl_modify_range(imx678->exposure, + IMX678_EXPOSURE_MIN, + imx678->vmax - IMX678_SHR_MIN, + 1, current_exposure); + if (ret) + return ret; + } + + /* + * Only apply control values when device is powered on (RPM ACTIVE) + * and streaming (usage count != 0) + */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + cci_write(imx678->cci, IMX678_REG_VMAX, imx678->vmax, &ret); + fallthrough; /* SHR = VMAX - exposure, so update it */ + case V4L2_CID_EXPOSURE: { + u32 shr = imx678->vmax - imx678->exposure->val; + + cci_write(imx678->cci, IMX678_REG_SHR, shr, &ret); + break; + } + case V4L2_CID_ANALOGUE_GAIN: + cci_write(imx678->cci, IMX678_REG_GAIN, ctrl->val, &ret); + break; + case V4L2_CID_HBLANK: { + u32 hmax = (format->width + ctrl->val) / IMX678_PIX_PER_CLK; + + cci_write(imx678->cci, IMX678_REG_HMAX, hmax, &ret); + break; + } + case V4L2_CID_TEST_PATTERN: { + cci_write(imx678->cci, IMX678_REG_TPG_COLORWIDTH, + IMX678_TPG_COLORWIDTH_160PIX, &ret); + cci_write(imx678->cci, IMX678_REG_TPG_PATSEL_DUOUT, + imx678_tpg_val[ctrl->val], &ret); + cci_write(imx678->cci, IMX678_REG_TPG_EN_DUOUT, + (ctrl->val) ? 1 : 0, + &ret); + break; + } + case V4L2_CID_HFLIP: + cci_write(imx678->cci, IMX678_REG_WINMODEH, ctrl->val, &ret); + break; + case V4L2_CID_VFLIP: + cci_write(imx678->cci, IMX678_REG_WINMODEV, ctrl->val, &ret); + break; + default: + dev_warn(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx678_ctrl_ops = { + .s_ctrl = imx678_set_ctrl, +}; + +static int imx678_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx678 *imx678 = to_imx678(sd); + + if (code->index >= imx678->info->num_codes) + return -EINVAL; + + code->code = imx678->info->codes[code->index]; + + return 0; +} + +static int imx678_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx678 *imx678 = to_imx678(sd); + const struct v4l2_rect *crop; + + if (fse->index) + return -EINVAL; + + if (!imx678_mbus_code_supported(imx678, fse->code)) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(sd_state, fse->pad); + + fse->min_width = crop->width; + fse->max_width = fse->min_width; + fse->min_height = crop->height; + fse->max_height = fse->min_height; + + return 0; +} + +static int imx678_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); + return 0; + + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r = imx678_native_area; + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r = imx678_active_area; + return 0; + } + + return -EINVAL; +} + +static int imx678_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct imx678 *imx678 = to_imx678(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_state_get_crop(state, IMX678_SOURCE_PAD); + *crop = imx678_active_area; + + format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); + format->code = imx678_default_mbus_code(imx678); + format->width = imx678_active_area.width; + format->height = imx678_active_area.height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + return 0; +} + +static int imx678_write_common(struct imx678 *imx678) +{ + int ret = 0; + + cci_multi_reg_write(imx678->cci, common_regs, ARRAY_SIZE(common_regs), + &ret); + + cci_write(imx678->cci, IMX678_REG_INCK_SEL, imx678->inck_sel_val, &ret); + cci_write(imx678->cci, IMX678_REG_DATARATE_SEL, + link_freqs_reg_value[__ffs(imx678->link_freq_bitmap)], &ret); + cci_write(imx678->cci, IMX678_REG_LANEMODE, imx678->lane_mode, &ret); + + cci_write(imx678->cci, IMX678_REG_INTERFACE_SEL, IMX678_INTERFACE_2L_4L, + &ret); + + return ret; +} + +static int imx678_program_window(struct imx678 *imx678, + const struct v4l2_rect *crop) +{ + int ret = 0; + + cci_write(imx678->cci, IMX678_REG_ADDMODE, 0x00, &ret); + cci_write(imx678->cci, IMX678_REG_WINMODE, + v4l2_rect_equal(crop, &imx678_active_area) ? 0x00 : 0x04, + &ret); + cci_write(imx678->cci, IMX678_REG_PIX_HST, + crop->left - imx678_active_area.left, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_HWIDTH, crop->width, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_VST, + crop->top - imx678_active_area.top, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_VWIDTH, crop->height, &ret); + cci_write(imx678->cci, IMX678_REG_ADBIT, 0x01, &ret); + + return ret; +} + +static int imx678_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 mask) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx678 *imx678 = to_imx678(sd); + const struct v4l2_rect *crop; + int ret; + + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + return ret; + + crop = v4l2_subdev_state_get_crop(state, pad); + ret = imx678_program_window(imx678, crop); + if (ret) { + dev_err(&client->dev, "%s failed to set mode\n", __func__); + goto err_rpm_put; + } + + ret = __v4l2_ctrl_handler_setup(imx678->sd.ctrl_handler); + if (ret) { + dev_err(&client->dev, "%s failed to apply user values\n", + __func__); + goto err_rpm_put; + } + + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STREAMING, + &ret); + usleep_range(IMX678_STREAM_DELAY_US, IMX678_STREAM_DELAY_US + + IMX678_STREAM_DELAY_RANGE_US); + cci_write(imx678->cci, IMX678_REG_XMSTA, 0x00, &ret); + + if (ret) { + dev_err(&client->dev, "%s failed to start streaming\n", + __func__); + goto err_rpm_put; + } + + return 0; + +err_rpm_put: + pm_runtime_put(&client->dev); + + return ret; +} + +static int imx678_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 mask) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx678 *imx678 = to_imx678(sd); + int ret = 0; + + /* Master mode disable */ + cci_write(imx678->cci, IMX678_REG_XMSTA, 0x01, &ret); + /* Standby */ + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STANDBY, + &ret); + if (ret) + dev_err(&client->dev, "%s failed to stop stream\n", __func__); + + pm_runtime_put(&client->dev); + + return ret; +} + +static int imx678_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + if (ret) { + dev_err(&client->dev, "%s: failed to enable regulators\n", + __func__); + return ret; + } + + fsleep(1); /* Tlow > 500ns */ + + gpiod_set_value_cansleep(imx678->reset_gpio, 0); + + fsleep(1); /* T3 > 1us */ + + ret = clk_prepare_enable(imx678->xclk); + if (ret) { + dev_err(&client->dev, "%s: failed to enable clock\n", + __func__); + goto reg_off; + } + + fsleep(20); /* T4 > 20us */ + + ret = imx678_write_common(imx678); + if (ret) { + dev_err(&client->dev, "%s failed to write registers\n", + __func__); + goto clk_off; + } + + return 0; + +clk_off: + clk_disable_unprepare(imx678->xclk); + +reg_off: + gpiod_set_value_cansleep(imx678->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + + return ret; +} + +static int imx678_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + + clk_disable_unprepare(imx678->xclk); + gpiod_set_value_cansleep(imx678->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + + return 0; +} + +static int imx678_identify_model(struct imx678 *imx678) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + const struct imx678_model_info *info; + enum imx678_type detected; + int ret = 0; + u64 val = 0; + + info = device_get_match_data(&client->dev); + + /* + * This sensor's ID registers become accessible 80ms after coming out + * of STANDBY mode. + */ + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, 0, &ret); + fsleep(IMX678_MODULE_ID_DELAY); + + cci_read(imx678->cci, IMX678_REG_MODULE_ID, &val, &ret); + + if (ret) { + dev_err(&client->dev, + "I2C transaction failed ret = %d\n", ret); + return ret; + } + + if (val != IMX678_ID) { + dev_err(&client->dev, + "Chip ID mismatch: %x!=%llx\n", IMX678_ID, val); + return -ENXIO; + } + + cci_read(imx678->cci, IMX678_REG_MONOCHROME, &val, &ret); + + if (ret) { + dev_err(&client->dev, + "I2C transaction failed ret = %d\n", ret); + return ret; + } + + detected = val & IMX678_TYPE; + + /* Prefer to use sensor type specified in device tree */ + if (info) { + imx678->info = info; + if (detected != info->type) + dev_err(&client->dev, + "detected %s sensor, DT specifies %s; using DT value\n", + detected == IMX678_COLOR ? "color" : "mono", + info->type == IMX678_COLOR ? "color" : "mono"); + } else { + imx678->info = detected == IMX678_MONOCHROME ? + &imx678_aamr_info : &imx678_aaqr_info; + dev_info(&client->dev, + "sensor type missing in DT; detected %s sensor\n", + detected == IMX678_MONOCHROME ? "mono" : "color"); + } + + return 0; +} + +static const struct v4l2_subdev_video_ops imx678_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops imx678_pad_ops = { + .enum_mbus_code = imx678_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = v4l2_subdev_get_fmt, + .get_selection = imx678_get_selection, + .enum_frame_size = imx678_enum_frame_size, + .enable_streams = imx678_enable_streams, + .disable_streams = imx678_disable_streams, +}; + +static const struct v4l2_subdev_ops imx678_subdev_ops = { + .video = &imx678_video_ops, + .pad = &imx678_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops imx678_internal_ops = { + .init_state = imx678_init_state, +}; + +static int imx678_init_controls(struct imx678 *imx678) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + const u32 hmax_4lane = min_hmax_4lane[__ffs(imx678->link_freq_bitmap)]; + const u32 lane_scale = imx678->lane_mode == IMX678_LANEMODE_2L ? 2 : 1; + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *link_freq; + s32 hblank, max_hblank, vblank, max_vblank; + u32 hmax; + int ret; + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret < 0) + return ret; + + ctrl_hdlr = &imx678->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11); + if (ret) + return ret; + + imx678->vmax = IMX678_VMAX_DEFAULT; + hmax = hmax_4lane * lane_scale; + + /* PIXEL_RATE is fixed and read-only */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_PIXEL_RATE, + IMX678_PIXEL_RATE, IMX678_PIXEL_RATE, 1, + IMX678_PIXEL_RATE); + + /* LINK_FREQ is also read only */ + link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freqs) - 1, + __ffs(imx678->link_freq_bitmap), + link_freqs); + + if (link_freq) + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank = imx678->vmax - imx678_active_area.height; + max_vblank = IMX678_VMAX_MAX - imx678_active_area.height; + imx678->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_VBLANK, vblank, max_vblank, + 2, vblank); + + hblank = hmax * IMX678_PIX_PER_CLK - imx678_active_area.width; + max_hblank = IMX678_HMAX_MAX * IMX678_PIX_PER_CLK - + imx678_active_area.width; + imx678->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_HBLANK, hblank, max_hblank, + IMX678_PIX_PER_CLK, hblank); + + imx678->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX678_EXPOSURE_MIN, + IMX678_VMAX_DEFAULT - + IMX678_SHR_MIN, + IMX678_EXPOSURE_STEP, + IMX678_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX678_ANA_GAIN_MIN_NORMAL, + IMX678_ANA_GAIN_MAX_NORMAL, IMX678_ANA_GAIN_STEP, + IMX678_ANA_GAIN_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx678_tpg_menu) - 1, 0, 0, + imx678_tpg_menu); + + v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx678_ctrl_ops, &props); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ret; + } + + imx678->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static int imx678_check_hwcfg(struct device *dev, struct imx678 *imx678) +{ + struct fwnode_handle *endpoint; + struct v4l2_fwnode_endpoint ep_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret = -EINVAL; + + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + if (!endpoint) { + dev_err(dev, "endpoint node not found\n"); + return -EINVAL; + } + + if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { + dev_err(dev, "could not parse endpoint\n"); + goto error_out; + } + + switch (ep_cfg.bus.mipi_csi2.num_data_lanes) { + case 2: + imx678->lane_mode = IMX678_LANEMODE_2L; + break; + case 4: + imx678->lane_mode = IMX678_LANEMODE_4L; + break; + default: + dev_err(dev, + "only 2 or 4 CSI2 data lanes are currently supported\n"); + goto error_out; + } + + ret = v4l2_link_freq_to_bitmap(dev, ep_cfg.link_frequencies, + ep_cfg.nr_of_link_frequencies, + link_freqs, ARRAY_SIZE(link_freqs), + &imx678->link_freq_bitmap); + +error_out: + v4l2_fwnode_endpoint_free(&ep_cfg); + fwnode_handle_put(endpoint); + + return ret; +} + +static int imx678_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct imx678 *imx678; + int ret, i; + + imx678 = devm_kzalloc(&client->dev, sizeof(*imx678), GFP_KERNEL); + if (!imx678) + return -ENOMEM; + + v4l2_i2c_subdev_init(&imx678->sd, client, &imx678_subdev_ops); + + imx678->cci = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx678->cci)) + return dev_err_probe(dev, PTR_ERR(imx678->cci), + "failed to init CCI\n"); + + if (imx678_check_hwcfg(dev, imx678)) + return -EINVAL; + + imx678->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(imx678->xclk)) + return dev_err_probe(dev, PTR_ERR(imx678->xclk), + "failed to get xclk\n"); + + imx678->xclk_freq = clk_get_rate(imx678->xclk); + + for (i = 0; i < ARRAY_SIZE(imx678_inck_table); ++i) { + if (imx678_inck_table[i].xclk_hz == imx678->xclk_freq) { + imx678->inck_sel_val = imx678_inck_table[i].inck_sel; + break; + } + } + + if (i == ARRAY_SIZE(imx678_inck_table)) + return dev_err_probe(dev, -EINVAL, + "unsupported XCLK rate %u Hz\n", + imx678->xclk_freq); + + for (i = 0; i < ARRAY_SIZE(imx678_supply_name); i++) + imx678->supplies[i].supply = imx678_supply_name[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + imx678->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(imx678->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(imx678->reset_gpio), + "failed to get reset GPIO\n"); + + ret = imx678_power_on(dev); + if (ret) + return ret; + + ret = imx678_identify_model(imx678); + if (ret) + goto error_power_off; + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = imx678_init_controls(imx678); + if (ret) + goto error_pm_runtime; + + imx678->sd.internal_ops = &imx678_internal_ops; + imx678->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx678->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx678->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&imx678->sd.entity, 1, &imx678->pad); + if (ret) { + dev_err_probe(dev, ret, "failed to init entity pads\n"); + goto error_handler_free; + } + + imx678->sd.state_lock = imx678->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx678->sd); + if (ret < 0) { + dev_err_probe(dev, ret, "subdev init error\n"); + goto error_media_entity; + } + + ret = v4l2_async_register_subdev_sensor(&imx678->sd); + if (ret < 0) { + dev_err_probe(dev, ret, + "failed to register sensor sub-device\n"); + goto error_subdev_cleanup; + } + + pm_runtime_idle(dev); + + return 0; + +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx678->sd); + +error_media_entity: + media_entity_cleanup(&imx678->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); + +error_pm_runtime: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + +error_power_off: + imx678_power_off(&client->dev); + + return ret; +} + +static void imx678_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx678_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); +} + +static const struct dev_pm_ops imx678_pm_ops = { + SET_RUNTIME_PM_OPS(imx678_power_off, imx678_power_on, NULL) +}; + +static const struct of_device_id imx678_of_match[] = { + { .compatible = "sony,imx678-aamr", .data = &imx678_aamr_info }, + { .compatible = "sony,imx678-aaqr", .data = &imx678_aaqr_info }, + /* for non-conforming DTs that rely on runtime check */ + { .compatible = "sony,imx678" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, imx678_of_match); + +static struct i2c_driver imx678_i2c_driver = { + .driver = { + .name = "imx678", + .of_match_table = imx678_of_match, + .pm = pm_ptr(&imx678_pm_ops), + }, + .probe = imx678_probe, + .remove = imx678_remove, +}; + +module_i2c_driver(imx678_i2c_driver); + +MODULE_AUTHOR("Will Whang <will@willwhang.com>"); +MODULE_AUTHOR("Tetsuya NOMURA <tetsuya.nomura@soho-enterprise.com>"); +MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>"); +MODULE_DESCRIPTION("Sony imx678 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index ac0712ce1e65..79eab9045e24 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1062,7 +1062,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv) priv->sd.state_lock = priv->ctrls.lock; ret = v4l2_subdev_init_finalize(&priv->sd); if (ret) - goto err_async; + goto err_entity; ret = v4l2_async_register_subdev(&priv->sd); if (ret < 0) { @@ -1074,6 +1074,8 @@ static int max9286_v4l2_register(struct max9286_priv *priv) err_subdev: v4l2_subdev_cleanup(&priv->sd); +err_entity: + media_entity_cleanup(&priv->sd.entity); err_async: v4l2_ctrl_handler_free(&priv->ctrls); max9286_v4l2_notifier_unregister(priv); @@ -1084,6 +1086,7 @@ err_async: static void max9286_v4l2_unregister(struct max9286_priv *priv) { v4l2_subdev_cleanup(&priv->sd); + media_entity_cleanup(&priv->sd.entity); v4l2_ctrl_handler_free(&priv->ctrls); v4l2_async_unregister_subdev(&priv->sd); max9286_v4l2_notifier_unregister(priv); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 413cfbc2dd94..a540b211f7d7 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -717,6 +717,7 @@ static int msp_probe(struct i2c_client *client) if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { dev_dbg_lvl(&client->dev, 1, msp_debug, "not an msp3400 (cannot read chip version)\n"); + media_entity_cleanup(&sd->entity); return -ENODEV; } @@ -812,6 +813,7 @@ static int msp_probe(struct i2c_client *client) int err = hdl->error; v4l2_ctrl_handler_free(hdl); + media_entity_cleanup(&sd->entity); return err; } @@ -865,6 +867,7 @@ static void msp_remove(struct i2c_client *client) msp_reset(client); v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&state->sd.entity); } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index d21510caf45a..2b09e8315c8e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -452,11 +452,7 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031) ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank - 1); if (ret < 0) return ret; - ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1); - if (ret < 0) - return ret; - - return ret; + return mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1); } static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index bd2268154ca7..b3a6c6d76632 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1079,11 +1079,12 @@ static int mt9t112_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk"); - if (PTR_ERR(priv->clk) == -ENOENT) + if (IS_ERR(priv->clk)) { + if (PTR_ERR(priv->clk) != -ENOENT) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "Unable to get clock \"extclk\"\n"); priv->clk = NULL; - else if (IS_ERR(priv->clk)) - return dev_err_probe(&client->dev, PTR_ERR(priv->clk), - "Unable to get clock \"extclk\"\n"); + } priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 985517f1cff7..ff55a8ff32b4 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -520,6 +520,7 @@ static int mt9v011_probe(struct i2c_client *c) (version != MT9V011_REV_B_VERSION)) { v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n", version); + media_entity_cleanup(&sd->entity); return -EINVAL; } @@ -542,6 +543,7 @@ static int mt9v011_probe(struct i2c_client *c) v4l2_err(sd, "control initialization error %d\n", ret); v4l2_ctrl_handler_free(&core->ctrls); + media_entity_cleanup(&sd->entity); return ret; } core->sd.ctrl_handler = &core->ctrls; @@ -577,6 +579,7 @@ static void mt9v011_remove(struct i2c_client *c) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&core->ctrls); + media_entity_cleanup(&sd->entity); } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 143dcfe10445..0150e4d296af 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -820,18 +820,16 @@ static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) if (!ep) return -ENXIO; + /* Optional indication of MIPI clock voltage unit */ + if (!fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", + &clk_volt)) + ov02a10->mipi_clock_voltage = clk_volt; + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) return ret; - /* Optional indication of MIPI clock voltage unit */ - ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", - &clk_volt); - - if (!ret) - ov02a10->mipi_clock_voltage = clk_volt; - for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { if (link_freq_menu_items[i] == diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index fb590dfadda1..39003c1632ad 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1241,41 +1241,42 @@ exit: return ret; } +static const struct regmap_config regmap_config = { + .val_bits = 8, + .reg_bits = 16, + .disable_locking = true, +}; + static int ov2740_register_nvmem(struct i2c_client *client, struct ov2740 *ov2740) { struct nvm_data *nvm; - struct regmap_config regmap_config = { }; - struct nvmem_config nvmem_config = { }; struct regmap *regmap; struct device *dev = ov2740->dev; + struct nvmem_config nvmem_config = { + .name = dev_name(dev), + .dev = dev, + .read_only = true, + .root_only = true, + .owner = THIS_MODULE, + .compat = true, + .base_dev = dev, + .reg_read = ov2740_nvmem_read, + .stride = 1, + .word_size = 1, + .size = CUSTOMER_USE_OTP_SIZE, + }; nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); if (!nvm) return -ENOMEM; - regmap_config.val_bits = 8; - regmap_config.reg_bits = 16; - regmap_config.disable_locking = true; regmap = devm_regmap_init_i2c(client, ®map_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); nvm->regmap = regmap; - - nvmem_config.name = dev_name(dev); - nvmem_config.dev = dev; - nvmem_config.read_only = true; - nvmem_config.root_only = true; - nvmem_config.owner = THIS_MODULE; - nvmem_config.compat = true; - nvmem_config.base_dev = dev; - nvmem_config.reg_read = ov2740_nvmem_read; - nvmem_config.reg_write = NULL; nvmem_config.priv = nvm; - nvmem_config.stride = 1; - nvmem_config.word_size = 1; - nvmem_config.size = CUSTOMER_USE_OTP_SIZE; nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); if (IS_ERR(nvm->nvmem)) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index c2e02f191816..b4e14171556f 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1116,18 +1116,14 @@ static void ov7740_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); - mutex_destroy(&ov7740->mutex); - v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); - media_entity_cleanup(&ov7740->subdev.entity); v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&ov7740->subdev.entity); ov7740_free_controls(ov7740); - pm_runtime_get_sync(&client->dev); pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov7740_set_power(ov7740, 0); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); - - ov7740_set_power(ov7740, 0); } static int __maybe_unused ov7740_runtime_suspend(struct device *dev) diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index 8c9cd769fa01..289a34a3eeb1 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2608,7 +2608,7 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) { struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); struct ov8865_state *state = &sensor->state; - int ret; + int ret = 0; if (enable) { ret = pm_runtime_resume_and_get(sensor->dev); @@ -2617,18 +2617,32 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) } mutex_lock(&sensor->mutex); - ret = ov8865_sw_standby(sensor, !enable); - mutex_unlock(&sensor->mutex); - if (ret) - return ret; + /* + * The sensor may have been kept powered by something else (e.g. the + * VCM's runtime PM device link on IPU3 platforms), in which case + * runtime resume did not run and the hardware may still be + * configured for a previous mode. Always program the negotiated + * configuration on stream start. + */ + if (enable) { + ret = ov8865_sensor_init(sensor); + if (!ret) + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + } - state->streaming = !!enable; + if (!ret) + ret = ov8865_sw_standby(sensor, !enable); + + mutex_unlock(&sensor->mutex); - if (!enable) + if (ret || !enable) pm_runtime_put(sensor->dev); - return 0; + if (!ret) + state->streaming = enable; + + return ret; } static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = { @@ -2915,15 +2929,15 @@ static int ov8865_resume(struct device *dev) if (ret) goto complete; - ret = ov8865_sensor_init(sensor); - if (ret) - goto error_power; + if (state->streaming) { + ret = ov8865_sensor_init(sensor); + if (ret) + goto error_power; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); - if (ret) - goto error_power; + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) + goto error_power; - if (state->streaming) { ret = ov8865_sw_standby(sensor, false); if (ret) goto error_power; diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 5b6f897a74fc..5d301660a87d 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -197,7 +197,6 @@ struct ov9282_mode { * @noncontinuous_clock: Selection of CSI2 noncontinuous clock mode * @cur_mode: Pointer to current selected sensor mode * @code: Mbus code currently selected - * @mutex: Mutex for serializing sensor controls */ struct ov9282 { struct device *dev; @@ -648,7 +647,8 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) ctrl->val ? OV9282_OUTPUT_ENABLE6_STROBE : 0, NULL); break; case V4L2_CID_FLASH_DURATION: - ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN, ctrl->val, NULL); + ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN, + ov9282_us_to_flash_duration(ov9282, ctrl->val), NULL); break; default: dev_err(ov9282->dev, "Invalid control %d", ctrl->id); diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index bcab462708c7..ece8a410e7ce 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -588,10 +588,12 @@ static int rdacm21_probe(struct i2c_client *client) ret = v4l2_async_register_subdev(&dev->sd); if (ret) - goto error_free_ctrls; + goto error_entity_cleanup; return 0; +error_entity_cleanup: + media_entity_cleanup(&dev->sd.entity); error_free_ctrls: v4l2_ctrl_handler_free(&dev->ctrls); error: @@ -606,6 +608,7 @@ static void rdacm21_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dev->sd); v4l2_ctrl_handler_free(&dev->ctrls); + media_entity_cleanup(&dev->sd.entity); i2c_unregister_device(dev->isp); } diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 7cce90750c93..d20695238b48 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1867,6 +1867,7 @@ static int saa711x_probe(struct i2c_client *client) int err = hdl->error; v4l2_ctrl_handler_free(hdl); + media_entity_cleanup(&sd->entity); return err; } v4l2_ctrl_auto_cluster(2, &state->agc, 0, true); @@ -1925,6 +1926,7 @@ static void saa711x_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(sd->ctrl_handler); + media_entity_cleanup(&sd->entity); } static const struct i2c_device_id saa711x_id[] = { diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index 78d18c028154..6f458f611f63 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -29,11 +29,7 @@ /* Register Map */ #define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000) -#define VD55G1_MODEL_ID_VD55G1 0x53354731 /* Mono */ -#define VD55G1_MODEL_ID_VD65G4 0x53354733 /* RGB */ -#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004) -#define VD55G1_REVISION_CCB 0x2020 -#define VD55G1_REVISION_BAYER 0x3030 +#define VD55G1_REG_COLOR_VERSION CCI_REG32_LE(0x0670) #define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012) #define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) #define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c) @@ -60,7 +56,10 @@ #define VD55G1_PATGEN_ENABLE BIT(0) #define VD55G1_REG_MANUAL_ANALOG_GAIN CCI_REG8(0x0501) #define VD55G1_REG_MANUAL_COARSE_EXPOSURE CCI_REG16_LE(0x0502) -#define VD55G1_REG_MANUAL_DIGITAL_GAIN CCI_REG16_LE(0x0504) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0 CCI_REG16_LE(0x0504) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1 CCI_REG16_LE(0x0506) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2 CCI_REG16_LE(0x0508) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3 CCI_REG16_LE(0x050a) #define VD55G1_REG_APPLIED_COARSE_EXPOSURE CCI_REG16_LE(0x00e8) #define VD55G1_REG_APPLIED_ANALOG_GAIN CCI_REG16_LE(0x00ea) #define VD55G1_REG_APPLIED_DIGITAL_GAIN CCI_REG16_LE(0x00ec) @@ -114,9 +113,8 @@ #define VD55G1_WIDTH 804 #define VD55G1_HEIGHT 704 -#define VD55G1_MODE_DEF 0 +#define VD55G1_MODE_IDX_DEF 0 #define VD55G1_NB_GPIOS 4 -#define VD55G1_MBUS_CODE_DEF 0 #define VD55G1_DGAIN_DEF 256 #define VD55G1_AGAIN_DEF 19 #define VD55G1_EXPO_MAX_TERM 64 @@ -135,8 +133,39 @@ #define VD55G1_MIPI_RATE_MIN (250 * MEGA) #define VD55G1_MIPI_RATE_MAX (1200 * MEGA) -#define VD55G1_MODEL_ID_NAME(id) \ - ((id) == VD55G1_MODEL_ID_VD55G1 ? "vd55g1" : "vd65g4") +enum vd55g1_model_id { + VD55G1_MODEL_ID_2 = 0x53354731, + VD55G1_MODEL_ID_3 = 0x53354733, +}; + +enum vd55g1_color_version { + VD55G1_COLOR_VERSION_MONO, + VD55G1_COLOR_VERSION_BAYER, +}; + +struct vd55g1_version { + char *name; + enum vd55g1_model_id id; + enum vd55g1_color_version color; +}; + +static const struct vd55g1_version vd55g1_versions[] = { + { + .name = "vd55g1", + .id = VD55G1_MODEL_ID_2, + .color = VD55G1_COLOR_VERSION_MONO, + }, + { + .name = "vd55g4", + .id = VD55G1_MODEL_ID_3, + .color = VD55G1_COLOR_VERSION_MONO, + }, + { + .name = "vd65g4", + .id = VD55G1_MODEL_ID_3, + .color = VD55G1_COLOR_VERSION_BAYER, + }, +}; static const u8 vd55g1_patch_array[] = { 0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, @@ -532,7 +561,7 @@ struct vd55g1_vblank_limits { struct vd55g1 { struct device *dev; - unsigned int id; + const struct vd55g1_version *version; struct v4l2_subdev sd; struct media_pad pad; struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)]; @@ -623,20 +652,28 @@ static unsigned int vd55g1_get_fmt_data_type(u32 code) static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code) { + u32 fallback_code; unsigned int i, j; - if (sensor->id == VD55G1_MODEL_ID_VD55G1) - return code; - - for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) { - for (j = 0; j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); j++) { - if (vd55g1_mbus_formats_bayer[i][j] == code) - goto adapt_bayer_pattern; + if (sensor->version->color == VD55G1_COLOR_VERSION_MONO) { + fallback_code = vd55g1_mbus_formats_mono[0]; + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_mono); i++) + if (vd55g1_mbus_formats_mono[i] == code) + return code; + } else { + fallback_code = vd55g1_mbus_formats_bayer[0][0]; + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) { + for (j = 0; + j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); + j++) { + if (vd55g1_mbus_formats_bayer[i][j] == code) + goto adapt_bayer_pattern; + } } } - dev_warn(sensor->dev, "Unsupported mbus format\n"); + dev_warn(sensor->dev, "Unsupported mbus format: 0x%x\n", code); - return code; + return fallback_code; adapt_bayer_pattern: j = 0; @@ -649,12 +686,6 @@ adapt_bayer_pattern: return vd55g1_mbus_formats_bayer[i][j]; } -static s32 vd55g1_get_pixel_rate(struct vd55g1 *sensor, - struct v4l2_mbus_framefmt *format) -{ - return sensor->mipi_rate / vd55g1_get_fmt_bpp(format->code); -} - static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor, struct v4l2_mbus_framefmt *format, struct v4l2_rect *crop) @@ -850,9 +881,16 @@ static int vd55g1_update_expo_cluster(struct vd55g1 *sensor, bool is_auto) vd55g1_write(sensor, VD55G1_REG_MANUAL_ANALOG_GAIN, sensor->again_ctrl->val, &ret); - if (!is_auto && sensor->dgain_ctrl->is_new) - vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN, + if (!is_auto && sensor->dgain_ctrl->is_new) { + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0, sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1, + sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2, + sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3, + sensor->dgain_ctrl->val, &ret); + } return ret; } @@ -1173,8 +1211,8 @@ static int vd55g1_patch(struct vd55g1 *sensor) u64 patch; int ret = 0; - /* vd55g1 needs a patch while vd65g4 does not */ - if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + /* Version 2 needs a patch while version 3 does not */ + if (sensor->version->id == VD55G1_MODEL_ID_2) { vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, sizeof(vd55g1_patch_array), vd55g1_patch_array, &ret); @@ -1246,7 +1284,7 @@ static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd, struct vd55g1 *sensor = to_vd55g1(sd); u32 base_code; - if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER) { if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_mono)) return -EINVAL; base_code = vd55g1_mbus_formats_mono[code->index]; @@ -1285,12 +1323,6 @@ static int vd55g1_new_format_change_controls(struct vd55g1 *sensor, if (ret) return ret; - /* Update pixel rate to reflect new bpp */ - ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl, - vd55g1_get_pixel_rate(sensor, format)); - if (ret) - return ret; - /* Update hblank according to new width */ hblank = vd55g1_get_hblank_min(sensor, format, crop); ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, @@ -1347,6 +1379,7 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, { struct vd55g1 *sensor = to_vd55g1(sd); struct v4l2_subdev_format fmt = { 0 }; + int code; struct v4l2_subdev_route routes[] = { { .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE } }; @@ -1361,9 +1394,13 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, if (ret) return ret; - vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF], - vd55g1_get_fmt_code(sensor, VD55G1_MBUS_CODE_DEF), - &fmt.format); + if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER) + code = vd55g1_mbus_formats_mono[0]; + else + code = vd55g1_mbus_formats_bayer[0][0]; + fmt.format.code = vd55g1_get_fmt_code(sensor, code); + fmt.format.width = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].width; + fmt.format.height = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].height; return vd55g1_set_pad_fmt(sd, sd_state, &fmt); } @@ -1549,7 +1586,6 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor) v4l2_subdev_state_get_crop(state, 0); struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(state, 0); - s32 pixel_rate = vd55g1_get_pixel_rate(sensor, format); int ret; v4l2_ctrl_handler_init(hdl, 16); @@ -1591,7 +1627,7 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor) sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, - pixel_rate); + sensor->pixel_clock); if (sensor->pixel_rate_ctrl) sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; sensor->ae_lock_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, @@ -1644,38 +1680,46 @@ unlock_state: return ret; } +static const struct vd55g1_version * +vd55g1_get_version(enum vd55g1_model_id id, + enum vd55g1_color_version color) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(vd55g1_versions); i++) { + if (vd55g1_versions[i].id == id && + vd55g1_versions[i].color == color) + return &vd55g1_versions[i]; + } + + return NULL; +} + static int vd55g1_detect(struct vd55g1 *sensor) { - unsigned int dt_id = (uintptr_t)device_get_match_data(sensor->dev); - u64 rev, id; - int ret; + const struct vd55g1_version *dt_version = + device_get_match_data(sensor->dev); + const struct vd55g1_version *version; + u64 color, id; + int ret = 0; - ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL); + vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, &ret); + vd55g1_read(sensor, VD55G1_REG_COLOR_VERSION, &color, &ret); if (ret) return ret; - if (id != VD55G1_MODEL_ID_VD55G1 && id != VD55G1_MODEL_ID_VD65G4) { - dev_warn(sensor->dev, "Unsupported sensor id 0x%x\n", - (u32)id); + version = vd55g1_get_version(id, color); + if (!version) { + dev_warn(sensor->dev, "Unsupported sensor version, expected %s\n", + dt_version->name); return -ENODEV; } - if (id != dt_id) { - dev_err(sensor->dev, "Probed sensor %s and device tree definition (%s) mismatch", - VD55G1_MODEL_ID_NAME(id), VD55G1_MODEL_ID_NAME(dt_id)); + if (version->id != dt_version->id || + version->color != dt_version->color) { + dev_err(sensor->dev, "Probed sensor version %s and device tree definition %s mismatch", + version->name, dt_version->name); return -ENODEV; } - sensor->id = id; - ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &rev, NULL); - if (ret) - return ret; - - if ((id == VD55G1_MODEL_ID_VD55G1 && rev != VD55G1_REVISION_CCB) && - (id == VD55G1_MODEL_ID_VD65G4 && rev != VD55G1_REVISION_BAYER)) { - dev_err(sensor->dev, "Unsupported sensor revision 0x%x for sensor %s\n", - (u16)rev, VD55G1_MODEL_ID_NAME(id)); - return -ENODEV; - } + sensor->version = version; return 0; } @@ -2033,8 +2077,9 @@ static void vd55g1_remove(struct i2c_client *client) } static const struct of_device_id vd55g1_dt_ids[] = { - { .compatible = "st,vd55g1", .data = (void *)VD55G1_MODEL_ID_VD55G1 }, - { .compatible = "st,vd65g4", .data = (void *)VD55G1_MODEL_ID_VD65G4 }, + { .compatible = "st,vd55g1", .data = (void *)&vd55g1_versions[0] }, + { .compatible = "st,vd55g4", .data = (void *)&vd55g1_versions[1] }, + { .compatible = "st,vd65g4", .data = (void *)&vd55g1_versions[2] }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, vd55g1_dt_ids); diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 6b50fb422a61..4811a0489524 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -522,8 +522,12 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data, "%s-vid-cap", data->v4l2_dev.name); ret = PTR_ERR_OR_ZERO(data->kthread_vid_cap); - if (!ret) - return 0; + if (ret) { + data->kthread_vid_cap = NULL; + goto error_rpm_put; + } + + return 0; error_rpm_put: pm_runtime_put_autosuspend(dev); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 663469208271..c631b8bbd386 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3563,12 +3563,12 @@ static int __maybe_unused bttv_resume(struct device *dev) } static const struct pci_device_id bttv_pci_tbl[] = { - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0}, - {0,} + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879) }, + { } }; MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c index 7bb7f13c70c0..9ed547cd40af 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-main.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -135,7 +135,6 @@ int cobalt_alsa_init(struct cobalt_stream *s) err_exit_free: if (sc != NULL) snd_card_free(sc); - kfree(cobsc); err_exit: return ret; } diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 9b9f69ff4016..7b1ca1238c8d 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -26,9 +26,8 @@ /* add your revision and whatnot here */ static const struct pci_device_id cobalt_pci_tbl[] = { - {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_COBALT) }, + { } }; MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl); diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index f778f79b921d..214fac7af61e 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -40,9 +40,8 @@ EXPORT_SYMBOL(cx18_ext_init); /* add your revision and whatnot here */ static const struct pci_device_id cx18_pci_tbl[] = { - {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(CX, PCI_DEVICE_ID_CX23418) }, + { } }; MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c index 8dc4ce325935..3a8430f3259e 100644 --- a/drivers/media/pci/cx18/cx18-vbi.c +++ b/drivers/media/pci/cx18/cx18-vbi.c @@ -135,7 +135,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, : VBI_HBLANK_SAMPLES_50HZ; /* find the first valid line */ - for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { + for (i = hdr_size, buf += hdr_size; i + 3 < size; i++, buf++) { if (buf[0] == 0xff && !buf[1] && !buf[2] && (buf[3] == sliced_vbi_eav_rp[0] || buf[3] == sliced_vbi_eav_rp[1])) diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 154918984534..723509fa1e06 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -528,6 +528,7 @@ void netup_ci_exit(struct cx23885_tsport *port) if (NULL == state->ca.data) return; + cancel_work_sync(&state->work); dvb_ca_en50221_release(&state->ca); kfree(state); } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 9b92e8db494c..5fb26285e4af 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2279,16 +2279,10 @@ static int __maybe_unused cx23885_resume(struct device *dev_d) static const struct pci_device_id cx23885_pci_tbl[] = { { /* CX23885 */ - .vendor = 0x14f1, - .device = 0x8852, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8852), }, { /* CX23887 Rev 2 */ - .vendor = 0x14f1, - .device = 0x8880, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8880), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 4fdc59aaed8e..f963ae79f685 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -681,8 +681,8 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, */ static const struct pci_device_id __maybe_unused cx25821_audio_pci_tbl[] = { - {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_DEVICE(0x14f1, 0x0920) }, + { } }; MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 5acb1dc00ae8..f883a779b570 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1347,16 +1347,10 @@ static void cx25821_finidev(struct pci_dev *pci_dev) static const struct pci_device_id cx25821_pci_tbl[] = { { /* CX25821 Athena */ - .vendor = 0x14f1, - .device = 0x8210, - .subvendor = 0x14f1, - .subdevice = 0x0920, + PCI_DEVICE_SUB(0x14f1, 0x8210, 0x14f1, 0x0920), }, { /* CX25821 No Brand */ - .vendor = 0x14f1, - .device = 0x8210, - .subvendor = 0x0000, - .subdevice = 0x0000, + PCI_DEVICE_SUB(0x14f1, 0x8210, 0x0000, 0x0000), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index dce041a5e47a..d2534f90cfba 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -809,9 +809,9 @@ static const struct snd_kcontrol_new snd_cx88_alc_switch = { */ static const struct pci_device_id cx88_audio_pci_tbl[] = { - {0x14f1, 0x8801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x14f1, 0x8811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0, } + { PCI_DEVICE(0x14f1, 0x8801) }, + { PCI_DEVICE(0x14f1, 0x8811) }, + { } }; MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 676160e9554d..0c07ad335799 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -640,6 +640,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) list_add_tail(&driver->drvlist, &dev->drvlist); } else { pr_err("cx8802 probe failed, err = %d\n", err); + kfree(driver); } mutex_unlock(&drv->core->lock); } @@ -787,10 +788,7 @@ static void cx8802_remove(struct pci_dev *pci_dev) static const struct pci_device_id cx8802_pci_tbl[] = { { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8802), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index c78b156c5cda..eaa46a2f92e7 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1610,10 +1610,7 @@ static int __maybe_unused cx8800_resume(struct device *dev_d) static const struct pci_device_id cx8800_pci_tbl[] = { { - .vendor = 0x14f1, - .device = 0x8800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8800), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c index 363badab7cf0..248ace29e5c8 100644 --- a/drivers/media/pci/ddbridge/ddbridge-main.c +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -269,7 +269,7 @@ static const struct pci_device_id ddb_id_table[] = { DDB_DEVICE_ANY(0x0323), DDB_DEVICE_ANY(0x0328), DDB_DEVICE_ANY(0x0329), - {0} + { } }; MODULE_DEVICE_TABLE(pci, ddb_id_table); diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index f01ecdb0b627..cf50898f9a92 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -14,7 +14,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/dvb/ca.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 80d2e143384b..ae4544042a74 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -1209,15 +1209,9 @@ static void dm1105_remove(struct pci_dev *pdev) static const struct pci_device_id dm1105_id_table[] = { { - .vendor = PCI_VENDOR_ID_TRIGEM, - .device = PCI_DEVICE_ID_DM1105, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(TRIGEM, PCI_DEVICE_ID_DM1105), }, { - .vendor = PCI_VENDOR_ID_AXESS, - .device = PCI_DEVICE_ID_DM05, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(AXESS, PCI_DEVICE_ID_DM05), }, { /* empty */ }, diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 7bddcbba4cf1..660aab6b62e0 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -577,8 +577,8 @@ static void dt3155_remove(struct pci_dev *pdev) } static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) }, - { 0, /* zero marks the end */ }, + { PCI_VDEVICE(INTEL, DT3155_DEVICE_ID) }, + { /* zero marks the end */ }, }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/media/pci/hws/hws_v4l2_ioctl.h b/drivers/media/pci/hws/hws_v4l2_ioctl.h index 53044f78d6fa..9a81e940e33e 100644 --- a/drivers/media/pci/hws/hws_v4l2_ioctl.h +++ b/drivers/media/pci/hws/hws_v4l2_ioctl.h @@ -17,14 +17,10 @@ int hws_vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *setfp int hws_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i); int hws_vidioc_g_input(struct file *file, void *priv, unsigned int *i); int hws_vidioc_s_input(struct file *file, void *priv, unsigned int i); -int hws_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); -int hws_vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); int hws_vidioc_dv_timings_cap(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap); int hws_vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings); - -int hws_vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); int hws_vidioc_g_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings); int hws_vidioc_enum_dv_timings(struct file *file, void *fh, diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index 88581a4c081d..1bb3a3e98d6b 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -49,6 +49,8 @@ * Please keep the list sorted by ACPI HID. */ static const struct ipu_sensor_config ipu_supported_sensors[] = { + /* Himax HM1092 */ + IPU_SENSOR_CONFIG("HIMX1092", 2, 180000000, 180480000), /* Himax HM11B1 */ IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000), /* Himax HM2170 */ @@ -97,6 +99,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), /* Sony IMX471 */ IPU_SENSOR_CONFIG("SONY471A", 1, 200000000), + /* Sony IMX471 (found on Lenovo X1 Carbon G14) */ + IPU_SENSOR_CONFIG("TBE20A0", 1, 200000000), /* Toshiba T4KA3 */ IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), }; @@ -134,6 +138,60 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { }, .driver_data = "OVTI02C1", }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 16 (Dell 16 Premium) DA16250"), + }, + .driver_data = "OVTI02C1", + }, + /* + * The first four characters of DMI_BOARD_NAME identify the Lenovo + * machine type/model. For example, a DMI_BOARD_NAME starting with + * "21Q6" indicates a ThinkPad X9-15. + * + * Reference: https://psref.lenovo.com/ + */ + { + /* Lenovo X9-14 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21QA"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-14 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21QB"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21Q6"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21Q7"), + }, + .driver_data = "SONY471A", + }, + { + /* Samsung Galaxy Book5 Pro 360 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "960QHA"), + }, + .driver_data = "OVTI02E1", + }, {} /* Terminating entry */ }; @@ -171,6 +229,7 @@ static const struct acpi_device_id ivsc_acpi_ids[] = { { "INTC10DE" }, /* LNL */ { "INTC10E0" }, /* ARL */ { "INTC10E1" }, /* PTL */ + { "INTC10FA" }, /* NVL */ }; static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev) @@ -180,8 +239,8 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) { const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i]; struct acpi_device *consumer, *ivsc_adev; - acpi_handle handle = acpi_device_handle(ACPI_PTR(adev)); + for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1) /* camera sensor depends on IVSC in DSDT if exist */ for_each_acpi_consumer_dev(ivsc_adev, consumer) @@ -298,9 +357,11 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, { const struct dmi_system_id *dmi_id; - dmi_id = dmi_first_match(upside_down_sensor_dmi_ids); - if (dmi_id && acpi_dev_hid_match(adev, dmi_id->driver_data)) - return 180; + /* A machine may have one entry per sensor, so check all matches. */ + for (dmi_id = dmi_first_match(upside_down_sensor_dmi_ids); dmi_id; + dmi_id = dmi_first_match(dmi_id + 1)) + if (acpi_dev_hid_match(adev, dmi_id->driver_data)) + return 180; switch (ssdb->degree) { case IPU_SENSOR_ROTATION_NORMAL: diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 986b9afd7cb5..eb1824ee86fd 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1961,7 +1961,7 @@ static const struct dev_pm_ops cio2_pm_ops = { }; static const struct pci_device_id cio2_pci_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, CIO2_PCI_ID) }, + { PCI_VDEVICE(INTEL, CIO2_PCI_ID) }, { } }; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c index c9cdeb7054d7..24db2763de54 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c @@ -761,6 +761,7 @@ static int isys_notifier_init(struct ipu6_isys *isys) err_parse: fwnode_handle_put(ep); + v4l2_async_nf_cleanup(&isys->notifier); return ret; } diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c index d033d4618169..5449a2006bcc 100644 --- a/drivers/media/pci/intel/ipu6/ipu6.c +++ b/drivers/media/pci/intel/ipu6/ipu6.c @@ -400,7 +400,6 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant); if (IS_ERR(isys_adev->mmu)) { put_device(&isys_adev->auxdev.dev); - kfree(pdata); return dev_err_cast_probe(dev, isys_adev->mmu, "ipu6_mmu_init(isys_adev->mmu) failed\n"); } @@ -408,10 +407,8 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, isys_adev->mmu->dev = &isys_adev->auxdev.dev; ret = ipu6_bus_add_device(isys_adev); - if (ret) { - kfree(pdata); + if (ret) return ERR_PTR(ret); - } return isys_adev; } @@ -444,7 +441,6 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant); if (IS_ERR(psys_adev->mmu)) { put_device(&psys_adev->auxdev.dev); - kfree(pdata); return dev_err_cast_probe(&pdev->dev, psys_adev->mmu, "ipu6_mmu_init(psys_adev->mmu) failed\n"); } @@ -452,10 +448,8 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, psys_adev->mmu->dev = &psys_adev->auxdev.dev; ret = ipu6_bus_add_device(psys_adev); - if (ret) { - kfree(pdata); + if (ret) return ERR_PTR(ret); - } return psys_adev; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index e0091a8e5c88..b9ea56ec9593 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -60,11 +60,9 @@ EXPORT_SYMBOL(ivtv_ext_init); /* add your revision and whatnot here */ static const struct pci_device_id ivtv_pci_tbl[] = { - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV15) }, + { PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV16) }, + { } }; MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c index ae7a00f46257..af086c4cbe1a 100644 --- a/drivers/media/pci/ivtv/ivtv-vbi.c +++ b/drivers/media/pci/ivtv/ivtv-vbi.c @@ -330,7 +330,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 unsigned lines = 0; /* find the first valid line */ - for (i = 0; i < size; i++, buf++) { + for (i = 0; i + 3 < size; i++, buf++) { if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) break; } diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index 6e563ecd94e8..f357ca268dd1 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -58,11 +58,9 @@ #define TERRATEC 0x153b #define MAKE_ENTRY(__subven, __subdev, __configptr, __rc) { \ - .vendor = TWINHAN_TECHNOLOGIES, \ - .device = MANTIS, \ - .subvendor = (__subven), \ - .subdevice = (__subdev), \ - .driver_data = (unsigned long) \ + PCI_DEVICE_SUB(TWINHAN_TECHNOLOGIES, MANTIS, \ + (__subven), (__subdev)), \ + .driver_data = (unsigned long) \ &(struct mantis_pci_drvdata){__configptr, __rc} \ } diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c index d23d854581c5..cbd193e06536 100644 --- a/drivers/media/pci/mgb4/mgb4_core.c +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -694,9 +694,9 @@ static void mgb4_remove(struct pci_dev *pdev) } static const struct pci_device_id mgb4_pci_ids[] = { - { PCI_DEVICE(DIGITEQ_VID, T100_DID), }, - { PCI_DEVICE(DIGITEQ_VID, T200_DID), }, - { 0, } + { PCI_DEVICE(DIGITEQ_VID, T100_DID) }, + { PCI_DEVICE(DIGITEQ_VID, T200_DID) }, + { } }; MODULE_DEVICE_TABLE(pci, mgb4_pci_ids); diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index ec08023b5d5e..00f81e4c8e8d 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -1014,7 +1014,7 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) static const struct pci_device_id netup_unidvb_pci_tbl[] = { { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ - { 0, } + { } }; MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7dbc21e1a2ca..a1a83f3bb6b4 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -1155,8 +1155,7 @@ static const struct ngene_info ngene_info_terratec = { /****************************************************************************/ #define NGENE_ID(_subvend, _subdev, _driverdata) { \ - .vendor = NGENE_VID, .device = NGENE_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ + PCI_DEVICE_SUB(NGENE_VID, NGENE_PID, (_subvend), (_subdev)), \ .driver_data = (unsigned long) &_driverdata } /****************************************************************************/ @@ -1173,7 +1172,7 @@ static const struct pci_device_id ngene_id_tbl[] = { NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), NGENE_ID(0x1461, 0x062e, ngene_info_m780), NGENE_ID(0x153b, 0x1167, ngene_info_terratec), - {0} + { } }; MODULE_DEVICE_TABLE(pci, ngene_id_tbl); diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index 22c2222d5c4d..77b3e4eec54d 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -762,10 +762,7 @@ static void pluto2_remove(struct pci_dev *pdev) static const struct pci_device_id pluto2_id_table[] = { { - .vendor = PCI_VENDOR_ID_SCM, - .device = PCI_DEVICE_ID_PLUTO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(SCM, PCI_DEVICE_ID_PLUTO2), }, { /* empty */ }, diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index e80fb4ebfda6..a7d665407460 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -5800,1317 +5800,758 @@ const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); struct pci_device_id saa7134_pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x6752, - .driver_data = SAA7134_BOARD_EMPRESS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x4e85, - .driver_data = SAA7134_BOARD_MONSTERTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1142, - .driver_data = SAA7134_BOARD_CINERGY400, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1143, - .driver_data = SAA7134_BOARD_CINERGY600, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1158, - .driver_data = SAA7134_BOARD_CINERGY600_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1162, - .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5169, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0212, /* minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x14c0, - .subdevice = 0x1212, /* minipci, LR1212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x0212, /* OEM minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0214, /* Standard PCI, LR214 Rev E and earlier (SAA7135) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x5214, /* Standard PCI, LR214 Rev F onwards (SAA7131) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, /* KYE */ - .subdevice = 0x0214, /* Genius VideoWonder ProTV */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0003, - .driver_data = SAA7134_BOARD_MD7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */ - .subdevice = 0x5000, /* only analog TV and DVB-T for now */ - .driver_data = SAA7134_BOARD_MD7134, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_PROTEUS_PRO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226b, - .driver_data = SAA7134_BOARD_ELSA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226a, - .driver_data = SAA7134_BOARD_ELSA_500TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226c, - .driver_data = SAA7134_BOARD_ELSA_700TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4842, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4845, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4830, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4843, - .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4840, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xa006, - .driver_data = SAA7134_BOARD_TVSTATION_DVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x7133, - .driver_data = SAA7134_BOARD_VA1000POWER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_MATROX, - .subdevice = 0x48d0, - .driver_data = SAA7134_BOARD_CRONOS_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70b, - .driver_data = SAA7134_BOARD_MD2819, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a1, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_PROTEUS_PRO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a2, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x6752), + .driver_data = SAA7134_BOARD_EMPRESS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1131, 0x4e85), + .driver_data = SAA7134_BOARD_MONSTERTV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1142), + .driver_data = SAA7134_BOARD_CINERGY400, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1143), + .driver_data = SAA7134_BOARD_CINERGY600, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1158), + .driver_data = SAA7134_BOARD_CINERGY600_MK3, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1162), + .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5169, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + }, { + /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x4e42, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5168, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO2000, + }, { + /* Typhoon LifeView FlyTV Prime30 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x4e42, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO2000, + }, { + /* minipci, LR212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + /* minipci, LR1212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x14c0, 0x1212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, + }, { + /* OEM minipci, LR212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x0212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + /* + * Animation Technologies (LifeView) + * Standard PCI, LR214 Rev E and earlier (SAA7135) + */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, + }, { + /* + * Animation Technologies (LifeView) + * Standard PCI, LR214 Rev F onwards (SAA7131) + */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x5214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, + }, { + /* KYE Genius VideoWonder ProTV */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1489, 0x0214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x0003), + .driver_data = SAA7134_BOARD_MD7134, + }, { + /* CTX946 analog TV, HW mpeg, DVB-T; only analog TV and DVB-T for now */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x5000), + .driver_data = SAA7134_BOARD_MD7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226b), + .driver_data = SAA7134_BOARD_ELSA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226a), + .driver_data = SAA7134_BOARD_ELSA_500TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226c), + .driver_data = SAA7134_BOARD_ELSA_700TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4842), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_ASUSTEK, 0x4845), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4830), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_ASUSTEK, 0x4843), + .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4840), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0xfe01), + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1894, 0xfe01), + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1894, 0xa006), + .driver_data = SAA7134_BOARD_TVSTATION_DVR, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1131, 0x7133), + .driver_data = SAA7134_BOARD_VA1000POWER, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_10MOONSTVMASTER, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_MATROX, 0x48d0), + .driver_data = SAA7134_BOARD_CRONOS_PLUS, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa70b), + .driver_data = SAA7134_BOARD_MD2819, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa7a1), + .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa7a2), + .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x2115), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0xa115), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x2108), + .driver_data = SAA7134_BOARD_AVERMEDIA_305, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x10ff), + .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_AVERMEDIA_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x10ff, - .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, - },{ /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xd6ee, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, - },{ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xd6ee), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, + }, { /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xb7e9, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xb7e9), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, }, { - /* TransGear 3000TV */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x050c, - .driver_data = SAA7134_BOARD_TG3000TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002b, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002d, - .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb4, - .driver_data = SAA7134_BOARD_ECS_TVP3XP, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1019, - .subdevice = 0x4cb5, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb6, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x12ab, - .subdevice = 0x0800, - .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x153b, - .subdevice = 0x1152, - .driver_data = SAA7134_BOARD_CINERGY200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70a, - .driver_data = SAA7134_BOARD_AVERMEDIA_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc200, - .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1540, - .subdevice = 0x9524, - .driver_data = SAA7134_BOARD_PROVIDEO_PV952, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0306, /* PCI version */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31f, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf11d, - .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + /* AVerMedia TransGear 3000TV */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x050c), + .driver_data = SAA7134_BOARD_TG3000TV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4155, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x11bd, 0x002b), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4255, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x11bd, 0x002d), + .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0350, /* PCI version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0351, /* PCI version, new revision */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x1370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0502, /* LifeView LR502 OEM */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci NTSC version */ - .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci PAL/SECAM version */ - .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */ - .subdevice = 0x4091, - .driver_data = SAA7134_BOARD_BEHOLD_409FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5456, /* GoTView */ - .subdevice = 0x7135, - .driver_data = SAA7134_BOARD_GOTVIEW_7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc901, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_RTD_VFG7350, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7330, - .driver_data = SAA7134_BOARD_RTD_VFG7330, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x1044, - .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1131, - .subdevice = 0x4ee9, - .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002e, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4862, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2018, - .driver_data = SAA7134_BOARD_PHILIPS_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x6231, /* tda8275a, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x8624, /* tda8275, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1160, - .driver_data = SAA7134_BOARD_CINERGY250PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */ - .subvendor = 0x5168, - .subdevice = 0x0319, - .driver_data = SAA7134_BOARD_FLYDVB_TRIO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0301, - .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0331, - .subdevice = 0x1421, - .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7201, - .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7250, - .driver_data = SAA7134_BOARD_KWORLD_DVBT_210, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7352, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0xa134, - .driver_data = SAA7134_BOARD_KWORLD_PC150U, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1019, 0x4cb4), + .driver_data = SAA7134_BOARD_ECS_TVP3XP, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1019, 0x4cb5), + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1019, 0x4cb6), + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x12ab, 0x0800), + .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x153b, 0x1152), + .driver_data = SAA7134_BOARD_CINERGY200, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x9715), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa70a), + .driver_data = SAA7134_BOARD_AVERMEDIA_307, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x185b, 0xc200), + .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1540, 0x9524), + .driver_data = SAA7134_BOARD_PROVIDEO_PV952, + }, { + /* Cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* PCI version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0306), + .driver_data = SAA7134_BOARD_FLYDVBTDUO, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31f), + .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf11d), + .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x4155), + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x4255), + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, + }, { + /* PCI version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0350), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* PCI version, new revision */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0351), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0370), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x1370), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* Typhoon LifeView LR502 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* mini pci NTSC version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x0210), + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, + }, { + /* mini pci PAL/SECAM version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x0210), + .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, + }, { + /* subvendor == 0 shouldn't break anything, since subdevice id seems unique */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x4091), + .driver_data = SAA7134_BOARD_BEHOLD_409FM, + }, { + /* GoTView */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5456, 0x7135), + .driver_data = SAA7134_BOARD_GOTVIEW_7135, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc901), + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1435, 0x7350), + .driver_data = SAA7134_BOARD_RTD_VFG7350, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1435, 0x7330), + .driver_data = SAA7134_BOARD_RTD_VFG7330, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x1044), + .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1131, 0x4ee9), + .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x11bd, 0x002e), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4862), + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2018), + .driver_data = SAA7134_BOARD_PHILIPS_TIGER, + }, { + /* tda8275a, ks003 IR */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x6231), + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x7360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x6360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0005, - .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0300, - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, - .subdevice = 0x0300,/* LR300 */ - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1489, - .subdevice = 0x0301, + /* tda8275, ks003 IR */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x8624), + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1160), + .driver_data = SAA7134_BOARD_CINERGY250PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0319), + .driver_data = SAA7134_BOARD_FLYDVB_TRIO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x2c05), + .driver_data = SAA7134_BOARD_AVERMEDIA_777, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0301), + .driver_data = SAA7134_BOARD_FLYDVBT_LR301, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0331, 0x1421), + .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7201), + .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7250), + .driver_data = SAA7134_BOARD_KWORLD_DVBT_210, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7350), + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7352), + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0xa134), + .driver_data = SAA7134_BOARD_KWORLD_PC150U, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x7360), + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x6360), + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x0005), + .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0300), + .driver_data = SAA7134_BOARD_FLYDVBS_LR300, + }, { + /* LR300 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x4e42, 0x0300), + .driver_data = SAA7134_BOARD_FLYDVBS_LR300, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1489, 0x0301), .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0304, + }, { + /* Animation Technologies (LifeView) */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0304), .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3306, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3502, /* what's the difference to 0x3306 ?*/ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0007, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0008, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x000d, /* triple CTX948_V1.1.1 */ - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3306), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + /* what's the difference to .subdevice = 0x3306 above? */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3502), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + /* FlyDVB-T Hybrid Mini PCI */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3307), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0007), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0008), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + /* triple CTX948_V1.1.1 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x000d), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x2c05), + .driver_data = SAA7134_BOARD_AVERMEDIA_777, + }, { + /* Cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1489, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* Philips Proteus PRO 2309 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0919, 0x2003), + .driver_data = SAA7134_BOARD_PROTEUS_2309, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x2c00), + .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x4860), + .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x11bd, 0x002f), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x9715), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa11b), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4876), + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6700), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6701), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6702), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6703), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6704), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6705), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6706), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6707), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6708), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6709), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x670a), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1172), + .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0919, /* Philips Proteus PRO 2309 */ - .subdevice = 0x2003, - .driver_data = SAA7134_BOARD_PROTEUS_2309, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c00, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4860, - .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002f, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa11b, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2342), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4876, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6700, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6701, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6702, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6703, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6704, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6705, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6706, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6707, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6708, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6709, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x670a, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1172, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2342, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x2341, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x3016, - .subdevice = 0x2344, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x230f, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1a7f, - .subdevice = 0x2008, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1131, 0x2341), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1a7f, - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x3016, 0x2344), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1175, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31e, - .driver_data = SAA7134_BOARD_AVERMEDIA_M102, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4E42, /* MSI */ - .subdevice = 0x0306, /* TV@nywhere DUO */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4871, - .driver_data = SAA7134_BOARD_ASUS_P7131_4871, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4857, /* REV:1.00 */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */ - .subdevice = 0x2003, /* OEM cardbus */ - .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2304, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ - .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4016, - .driver_data = SAA7134_BOARD_BEHOLD_401, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4036, - .driver_data = SAA7134_BOARD_BEHOLD_403, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4037, - .driver_data = SAA7134_BOARD_BEHOLD_403FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4050, - .driver_data = SAA7134_BOARD_BEHOLD_405, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4051, - .driver_data = SAA7134_BOARD_BEHOLD_405FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4070, - .driver_data = SAA7134_BOARD_BEHOLD_407, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4071, - .driver_data = SAA7134_BOARD_BEHOLD_407FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x4090, - .driver_data = SAA7134_BOARD_BEHOLD_409, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1131, 0x230f), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5050, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x5070, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5090, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5201, - .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6190, - .driver_data = SAA7134_BOARD_BEHOLD_M6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6193, - .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1a7f, 0x2008), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6191, - .driver_data = SAA7134_BOARD_BEHOLD_M63, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x3502, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1a7f, 0x2108), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/ - .subdevice = 0x0022, - .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1175), + .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0010, /* Medion version CTX953_V.1.4.3 */ - .driver_data = SAA7134_BOARD_CREATIX_CTX953, + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31e), + .driver_data = SAA7134_BOARD_AVERMEDIA_M102, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, /* MSI */ - .subdevice = 0x8625, /* TV@nywhere A/D v1.1 */ - .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf436, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506, + /* MSI TV@nywhere DUO */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4E42, 0x0306), + .driver_data = SAA7134_BOARD_FLYDVBTDUO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf936, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16D, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4871), + .driver_data = SAA7134_BOARD_ASUS_P7131_4871, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa836, - .driver_data = SAA7134_BOARD_AVERMEDIA_M115, + /* REV:1.00 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4857), + .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_T750, + /* SinoVideo PCI 2309 Proteus (7134) OEM cardbus */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0919, 0x2003), + .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x1421, - .subdevice = 0x0380, - .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2304), + .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5169, - .subdevice = 0x1502, - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + /* Avermedia Technologies Inc AVerTV DVB-T Super 007 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf01d), + .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6290, - .driver_data = SAA7134_BOARD_BEHOLD_H6, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4016), + .driver_data = SAA7134_BOARD_BEHOLD_401, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf636, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4036), + .driver_data = SAA7134_BOARD_BEHOLD_403, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf736, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4037), + .driver_data = SAA7134_BOARD_BEHOLD_403FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4878, /* REV:1.02G */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4050), + .driver_data = SAA7134_BOARD_BEHOLD_405, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x48cd, - .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4051), + .driver_data = SAA7134_BOARD_BEHOLD_405FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x17de, - .subdevice = 0x7128, - .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4070), + .driver_data = SAA7134_BOARD_BEHOLD_407, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0xb136, - .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4071), + .driver_data = SAA7134_BOARD_BEHOLD_407FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31d, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x4090), + .driver_data = SAA7134_BOARD_BEHOLD_409, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_S350, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x505B), + .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7595, - .driver_data = SAA7134_BOARD_BEHOLD_X7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x5051), + .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x19d1, /* RoverMedia */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5ace, 0x5050), + .driver_data = SAA7134_BOARD_BEHOLD_505FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x5071), + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4847, - .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x507B), + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x107d, - .subdevice = 0x6655, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x5070), + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x13c2, - .subdevice = 0x2804, - .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x5090), + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7190, - .driver_data = SAA7134_BOARD_BEHOLD_H7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x5201), + .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7090, - .driver_data = SAA7134_BOARD_BEHOLD_A7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6070), + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6071), + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5030, - .driver_data = SAA7134_BOARD_BEHOLD_503FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6072), + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5010, - .driver_data = SAA7134_BOARD_BEHOLD_501, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6073), + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x17de, - .subdevice = 0xd136, - .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6090), + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x6000, - .subdevice = 0x0811, - .driver_data = SAA7134_BOARD_SENSORAY811_911, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6091), + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x6000, - .subdevice = 0x0911, - .driver_data = SAA7134_BOARD_SENSORAY811_911, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6092), + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */ - .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6093), + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1905, /* WIS */ - .subdevice = 0x7007, - .driver_data = SAA7134_BOARD_WIS_VOYAGER, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6190), + .driver_data = SAA7134_BOARD_BEHOLD_M6, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa10a, - .driver_data = SAA7134_BOARD_AVERMEDIA_505, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6193), + .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x107d, - .subdevice = 0x6f3a, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6191), + .driver_data = SAA7134_BOARD_BEHOLD_M63, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1779, /* V One Multimedia PTE Ltd */ - .subdevice = 0x13cf, - .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x3502), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x107d, - .subdevice = 0x6f2e, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H, + /*Twinhan Technology Co. Ltd*/ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1822, 0x0022), + .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, + }, { + /* Medion version CTX953_V.1.4.3 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0010), + .driver_data = SAA7134_BOARD_CREATIX_CTX953, + }, { + /* MSI TV@nywhere A/D v1.1 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x8625), + .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf436), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf936), + .driver_data = SAA7134_BOARD_AVERMEDIA_A16D, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa836), + .driver_data = SAA7134_BOARD_AVERMEDIA_M115, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_T750, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0380), + .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5169, 0x1502), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6290), + .driver_data = SAA7134_BOARD_BEHOLD_H6, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf636), + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf736), + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { + /* REV:1.02G */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4878), + .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x48cd), + .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x17de, 0x7128), + .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0xb136), + .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31d), + .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_S350, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7595), + .driver_data = SAA7134_BOARD_BEHOLD_X7, + }, { + /* RoverMedia LifeView FlyTV Prime30 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x19d1, 0x0138), + .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x4847), + .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x107d, 0x6655), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x13c2, 0x2804), + .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7190), + .driver_data = SAA7134_BOARD_BEHOLD_H7, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7090), + .driver_data = SAA7134_BOARD_BEHOLD_A7, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7135, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x5030), + .driver_data = SAA7134_BOARD_BEHOLD_503FM, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5ace, 0x5010), + .driver_data = SAA7134_BOARD_BEHOLD_501, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x17de, 0xd136), + .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x6000, 0x0811), + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x6000, 0x0911), + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + /* Avermedia Technologies Inc AverTV Satellite Hybrid+FM A706 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x2055), + .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + }, { + /* WIS */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1905, 0x7007), + .driver_data = SAA7134_BOARD_WIS_VOYAGER, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0xa10a), + .driver_data = SAA7134_BOARD_AVERMEDIA_505, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x107d, 0x6f3a), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM, + }, { + /* V One Multimedia PTE Ltd */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1779, 0x13cf), + .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x107d, 0x6f2e), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H, }, { /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0), + .driver_data = SAA7134_BOARD_NOAUTO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0), + .driver_data = SAA7134_BOARD_NOAUTO, + }, { /* --- default catch --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7135), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { /* --- end of list --- */ } }; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 1eef4e102972..f2298e8bb96d 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -361,22 +361,14 @@ static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2401, - .driver_data = (unsigned long) &hexium_gemini_4bnc, - }, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2401), + .driver_data = (unsigned long)&hexium_gemini_4bnc, + }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2402, - .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, - }, - { - .vendor = 0, - } + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2402), + .driver_data = (unsigned long)&hexium_gemini_dual_4bnc, + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 6f1b4bff7596..8ef2a4e8235d 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -425,29 +425,16 @@ static struct saa7146_pci_extension_data hexium_orion_4bnc = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long) &hexium_hv_pci6, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x0101, - .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2101, - .driver_data = (unsigned long) &hexium_orion_4bnc, - }, - { - .vendor = 0, - } + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000), + .driver_data = (unsigned long)&hexium_hv_pci6, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x0101), + .driver_data = (unsigned long)&hexium_orion_1svhs_3bnc, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2101), + .driver_data = (unsigned long)&hexium_orion_4bnc, + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index d931b4e3052f..d759e8a87e24 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -821,14 +821,10 @@ static struct saa7146_pci_extension_data mxb = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000), .driver_data = (unsigned long)&mxb, - }, { - .vendor = 0, - } + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 6bcde506adf5..ac5eb6b923e2 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -878,6 +878,9 @@ static int get_resources(struct saa7164_dev *dev) if (request_mem_region(pci_resource_start(dev->pci, 2), pci_resource_len(dev->pci, 2), dev->name)) return 0; + + release_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); } printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n", @@ -1000,8 +1003,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev) dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); - saa7164_devcount--; - return -ENODEV; + goto err_devlist; } /* PCI/e allocations */ @@ -1039,7 +1041,7 @@ err_ioremap_bar2: iounmap(dev->lmmio); err_ioremap_bar0: release_resources(dev); - +err_devlist: scoped_guard(mutex, &devlist) { list_del(&dev->devlist); } @@ -1535,10 +1537,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev) static const struct pci_device_id saa7164_pci_tbl[] = { { /* SAA7164 */ - .vendor = 0x1131, - .device = 0x7164, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x1131, 0x7164), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c index 387c29958c98..5f18abb48b17 100644 --- a/drivers/media/pci/smipcie/smipcie-main.c +++ b/drivers/media/pci/smipcie/smipcie-main.c @@ -1097,8 +1097,7 @@ static const struct smi_cfg_info technotrend_s2_4200_cfg = { /* PCI IDs */ #define SMI_ID(_subvend, _subdev, _driverdata) { \ - .vendor = SMI_VID, .device = SMI_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ + PCI_DEVICE_SUB(SMI_VID, SMI_PID, (_subvend), (_subdev)), \ .driver_data = (unsigned long)&_driverdata } static const struct pci_device_id smi_id_table[] = { @@ -1106,7 +1105,7 @@ static const struct pci_device_id smi_id_table[] = { SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), - {0} + { } }; MODULE_DEVICE_TABLE(pci, smi_id_table); diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 11cddf4b4312..282c2c87151f 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -656,7 +656,7 @@ static const struct pci_device_id solo_id_table[] = { .driver_data = SOLO_DEV_6110 }, { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), .driver_data = SOLO_DEV_6110 }, - {0,} + { } }; MODULE_DEVICE_TABLE(pci, solo_id_table); diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 8b496b959d7e..eb82a670c5bf 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -1537,9 +1537,7 @@ static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), - { - .vendor = 0, - } + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 95370156aff5..c9f419fc07ad 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -858,9 +858,7 @@ static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52), - { - .vendor = 0, - } + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c index 832788603f88..6ec8bce4ac4f 100644 --- a/drivers/media/pci/tw5864/tw5864-core.c +++ b/drivers/media/pci/tw5864/tw5864-core.c @@ -72,8 +72,8 @@ MODULE_PARM_DESC(video_nr, "video devices numbers array"); * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ static const struct pci_device_id tw5864_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_5864)}, - {0,} + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_5864) }, + { } }; void tw5864_irqmask_apply(struct tw5864_dev *dev) diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 08b7ce1043aa..509d7ddec150 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -62,14 +62,14 @@ static atomic_t tw68_instance = ATOMIC_INIT(0); * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ static const struct pci_device_id tw68_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6800)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6801)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6804)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_4)}, - {0,} + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6800) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6801) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6804) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_1) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_2) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_3) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_4) }, + { } }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index a10e38221817..5a4ab329c06e 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -416,25 +416,24 @@ static void tw686x_remove(struct pci_dev *pci_dev) /* driver_data is number of A/V channels */ static const struct pci_device_id tw686x_pci_tbl[] = { { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864), - .driver_data = 4 - }, - { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */ - .driver_data = 4 | TYPE_SECOND_GEN + PCI_VDEVICE(TECHWELL, 0x6864), + .driver_data = 4, + }, { + PCI_VDEVICE(TECHWELL, 0x6865), /* not tested */ + .driver_data = 4 | TYPE_SECOND_GEN, }, /* * TW6868 supports 8 A/V channels with an external TW2865 chip; * not supported by the driver. */ { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */ - .driver_data = 4 + PCI_VDEVICE(TECHWELL, 0x6868), /* not tested */ + .driver_data = 4, + }, { + PCI_VDEVICE(TECHWELL, 0x6869), + .driver_data = 8 | TYPE_SECOND_GEN }, - { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869), - .driver_data = 8 | TYPE_SECOND_GEN}, - {} + { } }; MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl); diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index f707bdc1fb0f..e5ff407318df 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -75,8 +75,9 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(ZORAN_VERSION); #define ZR_DEVICE(subven, subdev, data) { \ - .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ - .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } + PCI_DEVICE_SUB(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, \ + (subven), (subdev)), \ + .driver_data = (data) } static const struct pci_device_id zr36067_pci_tbl[] = { ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10_PLUS), @@ -84,7 +85,7 @@ static const struct pci_device_id zr36067_pci_tbl[] = { ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), - {0} + { } }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); @@ -885,7 +886,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_ static void zoran_exit_video_devices(struct zoran *zr) { video_unregister_device(zr->video_dev); - kfree(zr->video_dev); + zr->video_dev = NULL; } static int zoran_init_video_devices(struct zoran *zr) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 0b33e927bd59..2c7699b6610b 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -72,6 +72,7 @@ source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/broadcom/Kconfig" source "drivers/media/platform/cadence/Kconfig" source "drivers/media/platform/chips-media/Kconfig" +source "drivers/media/platform/dreamchip/Kconfig" source "drivers/media/platform/imagination/Kconfig" source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 16c185752474..d47c47d817da 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -15,6 +15,7 @@ obj-y += atmel/ obj-y += broadcom/ obj-y += cadence/ obj-y += chips-media/ +obj-y += dreamchip/ obj-y += imagination/ obj-y += intel/ obj-y += marvell/ diff --git a/drivers/media/platform/amd/isp4/Kconfig b/drivers/media/platform/amd/isp4/Kconfig index 9d1927af1cb8..77b61fae82ba 100644 --- a/drivers/media/platform/amd/isp4/Kconfig +++ b/drivers/media/platform/amd/isp4/Kconfig @@ -5,6 +5,7 @@ config VIDEO_AMD_ISP4_CAPTURE depends on DRM_AMDGPU && DRM_AMD_ISP depends on HAS_DMA depends on VIDEO_DEV + select MEDIA_CONTROLLER select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS select VIDEOBUF2_V4L2 diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c index 8d73f66bb42c..4801617f9559 100644 --- a/drivers/media/platform/amd/isp4/isp4_interface.c +++ b/drivers/media/platform/amd/isp4/isp4_interface.c @@ -148,12 +148,9 @@ static void isp4if_gpu_mem_free(struct isp4_interface *ispif, struct isp4if_gpu_mem_info **mem_info_ptr) { struct isp4if_gpu_mem_info *mem_info = *mem_info_ptr; - struct device *dev = ispif->dev; - if (!mem_info) { - dev_err(dev, "invalid mem_info\n"); + if (!mem_info) return; - } *mem_info_ptr = NULL; isp_kernel_buffer_free(&mem_info->mem_handle, &mem_info->gpu_mc_addr, @@ -201,6 +198,7 @@ static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif) error_no_memory: dev_err(dev, "failed to allocate gpu memory\n"); + isp4if_dealloc_fw_gpumem(ispif); return -ENOMEM; } @@ -375,7 +373,7 @@ static int isp4if_send_fw_cmd(struct isp4_interface *ispif, u32 cmd_id, return -ENOMEM; /* Get two references: one for the resp thread, one for us */ - atomic_set(&ele->refcnt, 2); + refcount_set(&ele->refcnt, 2); init_completion(&ele->cmd_done); } @@ -455,7 +453,7 @@ err_dequeue_ele: put_ele_ref: /* Don't free the command if we didn't put the last reference */ - if (ele && atomic_dec_return(&ele->refcnt)) + if (ele && !refcount_dec_and_test(&ele->refcnt)) ele = NULL; free_ele: diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h index ce3ac9b9e5cd..04db71cd54e6 100644 --- a/drivers/media/platform/amd/isp4/isp4_interface.h +++ b/drivers/media/platform/amd/isp4/isp4_interface.h @@ -68,7 +68,7 @@ struct isp4if_cmd_element { u32 seq_num; u32 cmd_id; struct completion cmd_done; - atomic_t refcnt; + refcount_t refcnt; }; struct isp4_interface { diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c b/drivers/media/platform/amd/isp4/isp4_subdev.c index 48deea79ce6c..6716ab9c128a 100644 --- a/drivers/media/platform/amd/isp4/isp4_subdev.c +++ b/drivers/media/platform/amd/isp4/isp4_subdev.c @@ -391,7 +391,7 @@ static void isp4sd_fw_resp_cmd_done(struct isp4_subdev *isp_subdev, if (ele) { complete(&ele->cmd_done); - if (atomic_dec_and_test(&ele->refcnt)) + if (refcount_dec_and_test(&ele->refcnt)) kfree(ele); } } @@ -687,7 +687,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) if (ret) { dev_err(dev, "fail to power on isp_subdev ret %d\n", ret); - goto err_deinit; + goto err_module_disable; } /* ISPPG ISP Power Status */ @@ -697,7 +697,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) dev_err(dev, "fail to set performance state %u, ret %d\n", perf_state, ret); - goto err_deinit; + goto err_power_off; } ispif->status = ISP4IF_STATUS_PWR_ON; @@ -709,12 +709,12 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) ret = isp4if_start(ispif); if (ret) { dev_err(dev, "fail to start isp_subdev interface\n"); - goto err_deinit; + goto err_perf_restore; } if (isp4sd_start_resp_proc_threads(isp_subdev)) { dev_err(dev, "isp_start_resp_proc_threads fail\n"); - goto err_deinit; + goto err_stop_interface; } dev_dbg(dev, "create resp threads ok\n"); @@ -724,8 +724,24 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) isp_subdev->irq_enabled = true; return 0; -err_deinit: - isp4sd_pwroff_and_deinit(sd); + +err_stop_interface: + isp4if_stop(ispif); +err_perf_restore: + ret = dev_pm_genpd_set_performance_state(dev, ISP4SD_PERFORMANCE_STATE_LOW); + if (ret) + dev_err(dev, "fail to set performance state %u, ret %d\n", + ISP4SD_PERFORMANCE_STATE_LOW, ret); +err_power_off: + isp4hw_wreg(isp_subdev->mmio, ISP_SOFT_RESET, 0); + isp4hw_wreg(isp_subdev->mmio, ISP_POWER_STATUS, 0); + ret = pm_runtime_put_sync(dev); + if (ret) + dev_err(dev, "power off isp_subdev fail %d\n", ret); + ispif->status = ISP4IF_STATUS_PWR_OFF; +err_module_disable: + isp4sd_module_enable(isp_subdev, false); + msleep(20); return -EINVAL; } diff --git a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c index aec3eed0e443..ae0777a20bda 100644 --- a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +++ b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c @@ -535,16 +535,52 @@ static const c3_isp_block_handler c3_isp_params_handlers[] = { [C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc, }; -#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ +static int +c3_isp_params_awb_config_validate(struct device *dev, + const struct v4l2_isp_block_header *block) +{ + const struct c3_isp_params_awb_config *cfg = + (const struct c3_isp_params_awb_config *)block; + + if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AWB_MAX_ZONES) { + dev_dbg(dev, "Invalid number of AWB measurement zones\n"); + return -EINVAL; + } + + return 0; +} + +static int +c3_isp_params_ae_config_validate(struct device *dev, + const struct v4l2_isp_block_header *block) +{ + const struct c3_isp_params_ae_config *cfg = + (const struct c3_isp_params_ae_config *)block; + + if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AE_MAX_ZONES) { + dev_dbg(dev, "Invalid number of AE measurement zones\n"); + return -EINVAL; + } + + return 0; +} + +#define C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, cbk) \ [C3_ISP_PARAMS_BLOCK_ ## block] = { \ .size = sizeof(struct c3_isp_params_ ## data), \ + .block_validate = (cbk)\ } +#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ + C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, NULL) + static const struct v4l2_isp_params_block_type_info c3_isp_params_block_types_info[] = { C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains), - C3_ISP_PARAMS_BLOCK_INFO(AWB_CONFIG, awb_config), - C3_ISP_PARAMS_BLOCK_INFO(AE_CONFIG, ae_config), + C3_ISP_PARAMS_BLOCK_INFO_CBK(AWB_CONFIG, awb_config, + &c3_isp_params_awb_config_validate), + C3_ISP_PARAMS_BLOCK_INFO_CBK(AE_CONFIG, ae_config, + &c3_isp_params_ae_config_validate), C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config), C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma), C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm), diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 0b3d58b9f2f7..2ba4ae20f829 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -973,8 +973,6 @@ static int venc_start_session(struct vpu_inst *inst, u32 type) venc->ready_count = 0; venc->stopped = false; vpu_process_output_buffer(inst); - if (venc->frame_count == 0) - dev_err(inst->dev, "[%d] there is no input when starting\n", inst->id); return 0; error: diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-capture.c b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c index 7aaa5c3f7354..ff01553026fb 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-capture.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c @@ -857,10 +857,8 @@ static int mali_c55_register_cap_dev(struct mali_c55 *mali_c55, cap_dev->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&cap_dev->vdev.entity, 1, &cap_dev->pad); - if (ret) { - mutex_destroy(&cap_dev->lock); + if (ret) goto err_destroy_mutex; - } vb2q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; vb2q->io_modes = VB2_MMAP | VB2_DMABUF; diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-core.c b/drivers/media/platform/arm/mali-c55/mali-c55-core.c index 94a389b3f833..f28e9f4354ac 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-core.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-core.c @@ -698,6 +698,8 @@ static int __mali_c55_power_on(struct mali_c55 *mali_c55) mali_c55->resets); if (ret) { dev_err(mali_c55->dev, "failed to deassert resets\n"); + clk_bulk_disable_unprepare(ARRAY_SIZE(mali_c55->clks), + mali_c55->clks); return ret; } diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-params.c b/drivers/media/platform/arm/mali-c55/mali-c55-params.c index de0e9d898db7..70106276b7e4 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-params.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-params.c @@ -46,6 +46,9 @@ * @awb_config: For header->type == MALI_C55_PARAM_BLOCK_AWB_CONFIG * @shading_config: For header->type == MALI_C55_PARAM_MESH_SHADING_CONFIG * @shading_selection: For header->type == MALI_C55_PARAM_MESH_SHADING_SELECTION + * @ccm: For header->type == MALI_C55_PARAM_BLOCK_CCM + * @gamma: For header->type == MALI_C55_PARAM_BLOCK_GAMMA_FR and + * header->type = MALI_C55_PARAM_BLOCK_GAMMA_DS * @data: Allows easy initialisation of a union variable with a * pointer into a __u8 array. */ @@ -59,6 +62,8 @@ union mali_c55_params_block { const struct mali_c55_params_awb_config *awb_config; const struct mali_c55_params_mesh_shading_config *shading_config; const struct mali_c55_params_mesh_shading_selection *shading_selection; + const struct mali_c55_params_ccm *ccm; + const struct mali_c55_params_gamma *gamma; const __u8 *data; }; @@ -212,6 +217,7 @@ mali_c55_params_aexp_hist_weights(struct mali_c55 *mali_c55, val = params->zone_weights[MALI_C55_MAX_ZONES - 1]; addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * 56); + mali_c55_ctx_write(mali_c55, addr, val & MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK); } static void mali_c55_params_digital_gain(struct mali_c55 *mali_c55, @@ -414,6 +420,116 @@ static void mali_c55_params_lsc_selection(struct mali_c55 *mali_c55, params->mesh_strength); } +static void mali_c55_params_ccm(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_ccm *params = block.ccm; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 0); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][2]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][2]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][2]); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_R, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_G, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_B, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[2]); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_R, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_G, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_B, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[2]); + + mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 1); +} + +static void mali_c55_params_gamma(struct mali_c55 *mali_c55, + union mali_c55_params_block block, + __u32 offset, __u32 lut_base) +{ + const struct mali_c55_params_gamma *params = block.gamma; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_RGB_ENABLE + offset, + MALI_C55_GAMMA_ENABLE_MASK, 0x00); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset, + MALI_C55_GAMMA_GAIN_R_MASK, params->gains[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset, + MALI_C55_GAMMA_GAIN_G_MASK, + MALI_C55_GAMMA_GAIN_G(params->gains[1])); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_B + offset, + MALI_C55_GAMMA_GAIN_B_MASK, params->gains[2]); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_RG + offset, + MALI_C55_GAMMA_OFFSET_R_MASK, + params->offs[0]); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_RG + offset, + MALI_C55_GAMMA_OFFSET_G_MASK, + MALI_C55_GAMMA_OFFSET_G(params->offs[1])); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_B + offset, + MALI_C55_GAMMA_OFFSET_B_MASK, + params->offs[2]); + + for (unsigned int i = 0; i < MALI_C55_NUM_GAMMA_LUT_ELEMENTS; i++) { + __u32 addr = lut_base + (i * 4); + + mali_c55_ctx_write(mali_c55, addr, params->lut[i]); + } + + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_RGB_ENABLE + offset, + MALI_C55_GAMMA_ENABLE_MASK, 0x1); +} + +static void mali_c55_params_gamma_fr(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + return mali_c55_params_gamma(mali_c55, block, + MALI_C55_CAP_DEV_FR_REG_OFFSET, + MALI_C55_REG_FR_GAMMA_RGB_MEM); +} + +static void mali_c55_params_gamma_ds(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + /* We cannot apply parameters to DS if it is not fitted. */ + if (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED)) + return; + + return mali_c55_params_gamma(mali_c55, block, + MALI_C55_CAP_DEV_DS_REG_OFFSET, + MALI_C55_REG_DS_GAMMA_RGB_MEM); +} + static const mali_c55_params_handler mali_c55_params_handlers[] = { [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = &mali_c55_params_sensor_offs, [MALI_C55_PARAM_BLOCK_AEXP_HIST] = &mali_c55_params_aexp_hist, @@ -426,6 +542,9 @@ static const mali_c55_params_handler mali_c55_params_handlers[] = { [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = &mali_c55_params_awb_gains, [MALI_C55_PARAM_MESH_SHADING_CONFIG] = &mali_c55_params_lsc_config, [MALI_C55_PARAM_MESH_SHADING_SELECTION] = &mali_c55_params_lsc_selection, + [MALI_C55_PARAM_BLOCK_CCM] = &mali_c55_params_ccm, + [MALI_C55_PARAM_BLOCK_GAMMA_FR] = &mali_c55_params_gamma_fr, + [MALI_C55_PARAM_BLOCK_GAMMA_DS] = &mali_c55_params_gamma_ds, }; static const struct v4l2_isp_params_block_type_info @@ -463,6 +582,15 @@ mali_c55_params_block_types_info[] = { [MALI_C55_PARAM_MESH_SHADING_SELECTION] = { .size = sizeof(struct mali_c55_params_mesh_shading_selection), }, + [MALI_C55_PARAM_BLOCK_CCM] = { + .size = sizeof(struct mali_c55_params_ccm), + }, + [MALI_C55_PARAM_BLOCK_GAMMA_FR] = { + .size = sizeof(struct mali_c55_params_gamma), + }, + [MALI_C55_PARAM_BLOCK_GAMMA_DS] = { + .size = sizeof(struct mali_c55_params_gamma), + }, }; static_assert(ARRAY_SIZE(mali_c55_params_handlers) == @@ -487,7 +615,7 @@ static int mali_c55_params_g_fmt_meta_out(struct file *file, void *fh, { static const struct v4l2_meta_format mfmt = { .dataformat = V4L2_META_FMT_MALI_C55_PARAMS, - .buffersize = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + .buffersize = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE), }; f->fmt.meta = mfmt; @@ -540,13 +668,13 @@ mali_c55_params_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, if (*num_planes && *num_planes > 1) return -EINVAL; - if (sizes[0] && sizes[0] < v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) + if (sizes[0] && sizes[0] < v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) return -EINVAL; *num_planes = 1; if (!sizes[0]) - sizes[0] = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE); + sizes[0] = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE); return 0; } @@ -556,7 +684,7 @@ static int mali_c55_params_buf_init(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); - buf->config = kvmalloc(v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + buf->config = kvmalloc(v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE), GFP_KERNEL); if (!buf->config) return -ENOMEM; @@ -583,7 +711,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) int ret; ret = v4l2_isp_params_validate_buffer_size(mali_c55->dev, vb, - v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); if (ret) return ret; @@ -593,7 +721,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) * changed to the buffer content whilst the driver processes it. */ - memcpy(buf->config, config, v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + memcpy(buf->config, config, v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); return v4l2_isp_params_validate_buffer(mali_c55->dev, vb, buf->config, mali_c55_params_block_types_info, diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h index f098effde7b4..8a7c3bfe7051 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h +++ b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h @@ -173,7 +173,7 @@ enum mali_c55_interrupts { #define MALI_C55_AEXP_HIST_SWITCH_MASK GENMASK(14, 13) #define MALI_C55_AEXP_HIST_SWITCH(x) ((x) << 13) #define MALI_C55_AEXP_IHIST_DISABLE_MASK BIT(16) -#define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 12) +#define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 16) #define MALI_C55_AEXP_SRC_MASK BIT(24) #define MALI_C55_REG_TPG_CH0 0x18ed8 @@ -422,15 +422,17 @@ enum mali_c55_interrupts { #define MALI_C55_REG_GAMMA_RGB_ENABLE 0x1c064 #define MALI_C55_GAMMA_ENABLE_MASK BIT(0) -#define MALI_C55_REG_GAMMA_GAINS_1 0x1c068 +#define MALI_C55_REG_GAMMA_GAINS_RG 0x1c068 #define MALI_C55_GAMMA_GAIN_R_MASK GENMASK(11, 0) #define MALI_C55_GAMMA_GAIN_G_MASK GENMASK(27, 16) -#define MALI_C55_REG_GAMMA_GAINS_2 0x1c06c +#define MALI_C55_GAMMA_GAIN_G(x) ((x) << 16) +#define MALI_C55_REG_GAMMA_GAINS_B 0x1c06c #define MALI_C55_GAMMA_GAIN_B_MASK GENMASK(11, 0) -#define MALI_C55_REG_GAMMA_OFFSETS_1 0x1c070 +#define MALI_C55_REG_GAMMA_OFFSETS_RG 0x1c070 #define MALI_C55_GAMMA_OFFSET_R_MASK GENMASK(11, 0) #define MALI_C55_GAMMA_OFFSET_G_MASK GENMASK(27, 16) -#define MALI_C55_REG_GAMMA_OFFSETS_2 0x1c074 +#define MALI_C55_GAMMA_OFFSET_G(x) ((x) << 16) +#define MALI_C55_REG_GAMMA_OFFSETS_B 0x1c074 #define MALI_C55_GAMMA_OFFSET_B_MASK GENMASK(11, 0) /* @@ -441,6 +443,9 @@ enum mali_c55_interrupts { #define MALI_C55_REG_FR_GAMMA_RGB_ENABLE 0x1c064 #define MALI_C55_REG_DS_GAMMA_RGB_ENABLE 0x1c1d8 +#define MALI_C55_REG_FR_GAMMA_RGB_MEM 0x18280 +#define MALI_C55_REG_DS_GAMMA_RGB_MEM 0x18484 + #define MALI_C55_REG_FR_SCALER_HFILT 0x34a8 #define MALI_C55_REG_FR_SCALER_VFILT 0x44a8 #define MALI_C55_REG_DS_SCALER_HFILT 0x14a8 diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c index c4f46651dcee..6706939b4a90 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c @@ -15,7 +15,7 @@ #include "mali-c55-registers.h" /* Scaling factor in Q4.20 format. */ -#define MALI_C55_RSZ_SCALER_FACTOR (1U << 20) +#define MALI_C55_RSZ_SCALER_FACTOR BIT_ULL(20) #define MALI_C55_RSZ_COEFS_BANKS 8 #define MALI_C55_RSZ_COEFS_ENTRIES 64 diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c index 8d28ba0b59a3..14bb916dd7b1 100644 --- a/drivers/media/platform/broadcom/bcm2835-unicam.c +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c @@ -2158,7 +2158,8 @@ static int unicam_video_link_validate(struct media_link *link) * In order to allow the applications using the old behaviour to * run, let's accept the old combination, but warn about it. */ - if (fmtinfo->fourcc != fmt->pixelformat) { + if (fmt->pixelformat != fmtinfo->fourcc && + fmt->pixelformat != fmtinfo->unpacked_fourcc) { if ((fmt->pixelformat == V4L2_PIX_FMT_BGR24 && format->code == MEDIA_BUS_FMT_BGR888_1X24) || (fmt->pixelformat == V4L2_PIX_FMT_RGB24 && @@ -2613,6 +2614,7 @@ static int unicam_async_nf_init(struct unicam_device *unicam) return 0; error: + v4l2_async_nf_cleanup(&unicam->notifier); fwnode_handle_put(ep_handle); return ret; } @@ -2745,6 +2747,7 @@ static void unicam_remove(struct platform_device *pdev) v4l2_device_unregister(&unicam->v4l2_dev); media_device_unregister(&unicam->mdev); v4l2_async_nf_unregister(&unicam->notifier); + v4l2_async_nf_cleanup(&unicam->notifier); unicam_subdev_cleanup(unicam); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index bb2ba9204a83..6564cf3ec739 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -5,6 +5,7 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include <linux/delay.h> #include <linux/pm_runtime.h> #include "wave5-helper.h" @@ -474,7 +475,10 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } - inst->queuing_fail = false; + if (inst->queuing_fail) { + inst->queuing_fail = false; + v4l2_m2m_try_schedule(m2m_ctx); + } } static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) @@ -819,7 +823,15 @@ static int wave5_vpu_dec_stop(struct vpu_instance *inst) * calls do not block on a mutex while inside this spinlock. */ spin_unlock_irqrestore(&inst->state_spinlock, flags); + /* + * V4L2_DEC_CMD_STOP can arrive while the device is runtime + * suspended (e.g. on pipeline teardown). Setting the EOS flag + * accesses VPU registers via send_firmware_command(), so the + * device must be resumed first to avoid an asynchronous SError. + */ + pm_runtime_resume_and_get(inst->dev->dev); ret = wave5_vpu_dec_set_eos_on_firmware(inst); + pm_runtime_put_autosuspend(inst->dev->dev); if (ret) return ret; @@ -1403,6 +1415,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; if (inst->state == VPU_INST_STATE_STOP) ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); @@ -1410,6 +1423,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count goto return_buffers; if (inst->state == VPU_INST_STATE_INIT_SEQ && + p_dec_info->initial_info_obtained && inst->dev->product_code == WAVE521C_CODE) { if (initial_info->luma_bitdepth != 8) { dev_info(inst->dev->dev, "%s: no support for %d bit depth", @@ -1418,7 +1432,6 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count goto return_buffers; } } - } pm_runtime_put_autosuspend(inst->dev->dev); return ret; @@ -1536,15 +1549,15 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) { struct vpu_instance *inst = vb2_get_drv_priv(q); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; - - bool check_cmd = TRUE; + unsigned long timeout; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); pm_runtime_resume_and_get(inst->dev->dev); inst->empty_queue = true; - while (check_cmd) { + + timeout = jiffies + msecs_to_jiffies(VPU_DEC_STOP_TIMEOUT); + while (true) { struct queue_status_info q_status; - struct dec_output_info dec_output_info; wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); if ((inst->state == VPU_INST_STATE_STOP || @@ -1553,8 +1566,10 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) q_status.report_queue_count == 0) break; - if (wave5_vpu_dec_get_output_info(inst, &dec_output_info)) - dev_dbg(inst->dev->dev, "there is no output info\n"); + if (time_after(jiffies, timeout)) + break; + + usleep_range(1000, 2000); } v4l2_m2m_update_stop_streaming_state(m2m_ctx, q); @@ -1651,6 +1666,7 @@ static void wave5_vpu_dec_device_run(void *priv) struct queue_status_info q_status; u32 fail_res = 0; int ret = 0; + bool cmd_issued = false; dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); pm_runtime_resume_and_get(inst->dev->dev); @@ -1662,9 +1678,13 @@ static void wave5_vpu_dec_device_run(void *priv) } else if (!inst->eos && inst->queuing_num == 0 && inst->state == VPU_INST_STATE_PIC_RUN) { - dev_dbg(inst->dev->dev, "%s: no bitstream for feeding, so skip ", __func__); - inst->empty_queue = true; - goto finish_job_and_return; + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + if (q_status.instance_queue_count == v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, "%s: no bitstream, skip\n", + __func__); + inst->empty_queue = true; + goto finish_job_and_return; + } } } @@ -1744,6 +1764,7 @@ static void wave5_vpu_dec_device_run(void *priv) inst->retry = false; if (!inst->eos) inst->queuing_num--; + cmd_issued = true; } break; default: @@ -1761,8 +1782,16 @@ finish_job_and_return: * in power and CPU time. * If EOS is passed, device_run will not call job_finish no more, it is called * only if HW is idle status in order to reduce overhead. + * + * Deferring job_finish() is only safe when this run actually queued a + * DEC_PIC command (cmd_issued): that guarantees a completion IRQ, and + * thus a later finish_decode(), will release the shared job slot. When + * device_run() is entered with no command to issue (e.g. a job that was + * queued while draining but reached the STOP state by the time it ran), + * no IRQ follows, so finish the job here to avoid leaking the slot and + * stalling every instance sharing the VPU. */ - if (!inst->sent_eos) + if (!inst->sent_eos || !cmd_issued) v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1776,11 +1805,22 @@ static void wave5_vpu_dec_job_abort(void *priv) if (ret) return; + /* + * job_abort() runs from the STREAMOFF path and may be called while the + * device is runtime suspended. Setting the EOS flag talks to the + * firmware (send_firmware_command() accesses VPU registers), so the + * device must be resumed first; otherwise the register access faults + * with an asynchronous SError. + */ + pm_runtime_resume_and_get(inst->dev->dev); + ret = wave5_vpu_dec_set_eos_on_firmware(inst); if (ret) dev_warn(inst->dev->dev, "Setting EOS for the bitstream, fail: %d\n", ret); + pm_runtime_put_autosuspend(inst->dev->dev); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index e6c94b6f2671..f9fcdf4c224b 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1494,7 +1494,8 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = { .stop_streaming = wave5_vpu_enc_stop_streaming, }; -static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, +static void wave5_set_default_format(struct vpu_instance *inst, + struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; @@ -1506,6 +1507,7 @@ static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC, W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, &enc_frmsize[VPU_FMT_TYPE_CODEC]); + inst->std = wave5_to_vpu_std(dst_fmt->pixelformat, inst->type); } static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1770,7 +1772,7 @@ static int wave5_vpu_open_enc(struct file *filp) inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); - wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + wave5_set_default_format(inst, &inst->src_fmt, &inst->dst_fmt); inst->conf_win.width = inst->dst_fmt.width; inst->conf_win.height = inst->dst_fmt.height; inst->colorspace = V4L2_COLORSPACE_REC709; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h index 4ebd48d5550e..e04f2dbf3b65 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h @@ -59,7 +59,7 @@ // application specific configuration #define VPU_ENC_TIMEOUT 60000 #define VPU_DEC_TIMEOUT 60000 -#define VPU_DEC_STOP_TIMEOUT 10 +#define VPU_DEC_STOP_TIMEOUT 300 // for WAVE encoder #define USE_SRC_PRP_AXI 0 diff --git a/drivers/media/platform/dreamchip/Kconfig b/drivers/media/platform/dreamchip/Kconfig new file mode 100644 index 000000000000..d177d4ee79ae --- /dev/null +++ b/drivers/media/platform/dreamchip/Kconfig @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +source "drivers/media/platform/dreamchip/rppx1/Kconfig" diff --git a/drivers/media/platform/dreamchip/Makefile b/drivers/media/platform/dreamchip/Makefile new file mode 100644 index 000000000000..ba47ba2d136e --- /dev/null +++ b/drivers/media/platform/dreamchip/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Dreamchip device drivers. +# + +obj-y += rppx1/ diff --git a/drivers/media/platform/dreamchip/rppx1/Kconfig b/drivers/media/platform/dreamchip/rppx1/Kconfig new file mode 100644 index 000000000000..0998a7d10bf2 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_DCT_RPPX1 + tristate + depends on V4L_PLATFORM_DRIVERS + select V4L2_ISP + help + Support library for Dreamchip HDR RPP X1 High Dynamic Range Real-time + Pixel Processor (RPP). The library can be used by other drivers who + utilises the RPP as part of an ISP implementation. + + To compile this driver as a module, choose M here: the + module will be called rppx1. diff --git a/drivers/media/platform/dreamchip/rppx1/Makefile b/drivers/media/platform/dreamchip/rppx1/Makefile new file mode 100644 index 000000000000..b2bd6b5d68bc --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0 +dct-rpp-x1-objs = \ + rpp_module.o \ + rpp_params.o \ + rpp_stats.o \ + rppx1.o \ + rppx1_acq.o \ + rppx1_awbg.o \ + rppx1_bd.o \ + rppx1_bdrgb.o \ + rppx1_bls.o \ + rppx1_cac.o \ + rppx1_ccor.o \ + rppx1_db.o \ + rppx1_dpcc.o \ + rppx1_exm.o \ + rppx1_ga.o \ + rppx1_hist.o \ + rppx1_hist256.o \ + rppx1_is.o \ + rppx1_lin.o \ + rppx1_lsc.o \ + rppx1_ltm.o \ + rppx1_ltmmeas.o \ + rppx1_outif.o \ + rppx1_outregs.o \ + rppx1_rmap.o \ + rppx1_rmapmeas.o \ + rppx1_shrp.o \ + rppx1_wbmeas.o \ + rppx1_xyz2luv.o + +obj-$(CONFIG_VIDEO_DCT_RPPX1) += dct-rpp-x1.o diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.c b/drivers/media/platform/dreamchip/rppx1/rpp_module.c new file mode 100644 index 000000000000..cb3e5a33d68c --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rppx1.h" +#include "rpp_module.h" + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base) +{ + mod->rpp = rpp; + mod->base = base; + mod->ops = ops; + + if (ops->probe) + return ops->probe(mod); + + return 0; +} + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value) +{ + rppx1_write(mod->rpp, mod->base + offset, value); +} + +u32 rpp_module_read(struct rpp_module *mod, u32 offset) +{ + return rppx1_read(mod->rpp, mod->base + offset); +} + +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 value) +{ + u32 reg = rpp_module_read(mod, offset) & ~mask; + + rpp_module_write(mod, offset, reg | value); +} diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h b/drivers/media/platform/dreamchip/rppx1/rpp_module.h new file mode 100644 index 000000000000..072309d8662d --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __RPPX1_MODULE_H__ +#define __RPPX1_MODULE_H__ + +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/v4l2-mediabus.h> + +#include <linux/media/dreamchip/rppx1-config.h> + +#include <media/rppx1.h> + +struct rpp_module_ops; + +enum rpp_raw_pattern { + RPP_RGGB = 0, + RPP_GRBG, + RPP_GBRG, + RPP_BGGR, +}; + +struct rpp_module { + struct rppx1 *rpp; + u32 base; + + const struct rpp_module_ops *ops; + + union { + struct { + enum rpp_raw_pattern raw_pattern; + } acq; + } info; +}; + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base); + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value); +u32 rpp_module_read(struct rpp_module *mod, u32 offset); +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 value); + +union rppx1_params_block { + struct v4l2_isp_block_header header; + struct rppx1_bls_params bls; + struct rppx1_lin_params lin; + struct rppx1_lsc_params lsc; + struct rppx1_awbg_params awbg; + struct rppx1_ccor_params ccor; + struct rppx1_hist_params hist; + struct rppx1_exm_params exm; + struct rppx1_wbmeas_params wbmeas; + struct rppx1_ga_params ga; +}; + +union rppx1_stats_block { + struct v4l2_isp_block_header header; + struct rppx1_hist_stats hist; + struct rppx1_exm_stats exm; + struct rppx1_wbmeas_stats wbmeas; +}; + +struct rpp_module_ops { + int (*probe)(struct rpp_module *mod); + int (*start)(struct rpp_module *mod, const struct v4l2_mbus_framefmt *fmt); + + int (*fill_params)(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv); + int (*fill_stats)(struct rpp_module *mod, + union rppx1_stats_block *block); +}; + +extern const struct rpp_module_ops rppx1_acq_ops; +extern const struct rpp_module_ops rppx1_awbg_ops; +extern const struct rpp_module_ops rppx1_bd_ops; +extern const struct rpp_module_ops rppx1_bdrgb_ops; +extern const struct rpp_module_ops rppx1_bls_ops; +extern const struct rpp_module_ops rppx1_cac_ops; +extern const struct rpp_module_ops rppx1_ccor_ops; +extern const struct rpp_module_ops rppx1_ccor_csm_ops; +extern const struct rpp_module_ops rppx1_db_ops; +extern const struct rpp_module_ops rppx1_dpcc_ops; +extern const struct rpp_module_ops rppx1_exm_ops; +extern const struct rpp_module_ops rppx1_ga_ops; +extern const struct rpp_module_ops rppx1_hist256_ops; +extern const struct rpp_module_ops rppx1_hist_ops; +extern const struct rpp_module_ops rppx1_is_ops; +extern const struct rpp_module_ops rppx1_lin_ops; +extern const struct rpp_module_ops rppx1_lsc_ops; +extern const struct rpp_module_ops rppx1_ltm_ops; +extern const struct rpp_module_ops rppx1_ltmmeas_ops; +extern const struct rpp_module_ops rppx1_outif_ops; +extern const struct rpp_module_ops rppx1_outregs_ops; +extern const struct rpp_module_ops rppx1_rmapmeas_ops; +extern const struct rpp_module_ops rppx1_rmap_ops; +extern const struct rpp_module_ops rppx1_shrp_ops; +extern const struct rpp_module_ops rppx1_wbmeas_ops; +extern const struct rpp_module_ops rppx1_xyz2luv_ops; + +#define rpp_module_call(mod, op, args...) \ + ({ \ + struct rpp_module *__mod = (mod); \ + int __result; \ + if (!__mod) \ + __result = -ENODEV; \ + else if (!__mod->ops->op) \ + __result = 0; \ + else \ + __result = __mod->ops->op(__mod, ##args); \ + __result; \ + }) + +#endif /* __RPPX1_MODULE_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/media/platform/dreamchip/rppx1/rpp_params.c new file mode 100644 index 000000000000..a75a27a8afd0 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <media/v4l2-isp.h> +#include <media/videobuf2-v4l2.h> + +#include "rppx1.h" + +#define RPPX1_PARAMS_BLOCK_INFO(block, data) \ + [RPPX1_PARAMS_BLOCK_TYPE_ ## block] = { \ + .size = sizeof(struct rppx1_ ## data ## _params), \ + } + +static const struct v4l2_isp_params_block_type_info +rppx1_ext_params_blocks_info[] = { + RPPX1_PARAMS_BLOCK_INFO(BLS_PRE1, bls), + RPPX1_PARAMS_BLOCK_INFO(BLS_PRE2, bls), + RPPX1_PARAMS_BLOCK_INFO(LIN_PRE1, lin), + RPPX1_PARAMS_BLOCK_INFO(LIN_PRE2, lin), + RPPX1_PARAMS_BLOCK_INFO(LSC_PRE1, lsc), + RPPX1_PARAMS_BLOCK_INFO(LSC_PRE2, lsc), + RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg), + RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg), + RPPX1_PARAMS_BLOCK_INFO(CCOR_POST, ccor), + RPPX1_PARAMS_BLOCK_INFO(HIST_PRE1, hist), + RPPX1_PARAMS_BLOCK_INFO(HIST_PRE2, hist), + RPPX1_PARAMS_BLOCK_INFO(HIST_POST, hist), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE1, exm), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE2, exm), + RPPX1_PARAMS_BLOCK_INFO(WBMEAS_POST, wbmeas), + RPPX1_PARAMS_BLOCK_INFO(GA_HV, ga), + RPPX1_PARAMS_BLOCK_INFO(GA_MV, ga), +}; + +int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size, + rppx1_reg_write write, void *priv) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct v4l2_isp_buffer *cfg; + size_t block_offset; + int ret; + + ret = v4l2_isp_params_validate_buffer_size(rpp->dev, vb, max_size); + if (ret) + return ret; + + cfg = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + + ret = v4l2_isp_params_validate_buffer(rpp->dev, vb, cfg, + rppx1_ext_params_blocks_info, + ARRAY_SIZE(rppx1_ext_params_blocks_info)); + if (ret) + return ret; + + /* Walk the list of parameter blocks and process them. */ + block_offset = 0; + while (block_offset < cfg->data_size) { + const union rppx1_params_block *block = + (const union rppx1_params_block *)&cfg->data[block_offset]; + struct rpp_module *module; + int ret; + + block_offset += block->header.size; + + switch (block->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: + module = &rpp->pre1.bls; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1: + module = &rpp->pre1.lin; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE1: + module = &rpp->pre1.lsc; + break; + case RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1: + module = &rpp->pre1.awbg; + break; + case RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST: + module = &rpp->post.ccor; + break; + case RPPX1_PARAMS_BLOCK_TYPE_HIST_POST: + module = &rpp->post.hist; + break; + case RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1: + module = &rpp->pre1.exm; + break; + case RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST: + module = &rpp->post.wbmeas; + break; + case RPPX1_PARAMS_BLOCK_TYPE_GA_HV: + module = &rpp->hv.ga; + break; + default: + dev_warn(rpp->dev, + "Not handled RPPX1 block type: 0x%04x\n", + block->header.type); + continue; + } + + ret = rpp_module_call(module, fill_params, block, write, priv); + if (ret) { + dev_err(rpp->dev, + "Error processing RPPX1 block type: 0x%04x\n", + block->header.type); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_params); diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c new file mode 100644 index 000000000000..4c7fe611d004 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rppx1.h" +#include "rpp_module.h" + +#include <media/v4l2-isp.h> + +#define RPPX1_STATS_BLOCK_INFO(type, block) \ + [RPPX1_STATS_BLOCK_TYPE_ ## type] = { \ + .size = sizeof(struct rppx1_ ## block ## _stats), \ + } + +static const struct v4l2_isp_stats_block_type_info +rppx1_stats_blocks_info[] = { + RPPX1_STATS_BLOCK_INFO(HIST_POST, hist), + RPPX1_STATS_BLOCK_INFO(EXM_PRE1, exm), + RPPX1_STATS_BLOCK_INFO(WBMEAS_POST, wbmeas), +}; + +#define rppx1_init_stats_block(rpp, buf, type) \ + ((union rppx1_stats_block *) \ + v4l2_isp_stats_init_block((rpp)->dev, (buf), \ + rppx1_stats_blocks_info, \ + ARRAY_SIZE(rppx1_stats_blocks_info), \ + (type), RPPX1_STATS_MAX_SIZE)) \ + +void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf) +{ + struct v4l2_isp_buffer *stats = buf; + union rppx1_stats_block *block; + + v4l2_isp_stats_init_buffer(stats, V4L2_ISP_VERSION_V1); + + if (isc & RPPX1_IRQ_ID_POST_HIST_MEAS) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_HIST_POST); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->post.hist, fill_stats, block); + } + + if (isc & RPPX1_IRQ_ID_PRE1_EXM) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_EXM_PRE1); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->pre1.exm, fill_stats, block); + } + + if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->post.wbmeas, fill_stats, block); + } +} +EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.c b/drivers/media/platform/dreamchip/rppx1/rppx1.c new file mode 100644 index 000000000000..c502be797914 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + * + * Support library for Dreamchip HDR RPPX1 High Dynamic Range Real-time Pixel + * Processor. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "rppx1.h" + +/* RPP_HDR Base Addresses */ +#define RPPX1_HDRREGS_BASE 0x0000 +#define RPPX1_HDR_IRQ_BASE 0x0200 +#define RPPX1_RPP_OUT_BASE 0x0800 +#define RPPX1_RPP_RMAP_BASE 0x0c00 +#define RPPX1_RPP_RMAP_MEAS_BASE 0x1000 +#define RPPX1_RPP_MAIN_PRE1_BASE 0x2000 +#define RPPX1_RPP_MAIN_PRE2_BASE 0x4000 +#define RPPX1_RPP_MAIN_POST_BASE 0xa000 +#define RPPX1_RPP_MVOUT_BASE 0xc000 +#define RPPX1_RPP_FUSA_BASE 0xf000 + +#define RPPX1_RPP_HDRREGS_VERSION_REG (RPPX1_HDRREGS_BASE + 0x0000) + +#define RPPX1_RPP_HDR_UPD_REG (RPPX1_HDRREGS_BASE + 0x0004) +#define RPPX1_RPP_HDR_UPD_REGS_GEN_CFG_UPD BIT(1) +#define RPPX1_RPP_HDR_UPD_REGS_CFG_UPD BIT(0) + +#define RPPX1_RESERVED_3_REG (RPPX1_HDRREGS_BASE + 0x0008) + +#define RPPX1_RPP_HDR_INFORM_ENABLE_REG (RPPX1_HDRREGS_BASE + 0x000c) +#define RPPX1_RPP_HDR_INFORM_ENABLE_ENABLE 1 +#define RPPX1_RPP_HDR_INFORM_ENABLE_DISABLE 0 + +#define RPPX1_RPP_HDR_OUT_IF_ON_REG (RPPX1_HDRREGS_BASE + 0x0010) +#define RPPX1_RPP_HDR_OUT_IF_OFF_REG (RPPX1_HDRREGS_BASE + 0x0014) + +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG (RPPX1_HDRREGS_BASE + 0x0018) +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_ENABLE 1 +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_DISABLE 0 + +#define RPPX1_RPP_ISM (RPPX1_HDR_IRQ_BASE + 0x00) +#define RPPX1_RPP_RIS (RPPX1_HDR_IRQ_BASE + 0x04) +#define RPPX1_RPP_MIS (RPPX1_HDR_IRQ_BASE + 0x08) +#define RPPX1_RPP_ISC (RPPX1_HDR_IRQ_BASE + 0x0c) + +/* RPP_OUT/MV_OUT Pipelines - Base Addresses */ +#define RPPX1_GAMMA_OUT_BASE 0x0000 /* HV, MV */ +#define RPPX1_IS_BASE 0x00c0 /* HV, MV */ +#define RPPX1_CSM_BASE 0x0100 /* HV, MV */ +#define RPPX1_OUT_IF_BASE 0x0200 /* HV, MV */ +#define RPPX1_RPP_OUTREGS_BASE 0x02c0 /* HV, MV */ +#define RPPX1_LUV_BASE 0x0300 /* MV */ + +/* PRE1/PRE2/POST Pipelines - Base Addresses */ +#define RPPX1_ACQ_BASE 0x0080 /* PRE1, PRE2 */ +#define RPPX1_BLS_BASE 0x0100 /* PRE1, PRE2 */ +#define RPPX1_GAMMA_IN_BASE 0x0200 /* PRE1, PRE2 */ +#define RPPX1_LSC_BASE 0x0400 /* PRE1, PRE2 */ +#define RPPX1_AWB_GAIN_BASE 0x0500 /* PRE1, PRE2, POST */ +#define RPPX1_DPCC_BASE 0x0600 /* PRE1, PRE2 */ +#define RPPX1_DPF_BASE 0x0700 /* PRE1, PRE2 */ +#define RPPX1_FILT_BASE 0x0800 /* POST */ +#define RPPX1_CAC_BASE 0x0880 /* POST */ +#define RPPX1_CCOR_BASE 0x0900 /* POST */ +#define RPPX1_HIST_BASE 0x0a00 /* PRE1, PRE2, POST */ +#define RPPX1_HIST256_BASE 0x0b00 /* PRE1 */ +#define RPPX1_EXM_BASE 0x0c00 /* PRE1, PRE2 */ +#define RPPX1_LTM_BASE 0x1000 /* POST */ +#define RPPX1_LTM_MEAS_BASE 0x1200 /* POST */ +#define RPPX1_WBMEAS_BASE 0x1700 /* POST */ +#define RPPX1_BDRGB_BASE 0x1800 /* POST */ +#define RPPX1_SHRP_BASE 0x1a00 /* POST */ + +/* Functional Safety Module Base Addresses */ +#define RPPX1_FMU_BASE 0x0100 + +#define RPPX1_RPP_HDR_FMU_FSM_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x00) +#define RPPX1_RPP_HDR_FMU_FSM_FSM_IRQM_FAULT BIT(23) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_SIZE_FAULT BIT(20) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_TIME_FAULT BIT(19) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_SIZE_FAULT BIT(18) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_TIME_FAULT BIT(17) +#define RPPX1_RPP_HDR_FMU_FSM_SIZE_FAULT BIT(16) +#define RPPX1_RPP_HDR_FMU_FSM_TIME_FAULT BIT(15) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_SIZE_FAULT BIT(14) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_TIME_FAULT BIT(13) +#define RPPX1_RPP_HDR_FMU_FSM_HV_OUT_SIZE_FAULT BIT(12) +#define RPPX1_RPP_HDR_FMU_FSM_HV_OUT_TIME_FAULT BIT(11) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_SIZE_ERR BIT(10) +#define RPPX1_RPP_HDR_FMU_FSM_IS_OUT_SIZE_ERR BIT(9) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_FIFO_OVFLW BIT(7) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_FIFO_OVFLW BIT(6) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_INFORM_SIZE BIT(5) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_OUTFORM_SIZE BIT(4) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_INFORM_SIZE BIT(3) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_OUTFORM_SIZE BIT(2) + +#define RPPX1_RPP_HDR_FMU_RFS_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x04) +#define RPPX1_RPP_HDR_FMU_MFS_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x08) +#define RPPX1_RPP_HDR_FMU_FSC_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x0c) + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value) +{ + iowrite32(value, rpp->base + offset); +} + +u32 rppx1_read(struct rppx1 *rpp, u32 offset) +{ + return ioread32(rpp->base + offset); +} + +bool rppx1_interrupt(struct rppx1 *rpp, u32 *isc) +{ + u32 status, raw, fault; + + fault = rppx1_read(rpp, RPPX1_RPP_HDR_FMU_MFS_REG); + if (fault) { + dev_err(rpp->dev, "%s: fault 0x%08x\n", __func__, fault); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSC_REG, fault); + } + + /* Read raw interrupt status. */ + raw = rppx1_read(rpp, RPPX1_RPP_RIS); + status = rppx1_read(rpp, RPPX1_RPP_MIS); + + /* Propagate the isc status. */ + if (isc) + *isc = status | raw; + + /* Clear enabled interrupts */ + rppx1_write(rpp, RPPX1_RPP_ISC, status); + + return !!(status & RPPX1_IRQ_ID_OUT_FRAME); +} +EXPORT_SYMBOL_GPL(rppx1_interrupt); + +void rppx1_destroy(struct rppx1 *rpp) +{ + kfree(rpp); +} +EXPORT_SYMBOL_GPL(rppx1_destroy); + +/* + * Allocate the private data structure and verify the hardware is present. + */ +struct rppx1 *rppx1_create(void __iomem *base, struct device *dev) +{ + struct rppx1 *rpp; + u32 reg; + + /* Allocate library structure */ + rpp = kzalloc_obj(*rpp); + if (!rpp) + return NULL; + + rpp->base = base; + rpp->dev = dev; + + /* Check communication with RPP and verify it truly is a X1. */ + reg = rppx1_read(rpp, RPPX1_RPP_HDRREGS_VERSION_REG); + if (reg != 3) { + dev_err(rpp->dev, "Unsupported HDR version (%u)\n", reg); + rppx1_destroy(rpp); + return NULL; + } + + /* Probe the PRE1 pipeline. */ + if (rpp_module_probe(&rpp->pre1.acq, rpp, &rppx1_acq_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_ACQ_BASE) || + rpp_module_probe(&rpp->pre1.bls, rpp, &rppx1_bls_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_BLS_BASE) || + rpp_module_probe(&rpp->pre1.lin, rpp, &rppx1_lin_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre1.lsc, rpp, &rppx1_lsc_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_LSC_BASE) || + rpp_module_probe(&rpp->pre1.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre1.dpcc, rpp, &rppx1_dpcc_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_DPCC_BASE) || + rpp_module_probe(&rpp->pre1.bd, rpp, &rppx1_bd_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_DPF_BASE) || + rpp_module_probe(&rpp->pre1.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->pre1.hist256, rpp, &rppx1_hist256_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_HIST256_BASE) || + rpp_module_probe(&rpp->pre1.exm, rpp, &rppx1_exm_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_EXM_BASE)) + goto err; + + /* Probe the PRE2 pipeline. */ + if (rpp_module_probe(&rpp->pre2.acq, rpp, &rppx1_acq_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_ACQ_BASE) || + rpp_module_probe(&rpp->pre2.bls, rpp, &rppx1_bls_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_BLS_BASE) || + rpp_module_probe(&rpp->pre2.lin, rpp, &rppx1_lin_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre2.lsc, rpp, &rppx1_lsc_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_LSC_BASE) || + rpp_module_probe(&rpp->pre2.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre2.dpcc, rpp, &rppx1_dpcc_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_DPCC_BASE) || + rpp_module_probe(&rpp->pre2.bd, rpp, &rppx1_bd_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_DPF_BASE) || + rpp_module_probe(&rpp->pre2.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->pre2.exm, rpp, &rppx1_exm_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_EXM_BASE)) + goto err; + + /* Probe the POST pipeline. */ + if (rpp_module_probe(&rpp->post.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->post.ccor, rpp, &rppx1_ccor_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_CCOR_BASE) || + rpp_module_probe(&rpp->post.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->post.db, rpp, &rppx1_db_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_FILT_BASE) || + rpp_module_probe(&rpp->post.cac, rpp, &rppx1_cac_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_CAC_BASE) || + rpp_module_probe(&rpp->post.ltm, rpp, &rppx1_ltm_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_LTM_BASE) || + rpp_module_probe(&rpp->post.ltmmeas, rpp, &rppx1_ltmmeas_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_LTM_MEAS_BASE) || + rpp_module_probe(&rpp->post.wbmeas, rpp, &rppx1_wbmeas_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_WBMEAS_BASE) || + rpp_module_probe(&rpp->post.bdrgb, rpp, &rppx1_bdrgb_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_BDRGB_BASE) || + rpp_module_probe(&rpp->post.shrp, rpp, &rppx1_shrp_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_SHRP_BASE)) + goto err; + + /* Probe the Human Vision pipeline. */ + if (rpp_module_probe(&rpp->hv.ga, rpp, &rppx1_ga_ops, + RPPX1_RPP_OUT_BASE + RPPX1_GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->hv.is, rpp, &rppx1_is_ops, + RPPX1_RPP_OUT_BASE + RPPX1_IS_BASE) || + rpp_module_probe(&rpp->hv.ccor, rpp, &rppx1_ccor_csm_ops, + RPPX1_RPP_OUT_BASE + RPPX1_CSM_BASE) || + rpp_module_probe(&rpp->hv.outif, rpp, &rppx1_outif_ops, + RPPX1_RPP_OUT_BASE + RPPX1_OUT_IF_BASE) || + rpp_module_probe(&rpp->hv.outregs, rpp, &rppx1_outregs_ops, + RPPX1_RPP_OUT_BASE + RPPX1_RPP_OUTREGS_BASE)) + goto err; + + /* Probe the Machine Vision pipeline. */ + if (rpp_module_probe(&rpp->mv.ga, rpp, &rppx1_ga_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->mv.is, rpp, &rppx1_is_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_IS_BASE) || + rpp_module_probe(&rpp->mv.ccor, rpp, &rppx1_ccor_csm_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_CSM_BASE) || + rpp_module_probe(&rpp->mv.outif, rpp, &rppx1_outif_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_OUT_IF_BASE) || + rpp_module_probe(&rpp->mv.outregs, rpp, &rppx1_outregs_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_RPP_OUTREGS_BASE) || + rpp_module_probe(&rpp->mv.xyz2luv, rpp, &rppx1_xyz2luv_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_LUV_BASE)) + goto err; + + /* Probe the standalone Radiance Mapping modules. */ + if (rpp_module_probe(&rpp->rmap, rpp, &rppx1_rmap_ops, + RPPX1_RPP_RMAP_BASE) || + rpp_module_probe(&rpp->rmapmeas, rpp, &rppx1_rmapmeas_ops, + RPPX1_RPP_RMAP_MEAS_BASE)) + goto err; + + return rpp; +err: + rppx1_destroy(rpp); + + return NULL; +} +EXPORT_SYMBOL_GPL(rppx1_create); + +int rppx1_start(struct rppx1 *rpp, + const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *hv, + const struct v4l2_mbus_framefmt *mv) +{ + if (rpp_module_call(&rpp->pre1.acq, start, input) || + rpp_module_call(&rpp->pre1.bls, start, input) || + rpp_module_call(&rpp->pre1.lin, start, input) || + rpp_module_call(&rpp->pre1.lsc, start, input) || + rpp_module_call(&rpp->pre1.awbg, start, input) || + rpp_module_call(&rpp->pre1.dpcc, start, input) || + rpp_module_call(&rpp->pre1.bd, start, input) || + rpp_module_call(&rpp->pre1.hist, start, input) || + rpp_module_call(&rpp->pre1.exm, start, input) || + rpp_module_call(&rpp->pre1.hist256, start, input)) + return -EINVAL; + + if (rpp_module_call(&rpp->rmap, start, NULL) || + rpp_module_call(&rpp->rmapmeas, start, NULL)) + return -EINVAL; + + if (rpp_module_call(&rpp->post.awbg, start, input) || + rpp_module_call(&rpp->post.db, start, input) || + rpp_module_call(&rpp->post.cac, start, input) || + rpp_module_call(&rpp->post.ccor, start, input) || + rpp_module_call(&rpp->post.ltm, start, input) || + rpp_module_call(&rpp->post.bdrgb, start, input) || + rpp_module_call(&rpp->post.shrp, start, input) || + rpp_module_call(&rpp->post.ltmmeas, start, input) || + rpp_module_call(&rpp->post.wbmeas, start, input) || + rpp_module_call(&rpp->post.hist, start, input)) + return -EINVAL; + + if (hv && (rpp_module_call(&rpp->hv.ga, start, hv) || + rpp_module_call(&rpp->hv.ccor, start, hv) || + rpp_module_call(&rpp->hv.outregs, start, hv) || + rpp_module_call(&rpp->hv.is, start, hv) || + rpp_module_call(&rpp->hv.outif, start, hv))) + return -EINVAL; + + if (mv && (rpp_module_call(&rpp->mv.ga, start, mv) || + rpp_module_call(&rpp->mv.ccor, start, mv) || + rpp_module_call(&rpp->mv.xyz2luv, start, mv) || + rpp_module_call(&rpp->mv.outregs, start, mv) || + rpp_module_call(&rpp->mv.is, start, mv) || + rpp_module_call(&rpp->mv.outif, start, mv))) + return -EINVAL; + + /* Immediate update for shadows. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_CFG_UPD); + + /* Clear fault interrupts. */ + rppx1_write(rpp, RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, + RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_ENABLE); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSM_REG, + RPPX1_RPP_HDR_FMU_FSM_PRE2_FIFO_OVFLW | + RPPX1_RPP_HDR_FMU_FSM_PRE1_FIFO_OVFLW); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSC_REG, + rppx1_read(rpp, RPPX1_RPP_HDR_FMU_MFS_REG)); + rppx1_write(rpp, RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, + RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_DISABLE); + + /* Set interrupt mask. */ + rppx1_write(rpp, RPPX1_RPP_ISM, RPPX1_IRQ_ID_OUT_FRAME); + + /* Immediate commit update for shadows. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_CFG_UPD); + + /* Then for operation update shadows with picture synchronization. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_GEN_CFG_UPD); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + /* Enable input formatters. */ + rppx1_write(rpp, RPPX1_RPP_HDR_INFORM_ENABLE_REG, + RPPX1_RPP_HDR_INFORM_ENABLE_ENABLE); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_start); + +int rppx1_stop(struct rppx1 *rpp) +{ + /* Disable input formatters. */ + rppx1_write(rpp, RPPX1_RPP_HDR_INFORM_ENABLE_REG, + RPPX1_RPP_HDR_INFORM_ENABLE_DISABLE); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_stop); + +MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); +MODULE_DESCRIPTION("Dreamchip HDR RPPX1 support library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.h b/drivers/media/platform/dreamchip/rppx1/rppx1.h new file mode 100644 index 000000000000..3bf3955afbae --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __MEDIA_RPPX1_H__ +#define __MEDIA_RPPX1_H__ + +#include <linux/device.h> +#include <linux/types.h> + +#include "rpp_module.h" + +#define RPPX1_IRQ_ID_256HIST BIT(27) +#define RPPX1_IRQ_ID_PRE2_DPCC BIT(25) +#define RPPX1_IRQ_ID_PRE1_DPCC BIT(24) +#define RPPX1_IRQ_ID_MV_OUT_FRAME_OUT BIT(23) +#define RPPX1_IRQ_ID_MV_OUT_OFF BIT(22) +#define RPPX1_IRQ_ID_POST_AWB_MEAS BIT(21) +#define RPPX1_IRQ_ID_POST_HIST_MEAS BIT(20) +#define RPPX1_IRQ_ID_POST_TM BIT(19) +#define RPPX1_IRQ_ID_PRE1_EXM BIT(18) +#define RPPX1_IRQ_ID_PRE1_HIST BIT(17) +#define RPPX1_IRQ_ID_PRE1_FRAME_IN BIT(16) +#define RPPX1_IRQ_ID_PRE1_HSTART BIT(15) +#define RPPX1_IRQ_ID_PRE1_VSTART BIT(14) +#define RPPX1_IRQ_ID_PRE2_EXM BIT(13) +#define RPPX1_IRQ_ID_PRE2_HIST BIT(12) +#define RPPX1_IRQ_ID_PRE2_FRAME_IN BIT(11) +#define RPPX1_IRQ_ID_PRE2_HSTART BIT(10) +#define RPPX1_IRQ_ID_PRE2_VSTART BIT(9) +#define RPPX1_IRQ_ID_OUT_FRAME BIT(3) +#define RPPX1_IRQ_ID_OUT_OFF BIT(2) +#define RPPX1_IRQ_ID_RMAP_MEAS BIT(1) +#define RPPX1_IRQ_ID_RMAP_DONE BIT(0) + +struct rppx1 { + struct device *dev; + void __iomem *base; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module hist256; + struct rpp_module exm; + } pre1; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module exm; + } pre2; + + struct { + struct rpp_module awbg; + struct rpp_module ccor; + struct rpp_module hist; + struct rpp_module db; + struct rpp_module cac; + struct rpp_module ltm; + struct rpp_module ltmmeas; + struct rpp_module wbmeas; + struct rpp_module bdrgb; + struct rpp_module shrp; + } post; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + } hv; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + struct rpp_module xyz2luv; + } mv; + + struct rpp_module rmap; + struct rpp_module rmapmeas; +}; + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value); +u32 rppx1_read(struct rppx1 *rpp, u32 offset); + +#endif /* __MEDIA_RPPX1_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c b/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c new file mode 100644 index 000000000000..d5624e3c76a9 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define ACQ_VERSION_REG 0x0000 + +#define ACQ_CTRL_REG 0x0004 +#define ACQ_CTRL_ALTERNATIVE_CFG_MODE_ENABLE BIT(8) +#define ACQ_CTRL_RPP_MODE_MASK GENMASK(3, 1) +#define ACQ_CTRL_RPP_MODE_RAWBT601 (0 << 1) +#define ACQ_CTRL_RPP_MODE_BT656 (1 << 1) +#define ACQ_CTRL_RPP_MODE_BT601 (2 << 1) +#define ACQ_CTRL_RPP_MODE_BAYER (3 << 1) +#define ACQ_CTRL_RPP_MODE_DATA (4 << 1) +#define ACQ_CTRL_RPP_MODE_BAYERRGB (5 << 1) +#define ACQ_CTRL_RPP_MODE_RAWBT656 (6 << 1) +#define ACQ_CTRL_INFORM_EN_ENABLE BIT(0) + +#define ACQ_PROP_REG 0x0008 + +#define ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB BIT(30) +#define ACQ_PROP_YUV_OUT_SEL BIT(25) +#define ACQ_PROP_MUX_DMA_SEL BIT(24) +#define ACQ_PROP_SECOND_INPUT_TYPE BIT(18) +#define ACQ_PROP_LATENCY_FIFO_INPUT_SELECTION BIT(15) +#define ACQ_PROP_INPUT_SELECTION_MASK GENMASK(14, 12) +#define ACQ_PROP_INPUT_SELECTION_8BIT (0 << 12) +#define ACQ_PROP_INPUT_SELECTION_10BIT (1 << 12) +#define ACQ_PROP_INPUT_SELECTION_12BIT (2 << 12) +#define ACQ_PROP_BAYER_PAT_MASK GENMASK(4, 3) +#define ACQ_PROP_BAYER_PAT_RGRG (0 << 3) +#define ACQ_PROP_BAYER_PAT_GRGR (1 << 3) +#define ACQ_PROP_BAYER_PAT_GBGB (2 << 3) +#define ACQ_PROP_BAYER_PAT_BGBG (3 << 3) +#define ACQ_PROP_VSYNC_POL BIT(2) +#define ACQ_PROP_HSYNC_POL BIT(1) +#define ACQ_PROP_SAMPLE_EDGE BIT(0) + +#define ACQ_H_OFFS_REG 0x000c +#define ACQ_V_OFFS_REG 0x0010 +#define ACQ_H_SIZE_REG 0x0014 +#define ACQ_V_SIZE_REG 0x0018 +#define ACQ_OUT_H_OFFS_REG 0x001c +#define ACQ_OUT_V_OFFS_REG 0x0020 +#define ACQ_OUT_H_SIZE_REG 0x0024 +#define ACQ_OUT_V_SIZE_REG 0x0028 +#define FLAGS_SHD_REG 0x002c +#define ACQ_OUT_H_OFFS_SHD_REG 0x0030 +#define ACQ_OUT_V_OFFS_SHD_REG 0x0034 +#define ACQ_OUT_H_SIZE_SHD_REG 0x0038 +#define ACQ_OUT_V_SIZE_SHD_REG 0x003c + +static int rppx1_acq_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, ACQ_VERSION_REG) != 0x0b) + return -EINVAL; + + return 0; +} + +static int rppx1_acq_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 bayerpat, selection; + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_RPP_MODE_MASK, + ACQ_CTRL_RPP_MODE_BAYER); + + rpp_module_write(mod, ACQ_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_V_SIZE_REG, fmt->height); + rpp_module_write(mod, ACQ_OUT_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_OUT_V_SIZE_REG, fmt->height); + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + mod->info.acq.raw_pattern = RPP_BGGR; + bayerpat = ACQ_PROP_BAYER_PAT_BGBG; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: + mod->info.acq.raw_pattern = RPP_GBRG; + bayerpat = ACQ_PROP_BAYER_PAT_GBGB; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG12_1X12: + mod->info.acq.raw_pattern = RPP_GRBG; + bayerpat = ACQ_PROP_BAYER_PAT_GRGR; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB12_1X12: + mod->info.acq.raw_pattern = RPP_RGGB; + bayerpat = ACQ_PROP_BAYER_PAT_RGRG; + break; + default: + return -EINVAL; + } + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + selection = ACQ_PROP_INPUT_SELECTION_8BIT; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + selection = ACQ_PROP_INPUT_SELECTION_10BIT; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + selection = ACQ_PROP_INPUT_SELECTION_12BIT; + break; + default: + return -EINVAL; + } + + rpp_module_write(mod, ACQ_PROP_REG, bayerpat | selection | + ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB); + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_INFORM_EN_ENABLE, + ACQ_CTRL_INFORM_EN_ENABLE); + + return 0; +} + +const struct rpp_module_ops rppx1_acq_ops = { + .probe = rppx1_acq_probe, + .start = rppx1_acq_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c new file mode 100644 index 000000000000..f30e12d6f880 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define AWB_GAIN_VERSION_REG 0x0000 + +#define AWB_ENABLE_REG 0x0004 +#define AWB_ENABLE_AWB_GAIN_EN BIT(0) + +#define AWB_GAIN_GR_REG 0x0008 +#define AWB_GAIN_GB_REG 0x000c +#define AWB_GAIN_R_REG 0x0010 +#define AWB_GAIN_B_REG 0x0014 + +static int rppx1_awbg_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, AWB_GAIN_VERSION_REG) != 3) + return -EINVAL; + + return 0; +} + +static int +rppx1_awbg_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_awbg_params *cfg = &block->awbg; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_ENABLE_REG, 0); + return 0; + } + + /* + * RPP gains are 18-bit with 12 bit fractional part and 0x1000 = 1.0, + * giving a possible range of 0.0 to 64.0. NOTE: RPP documentation is + * contradictory this is the register definition, the function + * description states 0x400 = 1.0 AND 18-bit with 12 fractional bits, + * which is not possible... + */ + + write(priv, mod->base + AWB_GAIN_GR_REG, cfg->gain_green_r); + write(priv, mod->base + AWB_GAIN_GB_REG, cfg->gain_green_b); + write(priv, mod->base + AWB_GAIN_R_REG, cfg->gain_red); + write(priv, mod->base + AWB_GAIN_B_REG, cfg->gain_blue); + + write(priv, mod->base + AWB_ENABLE_REG, AWB_ENABLE_AWB_GAIN_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_awbg_ops = { + .probe = rppx1_awbg_probe, + .fill_params = rppx1_awbg_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c new file mode 100644 index 000000000000..fcbaa0ee9281 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define DPF_VERSION_REG 0x0000 + +#define DPF_MODE_REG 0x0004 +#define DPF_MODE_USE_NF_GAIN BIT(9) +#define DPF_MODE_LSC_GAIN_COMP BIT(8) +#define DPF_MODE_NLL_SEGMENTATION BIT(6) +#define DPF_MODE_RB_FILTER_SIZE BIT(5) +#define DPF_MODE_R_FILTER_OFF BIT(4) +#define DPF_MODE_GR_FILTER_OFF BIT(3) +#define DPF_MODE_GB_FILTER_OFF BIT(2) +#define DPF_MODE_B_FILTER_OFF BIT(1) +#define DPF_MODE_DPF_ENABLE BIT(0) + +#define DPF_STRENGTH_R_REG 0x0008 +#define DPF_STRENGTH_G_REG 0x000c +#define DPF_STRENGTH_B_REG 0x0010 +#define DPF_S_WEIGHT_G_1_4_REG 0x0014 +#define DPF_S_WEIGHT_G_5_6_REG 0x0018 +#define DPF_S_WEIGHT_RB_1_4_REG 0x001c +#define DPF_S_WEIGHT_RB_5_6_REG 0x0020 + +#define DPF_NLL_G_COEFF_REG_NUM 17 +#define DPF_NLL_G_COEFF_REG(n) (0x0024 + (4 * (n))) + +#define DPF_NLL_RB_COEFF_REG_NUM 17 +#define DPF_NLL_RB_COEFF_REG(n) (0x0068 + (4 * (n))) + +#define DPF_NF_GAIN_R_REG 0x00ac +#define DPF_NF_GAIN_GR_REG 0x00b0 +#define DPF_NF_GAIN_GB_REG 0x00b4 +#define DPF_NF_GAIN_B_REG 0x00b8 + +static int rppx1_bd_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, DPF_VERSION_REG) != 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_bd_ops = { + .probe = rppx1_bd_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c new file mode 100644 index 000000000000..1accc106d65b --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RGBDENOISE_VERSION_REG 0x0000 + +#define RGBDENOISE_HW_BYPASS_REG 0x0004 +#define RGBDENOISE_HW_BYPASS_BYPASS_EN BIT(0) + +#define RGBDENOISE_SPNR_CTRL_REG 0x0008 +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_C_MASK GENMASK(11, 8) +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_Y_MASK GENMASK(7, 4) +#define RGBDENOISE_SPNR_CTRL_C2NR_EN BIT(0) + +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_REG 0x000c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_REG 0x0010 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_REG 0x0014 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_REG 0x0018 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_REG 0x001c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_REG 0x0020 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_REG 0x0024 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_REG 0x0028 +#define RGBDENOISE_SPNR_SPATIAL_COEF_0_3_REG 0x002c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_REG 0x0030 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_REG 0x0034 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_REG 0x0038 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_REG 0x003c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_REG 0x0040 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_REG 0x0044 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_REG 0x0048 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_REG 0x004c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_REG 0x0050 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_REG 0x0054 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_REG 0x0058 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_REG 0x005c +#define RGBDENOISE_HW_BYPASS_SDW_REG 0x0060 +#define RGBDENOISE_SPNR_CTRL_SDW_REG 0x0064 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_SDW_REG 0x0068 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_SDW_REG 0x006c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_SDW_REG 0x0070 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_SDW_REG 0x0074 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_SDW_REG 0x0078 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_SDW_REG 0x007c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_SDW_REG 0x0080 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_SDW_REG 0x0084 +#define RGBDENOISE_SPNR_SPATIAL_COEFF_0_3_SDW_REG 0x0088 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_SDW_REG 0x008c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_SDW_REG 0x0090 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_SDW_REG 0x0094 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_SDW_REG 0x0098 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_SDW_REG 0x009c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_SDW_REG 0x00a0 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_SDW_REG 0x00a4 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_SDW_REG 0x00a8 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_SDW_REG 0x00ac +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_SDW_REG 0x00b0 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_SDW_REG 0x00b4 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_SDW_REG 0x00b8 + +static int rppx1_bdrgb_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RGBDENOISE_VERSION_REG)) { + case 6: + /* 12-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_bdrgb_ops = { + .probe = rppx1_bdrgb_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c new file mode 100644 index 000000000000..01a61db279bf --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" +#include "rppx1.h" + +#define BLS_VERSION_REG 0x0000 + +#define BLS_CTRL_REG 0x0004 +#define BLS_CTRL_BLS_WIN2 BIT(3) +#define BLS_CTRL_BLS_WIN1 BIT(2) +#define BLS_CTRL_BLS_MODE_MEASURED BIT(1) +#define BLS_CTRL_BLS_EN BIT(0) + +#define BLS_SAMPLES_REG 0x0008 +#define BLS_H1_START_REG 0x000c +#define BLS_H1_STOP_REG 0x0010 +#define BLS_V1_START_REG 0x0014 +#define BLS_V1_STOP_REG 0x0018 +#define BLS_H2_START_REG 0x001c +#define BLS_H2_STOP_REG 0x0020 +#define BLS_V2_START_REG 0x0024 +#define BLS_V2_STOP_REG 0x0028 +#define BLS_A_FIXED_REG 0x002c +#define BLS_B_FIXED_REG 0x0030 +#define BLS_C_FIXED_REG 0x0034 +#define BLS_D_FIXED_REG 0x0038 +#define BLS_A_MEASURED_REG 0x003c +#define BLS_B_MEASURED_REG 0x0040 +#define BLS_C_MEASURED_REG 0x0044 +#define BLS_D_MEASURED_REG 0x0048 +#define BLS_PRE1_FIXED_MASK GENMASK(24, 0) +#define BLS_PRE2_FIXED_MASK GENMASK(12, 0) + +static int rppx1_bls_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, BLS_VERSION_REG)) { + case 3: + case 5: + /* 12-bit. */ + break; + case 2: + case 4: + /* 20-bit. */ + break; + case 6: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static void +rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4]) +{ + static const unsigned int swap[4][4] = { + [RPP_RGGB] = { 0, 1, 2, 3 }, + [RPP_GRBG] = { 1, 0, 3, 2 }, + [RPP_GBRG] = { 2, 3, 0, 1 }, + [RPP_BGGR] = { 3, 2, 1, 0 }, + }; + + /* Swap to pattern used in our path, PRE1 or PRE2. */ + struct rpp_module *acq = mod == &mod->rpp->pre1.bls ? + &mod->rpp->pre1.acq : &mod->rpp->pre2.bls; + enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern; + + for (unsigned int i = 0; i < 4; ++i) + output[i] = input[swap[pattern][i]]; +} + +static int +rppx1_bls_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_bls_params *cfg = &block->bls; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + BLS_CTRL_REG, 0); + return 0; + } + + u32 ctrl = BLS_CTRL_BLS_EN; + + if (cfg->mode == RPPX1_BLS_MODE_FIXED) { + static const u32 regs[] = { + BLS_A_FIXED_REG, + BLS_B_FIXED_REG, + BLS_C_FIXED_REG, + BLS_D_FIXED_REG, + }; + u32 swapped[4]; + + rppx1_bls_swap_regs(mod, regs, swapped); + + /* + * The PRE1 pipe fixed values are 24-bits + 1 sign bit, while + * the PRE2 pipe values are 12-bits + 1 sign bit. + */ + u32 mask; + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: + mask = BLS_PRE1_FIXED_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2: + mask = BLS_PRE2_FIXED_MASK; + break; + default: + return -EINVAL; + } + + write(priv, mod->base + swapped[0], cfg->fixed.a & mask); + write(priv, mod->base + swapped[1], cfg->fixed.b & mask); + write(priv, mod->base + swapped[2], cfg->fixed.c & mask); + write(priv, mod->base + swapped[3], cfg->fixed.d & mask); + } else { + write(priv, mod->base + BLS_SAMPLES_REG, cfg->samples); + + if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN1) { + write(priv, mod->base + BLS_H1_START_REG, cfg->window1.h_offs); + write(priv, mod->base + BLS_H1_STOP_REG, cfg->window1.h_size); + write(priv, mod->base + BLS_V1_START_REG, cfg->window1.v_offs); + write(priv, mod->base + BLS_V1_STOP_REG, cfg->window1.v_size); + ctrl |= BLS_CTRL_BLS_WIN1; + } + + if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN2) { + write(priv, mod->base + BLS_H2_START_REG, cfg->window2.h_offs); + write(priv, mod->base + BLS_H2_STOP_REG, cfg->window2.h_size); + write(priv, mod->base + BLS_V2_START_REG, cfg->window2.v_offs); + write(priv, mod->base + BLS_V2_STOP_REG, cfg->window2.v_size); + ctrl |= BLS_CTRL_BLS_WIN2; + } + + ctrl |= BLS_CTRL_BLS_MODE_MEASURED; + } + + write(priv, mod->base + BLS_CTRL_REG, ctrl); + + return 0; +} + +const struct rpp_module_ops rppx1_bls_ops = { + .probe = rppx1_bls_probe, + .fill_params = rppx1_bls_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c b/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c new file mode 100644 index 000000000000..fb3bfa668425 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define CAC_VERSION_REG 0x0000 +#define CAC_CTRL_REG 0x0004 +#define CAC_COUNT_START_REG 0x0008 +#define CAC_A_REG 0x000c +#define CAC_B_REG 0x0010 +#define CAC_C_REG 0x0014 +#define CAC_X_NORM_REG 0x0018 +#define CAC_Y_NORM_REG 0x001c + +static int rppx1_cac_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, CAC_VERSION_REG) != 3) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_cac_ops = { + .probe = rppx1_cac_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c new file mode 100644 index 000000000000..5ddc7edf6930 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define CCOR_VERSION_REG 0x0000 + +#define CCOR_COEFF_REG_NUM 9 +#define CCOR_COEFF_REG(n) (0x0004 + (4 * (n))) + +#define CCOR_OFFSET_R_REG 0x0028 +#define CCOR_OFFSET_G_REG 0x002c +#define CCOR_OFFSET_B_REG 0x0030 + +#define CCOR_CONFIG_TYPE_REG 0x0034 +#define CCOR_CONFIG_TYPE_USE_OFFSETS_AS_PRE_OFFSETS BIT(1) +#define CCOR_CONFIG_TYPE_CCOR_RANGE_AVAILABLE BIT(0) + +#define CCOR_RANGE_REG 0x0038 +#define CCOR_RANGE_CCOR_C_RANGE BIT(1) +#define CCOR_RANGE_CCOR_Y_RANGE BIT(0) + +static int rppx1_ccor_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, CCOR_VERSION_REG)) { + case 3: + /* 12-bit. */ + break; + case 4: + /* 20-bit. */ + break; + case 5: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_ccor_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Configure matrix in bypass mode. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0x1000); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000000); + + return 0; +} + +static int +rppx1_ccor_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_ccor_params *cfg = &block->ccor; + + /* If the modules is disabled, configure in bypass mode. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(2), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(5), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(8), 0x1000); + + write(priv, mod->base + CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_B_REG, 0x00000000); + + return 0; + } + + /* + * Coefficient n for color correction matrix. + * + * RPP coefficients are 16-bit signed fixed-point numbers with 4 bit + * integer and 12 bit fractional part ranging from -8 (0x8000) to + * +7.9996 (0x7FFF). 0 is represented by 0x0000 and a coefficient + * value of 1 as 0x1000. + */ + write(priv, mod->base + CCOR_COEFF_REG(0), cfg->coeff[0][0]); + write(priv, mod->base + CCOR_COEFF_REG(1), cfg->coeff[0][1]); + write(priv, mod->base + CCOR_COEFF_REG(2), cfg->coeff[0][2]); + + write(priv, mod->base + CCOR_COEFF_REG(3), cfg->coeff[1][0]); + write(priv, mod->base + CCOR_COEFF_REG(4), cfg->coeff[1][1]); + write(priv, mod->base + CCOR_COEFF_REG(5), cfg->coeff[1][2]); + + write(priv, mod->base + CCOR_COEFF_REG(6), cfg->coeff[2][0]); + write(priv, mod->base + CCOR_COEFF_REG(7), cfg->coeff[2][1]); + write(priv, mod->base + CCOR_COEFF_REG(8), cfg->coeff[2][2]); + + /* + * Offset for color components correction matrix. + * + * Values are a two's complement integer with one sign bit. + */ + write(priv, mod->base + CCOR_OFFSET_R_REG, cfg->offset[0]); + write(priv, mod->base + CCOR_OFFSET_G_REG, cfg->offset[1]); + write(priv, mod->base + CCOR_OFFSET_B_REG, cfg->offset[2]); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_ops = { + .probe = rppx1_ccor_probe, + .start = rppx1_ccor_start, + .fill_params = rppx1_ccor_fill_params, +}; + +static int rppx1_ccor_csm_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Reuse bypass matrix setup. */ + if (fmt->code == MEDIA_BUS_FMT_RGB888_1X24) + return rppx1_ccor_start(mod, fmt); + + /* Color Transformation RGB to YUV according to ITU-R BT.709. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x0367); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0b71); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0128); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0xfe2b); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0xf9d5); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0800); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0800); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0xf8bc); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0xff44); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000800); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000800); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_csm_ops = { + .probe = rppx1_ccor_probe, + .start = rppx1_ccor_csm_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_db.c b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c new file mode 100644 index 000000000000..78a330066b7e --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define FILT_VERSION_REG 0x0000 + +#define DEMOSAIC_REG 0x0004 +#define DEMOSAIC_DEMOSAIC_BYPASS BIT(16) +#define DEMOSAIC_DEMOSAIC_TH_MASK GENMASK(15, 0) + +#define FILT_MODE_REG 0x0008 +#define FILT_MODE_FILT_LP_SELECT_MASK GENMASK(11, 8) +#define FILT_MODE_FILT_CHR_H_MODE_MASK GENMASK(7, 6) +#define FILT_MODE_FILT_CHR_V_MODE_MASK GENMASK(5, 4) +#define FILT_MODE_FILT_MODE BIT(1) +#define FILT_MODE_FILT_ENABLE BIT(0) + +#define FILT_THRESH_BL0_REG 0x000c +#define FILT_THRESH_BL1_REG 0x0010 +#define FILT_THRESH_SH0_REG 0x0014 +#define FILT_THRESH_SH1_REG 0x0018 +#define FILT_LUM_WEIGHT_REG 0x001c +#define FILT_FAC_SH1_REG 0x0020 +#define FILT_FAC_SH0_REG 0x0024 +#define FILT_FAC_MID_REG 0x0028 +#define FILT_FAC_BL0_REG 0x002c +#define FILT_FAC_BL1_REG 0x0030 + +static int rppx1_db_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, FILT_VERSION_REG) != 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_db_ops = { + .probe = rppx1_db_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c b/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c new file mode 100644 index 000000000000..3d5d9c0a7e72 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define DPCC_VERSION_REG 0x0000 + +#define DPCC_MODE_REG 0x0004 +#define DPCC_MODE_STAGE1_ENABLE BIT(2) +#define DPCC_MODE_GRAYSCALE_MODE BIT(1) +#define DPCC_MODE_DPCC_ENABLE BIT(0) + +#define DPCC_OUTPUT_MODE_REG 0x0008 +#define DPCC_SET_USE_REG 0x000c +#define DPCC_METHODS_SET_1_REG 0x0010 +#define DPCC_METHODS_SET_2_REG 0x0014 +#define DPCC_METHODS_SET_3_REG 0x0018 +#define DPCC_LINE_THRESH_1_REG 0x001c +#define DPCC_LINE_MAD_FAC_1_REG 0x0020 +#define DPCC_PG_FAC_1_REG 0x0024 +#define DPCC_RND_THRESH_1_REG 0x0028 +#define DPCC_RG_FAC_1_REG 0x002c +#define DPCC_LINE_THRESH_2_REG 0x0030 +#define DPCC_LINE_MAD_FAC_2_REG 0x0034 +#define DPCC_PG_FAC_2_REG 0x0038 +#define DPCC_RND_THRESH_2_REG 0x003c +#define DPCC_RG_FAC_2_REG 0x0040 +#define DPCC_LINE_THRESH_3_REG 0x0044 +#define DPCC_LINE_MAD_FAC_3_REG 0x0048 +#define DPCC_PG_FAC_3_REG 0x004c +#define DPCC_RND_THRESH_3_REG 0x0050 +#define DPCC_RG_FAC_3_REG 0x0054 +#define DPCC_RO_LIMITS_REG 0x0058 +#define DPCC_RND_OFFS_REG 0x005c +#define DPCC_BPT_CTRL_REG 0x0060 +#define DPCC_BP_NUMBER_REG 0x0064 +#define DPCC_BP_TADDR_REG 0x0068 +#define DPCC_BP_POSITION_REG 0x006c + +static int rppx1_dpcc_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, DPCC_VERSION_REG)) { + case 2: + case 4: + case 6: + /* 12-bit. */ + break; + case 3: + case 5: + case 7: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_dpcc_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass stage1 and DPCC. */ + rpp_module_write(mod, DPCC_MODE_REG, 0); + + return 0; +} + +const struct rpp_module_ops rppx1_dpcc_ops = { + .probe = rppx1_dpcc_probe, + .start = rppx1_dpcc_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c new file mode 100644 index 000000000000..c7b24c356222 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define EXM_VERSION_REG 0x0000 +#define EXM_START_REG 0x0004 + +#define EXM_CTRL_REG 0x0008 +#define EXM_CTRL_EXM_AUTOSTOP BIT(1) /* HW doc says not supported. */ +#define EXM_CTRL_EXM_UPDATE_ENABLE BIT(0) + +#define EXM_MODE_REG 0x000c + +#define EXM_CHANNEL_SEL_REG 0x0010 +#define EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + +#define EXM_LAST_MEAS_LINE_REG 0x0014 +#define EXM_COEFF_R_REG 0x0018 +#define EXM_COEFF_G_GR_REG 0x001c +#define EXM_COEFF_B_REG 0x0020 +#define EXM_COEFF_GB_REG 0x0024 +#define EXM_H_OFFS_REG 0x0028 +#define EXM_V_OFFS_REG 0x002c +#define EXM_H_SIZE_REG 0x0030 +#define EXM_V_SIZE_REG 0x0034 +#define EXM_FORCED_UPD_START_LINE_REG 0x0038 +#define EXM_VSTART_STATUS_REG 0x003c + +#define EXM_MEAN_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_exm_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, EXM_VERSION_REG)) { + case 1: + /* 8-bit. */ + break; + case 3: + /* 20-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +rppx1_exm_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_exm_params *cfg = &block->exm; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + switch (cfg->mode) { + case RPPX1_EXP_MEASURING_MODE_RGB: + case RPPX1_EXP_MEASURING_MODE_BAYER: + write(priv, mod->base + EXM_MODE_REG, cfg->mode); + break; + default: + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + write(priv, mod->base + EXM_COEFF_R_REG, cfg->coeff_r); + write(priv, mod->base + EXM_COEFF_G_GR_REG, cfg->coeff_g_gr); + write(priv, mod->base + EXM_COEFF_GB_REG, cfg->coeff_gb); + write(priv, mod->base + EXM_COEFF_B_REG, cfg->coeff_b); + + /* Select sample point */ + write(priv, mod->base + EXM_CHANNEL_SEL_REG, + cfg->channel_sel & EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK); + + /* + * Adjust and set measurement window, + * - Offsets must be even. + * - Width and height must be even and divisible in 5 windows. + */ + h_offs = cfg->wnd.h_offs & 0x1ffe; + v_offs = cfg->wnd.v_offs & 0x1ffe; + h_size = (cfg->wnd.h_size - 1) - ((cfg->wnd.h_size - 1) % 10); + v_size = (cfg->wnd.v_size - 1) - ((cfg->wnd.v_size - 1) % 10); + + write(priv, mod->base + EXM_H_OFFS_REG, h_offs); + write(priv, mod->base + EXM_V_OFFS_REG, v_offs); + write(priv, mod->base + EXM_H_SIZE_REG, h_size / 5); + write(priv, mod->base + EXM_V_SIZE_REG, v_size / 5); + + /* + * Set last measurement line for ready interrupt. Ignore the value + * from the parameters as it is only useful for fast-channel switching. + */ + write(priv, mod->base + EXM_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + write(priv, mod->base + EXM_START_REG, 1); + + return 0; +} + +static int rppx1_exm_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_exm_stats *stats = &block->exm; + + for (unsigned int i = 0; i < RPPX1_EXM_NUM_WIN; i++) + stats->exp_mean[i] = rpp_module_read(mod, EXM_MEAN_REG(i)); + + return 0; +} + +const struct rpp_module_ops rppx1_exm_ops = { + .probe = rppx1_exm_probe, + .fill_params = rppx1_exm_fill_params, + .fill_stats = rppx1_exm_fill_stats, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c new file mode 100644 index 000000000000..1d9c24c43f77 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define GAMMA_OUT_VERSION_REG 0x0000 + +#define GAMMA_OUT_ENABLE_REG 0x0004 +#define GAMMA_OUT_ENABLE_GAMMA_OUT_EN BIT(0) + +#define GAMMA_OUT_MODE_REG 0x0008 +#define GAMMA_OUT_MODE_GAMMA_OUT_EQU_SEGM BIT(0) + +#define GAMMA_OUT_Y_REG(n) (0x000c + (4 * (n))) + +#define GAMMA_OUT_HV_GAMMA_CURVE_MASK GENMASK(11, 0) +#define GAMMA_OUT_MV_GAMMA_CURVE_MASK GENMASK(23, 0) + +static int rppx1_ga_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, GAMMA_OUT_VERSION_REG)) { + case 1: + /* 12-bit. */ + break; + case 2: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_ga_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Disable stage. */ + rpp_module_write(mod, GAMMA_OUT_ENABLE_REG, 0); + + return 0; +} + +static int +rppx1_ga_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_ga_params *cfg = &block->ga; + u32 mask; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, 0); + return 0; + } + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_GA_HV: + mask = GAMMA_OUT_HV_GAMMA_CURVE_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_GA_MV: + mask = GAMMA_OUT_MV_GAMMA_CURVE_MASK; + break; + default: + return -EINVAL; + } + + write(priv, mod->base + GAMMA_OUT_MODE_REG, cfg->mode); + + for (unsigned int i = 0; i < RPPX1_GA_MAX_SAMPLES; i++) + write(priv, mod->base + GAMMA_OUT_Y_REG(i), + cfg->gamma_y[i] & mask); + + /* Enable module. */ + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, + GAMMA_OUT_ENABLE_GAMMA_OUT_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_ga_ops = { + .probe = rppx1_ga_probe, + .start = rppx1_ga_start, + .fill_params = rppx1_ga_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c new file mode 100644 index 000000000000..8fe8cbbc85df --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#include <linux/bitfield.h> + +#define HIST_VERSION_REG 0x0000 + +#define HIST_CTRL_REG 0x0004 +#define HIST_CTRL_HIST_UPDATE_ENABLE BIT(0) + +#define HIST_MODE_REG 0x0008 +#define HIST_MODE_HIST_MODE_MASK GENMASK(2, 0) +#define HIST_MODE_HIST_MODE_DISABLE 0 +#define HIST_MODE_HIST_MODE_YRGB 1 +#define HIST_MODE_HIST_MODE_R 2 +#define HIST_MODE_HIST_MODE_GR 3 +#define HIST_MODE_HIST_MODE_B 4 +#define HIST_MODE_HIST_MODE_GB 5 + +#define HIST_CHANNEL_SEL_REG 0x000c +#define HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + +#define HIST_LAST_MEAS_LINE_REG 0x0010 +#define HIST_SUBSAMPLING_REG 0x0014 +#define HIST_SUBSAMPLING_V_STEPSIZE(x) (((x) & 0x7f) << 24) +#define HIST_SUBSAMPLING_H_STEP_INC(x) (((x) & 0x1ffff)) + +#define HIST_COEFF_R_REG 0x0018 +#define HIST_COEFF_G_REG 0x001c +#define HIST_COEFF_B_REG 0x0020 +#define HIST_H_OFFS_REG 0x0024 +#define HIST_V_OFFS_REG 0x0028 +#define HIST_H_SIZE_REG 0x002c +#define HIST_V_SIZE_REG 0x0030 + +#define HIST_SAMPLE_RANGE_REG 0x0034 +#define HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK GENMASK(28, 24) +#define HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK GENMASK(23, 0) + +#define HIST_WEIGHT_00TO30_REG 0x0038 +#define HIST_WEIGHT_40TO21_REG 0x003c +#define HIST_WEIGHT_31TO12_REG 0x0040 +#define HIST_WEIGHT_22TO03_REG 0x0044 +#define HIST_WEIGHT_13TO43_REG 0x0048 +#define HIST_WEIGHT_04TO34_REG 0x004c +#define HIST_WEIGHT_44_REG 0x0050 +#define HIST_FORCED_UPD_START_LINE_REG 0x0054 +#define HIST_FORCED_UPDATE_REG 0x0058 +#define HIST_VSTART_STATUS_REG 0x005c + +#define HIST_BIN_REG(n) (0x0060 + (4 * (n))) + +static int rppx1_hist_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, HIST_VERSION_REG)) { + case 3: + /* 12-bit. */ + break; + case 4: + /* 20-bit. */ + break; + case 5: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +#define RPPX1_HIST_WEIGHT(v0, v1, v2, v3) \ + (((v0) & 0x1f) | (((v1) & 0x1f) << 8) | \ + (((v2) & 0x1f) << 16) | \ + (((v3) & 0x1f) << 24)) + +static int rppx1_hist_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_hist_params *cfg = &block->hist; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + HIST_MODE_REG, + HIST_MODE_HIST_MODE_DISABLE); + return 0; + } + + /* Select sample point */ + write(priv, mod->base + HIST_CHANNEL_SEL_REG, + cfg->channel_sel & HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK); + + /* + * Configure the input subsampling. + * + * In Bayer mode the vertical and horizontal subsampling counters are + * only incremented for color channels selected by hist_mode. + */ + write(priv, mod->base + HIST_SUBSAMPLING_REG, + HIST_SUBSAMPLING_V_STEPSIZE(cfg->v_stepsize) | + HIST_SUBSAMPLING_H_STEP_INC(cfg->h_step_inc)); + + /* + * Adjust and set measurement window to hardware limitations, + * - Offsets must be even. + * - Width and height must be even and divisible in 5 windows. + */ + h_offs = cfg->wnd.h_offs & 0x1ffe; + v_offs = cfg->wnd.v_offs & 0x1ffe; + h_size = cfg->wnd.h_size - cfg->wnd.h_size % 10; + v_size = cfg->wnd.v_size - cfg->wnd.v_size % 10; + + write(priv, mod->base + HIST_H_OFFS_REG, h_offs); + write(priv, mod->base + HIST_V_OFFS_REG, v_offs); + write(priv, mod->base + HIST_H_SIZE_REG, h_size / 5); + write(priv, mod->base + HIST_V_SIZE_REG, v_size / 5); + + /* + * Set last measurement line for ready interrupt. Ignore the value + * from the parameters as it is only useful for fast-channel switching. + */ + write(priv, mod->base + HIST_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + /* Set measurement window weights. */ + write(priv, mod->base + HIST_WEIGHT_00TO30_REG, + RPPX1_HIST_WEIGHT(cfg->weights[0], cfg->weights[1], + cfg->weights[2], cfg->weights[3])); + write(priv, mod->base + HIST_WEIGHT_40TO21_REG, + RPPX1_HIST_WEIGHT(cfg->weights[4], cfg->weights[5], + cfg->weights[6], cfg->weights[7])); + write(priv, mod->base + HIST_WEIGHT_31TO12_REG, + RPPX1_HIST_WEIGHT(cfg->weights[8], cfg->weights[9], + cfg->weights[10], cfg->weights[11])); + write(priv, mod->base + HIST_WEIGHT_22TO03_REG, + RPPX1_HIST_WEIGHT(cfg->weights[12], cfg->weights[13], + cfg->weights[14], cfg->weights[15])); + write(priv, mod->base + HIST_WEIGHT_13TO43_REG, + RPPX1_HIST_WEIGHT(cfg->weights[16], cfg->weights[17], + cfg->weights[18], cfg->weights[19])); + write(priv, mod->base + HIST_WEIGHT_04TO34_REG, + RPPX1_HIST_WEIGHT(cfg->weights[20], cfg->weights[21], + cfg->weights[22], cfg->weights[23])); + write(priv, mod->base + HIST_WEIGHT_44_REG, + RPPX1_HIST_WEIGHT(cfg->weights[24], 0, 0, 0)); + + write(priv, mod->base + HIST_MODE_REG, cfg->mode); + write(priv, mod->base + HIST_COEFF_R_REG, cfg->coeff[0]); + write(priv, mod->base + HIST_COEFF_G_REG, cfg->coeff[1]); + write(priv, mod->base + HIST_COEFF_B_REG, cfg->coeff[2]); + + u32 sample_reg = FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK, + cfg->sample_shift) | + FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK, + cfg->sample_offs); + write(priv, mod->base + HIST_SAMPLE_RANGE_REG, sample_reg); + + write(priv, mod->base + HIST_FORCED_UPDATE_REG, 1); + + return 0; +} + +static int rppx1_hist_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_hist_stats *stats = &block->hist; + + for (unsigned int i = 0; i < RPPX1_HIST_NUM_BINS; i++) + stats->hist_bins[i] = rpp_module_read(mod, HIST_BIN_REG(i)); + + return 0; +} + +const struct rpp_module_ops rppx1_hist_ops = { + .probe = rppx1_hist_probe, + .fill_params = rppx1_hist_fill_params, + .fill_stats = rppx1_hist_fill_stats, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c b/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c new file mode 100644 index 000000000000..80b3244c77aa --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define HIST256_VERSION_REG 0x0000 +#define HIST256_MODE_REG 0x0004 +#define HIST256_MODE_HIST256_MODE BIT(0) + +#define HIST256_CHANNEL_SEL_REG 0x0008 +#define HIST256_CHANNEL_SEL_CHANNEL_SELECT GENMASK(2, 0) + +#define HIST256_H_OFFS_REG 0x000c +#define HIST256_V_OFFS_REG 0x0010 +#define HIST256_H_SIZE_REG 0x0014 +#define HIST256_V_SIZE_REG 0x0018 +#define HIST256_SAMPLE_OFFSET_REG 0x001c +#define HIST256_SAMPLE_SCALE_REG 0x0020 +#define HIST256_MEAS_RESULT_ADDR_AUTOINCR_REG 0x0024 +#define HIST256_MEAS_RESULT_ADDR_REG 0x0028 +#define HIST256_MEAS_RESULT_DATA_REG 0x002c + +#define HIST256_LOG_ENABLE_REG 0x0030 +#define HIST256_LOG_ENABLE_HIST256_LOG_EN BIT(0) + +#define HIST256_LOG_DX_LO_REG 0x0034 +#define HIST256_LOG_DX_HI_REG 0x0038 + +#define HIST256_Y_REG_NUM 17 +#define HIST256_Y_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_hist256_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, HIST256_VERSION_REG) != 2) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_hist256_ops = { + .probe = rppx1_hist256_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_is.c b/drivers/media/platform/dreamchip/rppx1/rppx1_is.c new file mode 100644 index 000000000000..7b1b6f6538cf --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_is.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define IS_VERSION 0x0000 +#define IS_H_OFFS 0x0008 +#define IS_V_OFFS 0x000c +#define IS_H_SIZE 0x0010 +#define IS_V_SIZE 0x0014 +#define IS_H_OFFS_SHD 0x0024 +#define IS_V_OFFS_SHD 0x0028 +#define IS_H_SIZE_SHD 0x002c +#define IS_V_SIZE_SHD 0x0030 + +static int rppx1_is_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, IS_VERSION) != 1) + return -EINVAL; + + return 0; +} + +static int rppx1_is_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_write(mod, IS_H_OFFS, 0); + rpp_module_write(mod, IS_V_OFFS, 0); + rpp_module_write(mod, IS_H_SIZE, fmt->width); + rpp_module_write(mod, IS_V_SIZE, fmt->height); + + return 0; +} + +const struct rpp_module_ops rppx1_is_ops = { + .probe = rppx1_is_probe, + .start = rppx1_is_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c b/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c new file mode 100644 index 000000000000..b389778f9383 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +/* NOTE: The module is called LIN the registers GAMMA_IN. */ +#define LIN_VERSION_REG 0x0000 + +#define LIN_ENABLE_REG 0x0004 +#define LIN_ENABLE_GAMMA_IN_EN BIT(0) + +#define LIN_DX_LO_REG 0x0008 +#define LIN_DX_HI_REG 0x000c + +#define LIN_R_Y_REG_NUM 17 +#define LIN_R_Y_REG(n) (0x0010 + (4 * (n))) + +#define LIN_G_Y_REG_NUM 17 +#define LIN_G_Y_REG(n) (0x0054 + (4 * (n))) + +#define LIN_B_Y_REG_NUM 17 +#define LIN_B_Y_REG(n) (0x0098 + (4 * (n))) + +#define LIN_PRE1_DEGAMMA_CURVE_MASK GENMASK(23, 0) +#define LIN_PRE1_SAMPLE_POINTS_MASK GENMASK(3, 0) +#define LIN_PRE2_DEGAMMA_CURVE_MASK GENMASK(11, 0) +#define LIN_PRE2_SAMPLE_POINTS_MASK GENMASK(2, 0) + +static int rppx1_lin_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, LIN_VERSION_REG)) { + case 7: + /* 12-bit. */ + break; + case 8: + /* 20-bit. */ + break; + case 9: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_lin_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, LIN_ENABLE_REG, LIN_ENABLE_GAMMA_IN_EN, 0); + + return 0; +} + +static int rppx1_lin_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_lin_params *cfg = &block->lin; + u8 sample_mask; + u32 dx_lo = 0; + u32 dx_hi = 0; + u32 mask; + + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + LIN_ENABLE_REG, 0); + return 0; + } + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1: + mask = LIN_PRE1_DEGAMMA_CURVE_MASK; + sample_mask = LIN_PRE1_SAMPLE_POINTS_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2: + mask = LIN_PRE2_DEGAMMA_CURVE_MASK; + sample_mask = LIN_PRE2_SAMPLE_POINTS_MASK; + break; + default: + return -EINVAL; + } + + for (unsigned int i = 0; i < 8; ++i) { + dx_lo |= (cfg->dx[i] & sample_mask) << 4 * i; + dx_hi |= (cfg->dx[i + 8] & sample_mask) << 4 * i; + } + + write(priv, mod->base + LIN_DX_LO_REG, dx_lo); + write(priv, mod->base + LIN_DX_HI_REG, dx_hi); + + for (unsigned int i = 0; i < RPPX1_LIN_DEGAMMA_CURVE_NUM; i++) { + write(priv, mod->base + LIN_R_Y_REG(i), cfg->curve_r[i] & mask); + write(priv, mod->base + LIN_G_Y_REG(i), cfg->curve_g[i] & mask); + write(priv, mod->base + LIN_B_Y_REG(i), cfg->curve_b[i] & mask); + } + + write(priv, mod->base + LIN_ENABLE_REG, LIN_ENABLE_GAMMA_IN_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_lin_ops = { + .probe = rppx1_lin_probe, + .start = rppx1_lin_start, + .fill_params = rppx1_lin_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c new file mode 100644 index 000000000000..8badeca23e24 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LSC_VERSION_REG 0x0000 + +#define LSC_CTRL_REG 0x0004 +#define LSC_CTRL_LSC_EN BIT(0) + +#define LSC_R_TABLE_ADDR_REG 0x0008 +#define LSC_GR_TABLE_ADDR_REG 0x000c +#define LSC_B_TABLE_ADDR_REG 0x0010 +#define LSC_GB_TABLE_ADDR_REG 0x0014 +#define LSC_R_TABLE_DATA_REG 0x0018 +#define LSC_GR_TABLE_DATA_REG 0x001c +#define LSC_B_TABLE_DATA_REG 0x0020 +#define LSC_GB_TABLE_DATA_REG 0x0024 +#define LSC_XGRAD_01_REG 0x0028 +#define LSC_XGRAD_23_REG 0x002c +#define LSC_XGRAD_45_REG 0x0030 +#define LSC_XGRAD_67_REG 0x0034 +#define LSC_XGRAD_89_REG 0x0038 +#define LSC_XGRAD_1011_REG 0x003c +#define LSC_XGRAD_1213_REG 0x0040 +#define LSC_XGRAD_1415_REG 0x0044 +#define LSC_YGRAD_01_REG 0x0048 +#define LSC_YGRAD_23_REG 0x004c +#define LSC_YGRAD_45_REG 0x0050 +#define LSC_YGRAD_67_REG 0x0054 +#define LSC_YGRAD_89_REG 0x0058 +#define LSC_YGRAD_1011_REG 0x005c +#define LSC_YGRAD_1213_REG 0x0060 +#define LSC_YGRAD_1415_REG 0x0064 +#define LSC_XSIZE_01_REG 0x0068 +#define LSC_XSIZE_23_REG 0x006c +#define LSC_XSIZE_45_REG 0x0070 +#define LSC_XSIZE_67_REG 0x0074 +#define LSC_XSIZE_89_REG 0x0078 +#define LSC_XSIZE_1011_REG 0x007c +#define LSC_XSIZE_1213_REG 0x0080 +#define LSC_XSIZE_1415_REG 0x0084 +#define LSC_YSIZE_01_REG 0x0088 +#define LSC_YSIZE_23_REG 0x008c +#define LSC_YSIZE_45_REG 0x0090 +#define LSC_YSIZE_67_REG 0x0094 +#define LSC_YSIZE_89_REG 0x0098 +#define LSC_YSIZE_1011_REG 0x009c +#define LSC_YSIZE_1213_REG 0x00a0 +#define LSC_YSIZE_1415_REG 0x00a4 +#define LSC_TABLE_SEL_REG 0x00a8 +#define LSC_STATUS_REG 0x00ac + +#define LSC_R_TABLE_DATA_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) << 12)) +#define LSC_GRAD_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) << 16)) +#define LSC_SIZE_VALUE(v1, v2) (((v1) & 0x1ff) | (((v2) & 0x1ff) << 16)) + +static int rppx1_lsc_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LSC_VERSION_REG) != 0x04) + return -EINVAL; + + return 0; +} + +static int +rppx1_lsc_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_lsc_params *cfg = &block->lsc; + const __u16 *v; + + /* Always disable module as it needs be disabled before configuring. */ + write(priv, mod->base + LSC_CTRL_REG, 0); + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) + return 0; + + /* + * Program the color correction sectors. + * + * There are two tables to one can program and switch between. As the + * RPPX1 supports preparing a buffer of commands to be applied later + * only use table 0. This works as long as the ISP is not used in + * inline-mode. + * + * For inline-mode support using DMA for configuration is not possible + * so this is not an issue, but needs to be address if inline-mode + * support is added to the driver. + */ + + /* Start writing at beginning of table 0. */ + write(priv, mod->base + LSC_R_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GR_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_B_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GB_TABLE_ADDR_REG, 0); + + /* Program data tables. */ + for (unsigned int i = 0; i < RPPX1_LSC_SAMPLES_MAX; i++) { + const __u16 *r = cfg->r_data[i]; + const __u16 *gr = cfg->gr_data[i]; + const __u16 *b = cfg->b_data[i]; + const __u16 *gb = cfg->gb_data[i]; + unsigned int j; + + for (j = 0; j < RPPX1_LSC_SAMPLES_MAX - 1; j += 2) { + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], r[j + 1])); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], gr[j + 1])); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], b[j + 1])); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], gb[j + 1])); + } + + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], 0)); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], 0)); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], 0)); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], 0)); + } + + /* Activate table 0. */ + write(priv, mod->base + LSC_TABLE_SEL_REG, 0); + + /* + * Program X- and Y- sizes, and gradients. + */ + + v = cfg->x_grad; + write(priv, mod->base + LSC_XGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XGRAD_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_XGRAD_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_XGRAD_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_XGRAD_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->y_grad; + write(priv, mod->base + LSC_YGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YGRAD_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_YGRAD_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_YGRAD_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_YGRAD_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->x_sect_size; + write(priv, mod->base + LSC_XSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XSIZE_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_XSIZE_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_XSIZE_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_XSIZE_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->y_sect_size; + write(priv, mod->base + LSC_YSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YSIZE_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_YSIZE_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_YSIZE_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_YSIZE_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + /* Enable module. */ + write(priv, mod->base + LSC_CTRL_REG, LSC_CTRL_LSC_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_lsc_ops = { + .probe = rppx1_lsc_probe, + .fill_params = rppx1_lsc_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c new file mode 100644 index 000000000000..9a71155e7e13 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LTM_VERSION_REG 0x0000 + +#define LTM_CTRL_REG 0x0004 +#define LTM_CTRL_LTM_ENABLE BIT(0) + +#define LTM_RGB_WEIGHTS_REG 0x0008 +#define LTM_CLB_LINESIZE_REG 0x000c +#define LTM_TONECURVE_1_REG 0x0010 +#define LTM_TONECURVE_2_REG 0x0014 +#define LTM_TONECURVE_3_REG 0x0018 +#define LTM_TONECURVE_4_REG 0x001c +#define LTM_TONECURVE_5_REG 0x0020 +#define LTM_TONECURVE_6_REG 0x0024 +#define LTM_TONECURVE_YM_REG(n) (0x0028 + (4 * (n))) +#define LTM_L0W_REG 0x00ec +#define LTM_L0W_R_REG 0x00f0 +#define LTM_L0D_REG 0x00f4 +#define LTM_L0D_R_REG 0x00f8 +#define LTM_KMIND_REG 0x00fc +#define LTM_KMAXD_REG 0x0100 +#define LTM_KDIFFD_REG 0x0104 +#define LTM_KDIFFD_R_REG 0x0108 +#define LTM_KW_REG 0x010c +#define LTM_KW_R_REG 0x0110 +#define LTM_CGAIN_REG 0x0114 +#define LTM_LPRCH_R_HIGH_REG 0x0118 +#define LTM_LPRCH_R_LOW_REG 0x011c + +static int rppx1_ltm_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_VERSION_REG) != 8) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltm_ops = { + .probe = rppx1_ltm_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c new file mode 100644 index 000000000000..c874b8fa8999 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LTM_MEAS_VERSION_REG 0x0000 + +#define LTM_MEAS_CTRL_REG 0x0004 +#define LTM_MEAS_CTRL_LTM_MEAS_ENABLE BIT(0) + +#define LTM_MEAS_RGB_WEIGHTS_REG 0x0008 +#define LTM_MEAS_H_OFFS_REG 0x000c +#define LTM_MEAS_V_OFFS_REG 0x0010 +#define LTM_MEAS_H_SIZE_REG 0x0014 +#define LTM_MEAS_V_SIZE_REG 0x0018 + +#define LTM_MEAS_PRC_THRESH_NUM 8 +#define LTM_MEAS_PRC_THRESH_REG(n) (0x001c + (4 * (n))) + +#define LTM_MEAS_PRC_REG_NUM 8 +#define LTM_MEAS_PRC_REG(n) (0x003c + (4 * (n))) + +#define LTM_MEAS_L_MIN_REG 0x005c +#define LTM_MEAS_L_MAX_REG 0x0060 +#define LTM_MEAS_L_GMEAN_REG 0x0064 + +static int rppx1_ltmmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_MEAS_VERSION_REG) != 1) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltmmeas_ops = { + .probe = rppx1_ltmmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c b/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c new file mode 100644 index 000000000000..973b82a40d7c --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define OUT_IF_VERSION_REG 0x0000 + +#define OUT_IF_ON_REG 0x0004 +#define OUT_IF_ON_RPP_ON BIT(0) + +#define OUT_IF_OFF_REG 0x0008 + +#define OUT_IF_NR_FRAMES_REG 0x000c +#define OUT_IF_NR_FRAMES_NR_FRAMES GENMASK(9, 0) + +#define OUT_IF_NR_FRAMES_CNT_REG 0x0010 +#define FLAGS_SHD_REG 0x0018 + +static int rppx1_outif_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUT_IF_VERSION_REG) != 1) + return -EINVAL; + + return 0; +} + +static int rppx1_outif_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, OUT_IF_NR_FRAMES_REG, + OUT_IF_NR_FRAMES_NR_FRAMES, 0); + + rpp_module_write(mod, OUT_IF_ON_REG, OUT_IF_ON_RPP_ON); + + return 0; +} + +const struct rpp_module_ops rppx1_outif_ops = { + .probe = rppx1_outif_probe, + .start = rppx1_outif_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c b/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c new file mode 100644 index 000000000000..ac8b71867137 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define OUTREGS_VERSION_REG 0x0000 + +#define OUT_MODE_REG 0x0004 +#define OUT_MODE_UNSELECTED_MODE_MASK GENMASK(11, 8) +#define OUT_MODE_UNSELECTED_MODE_MAIN (0x1 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE1 (0x2 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE2 (0x4 << 8) +#define OUT_MODE_IN_SEL_MASK GENMASK(3, 0) +#define OUT_MODE_IN_SEL_MAIN 1 +#define OUT_MODE_IN_SEL_PRE1 2 +#define OUT_MODE_IN_SEL_PRE2 4 + +#define OUT_CONV_422_METHOD_REG 0x0008 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_MASK GENMASK(1, 0) +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1 0 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED2 1 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_NON_CO_SITED 2 + +#define OUTREGS_FORMAT_REG 0x000c +#define OUTREGS_FORMAT_OUTPUT_FORMAT_MASK GENMASK(1, 0) +#define OUTREGS_FORMAT_OUTPUT_FORMAT_RGB 0 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422 1 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV420 2 + +static int rppx1_outregs_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUTREGS_VERSION_REG) != 2) + return -EINVAL; + + return 0; +} + +static int rppx1_outregs_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 format; + + switch (fmt->code) { + case MEDIA_BUS_FMT_YUYV12_1X24: + format = OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + format = OUTREGS_FORMAT_OUTPUT_FORMAT_RGB; + break; + default: + return -EINVAL; + } + + rpp_module_clrset(mod, OUT_MODE_REG, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MASK, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MAIN); + + rpp_module_clrset(mod, OUT_CONV_422_METHOD_REG, + OUT_CONV_422_METHOD_CONV_422_METHOD_MASK, + OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1); + + rpp_module_clrset(mod, OUTREGS_FORMAT_REG, + OUTREGS_FORMAT_OUTPUT_FORMAT_MASK, format); + + return 0; +} + +const struct rpp_module_ops rppx1_outregs_ops = { + .probe = rppx1_outregs_probe, + .start = rppx1_outregs_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c b/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c new file mode 100644 index 000000000000..0a891caf3c52 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RMAP_DATA_VERSION_REG 0x0000 + +#define RMAP_CTRL_REG 0x0004 +#define RMAP_CTRL_BYPASS_LONG BIT(2) + +#define RMAP_WBTHRESHOLD_LONG_REG 0x0008 +#define RMAP_WBTHRESHOLD_SHORT_REG 0x000c +#define RMAP_RESERVED_1_REG 0x0010 +#define RMAP_WBGAIN_LONG_RED_REG 0x0014 +#define RMAP_WBGAIN_LONG_BLUE_REG 0x0018 +#define RMAP_WBGAIN_SHORT_RED_REG 0x001c +#define RMAP_WBGAIN_SHORT_BLUE_REG 0x0020 +#define RMAP_RESERVED_2_REG 0x0024 +#define RMAP_RESERVED_3_REG 0x0028 +#define RMAP_MAP_FAC_SHORT_REG 0x002c +#define RMAP_RESERVED_4_REG 0x0030 +#define RMAP_MIN_THRES_SHORT_REG 0x0034 +#define RMAP_MAX_THRES_SHORT_REG 0x0038 +#define RMAP_STEPSIZE_SHORT_REG 0x003c +#define RMAP_MIN_THRES_LONG_REG 0x0040 +#define RMAP_MAX_THRES_LONG_REG 0x0044 +#define RMAP_STEPSIZE_LONG_REG 0x0048 +#define RMAP_CLB_LINESIZE_REG 0x004c + +static int rppx1_rmap_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_DATA_VERSION_REG)) { + case 8: + /* low: 12-bit, high: 20-bit. */ + break; + case 9: + /* low: 12-bit, high: 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_rmap_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass radiance mapping and use the long exposure channel (PRE1). */ + rpp_module_write(mod, RMAP_CTRL_REG, RMAP_CTRL_BYPASS_LONG); + + return 0; +} + +const struct rpp_module_ops rppx1_rmap_ops = { + .probe = rppx1_rmap_probe, + .start = rppx1_rmap_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c new file mode 100644 index 000000000000..ef709d2a6ee9 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RMAP_MEAS_VERSION_REG 0x0000 +#define RMAP_MEAS_MODE_REG 0x0004 +#define RMAP_MEAS_SUBSAMPLING_REG 0x0008 +#define RMAP_MEAS_RESERVED_1_REG 0x000c +#define RMAP_MEAS_MIN_THRES_SHORT_REG 0x0010 +#define RMAP_MEAS_MAX_THRES_SHORT_REG 0x0014 +#define RMAP_MEAS_MAX_THRES_LONG_REG 0x0018 +#define RMAP_MEAS_H_OFFS_REG 0x001c +#define RMAP_MEAS_V_OFFS_REG 0x0020 +#define RMAP_MEAS_H_SIZE_REG 0x0024 +#define RMAP_MEAS_V_SIZE_REG 0x0028 +#define RMAP_MEAS_LAST_MEAS_LINE_REG 0x002c +#define RMAP_MEAS_LS_RESULTSHORT0_REG 0x0030 +#define RMAP_MEAS_LS_RESULTLONG0_REG 0x0034 +#define RMAP_MEAS_RESERVED_2_REG 0x0038 +#define RMAP_MEAS_RESERVED_3_REG 0x003c +#define RMAP_MEAS_LS_RESULTSHORT1_REG 0x0040 +#define RMAP_MEAS_LS_RESULTLONG1_REG 0x0044 +#define RMAP_MEAS_RESERVED_4_REG 0x0048 +#define RMAP_MEAS_RESERVED_5_REG 0x004c + +static int rppx1_rmapmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_MEAS_VERSION_REG)) { + case 3: + /* low: 12-bit, high: 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_rmapmeas_ops = { + .probe = rppx1_rmapmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c b/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c new file mode 100644 index 000000000000..c155418129e5 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define SHRPCNR_VERSION_REG 0x0000 + +#define SHRPCNR_CTRL_REG 0x0004 +#define SHRPCNR_CTRL_CAD_EN BIT(3) +#define SHRPCNR_CTRL_DESAT_EN BIT(2) +#define SHRPCNR_CTRL_CNR_EN BIT(1) +#define SHRPCNR_CTRL_SHARPEN_EN BIT(0) + +#define SHRPCNR_PARAM_REG 0x0008 +#define SHRPCNR_PARAM_SHARP_FACTOR_MASK GENMASK(19, 12) +#define SHRPCNR_PARAM_CORING_THR_MASK GENMASK(11, 0) + +#define SHRPCNR_MAT_1_REG 0x000c +#define SHRPCNR_MAT_2_REG 0x0010 +#define SHRPCNR_CLB_LINESIZE_REG 0x0014 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_0_REG 0x0018 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_1_REG 0x001c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_2_REG 0x0020 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_3_REG 0x0024 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_4_REG 0x0028 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_5_REG 0x002c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_6_REG 0x0030 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_7_REG 0x0034 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_8_REG 0x0038 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_R_REG 0x003c +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_G_REG 0x0040 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_B_REG 0x0044 + +#define SHRPCNR_CNR_THRES_REG 0x0048 +#define SHRPCNR_CNR_THRES_CNR_THRES_CR_MASK GENMASK(27, 16) +#define SHRPCNR_CNR_THRES_CNR_THRES_CB_MASK GENMASK(11, 0) + +#define SHRPCNR_CRED_THRES_REG 0x004c +#define SHRPCNR_CRED_SLOPE_REG 0x0050 +#define SHRPCNR_CAD_RESTORE_LVL_REG 0x0054 +#define SHRPCNR_CAD_THRESH_V_UNEG_REG 0x0058 +#define SHRPCNR_CAD_THRESH_V_UPOS_REG 0x005c +#define SHRPCNR_CAD_THRESH_U_REG 0x0060 + +static int rppx1_shrp_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, SHRPCNR_VERSION_REG)) { + case 2: + /* 12-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_shrp_ops = { + .probe = rppx1_shrp_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c new file mode 100644 index 000000000000..f0a943556238 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define AWB_MEAS_VERSION_REG 0x0000 + +#define AWB_MEAS_PROP_REG 0x0004 +#define AWB_MEAS_PROP_MEAS_MODE_RGB BIT(16) /* 0: YCbCr 1: RGB */ +#define AWB_MEAS_PROP_YMAX BIT(2) +#define AWB_MEAS_PROP_AWB_MODE_ON BIT(1) + +#define AWB_MEAS_H_OFFS_REG 0x0008 +#define AWB_MEAS_V_OFFS_REG 0x000c +#define AWB_MEAS_H_SIZE_REG 0x0010 +#define AWB_MEAS_V_SIZE_REG 0x0014 +#define AWB_MEAS_FRAMES_REG 0x0018 +#define AWB_MEAS_REF_CB_MAX_B_REG 0x001c +#define AWB_MEAS_REF_CR_MAX_R_REG 0x0020 +#define AWB_MEAS_MAX_Y_REG 0x0024 +#define AWB_MEAS_MIN_Y_MAX_G_REG 0x0028 +#define AWB_MEAS_MAX_CSUM_REG 0x002c +#define AWB_MEAS_MIN_C_REG 0x0030 +#define AWB_MEAS_WHITE_CNT_REG 0x0034 +#define AWB_MEAS_MEAN_Y_G_REG 0x0038 +#define AWB_MEAS_MEAN_CB_B_REG 0x003c +#define AWB_MEAS_MEAN_CR_R_REG 0x0040 + +#define AWB_MEAS_CCOR_COEFF_NUM 9 +#define AWB_MEAS_CCOR_COEFF_REG(n) (0x0044 + (4 * (n))) + +#define AWB_MEAS_CCOR_OFFSET_R_REG 0x0068 +#define AWB_MEAS_CCOR_OFFSET_G_REG 0x006c +#define AWB_MEAS_CCOR_OFFSET_B_REG 0x0070 + +static int rppx1_wbmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, AWB_MEAS_VERSION_REG)) { + case 1: + /* 8-bit. */ + break; + case 2: + /* 20-bit. */ + break; + case 3: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +rppx1_wbmeas_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_wbmeas_params *cfg = &block->wbmeas; + u32 awb_meas_props; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_MEAS_PROP_REG, 0); + return 0; + } + + /* Program measurement window. */ + write(priv, mod->base + AWB_MEAS_H_OFFS_REG, cfg->wnd.h_offs); + write(priv, mod->base + AWB_MEAS_V_OFFS_REG, cfg->wnd.v_offs); + write(priv, mod->base + AWB_MEAS_H_SIZE_REG, cfg->wnd.h_size); + write(priv, mod->base + AWB_MEAS_V_SIZE_REG, cfg->wnd.v_size); + + /* Set number of frames to sample. */ + write(priv, mod->base + AWB_MEAS_FRAMES_REG, cfg->frames); + + if (cfg->mode == RPPX1_WBMEAS_MODE_YCBCR) { + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->ref_cb_max_b); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->ref_cr_max_r); + write(priv, mod->base + AWB_MEAS_MAX_Y_REG, cfg->max_y); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->min_y_max_g); + write(priv, mod->base + AWB_MEAS_MAX_CSUM_REG, cfg->max_csum); + write(priv, mod->base + AWB_MEAS_MIN_C_REG, cfg->min_c); + + /* + * Program the color conversion matrix coefficients and the + * per-color channel offsets. + */ + for (unsigned int i = 0; i < 3; i++) { + for (unsigned int j = 0; j < 3; j++) { + unsigned int index = i * 3 + j; + + write(priv, + mod->base + AWB_MEAS_CCOR_COEFF_REG(index), + cfg->ccor_coeff[i][j]); + } + } + + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, + cfg->ccor_offs[0]); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, + cfg->ccor_offs[1]); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, + cfg->ccor_offs[2]); + + awb_meas_props = cfg->ymax_cmp ? AWB_MEAS_PROP_YMAX : 0; + } else { + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->ref_cb_max_b); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->ref_cr_max_r); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->min_y_max_g); + + /* Bypass color conversion matrix and color offsets. */ + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00000000); + + awb_meas_props = AWB_MEAS_PROP_MEAS_MODE_RGB; + } + + write(priv, mod->base + AWB_MEAS_PROP_REG, + awb_meas_props | AWB_MEAS_PROP_AWB_MODE_ON); + + return 0; +} + +static int rppx1_wbmeas_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_wbmeas_stats *stats = &block->wbmeas; + + /* Return measurements at native hardware precision. */ + stats->cnt = rpp_module_read(mod, AWB_MEAS_WHITE_CNT_REG); + stats->mean_y_or_g = rpp_module_read(mod, AWB_MEAS_MEAN_Y_G_REG); + stats->mean_cb_or_b = rpp_module_read(mod, AWB_MEAS_MEAN_CB_B_REG); + stats->mean_cr_or_r = rpp_module_read(mod, AWB_MEAS_MEAN_CR_R_REG); + + return 0; +} + +const struct rpp_module_ops rppx1_wbmeas_ops = { + .probe = rppx1_wbmeas_probe, + .fill_params = rppx1_wbmeas_fill_params, + .fill_stats = rppx1_wbmeas_fill_stats +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c b/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c new file mode 100644 index 000000000000..cc6f977c8a03 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define XYZ2LUV_VERSION_REG 0x0000 +#define XYZ2LUV_U_REF_REG 0x0004 +#define XYZ2LUV_V_REF_REG 0x0008 +#define XYZ2LUV_LUMA_OUT_FAC_REG 0x000c +#define XYZ2LUV_CHROMA_OUT_FAC_REG 0x0010 + +static int rppx1_xyz2luv_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, XYZ2LUV_VERSION_REG) != 4) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_xyz2luv_ops = { + .probe = rppx1_xyz2luv_probe, +}; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c index d30a05782ab9..96a66aadf0cd 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -321,7 +321,7 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, /* Enable mux settings */ for (index = 0; index < ctrl->num_sets; index++) { set = &ctrl->sets[index]; - cmdq_pkt_write(&cmd->pkt, set->subsys_id, set->reg, set->value); + cmdq_pkt_write_subsys(&cmd->pkt, set->subsys_id, set->reg, set->reg, set->value); } /* Config sub-frame information */ for (index = (num_comp - 1); index >= 0; index--) { @@ -376,7 +376,7 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, /* Disable mux settings */ for (index = 0; index < ctrl->num_sets; index++) { set = &ctrl->sets[index]; - cmdq_pkt_write(&cmd->pkt, set->subsys_id, set->reg, 0); + cmdq_pkt_write_subsys(&cmd->pkt, set->subsys_id, set->reg, set->reg, 0); } return 0; @@ -628,7 +628,7 @@ static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp, goto err_free_path; } cmdq_pkt_eoc(&cmd->pkt); - cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]); + cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]); for (i = 0; i < num_comp; i++) { s32 inner_id = MDP_COMP_NONE; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h index 681906c16419..c6fc180950f2 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h @@ -12,14 +12,14 @@ #define MM_REG_WRITE_MASK(cmd, id, base, ofst, val, mask) \ do { \ typeof(mask) (m) = (mask); \ - cmdq_pkt_write_mask(&((cmd)->pkt), id, (base) + (ofst), \ - (val), \ + cmdq_pkt_write_mask_subsys(&((cmd)->pkt), (id), (base), \ + (base) + (ofst), (val), \ (((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \ (0xffffffff) : (m)); \ } while (0) #define MM_REG_WRITE(cmd, id, base, ofst, val) \ - cmdq_pkt_write(&((cmd)->pkt), id, (base) + (ofst), (val)) + cmdq_pkt_write_subsys(&((cmd)->pkt), (id), (base), (base) + (ofst), (val)) #define MM_REG_WAIT(cmd, evt) \ do { \ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 8f4da4cf55d2..f412aadb5996 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -294,7 +294,11 @@ static int mdp_probe(struct platform_device *pdev) goto err_destroy_clock_wq; } mdp->scp = platform_get_drvdata(mm_pdev); - put_device(&mm_pdev->dev); + } + + if (!mdp->scp) { + ret = -EPROBE_DEFER; + goto err_destroy_clock_wq; } mdp->rproc_handle = scp_get_rproc(mdp->scp); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index adbacabdbebc..ba7a1cd998b9 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -974,10 +974,10 @@ static int vdec_vp9_slice_setup_pfc(struct vdec_vp9_slice_instance *instance, return 0; } -static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, - struct vdec_vp9_slice_vsi *vsi, - struct mtk_vcodec_mem *bs, - struct vdec_lat_buf *lat_buf) +static void vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf) { int i; @@ -1011,12 +1011,10 @@ static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *insta vsi->row_info.buf = 0; vsi->row_info.size = 0; - - return 0; } -static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, - struct vdec_vp9_slice_vsi *vsi) +static void vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) { struct vdec_vp9_slice_frame_ctx *frame_ctx; struct vdec_vp9_slice_uncompressed_header *uh; @@ -1032,8 +1030,6 @@ static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *inst else frame_ctx = vdec_vp9_slice_default_frame_ctx; memcpy(instance->prob.va, frame_ctx, sizeof(*frame_ctx)); - - return 0; } static void vdec_vp9_slice_setup_seg_buffer(struct vdec_vp9_slice_instance *instance, @@ -1166,17 +1162,13 @@ static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, if (ret) goto err; - ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); - if (ret) - goto err; + vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); /* setup prob/tile buffers for LAT */ - ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); - if (ret) - goto err; + vdec_vp9_slice_setup_prob_buffer(instance, vsi); ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) @@ -1808,10 +1800,7 @@ static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance, vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb); vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); - - ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); - if (ret) - goto err; + vdec_vp9_slice_setup_prob_buffer(instance, vsi); ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c index b0302dfc3278..7383341ec51d 100644 --- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c +++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c @@ -598,13 +598,8 @@ static int __maybe_unused xisc_runtime_suspend(struct device *dev) static int __maybe_unused xisc_runtime_resume(struct device *dev) { struct isc_device *isc = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(isc->hclock); - if (ret) - return ret; - return ret; + return clk_prepare_enable(isc->hclock); } static const struct dev_pm_ops microchip_xisc_dev_pm_ops = { diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index e8545761b5ff..0ae5f35e017c 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -318,6 +318,7 @@ static const struct mxc_isi_plat_data mxc_imx95_data = { .model = MXC_ISI_IMX95, .num_ports = 4, .num_channels = 8, + .num_vc = 8, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, @@ -329,6 +330,7 @@ static const struct mxc_isi_plat_data mxc_imx8qm_data = { .model = MXC_ISI_IMX8QM, .num_ports = 5, .num_channels = 8, + .num_vc = 4, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_qm, .set_thd = &mxc_imx8_isi_thd_v1, @@ -340,6 +342,7 @@ static const struct mxc_isi_plat_data mxc_imx8qxp_data = { .model = MXC_ISI_IMX8QXP, .num_ports = 5, .num_channels = 6, + .num_vc = 4, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h index 7547a6559d4c..58b47335afc7 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h @@ -170,6 +170,7 @@ struct mxc_isi_plat_data { enum model model; unsigned int num_ports; unsigned int num_channels; + unsigned int num_vc; /* Number of VCs, 0 = no VC support */ unsigned int reg_offset; const struct mxc_isi_ier_reg *ier_reg; const struct mxc_isi_set_thd *set_thd; @@ -185,7 +186,7 @@ struct mxc_isi_dma_buffer { }; struct mxc_isi_input { - unsigned int enable_count; + u64 enabled_streams; }; struct mxc_isi_crossbar { @@ -258,6 +259,14 @@ struct mxc_isi_pipe { u8 acquired_res; u8 chained_res; bool chained; + + unsigned int input; + /* + * Stream on the connected crossbar input, expressed as a bitmask. Zero + * when the pipeline is disabled, a single bit set when the pipeline is + * enabled (as each pipeline processes a single stream). + */ + u64 input_stream; }; struct mxc_isi_m2m { @@ -378,6 +387,7 @@ void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe); void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, const struct v4l2_area *in_size, const struct v4l2_area *scale, const struct v4l2_rect *crop, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c index c580c831972e..7bb1335f2110 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c @@ -106,8 +106,20 @@ static int __mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd, if (ret) return ret; - /* The memory input can be routed to the first pipeline only. */ - for_each_active_route(&state->routing, route) { + /* + * Validate routes against hardware constraints: + * - SOURCE stream must be 0 (pipes are hardcoded to stream 0) + * - Memory input can only route to the first pipeline + */ + for_each_active_route(routing, route) { + if (route->source_stream != 0) { + dev_dbg(xbar->isi->dev, + "route to pipe %u must use source_stream=0, got %u\n", + route->source_pad - xbar->num_sinks, + route->source_stream); + return -ENXIO; + } + if (route->sink_pad == xbar->num_sinks - 1 && route->source_pad != xbar->num_sinks) { dev_dbg(xbar->isi->dev, @@ -145,10 +157,10 @@ mxc_isi_crossbar_xlate_streams(struct mxc_isi_crossbar *xbar, */ for_each_active_route(&state->routing, route) { if (route->source_pad != source_pad || - !(source_streams & BIT(route->source_stream))) + !(source_streams & BIT_ULL(route->source_stream))) continue; - sink_streams |= BIT(route->sink_stream); + sink_streams |= BIT_ULL(route->sink_stream); sink_pad = route->sink_pad; } @@ -318,11 +330,32 @@ static int mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd, return __mxc_isi_crossbar_set_routing(sd, state, routing); } +/* + * Check if a stream on a sink pad is in used by any of the ISI pipelines. The + * sink_streams argument is a bitmask that must have a single bit set (enforced + * by mxc_isi_crossbar_xlate_streams() translating the single stream mask of the + * pipeline to a single stream on the crossbar input side). + */ +static bool mxc_isi_crossbar_stream_in_use(const struct mxc_isi_crossbar *xbar, + unsigned int sink_pad, u64 sink_streams) +{ + for (unsigned int i = 0; i < xbar->isi->pdata->num_channels; ++i) { + const struct mxc_isi_pipe *pipe = &xbar->isi->pipes[i]; + + if (pipe->input == sink_pad && + pipe->input_stream == sink_streams) + return true; + } + + return false; +} + static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd); + struct mxc_isi_pipe *pipe = &xbar->isi->pipes[pad - xbar->num_sinks]; struct v4l2_subdev *remote_sd; struct mxc_isi_input *input; u64 sink_streams; @@ -339,29 +372,44 @@ static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, input = &xbar->inputs[sink_pad]; /* - * TODO: Track per-stream enable counts to support multiplexed - * streams. + * Check if any other pipe already receives the same input stream. + * If so, just record this pipe's usage and return. */ - if (!input->enable_count) { + if (mxc_isi_crossbar_stream_in_use(xbar, sink_pad, sink_streams)) { + pipe->input = sink_pad; + pipe->input_stream = sink_streams; + return 0; + } + + /* Enable the gasket when the first stream is enabled for this input. */ + if (!input->enabled_streams) { ret = mxc_isi_crossbar_gasket_enable(xbar, state, remote_sd, remote_pad, sink_pad); if (ret) return ret; + } - ret = v4l2_subdev_enable_streams(remote_sd, remote_pad, - sink_streams); - if (ret) { - dev_err(xbar->isi->dev, - "failed to enable streams 0x%llx on '%s':%u: %d\n", - sink_streams, remote_sd->name, remote_pad, ret); - mxc_isi_crossbar_gasket_disable(xbar, sink_pad); - return ret; - } + ret = v4l2_subdev_enable_streams(remote_sd, remote_pad, sink_streams); + if (ret) { + dev_err(xbar->isi->dev, + "failed to enable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); + goto err_gasket_disable; } - input->enable_count++; + input->enabled_streams |= sink_streams; + + /* Record the input and stream for this pipe. */ + pipe->input = sink_pad; + pipe->input_stream = sink_streams; return 0; + +err_gasket_disable: + if (!input->enabled_streams) + mxc_isi_crossbar_gasket_disable(xbar, sink_pad); + + return ret; } static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, @@ -369,6 +417,7 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask) { struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd); + struct mxc_isi_pipe *pipe = &xbar->isi->pipes[pad - xbar->num_sinks]; struct v4l2_subdev *remote_sd; struct mxc_isi_input *input; u64 sink_streams; @@ -384,18 +433,27 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, input = &xbar->inputs[sink_pad]; - input->enable_count--; + /* Clear the input and stream for this pipe. */ + pipe->input = UINT_MAX; + pipe->input_stream = 0; - if (!input->enable_count) { - ret = v4l2_subdev_disable_streams(remote_sd, remote_pad, - sink_streams); - if (ret) - dev_err(xbar->isi->dev, - "failed to disable streams 0x%llx on '%s':%u: %d\n", - sink_streams, remote_sd->name, remote_pad, ret); + /* + * Check if any other pipe receives the same input stream. If so we + * can't disable it yet, so return immediately. + */ + if (mxc_isi_crossbar_stream_in_use(xbar, sink_pad, sink_streams)) + return 0; + ret = v4l2_subdev_disable_streams(remote_sd, remote_pad, sink_streams); + if (ret) + dev_err(xbar->isi->dev, + "failed to disable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); + + input->enabled_streams &= ~sink_streams; + + if (!input->enabled_streams) mxc_isi_crossbar_gasket_disable(xbar, sink_pad); - } return ret; } @@ -404,6 +462,7 @@ static const struct v4l2_subdev_pad_ops mxc_isi_crossbar_subdev_pad_ops = { .enum_mbus_code = mxc_isi_crossbar_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mxc_isi_crossbar_set_fmt, + .get_frame_desc = v4l2_subdev_get_frame_desc_passthrough, .set_routing = mxc_isi_crossbar_set_routing, .enable_streams = mxc_isi_crossbar_enable_streams, .disable_streams = mxc_isi_crossbar_disable_streams, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c index 16b20ea2d1db..6aa760ce3605 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c @@ -11,8 +11,6 @@ #include "imx8-isi-core.h" #include "imx8-isi-regs.h" -#define ISI_DOWNSCALE_THRESHOLD 0x4000 - static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg) { return readl(pipe->regs + reg); @@ -118,8 +116,7 @@ static u32 mxc_isi_channel_scaling_ratio(unsigned int from, unsigned int to, * output (input / scale_factor) rounds up to exactly the desired * output. */ - return min_t(u32, DIV_ROUND_UP(from * 0x1000, to * *dec), - ISI_DOWNSCALE_THRESHOLD); + return DIV_ROUND_UP(from * 0x1000, to * *dec); } static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe, @@ -308,6 +305,7 @@ static void mxc_isi_channel_set_panic_threshold(struct mxc_isi_pipe *pipe) static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, bool bypass) { u32 val; @@ -319,6 +317,10 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, CHNL_CTRL_SRC_TYPE_MASK | CHNL_CTRL_MIPI_VC_ID_MASK | CHNL_CTRL_SRC_INPUT_MASK); + /* Clear the VC_ID_1 bit on platforms supporting more than 4 VCs. */ + if (pipe->isi->pdata->num_vc > 4) + val &= ~CHNL_CTRL_VC_ID_1_MASK; + /* * If no scaling or color space conversion is needed, bypass the * channel. @@ -345,7 +347,14 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, } else { val |= CHNL_CTRL_SRC_TYPE(CHNL_CTRL_SRC_TYPE_DEVICE); val |= CHNL_CTRL_SRC_INPUT(input); - val |= CHNL_CTRL_MIPI_VC_ID(0); /* FIXME: For CSI-2 only */ + val |= CHNL_CTRL_MIPI_VC_ID(vc); /* FIXME: For CSI-2 only */ + + /* + * On platforms with more than 4 VCs (i.MX95), the VC ID is + * split across VC_ID_0 (bits 7:6) and VC_ID_1 (bit 16). + */ + if (pipe->isi->pdata->num_vc > 4) + val |= CHNL_CTRL_VC_ID_1(vc >> 2); } mxc_isi_write(pipe, CHNL_CTRL, val); @@ -355,6 +364,7 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, const struct v4l2_area *in_size, const struct v4l2_area *scale, const struct v4l2_rect *crop, @@ -381,7 +391,7 @@ void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, mxc_isi_channel_set_panic_threshold(pipe); /* Channel control */ - mxc_isi_channel_set_control(pipe, input, csc_bypass && scaler_bypass); + mxc_isi_channel_set_control(pipe, input, vc, csc_bypass && scaler_bypass); } void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index de398b232d74..b729eecad0fe 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -144,7 +144,7 @@ static void mxc_isi_m2m_device_run(void *priv) .height = ctx->queues.cap.format.height, }; - mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM, + mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM, 0, &in_size, &scale, &crop, ctx->queues.out.info->encoding, ctx->queues.cap.info->encoding); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c index 2d0843c86534..934f7b356258 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c @@ -84,6 +84,12 @@ static const struct mxc_isi_bus_format_info mxc_isi_bus_formats[] = { | BIT(MXC_ISI_PIPE_PAD_SOURCE), .encoding = MXC_ISI_ENC_RAW, }, { + .mbus_code = MEDIA_BUS_FMT_Y16_1X16, + .output = MEDIA_BUS_FMT_Y16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .output = MEDIA_BUS_FMT_SBGGR8_1X8, .pads = BIT(MXC_ISI_PIPE_PAD_SINK) @@ -179,6 +185,30 @@ static const struct mxc_isi_bus_format_info mxc_isi_bus_formats[] = { .pads = BIT(MXC_ISI_PIPE_PAD_SINK) | BIT(MXC_ISI_PIPE_PAD_SOURCE), .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .output = MEDIA_BUS_FMT_SBGGR16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .output = MEDIA_BUS_FMT_SGBRG16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .output = MEDIA_BUS_FMT_SGRBG16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .output = MEDIA_BUS_FMT_SRGGB16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, }, /* JPEG */ { @@ -232,6 +262,47 @@ static inline struct mxc_isi_pipe *to_isi_pipe(struct v4l2_subdev *sd) return container_of(sd, struct mxc_isi_pipe, sd); } +static int mxc_isi_get_vc(struct mxc_isi_pipe *pipe) +{ + struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; + struct device *dev = pipe->isi->dev; + struct v4l2_mbus_frame_desc fd = { }; + unsigned int source_pad = xbar->num_sinks + pipe->id; + unsigned int num_vcs; + unsigned int i; + int ret; + + ret = v4l2_subdev_call(&xbar->sd, pad, get_frame_desc, + source_pad, &fd); + if (ret < 0) { + dev_err(dev, "Failed to get source frame desc from pad %u\n", + source_pad); + return ret; + } + + /* Find stream 0 in the frame descriptor. */ + for (i = 0; i < fd.num_entries; i++) { + if (fd.entry[i].stream == 0) + break; + } + + if (i == fd.num_entries) { + dev_err(dev, "Failed to find stream from source frame desc\n"); + return -EPIPE; + } + + num_vcs = pipe->isi->pdata->num_vc ? : 1; + + /* Check virtual channel range. */ + if (fd.entry[i].bus.csi2.vc >= num_vcs) { + dev_err(dev, "Virtual channel %u exceeds maximum %u\n", + fd.entry[i].bus.csi2.vc, num_vcs - 1); + return -EPIPE; + } + + return fd.entry[i].bus.csi2.vc; +} + int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) { struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; @@ -246,6 +317,7 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) struct v4l2_rect crop; u32 input; int ret; + int vc; /* * Find the connected input by inspecting the crossbar switch routing @@ -280,8 +352,12 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) v4l2_subdev_unlock_state(state); + vc = mxc_isi_get_vc(pipe); + if (vc < 0) + return vc; + /* Configure the ISI channel. */ - mxc_isi_channel_config(pipe, input, &in_size, &scale, &crop, + mxc_isi_channel_config(pipe, input, vc, &in_size, &scale, &crop, sink_info->encoding, src_info->encoding); mxc_isi_channel_enable(pipe); @@ -770,6 +846,7 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id) pipe->acquired_res = 0; pipe->chained_res = 0; pipe->chained = false; + pipe->input = UINT_MAX; sd = &pipe->sd; v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h index 1b65eccdf0da..e795f4daf3ff 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h @@ -6,6 +6,7 @@ #ifndef __IMX8_ISI_REGS_H__ #define __IMX8_ISI_REGS_H__ +#include <linux/bitfield.h> #include <linux/bits.h> /* ISI Registers Define */ @@ -19,9 +20,14 @@ #define CHNL_CTRL_CHAIN_BUF_NO_CHAIN 0 #define CHNL_CTRL_CHAIN_BUF_2_CHAIN 1 #define CHNL_CTRL_SW_RST BIT(24) -#define CHNL_CTRL_BLANK_PXL(n) ((n) << 16) -#define CHNL_CTRL_BLANK_PXL_MASK GENMASK(23, 16) -#define CHNL_CTRL_MIPI_VC_ID(n) ((n) << 6) +/* + * CHNL_CTRL_BLANK_PXL: i.MX8{QM,QXP} only + * CHNL_CTRL_VC_ID_1, CHNL_CTRL_VC_ID_1_MASK: i.MX95 only + */ +#define CHNL_CTRL_BLANK_PXL(n) FIELD_PREP(GENMASK(23, 16), (n)) +#define CHNL_CTRL_VC_ID_1(n) FIELD_PREP(BIT(16), (n)) +#define CHNL_CTRL_VC_ID_1_MASK BIT(16) +#define CHNL_CTRL_MIPI_VC_ID(n) FIELD_PREP(GENMASK(7, 6), (n)) #define CHNL_CTRL_MIPI_VC_ID_MASK GENMASK(7, 6) #define CHNL_CTRL_SRC_TYPE(n) ((n) << 4) #define CHNL_CTRL_SRC_TYPE_MASK BIT(4) diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c index fe4adfa3a1f0..f45c2aae59ce 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -151,7 +151,7 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .fourcc = V4L2_PIX_FMT_XBGR32, .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT | MXC_ISI_VIDEO_M2M_CAP, - .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8, .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888, .mem_planes = 1, .color_planes = 1, @@ -166,6 +166,57 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .color_planes = 1, .depth = { 32 }, .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_BGRA32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGBA8888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_RGBA32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_ABGR8888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_BGRX32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_RGBX8, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGBX888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_RGBX32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_XBGR888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_ARGB2101010, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_A2RGB10, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_A2RGB10, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, }, /* * RAW formats @@ -213,6 +264,15 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .depth = { 16 }, .encoding = MXC_ISI_ENC_RAW, }, { + .mbus_code = MEDIA_BUS_FMT_Y16_1X16, + .fourcc = V4L2_PIX_FMT_Y16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .fourcc = V4L2_PIX_FMT_SBGGR8, .type = MXC_ISI_VIDEO_CAP, @@ -356,6 +416,42 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .color_planes = 1, .depth = { 16 }, .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .fourcc = V4L2_PIX_FMT_SBGGR16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .fourcc = V4L2_PIX_FMT_SGBRG16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .fourcc = V4L2_PIX_FMT_SGRBG16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .fourcc = V4L2_PIX_FMT_SRGGB16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, }, /* JPEG */ { diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index aaf3caa42d33..20ccd7b1f11f 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -83,8 +83,8 @@ (0x270 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(m, n) \ (0x27c + 0x200 * (m) + 0x4 * (n)) -#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(c) \ - (1 << ((cid % 8) * 4)) +#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(cid) \ + (1 << (((cid) % 8) * 4)) #define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) \ (0x2c0 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) \ diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index 246ad0abbac3..eb8de60c1177 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -492,39 +492,41 @@ static void iris_fill_internal_buf_info(struct iris_inst *inst, buffers->min_count = iris_vpu_buf_count(inst, buffer_type); } -void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) +static void iris_get_int_buf_tbl(struct iris_inst *inst, u32 plane, + const u32 **internal_buf_type, u32 *internal_buffer_count) { const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; - const u32 *internal_buf_type; - u32 internal_buffer_count, i; if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->dec_ip_int_buf_tbl; + *internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->dec_op_int_buf_tbl; + *internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; } } else { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->enc_ip_int_buf_tbl; + *internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->enc_op_int_buf_tbl; + *internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; } } } +void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) +{ + const u32 *internal_buf_type; + u32 internal_buffer_count, i; + + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); + + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); +} + static int iris_create_internal_buffer(struct iris_inst *inst, enum iris_buffer_type buffer_type, u32 index) { @@ -559,29 +561,12 @@ static int iris_create_internal_buffer(struct iris_inst *inst, int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; u32 internal_buffer_count, i, j; struct iris_buffers *buffers; const u32 *internal_buf_type; int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -635,30 +620,13 @@ int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffe int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; struct iris_buffer *buffer, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -680,7 +648,7 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) return 0; } -int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer) +void iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer) { struct iris_core *core = inst->core; @@ -688,36 +656,16 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf dma_free_attrs(core->dev, buffer->buffer_size, buffer->kvaddr, buffer->device_addr, buffer->dma_attrs); kfree(buffer); - - return 0; } static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; struct iris_buffer *buf, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 i, len; - int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - len = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - len = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - len = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - len = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &len); for (i = 0; i < len; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -730,9 +678,7 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool if (!force && buf->attr & BUF_ATTR_QUEUED) continue; - ret = iris_destroy_internal_buffer(inst, buf); - if (ret) - return ret; + iris_destroy_internal_buffer(inst, buf); } } @@ -742,11 +688,8 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool else buffers = &inst->buffers[BUF_ARP]; - list_for_each_entry_safe(buf, next, &buffers->list, list) { - ret = iris_destroy_internal_buffer(inst, buf); - if (ret) - return ret; - } + list_for_each_entry_safe(buf, next, &buffers->list, list) + iris_destroy_internal_buffer(inst, buf); } return 0; @@ -788,18 +731,12 @@ static int iris_release_internal_buffers(struct iris_inst *inst, static int iris_release_input_internal_buffers(struct iris_inst *inst) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret; - if (inst->domain == DECODER) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } + iris_get_int_buf_tbl(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { ret = iris_release_internal_buffers(inst, internal_buf_type[i]); diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h index 75bb76776182..ab8e5d953101 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_buffer.h @@ -112,7 +112,7 @@ void iris_get_internal_buffers(struct iris_inst *inst, u32 plane); int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type); -int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); +void iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane); int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane); int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buf_type); diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 52bf56e517f9..8c335dbfce16 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -12,18 +12,24 @@ void iris_core_deinit(struct iris_core *core) { - pm_runtime_resume_and_get(core->dev); + int ret; + + ret = pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); if (core->state != IRIS_CORE_DEINIT) { iris_fw_unload(core); - iris_vpu_power_off(core); + + if (!ret) + iris_vpu_power_off(core); + iris_hfi_queues_deinit(core); core->state = IRIS_CORE_DEINIT; } mutex_unlock(&core->lock); - pm_runtime_put_sync(core->dev); + if (!ret) + pm_runtime_put_sync(core->dev); } static int iris_wait_for_system_response(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 10e33b8a73f6..bf17d310eac0 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -154,6 +154,8 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) return LAYER4_BITRATE_HEVC; case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return LAYER5_BITRATE_HEVC; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + return REQUEST_SYNC_FRAME; default: return INST_FW_CAP_MAX; } @@ -297,6 +299,8 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR; case LAYER5_BITRATE_HEVC: return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR; + case REQUEST_SYNC_FRAME: + return V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME; default: return 0; } @@ -1293,7 +1297,7 @@ int iris_set_use_and_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_ int iris_set_intra_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 gop_size = inst->fw_caps[GOP_SIZE].value; + u32 gop_size = inst->fw_caps[cap_id].value; u32 b_frame = inst->fw_caps[B_FRAME].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; struct hfi_intra_period intra_period; @@ -1477,6 +1481,43 @@ int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_typ &bitrate, sizeof(u32)); } +int iris_set_req_sync_frame(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val = 0; + + if (inst->fw_caps[PREPEND_SPSPPS_TO_IDR].value) + hfi_val = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR; + else + hfi_val = HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_val, sizeof(u32)); +} + +int iris_set_time_delta_based_rc(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 value = inst->fw_caps[cap_id].value; + + /* + * Disable time-delta-based rate control (value = 0). + * This overrides the firmware's default (enabled), ensuring the + * firmware uses the configured bitrate target rather than calculating + * bitrate from frame timing. + */ + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &value, sizeof(u32)); +} + int iris_set_properties(struct iris_inst *inst, u32 plane) { const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 3c462ec9190b..5180d53d3c90 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -47,6 +47,8 @@ int iris_set_layer_type(struct iris_inst *inst, enum platform_inst_fw_cap_type c int iris_set_layer_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_layer_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_req_sync_frame(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_time_delta_based_rc(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index ea9654dd679e..21cdf1c39835 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -17,20 +17,109 @@ #define MAX_FIRMWARE_NAME_SIZE 128 -static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) +/* Detect Gen2 firmware by scanning the blob for: + * QC_IMAGE_VERSION_STRING=<version> + * and then checking: + * - version starts with "vfw", OR + * - version matches "video-firmware.N.M" with N >= 2 + */ + +static bool iris_detect_gen2_from_fwdata(const u8 *data, size_t size) +{ + static const char *marker = "QC_IMAGE_VERSION_STRING="; + const size_t mlen = strlen(marker); + static const char *vfw = "vfw"; + const size_t vfwlen = strlen(vfw); + static const char *vf = "video-firmware."; + const size_t vflen = strlen(vf); + + for (size_t i = 0; i + mlen < size; i++) { + const char *found; + + if (memcmp(data + i, marker, mlen)) + continue; + + found = data + i + mlen; + size -= i + mlen; + + /* vfw => Gen2 */ + if (size > vfwlen && !memcmp(found, vfw, vfwlen)) + return true; + + if (size < vflen || + memcmp(found, vf, vflen)) + return false; + + found += vflen; + size -= vflen; + + /* + * video-firmware.1.x is Gen1. + * video-firmware.2.x and video-firmware.10.x are Gen2. + */ + return size >= 2 && + (*found >= '2' || (*found == '1' && found[1] != '.')); + } + + return false; +} + +static const struct firmware *iris_detect_firmware(struct iris_core *core, + const char **fw_name) +{ + const struct firmware *firmware; + bool has_both_gens; + int ret; + + *fw_name = NULL; + if (core->iris_platform_data->firmware_desc_gen2) + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen2; + else if (core->iris_platform_data->firmware_desc_gen1) + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + else + return ERR_PTR(-EINVAL); + + has_both_gens = core->iris_platform_data->firmware_desc_gen2 && + core->iris_platform_data->firmware_desc_gen1; + + ret = of_property_read_string_index(dev_of_node(core->dev), "firmware-name", 0, fw_name); + if (ret) { + *fw_name = core->iris_firmware_desc->fwname; + ret = request_firmware(&firmware, *fw_name, core->dev); + if (ret && has_both_gens) { + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + *fw_name = core->iris_firmware_desc->fwname; + ret = request_firmware(&firmware, *fw_name, core->dev); + } + + return ret ? ERR_PTR(ret) : firmware; + } + + ret = request_firmware(&firmware, *fw_name, core->dev); + if (ret) + return ERR_PTR(ret); + + if (has_both_gens && + !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) { + dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name); + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + } + + return firmware; +} + +static int iris_load_fw_to_memory(struct iris_core *core) { const struct firmware *firmware = NULL; struct device *dev = core->dev; struct resource res; phys_addr_t mem_phys; + const char *fw_name; size_t res_size; ssize_t fw_size; void *mem_virt; int ret; - if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) - return -EINVAL; - ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); if (ret) return ret; @@ -38,9 +127,11 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) mem_phys = res.start; res_size = resource_size(&res); - ret = request_firmware(&firmware, fw_name, dev); - if (ret) - return ret; + firmware = iris_detect_firmware(core, &fw_name); + if (IS_ERR(firmware)) + return PTR_ERR(firmware); + + core->iris_firmware_data = core->iris_firmware_desc->firmware_data; fw_size = qcom_mdt_get_size(firmware); if (fw_size < 0 || res_size < (size_t)fw_size) { @@ -67,18 +158,12 @@ err_release_fw: int iris_fw_load(struct iris_core *core) { const struct tz_cp_config *cp_config; - const char *fwpath = NULL; int i, ret; - ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0, - &fwpath); - if (ret) - fwpath = core->iris_firmware_desc->fwname; - - ret = iris_load_fw_to_memory(core, fwpath); + ret = iris_load_fw_to_memory(core); if (ret) { - dev_err(core->dev, "firmware download failed\n"); - return -ENOMEM; + dev_err(core->dev, "firmware download failed %d\n", ret); + return ret; } ret = qcom_pas_auth_and_reset(IRIS_PAS_ID); @@ -100,7 +185,7 @@ int iris_fw_load(struct iris_core *core) } } - return ret; + return 0; } int iris_fw_unload(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c index ca1545d28b53..0f7e7d6b25f4 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c @@ -171,7 +171,9 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .max = (1 << 16) - 1, .step_or_mask = 1, .value = 30, - .set = iris_set_u32 + .hfi_id = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_intra_period, }, { .cap_id = ENTROPY_MODE, @@ -240,7 +242,7 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .step_or_mask = 1, .value = 0, .hfi_id = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH, - .flags = CAP_FLAG_OUTPUT_PORT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_ir_period_gen1, }, { @@ -282,16 +284,6 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .flags = CAP_FLAG_OUTPUT_PORT, }, { - .cap_id = INTRA_PERIOD, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 0, - .hfi_id = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, - .flags = CAP_FLAG_OUTPUT_PORT, - .set = iris_set_intra_period, - }, - { .cap_id = LAYER_ENABLE, .min = 0, .max = 1, @@ -383,6 +375,16 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_bitrate_gen1, }, + { + .cap_id = REQUEST_SYNC_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_req_sync_frame, + }, }; static const u32 sm8250_vdec_input_config_param_default[] = { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 7674b47ad6c4..f6e9cbfccd09 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -442,7 +442,7 @@ static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct ir ret = iris_wait_for_session_response(inst, false); if (!ret) - ret = iris_destroy_internal_buffer(inst, buf); + iris_destroy_internal_buffer(inst, buf); exit: kfree(pkt); @@ -741,6 +741,9 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p packet->shdr.hdr.size += sizeof(u32); break; } + case HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME: { + break; + } default: return -EINVAL; } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 0e4dee192384..275f3fea3d2a 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -157,6 +157,7 @@ #define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026 #define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE 0x2006001 #define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD 0x2006003 +#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME 0x2006004 #define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME 0x2006009 #define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME 0x200600a #define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER 0x2006008 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c index acc0ed8adda1..3b8fbefb8b93 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c @@ -11,8 +11,832 @@ #include "iris_vpu_buffer.h" #define VIDEO_ARCH_LX 1 +#define MILOS_BITRATE_MAX 100000000 #define BITRATE_MAX 245000000 +static const struct platform_inst_fw_cap inst_fw_cap_milos_dec[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = PIPE, + /* .max, .min and .value are set via platform data */ + .step_or_mask = 1, + .hfi_id = HFI_PROP_PIPE, + .set = iris_set_pipe, + }, + { + .cap_id = POC, + .min = 0, + .max = 2, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, + }, + { + .cap_id = CODED_FRAMES, + .min = CODED_FRAMES_PROGRESSIVE, + .max = CODED_FRAMES_PROGRESSIVE, + .step_or_mask = 0, + .value = CODED_FRAMES_PROGRESSIVE, + .hfi_id = HFI_PROP_CODED_FRAMES, + }, + { + .cap_id = BIT_DEPTH, + .min = BIT_DEPTH_8, + .max = BIT_DEPTH_10, + .step_or_mask = 1, + .value = BIT_DEPTH_8, + .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + }, + { + .cap_id = RAP_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, +}; + +static const struct platform_inst_fw_cap inst_fw_cap_milos_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen2, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate_gen2, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_peak_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen2, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_u32, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen2, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = OUTPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = ROTATION, + .min = 0, + .max = 270, + .step_or_mask = 90, + .value = 0, + .hfi_id = HFI_PROP_ROTATION, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_rotation, + }, + { + .cap_id = HFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = VFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = IR_TYPE, + .min = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .max = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .step_or_mask = BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM), + .value = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = IR_PERIOD, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 0, + .flags = CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_ir_period_gen2, + }, + { + .cap_id = LTR_COUNT, + .min = 0, + .max = MAX_LTR_FRAME_COUNT_GEN2, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LTR_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_ltr_count_gen2, + }, + { + .cap_id = USE_LTR, + .min = 0, + .max = ((1 << MAX_LTR_FRAME_COUNT_GEN2) - 1), + .step_or_mask = 0, + .value = 0, + .hfi_id = HFI_PROP_LTR_USE, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_use_and_mark_ltr, + }, + { + .cap_id = MARK_LTR, + .min = INVALID_DEFAULT_MARK_OR_USE_LTR, + .max = (MAX_LTR_FRAME_COUNT_GEN2 - 1), + .step_or_mask = 1, + .value = INVALID_DEFAULT_MARK_OR_USE_LTR, + .hfi_id = HFI_PROP_LTR_MARK, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_use_and_mark_ltr, + }, + { + .cap_id = B_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_MAX_B_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = LAYER_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = LAYER_TYPE_H264, + .min = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + .max = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + .value = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + .hfi_id = HFI_PROP_LAYER_ENCODING_TYPE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_layer_type, + }, + { + .cap_id = LAYER_TYPE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .max = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + .value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .hfi_id = HFI_PROP_LAYER_ENCODING_TYPE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_layer_type, + }, + { + .cap_id = LAYER_COUNT_H264, + .min = 0, + .max = 5, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LAYER_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_count_gen2, + }, + { + .cap_id = LAYER_COUNT_HEVC, + .min = 0, + .max = 5, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LAYER_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_count_gen2, + }, + { + .cap_id = LAYER0_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER1, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER1_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER2, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER2_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER3, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER3_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER4, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER4_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER5, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER5_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER6, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER0_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER1, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER1_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER2, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER2_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER3, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER3_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER4, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER4_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER5, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER5_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER6, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + } +}; + static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { { .cap_id = PROFILE_H264, @@ -417,6 +1241,16 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { .set = iris_set_bitrate_mode_gen2, }, { + .cap_id = TIME_DELTA_BASED_RC, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_time_delta_based_rc, + }, + { .cap_id = FRAME_SKIP_MODE, .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, @@ -937,7 +1771,17 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_layer_bitrate, - } + }, + { + .cap_id = REQUEST_SYNC_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_REQUEST_SYNC_FRAME, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_req_sync_frame, + }, }; static const u32 sm8550_vdec_input_config_params_default[] = { @@ -1118,3 +1962,62 @@ const struct iris_firmware_data iris_hfi_gen2_data = { .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; + +const struct iris_firmware_data iris_hfi_milos_data = { + .init_hfi_ops = iris_hfi_gen2_sys_ops_init, + + .core_arch = VIDEO_ARCH_LX, + + .inst_fw_caps_dec = inst_fw_cap_milos_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_milos_dec), + .inst_fw_caps_enc = inst_fw_cap_milos_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_milos_enc), + + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index ca2954f8bd3a..388a36ff2b07 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -603,10 +603,9 @@ static int iris_hfi_gen2_set_tier(struct iris_inst *inst, u32 plane) { u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 tier = inst->fw_caps[TIER].value; + u32 tier_cap = (inst->codec == V4L2_PIX_FMT_AV1) ? TIER_AV1 : TIER; + u32 tier = inst->fw_caps[tier_cap].value; - tier = (inst->codec == V4L2_PIX_FMT_AV1) ? inst->fw_caps[TIER_AV1].value : - inst->fw_caps[TIER].value; inst_hfi_gen2->src_subcr_params.tier = tier; return iris_hfi_gen2_session_set_property(inst, @@ -692,7 +691,6 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_FRAME_RATE, iris_hfi_gen2_set_frame_rate }, {HFI_PROP_AV1_FILM_GRAIN_PRESENT, iris_hfi_gen2_set_film_grain }, {HFI_PROP_AV1_SUPER_BLOCK_ENABLED, iris_hfi_gen2_set_super_block }, - {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, }; if (inst->domain == DECODER) { @@ -766,6 +764,7 @@ static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) break; case V4L2_PIX_FMT_AV1: codec = HFI_CODEC_DECODE_AV1; + break; } iris_hfi_gen2_packet_session_property(inst, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 776b21cd11b2..f43aea10090d 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -67,6 +67,7 @@ enum hfi_rate_control { }; #define HFI_PROP_RATE_CONTROL 0x0300012a +#define HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL 0x0300012b #define HFI_PROP_QP_PACKED 0x0300012e #define HFI_PROP_MIN_QP_PACKED 0x0300012f #define HFI_PROP_MAX_QP_PACKED 0x03000130 @@ -90,6 +91,13 @@ enum hfi_layer_encoding_type { #define HFI_PROP_BITRATE_LAYER4 0x0300013f #define HFI_PROP_BITRATE_LAYER5 0x03000140 #define HFI_PROP_BITRATE_LAYER6 0x03000141 + +enum hfi_syncframe_request_mode { + HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR = 0x00000001, + HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR = 0x00000002, +}; + +#define HFI_PROP_REQUEST_SYNC_FRAME 0x03000145 #define HFI_PROP_MAX_GOP_FRAMES 0x03000146 #define HFI_PROP_MAX_B_FRAMES 0x03000147 #define HFI_PROP_QUALITY_MODE 0x03000148 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index 25162ae71357..8c2644c7f6e8 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -447,7 +447,9 @@ static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, buf->attr &= ~BUF_ATTR_QUEUED; - return iris_destroy_internal_buffer(inst, buf); + iris_destroy_internal_buffer(inst, buf); + + return 0; } static int iris_hfi_gen2_handle_session_stop(struct iris_inst *inst, diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index c9256f2323dc..974809509146 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -52,7 +52,9 @@ enum pipe_type { extern const struct iris_firmware_data iris_hfi_gen1_data; extern const struct iris_firmware_data iris_hfi_gen2_data; +extern const struct iris_firmware_data iris_hfi_milos_data; +extern const struct iris_platform_data milos_data; extern const struct iris_platform_data qcs8300_data; extern const struct iris_platform_data sc7280_data; extern const struct iris_platform_data sm8250_data; @@ -165,7 +167,6 @@ enum platform_inst_fw_cap_type { USE_LTR, MARK_LTR, B_FRAME, - INTRA_PERIOD, LAYER_ENABLE, LAYER_TYPE_H264, LAYER_TYPE_HEVC, @@ -183,6 +184,8 @@ enum platform_inst_fw_cap_type { LAYER3_BITRATE_HEVC, LAYER4_BITRATE_HEVC, LAYER5_BITRATE_HEVC, + REQUEST_SYNC_FRAME, + TIME_DELTA_BASED_RC, INST_FW_CAP_MAX, }; @@ -289,11 +292,7 @@ struct iris_firmware_desc { }; struct iris_platform_data { - /* - * XXX: replace with gen1 / gen2 pointers once we have platforms - * supporting both firmware kinds. - */ - const struct iris_firmware_desc *firmware_desc; + const struct iris_firmware_desc *firmware_desc_gen1, *firmware_desc_gen2; const struct vpu_ops *vpu_ops; const struct icc_info *icc_tbl; diff --git a/drivers/media/platform/qcom/iris/iris_platform_milos.h b/drivers/media/platform/qcom/iris/iris_platform_milos.h new file mode 100644 index 000000000000..8a45a4aa9e86 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_milos.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __IRIS_PLATFORM_MILOS_H__ +#define __IRIS_PLATFORM_MILOS_H__ + +#define MILOS_MAXIMUM_FPS 240 + +static const struct icc_info iris_icc_info_milos[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 10000000 }, +}; + +static const char * const milos_opp_pd_table[] = { "cx", "mx" }; + +static struct platform_inst_caps platform_inst_cap_milos = { + .min_frame_width = 96, + .max_frame_width = 4096, + .min_frame_height = 96, + .max_frame_height = 4096, + .max_mbpf = (4096 * 2176) / 256, + .mb_cycles_vsp = 25, + .mb_cycles_vpp = 200, + .max_frame_rate = MILOS_MAXIMUM_FPS, + .max_operating_rate = MILOS_MAXIMUM_FPS, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c index 6e06a32822bb..bbdbf21961d7 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c @@ -13,15 +13,28 @@ #include "iris_vpu_common.h" #include "iris_instance.h" +#include "iris_platform_milos.h" #include "iris_platform_sc7280.h" #include "iris_platform_sm8250.h" +static const struct iris_firmware_desc iris_milos_desc = { + .firmware_data = &iris_hfi_milos_data, + .get_vpu_buffer_size = iris_vpu_buf_size, + .fwname = "qcom/vpu/vpu20_p2_gen2_s7.mbn", +}; + static const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = { .firmware_data = &iris_hfi_gen1_data, .get_vpu_buffer_size = iris_vpu_buf_size, .fwname = "qcom/vpu/vpu20_p1.mbn", }; +static const struct iris_firmware_desc iris_vpu20_p1_gen2_s6_desc = { + .firmware_data = &iris_hfi_gen2_data, + .get_vpu_buffer_size = iris_vpu33_buf_size, + .fwname = "qcom/vpu/vpu20_p1_gen2_s6.mbn", +}; + static const struct iris_firmware_desc iris_vpu20_p4_gen1_desc = { .firmware_data = &iris_hfi_gen1_data, .get_vpu_buffer_size = iris_vpu_buf_size, @@ -64,8 +77,37 @@ static const struct tz_cp_config tz_cp_config_vpu2[] = { }, }; +const struct iris_platform_data milos_data = { + .firmware_desc_gen1 = &iris_milos_desc, + .vpu_ops = &iris_vpu2_ops, + .icc_tbl = iris_icc_info_milos, + .icc_tbl_size = ARRAY_SIZE(iris_icc_info_milos), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .pmdomain_tbl = iris_pmdomain_table_vpu2, + .pmdomain_tbl_size = ARRAY_SIZE(iris_pmdomain_table_vpu2), + .opp_pd_tbl = milos_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(milos_opp_pd_table), + .clk_tbl = sm8250_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), + .opp_clk_tbl = sm8250_opp_clk_table, + .clk_rst_tbl = iris_clk_reset_table_vpu2, + .clk_rst_tbl_size = ARRAY_SIZE(iris_clk_reset_table_vpu2), + .dma_mask = 0xe0000000 - 1, + .inst_iris_fmts = iris_fmts_vpu2_dec, + .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu2_dec), + .inst_caps = &platform_inst_cap_milos, + .tz_cp_config_data = tz_cp_config_vpu2, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2), + .num_vpp_pipe = 2, + .max_session_count = 16, + .max_core_mbpf = ((4096 * 2176) / 256) * 2, + .max_core_mbps = ((3840 * 2176) / 256) * 30 + ((1920 * 1088) / 256) * 30, +}; + const struct iris_platform_data sc7280_data = { - .firmware_desc = &iris_vpu20_p1_gen1_desc, + .firmware_desc_gen1 = &iris_vpu20_p1_gen1_desc, + .firmware_desc_gen2 = &iris_vpu20_p1_gen2_s6_desc, .vpu_ops = &iris_vpu2_ops, .icc_tbl = iris_icc_info_vpu2, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2), @@ -94,7 +136,7 @@ const struct iris_platform_data sc7280_data = { }; const struct iris_platform_data sm8250_data = { - .firmware_desc = &iris_vpu20_p4_gen1_desc, + .firmware_desc_gen1 = &iris_vpu20_p4_gen1_desc, .vpu_ops = &iris_vpu2_ops, .icc_tbl = iris_icc_info_vpu2, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2), diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c index 2c63adbc5579..74626b35d9cb 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c @@ -90,7 +90,7 @@ static const struct tz_cp_config tz_cp_config_vpu3[] = { * - inst_caps to platform_inst_cap_qcs8300 */ const struct iris_platform_data qcs8300_data = { - .firmware_desc = &iris_vpu30_p4_s6_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p4_s6_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -119,7 +119,7 @@ const struct iris_platform_data qcs8300_data = { }; const struct iris_platform_data sm8550_data = { - .firmware_desc = &iris_vpu30_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p4_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -154,7 +154,7 @@ const struct iris_platform_data sm8550_data = { * - controller_rst_tbl to sm8650_controller_reset_table */ const struct iris_platform_data sm8650_data = { - .firmware_desc = &iris_vpu33_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu33_p4_gen2_desc, .vpu_ops = &iris_vpu33_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -185,7 +185,7 @@ const struct iris_platform_data sm8650_data = { }; const struct iris_platform_data sm8750_data = { - .firmware_desc = &iris_vpu35_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu35_p4_gen2_desc, .vpu_ops = &iris_vpu35_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -220,7 +220,7 @@ const struct iris_platform_data sm8750_data = { * - different num_vpp_pipe */ const struct iris_platform_data x1p42100_data = { - .firmware_desc = &iris_vpu30_p1_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p1_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index c2dcb50a2782..e4acf4a74f94 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -251,8 +251,6 @@ static int iris_probe(struct platform_device *pdev) return core->irq; core->iris_platform_data = of_device_get_match_data(core->dev); - core->iris_firmware_desc = core->iris_platform_data->firmware_desc; - core->iris_firmware_data = core->iris_firmware_desc->firmware_data; core->ubwc_cfg = qcom_ubwc_config_get_data(); if (IS_ERR(core->ubwc_cfg)) @@ -271,8 +269,6 @@ static int iris_probe(struct platform_device *pdev) if (ret) return ret; - iris_session_init_caps(core); - ret = v4l2_device_register(dev, &core->v4l2_dev); if (ret) return ret; @@ -361,6 +357,10 @@ static const struct dev_pm_ops iris_pm_ops = { static const struct of_device_id iris_dt_match[] = { { + .compatible = "qcom,milos-iris", + .data = &milos_data, + }, + { .compatible = "qcom,qcs8300-iris", .data = &qcs8300_data, }, diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index 773f6548370a..2c4d34c7bd77 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -61,9 +61,9 @@ int iris_unset_icc_bw(struct iris_core *core) int iris_opp_set_rate(struct device *dev, unsigned long freq) { - struct dev_pm_opp *opp __free(put_opp); + struct dev_pm_opp *opp __free(put_opp) = + devfreq_recommended_opp(dev, &freq, 0); - opp = devfreq_recommended_opp(dev, &freq, 0); if (IS_ERR(opp)) return PTR_ERR(opp); @@ -78,24 +78,21 @@ int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev) if (ret) return ret; - ret = pm_runtime_get_sync(pd_dev); - if (ret < 0) - return ret; - - return ret; + return pm_runtime_resume_and_get(pd_dev); } int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev) { int ret; + int pm_ret; ret = iris_opp_set_rate(core->dev, 0); - if (ret) - return ret; - pm_runtime_put_sync(pd_dev); + pm_ret = pm_runtime_put_sync(pd_dev); + if (!ret) + ret = pm_ret; - return 0; + return ret; } static struct clk *iris_get_clk_by_type(struct iris_core *core, enum platform_clk_type clk_type) diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c index d14472414750..5552725c614e 100644 --- a/drivers/media/platform/qcom/iris/iris_state.c +++ b/drivers/media/platform/qcom/iris/iris_state.c @@ -60,9 +60,9 @@ int iris_inst_change_state(struct iris_inst *inst, return -EINVAL; change_state: - inst->state = request_state; dev_dbg(inst->core->dev, "state changed from %x to %x\n", inst->state, request_state); + inst->state = request_state; return 0; } @@ -269,7 +269,7 @@ bool iris_allow_cmd(struct iris_inst *inst, u32 cmd) return true; } else if (cmd == V4L2_DEC_CMD_STOP || cmd == V4L2_ENC_CMD_STOP) { if (vb2_is_streaming(src_q)) - if (inst->sub_state != IRIS_INST_SUB_DRAIN) + if (!(inst->sub_state & IRIS_INST_SUB_DRAIN)) return true; } diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 14d63dc76c9b..fcbc60016bee 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -9,6 +9,7 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> +#include "iris_ctrls.h" #include "iris_vidc.h" #include "iris_instance.h" #include "iris_vdec.h" @@ -196,6 +197,8 @@ int iris_open(struct file *filp) goto fail_m2m_release; } + iris_session_init_caps(core); + if (inst->domain == DECODER) ret = iris_vdec_inst_init(inst); else if (inst->domain == ENCODER) @@ -449,14 +452,21 @@ static int iris_enum_frameintervals(struct file *filp, void *fh, static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *cap) { + struct iris_core *core = video_drvdata(filp); struct iris_inst *inst = iris_get_inst(filp); + char *info; strscpy(cap->driver, IRIS_DRV_NAME, sizeof(cap->driver)); - if (inst->domain == DECODER) + if (inst->domain == DECODER) { strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); - else + info = "dec"; + } else { strscpy(cap->card, "Iris Encoder", sizeof(cap->card)); + info = "enc"; + } + snprintf(cap->bus_info, sizeof(cap->bus_info), + "plat:%s:%s", dev_name(core->dev), info); return 0; } diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index fb6f1016415e..faebb5472866 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -580,7 +580,7 @@ static u32 hfi_buffer_line_av1d(u32 frame_width, u32 frame_height, ALIGN(size_av1d_qp(frame_width, frame_height), DMA_ALIGNMENT); opbwr8 = size_av1d_lb_opb_wr1_nv12_ubwc(frame_width, frame_height); opbwr10 = size_av1d_lb_opb_wr1_tp10_ubwc(frame_width, frame_height); - opbwrbufsize = opbwr8 >= opbwr10 ? opbwr8 : opbwr10; + opbwrbufsize = max(opbwr8, opbwr10); size = ALIGN((size + opbwrbufsize), DMA_ALIGNMENT); if (is_opb) { vpss_lb_size = size_vpss_lb(frame_width, frame_height); @@ -700,7 +700,7 @@ static u32 hfi_buffer_ibc_av1d(u32 frame_width, u32 frame_height) ibc8 = size_av1d_ibc_nv12_ubwc(frame_width, frame_height); ibc10 = size_av1d_ibc_tp10_ubwc(frame_width, frame_height); - size = ibc8 >= ibc10 ? ibc8 : ibc10; + size = max(ibc8, ibc10); return ALIGN(size, DMA_ALIGNMENT); } diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index ab41da1f47c8..e4847c107709 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -237,7 +237,7 @@ void iris_vpu_power_off(struct iris_core *core) iris_unset_icc_bw(core); if (!iris_vpu_watchdog(core, core->intr_status)) - disable_irq_nosync(core->irq); + disable_irq(core->irq); } int iris_vpu_power_on_controller(struct iris_core *core) diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index f44059f19505..e96d458c52fa 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -616,7 +616,7 @@ struct hfi_capability { struct hfi_capabilities { u32 num_capabilities; - struct hfi_capability data[]; + struct hfi_capability data[] __counted_by(num_capabilities); }; #define HFI_DEBUG_MSG_LOW 0x01 @@ -802,7 +802,7 @@ struct hfi_profile_level { struct hfi_profile_level_supported { u32 profile_count; - struct hfi_profile_level profile_level[]; + struct hfi_profile_level profile_level[] __counted_by(profile_count); }; struct hfi_quality_vs_speed { @@ -1085,7 +1085,7 @@ struct hfi_resource_ocmem_requirement { struct hfi_resource_ocmem_requirement_info { u32 num_entries; - struct hfi_resource_ocmem_requirement requirements[]; + struct hfi_resource_ocmem_requirement requirements[] __counted_by(num_entries); }; struct hfi_property_sys_image_version_info_type { diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 47b99d5b5af7..5c2025c5acc7 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -690,7 +690,7 @@ struct hfi_done_handler { u32 pkt; u32 pkt_sz; u32 pkt_sz2; - void (*done)(struct venus_core *, struct venus_inst *, void *); + void (*done)(struct venus_core *core, struct venus_inst *inst, void *packet); bool is_sys_pkt; }; diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index b1657443f23f..d07845f37c55 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -85,7 +85,7 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) type++; } - return sizeof(*mode); + return mode->num_entries * sizeof(u32) + sizeof(*mode); } static void fill_profile_level(struct hfi_plat_caps *cap, const void *data, @@ -146,7 +146,7 @@ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data) for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, fill_caps, caps_arr, num_caps); - return sizeof(*caps); + return num_caps * sizeof(*cap) + sizeof(u32); } static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts, @@ -171,7 +171,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) u32 entries = fmt->format_entries; unsigned int i = 0; u32 num_planes = 0; - u32 size; + u32 size = 2 * sizeof(u32); while (entries) { num_planes = pinfo->num_planes; @@ -186,6 +186,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) if (pinfo->num_planes > MAX_PLANES) break; + size += sizeof(*constr) * num_planes + 2 * sizeof(u32); pinfo = (void *)pinfo + sizeof(*constr) * num_planes + 2 * sizeof(u32); entries--; @@ -193,8 +194,6 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, fill_raw_fmts, rawfmts, i); - size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32)) - + 2 * sizeof(u32); return size; } diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index be1cbd5cfe84..e88e66be4f6d 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -781,7 +781,6 @@ static int decide_core(struct venus_inst *inst) unsigned long max_freq = ULONG_MAX; struct device *dev = core->dev; struct dev_pm_opp *opp; - int ret = 0; if (legacy_binding) { if (inst->session_type == VIDC_SESSION_TYPE_DEC) @@ -829,11 +828,7 @@ static int decide_core(struct venus_inst *inst) } done: - ret = hfi_session_set_property(inst, ptype, &cu); - if (ret) - return ret; - - return ret; + return hfi_session_set_property(inst, ptype, &cu); } static int acquire_core(struct venus_inst *inst) diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c index 7305cc4a04cb..6635f5782175 100644 --- a/drivers/media/platform/renesas/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-csi2.c @@ -2273,11 +2273,7 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, return ret; } - ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); - if (ret) - return ret; - - return ret; + return rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/renesas/rcar-isp/Kconfig b/drivers/media/platform/renesas/rcar-isp/Kconfig index 242f6a23851f..bacc15c250fe 100644 --- a/drivers/media/platform/renesas/rcar-isp/Kconfig +++ b/drivers/media/platform/renesas/rcar-isp/Kconfig @@ -5,10 +5,12 @@ config VIDEO_RCAR_ISP depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && OF depends on ARCH_RENESAS || COMPILE_TEST + depends on VIDEO_RENESAS_VSP1 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select RESET_CONTROLLER select V4L2_FWNODE + select VIDEO_DCT_RPPX1 help Support for Renesas R-Car Image Signal Processor (ISP). Enable this to support the Renesas R-Car Image Signal diff --git a/drivers/media/platform/renesas/rcar-isp/Makefile b/drivers/media/platform/renesas/rcar-isp/Makefile index b542118c831e..c0c80303682c 100644 --- a/drivers/media/platform/renesas/rcar-isp/Makefile +++ b/drivers/media/platform/renesas/rcar-isp/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -rcar-isp-objs = csisp.o +rcar-isp-objs = csisp.o core.o core-io.o obj-$(CONFIG_VIDEO_RCAR_ISP) += rcar-isp.o diff --git a/drivers/media/platform/renesas/rcar-isp/core-io.c b/drivers/media/platform/renesas/rcar-isp/core-io.c new file mode 100644 index 000000000000..820af506f896 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core-io.c @@ -0,0 +1,997 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-isp.h> +#include <media/v4l2-mc.h> + +#include <linux/media/dreamchip/rppx1-config.h> + +#include "risp-core.h" + +#define risp_io_err(d, fmt, arg...) dev_err((d)->core->dev, fmt, ##arg) + +static struct risp_buffer *risp_io_vb2buf(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct risp_buffer, vb); +} + +static int risp_io_open(struct file *file) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + int ret; + + ret = mutex_lock_interruptible(&io->lock); + if (ret) + return ret; + + file->private_data = io; + + ret = v4l2_fh_open(file); + if (ret) + goto err_unlock; + + ret = v4l2_pipeline_pm_get(&io->vdev.entity); + if (ret < 0) + goto err_open; + + mutex_unlock(&io->lock); + + return 0; +err_open: + v4l2_fh_release(file); +err_unlock: + mutex_unlock(&io->lock); + + return ret; +} + +static int risp_io_release(struct file *file) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + int ret; + + mutex_lock(&io->lock); + + ret = _vb2_fop_release(file, NULL); + + v4l2_pipeline_pm_put(&io->vdev.entity); + + mutex_unlock(&io->lock); + + return ret; +} + +static const struct v4l2_file_operations risp_io_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = risp_io_open, + .release = risp_io_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +/* ----------------------------------------------------------------------------- + * Common queue + */ + +static int risp_io_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + const struct v4l2_pix_format_mplane *pix = &io->format.fmt.pix_mp; + + if (*nplanes) { + if (*nplanes > pix->num_planes) + return -EINVAL; + + for (unsigned int i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *nplanes = pix->num_planes; + for (unsigned int i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + } else { + if (*nplanes) { + if (sizes[0] < io->format.fmt.meta.buffersize) + return -EINVAL; + + return 0; + } + + *nplanes = 1; + sizes[0] = io->format.fmt.meta.buffersize; + } + + /* Initialize buffer queue */ + INIT_LIST_HEAD(&io->buffers); + + return 0; +}; + +static int risp_io_buffer_prepare_set(struct rcar_isp_core_io *io, + struct vb2_buffer *vb, unsigned int plane, + unsigned long size) +{ + if (vb2_plane_size(vb, plane) < size) { + risp_io_err(io, "Buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, plane), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, plane, size); + + return 0; +} + +static int risp_io_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + + if (V4L2_TYPE_IS_MULTIPLANAR(vb->vb2_queue->type)) { + const struct v4l2_pix_format_mplane *pix = &io->format.fmt.pix_mp; + int ret = 0; + + for (unsigned int i = 0; i < pix->num_planes; i++) { + ret = risp_io_buffer_prepare_set(io, vb, i, + pix->plane_fmt[i].sizeimage); + if (ret) + break; + } + + return ret; + } + + return risp_io_buffer_prepare_set(io, vb, 0, + io->format.fmt.meta.buffersize); +} + +static void risp_io_buffer_queue(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + + guard(mutex)(&io->core->io_lock); + + list_add_tail(&buf->list, &io->buffers); + + if (risp_core_job_prepare(io->core)) + risp_io_err(io, "Failed to prepare job\n"); +} + +static void risp_io_return_buffers(struct rcar_isp_core_io *io, + enum vb2_buffer_state state) +{ + struct risp_buffer *buf, *node; + + lockdep_assert_held(&io->core->io_lock); + + list_for_each_entry_safe(buf, node, &io->buffers, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } +} + +static int risp_io_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + int ret; + + scoped_guard(mutex, &io->core->io_lock) { + if (io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width != + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width || + io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height != + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height) { + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return -EPIPE; + } + + io->streaming = true; + } + + ret = risp_core_start_streaming(io->core); + if (ret) { + guard(mutex)(&io->core->io_lock); + + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return ret; + } + + return 0; +} + +static void risp_io_stop_streaming(struct vb2_queue *vq) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + + scoped_guard(mutex, &io->core->io_lock) { + io->streaming = false; + risp_core_stop_streaming(io->core); + risp_io_return_buffers(io, VB2_BUF_STATE_ERROR); + } + + /* + * Wait for buffers part of the jobs not yet processed. Note that this + * might complete buffers out of order. + */ + vb2_wait_for_all_buffers(&io->queue); +} + +/* ----------------------------------------------------------------------------- + * Common V4L2 IOCTLs + */ + +static int risp_io_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Input Exposure + */ + +static int risp_io_input_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + struct rcar_isp_core *core = io->core; + struct device *bus_master; + int ret; + + ret = risp_io_queue_setup(vq, nbuffers, nplanes, sizes, alloc_devs); + if (ret) + return ret; + + bus_master = vsp1_isp_get_bus_master(core->vspx.dev); + if (IS_ERR_OR_NULL(bus_master)) { + risp_io_err(io, "Missing reference to bus-master device\n"); + return -EINVAL; + } + + /* + * Allocate buffers using the bus_master device associated with the + * VSPX associated to this ISP instance. + */ + alloc_devs[0] = bus_master; + + return 0; +}; + +static const struct vb2_ops risp_io_input_qops = { + .queue_setup = risp_io_input_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_input_default_format = { + .width = 1920, + .height = 1080, + .field = V4L2_FIELD_NONE, + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .colorspace = V4L2_COLORSPACE_RAW, + .xfer_func = V4L2_XFER_FUNC_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .num_planes = 1, + .plane_fmt = { + [0] = { + .sizeimage = 1920 * 1080, + .bytesperline = 1920, + }, + }, +}; + +static const struct risp_io_input_format { + unsigned int fourcc; + unsigned int bpp; +} risp_io_input_formats[] = { + { .fourcc = V4L2_PIX_FMT_SBGGR8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SGBRG8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SGRBG8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SRGGB8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SBGGR10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGBRG10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGRBG10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SRGGB10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SBGGR12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGBRG12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGRBG12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SRGGB12, .bpp = 2 }, +}; + +static void risp_io_input_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpp = 0; + + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + for (unsigned int i = 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc == pix->pixelformat) { + bpp = risp_io_input_formats[i].bpp; + break; + } + } + + if (!bpp) { + pix->pixelformat = risp_io_input_formats[0].fourcc; + bpp = risp_io_input_formats[0].bpp; + } + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_RAW; + + pix->num_planes = 1; + pix->plane_fmt[0].bytesperline = pix->width * bpp; + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; +} + +static int risp_io_input_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ARRAY_SIZE(risp_io_input_formats)) + return -EINVAL; + + f->pixelformat = risp_io_input_formats[f->index].fourcc; + + return 0; +} + +static int risp_io_input_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + f->fmt.pix_mp = io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_input_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp = f->fmt.pix_mp; + + return 0; +} + +static int risp_io_input_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_input_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + bool found = false; + + if (fsize->index != 0) + return -EINVAL; + + for (unsigned int i = 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc == fsize->pixel_format) { + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = 128; + fsize->stepwise.max_width = 5120; + fsize->stepwise.step_width = 2; + + fsize->stepwise.min_height = 128; + fsize->stepwise.max_height = 4096; + fsize->stepwise.step_height = 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_input_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_vid_out = risp_io_input_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = risp_io_input_g_fmt, + .vidioc_s_fmt_vid_out_mplane = risp_io_input_s_fmt, + .vidioc_try_fmt_vid_out_mplane = risp_io_input_try_fmt, + .vidioc_enum_framesizes = risp_io_input_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Parameters + * + */ + +static int risp_io_params_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core = io->core; + size_t size; + int ret; + + memset(&buf->vsp_buffer, 0, sizeof(buf->vsp_buffer)); + + size = RISP_IO_PARAMS_BUF_SIZE; + ret = vsp1_isp_alloc_buffer(core->vspx.dev, size, &buf->vsp_buffer); + if (ret) + return -EINVAL; + + memset(buf->vsp_buffer.cpu_addr, 0, RISP_IO_PARAMS_BUF_SIZE); + + return 0; +} + +static void risp_io_params_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core = io->core; + + vsp1_isp_free_buffer(core->vspx.dev, &buf->vsp_buffer); +} + +struct risp_conf_dma_write_desc { + u32 *buf; + u32 base; + unsigned int count; +}; + +static int risp_conf_dma_prepare(void *priv, u32 offset, u32 value) +{ + struct risp_conf_dma_write_desc *desc = priv; + + /* Bounds check, 8 bytes = address (4)+ value (4). */ + if ((desc->count + 1) * 8 > RISP_IO_PARAMS_BUF_SIZE) + return -ENOMEM; + + (*desc->buf++) = desc->base | offset; + (*desc->buf++) = value; + + desc->count++; + + return 0; +} + +static int risp_io_params_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct risp_conf_dma_write_desc desc; + u32 *cpu_addr; + int ret; + + /* Prepare params. */ + cpu_addr = (u32 *)buf->vsp_buffer.cpu_addr; + + desc.buf = cpu_addr + 2; + desc.base = io->core->rppaddr; + desc.count = 0; + + /* Fill params body. */ + ret = rppx1_params(io->core->rpp, vb, io->format.fmt.meta.buffersize, + risp_conf_dma_prepare, &desc); + if (ret) + return ret; + + /* Fill params header. */ + cpu_addr[0] = desc.count; + cpu_addr[1] = 0x0; + + return 0; +} + +static const struct vb2_ops risp_io_params_qops = { + .queue_setup = risp_io_queue_setup, + .buf_init = risp_io_params_buf_init, + .buf_cleanup = risp_io_params_buf_cleanup, + .buf_prepare = risp_io_params_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_params_default_format = { + .dataformat = V4L2_META_FMT_RPPX1_PARAMS, + .buffersize = v4l2_isp_buffer_size(RPPX1_PARAMS_MAX_SIZE), +}; + +static int risp_io_params_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_META_OUTPUT || f->index) + return -EINVAL; + + f->pixelformat = io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_params_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + *meta = io->format.fmt.meta; + + return 0; +} + +static int risp_io_params_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_params_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_params_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_meta_out = risp_io_params_enum_fmt, + .vidioc_g_fmt_meta_out = risp_io_params_g_fmt, + .vidioc_s_fmt_meta_out = risp_io_params_s_fmt, + .vidioc_try_fmt_meta_out = risp_io_params_g_fmt, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Statistics + */ + +static const struct vb2_ops risp_io_stats_qops = { + .queue_setup = risp_io_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_stats_default_format = { + .dataformat = V4L2_META_FMT_RPPX1_STATS, + .buffersize = v4l2_isp_buffer_size(RPPX1_STATS_MAX_SIZE), +}; + +static int risp_io_stats_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_META_CAPTURE || f->index) + return -EINVAL; + + f->pixelformat = io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_stats_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != V4L2_BUF_TYPE_META_CAPTURE) + return -EINVAL; + + *meta = io->format.fmt.meta; + + return 0; +} + +static int risp_io_stats_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_stats_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_stats_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_meta_cap = risp_io_stats_enum_fmt, + .vidioc_g_fmt_meta_cap = risp_io_stats_g_fmt, + .vidioc_s_fmt_meta_cap = risp_io_stats_s_fmt, + .vidioc_try_fmt_meta_cap = risp_io_stats_g_fmt, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Video capture + */ + +static const struct vb2_ops risp_io_capture_qops = { + .queue_setup = risp_io_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_capture_default_format = { + .width = 1920, + .height = 1080, + .pixelformat = V4L2_PIX_FMT_XBGR32, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + .num_planes = 1, + .plane_fmt = { + [0] = { + .bytesperline = ALIGN(1920 * 4, 256), + .sizeimage = ALIGN(1920 * 4, 256) * 1080, + }, + }, +}; + +static void risp_io_capture_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_SRGB; + pix->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix->xfer_func = V4L2_XFER_FUNC_SRGB; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + pix->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix->num_planes = 2; + pix->plane_fmt[0].bytesperline = ALIGN(pix->width, 256); + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; + pix->plane_fmt[1].bytesperline = ALIGN(pix->width, 256); + pix->plane_fmt[1].sizeimage = pix->plane_fmt[1].bytesperline * pix->height; + break; + default: + pix->pixelformat = V4L2_PIX_FMT_XBGR32; + pix->quantization = V4L2_QUANTIZATION_FULL_RANGE; + pix->num_planes = 1; + pix->plane_fmt[0].bytesperline = ALIGN(pix->width * 4, 256); + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; + break; + } +} + +static int risp_io_capture_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (f->index) { + case 0: + f->pixelformat = V4L2_PIX_FMT_NV16M; + break; + case 1: + f->pixelformat = V4L2_PIX_FMT_XBGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int risp_io_capture_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + f->fmt.pix_mp = io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp = f->fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_capture_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0) + return -EINVAL; + + switch (fsize->pixel_format) { + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_XBGR32: + break; + default: + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = 128; + fsize->stepwise.max_width = 5120; + fsize->stepwise.step_width = 2; + + fsize->stepwise.min_height = 128; + fsize->stepwise.max_height = 4096; + fsize->stepwise.step_height = 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_capture_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_vid_cap = risp_io_capture_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = risp_io_capture_g_fmt, + .vidioc_s_fmt_vid_cap_mplane = risp_io_capture_s_fmt, + .vidioc_try_fmt_vid_cap_mplane = risp_io_capture_try_fmt, + .vidioc_enum_framesizes = risp_io_capture_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Create and remove IO video devices + */ + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad) +{ + struct video_device *vdev = &io->vdev; + struct vb2_queue *q = &io->queue; + int ret; + + switch (pad) { + case RISP_CORE_INPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s input1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_TX; + vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE; + vdev->ioctl_ops = &risp_io_input_ioctl_ops; + + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->ops = &risp_io_input_qops; + + io->pad.flags = MEDIA_PAD_FL_SOURCE; + io->format.fmt.pix_mp = risp_io_input_default_format; + break; + + case RISP_CORE_PARAMS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s params", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_TX; + vdev->device_caps = V4L2_CAP_META_OUTPUT; + vdev->ioctl_ops = &risp_io_params_ioctl_ops; + + q->type = V4L2_BUF_TYPE_META_OUTPUT; + q->ops = &risp_io_params_qops; + + io->pad.flags = MEDIA_PAD_FL_SOURCE; + io->format.fmt.meta = risp_io_params_default_format; + break; + + case RISP_CORE_STATS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s stats", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_RX; + vdev->device_caps = V4L2_CAP_META_CAPTURE; + vdev->ioctl_ops = &risp_io_stats_ioctl_ops; + + q->type = V4L2_BUF_TYPE_META_CAPTURE; + q->ops = &risp_io_stats_qops; + + io->pad.flags = MEDIA_PAD_FL_SINK; + io->format.fmt.meta = risp_io_stats_default_format; + break; + + case RISP_CORE_OUTPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s output1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_RX; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE; + vdev->ioctl_ops = &risp_io_capture_ioctl_ops; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->ops = &risp_io_capture_qops; + + io->pad.flags = MEDIA_PAD_FL_SINK; + io->format.fmt.pix_mp = risp_io_capture_default_format; + break; + } + + io->core = core; + + mutex_init(&io->lock); + INIT_LIST_HEAD(&io->buffers); + + /* Create media graph pad. */ + ret = media_entity_pads_init(&io->vdev.entity, 1, &io->pad); + if (ret) + return ret; + + /* Create queue */ + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->lock = &io->lock; + q->drv_priv = io; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct risp_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = dev; + + ret = vb2_queue_init(q); + if (ret < 0) { + risp_io_err(io, "Failed to initialize VB2 queue\n"); + return ret; + } + + /* Create video device */ + vdev->v4l2_dev = &core->v4l2_dev; + vdev->queue = &io->queue; + + vdev->release = video_device_release_empty; + vdev->lock = &io->lock; + vdev->fops = &risp_io_fops; + + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + risp_io_err(io, "Failed to register video device\n"); + return ret; + } + + video_set_drvdata(&io->vdev, io); + + v4l2_info(&core->v4l2_dev, "Device registered as %s\n", + video_device_node_name(vdev)); + + switch (pad) { + case RISP_CORE_INPUT1: + case RISP_CORE_PARAMS: + ret = media_create_pad_link(&io->vdev.entity, 0, + &core->subdev.entity, pad, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + case RISP_CORE_STATS: + case RISP_CORE_OUTPUT1: + ret = media_create_pad_link(&core->subdev.entity, pad, + &io->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + } + + return ret; +} + +void risp_core_io_destroy(struct rcar_isp_core_io *io) +{ + if (!video_is_registered(&io->vdev)) + return; + + vb2_video_unregister_device(&io->vdev); +} diff --git a/drivers/media/platform/renesas/rcar-isp/core.c b/drivers/media/platform/renesas/rcar-isp/core.c new file mode 100644 index 000000000000..b5861d0cd0e8 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core.c @@ -0,0 +1,916 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <linux/delay.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> +#include <media/vsp1.h> + +#include "risp-core.h" + +#define ISP_CS_STREAMER_MODE_REG 0x7000 +#define ISP_CS_STREAMER_MODE_STREAMER_EN 0xf + +#define ISP_CS_STREAMER_VBLANK_REG 0x7004 +#define ISP_CS_STREAMER_HBLANK_REG 0x7008 + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG 0x7100 +#define ISP_CS_STREAMER_CONFIG_DMA_REG_ADDRESS_UPPER_8BIT_MASK GENMASK(31, 24) +#define ISP_CS_STREAMER_CONFIG_DMA_ENABLE0 BIT(0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG 0x2100 +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 BIT(31) +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_CONFIG_DATA_START_REG_ADDRESS_MASK GENMASK(15, 0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG 0x2104 + +#define ISP_CORE_ISPCORE_INT_STATUS 0x80000 +#define ISP_CORE_ISPCORE_INT_ENABLE 0x80004 +#define ISPCORE_DMA_IMAGE_FRAME_MODE(i, f) (0x84000 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(i, f) (0x84004 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(i, f) (0x84008 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(i, f) (0x8400c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(i, f) (0x84010 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(i, f) (0x84014 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP2(i, f) (0x84018 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP3(i, f) (0x8401c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(i, f) (0x84020 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(i, f) (0x84024 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP2(i, f) (0x84028 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP3(i, f) (0x8402c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_AXI_ID(i, f) (0x84030 + 0x1000 * (i) + 0x100 * (f)) + +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(i) (0x84400 + 0x1000 * (i)) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_MASK GENMASK(31, 16) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT 16 + +#define ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(i) (0x84800 + 0x1000 * (i)) + +static void risp_cs_write(struct rcar_isp_core *core, u32 offset, u32 value) +{ + iowrite32(value, core->csbase + offset); +} + +static u32 risp_cs_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->csbase + offset); +} + +static void risp_core_write(struct rcar_isp_core *core, u32 offset, u32 value) +{ + iowrite32(value, core->base + offset); +} + +static u32 risp_core_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->base + offset); +} + +static void risp_core_job_run_params(struct rcar_isp_core *core, + struct vsp1_isp_job_desc *vspx_job, + struct risp_buffer *buf) +{ + u32 *params_buf = (u32 *)buf->vsp_buffer.cpu_addr; + bool have_config = !!params_buf[0]; + u32 ctrl0, ctrl1, ctrl2; + + /* + * If we have a configuration but not asked the VSPX to program it, + * use MMIO to write the configuration. This might be needed to work + * around limitations of the VSPX ConfigDMA, see comment in + * risp_core_job_prepare(). + */ + if (have_config && !vspx_job->config.pairs) { + for (unsigned int i = 0; i < params_buf[0]; i++) + risp_core_write(core, params_buf[2 + i * 2] & 0xffff, + params_buf[3 + i * 2]); + + /* Disable ConfigDMA. */ + have_config = false; + } + + ctrl0 = risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG) & + ~ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 = risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG) & + ~(ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | 0xffff); + ctrl2 = 0; + + if (have_config) { + ctrl0 |= ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 |= ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | + (params_buf[2] & 0xffff); + ctrl2 = params_buf[3]; + } + + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG, ctrl0); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG, ctrl1); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG, ctrl2); +} + +static void risp_core_job_run_output(struct rcar_isp_core *core, + struct risp_buffer *buf) +{ + const struct v4l2_format *fmt = &core->io[RISP_CORE_OUTPUT1].format; + dma_addr_t mem; + u32 reg; + + for (unsigned int frame = 0; frame < 4; frame++) { + reg = ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(0, frame); + mem = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + risp_core_write(core, reg, mem); + + /* Only NV16 uses 2 planes. */ + if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV16M) + continue; + + reg = ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(0, frame); + mem = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); + risp_core_write(core, reg, mem); + } +} + +static void risp_core_job_run(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job; + + lockdep_assert_held(&core->lock); + + /* ISP not yet started, nothing to do. */ + if (!core->streaming) + return; + + /* If we have active buffers in the ISP core, nothing to do. */ + if (core->vspx.job) + return; + + job = list_first_entry_or_null(&core->risp_jobs, + struct rcar_isp_job, + job_queue); + if (!job) + return; + + list_del(&job->job_queue); + + core->vspx.job = job; + + /* Program the ISP register before kicking the VSPX. */ + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + switch (i) { + case RISP_CORE_PARAMS: + risp_core_job_run_params(core, &job->vspx_job, buf); + break; + case RISP_CORE_OUTPUT1: + risp_core_job_run_output(core, buf); + break; + } + } + + if (vsp1_isp_job_run(core->vspx.dev, &job->vspx_job)) { + /* + * Release all buffers in this job if running on the VSPX + * failed. Userspace should recover from this, no new jobs are + * scheduled. + */ + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + core->vspx.job = NULL; + kfree(job); + + dev_err(core->dev, "Failed to run job"); + } +} + +static int risp_core_pixfmt_to_vspx(u32 pixfmt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return V4L2_PIX_FMT_GREY; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return V4L2_PIX_FMT_Y10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return V4L2_PIX_FMT_Y12; + default: + return -EINVAL; + } +} + +int risp_core_job_prepare(struct rcar_isp_core *core) +{ + struct vsp1_isp_job_desc *vspx_job; + int vspx_pixfmt = -EINVAL; + struct rcar_isp_job *job; + int ret; + + lockdep_assert_held(&core->io_lock); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (list_empty(&core->io[i].buffers)) + return 0; + } + + /* Memory is released when the job is consumed. */ + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + vspx_job = &job->vspx_job; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + /* + * Extract buffer from the IO queue and save a reference in + * the job description. Buffers will be completed when the + * corresponding frame will be completed by the ISP. + */ + buf = list_first_entry_or_null(&core->io[i].buffers, + struct risp_buffer, list); + /* + * This should not happen as we have checked there is buffers, + * with the lock held, but check the return value anyhow. + */ + if (WARN_ON(!buf)) { + ret = -EINVAL; + goto error_return_buffers; + } + + switch (i) { + case RISP_CORE_INPUT1: { + u32 isp_pixfmt = core->io[i].format.fmt.pix_mp.pixelformat; + + vspx_pixfmt = risp_core_pixfmt_to_vspx(isp_pixfmt); + + vspx_job->img.fmt = core->io[i].format.fmt.pix_mp; + vspx_job->img.fmt.pixelformat = vspx_pixfmt; + vspx_job->img.mem = + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, + 0); + break; + } + case RISP_CORE_PARAMS: { + u32 *params_buf = (u32 *)buf->vsp_buffer.cpu_addr; + u32 pairs = params_buf[0]; + + /* + * Check config pairs not larger then buffer. + * + * Remove 8 byte header and each pair is 16 bytes. + */ + if (pairs > (RISP_IO_PARAMS_BUF_SIZE - 8) / 16) { + ret = -EINVAL; + goto error_return_buffers; + } + + /* + * Work around undocumented behavior of the ConfigDMA + * interface by using MMIO if 16 or less pairs are to + * be programmed. + * + * Programming 15 or less pairs corrupts the image data + * following the config buffer, programming exactly 16 + * pairs freeze the whole VSPX. + */ + if (pairs <= 16) { + vspx_job->config.pairs = 0; + } else { + vspx_job->config.pairs = pairs; + vspx_job->config.mem = buf->vsp_buffer.dma_addr; + } + break; + } + } + + list_del(&buf->list); + job->buffers[i] = buf; + } + + if (vspx_pixfmt < 0) { + ret = -EINVAL; + goto error_return_buffers; + } + + ret = vsp1_isp_job_prepare(core->vspx.dev, vspx_job); + if (ret) + goto error_return_buffers; + + scoped_guard(spinlock_irqsave, &core->lock) { + list_add_tail(&job->job_queue, &core->risp_jobs); + risp_core_job_run(core); + } + + return 0; + +error_return_buffers: + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (!job->buffers[i]) + continue; + + vb2_buffer_done(&job->buffers[i]->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + } + kfree(job); + return ret; +} + +static int risp_core_config_output(struct rcar_isp_core *core, + unsigned int index, + const struct v4l2_pix_format_mplane *pix) +{ + /* For all frame capture slots. */ + for (unsigned int frame = 0; frame < 4; frame++) { + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 1); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 4 << 8 | 16 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 7 << 8 | 7 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 3 << 12 | 0 << 8 | + 3 << 4 | 0 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(index, frame), + pix->plane_fmt[1].bytesperline); + break; + case V4L2_PIX_FMT_XBGR32: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 0 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 23 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 0 << 12 | 0 << 8 | + 3 << 4 | 2 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + break; + default: + return -EINVAL; + } + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_AXI_ID(index, frame), + 0); + } + + /* Set image out flush EOF. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(index), + pix->plane_fmt[0].bytesperline << + ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT); + + /* Enable DMA and set burst length. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(index), + BIT(31) | 7); + + return 0; +} + +static u32 risp_core_pix2bus(const struct rcar_isp_core_io *io) +{ + switch (io->format.fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_SBGGR8: + return MEDIA_BUS_FMT_SBGGR8_1X8; + case V4L2_PIX_FMT_SGBRG8: + return MEDIA_BUS_FMT_SGBRG8_1X8; + case V4L2_PIX_FMT_SGRBG8: + return MEDIA_BUS_FMT_SGRBG8_1X8; + case V4L2_PIX_FMT_SRGGB8: + return MEDIA_BUS_FMT_SRGGB8_1X8; + case V4L2_PIX_FMT_SBGGR10: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case V4L2_PIX_FMT_SGBRG10: + return MEDIA_BUS_FMT_SGBRG10_1X10; + case V4L2_PIX_FMT_SGRBG10: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case V4L2_PIX_FMT_SRGGB10: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case V4L2_PIX_FMT_SBGGR12: + return MEDIA_BUS_FMT_SBGGR12_1X12; + case V4L2_PIX_FMT_SGBRG12: + return MEDIA_BUS_FMT_SGBRG12_1X12; + case V4L2_PIX_FMT_SGRBG12: + return MEDIA_BUS_FMT_SGRBG12_1X12; + case V4L2_PIX_FMT_SRGGB12: + return MEDIA_BUS_FMT_SRGGB12_1X12; + case V4L2_PIX_FMT_XBGR32: + return MEDIA_BUS_FMT_RGB888_1X24; + case V4L2_PIX_FMT_NV16M: + return MEDIA_BUS_FMT_YUYV12_1X24; + default: + return 0; + } +} + +static void risp_core_try_next_job(struct rcar_isp_core *core) +{ + lockdep_assert_held(&core->lock); + + struct rcar_isp_job *job = core->vspx.job; + + /* If the ISP or the VSPX is not done with the job, wait. */ + if (!job || !job->done_isp || !job->done_vspx) + return; + + core->vspx.job = NULL; + kfree(job); + + core->sequence++; + + /* Kickoff processing of next frame (if any). */ + risp_core_job_run(core); +} + +static void risp_core_vspx_frame_end(void *data) +{ + struct rcar_isp_core *core = data; + + guard(spinlock_irqsave)(&core->lock); + + /* + * In tear-down the ISP may report a frame end event but we have already + * freed the job. It is safe to ignore the end of frame event. + */ + if (!core->vspx.job) + return; + + core->vspx.job->done_vspx = true; + risp_core_try_next_job(core); +} + +static int risp_core_power_on(struct rcar_isp_core *core) +{ + int ret; + + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + + ret = reset_control_deassert(core->csrstc); + if (ret) + goto err_pm; + + ret = clk_prepare_enable(core->clk); + if (ret) + goto err_csrstc; + + return 0; + +err_csrstc: + reset_control_assert(core->csrstc); +err_pm: + pm_runtime_put(core->dev); + + return ret; +} + +static void risp_core_power_off(struct rcar_isp_core *core) +{ + clk_disable_unprepare(core->clk); + + reset_control_assert(core->csrstc); + + pm_runtime_put(core->dev); +} + +int risp_core_start_streaming(struct rcar_isp_core *core) +{ + struct vsp1_vspx_frame_end vspx_fe = { + .vspx_frame_end = risp_core_vspx_frame_end, + .frame_end_data = core, + }; + + struct v4l2_mbus_framefmt inputfmt = { + .width = core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width, + .height = core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height, + .code = risp_core_pix2bus(&core->io[RISP_CORE_INPUT1]), + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_RAW, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_NONE, + }; + + struct v4l2_mbus_framefmt hvout = { + .width = core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width, + .height = core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height, + .code = risp_core_pix2bus(&core->io[RISP_CORE_OUTPUT1]), + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = + core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_XBGR32 ? + V4L2_QUANTIZATION_FULL_RANGE : + V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; + int ret; + + scoped_guard(mutex, &core->io_lock) { + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (!core->io[i].streaming) + return 0; + } + + /* + * The state core->streaming is protected by core->lock, which + * is not held yet. It is however safe to read it here since + * core->io_lock is held both in risp_core_stop_streaming() and + * here, the only two places the variable is modified. + * + * With this small implied dependency on the two locks for write + * access, the interrupt handler can safely depend sole on the + * spinlock core->lock for read access to core->streaming. + * + * The gain is an interrupt handler which can hold the spinlock + * and a start/stop procedure which can reset the ISP using the + * reset_control_reset() API, The later which can not be called + * from a context that may sleep. + * + * All other locations core->streaming is read and _all_ + * locations where it is written core->lock is held. + */ + if (core->streaming) + return 0; + + ret = risp_core_power_on(core); + if (ret) + return ret; + + /* Reset and wait for ISP core to initialize itself. */ + reset_control_reset(core->rstc); + usleep_range(2000, 4000); + + scoped_guard(spinlock_irqsave, &core->lock) { + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 1); + + /* Configure output DMA */ + risp_core_config_output(core, 0, + &core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp); + + risp_cs_write(core, ISP_CS_STREAMER_VBLANK_REG, inputfmt.width * 25); + risp_cs_write(core, ISP_CS_STREAMER_HBLANK_REG, 64); + + /* Enable ISP Streaming bridge. */ + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, + ISP_CS_STREAMER_MODE_STREAMER_EN); + + /* Start RPP ISP */ + ret = rppx1_start(core->rpp, &inputfmt, &hvout, NULL); + if (ret) { + risp_core_power_off(core); + return ret; + } + + core->vspx.job = NULL; + core->sequence = 0; + core->streaming = true; + } + + /* Start VSPX */ + vsp1_isp_start_streaming(core->vspx.dev, &vspx_fe); + + scoped_guard(spinlock_irqsave, &core->lock) { + risp_core_job_run(core); + } + } + + return 0; +} + +void risp_core_stop_streaming(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job, *tmp; + + /* + * This function releases buffers and jobs: make sure the queues mutex + * is held. + */ + lockdep_assert_held(&core->io_lock); + + scoped_guard(spinlock_irqsave, &core->lock) { + /* Stop is called by each vdev, only act on the first call. */ + if (!core->streaming) + return; + + /* Stop queueing jobs to VSPX. */ + core->streaming = false; + } + + /* Wait for active VSPX job to finish. */ + for (unsigned int retry = 0; retry <= 10; retry++) { + if (!core->vspx.job) + break; + + usleep_range(2000, 4000); + } + + if (core->vspx.job) + dev_err(core->dev, "Failed to complete running job"); + + /* Free all buffers and switch off the hardware. */ + scoped_guard(spinlock_irqsave, &core->lock) { + /* Free all jobs and buffers. */ + list_for_each_entry_safe(job, tmp, &core->risp_jobs, job_queue) { + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + list_del(&job->job_queue); + kfree(job); + } + + rppx1_stop(core->rpp); + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, 0); + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 0); + } + + vsp1_isp_stop_streaming(core->vspx.dev); + + risp_core_power_off(core); +} + +static irqreturn_t risp_core_irq(int irq, void *data) +{ + struct rcar_isp_core *core = data; + struct rcar_isp_job *job; + u32 status; + + status = risp_core_read(core, ISP_CORE_ISPCORE_INT_STATUS); + if (!(status & BIT(0))) + return IRQ_NONE; + + if (!rppx1_interrupt(core->rpp, &status)) + return IRQ_HANDLED; + + guard(spinlock_irqsave)(&core->lock); + + job = core->vspx.job; + if (!job) + return IRQ_HANDLED; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + buf = job->buffers[i]; + + switch (i) { + case RISP_CORE_STATS: + rppx1_stats_fill_isr(core->rpp, status, + vb2_plane_vaddr(&buf->vb.vb2_buf, 0)); + fallthrough; + case RISP_CORE_OUTPUT1: + case RISP_CORE_INPUT1: + buf->vb.sequence = core->sequence; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + fallthrough; + case RISP_CORE_PARAMS: + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + break; + } + } + + core->vspx.job->done_isp = true; + risp_core_try_next_job(core); + + return IRQ_HANDLED; +} + +static const struct v4l2_subdev_ops risp_core_subdev_ops = { +}; + +static int risp_core_create_subdev(struct rcar_isp_core *core) +{ + struct v4l2_subdev *subdev = &core->subdev; + int ret; + + subdev->owner = THIS_MODULE; + subdev->dev = core->dev; + v4l2_subdev_init(subdev, &risp_core_subdev_ops); + v4l2_set_subdevdata(subdev, core->dev); + snprintf(subdev->name, sizeof(subdev->name), "%s %s core", + KBUILD_MODNAME, dev_name(core->dev)); + subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + + subdev->entity.function = MEDIA_ENT_F_VID_MUX; + + core->pads[RISP_CORE_INPUT1].flags = MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_PARAMS].flags = MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_STATS].flags = MEDIA_PAD_FL_SOURCE; + core->pads[RISP_CORE_OUTPUT1].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, RISP_CORE_NUM_PADS, + core->pads); + if (ret) + return ret; + + return 0; +} + +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *sd) +{ + int ret; + + core->v4l2_dev.mdev = sd->v4l2_dev->mdev; + + /* Register ISP Core subdevice. */ + ret = v4l2_device_register_subdev(&core->v4l2_dev, &core->subdev); + if (ret) + return ret; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + ret = risp_core_io_create(core->dev, core, &core->io[i], i); + if (ret) { + /* It is safe to destroy io node that is not created. */ + for (unsigned int n = 0; n < RISP_CORE_NUM_PADS; n++) + risp_core_io_destroy(&core->io[n]); + + v4l2_device_unregister_subdev(&core->subdev); + + return ret; + } + } + + return 0; +} + +static int risp_core_probe_resources(struct rcar_isp_core *core, + struct platform_device *pdev) +{ + struct platform_device *vspx; + struct device_node *of_vspx; + struct resource *res; + int ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); + if (!res) + return -ENODEV; + + core->rppaddr = res->start; + core->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(core->base)) + return PTR_ERR(core->base); + + ret = platform_get_irq_byname(pdev, "core"); + if (ret < 0) + return -ENODEV; + + ret = devm_request_irq(&pdev->dev, ret, risp_core_irq, IRQF_SHARED, + KBUILD_MODNAME, core); + if (ret) + return ret; + + core->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(core->clk)) + return -ENODEV; + + core->rstc = devm_reset_control_get(&pdev->dev, "core"); + if (IS_ERR(core->rstc)) + return -ENODEV; + + of_vspx = of_parse_phandle(pdev->dev.of_node, "renesas,vspx", 0); + if (!of_vspx) + return -ENODEV; + + vspx = of_find_device_by_node(of_vspx); + of_node_put(of_vspx); + if (!vspx) + return -ENODEV; + + /* Attach to VSP-X */ + core->vspx.dev = &vspx->dev; + + ret = vsp1_isp_init(&vspx->dev); + if (ret < 0) + goto err_put_vspx; + + /* Attach to the RPP library + * + * 1. Start and wait for the ISP to startup. + * 2. Attach the RPP library and talk with the RPP ISP. + * 3. Turn off ISP. + * 4. Fail if the RPP is unhappy with the hardware. + */ + ret = clk_prepare_enable(core->clk); + if (ret) + goto err_put_vspx; + + usleep_range(2000, 4000); + + core->rpp = rppx1_create(core->base, &pdev->dev); + + clk_disable_unprepare(core->clk); + + if (!core->rpp) { + ret = -ENODEV; + goto err_put_vspx; + } + + return 0; + +err_put_vspx: + put_device(&vspx->dev); + return ret; +} + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pdev, + void __iomem *csbase, struct reset_control *csrstc) +{ + int ret; + + core->dev = &pdev->dev; + core->csrstc = csrstc; + core->csbase = csbase; + + ret = risp_core_probe_resources(core, pdev); + if (ret) { + core->base = NULL; + return ret; + } + + ret = v4l2_device_register(core->dev, &core->v4l2_dev); + if (ret) + goto err_destroy_rpp; + + ret = risp_core_create_subdev(core); + if (ret) + goto err_unregister_v4l2; + + mutex_init(&core->io_lock); + spin_lock_init(&core->lock); + INIT_LIST_HEAD(&core->risp_jobs); + + return 0; + +err_unregister_v4l2: + v4l2_device_unregister(&core->v4l2_dev); +err_destroy_rpp: + rppx1_destroy(core->rpp); + put_device(core->vspx.dev); + return ret; +} + +void risp_core_remove(struct rcar_isp_core *core) +{ + /* If we did not probe the ISP core, nothing to do. */ + if (!core->base) + return; + + dev_info(core->dev, "Remove ISP Core\n"); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) + risp_core_io_destroy(&core->io[i]); + + v4l2_device_unregister(&core->v4l2_dev); + + mutex_destroy(&core->io_lock); + rppx1_destroy(core->rpp); + put_device(core->vspx.dev); +} diff --git a/drivers/media/platform/renesas/rcar-isp/csisp.c b/drivers/media/platform/renesas/rcar-isp/csisp.c index 8fb2cc3b5650..53ce47020d17 100644 --- a/drivers/media/platform/renesas/rcar-isp/csisp.c +++ b/drivers/media/platform/renesas/rcar-isp/csisp.c @@ -11,14 +11,13 @@ */ #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/reset.h> #include <media/mipi-csi2.h> -#include <media/v4l2-subdev.h> +#include <media/v4l2-async.h> + +#include "risp-core.h" #define ISPINPUTSEL0_REG 0x0008 #define ISPINPUTSEL0_SEL_CSI0 BIT(31) @@ -158,6 +157,7 @@ struct rcar_isp { struct device *dev; void __iomem *csbase; struct reset_control *rstc; + struct rcar_isp_core core; enum rcar_isp_input csi_input; @@ -452,6 +452,21 @@ static int risp_parse_dt(struct rcar_isp *isp) } /* ----------------------------------------------------------------------------- + * ISP Core connection + */ + +static int risp_cs_registered(struct v4l2_subdev *sd) +{ + struct rcar_isp *isp = sd_to_isp(sd); + + return risp_core_registered(&isp->core, sd); +} + +static const struct v4l2_subdev_internal_ops risp_cs_internal_ops = { + .registered = risp_cs_registered, +}; + +/* ----------------------------------------------------------------------------- * Platform Device Driver */ @@ -477,7 +492,7 @@ static int risp_probe_resources(struct rcar_isp *isp, if (IS_ERR(isp->csbase)) return PTR_ERR(isp->csbase); - isp->rstc = devm_reset_control_get(&pdev->dev, NULL); + isp->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); return PTR_ERR_OR_ZERO(isp->rstc); } @@ -541,14 +556,31 @@ static int risp_probe(struct platform_device *pdev) if (ret) goto error_notifier; + ret = risp_core_probe(&isp->core, pdev, isp->csbase, isp->rstc); + switch (ret) { + case 0: + /* The device have an ISP core. */ + isp->subdev.internal_ops = &risp_cs_internal_ops; + break; + case -ENODEV: + /* The device don't have an ISP core, that is OK. */ + ret = 0; + break; + default: + /* Something went wrong registering the ISP core. */ + goto error_subdev; + } + ret = v4l2_async_register_subdev(&isp->subdev); if (ret < 0) - goto error_subdev; + goto error_core; dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); return 0; +error_core: + risp_core_remove(&isp->core); error_subdev: v4l2_subdev_cleanup(&isp->subdev); error_notifier: @@ -564,6 +596,8 @@ static void risp_remove(struct platform_device *pdev) { struct rcar_isp *isp = platform_get_drvdata(pdev); + risp_core_remove(&isp->core); + v4l2_async_nf_unregister(&isp->notifier); v4l2_async_nf_cleanup(&isp->notifier); diff --git a/drivers/media/platform/renesas/rcar-isp/risp-core.h b/drivers/media/platform/renesas/rcar-isp/risp-core.h new file mode 100644 index 000000000000..627a762d6b19 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/risp-core.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __RCAR_ISP__ +#define __RCAR_ISP__ + +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/spinlock.h> +#include <linux/videodev2.h> + +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include <media/rppx1.h> +#include <media/vsp1.h> + +/* Max 2048 address + value pairs in one VSPX buffer, increase if needed. */ +#define RISP_IO_PARAMS_BUF_SIZE 16384 + +struct rcar_isp_core; + +enum risp_core_pads { + RISP_CORE_INPUT1, + RISP_CORE_PARAMS, + RISP_CORE_STATS, + RISP_CORE_OUTPUT1, + RISP_CORE_NUM_PADS, +}; + +/** + * struct risp_buffer - Describe an IO buffer + * @vb: The VB2 buffer + * @list: List of buffers queued to the IO queue + * @vsp_buffer: Buffer mapped from VSP-X, only used for params IO + */ +struct risp_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; + struct vsp1_isp_buffer_desc vsp_buffer; +}; + +/** + * struct rcar_isp_core_io - Information for a IO video devices + * @core: Backlink to the common ISP core structure + * + * @lock: Protects @vdev, @pad and @queue + open/close fops + * @vdev: V4L2 video device associated with this IO port + * @pad: Media pad for @vdev + * @queue: VB2 buffers queue for $@vdev + * + * @streaming: Flag to indicate if device is streaming, or not + * @buffers: List of buffers queued to the device + * + * @format: The active V4L2 format + */ +struct rcar_isp_core_io { + struct rcar_isp_core *core; + + struct mutex lock; /* See KDoc block. */ + struct video_device vdev; + struct media_pad pad; + struct vb2_queue queue; + + bool streaming; + struct list_head buffers; + + struct v4l2_format format; +}; + +/** + * struct rcar_isp_job - R-Car ISP job description + * + * Both done_isp and done_vspx shall be set before the job can be considered + * completely done. + * + * @buffers: IO buffers that form a job + * @vspx_job: VSPX job description + * @job_queue: list handle + * @done_isp: Flag to indicate the ISP is done with the job + * @done_vspx: Flag to indicate the VSPX is done with the job + */ +struct rcar_isp_job { + struct risp_buffer *buffers[RISP_CORE_NUM_PADS]; + struct vsp1_isp_job_desc vspx_job; + struct list_head job_queue; + bool done_isp; + bool done_vspx; +}; + +/** + * struct rcar_isp_vspx - R-Car ISP job description + * + * @dev: Device reference to VSPX + * @job: Job currently being processed by VSPX + */ +struct rcar_isp_vspx { + struct device *dev; + struct rcar_isp_job *job; +}; + +/** + * struct rcar_isp_core - ISP Core + * @dev: (OF) device + * @rppaddr: Hardware address of the RPP ISP (from OF) + * @clk: The clock for the ISP CORE + * @rstc: The reset for the ISP Core + * @csrstc: The reset for the ISP Channel Selector + * + * @base: MMIO base of the ISP CORE + * @csbase: MMIO base of the ISP CS + * + * @subdev: V4L2 subdevice to represent the ISP CORE + * @pads: Media pad for @subdev + * + * @v4l2_dev: V4L2 device + * @rpp: Handle to the RPP ISP connected to the ISP CORE + * + * @io_lock: Protect io[*].streaming and io[*].buffers + * @io: Array of IO ports to the ISP CORE + * + * @lock: Protects @vspx, @risp_jobs, @sequence and @streaming + * @vspx: Handle to the resources used by VSPX connected to the ISP CORE + * @risp_jobs: Queue of VSPX transfer jobs + * @sequence: V4L2 buffers sequence number + * @streaming: Tracks if the device is streaming + */ +struct rcar_isp_core { + struct device *dev; + + u32 rppaddr; + struct clk *clk; + + struct reset_control *rstc; + struct reset_control *csrstc; + + void __iomem *base; + void __iomem *csbase; + + struct v4l2_subdev subdev; + struct media_pad pads[RISP_CORE_NUM_PADS]; + + struct v4l2_device v4l2_dev; + struct rppx1 *rpp; + + struct mutex io_lock; /* See KDoc block. */ + struct rcar_isp_core_io io[RISP_CORE_NUM_PADS]; + + spinlock_t lock; /* See KDoc block. */ + struct rcar_isp_vspx vspx; + struct list_head risp_jobs; + unsigned int sequence; + bool streaming; +}; + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pdev, + void __iomem *csbase, struct reset_control *csrstc); +void risp_core_remove(struct rcar_isp_core *core); +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *sd); + +int risp_core_job_prepare(struct rcar_isp_core *core); + +int risp_core_start_streaming(struct rcar_isp_core *core); +void risp_core_stop_streaming(struct rcar_isp_core *core); + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad); +void risp_core_io_destroy(struct rcar_isp_core_io *io); + +#endif diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index 5bf334e173d2..b426bc7898bf 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -116,11 +116,9 @@ struct rzg2l_cru_info { * @scratch_phys: physical address of the scratch buffer * * @qlock: protects @queue_buf, @buf_list, @sequence - * @state * @queue_buf: Keeps track of buffers given to HW slot * @buf_list: list of queued buffers * @sequence: V4L2 buffers sequence number - * @state: keeps track of operation state * * @format: active V4L2 pixel format */ diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index 5185a547461d..91eda5034248 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -851,6 +851,11 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, v4l2_fill_pixfmt(pix, pix->pixelformat, pix->width, pix->height); + if (info->has_stride) { + pix->bytesperline = ALIGN(pix->bytesperline, RZG2L_CRU_STRIDE_ALIGN); + pix->sizeimage = pix->bytesperline * pix->height; + } + dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", pix->width, pix->height, pix->bytesperline, pix->sizeimage); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c index 325be30836d7..360a42502947 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c @@ -155,9 +155,7 @@ static int brx_set_format(struct v4l2_subdev *subdev, /* Propagate the format code to all pads. */ if (fmt->pad == BRX_PAD_SINK(0)) { - unsigned int i; - - for (i = 0; i <= brx->entity.source_pad; ++i) { + for (unsigned int i = 0; i <= brx->entity.source_pad; ++i) { format = v4l2_subdev_state_get_format(state, i); format->code = fmt->format.code; } @@ -271,7 +269,6 @@ static void brx_configure_stream(struct vsp1_entity *entity, struct vsp1_brx *brx = to_brx(&entity->subdev); struct v4l2_mbus_framefmt *format; unsigned int flags; - unsigned int i; format = v4l2_subdev_state_get_format(state, brx->entity.source_pad); @@ -315,7 +312,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, VI6_BRU_ROP_CROP(VI6_ROP_NOP) | VI6_BRU_ROP_AROP(VI6_ROP_NOP)); - for (i = 0; i < brx->entity.source_pad; ++i) { + for (unsigned int i = 0; i < brx->entity.source_pad; ++i) { bool premultiplied = false; u32 ctrl = 0; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c index a6e4bcab5101..4b7d07d730da 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c @@ -43,14 +43,13 @@ static inline void vsp1_clu_write(struct vsp1_clu *clu, static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; - unsigned int i; dlb = vsp1_dl_body_get(clu->pool); if (!dlb) return -ENOMEM; vsp1_dl_body_write(dlb, VI6_CLU_ADDR, 0); - for (i = 0; i < CLU_SIZE; ++i) + for (unsigned int i = 0; i < CLU_SIZE; ++i) vsp1_dl_body_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]); scoped_guard(spinlock_irq, &clu->lock) { diff --git a/drivers/media/platform/renesas/vsp1/vsp1_dl.c b/drivers/media/platform/renesas/vsp1/vsp1_dl.c index 3dc74fed91dc..6430f2ec8b32 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_dl.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_dl.c @@ -257,7 +257,6 @@ vsp1_dl_body_pool_create(struct vsp1_device *vsp1, unsigned int num_bodies, { struct vsp1_dl_body_pool *pool; size_t dlb_size; - unsigned int i; pool = kzalloc_obj(*pool); if (!pool) @@ -291,7 +290,7 @@ vsp1_dl_body_pool_create(struct vsp1_device *vsp1, unsigned int num_bodies, spin_lock_init(&pool->lock); INIT_LIST_HEAD(&pool->free); - for (i = 0; i < num_bodies; ++i) { + for (unsigned int i = 0; i < num_bodies; ++i) { struct vsp1_dl_body *dlb = &pool->bodies[i]; dlb->pool = pool; @@ -426,7 +425,6 @@ vsp1_dl_cmd_pool_create(struct vsp1_device *vsp1, enum vsp1_extcmd_type type, unsigned int num_cmds) { struct vsp1_dl_cmd_pool *pool; - unsigned int i; size_t cmd_size; pool = kzalloc_obj(*pool); @@ -457,7 +455,7 @@ vsp1_dl_cmd_pool_create(struct vsp1_device *vsp1, enum vsp1_extcmd_type type, return NULL; } - for (i = 0; i < num_cmds; ++i) { + for (unsigned int i = 0; i < num_cmds; ++i) { struct vsp1_dl_ext_cmd *cmd = &pool->cmds[i]; size_t cmd_offset = i * cmd_size; /* data_offset must be 16 byte aligned for DMA. */ @@ -1046,7 +1044,6 @@ unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) /* Hardware Setup */ void vsp1_dlm_setup(struct vsp1_device *vsp1) { - unsigned int i; u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT) | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 | VI6_DL_CTRL_DLE; @@ -1054,7 +1051,7 @@ void vsp1_dlm_setup(struct vsp1_device *vsp1) | VI6_DL_EXT_CTRL_DLPRI | VI6_DL_EXT_CTRL_EXT; if (vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) { - for (i = 0; i < vsp1->info->wpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) vsp1_write(vsp1, VI6_DL_EXT_CTRL(i), ext_dl); } @@ -1092,7 +1089,6 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, { struct vsp1_dl_manager *dlm; size_t header_size; - unsigned int i; dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL); if (!dlm) @@ -1128,7 +1124,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, if (!dlm->pool) return NULL; - for (i = 0; i < prealloc; ++i) { + for (unsigned int i = 0; i < prealloc; ++i) { struct vsp1_dl_list *dl; dl = vsp1_dl_list_alloc(dlm); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c index f6fbd3475329..9cd5c025d2be 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c @@ -419,13 +419,12 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, struct vsp1_entity *uif; bool use_uif = false; struct vsp1_brx *brx; - unsigned int i; int ret; /* Count the number of enabled inputs and sort them by Z-order. */ pipe->num_inputs = 0; - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; @@ -457,7 +456,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, brx = to_brx(&pipe->brx->subdev); /* Setup the RPF input pipeline for every enabled input. */ - for (i = 0; i < pipe->brx->source_pad; ++i) { + for (unsigned int i = 0; i < pipe->brx->source_pad; ++i) { struct vsp1_rwpf *rpf = inputs[i]; if (!rpf) { @@ -732,7 +731,6 @@ int vsp1_du_disable(struct device *dev, unsigned int pipe_index) struct vsp1_device *vsp1 = dev_get_drvdata(dev); struct vsp1_drm_pipeline *drm_pipe; struct vsp1_pipeline *pipe; - unsigned int i; int ret; if (pipe_index >= vsp1->info->lif_count) @@ -748,7 +746,7 @@ int vsp1_du_disable(struct device *dev, unsigned int pipe_index) if (ret == -ETIMEDOUT) dev_err(vsp1->dev, "DRM pipeline stop timeout\n"); - for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { struct vsp1_rwpf *rpf = pipe->inputs[i]; if (!rpf) @@ -964,8 +962,6 @@ EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg); int vsp1_drm_init(struct vsp1_device *vsp1) { - unsigned int i; - vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL); if (!vsp1->drm) return -ENOMEM; @@ -973,7 +969,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) mutex_init(&vsp1->drm->lock); /* Create one DRM pipeline per LIF. */ - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i]; struct vsp1_pipeline *pipe = &drm_pipe->pipe; @@ -1010,7 +1006,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) } /* Disable all RPFs initially. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = vsp1->rpf[i]; INIT_LIST_HEAD(&input->entity.list_pipe); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 627b5046fa80..762a9e776a94 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -51,10 +51,9 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) VI6_WPF_IRQ_STA_UND; struct vsp1_device *vsp1 = data; irqreturn_t ret = IRQ_NONE; - unsigned int i; u32 status; - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; if (wpf == NULL) @@ -103,7 +102,6 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, { struct media_entity *entity = &sink->subdev.entity; struct vsp1_entity *source; - unsigned int pad; int ret; list_for_each_entry(source, &vsp1->entities, list_dev) { @@ -123,7 +121,7 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, source->index == sink->index ? MEDIA_LNK_FL_ENABLED : 0; - for (pad = 0; pad < entity->num_pads; ++pad) { + for (unsigned int pad = 0; pad < entity->num_pads; ++pad) { if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK)) continue; @@ -144,7 +142,6 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, static int vsp1_uapi_create_links(struct vsp1_device *vsp1) { struct vsp1_entity *entity; - unsigned int i; int ret; list_for_each_entry(entity, &vsp1->entities, list_dev) { @@ -177,7 +174,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { if (!vsp1->lif[i]) continue; @@ -189,7 +186,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf = vsp1->rpf[i]; ret = media_create_pad_link(&rpf->video->video.entity, 0, @@ -201,7 +198,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { /* * Connect the video device to the WPF. All connections are * immutable. @@ -253,7 +250,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) struct media_device *mdev = &vsp1->media_dev; struct v4l2_device *vdev = &vsp1->v4l2_dev; struct vsp1_entity *entity; - unsigned int i; int ret; mdev->dev = vsp1->dev; @@ -365,7 +361,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) * enabled skip the LIFs, even when present. */ if (!vsp1->info->uapi) { - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { struct vsp1_lif *lif; lif = vsp1_lif_create(vsp1, i); @@ -389,7 +385,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf; rpf = vsp1_rpf_create(vsp1, i); @@ -423,7 +419,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->uds_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->uds_count; ++i) { struct vsp1_uds *uds; uds = vsp1_uds_create(vsp1, i); @@ -436,7 +432,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uds->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->uif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->uif_count; ++i) { struct vsp1_uif *uif; uif = vsp1_uif_create(vsp1, i); @@ -449,7 +445,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uif->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf; wpf = vsp1_wpf_create(vsp1, i); @@ -543,11 +539,10 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) static int vsp1_device_init(struct vsp1_device *vsp1) { - unsigned int i; int ret; /* Reset any channel that might be running. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { ret = vsp1_reset_wpf(vsp1, i); if (ret < 0) return ret; @@ -556,13 +551,13 @@ static int vsp1_device_init(struct vsp1_device *vsp1) vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); - for (i = 0; i < vsp1->info->rpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->info->uds_count; ++i) + for (unsigned int i = 0; i < vsp1->info->uds_count; ++i) vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->info->uif_count; ++i) + for (unsigned int i = 0; i < vsp1->info->uif_count; ++i) vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED); vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); @@ -587,11 +582,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1) static void vsp1_mask_all_interrupts(struct vsp1_device *vsp1) { - unsigned int i; - - for (i = 0; i < vsp1->info->lif_count; ++i) + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) vsp1_write(vsp1, VI6_DISP_IRQ_ENB(i), 0); - for (i = 0; i < vsp1->info->wpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) vsp1_write(vsp1, VI6_WPF_IRQ_ENB(i), 0); } @@ -891,7 +884,6 @@ static const struct vsp1_device_info rzg2l_vsp2_device_info = { static const struct vsp1_device_info *vsp1_lookup_info(struct vsp1_device *vsp1) { const struct vsp1_device_info *info; - unsigned int i; u32 model; u32 soc; @@ -909,7 +901,7 @@ static const struct vsp1_device_info *vsp1_lookup_info(struct vsp1_device *vsp1) model = vsp1->version & VI6_IP_VERSION_MODEL_MASK; soc = vsp1->version & VI6_IP_VERSION_SOC_MASK; - for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { info = &vsp1_device_infos[i]; if (model == info->version && (!info->soc || soc == info->soc)) @@ -947,7 +939,7 @@ static int vsp1_probe(struct platform_device *pdev) if (irq < 0) return irq; - vsp1->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); + vsp1->rstc = devm_reset_control_get_optional_shared(&pdev->dev, NULL); if (IS_ERR(vsp1->rstc)) return dev_err_probe(&pdev->dev, PTR_ERR(vsp1->rstc), "failed to get reset control\n"); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 2ae2a573f0de..26b21559878d 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -372,10 +372,8 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, static int vsp1_entity_init_state(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - unsigned int pad; - /* Initialize all pad formats with default values. */ - for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { + for (unsigned int pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { struct v4l2_subdev_format format = { .pad = pad, .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c index 0ef512e3a94b..d3eaa7c2d595 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c @@ -42,7 +42,6 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) { struct vsp1_hgo *hgo = to_hgo(&entity->subdev); struct vsp1_histogram_buffer *buf; - unsigned int i; size_t size; u32 *data; @@ -56,7 +55,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); - for (i = 0; i < 256; ++i) { + for (unsigned int i = 0; i < 256; ++i) { vsp1_write(hgo->histo.entity.vsp1, VI6_HGO_EXT_HIST_ADDR, i); *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA); @@ -67,7 +66,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); - for (i = 0; i < 64; ++i) + for (unsigned int i = 0; i < 64; ++i) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); size = (2 + 64) * sizeof(u32); @@ -80,7 +79,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM); - for (i = 0; i < 64; ++i) { + for (unsigned int i = 0; i < 64; ++i) { data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i)); data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i)); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c index 78b5a9201c70..8c04bdec8510 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c @@ -42,8 +42,6 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) { struct vsp1_hgt *hgt = to_hgt(&entity->subdev); struct vsp1_histogram_buffer *buf; - unsigned int m; - unsigned int n; u32 *data; buf = vsp1_histogram_buffer_get(&hgt->histo); @@ -55,9 +53,10 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgt_read(hgt, VI6_HGT_MAXMIN); *data++ = vsp1_hgt_read(hgt, VI6_HGT_SUM); - for (m = 0; m < 6; ++m) - for (n = 0; n < 32; ++n) + for (unsigned int m = 0; m < 6; ++m) { + for (unsigned int n = 0; n < 32; ++n) *data++ = vsp1_hgt_read(hgt, VI6_HGT_HISTO(m, n)); + } vsp1_histogram_buffer_complete(&hgt->histo, buf, HGT_DATA_SIZE); } @@ -71,7 +70,6 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl) { const u8 *values = ctrl->p_new.p_u8; - unsigned int i; /* * The hardware has constraints on the hue area boundaries beyond the @@ -83,7 +81,7 @@ static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl) * * Start by verifying the common part... */ - for (i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) { + for (unsigned int i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) { if (values[i] > values[i+1]) return -EINVAL; } @@ -138,7 +136,6 @@ static void hgt_configure_stream(struct vsp1_entity *entity, unsigned int vratio; u8 lower; u8 upper; - unsigned int i; crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK); compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK); @@ -153,7 +150,7 @@ static void hgt_configure_stream(struct vsp1_entity *entity, (crop->height << VI6_HGT_SIZE_VSIZE_SHIFT)); scoped_guard(mutex, hgt->ctrls.lock) { - for (i = 0; i < HGT_NUM_HUE_AREAS; ++i) { + for (unsigned int i = 0; i < HGT_NUM_HUE_AREAS; ++i) { lower = hgt->hue_areas[i*2 + 0]; upper = hgt->hue_areas[i*2 + 1]; vsp1_hgt_write(hgt, dlb, VI6_HGT_HUE_AREA(i), diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c index a22c31e17cb7..6433b5515ef9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c @@ -40,13 +40,12 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; - unsigned int i; dlb = vsp1_dl_body_get(lut->pool); if (!dlb) return -ENOMEM; - for (i = 0; i < LUT_SIZE; ++i) + for (unsigned int i = 0; i < LUT_SIZE; ++i) vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i, ctrl->p_new.p_u32[i]); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c index 32bb02ce0366..c6a624e193b3 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c @@ -391,16 +391,15 @@ void vsp1_adjust_color_space(u32 code, u32 *colorspace, u8 *xfer_func, void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; - unsigned int i; if (pipe->brx) { struct vsp1_brx *brx = to_brx(&pipe->brx->subdev); - for (i = 0; i < ARRAY_SIZE(brx->inputs); ++i) + for (unsigned int i = 0; i < ARRAY_SIZE(brx->inputs); ++i) brx->inputs[i].rpf = NULL; } - for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) + for (unsigned int i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) pipe->inputs[i] = NULL; pipe->output = NULL; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 5a1d284213ad..b85351986fae 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -104,14 +104,13 @@ static int __vsp1_video_try_format(struct vsp1_video *video, const struct vsp1_format_info *info; unsigned int width = pix->width; unsigned int height = pix->height; - unsigned int i; /* * Backward compatibility: replace deprecated RGB formats by their XRGB * equivalent. This selects the format older userspace applications want * while still exposing the new format. */ - for (i = 0; i < ARRAY_SIZE(xrgb_formats); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(xrgb_formats); ++i) { if (xrgb_formats[i][0] == pix->pixelformat) { pix->pixelformat = xrgb_formats[i][1]; break; @@ -161,7 +160,7 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * the datasheet, strides not aligned to a multiple of 128 bytes result * in image corruption. */ - for (i = 0; i < min(info->planes, 2U); ++i) { + for (unsigned int i = 0; i < min(info->planes, 2U); ++i) { unsigned int hsub = i > 0 ? info->hsub : 1; unsigned int vsub = i > 0 ? info->vsub : 1; unsigned int align = 128; @@ -209,7 +208,6 @@ vsp1_video_complete_buffer(struct vsp1_video *video) struct vsp1_pipeline *pipe = video->rwpf->entity.pipe; struct vsp1_vb2_buffer *next = NULL; struct vsp1_vb2_buffer *done; - unsigned int i; scoped_guard(spinlock_irqsave, &video->irqlock) { if (list_empty(&video->irqqueue)) @@ -227,7 +225,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video) done->buf.sequence = pipe->sequence; done->buf.vb2_buf.timestamp = ktime_get_ns(); - for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) + for (unsigned int i = 0; i < done->buf.vb2_buf.num_planes; ++i) vb2_set_plane_payload(&done->buf.vb2_buf, i, vb2_plane_size(&done->buf.vb2_buf, i)); vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); @@ -267,7 +265,6 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) struct vsp1_entity *entity; struct vsp1_dl_body *dlb; struct vsp1_dl_list *dl; - unsigned int partition; dl = vsp1_dl_list_get(pipe->output->dlm); @@ -289,7 +286,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) vsp1_video_pipeline_run_partition(pipe, dl, 0); /* Process consecutive partitions as necessary. */ - for (partition = 1; partition < pipe->partitions; ++partition) { + for (unsigned int partition = 1; partition < pipe->partitions; ++partition) { struct vsp1_dl_list *dl_next; dl_next = vsp1_dl_list_get(pipe->output->dlm); @@ -321,7 +318,6 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe, struct vsp1_device *vsp1 = pipe->output->entity.vsp1; enum vsp1_pipeline_state state; unsigned long flags; - unsigned int i; /* M2M Pipelines should never call here with an incomplete frame. */ WARN_ON_ONCE(!(completion & VSP1_DL_FRAME_END_COMPLETED)); @@ -329,7 +325,7 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe, spin_lock_irqsave(&pipe->irqlock, flags); /* Complete buffers on all video nodes. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { if (!pipe->inputs[i]) continue; @@ -449,7 +445,6 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, struct media_graph graph; struct media_entity *entity = &video->video.entity; struct media_device *mdev = entity->graph_obj.mdev; - unsigned int i; int ret; /* Walk the graph to locate the entities and video nodes. */ @@ -517,7 +512,7 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, * Follow links downstream for each input and make sure the graph * contains no loop and that all branches end at the output WPF. */ - for (i = 0; i < video->vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < video->vsp1->info->rpf_count; ++i) { if (!pipe->inputs[i]) continue; @@ -606,13 +601,12 @@ vsp1_video_queue_setup(struct vb2_queue *vq, { struct vsp1_video *video = vb2_get_drv_priv(vq); const struct v4l2_pix_format_mplane *format = &video->rwpf->format; - unsigned int i; if (*nplanes) { if (*nplanes != format->num_planes) return -EINVAL; - for (i = 0; i < *nplanes; i++) + for (unsigned int i = 0; i < *nplanes; i++) if (sizes[i] < format->plane_fmt[i].sizeimage) return -EINVAL; return 0; @@ -620,7 +614,7 @@ vsp1_video_queue_setup(struct vb2_queue *vq, *nplanes = format->num_planes; - for (i = 0; i < format->num_planes; ++i) + for (unsigned int i = 0; i < format->num_planes; ++i) sizes[i] = format->plane_fmt[i].sizeimage; return 0; @@ -682,7 +676,6 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) const struct v4l2_mbus_framefmt *format; struct vsp1_entity *entity; unsigned int div_size; - unsigned int i; /* * Partitions are computed on the size before rotation, use the format @@ -716,7 +709,7 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) if (!pipe->part_table) return -ENOMEM; - for (i = 0; i < pipe->partitions; ++i) + for (unsigned int i = 0; i < pipe->partitions; ++i) vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[i], div_size, i); @@ -1116,7 +1109,6 @@ static const struct media_entity_operations vsp1_video_media_ops = { void vsp1_video_suspend(struct vsp1_device *vsp1) { - unsigned int i; int ret; /* @@ -1124,7 +1116,7 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) * pipelines twice, first to set them all to the stopping state, and * then to wait for the stop to complete. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; @@ -1141,7 +1133,7 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) } } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; @@ -1162,10 +1154,8 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) void vsp1_video_resume(struct vsp1_device *vsp1) { - unsigned int i; - /* Resume all running pipelines. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c index 0ec707d2913f..821887815eb2 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c @@ -232,7 +232,6 @@ static void wpf_configure_stream(struct vsp1_entity *entity, const struct v4l2_mbus_framefmt *source_format; const struct v4l2_mbus_framefmt *sink_format; unsigned int index = wpf->entity.index; - unsigned int i; u32 outfmt = 0; u32 srcrpf = 0; int ret; @@ -314,7 +313,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity, * inputs as sub-layers and select the virtual RPF as the master * layer. For VSPX configure the enabled sources as masters. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; if (!input) @@ -399,7 +398,6 @@ static void wpf_configure_partition(struct vsp1_entity *entity, unsigned int left; unsigned int offset; unsigned int flip; - unsigned int i; /* * Cropping. The partition algorithm can split the image into multiple @@ -448,7 +446,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, else offset = left; - for (i = 0; i < format->num_planes; ++i) { + for (unsigned int i = 0; i < format->num_planes; ++i) { unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; @@ -490,7 +488,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, * Compute the output coordinate. The partition * horizontal (left) offset becomes a vertical offset. */ - for (i = 0; i < format->num_planes; ++i) { + for (unsigned int i = 0; i < format->num_planes; ++i) { unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; mem.addr[i] += hoffset / hsub diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c index ca1c268303dd..c4a71306278b 100644 --- a/drivers/media/platform/rockchip/rga/rga3-hw.c +++ b/drivers/media/platform/rockchip/rga/rga3-hw.c @@ -450,10 +450,14 @@ static void *rga3_adjust_and_map_format(struct rga_ctx *ctx, other_format = is_output ? &ctx->out.pix : &ctx->in.pix; other_format_info = v4l2_format_info(other_format->pixelformat); - if ((v4l2_is_format_rgb(format_info) && - v4l2_is_format_yuv(other_format_info)) || - (v4l2_is_format_yuv(format_info) && - v4l2_is_format_rgb(other_format_info))) { + /* + * Only apply the quantization restrictions when we need to + * convert between RGB and YUV. Otherwise there is no point + * to limit the quantization for operations like scaling or + * rotations. + */ + if (v4l2_is_format_yuv(format_info) && + v4l2_is_format_rgb(other_format_info)) { /* * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions * Additionally BT709 and BT2020 only support limited range YUV. diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c index f89602075121..9c4a6093af32 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c @@ -209,6 +209,9 @@ static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx, int i, j; int dPoc; + if ((unsigned int)rps_data->delta_idx_minus1 + 1 > idx) + return; + ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */ delta_rps = (1 - 2 * rps_data->delta_rps_sign) * (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */ diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c index 87abf93dfd5e..ff3942f91c5d 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c @@ -258,9 +258,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, for (i = 0; i <= pps->num_tile_rows_minus1; i++) WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); } else { - WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + WRITE_PPS(DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_y) - 1, COLUMN_WIDTH(0)); - WRITE_PPS(((sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + WRITE_PPS(DIV_ROUND_UP(sps->pic_height_in_luma_samples, ctb_size_y) - 1, ROW_HEIGHT(0)); } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c index fe6414a17551..d07c74679552 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c @@ -261,8 +261,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, memset(row_height, 0, sizeof(row_height)); max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size); - pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width; - pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width; + pic_in_cts_width = DIV_ROUND_UP(width, max_cu_width); + pic_in_cts_height = DIV_ROUND_UP(height, max_cu_width); if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { @@ -275,8 +275,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, column_width, row_height); } } else { - column_width[0] = (width + max_cu_width - 1) / max_cu_width; - row_height[0] = (height + max_cu_width - 1) / max_cu_width; + column_width[0] = DIV_ROUND_UP(width, max_cu_width); + row_height[0] = DIV_ROUND_UP(height, max_cu_width); } for (i = 0; i < 20; i++) { diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c index 3575338a531a..3462d995d4cf 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c @@ -287,8 +287,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, memset(row_height, 0, sizeof(row_height)); max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size); - pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width; - pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width; + pic_in_cts_width = DIV_ROUND_UP(width, max_cu_width); + pic_in_cts_height = DIV_ROUND_UP(height, max_cu_width); if (tiles_enabled) { if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { @@ -301,8 +301,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, column_width, row_height); } } else { - column_width[0] = (width + max_cu_width - 1) / max_cu_width; - row_height[0] = (height + max_cu_width - 1) / max_cu_width; + column_width[0] = DIV_ROUND_UP(width, max_cu_width); + row_height[0] = DIV_ROUND_UP(height, max_cu_width); } for (i = 0; i < 20; i++) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 1d1e9bfef8e9..061281f903f3 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -278,12 +278,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = { { .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS, .cfg.ops = &rkvdec_ctrl_ops, - .cfg.dims = { 65 }, + .cfg.dims = { 64 }, }, { .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS, .cfg.ops = &rkvdec_ctrl_ops, - .cfg.dims = { 65 }, + .cfg.dims = { 32 }, }, }; @@ -1818,8 +1818,8 @@ static int rkvdec_probe(struct platform_device *pdev) vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; + if (irq < 0) + return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, rkvdec_irq_handler, IRQF_ONESHOT, diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c index 221e3c447f36..bb06847f3a63 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-core.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c @@ -12,7 +12,6 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -302,7 +301,6 @@ static int camif_media_dev_init(struct camif_dev *camif) struct media_device *md = &camif->media_dev; struct v4l2_device *v4l2_dev = &camif->v4l2_dev; unsigned int ip_rev = camif->variant->ip_revision; - int ret; memset(md, 0, sizeof(*md)); snprintf(md->model, sizeof(md->model), "Samsung S3C%s CAMIF", @@ -317,11 +315,7 @@ static int camif_media_dev_init(struct camif_dev *camif) media_device_init(md); - ret = v4l2_device_register(camif->dev, v4l2_dev); - if (ret < 0) - return ret; - - return ret; + return v4l2_device_register(camif->dev, v4l2_dev); } static void camif_clk_put(struct camif_dev *camif) @@ -412,7 +406,7 @@ static int s3c_camif_probe(struct platform_device *pdev) camif->dev = dev; - if (!pdata || !pdata->gpio_get || !pdata->gpio_put) { + if (!pdata) { dev_err(dev, "wrong platform data\n"); return -EINVAL; } @@ -429,9 +423,7 @@ static int s3c_camif_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = pdata->gpio_get(); - if (ret < 0) - return ret; + /* FIXME: get GPIOs here */ ret = s3c_camif_create_subdev(camif); if (ret < 0) @@ -504,14 +496,12 @@ err_disable: err_clk: s3c_camif_unregister_subdev(camif); err_sd: - pdata->gpio_put(); return ret; } static void s3c_camif_remove(struct platform_device *pdev) { struct camif_dev *camif = platform_get_drvdata(pdev); - struct s3c_camif_plat_data *pdata = &camif->pdata; media_device_unregister(&camif->media_dev); media_device_cleanup(&camif->media_dev); @@ -521,7 +511,6 @@ static void s3c_camif_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); camif_clk_put(camif); s3c_camif_unregister_subdev(camif); - pdata->gpio_put(); } static int s3c_camif_runtime_resume(struct device *dev) diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index eeb0199864dd..aa79fe60ff0c 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -2024,8 +2024,10 @@ static int dcmi_probe(struct platform_device *pdev) mdma_chan = dma_request_chan(&pdev->dev, "mdma_tx"); if (IS_ERR(mdma_chan)) { ret = PTR_ERR(mdma_chan); - if (ret != -ENODEV) - return dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n"); + if (ret != -ENODEV) { + dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n"); + goto err_release_chan; + } mdma_chan = NULL; } @@ -2050,6 +2052,7 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); if (!dcmi->sram_pool) { dev_info(&pdev->dev, "No SRAM pool, can't use MDMA chaining\n"); + ret = -ENOMEM; goto err_dma_slave_config; } @@ -2061,6 +2064,7 @@ static int dcmi_probe(struct platform_device *pdev) &dcmi->sram_dma_buf); if (!dcmi->sram_buf) { dev_err(dcmi->dev, "Failed to allocate from SRAM\n"); + ret = -ENOMEM; goto err_dma_slave_config; } @@ -2206,12 +2210,13 @@ err_device_unregister: err_media_device_cleanup: media_device_cleanup(&dcmi->mdev); err_mdma_slave_config: - if (dcmi->mdma_chan) + if (mdma_chan) gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size); err_dma_slave_config: - dma_release_channel(dcmi->dma_chan); - if (dcmi->mdma_chan) + if (mdma_chan) dma_release_channel(mdma_chan); +err_release_chan: + dma_release_channel(chan); return ret; } @@ -2273,9 +2278,7 @@ static int dcmi_resume(struct device *dev) pinctrl_pm_select_default_state(dev); /* clock enable */ - pm_runtime_force_resume(dev); - - return 0; + return pm_runtime_force_resume(dev); } static const struct dev_pm_ops dcmi_pm_ops = { diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c index 49398d077764..516334541b2c 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -649,9 +649,7 @@ static int dcmipp_resume(struct device *dev) pinctrl_pm_select_default_state(dev); /* clock enable */ - pm_runtime_force_resume(dev); - - return 0; + return pm_runtime_force_resume(dev); } static const struct dev_pm_ops dcmipp_pm_ops = { diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index d0cb05481bd8..1a020b2bbb4f 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -50,6 +50,7 @@ config VIDEO_TI_VIP select VIDEO_TI_VPDMA select VIDEO_TI_SC select VIDEO_TI_CSC + select V4L2_FWNODE help Driver support for VIP module on certain TI SoC's VIP = Video Input Port. diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c index e56a95f53ea9..ccb688f4d7af 100644 --- a/drivers/media/platform/ti/vpe/vip.c +++ b/drivers/media/platform/ti/vpe/vip.c @@ -815,6 +815,22 @@ static void clear_irqs(struct vip_dev *dev, int irq_num, int list_num) vpdma_clear_list_stat(dev->shared->vpdma, irq_num, dev->slice_id); } +/* + * Quiesce recovery work and per-list IRQs before releasing stream resources. + * disable_work_sync() prevents the overflow handler from requeueing recovery + * work. Mask and synchronize IRQs afterwards because a running worker may + * have re-enabled them before exiting. + */ +static void vip_quiesce_stream(struct vip_stream *stream) +{ + struct vip_dev *dev = stream->port->dev; + + disable_work_sync(&stream->recovery_work); + disable_irqs(dev, dev->slice_id, stream->list_num); + clear_irqs(dev, dev->slice_id, stream->list_num); + synchronize_irq(dev->irq); +} + static void populate_desc_list(struct vip_stream *stream) { struct vip_port *port = stream->port; @@ -2429,6 +2445,7 @@ static int vip_start_streaming(struct vb2_queue *vq, unsigned int count) goto err; stream->num_recovery = 0; + enable_work(&stream->recovery_work); clear_irqs(dev, dev->slice_id, stream->list_num); enable_irqs(dev, dev->slice_id, stream->list_num); @@ -2453,13 +2470,17 @@ static void vip_stop_streaming(struct vb2_queue *vq) struct vip_dev *dev = port->dev; int ret; + /* + * A running recovery worker may re-enable the parser, so quiesce it + * and its IRQ handler before stopping the parser or releasing the + * descriptor list. + */ + vip_quiesce_stream(stream); + vip_parser_stop_imm(port, true); vip_enable_parser(port, false); unset_fmt_params(stream); - disable_irqs(dev, dev->slice_id, stream->list_num); - clear_irqs(dev, dev->slice_id, stream->list_num); - if (port->subdev) { ret = v4l2_subdev_call(port->subdev, video, s_stream, 0); if (ret) @@ -3075,6 +3096,8 @@ static int alloc_stream(struct vip_port *port, int stream_id, int vfl_type) goto do_free_hwlist; INIT_WORK(&stream->recovery_work, vip_overflow_recovery_work); + /* Start disabled; vip_start_streaming() enables it before IRQs. */ + disable_work(&stream->recovery_work); INIT_LIST_HEAD(&stream->vidq); @@ -3140,6 +3163,13 @@ static void free_stream(struct vip_stream *stream) return; dev = stream->port->dev; + /* + * Quiesce the IRQ handler and recovery worker, then drop the stream + * from cap_streams[], before releasing stream-owned resources. + */ + vip_quiesce_stream(stream); + stream->port->cap_streams[stream->stream_id] = NULL; + /* Free up the Drop queue */ list_for_each_safe(pos, q, &stream->dropq) { buf = list_entry(pos, @@ -3151,7 +3181,6 @@ static void free_stream(struct vip_stream *stream) video_unregister_device(stream->vfd); vpdma_hwlist_release(dev->shared->vpdma, stream->list_num); - stream->port->cap_streams[stream->stream_id] = NULL; kfree(stream); } diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 2e81877f640f..ad71c0402ef3 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -771,8 +771,10 @@ static int hantro_register_entity(struct media_device *mdev, return ret; ret = media_device_register_entity(mdev, entity); - if (ret) + if (ret) { + media_entity_cleanup(entity); return ret; + } return 0; } @@ -860,12 +862,13 @@ err_rm_links0: err_rel_entity2: media_device_unregister_entity(&func->sink); - + media_entity_cleanup(&func->sink); err_rel_entity1: media_device_unregister_entity(&func->proc); - + media_entity_cleanup(&func->proc); err_rel_entity0: media_device_unregister_entity(&func->vdev.entity); + media_entity_cleanup(&func->vdev.entity); return ret; } @@ -878,6 +881,9 @@ static void hantro_detach_func(struct hantro_func *func) media_device_unregister_entity(&func->sink); media_device_unregister_entity(&func->proc); media_device_unregister_entity(&func->vdev.entity); + media_entity_cleanup(&func->sink); + media_entity_cleanup(&func->proc); + media_entity_cleanup(&func->vdev.entity); } static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 5110754e1a31..53c1d1061cf4 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -527,8 +527,8 @@ static const struct v4l2_ctrl_ops cadet_ctrl_ops = { static const struct pnp_device_id cadet_pnp_devices[] = { /* ADS Cadet AM/FM Radio Card */ - {.id = "MSM0c24", .driver_data = 0}, - {.id = ""} + { .id = "MSM0c24" }, + { } }; MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 3d1d0b46195b..7e4257e4b71d 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -284,8 +284,8 @@ static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c } #ifdef CONFIG_PNP static const struct pnp_device_id gemtek_pnp_devices[] = { /* AOpen FX-3D/Pro Radio */ - {.id = "ADS7183", .driver_data = 0}, - {.id = ""} + { .id = "ADS7183" }, + { } }; MODULE_DEVICE_TABLE(pnp, gemtek_pnp_devices); diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 5055dfc3f465..c196ee923ecd 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -642,8 +642,8 @@ static void fintek_shutdown(struct pnp_dev *pdev) } static const struct pnp_device_id fintek_ids[] = { - { "FIT0002", 0 }, /* CIR */ - { "", 0 }, + { .id = "FIT0002" }, /* CIR */ + { } }; static struct pnp_driver fintek_driver = { diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index bde2a7051231..1fbafcd8219e 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1203,9 +1203,16 @@ static void ite_close(struct rc_dev *rcdev) spin_unlock_irqrestore(&dev->lock, flags); } +enum ite_model_type { + ITE8704, + ITE8713, + ITE8708, + ITE8709, +}; + /* supported models and their parameters */ static const struct ite_dev_params ite_dev_descs[] = { - { /* 0: ITE8704 */ + [ITE8704] = { .model = "ITE8704 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1224,7 +1231,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it87_init_hardware, .set_carrier_params = it87_set_carrier_params, }, - { /* 1: ITE8713 */ + [ITE8713] = { .model = "ITE8713 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1243,7 +1250,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it87_init_hardware, .set_carrier_params = it87_set_carrier_params, }, - { /* 2: ITE8708 */ + [ITE8708] = { .model = "ITE8708 CIR transceiver", .io_region_size = IT8708_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1263,7 +1270,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it8708_init_hardware, .set_carrier_params = it8708_set_carrier_params, }, - { /* 3: ITE8709 */ + [ITE8709] = { .model = "ITE8709 CIR transceiver", .io_region_size = IT8709_IOREG_LENGTH, .io_rsrc_no = 2, @@ -1286,11 +1293,11 @@ static const struct ite_dev_params ite_dev_descs[] = { }; static const struct pnp_device_id ite_ids[] = { - {"ITE8704", 0}, /* Default model */ - {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ - {"ITE8708", 2}, /* Bridged IT8512 */ - {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ - {"", 0}, + { .id = "ITE8704", .driver_data = ITE8704 }, /* Default model */ + { .id = "ITE8713", .driver_data = ITE8713 }, /* CIR found in EEEBox 1501U */ + { .id = "ITE8708", .driver_data = ITE8708 }, /* Bridged IT8512 */ + { .id = "ITE8709", .driver_data = ITE8709 }, /* SRAM-Bridged IT8512 */ + { } }; /* allocate memory, probe hardware, and initialize everything */ @@ -1301,7 +1308,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id struct ite_dev *itdev = NULL; struct rc_dev *rdev = NULL; int ret = -ENOMEM; - int model_no; + enum ite_model_type model_no; int io_rsrc_no; itdev = kzalloc_obj(struct ite_dev); @@ -1317,7 +1324,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ret = -ENODEV; /* get the model number */ - model_no = (int)dev_id->driver_data; + model_no = dev_id->driver_data; dev_dbg(&pdev->dev, "Auto-detected model: %s\n", ite_dev_descs[model_no].model); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index d04572627cdd..38b84e34b225 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -129,7 +129,7 @@ obj-$(CONFIG_RC_MAP) += \ rc-twinhan1027.o \ rc-twinhan-dtv-cab-ci.o \ rc-vega-s9x.o \ - rc-videomate-m1f.o \ + rc-videomate-k100.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ rc-videostrong-kii-pro.o \ diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-k100.c index 1f9be84ff27b..6664cfd0b7f3 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-k100.c @@ -87,4 +87,4 @@ module_exit(exit_rc_map_videomate_k100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>"); -MODULE_DESCRIPTION("videomate-m1f remote controller keytable"); +MODULE_DESCRIPTION("videomate-k100 remote controller keytable"); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 4e5a0c8dc9a0..918258dadd69 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1092,9 +1092,9 @@ static void nvt_shutdown(struct pnp_dev *pdev) } static const struct pnp_device_id nvt_ids[] = { - { "WEC0530", 0 }, /* CIR */ - { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ - { "", 0 }, + { .id = "WEC0530" }, /* CIR */ + { .id = "NTN0530" }, /* CIR for new chip's pnp id*/ + { } }; static struct pnp_driver nvt_driver = { diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index cb4c56bf0752..28e840a7e5b8 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -344,22 +344,25 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->irq = platform_get_irq(pdev, 0); if (ir->irq < 0) { ret = ir->irq; - goto exit_free_dev; + goto exit_unregister_dev; } ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir); if (ret) { dev_err(dev, "failed request irq\n"); - goto exit_free_dev; + goto exit_unregister_dev; } ret = sunxi_ir_hw_init(dev); if (ret) - goto exit_free_dev; + goto exit_unregister_dev; dev_info(dev, "initialized sunXi IR driver\n"); return 0; +exit_unregister_dev: + rc_unregister_device(ir->rc); + exit_free_dev: rc_free_device(ir->rc); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 8e804661a621..1ae036f8a296 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1179,8 +1179,8 @@ wbcir_remove(struct pnp_dev *device) } static const struct pnp_device_id wbcir_ids[] = { - { "WEC1022", 0 }, - { "", 0 } + { .id = "WEC1022" }, + { } }; MODULE_DEVICE_TABLE(pnp, wbcir_ids); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 318e8330f16a..ff9d50fb05fd 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -63,11 +63,11 @@ struct pixfmt_info { }; static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { - V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 + V4L2_PIX_FMT_FWHT, 0, 4, 1, 1, 1, 1, 1, 0, 1 }; static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { - V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 + V4L2_PIX_FMT_FWHT_STATELESS, 0, 4, 1, 1, 1, 1, 1, 0, 1 }; static void vicodec_dev_release(struct device *dev) diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index e0c6bc9f8f20..ac60c9b5418e 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -175,8 +175,8 @@ static int vimc_capture_enum_framesizes(struct file *file, void *priv, if (fsize->index) return -EINVAL; - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fsize->pixel_format); + /* Only accept pixel_format in the pix map table */ + vpix = vimc_pix_map_by_pixelformat(fsize->pixel_format); if (!vpix) return -EINVAL; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 5deebcc78a33..83dcc9d61ee0 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -92,8 +92,8 @@ static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor, tpg_s_xfer_func(&vsensor->tpg, format->xfer_func); } -static int vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, - u32 width, u32 height) +static void vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, + u32 width, u32 height) { struct vimc_sensor_device *vsensor = container_of(sd, struct vimc_sensor_device, sd); @@ -103,13 +103,15 @@ static int vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, u64 total_pixels = (u64)hts * vts; u64 frame_interval_ns; + /* Sanity check, pixel rate is fixed and fits in 32 bits. */ + if (WARN_ON(pixel_rate >= 0x100000000)) + return; + frame_interval_ns = total_pixels * NSEC_PER_SEC; - do_div(frame_interval_ns, pixel_rate); + do_div(frame_interval_ns, (u32)pixel_rate); vsensor->hw.fps_jiffies = nsecs_to_jiffies(frame_interval_ns); if (vsensor->hw.fps_jiffies == 0) vsensor->hw.fps_jiffies = 1; - - return 0; } static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 55e5e5dec2f2..ca913b808225 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -17,12 +17,8 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct vivid_dev *dev = vb2_get_drv_priv(vq); unsigned int size = sizeof(struct vivid_meta_out_buf); - if (!vivid_is_webcam(dev)) - return -EINVAL; - if (*nplanes) { if (sizes[0] < size) return -EINVAL; @@ -127,11 +123,6 @@ const struct vb2_ops vivid_meta_out_qops = { int vidioc_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - if (f->index > 0) return -EINVAL; @@ -143,12 +134,8 @@ int vidioc_enum_fmt_meta_out(struct file *file, void *priv, int vidioc_g_fmt_meta_out(struct file *file, void *priv, struct v4l2_format *f) { - struct vivid_dev *dev = video_drvdata(file); struct v4l2_meta_format *meta = &f->fmt.meta; - if (!vivid_is_webcam(dev) || !dev->has_meta_out) - return -EINVAL; - meta->dataformat = V4L2_META_FMT_VIVID; meta->buffersize = sizeof(struct vivid_meta_out_buf); return 0; @@ -159,10 +146,12 @@ void vivid_meta_out_process(struct vivid_dev *dev, { struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - v4l2_ctrl_s_ctrl(dev->brightness, meta->brightness); - v4l2_ctrl_s_ctrl(dev->contrast, meta->contrast); - v4l2_ctrl_s_ctrl(dev->saturation, meta->saturation); - v4l2_ctrl_s_ctrl(dev->hue, meta->hue); + if (dev->brightness) { + v4l2_ctrl_s_ctrl(dev->brightness, meta->brightness); + v4l2_ctrl_s_ctrl(dev->contrast, meta->contrast); + v4l2_ctrl_s_ctrl(dev->saturation, meta->saturation); + v4l2_ctrl_s_ctrl(dev->hue, meta->hue); + } dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", __func__, meta->brightness, meta->contrast, diff --git a/drivers/media/tuners/tda18250.c b/drivers/media/tuners/tda18250.c index 7bb945ba0989..bd7ed50fb6e8 100644 --- a/drivers/media/tuners/tda18250.c +++ b/drivers/media/tuners/tda18250.c @@ -440,8 +440,8 @@ static int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv, goto err; exp = (uval & 0x70) >> 4; - if (exp > 5) - exp = 0; + if (exp == 0 || exp > 5) + exp = 1; lopd = 1 << (exp - 1); scale = uval & 0x0f; fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency); diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 57edb42463e8..358a66ab8e48 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -464,14 +464,21 @@ static void airspy_disconnect(struct usb_interface *intf) dev_dbg(s->dev, "\n"); - mutex_lock(&s->vb_queue_lock); + /* + * vb2_video_unregister_device() releases the vb2 queue, which + * triggers airspy_stop_streaming() if streaming is active. + * stop_streaming() dereferences s->udev via airspy_ctrl_msg() and + * airspy_free_stream_bufs(), so it must run before s->udev is + * cleared. vb2_video_unregister_device() locks vb_queue_lock + * internally and stop_streaming() locks v4l2_lock, so neither may + * be held by the caller. + */ + v4l2_device_disconnect(&s->v4l2_dev); + vb2_video_unregister_device(&s->vdev); + mutex_lock(&s->v4l2_lock); - /* No need to keep the urbs around after disconnection */ s->udev = NULL; - v4l2_device_disconnect(&s->v4l2_dev); - video_unregister_device(&s->vdev); mutex_unlock(&s->v4l2_lock); - mutex_unlock(&s->vb_queue_lock); v4l2_device_put(&s->v4l2_dev); } diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 9929ce5dcdcd..8ab100db01ab 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -124,6 +124,17 @@ struct au0828_board au0828_boards[] = { }, }, }, + [AU0828_BOARD_MONOPRICE_106456] = { + /* + * Monoprice 106456 USB ATSC/QAM tuner (board rev TV22AD-A), + * a.k.a. AnyTV AUTV002, USB ID 05e1:0400. Same AU8522 demod + + * NXP TDA18271HDC2 tuner @ 0x60 as the Hauppauge Woodbury. + */ + .name = "Monoprice 106456 USB ATSC/QAM (TV22AD-A)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + }, [AU0828_BOARD_HAUPPAUGE_HVR1265] = { .name = "Hauppauge HVR1265", .tuner_type = TUNER_XC5000, @@ -294,6 +305,7 @@ void au0828_gpio_setup(struct au0828_dev *dev) case AU0828_BOARD_HAUPPAUGE_WOODBURY: case AU0828_BOARD_HAUPPAUGE_HVR1265: case AU0828_BOARD_HAUPPAUGE_IMPACTVCBE: + case AU0828_BOARD_MONOPRICE_106456: /* GPIO's * 4 - CS5340 * 5 - AU8522 Demodulator @@ -378,6 +390,8 @@ struct usb_device_id au0828_usb_id_table[] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x05e1, 0x0480), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { USB_DEVICE(0x05e1, 0x0400), + .driver_info = AU0828_BOARD_MONOPRICE_106456 }, { USB_DEVICE(0x2040, 0x8200), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, { USB_DEVICE(0x2040, 0x7260), diff --git a/drivers/media/usb/au0828/au0828-cards.h b/drivers/media/usb/au0828/au0828-cards.h index a438aeb334a0..a4a283731f7d 100644 --- a/drivers/media/usb/au0828/au0828-cards.h +++ b/drivers/media/usb/au0828/au0828-cards.h @@ -13,3 +13,4 @@ #define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 #define AU0828_BOARD_HAUPPAUGE_IMPACTVCBE 6 #define AU0828_BOARD_HAUPPAUGE_HVR1265 7 +#define AU0828_BOARD_MONOPRICE_106456 8 diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 31123e6f9fc3..9c95b7ceaecd 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -600,6 +600,7 @@ int au0828_dvb_register(struct au0828_dev *dev) &mxl5007t_hvr950q_config); break; case AU0828_BOARD_HAUPPAUGE_WOODBURY: + case AU0828_BOARD_MONOPRICE_106456: dvb->frontend = dvb_attach(au8522_attach, &hauppauge_woodbury_config, &dev->i2c_adap); diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 9c71b32552df..b24ceef497e4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -443,6 +443,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) int ret; struct cx231xx *dev = snd_pcm_substream_chip(substream); + if (!dev) { + pr_err("cx231xx: called with null device\n"); + return -ENODEV; + } + dev_dbg(dev->dev, "closing device\n"); /* inform hardware to stop streaming */ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2cd4e333bc4b..70aa99fead27 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -898,7 +898,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (rc) return rc; - if (vb2_is_busy(&dev->vidq)) { + if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq)) { dev_err(dev->dev, "%s: queue busy\n", __func__); return -EBUSY; } @@ -933,7 +933,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) if (dev->norm == norm) return 0; - if (vb2_is_busy(&dev->vidq)) + if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq)) return -EBUSY; dev->norm = norm; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 870ac3c8b085..6404eb74db32 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -987,11 +987,7 @@ static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) if (ret < 0) return ret; - ret = mxl111sf_lg2160_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; + return mxl111sf_lg2160_frontend_attach(adap, 2); } static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) @@ -1007,11 +1003,7 @@ static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) if (ret < 0) return ret; - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; + return mxl111sf_lg2161_ep6_frontend_attach(adap, 2); } static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index fbfb74eab475..b7c534fc8a21 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2677,6 +2677,28 @@ const struct em28xx_board em28xx_boards[] = { .gpio = mygica_utv3_tuner_audio_gpio, } }, }, + /* eb1a:8286 StarTech SVID2USB232 + * Empia EM28281 with integrated TVP5150-compatible video decoder. + * Composite and S-Video inputs, stereo line-in audio. + */ + [EM28281_BOARD_STARTECH_SVID2USB232] = { + .name = "StarTech SVID2USB232", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .has_dvb = 0, + .decoder = EM28XX_BUILTIN, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE, + .vmux = EM2828X_COMPOSITE, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = EM2828X_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, [EM2828X_BOARD_HAUPPAUGE_USB_LIVE2] = { .name = "Hauppauge USB Live2", .vchannels = 2, @@ -2946,6 +2968,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, { USB_DEVICE(0x2040, 0xc220), .driver_info = EM2828X_BOARD_HAUPPAUGE_USB_LIVE2 }, + { USB_DEVICE(0xeb1a, 0x8286), + .driver_info = EM28281_BOARD_STARTECH_SVID2USB232 }, { USB_DEVICE(0x2040, 0x0360), .driver_info = EM2828X_BOARD_HAUPPAUGE_935_V2 }, { USB_DEVICE(0x2040, 0x8360), @@ -3651,6 +3675,7 @@ static void request_module_async(struct work_struct *work) * intf. Don't register extensions twice on those devices. */ if (dev->is_audio_only) { + em28xx_init_extension(dev); #if defined(CONFIG_MODULES) && defined(MODULE) request_module("em28xx-alsa"); #endif @@ -3758,7 +3783,7 @@ void em28xx_free_device(struct kref *ref) { struct em28xx *dev = kref_to_dev(ref); - dev_info(&dev->intf->dev, "Freeing device\n"); + pr_info("%s: Freeing device\n", dev->name); if (!dev->disconnected) em28xx_release_resources(dev); @@ -3859,6 +3884,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev->wait_after_write = 0; dev->eeprom_addrwidth_16bit = 1; break; + case CHIP_ID_EM28281: + chip_name = "em28281"; + dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; + break; case CHIP_ID_EM2883: chip_name = "em2882/3"; dev->wait_after_write = 0; @@ -3884,8 +3914,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = -ENODEV; goto err_deinit_media; } - em28xx_init_extension(dev); - return 0; } @@ -4082,7 +4110,7 @@ static void em28xx_check_usb_descriptor(struct em28xx *dev, dev->analog_ep_bulk = e->bEndpointAddress; } return; - }; + } } /* diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 5bbb082dbed9..0b998e7cafef 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -632,7 +632,7 @@ void em2828X_decoder_vmux(struct em28xx *dev, unsigned int vin) default: dev_dbg(&dev->intf->dev, "EM2828X_SVIDEO\n"); break; - }; + } em28xx_write_reg(dev, 0x24, 0x00); em28xx_write_reg(dev, 0x25, 0x02); @@ -1265,6 +1265,8 @@ void em28xx_close_extension(struct em28xx *dev) ops->fini(dev); } } + if (dev->dev_next) + list_del(&dev->dev_next->devlist); list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); } diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 938f1980d448..8482fc4045ea 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -29,7 +29,7 @@ #include <media/dmxdev.h> #include <media/tuner.h> #include "tuner-simple.h" -#include <linux/gpio.h> +#include <linux/gpio/legacy.h> #include "lgdt330x.h" #include "lgdt3305.h" diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 68a0fcc2fa72..8931733a8e24 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -283,6 +283,7 @@ enum em28xx_chip_id { CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, CHIP_ID_EM28178 = 114, + CHIP_ID_EM28281 = 145, CHIP_ID_EM2828X = 148, }; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index da0422c65e5f..c418add65bb5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1213,6 +1213,9 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) { struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct em28xx_dmaqueue *dmaq = vq->type == V4L2_BUF_TYPE_VBI_CAPTURE ? + &dev->vbiq : &dev->vidq; + unsigned long flags = 0; struct v4l2_frequency f; struct v4l2_fh *owner; int rc = 0; @@ -1227,7 +1230,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) */ rc = res_get(dev, vq->type); if (rc) - return rc; + goto exit; if (v4l2->streaming_users == 0) { /* First active streaming user, so allocate all the URBs */ @@ -1250,7 +1253,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) em28xx_urb_data_copy); if (rc < 0) { res_free(dev, vq->type); - return rc; + goto exit; } /* @@ -1275,7 +1278,18 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) } v4l2->streaming_users++; + return 0; + +exit: + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct em28xx_buffer *buf; + buf = list_entry(dmaq->active.next, struct em28xx_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&dev->slock, flags); return rc; } @@ -2275,18 +2289,27 @@ static int radio_s_tuner(struct file *file, void *priv, } /* - * em28xx_free_v4l2() - Free struct em28xx_v4l2 + * em28xx_free_v4l2() - v4l2_device release callback * - * @ref: struct kref for struct em28xx_v4l2 + * @v4l2_dev: pointer to struct v4l2_device embedded in struct em28xx_v4l2 * - * Called when all users of struct em28xx_v4l2 are gone + * Called by the v4l2 core when the last reference to the v4l2_device is + * released. At this point no userspace file handle nor video_device node + * keeps the v4l2 instance alive anymore, so it is safe to release all + * v4l2-related resources and drop the em28xx device reference taken when + * the v4l2 extension was initialized. */ -static void em28xx_free_v4l2(struct kref *ref) +static void em28xx_free_v4l2(struct v4l2_device *v4l2_dev) { - struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref); + struct em28xx_v4l2 *v4l2 = + container_of(v4l2_dev, struct em28xx_v4l2, v4l2_dev); + struct em28xx *dev = v4l2->dev; - v4l2->dev->v4l2 = NULL; + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + dev->v4l2 = NULL; kfree(v4l2); + kref_put(&dev->ref, em28xx_free_device); } /* @@ -2323,9 +2346,8 @@ static int em28xx_v4l2_open(struct file *filp) return -ENODEV; } - em28xx_videodbg("open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[fh_type], - v4l2->users); + em28xx_videodbg("open dev=%s type=%s\n", + video_device_node_name(vdev), v4l2_type_names[fh_type]); ret = v4l2_fh_open(filp); if (ret) { @@ -2336,7 +2358,7 @@ static int em28xx_v4l2_open(struct file *filp) return ret; } - if (v4l2->users == 0) { + if (v4l2_fh_is_singular_file(filp)) { em28xx_set_mode(dev, EM28XX_ANALOG_MODE); if (vdev->vfl_type != VFL_TYPE_RADIO) @@ -2354,10 +2376,6 @@ static int em28xx_v4l2_open(struct file *filp) v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio); } - kref_get(&dev->ref); - kref_get(&v4l2->ref); - v4l2->users++; - mutex_unlock(&dev->lock); return 0; @@ -2398,27 +2416,27 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (video_is_registered(&v4l2->radio_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); - video_unregister_device(&v4l2->radio_dev); + vb2_video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); - video_unregister_device(&v4l2->vbi_dev); + vb2_video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); - video_unregister_device(&v4l2->vdev); + vb2_video_unregister_device(&v4l2->vdev); } - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - v4l2_device_unregister(&v4l2->v4l2_dev); - - kref_put(&v4l2->ref, em28xx_free_v4l2); - mutex_unlock(&dev->lock); - kref_put(&dev->ref, em28xx_free_device); + /* + * Drop the initial reference taken at v4l2_device_register() time. + * The em28xx_free_v4l2() release callback will be invoked once all + * userspace file handles to the video device nodes are closed. + */ + v4l2_device_put(&v4l2->v4l2_dev); return 0; } @@ -2460,13 +2478,13 @@ static int em28xx_v4l2_close(struct file *filp) struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); int err; + bool last_user; - em28xx_videodbg("users=%d\n", v4l2->users); - - vb2_fop_release(filp); mutex_lock(&dev->lock); + last_user = v4l2_fh_is_singular_file(filp); + _vb2_fop_release(filp, NULL); - if (v4l2->users == 1) { + if (last_user) { /* No sense to try to write to the device */ if (dev->disconnected) goto exit; @@ -2489,10 +2507,7 @@ static int em28xx_v4l2_close(struct file *filp) } exit: - v4l2->users--; - kref_put(&v4l2->ref, em28xx_free_v4l2); mutex_unlock(&dev->lock); - kref_put(&dev->ref, em28xx_free_device); return 0; } @@ -2711,7 +2726,6 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_unlock(&dev->lock); return -ENOMEM; } - kref_init(&v4l2->ref); v4l2->dev = dev; dev->v4l2 = v4l2; @@ -2722,9 +2736,21 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (ret < 0) { dev_err(&dev->intf->dev, "Call to v4l2_device_register() failed!\n"); - goto err; + dev->v4l2 = NULL; + kfree(v4l2); + mutex_unlock(&dev->lock); + return ret; } + /* + * From this point on, em28xx_free_v4l2() will be used to release + * v4l2-related resources when the v4l2_device refcount reaches + * zero. Take a reference to the em28xx device so that it cannot + * be freed before the v4l2 instance is released. + */ + v4l2->v4l2_dev.release = em28xx_free_v4l2; + kref_get(&dev->ref); + hdl = &v4l2->ctrl_handler; v4l2_ctrl_handler_init(hdl, 9); v4l2->v4l2_dev.ctrl_handler = hdl; @@ -3048,8 +3074,6 @@ static int em28xx_v4l2_init(struct em28xx *dev) dev_info(&dev->intf->dev, "V4L2 extension successfully initialized\n"); - kref_get(&dev->ref); - mutex_unlock(&dev->lock); return 0; @@ -3058,27 +3082,29 @@ unregister_dev: dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); - video_unregister_device(&v4l2->radio_dev); + vb2_video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); - video_unregister_device(&v4l2->vbi_dev); + vb2_video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); - video_unregister_device(&v4l2->vdev); + vb2_video_unregister_device(&v4l2->vdev); } - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - v4l2_device_unregister(&v4l2->v4l2_dev); -err: - dev->v4l2 = NULL; - kref_put(&v4l2->ref, em28xx_free_v4l2); mutex_unlock(&dev->lock); + + /* + * Drop the initial reference. em28xx_free_v4l2() will be called + * once the last video_device node release has decremented the + * v4l2_device refcount to zero. + */ + v4l2_device_put(&v4l2->v4l2_dev); return ret; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 711f281613f5..8eee639b0940 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -150,6 +150,7 @@ #define EM2828X_BOARD_HAUPPAUGE_955_V2 110 #define EM2828X_BOARD_HAUPPAUGE_975_V2 111 #define EM28178_BOARD_PCTV_461E_V3 112 +#define EM28281_BOARD_STARTECH_SVID2USB232 113 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -558,7 +559,6 @@ struct em28xx_eeprom { #define EM28XX_RESOURCE_VBI 0x02 struct em28xx_v4l2 { - struct kref ref; struct em28xx *dev; struct v4l2_device v4l2_dev; @@ -582,7 +582,6 @@ struct em28xx_v4l2 { int sensor_yres; int sensor_xtal; - int users; /* user count for exclusive use */ int streaming_users; /* number of actively streaming users */ u32 frequency; /* selected tuner frequency */ diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 25b3ee25aaa4..453ab5c3aa03 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -264,17 +264,17 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) ret = go7007_init_encoder(go); mutex_unlock(&go->hw_lock); if (ret < 0) - return ret; + goto err_unregister_v4l2_dev; ret = go7007_v4l2_ctrl_init(go); if (ret < 0) - return ret; + goto err_free_controls; if (!go->i2c_adapter_online && go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { ret = go7007_i2c_init(go); if (ret < 0) - return ret; + goto err_free_controls; go->i2c_adapter_online = 1; } if (go->i2c_adapter_online) { @@ -304,13 +304,19 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) ret = go7007_v4l2_init(go); if (ret < 0) - return ret; + goto err_free_controls; if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { go->audio_enabled = 1; go7007_snd_init(go); } return 0; + +err_free_controls: + v4l2_ctrl_handler_free(&go->hdl); +err_unregister_v4l2_dev: + v4l2_device_unregister(&go->v4l2_dev); + return ret; } EXPORT_SYMBOL(go7007_register_encoder); diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 86ce593e0c54..8cf959c20e30 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -13,6 +13,7 @@ */ #include <linux/module.h> +#include <linux/bitops.h> #include <linux/time.h> #include <linux/mm.h> #include <linux/device.h> @@ -58,14 +59,16 @@ struct code_gen { #define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 } #define CODE_ADD(name, val, length) do { \ - name.b -= (length); \ - name.a |= (val) << name.b; \ - while (name.b <= 24) { \ - *name.p = name.a >> 24; \ - ++name.p; \ - name.a <<= 8; \ - name.b += 8; \ - name.len += 8; \ + if (length) { \ + name.b -= (length); \ + name.a |= (val) << name.b; \ + while (name.b <= 24) { \ + *name.p = name.a >> 24; \ + ++name.p; \ + name.a <<= 8; \ + name.b += 8; \ + name.len += 8; \ + } \ } \ } while (0) @@ -707,11 +710,10 @@ done: static int vti_bitlen(struct go7007 *go) { - unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale; + unsigned int max_time_incr = go->sensor_framerate / go->fps_scale; + int bitlen = fls(max_time_incr); - for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i) - ; - return i + 1; + return bitlen ?: 1; } static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf, @@ -1209,7 +1211,7 @@ static int seqhead_to_package(struct go7007 *go, __le16 *code, int space, 0xbf08, fps, 0xbf09, 0, 0xbff2, vop_time_increment_bitlength, - 0xbff3, (1 << vop_time_increment_bitlength) - 1, + 0xbff3, GENMASK(vop_time_increment_bitlength - 1, 0), 0xbfe6, 0, 0xbfe7, (fps / 1000) << 8, 0, 0, diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 0901d79e827d..d11f8e723624 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -365,36 +365,48 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl) struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl); struct i2c_client *client = v4l2_get_subdevdata(&state->sd); u16 oldvalue; + int ret; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, - ctrl->val | (oldvalue & ~0xff)); - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, - ctrl->val | (oldvalue & ~0xff)); - write_reg_fp(client, 0x140, 0x60); - break; + ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, + ctrl->val | (oldvalue & ~0xff)); + if (ret) + return ret; + ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, + ctrl->val | (oldvalue & ~0xff)); + if (ret) + return ret; + return write_reg_fp(client, 0x140, 0x60); case V4L2_CID_CONTRAST: - read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST0, - ctrl->val | (oldvalue & ~0x3f)); - read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST1, - ctrl->val | (oldvalue & ~0x3f)); - write_reg_fp(client, 0x140, 0x60); - break; + ret = read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_CONTRAST0, + ctrl->val | (oldvalue & ~0x3f)); + if (ret) + return ret; + ret = read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_CONTRAST1, + ctrl->val | (oldvalue & ~0x3f)); + if (ret) + return ret; + return write_reg_fp(client, 0x140, 0x60); case V4L2_CID_SATURATION: - write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val); - break; + return write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val); case V4L2_CID_HUE: - write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val); - break; + return write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val); default: return -EINVAL; } - return 0; } static int s2250_set_fmt(struct v4l2_subdev *sd, diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index e4b9f37be77b..01d547ad678d 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -195,6 +195,13 @@ static const struct snd_device_ops go7007_snd_device_ops = { .dev_free = go7007_snd_free, }; +static void go7007_snd_card_free(struct snd_card *card) +{ + struct go7007 *go = card->private_data; + + v4l2_device_put(&go->v4l2_dev); +} + int go7007_snd_init(struct go7007 *go) { static int dev; @@ -245,6 +252,8 @@ int go7007_snd_init(struct go7007 *go) gosnd->substream = NULL; go->snd_context = gosnd; v4l2_device_get(&go->v4l2_dev); + gosnd->card->private_data = go; + gosnd->card->private_free = go7007_snd_card_free; ++dev; return 0; @@ -263,7 +272,6 @@ int go7007_snd_remove(struct go7007 *go) snd_card_disconnect(gosnd->card); snd_card_free_when_closed(gosnd->card); - v4l2_device_put(&go->v4l2_dev); return 0; } EXPORT_SYMBOL(go7007_snd_remove); diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c index a408fcc3a060..4988fbf5005e 100644 --- a/drivers/media/usb/gspca/jl2005bcd.c +++ b/drivers/media/usb/gspca/jl2005bcd.c @@ -148,17 +148,12 @@ static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, unsigned char value) { - int retval; u8 instruction[2]; instruction[0] = reg; instruction[1] = value; - retval = jl2005c_write2(gspca_dev, instruction); - if (retval < 0) - return retval; - - return retval; + return jl2005c_write2(gspca_dev, instruction); } static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 0b8182edf8e4..15012d73975c 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -69,7 +69,7 @@ #define MAX_CHANNELS 4 #define SYS_FRAMES 4 /* maximum size is PAL full size plus room for the marker header(s) */ -#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) +#define SYS_FRAMES_MAXSIZE (720 * 288 * 2 * 2 + 4096) #define DEF_USB_BLOCK S2255_USB_XFER_SIZE #define LINE_SZ_4CIFS_NTSC 640 #define LINE_SZ_2CIFS_NTSC 640 @@ -86,7 +86,6 @@ #define LINE_SZ_DEF 640 #define NUM_LINES_DEF 240 - /* predefined settings */ #define FORMAT_NTSC 1 #define FORMAT_PAL 2 @@ -111,9 +110,9 @@ #define FDEC_3 3 /* capture every 3rd frame */ #define FDEC_5 5 /* capture every 5th frame */ -/*------------------------------------------------------- - * Default mode parameters. - *-------------------------------------------------------*/ +/*-------------------------------------------------------*/ +/* Default mode parameters. */ +/*-------------------------------------------------------*/ #define DEF_SCALE SCALE_4CIFS #define DEF_COLOR COLOR_YUVPL #define DEF_FDEC FDEC_1 @@ -144,21 +143,20 @@ struct s2255_mode { u32 restart; /* if DSP requires restart */ }; - #define S2255_READ_IDLE 0 #define S2255_READ_FRAME 1 /* frame structure */ struct s2255_framei { unsigned long size; - unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ + unsigned long state; /* state:S2255_READ_IDLE, S2255_READ_FRAME*/ void *lpvbits; /* image data */ unsigned long cur_size; /* current data copied to it */ }; /* image buffer structure */ struct s2255_bufferi { - unsigned long dwFrames; /* number of frames in buffer */ + unsigned long num_frames; /* number of frames in buffer */ struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ }; @@ -212,7 +210,7 @@ struct s2255_vc { struct s2255_mode mode; v4l2_std_id std; /* jpeg compression */ - unsigned jpegqual; + unsigned int jpegqual; /* capture parameters (for high quality mode full size) */ struct v4l2_captureparm cap_parm; int cur_frame; @@ -243,7 +241,6 @@ struct s2255_vc { spinlock_t qlock; }; - struct s2255_dev { struct s2255_vc vc[MAX_CHANNELS]; struct v4l2_device v4l2_dev; @@ -284,7 +281,6 @@ struct s2255_buffer { struct list_head list; }; - /* current cypress EEPROM firmware version */ #define S2255_CUR_USB_FWVER ((3 << 8) | 12) /* current DSP FW version */ @@ -343,8 +339,8 @@ static int s2255_board_shutdown(struct s2255_dev *dev); static void s2255_fwload_start(struct s2255_dev *dev); static void s2255_destroy(struct s2255_dev *dev); static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, - u16 index, u16 value, void *buf, - s32 buf_len, int bOut); + u16 index, u16 value, void *xfer_buf, + s32 xfer_buf_len, int is_out); /* dev_err macro with driver name */ #define S2255_DRIVER_NAME "s2255" @@ -352,7 +348,7 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) #define dprintk(dev, level, fmt, arg...) \ - v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) + v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ## arg) static struct usb_driver s2255_driver; @@ -430,7 +426,6 @@ static int norm_minh(struct s2255_vc *vc) (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); } - /* * TODO: fixme: move YUV reordering to hardware * converts 2255 planar format to yuyv or uyvy @@ -440,21 +435,21 @@ static void planar422p_to_yuv_packed(const unsigned char *in, int width, int height, int fmt) { - unsigned char *pY; - unsigned char *pCb; - unsigned char *pCr; + unsigned char *p_y; + unsigned char *p_cb; + unsigned char *p_cr; unsigned long size = height * width; unsigned int i; - pY = (unsigned char *)in; - pCr = (unsigned char *)in + height * width; - pCb = (unsigned char *)in + height * width + (height * width / 2); + + p_y = (unsigned char *)in; + p_cr = (unsigned char *)in + height * width; + p_cb = (unsigned char *)in + height * width + (height * width / 2); for (i = 0; i < size * 2; i += 4) { - out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; - out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; - out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; - out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; + out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_y++ : *p_cr++; + out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_cr++ : *p_y++; + out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_y++ : *p_cb++; + out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_cb++ : *p_y++; } - return; } static void s2255_reset_dsppower(struct s2255_dev *dev) @@ -464,7 +459,6 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); msleep(600); s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); - return; } /* kickstarts the firmware loading. from probe @@ -473,6 +467,7 @@ static void s2255_timer(struct timer_list *t) { struct s2255_dev *dev = timer_container_of(dev, t, timer); struct s2255_fw *data = dev->fw_data; + if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { pr_err("s2255: can't submit urb\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -482,18 +477,18 @@ static void s2255_timer(struct timer_list *t) } } - /* this loads the firmware asynchronously. - Originally this was done synchronously in probe. - But it is better to load it asynchronously here than block - inside the probe function. Blocking inside probe affects boot time. - FW loading is triggered by the timer in the probe function -*/ + * Originally this was done synchronously in probe. + * But it is better to load it asynchronously here than block + * inside the probe function. Blocking inside probe affects boot time. + * FW loading is triggered by the timer in the probe function + */ static void s2255_fwchunk_complete(struct urb *urb) { struct s2255_fw *data = urb->context; struct usb_device *udev = urb->dev; int len; + if (urb->status) { dev_err(&udev->dev, "URB failed with status %d\n", urb->status); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -501,7 +496,7 @@ static void s2255_fwchunk_complete(struct urb *urb) wake_up(&data->wait_fw); return; } - if (data->fw_urb == NULL) { + if (!data->fw_urb) { s2255_dev_err(&udev->dev, "disconnected\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); /* wake up anything waiting for the firmware */ @@ -510,8 +505,8 @@ static void s2255_fwchunk_complete(struct urb *urb) } #define CHUNK_SIZE 512 /* all USB transfers must be done with continuous kernel memory. - can't allocate more than 128k in current linux kernel, so - upload the firmware in chunks + * can't allocate more than 128k in current linux kernel, so + * upload the firmware in chunks */ if (data->fw_loaded < data->fw_size) { len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? @@ -521,7 +516,7 @@ static void s2255_fwchunk_complete(struct urb *urb) memset(data->pfw_data, 0, CHUNK_SIZE); memcpy(data->pfw_data, - (char *) data->fw->data + data->fw_loaded, len); + (char *)data->fw->data + data->fw_loaded, len); usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), data->pfw_data, CHUNK_SIZE, @@ -534,10 +529,9 @@ static void s2255_fwchunk_complete(struct urb *urb) return; } data->fw_loaded += len; - } else + } else { atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - return; - + } } static void s2255_got_frame(struct s2255_vc *vc, int jpgsize) @@ -569,11 +563,12 @@ static void s2255_got_frame(struct s2255_vc *vc, int jpgsize) static const struct s2255_fmt *format_by_fourcc(int fourcc) { unsigned int i; + for (i = 0; i < ARRAY_SIZE(formats); i++) { if (-1 == formats[i].fourcc) continue; - if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) + if (!jpeg_enable && (formats[i].fourcc == V4L2_PIX_FMT_JPEG || + formats[i].fourcc == V4L2_PIX_FMT_MJPEG)) continue; if (formats[i].fourcc == fourcc) return formats + i; @@ -617,6 +612,12 @@ static void s2255_fillbuff(struct s2255_vc *vc, break; case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_MJPEG: + if (jpgsize < 0 || + jpgsize > vb2_plane_size(&buf->vb.vb2_buf, 0)) { + dprintk(dev, 1, "bad JPEG frame size %d\n", + jpgsize); + break; + } vb2_set_plane_payload(&buf->vb.vb2_buf, 0, jpgsize); memcpy(vbuf, tmpbuf, jpgsize); break; @@ -636,16 +637,16 @@ static void s2255_fillbuff(struct s2255_vc *vc, vbuf, pos); } - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ +/* ------------------------------------------------------------------ */ +/* Videobuf operations */ +/* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct s2255_vc *vc = vb2_get_drv_priv(vq); + if (*nbuffers < S2255_MIN_BUFS) *nbuffers = S2255_MIN_BUFS; *nplanes = 1; @@ -662,14 +663,13 @@ static int buffer_prepare(struct vb2_buffer *vb) int h = vc->height; unsigned long size; - dprintk(vc->dev, 4, "%s\n", __func__); - if (vc->fmt == NULL) + if (!vc->fmt) return -EINVAL; - if ((w < norm_minw(vc)) || - (w > norm_maxw(vc)) || - (h < norm_minh(vc)) || - (h > norm_maxh(vc))) { + if (w < norm_minw(vc) || + w > norm_maxw(vc) || + h < norm_minh(vc) || + h > norm_maxh(vc)) { dprintk(vc->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } @@ -689,7 +689,7 @@ static void buffer_queue(struct vb2_buffer *vb) struct s2255_buffer *buf = container_of(vbuf, struct s2255_buffer, vb); struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); unsigned long flags = 0; - dprintk(vc->dev, 1, "%s\n", __func__); + spin_lock_irqsave(&vc->qlock, flags); list_add_tail(&buf->list, &vc->buf_list); spin_unlock_irqrestore(&vc->qlock, flags); @@ -719,21 +719,21 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { int index = f->index; if (index >= ARRAY_SIZE(formats)) return -EINVAL; - if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) + if (!jpeg_enable && (formats[index].fourcc == V4L2_PIX_FMT_JPEG || + formats[index].fourcc == V4L2_PIX_FMT_MJPEG)) return -EINVAL; f->pixelformat = formats[index].fourcc; return 0; } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct s2255_vc *vc = video_drvdata(file); int is_ntsc = vc->std & V4L2_STD_525_60; @@ -753,7 +753,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { const struct s2255_fmt *fmt; enum v4l2_field field; @@ -762,7 +762,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (fmt == NULL) + if (!fmt) return -EINVAL; dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n", @@ -804,7 +804,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; @@ -819,7 +819,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (fmt == NULL) + if (!fmt) return -EINVAL; if (vb2_is_busy(q)) { @@ -839,8 +839,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, mode.scale = SCALE_4CIFSI; else mode.scale = SCALE_4CIFS; - } else + } else { mode.scale = SCALE_2CIFS; + } } else { mode.scale = SCALE_1CIFS; @@ -875,11 +876,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, else if (mode.format != vc->mode.format) mode.restart = 1; vc->mode = mode; - (void) s2255_set_mode(vc, &mode); + (void)s2255_set_mode(vc, &mode); return 0; } - /* write to the configuration pipe, synchronously */ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, int size) @@ -887,6 +887,7 @@ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, int pipe; int done; long retval = -1; + if (udev) { pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); @@ -896,29 +897,29 @@ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, static u32 get_transfer_size(struct s2255_mode *mode) { - int linesPerFrame = LINE_SZ_DEF; - int pixelsPerLine = NUM_LINES_DEF; - u32 outImageSize; - u32 usbInSize; + int lines_per_frame = LINE_SZ_DEF; + int pixels_per_line = NUM_LINES_DEF; + u32 out_image_size; + u32 usb_in_size; unsigned int mask_mult; - if (mode == NULL) + if (!mode) return 0; if (mode->format == FORMAT_NTSC) { switch (mode->scale) { case SCALE_4CIFS: case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; - pixelsPerLine = LINE_SZ_4CIFS_NTSC; + lines_per_frame = NUM_LINES_4CIFS_NTSC * 2; + pixels_per_line = LINE_SZ_4CIFS_NTSC; break; case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_NTSC; - pixelsPerLine = LINE_SZ_2CIFS_NTSC; + lines_per_frame = NUM_LINES_2CIFS_NTSC; + pixels_per_line = LINE_SZ_2CIFS_NTSC; break; case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_NTSC; - pixelsPerLine = LINE_SZ_1CIFS_NTSC; + lines_per_frame = NUM_LINES_1CIFS_NTSC; + pixels_per_line = LINE_SZ_1CIFS_NTSC; break; default: break; @@ -927,40 +928,42 @@ static u32 get_transfer_size(struct s2255_mode *mode) switch (mode->scale) { case SCALE_4CIFS: case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_PAL * 2; - pixelsPerLine = LINE_SZ_4CIFS_PAL; + lines_per_frame = NUM_LINES_4CIFS_PAL * 2; + pixels_per_line = LINE_SZ_4CIFS_PAL; break; case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_PAL; - pixelsPerLine = LINE_SZ_2CIFS_PAL; + lines_per_frame = NUM_LINES_2CIFS_PAL; + pixels_per_line = LINE_SZ_2CIFS_PAL; break; case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_PAL; - pixelsPerLine = LINE_SZ_1CIFS_PAL; + lines_per_frame = NUM_LINES_1CIFS_PAL; + pixels_per_line = LINE_SZ_1CIFS_PAL; break; default: break; } } - outImageSize = linesPerFrame * pixelsPerLine; + out_image_size = lines_per_frame * pixels_per_line; if ((mode->color & MASK_COLOR) != COLOR_Y8) { /* 2 bytes/pixel if not monochrome */ - outImageSize *= 2; + out_image_size *= 2; } /* total bytes to send including prefix and 4K padding; - must be a multiple of USB_READ_SIZE */ - usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ + * must be a multiple of USB_READ_SIZE + */ + usb_in_size = out_image_size + PREFIX_SIZE; /* always send prefix */ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; /* if size not a multiple of USB_READ_SIZE */ - if (usbInSize & ~mask_mult) - usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); - return usbInSize; + if (usb_in_size & ~mask_mult) + usb_in_size = (usb_in_size & mask_mult) + (DEF_USB_BLOCK); + return usb_in_size; } static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) { struct device *dev = &sdev->udev->dev; + dev_info(dev, "------------------------------------------------\n"); dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale); dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color); @@ -1001,7 +1004,7 @@ static int s2255_set_mode(struct s2255_vc *vc, dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size); /* set the mode */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_SET_MODE; for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++) buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]); @@ -1038,7 +1041,7 @@ static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus) dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx); /* form the get vid status command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_STATUS; *pstatus = 0; vc->vidstatus_ready = 0; @@ -1066,7 +1069,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) vc->cur_frame = 0; vc->frame_count = 0; for (j = 0; j < SYS_FRAMES; j++) { - vc->buffer.frame[j].ulState = S2255_READ_IDLE; + vc->buffer.frame[j].state = S2255_READ_IDLE; vc->buffer.frame[j].cur_size = 0; } return s2255_start_acquire(vc); @@ -1078,7 +1081,7 @@ static void stop_streaming(struct vb2_queue *vq) struct s2255_vc *vc = vb2_get_drv_priv(vq); struct s2255_buffer *buf, *node; unsigned long flags; - (void) s2255_stop_acquire(vc); + (void)s2255_stop_acquire(vc); spin_lock_irqsave(&vc->qlock, flags); list_for_each_entry_safe(buf, node, &vc->buf_list, list) { list_del(&buf->list); @@ -1122,8 +1125,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) vc->width = LINE_SZ_4CIFS_PAL; vc->height = NUM_LINES_4CIFS_PAL * 2; } - } else + } else { return -EINVAL; + } vc->std = i; if (mode.restart) s2255_set_mode(vc, &mode); @@ -1139,12 +1143,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) } /* Sensoray 2255 is a multiple channel capture device. - It does not have a "crossbar" of inputs. - We use one V4L device per channel. The user must - be aware that certain combinations are not allowed. - For instance, you cannot do full FPS on more than 2 channels(2 videodevs) - at once in color(you can do full fps on 4 channels with greyscale. -*/ + * It does not have a "crossbar" of inputs. + * We use one V4L device per channel. The user must + * be aware that certain combinations are not allowed. + * For instance, you cannot do full FPS on more than 2 channels(2 videodevs) + * at once in color(you can do full fps on 4 channels with greyscale. + */ static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { @@ -1159,6 +1163,7 @@ static int vidioc_enum_input(struct file *file, void *priv, inp->status = 0; if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { int rc; + rc = s2255_cmd_status(vc, &status); dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n", rc, status); @@ -1184,6 +1189,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) *i = 0; return 0; } + static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { if (i > 0) @@ -1196,6 +1202,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) struct s2255_vc *vc = container_of(ctrl->handler, struct s2255_vc, hdl); struct s2255_mode mode; + mode = vc->mode; /* update the mode to the corresponding value */ switch (ctrl->id) { @@ -1223,15 +1230,15 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) } mode.restart = 0; /* set mode here. Note: stream does not need restarted. - some V4L programs restart stream unnecessarily - after a s_crtl. - */ + * some V4L programs restart stream unnecessarily + * after a s_crtl. + */ s2255_set_mode(vc, &mode); return 0; } static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jc) + struct v4l2_jpegcompression *jc) { struct s2255_vc *vc = video_drvdata(file); @@ -1242,7 +1249,7 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, } static int vidioc_s_jpegcomp(struct file *file, void *priv, - const struct v4l2_jpegcompression *jc) + const struct v4l2_jpegcompression *jc) { struct s2255_vc *vc = video_drvdata(file); @@ -1297,20 +1304,21 @@ static int vidioc_s_parm(struct file *file, void *priv, struct s2255_mode mode; int fdec = FDEC_1; __u32 def_num, def_dem; + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; mode = vc->mode; /* high quality capture mode requires a stream restart */ - if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode) - && vb2_is_streaming(&vc->vb_vidq)) + if (vc->cap_parm.capturemode != sp->parm.capture.capturemode && + vb2_is_streaming(&vc->vb_vidq)) return -EBUSY; def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; - if (def_dem != sp->parm.capture.timeperframe.denominator) + if (def_dem != sp->parm.capture.timeperframe.denominator) { sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= def_num) + } else if (sp->parm.capture.timeperframe.numerator <= def_num) { sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { + } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { sp->parm.capture.timeperframe.numerator = def_num * 2; fdec = FDEC_2; } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) { @@ -1338,6 +1346,7 @@ static const struct v4l2_frmsize_discrete ntsc_sizes[] = { { 640, 240 }, { 320, 240 }, }; + static const struct v4l2_frmsize_discrete pal_sizes[] = { { 704, 576 }, { 704, 288 }, @@ -1345,7 +1354,7 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = { }; static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fe) + struct v4l2_frmsizeenum *fe) { struct s2255_vc *vc = video_drvdata(file); int is_ntsc = vc->std & V4L2_STD_525_60; @@ -1355,7 +1364,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; fmt = format_by_fourcc(fe->pixel_format); - if (fmt == NULL) + if (!fmt) return -EINVAL; fe->type = V4L2_FRMSIZE_TYPE_DISCRETE; fe->discrete = is_ntsc ? ntsc_sizes[fe->index] : pal_sizes[fe->index]; @@ -1363,7 +1372,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, } static int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fe) + struct v4l2_frmivalenum *fe) { struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; @@ -1377,7 +1386,7 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, return -EINVAL; fmt = format_by_fourcc(fe->pixel_format); - if (fmt == NULL) + if (!fmt) return -EINVAL; sizes = is_ntsc ? ntsc_sizes : pal_sizes; @@ -1415,7 +1424,7 @@ static int s2255_open(struct file *file) return -ENODEV; case S2255_FW_FAILED: s2255_dev_err(&dev->udev->dev, - "firmware load failed. retrying.\n"); + "firmware load failed. retrying.\n"); s2255_fwload_start(dev); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) @@ -1429,7 +1438,8 @@ static int s2255_open(struct file *file) case S2255_FW_NOTLOADED: case S2255_FW_LOADED_DSPWAIT: /* give S2255_LOAD_TIMEOUT time for firmware to load in case - driver loaded and then device immediately opened */ + * driver loaded and then device immediately opened + */ pr_info("%s waiting for firmware load\n", __func__); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) @@ -1481,7 +1491,6 @@ static int s2255_open(struct file *file) static void s2255_destroy(struct s2255_dev *dev) { - dprintk(dev, 1, "%s", __func__); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ @@ -1554,7 +1563,6 @@ static void s2255_video_device_release(struct video_device *vdev) if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); - return; } static const struct video_device template = { @@ -1598,17 +1606,17 @@ static int s2255_probe_v4l(struct s2255_dev *dev) v4l2_ctrl_handler_init(&vc->hdl, 6); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); + V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); + V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); + V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_HUE, 0, 255, 1, DEF_HUE); + V4L2_CID_HUE, 0, 255, 1, DEF_HUE); vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl, - &s2255_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, - 0, 100, 1, S2255_DEF_JPEG_QUAL); + &s2255_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + 0, 100, 1, S2255_DEF_JPEG_QUAL); if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && (dev->pid != 0x2257 || vc->idx <= 1)) v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl, @@ -1660,7 +1668,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) refcount_inc(&dev->num_channels); v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", video_device_node_name(&vc->vdev)); - } pr_info("Sensoray 2255 V4L driver Revision: %s\n", S2255_VERSION); @@ -1697,11 +1704,12 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) struct s2255_framei *frm; unsigned char *pdata; struct s2255_vc *vc; + dprintk(dev, 100, "buffer to user\n"); vc = &dev->vc[dev->cc]; idx = vc->cur_frame; frm = &vc->buffer.frame[idx]; - if (frm->ulState == S2255_READ_IDLE) { + if (frm->state == S2255_READ_IDLE) { int jj; unsigned int cc; __le32 *pdword; /*data from dsp is little endian */ @@ -1790,20 +1798,19 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) /* search done. now find out if should be acquiring on this channel */ if (!vb2_is_streaming(&vc->vb_vidq)) { /* we found a frame, but this channel is turned off */ - frm->ulState = S2255_READ_IDLE; + frm->state = S2255_READ_IDLE; return -EINVAL; } - if (frm->ulState == S2255_READ_IDLE) { - frm->ulState = S2255_READ_FRAME; + if (frm->state == S2255_READ_IDLE) { + frm->state = S2255_READ_FRAME; frm->cur_size = 0; } /* skip the marker 512 bytes (and offset if out of sync) */ psrc = (u8 *)pipe_info->transfer_buffer + offset; - - if (frm->lpvbits == NULL) { + if (!frm->lpvbits) { dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d", frm, dev, dev->cc, idx); return -ENOMEM; @@ -1828,16 +1835,15 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) vc->last_frame = vc->cur_frame; vc->cur_frame++; /* end of system frame ring buffer, start at zero */ - if ((vc->cur_frame == SYS_FRAMES) || - (vc->cur_frame == vc->buffer.dwFrames)) + if (vc->cur_frame == SYS_FRAMES || + vc->cur_frame == vc->buffer.num_frames) vc->cur_frame = 0; /* frame ready */ if (vb2_is_streaming(&vc->vb_vidq)) s2255_got_frame(vc, vc->jpg_size); vc->frame_count++; - frm->ulState = S2255_READ_IDLE; + frm->state = S2255_READ_IDLE; frm->cur_size = 0; - } /* done successfully */ return 0; @@ -1847,6 +1853,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) { int res; + dprintk(dev, 50, "callback read video\n"); if (dev->cc >= MAX_CHANNELS) { @@ -1860,36 +1867,35 @@ static void s2255_read_video_callback(struct s2255_dev *dev, dprintk(dev, 4, "s2255: read callback failed\n"); dprintk(dev, 50, "callback read video done\n"); - return; } -static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, - u16 Index, u16 Value, void *TransferBuffer, - s32 TransferBufferLength, int bOut) +static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, + u16 index, u16 value, void *xfer_buf, + s32 xfer_buf_len, int is_out) { int r; unsigned char *buf; - buf = kmalloc(TransferBufferLength, GFP_KERNEL); + buf = kmalloc(xfer_buf_len, GFP_KERNEL); if (!buf) return -ENOMEM; - if (!bOut) { + if (!is_out) { r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - Request, + req, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - Value, Index, buf, - TransferBufferLength, USB_CTRL_SET_TIMEOUT); + value, index, buf, + xfer_buf_len, USB_CTRL_SET_TIMEOUT); if (r >= 0) - memcpy(TransferBuffer, buf, TransferBufferLength); + memcpy(xfer_buf, buf, xfer_buf_len); } else { - memcpy(buf, TransferBuffer, TransferBufferLength); + memcpy(buf, xfer_buf, xfer_buf_len); r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - Value, Index, buf, - TransferBufferLength, USB_CTRL_SET_TIMEOUT); + req, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, buf, + xfer_buf_len, USB_CTRL_SET_TIMEOUT); } kfree(buf); return r; @@ -1904,14 +1910,14 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) { int fw; int ret; - u8 transBuffer[2] = {}; + u8 trans_buf[2] = {}; - ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, - sizeof(transBuffer), S2255_VR_IN); + ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, trans_buf, + sizeof(trans_buf), S2255_VR_IN); if (ret < 0) dprintk(dev, 2, "get fw error: %x\n", ret); - fw = transBuffer[0] + (transBuffer[1] << 8); - dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); + fw = trans_buf[0] + (trans_buf[1] << 8); + dprintk(dev, 2, "Get FW %x %x\n", trans_buf[0], trans_buf[1]); return fw; } @@ -1923,7 +1929,8 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) { unsigned long i; unsigned long reqsize; - vc->buffer.dwFrames = SYS_FRAMES; + + vc->buffer.num_frames = SYS_FRAMES; /* always allocate maximum size(PAL) for system buffers */ reqsize = SYS_FRAMES_MAXSIZE; @@ -1934,16 +1941,15 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) /* allocate the frames */ vc->buffer.frame[i].lpvbits = vmalloc(reqsize); vc->buffer.frame[i].size = reqsize; - if (vc->buffer.frame[i].lpvbits == NULL) { - pr_info("out of memory. using less frames\n"); - vc->buffer.dwFrames = i; + if (!vc->buffer.frame[i].lpvbits) { + vc->buffer.num_frames = i; break; } } /* make sure internal states are set */ for (i = 0; i < SYS_FRAMES; i++) { - vc->buffer.frame[i].ulState = 0; + vc->buffer.frame[i].state = 0; vc->buffer.frame[i].cur_size = 0; } @@ -1955,6 +1961,7 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) static int s2255_release_sys_buffers(struct s2255_vc *vc) { unsigned long i; + for (i = 0; i < SYS_FRAMES; i++) { vfree(vc->buffer.frame[i].lpvbits); vc->buffer.frame[i].lpvbits = NULL; @@ -1968,6 +1975,7 @@ static int s2255_board_init(struct s2255_dev *dev) int fw_ver; int j; struct s2255_pipeinfo *pipe = &dev->pipe; + dprintk(dev, 4, "board init: %p", dev); memset(pipe, 0, sizeof(*pipe)); pipe->dev = dev; @@ -1976,10 +1984,8 @@ static int s2255_board_init(struct s2255_dev *dev) pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { - dprintk(dev, 1, "out of memory!\n"); + if (!pipe->transfer_buffer) return -ENOMEM; - } /* query the firmware */ fw_ver = s2255_get_fx2fw(dev); @@ -1992,6 +1998,7 @@ static int s2255_board_init(struct s2255_dev *dev) for (j = 0; j < MAX_CHANNELS; j++) { struct s2255_vc *vc = &dev->vc[j]; + vc->mode = mode_def; if (dev->pid == 0x2257 && j > 1) vc->mode.color |= (1 << 16); @@ -2015,6 +2022,7 @@ static int s2255_board_init(struct s2255_dev *dev) static int s2255_board_shutdown(struct s2255_dev *dev) { u32 i; + dprintk(dev, 1, "%s: dev: %p", __func__, dev); for (i = 0; i < MAX_CHANNELS; i++) { @@ -2035,13 +2043,14 @@ static void read_pipe_completion(struct urb *purb) struct s2255_dev *dev; int status; int pipe; + pipe_info = purb->context; - if (pipe_info == NULL) { + if (!pipe_info) { dev_err(&purb->dev->dev, "no context!\n"); return; } dev = pipe_info->dev; - if (dev == NULL) { + if (!dev) { dev_err(&purb->dev->dev, "no context!\n"); return; } @@ -2058,9 +2067,9 @@ static void read_pipe_completion(struct urb *purb) return; } - if (status == 0) + if (status == 0) { s2255_read_video_callback(dev, pipe_info); - else { + } else { pipe_info->err_count++; dprintk(dev, 1, "%s: failed URB %d\n", __func__, status); } @@ -2079,7 +2088,6 @@ static void read_pipe_completion(struct urb *purb) } else { dprintk(dev, 2, "%s :complete state 0\n", __func__); } - return; } static int s2255_start_readpipe(struct s2255_dev *dev) @@ -2087,6 +2095,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) int pipe; int retval; struct s2255_pipeinfo *pipe_info = &dev->pipe; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint); pipe_info->state = 1; @@ -2123,13 +2132,13 @@ static int s2255_start_acquire(struct s2255_vc *vc) vc->bad_payload = 0; vc->cur_frame = 0; for (j = 0; j < SYS_FRAMES; j++) { - vc->buffer.frame[j].ulState = 0; + vc->buffer.frame[j].state = 0; vc->buffer.frame[j].cur_size = 0; } /* send the start command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_START; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (res != 0) @@ -2151,7 +2160,7 @@ static int s2255_stop_acquire(struct s2255_vc *vc) chn_rev = G_chnmap[vc->idx]; /* send the stop command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_STOP; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); @@ -2174,8 +2183,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) usb_free_urb(pipe->stream_urb); pipe->stream_urb = NULL; } - dprintk(dev, 4, "%s", __func__); - return; } static void s2255_fwload_start(struct s2255_dev *dev) @@ -2208,30 +2215,26 @@ static int s2255_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it to zero */ dev = kzalloc_obj(struct s2255_dev); - if (dev == NULL) { - s2255_dev_err(&interface->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL); - if (dev->cmdbuf == NULL) { - s2255_dev_err(&interface->dev, "out of memory\n"); - goto errorFWDATA1; - } + if (!dev->cmdbuf) + goto err_fwdata1; refcount_set(&dev->num_channels, 0); dev->pid = id->idProduct; dev->fw_data = kzalloc_obj(struct s2255_fw); if (!dev->fw_data) - goto errorFWDATA1; + goto err_fwdata1; mutex_init(&dev->lock); mutex_init(&dev->cmdlock); /* grab usb_device and save it */ dev->udev = usb_get_dev(interface_to_usbdev(interface)); - if (dev->udev == NULL) { + if (!dev->udev) { dev_err(&interface->dev, "null usb device\n"); retval = -ENODEV; - goto errorUDEV; + goto err_udev; } dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n", dev, dev->udev, interface); @@ -2243,7 +2246,7 @@ static int s2255_probe(struct usb_interface *interface, if (usb_find_bulk_in_endpoint(iface_desc, &endpoint)) { dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); - goto errorEP; + goto err_ep; } dev->read_endpoint = endpoint->bEndpointAddress; @@ -2252,6 +2255,7 @@ static int s2255_probe(struct usb_interface *interface, init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { struct s2255_vc *vc = &dev->vc[i]; + vc->idx = i; vc->dev = dev; init_waitqueue_head(&vc->wait_setmode); @@ -2262,37 +2266,41 @@ static int s2255_probe(struct usb_interface *interface, dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->fw_data->fw_urb) - goto errorFWURB; + goto err_fwurb; dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); - if (!dev->fw_data->pfw_data) { - dev_err(&interface->dev, "out of memory!\n"); - goto errorFWDATA2; - } + if (!dev->fw_data->pfw_data) + goto err_fwdata2; /* load the first chunk */ if (request_firmware(&dev->fw_data->fw, FIRMWARE_FILE_NAME, &dev->udev->dev)) { dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n"); - goto errorREQFW; + goto err_reqfw; } /* check the firmware is valid */ fw_size = dev->fw_data->fw->size; - pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; + if (fw_size < 8) { + dev_err(&interface->dev, "Firmware invalid: too small.\n"); + retval = -ENODEV; + goto err_fwmarker; + } + pdata = (__le32 *)&dev->fw_data->fw->data[fw_size - 8]; if (*pdata != S2255_FW_MARKER) { dev_err(&interface->dev, "Firmware invalid.\n"); retval = -ENODEV; - goto errorFWMARKER; + goto err_fwmarker; } else { /* make sure firmware is the latest */ - __le32 *pRel; - pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); - dev->dsp_fw_ver = le32_to_cpu(*pRel); + __le32 *p_rel; + + p_rel = (__le32 *)&dev->fw_data->fw->data[fw_size - 4]; + pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*p_rel)); + dev->dsp_fw_ver = le32_to_cpu(*p_rel); if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) pr_info("s2255: f2255usb.bin out of date.\n"); if (dev->pid == 0x2257 && - dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) + dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) pr_warn("2257 needs firmware %d or above.\n", S2255_MIN_DSP_COLORFILTER); } @@ -2300,30 +2308,30 @@ static int s2255_probe(struct usb_interface *interface, /* load 2255 board specific */ retval = s2255_board_init(dev); if (retval) - goto errorBOARDINIT; + goto err_boardinit; s2255_fwload_start(dev); /* loads v4l specific */ retval = s2255_probe_v4l(dev); if (retval) - goto errorBOARDINIT; + goto err_boardinit; dev_info(&interface->dev, "Sensoray 2255 detected\n"); return 0; -errorBOARDINIT: +err_boardinit: s2255_board_shutdown(dev); -errorFWMARKER: +err_fwmarker: release_firmware(dev->fw_data->fw); -errorREQFW: +err_reqfw: kfree(dev->fw_data->pfw_data); -errorFWDATA2: +err_fwdata2: usb_free_urb(dev->fw_data->fw_urb); -errorFWURB: +err_fwurb: timer_shutdown_sync(&dev->timer); -errorEP: +err_ep: usb_put_dev(dev->udev); -errorUDEV: +err_udev: kfree(dev->fw_data); mutex_destroy(&dev->lock); -errorFWDATA1: +err_fwdata1: kfree(dev->cmdbuf); kfree(dev); pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval); @@ -2336,6 +2344,7 @@ static void s2255_disconnect(struct usb_interface *interface) struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); int i; int channels = refcount_read(&dev->num_channels); + mutex_lock(&dev->lock); v4l2_device_disconnect(&dev->v4l2_dev); mutex_unlock(&dev->lock); @@ -2355,7 +2364,6 @@ static void s2255_disconnect(struct usb_interface *interface) } if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); - dev_info(&interface->dev, "%s\n", __func__); } static struct usb_driver s2255_driver = { diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index f9462a9ca761..5058cada0d0a 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -263,7 +263,7 @@ static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, static int stk1160_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int rc = 0; + int rc; unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ struct usb_device *udev; @@ -290,15 +290,13 @@ static int stk1160_probe(struct usb_interface *interface, * Also, check if device speed is fast enough. */ rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size); - if (rc < 0) { - kfree(alt_max_pkt_size); - return rc; - } + if (rc < 0) + goto free_array; dev = kzalloc_obj(struct stk1160); if (dev == NULL) { - kfree(alt_max_pkt_size); - return -ENOMEM; + rc = -ENOMEM; + goto free_array; } dev->alt_max_pkt_size = alt_max_pkt_size; @@ -379,8 +377,9 @@ unreg_v4l2: free_ctrl: v4l2_ctrl_handler_free(&dev->ctrl_handler); free_err: - kfree(alt_max_pkt_size); kfree(dev); +free_array: + kfree(alt_max_pkt_size); return rc; } diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index f4baf9263286..020b75fc5b2d 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -48,6 +48,9 @@ static inline void print_err_status(struct stk1160 *dev, case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; + case -ESHUTDOWN: + errmsg = "host controller removed"; + break; case -ETIME: errmsg = "Device does not respond"; break; diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 333bd305a4f9..ae0a14e5ed2a 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -317,6 +317,13 @@ static const struct snd_pcm_ops snd_usbtv_pcm_ops = { .pointer = snd_usbtv_pointer, }; +static void usbtv_audio_card_free(struct snd_card *card) +{ + struct usbtv *usbtv = card->private_data; + + v4l2_device_put(&usbtv->v4l2_dev); +} + int usbtv_audio_init(struct usbtv *usbtv) { int rv; @@ -331,6 +338,10 @@ int usbtv_audio_init(struct usbtv *usbtv) if (rv < 0) return rv; + v4l2_device_get(&usbtv->v4l2_dev); + card->private_data = usbtv; + card->private_free = usbtv_audio_card_free; + strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver)); strscpy(card->shortname, "usbtv", sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 6c4facf4f41a..4f10f6613bc4 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -119,7 +119,10 @@ usbtv_audio_fail: usbtv_video_fail: usb_set_intfdata(intf, NULL); - kfree(usbtv); + if (usbtv->v4l2_dev.dev) + v4l2_device_put(&usbtv->v4l2_dev); + else + kfree(usbtv); return ret; } diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index de0328100a60..92bc7a2509c3 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -949,13 +949,11 @@ int usbtv_video_init(struct usbtv *usbtv) ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { dev_warn(usbtv->dev, "Could not register video device\n"); - goto vdev_fail; + return ret; } return 0; -vdev_fail: - v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: ctrl_fail: v4l2_ctrl_handler_free(&usbtv->ctrl); diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 888a2e213b08..460bf3dbbb88 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -392,7 +392,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, err_call_unbind: v4l2_async_nf_call_unbind(notifier, sd, asc); - list_del(&asc->asc_subdev_entry); err_unregister_subdev: if (registered) @@ -898,9 +897,18 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) sd->subdev_notifier = NULL; if (sd->asc_list.next) { - list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, - asc_subdev_entry) { - v4l2_async_unbind_subdev_one(asc->notifier, asc); + if (list_empty(&sd->asc_list)) { + /* + * If the sub-device was registered through other means + * than v4l2-async, there are no async connections but + * the sub-device may still well be registered. + * Unregister it now. + */ + v4l2_device_unregister_subdev(sd); + } else { + list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, + asc_subdev_entry) + v4l2_async_unbind_subdev_one(asc->notifier, asc); } } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index ba047d7d8601..5b8a594fb9e2 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -16,6 +16,9 @@ static const union v4l2_ctrl_ptr ptr_null; +#define V4L2_HEVC_MAX_SHORT_TERM_REF_PIC_SETS 64 +#define V4L2_HEVC_MAX_LONG_TERM_REF_PICS_SPS 32 + static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { @@ -1214,6 +1217,10 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_HEVC_SPS: p_hevc_sps = p; + if (p_hevc_sps->num_short_term_ref_pic_sets > + V4L2_HEVC_MAX_SHORT_TERM_REF_PIC_SETS) + return -EINVAL; + if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) { p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0; p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0; @@ -1224,6 +1231,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) p_hevc_sps->num_long_term_ref_pics_sps = 0; + else if (p_hevc_sps->num_long_term_ref_pics_sps > + V4L2_HEVC_MAX_LONG_TERM_REF_PICS_SPS) + return -EINVAL; break; case V4L2_CTRL_TYPE_HEVC_PPS: @@ -1280,6 +1290,11 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, if (p_hevc_st_rps->flags & ~V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED) return -EINVAL; + if (p_hevc_st_rps->num_negative_pics > 16 || + p_hevc_st_rps->num_positive_pics > 16 || + p_hevc_st_rps->num_negative_pics + + p_hevc_st_rps->num_positive_pics > 16) + return -EINVAL; break; case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS: @@ -1307,24 +1322,41 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, return -EINVAL; } - if (p_hdr10_mastering->white_point_x < - V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW || - p_hdr10_mastering->white_point_x > - V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH || - p_hdr10_mastering->white_point_y < - V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW || - p_hdr10_mastering->white_point_y > - V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) + /* + * SMPTE ST 2086 Annex A documents that CTA 861-G uses + * (0, 0) to indicate that the white point chromaticity + * is unknown. + */ + if (p_hdr10_mastering->white_point_x || + p_hdr10_mastering->white_point_y) { + if (p_hdr10_mastering->white_point_x < + V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW || + p_hdr10_mastering->white_point_x > + V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH || + p_hdr10_mastering->white_point_y < + V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW || + p_hdr10_mastering->white_point_y > + V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) + return -EINVAL; + } + + /* + * SMPTE ST 2086 Annex A documents that CTA 861-G uses zero + * maximum and minimum luminance values to indicate that + * the corresponding values are unknown. + */ + if (p_hdr10_mastering->max_display_mastering_luminance && + (p_hdr10_mastering->max_display_mastering_luminance < + V4L2_HDR10_MASTERING_MAX_LUMA_LOW || + p_hdr10_mastering->max_display_mastering_luminance > + V4L2_HDR10_MASTERING_MAX_LUMA_HIGH)) return -EINVAL; - if (p_hdr10_mastering->max_display_mastering_luminance < - V4L2_HDR10_MASTERING_MAX_LUMA_LOW || - p_hdr10_mastering->max_display_mastering_luminance > - V4L2_HDR10_MASTERING_MAX_LUMA_HIGH || - p_hdr10_mastering->min_display_mastering_luminance < - V4L2_HDR10_MASTERING_MIN_LUMA_LOW || - p_hdr10_mastering->min_display_mastering_luminance > - V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) + if (p_hdr10_mastering->min_display_mastering_luminance && + (p_hdr10_mastering->min_display_mastering_luminance < + V4L2_HDR10_MASTERING_MIN_LUMA_LOW || + p_hdr10_mastering->min_display_mastering_luminance > + V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)) return -EINVAL; /* The following restriction comes from ITU-T Rec. H.265 spec */ diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 5516b2bbb08f..fd267fb74905 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -1071,25 +1071,39 @@ int __video_register_device(struct video_device *vdev, vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); vdev->dev.parent = vdev->dev_parent; - vdev->dev.release = v4l2_device_release; dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); - - /* Increase v4l2_device refcount */ - v4l2_device_get(vdev->v4l2_dev); - mutex_lock(&videodev_lock); ret = device_register(&vdev->dev); if (ret < 0) { + /* + * We should do a put_device() here, but the problem is that + * the V4L2 API expects drivers to call video_device_release() + * on error, and so both put_device() and video_device_release + * would kfree vdev. + * + * The proper solution would be to split this function into + * two parts: initialization and registration, and then rework + * all drivers. + * + * Until then just skip the put_device and free everything. + * This will result in a small memory leak, which is better + * than a double-free. + */ mutex_unlock(&videodev_lock); pr_err("%s: device_register failed\n", __func__); - put_device(&vdev->dev); - return ret; + goto cleanup; } + /* Register the release callback that will be called when the last + reference to the device goes away. */ + vdev->dev.release = v4l2_device_release; if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) pr_warn("%s: requested %s%d, got %s\n", __func__, name_base, nr, video_device_node_name(vdev)); + /* Increase v4l2_device refcount */ + v4l2_device_get(vdev->v4l2_dev); + /* Part 5: Register the entity. */ ret = video_register_media_controller(vdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 62a3a452f788..570df3c415b0 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -633,6 +633,8 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, if (!link->remote_node) goto err_put_remote_endpoint; + fwnode_handle_put(fwnode); + return 0; err_put_remote_endpoint: diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index a2b650f4ec3c..17ba1ae70735 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1471,6 +1471,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break; case V4L2_META_FMT_MALI_C55_PARAMS: descr = "ARM Mali-C55 ISP Parameters"; break; case V4L2_META_FMT_MALI_C55_STATS: descr = "ARM Mali-C55 ISP 3A Statistics"; break; + case V4L2_META_FMT_RPPX1_PARAMS: descr = "Dreamchip RPP-X1 ISP Parameters"; break; + case V4L2_META_FMT_RPPX1_STATS: descr = "Dreamchip RPP-X1 ISP Statistics"; break; case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break; diff --git a/drivers/media/v4l2-core/v4l2-isp.c b/drivers/media/v4l2-core/v4l2-isp.c index 29831f7032e9..1eb46e080afa 100644 --- a/drivers/media/v4l2-core/v4l2-isp.c +++ b/drivers/media/v4l2-core/v4l2-isp.c @@ -114,6 +114,9 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, return -EINVAL; } + if (info->block_validate && info->block_validate(dev, block)) + return -EINVAL; + block_offset += block->size; buffer_size -= block->size; } @@ -127,6 +130,58 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, } EXPORT_SYMBOL_GPL(v4l2_isp_params_validate_buffer); +void v4l2_isp_stats_init_buffer(struct v4l2_isp_buffer *buf, + enum v4l2_isp_version version) +{ + if (WARN_ON(!buf)) + return; + + if (WARN_ON(version > V4L2_ISP_VERSION_V1)) + return; + + buf->version = version; + buf->data_size = 0; +} +EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_buffer); + +struct v4l2_isp_block_header * +v4l2_isp_stats_init_block(struct device *dev, struct v4l2_isp_buffer *buf, + const struct v4l2_isp_stats_block_type_info *type_info, + size_t num_block_types, unsigned int block_type, + size_t max_size) +{ + const struct v4l2_isp_stats_block_type_info *block_info; + struct v4l2_isp_block_header *header; + size_t used; + + if (WARN_ON(!dev || !buf || !type_info)) + return ERR_PTR(-EINVAL); + + if (block_type >= num_block_types) { + dev_err(dev, "Invalid block type %u\n", block_type); + return ERR_PTR(-EINVAL); + } + + block_info = &type_info[block_type]; + used = buf->data_size; + + if (used + block_info->size > max_size) { + dev_err(dev, "No space for stats block type %u of size %zu\n", + block_type, block_info->size); + return ERR_PTR(-ENOMEM); + } + + buf->data_size += block_info->size; + + header = (struct v4l2_isp_block_header *)&buf->data[used]; + header->type = block_type; + header->size = block_info->size; + header->flags = 0; + + return header; +} +EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_block); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com"); MODULE_DESCRIPTION("V4L2 generic ISP parameters and statistics helpers"); diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 115bb37577a1..6c729fcfce5d 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -123,10 +123,31 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, return desc; } +/* + * Other vana-supply users (e.g. ST, Toshiba, Sony sensors) can be added to + * this array instead of adding new quirk table entries. + */ +static const char * const power_enable_hids_vana[] = { + "SONY471A", /* imx471 on Lenovo X9-14 and X9-15 */ + "TBE20A0", /* imx471 on Lenovo X1 Carbon G14 */ + NULL +}; + +static const char * const power_enable_hids_vdd[] = { + "INT33F0", /* mt9m114 */ + NULL +}; + +static const char * const power_enable_hids_enable[] = { + "INT347E", /* ov7251 */ + NULL +}; + /** * struct int3472_gpio_map - Map GPIOs to whatever is expected by the * sensor driver (as in DT bindings) - * @hid: The ACPI HID of the device without the instance number e.g. INT347E + * @hids: NULL-terminated array of ACPI HIDs of the devices without the + * instance number e.g. INT347E * @type_from: The GPIO type from ACPI ?SDT * @type_to: The assigned GPIO type, typically same as @type_from * @enable_time_us: Enable time in usec for GPIOs mapped to regulators @@ -135,7 +156,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, * GPIO_ACTIVE_HIGH otherwise */ struct int3472_gpio_map { - const char *hid; + const char * const *hids; u8 type_from; u8 type_to; bool polarity_low; @@ -145,27 +166,45 @@ struct int3472_gpio_map { static const struct int3472_gpio_map int3472_gpio_map[] = { { /* mt9m114 designs declare a powerdown pin which controls the regulators */ - .hid = "INT33F0", + .hids = power_enable_hids_vdd, .type_from = INT3472_GPIO_TYPE_POWERDOWN, .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, .con_id = "vdd", .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, }, { /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ - .hid = "INT347E", + .hids = power_enable_hids_enable, .type_from = INT3472_GPIO_TYPE_RESET, .type_to = INT3472_GPIO_TYPE_RESET, .con_id = "enable", }, { /* ov08x40's handshake pin needs a 45 ms delay on some HP laptops */ - .hid = "OVTI08F4", + .hids = (const char * const[]) { "OVTI08F4", NULL }, .type_from = INT3472_GPIO_TYPE_HANDSHAKE, .type_to = INT3472_GPIO_TYPE_HANDSHAKE, .con_id = "dvdd", .enable_time_us = 45 * USEC_PER_MSEC, }, + { /* Sensors which expect "vana" as con_id for power enable */ + .hids = power_enable_hids_vana, + .type_from = INT3472_GPIO_TYPE_POWER_ENABLE, + .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, + .con_id = "vana", + .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, + }, }; +static bool int3472_gpio_map_hids_match(struct acpi_device *adev, + const char * const *hids) +{ + for (unsigned int i = 0; hids[i]; i++) { + if (acpi_dev_hid_uid_match(adev, hids[i], NULL)) + return true; + } + + return false; +} + static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, const char **con_id, unsigned long *gpio_flags, unsigned int *enable_time_us) @@ -182,7 +221,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 if (*type != int3472_gpio_map[i].type_from) continue; - if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL)) + if (!int3472_gpio_map_hids_match(adev, int3472_gpio_map[i].hids)) continue; dev_dbg(int3472->dev, "mapping type 0x%02x pin to 0x%02x %s\n", diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h index 4732b45b25ee..fbcd73b711ba 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h @@ -20,7 +20,7 @@ * Data structures. * ****************************************************************/ -/** +/* * @brief Data structure for the circular buffer. */ typedef struct ia_css_circbuf_s ia_css_circbuf_t; @@ -29,7 +29,7 @@ struct ia_css_circbuf_s { ia_css_circbuf_elem_t *elems; /* an array of elements */ }; -/** +/* * @brief Create the circular buffer. * * @param cb The pointer to the circular buffer. @@ -41,7 +41,7 @@ void ia_css_circbuf_create( ia_css_circbuf_elem_t *elems, ia_css_circbuf_desc_t *desc); -/** +/* * @brief Destroy the circular buffer. * * @param cb The pointer to the circular buffer. @@ -49,7 +49,7 @@ void ia_css_circbuf_create( void ia_css_circbuf_destroy( ia_css_circbuf_t *cb); -/** +/* * @brief Pop a value out of the circular buffer. * Get a value at the head of the circular buffer. * The user should call "ia_css_circbuf_is_empty()" @@ -62,7 +62,7 @@ void ia_css_circbuf_destroy( uint32_t ia_css_circbuf_pop( ia_css_circbuf_t *cb); -/** +/* * @brief Extract a value out of the circular buffer. * Get a value at an arbitrary position in the circular * buffer. The user should call "ia_css_circbuf_is_empty()" @@ -82,7 +82,7 @@ uint32_t ia_css_circbuf_extract( * Inline functions. * ****************************************************************/ -/** +/* * @brief Set the "val" field in the element. * * @param elem The pointer to the element. @@ -97,7 +97,7 @@ static inline void ia_css_circbuf_elem_set_val( elem->val = val; } -/** +/* * @brief Initialize the element. * * @param elem The pointer to the element. @@ -109,7 +109,7 @@ static inline void ia_css_circbuf_elem_init( ia_css_circbuf_elem_set_val(elem, 0); } -/** +/* * @brief Copy an element. * * @param src The element as the copy source. @@ -125,7 +125,7 @@ static inline void ia_css_circbuf_elem_cpy( ia_css_circbuf_elem_set_val(dest, src->val); } -/** +/* * @brief Get position in the circular buffer. * * @param cb The pointer to the circular buffer. @@ -151,7 +151,7 @@ static inline uint8_t ia_css_circbuf_get_pos_at_offset( return (base + offset) % cb->desc->size; } -/** +/* * @brief Get the offset between two positions in the circular buffer. * Get the offset from the source position to the terminal position, * along the direction in which the new elements come in. @@ -178,7 +178,7 @@ static inline int ia_css_circbuf_get_offset( return offset; } -/** +/* * @brief Get the maximum number of elements. * * @param cb The pointer to the circular buffer. @@ -196,7 +196,7 @@ static inline uint32_t ia_css_circbuf_get_size( return cb->desc->size; } -/** +/* * @brief Get the number of available elements. * * @param cb The pointer to the circular buffer. @@ -216,7 +216,7 @@ static inline uint32_t ia_css_circbuf_get_num_elems( return (uint32_t)num; } -/** +/* * @brief Test if the circular buffer is empty. * * @param cb The pointer to the circular buffer. @@ -234,7 +234,7 @@ static inline bool ia_css_circbuf_is_empty( return ia_css_circbuf_desc_is_empty(cb->desc); } -/** +/* * @brief Test if the circular buffer is full. * * @param cb The pointer to the circular buffer. @@ -251,7 +251,7 @@ static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) return ia_css_circbuf_desc_is_full(cb->desc); } -/** +/* * @brief Write a new element into the circular buffer. * Write a new element WITHOUT checking whether the * circular buffer is full or not. So it also overwrites @@ -275,7 +275,7 @@ static inline void ia_css_circbuf_write( cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1); } -/** +/* * @brief Push a value in the circular buffer. * Put a new value at the tail of the circular buffer. * The user should call "ia_css_circbuf_is_full()" @@ -300,7 +300,7 @@ static inline void ia_css_circbuf_push( ia_css_circbuf_write(cb, elem); } -/** +/* * @brief Get the number of free elements. * * @param cb The pointer to the circular buffer. @@ -316,7 +316,7 @@ static inline uint32_t ia_css_circbuf_get_free_elems( return ia_css_circbuf_desc_get_free_elems(cb->desc); } -/** +/* * @brief Peek an element in Circular Buffer. * * @param cb The pointer to the circular buffer. @@ -328,7 +328,7 @@ uint32_t ia_css_circbuf_peek( ia_css_circbuf_t *cb, int offset); -/** +/* * @brief Get an element in Circular Buffer. * * @param cb The pointer to the circular buffer. @@ -340,7 +340,7 @@ uint32_t ia_css_circbuf_peek_from_start( ia_css_circbuf_t *cb, int offset); -/** +/* * @brief Increase Size of a Circular Buffer. * Use 'CAUTION' before using this function, This was added to * support / fix issue with increasing size for tagger only diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h index 971e07f2acc5..090e2e764042 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h @@ -24,7 +24,7 @@ * Portable Data structures * ****************************************************************/ -/** +/* * @brief Data structure for the circular descriptor. */ typedef struct ia_css_circbuf_desc_s ia_css_circbuf_desc_t; @@ -40,7 +40,7 @@ struct ia_css_circbuf_desc_s { static_assert(sizeof(struct ia_css_circbuf_desc_s) == SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT); -/** +/* * @brief Data structure for the circular buffer element. */ typedef struct ia_css_circbuf_elem_s ia_css_circbuf_elem_t; diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h index 64f754f1d49b..3306a7a0fa5e 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h @@ -17,7 +17,7 @@ * Inline functions. * ****************************************************************/ -/** +/* * @brief Test if the circular buffer is empty. * * @param cb_desc The pointer to the circular buffer descriptor. @@ -33,7 +33,7 @@ static inline bool ia_css_circbuf_desc_is_empty( return (cb_desc->end == cb_desc->start); } -/** +/* * @brief Test if the circular buffer descriptor is full. * * @param cb_desc The pointer to the circular buffer @@ -50,7 +50,7 @@ static inline bool ia_css_circbuf_desc_is_full( return ((cb_desc->end + 1) % cb_desc->size) == cb_desc->start; } -/** +/* * @brief Initialize the circular buffer descriptor * * @param cb_desc The pointer circular buffer descriptor @@ -64,7 +64,7 @@ static inline void ia_css_circbuf_desc_init( cb_desc->size = size; } -/** +/* * @brief Get a position in the circular buffer descriptor. * * @param cb The pointer to the circular buffer descriptor. @@ -89,7 +89,7 @@ static inline uint8_t ia_css_circbuf_desc_get_pos_at_offset( return (base + offset) % cb_desc->size; } -/** +/* * @brief Get the offset between two positions in the circular buffer * descriptor. * Get the offset from the source position to the terminal position, @@ -116,7 +116,7 @@ static inline int ia_css_circbuf_desc_get_offset( return offset; } -/** +/* * @brief Get the number of available elements. * * @param cb_desc The pointer to the circular buffer. @@ -137,7 +137,7 @@ static inline uint32_t ia_css_circbuf_desc_get_num_elems( return (uint32_t)num; } -/** +/* * @brief Get the number of free elements. * * @param cb_desc The pointer to the circular buffer descriptor. diff --git a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h index 24cd99a659ca..dce8dd23b47c 100644 --- a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h +++ b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h @@ -81,7 +81,7 @@ bool ia_css_util_res_leq( struct ia_css_resolution b); /* ISP2401 */ -/** +/* * @brief Check if resolution is zero * * @param[in] resolution The resolution to check diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h index 989f55bec519..43bb352a8e05 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h @@ -21,7 +21,7 @@ * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ @@ -35,7 +35,7 @@ static inline hrt_data csi_rx_fe_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ @@ -51,7 +51,7 @@ static inline void csi_rx_fe_ctrl_reg_store( value); } -/** +/* * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ @@ -65,7 +65,7 @@ static inline hrt_data csi_rx_be_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ @@ -88,7 +88,7 @@ static inline void csi_rx_be_ctrl_reg_store( * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the state of the csi rx fe dlane process. * Refer to "csi_rx_public.h" for details. */ @@ -103,7 +103,7 @@ static inline void csi_rx_fe_ctrl_get_dlane_state( csi_rx_fe_ctrl_reg_load(ID, _HRT_CSI_RX_DLY_CNT_SETTLE_DLANE_REG_IDX(lane)); } -/** +/* * @brief Get the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ @@ -142,7 +142,7 @@ static inline void csi_rx_fe_ctrl_get_state( } } -/** +/* * @brief dump the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ @@ -180,7 +180,7 @@ static inline void csi_rx_fe_ctrl_dump_state( } } -/** +/* * @brief Get the csi rx be state. * Refer to "csi_rx_public.h" for details. */ @@ -243,7 +243,7 @@ static inline void csi_rx_be_ctrl_get_state( } } -/** +/* * @brief Dump the csi rx be state. * Refer to "csi_rx_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h index 4bd8209aaa01..85439d561ba3 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h @@ -15,7 +15,7 @@ | Native command interface (NCI) | + -------------------------------------------------------*/ -/** +/* * @brief Get the isys irq status. * Refer to "isys_irq.h" for details. */ @@ -34,7 +34,7 @@ void isys_irqc_state_get( */ } -/** +/* * @brief Dump the isys irq status. * Refer to "isys_irq.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h index 8e295cd78129..88a763365631 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h @@ -27,7 +27,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the stream2mmio-controller state. * Refer to "stream2mmio_public.h" for details. */ @@ -45,7 +45,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_get_state( stream2mmio_get_sid_state(ID, i, &state->sid_state[i]); } -/** +/* * @brief Get the state of the stream2mmio-controller sidess. * Refer to "stream2mmio_public.h" for details. */ @@ -76,7 +76,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_get_sid_state( stream2mmio_reg_load(ID, sid_id, STREAM2MMIO_BLOCK_WHEN_NO_CMD_REG_ID); } -/** +/* * @brief Dump the state of the stream2mmio-controller sidess. * Refer to "stream2mmio_public.h" for details. */ @@ -92,7 +92,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_print_sid_state( ia_css_print("\t \t block when no cmd 0x%x\n", state->block_when_no_cmd); } -/** +/* * @brief Dump the ibuf-controller state. * Refer to "stream2mmio_public.h" for details. */ @@ -119,7 +119,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "stream2mmio_public.h" for details. */ @@ -137,7 +137,7 @@ STORAGE_CLASS_STREAM2MMIO_C hrt_data stream2mmio_reg_load( (reg_bank_offset + reg_idx) * sizeof(hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "stream2mmio_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h index b8b98106bd31..0faf6ffdf55d 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h @@ -16,7 +16,7 @@ * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "pixelgen_public.h" for details. */ @@ -30,7 +30,7 @@ STORAGE_CLASS_PIXELGEN_C hrt_data pixelgen_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "pixelgen_ctrl_public.h" for details. */ @@ -53,7 +53,7 @@ STORAGE_CLASS_PIXELGEN_C void pixelgen_ctrl_reg_store( * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the pixelgen state. * Refer to "pixelgen_public.h" for details. */ @@ -117,7 +117,7 @@ STORAGE_CLASS_PIXELGEN_C void pixelgen_ctrl_get_state( pixelgen_ctrl_reg_load(ID, _PXG_TPG_B2_REG_IDX); } -/** +/* * @brief Dump the pixelgen state. * Refer to "pixelgen_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h index 59e0b44bfdc3..b5a6a8f0c3d2 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h @@ -9,7 +9,7 @@ #include <type_support.h> -/** +/* * Pixel-generator. ("pixelgen_global.h") */ /* diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h index 2dc0fb88399f..e4c136660b1e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h @@ -11,7 +11,7 @@ #include "timed_controller_defs.h" -/** +/* * Order of the input bits for the timed controller taken from * ISP_CSS_2401 System Architecture Description valid for * 2400, 2401. diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h index ca33a1e03d8d..f5b0ff414395 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h index 2002960f078e..e8ce556bfd6a 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the csi rx frontend state. * Get the state of the csi rx frontend regiester-set. * @@ -22,7 +22,7 @@ void csi_rx_fe_ctrl_get_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); -/** +/* * @brief Dump the csi rx frontend state. * Dump the state of the csi rx frontend regiester-set. * @@ -32,7 +32,7 @@ void csi_rx_fe_ctrl_get_state( void csi_rx_fe_ctrl_dump_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); -/** +/* * @brief Get the state of the csi rx fe dlane. * Get the state of the register set per dlane process. * @@ -44,7 +44,7 @@ void csi_rx_fe_ctrl_get_dlane_state( const csi_rx_frontend_ID_t ID, const u32 lane, csi_rx_fe_ctrl_lane_t *dlane_state); -/** +/* * @brief Get the csi rx backend state. * Get the state of the csi rx backend regiester-set. * @@ -54,7 +54,7 @@ void csi_rx_fe_ctrl_get_dlane_state( void csi_rx_be_ctrl_get_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state); -/** +/* * @brief Dump the csi rx backend state. * Dump the state of the csi rx backend regiester-set. * @@ -71,7 +71,7 @@ void csi_rx_be_ctrl_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the csi rx fe. * @@ -83,7 +83,7 @@ void csi_rx_be_ctrl_dump_state( hrt_data csi_rx_fe_ctrl_reg_load( const csi_rx_frontend_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the register of the csi rx fe. * @@ -96,7 +96,7 @@ void csi_rx_fe_ctrl_reg_store( const csi_rx_frontend_ID_t ID, const hrt_address reg, const hrt_data value); -/** +/* * @brief Load the register value. * Load the value of the register of the csirx be. * @@ -108,7 +108,7 @@ void csi_rx_fe_ctrl_reg_store( hrt_data csi_rx_be_ctrl_reg_load( const csi_rx_backend_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the register of the csi rx be. * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h index 7ed55d427cf6..e4f77e975f4e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the stream2mmio-controller state. * Get the state of the stream2mmio-controller regiester-set. * @@ -23,7 +23,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_get_state( const stream2mmio_ID_t ID, stream2mmio_state_t *state); -/** +/* * @brief Get the state of the stream2mmio-controller sidess. * Get the state of the register set per buf-controller sidess. * @@ -42,7 +42,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_get_sid_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the stream2mmio-controller. * @@ -57,7 +57,7 @@ STORAGE_CLASS_STREAM2MMIO_H hrt_data stream2mmio_reg_load( const stream2mmio_sid_ID_t sid_id, const uint32_t reg_idx); -/** +/* * @brief Dump the SID processor state. * Dump the state of the sid regiester-set. * @@ -65,7 +65,7 @@ STORAGE_CLASS_STREAM2MMIO_H hrt_data stream2mmio_reg_load( */ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_print_sid_state( stream2mmio_sid_state_t *state); -/** +/* * @brief Dump the stream2mmio state. * Dump the state of the ibuf-controller regiester-set. * @@ -75,7 +75,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_print_sid_state( STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_dump_state( const stream2mmio_ID_t ID, stream2mmio_state_t *state); -/** +/* * @brief Store a value to the register. * Store a value to the registe of the stream2mmio-controller. * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h index dc31ce3cd741..6aabf0b1995f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the pixelgen state. * Get the state of the pixelgen regiester-set. * @@ -22,7 +22,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_get_state( const pixelgen_ID_t ID, pixelgen_ctrl_state_t *state); -/** +/* * @brief Dump the pixelgen state. * Dump the state of the pixelgen regiester-set. * @@ -39,7 +39,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the pixelgen * @@ -51,7 +51,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_dump_state( STORAGE_CLASS_PIXELGEN_H hrt_data pixelgen_ctrl_reg_load( const pixelgen_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the registe of the pixelgen * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h index ad83ff97bbd6..1652c9f79349 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h @@ -7,7 +7,7 @@ #ifndef __TAG_PUBLIC_H_INCLUDED__ #define __TAG_PUBLIC_H_INCLUDED__ -/** +/* * @brief Creates the tag description from the given parameters. * @param[in] num_captures * @param[in] skip @@ -21,7 +21,7 @@ sh_css_create_tag_descr(int num_captures, unsigned int exp_id, struct sh_css_tag_descr *tag_descr); -/** +/* * @brief Encodes the members of tag description into a 32-bit value. * @param[in] tag Pointer to the tag description * @return (unsigned int) Encoded 32-bit tag-info diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h index 473d8d4fb9ba..20a5faad0716 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h @@ -7,7 +7,7 @@ #ifndef __PLATFORM_SUPPORT_H_INCLUDED__ #define __PLATFORM_SUPPORT_H_INCLUDED__ -/** +/* * @file * Platform specific includes and functionality. */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h index 097be6bd3cb5..cbd290121a28 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h @@ -7,7 +7,7 @@ #ifndef __TYPE_SUPPORT_H_INCLUDED__ #define __TYPE_SUPPORT_H_INCLUDED__ -/** +/* * @file * Platform specific types. * diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h index 7acfedb541d8..936b17950b3a 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h @@ -119,7 +119,7 @@ struct ia_css_frame_info { .raw_bayer_order = IA_CSS_BAYER_ORDER_NUM, \ } -/** +/* * Specifies the DVS loop delay in "frame periods" */ enum ia_css_frame_delay { diff --git a/drivers/staging/media/atomisp/pci/ia_css_host_data.h b/drivers/staging/media/atomisp/pci/ia_css_host_data.h index 0e45650cc1ab..547542577902 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_host_data.h +++ b/drivers/staging/media/atomisp/pci/ia_css_host_data.h @@ -10,7 +10,7 @@ #include <ia_css_types.h> /* ia_css_pipe */ -/** +/* * @brief Allocate structure ia_css_host_data. * * @param[in] size Size of the requested host data @@ -22,7 +22,7 @@ struct ia_css_host_data * ia_css_host_data_allocate(size_t size); -/** +/* * @brief Free structure ia_css_host_data. * * @param[in] me Pointer to structure, if a NULL is passed functions diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h index 2bb06b0ff5db..1d1b704b2bc6 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h @@ -44,7 +44,7 @@ enum ia_css_pipe_mode { /* Temporary define */ #define IA_CSS_PIPE_MODE_NUM (IA_CSS_PIPE_MODE_YUVPP + 1) -/** +/* * Enumeration of pipe versions. * the order should match with definition in sh_css_defs.h */ @@ -55,7 +55,7 @@ enum ia_css_pipe_version { IA_CSS_PIPE_VERSION_2_7 = 4 /** ISP2.7 pipe */ }; -/** +/* * Pipe configuration structure. * Resolution properties are filled by Driver, kernel configurations are * set by AIC @@ -123,7 +123,7 @@ struct ia_css_pipe_config { to retrieve shading gains which correspond to bayer data. */ }; -/** +/* * Default settings for newly created pipe configurations. */ #define DEFAULT_PIPE_CONFIG { \ @@ -175,7 +175,7 @@ struct ia_css_pipe_info { output at the first valid frame. */ }; -/** +/* * Defaults for ia_css_pipe_info structs. */ #define DEFAULT_PIPE_INFO {\ diff --git a/drivers/staging/media/atomisp/pci/ia_css_prbs.h b/drivers/staging/media/atomisp/pci/ia_css_prbs.h index abdbcb8fda53..3bb1e5dbb4fc 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_prbs.h +++ b/drivers/staging/media/atomisp/pci/ia_css_prbs.h @@ -19,7 +19,7 @@ enum ia_css_prbs_id { IA_CSS_PRBS_ID2 }; -/** +/* * Maximum number of PRBS IDs. * * Make sure the value of this define gets changed to reflect the correct @@ -27,7 +27,7 @@ enum ia_css_prbs_id { */ #define N_CSS_PRBS_IDS (IA_CSS_PRBS_ID2 + 1) -/** +/* * PRBS configuration structure. * * Seed the for the Pseudo Random Bit Sequence. diff --git a/drivers/staging/media/atomisp/pci/ia_css_stream.h b/drivers/staging/media/atomisp/pci/ia_css_stream.h index c8de632a8e12..578dc45785fc 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_stream.h +++ b/drivers/staging/media/atomisp/pci/ia_css_stream.h @@ -13,7 +13,7 @@ #include "ia_css_types.h" #include "ia_css_stream_public.h" -/** +/* * structure to hold all internal stream related information */ struct ia_css_stream { diff --git a/drivers/staging/media/atomisp/pci/ia_css_timer.h b/drivers/staging/media/atomisp/pci/ia_css_timer.h index da752834adf4..5c73e8c61588 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_timer.h +++ b/drivers/staging/media/atomisp/pci/ia_css_timer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. @@ -42,7 +42,10 @@ struct ia_css_time_meas { clock_value_t end_timer_value; /** measured time in ticks */ }; -/**@brief SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT checks to ensure correct alignment for struct ia_css_clock_tick. */ +/* + * @brief SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT checks to ensure correct alignment + * for struct ia_css_clock_tick. + */ #define SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT sizeof(clock_value_t) /* @brief checks to ensure correct alignment for ia_css_time_meas. */ #define SIZE_OF_IA_CSS_TIME_MEAS_STRUCT (sizeof(clock_value_t) \ diff --git a/drivers/staging/media/atomisp/pci/ia_css_types.h b/drivers/staging/media/atomisp/pci/ia_css_types.h index 2b7db9cda23a..7065eded7a33 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_types.h @@ -53,7 +53,7 @@ #include "isp/kernels/output/output_1.0/ia_css_output_types.h" #define IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED -/** Should be removed after Driver adaptation will be done */ +/* Should be removed after Driver adaptation will be done */ #define IA_CSS_VERSION_MAJOR 2 #define IA_CSS_VERSION_MINOR 0 @@ -421,7 +421,7 @@ struct ia_css_dvs_6axis_config { u32 *ycoords_uv; }; -/** +/* * This specifies the coordinates (x,y) */ struct ia_css_point { @@ -429,7 +429,7 @@ struct ia_css_point { s32 y; /** y coordinate */ }; -/** +/* * Digital zoom: * This feature is currently available only for video, but will become * available for preview and capture as well. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h index 374261d25520..ee2cf2877b7d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h @@ -7,7 +7,7 @@ #ifndef __IA_CSS_CONVERSION_TYPES_H #define __IA_CSS_CONVERSION_TYPES_H -/** +/* * Conversion Kernel parameters. * Deinterleave bayer quad into isys format * diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h index 0b977eb7ad71..bbd97c71a6fd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h @@ -13,7 +13,7 @@ #include "type_support.h" -/** +/* * \brief EED1_8 public parameters. * \details Struct with all parameters for the EED1.8 kernel that can be set * from the CSS API. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h index e32290d1c86b..d6785724fe97 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h @@ -10,44 +10,46 @@ #define IA_CSS_HDR_MAX_NUM_INPUT_FRAMES (3) -/** +/* * \brief HDR Irradiance Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_irradiance_params { - int test_irr; /** Test parameter */ - int match_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Histogram matching shift parameter */ - int match_mul[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Histogram matching multiplication parameter */ - int thr_low[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Weight map soft threshold low bound parameter */ - int thr_high[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Weight map soft threshold high bound parameter */ - int thr_coeff[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Soft threshold linear function coefficien */ - int thr_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Soft threshold precision shift parameter */ - int weight_bpp; /** Weight map bits per pixel */ + /* Test parameter */ + int test_irr; + /* Histogram matching shift parameter */ + int match_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Histogram matching multiplication parameter */ + int match_mul[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map soft threshold low bound parameter */ + int thr_low[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map soft threshold high bound parameter */ + int thr_high[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Soft threshold linear function coefficien */ + int thr_coeff[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Soft threshold precision shift parameter */ + int thr_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map bits per pixel */ + int weight_bpp; }; -/** +/* * \brief HDR Deghosting Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_deghost_params { - int test_deg; /** Test parameter */ + int test_deg; /* Test parameter */ }; -/** +/* * \brief HDR Exclusion Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_exclusion_params { - int test_excl; /** Test parameter */ + int test_excl; /* Test parameter */ }; -/** +/* * \brief HDR public parameters. * \details Struct with all parameters for HDR that can be seet from * the CSS API. Currently, only test parameters are defined. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h index c9a3f7bfaa90..de535503b70e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h index c1c93b2245c5..69a40a15264b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h index e6ce0cba44b9..72310781cf7e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h index 429fcdb73f60..9fabb8b2d3b8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h index 485ad17cb29b..1daafd96a0cd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h index 42b760ffac67..676a633336a2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. @@ -12,7 +12,7 @@ Copyright (c) 2010 - 2015, Intel Corporation. * CSS-API header file for Temporal Noise Reduction v3 (TNR3) kernel */ -/** +/* * \brief Number of piecewise linear segments. * \details The parameters to TNR3 are specified as a piecewise linear segment. * The number of such segments is fixed at 3. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h index c012c1865d1e..fc4b9033951c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h @@ -11,25 +11,25 @@ * CSS-API header file for Extra Noise Reduction (XNR) parameters. */ -/** +/* * \brief Scale of the XNR sigma parameters. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_SIGMA_SCALE BIT(10) -/** +/* * \brief Scale of the XNR coring parameters. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_CORING_SCALE BIT(15) -/** +/* * \brief Scale of the XNR blending parameter. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_BLENDING_SCALE BIT(11) -/** +/* * \brief XNR3 Sigma Parameters. * \details Sigma parameters define the strength of the XNR filter. * A higher number means stronger filtering. There are two values for each of @@ -46,7 +46,7 @@ struct ia_css_xnr3_sigma_params { int v1; /** Sigma for V range similarity in bright area */ }; -/** +/* * \brief XNR3 Coring Parameters * \details Coring parameters define the "coring" strength, which is a soft * thresholding technique to avoid false coloring. There are two values for @@ -61,7 +61,7 @@ struct ia_css_xnr3_coring_params { int v1; /** Coring threshold of V channel in bright area */ }; -/** +/* * \brief XNR3 Blending Parameters * \details Blending parameters define the blending strength of filtered * output pixels with the original chroma pixels from before xnr3. The @@ -75,7 +75,7 @@ struct ia_css_xnr3_blending_params { int strength; /** Blending strength */ }; -/** +/* * \brief XNR3 public parameters. * \details Struct with all parameters for the XNR3 kernel that can be set * from the CSS API. diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h index 6a0257359e69..d6ed1fbb0e8e 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h index 9c682f2ecbb2..5f768af9bc1d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h +++ b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h index 3e7dadca6d70..618172f17b63 100644 --- a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h @@ -13,7 +13,7 @@ #include "ia_css_err.h" #define BUFQ_EVENT_SIZE 4 -/** +/* * @brief Query the internal frame ID. * * @param[in] key The query key. @@ -29,7 +29,7 @@ bool ia_css_query_internal_queue_id( enum sh_css_queue_id *val ); -/** +/* * @brief Map buffer type to a internal queue id. * * @param[in] thread id Thread in which the buffer type has to be mapped or unmapped @@ -43,13 +43,13 @@ void ia_css_queue_map( bool map ); -/** +/* * @brief Initialize buffer type to a queue id mapping * @return none */ void ia_css_queue_map_init(void); -/** +/* * @brief initializes bufq module * It create instances of * -host to SP buffer queue which is a list with predefined size, @@ -62,7 +62,7 @@ void ia_css_queue_map_init(void); */ void ia_css_bufq_init(void); -/** +/* * @brief Enqueues an item into host to SP buffer queue * * @param thread_index[in] Thread in which the item to be enqueued @@ -77,7 +77,7 @@ int ia_css_bufq_enqueue_buffer( int queue_id, uint32_t item); -/** +/* * @brief Dequeues an item from SP to host buffer queue. * * @param queue_id[in] Specifies the index of the queue in the list where @@ -90,7 +90,7 @@ int ia_css_bufq_dequeue_buffer( int queue_id, uint32_t *item); -/** +/* * @brief Enqueue an event item into host to SP communication event queue. * * @param[in] evt_id The event ID. @@ -107,7 +107,7 @@ int ia_css_bufq_enqueue_psys_event( uint8_t evt_payload_2 ); -/** +/* * @brief Dequeue an item from SP to host communication event queue. * * @param item Object to be dequeued into this item. @@ -119,7 +119,7 @@ int ia_css_bufq_dequeue_psys_event( ); -/** +/* * @brief Enqueue an event item into host to SP EOF event queue. * * @param[in] evt_id The event ID. @@ -129,7 +129,7 @@ int ia_css_bufq_dequeue_psys_event( int ia_css_bufq_enqueue_isys_event( uint8_t evt_id); -/** +/* * @brief Dequeue an item from SP to host communication EOF event queue. * @@ -140,7 +140,7 @@ int ia_css_bufq_enqueue_isys_event( int ia_css_bufq_dequeue_isys_event( u8 item[BUFQ_EVENT_SIZE]); -/** +/* * @brief Enqueue a tagger command item into tagger command queue.. * * @param item Object to be enqueue. @@ -150,7 +150,7 @@ int ia_css_bufq_dequeue_isys_event( int ia_css_bufq_enqueue_tag_cmd( uint32_t item); -/** +/* * @brief Uninitializes bufq module. * * @return 0 or error code upon error. @@ -158,7 +158,7 @@ int ia_css_bufq_enqueue_tag_cmd( */ int ia_css_bufq_deinit(void); -/** +/* * @brief Dump queue states * * @return None diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index 2d0e906530af..b7ff809eeeab 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -312,7 +312,7 @@ void ia_css_debug_dump_stream_config( const struct ia_css_stream_config *config, int num_pipes); -/** +/* * @brief Initialize the debug mode. * * WARNING: @@ -324,7 +324,7 @@ void ia_css_debug_dump_stream_config( */ bool ia_css_debug_mode_init(void); -/** +/* * @brief Disable the DMA channel. * * @param[in] dma_ID The ID of the target DMA. @@ -344,7 +344,7 @@ bool ia_css_debug_mode_disable_dma_channel( int dma_ID, int channel_id, int request_type); -/** +/* * @brief Enable the DMA channel. * * @param[in] dma_ID The ID of the target DMA. @@ -363,7 +363,7 @@ bool ia_css_debug_mode_enable_dma_channel( int channel_id, int request_type); -/** +/* * @brief Dump tracer data. * [Currently support is only for SKC] * @@ -373,7 +373,7 @@ bool ia_css_debug_mode_enable_dma_channel( void ia_css_debug_dump_trace(void); /* ISP2401 */ -/** +/* * @brief Program counter dumping (in loop) * * @param[in] id The ID of the SP diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h index 80c58cb934d5..6f6cd77ce91d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h @@ -13,21 +13,21 @@ #include <ia_css_stream_public.h> #include "ia_css_pipeline.h" -/** +/* * @brief Internal debug support for constructing a pipe graph. * * @return None */ void ia_css_debug_pipe_graph_dump_prologue(void); -/** +/* * @brief Internal debug support for constructing a pipe graph. * * @return None */ void ia_css_debug_pipe_graph_dump_epilogue(void); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] stage Pipeline stage. * @param[in] id Pipe id. @@ -38,7 +38,7 @@ void ia_css_debug_pipe_graph_dump_stage( struct ia_css_pipeline_stage *stage, enum ia_css_pipe_id id); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] out_frame Output frame of SP raw copy. * @@ -47,7 +47,7 @@ void ia_css_debug_pipe_graph_dump_stage( void ia_css_debug_pipe_graph_dump_sp_raw_copy( struct ia_css_frame *out_frame); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] stream_config info about sensor and input formatter. * diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h index 9b058e296c93..f8ce32e9b90d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h @@ -9,7 +9,7 @@ #include "ia_css_queue.h" /* queue APIs */ -/** +/* * @brief HOST receives event from SP. * * @param[in] eventq_handle eventq_handle. @@ -22,7 +22,7 @@ int ia_css_eventq_recv( ia_css_queue_t *eventq_handle, uint8_t *payload); -/** +/* * @brief The Host sends the event to SP. * The caller of this API will be blocked until the event * is sent. diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h index d6d60508c1bf..095d1853670f 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h index 29eebe8f9078..8870ff294c1e 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h @@ -15,7 +15,7 @@ #include <system_global.h> #include "ia_css_isys_comm.h" -/** +/* * Virtual Input System. (Input System 2401) */ typedef isp2401_input_system_cfg_t ia_css_isys_descr_t; @@ -28,7 +28,7 @@ enum mipi_port_id ia_css_isys_port_to_mipi_port( enum mipi_port_id api_port); -/** +/* * @brief Register one (virtual) stream. This is used to track when all * virtual streams are configured inside the input system. The CSI RX is * only started when all registered streams are configured. @@ -43,7 +43,7 @@ int ia_css_isys_csi_rx_register_stream( enum mipi_port_id port, uint32_t isys_stream_id); -/** +/* * @brief Unregister one (virtual) stream. This is used to track when all * virtual streams are configured inside the input system. The CSI RX is * only started when all registered streams are configured. @@ -97,7 +97,7 @@ int ia_css_isys_convert_stream_format_to_mipi_format( mipi_predictor_t compression, unsigned int *fmt_type); -/** +/* * Virtual Input System. (Input System 2401) */ ia_css_isys_error_t ia_css_isys_stream_create( diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h index 8b7cbf31a1a2..04d9f1fdb5b0 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -219,7 +219,7 @@ int ia_css_pipeline_get_output_stage( */ bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); -/** +/* * @brief get the SP thread ID. * * @param[in] key The query key, typical use is pipe_num. @@ -231,7 +231,7 @@ bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); */ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); -/** +/* * @brief Get the pipeline io status * * @param[in] None @@ -240,7 +240,7 @@ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); */ struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); -/** +/* * @brief Map an SP thread to this pipeline * * @param[in] pipe_num @@ -249,7 +249,7 @@ struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); */ void ia_css_pipeline_map(unsigned int pipe_num, bool map); -/** +/* * @brief Checks whether the pipeline is mapped to SP threads * * @param[in] Query key, typical use is pipe_num @@ -260,7 +260,7 @@ void ia_css_pipeline_map(unsigned int pipe_num, bool map); */ bool ia_css_pipeline_is_mapped(unsigned int key); -/** +/* * @brief Print pipeline thread mapping * * @param[in] none diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h index 00b903d950df..4c86c19811bb 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h @@ -17,12 +17,12 @@ #define STORAGE_CLASS_RMGR_C static inline #endif /* __INLINE_RMGR__ */ -/** +/* * @brief Initialize resource manager (host/common) */ int ia_css_rmgr_init(void); -/** +/* * @brief Uninitialize resource manager (host/common) */ void ia_css_rmgr_uninit(void); diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h index 6820bfc77432..68285334bc88 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h @@ -12,7 +12,7 @@ #include <ia_css_types.h> #include <system_local.h> -/** +/* * @brief Data structure for the resource handle (host, vbuf) */ struct ia_css_rmgr_vbuf_handle { @@ -21,7 +21,7 @@ struct ia_css_rmgr_vbuf_handle { u32 size; }; -/** +/* * @brief Data structure for the resource pool (host, vbuf) */ struct ia_css_rmgr_vbuf_pool { @@ -32,14 +32,14 @@ struct ia_css_rmgr_vbuf_pool { struct ia_css_rmgr_vbuf_handle **handles; }; -/** +/* * @brief VBUF resource pools */ extern struct ia_css_rmgr_vbuf_pool *vbuf_ref; extern struct ia_css_rmgr_vbuf_pool *vbuf_write; extern struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool; -/** +/* * @brief Initialize the resource pool (host, vbuf) * * @param pool The pointer to the pool @@ -47,7 +47,7 @@ extern struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool; STORAGE_CLASS_RMGR_H int ia_css_rmgr_init_vbuf( struct ia_css_rmgr_vbuf_pool *pool); -/** +/* * @brief Uninitialize the resource pool (host, vbuf) * * @param pool The pointer to the pool @@ -55,7 +55,7 @@ STORAGE_CLASS_RMGR_H int ia_css_rmgr_init_vbuf( STORAGE_CLASS_RMGR_H void ia_css_rmgr_uninit_vbuf( struct ia_css_rmgr_vbuf_pool *pool); -/** +/* * @brief Acquire a handle from the pool (host, vbuf) * * @param pool The pointer to the pool @@ -65,7 +65,7 @@ STORAGE_CLASS_RMGR_H void ia_css_rmgr_acq_vbuf( struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Release a handle to the pool (host, vbuf) * * @param pool The pointer to the pool @@ -75,14 +75,14 @@ STORAGE_CLASS_RMGR_H void ia_css_rmgr_rel_vbuf( struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Retain the reference count for a handle (host, vbuf) * * @param handle The pointer to the handle */ void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Release the reference count for a handle (host, vbuf) * * @param handle The pointer to the handle diff --git a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h index 79006c325de6..9208c650fde7 100644 --- a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h +++ b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h @@ -10,14 +10,14 @@ #include <system_local.h> #include <type_support.h> -/** +/* * @brief The tagger's circular buffer. * * Should be one less than NUM_CONTINUOUS_FRAMES in sh_css_internal.h */ #define MAX_CB_ELEMS_FOR_TAGGER 14 -/** +/* * @brief Data structure for the tagger buffer element. */ typedef struct { diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index 9155a83fcc03..ec68c16d4272 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -80,7 +80,7 @@ #define SH_CSS_MAX_SP_THREADS 5 -/** +/* * The C99 standard does not specify the exact object representation of structs; * the representation is compiler dependent. * @@ -638,7 +638,7 @@ struct sh_css_sp_output { unsigned int sw_interrupt_value[SH_CSS_NUM_SDW_IRQS]; }; -/** +/* * @brief Data structure for the circular buffer. * The circular buffer is empty if "start == end". The * circular buffer is full if "(end + 1) % size == start". diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.h b/drivers/staging/media/atomisp/pci/sh_css_sp.h index 78aec5b7e8fa..6985ca200f09 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.h +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.h @@ -68,7 +68,7 @@ sh_css_read_host2sp_command(void); void sh_css_init_host2sp_frame_data(void); -/** +/* * @brief Update the offline frame information in host_sp_communication. * * @param[in] frame_num The offline frame number. @@ -80,7 +80,7 @@ sh_css_update_host2sp_offline_frame( struct ia_css_frame *frame, struct ia_css_metadata *metadata); -/** +/* * @brief Update the mipi frame information in host_sp_communication. * * @param[in] frame_num The mipi frame number. @@ -91,7 +91,7 @@ sh_css_update_host2sp_mipi_frame( unsigned int frame_num, struct ia_css_frame *frame); -/** +/* * @brief Update the mipi metadata information in host_sp_communication. * * @param[in] frame_num The mipi frame number. @@ -102,7 +102,7 @@ sh_css_update_host2sp_mipi_metadata( unsigned int frame_num, struct ia_css_metadata *metadata); -/** +/* * @brief Update the nr of mipi frames to use in host_sp_communication. * * @param[in] num_frames The number of mipi frames to use. @@ -110,7 +110,7 @@ sh_css_update_host2sp_mipi_metadata( void sh_css_update_host2sp_num_mipi_frames(unsigned int num_frames); -/** +/* * @brief Update the nr of offline frames to use in host_sp_communication. * * @param[in] num_frames The number of raw frames to use. @@ -170,7 +170,7 @@ sh_css_sp_set_disable_continuous_viewfinder(bool flag); void sh_css_sp_reset_global_vars(void); -/** +/* * @brief Initialize the DMA software-mask in the debug mode. * This API should be ONLY called in the debugging mode. * And it should be always called before the first call of @@ -185,7 +185,7 @@ sh_css_sp_reset_global_vars(void); bool sh_css_sp_init_dma_sw_reg(int dma_id); -/** +/* * @brief Set the DMA software-mask in the debug mode. * This API should be ONLYL called in the debugging mode. Must * call "sh_css_set_dma_sw_reg(...)" before this diff --git a/drivers/staging/media/atomisp/pci/system_global.h b/drivers/staging/media/atomisp/pci/system_global.h index e8a29f73d67a..ee1d9b66ccb1 100644 --- a/drivers/staging/media/atomisp/pci/system_global.h +++ b/drivers/staging/media/atomisp/pci/system_global.h @@ -293,7 +293,7 @@ typedef enum { } stream2mmio_sid_ID_t; /* end of Stream2MMIO */ -/** +/* * Input System 2401: CSI-MIPI recevier. */ typedef enum { @@ -324,7 +324,7 @@ typedef enum { N_ISYS2401_DMA_ID } isys2401_dma_ID_t; -/** +/* * Pixel-generator. ("system_global.h") */ typedef enum { diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c index 862aee993889..06c43b5f8a87 100644 --- a/drivers/staging/media/av7110/av7110.c +++ b/drivers/staging/media/av7110/av7110.c @@ -942,16 +942,16 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) (feed->pes_type <= DMX_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: - if (feed->ts_type & TS_DECODER) - if (feed->pes_type < 2 && - !(demux->pids[0] & 0x8000) && - !(demux->pids[1] & 0x8000)) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - ret = av7110_av_start_play(av7110, RP_AV); - if (!ret) - demux->playing = 1; - } + if (feed->pes_type >= 2 || + (demux->pids[0] & 0x8000) || + (demux->pids[1] & 0x8000)) + break; + + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + ret = av7110_av_start_play(av7110, RP_AV); + if (!ret) + demux->playing = 1; break; default: ret = dvb_feed_start_pid(feed); diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c index cb2f49f3e0fa..601e5a79ef8e 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.c +++ b/drivers/staging/media/ipu7/ipu7-isys.c @@ -233,6 +233,7 @@ static int isys_notifier_init(struct ipu7_isys *isys) err_parse: fwnode_handle_put(ep); + v4l2_async_nf_cleanup(&isys->notifier); return ret; } @@ -773,6 +774,7 @@ static int isys_probe(struct auxiliary_device *auxdev, return 0; out_cleanup: + isys_notifier_cleanup(isys); isys_unregister_devices(isys); out_cleanup_fw: ipu7_fw_isys_release(isys); diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c index 310e3f24e571..48a35bda4237 100644 --- a/drivers/staging/media/ipu7/ipu7.c +++ b/drivers/staging/media/ipu7/ipu7.c @@ -2343,7 +2343,7 @@ static int ipu7_init_fw_code_region_by_sys(struct ipu7_bus_device *sys, return ret; } - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "Failed to get runtime PM\n"); return ret; @@ -2702,7 +2702,7 @@ static int ipu7_resume(struct device *dev) if (ret) dev_err(dev, "IPC reset protocol failed!\n"); - ret = pm_runtime_get_sync(&isp->psys->auxdev.dev); + ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev); if (ret < 0) { dev_err(dev, "Failed to get runtime PM\n"); return 0; diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index a039d925c0fe..c18bf352b199 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -504,8 +504,8 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: fmt_out = find_format(fmts, size, pixmp->pixelformat); if (!fmt_out) { - pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; - fmt_out = find_format(fmts, size, pixmp->pixelformat); + pixmp->pixelformat = fmts[0].pixfmt; + fmt_out = &fmts[0]; } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index bbd186b8035b..96acd52e380c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -285,8 +285,10 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1; ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL); - if (!ctx->ctrls) + if (!ctx->ctrls) { + v4l2_ctrl_handler_free(hdl); return -ENOMEM; + } j = 0; for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c index e513e6ccb776..eb1fc5b7e2cd 100644 --- a/drivers/staging/media/tegra-video/tegra20.c +++ b/drivers/staging/media/tegra-video/tegra20.c @@ -552,7 +552,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan, case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_1), base); - tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), base + chan->start_offset); + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), + base + chan->start_offset); break; /* RAW8 */ case V4L2_PIX_FMT_SRGGB8: @@ -565,7 +566,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan, case V4L2_PIX_FMT_SGBRG10: case V4L2_PIX_FMT_SBGGR10: tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_2), base); - tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), base + chan->start_offset); + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), + base + chan->start_offset); break; } } diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 456134a9e8cf..01622013c109 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -1257,6 +1257,7 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) struct device_node *parent; struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; unsigned int lanes; + int err; int ret = 0; ports = of_get_child_by_name(node, "ports"); @@ -1267,8 +1268,8 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) if (!of_node_name_eq(port, "port")) continue; - ret = of_property_read_u32(port, "reg", &port_num); - if (ret < 0) + err = of_property_read_u32(port, "reg", &port_num); + if (err < 0) continue; if (port_num > vi->soc->vi_max_channels) { @@ -1289,10 +1290,10 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) ep = of_graph_get_endpoint_by_regs(parent, 0, 0); of_node_put(parent); - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), + err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); of_node_put(ep); - if (ret) + if (err) continue; lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; @@ -1468,7 +1469,6 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan, struct tegra_vi *vi = chan->vi; struct tegra_vi_graph_entity *ent; struct fwnode_handle *ep = NULL; - struct v4l2_fwnode_link link; struct media_entity *local = entity->entity; struct media_entity *remote; struct media_pad *local_pad; @@ -1478,70 +1478,64 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan, dev_dbg(vi->dev, "creating links for entity %s\n", local->name); - while (1) { - ep = fwnode_graph_get_next_endpoint(entity->asd.match.fwnode, - ep); - if (!ep) - break; + fwnode_graph_for_each_endpoint(entity->asd.match.fwnode, ep) { + struct fwnode_handle *remote_parent __free(fwnode_handle) = NULL; + struct fwnode_handle *sink_ep __free(fwnode_handle) = NULL; + int src_idx, sink_idx; - ret = v4l2_fwnode_parse_link(ep, &link); - if (ret < 0) { - dev_err(vi->dev, "failed to parse link for %pOF: %d\n", - to_of_node(ep), ret); + src_idx = media_entity_get_fwnode_pad(local, ep, + MEDIA_PAD_FL_SOURCE); + if (src_idx < 0) { + dev_dbg(vi->dev, "no source pad found for %pfw\n", ep); continue; } - if (link.local_port >= local->num_pads) { - dev_err(vi->dev, "invalid port number %u on %pOF\n", - link.local_port, to_of_node(link.local_node)); - v4l2_fwnode_put_link(&link); - ret = -EINVAL; - break; + remote_parent = fwnode_graph_get_remote_port_parent(ep); + if (!remote_parent) { + dev_dbg(vi->dev, "no remote parent found for %pfw\n", + ep); + continue; } - local_pad = &local->pads[link.local_port]; + local_pad = &local->pads[src_idx]; /* Remote node is vi node. So use channel video entity and pad * as remote/sink. */ - if (link.remote_node == of_fwnode_handle(vi->dev->of_node)) { + if (remote_parent == of_fwnode_handle(vi->dev->of_node)) { remote = &chan->video.entity; remote_pad = &chan->pad; goto create_link; } - /* - * Skip sink ports, they will be processed from the other end - * of the link. - */ - if (local_pad->flags & MEDIA_PAD_FL_SINK) { - dev_dbg(vi->dev, "skipping sink port %pOF:%u\n", - to_of_node(link.local_node), link.local_port); - v4l2_fwnode_put_link(&link); - continue; - } - /* find the remote entity from notifier list */ ent = tegra_vi_graph_find_entity(&chan->notifier.done_list, - link.remote_node); + remote_parent); if (!ent) { - dev_err(vi->dev, "no entity found for %pOF\n", - to_of_node(link.remote_node)); - v4l2_fwnode_put_link(&link); + fwnode_handle_put(ep); + dev_err(vi->dev, "no entity found for %pfw\n", + remote_parent); ret = -ENODEV; break; } remote = ent->entity; - if (link.remote_port >= remote->num_pads) { - dev_err(vi->dev, "invalid port number %u on %pOF\n", - link.remote_port, - to_of_node(link.remote_node)); - v4l2_fwnode_put_link(&link); - ret = -EINVAL; - break; + + sink_ep = fwnode_graph_get_remote_endpoint(ep); + if (!sink_ep) { + dev_dbg(vi->dev, "no sink ep found for %pfw\n", + ep); + continue; + } + + sink_idx = media_entity_get_fwnode_pad(remote, sink_ep, + MEDIA_PAD_FL_SINK); + if (sink_idx < 0) { + dev_dbg(vi->dev, "no sink pad found for %pfw\n", + sink_ep); + continue; } - remote_pad = &remote->pads[link.remote_port]; + remote_pad = &remote->pads[sink_idx]; create_link: dev_dbg(vi->dev, "creating %s:%u -> %s:%u link\n", @@ -1551,8 +1545,8 @@ create_link: ret = media_create_pad_link(local, local_pad->index, remote, remote_pad->index, link_flags); - v4l2_fwnode_put_link(&link); if (ret < 0) { + fwnode_handle_put(ep); dev_err(vi->dev, "failed to create %s:%u -> %s:%u link: %d\n", local->name, local_pad->index, @@ -1561,7 +1555,6 @@ create_link: } } - fwnode_handle_put(ep); return ret; } diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c index 9ff1f1750a15..5fba11e31e1d 100644 --- a/drivers/staging/media/tegra-video/vip.c +++ b/drivers/staging/media/tegra-video/vip.c @@ -126,7 +126,7 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) if (!ep) { err = -EINVAL; dev_err_probe(dev, err, "%pOF: error getting endpoint node\n", np); - goto err_node_put; + return err; } fwh = of_fwnode_handle(ep); @@ -134,14 +134,14 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) of_node_put(ep); if (err) { dev_err_probe(dev, err, "%pOF: failed to parse v4l2 endpoint\n", np); - goto err_node_put; + return err; } num_pads = of_graph_get_endpoint_count(np); if (num_pads != TEGRA_VIP_PADS_NUM) { err = -EINVAL; dev_err_probe(dev, err, "%pOF: need 2 pads, got %d\n", np, num_pads); - goto err_node_put; + return err; } vip->chan.of_node = of_node_get(np); @@ -149,10 +149,6 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) vip->chan.pads[TEGRA_VIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; return 0; - -err_node_put: - of_node_put(np); - return err; } static int tegra_vip_channel_init(struct tegra_vip *vip) diff --git a/include/media/cec.h b/include/media/cec.h index 0c8e86115b6f..4c8b0950b377 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -85,7 +85,6 @@ struct cec_event_entry { struct cec_event ev; }; -#define CEC_NUM_CORE_EVENTS 2 #define CEC_NUM_EVENTS CEC_EVENT_PIN_5V_HIGH struct cec_fh { @@ -101,7 +100,6 @@ struct cec_fh { struct list_head events[CEC_NUM_EVENTS]; /* queued events */ u16 queued_events[CEC_NUM_EVENTS]; unsigned int total_queued_events; - struct cec_event_entry core_events[CEC_NUM_CORE_EVENTS]; struct list_head msgs; /* queued messages */ unsigned int queued_msgs; }; @@ -223,6 +221,8 @@ struct cec_adap_ops { * @tx_error_log_cnt: number of logged Error transmits since the adapter was * enabled. Used to avoid flooding the kernel log if this * happens a lot. + * @error_inj_tx_timeouts: error injection: the next @error_inj_tx_timeouts + * transmits will time out. * @notifier: CEC notifier * @pin: CEC pin status struct * @cec_dir: debugfs cec directory @@ -283,6 +283,8 @@ struct cec_adapter { u32 tx_low_drive_log_cnt; u32 tx_error_log_cnt; + u32 error_inj_tx_timeouts; + #ifdef CONFIG_CEC_NOTIFIER struct cec_notifier *notifier; #endif diff --git a/include/media/drv-intf/s3c_camif.h b/include/media/drv-intf/s3c_camif.h index f746851a5ce6..00d83620ea5f 100644 --- a/include/media/drv-intf/s3c_camif.h +++ b/include/media/drv-intf/s3c_camif.h @@ -31,8 +31,6 @@ struct s3c_camif_sensor_info { struct s3c_camif_plat_data { struct s3c_camif_sensor_info sensor; - int (*gpio_get)(void); - int (*gpio_put)(void); }; #endif /* MEDIA_S3C_CAMIF_ */ diff --git a/include/media/drv-intf/saa7146.h b/include/media/drv-intf/saa7146.h index 71ce63c99cb4..b8f2fe5680f0 100644 --- a/include/media/drv-intf/saa7146.h +++ b/include/media/drv-intf/saa7146.h @@ -77,13 +77,10 @@ struct saa7146_pci_extension_data { void *ext_priv; /* most likely a name string */ }; -#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device) \ - { \ - .vendor = PCI_VENDOR_ID_PHILIPS, \ - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, \ - .subvendor = x_vendor, \ - .subdevice = x_device, \ - .driver_data = (unsigned long)& x_var, \ +#define MAKE_EXTENSION_PCI(x_var, x_vendor, x_device) \ + { \ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, (x_vendor), (x_device)),\ + .driver_data = (unsigned long)&(x_var), \ } struct saa7146_extension diff --git a/include/media/media-entity.h b/include/media/media-entity.h index d9b72cd87d52..fa393e840669 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -1387,6 +1387,7 @@ void media_remove_intf_links(struct media_interface *intf); * @entity: entity where the @operation will be called * @operation: type of the operation. Should be the name of a member of * struct &media_entity_operations. + * @args: arguments for the operation. * * This helper function will check if @operation is not %NULL. On such case, * it will issue a call to @operation\(@entity, @args\). diff --git a/include/media/rc-map.h b/include/media/rc-map.h index d90e4611b066..d95ed3e96de2 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -262,7 +262,6 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" #define RC_MAP_GOTVIEW7135 "rc-gotview7135" #define RC_MAP_HAUPPAUGE "rc-hauppauge" -#define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" #define RC_MAP_HISI_POPLAR "rc-hisi-poplar" #define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" #define RC_MAP_IMON_MCE "rc-imon-mce" @@ -309,7 +308,6 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_PROTEUS_2309 "rc-proteus-2309" #define RC_MAP_PURPLETV "rc-purpletv" #define RC_MAP_PV951 "rc-pv951" -#define RC_MAP_RC5_TV "rc-rc5-tv" #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" #define RC_MAP_REDDO "rc-reddo" diff --git a/include/media/rppx1.h b/include/media/rppx1.h new file mode 100644 index 000000000000..2e761046db38 --- /dev/null +++ b/include/media/rppx1.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __MEDIA_DCT_RPPX1_H__ +#define __MEDIA_DCT_RPPX1_H__ + +#include <linux/v4l2-mediabus.h> +#include <linux/media/dreamchip/rppx1-config.h> + +#include <media/videobuf2-core.h> + +struct rppx1; + +struct rppx1 *rppx1_create(void __iomem *base, struct device *dev); + +void rppx1_destroy(struct rppx1 *rpp); + +int rppx1_start(struct rppx1 *rpp, const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *hv, + const struct v4l2_mbus_framefmt *mv); + +int rppx1_stop(struct rppx1 *rpp); + +bool rppx1_interrupt(struct rppx1 *rpp, u32 *isc); + +typedef int (*rppx1_reg_write)(void *priv, u32 offset, u32 value); +int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size, + rppx1_reg_write write, void *priv); + +void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf); + +#endif /* __MEDIA_DCT_RPPX1_H__ */ diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 54c83b18d555..a13dca7c609f 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -736,8 +736,8 @@ long int video_usercopy(struct file *file, unsigned int cmd, * @cmd: Ioctl name. * @arg: Ioctl argument. * - * Method used to hancle an ioctl. Should be used to fill the - * &v4l2_ioctl_ops.unlocked_ioctl on all V4L2 drivers. + * Method used to handle an ioctl. Should be used to fill the + * &v4l2_file_operations.unlocked_ioctl on all V4L2 drivers. */ long int video_ioctl2(struct file *file, unsigned int cmd, unsigned long int arg); diff --git a/include/media/v4l2-isp.h b/include/media/v4l2-isp.h index f3a6d0edcb24..7a54cf98c79a 100644 --- a/include/media/v4l2-isp.h +++ b/include/media/v4l2-isp.h @@ -15,17 +15,21 @@ struct device; struct vb2_buffer; /** - * v4l2_isp_params_buffer_size - Calculate size of v4l2_isp_params_buffer - * @max_params_size: The total size of the ISP configuration blocks + * v4l2_isp_buffer_size - Calculate size of v4l2_isp_buffer + * @max_size: The total size of the ISP configuration or statistics blocks + * + * Users of v4l2-isp will have differing sized data arrays for parameters and + * statistics, depending on their specific blocks. Drivers need to be able to + * calculate the appropriate size of the buffer to accommodate all ISP blocks + * supported by the platform. This macro provides a convenient tool for the + * calculation. + * + * The intended users of this function are drivers initializing the size + * of their metadata (parameters and statistics) buffers. * - * Users of the v4l2 extensible parameters will have differing sized data arrays - * depending on their specific parameter buffers. Drivers and userspace will - * need to be able to calculate the appropriate size of the struct to - * accommodate all ISP configuration blocks provided by the platform. - * This macro provides a convenient tool for the calculation. */ -#define v4l2_isp_params_buffer_size(max_params_size) \ - (offsetof(struct v4l2_isp_params_buffer, data) + (max_params_size)) +#define v4l2_isp_buffer_size(max_size) \ + (offsetof(struct v4l2_isp_buffer, data) + (max_size)) /** * v4l2_isp_params_validate_buffer_size - Validate a V4L2 ISP buffer sizes @@ -49,19 +53,24 @@ int v4l2_isp_params_validate_buffer_size(struct device *dev, size_t max_size); /** - * struct v4l2_isp_params_block_type_info - V4L2 ISP per-block-type info + * struct v4l2_isp_params_block_type_info - V4L2 ISP params per-block-type info * @size: the block type expected size + * @block_validate: driver's callback to implement per-block validation * * The v4l2_isp_params_block_type_info collects information of the ISP - * configuration block types for validation purposes. It currently only contains - * the expected block type size. + * configuration block types for validation purposes. It contains the expected + * block type size and a function pointer where drivers can register a callback + * for additional per-block validation purposes. The validation function is + * expected to return 0 on success or a negative error number for errors. * * Drivers shall prepare a list of block type info, indexed by block type, one * for each supported ISP block type and correctly populate them with the - * expected block type size. + * expected block type size and the optional callback. */ struct v4l2_isp_params_block_type_info { size_t size; + int (*block_validate)(struct device *dev, + const struct v4l2_isp_block_header *block); }; /** @@ -88,4 +97,61 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, const struct v4l2_isp_params_block_type_info *type_info, size_t num_block_types); +/** + * struct v4l2_isp_stats_block_type_info - V4L2 ISP stats per-block-type info + * @size: the block type expected size + * + * The v4l2_isp_stats_block_type_info collects information of the ISP + * statistics block types for validation purposes. It currently only contains + * the expected block size. + * + * Drivers shall prepare a list of statistics block type info, indexed by block + * type, one for each supported ISP statistics block type and correctly populate + * them with the expected block size. + */ +struct v4l2_isp_stats_block_type_info { + size_t size; +}; + +/** + * v4l2_isp_stats_init_buffer - Initialize a statistics buffer + * + * Initialize a buffer of statistics. Only set the 'version' field and reset + * 'data_size' to 0. + * + * @buf: the v4l2_isp_buffer to initialize + * @version: the v4l2-isp serialization format version used by the driver + */ +void v4l2_isp_stats_init_buffer(struct v4l2_isp_buffer *buf, + enum v4l2_isp_version version); + +/** + * v4l2_isp_stats_init_block - Create and initialize a new block in a statistics + * buffer + * @dev: the driver's device pointer + * @buf: the v4l2_isp_buffer where statistics are serialized + * @type_info: the array of per-block-type validation info + * @num_block_types: the number of block types in the type_info array + * @block_type: the type of the statistics block to initialize + * @max_size: the maximum size of the data[] member of @buf + * + * This function locates and initialize a new statistics block in @buf for the + * driver to populate its content. The function checks that enough space for the + * requested @block_type is available in @buf and increments the 'data_size' + * member of @buf. The newly created statistics block's header is initialized + * with the size and type information provided by the caller in @type_info. + * + * Drivers should call this function before populating a new statistics block + * content. + * + * Returns a pointer to the next available location in @buf, or an error pointer + * if the requested @block_size is not available in @buf or @block_type is not + * valid. + */ +struct v4l2_isp_block_header * +v4l2_isp_stats_init_block(struct device *dev, struct v4l2_isp_buffer *buf, + const struct v4l2_isp_stats_block_type_info *type_info, + size_t num_block_types, unsigned int block_type, + size_t max_size); + #endif /* _V4L2_ISP_H_ */ diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 71d2864fb235..d51e10c10fc0 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -72,6 +72,19 @@ struct vb2_v4l2_buffer { */ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp); +/** + * vb2_querybuf() - Query video buffer information + * @q: pointer to &struct vb2_queue with videobuf2 queue. + * @b: buffer structure passed from userspace to + * &v4l2_ioctl_ops->vidioc_querybuf handler in driver + * + * Should be called from vidioc_querybuf ioctl handler in driver. + * This function will verify the passed v4l2_buffer structure and fill the + * relevant information for the userspace. + * + * The return values from this function are intended to be directly returned + * from vidioc_querybuf handler in driver. + */ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b); /** diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 81a05c9c0706..fdfc97a6e4ec 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -403,6 +403,8 @@ struct cec_log_addrs { #define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1) /* CDC-Only device: supports only CDC messages */ #define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2) +/* Configuration failed */ +#define CEC_LOG_ADDRS_FL_CONFIG_FAILED (1 << 3) /** * struct cec_drm_connector_info - tells which drm connector is diff --git a/include/uapi/linux/media/arm/mali-c55-config.h b/include/uapi/linux/media/arm/mali-c55-config.h index 3d335f950eeb..ef0fe17df96e 100644 --- a/include/uapi/linux/media/arm/mali-c55-config.h +++ b/include/uapi/linux/media/arm/mali-c55-config.h @@ -36,6 +36,9 @@ */ #define MALI_C55_MAX_ZONES (15 * 15) +/* Number of RGB gamma LUT entries. */ +#define MALI_C55_NUM_GAMMA_LUT_ELEMENTS 129 + /** * struct mali_c55_ae_1024bin_hist - Auto Exposure 1024-bin histogram statistics * @@ -219,6 +222,9 @@ struct mali_c55_stats_buffer { * @MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP: Auto-white balance gains for AEXP-0 tap * @MALI_C55_PARAM_MESH_SHADING_CONFIG : Mesh shading tables configuration * @MALI_C55_PARAM_MESH_SHADING_SELECTION: Mesh shading table selection + * @MALI_C55_PARAM_BLOCK_CCM: Colour correction matrix + * @MALI_C55_PARAM_BLOCK_GAMMA_FR: Gamma gain and offset for FR pipe + * @MALI_C55_PARAM_BLOCK_GAMMA_DS: Gamma gain and offset for DS pipe */ enum mali_c55_param_block_type { MALI_C55_PARAM_BLOCK_SENSOR_OFFS, @@ -232,6 +238,9 @@ enum mali_c55_param_block_type { MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP, MALI_C55_PARAM_MESH_SHADING_CONFIG, MALI_C55_PARAM_MESH_SHADING_SELECTION, + MALI_C55_PARAM_BLOCK_CCM, + MALI_C55_PARAM_BLOCK_GAMMA_FR, + MALI_C55_PARAM_BLOCK_GAMMA_DS, }; /** @@ -758,6 +767,78 @@ struct mali_c55_params_mesh_shading_selection { }; /** + * struct mali_c55_params_ccm - Coefficients, offsets and gains for the colour + * correction matrix + * + * The colour correction module converts images data from a sensor-specific + * colour space to known one. + * + * Colour correction is applied after demosaicing and each pixel is represented + * as a column vector of the three RGB colour channels on which the following + * operations take place: + * 1) An offset is subtracted from each colour channel + * 2) Each colour channel is multiplied by a gain + * 3) The pixel column vector is multiplied by the colour correction matrix + * + * This struct allows users to configure the coefficients for CCM and the + * per-channel offsets and gains. The nine matrix coefficients are expressed as + * 13 bits signed Q4.8 Sign/Magnitude fixed-point numbers, the three gain + * multipliers are expressed as 12 bits unsigned Q4.8 fixed-point numbers and + * the three offsets are expressed as a 12 bits unsigned integers. + * + * header.type should be set to MALI_C55_PARAM_BLOCK_CCM from + * :c:type:`mali_c55_param_block_type`. + * + * @header: The Mali-C55 parameters block header + * @coeffs: 3x3 color conversion matrix coefficients in sign/magnitude + * Q4.8 format + * @gains: Gains for red, green and blue channels in unsigned Q4.8 format + * @offs: Offsets for red, green and blue channels + */ +struct mali_c55_params_ccm { + struct v4l2_isp_params_block_header header; + __u16 coeffs[3][3]; + __u16 gains[3]; + __u16 offs[3]; +}; + +/** + * struct mali_c55_params_gamma - RGB Gamma correction + * + * Gamma correction is used to program a standard gamma curve such as the sRGB + * one. It provides gains and offsets to implement contrast adjustments. + * + * Gamma correction is applied on both the FR and DS pipes separately in the RGB + * colour domain where the following operations take place: + * 1) An offset is subtracted from each colour channel + * 2) Each colour channel is multiplied by a gain + * 3) The Gamma LUT is applied to each colour channel + * + * The Gamma LUT has 129 entries where each node is an unsigned 12 bit number. + * It is expected that LUT[0]=0 and LUT[128]=0xfff, with the other 127 values + * defining the Gamma correction curve. The three gain multipliers are expressed + * as 12-bits unsigned Q4.8 fixed-point numbers and the three offsets are + * expressed as a 12-bits unsigned integers. + * + * As one Gamma correction block is available on both the FR and DS pipes, the + * header.type field should be set to one of either + * MALI_C55_PARAM_BLOCK_GAMMA_FR or MALI_C55_PARAM_BLOCK_GAMMA_DS from + * :c:type:`mali_c55_param_block_type`. + * + * @header: The Mali-C55 parameters block header + * @gains: Gains for the red, green and blue channel in unsigned Q4.8 format + * @offs: Offsets subtracted from the red, green and blue channels + * in unsigned 12 bits format + * @lut: 129-node Gamma LUT in unsigned 12 bits format + */ +struct mali_c55_params_gamma { + struct v4l2_isp_params_block_header header; + __u16 gains[3]; + __u16 offs[3]; + __u32 lut[MALI_C55_NUM_GAMMA_LUT_ELEMENTS]; +}; + +/** * define MALI_C55_PARAMS_MAX_SIZE - Maximum size of all Mali C55 Parameters * * Though the parameters for the Mali-C55 are passed as optional blocks, the @@ -780,6 +861,9 @@ struct mali_c55_params_mesh_shading_selection { sizeof(struct mali_c55_params_awb_config) + \ sizeof(struct mali_c55_params_awb_gains) + \ sizeof(struct mali_c55_params_mesh_shading_config) + \ - sizeof(struct mali_c55_params_mesh_shading_selection)) + sizeof(struct mali_c55_params_mesh_shading_selection) + \ + sizeof(struct mali_c55_params_ccm) + \ + sizeof(struct mali_c55_params_gamma) + \ + sizeof(struct mali_c55_params_gamma)) #endif /* __UAPI_MALI_C55_CONFIG_H */ diff --git a/include/uapi/linux/media/dreamchip/rppx1-config.h b/include/uapi/linux/media/dreamchip/rppx1-config.h new file mode 100644 index 000000000000..3507a9ab03df --- /dev/null +++ b/include/uapi/linux/media/dreamchip/rppx1-config.h @@ -0,0 +1,730 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Dreamchip RPP-X1 ISP Driver - Userspace API + * + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __UAPI_RPP_X1_CONFIG_H +#define __UAPI_RPP_X1_CONFIG_H + +#include <linux/media/v4l2-isp.h> + +/** + * struct rppx1_window - Measurement window + * + * RPP-X1 measurement window. Different blocks use a window or multiple + * windows for measurement purposes. This defines a common type for all of + * them. The number of relevant bits depends on the block where the window is + * used and is specified in the per-block description + * + * @h_offs: horizontal offset from the left of the frame in pixels + * @v_offs: vertical offset from the top of the frame in pixels + * @h_size: horizontal size of the window in pixels + * @v_size: vertical size of the window in pixels + */ +struct rppx1_window { + __u16 h_offs; + __u16 v_offs; + __u16 h_size; + __u16 v_size; +}; + +/** + * enum rppx1_meas_chan - Measurement point for the Histogram and EXM Modules + * + * Measurement points for the RPP-X1 Histogram measurement module and Exposure + * measurement module. + * + * All tap points are available for the PRE1/PRE2 pipes. Only + * RPPX1_MEAS_CHAN_SEL4 and RPPX1_MEAS_CHAN_SEL7 are available for the + * MAIN_POST pipe. + * + * @RPPX1_MEAS_CHAN_SEL0: after input acquisition + * @RPPX1_MEAS_CHAN_SEL1: after black level subtraction + * @RPPX1_MEAS_CHAN_SEL2: after sensor gamma linearization + * @RPPX1_MEAS_CHAN_SEL3: after lens shading correction + * @RPPX1_MEAS_CHAN_SEL4: after auto white balance gains + * @RPPX1_MEAS_CHAN_SEL5: after defect pixel correction + * @RPPX1_MEAS_CHAN_SEL6: after denoise pre-filter + * @RPPX1_MEAS_CHAN_SEL7: after demosaicing + */ +enum rppx1_meas_chan { + RPPX1_MEAS_CHAN_SEL0, + RPPX1_MEAS_CHAN_SEL1, + RPPX1_MEAS_CHAN_SEL2, + RPPX1_MEAS_CHAN_SEL3, + RPPX1_MEAS_CHAN_SEL4, + RPPX1_MEAS_CHAN_SEL5, + RPPX1_MEAS_CHAN_SEL6, + RPPX1_MEAS_CHAN_SEL7, +}; + +/* --------------------------------------------------------------------------- + * Parameter Structures + * + * The same ISP block might be instantiated in multiple pipeliness and operate + * on a different bitdepth/precision. For fields of varying length among + * different instances of the same block, use a data type that can accommodate + * the larger bitdepth/precision. + */ + +/** + * enum rppx1_params_block_type - RPP-X1 extensible params block types + * + * NOTE: Only append to the enumeration as the numbers are uAPI. + * + * @RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST: AWB Measurement Configuration + * @RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1: PRE1 pipe White Balance Gains + * @RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE2: PRE2 White Balance Gains + * @RPPX1_PARAMS_BLOCK_TYPE_AWBG_POST: MAIN_POST White Balance Gains + * @RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1: PRE1 pipe Exposure Measurement + * @RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE2: PRE2 pipe Exposure Measurement + * @RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1: PRE1 pipe Histogram Measurement + * @RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2: PRE2 pipe Histogram Measurement + * @RPPX1_PARAMS_BLOCK_TYPE_HIST_POST: POST pipe Histogram Measurement + * @RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: PRE1 pipe Black Level Subtraction + * @RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2: PRE2 pipe Black Level Subtraction + * @RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST: POST pipe Color Correction + * @RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE1: PRE1 pipe Lens Shading Correction + * @RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE2: PRE2 pipe Lens Shading Correction + * @RPPX1_PARAMS_BLOCK_TYPE_GA_HV: Human Vision Pipe Gamma Out Correction + * @RPPX1_PARAMS_BLOCK_TYPE_GA_MV: Machine Vision Gamma Out Correction + * @RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1: PRE1 pipe Linearization (Sensor De-gamma) + * @RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2: PRE2 pipe Linearization (Sensor De-gamma) + */ +enum rppx1_params_block_type { + RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST, + RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE2, + RPPX1_PARAMS_BLOCK_TYPE_AWBG_POST, + RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE2, + RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2, + RPPX1_PARAMS_BLOCK_TYPE_HIST_POST, + RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2, + RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST, + RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE2, + RPPX1_PARAMS_BLOCK_TYPE_GA_HV, + RPPX1_PARAMS_BLOCK_TYPE_GA_MV, + RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1, + RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2, +}; + +/** + * enum rppx1_wbmeas_mode - AWB measurement mode + * + * @RPPX1_WBMEAS_MODE_YCBCR: YCbCr measurement mode + * @RPPX1_WBMEAS_MODE_RGB: RGB measurement mode + */ +enum rppx1_wbmeas_mode { + RPPX1_WBMEAS_MODE_YCBCR, + RPPX1_WBMEAS_MODE_RGB, +}; + +/** + * struct rppx1_wbmeas_params - AWB measurement configuration + * + * The Auto-White Balance measurement module is available on the MAIN_POST pipe. + * It supports two measurement modes, selected by the @mode field. The + * measurement window is programmed through the @wnd field. + * + * To support measurement in YCbCr mode a color conversion matrix with + * programmable offset is available in the @ccor_coeff and @ccor_offs fields. + * The color conversion matrix coefficients are represented as 16 bits signed + * Q4.12 numbers ranging from -8 to +7.99. The per-color channel offsets are + * represented as 25 bits 2's complement integer numbers ranging from -16777216 + * to +16777215. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST) + * @wnd: measurement window + * @mode: measurement mode (from enum rppx1_wbmeas_mode) + * @ymax_cmp: enable Y_MAX compare using @max_y + * @frames: number of frames for mean value calculation (0 = 1 frame) + * @reserved: padding + * @ref_cr_max_r: reference Cr or max red value in RGB mode, 24 bits + * @ref_cb_max_b: reference Cb or max blue value in RGB mode, 24 bits + * @min_y_max_g: luminance minimum value or max green value in RGB mode, 24 bits + * @max_y: luminance maximum value, only valid if @mode is set to YCbCr and + * @ymax_cmp is set to enabled, 24 bits + * @max_csum: chrominance sum maximum value, 24 bits + * @min_c: chrominance minimum value, 24 bits + * @ccor_coeff: coefficients for color conversion matrix, signed 16 bits Q4.6 + * @reserved2: padding + * @ccor_offs: R-G-B color conversion coefficients, signed 25 bits 2's complement + * @reserved3: padding + */ +struct rppx1_wbmeas_params { + struct v4l2_isp_params_block_header header; + struct rppx1_window wnd; + __u8 mode; + __u8 ymax_cmp; + __u8 frames; + __u8 reserved; + __u32 ref_cr_max_r; + __u32 ref_cb_max_b; + __u32 min_y_max_g; + __u32 max_y; + __u32 max_csum; + __u32 min_c; + __u16 ccor_coeff[3][3]; + __u16 reserved2; + __u32 ccor_offs[3]; + __u32 reserved3; +}; + +/** + * struct rppx1_awbg_params - WB gain configuration + * + * The RPP-X1 White Balance Gain module is available in the PRE1 and PRE2 + * pre-fusion pipes and in the MAIN_POST post-fusion pipe. Userspace selects + * which pipe to operate by setting the @header.type field to + * RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1, RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE2 + * or RPPX1_PARAMS_BLOCK_TYPE_AWBG_POST. + * + * The White Balance module allows to specify per-color channel gains, expressed + * as unsigned fixed-point values as 18 bits unsigned integers in Q6.12 format + * with a maximum of 63.999. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1 or + * type = RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE2 or + * type = RPPX1_PARAMS_BLOCK_TYPE_AWBG_POST) + * @gain_red: gain for red component, 18-bit (unsigned Q6.12) + * @gain_green_r: gain for green component in red lines, 18-bit (unsigned Q6.12) + * @gain_blue: gain for blue component, 18-bit (unsigned Q6.12) + * @gain_green_b: gain for green component in blue lines, 18-bit (unsigned Q6.12) + */ +struct rppx1_awbg_params { + struct v4l2_isp_params_block_header header; + __u32 gain_red; + __u32 gain_green_r; + __u32 gain_blue; + __u32 gain_green_b; +}; + +/** + * enum rppx1_exm_mode - Exposure measurement mode + * + * Exaposure measurement mode selection (RGB/Bayer). + * + * @RPPX1_EXP_MEASURING_MODE_DISABLED: no measurement + * @RPPX1_EXP_MEASURING_MODE_RGB: Y/R/G/B measurement + * @RPPX1_EXP_MEASURING_MODE_BAYER: Bayer RGB measurement + */ +enum rppx1_exm_mode { + RPPX1_EXP_MEASURING_MODE_DISABLED, + RPPX1_EXP_MEASURING_MODE_RGB, + RPPX1_EXP_MEASURING_MODE_BAYER, +}; + +/** + * struct rppx1_exm_params - Exposure measurement configuration + * + * The RPP-X1 Exposure measurement unit is available on the PRE1 and PRE2 + * pre-fusion pipes. Userspace selects which pipe to operate by setting + * the @header.type field to RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1 or + * RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE2. + * + * Exposure measurement is performed in the RGB or Bayer domain, according to + * the setting of the @mode field. The exposure measurement tap point is + * selected according to the value of @channel_sel. + * + * The exposure measurement is performed on an input window specified in @wnd. + * To each color component a programmable weight coefficient is associated. + * Coefficients are represented as unsigned 8 bits integer values in Q1.7 format + * ranging from 0 to 1.992. + * + * The @last_line fields controls when the exposure measurement completes. It + * is usually programmed to the value of (@wnd.v_offs + @wnd.v_size + 1). + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1 or + * type = RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE2) + * @wnd: measurement window coordinates + * @mode: exposure measure mode (from enum rppx1_exm_mode) + * @last_line: line number for which the exposure measurement completes + * @channel_sel: exposure measurement point (see enum rppx1_meas_chan) + * @coeff_r: coefficient for the red Bayer sample or red color channel, Q1.7 + * @coeff_g_gr: coefficient for the green/red Bayer sample or green color channel, Q1.7 + * @coeff_b: coefficient for the blue Bayer sample or blue color channel, Q1.7 + * @coeff_gb: coefficient for the green/blue Bayer sample, unused in RGB mode, Q1.7 + * @reserved: padding + */ +struct rppx1_exm_params { + struct v4l2_isp_params_block_header header; + struct rppx1_window wnd; + __u32 mode; + __u32 last_line; + __u8 channel_sel; + __u8 coeff_r; + __u8 coeff_g_gr; + __u8 coeff_b; + __u8 coeff_gb; + __u8 reserved[3]; +}; + +/* Histogram */ +#define RPPX1_HIST_WEIGHT_GRIDS_SIZE 25 + +/** + * enum rppx1_hist_mode - Histogram measurement mode + * + * Histogram measurement mode. Select which channel or combination of channels + * the histogram measurement is performed on. + * + * @RPPX1_HIST_MODE_DISABLE: histogram disabled + * @RPPX1_HIST_MODE_RGB_COMBINED: combined RGB histogram + * @RPPX1_HIST_MODE_R_HISTOGRAM: red channel histogram + * @RPPX1_HIST_MODE_GR_HISTOGRAM: green/red channel histogram + * @RPPX1_HIST_MODE_B_HISTOGRAM: blue channel histogram + * @RPPX1_HIST_MODE_GB_HISTOGRAM: green/blue histogram + */ +enum rppx1_hist_mode { + RPPX1_HIST_MODE_DISABLE, + RPPX1_HIST_MODE_RGB_COMBINED, + RPPX1_HIST_MODE_R_HISTOGRAM, + RPPX1_HIST_MODE_GR_HISTOGRAM, + RPPX1_HIST_MODE_B_HISTOGRAM, + RPPX1_HIST_MODE_GB_HISTOGRAM, +}; + +/** + * struct rppx1_hist_params - Histogram measurement configuration + * + * The RPP-X1 Histogram measurement unit is available on the PRE1, PRE2 and + * MAIN_POST pipes. Userspace selects which pipe to operate by setting the + * @header.type field to RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1, + * RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2 or + * RPPX1_PARAMS_BLOCK_TYPE_HIST_POST. + * + * The histogram measurement point is selected using the @channel field while + * histogram measurement mode is selected using the @mode field. + * + * Histogram measurement is performed by programming subsampling factors using + * the @v_stepsize and @h_step_inc fields and by weighted windowing, by + * programming the size of the measurement window @wnd with @weights associated + * to each cell of the 5x5 measurement grid. Weights are represented as 5 bits + * integer values ranging from 0 to 16. + * + * The @last_line fields controls when the histogram measurement completes. It + * is usually programmed to the value of (@wnd.v_offs + @wnd.v_size - 1). + * + * Histogram values are calculated by applying a per-color channel coefficient + * represented as an 8 bits unsigned Q1.7 integer value. The @sample_offs and + * @sample_shift fields allow to reduce the color dynamic range on which + * histogram data are produced. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE1, + * type = RPPX1_PARAMS_BLOCK_TYPE_HIST_PRE2 or + * type = RPPX1_PARAMS_BLOCK_TYPE_HIST_POST) + * @wnd: measurement window coordinates + * @last_line: line number for which the histogram measurement completes + * @v_stepsize: vertical subsampling divider, 7 bits + * @h_step_inc: horizontal subsampling step counter, 17 bits + * @sample_offs: sample offset, 24 bits + * @mode: histogram measurement mode (from enum rppx1_hist_mode) + * @channel_sel: histogram measurement point (see enum rppx1_meas_chan) + * @weights: weighting factors for each sub-window (5x5 grid) + * @coeff: R-G-B coefficients, 8 bits unsigned Q1.7 + * @sample_shift: sample shift, 4 bits + * @reserved: padding + */ +struct rppx1_hist_params { + struct v4l2_isp_params_block_header header; + struct rppx1_window wnd; + __u32 last_line; + __u32 v_stepsize; + __u32 h_step_inc; + __u32 sample_offs; + __u8 mode; + __u8 channel_sel; + __u8 weights[RPPX1_HIST_WEIGHT_GRIDS_SIZE]; + __u8 coeff[3]; + __u8 sample_shift; + __u8 reserved; +}; + +/** + * struct rppx1_bls_fixed - BLS fixed subtraction values + * + * Fixed black level values subtracted from sensor data per Bayer channel. + * Negative values result in addition. + * + * The PRE1 pipe BLS module operates on a 24-bits input data and fixed black + * levels are stored as a signed 2's complement representation ranging from + * -2^24 to 2^24-1. + * + * The PRE2 pipe BLS module operates on a 12-bits input data and fixed black + * levels are stored as a signed 2's complement representation ranging from + * -2^12 to 2^12-1. + * + * Userspace is expected to provide fixed black level values with a bit-depth + * matching the one of pipe in use. + * + * These subtraction values are matched with the sensor native Bayer components + * ordering according to the cropping configuration on the input port. + * + * @a: subtraction value for channel A + * @b: subtraction value for channel B + * @c: subtraction value for channel C + * @d: subtraction value for channel D + */ +struct rppx1_bls_fixed { + __u32 a; + __u32 b; + __u32 c; + __u32 d; +}; + +/** + * enum rppx1_bls_mode - BLS subtraction mode + * + * Select if subtracted black level come from fixed or measured values. + * + * @RPPX1_BLS_MODE_FIXED: subtract fixed values + * @RPPX1_BLS_MODE_MEAS: subtract measured values + */ +enum rppx1_bls_mode { + RPPX1_BLS_MODE_FIXED, + RPPX1_BLS_MODE_MEAS, +}; + +/** + * enum rppx1_bls_win_en: BLS measurement configuration + * + * Select the measurement window to use for measured black level values. + * + * @RPPX1_BLS_WIN_EN_OFF: disable measurement + * @RPPX1_BLS_WIN_EN_WIN1: Enable measurement from window 1 + * @RPPX1_BLS_WIN_EN_WIN2: enable measurement from window 2 + * @RPPX1_BLS_WIN_EN_WIN12: enable measurement from window 1 and window 2 + */ +enum rppx1_bls_win_en { + RPPX1_BLS_WIN_EN_OFF, + RPPX1_BLS_WIN_EN_WIN1, + RPPX1_BLS_WIN_EN_WIN2, + RPPX1_BLS_WIN_EN_WIN12, +}; + +/** + * struct rppx1_bls_params - RPP-X1 Black Level Subtraction Module + * + * The RPP-X1 Black Level Subtraction module is available on the PRE1 and PRE2 + * pre-fusion pipes. Userspace selects which pipe to operate by setting the + * @header.type field to RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1 or + * RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2. + * + * The BLS module operates on fixed or measured data according to the setting of + * the @mode field. When RPPX1_BLS_MODE_FIXED is used userspace shall provide + * the per-channel black levels in @fixed. When RPPX1_BLS_MODE_MEAS is used + * userspace shall configure the measurement windows @window1 and optionally + * @window2 to select the optically black pixels region in the input frame. The + * @samples fields controls how many measure samples are used for averaging the + * measured black levels. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1 or + * type == RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2) + * @window1: BLS measurement window 1 (14 bits) + * @window2: BLS measurement window 2 (14 bits) + * @fixed: fixed subtraction values (see enum rppx1_bls_fixed) + * @mode: BLS subtraction mode (see enum rppx1_bls_mode) + * @en_windows: BLS measurement mode (see rppx1_bls_win_en) + * @samples: log2 of the number of measured pixels per Bayer position + * @reserved: padding + */ +struct rppx1_bls_params { + struct v4l2_isp_params_block_header header; + struct rppx1_window window1; + struct rppx1_window window2; + struct rppx1_bls_fixed fixed; + __u8 mode; + __u8 en_windows; + __u8 samples; + __u8 reserved[5]; +}; + +/** + * struct rppx1_ccor_params - Color CORrection configuration + * + * The CCOR (Color Correction) module is available on the MAIN_POST pipe. It + * performs color space correction on a pixel-per-pixel basis using a 3x3 matrix + * of coefficients and per-color channel offsets. + * + * The matrix coefficients are represented as 16 bits signed fixed point values + * in Q4.12 format ranging from -8 to +7.999. + * + * The per-channel color offsets are represented as 2's complement values + * stored in 25 bits ranging from -16777216 to 16777215. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST) + * @coeff: color correction matrix coefficients, 16 bits signed Q4.12 + * @reserved: padding + * @offset: R, G, B offsets, 2's complement 25 bits + */ +struct rppx1_ccor_params { + struct v4l2_isp_params_block_header header; + __u16 coeff[3][3]; + __u16 reserved; + __u32 offset[3]; +}; + +/* Lens Shade Correction */ +#define RPPX1_LSC_SAMPLES_MAX 17 +#define RPPX1_LSC_NUM_SECTORS 16 + +/** + * struct rppx1_lsc_params - Lens Shading Correction configuration + * + * The RPP-X1 Lens shading correction module is available on the PRE1 and PRE2 + * pre-fusion pipes. Userspace selects which pipe to operate by setting the + * @header.type field to RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE1 or + * RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE2. + * + * The module applies per-color channel correction factors @r_data, @gr_data, + * @gb_data and @b_data as a 16x16 grid mapped on the image. The size of each + * grid segment is expressed by the @x_sect_size and @y_sect_size arrays. Each + * segment shall be at least 8 pixels in size and the sum of all horizontal + * segments @x_sect_size shall match the input frame size width. + * + * The correction factors values are expressed as unsigned Q2.10 integers + * ranging from 1 to 3.999. + * + * Pre-calculated interpolation factors shall be provided in the @x_grad + * and @y_grad fields, expressed as 12 bits integer values. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_LSC) + * @r_data: correction factors for the red channel in Q2.10 format + * @gr_data: correction factors for the green (red) channel in Q2.10 format + * @gb_data: correction factors for the green (blue) channel in Q2.10 format + * @b_data: correction factors for the blue channel in Q2.10 format + * @x_grad: Interpolation gradients for each horizontal sector (12 bits) + * @y_grad: Interpolation gradients for each vertical sector (12 bits) + * @x_sect_size: Horizontal sectors sizes + * @y_sect_size: Vertical sectors sizes + */ +struct rppx1_lsc_params { + struct v4l2_isp_params_block_header header; + __u16 r_data[RPPX1_LSC_SAMPLES_MAX][RPPX1_LSC_SAMPLES_MAX]; + __u16 gr_data[RPPX1_LSC_SAMPLES_MAX][RPPX1_LSC_SAMPLES_MAX]; + __u16 gb_data[RPPX1_LSC_SAMPLES_MAX][RPPX1_LSC_SAMPLES_MAX]; + __u16 b_data[RPPX1_LSC_SAMPLES_MAX][RPPX1_LSC_SAMPLES_MAX]; + __u16 x_grad[RPPX1_LSC_NUM_SECTORS]; + __u16 y_grad[RPPX1_LSC_NUM_SECTORS]; + __u16 x_sect_size[RPPX1_LSC_NUM_SECTORS]; + __u16 y_sect_size[RPPX1_LSC_NUM_SECTORS]; +}; + +/* Gamma Out */ +#define RPPX1_GA_MAX_SAMPLES 17 + +/** + * enum rppx1_ga_seg_mode - Gamma out curve segmentation mode + * + * Segmentation mode of the 16 input sampling points for the Gamma Out + * Correction module. + * + * @RPPX1_GA_SEG_MODE_LOGARITHMIC: logarithmic-like segmentation mode + * @RPPX1_GA_SEG_MODE_EQUIDISTANT: equidistant segmentation mode + */ +enum rppx1_ga_seg_mode { + RPPX1_GA_SEG_MODE_LOGARITHMIC, + RPPX1_GA_SEG_MODE_EQUIDISTANT +}; + +/** + * struct rppx1_ga_params - Gamma Out Correction configuration + * + * The Gamma Out Correction module is available on the Human Vision Output + * Pipe (HV) and the Machine Vision Output Pipe (MV). Userspace selects + * which pipe to operate by setting the @header.type field to + * RPPX1_PARAMS_BLOCK_TYPE_GA_HV or RPPX1_PARAMS_BLOCK_TYPE_GA_MV. + * + * The module allows to apply a @gamma_y gamma correction curve to RGB data + * represented as a table of 16 entries. The 16 input sampling points can be + * equidistant or segmented using a logarithmic scale according to the value of + * @mode. + * + * The gamma curve values are 12 bits on the HV output pipe and 24 bits on the + * MV output pipe. Userspace is expected to provide the curve values with a + * bit-depth matching the one of pipe in use. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_GA_HV or + * type = RPPX1_PARAMS_BLOCK_TYPE_GA_MV) + * @gamma_y: gamma out curve y-axis values + * @mode: gamma curve input segmentation mode (see rppx1_ga_seg_mode) + * @reserved: padding + */ +struct rppx1_ga_params { + struct v4l2_isp_params_block_header header; + __u32 gamma_y[RPPX1_GA_MAX_SAMPLES]; + __u8 mode; + __u8 reserved[3]; +}; + +/* Linearization (Sensor De-gamma) */ +#define RPPX1_LIN_SAMPLE_POINTS_NUM 16 +#define RPPX1_LIN_DEGAMMA_CURVE_NUM 17 + +/** + * struct rppx1_lin_params - Linearization (Sensor De-gamma) configuration + * + * The RPP-X1 linearization module is available on the PRE1 and PRE2 pre-fusion + * pipes. Userspace selects which pipe to operate by setting the @header.type + * field to RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1 or + * RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2. + * + * The LIN module applies the per-color channel de-gamma linearization curves + * @curve_r, @curve_g and @curve_b defined on the input sampling points @dx. + * + * For the PRE1 pipe the de-gamma curves values are 24-bits, for the PRE2 pipe + * the de-gamma curve values are 12-bits. + * + * For the PRE1 pipe de-gamma module sampling points @dx values are in the range + * [0, 15] (4 bits). For the PRE2 pipe de-gamma module sampling points values + * are in the range [0, 7] (3 bits). + * + * Userspace is expected to provide the curve values and sampling points with a + * bit-depth matching the one of pipe in use. + * + * @header: block header (type = RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1 or + * RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2) + * @curve_r: de-gamma linearization curve for red channel + * @curve_g: de-gamma linearization curve for green channel + * @curve_b: de-gamma linearization curve for blue channel + * @dx: input sampling points + * @reserved: padding + */ +struct rppx1_lin_params { + struct v4l2_isp_params_block_header header; + __u32 curve_r[RPPX1_LIN_DEGAMMA_CURVE_NUM]; + __u32 curve_g[RPPX1_LIN_DEGAMMA_CURVE_NUM]; + __u32 curve_b[RPPX1_LIN_DEGAMMA_CURVE_NUM]; + __u8 dx[RPPX1_LIN_SAMPLE_POINTS_NUM]; + __u32 reserved; +}; + +/** + * RPPX1_PARAMS_MAX_SIZE - Maximum size of all RPP-X1 parameter blocks + * + * Some types are reported twice as the same block might be instantiated in + * multiple pipes. + */ +#define RPPX1_PARAMS_MAX_SIZE \ + (sizeof(struct rppx1_wbmeas_params) + \ + sizeof(struct rppx1_awbg_params) + \ + sizeof(struct rppx1_awbg_params) + \ + sizeof(struct rppx1_awbg_params) + \ + sizeof(struct rppx1_exm_params) + \ + sizeof(struct rppx1_exm_params) + \ + sizeof(struct rppx1_hist_params) + \ + sizeof(struct rppx1_hist_params) + \ + sizeof(struct rppx1_hist_params) + \ + sizeof(struct rppx1_bls_params) + \ + sizeof(struct rppx1_bls_params) + \ + sizeof(struct rppx1_ccor_params) + \ + sizeof(struct rppx1_lsc_params) + \ + sizeof(struct rppx1_lsc_params) + \ + sizeof(struct rppx1_ga_params) + \ + sizeof(struct rppx1_ga_params) + \ + sizeof(struct rppx1_lin_params) + \ + sizeof(struct rppx1_lin_params)) + +/* --------------------------------------------------------------------------- + * Statistics Structures + * + * The same ISP block might be instantiated in multiple pipeliness and operate + * on a different bitdepth/precision. For fields of varying length among + * different instances of the same block, use a data type that can accommodate + * the larger bitdepth/precision. + */ + +/** + * enum rppx1_stats_block_type - RPP-X1 extensible stats block types + * + * NOTE: Only append to the enumeration as the numbers are uAPI. + * + * @RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST: post-fusion white-balance measurement + * @RPPX1_STATS_BLOCK_TYPE_EXM_PRE1: pre-fusion pipe1 exposure measurement + * @RPPX1_STATS_BLOCK_TYPE_EXM_PRE2: pre-fusion pipe2 exposure measurement + * @RPPX1_STATS_BLOCK_TYPE_HIST_PRE1: pre-fusion pipe1 histogram + * @RPPX1_STATS_BLOCK_TYPE_HIST_PRE2: pre-fusion pipe2 histogram + * @RPPX1_STATS_BLOCK_TYPE_HIST_POST: post-fusion histogram + */ +enum rppx1_stats_block_type { + RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST, + RPPX1_STATS_BLOCK_TYPE_EXM_PRE1, + RPPX1_STATS_BLOCK_TYPE_EXM_PRE2, + RPPX1_STATS_BLOCK_TYPE_HIST_PRE1, + RPPX1_STATS_BLOCK_TYPE_HIST_PRE2, + RPPX1_STATS_BLOCK_TYPE_HIST_POST, +}; + +/** + * struct rppx1_wbmeas_stats - AWB statistics + * + * @header: block header (type = RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST) + * @cnt: Number of pixels matched + * @mean_y_or_g: mean Y (or G in RGB mode) value, 24-bit + * @mean_cb_or_b: mean Cb (or B in RGB mode) value, 24-bit + * @mean_cr_or_r: mean Cr (or R in RGB mode) value, 24-bit + */ +struct rppx1_wbmeas_stats { + struct v4l2_isp_block_header header; + __u32 cnt; + __u32 mean_y_or_g; + __u32 mean_cb_or_b; + __u32 mean_cr_or_r; +}; + +/* Exposure Measurement */ +#define RPPX1_EXM_NUM_WIN 25 + +/** + * struct rppx1_exm_stats - Exposure measurement + * + * RPP-X1 exposure measurement calculates the mean value on 25 programmable + * windows on the input picture. + * + * @header: block header (type = RPPX1_STATS_BLOCK_TYPE_EXM_PRE1) + * @exp_mean: mean luminance values per block, up to 20-bit + * @reserved: padding + */ +struct rppx1_exm_stats { + struct v4l2_isp_block_header header; + __u32 exp_mean[RPPX1_EXM_NUM_WIN]; + __u32 reserved; +}; + +/* Histogram */ +#define RPPX1_HIST_NUM_BINS 32 + +/** + * struct rppx1_hist_stats - Histogram statistics + * + * @header: block header (type = RPPX1_STATS_BLOCK_TYPE_HIST_POST) + * @hist_bins: accumulation histogram results in unsigned 20-bit Q16.4 format + */ +struct rppx1_hist_stats { + struct v4l2_isp_block_header header; + __u32 hist_bins[RPPX1_HIST_NUM_BINS]; +}; + +/** + * RPPX1_STATS_MAX_SIZE - Maximum size of all RPP-X1 statistics + * + * Some types are reported twice as the same block might be instantiated in + * multiple pipes. + */ +#define RPPX1_STATS_MAX_SIZE \ + (sizeof(struct rppx1_wbmeas_stats) + \ + sizeof(struct rppx1_exm_stats) + \ + sizeof(struct rppx1_exm_stats) + \ + sizeof(struct rppx1_hist_stats) + \ + sizeof(struct rppx1_hist_stats) + \ + sizeof(struct rppx1_hist_stats)) + +#endif /* __UAPI_RPP_X1_CONFIG_H */ diff --git a/include/uapi/linux/media/v4l2-isp.h b/include/uapi/linux/media/v4l2-isp.h index 779168f9058e..e4607e1217e1 100644 --- a/include/uapi/linux/media/v4l2-isp.h +++ b/include/uapi/linux/media/v4l2-isp.h @@ -13,25 +13,33 @@ #include <linux/types.h> /** - * enum v4l2_isp_params_version - V4L2 ISP parameters versioning + * enum v4l2_isp_version - V4L2 ISP serialization format versioning * - * @V4L2_ISP_PARAMS_VERSION_V0: First version of the V4L2 ISP parameters format - * (for compatibility) - * @V4L2_ISP_PARAMS_VERSION_V1: First version of the V4L2 ISP parameters format + * @V4L2_ISP_VERSION_V0: First version of the V4L2 ISP serialization format + * (for compatibility) + * @V4L2_ISP_VERSION_V1: First version of the V4L2 ISP serialization format * * V0 and V1 are identical in order to support drivers compatible with the V4L2 - * ISP parameters format already upstreamed which use either 0 or 1 as their - * versioning identifier. Both V0 and V1 refers to the first version of the - * V4L2 ISP parameters format. + * ISP format already upstreamed which use either 0 or 1 as their versioning + * identifier. Both V0 and V1 refers to the first version of the V4L2 ISP + * serialization format. * - * Future revisions of the V4L2 ISP parameters format should start from the + * Future revisions of the V4L2 ISP serialization format should start from the * value of 2. */ -enum v4l2_isp_params_version { - V4L2_ISP_PARAMS_VERSION_V0 = 0, - V4L2_ISP_PARAMS_VERSION_V1 +enum v4l2_isp_version { + V4L2_ISP_VERSION_V0 = 0, + V4L2_ISP_VERSION_V1 }; +/* + * Compatibility with existing users of v4l2_isp_params which pre-date the + * introduction of v4l2_isp_stats. + */ +#define v4l2_isp_params_version v4l2_isp_version +#define V4L2_ISP_PARAMS_VERSION_V0 V4L2_ISP_VERSION_V0 +#define V4L2_ISP_PARAMS_VERSION_V1 V4L2_ISP_VERSION_V1 + #define V4L2_ISP_PARAMS_FL_BLOCK_DISABLE (1U << 0) #define V4L2_ISP_PARAMS_FL_BLOCK_ENABLE (1U << 1) @@ -39,64 +47,89 @@ enum v4l2_isp_params_version { * Reserve the first 8 bits for V4L2_ISP_PARAMS_FL_* flag. * * Driver-specific flags should be defined as: - * #define DRIVER_SPECIFIC_FLAG0 ((1U << V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(0)) - * #define DRIVER_SPECIFIC_FLAG1 ((1U << V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(1)) + * #define DRIVER_SPECIFIC_FLAG0 ((1U << V4L2_ISP_FL_DRIVER_FLAGS(0)) + * #define DRIVER_SPECIFIC_FLAG1 ((1U << V4L2_ISP_FL_DRIVER_FLAGS(1)) */ -#define V4L2_ISP_PARAMS_FL_DRIVER_FLAGS(n) ((n) + 8) +#define V4L2_ISP_FL_DRIVER_FLAGS(n) ((n) + 8) /** - * struct v4l2_isp_params_block_header - V4L2 extensible parameters block header - * @type: The parameters block type (driver-specific) + * struct v4l2_isp_block_header - V4L2 extensible block header + * @type: The parameters or statistics block type (driver-specific) * @flags: A bitmask of block flags (driver-specific) - * @size: Size (in bytes) of the parameters block, including this header + * @size: Size (in bytes) of the block, including this header * - * This structure represents the common part of all the ISP configuration - * blocks. Each parameters block shall embed an instance of this structure type - * as its first member, followed by the block-specific configuration data. + * This structure represents the common part of all the ISP configuration or + * statistic blocks. Each block shall embed an instance of this structure type + * as its first member, followed by the block-specific configuration or + * statistic data. * * The @type field is an ISP driver-specific value that identifies the block - * type. The @size field specifies the size of the parameters block. + * type. The @size field specifies the size of the block, including this + * header. * - * The @flags field is a bitmask of per-block flags V4L2_PARAMS_ISP_FL_* and - * driver-specific flags specified by the driver header. + * The @flags field is a bitmask of per-block flags. If a block is used for + * configuration parameters this field can be a combination of + * V4L2_ISP_PARAMS_FL_* and driver-specific flags. If a block is used + * for statistics this fields is used to report optional + * driver-specific flags, if any. */ -struct v4l2_isp_params_block_header { +struct v4l2_isp_block_header { __u16 type; __u16 flags; __u32 size; } __attribute__((aligned(8))); /** - * struct v4l2_isp_params_buffer - V4L2 extensible parameters configuration - * @version: The parameters buffer version (driver-specific) - * @data_size: The configuration data effective size, excluding this header - * @data: The configuration data + * v4l2_isp_params_block_header - V4L2 extensible parameters block header + * + * Compatibility with existing users of v4l2_isp_params_block_header + * which pre-date the introduction of v4l2_isp_block_header. + */ +#define v4l2_isp_params_block_header v4l2_isp_block_header + +/** + * struct v4l2_isp_buffer - V4L2 extensible buffer + * @version: The extensible buffer version (driver-specific) + * @data_size: The data effective size, excluding this header + * @data: The configuration or statistics data * - * This structure contains the configuration parameters of the ISP algorithms, - * serialized by userspace into a data buffer. Each configuration parameter - * block is represented by a block-specific structure which contains a - * :c:type:`v4l2_isp_params_block_header` entry as first member. Userspace - * populates the @data buffer with configuration parameters for the blocks that - * it intends to configure. As a consequence, the data buffer effective size - * changes according to the number of ISP blocks that userspace intends to - * configure and is set by userspace in the @data_size field. + * This structure contains ISP configuration parameters or ISP hardware + * statistics serialized into a data buffer. Each block is represented by a + * block-specific structure which contains a :c:type:`v4l2_isp_block_header` + * entry as first member. * - * The parameters buffer is versioned by the @version field to allow modifying - * and extending its definition. Userspace shall populate the @version field to - * inform the driver about the version it intends to use. The driver will parse - * and handle the @data buffer according to the data layout specific to the - * indicated version and return an error if the desired version is not + * When used for ISP parameters, userspace populates the @data buffer with + * configuration parameters for the blocks that it intends to configure. As a + * consequence, the data buffer effective size changes according to the number + * of ISP blocks that userspace intends to configure. + * + * When used to report ISP statistics, the driver populates the @data buffer + * with statistics for each supported measurement block. + * + * The buffer is versioned by the @version field to allow modifying + * and extending its definition. The writer shall populate the @version field + * to inform the reader about the version it intends to use. The reader will + * parse and handle the @data buffer according to the data layout specific to + * the indicated version and return an error if the desired version is not * supported. * - * For each ISP block that userspace wants to configure, a block-specific - * structure is appended to the @data buffer, one after the other without gaps - * in between. Userspace shall populate the @data_size field with the effective - * size, in bytes, of the @data buffer. + * For each ISP block, a block-specific structure is appended to the @data + * buffer, one after the other without gaps in between. The writer shall + * populate the @data_size field with the effective size, in bytes, of the + * @data buffer. */ -struct v4l2_isp_params_buffer { +struct v4l2_isp_buffer { __u32 version; __u32 data_size; __u8 data[] __counted_by(data_size); }; +/** + * v4l2_isp_params_buffer - V4L2 extensible parameters compatibility + * + * Compatibility with existing users of v4l2_isp_params_buffer which + * pre-date the introduction of v4l2_isp_buffer. + */ +#define v4l2_isp_params_buffer v4l2_isp_buffer + #endif /* _UAPI_V4L2_ISP_H_ */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index eda4492e40dc..5373dba640fa 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -889,6 +889,10 @@ struct v4l2_pix_format { #define V4L2_META_FMT_MALI_C55_PARAMS v4l2_fourcc('C', '5', '5', 'P') /* ARM Mali-C55 Parameters */ #define V4L2_META_FMT_MALI_C55_STATS v4l2_fourcc('C', '5', '5', 'S') /* ARM Mali-C55 3A Statistics */ +/* Vendor specific - used for Dreamchip RPP-X1 ISP */ +#define V4L2_META_FMT_RPPX1_PARAMS v4l2_fourcc('D', 'R', '1', 'P') /* Dreamchip RPP-X1 Parameters */ +#define V4L2_META_FMT_RPPX1_STATS v4l2_fourcc('D', 'R', '1', 'S') /* Dreamchip RPP-X1 Statistics */ + #ifdef __KERNEL__ /* * Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when |
