diff options
489 files changed, 12756 insertions, 5363 deletions
diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt deleted file mode 100644 index 1872688fa408..000000000000 --- a/Documentation/devicetree/bindings/media/exynos5-gsc.txt +++ /dev/null @@ -1,38 +0,0 @@ -* Samsung Exynos5 G-Scaler device - -G-Scaler is used for scaling and color space conversion on Exynos5 SoCs. - -Required properties: -- compatible: should be one of - "samsung,exynos5250-gsc" - "samsung,exynos5420-gsc" - "samsung,exynos5433-gsc" - "samsung,exynos5-gsc" (deprecated) -- reg: should contain G-Scaler physical address location and length. -- interrupts: should contain G-Scaler interrupt number - -Optional properties: -- samsung,sysreg: handle to syscon used to control the system registers to - set writeback input and destination - -Example: - -gsc_0: gsc@13e00000 { - compatible = "samsung,exynos5250-gsc"; - reg = <0x13e00000 0x1000>; - interrupts = <0 85 0>; -}; - -Aliases: -Each G-Scaler node should have a numbered alias in the aliases node, -in the form of gscN, N = 0...3. G-Scaler driver uses these aliases -to retrieve the device IDs using "of_alias_get_id()" call. - -Example: - -aliases { - gsc0 =&gsc_0; - gsc1 =&gsc_1; - gsc2 =&gsc_2; - gsc3 =&gsc_3; -}; diff --git a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt deleted file mode 100644 index b88dcdd41def..000000000000 --- a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt +++ /dev/null @@ -1,9 +0,0 @@ -Dongwoon Anatech DW9714 camera voice coil lens driver - -DW9174 is a 10-bit DAC with current sink capability. It is intended -for driving voice coil lenses in camera modules. - -Mandatory properties: - -- compatible: "dongwoon,dw9714" -- reg: I²C slave address diff --git a/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml new file mode 100644 index 000000000000..66229a3dc05d --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/dongwoon,dw9714.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dongwoon Anatech DW9714 camera voice coil lens driver + +maintainers: + - Krzysztof Kozlowski <krzk@kernel.org> + +description: + DW9174 is a 10-bit DAC with current sink capability. It is intended for + driving voice coil lenses in camera modules. + +properties: + compatible: + const: dongwoon,dw9714 + + reg: + maxItems: 1 + + powerdown-gpios: + description: + XSD pin for shutdown (active low) + + vcc-supply: + description: VDD power supply + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + camera-lens@c { + compatible = "dongwoon,dw9714"; + reg = <0x0c>; + vcc-supply = <®_csi_1v8>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml new file mode 100644 index 000000000000..9cfc0c7d23e0 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-rdma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Read Direct Memory Access + +maintainers: + - Matthias Brugger <matthias.bgg@gmail.com> + - Moudy Ho <moudy.ho@mediatek.com> + +description: | + MediaTek Read Direct Memory Access(RDMA) component used to do read DMA. + It contains one line buffer to store the sufficient pixel data, and + must be siblings to the central MMSYS_CONFIG node. + For a description of the MMSYS_CONFIG binding, see + Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.yaml + for details. + +properties: + compatible: + items: + - const: mediatek,mt8183-mdp3-rdma + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + $ref: '/schemas/types.yaml#/definitions/phandle-array' + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + description: The register of client driver can be configured by gce with + 4 arguments defined in this property. Each GCE subsys id is mapping to + a client defined in the header include/dt-bindings/gce/<chip>-gce.h. + + mediatek,gce-events: + description: + The event id which is mapping to the specific hardware event signal + to gce. The event id is defined in the gce header + include/dt-bindings/gce/<chip>-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/uint32-array + + power-domains: + maxItems: 1 + + clocks: + items: + - description: RDMA clock + - description: RSZ clock + + iommus: + maxItems: 1 + + mboxes: + items: + - description: used for 1st data pipe from RDMA + - description: used for 2nd data pipe from RDMA + +required: + - compatible + - reg + - mediatek,gce-client-reg + - mediatek,gce-events + - power-domains + - clocks + - iommus + - mboxes + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8183-clk.h> + #include <dt-bindings/gce/mt8183-gce.h> + #include <dt-bindings/power/mt8183-power.h> + #include <dt-bindings/memory/mt8183-larb-port.h> + + mdp3_rdma0: mdp3-rdma0@14001000 { + compatible = "mediatek,mt8183-mdp3-rdma"; + reg = <0x14001000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_RDMA0_SOF>, + <CMDQ_EVENT_MDP_RDMA0_EOF>; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_RDMA0>, + <&mmsys CLK_MM_MDP_RSZ1>; + iommus = <&iommu>; + mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST>, + <&gce 21 CMDQ_THR_PRIO_LOWEST>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml new file mode 100644 index 000000000000..78f9de6192ef --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rsz.yaml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-rsz.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Resizer + +maintainers: + - Matthias Brugger <matthias.bgg@gmail.com> + - Moudy Ho <moudy.ho@mediatek.com> + +description: | + One of Media Data Path 3 (MDP3) components used to do frame resizing. + +properties: + compatible: + items: + - enum: + - mediatek,mt8183-mdp3-rsz + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + description: The register of client driver can be configured by gce with + 4 arguments defined in this property. Each GCE subsys id is mapping to + a client defined in the header include/dt-bindings/gce/<chip>-gce.h. + + mediatek,gce-events: + description: + The event id which is mapping to the specific hardware event signal + to gce. The event id is defined in the gce header + include/dt-bindings/gce/<chip>-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/uint32-array + + clocks: + minItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - mediatek,gce-events + - clocks + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8183-clk.h> + #include <dt-bindings/gce/mt8183-gce.h> + + mdp3_rsz0: mdp3-rsz0@14003000 { + compatible = "mediatek,mt8183-mdp3-rsz"; + reg = <0x14003000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x3000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_RSZ0_SOF>, + <CMDQ_EVENT_MDP_RSZ0_EOF>; + clocks = <&mmsys CLK_MM_MDP_RSZ0>; + }; + + mdp3_rsz1: mdp3-rsz1@14004000 { + compatible = "mediatek,mt8183-mdp3-rsz"; + reg = <0x14004000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x4000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_RSZ1_SOF>, + <CMDQ_EVENT_MDP_RSZ1_EOF>; + clocks = <&mmsys CLK_MM_MDP_RSZ1>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml new file mode 100644 index 000000000000..0baa77198fa2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-wrot.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek,mdp3-wrot.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Write DMA with Rotation + +maintainers: + - Matthias Brugger <matthias.bgg@gmail.com> + - Moudy Ho <moudy.ho@mediatek.com> + +description: | + One of Media Data Path 3 (MDP3) components used to write DMA with frame rotation. + +properties: + compatible: + items: + - enum: + - mediatek,mt8183-mdp3-wrot + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + description: The register of client driver can be configured by gce with + 4 arguments defined in this property. Each GCE subsys id is mapping to + a client defined in the header include/dt-bindings/gce/<chip>-gce.h. + + mediatek,gce-events: + description: + The event id which is mapping to the specific hardware event signal + to gce. The event id is defined in the gce header + include/dt-bindings/gce/<chip>-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/uint32-array + + power-domains: + maxItems: 1 + + clocks: + minItems: 1 + + iommus: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - mediatek,gce-events + - power-domains + - clocks + - iommus + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8183-clk.h> + #include <dt-bindings/gce/mt8183-gce.h> + #include <dt-bindings/power/mt8183-power.h> + #include <dt-bindings/memory/mt8183-larb-port.h> + + mdp3_wrot0: mdp3-wrot0@14005000 { + compatible = "mediatek,mt8183-mdp3-wrot"; + reg = <0x14005000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_WROT0_SOF>, + <CMDQ_EVENT_MDP_WROT0_EOF>; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_WROT0>; + iommus = <&iommu>; + }; diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml index d36fcca04cbc..32aee09aea33 100644 --- a/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-encoder.yaml @@ -20,6 +20,7 @@ properties: - mediatek,mt8173-vcodec-enc-vp8 - mediatek,mt8173-vcodec-enc - mediatek,mt8183-vcodec-enc + - mediatek,mt8188-vcodec-enc - mediatek,mt8192-vcodec-enc - mediatek,mt8195-vcodec-enc diff --git a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml index d4e2051beeb6..c4f20acdc1f8 100644 --- a/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml +++ b/Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml @@ -57,6 +57,7 @@ properties: enum: - mediatek,mt8192-vcodec-dec - mediatek,mt8186-vcodec-dec + - mediatek,mt8188-vcodec-dec - mediatek,mt8195-vcodec-dec reg: diff --git a/Documentation/devicetree/bindings/media/nxp,dw100.yaml b/Documentation/devicetree/bindings/media/nxp,dw100.yaml new file mode 100644 index 000000000000..21910ff0e1c3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,dw100.yaml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,dw100.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8MP DW100 Dewarper core + +maintainers: + - Xavier Roumegue <xavier.roumegue@oss.nxp.com> + +description: |- + The Dewarp Engine provides high-performance dewarp processing for the + correction of the distortion that is introduced in images produced by fisheye + and wide angle lenses. It is implemented with a line/tile-cache based + architecture. With configurable address mapping look up tables and per tile + processing, it successfully generates a corrected output image. + The engine can be used to perform scaling, cropping and pixel format + conversion. + +properties: + compatible: + enum: + - nxp,imx8mp-dw100 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: The AXI clock + - description: The AHB clock + + clock-names: + items: + - const: axi + - const: ahb + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - power-domains + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/imx8mp-clock.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/power/imx8mp-power.h> + + dewarp: dwe@32e30000 { + compatible = "nxp,imx8mp-dw100"; + reg = <0x32e30000 0x10000>; + interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk IMX8MP_CLK_MEDIA_AXI_ROOT>, + <&clk IMX8MP_CLK_MEDIA_APB_ROOT>; + clock-names = "axi", "ahb"; + power-domains = <&media_blk_ctrl IMX8MP_MEDIABLK_PD_DWE>; + }; diff --git a/Documentation/devicetree/bindings/media/renesas,vsp1.yaml b/Documentation/devicetree/bindings/media/renesas,vsp1.yaml index 990e9c1dbc43..7a8f32473852 100644 --- a/Documentation/devicetree/bindings/media/renesas,vsp1.yaml +++ b/Documentation/devicetree/bindings/media/renesas,vsp1.yaml @@ -17,6 +17,7 @@ description: properties: compatible: enum: + - renesas,r9a07g044-vsp2 # RZ/G2L - renesas,vsp1 # R-Car Gen2 and RZ/G1 - renesas,vsp2 # R-Car Gen3 and RZ/G2 @@ -26,8 +27,8 @@ properties: interrupts: maxItems: 1 - clocks: - maxItems: 1 + clocks: true + clock-names: true power-domains: maxItems: 1 @@ -50,17 +51,43 @@ required: additionalProperties: false -if: - properties: - compatible: - items: - - const: renesas,vsp1 -then: - properties: - renesas,fcp: false -else: - required: - - renesas,fcp +allOf: + - if: + properties: + compatible: + contains: + const: renesas,vsp1 + then: + properties: + renesas,fcp: false + else: + required: + - renesas,fcp + + - if: + properties: + compatible: + contains: + const: renesas,r9a07g044-vsp2 + then: + properties: + clocks: + items: + - description: Main clock + - description: Register access clock + - description: Video clock + clock-names: + items: + - const: aclk + - const: pclk + - const: vclk + required: + - clock-names + else: + properties: + clocks: + maxItems: 1 + clock-names: false examples: # R8A7790 (R-Car H2) VSP1-S diff --git a/Documentation/devicetree/bindings/media/samsung,exynos5250-gsc.yaml b/Documentation/devicetree/bindings/media/samsung,exynos5250-gsc.yaml new file mode 100644 index 000000000000..878397830a4d --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung,exynos5250-gsc.yaml @@ -0,0 +1,109 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/samsung,exynos5250-gsc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung Exynos SoC G-Scaler + +maintainers: + - Inki Dae <inki.dae@samsung.com> + - Krzysztof Kozlowski <krzk@kernel.org> + - Seung-Woo Kim <sw0312.kim@samsung.com + +description: + G-Scaler is used for scaling and color space conversion on Samsung Exynos + SoCs. + + Each G-Scaler node should have a numbered alias in the aliases node, in the + form of gscN, N = 0...3. + +properties: + compatible: + oneOf: + - items: + - enum: + - samsung,exynos5250-gsc + - samsung,exynos5420-gsc + - const: samsung,exynos5-gsc + - enum: + - samsung,exynos5433-gsc + - const: samsung,exynos5-gsc + deprecated: True + + clocks: + minItems: 1 + maxItems: 5 + + clock-names: + minItems: 1 + maxItems: 5 + + interrupts: + maxItems: 1 + + iommus: + maxItems: 1 + + power-domains: + maxItems: 1 + + reg: + maxItems: 1 + + samsung,sysreg: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Syscon used to control the system registers to set writeback input and destination. + +required: + - compatible + - clocks + - clock-names + - interrupts + - reg + +allOf: + - if: + properties: + compatible: + contains: + enum: + - samsung,exynos5-gsc + - samsung,exynos5250-gsc + - samsung,exynos5420-gsc + then: + properties: + clocks: + maxItems: 1 + clock-names: + items: + - const: gscl + else: + properties: + clocks: + minItems: 5 + clock-names: + items: + - const: pclk + - const: aclk + - const: aclk_xiu + - const: aclk_gsclbend + - const: gsd + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/exynos5250.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + + video-scaler@13e00000 { + compatible = "samsung,exynos5250-gsc", "samsung,exynos5-gsc"; + reg = <0x13e00000 0x1000>; + interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; + power-domains = <&pd_gsc>; + clocks = <&clock CLK_GSCL0>; + clock-names = "gscl"; + iommus = <&sysmmu_gsc0>; + }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,ccorr.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,ccorr.yaml new file mode 100644 index 000000000000..4380b98b0dfe --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,ccorr.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/mediatek/mediatek,ccorr.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek color correction + +maintainers: + - Matthias Brugger <matthias.bgg@gmail.com> + - Moudy Ho <moudy.ho@mediatek.com> + +description: | + MediaTek color correction with 3X3 matrix. + +properties: + compatible: + items: + - enum: + - mediatek,mt8183-mdp3-ccorr + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + description: The register of client driver can be configured by gce with + 4 arguments defined in this property. Each GCE subsys id is mapping to + a client defined in the header include/dt-bindings/gce/<chip>-gce.h. + + mediatek,gce-events: + description: + The event id which is mapping to the specific hardware event signal + to gce. The event id is defined in the gce header + include/dt-bindings/gce/<chip>-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/uint32-array + + clocks: + minItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - mediatek,gce-events + - clocks + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8183-clk.h> + #include <dt-bindings/gce/mt8183-gce.h> + + mdp3_ccorr: mdp3-ccorr@1401c000 { + compatible = "mediatek,mt8183-mdp3-ccorr"; + reg = <0x1401c000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0xc000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_CCORR_SOF>, + <CMDQ_EVENT_MDP_CCORR_EOF>; + clocks = <&mmsys CLK_MM_MDP_CCORR>; + }; diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,wdma.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,wdma.yaml new file mode 100644 index 000000000000..69afb329e5f4 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,wdma.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/mediatek/mediatek,wdma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Write Direct Memory Access + +maintainers: + - Matthias Brugger <matthias.bgg@gmail.com> + - Moudy Ho <moudy.ho@mediatek.com> + +description: | + MediaTek Write Direct Memory Access(WDMA) component used to write + the data into DMA. + +properties: + compatible: + items: + - enum: + - mediatek,mt8183-mdp3-wdma + + reg: + maxItems: 1 + + mediatek,gce-client-reg: + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: phandle of GCE + - description: GCE subsys id + - description: register offset + - description: register size + description: The register of client driver can be configured by gce with + 4 arguments defined in this property. Each GCE subsys id is mapping to + a client defined in the header include/dt-bindings/gce/<chip>-gce.h. + + mediatek,gce-events: + description: + The event id which is mapping to the specific hardware event signal + to gce. The event id is defined in the gce header + include/dt-bindings/gce/<chip>-gce.h of each chips. + $ref: /schemas/types.yaml#/definitions/uint32-array + + power-domains: + maxItems: 1 + + clocks: + minItems: 1 + + iommus: + maxItems: 1 + +required: + - compatible + - reg + - mediatek,gce-client-reg + - mediatek,gce-events + - power-domains + - clocks + - iommus + +additionalProperties: false + +examples: + - | + #include <dt-bindings/clock/mt8183-clk.h> + #include <dt-bindings/gce/mt8183-gce.h> + #include <dt-bindings/power/mt8183-power.h> + #include <dt-bindings/memory/mt8183-larb-port.h> + + mdp3_wdma: mdp3-wdma@14006000 { + compatible = "mediatek,mt8183-mdp3-wdma"; + reg = <0x14006000 0x1000>; + mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x6000 0x1000>; + mediatek,gce-events = <CMDQ_EVENT_MDP_WDMA0_SOF>, + <CMDQ_EVENT_MDP_WDMA0_EOF>; + power-domains = <&spm MT8183_POWER_DOMAIN_DISP>; + clocks = <&mmsys CLK_MM_MDP_WDMA0>; + iommus = <&iommu>; + }; diff --git a/Documentation/driver-api/media/drivers/pxa_camera.rst b/Documentation/driver-api/media/drivers/pxa_camera.rst index ee1bd96b66dd..46919919baac 100644 --- a/Documentation/driver-api/media/drivers/pxa_camera.rst +++ b/Documentation/driver-api/media/drivers/pxa_camera.rst @@ -19,7 +19,7 @@ Global video workflow a) QCI stopped Initially, the QCI interface is stopped. - When a buffer is queued (pxa_videobuf_ops->buf_queue), the QCI starts. + When a buffer is queued, start_streaming is called and the QCI starts. b) QCI started More buffers can be queued while the QCI is started without halting the diff --git a/Documentation/driver-api/media/mc-core.rst b/Documentation/driver-api/media/mc-core.rst index 84aa7cdb5341..400b8ca29367 100644 --- a/Documentation/driver-api/media/mc-core.rst +++ b/Documentation/driver-api/media/mc-core.rst @@ -214,18 +214,29 @@ Link properties can be modified at runtime by calling Pipelines and media streams ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +A media stream is a stream of pixels or metadata originating from one or more +source devices (such as a sensors) and flowing through media entity pads +towards the final sinks. The stream can be modified on the route by the +devices (e.g. scaling or pixel format conversions), or it can be split into +multiple branches, or multiple branches can be merged. + +A media pipeline is a set of media streams which are interdependent. This +interdependency can be caused by the hardware (e.g. configuration of a second +stream cannot be changed if the first stream has been enabled) or by the driver +due to the software design. Most commonly a media pipeline consists of a single +stream which does not branch. + When starting streaming, drivers must notify all entities in the pipeline to prevent link states from being modified during streaming by calling :c:func:`media_pipeline_start()`. -The function will mark all entities connected to the given entity through -enabled links, either directly or indirectly, as streaming. +The function will mark all the pads which are part of the pipeline as streaming. The struct media_pipeline instance pointed to by -the pipe argument will be stored in every entity in the pipeline. +the pipe argument will be stored in every pad in the pipeline. Drivers should embed the struct media_pipeline in higher-level pipeline structures and can then access the -pipeline through the struct media_entity +pipeline through the struct media_pad pipe field. Calls to :c:func:`media_pipeline_start()` can be nested. diff --git a/Documentation/userspace-api/media/cec.h.rst.exceptions b/Documentation/userspace-api/media/cec.h.rst.exceptions index 13de01d9555e..15fa1752d4ef 100644 --- a/Documentation/userspace-api/media/cec.h.rst.exceptions +++ b/Documentation/userspace-api/media/cec.h.rst.exceptions @@ -239,6 +239,7 @@ ignore define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL ignore define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE ignore define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX ignore define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX +ignore define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_VOLUME_LEVEL ignore define CEC_MSG_GIVE_FEATURES @@ -487,6 +488,7 @@ ignore define CEC_OP_SYS_AUD_STATUS_ON ignore define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST ignore define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS +ignore define CEC_MSG_SET_AUDIO_VOLUME_LEVEL ignore define CEC_OP_AUD_FMT_ID_CEA861 ignore define CEC_OP_AUD_FMT_ID_CEA861_CXT diff --git a/Documentation/userspace-api/media/drivers/dw100.rst b/Documentation/userspace-api/media/drivers/dw100.rst new file mode 100644 index 000000000000..fceea6ece622 --- /dev/null +++ b/Documentation/userspace-api/media/drivers/dw100.rst @@ -0,0 +1,84 @@ +.. SPDX-License-Identifier: GPL-2.0 + +DW100 dewarp driver +=================== + +The Vivante DW100 Dewarp Processor IP core found on i.MX8MP SoC applies a +programmable geometrical transformation on the input image to correct distortion +introduced by lenses. + +The transformation function is exposed by the hardware as a grid map with 16x16 +pixel macroblocks indexed using X, Y vertex coordinates. +:: + + Image width + <---------------------------------------> + + ^ .-------.-------.-------.-------.-------. + | | 16x16 | | | | | + I | | pixel | | | | | + m | | block | | | | | + a | .-------.-------.-------.-------.-------. + g | | | | | | | + e | | | | | | | + | | | | | | | + h | .-------.-------.-------.-------.-------. + e | | | | | | | + i | | | | | | | + g | | | | | | | + h | .-------.-------.-------.-------.-------. + t | | | | | | | + | | | | | | | + | | | | | | | + v '-------'-------'-------'-------'-------' + + Grid of Image Blocks for Dewarping Map + + +Each x, y coordinate register uses 16 bits to record the coordinate address in +an unsigned 12.4 fixed point format (UQ12.4). +:: + + .----------------------.--------..----------------------.--------. + | 31~20 | 19~16 || 15~4 | 3~0 | + | (integer) | (frac) || (integer) | (frac) | + '----------------------'--------''----------------------'--------' + <-------------------------------><-------------------------------> + Y coordinate X coordinate + + Remap Register Layout + +The dewarping map is set from applications using the +V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP control. The control contains +an array of u32 values storing (x, y) destination coordinates for each +vertex of the grid. The x coordinate is stored in the 16 LSBs and the y +coordinate in the 16 MSBs. + +The number of elements in the array must match the image size: + +.. code-block:: C + + elems = (DIV_ROUND_UP(width, 16) + 1) * (DIV_ROUND_UP(height, 16) + 1); + +If the control has not been set by the application, the driver uses an identity +map. + +More details on the DW100 hardware operations can be found in +*chapter 13.15 DeWarp* of IMX8MP_ reference manual. + +The Vivante DW100 m2m driver implements the following driver-specific control: + +``V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP (__u32 array)`` + Specifies to DW100 driver its dewarping map (aka LUT) blob as described in + *chapter 13.15.2.3 Dewarping Remap* of IMX8MP_ reference manual as an U32 + dynamic array. The image is divided into many small 16x16 blocks. If the + width/height of the image is not divisible by 16, the size of the + rightmost/bottommost block is the remainder. The dewarping map only saves + the vertex coordinates of the block. The dewarping grid map is comprised of + vertex coordinates for x and y. Each x, y coordinate register uses 16 bits + (UQ12.4) to record the coordinate address, with the Y coordinate in the + upper bits and X in the lower bits. The driver modifies the dimensions of + this control when the sink format is changed, to reflect the new input + resolution. + +.. _IMX8MP: https://www.nxp.com/webapp/Download?colCode=IMX8MPRM diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst index 1a9038f5f9fa..32f82aed47d9 100644 --- a/Documentation/userspace-api/media/drivers/index.rst +++ b/Documentation/userspace-api/media/drivers/index.rst @@ -33,6 +33,7 @@ For more details see the file COPYING in the source distribution of Linux. ccs cx2341x-uapi + dw100 imx-uapi max2175 meye-uapi diff --git a/Documentation/userspace-api/media/v4l/async.rst b/Documentation/userspace-api/media/v4l/async.rst deleted file mode 100644 index d6960ff5c382..000000000000 --- a/Documentation/userspace-api/media/v4l/async.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later - -.. _async: - -**************** -Asynchronous I/O -**************** - -This method is not defined yet. diff --git a/Documentation/userspace-api/media/v4l/dev-raw-vbi.rst b/Documentation/userspace-api/media/v4l/dev-raw-vbi.rst index 58f97c3a7792..2bec20d87928 100644 --- a/Documentation/userspace-api/media/v4l/dev-raw-vbi.rst +++ b/Documentation/userspace-api/media/v4l/dev-raw-vbi.rst @@ -41,7 +41,7 @@ Devices supporting the raw VBI capturing or output API set the in the ``capabilities`` field of struct :c:type:`v4l2_capability` returned by the :ref:`VIDIOC_QUERYCAP` ioctl. At least one of the -read/write, streaming or asynchronous I/O methods must be supported. VBI +read/write or streaming I/O methods must be supported. VBI devices may or may not have a tuner or modulator. Supplemental Functions diff --git a/Documentation/userspace-api/media/v4l/dev-sdr.rst b/Documentation/userspace-api/media/v4l/dev-sdr.rst index 928884dfe09d..dfdeddbca41f 100644 --- a/Documentation/userspace-api/media/v4l/dev-sdr.rst +++ b/Documentation/userspace-api/media/v4l/dev-sdr.rst @@ -34,7 +34,7 @@ Devices supporting the SDR transmitter interface set the device has an Digital to Analog Converter (DAC), which is a mandatory element for the SDR transmitter. -At least one of the read/write, streaming or asynchronous I/O methods +At least one of the read/write or streaming I/O methods must be supported. diff --git a/Documentation/userspace-api/media/v4l/dev-sliced-vbi.rst b/Documentation/userspace-api/media/v4l/dev-sliced-vbi.rst index 97ec2b115c71..44415822c7c5 100644 --- a/Documentation/userspace-api/media/v4l/dev-sliced-vbi.rst +++ b/Documentation/userspace-api/media/v4l/dev-sliced-vbi.rst @@ -36,7 +36,7 @@ Devices supporting the sliced VBI capturing or output API set the respectively, in the ``capabilities`` field of struct :c:type:`v4l2_capability` returned by the :ref:`VIDIOC_QUERYCAP` ioctl. At least one of the -read/write, streaming or asynchronous :ref:`I/O methods <io>` must be +read/write or streaming :ref:`I/O methods <io>` must be supported. Sliced VBI devices may have a tuner or modulator. Supplemental Functions diff --git a/Documentation/userspace-api/media/v4l/hist-v4l2.rst b/Documentation/userspace-api/media/v4l/hist-v4l2.rst index 28a2750d5c8c..dbc04374dc22 100644 --- a/Documentation/userspace-api/media/v4l/hist-v4l2.rst +++ b/Documentation/userspace-api/media/v4l/hist-v4l2.rst @@ -316,7 +316,7 @@ This unnamed version was finally merged into Linux 2.5.46. There are new fields to identify the driver, a new RDS device function ``V4L2_CAP_RDS_CAPTURE``, the ``V4L2_CAP_AUDIO`` flag indicates if the device has any audio connectors, another I/O - capability ``V4L2_CAP_ASYNCIO`` can be flagged. In response to these + capability V4L2_CAP_ASYNCIO can be flagged. In response to these changes the ``type`` field became a bit set and was merged into the ``flags`` field. ``V4L2_FLAG_TUNER`` was renamed to ``V4L2_CAP_TUNER``, ``V4L2_CAP_VIDEO_OVERLAY`` replaced diff --git a/Documentation/userspace-api/media/v4l/io.rst b/Documentation/userspace-api/media/v4l/io.rst index ce0cece6f35f..4b1964df9d73 100644 --- a/Documentation/userspace-api/media/v4l/io.rst +++ b/Documentation/userspace-api/media/v4l/io.rst @@ -17,8 +17,7 @@ read or write will fail at any time. Other methods must be negotiated. To select the streaming I/O method with memory mapped or user buffers applications call the -:ref:`VIDIOC_REQBUFS` ioctl. The asynchronous I/O -method is not defined yet. +:ref:`VIDIOC_REQBUFS` ioctl. Video overlay can be considered another I/O method, although the application does not directly receive the image data. It is selected by @@ -46,6 +45,5 @@ The following sections describe the various I/O methods in more detail. mmap userp dmabuf - async buffer field-order diff --git a/Documentation/userspace-api/media/v4l/libv4l-introduction.rst b/Documentation/userspace-api/media/v4l/libv4l-introduction.rst index 90215313b965..7c8bf160e1c6 100644 --- a/Documentation/userspace-api/media/v4l/libv4l-introduction.rst +++ b/Documentation/userspace-api/media/v4l/libv4l-introduction.rst @@ -136,9 +136,9 @@ V4L2 functions operates like the :c:func:`read()` function. -.. c:function:: void v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset); +.. c:function:: void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, int64_t offset); - operates like the :c:func:`munmap()` function. + operates like the :c:func:`mmap()` function. .. c:function:: int v4l2_munmap(void *_start, size_t length); diff --git a/Documentation/userspace-api/media/v4l/vidioc-dqevent.rst b/Documentation/userspace-api/media/v4l/vidioc-dqevent.rst index 6eb40073c906..8db103760930 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-dqevent.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-dqevent.rst @@ -332,6 +332,11 @@ call. - 0x0004 - This control event was triggered because the minimum, maximum, step or the default value of the control changed. + * - ``V4L2_EVENT_CTRL_CH_DIMENSIONS`` + - 0x0008 + - This control event was triggered because the dimensions of the + control changed. Note that the number of dimensions remains the + same. .. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.5cm}| diff --git a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst index 63e23f6f95ee..6c57b8428356 100644 --- a/Documentation/userspace-api/media/v4l/vidioc-querycap.rst +++ b/Documentation/userspace-api/media/v4l/vidioc-querycap.rst @@ -244,9 +244,6 @@ specification the ioctl returns an ``EINVAL`` error code. - 0x01000000 - The device supports the :c:func:`read()` and/or :c:func:`write()` I/O methods. - * - ``V4L2_CAP_ASYNCIO`` - - 0x02000000 - - The device supports the :ref:`asynchronous <async>` I/O methods. * - ``V4L2_CAP_STREAMING`` - 0x04000000 - The device supports the :ref:`streaming <mmap>` I/O method. diff --git a/Documentation/userspace-api/media/videodev2.h.rst.exceptions b/Documentation/userspace-api/media/videodev2.h.rst.exceptions index 64b2c0b1f666..2a589d34b80e 100644 --- a/Documentation/userspace-api/media/videodev2.h.rst.exceptions +++ b/Documentation/userspace-api/media/videodev2.h.rst.exceptions @@ -514,6 +514,7 @@ replace define V4L2_EVENT_PRIVATE_START event-type replace define V4L2_EVENT_CTRL_CH_VALUE ctrl-changes-flags replace define V4L2_EVENT_CTRL_CH_FLAGS ctrl-changes-flags replace define V4L2_EVENT_CTRL_CH_RANGE ctrl-changes-flags +replace define V4L2_EVENT_CTRL_CH_DIMENSIONS ctrl-changes-flags replace define V4L2_EVENT_SRC_CH_RESOLUTION src-changes-flags diff --git a/MAINTAINERS b/MAINTAINERS index 8a5012ba6ff9..d0f844857447 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6244,7 +6244,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.txt +F: Documentation/devicetree/bindings/media/i2c/dongwoon,dw9714.yaml F: drivers/media/i2c/dw9714.c DONGWOON DW9768 LENS VOICE COIL DRIVER @@ -8904,7 +8904,7 @@ S: Maintained F: Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml F: Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml F: Documentation/devicetree/bindings/media/rockchip-vpu.yaml -F: drivers/staging/media/hantro/ +F: drivers/media/platform/verisilicon/ HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER M: Frank Seidel <frank@f-seidel.de> @@ -13775,7 +13775,7 @@ MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER S: Orphan W: http://popies.net/meye/ F: Documentation/userspace-api/media/drivers/meye* -F: drivers/media/pci/meye/ +F: drivers/staging/media/deprecated/meye/ F: include/uapi/linux/meye.h MOTORCOMM PHY DRIVER @@ -14690,6 +14690,15 @@ S: Orphan F: Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml F: drivers/nfc/nxp-nci +NXP i.MX 8MP DW100 V4L2 DRIVER +M: Xavier Roumegue <xavier.roumegue@oss.nxp.com> +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/nxp,dw100.yaml +F: Documentation/userspace-api/media/drivers/dw100.rst +F: drivers/media/platform/nxp/dw100/ +F: include/uapi/linux/dw100.h + NXP i.MX 8QXP/8QM JPEG V4L2 DRIVER M: Mirela Rabulea <mirela.rabulea@nxp.com> R: NXP Linux Team <linux-imx@nxp.com> @@ -17901,9 +17910,7 @@ M: Hans Verkuil <hverkuil@xs4all.nl> L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git -F: drivers/media/common/saa7146/ -F: drivers/media/pci/saa7146/ -F: include/media/drv-intf/saa7146* +F: drivers/staging/media/deprecated/saa7146/ SAFESETID SECURITY MODULE M: Micah Morton <mortonm@chromium.org> @@ -20320,6 +20327,7 @@ W: https://linuxtv.org Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git F: drivers/media/platform/ti/davinci/ +F: drivers/staging/media/deprecated/vpfe_capture/ F: include/media/davinci/ TI ENHANCED QUADRATURE ENCODER PULSE (eQEP) DRIVER @@ -20460,7 +20468,7 @@ S: Odd fixes W: https://linuxtv.org T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/tm6000* -F: drivers/media/usb/tm6000/ +F: drivers/staging/media/deprecated/tm6000/ TMIO/SDHI MMC DRIVER M: Wolfram Sang <wsa+renesas@sang-engineering.com> @@ -20560,9 +20568,10 @@ F: include/linux/toshiba.h F: include/uapi/linux/toshiba.h TOSHIBA TC358743 DRIVER -M: Mats Randgaard <matrandg@cisco.com> +M: Hans Verkuil <hverkuil-cisco@xs4all.nl> L: linux-media@vger.kernel.org S: Maintained +F: Documentation/devicetree/bindings/media/i2c/tc358743.txt F: drivers/media/i2c/tc358743* F: include/media/i2c/tc358743.h @@ -21209,7 +21218,7 @@ S: Maintained W: http://royale.zerezo.com/zr364xx/ T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/zr364xx* -F: drivers/media/usb/zr364xx/ +F: drivers/staging/media/deprecated/zr364xx/ USER-MODE LINUX (UML) M: Richard Weinberger <richard@nod.at> @@ -22498,7 +22507,7 @@ S: Maintained W: http://mjpeg.sourceforge.net/driver-zoran/ Q: https://patchwork.linuxtv.org/project/linux-media/list/ F: Documentation/driver-api/media/drivers/zoran.rst -F: drivers/staging/media/zoran/ +F: drivers/media/pci/zoran/ ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER M: Minchan Kim <minchan@kernel.org> diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ba6592b3dab2..283b78b5766e 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -24,7 +24,7 @@ if MEDIA_SUPPORT config MEDIA_SUPPORT_FILTER bool "Filter media drivers" - default y if !EMBEDDED && !EXPERT + default y if !EXPERT help Configuring the media subsystem can be complex, as there are hundreds of drivers and other config options. diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 41a79293ee02..4f5ab3cae8a7 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -1027,6 +1027,7 @@ static const u8 cec_msg_size[256] = { [CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, [CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, [CEC_MSG_SET_SYSTEM_AUDIO_MODE] = 3 | BOTH, + [CEC_MSG_SET_AUDIO_VOLUME_LEVEL] = 3 | DIRECTED, [CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST] = 2 | DIRECTED, [CEC_MSG_SYSTEM_AUDIO_MODE_STATUS] = 3 | DIRECTED, [CEC_MSG_SET_AUDIO_RATE] = 3 | DIRECTED, diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index 3b583ed4da9d..6ebedc71d67d 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -44,6 +44,8 @@ static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) uint8_t *cec_message = cros_ec->event_data.data.cec_message; unsigned int len = cros_ec->event_size; + if (len > CEC_MAX_MSG_SIZE) + len = CEC_MAX_MSG_SIZE; cros_ec_cec->rx_msg.len = len; memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); @@ -221,6 +223,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = { { "Google", "Moli", "0000:00:02.0", "Port B" }, /* Google Kinox */ { "Google", "Kinox", "0000:00:02.0", "Port B" }, + /* Google Kuldax */ + { "Google", "Kuldax", "0000:00:02.0", "Port B" }, }; static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c index ce9a9d922f11..0a30e7acdc10 100644 --- a/drivers/media/cec/platform/s5p/s5p_cec.c +++ b/drivers/media/cec/platform/s5p/s5p_cec.c @@ -115,6 +115,8 @@ static irqreturn_t s5p_cec_irq_handler(int irq, void *priv) dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n"); cec->rx = STATE_BUSY; cec->msg.len = status >> 24; + if (cec->msg.len > CEC_MAX_MSG_SIZE) + cec->msg.len = CEC_MAX_MSG_SIZE; cec->msg.rx_status = CEC_RX_STATUS_OK; s5p_cec_get_rx_buf(cec, cec->msg.len, cec->msg.msg); diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c index abf8e8bcbb34..4edbdd09535d 100644 --- a/drivers/media/cec/platform/sti/stih-cec.c +++ b/drivers/media/cec/platform/sti/stih-cec.c @@ -256,8 +256,8 @@ static void stih_rx_done(struct stih_cec *cec, u32 status) if (!msg.len) return; - if (msg.len > 16) - msg.len = 16; + if (msg.len > CEC_MAX_MSG_SIZE) + msg.len = CEC_MAX_MSG_SIZE; for (i = 0; i < msg.len; i++) msg.msg[i] = readl(cec->regs + CEC_RX_DATA_BASE + i); diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index a2ae71270054..852b7d92fbdd 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -22,7 +22,6 @@ config VIDEO_TVEEPROM depends on I2C source "drivers/media/common/b2c2/Kconfig" -source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" source "drivers/media/common/v4l2-tpg/Kconfig" source "drivers/media/common/videobuf2/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index ad0b1e95fb12..d78a0df15478 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ videobuf2/ +obj-y += b2c2/ siano/ v4l2-tpg/ videobuf2/ # Please keep it alphabetically sorted by Kconfig name # (e. g. LC_ALL=C sort Makefile) diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index b203c1e26353..ab9697f3b5f1 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -398,7 +398,7 @@ static void init_buffer_cache_hints(struct vb2_queue *q, struct vb2_buffer *vb) } /* - * __vb2_queue_alloc() - allocate videobuf buffer structures and (for MMAP type) + * __vb2_queue_alloc() - allocate vb2 buffer structures and (for MMAP type) * video buffer memory for all buffers/planes on the queue and initializes the * queue * @@ -417,7 +417,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, VB2_MAX_FRAME - q->num_buffers); for (buffer = 0; buffer < num_buffers; ++buffer) { - /* Allocate videobuf buffer structures */ + /* Allocate vb2 buffer structures */ vb = kzalloc(q->buf_struct_size, GFP_KERNEL); if (!vb) { dprintk(q, 1, "memory alloc for buffer struct failed\n"); @@ -599,7 +599,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) } #endif - /* Free videobuf buffers */ + /* Free vb2 buffers */ for (buffer = q->num_buffers - buffers; buffer < q->num_buffers; ++buffer) { kfree(q->bufs[buffer]); @@ -1949,7 +1949,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, unsigned int *pindex, void *pb, if (pb) call_void_bufop(q, fill_user_buffer, vb, pb); - /* Remove from videobuf queue */ + /* Remove from vb2 queue */ list_del(&vb->queued_entry); q->queued_count--; @@ -1978,7 +1978,7 @@ EXPORT_SYMBOL_GPL(vb2_core_dqbuf); * __vb2_queue_cancel() - cancel and stop (pause) streaming * * Removes all queued buffers from driver's queue and all buffers queued by - * userspace from videobuf's queue. Returns to state after reqbufs. + * userspace from vb2's queue. Returns to state after reqbufs. */ static void __vb2_queue_cancel(struct vb2_queue *q) { @@ -2016,7 +2016,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) q->uses_qbuf = 0; /* - * Remove all buffers from videobuf's list... + * Remove all buffers from vb2's list... */ INIT_LIST_HEAD(&q->queued_list); /* @@ -2139,7 +2139,7 @@ int vb2_core_streamoff(struct vb2_queue *q, unsigned int type) /* * Cancel will pause streaming and remove all buffers from the driver - * and videobuf, effectively returning control over them to userspace. + * and vb2, effectively returning control over them to userspace. * * Note that we do this even if q->streaming == 0: if you prepare or * queue buffers, and then call streamoff without ever having called diff --git a/drivers/media/common/videobuf2/videobuf2-dvb.c b/drivers/media/common/videobuf2/videobuf2-dvb.c index 9d571c9d31e9..8c15bcd07eef 100644 --- a/drivers/media/common/videobuf2/videobuf2-dvb.c +++ b/drivers/media/common/videobuf2/videobuf2-dvb.c @@ -3,8 +3,8 @@ * * some helper function for simple DVB cards which simply DMA the * complete transport stream and let the computer sort everything else - * (i.e. we are using the software demux, ...). Also uses the - * video-buf to manage DMA buffers. + * (i.e. we are using the software demux, ...). Also uses vb2 + * to manage DMA buffers. * * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] */ diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index f26cb8586bd4..1f5d235a8441 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -268,7 +268,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b /* * Single-planar buffers do not use planes array, * so fill in relevant v4l2_buffer struct fields instead. - * In videobuf we use our internal V4l2_planes struct for + * In vb2 we use our internal V4l2_planes struct for * single-planar buffers as well, for simplicity. * * If bytesused == 0 for the output buffer, then fall back @@ -625,19 +625,6 @@ static const struct vb2_buf_ops v4l2_buf_ops = { .copy_timestamp = __copy_timestamp, }; -int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, - unsigned int start_idx) -{ - unsigned int i; - - for (i = start_idx; i < q->num_buffers; i++) - if (q->bufs[i]->copied_timestamp && - q->bufs[i]->timestamp == timestamp) - return i; - return -1; -} -EXPORT_SYMBOL_GPL(vb2_find_timestamp); - struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) { unsigned int i; @@ -652,7 +639,7 @@ EXPORT_SYMBOL_GPL(vb2_find_buffer); /* * vb2_querybuf() - query video buffer information - * @q: videobuf queue + * @q: vb2 queue * @b: buffer struct passed from userspace to vidioc_querybuf handler * in driver * diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index d67f2dd997d0..fe19d127abb3 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -3212,7 +3212,7 @@ static int dib8000_tune(struct dvb_frontend *fe) case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { - /* if there is a diversity fe in input and this fe is has not already failed : wait here until this this fe has succedeed or failed */ + /* if there is a diversity fe in input and this fe is has not already failed : wait here until this fe has succeeded or failed */ if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failed also, break the current one */ diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 9430295a8175..9807f5411996 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -3516,7 +3516,7 @@ static int set_dvbt_standard(struct drxk_state *state, status = write16(state, IQM_AF_CLP_LEN__A, 0); if (status < 0) goto error; - /* window size for for sense pre-SAW detection */ + /* window size for sense pre-SAW detection */ status = write16(state, IQM_AF_SNS_LEN__A, 0); if (status < 0) goto error; @@ -6660,7 +6660,7 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr) static int drxk_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { struct drxk_state *state = fe->demodulator_priv; - u16 err; + u16 err = 0; dprintk(1, "\n"); diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 6a4f2997d6f5..05f71d169726 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -245,7 +245,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) if (unlikely(fbuf == NULL)) { dev->vb_full++; dev_notice_ratelimited(&pdev->dev, - "videobuf is full, %d packets dropped\n", + "video buffer is full, %d packets dropped\n", dev->vb_full); goto skip; } diff --git a/drivers/media/dvb-frontends/tda1002x.h b/drivers/media/dvb-frontends/tda1002x.h index 60a0952c1bca..00491bea9975 100644 --- a/drivers/media/dvb-frontends/tda1002x.h +++ b/drivers/media/dvb-frontends/tda1002x.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* TDA10021/TDA10023 - Single Chip Cable Channel Receiver driver module - used on the the Siemens DVB-C cards + used on the Siemens DVB-C cards Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de> Copyright (C) 2004 Markus Schulz <msc@antzsystem.de> diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index d1d206ebdedd..0b3f6999515e 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -1118,7 +1118,7 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, state->pll_pfactor = 0; } - /* Establish any defaults the the user didn't pass */ + /* Establish any defaults the user didn't pass */ tda10048_establish_defaults(&state->frontend); /* Set the xtal and freq defaults */ diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index 202e0cd83f90..910b5e83946a 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -943,8 +943,8 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, msg.len); - if (msg.len > 16) - msg.len = 16; + if (msg.len > CEC_MAX_MSG_SIZE) + msg.len = CEC_MAX_MSG_SIZE; if (msg.len) { u8 i; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 497419a5cfdd..815fe108281f 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2047,8 +2047,8 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled) struct cec_msg msg; msg.len = cec_read(sd, 0x25) & 0x1f; - if (msg.len > 16) - msg.len = 16; + if (msg.len > CEC_MAX_MSG_SIZE) + msg.len = CEC_MAX_MSG_SIZE; if (msg.len) { u8 i; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 22caa070273b..c541f9b3444b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2215,8 +2215,8 @@ static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled) struct cec_msg msg; msg.len = cec_read(sd, 0x25) & 0x1f; - if (msg.len > 16) - msg.len = 16; + if (msg.len > CEC_MAX_MSG_SIZE) + msg.len = CEC_MAX_MSG_SIZE; if (msg.len) { u8 i; diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index c7bdfc69b9be..a586e0fc0ea3 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -406,7 +406,6 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { struct ar0521_dev *sensor = to_ar0521_dev(sd); - int ret = 0; ar0521_adj_fmt(&format->format); @@ -423,7 +422,7 @@ static int ar0521_set_fmt(struct v4l2_subdev *sd, } mutex_unlock(&sensor->lock); - return ret; + return 0; } static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl) @@ -756,10 +755,12 @@ static int ar0521_power_on(struct device *dev) gpiod_set_value(sensor->reset_gpio, 0); usleep_range(4500, 5000); /* min 45000 clocks */ - for (cnt = 0; cnt < ARRAY_SIZE(initial_regs); cnt++) - if (ar0521_write_regs(sensor, initial_regs[cnt].data, - initial_regs[cnt].count)) + for (cnt = 0; cnt < ARRAY_SIZE(initial_regs); cnt++) { + ret = ar0521_write_regs(sensor, initial_regs[cnt].data, + initial_regs[cnt].count); + if (ret) goto off; + } ret = ar0521_write_reg(sensor, AR0521_REG_SERIAL_FORMAT, AR0521_REG_SERIAL_FORMAT_MIPI | diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 9d7d1d149f1a..8cef9656c612 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -196,7 +196,7 @@ static u32 clock_divider_to_resolution(u16 divider) { /* * Resolution is the duration of 1 tick of the readable portion of - * of the pulse width counter as read from the FIFO. The two lsb's are + * the pulse width counter as read from the FIFO. The two lsb's are * not readable, hence the << 2. This function returns ns. */ return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 56674173524f..a229e2d69ed6 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -238,6 +238,43 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, return 1; } +static int get_key_geniatech(struct IR_i2c *ir, enum rc_proto *protocol, + u32 *scancode, u8 *toggle) +{ + int i, rc; + unsigned char b; + + /* poll IR chip */ + for (i = 0; i < 4; i++) { + rc = i2c_master_recv(ir->c, &b, 1); + if (rc == 1) + break; + msleep(20); + } + if (rc != 1) { + dev_dbg(&ir->rc->dev, "read error\n"); + if (rc < 0) + return rc; + return -EIO; + } + + /* don't repeat the key */ + if (ir->old == b) + return 0; + ir->old = b; + + /* decode to RC5 */ + b &= 0x7f; + b = (b - 1) / 2; + + dev_dbg(&ir->rc->dev, "key %02x\n", b); + + *protocol = RC_PROTO_RC5; + *scancode = b; + *toggle = ir->old >> 7; + return 1; +} + static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *toggle) { @@ -766,6 +803,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc_proto = RC_PROTO_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; + case 0x33: + name = "Geniatech"; + ir->get_key = get_key_geniatech; + rc_proto = RC_PROTO_BIT_RC5; + ir_codes = RC_MAP_TOTAL_MEDIA_IN_HAND_02; + ir->old = 0xfc; + break; case 0x6b: name = "FusionHDTV"; ir->get_key = get_key_fusionhdtv; @@ -825,6 +869,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case IR_KBD_GET_KEY_KNC1: ir->get_key = get_key_knc1; break; + case IR_KBD_GET_KEY_GENIATECH: + ir->get_key = get_key_geniatech; + break; case IR_KBD_GET_KEY_FUSIONHDTV: ir->get_key = get_key_fusionhdtv; break; diff --git a/drivers/media/i2c/isl7998x.c b/drivers/media/i2c/isl7998x.c index dc3068549dfa..27feefe1dfcd 100644 --- a/drivers/media/i2c/isl7998x.c +++ b/drivers/media/i2c/isl7998x.c @@ -8,7 +8,7 @@ #include <linux/bitfield.h> #include <linux/delay.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of_graph.h> diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 2dc4a0f24ce8..7beca0b70b72 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -633,7 +633,7 @@ static int mt9v111_hw_config(struct mt9v111_dev *mt9v111) /* * Set pixel integration time to the whole frame time. - * This value controls the the shutter delay when running with AE + * This value controls the shutter delay when running with AE * disabled. If longer than frame time, it affects the output * frame rate. */ diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 502f0b62e950..94db427e21de 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/types.h> @@ -447,8 +448,6 @@ struct ov5640_dev { /* lock to protect all members below */ struct mutex lock; - int power_count; - struct v4l2_mbus_framefmt fmt; bool pending_fmt_change; @@ -2696,39 +2695,24 @@ power_off: return ret; } -/* --------------- Subdev Operations --------------- */ - -static int ov5640_s_power(struct v4l2_subdev *sd, int on) +static int ov5640_sensor_suspend(struct device *dev) { - struct ov5640_dev *sensor = to_ov5640_dev(sd); - int ret = 0; - - mutex_lock(&sensor->lock); - - /* - * If the power count is modified from 0 to != 0 or from != 0 to 0, - * update the power state. - */ - if (sensor->power_count == !on) { - ret = ov5640_set_power(sensor, !!on); - if (ret) - goto out; - } + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5640_dev *ov5640 = to_ov5640_dev(sd); - /* Update the power count. */ - sensor->power_count += on ? 1 : -1; - WARN_ON(sensor->power_count < 0); -out: - mutex_unlock(&sensor->lock); + return ov5640_set_power(ov5640, false); +} - if (on && !ret && sensor->power_count == 1) { - /* restore controls */ - ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); - } +static int ov5640_sensor_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov5640_dev *ov5640 = to_ov5640_dev(sd); - return ret; + return ov5640_set_power(ov5640, true); } +/* --------------- Subdev Operations --------------- */ + static int ov5640_try_frame_interval(struct ov5640_dev *sensor, struct v4l2_fract *fi, u32 width, u32 height) @@ -3314,6 +3298,9 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) /* v4l2_ctrl_lock() locks our own mutex */ + if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) + return 0; + switch (ctrl->id) { case V4L2_CID_AUTOGAIN: val = ov5640_get_gain(sensor); @@ -3329,6 +3316,8 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_put_autosuspend(&sensor->i2c_client->dev); + return 0; } @@ -3358,9 +3347,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) /* * If the device is not powered up by the host driver do * not apply any controls to H/W at this time. Instead - * the controls will be restored right after power-up. + * the controls will be restored at start streaming time. */ - if (sensor->power_count == 0) + if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) return 0; switch (ctrl->id) { @@ -3402,6 +3391,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } + pm_runtime_put_autosuspend(&sensor->i2c_client->dev); + return ret; } @@ -3677,6 +3668,18 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) struct ov5640_dev *sensor = to_ov5640_dev(sd); int ret = 0; + if (enable) { + ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); + if (ret < 0) + return ret; + + ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) { + pm_runtime_put(&sensor->i2c_client->dev); + return ret; + } + } + mutex_lock(&sensor->lock); if (sensor->streaming == !enable) { @@ -3701,8 +3704,13 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) if (!ret) sensor->streaming = enable; } + out: mutex_unlock(&sensor->lock); + + if (!enable || ret) + pm_runtime_put_autosuspend(&sensor->i2c_client->dev); + return ret; } @@ -3724,7 +3732,6 @@ static int ov5640_init_cfg(struct v4l2_subdev *sd, } static const struct v4l2_subdev_core_ops ov5640_core_ops = { - .s_power = ov5640_s_power, .log_status = v4l2_ctrl_subdev_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -3770,26 +3777,20 @@ static int ov5640_check_chip_id(struct ov5640_dev *sensor) int ret = 0; u16 chip_id; - ret = ov5640_set_power_on(sensor); - if (ret) - return ret; - ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); if (ret) { dev_err(&client->dev, "%s: failed to read chip identifier\n", __func__); - goto power_off; + return ret; } if (chip_id != 0x5640) { dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", __func__, chip_id); - ret = -ENXIO; + return -ENXIO; } -power_off: - ov5640_set_power_off(sensor); - return ret; + return 0; } static int ov5640_probe(struct i2c_client *client) @@ -3880,26 +3881,43 @@ static int ov5640_probe(struct i2c_client *client) ret = ov5640_get_regulators(sensor); if (ret) - return ret; + goto entity_cleanup; mutex_init(&sensor->lock); - ret = ov5640_check_chip_id(sensor); + ret = ov5640_init_controls(sensor); if (ret) goto entity_cleanup; - ret = ov5640_init_controls(sensor); - if (ret) + ret = ov5640_sensor_resume(dev); + if (ret) { + dev_err(dev, "failed to power on\n"); goto entity_cleanup; + } + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); + + ret = ov5640_check_chip_id(sensor); + if (ret) + goto err_pm_runtime; ret = v4l2_async_register_subdev_sensor(&sensor->sd); if (ret) - goto free_ctrls; + goto err_pm_runtime; + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_put_autosuspend(dev); return 0; -free_ctrls: +err_pm_runtime: + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); v4l2_ctrl_handler_free(&sensor->ctrls.handler); + ov5640_sensor_suspend(dev); entity_cleanup: media_entity_cleanup(&sensor->sd.entity); mutex_destroy(&sensor->lock); @@ -3910,6 +3928,12 @@ static int ov5640_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov5640_dev *sensor = to_ov5640_dev(sd); + struct device *dev = &client->dev; + + pm_runtime_disable(dev); + if (!pm_runtime_status_suspended(dev)) + ov5640_sensor_suspend(dev); + pm_runtime_set_suspended(dev); v4l2_async_unregister_subdev(&sensor->sd); media_entity_cleanup(&sensor->sd.entity); @@ -3919,6 +3943,10 @@ static int ov5640_remove(struct i2c_client *client) return 0; } +static const struct dev_pm_ops ov5640_pm_ops = { + SET_RUNTIME_PM_OPS(ov5640_sensor_suspend, ov5640_sensor_resume, NULL) +}; + static const struct i2c_device_id ov5640_id[] = { {"ov5640", 0}, {}, @@ -3935,6 +3963,7 @@ static struct i2c_driver ov5640_i2c_driver = { .driver = { .name = "ov5640", .of_match_table = ov5640_dt_ids, + .pm = &ov5640_pm_ops, }, .id_table = ov5640_id, .probe_new = ov5640_probe, diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index b8f4f0d3e33d..15d0f79231dd 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -3034,11 +3034,13 @@ static int ov8865_probe(struct i2c_client *client) &rate); if (!ret && sensor->extclk) { ret = clk_set_rate(sensor->extclk, rate); - if (ret) - return dev_err_probe(dev, ret, - "failed to set clock rate\n"); + if (ret) { + dev_err_probe(dev, ret, "failed to set clock rate\n"); + goto error_endpoint; + } } else if (ret && !sensor->extclk) { - return dev_err_probe(dev, ret, "invalid clock config\n"); + dev_err_probe(dev, ret, "invalid clock config\n"); + goto error_endpoint; } sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index e18b8947ad7e..804b8ee8e4ab 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -964,6 +964,8 @@ static void tc358743_cec_handler(struct v4l2_subdev *sd, u16 intstatus, v = i2c_rd32(sd, CECRCTR); msg.len = v & 0x1f; + if (msg.len > CEC_MAX_MSG_SIZE) + msg.len = CEC_MAX_MSG_SIZE; for (i = 0; i < msg.len; i++) { v = i2c_rd32(sd, CECRBUF1 + i * 4); msg.msg[i] = v & 0xff; diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index b8176a3b76d3..25020d58eb06 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -581,7 +581,7 @@ static void __media_device_unregister_entity(struct media_entity *entity) struct media_device *mdev = entity->graph_obj.mdev; struct media_link *link, *tmp; struct media_interface *intf; - unsigned int i; + struct media_pad *iter; ida_free(&mdev->entity_internal_idx, entity->internal_idx); @@ -597,8 +597,8 @@ static void __media_device_unregister_entity(struct media_entity *entity) __media_entity_remove_links(entity); /* Remove all pads that belong to this entity */ - for (i = 0; i < entity->num_pads; i++) - media_gobj_destroy(&entity->pads[i].graph_obj); + media_entity_for_each_pad(entity, iter) + media_gobj_destroy(&iter->graph_obj); /* Remove the entity */ media_gobj_destroy(&entity->graph_obj); @@ -610,7 +610,7 @@ int __must_check media_device_register_entity(struct media_device *mdev, struct media_entity *entity) { struct media_entity_notify *notify, *next; - unsigned int i; + struct media_pad *iter; int ret; if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN || @@ -639,9 +639,8 @@ int __must_check media_device_register_entity(struct media_device *mdev, media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj); /* Initialize objects at the pads */ - for (i = 0; i < entity->num_pads; i++) - media_gobj_create(mdev, MEDIA_GRAPH_PAD, - &entity->pads[i].graph_obj); + media_entity_for_each_pad(entity, iter) + media_gobj_create(mdev, MEDIA_GRAPH_PAD, &iter->graph_obj); /* invoke entity_notify callbacks */ list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index afd1bd7ff7b6..b8bcbc734eaf 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -59,10 +59,12 @@ static inline const char *link_type_name(struct media_link *link) } } -__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, - int idx_max) +__must_check int media_entity_enum_init(struct media_entity_enum *ent_enum, + struct media_device *mdev) { - idx_max = ALIGN(idx_max, BITS_PER_LONG); + int idx_max; + + idx_max = ALIGN(mdev->entity_internal_idx_max + 1, BITS_PER_LONG); ent_enum->bmap = bitmap_zalloc(idx_max, GFP_KERNEL); if (!ent_enum->bmap) return -ENOMEM; @@ -71,7 +73,7 @@ __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, return 0; } -EXPORT_SYMBOL_GPL(__media_entity_enum_init); +EXPORT_SYMBOL_GPL(media_entity_enum_init); void media_entity_enum_cleanup(struct media_entity_enum *ent_enum) { @@ -193,7 +195,8 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_pad *pads) { struct media_device *mdev = entity->graph_obj.mdev; - unsigned int i; + struct media_pad *iter; + unsigned int i = 0; if (num_pads >= MEDIA_ENTITY_MAX_PADS) return -E2BIG; @@ -204,12 +207,12 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads, if (mdev) mutex_lock(&mdev->graph_mutex); - for (i = 0; i < num_pads; i++) { - pads[i].entity = entity; - pads[i].index = i; + media_entity_for_each_pad(entity, iter) { + iter->entity = entity; + iter->index = i++; if (mdev) media_gobj_create(mdev, MEDIA_GRAPH_PAD, - &entity->pads[i].graph_obj); + &iter->graph_obj); } if (mdev) @@ -223,6 +226,33 @@ EXPORT_SYMBOL_GPL(media_entity_pads_init); * Graph traversal */ +/* + * This function checks the interdependency inside the entity between @pad0 + * and @pad1. If two pads are interdependent they are part of the same pipeline + * and enabling one of the pads means that the other pad will become "locked" + * and doesn't allow configuration changes. + * + * This function uses the &media_entity_operations.has_pad_interdep() operation + * to check the dependency inside the entity between @pad0 and @pad1. If the + * has_pad_interdep operation is not implemented, all pads of the entity are + * considered to be interdependent. + */ +static bool media_entity_has_pad_interdep(struct media_entity *entity, + unsigned int pad0, unsigned int pad1) +{ + if (pad0 >= entity->num_pads || pad1 >= entity->num_pads) + return false; + + if (entity->pads[pad0].flags & entity->pads[pad1].flags & + (MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_SOURCE)) + return false; + + if (!entity->ops || !entity->ops->has_pad_interdep) + return true; + + return entity->ops->has_pad_interdep(entity, pad0, pad1); +} + static struct media_entity * media_entity_other(struct media_entity *entity, struct media_link *link) { @@ -367,139 +397,435 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph) } EXPORT_SYMBOL_GPL(media_graph_walk_next); -int media_entity_get_fwnode_pad(struct media_entity *entity, - struct fwnode_handle *fwnode, - unsigned long direction_flags) +/* ----------------------------------------------------------------------------- + * Pipeline management + */ + +/* + * The pipeline traversal stack stores pads that are reached during graph + * traversal, with a list of links to be visited to continue the traversal. + * When a new pad is reached, an entry is pushed on the top of the stack and + * points to the incoming pad and the first link of the entity. + * + * To find further pads in the pipeline, the traversal algorithm follows + * internal pad dependencies in the entity, and then links in the graph. It + * does so by iterating over all links of the entity, and following enabled + * links that originate from a pad that is internally connected to the incoming + * pad, as reported by the media_entity_has_pad_interdep() function. + */ + +/** + * struct media_pipeline_walk_entry - Entry in the pipeline traversal stack + * + * @pad: The media pad being visited + * @links: Links left to be visited + */ +struct media_pipeline_walk_entry { + struct media_pad *pad; + struct list_head *links; +}; + +/** + * struct media_pipeline_walk - State used by the media pipeline traversal + * algorithm + * + * @mdev: The media device + * @stack: Depth-first search stack + * @stack.size: Number of allocated entries in @stack.entries + * @stack.top: Index of the top stack entry (-1 if the stack is empty) + * @stack.entries: Stack entries + */ +struct media_pipeline_walk { + struct media_device *mdev; + + struct { + unsigned int size; + int top; + struct media_pipeline_walk_entry *entries; + } stack; +}; + +#define MEDIA_PIPELINE_STACK_GROW_STEP 16 + +static struct media_pipeline_walk_entry * +media_pipeline_walk_top(struct media_pipeline_walk *walk) { - struct fwnode_endpoint endpoint; - unsigned int i; + return &walk->stack.entries[walk->stack.top]; +} + +static bool media_pipeline_walk_empty(struct media_pipeline_walk *walk) +{ + return walk->stack.top == -1; +} + +/* Increase the stack size by MEDIA_PIPELINE_STACK_GROW_STEP elements. */ +static int media_pipeline_walk_resize(struct media_pipeline_walk *walk) +{ + struct media_pipeline_walk_entry *entries; + unsigned int new_size; + + /* Safety check, to avoid stack overflows in case of bugs. */ + if (walk->stack.size >= 256) + return -E2BIG; + + new_size = walk->stack.size + MEDIA_PIPELINE_STACK_GROW_STEP; + + entries = krealloc(walk->stack.entries, + new_size * sizeof(*walk->stack.entries), + GFP_KERNEL); + if (!entries) + return -ENOMEM; + + walk->stack.entries = entries; + walk->stack.size = new_size; + + return 0; +} + +/* Push a new entry on the stack. */ +static int media_pipeline_walk_push(struct media_pipeline_walk *walk, + struct media_pad *pad) +{ + struct media_pipeline_walk_entry *entry; int ret; - if (!entity->ops || !entity->ops->get_fwnode_pad) { - for (i = 0; i < entity->num_pads; i++) { - if (entity->pads[i].flags & direction_flags) - return i; + if (walk->stack.top + 1 >= walk->stack.size) { + ret = media_pipeline_walk_resize(walk); + if (ret) + return ret; + } + + walk->stack.top++; + entry = media_pipeline_walk_top(walk); + entry->pad = pad; + entry->links = pad->entity->links.next; + + dev_dbg(walk->mdev->dev, + "media pipeline: pushed entry %u: '%s':%u\n", + walk->stack.top, pad->entity->name, pad->index); + + return 0; +} + +/* + * Move the top entry link cursor to the next link. If all links of the entry + * have been visited, pop the entry itself. + */ +static void media_pipeline_walk_pop(struct media_pipeline_walk *walk) +{ + struct media_pipeline_walk_entry *entry; + + if (WARN_ON(walk->stack.top < 0)) + return; + + entry = media_pipeline_walk_top(walk); + + if (entry->links->next == &entry->pad->entity->links) { + dev_dbg(walk->mdev->dev, + "media pipeline: entry %u has no more links, popping\n", + walk->stack.top); + + walk->stack.top--; + return; + } + + entry->links = entry->links->next; + + dev_dbg(walk->mdev->dev, + "media pipeline: moved entry %u to next link\n", + walk->stack.top); +} + +/* Free all memory allocated while walking the pipeline. */ +static void media_pipeline_walk_destroy(struct media_pipeline_walk *walk) +{ + kfree(walk->stack.entries); +} + +/* Add a pad to the pipeline and push it to the stack. */ +static int media_pipeline_add_pad(struct media_pipeline *pipe, + struct media_pipeline_walk *walk, + struct media_pad *pad) +{ + struct media_pipeline_pad *ppad; + + list_for_each_entry(ppad, &pipe->pads, list) { + if (ppad->pad == pad) { + dev_dbg(pad->graph_obj.mdev->dev, + "media pipeline: already contains pad '%s':%u\n", + pad->entity->name, pad->index); + return 0; } + } - return -ENXIO; + ppad = kzalloc(sizeof(*ppad), GFP_KERNEL); + if (!ppad) + return -ENOMEM; + + ppad->pipe = pipe; + ppad->pad = pad; + + list_add_tail(&ppad->list, &pipe->pads); + + dev_dbg(pad->graph_obj.mdev->dev, + "media pipeline: added pad '%s':%u\n", + pad->entity->name, pad->index); + + return media_pipeline_walk_push(walk, pad); +} + +/* Explore the next link of the entity at the top of the stack. */ +static int media_pipeline_explore_next_link(struct media_pipeline *pipe, + struct media_pipeline_walk *walk) +{ + struct media_pipeline_walk_entry *entry = media_pipeline_walk_top(walk); + struct media_pad *pad; + struct media_link *link; + struct media_pad *local; + struct media_pad *remote; + int ret; + + pad = entry->pad; + link = list_entry(entry->links, typeof(*link), list); + media_pipeline_walk_pop(walk); + + dev_dbg(walk->mdev->dev, + "media pipeline: exploring link '%s':%u -> '%s':%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + /* Skip links that are not enabled. */ + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { + dev_dbg(walk->mdev->dev, + "media pipeline: skipping link (disabled)\n"); + return 0; } - ret = fwnode_graph_parse_endpoint(fwnode, &endpoint); + /* Get the local pad and remote pad. */ + if (link->source->entity == pad->entity) { + local = link->source; + remote = link->sink; + } else { + local = link->sink; + remote = link->source; + } + + /* + * Skip links that originate from a different pad than the incoming pad + * that is not connected internally in the entity to the incoming pad. + */ + if (pad != local && + !media_entity_has_pad_interdep(pad->entity, pad->index, local->index)) { + dev_dbg(walk->mdev->dev, + "media pipeline: skipping link (no route)\n"); + return 0; + } + + /* + * Add the local and remote pads of the link to the pipeline and push + * them to the stack, if they're not already present. + */ + ret = media_pipeline_add_pad(pipe, walk, local); if (ret) return ret; - ret = entity->ops->get_fwnode_pad(entity, &endpoint); - if (ret < 0) + ret = media_pipeline_add_pad(pipe, walk, remote); + if (ret) return ret; - if (ret >= entity->num_pads) - return -ENXIO; + return 0; +} - if (!(entity->pads[ret].flags & direction_flags)) - return -ENXIO; +static void media_pipeline_cleanup(struct media_pipeline *pipe) +{ + while (!list_empty(&pipe->pads)) { + struct media_pipeline_pad *ppad; - return ret; + ppad = list_first_entry(&pipe->pads, typeof(*ppad), list); + list_del(&ppad->list); + kfree(ppad); + } } -EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad); -/* ----------------------------------------------------------------------------- - * Pipeline management - */ +static int media_pipeline_populate(struct media_pipeline *pipe, + struct media_pad *pad) +{ + struct media_pipeline_walk walk = { }; + struct media_pipeline_pad *ppad; + int ret; + + /* + * Populate the media pipeline by walking the media graph, starting + * from @pad. + */ + INIT_LIST_HEAD(&pipe->pads); + pipe->mdev = pad->graph_obj.mdev; + + walk.mdev = pipe->mdev; + walk.stack.top = -1; + ret = media_pipeline_add_pad(pipe, &walk, pad); + if (ret) + goto done; + + /* + * Use a depth-first search algorithm: as long as the stack is not + * empty, explore the next link of the top entry. The + * media_pipeline_explore_next_link() function will either move to the + * next link, pop the entry if fully visited, or add new entries on + * top. + */ + while (!media_pipeline_walk_empty(&walk)) { + ret = media_pipeline_explore_next_link(pipe, &walk); + if (ret) + goto done; + } + + dev_dbg(pad->graph_obj.mdev->dev, + "media pipeline populated, found pads:\n"); + + list_for_each_entry(ppad, &pipe->pads, list) + dev_dbg(pad->graph_obj.mdev->dev, "- '%s':%u\n", + ppad->pad->entity->name, ppad->pad->index); + + WARN_ON(walk.stack.top != -1); -__must_check int __media_pipeline_start(struct media_entity *entity, + ret = 0; + +done: + media_pipeline_walk_destroy(&walk); + + if (ret) + media_pipeline_cleanup(pipe); + + return ret; +} + +__must_check int __media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = entity->graph_obj.mdev; - struct media_graph *graph = &pipe->graph; - struct media_entity *entity_err = entity; - struct media_link *link; + struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_pipeline_pad *err_ppad; + struct media_pipeline_pad *ppad; int ret; - if (pipe->streaming_count) { - pipe->streaming_count++; + lockdep_assert_held(&mdev->graph_mutex); + + /* + * If the entity is already part of a pipeline, that pipeline must + * be the same as the pipe given to media_pipeline_start(). + */ + if (WARN_ON(pad->pipe && pad->pipe != pipe)) + return -EINVAL; + + /* + * If the pipeline has already been started, it is guaranteed to be + * valid, so just increase the start count. + */ + if (pipe->start_count) { + pipe->start_count++; return 0; } - ret = media_graph_walk_init(&pipe->graph, mdev); + /* + * Populate the pipeline. This populates the media_pipeline pads list + * with media_pipeline_pad instances for each pad found during graph + * walk. + */ + ret = media_pipeline_populate(pipe, pad); if (ret) return ret; - media_graph_walk_start(&pipe->graph, entity); + /* + * Now that all the pads in the pipeline have been gathered, perform + * the validation steps. + */ + + list_for_each_entry(ppad, &pipe->pads, list) { + struct media_pad *pad = ppad->pad; + struct media_entity *entity = pad->entity; + bool has_enabled_link = false; + bool has_link = false; + struct media_link *link; - while ((entity = media_graph_walk_next(graph))) { - DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS); - DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS); + dev_dbg(mdev->dev, "Validating pad '%s':%u\n", pad->entity->name, + pad->index); - if (entity->pipe && entity->pipe != pipe) { - pr_err("Pipe active for %s. Can't start for %s\n", - entity->name, - entity_err->name); + /* + * 1. Ensure that the pad doesn't already belong to a different + * pipeline. + */ + if (pad->pipe) { + dev_dbg(mdev->dev, "Failed to start pipeline: pad '%s':%u busy\n", + pad->entity->name, pad->index); ret = -EBUSY; goto error; } - /* Already streaming --- no need to check. */ - if (entity->pipe) - continue; - - entity->pipe = pipe; - - if (!entity->ops || !entity->ops->link_validate) - continue; - - bitmap_zero(active, entity->num_pads); - bitmap_fill(has_no_links, entity->num_pads); - + /* + * 2. Validate all active links whose sink is the current pad. + * Validation of the source pads is performed in the context of + * the connected sink pad to avoid duplicating checks. + */ for_each_media_entity_data_link(entity, link) { - struct media_pad *pad = link->sink->entity == entity - ? link->sink : link->source; + /* Skip links unrelated to the current pad. */ + if (link->sink != pad && link->source != pad) + continue; - /* Mark that a pad is connected by a link. */ - bitmap_clear(has_no_links, pad->index, 1); + /* Record if the pad has links and enabled links. */ + if (link->flags & MEDIA_LNK_FL_ENABLED) + has_enabled_link = true; + has_link = true; /* - * Pads that either do not need to connect or - * are connected through an enabled link are - * fine. + * Validate the link if it's enabled and has the + * current pad as its sink. */ - if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) || - link->flags & MEDIA_LNK_FL_ENABLED) - bitmap_set(active, pad->index, 1); + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; - /* - * Link validation will only take place for - * sink ends of the link that are enabled. - */ - if (link->sink != pad || - !(link->flags & MEDIA_LNK_FL_ENABLED)) + if (link->sink != pad) + continue; + + if (!entity->ops || !entity->ops->link_validate) continue; ret = entity->ops->link_validate(link); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(entity->graph_obj.mdev->dev, - "link validation failed for '%s':%u -> '%s':%u, error %d\n", + if (ret) { + dev_dbg(mdev->dev, + "Link '%s':%u -> '%s':%u failed validation: %d\n", link->source->entity->name, link->source->index, - entity->name, link->sink->index, ret); + link->sink->entity->name, + link->sink->index, ret); goto error; } - } - /* Either no links or validated links are fine. */ - bitmap_or(active, active, has_no_links, entity->num_pads); + dev_dbg(mdev->dev, + "Link '%s':%u -> '%s':%u is valid\n", + link->source->entity->name, + link->source->index, + link->sink->entity->name, + link->sink->index); + } - if (!bitmap_full(active, entity->num_pads)) { + /* + * 3. If the pad has the MEDIA_PAD_FL_MUST_CONNECT flag set, + * ensure that it has either no link or an enabled link. + */ + if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) && has_link && + !has_enabled_link) { + dev_dbg(mdev->dev, + "Pad '%s':%u must be connected by an enabled link\n", + pad->entity->name, pad->index); ret = -ENOLINK; - dev_dbg(entity->graph_obj.mdev->dev, - "'%s':%u must be connected by an enabled link\n", - entity->name, - (unsigned)find_first_zero_bit( - active, entity->num_pads)); goto error; } + + /* Validation passed, store the pipe pointer in the pad. */ + pad->pipe = pipe; } - pipe->streaming_count++; + pipe->start_count++; return 0; @@ -508,42 +834,37 @@ error: * Link validation on graph failed. We revert what we did and * return the error. */ - media_graph_walk_start(graph, entity_err); - while ((entity_err = media_graph_walk_next(graph))) { - entity_err->pipe = NULL; - - /* - * We haven't started entities further than this so we quit - * here. - */ - if (entity_err == entity) + list_for_each_entry(err_ppad, &pipe->pads, list) { + if (err_ppad == ppad) break; + + err_ppad->pad->pipe = NULL; } - media_graph_walk_cleanup(graph); + media_pipeline_cleanup(pipe); return ret; } EXPORT_SYMBOL_GPL(__media_pipeline_start); -__must_check int media_pipeline_start(struct media_entity *entity, +__must_check int media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe) { - struct media_device *mdev = entity->graph_obj.mdev; + struct media_device *mdev = pad->entity->graph_obj.mdev; int ret; mutex_lock(&mdev->graph_mutex); - ret = __media_pipeline_start(entity, pipe); + ret = __media_pipeline_start(pad, pipe); mutex_unlock(&mdev->graph_mutex); return ret; } EXPORT_SYMBOL_GPL(media_pipeline_start); -void __media_pipeline_stop(struct media_entity *entity) +void __media_pipeline_stop(struct media_pad *pad) { - struct media_graph *graph = &entity->pipe->graph; - struct media_pipeline *pipe = entity->pipe; + struct media_pipeline *pipe = pad->pipe; + struct media_pipeline_pad *ppad; /* * If the following check fails, the driver has performed an @@ -552,29 +873,65 @@ void __media_pipeline_stop(struct media_entity *entity) if (WARN_ON(!pipe)) return; - if (--pipe->streaming_count) + if (--pipe->start_count) return; - media_graph_walk_start(graph, entity); - - while ((entity = media_graph_walk_next(graph))) - entity->pipe = NULL; + list_for_each_entry(ppad, &pipe->pads, list) + ppad->pad->pipe = NULL; - media_graph_walk_cleanup(graph); + media_pipeline_cleanup(pipe); + if (pipe->allocated) + kfree(pipe); } EXPORT_SYMBOL_GPL(__media_pipeline_stop); -void media_pipeline_stop(struct media_entity *entity) +void media_pipeline_stop(struct media_pad *pad) { - struct media_device *mdev = entity->graph_obj.mdev; + struct media_device *mdev = pad->entity->graph_obj.mdev; mutex_lock(&mdev->graph_mutex); - __media_pipeline_stop(entity); + __media_pipeline_stop(pad); mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_pipeline_stop); +__must_check int media_pipeline_alloc_start(struct media_pad *pad) +{ + struct media_device *mdev = pad->entity->graph_obj.mdev; + struct media_pipeline *new_pipe = NULL; + struct media_pipeline *pipe; + int ret; + + mutex_lock(&mdev->graph_mutex); + + /* + * Is the entity already part of a pipeline? If not, we need to allocate + * a pipe. + */ + pipe = media_pad_pipeline(pad); + if (!pipe) { + new_pipe = kzalloc(sizeof(*new_pipe), GFP_KERNEL); + if (!new_pipe) { + ret = -ENOMEM; + goto out; + } + + pipe = new_pipe; + pipe->allocated = true; + } + + ret = __media_pipeline_start(pad, pipe); + if (ret) + kfree(new_pipe); + +out: + mutex_unlock(&mdev->graph_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(media_pipeline_alloc_start); + /* ----------------------------------------------------------------------------- * Links management */ @@ -829,7 +1186,7 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) { const u32 mask = MEDIA_LNK_FL_ENABLED; struct media_device *mdev; - struct media_entity *source, *sink; + struct media_pad *source, *sink; int ret = -EBUSY; if (link == NULL) @@ -845,12 +1202,11 @@ int __media_entity_setup_link(struct media_link *link, u32 flags) if (link->flags == flags) return 0; - source = link->source->entity; - sink = link->sink->entity; + source = link->source; + sink = link->sink; if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && - (media_entity_is_streaming(source) || - media_entity_is_streaming(sink))) + (media_pad_is_streaming(source) || media_pad_is_streaming(sink))) return -EBUSY; mdev = source->graph_obj.mdev; @@ -991,6 +1347,60 @@ struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad) } EXPORT_SYMBOL_GPL(media_pad_remote_pad_unique); +int media_entity_get_fwnode_pad(struct media_entity *entity, + struct fwnode_handle *fwnode, + unsigned long direction_flags) +{ + struct fwnode_endpoint endpoint; + unsigned int i; + int ret; + + if (!entity->ops || !entity->ops->get_fwnode_pad) { + for (i = 0; i < entity->num_pads; i++) { + if (entity->pads[i].flags & direction_flags) + return i; + } + + return -ENXIO; + } + + ret = fwnode_graph_parse_endpoint(fwnode, &endpoint); + if (ret) + return ret; + + ret = entity->ops->get_fwnode_pad(entity, &endpoint); + if (ret < 0) + return ret; + + if (ret >= entity->num_pads) + return -ENXIO; + + if (!(entity->pads[ret].flags & direction_flags)) + return -ENXIO; + + return ret; +} +EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad); + +struct media_pipeline *media_entity_pipeline(struct media_entity *entity) +{ + struct media_pad *pad; + + media_entity_for_each_pad(entity, pad) { + if (pad->pipe) + return pad->pipe; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(media_entity_pipeline); + +struct media_pipeline *media_pad_pipeline(struct media_pad *pad) +{ + return pad->pipe; +} +EXPORT_SYMBOL_GPL(media_pad_pipeline); + static void media_interface_init(struct media_device *mdev, struct media_interface *intf, u32 gobj_type, diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 1224d908713a..dff0b450f387 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -13,12 +13,12 @@ if MEDIA_PCI_SUPPORT if MEDIA_CAMERA_SUPPORT comment "Media capture support" -source "drivers/media/pci/meye/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" source "drivers/media/pci/sta2x11/Kconfig" source "drivers/media/pci/tw5864/Kconfig" source "drivers/media/pci/tw68/Kconfig" source "drivers/media/pci/tw686x/Kconfig" +source "drivers/media/pci/zoran/Kconfig" endif @@ -27,7 +27,6 @@ if MEDIA_ANALOG_TV_SUPPORT source "drivers/media/pci/dt3155/Kconfig" source "drivers/media/pci/ivtv/Kconfig" -source "drivers/media/pci/saa7146/Kconfig" endif @@ -58,7 +57,6 @@ source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/pt1/Kconfig" source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/smipcie/Kconfig" -source "drivers/media/pci/ttpci/Kconfig" endif diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index 551169a3e434..8f887a8a7f17 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -5,8 +5,7 @@ # Please keep it alphabetically sorted by directory # (e. g. LC_ALL=C sort Makefile) -obj-y += ttpci/ \ - b2c2/ \ +obj-y += b2c2/ \ pluto2/ \ dm1105/ \ pt1/ \ @@ -14,7 +13,6 @@ obj-y += ttpci/ \ mantis/ \ ngene/ \ ddbridge/ \ - saa7146/ \ smipcie/ \ netup_unidvb/ \ intel/ @@ -32,10 +30,10 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_DT3155) += dt3155/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ obj-$(CONFIG_VIDEO_TW5864) += tw5864/ obj-$(CONFIG_VIDEO_TW686X) += tw686x/ obj-$(CONFIG_VIDEO_TW68) += tw68/ +obj-$(CONFIG_VIDEO_ZORAN) += zoran/ diff --git a/drivers/media/pci/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c index 833baa934448..78e05df9a7ba 100644 --- a/drivers/media/pci/cx18/cx18-av-audio.c +++ b/drivers/media/pci/cx18/cx18-av-audio.c @@ -50,7 +50,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. + * audio/video sync problems with SVideo and CVBS captures. */ if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index d3358643fb7d..ee6e71157786 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -339,7 +339,7 @@ void cx18_av_std_setup(struct cx18 *cx) /* * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is - * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 + * 864 pixels = 720 active + 144 blanking. ITU-R BT.601 * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after * the end of active video to start a horizontal line, so that * leaves 132 pixels of hblank to ignore. @@ -399,7 +399,7 @@ void cx18_av_std_setup(struct cx18 *cx) /* * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is - * is 858 pixels = 720 active + 138 blanking. The Hsync leading + * 858 pixels = 720 active + 138 blanking. The Hsync leading * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the * end of active video, leaving 122 pixels of hblank to ignore * before active video starts. diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index fdac310d7477..1b038b2802bf 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -248,7 +248,7 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. + * audio/video sync problems with SVideo and CVBS captures. */ /* the fast clock is at 200/245 MHz */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index a07b18f2034e..9232a966bcab 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2086,6 +2086,9 @@ static struct { /* 0x1419 is the PCI ID for the IOMMU found on 15h (Models 10h-1fh) family */ { PCI_VENDOR_ID_AMD, 0x1419 }, + /* 0x1631 is the PCI ID for the IOMMU found on Renoir/Cezanne + */ + { PCI_VENDOR_ID_AMD, 0x1631 }, /* 0x5a23 is the PCI ID for the IOMMU found on RD890S/RD990 */ { PCI_VENDOR_ID_ATI, 0x5a23 }, diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index ddfd2eb37484..222d04421468 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -235,7 +235,7 @@ static u32 clock_divider_to_resolution(u16 divider) { /* * Resolution is the duration of 1 tick of the readable portion of - * of the pulse width counter as read from the FIFO. The two lsb's are + * the pulse width counter as read from the FIFO. The two lsb's are * not readable, hence the << 2. This function returns ns. */ return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000, diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index f1e1fc1cb4bd..e378f3b215c7 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -24,7 +24,7 @@ /* * We calculate the baseband frequencies of the carrier and the pilot tones - * based on the the sampling rate of the audio rds fifo. + * based on the sampling rate of the audio rds fifo. */ #define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index ce0ef0b8186f..a04a1d33fadb 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -586,7 +586,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) { struct i2c_board_info info; static const unsigned short default_addr_list[] = { - 0x18, 0x6b, 0x71, + 0x18, 0x33, 0x6b, 0x71, I2C_CLIENT_END }; static const unsigned short pvr2000_addr_list[] = { diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index a075788c64d4..469aeaa725ad 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -144,11 +144,10 @@ static int buffer_prepare(struct vb2_buffer *vb) return -EINVAL; vb2_set_plane_payload(vb, 0, size); - cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl, - 0, VBI_LINE_LENGTH * lines, - VBI_LINE_LENGTH, 0, - lines); - return 0; + return cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl, + 0, VBI_LINE_LENGTH * lines, + VBI_LINE_LENGTH, 0, + lines); } static void buffer_finish(struct vb2_buffer *vb) diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index d3729be89252..c0ef03ed74f9 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -431,6 +431,7 @@ static int queue_setup(struct vb2_queue *q, static int buffer_prepare(struct vb2_buffer *vb) { + int ret; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct cx8800_dev *dev = vb->vb2_queue->drv_priv; struct cx88_core *core = dev->core; @@ -445,35 +446,35 @@ static int buffer_prepare(struct vb2_buffer *vb) switch (core->field) { case V4L2_FIELD_TOP: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, 0, UNSET, - buf->bpl, 0, core->height); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, core->height); break; case V4L2_FIELD_BOTTOM: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, UNSET, 0, - buf->bpl, 0, core->height); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, core->height); break; case V4L2_FIELD_SEQ_TB: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, - 0, buf->bpl * (core->height >> 1), - buf->bpl, 0, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (core->height >> 1), + buf->bpl, 0, + core->height >> 1); break; case V4L2_FIELD_SEQ_BT: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, - buf->bpl * (core->height >> 1), 0, - buf->bpl, 0, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (core->height >> 1), 0, + buf->bpl, 0, + core->height >> 1); break; case V4L2_FIELD_INTERLACED: default: - cx88_risc_buffer(dev->pci, &buf->risc, - sgt->sgl, 0, buf->bpl, - buf->bpl, buf->bpl, - core->height >> 1); + ret = cx88_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, buf->bpl, + buf->bpl, buf->bpl, + core->height >> 1); break; } dprintk(2, @@ -481,7 +482,7 @@ static int buffer_prepare(struct vb2_buffer *vb) buf, buf->vb.vb2_buf.index, __func__, core->width, core->height, dev->fmt->depth, dev->fmt->fourcc, (unsigned long)buf->risc.dma); - return 0; + return ret; } static void buffer_finish(struct vb2_buffer *vb) @@ -1387,6 +1388,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, } fallthrough; case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: + case CX88_BOARD_NOTONLYTV_LV3H: request_module("ir-kbd-i2c"); } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index a3fe547b7fce..390bd5ea3472 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -989,7 +989,7 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) return r; } - r = media_pipeline_start(&q->vdev.entity, &q->pipe); + r = video_device_pipeline_start(&q->vdev, &q->pipe); if (r) goto fail_pipeline; @@ -1009,7 +1009,7 @@ static int cio2_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) fail_csi2_subdev: cio2_hw_exit(cio2, q); fail_hw: - media_pipeline_stop(&q->vdev.entity); + video_device_pipeline_stop(&q->vdev); fail_pipeline: dev_dbg(dev, "failed to start streaming (%d)\n", r); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_QUEUED); @@ -1030,7 +1030,7 @@ static void cio2_vb2_stop_streaming(struct vb2_queue *vq) cio2_hw_exit(cio2, q); synchronize_irq(cio2->pci_dev->irq); cio2_vb2_return_all_buffers(q, VB2_BUF_STATE_ERROR); - media_pipeline_stop(&q->vdev.entity); + video_device_pipeline_stop(&q->vdev); pm_runtime_put(dev); cio2->streaming = false; } diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index e79e8a5a744a..4ba10c34a16a 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -538,7 +538,7 @@ static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *f) reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94); /* Okay, we've wasted time working out the correct value, - but if we use it, it fouls the the window alignment. + but if we use it, it fouls the window alignment. Fudge it to what we want... */ reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16)); reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16)); diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 3d296f1998a1..d1d7da84cd9d 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -596,43 +596,6 @@ struct mychip { int capture_source[MIXER_ADDR_LAST + 1][2]; }; -#ifdef NGENE_V4L -struct ngene_overlay { - int tvnorm; - struct v4l2_rect w; - enum v4l2_field field; - struct v4l2_clip *clips; - int nclips; - int setup_ok; -}; - -struct ngene_tvnorm { - int v4l2_id; - char *name; - u16 swidth, sheight; /* scaled standard width, height */ - int tuner_norm; - int soundstd; -}; - -struct ngene_vopen { - struct ngene_channel *ch; - enum v4l2_priority prio; - int width; - int height; - int depth; - struct videobuf_queue vbuf_q; - struct videobuf_queue vbi; - int fourcc; - int picxcount; - int resources; - enum v4l2_buf_type type; - const struct ngene_format *fmt; - - const struct ngene_format *ovfmt; - struct ngene_overlay ov; -}; -#endif - struct ngene_channel { struct device device; struct i2c_adapter i2c_adapter; @@ -709,18 +672,6 @@ struct ngene_channel { int tvnorm_num; int tvnorm; -#ifdef NGENE_V4L - int videousers; - struct v4l2_prio_state prio; - struct ngene_vopen init; - int resources; - struct v4l2_framebuffer fbuf; - struct ngene_buffer *screen; /* overlay */ - struct list_head capture; /* video capture queue */ - spinlock_t s_lock; - struct semaphore reslock; -#endif - int running; int tsin_offset; @@ -863,35 +814,6 @@ struct ngene_info { int (*switch_ctrl)(struct ngene_channel *, int, int); }; -#ifdef NGENE_V4L -struct ngene_format { - char *name; - int fourcc; /* video4linux 2 */ - int btformat; /* BT848_COLOR_FMT_* */ - int format; - int btswap; /* BT848_COLOR_CTL_* */ - int depth; /* bit/pixel */ - int flags; - int hshift, vshift; /* for planar modes */ - int palette; -}; - -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 - -struct ngene_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - /* ngene specific */ - const struct ngene_format *fmt; - int tvnorm; - int btformat; - int btswap; -}; -#endif - /* Provided by ngene-core.c */ int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 7973ae42873a..d5f32e3ff544 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -626,7 +626,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) portf = &dev->ports[SAA7164_PORT_VBI2]; /* Check that the hardware is accessible. If the status bytes are - * 0xFF then the device is not accessible, the the IRQ belongs + * 0xFF then the device is not accessible, the IRQ belongs * to another driver. * 4 x u32 interrupt registers. */ diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 80d20e2a2099..0adf3d80f248 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -1020,7 +1020,7 @@ static int solo_g_parm(struct file *file, void *priv, cp->timeperframe.numerator = solo_enc->interval; cp->timeperframe.denominator = solo_enc->solo_dev->fps; cp->capturemode = 0; - /* XXX: Shouldn't we be able to get/set this from videobuf? */ + /* XXX: Shouldn't we be able to get/set this from vb2? */ cp->readbuffers = 2; return 0; diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/media/pci/zoran/Kconfig index 3fb3e27e04a8..3fb3e27e04a8 100644 --- a/drivers/staging/media/zoran/Kconfig +++ b/drivers/media/pci/zoran/Kconfig diff --git a/drivers/staging/media/zoran/Makefile b/drivers/media/pci/zoran/Makefile index 9603bac0195c..9603bac0195c 100644 --- a/drivers/staging/media/zoran/Makefile +++ b/drivers/media/pci/zoran/Makefile diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c index a0c8bde5ec11..8efc5e06b0f7 100644 --- a/drivers/staging/media/zoran/videocodec.c +++ b/drivers/media/pci/zoran/videocodec.c @@ -92,9 +92,8 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) h->attached += 1; return codec; - } else { - kfree(codec); } + kfree(codec); } h = h->next; } @@ -255,8 +254,8 @@ int videocodec_debugfs_show(struct seq_file *m) struct codec_list *h = codeclist_top; struct attached_list *a; - seq_printf(m, "<S>lave or attached <M>aster name type flags magic "); - seq_printf(m, "(connected as)\n"); + seq_puts(m, "<S>lave or attached <M>aster name type flags magic "); + seq_puts(m, "(connected as)\n"); while (h) { seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", diff --git a/drivers/staging/media/zoran/videocodec.h b/drivers/media/pci/zoran/videocodec.h index 5e6057edd339..6b69f69667f9 100644 --- a/drivers/staging/media/zoran/videocodec.h +++ b/drivers/media/pci/zoran/videocodec.h @@ -12,109 +12,109 @@ /* general description */ /* =================== */ -/* Should ease the (re-)usage of drivers supporting cards with (different) - video codecs. The codecs register to this module their functionality, - and the processors (masters) can attach to them if they fit. - - The codecs are typically have a "strong" binding to their master - so I - don't think it makes sense to have a full blown interfacing as with e.g. - i2c. If you have an other opinion, let's discuss & implement it :-))) - - Usage: - - The slave has just to setup the videocodec structure and use two functions: - videocodec_register(codecdata); - videocodec_unregister(codecdata); - The best is just calling them at module (de-)initialisation. - - The master sets up the structure videocodec_master and calls: - codecdata=videocodec_attach(master_codecdata); - videocodec_detach(codecdata); - - The slave is called during attach/detach via functions setup previously - during register. At that time, the master_data pointer is set up - and the slave can access any io registers of the master device (in the case - the slave is bound to it). Otherwise it doesn't need this functions and - therfor they may not be initialized. - - The other functions are just for convenience, as they are for sure used by - most/all of the codecs. The last ones may be omitted, too. - - See the structure declaration below for more information and which data has - to be set up for the master and the slave. - - ---------------------------------------------------------------------------- - The master should have "knowledge" of the slave and vice versa. So the data - structures sent to/from slave via set_data/get_data set_image/get_image are - device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!) - ---------------------------------------------------------------------------- -*/ +/* + * Should ease the (re-)usage of drivers supporting cards with (different) + * video codecs. The codecs register to this module their functionality, + * and the processors (masters) can attach to them if they fit. + * + * The codecs are typically have a "strong" binding to their master - so I + * don't think it makes sense to have a full blown interfacing as with e.g. + * i2c. If you have an other opinion, let's discuss & implement it :-))) + * + * Usage: + * + * The slave has just to setup the videocodec structure and use two functions: + * videocodec_register(codecdata); + * videocodec_unregister(codecdata); + * The best is just calling them at module (de-)initialisation. + * + * The master sets up the structure videocodec_master and calls: + * codecdata=videocodec_attach(master_codecdata); + * videocodec_detach(codecdata); + * + * The slave is called during attach/detach via functions setup previously + * during register. At that time, the master_data pointer is set up + * and the slave can access any io registers of the master device (in the case + * the slave is bound to it). Otherwise it doesn't need this functions and + * therefor they may not be initialized. + * + * The other functions are just for convenience, as they are for sure used by + * most/all of the codecs. The last ones may be omitted, too. + * + * See the structure declaration below for more information and which data has + * to be set up for the master and the slave. + * + * ---------------------------------------------------------------------------- + * The master should have "knowledge" of the slave and vice versa. So the data + * structures sent to/from slave via set_data/get_data set_image/get_image are + * device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!) + * ---------------------------------------------------------------------------- + */ /* ========================================== */ /* description of the videocodec_io structure */ /* ========================================== */ /* - ==== master setup ==== - name -> name of the device structure for reference and debugging - master_data -> data ref. for the master (e.g. the zr36055,57,67) - readreg -> ref. to read-fn from register (setup by master, used by slave) - writereg -> ref. to write-fn to register (setup by master, used by slave) - this two functions do the lowlevel I/O job - - ==== slave functionality setup ==== - slave_data -> data ref. for the slave (e.g. the zr36050,60) - check -> fn-ref. checks availability of an device, returns -EIO on failure or - the type on success - this makes espcecially sense if a driver module supports more than - one codec which may be quite similar to access, nevertheless it - is good for a first functionality check - - -- main functions you always need for compression/decompression -- - - set_mode -> this fn-ref. resets the entire codec, and sets up the mode - with the last defined norm/size (or device default if not - available) - it returns 0 if the mode is possible - set_size -> this fn-ref. sets the norm and image size for - compression/decompression (returns 0 on success) - the norm param is defined in videodev2.h (V4L2_STD_*) - - additional setup may be available, too - but the codec should work with - some default values even without this - - set_data -> sets device-specific data (tables, quality etc.) - get_data -> query device-specific data (tables, quality etc.) - - if the device delivers interrupts, they may be setup/handled here - setup_interrupt -> codec irq setup (not needed for 36050/60) - handle_interrupt -> codec irq handling (not needed for 36050/60) - - if the device delivers pictures, they may be handled here - put_image -> puts image data to the codec (not needed for 36050/60) - get_image -> gets image data from the codec (not needed for 36050/60) - the calls include frame numbers and flags (even/odd/...) - if needed and a flag which allows blocking until its ready -*/ + * ==== master setup ==== + * name -> name of the device structure for reference and debugging + * master_data -> data ref. for the master (e.g. the zr36055,57,67) + * readreg -> ref. to read-fn from register (setup by master, used by slave) + * writereg -> ref. to write-fn to register (setup by master, used by slave) + * this two functions do the lowlevel I/O job + * + * ==== slave functionality setup ==== + * slave_data -> data ref. for the slave (e.g. the zr36050,60) + * check -> fn-ref. checks availability of an device, returns -EIO on failure or + * the type on success + * this makes espcecially sense if a driver module supports more than + * one codec which may be quite similar to access, nevertheless it + * is good for a first functionality check + * + * -- main functions you always need for compression/decompression -- + * + * set_mode -> this fn-ref. resets the entire codec, and sets up the mode + * with the last defined norm/size (or device default if not + * available) - it returns 0 if the mode is possible + * set_size -> this fn-ref. sets the norm and image size for + * compression/decompression (returns 0 on success) + * the norm param is defined in videodev2.h (V4L2_STD_*) + * + * additional setup may be available, too - but the codec should work with + * some default values even without this + * + * set_data -> sets device-specific data (tables, quality etc.) + * get_data -> query device-specific data (tables, quality etc.) + * + * if the device delivers interrupts, they may be setup/handled here + * setup_interrupt -> codec irq setup (not needed for 36050/60) + * handle_interrupt -> codec irq handling (not needed for 36050/60) + + * if the device delivers pictures, they may be handled here + * put_image -> puts image data to the codec (not needed for 36050/60) + * get_image -> gets image data from the codec (not needed for 36050/60) + * the calls include frame numbers and flags (even/odd/...) + * if needed and a flag which allows blocking until its ready + */ /* ============== */ /* user interface */ /* ============== */ /* - Currently there is only a information display planned, as the layer - is not visible for the user space at all. - - Information is available via procfs. The current entry is "/proc/videocodecs" - but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--. - -A example for such an output is: - -<S>lave or attached <M>aster name type flags magic (connected as) -S zr36050 0002 0000d001 00000000 (TEMPLATE) -M zr36055[0] 0001 0000c001 00000000 (zr36050[0]) -M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) - -*/ + * Currently there is only a information display planned, as the layer + * is not visible for the user space at all. + * + * Information is available via procfs. The current entry is "/proc/videocodecs" + * but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--. + * + * A example for such an output is: + * + * <S>lave or attached <M>aster name type flags magic (connected as) + * S zr36050 0002 0000d001 00000000 (TEMPLATE) + * M zr36055[0] 0001 0000c001 00000000 (zr36050[0]) + * M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) + */ /* =============================================== */ /* special defines for the videocodec_io structure */ @@ -293,15 +293,15 @@ struct videocodec_master { // * master structure needs to be kmalloc'ed before calling attach // and free'd after calling detach // * returns pointer on success, NULL on failure -extern struct videocodec *videocodec_attach(struct videocodec_master *); +struct videocodec *videocodec_attach(struct videocodec_master *master); // * 0 on success, <0 (errno) on failure -extern int videocodec_detach(struct videocodec *); +int videocodec_detach(struct videocodec *codec); /* register and unregister commands for the slaves */ // * 0 on success, <0 (errno) on failure -extern int videocodec_register(const struct videocodec *); +int videocodec_register(const struct videocodec *codec); // * 0 on success, <0 (errno) on failure -extern int videocodec_unregister(const struct videocodec *); +int videocodec_unregister(const struct videocodec *codec); /* the other calls are directly done via the videocodec structure! */ diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index 05227e5298f6..56340553b282 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -140,11 +140,16 @@ struct zoran_v4l_settings { /* jpg-capture/-playback settings */ struct zoran_jpg_settings { - int decimation; /* this bit is used to set everything to default */ - int hor_dcm, ver_dcm, tmp_dcm; /* capture decimation settings (tmp_dcm=1 means both fields) */ - int field_per_buff, odd_even; /* field-settings (odd_even=1 (+tmp_dcm=1) means top-field-first) */ - int img_x, img_y, img_width, img_height; /* crop settings (subframe capture) */ - struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */ + /* this bit is used to set everything to default */ + int decimation; + /* capture decimation settings (tmp_dcm=1 means both fields) */ + int hor_dcm, ver_dcm, tmp_dcm; + /* field-settings (odd_even=1 (+tmp_dcm=1) means top-field-first) */ + int field_per_buff, odd_even; + /* crop settings (subframe capture) */ + int img_x, img_y, img_width, img_height; + /* JPEG-specific capture settings */ + struct v4l2_jpegcompression jpg_comp; }; struct zoran; @@ -248,7 +253,8 @@ struct zoran { unsigned long vbseq; /* zr36057's code buffer table */ - __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ + __le32 *stat_com; /* Additional stuff for testing */ unsigned int ghost_int; @@ -292,14 +298,16 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct zoran, v4l2_dev); } -/* There was something called _ALPHA_BUZ that used the PCI address instead of - * the kernel iomapped address for btread/btwrite. */ +/* + * There was something called _ALPHA_BUZ that used the PCI address instead of + * the kernel iomapped address for btread/btwrite. + */ #define btwrite(dat, adr) writel((dat), zr->zr36057_mem + (adr)) #define btread(adr) readl(zr->zr36057_mem + (adr)) -#define btand(dat, adr) btwrite((dat) & btread(adr), adr) -#define btor(dat, adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), adr) +#define btand(dat, adr) btwrite((dat) & btread(adr), (adr)) +#define btor(dat, adr) btwrite((dat) | btread(adr), (adr)) +#define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), (adr)) #endif diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index 26f978a1cc72..3975fc1b2ee3 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -172,8 +172,6 @@ void zr36016_write(struct videocodec *codec, u16 reg, u32 val) static void dc10_init(struct zoran *zr) { - pci_dbg(zr->pci_dev, "%s\n", __func__); - /* Pixel clock selection */ GPIO(zr, 4, 0); GPIO(zr, 5, 1); @@ -183,13 +181,10 @@ static void dc10_init(struct zoran *zr) static void dc10plus_init(struct zoran *zr) { - pci_dbg(zr->pci_dev, "%s\n", __func__); } static void buz_init(struct zoran *zr) { - pci_dbg(zr->pci_dev, "%s\n", __func__); - /* some stuff from Iomega */ pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15); pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020); @@ -198,8 +193,6 @@ static void buz_init(struct zoran *zr) static void lml33_init(struct zoran *zr) { - pci_dbg(zr->pci_dev, "%s\n", __func__); - GPIO(zr, 2, 1); // Set Composite input/output } @@ -334,10 +327,6 @@ static void videocodec_exit(struct zoran *zr) codec_exit(zr, zr->card.video_vfe); } -// struct tvnorm { -// u16 wt, wa, h_start, h_sync_start, ht, ha, v_start; -// }; - static const struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; static const struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; static const struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; @@ -619,7 +608,10 @@ static struct card_info zoran_cards[NUM_CARDS] = { }, { .type = AVS6EYES, .name = "6-Eyes", -/* AverMedia chose not to brand the 6-Eyes. Thus it can't be autodetected, and requires card=x. */ + /* + * AverMedia chose not to brand the 6-Eyes. Thus it can't be + * autodetected, and requires card=x. + */ .i2c_decoder = "ks0127", .addrs_decoder = ks0127_addrs, .i2c_encoder = "bt866", @@ -764,7 +756,9 @@ int zoran_check_jpg_settings(struct zoran *zr, case 4: if (zr->card.type == DC10_NEW) { - pci_dbg(zr->pci_dev, "%s - HDec by 4 is not supported on the DC10\n", __func__); + pci_dbg(zr->pci_dev, + "%s - HDec by 4 is not supported on the DC10\n", + __func__); err0++; break; } @@ -882,12 +876,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_ video_dev->device_caps = V4L2_CAP_STREAMING | dir; strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); - /* - * It's not a mem2mem device, but you can both capture and output from one and the same - * device. This should really be split up into two device nodes, but that's a job for - * another day. - */ - video_dev->vfl_dir = VFL_DIR_M2M; + video_dev->vfl_dir = VFL_DIR_RX; zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); @@ -1019,7 +1008,9 @@ static int zr36057_init(struct zoran *zr) zr->timing = zr->card.tvn[ZR_NORM_SECAM]; } if (!zr->timing) { - pci_warn(zr->pci_dev, "%s - default TV standard not supported by hardware. PAL will be used.\n", __func__); + pci_warn(zr->pci_dev, + "%s - default TV standard not supported by hardware. PAL will be used.\n", + __func__); zr->norm = V4L2_STD_PAL; zr->timing = zr->card.tvn[ZR_NORM_PAL]; } @@ -1038,9 +1029,9 @@ static int zr36057_init(struct zoran *zr) zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), &zr->p_sc, GFP_KERNEL); - if (!zr->stat_com) { + if (!zr->stat_com) return -ENOMEM; - } + for (j = 0; j < BUZ_NUM_STAT_COM; j++) zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ @@ -1066,9 +1057,11 @@ static int zr36057_init(struct zoran *zr) return 0; exit_statcomb: - dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, + zr->stat_comb, zr->p_scb); exit_statcom: - dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc); + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), + zr->stat_com, zr->p_sc); return err; } @@ -1099,8 +1092,10 @@ static void zoran_remove(struct pci_dev *pdev) btwrite(0, ZR36057_SPGPPCR); pci_free_irq(zr->pci_dev, 0, zr); /* unmap and free memory */ - dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc); - dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), + zr->stat_com, zr->p_sc); + dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, + zr->stat_comb, zr->p_scb); pci_release_regions(pdev); pci_disable_device(zr->pci_dev); zoran_exit_video_devices(zr); @@ -1299,7 +1294,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_err(pdev, "Unknown card, try specifying card=X module parameter\n"); goto zr_unreg; } - pci_info(zr->pci_dev, "%s() - card %s detected\n", __func__, zoran_cards[card_num].name); + pci_info(zr->pci_dev, "%s() - card %s detected\n", __func__, + zoran_cards[card_num].name); } else { card_num = card[nr]; if (card_num >= NUM_CARDS || card_num < 0) { @@ -1324,7 +1320,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto zr_unreg; - zr->zr36057_mem = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + zr->zr36057_mem = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); if (!zr->zr36057_mem) { pci_err(pdev, "%s() - ioremap failed\n", __func__); goto zr_pci_release; @@ -1348,7 +1345,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) &latency); need_latency = zr->revision > 1 ? 32 : 48; if (latency != need_latency) { - pci_info(zr->pci_dev, "Changing PCI latency from %d to %d\n", latency, need_latency); + pci_info(zr->pci_dev, "Changing PCI latency from %d to %d\n", + latency, need_latency); pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, need_latency); } diff --git a/drivers/staging/media/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h index 8e0d634cb30f..518cb426b446 100644 --- a/drivers/staging/media/zoran/zoran_card.h +++ b/drivers/media/pci/zoran/zoran_card.h @@ -19,11 +19,10 @@ extern int zr36067_debug; extern const struct video_device zoran_template; -extern int zoran_check_jpg_settings(struct zoran *zr, - struct zoran_jpg_settings *settings, - int try); -extern void zoran_open_init_params(struct zoran *zr); -extern void zoran_vdev_release(struct video_device *vdev); +int zoran_check_jpg_settings(struct zoran *zr, + struct zoran_jpg_settings *settings, int try); +void zoran_open_init_params(struct zoran *zr); +void zoran_vdev_release(struct video_device *vdev); void zr36016_write(struct videocodec *codec, u16 reg, u32 val); diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index 2470889a58fa..31f049b55529 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -50,7 +50,6 @@ static bool lml33dpath; /* default = 0 module_param(lml33dpath, bool, 0644); MODULE_PARM_DESC(lml33dpath, "Use digital path capture mode (on LML33 cards)"); -int zr_set_buf(struct zoran *zr); /* * initialize video front end */ @@ -108,7 +107,6 @@ int post_office_wait(struct zoran *zr) { u32 por; -// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_PO_PEN | ZR36057_POR_PO_TIME)) == ZR36057_POR_PO_PEN) { while ((por = btread(ZR36057_POR)) & ZR36057_POR_PO_PEN) { /* wait for something to happen */ /* TODO add timeout */ @@ -155,10 +153,12 @@ void jpeg_codec_sleep(struct zoran *zr, int sleep) { GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); if (!sleep) { - pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n", __func__, btread(ZR36057_GPPGCR1)); - udelay(500); + pci_dbg(zr->pci_dev, "%s() - wake GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); + usleep_range(500, 1000); } else { - pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n", __func__, btread(ZR36057_GPPGCR1)); + pci_dbg(zr->pci_dev, "%s() - sleep GPIO=0x%08x\n", + __func__, btread(ZR36057_GPPGCR1)); udelay(2); } } @@ -284,7 +284,8 @@ static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, vcrop1 = (tvn->ha / 2 - he) / 2; vcrop2 = tvn->ha / 2 - he - vcrop1; v_start = tvn->v_start; - v_end = v_start + tvn->ha / 2; // - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP + // FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP + v_end = v_start + tvn->ha / 2; // - 1; v_start += vcrop1; v_end -= vcrop2; reg = ((v_start & ZR36057_VFEVCR_VMASK) << ZR36057_VFEVCR_V_START) @@ -298,10 +299,12 @@ static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, reg |= (hor_dcm << ZR36057_VFESPFR_HOR_DCM); reg |= (ver_dcm << ZR36057_VFESPFR_VER_DCM); reg |= (disp_mode << ZR36057_VFESPFR_DISP_MODE); - /* RJ: I don't know, why the following has to be the opposite + /* + * RJ: I don't know, why the following has to be the opposite * of the corresponding ZR36060 setting, but only this way - * we get the correct colors when uncompressing to the screen */ - //reg |= ZR36057_VFESPFR_VCLK_POL; /**/ + * we get the correct colors when uncompressing to the screen + */ + //reg |= ZR36057_VFESPFR_VCLK_POL; /* RJ: Don't know if that is needed for NTSC also */ if (!(zr->norm & V4L2_STD_NTSC)) reg |= ZR36057_VFESPFR_EXT_FL; // NEEDED!!!!!!! Wolfgang @@ -342,7 +345,7 @@ void zr36057_set_memgrab(struct zoran *zr, int mode) * will be stuck at 1 until capturing is turned back on. */ if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SNAP_SHOT) - pci_warn(zr->pci_dev, "zr36057_set_memgrab(1) with SnapShot on!?\n"); + pci_warn(zr->pci_dev, "%s(1) with SnapShot on!?\n", __func__); /* switch on VSync interrupts */ btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts @@ -595,11 +598,9 @@ void jpeg_start(struct zoran *zr) /* enable the Go generation */ btor(ZR36057_JMC_GO_EN, ZR36057_JMC); - udelay(30); + usleep_range(30, 100); set_frame(zr, 1); // /FRAME - - pci_dbg(zr->pci_dev, "jpeg_start\n"); } void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) @@ -803,8 +804,10 @@ static void zoran_reap_stat_com(struct zoran *zr) unsigned int size = 0; u32 fcnt; - /* In motion decompress we don't have a hardware frame counter, - * we just count the interrupts here */ + /* + * In motion decompress we don't have a hardware frame counter, + * we just count the interrupts here + */ if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) zr->jpg_seq_num++; @@ -938,9 +941,9 @@ void zoran_init_hardware(struct zoran *zr) void zr36057_restart(struct zoran *zr) { btwrite(0, ZR36057_SPGPPCR); - udelay(1000); + usleep_range(1000, 2000); btor(ZR36057_SPGPPCR_SOFT_RESET, ZR36057_SPGPPCR); - udelay(1000); + usleep_range(1000, 2000); /* assert P_Reset */ btwrite(0, ZR36057_JPC); diff --git a/drivers/media/pci/zoran/zoran_device.h b/drivers/media/pci/zoran/zoran_device.h new file mode 100644 index 000000000000..34fd5cc914eb --- /dev/null +++ b/drivers/media/pci/zoran/zoran_device.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Zoran zr36057/zr36067 PCI controller driver, for the + * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux + * Media Labs LML33/LML33R10. + * + * This part handles card-specific data and detection + * + * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> + */ + +#ifndef __ZORAN_DEVICE_H__ +#define __ZORAN_DEVICE_H__ + +/* general purpose I/O */ +void GPIO(struct zoran *zr, int bit, unsigned int value); + +/* codec (or actually: guest bus) access */ +int post_office_wait(struct zoran *zr); +int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, + unsigned int value); +int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg); + +void jpeg_codec_sleep(struct zoran *zr, int sleep); +int jpeg_codec_reset(struct zoran *zr); + +/* zr360x7 access to raw capture */ +void zr36057_overlay(struct zoran *zr, int on); +void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count); +void zr36057_set_memgrab(struct zoran *zr, int mode); +int wait_grab_pending(struct zoran *zr); + +/* interrupts */ +void print_interrupts(struct zoran *zr); +void clear_interrupt_counters(struct zoran *zr); +irqreturn_t zoran_irq(int irq, void *dev_id); + +/* JPEG codec access */ +void jpeg_start(struct zoran *zr); +void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode); +void zoran_feed_stat_com(struct zoran *zr); + +/* general */ +void zoran_set_pci_master(struct zoran *zr, int set_master); +void zoran_init_hardware(struct zoran *zr); +void zr36057_restart(struct zoran *zr); + +extern const struct zoran_format zoran_formats[]; + +extern int v4l_bufsize; +extern int jpg_bufsize; +extern int pass_through; + +/* i2c */ +#define decoder_call(zr, o, f, args...) \ + v4l2_subdev_call((zr)->decoder, o, f, ##args) +#define encoder_call(zr, o, f, args...) \ + v4l2_subdev_call((zr)->encoder, o, f, ##args) + +#endif /* __ZORAN_DEVICE_H__ */ diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 4304b7e21709..fa672cc8bc67 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -203,7 +203,6 @@ static int zoran_v4l_set_format(struct zoran *zr, int width, int height, static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm) { - if (!(norm & zr->card.norms)) { pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm); return -EINVAL; @@ -287,17 +286,6 @@ static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); } -#if 0 -/* TODO: output does not work yet */ -static int zoran_enum_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran *zr = video_drvdata(file); - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK); -} -#endif - static int zoran_g_fmt_vid_out(struct file *file, void *__fh, struct v4l2_format *fmt) { @@ -430,8 +418,10 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, fmt->fmt.pix.field = V4L2_FIELD_TOP; bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); - v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2, - &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0); + v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, + bpp == 2 ? 1 : 2, + &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, + 0, 0); fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp; fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height; return 0; @@ -627,38 +617,6 @@ static int zoran_s_input(struct file *file, void *__fh, unsigned int input) return res; } -#if 0 -/* TODO: output does not work yet */ -static int zoran_enum_output(struct file *file, void *__fh, - struct v4l2_output *outp) -{ - if (outp->index != 0) - return -EINVAL; - - outp->index = 0; - outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; - outp->std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - outp->capabilities = V4L2_OUT_CAP_STD; - strscpy(outp->name, "Autodetect", sizeof(outp->name)); - - return 0; -} -static int zoran_g_output(struct file *file, void *__fh, unsigned int *output) -{ - *output = 0; - - return 0; -} - -static int zoran_s_output(struct file *file, void *__fh, unsigned int output) -{ - if (output != 0) - return -EINVAL; - - return 0; -} -#endif - /* cropping (sub-frame capture) */ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) { @@ -746,9 +704,6 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = { .vidioc_enum_input = zoran_enum_input, .vidioc_g_input = zoran_g_input, .vidioc_s_input = zoran_s_input, -/* .vidioc_enum_output = zoran_enum_output, - .vidioc_g_output = zoran_g_output, - .vidioc_s_output = zoran_s_output,*/ .vidioc_g_std = zoran_g_std, .vidioc_s_std = zoran_s_std, .vidioc_create_bufs = vb2_ioctl_create_bufs, @@ -760,13 +715,9 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = { .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, -/* .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out,*/ .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, -/* .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out,*/ .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, -/* .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out,*/ .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, -/* .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out,*/ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -1013,7 +964,7 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) vq->dev = &zr->pci_dev->dev; vq->type = dir; - vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; + vq->io_modes = VB2_DMABUF | VB2_MMAP; vq->drv_priv = zr; vq->buf_struct_size = sizeof(struct zr_buffer); vq->ops = &zr_video_qops; diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/media/pci/zoran/zr36016.c index 0e0532537a3e..4b328ad6083f 100644 --- a/drivers/staging/media/zoran/zr36016.c +++ b/drivers/media/pci/zoran/zr36016.c @@ -15,18 +15,19 @@ /* codec io API */ #include "videocodec.h" -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ +/* + * it doesn't make sense to have more than 20 or so, + * just to prevent some unwanted loops + */ #define MAX_CODECS 20 /* amount of chips attached via this driver */ static int zr36016_codecs; -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ +/* + * Local hardware I/O functions: read/write via codec layer + * (registers are located in the master device) + */ /* read and write functions */ static u8 zr36016_read(struct zr36016 *ptr, u16 reg) @@ -58,9 +59,12 @@ static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value) zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name); } -/* indirect read and write functions */ -/* the 016 supports auto-addr-increment, but - * writing it all time cost not much and is safer... */ +/* + * indirect read and write functions + * + * the 016 supports auto-addr-increment, but + * writing it all time cost not much and is safer... + */ static u8 zr36016_readi(struct zr36016 *ptr, u16 reg) { u8 value = 0; @@ -68,8 +72,8 @@ static u8 zr36016_readi(struct zr36016 *ptr, u16 reg) /* just in case something is wrong... */ if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA + ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); + value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; } else { zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name); } @@ -88,18 +92,14 @@ static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value) /* just in case something is wrong... */ if (ptr->codec->master_data->writereg) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA + ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); + ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); } else { zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name); } } -/* ========================================================================= - Local helper function: - - version read - ========================================================================= */ +/* Local helper function: version read */ /* version kept in datastructure */ static u8 zr36016_read_version(struct zr36016 *ptr) @@ -108,11 +108,10 @@ static u8 zr36016_read_version(struct zr36016 *ptr) return ptr->version; } -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from PAX-Lo register - ========================================================================= */ +/* + * Local helper function: basic test of "connectivity", writes/reads + * to/from PAX-Lo register + */ static int zr36016_basic_test(struct zr36016 *ptr) { @@ -150,36 +149,7 @@ static int zr36016_basic_test(struct zr36016 *ptr) return 0; /* looks good! */ } -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - NO USE -- - ========================================================================= */ - -#if 0 -static int zr36016_pushit(struct zr36016 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - struct zoran *zr = videocodec_to_zoran(ptr->codec); - int i = 0; - - zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", - ptr->name, startreg, len); - while (i < len) { - zr36016_writei(ptr, startreg++, data[i++]); - } - - return i; -} -#endif - -/* ========================================================================= - Basic datasets & init: - - //TODO// - ========================================================================= */ +/* Basic datasets & init */ static void zr36016_init(struct zr36016 *ptr) { @@ -213,14 +183,16 @@ static void zr36016_init(struct zr36016 *ptr) zr36016_write(ptr, ZR016_GOSTOP, 1); } -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ +/* + * CODEC API FUNCTIONS + * + * These functions are accessed by the master via the API structure + */ -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ +/* + * set compression/expansion mode and launches codec - + * this should be the last call from the master before starting processing + */ static int zr36016_set_mode(struct videocodec *codec, int mode) { struct zr36016 *ptr = (struct zr36016 *)codec->data; @@ -249,22 +221,28 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm cap->x, cap->y, cap->width, cap->height, cap->decimation); - /* if () return -EINVAL; + /* + * if () return -EINVAL; * trust the master driver that it knows what it does - so - * we allow invalid startx/y for now ... */ + * we allow invalid startx/y for now ... + */ ptr->width = cap->width; ptr->height = cap->height; - /* (Ronald) This is ugly. zoran_device.c, line 387 + /* + * (Ronald) This is ugly. zoran_device.c, line 387 * already mentions what happens if h_start is even * (blue faces, etc., cr/cb inversed). There's probably * some good reason why h_start is 0 instead of 1, so I'm * leaving it to this for now, but really... This can be - * done a lot simpler */ + * done a lot simpler + */ ptr->xoff = (norm->h_start ? norm->h_start : 1) + cap->x; - /* Something to note here (I don't understand it), setting + /* + * Something to note here (I don't understand it), setting * v_start too high will cause the codec to 'not work'. I * really don't get it. values of 16 (v_start) already break - * it here. Just '0' seems to work. More testing needed! */ + * it here. Just '0' seems to work. More testing needed! + */ ptr->yoff = norm->v_start + cap->y; /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; @@ -319,11 +297,11 @@ static int zr36016_control(struct videocodec *codec, int type, int size, void *d return size; } -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ +/* + * Exit and unregister function: + * + * Deinitializes Zoran's JPEG processor + */ static int zr36016_unset(struct videocodec *codec) { @@ -344,14 +322,14 @@ static int zr36016_unset(struct videocodec *codec) return -EFAULT; } -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ +/* + * Setup and registry function: + * + * Initializes Zoran's JPEG processor + * + * Also sets pixel size, average code size, mode (compr./decompr.) + * (the given size is determined by the processor with the video interface) + */ static int zr36016_setup(struct videocodec *codec) { @@ -410,9 +388,7 @@ static const struct videocodec zr36016_codec = { /* others are not used */ }; -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ +/* HOOK IN DRIVER AS KERNEL MODULE */ int zr36016_init_module(void) { diff --git a/drivers/staging/media/zoran/zr36016.h b/drivers/media/pci/zoran/zr36016.h index 04afba35669d..04afba35669d 100644 --- a/drivers/staging/media/zoran/zr36016.h +++ b/drivers/media/pci/zoran/zr36016.h diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/media/pci/zoran/zr36050.c index 6a7ef28d996c..b07d7e5c1b4a 100644 --- a/drivers/staging/media/zoran/zr36050.c +++ b/drivers/media/pci/zoran/zr36050.c @@ -22,18 +22,20 @@ /* codec io API */ #include "videocodec.h" -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ +/* + * it doesn't make sense to have more than 20 or so, + * just to prevent some unwanted loops + */ #define MAX_CODECS 20 /* amount of chips attached via this driver */ static int zr36050_codecs; -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ +/* + * Local hardware I/O functions: + * + * read/write via codec layer (registers are located in the master device) + */ /* read and write functions */ static u8 zr36050_read(struct zr36050 *ptr, u16 reg) @@ -66,12 +68,6 @@ static void zr36050_write(struct zr36050 *ptr, u16 reg, u8 value) ptr->name); } -/* ========================================================================= - Local helper function: - - status read - ========================================================================= */ - /* status is kept in datastructure */ static u8 zr36050_read_status1(struct zr36050 *ptr) { @@ -81,12 +77,6 @@ static u8 zr36050_read_status1(struct zr36050 *ptr) return ptr->status1; } -/* ========================================================================= - Local helper function: - - scale factor read - ========================================================================= */ - /* scale factor is kept in datastructure */ static u16 zr36050_read_scalefactor(struct zr36050 *ptr) { @@ -98,11 +88,11 @@ static u16 zr36050_read_scalefactor(struct zr36050 *ptr) return ptr->scalefact; } -/* ========================================================================= - Local helper function: - - wait if codec is ready to proceed (end of processing) or time is over - ========================================================================= */ +/* + * Local helper function: + * + * wait if codec is ready to proceed (end of processing) or time is over + */ static void zr36050_wait_end(struct zr36050 *ptr) { @@ -120,11 +110,10 @@ static void zr36050_wait_end(struct zr36050 *ptr) } } -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from memory the SOF marker - ========================================================================= */ +/* + * Local helper function: basic test of "connectivity", writes/reads + * to/from memory the SOF marker + */ static int zr36050_basic_test(struct zr36050 *ptr) { @@ -160,11 +149,7 @@ static int zr36050_basic_test(struct zr36050 *ptr) return 0; /* looks good! */ } -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - ========================================================================= */ +/* Local helper function: simple loop for pushing the init datasets */ static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char *data) { @@ -179,16 +164,16 @@ static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char return i; } -/* ========================================================================= - Basic datasets: - - jpeg baseline setup data (you find it on lots places in internet, or just - extract it from any regular .jpg image...) - - Could be variable, but until it's not needed it they are just fixed to save - memory. Otherwise expand zr36050 structure with arrays, push the values to - it and initialize from there, as e.g. the linux zr36057/60 driver does it. - ========================================================================= */ +/* + * Basic datasets: + * + * jpeg baseline setup data (you find it on lots places in internet, or just + * extract it from any regular .jpg image...) + * + * Could be variable, but until it's not needed it they are just fixed to save + * memory. Otherwise expand zr36050 structure with arrays, push the values to + * it and initialize from there, as e.g. the linux zr36057/60 driver does it. + */ static const char zr36050_dqt[0x86] = { 0xff, 0xdb, //Marker: DQT @@ -281,18 +266,19 @@ static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; -/* ========================================================================= - Local helper functions: - - calculation and setup of parameter-dependent JPEG baseline segments - (needed for compression only) - ========================================================================= */ +/* + * Local helper functions: + * + * calculation and setup of parameter-dependent JPEG baseline segments + * (needed for compression only) + */ /* ------------------------------------------------------------------------- */ -/* SOF (start of frame) segment depends on width, height and sampling ratio - of each color component */ - +/* + * SOF (start of frame) segment depends on width, height and sampling ratio + * of each color component + */ static int zr36050_set_sof(struct zr36050 *ptr) { struct zoran *zr = videocodec_to_zoran(ptr->codec); @@ -313,7 +299,8 @@ static int zr36050_set_sof(struct zr36050 *ptr) sof_data[9] = NO_OF_COMPONENTS; for (i = 0; i < NO_OF_COMPONENTS; i++) { sof_data[10 + (i * 3)] = i; // index identifier - sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]); // sampling ratios + sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | + (ptr->v_samp_ratio[i]); // sampling ratios sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection } return zr36050_pushit(ptr, ZR050_SOF_IDX, @@ -322,8 +309,10 @@ static int zr36050_set_sof(struct zr36050 *ptr) /* ------------------------------------------------------------------------- */ -/* SOS (start of scan) segment depends on the used scan components - of each color component */ +/* + * SOS (start of scan) segment depends on the used scan components + * of each color component + */ static int zr36050_set_sos(struct zr36050 *ptr) { @@ -368,14 +357,14 @@ static int zr36050_set_dri(struct zr36050 *ptr) return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data); } -/* ========================================================================= - Setup function: - - Setup compression/decompression of Zoran's JPEG processor - ( see also zoran 36050 manual ) - - ... sorry for the spaghetti code ... - ========================================================================= */ +/* + * Setup function: + * + * Setup compression/decompression of Zoran's JPEG processor + * ( see also zoran 36050 manual ) + * + * ... sorry for the spaghetti code ... + */ static void zr36050_init(struct zr36050 *ptr) { int sum = 0; @@ -411,8 +400,10 @@ static void zr36050_init(struct zr36050 *ptr) sum += zr36050_set_sos(ptr); sum += zr36050_set_dri(ptr); - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ + /* + * setup the fixed jpeg tables - maybe variable, though - + * (see table init section above) + */ zrdev_dbg(zr, "%s: write DQT, DHT, APP\n", ptr->name); sum += zr36050_pushit(ptr, ZR050_DQT_IDX, sizeof(zr36050_dqt), zr36050_dqt); @@ -522,14 +513,16 @@ static void zr36050_init(struct zr36050 *ptr) zr36050_read(ptr, 0); } -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ +/* + * CODEC API FUNCTIONS + * + * this functions are accessed by the master via the API structure + */ -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ +/* + * set compression/expansion mode and launches codec - + * this should be the last call from the master before starting processing + */ static int zr36050_set_mode(struct videocodec *codec, int mode) { struct zr36050 *ptr = (struct zr36050 *)codec->data; @@ -558,9 +551,10 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm ptr->name, norm->h_start, norm->v_start, cap->x, cap->y, cap->width, cap->height, cap->decimation, cap->quality); - /* if () return -EINVAL; + /* * trust the master driver that it knows what it does - so - * we allow invalid startx/y and norm for now ... */ + * we allow invalid startx/y and norm for now ... + */ ptr->width = cap->width / (cap->decimation & 0xff); ptr->height = cap->height / ((cap->decimation >> 8) & 0xff); @@ -579,8 +573,10 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm ptr->real_code_vol = size >> 3; /* in bytes */ - /* Set max_block_vol here (previously in zr36050_init, moved - * here for consistency with zr36060 code */ + /* + * Set max_block_vol here (previously in zr36050_init, moved + * here for consistency with zr36060 code + */ zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol); return 0; @@ -637,8 +633,6 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d if (size != sizeof(int)) return -EFAULT; ptr->total_code_vol = *ival; - /* (Kieran Morrissey) - * code copied from zr36060.c to ensure proper bitrate */ ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; break; @@ -701,11 +695,7 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d return size; } -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ +/* Exit and unregister function: Deinitializes Zoran's JPEG processor */ static int zr36050_unset(struct videocodec *codec) { @@ -727,14 +717,14 @@ static int zr36050_unset(struct videocodec *codec) return -EFAULT; } -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ +/* + * Setup and registry function: + * + * Initializes Zoran's JPEG processor + * + * Also sets pixel size, average code size, mode (compr./decompr.) + * (the given size is determined by the processor with the video interface) + */ static int zr36050_setup(struct videocodec *codec) { @@ -771,8 +761,8 @@ static int zr36050_setup(struct videocodec *codec) memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8); memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8); - ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag - * (what is the difference?) */ + /* 0 or 1 - fixed file size flag (what is the difference?) */ + ptr->bitrate_ctrl = 0; ptr->mode = CODEC_DO_COMPRESSION; ptr->width = 384; ptr->height = 288; @@ -809,9 +799,7 @@ static const struct videocodec zr36050_codec = { // others are not used }; -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ +/* HOOK IN DRIVER AS KERNEL MODULE */ int zr36050_init_module(void) { diff --git a/drivers/staging/media/zoran/zr36050.h b/drivers/media/pci/zoran/zr36050.h index f9b58f4c77b9..f9b58f4c77b9 100644 --- a/drivers/staging/media/zoran/zr36050.h +++ b/drivers/media/pci/zoran/zr36050.h diff --git a/drivers/staging/media/zoran/zr36057.h b/drivers/media/pci/zoran/zr36057.h index a2a75fd9f535..45d8afc62b37 100644 --- a/drivers/staging/media/zoran/zr36057.h +++ b/drivers/media/pci/zoran/zr36057.h @@ -11,117 +11,117 @@ /* Zoran ZR36057 registers */ #define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ -#define ZR36057_VFEHCR_HS_POL BIT(30) -#define ZR36057_VFEHCR_H_START 10 +#define ZR36057_VFEHCR_HS_POL BIT(30) +#define ZR36057_VFEHCR_H_START 10 #define ZR36057_VFEHCR_H_END 0 #define ZR36057_VFEHCR_HMASK 0x3ff #define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ -#define ZR36057_VFEVCR_VS_POL BIT(30) -#define ZR36057_VFEVCR_V_START 10 +#define ZR36057_VFEVCR_VS_POL BIT(30) +#define ZR36057_VFEVCR_V_START 10 #define ZR36057_VFEVCR_V_END 0 #define ZR36057_VFEVCR_VMASK 0x3ff #define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ -#define ZR36057_VFESPFR_EXT_FL BIT(26) -#define ZR36057_VFESPFR_TOP_FIELD BIT(25) -#define ZR36057_VFESPFR_VCLK_POL BIT(24) -#define ZR36057_VFESPFR_H_FILTER 21 -#define ZR36057_VFESPFR_HOR_DCM 14 -#define ZR36057_VFESPFR_VER_DCM 8 -#define ZR36057_VFESPFR_DISP_MODE 6 +#define ZR36057_VFESPFR_EXT_FL BIT(26) +#define ZR36057_VFESPFR_TOP_FIELD BIT(25) +#define ZR36057_VFESPFR_VCLK_POL BIT(24) +#define ZR36057_VFESPFR_H_FILTER 21 +#define ZR36057_VFESPFR_HOR_DCM 14 +#define ZR36057_VFESPFR_VER_DCM 8 +#define ZR36057_VFESPFR_DISP_MODE 6 #define ZR36057_VFESPFR_YUV422 (0 << 3) #define ZR36057_VFESPFR_RGB888 (1 << 3) #define ZR36057_VFESPFR_RGB565 (2 << 3) #define ZR36057_VFESPFR_RGB555 (3 << 3) -#define ZR36057_VFESPFR_ERR_DIF (1 << 2) -#define ZR36057_VFESPFR_PACK24 (1 << 1) -#define ZR36057_VFESPFR_LITTLE_ENDIAN (1 << 0) +#define ZR36057_VFESPFR_ERR_DIF BIT(2) +#define ZR36057_VFESPFR_PACK24 BIT(1) +#define ZR36057_VFESPFR_LITTLE_ENDIAN BIT(0) #define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ #define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ #define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ -#define ZR36057_VSSFGR_DISP_STRIDE 16 -#define ZR36057_VSSFGR_VID_OVF BIT(8) -#define ZR36057_VSSFGR_SNAP_SHOT BIT(1) -#define ZR36057_VSSFGR_FRAME_GRAB BIT(0) +#define ZR36057_VSSFGR_DISP_STRIDE 16 +#define ZR36057_VSSFGR_VID_OVF BIT(8) +#define ZR36057_VSSFGR_SNAP_SHOT BIT(1) +#define ZR36057_VSSFGR_FRAME_GRAB BIT(0) #define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ -#define ZR36057_VDCR_VID_EN BIT(31) -#define ZR36057_VDCR_MIN_PIX 24 -#define ZR36057_VDCR_TRITON BIT(24) -#define ZR36057_VDCR_VID_WIN_HT 12 -#define ZR36057_VDCR_VID_WIN_WID 0 +#define ZR36057_VDCR_VID_EN BIT(31) +#define ZR36057_VDCR_MIN_PIX 24 +#define ZR36057_VDCR_TRITON BIT(24) +#define ZR36057_VDCR_VID_WIN_HT 12 +#define ZR36057_VDCR_VID_WIN_WID 0 #define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ #define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ #define ZR36057_OCR 0x024 /* Overlay Control Register */ -#define ZR36057_OCR_OVL_ENABLE BIT(15) -#define ZR36057_OCR_MASK_STRIDE 0 +#define ZR36057_OCR_OVL_ENABLE BIT(15) +#define ZR36057_OCR_MASK_STRIDE 0 #define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ -#define ZR36057_SPGPPCR_SOFT_RESET BIT(24) +#define ZR36057_SPGPPCR_SOFT_RESET BIT(24) #define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ #define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ #define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ -#define ZR36057_MCTCR_COD_TIME BIT(30) -#define ZR36057_MCTCR_C_EMPTY BIT(29) -#define ZR36057_MCTCR_C_FLUSH BIT(28) +#define ZR36057_MCTCR_COD_TIME BIT(30) +#define ZR36057_MCTCR_C_EMPTY BIT(29) +#define ZR36057_MCTCR_C_FLUSH BIT(28) #define ZR36057_MCTCR_COD_GUEST_ID 20 #define ZR36057_MCTCR_COD_GUEST_REG 16 #define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ #define ZR36057_ISR 0x03c /* Interrupt Status Register */ -#define ZR36057_ISR_GIRQ1 BIT(30) -#define ZR36057_ISR_GIRQ0 BIT(29) -#define ZR36057_ISR_COD_REP_IRQ BIT(28) -#define ZR36057_ISR_JPEG_REP_IRQ BIT(27) +#define ZR36057_ISR_GIRQ1 BIT(30) +#define ZR36057_ISR_GIRQ0 BIT(29) +#define ZR36057_ISR_COD_REP_IRQ BIT(28) +#define ZR36057_ISR_JPEG_REP_IRQ BIT(27) #define ZR36057_ICR 0x040 /* Interrupt Control Register */ -#define ZR36057_ICR_GIRQ1 BIT(30) -#define ZR36057_ICR_GIRQ0 BIT(29) -#define ZR36057_ICR_COD_REP_IRQ BIT(28) -#define ZR36057_ICR_JPEG_REP_IRQ BIT(27) -#define ZR36057_ICR_INT_PIN_EN BIT(24) +#define ZR36057_ICR_GIRQ1 BIT(30) +#define ZR36057_ICR_GIRQ0 BIT(29) +#define ZR36057_ICR_COD_REP_IRQ BIT(28) +#define ZR36057_ICR_JPEG_REP_IRQ BIT(27) +#define ZR36057_ICR_INT_PIN_EN BIT(24) #define ZR36057_I2CBR 0x044 /* I2C Bus Register */ -#define ZR36057_I2CBR_SDA BIT(1) -#define ZR36057_I2CBR_SCL BIT(0) +#define ZR36057_I2CBR_SDA BIT(1) +#define ZR36057_I2CBR_SCL BIT(0) #define ZR36057_JMC 0x100 /* JPEG Mode and Control */ -#define ZR36057_JMC_JPG BIT(31) -#define ZR36057_JMC_JPG_EXP_MODE (0 << 29) -#define ZR36057_JMC_JPG_CMP_MODE BIT(29) -#define ZR36057_JMC_MJPG_EXP_MODE (2 << 29) -#define ZR36057_JMC_MJPG_CMP_MODE (3 << 29) -#define ZR36057_JMC_RTBUSY_FB BIT(6) -#define ZR36057_JMC_GO_EN BIT(5) -#define ZR36057_JMC_SYNC_MSTR BIT(4) -#define ZR36057_JMC_FLD_PER_BUFF BIT(3) -#define ZR36057_JMC_VFIFO_FB BIT(2) -#define ZR36057_JMC_CFIFO_FB BIT(1) -#define ZR36057_JMC_STLL_LIT_ENDIAN BIT(0) +#define ZR36057_JMC_JPG BIT(31) +#define ZR36057_JMC_JPG_EXP_MODE (0 << 29) +#define ZR36057_JMC_JPG_CMP_MODE BIT(29) +#define ZR36057_JMC_MJPG_EXP_MODE (2 << 29) +#define ZR36057_JMC_MJPG_CMP_MODE (3 << 29) +#define ZR36057_JMC_RTBUSY_FB BIT(6) +#define ZR36057_JMC_GO_EN BIT(5) +#define ZR36057_JMC_SYNC_MSTR BIT(4) +#define ZR36057_JMC_FLD_PER_BUFF BIT(3) +#define ZR36057_JMC_VFIFO_FB BIT(2) +#define ZR36057_JMC_CFIFO_FB BIT(1) +#define ZR36057_JMC_STLL_LIT_ENDIAN BIT(0) #define ZR36057_JPC 0x104 /* JPEG Process Control */ -#define ZR36057_JPC_P_RESET BIT(7) -#define ZR36057_JPC_COD_TRNS_EN BIT(5) -#define ZR36057_JPC_ACTIVE BIT(0) +#define ZR36057_JPC_P_RESET BIT(7) +#define ZR36057_JPC_COD_TRNS_EN BIT(5) +#define ZR36057_JPC_ACTIVE BIT(0) #define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ -#define ZR36057_VSP_VSYNC_SIZE 16 -#define ZR36057_VSP_FRM_TOT 0 +#define ZR36057_VSP_VSYNC_SIZE 16 +#define ZR36057_VSP_FRM_TOT 0 #define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ -#define ZR36057_HSP_HSYNC_START 16 -#define ZR36057_HSP_LINE_TOT 0 +#define ZR36057_HSP_HSYNC_START 16 +#define ZR36057_HSP_LINE_TOT 0 #define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ #define ZR36057_FHAP_NAX 16 @@ -132,22 +132,22 @@ #define ZR36057_FVAP_PAY 0 #define ZR36057_FPP 0x118 /* Field Process Parameters */ -#define ZR36057_FPP_ODD_EVEN BIT(0) +#define ZR36057_FPP_ODD_EVEN BIT(0) #define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ #define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ #define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ -#define ZR36057_JCGI_JPE_GUEST_ID 4 -#define ZR36057_JCGI_JPE_GUEST_REG 0 +#define ZR36057_JCGI_JPE_GUEST_ID 4 +#define ZR36057_JCGI_JPE_GUEST_REG 0 #define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ #define ZR36057_POR 0x200 /* Post Office Register */ -#define ZR36057_POR_PO_PEN BIT(25) -#define ZR36057_POR_PO_TIME BIT(24) -#define ZR36057_POR_PO_DIR BIT(23) +#define ZR36057_POR_PO_PEN BIT(25) +#define ZR36057_POR_PO_TIME BIT(24) +#define ZR36057_POR_PO_DIR BIT(23) #define ZR36057_STR 0x300 /* "Still" Transfer Register */ diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/media/pci/zoran/zr36060.c index 7798016f1f96..75fd167603dc 100644 --- a/drivers/staging/media/zoran/zr36060.c +++ b/drivers/media/pci/zoran/zr36060.c @@ -243,7 +243,10 @@ static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; -/* SOF (start of frame) segment depends on width, height and sampling ratio of each color component */ +/* + * SOF (start of frame) segment depends on width, height and sampling ratio + * of each color component + */ static int zr36060_set_sof(struct zr36060 *ptr) { struct zoran *zr = videocodec_to_zoran(ptr->codec); @@ -555,8 +558,6 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm reg = 6 - 1; /* VsyncSize */ zr36060_write(ptr, ZR060_SGR_VSYNC, reg); - //reg = 30 - 1; /* HsyncSize */ -///*CP*/ reg = (zr->params.norm == 1 ? 57 : 68); reg = 68; zr36060_write(ptr, ZR060_SGR_HSYNC, reg); diff --git a/drivers/staging/media/zoran/zr36060.h b/drivers/media/pci/zoran/zr36060.h index fbf5429534ac..75c88677a4bd 100644 --- a/drivers/staging/media/zoran/zr36060.h +++ b/drivers/media/pci/zoran/zr36060.h @@ -124,78 +124,78 @@ struct zr36060 { /* ZR36060 LOAD register bits */ -#define ZR060_LOAD_LOAD BIT(7) -#define ZR060_LOAD_SYNC_RST BIT(0) +#define ZR060_LOAD_LOAD BIT(7) +#define ZR060_LOAD_SYNC_RST BIT(0) /* ZR36060 Code FIFO Status register bits */ -#define ZR060_CFSR_BUSY BIT(7) -#define ZR060_CFSR_C_BUSY BIT(2) +#define ZR060_CFSR_BUSY BIT(7) +#define ZR060_CFSR_C_BUSY BIT(2) #define ZR060_CFSR_CFIFO (3 << 0) /* ZR36060 Code Interface register */ -#define ZR060_CIR_CODE16 BIT(7) -#define ZR060_CIR_ENDIAN BIT(6) -#define ZR060_CIR_CFIS BIT(2) -#define ZR060_CIR_CODE_MSTR BIT(0) +#define ZR060_CIR_CODE16 BIT(7) +#define ZR060_CIR_ENDIAN BIT(6) +#define ZR060_CIR_CFIS BIT(2) +#define ZR060_CIR_CODE_MSTR BIT(0) /* ZR36060 Codec Mode register */ -#define ZR060_CMR_COMP BIT(7) -#define ZR060_CMR_ATP BIT(6) -#define ZR060_CMR_PASS2 BIT(5) -#define ZR060_CMR_TLM BIT(4) -#define ZR060_CMR_BRB BIT(2) -#define ZR060_CMR_FSF BIT(1) +#define ZR060_CMR_COMP BIT(7) +#define ZR060_CMR_ATP BIT(6) +#define ZR060_CMR_PASS2 BIT(5) +#define ZR060_CMR_TLM BIT(4) +#define ZR060_CMR_BRB BIT(2) +#define ZR060_CMR_FSF BIT(1) /* ZR36060 Markers Enable register */ -#define ZR060_MER_APP BIT(7) -#define ZR060_MER_COM BIT(6) -#define ZR060_MER_DRI BIT(5) -#define ZR060_MER_DQT BIT(4) -#define ZR060_MER_DHT BIT(3) +#define ZR060_MER_APP BIT(7) +#define ZR060_MER_COM BIT(6) +#define ZR060_MER_DRI BIT(5) +#define ZR060_MER_DQT BIT(4) +#define ZR060_MER_DHT BIT(3) /* ZR36060 Interrupt Mask register */ -#define ZR060_IMR_EOAV BIT(3) -#define ZR060_IMR_EOI BIT(2) -#define ZR060_IMR_END BIT(1) -#define ZR060_IMR_DATA_ERR BIT(0) +#define ZR060_IMR_EOAV BIT(3) +#define ZR060_IMR_EOI BIT(2) +#define ZR060_IMR_END BIT(1) +#define ZR060_IMR_DATA_ERR BIT(0) /* ZR36060 Interrupt Status register */ #define ZR060_ISR_PRO_CNT (3 << 6) -#define ZR060_ISR_EOAV BIT(3) -#define ZR060_ISR_EOI BIT(2) -#define ZR060_ISR_END BIT(1) -#define ZR060_ISR_DATA_ERR BIT(0) +#define ZR060_ISR_EOAV BIT(3) +#define ZR060_ISR_EOI BIT(2) +#define ZR060_ISR_END BIT(1) +#define ZR060_ISR_DATA_ERR BIT(0) /* ZR36060 Video Control register */ -#define ZR060_VCR_VIDEO8 BIT(7) -#define ZR060_VCR_RANGE BIT(6) -#define ZR060_VCR_FI_DET BIT(3) -#define ZR060_VCR_FI_VEDGE BIT(2) -#define ZR060_VCR_FI_EXT BIT(1) -#define ZR060_VCR_SYNC_MSTR BIT(0) +#define ZR060_VCR_VIDEO8 BIT(7) +#define ZR060_VCR_RANGE BIT(6) +#define ZR060_VCR_FI_DET BIT(3) +#define ZR060_VCR_FI_VEDGE BIT(2) +#define ZR060_VCR_FI_EXT BIT(1) +#define ZR060_VCR_SYNC_MSTR BIT(0) /* ZR36060 Video Polarity register */ -#define ZR060_VPR_VCLK_POL BIT(7) -#define ZR060_VPR_P_VAL_POL BIT(6) -#define ZR060_VPR_POE_POL BIT(5) -#define ZR060_VPR_S_IMG_POL BIT(4) -#define ZR060_VPR_BL_POL BIT(3) -#define ZR060_VPR_FI_POL BIT(2) -#define ZR060_VPR_HS_POL BIT(1) -#define ZR060_VPR_VS_POL BIT(0) +#define ZR060_VPR_VCLK_POL BIT(7) +#define ZR060_VPR_P_VAL_POL BIT(6) +#define ZR060_VPR_POE_POL BIT(5) +#define ZR060_VPR_S_IMG_POL BIT(4) +#define ZR060_VPR_BL_POL BIT(3) +#define ZR060_VPR_FI_POL BIT(2) +#define ZR060_VPR_HS_POL BIT(1) +#define ZR060_VPR_VS_POL BIT(0) /* ZR36060 Scaling register */ -#define ZR060_SR_V_SCALE BIT(2) -#define ZR060_SR_H_SCALE2 BIT(0) +#define ZR060_SR_V_SCALE BIT(2) +#define ZR060_SR_H_SCALE2 BIT(0) #define ZR060_SR_H_SCALE4 (2 << 0) int zr36060_init_module(void); diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f1056ceaf5a8..a9334263fa9b 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -81,6 +81,7 @@ source "drivers/media/platform/samsung/Kconfig" source "drivers/media/platform/st/Kconfig" source "drivers/media/platform/sunxi/Kconfig" source "drivers/media/platform/ti/Kconfig" +source "drivers/media/platform/verisilicon/Kconfig" source "drivers/media/platform/via/Kconfig" source "drivers/media/platform/xilinx/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index a881e97bae95..a91f42024273 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -24,6 +24,7 @@ obj-y += samsung/ obj-y += st/ obj-y += sunxi/ obj-y += ti/ +obj-y += verisilicon/ obj-y += via/ obj-y += xilinx/ diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index 5e7b319f300d..142d421a8d76 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -1030,7 +1030,6 @@ static int ge2d_remove(struct platform_device *pdev) video_unregister_device(ge2d->vfd); v4l2_m2m_release(ge2d->m2m_dev); - video_device_release(ge2d->vfd); v4l2_device_unregister(&ge2d->v4l2_dev); clk_disable_unprepare(ge2d->clk); diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 9e64041cc1c1..feb75dc204de 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -808,14 +808,6 @@ static void vdec_init_fmt(struct vpu_inst *inst) inst->cap_format.field = V4L2_FIELD_NONE; else inst->cap_format.field = V4L2_FIELD_SEQ_TB; - if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT) - vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709; - if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT) - vdec->codec_info.transfer_chars = V4L2_XFER_FUNC_709; - if (vdec->codec_info.matrix_coeffs == V4L2_YCBCR_ENC_DEFAULT) - vdec->codec_info.matrix_coeffs = V4L2_YCBCR_ENC_709; - if (vdec->codec_info.full_range == V4L2_QUANTIZATION_DEFAULT) - vdec->codec_info.full_range = V4L2_QUANTIZATION_LIM_RANGE; } static void vdec_init_crop(struct vpu_inst *inst) @@ -1555,6 +1547,14 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i vdec->codec_info.frame_rate.numerator, vdec->codec_info.frame_rate.denominator); break; + case 9: + num = scnprintf(str, size, "colorspace: %d, %d, %d, %d (%d)\n", + vdec->codec_info.color_primaries, + vdec->codec_info.transfer_chars, + vdec->codec_info.matrix_coeffs, + vdec->codec_info.full_range, + vdec->codec_info.vui_present); + break; default: break; } diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 461524dd1e44..37212f087fdd 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -644,7 +644,7 @@ static int venc_ctrl_init(struct vpu_inst *inst) BITRATE_DEFAULT_PEAK); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30); + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 8000, 1, 30); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 4, 1, 0); diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index f914de6ed81e..beac0309ca8d 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -119,7 +119,6 @@ struct vpu_mbox { enum vpu_core_state { VPU_CORE_DEINIT = 0, VPU_CORE_ACTIVE, - VPU_CORE_SNAPSHOT, VPU_CORE_HANG }; diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index 73faa50d2865..f9ec1753f7c8 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -89,7 +89,7 @@ static int vpu_core_boot_done(struct vpu_core *core) core->supported_instance_count = min(core->supported_instance_count, count); } core->fw_version = fw_version; - core->state = VPU_CORE_ACTIVE; + vpu_core_set_state(core, VPU_CORE_ACTIVE); return 0; } @@ -172,10 +172,26 @@ int vpu_alloc_dma(struct vpu_core *core, struct vpu_buffer *buf) return __vpu_alloc_dma(core->dev, buf); } -static void vpu_core_check_hang(struct vpu_core *core) +void vpu_core_set_state(struct vpu_core *core, enum vpu_core_state state) { - if (core->hang_mask) - core->state = VPU_CORE_HANG; + if (state != core->state) + vpu_trace(core->dev, "vpu core state change from %d to %d\n", core->state, state); + core->state = state; + if (core->state == VPU_CORE_DEINIT) + core->hang_mask = 0; +} + +static void vpu_core_update_state(struct vpu_core *core) +{ + if (!vpu_iface_get_power_state(core)) { + if (core->request_count) + vpu_core_set_state(core, VPU_CORE_HANG); + else + vpu_core_set_state(core, VPU_CORE_DEINIT); + + } else if (core->state == VPU_CORE_ACTIVE && core->hang_mask) { + vpu_core_set_state(core, VPU_CORE_HANG); + } } static struct vpu_core *vpu_core_find_proper_by_type(struct vpu_dev *vpu, u32 type) @@ -188,11 +204,13 @@ static struct vpu_core *vpu_core_find_proper_by_type(struct vpu_dev *vpu, u32 ty dev_dbg(c->dev, "instance_mask = 0x%lx, state = %d\n", c->instance_mask, c->state); if (c->type != type) continue; + mutex_lock(&c->lock); + vpu_core_update_state(c); + mutex_unlock(&c->lock); if (c->state == VPU_CORE_DEINIT) { core = c; break; } - vpu_core_check_hang(c); if (c->state != VPU_CORE_ACTIVE) continue; if (c->request_count < request_count) { @@ -409,6 +427,12 @@ int vpu_inst_register(struct vpu_inst *inst) } mutex_lock(&core->lock); + if (core->state != VPU_CORE_ACTIVE) { + dev_err(core->dev, "vpu core is not active, state = %d\n", core->state); + ret = -EINVAL; + goto exit; + } + if (inst->id >= 0 && inst->id < core->supported_instance_count) goto exit; @@ -450,7 +474,7 @@ int vpu_inst_unregister(struct vpu_inst *inst) vpu_core_release_instance(core, inst->id); inst->id = VPU_INST_NULL_ID; } - vpu_core_check_hang(core); + vpu_core_update_state(core); if (core->state == VPU_CORE_HANG && !core->instance_mask) { int err; @@ -459,7 +483,7 @@ int vpu_inst_unregister(struct vpu_inst *inst) err = vpu_core_sw_reset(core); mutex_lock(&core->lock); if (!err) { - core->state = VPU_CORE_ACTIVE; + vpu_core_set_state(core, VPU_CORE_ACTIVE); core->hang_mask = 0; } } @@ -609,7 +633,7 @@ static int vpu_core_probe(struct platform_device *pdev) mutex_init(&core->cmd_lock); init_completion(&core->cmp); init_waitqueue_head(&core->ack_wq); - core->state = VPU_CORE_DEINIT; + vpu_core_set_state(core, VPU_CORE_DEINIT); core->res = of_device_get_match_data(dev); if (!core->res) @@ -758,33 +782,18 @@ static int __maybe_unused vpu_core_resume(struct device *dev) mutex_lock(&core->lock); pm_runtime_resume_and_get(dev); vpu_core_get_vpu(core); - if (core->state != VPU_CORE_SNAPSHOT) - goto exit; - if (!vpu_iface_get_power_state(core)) { - if (!list_empty(&core->instances)) { + if (core->request_count) { + if (!vpu_iface_get_power_state(core)) ret = vpu_core_boot(core, false); - if (ret) { - dev_err(core->dev, "%s boot fail\n", __func__); - core->state = VPU_CORE_DEINIT; - goto exit; - } - } else { - core->state = VPU_CORE_DEINIT; - } - } else { - if (!list_empty(&core->instances)) { + else ret = vpu_core_sw_reset(core); - if (ret) { - dev_err(core->dev, "%s sw_reset fail\n", __func__); - core->state = VPU_CORE_HANG; - goto exit; - } + if (ret) { + dev_err(core->dev, "resume fail\n"); + vpu_core_set_state(core, VPU_CORE_HANG); } - core->state = VPU_CORE_ACTIVE; } - -exit: + vpu_core_update_state(core); pm_runtime_put_sync(dev); mutex_unlock(&core->lock); @@ -798,18 +807,11 @@ static int __maybe_unused vpu_core_suspend(struct device *dev) int ret = 0; mutex_lock(&core->lock); - if (core->state == VPU_CORE_ACTIVE) { - if (!list_empty(&core->instances)) { - ret = vpu_core_snapshot(core); - if (ret) { - mutex_unlock(&core->lock); - return ret; - } - } - - core->state = VPU_CORE_SNAPSHOT; - } + if (core->request_count) + ret = vpu_core_snapshot(core); mutex_unlock(&core->lock); + if (ret) + return ret; vpu_core_cancel_work(core); diff --git a/drivers/media/platform/amphion/vpu_core.h b/drivers/media/platform/amphion/vpu_core.h index 00a662997da4..65b562642603 100644 --- a/drivers/media/platform/amphion/vpu_core.h +++ b/drivers/media/platform/amphion/vpu_core.h @@ -11,5 +11,6 @@ u32 csr_readl(struct vpu_core *core, u32 reg); int vpu_alloc_dma(struct vpu_core *core, struct vpu_buffer *buf); void vpu_free_dma(struct vpu_buffer *buf); struct vpu_inst *vpu_core_find_instance(struct vpu_core *core, u32 index); +void vpu_core_set_state(struct vpu_core *core, enum vpu_core_state state); #endif diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index f72c8a506b22..260f1c4b8f8d 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -15,6 +15,7 @@ #include <linux/debugfs.h> #include "vpu.h" #include "vpu_defs.h" +#include "vpu_core.h" #include "vpu_helpers.h" #include "vpu_cmds.h" #include "vpu_rpc.h" @@ -233,6 +234,10 @@ static int vpu_dbg_core(struct seq_file *s, void *data) if (seq_write(s, str, num)) return 0; + num = scnprintf(str, sizeof(str), "power %s\n", + vpu_iface_get_power_state(core) ? "on" : "off"); + if (seq_write(s, str, num)) + return 0; num = scnprintf(str, sizeof(str), "state = %d\n", core->state); if (seq_write(s, str, num)) return 0; @@ -346,10 +351,10 @@ static ssize_t vpu_dbg_core_write(struct file *file, pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); - if (core->state != VPU_CORE_DEINIT && !core->instance_mask) { + if (vpu_iface_get_power_state(core) && !core->request_count) { dev_info(core->dev, "reset\n"); if (!vpu_core_sw_reset(core)) { - core->state = VPU_CORE_ACTIVE; + vpu_core_set_state(core, VPU_CORE_ACTIVE); core->hang_mask = 0; } } diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index f4a488bf9880..51e0702f9ae1 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -1293,7 +1293,7 @@ static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) vbuf = to_vb2_v4l2_buffer(scode->vb); data = vb2_plane_vaddr(scode->vb, 0); - if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) + if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) return 0; if (MALONE_VC1_CONTAIN_NAL(*data)) return 0; diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 8a3eed957ae6..b779e0ba916c 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -603,6 +603,10 @@ static int vpu_v4l2_release(struct vpu_inst *inst) inst->workqueue = NULL; } + if (inst->fh.m2m_ctx) { + v4l2_m2m_ctx_release(inst->fh.m2m_ctx); + inst->fh.m2m_ctx = NULL; + } v4l2_ctrl_handler_free(&inst->ctrl_handler); mutex_destroy(&inst->lock); v4l2_fh_del(&inst->fh); @@ -685,13 +689,6 @@ int vpu_v4l2_close(struct file *file) vpu_trace(vpu->dev, "tgid = %d, pid = %d, inst = %p\n", inst->tgid, inst->pid, inst); - vpu_inst_lock(inst); - if (inst->fh.m2m_ctx) { - v4l2_m2m_ctx_release(inst->fh.m2m_ctx); - inst->fh.m2m_ctx = NULL; - } - vpu_inst_unlock(inst); - call_void_vop(inst, release); vpu_inst_unregister(inst); vpu_inst_put(inst); diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c index a0b22b07f69a..435e7030fc2a 100644 --- a/drivers/media/platform/chips-media/coda-jpeg.c +++ b/drivers/media/platform/chips-media/coda-jpeg.c @@ -421,7 +421,7 @@ static inline void coda9_jpeg_write_huff_values(struct coda_dev *dev, u8 *bits, coda_write(dev, (s32)values[i], CODA9_REG_JPEG_HUFF_DATA); } -static int coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) +static void coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) { struct coda_huff_tab *huff_tab = ctx->params.jpeg_huff_tab; struct coda_dev *dev = ctx->dev; @@ -455,7 +455,6 @@ static int coda9_jpeg_dec_huff_setup(struct coda_ctx *ctx) coda9_jpeg_write_huff_values(dev, huff_tab->luma_ac, 162); coda9_jpeg_write_huff_values(dev, huff_tab->chroma_ac, 162); coda_write(dev, 0x000, CODA9_REG_JPEG_HUFF_CTRL); - return 0; } static inline void coda9_jpeg_write_qmat_tab(struct coda_dev *dev, @@ -1394,14 +1393,8 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->params.jpeg_restart_interval, CODA9_REG_JPEG_RST_INTVAL); - if (ctx->params.jpeg_huff_tab) { - ret = coda9_jpeg_dec_huff_setup(ctx); - if (ret < 0) { - v4l2_err(&dev->v4l2_dev, - "failed to set up Huffman tables: %d\n", ret); - return ret; - } - } + if (ctx->params.jpeg_huff_tab) + coda9_jpeg_dec_huff_setup(ctx); coda9_jpeg_qmat_setup(ctx); diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c index 35145e3348f0..54270d6b6f50 100644 --- a/drivers/media/platform/intel/pxa_camera.c +++ b/drivers/media/platform/intel/pxa_camera.c @@ -854,7 +854,7 @@ fail: return -ENOMEM; } -static void pxa_videobuf_set_actdma(struct pxa_camera_dev *pcdev, +static void pxa_video_buf_set_actdma(struct pxa_camera_dev *pcdev, struct pxa_buffer *buf) { buf->active_dma = DMA_Y; @@ -973,7 +973,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, * stopped. This means the tailed buffer would never be transferred by DMA. * This function restarts the capture for this corner case, where : * - DADR() == DADDR_STOP - * - a videobuffer is queued on the pcdev->capture list + * - a video buffer is queued on the pcdev->capture list * * Please check the "DMA hot chaining timeslice issue" in * Documentation/driver-api/media/drivers/pxa_camera.rst @@ -1163,7 +1163,7 @@ static void pxa_camera_eof(struct tasklet_struct *t) pcdev->active = list_first_entry(&pcdev->capture, struct pxa_buffer, queue); buf = pcdev->active; - pxa_videobuf_set_actdma(pcdev, buf); + pxa_video_buf_set_actdma(pcdev, buf); pxa_dma_start_channels(pcdev); } @@ -1416,7 +1416,7 @@ static int pxac_vb2_prepare(struct vb2_buffer *vb) * the actual buffer is yours */ buf->inwork = 0; - pxa_videobuf_set_actdma(pcdev, buf); + pxa_video_buf_set_actdma(pcdev, buf); return ret; } diff --git a/drivers/media/platform/marvell/mcam-core.h b/drivers/media/platform/marvell/mcam-core.h index f324d808d737..51e66db45af6 100644 --- a/drivers/media/platform/marvell/mcam-core.h +++ b/drivers/media/platform/marvell/mcam-core.h @@ -32,7 +32,7 @@ #if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \ !defined(MCAM_MODE_DMA_SG) -#error One of the videobuf buffer modes must be selected in the config +#error One of the vb2 buffer modes must be selected in the config #endif diff --git a/drivers/media/platform/mediatek/Kconfig b/drivers/media/platform/mediatek/Kconfig index af47d9888552..84104e2cd024 100644 --- a/drivers/media/platform/mediatek/Kconfig +++ b/drivers/media/platform/mediatek/Kconfig @@ -6,3 +6,4 @@ source "drivers/media/platform/mediatek/jpeg/Kconfig" source "drivers/media/platform/mediatek/mdp/Kconfig" source "drivers/media/platform/mediatek/vcodec/Kconfig" source "drivers/media/platform/mediatek/vpu/Kconfig" +source "drivers/media/platform/mediatek/mdp3/Kconfig" diff --git a/drivers/media/platform/mediatek/Makefile b/drivers/media/platform/mediatek/Makefile index d3850a13f128..38e6ba917fe5 100644 --- a/drivers/media/platform/mediatek/Makefile +++ b/drivers/media/platform/mediatek/Makefile @@ -3,3 +3,4 @@ obj-y += jpeg/ obj-y += mdp/ obj-y += vcodec/ obj-y += vpu/ +obj-y += mdp3/ diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 87685a62a5c2..3071b61946c3 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -1414,7 +1414,6 @@ static int mtk_jpeg_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); video_unregister_device(jpeg->vdev); - video_device_release(jpeg->vdev); v4l2_m2m_release(jpeg->m2m_dev); v4l2_device_unregister(&jpeg->v4l2_dev); diff --git a/drivers/media/platform/mediatek/mdp3/Kconfig b/drivers/media/platform/mediatek/mdp3/Kconfig new file mode 100644 index 000000000000..50ae07b75b5f --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_MEDIATEK_MDP3 + tristate "MediaTek MDP v3 driver" + depends on MTK_IOMMU || COMPILE_TEST + depends on VIDEO_DEV + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_DMA + depends on REMOTEPROC + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + select MTK_MMSYS + select VIDEO_MEDIATEK_VPU + select MTK_CMDQ + select MTK_SCP + default n + help + It is a v4l2 driver and present in MediaTek MT8183 SoC. + The driver supports scaling and color space conversion. + + To compile this driver as a module, choose M here: the + module will be called mtk-mdp3. diff --git a/drivers/media/platform/mediatek/mdp3/Makefile b/drivers/media/platform/mediatek/mdp3/Makefile new file mode 100644 index 000000000000..63e6c87e480b --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +mtk-mdp3-y += mtk-mdp3-core.o mtk-mdp3-vpu.o mtk-mdp3-regs.o +mtk-mdp3-y += mtk-mdp3-m2m.o +mtk-mdp3-y += mtk-mdp3-comp.o mtk-mdp3-cmdq.o + +obj-$(CONFIG_VIDEO_MEDIATEK_MDP3) += mtk-mdp3.o diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_ccorr.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_ccorr.h new file mode 100644 index 000000000000..3b2c6531c194 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_ccorr.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MDP_REG_CCORR_H__ +#define __MDP_REG_CCORR_H__ + +#define MDP_CCORR_EN 0x000 +#define MDP_CCORR_CFG 0x020 +#define MDP_CCORR_SIZE 0x030 + +/* MASK */ +#define MDP_CCORR_EN_MASK 0x00000001 +#define MDP_CCORR_CFG_MASK 0x70001317 +#define MDP_CCORR_SIZE_MASK 0x1fff1fff + +#endif // __MDP_REG_CCORR_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h new file mode 100644 index 000000000000..be4065e252d3 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MDP_REG_RDMA_H__ +#define __MDP_REG_RDMA_H__ + +#define MDP_RDMA_EN 0x000 +#define MDP_RDMA_RESET 0x008 +#define MDP_RDMA_CON 0x020 +#define MDP_RDMA_GMCIF_CON 0x028 +#define MDP_RDMA_SRC_CON 0x030 +#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE 0x060 +#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL 0x068 +#define MDP_RDMA_MF_SRC_SIZE 0x070 +#define MDP_RDMA_MF_CLIP_SIZE 0x078 +#define MDP_RDMA_MF_OFFSET_1 0x080 +#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE 0x090 +#define MDP_RDMA_SRC_END_0 0x100 +#define MDP_RDMA_SRC_END_1 0x108 +#define MDP_RDMA_SRC_END_2 0x110 +#define MDP_RDMA_SRC_OFFSET_0 0x118 +#define MDP_RDMA_SRC_OFFSET_1 0x120 +#define MDP_RDMA_SRC_OFFSET_2 0x128 +#define MDP_RDMA_SRC_OFFSET_0_P 0x148 +#define MDP_RDMA_TRANSFORM_0 0x200 +#define MDP_RDMA_RESV_DUMMY_0 0x2a0 +#define MDP_RDMA_MON_STA_1 0x408 +#define MDP_RDMA_SRC_BASE_0 0xf00 +#define MDP_RDMA_SRC_BASE_1 0xf08 +#define MDP_RDMA_SRC_BASE_2 0xf10 +#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y 0xf20 +#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C 0xf28 + +/* MASK */ +#define MDP_RDMA_EN_MASK 0x00000001 +#define MDP_RDMA_RESET_MASK 0x00000001 +#define MDP_RDMA_CON_MASK 0x00001110 +#define MDP_RDMA_GMCIF_CON_MASK 0xfffb3771 +#define MDP_RDMA_SRC_CON_MASK 0xf3ffffff +#define MDP_RDMA_MF_BKGD_SIZE_IN_BYTE_MASK 0x001fffff +#define MDP_RDMA_MF_BKGD_SIZE_IN_PXL_MASK 0x001fffff +#define MDP_RDMA_MF_SRC_SIZE_MASK 0x1fff1fff +#define MDP_RDMA_MF_CLIP_SIZE_MASK 0x1fff1fff +#define MDP_RDMA_MF_OFFSET_1_MASK 0x003f001f +#define MDP_RDMA_SF_BKGD_SIZE_IN_BYTE_MASK 0x001fffff +#define MDP_RDMA_SRC_END_0_MASK 0xffffffff +#define MDP_RDMA_SRC_END_1_MASK 0xffffffff +#define MDP_RDMA_SRC_END_2_MASK 0xffffffff +#define MDP_RDMA_SRC_OFFSET_0_MASK 0xffffffff +#define MDP_RDMA_SRC_OFFSET_1_MASK 0xffffffff +#define MDP_RDMA_SRC_OFFSET_2_MASK 0xffffffff +#define MDP_RDMA_SRC_OFFSET_0_P_MASK 0xffffffff +#define MDP_RDMA_TRANSFORM_0_MASK 0xff110777 +#define MDP_RDMA_RESV_DUMMY_0_MASK 0xffffffff +#define MDP_RDMA_MON_STA_1_MASK 0xffffffff +#define MDP_RDMA_SRC_BASE_0_MASK 0xffffffff +#define MDP_RDMA_SRC_BASE_1_MASK 0xffffffff +#define MDP_RDMA_SRC_BASE_2_MASK 0xffffffff +#define MDP_RDMA_UFO_DEC_LENGTH_BASE_Y_MASK 0xffffffff +#define MDP_RDMA_UFO_DEC_LENGTH_BASE_C_MASK 0xffffffff + +#endif // __MDP_REG_RDMA_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h new file mode 100644 index 000000000000..484f6d60641f --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MDP_REG_RSZ_H__ +#define __MDP_REG_RSZ_H__ + +#define PRZ_ENABLE 0x000 +#define PRZ_CONTROL_1 0x004 +#define PRZ_CONTROL_2 0x008 +#define PRZ_INPUT_IMAGE 0x010 +#define PRZ_OUTPUT_IMAGE 0x014 +#define PRZ_HORIZONTAL_COEFF_STEP 0x018 +#define PRZ_VERTICAL_COEFF_STEP 0x01c +#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET 0x020 +#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET 0x024 +#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET 0x028 +#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET 0x02c +#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET 0x030 +#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET 0x034 + +/* MASK */ +#define PRZ_ENABLE_MASK 0x00010001 +#define PRZ_CONTROL_1_MASK 0xfffffff3 +#define PRZ_CONTROL_2_MASK 0x0ffffaff +#define PRZ_INPUT_IMAGE_MASK 0xffffffff +#define PRZ_OUTPUT_IMAGE_MASK 0xffffffff +#define PRZ_HORIZONTAL_COEFF_STEP_MASK 0x007fffff +#define PRZ_VERTICAL_COEFF_STEP_MASK 0x007fffff +#define PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET_MASK 0x0000ffff +#define PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK 0x001fffff +#define PRZ_LUMA_VERTICAL_INTEGER_OFFSET_MASK 0x0000ffff +#define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET_MASK 0x001fffff +#define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET_MASK 0x0000ffff +#define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK 0x001fffff + +#endif // __MDP_REG_RSZ_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_wdma.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_wdma.h new file mode 100644 index 000000000000..0280e91c09e4 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_wdma.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MDP_REG_WDMA_H__ +#define __MDP_REG_WDMA_H__ + +#define WDMA_EN 0x008 +#define WDMA_RST 0x00c +#define WDMA_CFG 0x014 +#define WDMA_SRC_SIZE 0x018 +#define WDMA_CLIP_SIZE 0x01c +#define WDMA_CLIP_COORD 0x020 +#define WDMA_DST_W_IN_BYTE 0x028 +#define WDMA_ALPHA 0x02c +#define WDMA_BUF_CON2 0x03c +#define WDMA_DST_UV_PITCH 0x078 +#define WDMA_DST_ADDR_OFFSET 0x080 +#define WDMA_DST_U_ADDR_OFFSET 0x084 +#define WDMA_DST_V_ADDR_OFFSET 0x088 +#define WDMA_FLOW_CTRL_DBG 0x0a0 +#define WDMA_DST_ADDR 0xf00 +#define WDMA_DST_U_ADDR 0xf04 +#define WDMA_DST_V_ADDR 0xf08 + +/* MASK */ +#define WDMA_EN_MASK 0x00000001 +#define WDMA_RST_MASK 0x00000001 +#define WDMA_CFG_MASK 0xff03bff0 +#define WDMA_SRC_SIZE_MASK 0x3fff3fff +#define WDMA_CLIP_SIZE_MASK 0x3fff3fff +#define WDMA_CLIP_COORD_MASK 0x3fff3fff +#define WDMA_DST_W_IN_BYTE_MASK 0x0000ffff +#define WDMA_ALPHA_MASK 0x800000ff +#define WDMA_BUF_CON2_MASK 0xffffffff +#define WDMA_DST_UV_PITCH_MASK 0x0000ffff +#define WDMA_DST_ADDR_OFFSET_MASK 0x0fffffff +#define WDMA_DST_U_ADDR_OFFSET_MASK 0x0fffffff +#define WDMA_DST_V_ADDR_OFFSET_MASK 0x0fffffff +#define WDMA_FLOW_CTRL_DBG_MASK 0x0000f3ff +#define WDMA_DST_ADDR_MASK 0xffffffff +#define WDMA_DST_U_ADDR_MASK 0xffffffff +#define WDMA_DST_V_ADDR_MASK 0xffffffff + +#endif // __MDP_REG_WDMA_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h new file mode 100644 index 000000000000..6d3ff0e2b672 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MDP_REG_WROT_H__ +#define __MDP_REG_WROT_H__ + +#define VIDO_CTRL 0x000 +#define VIDO_MAIN_BUF_SIZE 0x008 +#define VIDO_SOFT_RST 0x010 +#define VIDO_SOFT_RST_STAT 0x014 +#define VIDO_CROP_OFST 0x020 +#define VIDO_TAR_SIZE 0x024 +#define VIDO_OFST_ADDR 0x02c +#define VIDO_STRIDE 0x030 +#define VIDO_OFST_ADDR_C 0x038 +#define VIDO_STRIDE_C 0x03c +#define VIDO_DITHER 0x054 +#define VIDO_STRIDE_V 0x06c +#define VIDO_OFST_ADDR_V 0x068 +#define VIDO_RSV_1 0x070 +#define VIDO_IN_SIZE 0x078 +#define VIDO_ROT_EN 0x07c +#define VIDO_FIFO_TEST 0x080 +#define VIDO_MAT_CTRL 0x084 +#define VIDO_BASE_ADDR 0xf00 +#define VIDO_BASE_ADDR_C 0xf04 +#define VIDO_BASE_ADDR_V 0xf08 + +/* MASK */ +#define VIDO_CTRL_MASK 0xf530711f +#define VIDO_MAIN_BUF_SIZE_MASK 0x1fff7f77 +#define VIDO_SOFT_RST_MASK 0x00000001 +#define VIDO_SOFT_RST_STAT_MASK 0x00000001 +#define VIDO_TAR_SIZE_MASK 0x1fff1fff +#define VIDO_CROP_OFST_MASK 0x1fff1fff +#define VIDO_OFST_ADDR_MASK 0x0fffffff +#define VIDO_STRIDE_MASK 0x0000ffff +#define VIDO_OFST_ADDR_C_MASK 0x0fffffff +#define VIDO_STRIDE_C_MASK 0x0000ffff +#define VIDO_DITHER_MASK 0xff000001 +#define VIDO_STRIDE_V_MASK 0x0000ffff +#define VIDO_OFST_ADDR_V_MASK 0x0fffffff +#define VIDO_RSV_1_MASK 0xffffffff +#define VIDO_IN_SIZE_MASK 0x1fff1fff +#define VIDO_ROT_EN_MASK 0x00000001 +#define VIDO_FIFO_TEST_MASK 0x00000fff +#define VIDO_MAT_CTRL_MASK 0x000000f3 +#define VIDO_BASE_ADDR_MASK 0xffffffff +#define VIDO_BASE_ADDR_C_MASK 0xffffffff +#define VIDO_BASE_ADDR_V_MASK 0xffffffff + +#endif // __MDP_REG_WROT_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h new file mode 100644 index 000000000000..3e66ebaee2da --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Holmes Chiou <holmes.chiou@mediatek.com> + * Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_IMG_IPI_H__ +#define __MTK_IMG_IPI_H__ + +#include <linux/types.h> + +/* + * ISP-MDP generic input information + * MD5 of the target SCP blob: + * 6da52bdcf4bf76a0983b313e1d4745d6 + */ + +#define IMG_MAX_HW_INPUTS 3 + +#define IMG_MAX_HW_OUTPUTS 4 + +#define IMG_MAX_PLANES 3 + +#define IMG_IPI_INIT 1 +#define IMG_IPI_DEINIT 2 +#define IMG_IPI_FRAME 3 +#define IMG_IPI_DEBUG 4 + +struct img_timeval { + u32 tv_sec; + u32 tv_usec; +} __packed; + +struct img_addr { + u64 va; /* Used for Linux OS access */ + u32 pa; /* Used for CM4 access */ + u32 iova; /* Used for IOMMU HW access */ +} __packed; + +struct tuning_addr { + u64 present; + u32 pa; /* Used for CM4 access */ + u32 iova; /* Used for IOMMU HW access */ +} __packed; + +struct img_sw_addr { + u64 va; /* Used for APMCU access */ + u32 pa; /* Used for CM4 access */ +} __packed; + +struct img_plane_format { + u32 size; + u16 stride; +} __packed; + +struct img_pix_format { + u16 width; + u16 height; + u32 colorformat; /* enum mdp_color */ + u16 ycbcr_prof; /* enum mdp_ycbcr_profile */ + struct img_plane_format plane_fmt[IMG_MAX_PLANES]; +} __packed; + +struct img_image_buffer { + struct img_pix_format format; + u32 iova[IMG_MAX_PLANES]; + /* enum mdp_buffer_usage, FD or advanced ISP usages */ + u32 usage; +} __packed; + +#define IMG_SUBPIXEL_SHIFT 20 + +struct img_crop { + s16 left; + s16 top; + u16 width; + u16 height; + u32 left_subpix; + u32 top_subpix; + u32 width_subpix; + u32 height_subpix; +} __packed; + +#define IMG_CTRL_FLAG_HFLIP BIT(0) +#define IMG_CTRL_FLAG_DITHER BIT(1) +#define IMG_CTRL_FLAG_SHARPNESS BIT(4) +#define IMG_CTRL_FLAG_HDR BIT(5) +#define IMG_CTRL_FLAG_DRE BIT(6) + +struct img_input { + struct img_image_buffer buffer; + u16 flags; /* HDR, DRE, dither */ +} __packed; + +struct img_output { + struct img_image_buffer buffer; + struct img_crop crop; + s16 rotation; + u16 flags; /* H-flip, sharpness, dither */ +} __packed; + +struct img_ipi_frameparam { + u32 index; + u32 frame_no; + struct img_timeval timestamp; + u8 type; /* enum mdp_stream_type */ + u8 state; + u8 num_inputs; + u8 num_outputs; + u64 drv_data; + struct img_input inputs[IMG_MAX_HW_INPUTS]; + struct img_output outputs[IMG_MAX_HW_OUTPUTS]; + struct tuning_addr tuning_data; + struct img_addr subfrm_data; + struct img_sw_addr config_data; + struct img_sw_addr self_data; +} __packed; + +struct img_sw_buffer { + u64 handle; /* Used for APMCU access */ + u32 scp_addr; /* Used for CM4 access */ +} __packed; + +struct img_ipi_param { + u8 usage; + struct img_sw_buffer frm_param; +} __packed; + +struct img_frameparam { + struct list_head list_entry; + struct img_ipi_frameparam frameparam; +}; + +/* ISP-MDP generic output information */ + +struct img_comp_frame { + u32 output_disable:1; + u32 bypass:1; + u16 in_width; + u16 in_height; + u16 out_width; + u16 out_height; + struct img_crop crop; + u16 in_total_width; + u16 out_total_width; +} __packed; + +struct img_region { + s16 left; + s16 right; + s16 top; + s16 bottom; +} __packed; + +struct img_offset { + s16 left; + s16 top; + u32 left_subpix; + u32 top_subpix; +} __packed; + +struct img_comp_subfrm { + u32 tile_disable:1; + struct img_region in; + struct img_region out; + struct img_offset luma; + struct img_offset chroma; + s16 out_vertical; /* Output vertical index */ + s16 out_horizontal; /* Output horizontal index */ +} __packed; + +#define IMG_MAX_SUBFRAMES 14 + +struct mdp_rdma_subfrm { + u32 offset[IMG_MAX_PLANES]; + u32 offset_0_p; + u32 src; + u32 clip; + u32 clip_ofst; +} __packed; + +struct mdp_rdma_data { + u32 src_ctrl; + u32 control; + u32 iova[IMG_MAX_PLANES]; + u32 iova_end[IMG_MAX_PLANES]; + u32 mf_bkgd; + u32 mf_bkgd_in_pxl; + u32 sf_bkgd; + u32 ufo_dec_y; + u32 ufo_dec_c; + u32 transform; + struct mdp_rdma_subfrm subfrms[IMG_MAX_SUBFRAMES]; +} __packed; + +struct mdp_rsz_subfrm { + u32 control2; + u32 src; + u32 clip; +} __packed; + +struct mdp_rsz_data { + u32 coeff_step_x; + u32 coeff_step_y; + u32 control1; + u32 control2; + struct mdp_rsz_subfrm subfrms[IMG_MAX_SUBFRAMES]; +} __packed; + +struct mdp_wrot_subfrm { + u32 offset[IMG_MAX_PLANES]; + u32 src; + u32 clip; + u32 clip_ofst; + u32 main_buf; +} __packed; + +struct mdp_wrot_data { + u32 iova[IMG_MAX_PLANES]; + u32 control; + u32 stride[IMG_MAX_PLANES]; + u32 mat_ctrl; + u32 fifo_test; + u32 filter; + struct mdp_wrot_subfrm subfrms[IMG_MAX_SUBFRAMES]; +} __packed; + +struct mdp_wdma_subfrm { + u32 offset[IMG_MAX_PLANES]; + u32 src; + u32 clip; + u32 clip_ofst; +} __packed; + +struct mdp_wdma_data { + u32 wdma_cfg; + u32 iova[IMG_MAX_PLANES]; + u32 w_in_byte; + u32 uv_stride; + struct mdp_wdma_subfrm subfrms[IMG_MAX_SUBFRAMES]; +} __packed; + +struct isp_data { + u64 dl_flags; /* 1 << (enum mdp_comp_type) */ + u32 smxi_iova[4]; + u32 cq_idx; + u32 cq_iova; + u32 tpipe_iova[IMG_MAX_SUBFRAMES]; +} __packed; + +struct img_compparam { + u16 type; /* enum mdp_comp_type */ + u16 id; /* enum mtk_mdp_comp_id */ + u32 input; + u32 outputs[IMG_MAX_HW_OUTPUTS]; + u32 num_outputs; + struct img_comp_frame frame; + struct img_comp_subfrm subfrms[IMG_MAX_SUBFRAMES]; + u32 num_subfrms; + union { + struct mdp_rdma_data rdma; + struct mdp_rsz_data rsz; + struct mdp_wrot_data wrot; + struct mdp_wdma_data wdma; + struct isp_data isp; + }; +} __packed; + +#define IMG_MAX_COMPONENTS 20 + +struct img_mux { + u32 reg; + u32 value; + u32 subsys_id; +}; + +struct img_mmsys_ctrl { + struct img_mux sets[IMG_MAX_COMPONENTS * 2]; + u32 num_sets; +}; + +struct img_config { + struct img_compparam components[IMG_MAX_COMPONENTS]; + u32 num_components; + struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES]; + u32 num_subfrms; +} __packed; + +#endif /* __MTK_IMG_IPI_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c new file mode 100644 index 000000000000..86c054600a08 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <linux/mailbox_controller.h> +#include <linux/platform_device.h> +#include "mtk-mdp3-cmdq.h" +#include "mtk-mdp3-comp.h" +#include "mtk-mdp3-core.h" +#include "mtk-mdp3-m2m.h" + +#define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS + +struct mdp_path { + struct mdp_dev *mdp_dev; + struct mdp_comp_ctx comps[MDP_PATH_MAX_COMPS]; + u32 num_comps; + const struct img_config *config; + const struct img_ipi_frameparam *param; + const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS]; + struct v4l2_rect bounds[IMG_MAX_HW_OUTPUTS]; +}; + +#define has_op(ctx, op) \ + ((ctx)->comp->ops && (ctx)->comp->ops->op) + #define call_op(ctx, op, ...) \ + (has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0) + +static bool is_output_disabled(const struct img_compparam *param, u32 count) +{ + return (count < param->num_subfrms) ? + (param->frame.output_disable || + param->subfrms[count].tile_disable) : + true; +} + +static int mdp_path_subfrm_require(const struct mdp_path *path, + struct mdp_cmdq_cmd *cmd, + s32 *mutex_id, u32 count) +{ + const struct img_config *config = path->config; + const struct mdp_comp_ctx *ctx; + const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data; + struct device *dev = &path->mdp_dev->pdev->dev; + struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; + int id, index; + + /* Decide which mutex to use based on the current pipeline */ + switch (path->comps[0].comp->id) { + case MDP_COMP_RDMA0: + *mutex_id = MDP_PIPE_RDMA0; + break; + case MDP_COMP_ISP_IMGI: + *mutex_id = MDP_PIPE_IMGI; + break; + case MDP_COMP_WPEI: + *mutex_id = MDP_PIPE_WPEI; + break; + case MDP_COMP_WPEI2: + *mutex_id = MDP_PIPE_WPEI2; + break; + default: + dev_err(dev, "Unknown pipeline and no mutex is assigned"); + return -EINVAL; + } + + /* Set mutex mod */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + if (is_output_disabled(ctx->param, count)) + continue; + id = ctx->comp->id; + mtk_mutex_write_mod(mutex[*mutex_id], + data->mdp_mutex_table_idx[id], false); + } + + mtk_mutex_write_sof(mutex[*mutex_id], + MUTEX_SOF_IDX_SINGLE_MODE); + + return 0; +} + +static int mdp_path_subfrm_run(const struct mdp_path *path, + struct mdp_cmdq_cmd *cmd, + s32 *mutex_id, u32 count) +{ + const struct img_config *config = path->config; + const struct mdp_comp_ctx *ctx; + struct device *dev = &path->mdp_dev->pdev->dev; + struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; + int index; + s32 event; + + if (-1 == *mutex_id) { + dev_err(dev, "Incorrect mutex id"); + return -EINVAL; + } + + /* Wait WROT SRAM shared to DISP RDMA */ + /* Clear SOF event for each engine */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + if (is_output_disabled(ctx->param, count)) + continue; + event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; + if (event != MDP_GCE_NO_EVENT) + MM_REG_CLEAR(cmd, event); + } + + /* Enable the mutex */ + mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt); + + /* Wait SOF events and clear mutex modules (optional) */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + if (is_output_disabled(ctx->param, count)) + continue; + event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF]; + if (event != MDP_GCE_NO_EVENT) + MM_REG_WAIT(cmd, event); + } + + return 0; +} + +static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path) +{ + const struct img_config *config = path->config; + int index, ret; + + if (config->num_components < 1) + return -EINVAL; + + for (index = 0; index < config->num_components; index++) { + ret = mdp_comp_ctx_config(mdp, &path->comps[index], + &config->components[index], + path->param); + if (ret) + return ret; + } + + return 0; +} + +static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, + struct mdp_path *path, u32 count) +{ + const struct img_config *config = path->config; + const struct img_mmsys_ctrl *ctrl = &config->ctrls[count]; + const struct img_mux *set; + struct mdp_comp_ctx *ctx; + s32 mutex_id; + int index, ret; + + /* Acquire components */ + ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count); + if (ret) + return ret; + /* Enable mux settings */ + for (index = 0; index < ctrl->num_sets; index++) { + set = &ctrl->sets[index]; + cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, + set->value, 0xFFFFFFFF); + } + /* Config sub-frame information */ + for (index = (config->num_components - 1); index >= 0; index--) { + ctx = &path->comps[index]; + if (is_output_disabled(ctx->param, count)) + continue; + ret = call_op(ctx, config_subfrm, cmd, count); + if (ret) + return ret; + } + /* Run components */ + ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count); + if (ret) + return ret; + /* Wait components done */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + if (is_output_disabled(ctx->param, count)) + continue; + ret = call_op(ctx, wait_comp_event, cmd); + if (ret) + return ret; + } + /* Advance to the next sub-frame */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + ret = call_op(ctx, advance_subfrm, cmd, count); + if (ret) + return ret; + } + /* Disable mux settings */ + for (index = 0; index < ctrl->num_sets; index++) { + set = &ctrl->sets[index]; + cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg, + 0, 0xFFFFFFFF); + } + + return 0; +} + +static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, + struct mdp_path *path) +{ + const struct img_config *config = path->config; + struct mdp_comp_ctx *ctx; + int index, count, ret; + + /* Config path frame */ + /* Reset components */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + ret = call_op(ctx, init_comp, cmd); + if (ret) + return ret; + } + /* Config frame mode */ + for (index = 0; index < config->num_components; index++) { + const struct v4l2_rect *compose = + path->composes[ctx->param->outputs[0]]; + + ctx = &path->comps[index]; + ret = call_op(ctx, config_frame, cmd, compose); + if (ret) + return ret; + } + + /* Config path sub-frames */ + for (count = 0; count < config->num_subfrms; count++) { + ret = mdp_path_config_subfrm(cmd, path, count); + if (ret) + return ret; + } + /* Post processing information */ + for (index = 0; index < config->num_components; index++) { + ctx = &path->comps[index]; + ret = call_op(ctx, post_process, cmd); + if (ret) + return ret; + } + return 0; +} + +static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt, + size_t size) +{ + struct device *dev; + dma_addr_t dma_addr; + + pkt->va_base = kzalloc(size, GFP_KERNEL); + if (!pkt->va_base) { + kfree(pkt); + return -ENOMEM; + } + pkt->buf_size = size; + pkt->cl = (void *)client; + + dev = client->chan->mbox->dev; + dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); + kfree(pkt->va_base); + return -ENOMEM; + } + + pkt->pa_base = dma_addr; + + return 0; +} + +static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt) +{ + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, + DMA_TO_DEVICE); + kfree(pkt->va_base); + pkt->va_base = NULL; +} + +static void mdp_auto_release_work(struct work_struct *work) +{ + struct mdp_cmdq_cmd *cmd; + struct mdp_dev *mdp; + + cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work); + mdp = cmd->mdp; + + mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]); + mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, + cmd->num_comps); + + atomic_dec(&mdp->job_count); + wake_up(&mdp->callback_wq); + + mdp_cmdq_pkt_destroy(&cmd->pkt); + kfree(cmd->comps); + cmd->comps = NULL; + kfree(cmd); + cmd = NULL; +} + +static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) +{ + struct mdp_cmdq_cmd *cmd; + struct cmdq_cb_data *data; + struct mdp_dev *mdp; + struct device *dev; + + if (!mssg) { + pr_info("%s:no callback data\n", __func__); + return; + } + + data = (struct cmdq_cb_data *)mssg; + cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt); + mdp = cmd->mdp; + dev = &mdp->pdev->dev; + + if (cmd->mdp_ctx) + mdp_m2m_job_finish(cmd->mdp_ctx); + + if (cmd->user_cmdq_cb) { + struct cmdq_cb_data user_cb_data; + + user_cb_data.sta = data->sta; + user_cb_data.pkt = data->pkt; + cmd->user_cmdq_cb(user_cb_data); + } + + INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work); + if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) { + dev_err(dev, "%s:queue_work fail!\n", __func__); + mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]); + mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, + cmd->num_comps); + + atomic_dec(&mdp->job_count); + wake_up(&mdp->callback_wq); + + mdp_cmdq_pkt_destroy(&cmd->pkt); + kfree(cmd->comps); + cmd->comps = NULL; + kfree(cmd); + cmd = NULL; + } +} + +int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) +{ + struct mdp_path *path = NULL; + struct mdp_cmdq_cmd *cmd = NULL; + struct mdp_comp *comps = NULL; + struct device *dev = &mdp->pdev->dev; + int i, ret; + + atomic_inc(&mdp->job_count); + if (atomic_read(&mdp->suspended)) { + atomic_dec(&mdp->job_count); + return -ECANCELED; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto err_cmdq_data; + } + + if (mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K)) { + ret = -ENOMEM; + goto err_cmdq_data; + } + + comps = kcalloc(param->config->num_components, sizeof(*comps), + GFP_KERNEL); + if (!comps) { + ret = -ENOMEM; + goto err_cmdq_data; + } + + path = kzalloc(sizeof(*path), GFP_KERNEL); + if (!path) { + ret = -ENOMEM; + goto err_cmdq_data; + } + + path->mdp_dev = mdp; + path->config = param->config; + path->param = param->param; + for (i = 0; i < param->param->num_outputs; i++) { + path->bounds[i].left = 0; + path->bounds[i].top = 0; + path->bounds[i].width = + param->param->outputs[i].buffer.format.width; + path->bounds[i].height = + param->param->outputs[i].buffer.format.height; + path->composes[i] = param->composes[i] ? + param->composes[i] : &path->bounds[i]; + } + + ret = mdp_path_ctx_init(mdp, path); + if (ret) { + dev_err(dev, "mdp_path_ctx_init error\n"); + goto err_cmdq_data; + } + + mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]); + + ret = mdp_path_config(mdp, cmd, path); + if (ret) { + dev_err(dev, "mdp_path_config error\n"); + goto err_cmdq_data; + } + cmdq_pkt_finalize(&cmd->pkt); + + for (i = 0; i < param->config->num_components; i++) + memcpy(&comps[i], path->comps[i].comp, + sizeof(struct mdp_comp)); + + mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback; + cmd->mdp = mdp; + cmd->user_cmdq_cb = param->cmdq_cb; + cmd->user_cb_data = param->cb_data; + cmd->comps = comps; + cmd->num_comps = param->config->num_components; + cmd->mdp_ctx = param->mdp_ctx; + + ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps); + if (ret) { + dev_err(dev, "comp %d failed to enable clock!\n", ret); + goto err_clock_off; + } + + dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev, + cmd->pkt.pa_base, cmd->pkt.cmd_buf_size, + DMA_TO_DEVICE); + ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt); + if (ret < 0) { + dev_err(dev, "mbox send message fail %d!\n", ret); + goto err_clock_off; + } + mbox_client_txdone(mdp->cmdq_clt->chan, 0); + + kfree(path); + return 0; + +err_clock_off: + mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]); + mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, + cmd->num_comps); +err_cmdq_data: + kfree(path); + atomic_dec(&mdp->job_count); + wake_up(&mdp->callback_wq); + if (cmd && cmd->pkt.buf_size > 0) + mdp_cmdq_pkt_destroy(&cmd->pkt); + kfree(comps); + kfree(cmd); + return ret; +} +EXPORT_SYMBOL_GPL(mdp_cmdq_send); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h new file mode 100644 index 000000000000..43475b862ddb --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_CMDQ_H__ +#define __MTK_MDP3_CMDQ_H__ + +#include <linux/platform_device.h> +#include <linux/videodev2.h> +#include <linux/soc/mediatek/mtk-cmdq.h> +#include "mtk-img-ipi.h" + +struct platform_device *mdp_get_plat_device(struct platform_device *pdev); + +struct mdp_cmdq_param { + struct img_config *config; + struct img_ipi_frameparam *param; + const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS]; + + void (*cmdq_cb)(struct cmdq_cb_data data); + void *cb_data; + void *mdp_ctx; +}; + +struct mdp_cmdq_cmd { + struct work_struct auto_release_work; + struct cmdq_pkt pkt; + s32 *event; + struct mdp_dev *mdp; + void (*user_cmdq_cb)(struct cmdq_cb_data data); + void *user_cb_data; + struct mdp_comp *comps; + void *mdp_ctx; + u8 num_comps; +}; + +struct mdp_dev; + +int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param); + +#endif /* __MTK_MDP3_CMDQ_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c new file mode 100644 index 000000000000..d3eaf8884412 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -0,0 +1,1034 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <linux/clk.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> +#include <linux/pm_runtime.h> +#include "mtk-mdp3-comp.h" +#include "mtk-mdp3-core.h" +#include "mtk-mdp3-regs.h" + +#include "mdp_reg_rdma.h" +#include "mdp_reg_ccorr.h" +#include "mdp_reg_rsz.h" +#include "mdp_reg_wrot.h" +#include "mdp_reg_wdma.h" + +static u32 mdp_comp_alias_id[MDP_COMP_TYPE_COUNT]; + +static inline const struct mdp_platform_config * +__get_plat_cfg(const struct mdp_comp_ctx *ctx) +{ + if (!ctx) + return NULL; + + return ctx->comp->mdp_dev->mdp_data->mdp_cfg; +} + +static s64 get_comp_flag(const struct mdp_comp_ctx *ctx) +{ + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + + if (mdp_cfg && mdp_cfg->rdma_rsz1_sram_sharing) + if (ctx->comp->id == MDP_COMP_RDMA0) + return BIT(MDP_COMP_RDMA0) | BIT(MDP_COMP_RSZ1); + + return BIT(ctx->comp->id); +} + +static int init_rdma(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if (mdp_cfg && mdp_cfg->rdma_support_10bit) { + struct mdp_comp *prz1 = ctx->comp->mdp_dev->comp[MDP_COMP_RSZ1]; + + /* Disable RSZ1 */ + if (ctx->comp->id == MDP_COMP_RDMA0 && prz1) + MM_REG_WRITE(cmd, subsys_id, prz1->reg_base, PRZ_ENABLE, + 0x0, BIT(0)); + } + + /* Reset RDMA */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESET, BIT(0), BIT(0)); + MM_REG_POLL(cmd, subsys_id, base, MDP_RDMA_MON_STA_1, BIT(8), BIT(8)); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_RESET, 0x0, BIT(0)); + return 0; +} + +static int config_rdma_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + const struct mdp_rdma_data *rdma = &ctx->param->rdma; + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + u32 colorformat = ctx->input->buffer.format.colorformat; + bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat); + bool en_ufo = MDP_COLOR_IS_UFP(colorformat); + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if (mdp_cfg && mdp_cfg->rdma_support_10bit) { + if (block10bit) + MM_REG_WRITE(cmd, subsys_id, base, + MDP_RDMA_RESV_DUMMY_0, 0x7, 0x7); + else + MM_REG_WRITE(cmd, subsys_id, base, + MDP_RDMA_RESV_DUMMY_0, 0x0, 0x7); + } + + /* Setup smi control */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_GMCIF_CON, + (7 << 4) + //burst type to 8 + (1 << 16), //enable pre-ultra + 0x00030071); + + /* Setup source frame info */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_CON, rdma->src_ctrl, + 0x03C8FE0F); + + if (mdp_cfg) + if (mdp_cfg->rdma_support_10bit && en_ufo) { + /* Setup source buffer base */ + MM_REG_WRITE(cmd, subsys_id, + base, MDP_RDMA_UFO_DEC_LENGTH_BASE_Y, + rdma->ufo_dec_y, 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, + base, MDP_RDMA_UFO_DEC_LENGTH_BASE_C, + rdma->ufo_dec_c, 0xFFFFFFFF); + /* Set 10bit source frame pitch */ + if (block10bit) + MM_REG_WRITE(cmd, subsys_id, + base, MDP_RDMA_MF_BKGD_SIZE_IN_PXL, + rdma->mf_bkgd_in_pxl, 0x001FFFFF); + } + + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_CON, rdma->control, + 0x1110); + /* Setup source buffer base */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_0, rdma->iova[0], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_1, rdma->iova[1], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_2, rdma->iova[2], + 0xFFFFFFFF); + /* Setup source buffer end */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_0, + rdma->iova_end[0], 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_1, + rdma->iova_end[1], 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_2, + rdma->iova_end[2], 0xFFFFFFFF); + /* Setup source frame pitch */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_BKGD_SIZE_IN_BYTE, + rdma->mf_bkgd, 0x001FFFFF); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SF_BKGD_SIZE_IN_BYTE, + rdma->sf_bkgd, 0x001FFFFF); + /* Setup color transform */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_TRANSFORM_0, + rdma->transform, 0x0F110000); + + return 0; +} + +static int config_rdma_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct mdp_rdma_subfrm *subfrm = &ctx->param->rdma.subfrms[index]; + const struct img_comp_subfrm *csf = &ctx->param->subfrms[index]; + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + u32 colorformat = ctx->input->buffer.format.colorformat; + bool block10bit = MDP_COLOR_IS_10BIT_PACKED(colorformat); + bool en_ufo = MDP_COLOR_IS_UFP(colorformat); + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Enable RDMA */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, BIT(0), BIT(0)); + + /* Set Y pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0, + subfrm->offset[0], 0xFFFFFFFF); + + /* Set 10bit UFO mode */ + if (mdp_cfg) + if (mdp_cfg->rdma_support_10bit && block10bit && en_ufo) + MM_REG_WRITE(cmd, subsys_id, base, + MDP_RDMA_SRC_OFFSET_0_P, + subfrm->offset_0_p, 0xFFFFFFFF); + + /* Set U pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_1, + subfrm->offset[1], 0xFFFFFFFF); + /* Set V pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_2, + subfrm->offset[2], 0xFFFFFFFF); + /* Set source size */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_SRC_SIZE, subfrm->src, + 0x1FFF1FFF); + /* Set target size */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_CLIP_SIZE, + subfrm->clip, 0x1FFF1FFF); + /* Set crop offset */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_OFFSET_1, + subfrm->clip_ofst, 0x003F001F); + + if (mdp_cfg && mdp_cfg->rdma_upsample_repeat_only) + if ((csf->in.right - csf->in.left + 1) > 320) + MM_REG_WRITE(cmd, subsys_id, base, + MDP_RDMA_RESV_DUMMY_0, BIT(2), BIT(2)); + + return 0; +} + +static int wait_rdma_event(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + struct device *dev = &ctx->comp->mdp_dev->pdev->dev; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if (ctx->comp->alias_id == 0) + MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); + else + dev_err(dev, "Do not support RDMA1_DONE event\n"); + + /* Disable RDMA */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, 0x0, BIT(0)); + return 0; +} + +static const struct mdp_comp_ops rdma_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_rdma, + .config_frame = config_rdma_frame, + .config_subfrm = config_rdma_subfrm, + .wait_comp_event = wait_rdma_event, +}; + +static int init_rsz(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Reset RSZ */ + MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x10000, BIT(16)); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x0, BIT(16)); + /* Enable RSZ */ + MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, BIT(0), BIT(0)); + return 0; +} + +static int config_rsz_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + const struct mdp_rsz_data *rsz = &ctx->param->rsz; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if (ctx->param->frame.bypass) { + /* Disable RSZ */ + MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x0, BIT(0)); + return 0; + } + + MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, rsz->control1, + 0x03FFFDF3); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, rsz->control2, + 0x0FFFC290); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_HORIZONTAL_COEFF_STEP, + rsz->coeff_step_x, 0x007FFFFF); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_VERTICAL_COEFF_STEP, + rsz->coeff_step_y, 0x007FFFFF); + return 0; +} + +static int config_rsz_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct mdp_rsz_subfrm *subfrm = &ctx->param->rsz.subfrms[index]; + const struct img_comp_subfrm *csf = &ctx->param->subfrms[index]; + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, subfrm->control2, + 0x00003800); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_INPUT_IMAGE, subfrm->src, + 0xFFFFFFFF); + + if (mdp_cfg && mdp_cfg->rsz_disable_dcm_small_sample) + if ((csf->in.right - csf->in.left + 1) <= 16) + MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, + BIT(27), BIT(27)); + + MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET, + csf->luma.left, 0xFFFF); + MM_REG_WRITE(cmd, subsys_id, + base, PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET, + csf->luma.left_subpix, 0x1FFFFF); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_INTEGER_OFFSET, + csf->luma.top, 0xFFFF); + MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET, + csf->luma.top_subpix, 0x1FFFFF); + MM_REG_WRITE(cmd, subsys_id, + base, PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET, + csf->chroma.left, 0xFFFF); + MM_REG_WRITE(cmd, subsys_id, + base, PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET, + csf->chroma.left_subpix, 0x1FFFFF); + + MM_REG_WRITE(cmd, subsys_id, base, PRZ_OUTPUT_IMAGE, subfrm->clip, + 0xFFFFFFFF); + + return 0; +} + +static int advance_rsz_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + + if (mdp_cfg && mdp_cfg->rsz_disable_dcm_small_sample) { + const struct img_comp_subfrm *csf = &ctx->param->subfrms[index]; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if ((csf->in.right - csf->in.left + 1) <= 16) + MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, 0x0, + BIT(27)); + } + + return 0; +} + +static const struct mdp_comp_ops rsz_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_rsz, + .config_frame = config_rsz_frame, + .config_subfrm = config_rsz_subfrm, + .advance_subfrm = advance_rsz_subfrm, +}; + +static int init_wrot(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Reset WROT */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, BIT(0), BIT(0)); + MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, BIT(0), BIT(0)); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, 0x0, BIT(0)); + MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, 0x0, BIT(0)); + return 0; +} + +static int config_wrot_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + const struct mdp_wrot_data *wrot = &ctx->param->wrot; + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Write frame base address */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR, wrot->iova[0], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_C, wrot->iova[1], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_V, wrot->iova[2], + 0xFFFFFFFF); + /* Write frame related registers */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, wrot->control, + 0xF131510F); + /* Write frame Y pitch */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE, wrot->stride[0], + 0x0000FFFF); + /* Write frame UV pitch */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_C, wrot->stride[1], + 0xFFFF); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_V, wrot->stride[2], + 0xFFFF); + /* Write matrix control */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAT_CTRL, wrot->mat_ctrl, 0xF3); + + /* Set the fixed ALPHA as 0xFF */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_DITHER, 0xFF000000, + 0xFF000000); + /* Set VIDO_EOL_SEL */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_RSV_1, BIT(31), BIT(31)); + /* Set VIDO_FIFO_TEST */ + if (wrot->fifo_test != 0) + MM_REG_WRITE(cmd, subsys_id, base, VIDO_FIFO_TEST, + wrot->fifo_test, 0xFFF); + /* Filter enable */ + if (mdp_cfg && mdp_cfg->wrot_filter_constraint) + MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, + wrot->filter, 0x77); + + return 0; +} + +static int config_wrot_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct mdp_wrot_subfrm *subfrm = &ctx->param->wrot.subfrms[index]; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Write Y pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR, + subfrm->offset[0], 0x0FFFFFFF); + /* Write U pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_C, + subfrm->offset[1], 0x0FFFFFFF); + /* Write V pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_V, + subfrm->offset[2], 0x0FFFFFFF); + /* Write source size */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_IN_SIZE, subfrm->src, + 0x1FFF1FFF); + /* Write target size */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_TAR_SIZE, subfrm->clip, + 0x1FFF1FFF); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_CROP_OFST, subfrm->clip_ofst, + 0x1FFF1FFF); + + MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, + subfrm->main_buf, 0x1FFF7F00); + + /* Enable WROT */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, BIT(0), BIT(0)); + + return 0; +} + +static int wait_wrot_event(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + struct device *dev = &ctx->comp->mdp_dev->pdev->dev; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + if (ctx->comp->alias_id == 0) + MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); + else + dev_err(dev, "Do not support WROT1_DONE event\n"); + + if (mdp_cfg && mdp_cfg->wrot_filter_constraint) + MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, 0x0, + 0x77); + + /* Disable WROT */ + MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, 0x0, BIT(0)); + + return 0; +} + +static const struct mdp_comp_ops wrot_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_wrot, + .config_frame = config_wrot_frame, + .config_subfrm = config_wrot_subfrm, + .wait_comp_event = wait_wrot_event, +}; + +static int init_wdma(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Reset WDMA */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_RST, BIT(0), BIT(0)); + MM_REG_POLL(cmd, subsys_id, base, WDMA_FLOW_CTRL_DBG, BIT(0), BIT(0)); + MM_REG_WRITE(cmd, subsys_id, base, WDMA_RST, 0x0, BIT(0)); + return 0; +} + +static int config_wdma_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + const struct mdp_wdma_data *wdma = &ctx->param->wdma; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, WDMA_BUF_CON2, 0x10101050, + 0xFFFFFFFF); + + /* Setup frame information */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_CFG, wdma->wdma_cfg, + 0x0F01B8F0); + /* Setup frame base address */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR, wdma->iova[0], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR, wdma->iova[1], + 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR, wdma->iova[2], + 0xFFFFFFFF); + /* Setup Y pitch */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_W_IN_BYTE, + wdma->w_in_byte, 0x0000FFFF); + /* Setup UV pitch */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_UV_PITCH, + wdma->uv_stride, 0x0000FFFF); + /* Set the fixed ALPHA as 0xFF */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_ALPHA, 0x800000FF, + 0x800000FF); + + return 0; +} + +static int config_wdma_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct mdp_wdma_subfrm *subfrm = &ctx->param->wdma.subfrms[index]; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* Write Y pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_ADDR_OFFSET, + subfrm->offset[0], 0x0FFFFFFF); + /* Write U pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_U_ADDR_OFFSET, + subfrm->offset[1], 0x0FFFFFFF); + /* Write V pixel offset */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_DST_V_ADDR_OFFSET, + subfrm->offset[2], 0x0FFFFFFF); + /* Write source size */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_SRC_SIZE, subfrm->src, + 0x3FFF3FFF); + /* Write target size */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_SIZE, subfrm->clip, + 0x3FFF3FFF); + /* Write clip offset */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_CLIP_COORD, subfrm->clip_ofst, + 0x3FFF3FFF); + + /* Enable WDMA */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_EN, BIT(0), BIT(0)); + + return 0; +} + +static int wait_wdma_event(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); + /* Disable WDMA */ + MM_REG_WRITE(cmd, subsys_id, base, WDMA_EN, 0x0, BIT(0)); + return 0; +} + +static const struct mdp_comp_ops wdma_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_wdma, + .config_frame = config_wdma_frame, + .config_subfrm = config_wdma_subfrm, + .wait_comp_event = wait_wdma_event, +}; + +static int init_ccorr(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + + /* CCORR enable */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_EN, BIT(0), BIT(0)); + /* Relay mode */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_CFG, BIT(0), BIT(0)); + return 0; +} + +static int config_ccorr_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + const struct img_comp_subfrm *csf = &ctx->param->subfrms[index]; + phys_addr_t base = ctx->comp->reg_base; + u8 subsys_id = ctx->comp->subsys_id; + u32 hsize, vsize; + + hsize = csf->in.right - csf->in.left + 1; + vsize = csf->in.bottom - csf->in.top + 1; + MM_REG_WRITE(cmd, subsys_id, base, MDP_CCORR_SIZE, + (hsize << 16) + (vsize << 0), 0x1FFF1FFF); + return 0; +} + +static const struct mdp_comp_ops ccorr_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_ccorr, + .config_subfrm = config_ccorr_subfrm, +}; + +static const struct mdp_comp_ops *mdp_comp_ops[MDP_COMP_TYPE_COUNT] = { + [MDP_COMP_TYPE_RDMA] = &rdma_ops, + [MDP_COMP_TYPE_RSZ] = &rsz_ops, + [MDP_COMP_TYPE_WROT] = &wrot_ops, + [MDP_COMP_TYPE_WDMA] = &wdma_ops, + [MDP_COMP_TYPE_CCORR] = &ccorr_ops, +}; + +struct mdp_comp_match { + enum mdp_comp_type type; + u32 alias_id; +}; + +static const struct mdp_comp_match mdp_comp_matches[MDP_MAX_COMP_COUNT] = { + [MDP_COMP_WPEI] = { MDP_COMP_TYPE_WPEI, 0 }, + [MDP_COMP_WPEO] = { MDP_COMP_TYPE_EXTO, 2 }, + [MDP_COMP_WPEI2] = { MDP_COMP_TYPE_WPEI, 1 }, + [MDP_COMP_WPEO2] = { MDP_COMP_TYPE_EXTO, 3 }, + [MDP_COMP_ISP_IMGI] = { MDP_COMP_TYPE_IMGI, 0 }, + [MDP_COMP_ISP_IMGO] = { MDP_COMP_TYPE_EXTO, 0 }, + [MDP_COMP_ISP_IMG2O] = { MDP_COMP_TYPE_EXTO, 1 }, + + [MDP_COMP_CAMIN] = { MDP_COMP_TYPE_DL_PATH, 0 }, + [MDP_COMP_CAMIN2] = { MDP_COMP_TYPE_DL_PATH, 1 }, + [MDP_COMP_RDMA0] = { MDP_COMP_TYPE_RDMA, 0 }, + [MDP_COMP_CCORR0] = { MDP_COMP_TYPE_CCORR, 0 }, + [MDP_COMP_RSZ0] = { MDP_COMP_TYPE_RSZ, 0 }, + [MDP_COMP_RSZ1] = { MDP_COMP_TYPE_RSZ, 1 }, + [MDP_COMP_PATH0_SOUT] = { MDP_COMP_TYPE_PATH, 0 }, + [MDP_COMP_PATH1_SOUT] = { MDP_COMP_TYPE_PATH, 1 }, + [MDP_COMP_WROT0] = { MDP_COMP_TYPE_WROT, 0 }, + [MDP_COMP_WDMA] = { MDP_COMP_TYPE_WDMA, 0 }, +}; + +static const struct of_device_id mdp_comp_dt_ids[] = { + { + .compatible = "mediatek,mt8183-mdp3-rdma", + .data = (void *)MDP_COMP_TYPE_RDMA, + }, { + .compatible = "mediatek,mt8183-mdp3-ccorr", + .data = (void *)MDP_COMP_TYPE_CCORR, + }, { + .compatible = "mediatek,mt8183-mdp3-rsz", + .data = (void *)MDP_COMP_TYPE_RSZ, + }, { + .compatible = "mediatek,mt8183-mdp3-wrot", + .data = (void *)MDP_COMP_TYPE_WROT, + }, { + .compatible = "mediatek,mt8183-mdp3-wdma", + .data = (void *)MDP_COMP_TYPE_WDMA, + }, + {} +}; + +static const struct of_device_id mdp_sub_comp_dt_ids[] = { + { + .compatible = "mediatek,mt8183-mdp3-wdma", + .data = (void *)MDP_COMP_TYPE_PATH, + }, { + .compatible = "mediatek,mt8183-mdp3-wrot", + .data = (void *)MDP_COMP_TYPE_PATH, + }, + {} +}; + +/* Used to describe the item order in MDP property */ +struct mdp_comp_info { + u32 clk_num; + u32 clk_ofst; + u32 dts_reg_ofst; +}; + +static const struct mdp_comp_info mdp_comp_dt_info[MDP_MAX_COMP_COUNT] = { + [MDP_COMP_RDMA0] = {2, 0, 0}, + [MDP_COMP_RSZ0] = {1, 0, 0}, + [MDP_COMP_WROT0] = {1, 0, 0}, + [MDP_COMP_WDMA] = {1, 0, 0}, + [MDP_COMP_CCORR0] = {1, 0, 0}, +}; + +static inline bool is_dma_capable(const enum mdp_comp_type type) +{ + return (type == MDP_COMP_TYPE_RDMA || + type == MDP_COMP_TYPE_WROT || + type == MDP_COMP_TYPE_WDMA); +} + +static inline bool is_bypass_gce_event(const enum mdp_comp_type type) +{ + /* + * Subcomponent PATH is only used for the direction of data flow and + * dose not need to wait for GCE event. + */ + return (type == MDP_COMP_TYPE_PATH); +} + +static int mdp_comp_get_id(enum mdp_comp_type type, int alias_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mdp_comp_matches); i++) + if (mdp_comp_matches[i].type == type && + mdp_comp_matches[i].alias_id == alias_id) + return i; + return -ENODEV; +} + +int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp) +{ + int i, ret; + + if (comp->comp_dev) { + ret = pm_runtime_resume_and_get(comp->comp_dev); + if (ret < 0) { + dev_err(dev, + "Failed to get power, err %d. type:%d id:%d\n", + ret, comp->type, comp->id); + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(comp->clks); i++) { + if (IS_ERR_OR_NULL(comp->clks[i])) + continue; + ret = clk_prepare_enable(comp->clks[i]); + if (ret) { + dev_err(dev, + "Failed to enable clk %d. type:%d id:%d\n", + i, comp->type, comp->id); + pm_runtime_put(comp->comp_dev); + return ret; + } + } + + return 0; +} + +void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(comp->clks); i++) { + if (IS_ERR_OR_NULL(comp->clks[i])) + continue; + clk_disable_unprepare(comp->clks[i]); + } + + if (comp->comp_dev) + pm_runtime_put(comp->comp_dev); +} + +int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num) +{ + int i; + + for (i = 0; i < num; i++) + if (mdp_comp_clock_on(dev, &comps[i]) != 0) + return ++i; + + return 0; +} + +void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num) +{ + int i; + + for (i = 0; i < num; i++) + mdp_comp_clock_off(dev, &comps[i]); +} + +static int mdp_get_subsys_id(struct device *dev, struct device_node *node, + struct mdp_comp *comp) +{ + struct platform_device *comp_pdev; + struct cmdq_client_reg cmdq_reg; + int ret = 0; + int index = 0; + + if (!dev || !node || !comp) + return -EINVAL; + + comp_pdev = of_find_device_by_node(node); + + if (!comp_pdev) { + dev_err(dev, "get comp_pdev fail! comp id=%d type=%d\n", + comp->id, comp->type); + return -ENODEV; + } + + index = mdp_comp_dt_info[comp->id].dts_reg_ofst; + ret = cmdq_dev_get_client_reg(&comp_pdev->dev, &cmdq_reg, index); + if (ret != 0) { + dev_err(&comp_pdev->dev, "cmdq_dev_get_subsys fail!\n"); + return -EINVAL; + } + + comp->subsys_id = cmdq_reg.subsys; + dev_dbg(&comp_pdev->dev, "subsys id=%d\n", cmdq_reg.subsys); + + return 0; +} + +static void __mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, + struct mdp_comp *comp) +{ + struct resource res; + phys_addr_t base; + int index = mdp_comp_dt_info[comp->id].dts_reg_ofst; + + if (of_address_to_resource(node, index, &res) < 0) + base = 0L; + else + base = res.start; + + comp->mdp_dev = mdp; + comp->regs = of_iomap(node, 0); + comp->reg_base = base; +} + +static int mdp_comp_init(struct mdp_dev *mdp, struct device_node *node, + struct mdp_comp *comp, enum mtk_mdp_comp_id id) +{ + struct device *dev = &mdp->pdev->dev; + int clk_num; + int clk_ofst; + int i; + s32 event; + + if (id < 0 || id >= MDP_MAX_COMP_COUNT) { + dev_err(dev, "Invalid component id %d\n", id); + return -EINVAL; + } + + comp->id = id; + comp->type = mdp_comp_matches[id].type; + comp->alias_id = mdp_comp_matches[id].alias_id; + comp->ops = mdp_comp_ops[comp->type]; + __mdp_comp_init(mdp, node, comp); + + clk_num = mdp_comp_dt_info[id].clk_num; + clk_ofst = mdp_comp_dt_info[id].clk_ofst; + + for (i = 0; i < clk_num; i++) { + comp->clks[i] = of_clk_get(node, i + clk_ofst); + if (IS_ERR(comp->clks[i])) + break; + } + + mdp_get_subsys_id(dev, node, comp); + + /* Set GCE SOF event */ + if (is_bypass_gce_event(comp->type) || + of_property_read_u32_index(node, "mediatek,gce-events", + MDP_GCE_EVENT_SOF, &event)) + event = MDP_GCE_NO_EVENT; + + comp->gce_event[MDP_GCE_EVENT_SOF] = event; + + /* Set GCE EOF event */ + if (is_dma_capable(comp->type)) { + if (of_property_read_u32_index(node, "mediatek,gce-events", + MDP_GCE_EVENT_EOF, &event)) { + dev_err(dev, "Component id %d has no EOF\n", id); + return -EINVAL; + } + } else { + event = MDP_GCE_NO_EVENT; + } + + comp->gce_event[MDP_GCE_EVENT_EOF] = event; + + return 0; +} + +static void mdp_comp_deinit(struct mdp_comp *comp) +{ + if (!comp) + return; + + if (comp->regs) + iounmap(comp->regs); +} + +static struct mdp_comp *mdp_comp_create(struct mdp_dev *mdp, + struct device_node *node, + enum mtk_mdp_comp_id id) +{ + struct device *dev = &mdp->pdev->dev; + struct mdp_comp *comp; + int ret; + + if (mdp->comp[id]) + return ERR_PTR(-EEXIST); + + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); + if (!comp) + return ERR_PTR(-ENOMEM); + + ret = mdp_comp_init(mdp, node, comp, id); + if (ret) { + devm_kfree(dev, comp); + return ERR_PTR(ret); + } + mdp->comp[id] = comp; + mdp->comp[id]->mdp_dev = mdp; + + dev_dbg(dev, "%s type:%d alias:%d id:%d base:%#x regs:%p\n", + dev->of_node->name, comp->type, comp->alias_id, id, + (u32)comp->reg_base, comp->regs); + return comp; +} + +static int mdp_comp_sub_create(struct mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + struct device_node *node, *parent; + + parent = dev->of_node->parent; + + for_each_child_of_node(parent, node) { + const struct of_device_id *of_id; + enum mdp_comp_type type; + int id, alias_id; + struct mdp_comp *comp; + + of_id = of_match_node(mdp_sub_comp_dt_ids, node); + if (!of_id) + continue; + if (!of_device_is_available(node)) { + dev_dbg(dev, "Skipping disabled sub comp. %pOF\n", + node); + continue; + } + + type = (enum mdp_comp_type)(uintptr_t)of_id->data; + alias_id = mdp_comp_alias_id[type]; + id = mdp_comp_get_id(type, alias_id); + if (id < 0) { + dev_err(dev, + "Fail to get sub comp. id: type %d alias %d\n", + type, alias_id); + return -EINVAL; + } + mdp_comp_alias_id[type]++; + + comp = mdp_comp_create(mdp, node, id); + if (IS_ERR(comp)) + return PTR_ERR(comp); + } + + return 0; +} + +void mdp_comp_destroy(struct mdp_dev *mdp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) { + if (mdp->comp[i]) { + pm_runtime_disable(mdp->comp[i]->comp_dev); + mdp_comp_deinit(mdp->comp[i]); + devm_kfree(mdp->comp[i]->comp_dev, mdp->comp[i]); + mdp->comp[i] = NULL; + } + } +} + +int mdp_comp_config(struct mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + struct device_node *node, *parent; + struct platform_device *pdev; + int ret; + + memset(mdp_comp_alias_id, 0, sizeof(mdp_comp_alias_id)); + + parent = dev->of_node->parent; + /* Iterate over sibling MDP function blocks */ + for_each_child_of_node(parent, node) { + const struct of_device_id *of_id; + enum mdp_comp_type type; + int id, alias_id; + struct mdp_comp *comp; + + of_id = of_match_node(mdp_comp_dt_ids, node); + if (!of_id) + continue; + + if (!of_device_is_available(node)) { + dev_dbg(dev, "Skipping disabled component %pOF\n", + node); + continue; + } + + type = (enum mdp_comp_type)(uintptr_t)of_id->data; + alias_id = mdp_comp_alias_id[type]; + id = mdp_comp_get_id(type, alias_id); + if (id < 0) { + dev_err(dev, + "Fail to get component id: type %d alias %d\n", + type, alias_id); + continue; + } + mdp_comp_alias_id[type]++; + + comp = mdp_comp_create(mdp, node, id); + if (IS_ERR(comp)) { + ret = PTR_ERR(comp); + goto err_init_comps; + } + + /* Only DMA capable components need the pm control */ + comp->comp_dev = NULL; + if (!is_dma_capable(comp->type)) + continue; + + pdev = of_find_device_by_node(node); + if (!pdev) { + dev_warn(dev, "can't find platform device of node:%s\n", + node->name); + return -ENODEV; + } + + comp->comp_dev = &pdev->dev; + pm_runtime_enable(comp->comp_dev); + } + + ret = mdp_comp_sub_create(mdp); + if (ret) + goto err_init_comps; + + return 0; + +err_init_comps: + mdp_comp_destroy(mdp); + return ret; +} + +int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx, + const struct img_compparam *param, + const struct img_ipi_frameparam *frame) +{ + struct device *dev = &mdp->pdev->dev; + int i; + + if (param->type < 0 || param->type >= MDP_MAX_COMP_COUNT) { + dev_err(dev, "Invalid component id %d", param->type); + return -EINVAL; + } + + ctx->comp = mdp->comp[param->type]; + if (!ctx->comp) { + dev_err(dev, "Uninit component id %d", param->type); + return -EINVAL; + } + + ctx->param = param; + ctx->input = &frame->inputs[param->input]; + for (i = 0; i < param->num_outputs; i++) + ctx->outputs[i] = &frame->outputs[param->outputs[i]]; + return 0; +} diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h new file mode 100644 index 000000000000..dc48f55ac4f7 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h @@ -0,0 +1,186 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_COMP_H__ +#define __MTK_MDP3_COMP_H__ + +#include "mtk-mdp3-cmdq.h" + +#define MM_REG_WRITE_MASK(cmd, id, base, ofst, val, mask, ...) \ + cmdq_pkt_write_mask(&((cmd)->pkt), id, \ + (base) + (ofst), (val), (mask), ##__VA_ARGS__) + +#define MM_REG_WRITE(cmd, id, base, ofst, val, mask, ...) \ +do { \ + typeof(mask) (m) = (mask); \ + MM_REG_WRITE_MASK(cmd, id, base, ofst, val, \ + (((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \ + (0xffffffff) : (m), ##__VA_ARGS__); \ +} while (0) + +#define MM_REG_WAIT(cmd, evt) \ +do { \ + typeof(cmd) (c) = (cmd); \ + typeof(evt) (e) = (evt); \ + cmdq_pkt_wfe(&((c)->pkt), (e), true); \ +} while (0) + +#define MM_REG_WAIT_NO_CLEAR(cmd, evt) \ +do { \ + typeof(cmd) (c) = (cmd); \ + typeof(evt) (e) = (evt); \ + cmdq_pkt_wfe(&((c)->pkt), (e), false); \ +} while (0) + +#define MM_REG_CLEAR(cmd, evt) \ +do { \ + typeof(cmd) (c) = (cmd); \ + typeof(evt) (e) = (evt); \ + cmdq_pkt_clear_event(&((c)->pkt), (e)); \ +} while (0) + +#define MM_REG_SET_EVENT(cmd, evt) \ +do { \ + typeof(cmd) (c) = (cmd); \ + typeof(evt) (e) = (evt); \ + cmdq_pkt_set_event(&((c)->pkt), (e)); \ +} while (0) + +#define MM_REG_POLL_MASK(cmd, id, base, ofst, val, _mask, ...) \ +do { \ + typeof(_mask) (_m) = (_mask); \ + cmdq_pkt_poll_mask(&((cmd)->pkt), id, \ + (base) + (ofst), (val), (_m), ##__VA_ARGS__); \ +} while (0) + +#define MM_REG_POLL(cmd, id, base, ofst, val, mask, ...) \ +do { \ + typeof(mask) (m) = (mask); \ + MM_REG_POLL_MASK((cmd), id, base, ofst, val, \ + (((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \ + (0xffffffff) : (m), ##__VA_ARGS__); \ +} while (0) + +enum mtk_mdp_comp_id { + MDP_COMP_NONE = -1, /* Invalid engine */ + + /* ISP */ + MDP_COMP_WPEI = 0, + MDP_COMP_WPEO, /* 1 */ + MDP_COMP_WPEI2, /* 2 */ + MDP_COMP_WPEO2, /* 3 */ + MDP_COMP_ISP_IMGI, /* 4 */ + MDP_COMP_ISP_IMGO, /* 5 */ + MDP_COMP_ISP_IMG2O, /* 6 */ + + /* IPU */ + MDP_COMP_IPUI, /* 7 */ + MDP_COMP_IPUO, /* 8 */ + + /* MDP */ + MDP_COMP_CAMIN, /* 9 */ + MDP_COMP_CAMIN2, /* 10 */ + MDP_COMP_RDMA0, /* 11 */ + MDP_COMP_AAL0, /* 12 */ + MDP_COMP_CCORR0, /* 13 */ + MDP_COMP_RSZ0, /* 14 */ + MDP_COMP_RSZ1, /* 15 */ + MDP_COMP_TDSHP0, /* 16 */ + MDP_COMP_COLOR0, /* 17 */ + MDP_COMP_PATH0_SOUT, /* 18 */ + MDP_COMP_PATH1_SOUT, /* 19 */ + MDP_COMP_WROT0, /* 20 */ + MDP_COMP_WDMA, /* 21 */ + + /* Dummy Engine */ + MDP_COMP_RDMA1, /* 22 */ + MDP_COMP_RSZ2, /* 23 */ + MDP_COMP_TDSHP1, /* 24 */ + MDP_COMP_WROT1, /* 25 */ + + MDP_MAX_COMP_COUNT /* ALWAYS keep at the end */ +}; + +enum mdp_comp_type { + MDP_COMP_TYPE_INVALID = 0, + + MDP_COMP_TYPE_RDMA, + MDP_COMP_TYPE_RSZ, + MDP_COMP_TYPE_WROT, + MDP_COMP_TYPE_WDMA, + MDP_COMP_TYPE_PATH, + + MDP_COMP_TYPE_TDSHP, + MDP_COMP_TYPE_COLOR, + MDP_COMP_TYPE_DRE, + MDP_COMP_TYPE_CCORR, + MDP_COMP_TYPE_HDR, + + MDP_COMP_TYPE_IMGI, + MDP_COMP_TYPE_WPEI, + MDP_COMP_TYPE_EXTO, /* External path */ + MDP_COMP_TYPE_DL_PATH, /* Direct-link path */ + + MDP_COMP_TYPE_COUNT /* ALWAYS keep at the end */ +}; + +#define MDP_GCE_NO_EVENT (-1) +enum { + MDP_GCE_EVENT_SOF = 0, + MDP_GCE_EVENT_EOF = 1, + MDP_GCE_EVENT_MAX, +}; + +struct mdp_comp_ops; + +struct mdp_comp { + struct mdp_dev *mdp_dev; + void __iomem *regs; + phys_addr_t reg_base; + u8 subsys_id; + struct clk *clks[6]; + struct device *comp_dev; + enum mdp_comp_type type; + enum mtk_mdp_comp_id id; + u32 alias_id; + s32 gce_event[MDP_GCE_EVENT_MAX]; + const struct mdp_comp_ops *ops; +}; + +struct mdp_comp_ctx { + struct mdp_comp *comp; + const struct img_compparam *param; + const struct img_input *input; + const struct img_output *outputs[IMG_MAX_HW_OUTPUTS]; +}; + +struct mdp_comp_ops { + s64 (*get_comp_flag)(const struct mdp_comp_ctx *ctx); + int (*init_comp)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd); + int (*config_frame)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose); + int (*config_subfrm)(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index); + int (*wait_comp_event)(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd); + int (*advance_subfrm)(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index); + int (*post_process)(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd); +}; + +struct mdp_dev; + +int mdp_comp_config(struct mdp_dev *mdp); +void mdp_comp_destroy(struct mdp_dev *mdp); +int mdp_comp_clock_on(struct device *dev, struct mdp_comp *comp); +void mdp_comp_clock_off(struct device *dev, struct mdp_comp *comp); +int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num); +void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num); +int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx, + const struct img_compparam *param, + const struct img_ipi_frameparam *frame); + +#endif /* __MTK_MDP3_COMP_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c new file mode 100644 index 000000000000..c413e59d4286 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/remoteproc.h> +#include <linux/remoteproc/mtk_scp.h> +#include <media/videobuf2-dma-contig.h> +#include "mtk-mdp3-core.h" +#include "mtk-mdp3-m2m.h" + +static const struct mdp_platform_config mt8183_plat_cfg = { + .rdma_support_10bit = true, + .rdma_rsz1_sram_sharing = true, + .rdma_upsample_repeat_only = true, + .rsz_disable_dcm_small_sample = false, + .wrot_filter_constraint = false, +}; + +static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = { + [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" }, + [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" }, + [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" } +}; + +static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = { + [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, + [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0, + [MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1, + [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0, + [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0, + [MDP_COMP_WDMA] = MUTEX_MOD_IDX_MDP_WDMA, + [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0, + [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0, +}; + +static const struct mtk_mdp_driver_data mt8183_mdp_driver_data = { + .mdp_probe_infra = mt8183_mdp_probe_infra, + .mdp_cfg = &mt8183_plat_cfg, + .mdp_mutex_table_idx = mt8183_mutex_idx, +}; + +static const struct of_device_id mdp_of_ids[] = { + { .compatible = "mediatek,mt8183-mdp3-rdma", + .data = &mt8183_mdp_driver_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mdp_of_ids); + +static struct platform_device *__get_pdev_by_id(struct platform_device *pdev, + enum mdp_infra_id id) +{ + struct device_node *node; + struct platform_device *mdp_pdev = NULL; + const struct mtk_mdp_driver_data *mdp_data; + const char *compat; + + if (!pdev) + return NULL; + + if (id < MDP_INFRA_MMSYS || id >= MDP_INFRA_MAX) { + dev_err(&pdev->dev, "Illegal infra id %d\n", id); + return NULL; + } + + mdp_data = of_device_get_match_data(&pdev->dev); + if (!mdp_data) { + dev_err(&pdev->dev, "have no driver data to find node\n"); + return NULL; + } + compat = mdp_data->mdp_probe_infra[id].compatible; + + node = of_find_compatible_node(NULL, NULL, compat); + if (WARN_ON(!node)) { + dev_err(&pdev->dev, "find node from id %d failed\n", id); + return NULL; + } + + mdp_pdev = of_find_device_by_node(node); + of_node_put(node); + if (WARN_ON(!mdp_pdev)) { + dev_err(&pdev->dev, "find pdev from id %d failed\n", id); + return NULL; + } + + return mdp_pdev; +} + +struct platform_device *mdp_get_plat_device(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *mdp_node; + struct platform_device *mdp_pdev; + + mdp_node = of_parse_phandle(dev->of_node, MDP_PHANDLE_NAME, 0); + if (!mdp_node) { + dev_err(dev, "can't get node %s\n", MDP_PHANDLE_NAME); + return NULL; + } + + mdp_pdev = of_find_device_by_node(mdp_node); + of_node_put(mdp_node); + + return mdp_pdev; +} +EXPORT_SYMBOL_GPL(mdp_get_plat_device); + +int mdp_vpu_get_locked(struct mdp_dev *mdp) +{ + int ret = 0; + + if (mdp->vpu_count++ == 0) { + ret = rproc_boot(mdp->rproc_handle); + if (ret) { + dev_err(&mdp->pdev->dev, + "vpu_load_firmware failed %d\n", ret); + goto err_load_vpu; + } + ret = mdp_vpu_register(mdp); + if (ret) { + dev_err(&mdp->pdev->dev, + "mdp_vpu register failed %d\n", ret); + goto err_reg_vpu; + } + ret = mdp_vpu_dev_init(&mdp->vpu, mdp->scp, &mdp->vpu_lock); + if (ret) { + dev_err(&mdp->pdev->dev, + "mdp_vpu device init failed %d\n", ret); + goto err_init_vpu; + } + } + return 0; + +err_init_vpu: + mdp_vpu_unregister(mdp); +err_reg_vpu: +err_load_vpu: + mdp->vpu_count--; + return ret; +} + +void mdp_vpu_put_locked(struct mdp_dev *mdp) +{ + if (--mdp->vpu_count == 0) { + mdp_vpu_dev_deinit(&mdp->vpu); + mdp_vpu_unregister(mdp); + } +} + +void mdp_video_device_release(struct video_device *vdev) +{ + struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev); + int i; + + scp_put(mdp->scp); + + destroy_workqueue(mdp->job_wq); + destroy_workqueue(mdp->clock_wq); + + pm_runtime_disable(&mdp->pdev->dev); + + vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev); + + mdp_comp_destroy(mdp); + for (i = 0; i < MDP_PIPE_MAX; i++) + mtk_mutex_put(mdp->mdp_mutex[i]); + + mdp_vpu_shared_mem_free(&mdp->vpu); + v4l2_m2m_release(mdp->m2m_dev); + kfree(mdp); +} + +static int mdp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mdp_dev *mdp; + struct platform_device *mm_pdev; + int ret, i; + + mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); + if (!mdp) { + ret = -ENOMEM; + goto err_return; + } + + mdp->pdev = pdev; + mdp->mdp_data = of_device_get_match_data(&pdev->dev); + + mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS); + if (!mm_pdev) { + ret = -ENODEV; + goto err_return; + } + mdp->mdp_mmsys = &mm_pdev->dev; + + mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX); + if (WARN_ON(!mm_pdev)) { + ret = -ENODEV; + goto err_return; + } + for (i = 0; i < MDP_PIPE_MAX; i++) { + mdp->mdp_mutex[i] = mtk_mutex_get(&mm_pdev->dev); + if (!mdp->mdp_mutex[i]) { + ret = -ENODEV; + goto err_return; + } + } + + ret = mdp_comp_config(mdp); + if (ret) { + dev_err(dev, "Failed to config mdp components\n"); + goto err_return; + } + + mdp->job_wq = alloc_workqueue(MDP_MODULE_NAME, WQ_FREEZABLE, 0); + if (!mdp->job_wq) { + dev_err(dev, "Unable to create job workqueue\n"); + ret = -ENOMEM; + goto err_deinit_comp; + } + + mdp->clock_wq = alloc_workqueue(MDP_MODULE_NAME "-clock", WQ_FREEZABLE, + 0); + if (!mdp->clock_wq) { + dev_err(dev, "Unable to create clock workqueue\n"); + ret = -ENOMEM; + goto err_destroy_job_wq; + } + + mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP); + if (WARN_ON(!mm_pdev)) { + dev_err(&pdev->dev, "Could not get scp device\n"); + ret = -ENODEV; + goto err_destroy_clock_wq; + } + mdp->scp = platform_get_drvdata(mm_pdev); + mdp->rproc_handle = scp_get_rproc(mdp->scp); + dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle); + + mutex_init(&mdp->vpu_lock); + mutex_init(&mdp->m2m_lock); + + mdp->cmdq_clt = cmdq_mbox_create(dev, 0); + if (IS_ERR(mdp->cmdq_clt)) { + ret = PTR_ERR(mdp->cmdq_clt); + goto err_put_scp; + } + + init_waitqueue_head(&mdp->callback_wq); + ida_init(&mdp->mdp_ida); + platform_set_drvdata(pdev, mdp); + + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + + ret = v4l2_device_register(dev, &mdp->v4l2_dev); + if (ret) { + dev_err(dev, "Failed to register v4l2 device\n"); + ret = -EINVAL; + goto err_mbox_destroy; + } + + ret = mdp_m2m_device_register(mdp); + if (ret) { + v4l2_err(&mdp->v4l2_dev, "Failed to register m2m device\n"); + goto err_unregister_device; + } + + dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id); + return 0; + +err_unregister_device: + v4l2_device_unregister(&mdp->v4l2_dev); +err_mbox_destroy: + cmdq_mbox_destroy(mdp->cmdq_clt); +err_put_scp: + scp_put(mdp->scp); +err_destroy_clock_wq: + destroy_workqueue(mdp->clock_wq); +err_destroy_job_wq: + destroy_workqueue(mdp->job_wq); +err_deinit_comp: + mdp_comp_destroy(mdp); +err_return: + for (i = 0; i < MDP_PIPE_MAX; i++) + if (mdp) + mtk_mutex_put(mdp->mdp_mutex[i]); + kfree(mdp); + dev_dbg(dev, "Errno %d\n", ret); + return ret; +} + +static int mdp_remove(struct platform_device *pdev) +{ + struct mdp_dev *mdp = platform_get_drvdata(pdev); + + v4l2_device_unregister(&mdp->v4l2_dev); + + dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); + return 0; +} + +static int __maybe_unused mdp_suspend(struct device *dev) +{ + struct mdp_dev *mdp = dev_get_drvdata(dev); + int ret; + + atomic_set(&mdp->suspended, 1); + + if (atomic_read(&mdp->job_count)) { + ret = wait_event_timeout(mdp->callback_wq, + !atomic_read(&mdp->job_count), + 2 * HZ); + if (ret == 0) { + dev_err(dev, + "%s:flushed cmdq task incomplete, count=%d\n", + __func__, atomic_read(&mdp->job_count)); + return -EBUSY; + } + } + + return 0; +} + +static int __maybe_unused mdp_resume(struct device *dev) +{ + struct mdp_dev *mdp = dev_get_drvdata(dev); + + atomic_set(&mdp->suspended, 0); + + return 0; +} + +static const struct dev_pm_ops mdp_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mdp_suspend, mdp_resume) +}; + +static struct platform_driver mdp_driver = { + .probe = mdp_probe, + .remove = mdp_remove, + .driver = { + .name = MDP_MODULE_NAME, + .pm = &mdp_pm_ops, + .of_match_table = of_match_ptr(mdp_of_ids), + }, +}; + +module_platform_driver(mdp_driver); + +MODULE_AUTHOR("Ping-Hsun Wu <ping-hsun.wu@mediatek.com>"); +MODULE_DESCRIPTION("MediaTek image processor 3 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h new file mode 100644 index 000000000000..2ef5fbc4f25a --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_CORE_H__ +#define __MTK_MDP3_CORE_H__ + +#include <media/v4l2-device.h> +#include <media/v4l2-mem2mem.h> +#include <linux/soc/mediatek/mtk-mmsys.h> +#include <linux/soc/mediatek/mtk-mutex.h> +#include "mtk-mdp3-comp.h" +#include "mtk-mdp3-vpu.h" + +#define MDP_MODULE_NAME "mtk-mdp3" +#define MDP_DEVICE_NAME "MediaTek MDP3" +#define MDP_PHANDLE_NAME "mediatek,mdp3" + +enum mdp_infra_id { + MDP_INFRA_MMSYS, + MDP_INFRA_MUTEX, + MDP_INFRA_SCP, + MDP_INFRA_MAX +}; + +enum mdp_buffer_usage { + MDP_BUFFER_USAGE_HW_READ, + MDP_BUFFER_USAGE_MDP, + MDP_BUFFER_USAGE_MDP2, + MDP_BUFFER_USAGE_ISP, + MDP_BUFFER_USAGE_WPE, +}; + +struct mdp_platform_config { + bool rdma_support_10bit; + bool rdma_rsz1_sram_sharing; + bool rdma_upsample_repeat_only; + bool rsz_disable_dcm_small_sample; + bool wrot_filter_constraint; +}; + +/* indicate which mutex is used by each pipepline */ +enum mdp_pipe_id { + MDP_PIPE_RDMA0, + MDP_PIPE_IMGI, + MDP_PIPE_WPEI, + MDP_PIPE_WPEI2, + MDP_PIPE_MAX +}; + +struct mtk_mdp_driver_data { + const struct of_device_id *mdp_probe_infra; + const struct mdp_platform_config *mdp_cfg; + const u32 *mdp_mutex_table_idx; +}; + +struct mdp_dev { + struct platform_device *pdev; + struct device *mdp_mmsys; + struct mtk_mutex *mdp_mutex[MDP_PIPE_MAX]; + struct mdp_comp *comp[MDP_MAX_COMP_COUNT]; + const struct mtk_mdp_driver_data *mdp_data; + + struct workqueue_struct *job_wq; + struct workqueue_struct *clock_wq; + struct mdp_vpu_dev vpu; + struct mtk_scp *scp; + struct rproc *rproc_handle; + /* synchronization protect for accessing vpu working buffer info */ + struct mutex vpu_lock; + s32 vpu_count; + u32 id_count; + struct ida mdp_ida; + struct cmdq_client *cmdq_clt; + wait_queue_head_t callback_wq; + + struct v4l2_device v4l2_dev; + struct video_device *m2m_vdev; + struct v4l2_m2m_dev *m2m_dev; + /* synchronization protect for m2m device operation */ + struct mutex m2m_lock; + atomic_t suspended; + atomic_t job_count; +}; + +int mdp_vpu_get_locked(struct mdp_dev *mdp); +void mdp_vpu_put_locked(struct mdp_dev *mdp); +int mdp_vpu_register(struct mdp_dev *mdp); +void mdp_vpu_unregister(struct mdp_dev *mdp); +void mdp_video_device_release(struct video_device *vdev); + +#endif /* __MTK_MDP3_CORE_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c new file mode 100644 index 000000000000..5f74ea3b7a52 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -0,0 +1,724 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <linux/platform_device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-dma-contig.h> +#include "mtk-mdp3-m2m.h" + +static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct mdp_m2m_ctx, fh); +} + +static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mdp_m2m_ctx, ctrl_handler); +} + +static inline struct mdp_frame *ctx_get_frame(struct mdp_m2m_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->curr_param.output; + else + return &ctx->curr_param.captures[0]; +} + +static inline void mdp_m2m_ctx_set_state(struct mdp_m2m_ctx *ctx, u32 state) +{ + atomic_or(state, &ctx->curr_param.state); +} + +static inline bool mdp_m2m_ctx_is_state_set(struct mdp_m2m_ctx *ctx, u32 mask) +{ + return ((atomic_read(&ctx->curr_param.state) & mask) == mask); +} + +static void mdp_m2m_process_done(void *priv, int vb_state) +{ + struct mdp_m2m_ctx *ctx = priv; + struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; + + src_vbuf = (struct vb2_v4l2_buffer *) + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst_vbuf = (struct vb2_v4l2_buffer *) + v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC]; + src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++; + dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++; + v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true); + + v4l2_m2m_buf_done(src_vbuf, vb_state); + v4l2_m2m_buf_done(dst_vbuf, vb_state); + v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx); +} + +static void mdp_m2m_device_run(void *priv) +{ + struct mdp_m2m_ctx *ctx = priv; + struct mdp_frame *frame; + struct vb2_v4l2_buffer *src_vb, *dst_vb; + struct img_ipi_frameparam param = {}; + struct mdp_cmdq_param task = {}; + enum vb2_buffer_state vb_state = VB2_BUF_STATE_ERROR; + int ret; + + if (mdp_m2m_ctx_is_state_set(ctx, MDP_M2M_CTX_ERROR)) { + dev_err(&ctx->mdp_dev->pdev->dev, + "mdp_m2m_ctx is in error state\n"); + goto worker_end; + } + + param.frame_no = ctx->curr_param.frame_no; + param.type = ctx->curr_param.type; + param.num_inputs = 1; + param.num_outputs = 1; + + frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + mdp_set_src_config(¶m.inputs[0], frame, &src_vb->vb2_buf); + + frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + mdp_set_dst_config(¶m.outputs[0], frame, &dst_vb->vb2_buf); + + ret = mdp_vpu_process(&ctx->vpu, ¶m); + if (ret) { + dev_err(&ctx->mdp_dev->pdev->dev, + "VPU MDP process failed: %d\n", ret); + goto worker_end; + } + + task.config = ctx->vpu.config; + task.param = ¶m; + task.composes[0] = &frame->compose; + task.cmdq_cb = NULL; + task.cb_data = NULL; + task.mdp_ctx = ctx; + + ret = mdp_cmdq_send(ctx->mdp_dev, &task); + if (ret) { + dev_err(&ctx->mdp_dev->pdev->dev, + "CMDQ sendtask failed: %d\n", ret); + goto worker_end; + } + + return; + +worker_end: + mdp_m2m_process_done(ctx, vb_state); +} + +static int mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); + struct mdp_frame *capture; + struct vb2_queue *vq; + int ret; + bool out_streaming, cap_streaming; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->frame_count[MDP_M2M_SRC] = 0; + + if (V4L2_TYPE_IS_CAPTURE(q->type)) + ctx->frame_count[MDP_M2M_DST] = 0; + + capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + vq = v4l2_m2m_get_src_vq(ctx->m2m_ctx); + out_streaming = vb2_is_streaming(vq); + vq = v4l2_m2m_get_dst_vq(ctx->m2m_ctx); + cap_streaming = vb2_is_streaming(vq); + + /* Check to see if scaling ratio is within supported range */ + if ((V4L2_TYPE_IS_OUTPUT(q->type) && cap_streaming) || + (V4L2_TYPE_IS_CAPTURE(q->type) && out_streaming)) { + ret = mdp_check_scaling_ratio(&capture->crop.c, + &capture->compose, + capture->rotation, + ctx->curr_param.limit); + if (ret) { + dev_err(&ctx->mdp_dev->pdev->dev, + "Out of scaling range\n"); + return ret; + } + } + + if (!mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) { + ret = mdp_vpu_get_locked(ctx->mdp_dev); + if (ret) + return ret; + + ret = mdp_vpu_ctx_init(&ctx->vpu, &ctx->mdp_dev->vpu, + MDP_DEV_M2M); + if (ret) { + dev_err(&ctx->mdp_dev->pdev->dev, + "VPU init failed %d\n", ret); + return -EINVAL; + } + mdp_m2m_ctx_set_state(ctx, MDP_VPU_INIT); + } + + return 0; +} + +static struct vb2_v4l2_buffer *mdp_m2m_buf_remove(struct mdp_m2m_ctx *ctx, + unsigned int type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return (struct vb2_v4l2_buffer *) + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + else + return (struct vb2_v4l2_buffer *) + v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); +} + +static void mdp_m2m_stop_streaming(struct vb2_queue *q) +{ + struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vb; + + vb = mdp_m2m_buf_remove(ctx, q->type); + while (vb) { + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + vb = mdp_m2m_buf_remove(ctx, q->type); + } +} + +static int mdp_m2m_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(q); + struct v4l2_pix_format_mplane *pix_mp; + u32 i; + + pix_mp = &ctx_get_frame(ctx, q->type)->format.fmt.pix_mp; + + /* from VIDIOC_CREATE_BUFS */ + if (*num_planes) { + if (*num_planes != pix_mp->num_planes) + return -EINVAL; + for (i = 0; i < pix_mp->num_planes; ++i) + if (sizes[i] < pix_mp->plane_fmt[i].sizeimage) + return -EINVAL; + } else {/* from VIDIOC_REQBUFS */ + *num_planes = pix_mp->num_planes; + for (i = 0; i < pix_mp->num_planes; ++i) + sizes[i] = pix_mp->plane_fmt[i].sizeimage; + } + + return 0; +} + +static int mdp_m2m_buf_prepare(struct vb2_buffer *vb) +{ + struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format_mplane *pix_mp; + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); + u32 i; + + v4l2_buf->field = V4L2_FIELD_NONE; + + if (V4L2_TYPE_IS_CAPTURE(vb->type)) { + pix_mp = &ctx_get_frame(ctx, vb->type)->format.fmt.pix_mp; + for (i = 0; i < pix_mp->num_planes; ++i) { + vb2_set_plane_payload(vb, i, + pix_mp->plane_fmt[i].sizeimage); + } + } + return 0; +} + +static int mdp_m2m_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); + + v4l2_buf->field = V4L2_FIELD_NONE; + + return 0; +} + +static void mdp_m2m_buf_queue(struct vb2_buffer *vb) +{ + struct mdp_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); + + v4l2_buf->field = V4L2_FIELD_NONE; + + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); +} + +static const struct vb2_ops mdp_m2m_qops = { + .queue_setup = mdp_m2m_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = mdp_m2m_buf_prepare, + .start_streaming = mdp_m2m_start_streaming, + .stop_streaming = mdp_m2m_stop_streaming, + .buf_queue = mdp_m2m_buf_queue, + .buf_out_validate = mdp_m2m_buf_out_validate, +}; + +static int mdp_m2m_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, MDP_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, MDP_DEVICE_NAME, sizeof(cap->card)); + + return 0; +} + +static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + return mdp_enum_fmt_mplane(f); +} + +static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_frame *frame; + struct v4l2_pix_format_mplane *pix_mp; + + frame = ctx_get_frame(ctx, f->type); + *f = frame->format; + pix_mp = &f->fmt.pix_mp; + pix_mp->colorspace = ctx->curr_param.colorspace; + pix_mp->xfer_func = ctx->curr_param.xfer_func; + pix_mp->ycbcr_enc = ctx->curr_param.ycbcr_enc; + pix_mp->quantization = ctx->curr_param.quant; + + return 0; +} + +static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_frame *frame = ctx_get_frame(ctx, f->type); + struct mdp_frame *capture; + const struct mdp_format *fmt; + struct vb2_queue *vq; + + fmt = mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id); + if (!fmt) + return -EINVAL; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + frame->format = *f; + frame->mdp_fmt = fmt; + frame->ycbcr_prof = mdp_map_ycbcr_prof_mplane(f, fmt->mdp_color); + frame->usage = V4L2_TYPE_IS_OUTPUT(f->type) ? + MDP_BUFFER_USAGE_HW_READ : MDP_BUFFER_USAGE_MDP; + + capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + capture->crop.c.left = 0; + capture->crop.c.top = 0; + capture->crop.c.width = f->fmt.pix_mp.width; + capture->crop.c.height = f->fmt.pix_mp.height; + ctx->curr_param.colorspace = f->fmt.pix_mp.colorspace; + ctx->curr_param.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + ctx->curr_param.quant = f->fmt.pix_mp.quantization; + ctx->curr_param.xfer_func = f->fmt.pix_mp.xfer_func; + } else { + capture->compose.left = 0; + capture->compose.top = 0; + capture->compose.width = f->fmt.pix_mp.width; + capture->compose.height = f->fmt.pix_mp.height; + } + + return 0; +} + +static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + + if (!mdp_try_fmt_mplane(f, &ctx->curr_param, ctx->id)) + return -EINVAL; + + return 0; +} + +static int mdp_m2m_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_frame *frame; + bool valid = false; + + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + valid = mdp_target_is_crop(s->target); + else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + valid = mdp_target_is_compose(s->target); + + if (!valid) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + s->r = frame->crop.c; + return 0; + case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + frame = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + s->r = frame->compose; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + frame = ctx_get_frame(ctx, s->type); + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->format.fmt.pix_mp.width; + s->r.height = frame->format.fmt.pix_mp.height; + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + frame = ctx_get_frame(ctx, s->type); + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->format.fmt.pix_mp.width; + s->r.height = frame->format.fmt.pix_mp.height; + return 0; + } + return -EINVAL; +} + +static int mdp_m2m_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_frame *frame = ctx_get_frame(ctx, s->type); + struct mdp_frame *capture; + struct v4l2_rect r; + struct device *dev = &ctx->mdp_dev->pdev->dev; + bool valid = false; + int ret; + + if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + valid = (s->target == V4L2_SEL_TGT_CROP); + else if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + valid = (s->target == V4L2_SEL_TGT_COMPOSE); + + if (!valid) { + dev_dbg(dev, "[%s:%d] invalid type:%u target:%u", __func__, + ctx->id, s->type, s->target); + return -EINVAL; + } + + ret = mdp_try_crop(ctx, &r, s, frame); + if (ret) + return ret; + capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + if (mdp_target_is_crop(s->target)) + capture->crop.c = r; + else + capture->compose = r; + + s->r = r; + + return 0; +} + +static const struct v4l2_ioctl_ops mdp_m2m_ioctl_ops = { + .vidioc_querycap = mdp_m2m_querycap, + .vidioc_enum_fmt_vid_cap = mdp_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_out = mdp_m2m_enum_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = mdp_m2m_g_fmt_mplane, + .vidioc_g_fmt_vid_out_mplane = mdp_m2m_g_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = mdp_m2m_s_fmt_mplane, + .vidioc_s_fmt_vid_out_mplane = mdp_m2m_s_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = mdp_m2m_try_fmt_mplane, + .vidioc_try_fmt_vid_out_mplane = mdp_m2m_try_fmt_mplane, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_g_selection = mdp_m2m_g_selection, + .vidioc_s_selection = mdp_m2m_s_selection, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int mdp_m2m_queue_init(void *priv, + struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct mdp_m2m_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->ops = &mdp_m2m_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->dev = &ctx->mdp_dev->pdev->dev; + src_vq->lock = &ctx->ctx_lock; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->ops = &mdp_m2m_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->dev = &ctx->mdp_dev->pdev->dev; + dst_vq->lock = &ctx->ctx_lock; + + return vb2_queue_init(dst_vq); +} + +static int mdp_m2m_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mdp_m2m_ctx *ctx = ctrl_to_ctx(ctrl); + struct mdp_frame *capture; + + capture = ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + switch (ctrl->id) { + case V4L2_CID_HFLIP: + capture->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + capture->vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + capture->rotation = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops mdp_m2m_ctrl_ops = { + .s_ctrl = mdp_m2m_s_ctrl, +}; + +static int mdp_m2m_ctrls_create(struct mdp_m2m_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrl_handler, MDP_MAX_CTRLS); + ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mdp_m2m_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mdp_m2m_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mdp_m2m_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + dev_err(&ctx->mdp_dev->pdev->dev, + "Failed to register controls\n"); + return err; + } + return 0; +} + +static int mdp_m2m_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct mdp_dev *mdp = video_get_drvdata(vdev); + struct mdp_m2m_ctx *ctx; + struct device *dev = &mdp->pdev->dev; + int ret; + struct v4l2_format default_format = {}; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (mutex_lock_interruptible(&mdp->m2m_lock)) { + ret = -ERESTARTSYS; + goto err_free_ctx; + } + + ctx->id = ida_alloc(&mdp->mdp_ida, GFP_KERNEL); + ctx->mdp_dev = mdp; + + v4l2_fh_init(&ctx->fh, vdev); + file->private_data = &ctx->fh; + ret = mdp_m2m_ctrls_create(ctx); + if (ret) + goto err_exit_fh; + + /* Use separate control handler per file handle */ + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + v4l2_fh_add(&ctx->fh); + + mutex_init(&ctx->ctx_lock); + ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + dev_err(dev, "Failed to initialize m2m context\n"); + ret = PTR_ERR(ctx->m2m_ctx); + goto err_release_handler; + } + ctx->fh.m2m_ctx = ctx->m2m_ctx; + + ctx->curr_param.ctx = ctx; + ret = mdp_frameparam_init(&ctx->curr_param); + if (ret) { + dev_err(dev, "Failed to initialize mdp parameter\n"); + goto err_release_m2m_ctx; + } + + mutex_unlock(&mdp->m2m_lock); + + /* Default format */ + default_format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + default_format.fmt.pix_mp.width = 32; + default_format.fmt.pix_mp.height = 32; + default_format.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420M; + mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); + default_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + mdp_m2m_s_fmt_mplane(file, &ctx->fh, &default_format); + + dev_dbg(dev, "%s:[%d]", __func__, ctx->id); + + return 0; + +err_release_m2m_ctx: + v4l2_m2m_ctx_release(ctx->m2m_ctx); +err_release_handler: + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); +err_exit_fh: + v4l2_fh_exit(&ctx->fh); + mutex_unlock(&mdp->m2m_lock); +err_free_ctx: + kfree(ctx); + + return ret; +} + +static int mdp_m2m_release(struct file *file) +{ + struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data); + struct mdp_dev *mdp = video_drvdata(file); + struct device *dev = &mdp->pdev->dev; + + mutex_lock(&mdp->m2m_lock); + v4l2_m2m_ctx_release(ctx->m2m_ctx); + if (mdp_m2m_ctx_is_state_set(ctx, MDP_VPU_INIT)) { + mdp_vpu_ctx_deinit(&ctx->vpu); + mdp_vpu_put_locked(mdp); + } + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + ida_free(&mdp->mdp_ida, ctx->id); + mutex_unlock(&mdp->m2m_lock); + + dev_dbg(dev, "%s:[%d]", __func__, ctx->id); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations mdp_m2m_fops = { + .owner = THIS_MODULE, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, + .open = mdp_m2m_open, + .release = mdp_m2m_release, +}; + +static const struct v4l2_m2m_ops mdp_m2m_ops = { + .device_run = mdp_m2m_device_run, +}; + +int mdp_m2m_device_register(struct mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + int ret = 0; + + mdp->m2m_vdev = video_device_alloc(); + if (!mdp->m2m_vdev) { + dev_err(dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_video_alloc; + } + mdp->m2m_vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | + V4L2_CAP_STREAMING; + mdp->m2m_vdev->fops = &mdp_m2m_fops; + mdp->m2m_vdev->ioctl_ops = &mdp_m2m_ioctl_ops; + mdp->m2m_vdev->release = mdp_video_device_release; + mdp->m2m_vdev->lock = &mdp->m2m_lock; + mdp->m2m_vdev->vfl_dir = VFL_DIR_M2M; + mdp->m2m_vdev->v4l2_dev = &mdp->v4l2_dev; + snprintf(mdp->m2m_vdev->name, sizeof(mdp->m2m_vdev->name), "%s:m2m", + MDP_MODULE_NAME); + video_set_drvdata(mdp->m2m_vdev, mdp); + + mdp->m2m_dev = v4l2_m2m_init(&mdp_m2m_ops); + if (IS_ERR(mdp->m2m_dev)) { + dev_err(dev, "Failed to initialize v4l2-m2m device\n"); + ret = PTR_ERR(mdp->m2m_dev); + goto err_m2m_init; + } + + ret = video_register_device(mdp->m2m_vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(dev, "Failed to register video device\n"); + goto err_video_register; + } + + v4l2_info(&mdp->v4l2_dev, "Driver registered as /dev/video%d", + mdp->m2m_vdev->num); + return 0; + +err_video_register: + v4l2_m2m_release(mdp->m2m_dev); +err_m2m_init: + video_device_release(mdp->m2m_vdev); +err_video_alloc: + + return ret; +} + +void mdp_m2m_device_unregister(struct mdp_dev *mdp) +{ + video_unregister_device(mdp->m2m_vdev); +} + +void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx) +{ + enum vb2_buffer_state vb_state = VB2_BUF_STATE_DONE; + + mdp_m2m_process_done(ctx, vb_state); +} diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h new file mode 100644 index 000000000000..61ddbaf1bf13 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_M2M_H__ +#define __MTK_MDP3_M2M_H__ + +#include <media/v4l2-ctrls.h> +#include "mtk-mdp3-core.h" +#include "mtk-mdp3-vpu.h" +#include "mtk-mdp3-regs.h" + +#define MDP_MAX_CTRLS 10 + +enum { + MDP_M2M_SRC = 0, + MDP_M2M_DST = 1, + MDP_M2M_MAX, +}; + +struct mdp_m2m_ctrls { + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *rotate; +}; + +struct mdp_m2m_ctx { + u32 id; + struct mdp_dev *mdp_dev; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + struct mdp_m2m_ctrls ctrls; + struct v4l2_m2m_ctx *m2m_ctx; + struct mdp_vpu_ctx vpu; + u32 frame_count[MDP_M2M_MAX]; + + struct mdp_frameparam curr_param; + /* synchronization protect for mdp m2m context */ + struct mutex ctx_lock; +}; + +int mdp_m2m_device_register(struct mdp_dev *mdp); +void mdp_m2m_device_unregister(struct mdp_dev *mdp); +void mdp_m2m_job_finish(struct mdp_m2m_ctx *ctx); + +#endif /* __MTK_MDP3_M2M_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c new file mode 100644 index 000000000000..4e84a37ecdfc --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c @@ -0,0 +1,735 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <media/v4l2-common.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-contig.h> +#include "mtk-mdp3-core.h" +#include "mtk-mdp3-regs.h" +#include "mtk-mdp3-m2m.h" + +/* + * All 10-bit related formats are not added in the basic format list, + * please add the corresponding format settings before use. + */ +static const struct mdp_format mdp_formats[] = { + { + .pixelformat = V4L2_PIX_FMT_GREY, + .mdp_color = MDP_COLOR_GREY, + .depth = { 8 }, + .row_depth = { 8 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB565X, + .mdp_color = MDP_COLOR_BGR565, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB565, + .mdp_color = MDP_COLOR_RGB565, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB24, + .mdp_color = MDP_COLOR_RGB888, + .depth = { 24 }, + .row_depth = { 24 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_BGR24, + .mdp_color = MDP_COLOR_BGR888, + .depth = { 24 }, + .row_depth = { 24 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_ABGR32, + .mdp_color = MDP_COLOR_BGRA8888, + .depth = { 32 }, + .row_depth = { 32 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_ARGB32, + .mdp_color = MDP_COLOR_ARGB8888, + .depth = { 32 }, + .row_depth = { 32 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_UYVY, + .mdp_color = MDP_COLOR_UYVY, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_VYUY, + .mdp_color = MDP_COLOR_VYUY, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUYV, + .mdp_color = MDP_COLOR_YUYV, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVYU, + .mdp_color = MDP_COLOR_YVYU, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUV420, + .mdp_color = MDP_COLOR_I420, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU420, + .mdp_color = MDP_COLOR_YV12, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV12, + .mdp_color = MDP_COLOR_NV12, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV21, + .mdp_color = MDP_COLOR_NV21, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV16, + .mdp_color = MDP_COLOR_NV16, + .depth = { 16 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV61, + .mdp_color = MDP_COLOR_NV61, + .depth = { 16 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV24, + .mdp_color = MDP_COLOR_NV24, + .depth = { 24 }, + .row_depth = { 8 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV42, + .mdp_color = MDP_COLOR_NV42, + .depth = { 24 }, + .row_depth = { 8 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_MT21C, + .mdp_color = MDP_COLOR_420_BLK_UFO, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 4, + .halign = 5, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_MM21, + .mdp_color = MDP_COLOR_420_BLK, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 4, + .halign = 5, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV12M, + .mdp_color = MDP_COLOR_NV12, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV21M, + .mdp_color = MDP_COLOR_NV21, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV16M, + .mdp_color = MDP_COLOR_NV16, + .depth = { 8, 8 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV61M, + .mdp_color = MDP_COLOR_NV61, + .depth = { 8, 8 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_YUV420M, + .mdp_color = MDP_COLOR_I420, + .depth = { 8, 2, 2 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU420M, + .mdp_color = MDP_COLOR_YV12, + .depth = { 8, 2, 2 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + } +}; + +static const struct mdp_limit mdp_def_limit = { + .out_limit = { + .wmin = 16, + .hmin = 16, + .wmax = 8176, + .hmax = 8176, + }, + .cap_limit = { + .wmin = 2, + .hmin = 2, + .wmax = 8176, + .hmax = 8176, + }, + .h_scale_up_max = 32, + .v_scale_up_max = 32, + .h_scale_down_max = 20, + .v_scale_down_max = 128, +}; + +static const struct mdp_format *mdp_find_fmt(u32 pixelformat, u32 type) +{ + u32 i, flag; + + flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : + MDP_FMT_FLAG_CAPTURE; + for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) { + if (!(mdp_formats[i].flags & flag)) + continue; + if (mdp_formats[i].pixelformat == pixelformat) + return &mdp_formats[i]; + } + return NULL; +} + +static const struct mdp_format *mdp_find_fmt_by_index(u32 index, u32 type) +{ + u32 i, flag, num = 0; + + flag = V4L2_TYPE_IS_OUTPUT(type) ? MDP_FMT_FLAG_OUTPUT : + MDP_FMT_FLAG_CAPTURE; + for (i = 0; i < ARRAY_SIZE(mdp_formats); ++i) { + if (!(mdp_formats[i].flags & flag)) + continue; + if (index == num) + return &mdp_formats[i]; + num++; + } + return NULL; +} + +enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f, + u32 mdp_color) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + + if (MDP_COLOR_IS_RGB(mdp_color)) + return MDP_YCBCR_PROFILE_FULL_BT601; + + switch (pix_mp->colorspace) { + case V4L2_COLORSPACE_JPEG: + return MDP_YCBCR_PROFILE_JPEG; + case V4L2_COLORSPACE_REC709: + case V4L2_COLORSPACE_DCI_P3: + if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) + return MDP_YCBCR_PROFILE_FULL_BT709; + return MDP_YCBCR_PROFILE_BT709; + case V4L2_COLORSPACE_BT2020: + if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) + return MDP_YCBCR_PROFILE_FULL_BT2020; + return MDP_YCBCR_PROFILE_BT2020; + default: + if (pix_mp->quantization == V4L2_QUANTIZATION_FULL_RANGE) + return MDP_YCBCR_PROFILE_FULL_BT601; + return MDP_YCBCR_PROFILE_BT601; + } +} + +static void mdp_bound_align_image(u32 *w, u32 *h, + struct v4l2_frmsize_stepwise *s, + unsigned int salign) +{ + unsigned int org_w, org_h; + + org_w = *w; + org_h = *h; + v4l_bound_align_image(w, s->min_width, s->max_width, s->step_width, + h, s->min_height, s->max_height, s->step_height, + salign); + + s->min_width = org_w; + s->min_height = org_h; + v4l2_apply_frmsize_constraints(w, h, s); +} + +static int mdp_clamp_align(s32 *x, int min, int max, unsigned int align) +{ + unsigned int mask; + + if (min < 0 || max < 0) + return -ERANGE; + + /* Bits that must be zero to be aligned */ + mask = ~((1 << align) - 1); + + min = 0 ? 0 : ((min + ~mask) & mask); + max = max & mask; + if ((unsigned int)min > (unsigned int)max) + return -ERANGE; + + /* Clamp to aligned min and max */ + *x = clamp(*x, min, max); + + /* Round to nearest aligned value */ + if (align) + *x = (*x + (1 << (align - 1))) & mask; + return 0; +} + +int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f) +{ + const struct mdp_format *fmt; + + fmt = mdp_find_fmt_by_index(f->index, f->type); + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixelformat; + return 0; +} + +const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f, + struct mdp_frameparam *param, + u32 ctx_id) +{ + struct device *dev = ¶m->ctx->mdp_dev->pdev->dev; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct mdp_format *fmt; + const struct mdp_pix_limit *pix_limit; + struct v4l2_frmsize_stepwise s; + u32 org_w, org_h; + unsigned int i; + + fmt = mdp_find_fmt(pix_mp->pixelformat, f->type); + if (!fmt) { + fmt = mdp_find_fmt_by_index(0, f->type); + if (!fmt) { + dev_dbg(dev, "%d: pixelformat %c%c%c%c invalid", ctx_id, + (pix_mp->pixelformat & 0xff), + (pix_mp->pixelformat >> 8) & 0xff, + (pix_mp->pixelformat >> 16) & 0xff, + (pix_mp->pixelformat >> 24) & 0xff); + return NULL; + } + } + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->flags = 0; + pix_mp->pixelformat = fmt->pixelformat; + if (V4L2_TYPE_IS_CAPTURE(f->type)) { + pix_mp->colorspace = param->colorspace; + pix_mp->xfer_func = param->xfer_func; + pix_mp->ycbcr_enc = param->ycbcr_enc; + pix_mp->quantization = param->quant; + } + + pix_limit = V4L2_TYPE_IS_OUTPUT(f->type) ? ¶m->limit->out_limit : + ¶m->limit->cap_limit; + s.min_width = pix_limit->wmin; + s.max_width = pix_limit->wmax; + s.step_width = fmt->walign; + s.min_height = pix_limit->hmin; + s.max_height = pix_limit->hmax; + s.step_height = fmt->halign; + org_w = pix_mp->width; + org_h = pix_mp->height; + + mdp_bound_align_image(&pix_mp->width, &pix_mp->height, &s, fmt->salign); + if (org_w != pix_mp->width || org_h != pix_mp->height) + dev_dbg(dev, "%d: size change: %ux%u to %ux%u", ctx_id, + org_w, org_h, pix_mp->width, pix_mp->height); + + if (pix_mp->num_planes && pix_mp->num_planes != fmt->num_planes) + dev_dbg(dev, "%d num of planes change: %u to %u", ctx_id, + pix_mp->num_planes, fmt->num_planes); + pix_mp->num_planes = fmt->num_planes; + + for (i = 0; i < pix_mp->num_planes; ++i) { + u32 min_bpl = (pix_mp->width * fmt->row_depth[i]) >> 3; + u32 max_bpl = (pix_limit->wmax * fmt->row_depth[i]) >> 3; + u32 bpl = pix_mp->plane_fmt[i].bytesperline; + u32 min_si, max_si; + u32 si = pix_mp->plane_fmt[i].sizeimage; + + bpl = clamp(bpl, min_bpl, max_bpl); + pix_mp->plane_fmt[i].bytesperline = bpl; + + min_si = (bpl * pix_mp->height * fmt->depth[i]) / + fmt->row_depth[i]; + max_si = (bpl * s.max_height * fmt->depth[i]) / + fmt->row_depth[i]; + + si = clamp(si, min_si, max_si); + pix_mp->plane_fmt[i].sizeimage = si; + + dev_dbg(dev, "%d: p%u, bpl:%u [%u, %u], sizeimage:%u [%u, %u]", + ctx_id, i, bpl, min_bpl, max_bpl, si, min_si, max_si); + } + + return fmt; +} + +static int mdp_clamp_start(s32 *x, int min, int max, unsigned int align, + u32 flags) +{ + if (flags & V4L2_SEL_FLAG_GE) + max = *x; + if (flags & V4L2_SEL_FLAG_LE) + min = *x; + return mdp_clamp_align(x, min, max, align); +} + +static int mdp_clamp_end(s32 *x, int min, int max, unsigned int align, + u32 flags) +{ + if (flags & V4L2_SEL_FLAG_GE) + min = *x; + if (flags & V4L2_SEL_FLAG_LE) + max = *x; + return mdp_clamp_align(x, min, max, align); +} + +int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r, + const struct v4l2_selection *s, struct mdp_frame *frame) +{ + struct device *dev = &ctx->mdp_dev->pdev->dev; + s32 left, top, right, bottom; + u32 framew, frameh, walign, halign; + int ret; + + dev_dbg(dev, "%d target:%d, set:(%d,%d) %ux%u", ctx->id, + s->target, s->r.left, s->r.top, s->r.width, s->r.height); + + left = s->r.left; + top = s->r.top; + right = s->r.left + s->r.width; + bottom = s->r.top + s->r.height; + framew = frame->format.fmt.pix_mp.width; + frameh = frame->format.fmt.pix_mp.height; + + if (mdp_target_is_crop(s->target)) { + walign = 1; + halign = 1; + } else { + walign = frame->mdp_fmt->walign; + halign = frame->mdp_fmt->halign; + } + + dev_dbg(dev, "%d align:%u,%u, bound:%ux%u", ctx->id, + walign, halign, framew, frameh); + + ret = mdp_clamp_start(&left, 0, right, walign, s->flags); + if (ret) + return ret; + ret = mdp_clamp_start(&top, 0, bottom, halign, s->flags); + if (ret) + return ret; + ret = mdp_clamp_end(&right, left, framew, walign, s->flags); + if (ret) + return ret; + ret = mdp_clamp_end(&bottom, top, frameh, halign, s->flags); + if (ret) + return ret; + + r->left = left; + r->top = top; + r->width = right - left; + r->height = bottom - top; + + dev_dbg(dev, "%d crop:(%d,%d) %ux%u", ctx->id, + r->left, r->top, r->width, r->height); + return 0; +} + +int mdp_check_scaling_ratio(const struct v4l2_rect *crop, + const struct v4l2_rect *compose, s32 rotation, + const struct mdp_limit *limit) +{ + u32 crop_w, crop_h, comp_w, comp_h; + + crop_w = crop->width; + crop_h = crop->height; + if (90 == rotation || 270 == rotation) { + comp_w = compose->height; + comp_h = compose->width; + } else { + comp_w = compose->width; + comp_h = compose->height; + } + + if ((crop_w / comp_w) > limit->h_scale_down_max || + (crop_h / comp_h) > limit->v_scale_down_max || + (comp_w / crop_w) > limit->h_scale_up_max || + (comp_h / crop_h) > limit->v_scale_up_max) + return -ERANGE; + return 0; +} + +/* Stride that is accepted by MDP HW */ +static u32 mdp_fmt_get_stride(const struct mdp_format *fmt, + u32 bytesperline, unsigned int plane) +{ + enum mdp_color c = fmt->mdp_color; + u32 stride; + + stride = (bytesperline * MDP_COLOR_BITS_PER_PIXEL(c)) + / fmt->row_depth[0]; + if (plane == 0) + return stride; + if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { + if (MDP_COLOR_IS_BLOCK_MODE(c)) + stride = stride / 2; + return stride; + } + return 0; +} + +/* Stride that is accepted by MDP HW of format with contiguous planes */ +static u32 mdp_fmt_get_stride_contig(const struct mdp_format *fmt, + u32 pix_stride, unsigned int plane) +{ + enum mdp_color c = fmt->mdp_color; + u32 stride = pix_stride; + + if (plane == 0) + return stride; + if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { + stride = stride >> MDP_COLOR_GET_H_SUBSAMPLE(c); + if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c)) + stride = stride * 2; + return stride; + } + return 0; +} + +/* Plane size that is accepted by MDP HW */ +static u32 mdp_fmt_get_plane_size(const struct mdp_format *fmt, + u32 stride, u32 height, unsigned int plane) +{ + enum mdp_color c = fmt->mdp_color; + u32 bytesperline; + + bytesperline = (stride * fmt->row_depth[0]) + / MDP_COLOR_BITS_PER_PIXEL(c); + if (plane == 0) + return bytesperline * height; + if (plane < MDP_COLOR_GET_PLANE_COUNT(c)) { + height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c); + if (MDP_COLOR_IS_BLOCK_MODE(c)) + bytesperline = bytesperline * 2; + return bytesperline * height; + } + return 0; +} + +static void mdp_prepare_buffer(struct img_image_buffer *b, + struct mdp_frame *frame, struct vb2_buffer *vb) +{ + struct v4l2_pix_format_mplane *pix_mp = &frame->format.fmt.pix_mp; + unsigned int i; + + b->format.colorformat = frame->mdp_fmt->mdp_color; + b->format.ycbcr_prof = frame->ycbcr_prof; + for (i = 0; i < pix_mp->num_planes; ++i) { + u32 stride = mdp_fmt_get_stride(frame->mdp_fmt, + pix_mp->plane_fmt[i].bytesperline, i); + + b->format.plane_fmt[i].stride = stride; + b->format.plane_fmt[i].size = + mdp_fmt_get_plane_size(frame->mdp_fmt, stride, + pix_mp->height, i); + b->iova[i] = vb2_dma_contig_plane_dma_addr(vb, i); + } + for (; i < MDP_COLOR_GET_PLANE_COUNT(b->format.colorformat); ++i) { + u32 stride = mdp_fmt_get_stride_contig(frame->mdp_fmt, + b->format.plane_fmt[0].stride, i); + + b->format.plane_fmt[i].stride = stride; + b->format.plane_fmt[i].size = + mdp_fmt_get_plane_size(frame->mdp_fmt, stride, + pix_mp->height, i); + b->iova[i] = b->iova[i - 1] + b->format.plane_fmt[i - 1].size; + } + b->usage = frame->usage; +} + +void mdp_set_src_config(struct img_input *in, + struct mdp_frame *frame, struct vb2_buffer *vb) +{ + in->buffer.format.width = frame->format.fmt.pix_mp.width; + in->buffer.format.height = frame->format.fmt.pix_mp.height; + mdp_prepare_buffer(&in->buffer, frame, vb); +} + +static u32 mdp_to_fixed(u32 *r, struct v4l2_fract *f) +{ + u32 q; + + if (f->denominator == 0) { + *r = 0; + return 0; + } + + q = f->numerator / f->denominator; + *r = div_u64(((u64)f->numerator - q * f->denominator) << + IMG_SUBPIXEL_SHIFT, f->denominator); + return q; +} + +static void mdp_set_src_crop(struct img_crop *c, struct mdp_crop *crop) +{ + c->left = crop->c.left + + mdp_to_fixed(&c->left_subpix, &crop->left_subpix); + c->top = crop->c.top + + mdp_to_fixed(&c->top_subpix, &crop->top_subpix); + c->width = crop->c.width + + mdp_to_fixed(&c->width_subpix, &crop->width_subpix); + c->height = crop->c.height + + mdp_to_fixed(&c->height_subpix, &crop->height_subpix); +} + +static void mdp_set_orientation(struct img_output *out, + s32 rotation, bool hflip, bool vflip) +{ + u8 flip = 0; + + if (hflip) + flip ^= 1; + if (vflip) { + /* + * A vertical flip is equivalent to + * a 180-degree rotation with a horizontal flip + */ + rotation += 180; + flip ^= 1; + } + + out->rotation = rotation % 360; + if (flip != 0) + out->flags |= IMG_CTRL_FLAG_HFLIP; + else + out->flags &= ~IMG_CTRL_FLAG_HFLIP; +} + +void mdp_set_dst_config(struct img_output *out, + struct mdp_frame *frame, struct vb2_buffer *vb) +{ + out->buffer.format.width = frame->compose.width; + out->buffer.format.height = frame->compose.height; + mdp_prepare_buffer(&out->buffer, frame, vb); + mdp_set_src_crop(&out->crop, &frame->crop); + mdp_set_orientation(out, frame->rotation, frame->hflip, frame->vflip); +} + +int mdp_frameparam_init(struct mdp_frameparam *param) +{ + struct mdp_frame *frame; + + if (!param) + return -EINVAL; + + INIT_LIST_HEAD(¶m->list); + param->limit = &mdp_def_limit; + param->type = MDP_STREAM_TYPE_BITBLT; + + frame = ¶m->output; + frame->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0); + frame->ycbcr_prof = + mdp_map_ycbcr_prof_mplane(&frame->format, + frame->mdp_fmt->mdp_color); + frame->usage = MDP_BUFFER_USAGE_HW_READ; + + param->num_captures = 1; + frame = ¶m->captures[0]; + frame->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + frame->mdp_fmt = mdp_try_fmt_mplane(&frame->format, param, 0); + frame->ycbcr_prof = + mdp_map_ycbcr_prof_mplane(&frame->format, + frame->mdp_fmt->mdp_color); + frame->usage = MDP_BUFFER_USAGE_MDP; + frame->crop.c.width = param->output.format.fmt.pix_mp.width; + frame->crop.c.height = param->output.format.fmt.pix_mp.height; + frame->compose.width = frame->format.fmt.pix_mp.width; + frame->compose.height = frame->format.fmt.pix_mp.height; + + return 0; +} diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h new file mode 100644 index 000000000000..f995e536d45f --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h @@ -0,0 +1,373 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_REGS_H__ +#define __MTK_MDP3_REGS_H__ + +#include <linux/videodev2.h> +#include <media/videobuf2-core.h> +#include "mtk-img-ipi.h" + +/* + * MDP native color code + * Plane count: 1, 2, 3 + * H-subsample: 0, 1, 2 + * V-subsample: 0, 1 + * Color group: 0-RGB, 1-YUV, 2-raw + */ +#define MDP_COLOR(PACKED, LOOSE, VIDEO, PLANE, HF, VF, BITS, GROUP, SWAP, ID)\ + (((PACKED) << 27) | ((LOOSE) << 26) | ((VIDEO) << 23) |\ + ((PLANE) << 21) | ((HF) << 19) | ((VF) << 18) | ((BITS) << 8) |\ + ((GROUP) << 6) | ((SWAP) << 5) | ((ID) << 0)) + +#define MDP_COLOR_IS_10BIT_PACKED(c) ((0x08000000 & (c)) >> 27) +#define MDP_COLOR_IS_10BIT_LOOSE(c) (((0x0c000000 & (c)) >> 26) == 1) +#define MDP_COLOR_IS_10BIT_TILE(c) (((0x0c000000 & (c)) >> 26) == 3) +#define MDP_COLOR_IS_UFP(c) ((0x02000000 & (c)) >> 25) +#define MDP_COLOR_IS_INTERLACED(c) ((0x01000000 & (c)) >> 24) +#define MDP_COLOR_IS_BLOCK_MODE(c) ((0x00800000 & (c)) >> 23) +#define MDP_COLOR_GET_PLANE_COUNT(c) ((0x00600000 & (c)) >> 21) +#define MDP_COLOR_GET_H_SUBSAMPLE(c) ((0x00180000 & (c)) >> 19) +#define MDP_COLOR_GET_V_SUBSAMPLE(c) ((0x00040000 & (c)) >> 18) +#define MDP_COLOR_BITS_PER_PIXEL(c) ((0x0003ff00 & (c)) >> 8) +#define MDP_COLOR_GET_GROUP(c) ((0x000000c0 & (c)) >> 6) +#define MDP_COLOR_IS_SWAPPED(c) ((0x00000020 & (c)) >> 5) +#define MDP_COLOR_GET_UNIQUE_ID(c) ((0x0000001f & (c)) >> 0) +#define MDP_COLOR_GET_HW_FORMAT(c) ((0x0000001f & (c)) >> 0) + +#define MDP_COLOR_IS_RGB(c) (MDP_COLOR_GET_GROUP(c) == 0) +#define MDP_COLOR_IS_YUV(c) (MDP_COLOR_GET_GROUP(c) == 1) + +enum mdp_color { + MDP_COLOR_UNKNOWN = 0, + + //MDP_COLOR_FULLG8, + MDP_COLOR_FULLG8_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 21), + MDP_COLOR_FULLG8_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 8, 2, 0, 21), + MDP_COLOR_FULLG8_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 8, 2, 0, 21), + MDP_COLOR_FULLG8_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 8, 2, 0, 21), + MDP_COLOR_FULLG8 = MDP_COLOR_FULLG8_BGGR, + + //MDP_COLOR_FULLG10, + MDP_COLOR_FULLG10_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 21), + MDP_COLOR_FULLG10_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2, 0, 21), + MDP_COLOR_FULLG10_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2, 0, 21), + MDP_COLOR_FULLG10_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2, 0, 21), + MDP_COLOR_FULLG10 = MDP_COLOR_FULLG10_BGGR, + + //MDP_COLOR_FULLG12, + MDP_COLOR_FULLG12_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 21), + MDP_COLOR_FULLG12_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2, 0, 21), + MDP_COLOR_FULLG12_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2, 0, 21), + MDP_COLOR_FULLG12_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2, 0, 21), + MDP_COLOR_FULLG12 = MDP_COLOR_FULLG12_BGGR, + + //MDP_COLOR_FULLG14, + MDP_COLOR_FULLG14_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 21), + MDP_COLOR_FULLG14_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2, 0, 21), + MDP_COLOR_FULLG14_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2, 0, 21), + MDP_COLOR_FULLG14_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2, 0, 21), + MDP_COLOR_FULLG14 = MDP_COLOR_FULLG14_BGGR, + + MDP_COLOR_UFO10 = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 24), + + //MDP_COLOR_BAYER8, + MDP_COLOR_BAYER8_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 20), + MDP_COLOR_BAYER8_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 8, 2, 0, 20), + MDP_COLOR_BAYER8_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 8, 2, 0, 20), + MDP_COLOR_BAYER8_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 8, 2, 0, 20), + MDP_COLOR_BAYER8 = MDP_COLOR_BAYER8_BGGR, + + //MDP_COLOR_BAYER10, + MDP_COLOR_BAYER10_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 20), + MDP_COLOR_BAYER10_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 10, 2, 0, 20), + MDP_COLOR_BAYER10_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 10, 2, 0, 20), + MDP_COLOR_BAYER10_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 10, 2, 0, 20), + MDP_COLOR_BAYER10 = MDP_COLOR_BAYER10_BGGR, + + //MDP_COLOR_BAYER12, + MDP_COLOR_BAYER12_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 20), + MDP_COLOR_BAYER12_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 12, 2, 0, 20), + MDP_COLOR_BAYER12_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 12, 2, 0, 20), + MDP_COLOR_BAYER12_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 12, 2, 0, 20), + MDP_COLOR_BAYER12 = MDP_COLOR_BAYER12_BGGR, + + //MDP_COLOR_BAYER14, + MDP_COLOR_BAYER14_RGGB = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 20), + MDP_COLOR_BAYER14_GRBG = MDP_COLOR(0, 0, 0, 1, 0, 1, 14, 2, 0, 20), + MDP_COLOR_BAYER14_GBRG = MDP_COLOR(0, 0, 0, 1, 1, 0, 14, 2, 0, 20), + MDP_COLOR_BAYER14_BGGR = MDP_COLOR(0, 0, 0, 1, 1, 1, 14, 2, 0, 20), + MDP_COLOR_BAYER14 = MDP_COLOR_BAYER14_BGGR, + + MDP_COLOR_RGB48 = MDP_COLOR(0, 0, 0, 1, 0, 0, 48, 0, 0, 23), + /* For bayer+mono raw-16 */ + MDP_COLOR_RGB565_RAW = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 2, 0, 0), + + MDP_COLOR_BAYER8_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 2, 0, 22), + MDP_COLOR_BAYER10_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 10, 2, 0, 22), + MDP_COLOR_BAYER12_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 12, 2, 0, 22), + MDP_COLOR_BAYER14_UNPAK = MDP_COLOR(0, 0, 0, 1, 0, 0, 14, 2, 0, 22), + + /* Unified formats */ + MDP_COLOR_GREY = MDP_COLOR(0, 0, 0, 1, 0, 0, 8, 1, 0, 7), + + MDP_COLOR_RGB565 = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0, 0, 0), + MDP_COLOR_BGR565 = MDP_COLOR(0, 0, 0, 1, 0, 0, 16, 0, 1, 0), + MDP_COLOR_RGB888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0, 1, 1), + MDP_COLOR_BGR888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 0, 0, 1), + MDP_COLOR_RGBA8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 1, 2), + MDP_COLOR_BGRA8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 0, 2), + MDP_COLOR_ARGB8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 1, 3), + MDP_COLOR_ABGR8888 = MDP_COLOR(0, 0, 0, 1, 0, 0, 32, 0, 0, 3), + + MDP_COLOR_UYVY = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 0, 4), + MDP_COLOR_VYUY = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 1, 4), + MDP_COLOR_YUYV = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 0, 5), + MDP_COLOR_YVYU = MDP_COLOR(0, 0, 0, 1, 1, 0, 16, 1, 1, 5), + + MDP_COLOR_I420 = MDP_COLOR(0, 0, 0, 3, 1, 1, 8, 1, 0, 8), + MDP_COLOR_YV12 = MDP_COLOR(0, 0, 0, 3, 1, 1, 8, 1, 1, 8), + MDP_COLOR_I422 = MDP_COLOR(0, 0, 0, 3, 1, 0, 8, 1, 0, 9), + MDP_COLOR_YV16 = MDP_COLOR(0, 0, 0, 3, 1, 0, 8, 1, 1, 9), + MDP_COLOR_I444 = MDP_COLOR(0, 0, 0, 3, 0, 0, 8, 1, 0, 10), + MDP_COLOR_YV24 = MDP_COLOR(0, 0, 0, 3, 0, 0, 8, 1, 1, 10), + + MDP_COLOR_NV12 = MDP_COLOR(0, 0, 0, 2, 1, 1, 8, 1, 0, 12), + MDP_COLOR_NV21 = MDP_COLOR(0, 0, 0, 2, 1, 1, 8, 1, 1, 12), + MDP_COLOR_NV16 = MDP_COLOR(0, 0, 0, 2, 1, 0, 8, 1, 0, 13), + MDP_COLOR_NV61 = MDP_COLOR(0, 0, 0, 2, 1, 0, 8, 1, 1, 13), + MDP_COLOR_NV24 = MDP_COLOR(0, 0, 0, 2, 0, 0, 8, 1, 0, 14), + MDP_COLOR_NV42 = MDP_COLOR(0, 0, 0, 2, 0, 0, 8, 1, 1, 14), + + /* MediaTek proprietary formats */ + /* UFO encoded block mode */ + MDP_COLOR_420_BLK_UFO = MDP_COLOR(0, 0, 5, 2, 1, 1, 256, 1, 0, 12), + /* Block mode */ + MDP_COLOR_420_BLK = MDP_COLOR(0, 0, 1, 2, 1, 1, 256, 1, 0, 12), + /* Block mode + field mode */ + MDP_COLOR_420_BLKI = MDP_COLOR(0, 0, 3, 2, 1, 1, 256, 1, 0, 12), + /* Block mode */ + MDP_COLOR_422_BLK = MDP_COLOR(0, 0, 1, 1, 1, 0, 512, 1, 0, 4), + + MDP_COLOR_IYU2 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 1, 0, 25), + MDP_COLOR_YUV444 = MDP_COLOR(0, 0, 0, 1, 0, 0, 24, 1, 0, 30), + + /* Packed 10-bit formats */ + MDP_COLOR_RGBA1010102 = MDP_COLOR(1, 0, 0, 1, 0, 0, 32, 0, 1, 2), + MDP_COLOR_BGRA1010102 = MDP_COLOR(1, 0, 0, 1, 0, 0, 32, 0, 0, 2), + /* Packed 10-bit UYVY */ + MDP_COLOR_UYVY_10P = MDP_COLOR(1, 0, 0, 1, 1, 0, 20, 1, 0, 4), + /* Packed 10-bit NV21 */ + MDP_COLOR_NV21_10P = MDP_COLOR(1, 0, 0, 2, 1, 1, 10, 1, 1, 12), + /* 10-bit block mode */ + MDP_COLOR_420_BLK_10_H = MDP_COLOR(1, 0, 1, 2, 1, 1, 320, 1, 0, 12), + /* 10-bit HEVC tile mode */ + MDP_COLOR_420_BLK_10_V = MDP_COLOR(1, 1, 1, 2, 1, 1, 320, 1, 0, 12), + /* UFO encoded 10-bit block mode */ + MDP_COLOR_420_BLK_U10_H = MDP_COLOR(1, 0, 5, 2, 1, 1, 320, 1, 0, 12), + /* UFO encoded 10-bit HEVC tile mode */ + MDP_COLOR_420_BLK_U10_V = MDP_COLOR(1, 1, 5, 2, 1, 1, 320, 1, 0, 12), + + /* Loose 10-bit formats */ + MDP_COLOR_UYVY_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 0, 4), + MDP_COLOR_VYUY_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 1, 4), + MDP_COLOR_YUYV_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 0, 5), + MDP_COLOR_YVYU_10L = MDP_COLOR(0, 1, 0, 1, 1, 0, 20, 1, 1, 5), + MDP_COLOR_NV12_10L = MDP_COLOR(0, 1, 0, 2, 1, 1, 10, 1, 0, 12), + MDP_COLOR_NV21_10L = MDP_COLOR(0, 1, 0, 2, 1, 1, 10, 1, 1, 12), + MDP_COLOR_NV16_10L = MDP_COLOR(0, 1, 0, 2, 1, 0, 10, 1, 0, 13), + MDP_COLOR_NV61_10L = MDP_COLOR(0, 1, 0, 2, 1, 0, 10, 1, 1, 13), + MDP_COLOR_YV12_10L = MDP_COLOR(0, 1, 0, 3, 1, 1, 10, 1, 1, 8), + MDP_COLOR_I420_10L = MDP_COLOR(0, 1, 0, 3, 1, 1, 10, 1, 0, 8), +}; + +static inline bool MDP_COLOR_IS_UV_COPLANE(enum mdp_color c) +{ + return (MDP_COLOR_GET_PLANE_COUNT(c) == 2 && MDP_COLOR_IS_YUV(c)); +} + +/* Minimum Y stride that is accepted by MDP HW */ +static inline u32 mdp_color_get_min_y_stride(enum mdp_color c, u32 width) +{ + return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) + 4) >> 3; +} + +/* Minimum UV stride that is accepted by MDP HW */ +static inline u32 mdp_color_get_min_uv_stride(enum mdp_color c, u32 width) +{ + u32 min_stride; + + if (MDP_COLOR_GET_PLANE_COUNT(c) == 1) + return 0; + min_stride = mdp_color_get_min_y_stride(c, width) + >> MDP_COLOR_GET_H_SUBSAMPLE(c); + if (MDP_COLOR_IS_UV_COPLANE(c) && !MDP_COLOR_IS_BLOCK_MODE(c)) + min_stride = min_stride * 2; + return min_stride; +} + +/* Minimum Y plane size that is necessary in buffer */ +static inline u32 mdp_color_get_min_y_size(enum mdp_color c, + u32 width, u32 height) +{ + if (MDP_COLOR_IS_BLOCK_MODE(c)) + return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) >> 8) * height; + return mdp_color_get_min_y_stride(c, width) * height; +} + +/* Minimum UV plane size that is necessary in buffer */ +static inline u32 mdp_color_get_min_uv_size(enum mdp_color c, + u32 width, u32 height) +{ + height = height >> MDP_COLOR_GET_V_SUBSAMPLE(c); + if (MDP_COLOR_IS_BLOCK_MODE(c) && (MDP_COLOR_GET_PLANE_COUNT(c) > 1)) + return ((MDP_COLOR_BITS_PER_PIXEL(c) * width) >> 8) * height; + return mdp_color_get_min_uv_stride(c, width) * height; +} + +/* Combine colorspace, xfer_func, ycbcr_encoding, and quantization */ +enum mdp_ycbcr_profile { + /* V4L2_YCBCR_ENC_601 and V4L2_QUANTIZATION_LIM_RANGE */ + MDP_YCBCR_PROFILE_BT601, + /* V4L2_YCBCR_ENC_709 and V4L2_QUANTIZATION_LIM_RANGE */ + MDP_YCBCR_PROFILE_BT709, + /* V4L2_YCBCR_ENC_601 and V4L2_QUANTIZATION_FULL_RANGE */ + MDP_YCBCR_PROFILE_JPEG, + MDP_YCBCR_PROFILE_FULL_BT601 = MDP_YCBCR_PROFILE_JPEG, + + /* Colorspaces not support for capture */ + /* V4L2_YCBCR_ENC_BT2020 and V4L2_QUANTIZATION_LIM_RANGE */ + MDP_YCBCR_PROFILE_BT2020, + /* V4L2_YCBCR_ENC_709 and V4L2_QUANTIZATION_FULL_RANGE */ + MDP_YCBCR_PROFILE_FULL_BT709, + /* V4L2_YCBCR_ENC_BT2020 and V4L2_QUANTIZATION_FULL_RANGE */ + MDP_YCBCR_PROFILE_FULL_BT2020, +}; + +#define MDP_FMT_FLAG_OUTPUT BIT(0) +#define MDP_FMT_FLAG_CAPTURE BIT(1) + +struct mdp_format { + u32 pixelformat; + u32 mdp_color; + u8 depth[VIDEO_MAX_PLANES]; + u8 row_depth[VIDEO_MAX_PLANES]; + u8 num_planes; + u8 walign; + u8 halign; + u8 salign; + u32 flags; +}; + +struct mdp_pix_limit { + u32 wmin; + u32 hmin; + u32 wmax; + u32 hmax; +}; + +struct mdp_limit { + struct mdp_pix_limit out_limit; + struct mdp_pix_limit cap_limit; + u32 h_scale_up_max; + u32 v_scale_up_max; + u32 h_scale_down_max; + u32 v_scale_down_max; +}; + +enum mdp_stream_type { + MDP_STREAM_TYPE_UNKNOWN, + MDP_STREAM_TYPE_BITBLT, + MDP_STREAM_TYPE_GPU_BITBLT, + MDP_STREAM_TYPE_DUAL_BITBLT, + MDP_STREAM_TYPE_2ND_BITBLT, + MDP_STREAM_TYPE_ISP_IC, + MDP_STREAM_TYPE_ISP_VR, + MDP_STREAM_TYPE_ISP_ZSD, + MDP_STREAM_TYPE_ISP_IP, + MDP_STREAM_TYPE_ISP_VSS, + MDP_STREAM_TYPE_ISP_ZSD_SLOW, + MDP_STREAM_TYPE_WPE, + MDP_STREAM_TYPE_WPE2, +}; + +struct mdp_crop { + struct v4l2_rect c; + struct v4l2_fract left_subpix; + struct v4l2_fract top_subpix; + struct v4l2_fract width_subpix; + struct v4l2_fract height_subpix; +}; + +struct mdp_frame { + struct v4l2_format format; + const struct mdp_format *mdp_fmt; + u32 ycbcr_prof; /* enum mdp_ycbcr_profile */ + u32 usage; /* enum mdp_buffer_usage */ + struct mdp_crop crop; + struct v4l2_rect compose; + s32 rotation; + u32 hflip:1; + u32 vflip:1; + u32 hdr:1; + u32 dre:1; + u32 sharpness:1; + u32 dither:1; +}; + +static inline bool mdp_target_is_crop(u32 target) +{ + return (target == V4L2_SEL_TGT_CROP) || + (target == V4L2_SEL_TGT_CROP_DEFAULT) || + (target == V4L2_SEL_TGT_CROP_BOUNDS); +} + +static inline bool mdp_target_is_compose(u32 target) +{ + return (target == V4L2_SEL_TGT_COMPOSE) || + (target == V4L2_SEL_TGT_COMPOSE_DEFAULT) || + (target == V4L2_SEL_TGT_COMPOSE_BOUNDS); +} + +#define MDP_MAX_CAPTURES IMG_MAX_HW_OUTPUTS + +#define MDP_VPU_INIT BIT(0) +#define MDP_M2M_CTX_ERROR BIT(1) + +struct mdp_frameparam { + struct list_head list; + struct mdp_m2m_ctx *ctx; + atomic_t state; + const struct mdp_limit *limit; + u32 type; /* enum mdp_stream_type */ + u32 frame_no; + struct mdp_frame output; + struct mdp_frame captures[MDP_MAX_CAPTURES]; + u32 num_captures; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_xfer_func xfer_func; + enum v4l2_quantization quant; +}; + +int mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f); +const struct mdp_format *mdp_try_fmt_mplane(struct v4l2_format *f, + struct mdp_frameparam *param, + u32 ctx_id); +enum mdp_ycbcr_profile mdp_map_ycbcr_prof_mplane(struct v4l2_format *f, + u32 mdp_color); +int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r, + const struct v4l2_selection *s, struct mdp_frame *frame); +int mdp_check_scaling_ratio(const struct v4l2_rect *crop, + const struct v4l2_rect *compose, s32 rotation, + const struct mdp_limit *limit); +void mdp_set_src_config(struct img_input *in, + struct mdp_frame *frame, struct vb2_buffer *vb); +void mdp_set_dst_config(struct img_output *out, + struct mdp_frame *frame, struct vb2_buffer *vb); +int mdp_frameparam_init(struct mdp_frameparam *param); + +#endif /* __MTK_MDP3_REGS_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c new file mode 100644 index 000000000000..a72bed927bb6 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#include <linux/remoteproc.h> +#include <linux/remoteproc/mtk_scp.h> +#include "mtk-mdp3-vpu.h" +#include "mtk-mdp3-core.h" + +#define MDP_VPU_MESSAGE_TIMEOUT 500U +#define vpu_alloc_size 0x600000 + +static inline struct mdp_dev *vpu_to_mdp(struct mdp_vpu_dev *vpu) +{ + return container_of(vpu, struct mdp_dev, vpu); +} + +static int mdp_vpu_shared_mem_alloc(struct mdp_vpu_dev *vpu) +{ + if (vpu->work && vpu->work_addr) + return 0; + + vpu->work = dma_alloc_coherent(scp_get_device(vpu->scp), vpu_alloc_size, + &vpu->work_addr, GFP_KERNEL); + + if (!vpu->work) + return -ENOMEM; + else + return 0; +} + +void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu) +{ + if (vpu->work && vpu->work_addr) + dma_free_coherent(scp_get_device(vpu->scp), vpu_alloc_size, + vpu->work, vpu->work_addr); +} + +static void mdp_vpu_ipi_handle_init_ack(void *data, unsigned int len, + void *priv) +{ + struct mdp_ipi_init_msg *msg = (struct mdp_ipi_init_msg *)data; + struct mdp_vpu_dev *vpu = + (struct mdp_vpu_dev *)(unsigned long)msg->drv_data; + + if (!vpu->work_size) + vpu->work_size = msg->work_size; + + vpu->status = msg->status; + complete(&vpu->ipi_acked); +} + +static void mdp_vpu_ipi_handle_deinit_ack(void *data, unsigned int len, + void *priv) +{ + struct mdp_ipi_deinit_msg *msg = (struct mdp_ipi_deinit_msg *)data; + struct mdp_vpu_dev *vpu = + (struct mdp_vpu_dev *)(unsigned long)msg->drv_data; + + vpu->status = msg->status; + complete(&vpu->ipi_acked); +} + +static void mdp_vpu_ipi_handle_frame_ack(void *data, unsigned int len, + void *priv) +{ + struct img_sw_addr *addr = (struct img_sw_addr *)data; + struct img_ipi_frameparam *param = + (struct img_ipi_frameparam *)(unsigned long)addr->va; + struct mdp_vpu_ctx *ctx = + (struct mdp_vpu_ctx *)(unsigned long)param->drv_data; + + if (param->state) { + struct mdp_dev *mdp = vpu_to_mdp(ctx->vpu_dev); + + dev_err(&mdp->pdev->dev, "VPU MDP failure:%d\n", param->state); + } + ctx->vpu_dev->status = param->state; + complete(&ctx->vpu_dev->ipi_acked); +} + +int mdp_vpu_register(struct mdp_dev *mdp) +{ + int err; + struct mtk_scp *scp = mdp->scp; + struct device *dev = &mdp->pdev->dev; + + err = scp_ipi_register(scp, SCP_IPI_MDP_INIT, + mdp_vpu_ipi_handle_init_ack, NULL); + if (err) { + dev_err(dev, "scp_ipi_register failed %d\n", err); + goto err_ipi_init; + } + err = scp_ipi_register(scp, SCP_IPI_MDP_DEINIT, + mdp_vpu_ipi_handle_deinit_ack, NULL); + if (err) { + dev_err(dev, "scp_ipi_register failed %d\n", err); + goto err_ipi_deinit; + } + err = scp_ipi_register(scp, SCP_IPI_MDP_FRAME, + mdp_vpu_ipi_handle_frame_ack, NULL); + if (err) { + dev_err(dev, "scp_ipi_register failed %d\n", err); + goto err_ipi_frame; + } + return 0; + +err_ipi_frame: + scp_ipi_unregister(scp, SCP_IPI_MDP_DEINIT); +err_ipi_deinit: + scp_ipi_unregister(scp, SCP_IPI_MDP_INIT); +err_ipi_init: + + return err; +} + +void mdp_vpu_unregister(struct mdp_dev *mdp) +{ + scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_INIT); + scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_DEINIT); + scp_ipi_unregister(mdp->scp, SCP_IPI_MDP_FRAME); +} + +static int mdp_vpu_sendmsg(struct mdp_vpu_dev *vpu, enum scp_ipi_id id, + void *buf, unsigned int len) +{ + struct mdp_dev *mdp = vpu_to_mdp(vpu); + unsigned int t = MDP_VPU_MESSAGE_TIMEOUT; + int ret; + + if (!vpu->scp) { + dev_dbg(&mdp->pdev->dev, "vpu scp is NULL"); + return -EINVAL; + } + ret = scp_ipi_send(vpu->scp, id, buf, len, 2000); + + if (ret) { + dev_err(&mdp->pdev->dev, "scp_ipi_send failed %d\n", ret); + return -EPERM; + } + ret = wait_for_completion_timeout(&vpu->ipi_acked, + msecs_to_jiffies(t)); + if (!ret) + ret = -ETIME; + else if (vpu->status) + ret = -EINVAL; + else + ret = 0; + return ret; +} + +int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, + struct mutex *lock) +{ + struct mdp_ipi_init_msg msg = { + .drv_data = (unsigned long)vpu, + }; + size_t mem_size; + phys_addr_t pool; + const size_t pool_size = sizeof(struct mdp_config_pool); + struct mdp_dev *mdp = vpu_to_mdp(vpu); + int err; + + init_completion(&vpu->ipi_acked); + vpu->scp = scp; + vpu->lock = lock; + vpu->work_size = 0; + err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg)); + if (err) + goto err_work_size; + /* vpu work_size was set in mdp_vpu_ipi_handle_init_ack */ + + mem_size = vpu_alloc_size; + err = mdp_vpu_shared_mem_alloc(vpu); + if (err) { + dev_err(&mdp->pdev->dev, "VPU memory alloc fail!"); + goto err_mem_alloc; + } + + pool = ALIGN((uintptr_t)vpu->work + vpu->work_size, 8); + if (pool + pool_size - (uintptr_t)vpu->work > mem_size) { + dev_err(&mdp->pdev->dev, + "VPU memory insufficient: %zx + %zx > %zx", + vpu->work_size, pool_size, mem_size); + err = -ENOMEM; + goto err_mem_size; + } + + dev_dbg(&mdp->pdev->dev, + "VPU work:%pK pa:%pad sz:%zx pool:%pa sz:%zx (mem sz:%zx)", + vpu->work, &vpu->work_addr, vpu->work_size, + &pool, pool_size, mem_size); + vpu->pool = (struct mdp_config_pool *)(uintptr_t)pool; + msg.work_addr = vpu->work_addr; + msg.work_size = vpu->work_size; + err = mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_INIT, &msg, sizeof(msg)); + if (err) + goto err_work_size; + + memset(vpu->pool, 0, sizeof(*vpu->pool)); + return 0; + +err_work_size: + switch (vpu->status) { + case -MDP_IPI_EBUSY: + err = -EBUSY; + break; + case -MDP_IPI_ENOMEM: + err = -ENOSPC; /* -ENOMEM */ + break; + } + return err; +err_mem_size: +err_mem_alloc: + return err; +} + +int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu) +{ + struct mdp_ipi_deinit_msg msg = { + .drv_data = (unsigned long)vpu, + .work_addr = vpu->work_addr, + }; + + return mdp_vpu_sendmsg(vpu, SCP_IPI_MDP_DEINIT, &msg, sizeof(msg)); +} + +static struct img_config *mdp_config_get(struct mdp_vpu_dev *vpu, + enum mdp_config_id id, uint32_t *addr) +{ + struct img_config *config; + + if (id < 0 || id >= MDP_CONFIG_POOL_SIZE) + return ERR_PTR(-EINVAL); + + mutex_lock(vpu->lock); + vpu->pool->cfg_count[id]++; + config = &vpu->pool->configs[id]; + *addr = vpu->work_addr + ((uintptr_t)config - (uintptr_t)vpu->work); + mutex_unlock(vpu->lock); + + return config; +} + +static int mdp_config_put(struct mdp_vpu_dev *vpu, + enum mdp_config_id id, + const struct img_config *config) +{ + int err = 0; + + if (id < 0 || id >= MDP_CONFIG_POOL_SIZE) + return -EINVAL; + if (vpu->lock) + mutex_lock(vpu->lock); + if (!vpu->pool->cfg_count[id] || config != &vpu->pool->configs[id]) + err = -EINVAL; + else + vpu->pool->cfg_count[id]--; + if (vpu->lock) + mutex_unlock(vpu->lock); + return err; +} + +int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu, + enum mdp_config_id id) +{ + ctx->config = mdp_config_get(vpu, id, &ctx->inst_addr); + if (IS_ERR(ctx->config)) { + int err = PTR_ERR(ctx->config); + + ctx->config = NULL; + return err; + } + ctx->config_id = id; + ctx->vpu_dev = vpu; + return 0; +} + +int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx) +{ + int err = mdp_config_put(ctx->vpu_dev, ctx->config_id, ctx->config); + + ctx->config_id = 0; + ctx->config = NULL; + ctx->inst_addr = 0; + return err; +} + +int mdp_vpu_process(struct mdp_vpu_ctx *ctx, struct img_ipi_frameparam *param) +{ + struct mdp_vpu_dev *vpu = ctx->vpu_dev; + struct mdp_dev *mdp = vpu_to_mdp(vpu); + struct img_sw_addr addr; + + if (!ctx->vpu_dev->work || !ctx->vpu_dev->work_addr) { + if (mdp_vpu_shared_mem_alloc(vpu)) { + dev_err(&mdp->pdev->dev, "VPU memory alloc fail!"); + return -ENOMEM; + } + } + memset((void *)ctx->vpu_dev->work, 0, ctx->vpu_dev->work_size); + memset(ctx->config, 0, sizeof(*ctx->config)); + param->config_data.va = (unsigned long)ctx->config; + param->config_data.pa = ctx->inst_addr; + param->drv_data = (unsigned long)ctx; + + memcpy((void *)ctx->vpu_dev->work, param, sizeof(*param)); + addr.pa = ctx->vpu_dev->work_addr; + addr.va = (uintptr_t)ctx->vpu_dev->work; + return mdp_vpu_sendmsg(ctx->vpu_dev, SCP_IPI_MDP_FRAME, + &addr, sizeof(addr)); +} diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h new file mode 100644 index 000000000000..244b3a32d689 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com> + */ + +#ifndef __MTK_MDP3_VPU_H__ +#define __MTK_MDP3_VPU_H__ + +#include <linux/platform_device.h> +#include "mtk-img-ipi.h" + +enum mdp_ipi_result { + MDP_IPI_SUCCESS = 0, + MDP_IPI_ENOMEM = 12, + MDP_IPI_EBUSY = 16, + MDP_IPI_EINVAL = 22, + MDP_IPI_EMINST = 24, + MDP_IPI_ERANGE = 34, + MDP_IPI_NR_ERRNO, + + MDP_IPI_EOTHER = MDP_IPI_NR_ERRNO, + MDP_IPI_PATH_CANT_MERGE, + MDP_IPI_OP_FAIL, +}; + +struct mdp_ipi_init_msg { + u32 status; + u64 drv_data; + u32 work_addr; /* [in] working buffer address */ + u32 work_size; /* [in] working buffer size */ +} __packed; + +struct mdp_ipi_deinit_msg { + u32 status; + u64 drv_data; + u32 work_addr; +} __packed; + +enum mdp_config_id { + MDP_DEV_M2M = 0, + MDP_CONFIG_POOL_SIZE /* ALWAYS keep at the end */ +}; + +struct mdp_config_pool { + u64 cfg_count[MDP_CONFIG_POOL_SIZE]; + struct img_config configs[MDP_CONFIG_POOL_SIZE]; +}; + +struct mdp_vpu_dev { + /* synchronization protect for accessing vpu working buffer info */ + struct mutex *lock; + struct mtk_scp *scp; + struct completion ipi_acked; + void *work; + dma_addr_t work_addr; + size_t work_size; + struct mdp_config_pool *pool; + u32 status; +}; + +struct mdp_vpu_ctx { + struct mdp_vpu_dev *vpu_dev; + u32 config_id; + struct img_config *config; + u32 inst_addr; +}; + +void mdp_vpu_shared_mem_free(struct mdp_vpu_dev *vpu); +int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, + struct mutex *lock /* for sync */); +int mdp_vpu_dev_deinit(struct mdp_vpu_dev *vpu); +int mdp_vpu_ctx_init(struct mdp_vpu_ctx *ctx, struct mdp_vpu_dev *vpu, + enum mdp_config_id id); +int mdp_vpu_ctx_deinit(struct mdp_vpu_ctx *ctx); +int mdp_vpu_process(struct mdp_vpu_ctx *vpu, struct img_ipi_frameparam *param); + +#endif /* __MTK_MDP3_VPU_H__ */ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 7d194a476713..641f533c417f 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -227,6 +227,8 @@ static int mtk_vcodec_dec_get_chip_name(void *priv) return 8195; else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec")) return 8186; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-dec")) + return 8188; else return 8173; } diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index e0b6ae9d6caa..174a6eec2f54 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -478,6 +478,10 @@ static const struct of_device_id mtk_vcodec_match[] = { .compatible = "mediatek,mt8195-vcodec-dec", .data = &mtk_lat_sig_core_pdata, }, + { + .compatible = "mediatek,mt8188-vcodec-dec", + .data = &mtk_lat_sig_core_pdata, + }, {}, }; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index ef4584a46417..9acab54fd650 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -278,6 +278,7 @@ struct vdec_pic_info { * @hw_id: hardware index used to identify different hardware. * * @msg_queue: msg queue used to store lat buffer information. + * @q_mutex: vb2_queue mutex. */ struct mtk_vcodec_ctx { enum mtk_instance_type type; @@ -324,6 +325,8 @@ struct mtk_vcodec_ctx { int hw_id; struct vdec_msg_queue msg_queue; + + struct mutex q_mutex; }; /* @@ -401,6 +404,7 @@ struct mtk_vcodec_dec_pdata { * @output_formats: array of supported output formats * @num_output_formats: number of entries in output_formats * @core_id: stand for h264 or vp8 encode index + * @uses_34bit: whether the encoder uses 34-bit iova */ struct mtk_vcodec_enc_pdata { bool uses_ext; @@ -411,9 +415,11 @@ struct mtk_vcodec_enc_pdata { const struct mtk_video_fmt *output_formats; size_t num_output_formats; int core_id; + bool uses_34bit; }; #define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext) +#define MTK_ENC_IOVA_IS_34BIT(ctx) ((ctx)->dev->venc_pdata->uses_34bit) /** * struct mtk_vcodec_dev - driver data diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c index 25e816863597..d810a78dde51 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c @@ -225,6 +225,8 @@ static int mtk_vcodec_enc_get_chip_name(void *priv) return 8192; else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-enc")) return 8195; + else if (of_device_is_compatible(dev->of_node, "mediatek,mt8188-vcodec-enc")) + return 8188; else return 8173; } @@ -503,13 +505,13 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, f->fmt.pix.pixelformat = fmt->fourcc; } - ret = vidioc_try_fmt_out(ctx, f, fmt); + q_data->visible_width = f->fmt.pix_mp.width; + q_data->visible_height = f->fmt.pix_mp.height; + q_data->fmt = fmt; + ret = vidioc_try_fmt_out(ctx, f, q_data->fmt); if (ret) return ret; - q_data->fmt = fmt; - q_data->visible_width = f->fmt.pix_mp.width; - q_data->visible_height = f->fmt.pix_mp.height; q_data->coded_width = f->fmt.pix_mp.width; q_data->coded_height = f->fmt.pix_mp.height; @@ -1300,7 +1302,7 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx) { struct mtk_q_data *q_data; - ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; + ctx->m2m_ctx->q_lock = &ctx->q_mutex; ctx->fh.m2m_ctx = ctx->m2m_ctx; ctx->fh.ctrl_handler = &ctx->ctrl_hdl; INIT_WORK(&ctx->encode_work, mtk_venc_worker); @@ -1403,7 +1405,8 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx) V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, - 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + ~(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); if (handler->error) { @@ -1435,7 +1438,7 @@ int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &mtk_venc_vb2_ops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->dev->dev_mutex; + src_vq->lock = &ctx->q_mutex; src_vq->dev = &ctx->dev->plat_dev->dev; ret = vb2_queue_init(src_vq); @@ -1449,7 +1452,7 @@ int mtk_vcodec_enc_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &mtk_venc_vb2_ops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->dev->dev_mutex; + dst_vq->lock = &ctx->q_mutex; dst_vq->dev = &ctx->dev->plat_dev->dev; return vb2_queue_init(dst_vq); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c index d2f5f30582a9..9095186d5495 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c @@ -130,6 +130,7 @@ static int fops_vcodec_open(struct file *file) INIT_LIST_HEAD(&ctx->list); ctx->dev = dev; init_waitqueue_head(&ctx->queue[0]); + mutex_init(&ctx->q_mutex); ctx->type = MTK_INST_ENCODER; ret = mtk_vcodec_enc_ctrls_setup(ctx); @@ -403,6 +404,18 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = { .core_id = VENC_SYS, }; +static const struct mtk_vcodec_enc_pdata mt8188_pdata = { + .uses_ext = true, + .capture_formats = mtk_video_formats_capture_h264, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), + .output_formats = mtk_video_formats_output, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), + .min_bitrate = 64, + .max_bitrate = 50000000, + .core_id = VENC_SYS, + .uses_34bit = true, +}; + static const struct mtk_vcodec_enc_pdata mt8192_pdata = { .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, @@ -431,6 +444,7 @@ static const struct of_device_id mtk_vcodec_enc_match[] = { {.compatible = "mediatek,mt8173-vcodec-enc-vp8", .data = &mt8173_vp8_pdata}, {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata}, + {.compatible = "mediatek,mt8188-vcodec-enc", .data = &mt8188_pdata}, {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata}, {.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata}, {}, diff --git a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c index 4d9b8798dffe..13c4f860fa69 100644 --- a/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc/venc_h264_if.c @@ -127,6 +127,72 @@ struct venc_h264_vsi { struct venc_h264_vpu_buf work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; }; +/** + * struct venc_h264_vpu_config_ext - Structure for h264 encoder configuration + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @input_fourcc: input fourcc + * @bitrate: target bitrate (in bps) + * @pic_w: picture width. Picture size is visible stream resolution, in pixels, + * to be used for display purposes; must be smaller or equal to buffer + * size. + * @pic_h: picture height + * @buf_w: buffer width. Buffer size is stream resolution in pixels aligned to + * hardware requirements. + * @buf_h: buffer height + * @gop_size: group of picture size (idr frame) + * @intra_period: intra frame period + * @framerate: frame rate in fps + * @profile: as specified in standard + * @level: as specified in standard + * @wfd: WFD mode 1:on, 0:off + * @max_qp: max quant parameter + * @min_qp: min quant parameter + * @reserved: reserved configs + */ +struct venc_h264_vpu_config_ext { + u32 input_fourcc; + u32 bitrate; + u32 pic_w; + u32 pic_h; + u32 buf_w; + u32 buf_h; + u32 gop_size; + u32 intra_period; + u32 framerate; + u32 profile; + u32 level; + u32 wfd; + u32 max_qp; + u32 min_qp; + u32 reserved[8]; +}; + +/** + * struct venc_h264_vpu_buf_34 - Structure for 34-bit buffer information + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @iova: 34-bit IO virtual address + * @vpua: VPU side memory addr which is used by RC_CODE + * @size: buffer size (in bytes) + */ +struct venc_h264_vpu_buf_34 { + u64 iova; + u32 vpua; + u32 size; +}; + +/** + * struct venc_h264_vsi_34 - Structure for VPU driver control and info share + * Used for 34-bit iova sharing + * @config: h264 encoder configuration + * @work_bufs: working buffer information in VPU side + */ +struct venc_h264_vsi_34 { + struct venc_h264_vpu_config_ext config; + struct venc_h264_vpu_buf_34 work_bufs[VENC_H264_VPU_WORK_BUF_MAX]; +}; + /* * struct venc_h264_inst - h264 encoder AP driver instance * @hw_base: h264 encoder hardware register base @@ -140,6 +206,8 @@ struct venc_h264_vsi { * @vpu_inst: VPU instance to exchange information between AP and VPU * @vsi: driver structure allocated by VPU side and shared to AP side for * control and info share + * @vsi_34: driver structure allocated by VPU side and shared to AP side for + * control and info share, used for 34-bit iova sharing. * @ctx: context for v4l2 layer integration */ struct venc_h264_inst { @@ -152,6 +220,7 @@ struct venc_h264_inst { unsigned int prepend_hdr; struct venc_vpu_inst vpu_inst; struct venc_h264_vsi *vsi; + struct venc_h264_vsi_34 *vsi_34; struct mtk_vcodec_ctx *ctx; }; @@ -244,14 +313,21 @@ static void h264_enc_free_work_buf(struct venc_h264_inst *inst) mtk_vcodec_debug_leave(inst); } -static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) +static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst, bool is_34bit) { + struct venc_h264_vpu_buf *wb = NULL; + struct venc_h264_vpu_buf_34 *wb_34 = NULL; int i; + u32 vpua, wb_size; int ret = 0; - struct venc_h264_vpu_buf *wb = inst->vsi->work_bufs; mtk_vcodec_debug_enter(inst); + if (is_34bit) + wb_34 = inst->vsi_34->work_bufs; + else + wb = inst->vsi->work_bufs; + for (i = 0; i < VENC_H264_VPU_WORK_BUF_MAX; i++) { /* * This 'wb' structure is set by VPU side and shared to AP for @@ -269,13 +345,22 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) * address and do some memcpy access to move to bitstream buffer * assigned by v4l2 layer. */ - inst->work_bufs[i].size = wb[i].size; + if (is_34bit) { + inst->work_bufs[i].size = wb_34[i].size; + vpua = wb_34[i].vpua; + wb_size = wb_34[i].size; + } else { + inst->work_bufs[i].size = wb[i].size; + vpua = wb[i].vpua; + wb_size = wb[i].size; + } + if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) { struct mtk_vcodec_fw *handler; handler = inst->vpu_inst.ctx->dev->fw_handler; inst->work_bufs[i].va = - mtk_vcodec_fw_map_dm_addr(handler, wb[i].vpua); + mtk_vcodec_fw_map_dm_addr(handler, vpua); inst->work_bufs[i].dma_addr = 0; } else { ret = mtk_vcodec_mem_alloc(inst->ctx, @@ -297,12 +382,14 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst) handler = inst->vpu_inst.ctx->dev->fw_handler; tmp_va = mtk_vcodec_fw_map_dm_addr(handler, - wb[i].vpua); - memcpy(inst->work_bufs[i].va, tmp_va, - wb[i].size); + vpua); + memcpy(inst->work_bufs[i].va, tmp_va, wb_size); } } - wb[i].iova = inst->work_bufs[i].dma_addr; + if (is_34bit) + wb_34[i].iova = inst->work_bufs[i].dma_addr; + else + wb[i].iova = inst->work_bufs[i].dma_addr; mtk_vcodec_debug(inst, "work_buf[%d] va=0x%p iova=%pad size=%zu", @@ -342,22 +429,22 @@ static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst) return irq_status; } -static int h264_frame_type(struct venc_h264_inst *inst) +static int h264_frame_type(unsigned int frm_cnt, unsigned int gop_size, + unsigned int intra_period) { - if ((inst->vsi->config.gop_size != 0 && - (inst->frm_cnt % inst->vsi->config.gop_size) == 0) || - (inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) { + if ((gop_size != 0 && (frm_cnt % gop_size) == 0) || + (frm_cnt == 0 && gop_size == 0)) { /* IDR frame */ return VENC_H264_IDR_FRM; - } else if ((inst->vsi->config.intra_period != 0 && - (inst->frm_cnt % inst->vsi->config.intra_period) == 0) || - (inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) { + } else if ((intra_period != 0 && (frm_cnt % intra_period) == 0) || + (frm_cnt == 0 && intra_period == 0)) { /* I frame */ return VENC_H264_I_FRM; } else { return VENC_H264_P_FRM; /* Note: B frames are not supported */ } } + static int h264_encode_sps(struct venc_h264_inst *inst, struct mtk_vcodec_mem *bs_buf, unsigned int *bs_size) @@ -438,18 +525,32 @@ static int h264_encode_frame(struct venc_h264_inst *inst, unsigned int *bs_size) { int ret = 0; + unsigned int gop_size; + unsigned int intra_period; unsigned int irq_status; struct venc_frame_info frame_info; + struct mtk_vcodec_ctx *ctx = inst->ctx; mtk_vcodec_debug_enter(inst); mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt); + + if (MTK_ENC_IOVA_IS_34BIT(ctx)) { + gop_size = inst->vsi_34->config.gop_size; + intra_period = inst->vsi_34->config.intra_period; + } else { + gop_size = inst->vsi->config.gop_size; + intra_period = inst->vsi->config.intra_period; + } frame_info.frm_count = inst->frm_cnt; frame_info.skip_frm_count = inst->skip_frm_cnt; - frame_info.frm_type = h264_frame_type(inst); + frame_info.frm_type = h264_frame_type(inst->frm_cnt, gop_size, + intra_period); mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n", frame_info.frm_count, frame_info.skip_frm_count, frame_info.frm_type); - ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf, bs_buf, &frame_info); + + ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, + frm_buf, bs_buf, &frame_info); if (ret) return ret; @@ -517,7 +618,10 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx) ret = vpu_enc_init(&inst->vpu_inst); - inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi; + if (MTK_ENC_IOVA_IS_34BIT(ctx)) + inst->vsi_34 = (struct venc_h264_vsi_34 *)inst->vpu_inst.vsi; + else + inst->vsi = (struct venc_h264_vsi *)inst->vpu_inst.vsi; mtk_vcodec_debug_leave(inst); @@ -624,31 +728,61 @@ encode_err: return ret; } +static void h264_enc_set_vsi_configs(struct venc_h264_inst *inst, + struct venc_enc_param *enc_prm) +{ + inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt; + inst->vsi->config.bitrate = enc_prm->bitrate; + inst->vsi->config.pic_w = enc_prm->width; + inst->vsi->config.pic_h = enc_prm->height; + inst->vsi->config.buf_w = enc_prm->buf_width; + inst->vsi->config.buf_h = enc_prm->buf_height; + inst->vsi->config.gop_size = enc_prm->gop_size; + inst->vsi->config.framerate = enc_prm->frm_rate; + inst->vsi->config.intra_period = enc_prm->intra_period; + inst->vsi->config.profile = + h264_get_profile(inst, enc_prm->h264_profile); + inst->vsi->config.level = + h264_get_level(inst, enc_prm->h264_level); + inst->vsi->config.wfd = 0; +} + +static void h264_enc_set_vsi_34_configs(struct venc_h264_inst *inst, + struct venc_enc_param *enc_prm) +{ + inst->vsi_34->config.input_fourcc = enc_prm->input_yuv_fmt; + inst->vsi_34->config.bitrate = enc_prm->bitrate; + inst->vsi_34->config.pic_w = enc_prm->width; + inst->vsi_34->config.pic_h = enc_prm->height; + inst->vsi_34->config.buf_w = enc_prm->buf_width; + inst->vsi_34->config.buf_h = enc_prm->buf_height; + inst->vsi_34->config.gop_size = enc_prm->gop_size; + inst->vsi_34->config.framerate = enc_prm->frm_rate; + inst->vsi_34->config.intra_period = enc_prm->intra_period; + inst->vsi_34->config.profile = + h264_get_profile(inst, enc_prm->h264_profile); + inst->vsi_34->config.level = + h264_get_level(inst, enc_prm->h264_level); + inst->vsi_34->config.wfd = 0; +} + static int h264_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { int ret = 0; struct venc_h264_inst *inst = (struct venc_h264_inst *)handle; + struct mtk_vcodec_ctx *ctx = inst->ctx; + const bool is_34bit = MTK_ENC_IOVA_IS_34BIT(ctx); mtk_vcodec_debug(inst, "->type=%d", type); switch (type) { case VENC_SET_PARAM_ENC: - inst->vsi->config.input_fourcc = enc_prm->input_yuv_fmt; - inst->vsi->config.bitrate = enc_prm->bitrate; - inst->vsi->config.pic_w = enc_prm->width; - inst->vsi->config.pic_h = enc_prm->height; - inst->vsi->config.buf_w = enc_prm->buf_width; - inst->vsi->config.buf_h = enc_prm->buf_height; - inst->vsi->config.gop_size = enc_prm->gop_size; - inst->vsi->config.framerate = enc_prm->frm_rate; - inst->vsi->config.intra_period = enc_prm->intra_period; - inst->vsi->config.profile = - h264_get_profile(inst, enc_prm->h264_profile); - inst->vsi->config.level = - h264_get_level(inst, enc_prm->h264_level); - inst->vsi->config.wfd = 0; + if (is_34bit) + h264_enc_set_vsi_34_configs(inst, enc_prm); + else + h264_enc_set_vsi_configs(inst, enc_prm); ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm); if (ret) break; @@ -656,7 +790,7 @@ static int h264_enc_set_param(void *handle, h264_enc_free_work_buf(inst); inst->work_buf_allocated = false; } - ret = h264_enc_alloc_work_buf(inst); + ret = h264_enc_alloc_work_buf(inst, is_34bit); if (ret) break; inst->work_buf_allocated = true; diff --git a/drivers/media/platform/mediatek/vcodec/venc_ipi_msg.h b/drivers/media/platform/mediatek/vcodec/venc_ipi_msg.h index 587a2cf15b76..bb16d96a7f57 100644 --- a/drivers/media/platform/mediatek/vcodec/venc_ipi_msg.h +++ b/drivers/media/platform/mediatek/vcodec/venc_ipi_msg.h @@ -101,6 +101,30 @@ struct venc_ap_ipi_msg_enc_ext { }; /** + * struct venc_ap_ipi_msg_enc_ext_34 - AP to SCP extended enc cmd structure + * @msg_id: message id (AP_IPIMSG_XXX_ENC_ENCODE) + * @vpu_inst_addr: VPU encoder instance addr + * @bs_mode: bitstream mode for h264 + * @reserved: for struct padding + * @input_addr: input frame buffer 34 bit address + * @bs_addr: output bitstream buffer 34 bit address + * @bs_size: bitstream buffer size + * @data_item: number of items in the data array + * @data: data array to store the set parameters + */ +struct venc_ap_ipi_msg_enc_ext_34 { + u32 msg_id; + u32 vpu_inst_addr; + u32 bs_mode; + u32 reserved; + u64 input_addr[3]; + u64 bs_addr; + u32 bs_size; + u32 data_item; + u32 data[32]; +}; + +/** * struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure * @msg_id: message id (AP_IPIMSG_XXX_ENC_DEINIT) * @vpu_inst_addr: VPU encoder instance addr diff --git a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c index d3570c4c177d..09e7eaa25aab 100644 --- a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c @@ -222,10 +222,11 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu, return 0; } -int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, - struct venc_frm_buf *frm_buf, - struct mtk_vcodec_mem *bs_buf, - struct venc_frame_info *frame_info) +static int vpu_enc_encode_32bits(struct venc_vpu_inst *vpu, + unsigned int bs_mode, + struct venc_frm_buf *frm_buf, + struct mtk_vcodec_mem *bs_buf, + struct venc_frame_info *frame_info) { const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx); size_t msg_size = is_ext ? @@ -267,6 +268,73 @@ int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, return -EINVAL; } + return 0; +} + +static int vpu_enc_encode_34bits(struct venc_vpu_inst *vpu, + unsigned int bs_mode, + struct venc_frm_buf *frm_buf, + struct mtk_vcodec_mem *bs_buf, + struct venc_frame_info *frame_info) +{ + struct venc_ap_ipi_msg_enc_ext_34 out; + size_t msg_size = sizeof(struct venc_ap_ipi_msg_enc_ext_34); + + mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode); + + memset(&out, 0, sizeof(out)); + out.msg_id = AP_IPIMSG_ENC_ENCODE; + out.vpu_inst_addr = vpu->inst_addr; + out.bs_mode = bs_mode; + + if (frm_buf) { + if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) && + (frm_buf->fb_addr[1].dma_addr % 16 == 0) && + (frm_buf->fb_addr[2].dma_addr % 16 == 0)) { + out.input_addr[0] = frm_buf->fb_addr[0].dma_addr; + out.input_addr[1] = frm_buf->fb_addr[1].dma_addr; + out.input_addr[2] = frm_buf->fb_addr[2].dma_addr; + } else { + mtk_vcodec_err(vpu, "dma_addr not align to 16"); + return -EINVAL; + } + } + if (bs_buf) { + out.bs_addr = bs_buf->dma_addr; + out.bs_size = bs_buf->size; + } + if (frame_info) { + out.data_item = 3; + out.data[0] = frame_info->frm_count; + out.data[1] = frame_info->skip_frm_count; + out.data[2] = frame_info->frm_type; + } + if (vpu_enc_send_msg(vpu, &out, msg_size)) { + mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail", + bs_mode); + return -EINVAL; + } + + return 0; +} + +int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode, + struct venc_frm_buf *frm_buf, + struct mtk_vcodec_mem *bs_buf, + struct venc_frame_info *frame_info) +{ + int ret; + + if (MTK_ENC_IOVA_IS_34BIT(vpu->ctx)) + ret = vpu_enc_encode_34bits(vpu, bs_mode, + frm_buf, bs_buf, frame_info); + else + ret = vpu_enc_encode_32bits(vpu, bs_mode, + frm_buf, bs_buf, frame_info); + + if (ret) + return ret; + mtk_vcodec_debug(vpu, "bs_mode %d state %d size %d key_frm %d <-", bs_mode, vpu->state, vpu->bs_size, vpu->is_key_frm); diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig index 1ac0a6e91111..5917634889b5 100644 --- a/drivers/media/platform/nxp/Kconfig +++ b/drivers/media/platform/nxp/Kconfig @@ -15,18 +15,6 @@ config VIDEO_IMX_MIPI_CSIS Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs. -config VIDEO_VIU - tristate "NXP VIU Video Driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C - select VIDEOBUF_DMA_CONTIG - help - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. - # mem2mem drivers config VIDEO_IMX_PXP @@ -51,4 +39,5 @@ config VIDEO_MX2_EMMAPRP memory to memory. Operations include resizing and format conversion. +source "drivers/media/platform/nxp/dw100/Kconfig" source "drivers/media/platform/nxp/imx-jpeg/Kconfig" diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile index efc38c6578ce..81ab304ef31c 100644 --- a/drivers/media/platform/nxp/Makefile +++ b/drivers/media/platform/nxp/Makefile @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-y += dw100/ obj-y += imx-jpeg/ obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o -obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o diff --git a/drivers/media/platform/nxp/dw100/Kconfig b/drivers/media/platform/nxp/dw100/Kconfig new file mode 100644 index 000000000000..cd4531bb3110 --- /dev/null +++ b/drivers/media/platform/nxp/dw100/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_DW100 + tristate "NXP i.MX DW100 dewarper" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_MXC || COMPILE_TEST + select MEDIA_CONTROLLER + select V4L2_MEM2MEM_DEV + select VIDEOBUF2_DMA_CONTIG + help + DW100 is a memory-to-memory engine performing geometrical + transformation on source images through a programmable dewarping map. + + To compile this driver as a module, choose M here: the module + will be called dw100. diff --git a/drivers/media/platform/nxp/dw100/Makefile b/drivers/media/platform/nxp/dw100/Makefile new file mode 100644 index 000000000000..49db80589e9a --- /dev/null +++ b/drivers/media/platform/nxp/dw100/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0+ + +obj-$(CONFIG_VIDEO_DW100) += dw100.o diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c new file mode 100644 index 000000000000..f6d48c36f386 --- /dev/null +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -0,0 +1,1707 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DW100 Hardware dewarper + * + * Copyright 2022 NXP + * Author: Xavier Roumegue (xavier.roumegue@oss.nxp.com) + * + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include <uapi/linux/dw100.h> + +#include "dw100_regs.h" + +#define DRV_NAME "dw100" + +#define DW100_MIN_W 176u +#define DW100_MIN_H 144u +#define DW100_MAX_W 4096u +#define DW100_MAX_H 3072u +#define DW100_ALIGN_W 3 +#define DW100_ALIGN_H 3 + +#define DW100_BLOCK_SIZE 16 + +#define DW100_DEF_W 640u +#define DW100_DEF_H 480u +#define DW100_DEF_LUT_W (DIV_ROUND_UP(DW100_DEF_W, DW100_BLOCK_SIZE) + 1) +#define DW100_DEF_LUT_H (DIV_ROUND_UP(DW100_DEF_H, DW100_BLOCK_SIZE) + 1) + +/* + * 16 controls have been reserved for this driver for future extension, but + * let's limit the related driver allocation to the effective number of controls + * in use. + */ +#define DW100_MAX_CTRLS 1 +#define DW100_CTRL_DEWARPING_MAP 0 + +enum { + DW100_QUEUE_SRC = 0, + DW100_QUEUE_DST = 1, +}; + +enum { + DW100_FMT_CAPTURE = BIT(0), + DW100_FMT_OUTPUT = BIT(1), +}; + +struct dw100_device { + struct platform_device *pdev; + struct v4l2_m2m_dev *m2m_dev; + struct v4l2_device v4l2_dev; + struct video_device vfd; + struct media_device mdev; + /* Video device lock */ + struct mutex vfd_mutex; + void __iomem *mmio; + struct clk_bulk_data *clks; + int num_clks; + struct dentry *debugfs_root; +}; + +struct dw100_q_data { + struct v4l2_pix_format_mplane pix_fmt; + unsigned int sequence; + const struct dw100_fmt *fmt; + struct v4l2_rect crop; +}; + +struct dw100_ctx { + struct v4l2_fh fh; + struct dw100_device *dw_dev; + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *ctrls[DW100_MAX_CTRLS]; + /* per context m2m queue lock */ + struct mutex vq_mutex; + + /* Look Up Table for pixel remapping */ + unsigned int *map; + dma_addr_t map_dma; + size_t map_size; + unsigned int map_width; + unsigned int map_height; + bool user_map_is_set; + + /* Source and destination queue data */ + struct dw100_q_data q_data[2]; +}; + +static const struct v4l2_frmsize_stepwise dw100_frmsize_stepwise = { + .min_width = DW100_MIN_W, + .min_height = DW100_MIN_H, + .max_width = DW100_MAX_W, + .max_height = DW100_MAX_H, + .step_width = 1UL << DW100_ALIGN_W, + .step_height = 1UL << DW100_ALIGN_H, +}; + +static const struct dw100_fmt { + u32 fourcc; + u32 types; + u32 reg_format; + bool reg_swap_uv; +} formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_SP, + .reg_swap_uv = false, + }, { + .fourcc = V4L2_PIX_FMT_NV16M, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_SP, + .reg_swap_uv = false, + }, { + .fourcc = V4L2_PIX_FMT_NV61, + .types = DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_SP, + .reg_swap_uv = true, + }, { + .fourcc = V4L2_PIX_FMT_NV61M, + .types = DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_SP, + .reg_swap_uv = true, + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED, + .reg_swap_uv = false, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED, + .reg_swap_uv = true, + }, { + .fourcc = V4L2_PIX_FMT_NV12, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV420_SP, + .reg_swap_uv = false, + }, { + .fourcc = V4L2_PIX_FMT_NV12M, + .types = DW100_FMT_OUTPUT | DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV420_SP, + .reg_swap_uv = false, + }, { + .fourcc = V4L2_PIX_FMT_NV21, + .types = DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV420_SP, + .reg_swap_uv = true, + }, { + .fourcc = V4L2_PIX_FMT_NV21M, + .types = DW100_FMT_CAPTURE, + .reg_format = DW100_DEWARP_CTRL_FORMAT_YUV420_SP, + .reg_swap_uv = true, + }, +}; + +static inline int to_dw100_fmt_type(enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return DW100_FMT_OUTPUT; + else + return DW100_FMT_CAPTURE; +} + +static const struct dw100_fmt *dw100_find_pixel_format(u32 pixel_format, + int fmt_type) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + const struct dw100_fmt *fmt = &formats[i]; + + if (fmt->fourcc == pixel_format && fmt->types & fmt_type) + return fmt; + } + + return NULL; +} + +static const struct dw100_fmt *dw100_find_format(struct v4l2_format *f) +{ + return dw100_find_pixel_format(f->fmt.pix_mp.pixelformat, + to_dw100_fmt_type(f->type)); +} + +static inline u32 dw100_read(struct dw100_device *dw_dev, u32 reg) +{ + return readl(dw_dev->mmio + reg); +} + +static inline void dw100_write(struct dw100_device *dw_dev, u32 reg, u32 val) +{ + writel(val, dw_dev->mmio + reg); +} + +static inline int dw100_dump_regs(struct seq_file *m) +{ + struct dw100_device *dw_dev = m->private; +#define __DECLARE_REG(x) { #x, x } + unsigned int i; + static const struct reg_desc { + const char * const name; + unsigned int addr; + } dw100_regs[] = { + __DECLARE_REG(DW100_DEWARP_ID), + __DECLARE_REG(DW100_DEWARP_CTRL), + __DECLARE_REG(DW100_MAP_LUT_ADDR), + __DECLARE_REG(DW100_MAP_LUT_SIZE), + __DECLARE_REG(DW100_MAP_LUT_ADDR2), + __DECLARE_REG(DW100_MAP_LUT_SIZE2), + __DECLARE_REG(DW100_SRC_IMG_Y_BASE), + __DECLARE_REG(DW100_SRC_IMG_UV_BASE), + __DECLARE_REG(DW100_SRC_IMG_SIZE), + __DECLARE_REG(DW100_SRC_IMG_STRIDE), + __DECLARE_REG(DW100_DST_IMG_Y_BASE), + __DECLARE_REG(DW100_DST_IMG_UV_BASE), + __DECLARE_REG(DW100_DST_IMG_SIZE), + __DECLARE_REG(DW100_DST_IMG_STRIDE), + __DECLARE_REG(DW100_DST_IMG_Y_SIZE1), + __DECLARE_REG(DW100_DST_IMG_UV_SIZE1), + __DECLARE_REG(DW100_SRC_IMG_Y_BASE2), + __DECLARE_REG(DW100_SRC_IMG_UV_BASE2), + __DECLARE_REG(DW100_SRC_IMG_SIZE2), + __DECLARE_REG(DW100_SRC_IMG_STRIDE2), + __DECLARE_REG(DW100_DST_IMG_Y_BASE2), + __DECLARE_REG(DW100_DST_IMG_UV_BASE2), + __DECLARE_REG(DW100_DST_IMG_SIZE2), + __DECLARE_REG(DW100_DST_IMG_STRIDE2), + __DECLARE_REG(DW100_DST_IMG_Y_SIZE2), + __DECLARE_REG(DW100_DST_IMG_UV_SIZE2), + __DECLARE_REG(DW100_SWAP_CONTROL), + __DECLARE_REG(DW100_VERTICAL_SPLIT_LINE), + __DECLARE_REG(DW100_HORIZON_SPLIT_LINE), + __DECLARE_REG(DW100_SCALE_FACTOR), + __DECLARE_REG(DW100_ROI_START), + __DECLARE_REG(DW100_BOUNDARY_PIXEL), + __DECLARE_REG(DW100_INTERRUPT_STATUS), + __DECLARE_REG(DW100_BUS_CTRL), + __DECLARE_REG(DW100_BUS_CTRL1), + __DECLARE_REG(DW100_BUS_TIME_OUT_CYCLE), + }; + + for (i = 0; i < ARRAY_SIZE(dw100_regs); i++) + seq_printf(m, "%s: %#x\n", dw100_regs[i].name, + dw100_read(dw_dev, dw100_regs[i].addr)); + + return 0; +} + +static inline struct dw100_ctx *dw100_file2ctx(struct file *file) +{ + return container_of(file->private_data, struct dw100_ctx, fh); +} + +static struct dw100_q_data *dw100_get_q_data(struct dw100_ctx *ctx, + enum v4l2_buf_type type) +{ + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return &ctx->q_data[DW100_QUEUE_SRC]; + else + return &ctx->q_data[DW100_QUEUE_DST]; +} + +static u32 dw100_get_n_vertices_from_length(u32 length) +{ + return DIV_ROUND_UP(length, DW100_BLOCK_SIZE) + 1; +} + +static u16 dw100_map_convert_to_uq12_4(u32 a) +{ + return (u16)((a & 0xfff) << 4); +} + +static u32 dw100_map_format_coordinates(u16 xq, u16 yq) +{ + return (u32)((yq << 16) | xq); +} + +static u32 *dw100_get_user_map(struct dw100_ctx *ctx) +{ + struct v4l2_ctrl *ctrl = ctx->ctrls[DW100_CTRL_DEWARPING_MAP]; + + return ctrl->p_cur.p_u32; +} + +/* + * Create the dewarp map used by the hardware from the V4L2 control values which + * have been initialized with an identity map or set by the application. + */ +static int dw100_create_mapping(struct dw100_ctx *ctx) +{ + u32 *user_map; + + if (ctx->map) + dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size, + ctx->map, ctx->map_dma); + + ctx->map = dma_alloc_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size, + &ctx->map_dma, GFP_KERNEL); + + if (!ctx->map) + return -ENOMEM; + + user_map = dw100_get_user_map(ctx); + memcpy(ctx->map, user_map, ctx->map_size); + + dev_dbg(&ctx->dw_dev->pdev->dev, + "%ux%u %s mapping created (d:%pad-c:%p) for stream %ux%u->%ux%u\n", + ctx->map_width, ctx->map_height, + ctx->user_map_is_set ? "user" : "identity", + &ctx->map_dma, ctx->map, + ctx->q_data[DW100_QUEUE_SRC].pix_fmt.width, + ctx->q_data[DW100_QUEUE_DST].pix_fmt.height, + ctx->q_data[DW100_QUEUE_SRC].pix_fmt.width, + ctx->q_data[DW100_QUEUE_DST].pix_fmt.height); + + return 0; +} + +static void dw100_destroy_mapping(struct dw100_ctx *ctx) +{ + if (ctx->map) { + dma_free_coherent(&ctx->dw_dev->pdev->dev, ctx->map_size, + ctx->map, ctx->map_dma); + ctx->map = NULL; + } +} + +static int dw100_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct dw100_ctx *ctx = + container_of(ctrl->handler, struct dw100_ctx, hdl); + + switch (ctrl->id) { + case V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP: + ctx->user_map_is_set = true; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops dw100_ctrl_ops = { + .s_ctrl = dw100_s_ctrl, +}; + +/* + * Initialize the dewarping map with an identity mapping. + * + * A 16 pixels cell size grid is mapped on the destination image. + * The last cells width/height might be lesser than 16 if the destination image + * width/height is not divisible by 16. This dewarping grid map specifies the + * source image pixel location (x, y) on each grid intersection point. + * Bilinear interpolation is used to compute inner cell points locations. + * + * The coordinates are saved in UQ12.4 fixed point format. + */ +static void dw100_ctrl_dewarping_map_init(const struct v4l2_ctrl *ctrl, + u32 from_idx, + union v4l2_ctrl_ptr ptr) +{ + struct dw100_ctx *ctx = + container_of(ctrl->handler, struct dw100_ctx, hdl); + + u32 sw, sh, mw, mh, idx; + u16 qx, qy, qdx, qdy, qsh, qsw; + u32 *map = ctrl->p_cur.p_u32; + + sw = ctx->q_data[DW100_QUEUE_SRC].pix_fmt.width; + sh = ctx->q_data[DW100_QUEUE_SRC].pix_fmt.height; + + mw = ctrl->dims[0]; + mh = ctrl->dims[1]; + + qsw = dw100_map_convert_to_uq12_4(sw); + qsh = dw100_map_convert_to_uq12_4(sh); + qdx = qsw / (mw - 1); + qdy = qsh / (mh - 1); + + ctx->map_width = mw; + ctx->map_height = mh; + ctx->map_size = mh * mw * sizeof(u32); + + for (idx = from_idx; idx < ctrl->elems; idx++) { + qy = min_t(u32, (idx / mw) * qdy, qsh); + qx = min_t(u32, (idx % mw) * qdx, qsw); + map[idx] = dw100_map_format_coordinates(qx, qy); + } + + ctx->user_map_is_set = false; +} + +static const struct v4l2_ctrl_type_ops dw100_ctrl_type_ops = { + .init = dw100_ctrl_dewarping_map_init, + .validate = v4l2_ctrl_type_op_validate, + .log = v4l2_ctrl_type_op_log, + .equal = v4l2_ctrl_type_op_equal, +}; + +static const struct v4l2_ctrl_config controls[] = { + [DW100_CTRL_DEWARPING_MAP] = { + .ops = &dw100_ctrl_ops, + .type_ops = &dw100_ctrl_type_ops, + .id = V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP, + .name = "Dewarping Vertex Map", + .type = V4L2_CTRL_TYPE_U32, + .min = 0x00000000, + .max = 0xffffffff, + .step = 1, + .def = 0, + .dims = { DW100_DEF_LUT_W, DW100_DEF_LUT_H }, + }, +}; + +static int dw100_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct dw100_ctx *ctx = vb2_get_drv_priv(vq); + const struct v4l2_pix_format_mplane *format; + unsigned int i; + + format = &dw100_get_q_data(ctx, vq->type)->pix_fmt; + + if (*nplanes) { + if (*nplanes != format->num_planes) + return -EINVAL; + + for (i = 0; i < *nplanes; ++i) { + if (sizes[i] < format->plane_fmt[i].sizeimage) + return -EINVAL; + } + + return 0; + } + + *nplanes = format->num_planes; + + for (i = 0; i < format->num_planes; ++i) + sizes[i] = format->plane_fmt[i].sizeimage; + + return 0; +} + +static int dw100_buf_prepare(struct vb2_buffer *vb) +{ + unsigned int i; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dw100_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct dw100_device *dw_dev = ctx->dw_dev; + const struct v4l2_pix_format_mplane *pix_fmt = + &dw100_get_q_data(ctx, vb->vb2_queue->type)->pix_fmt; + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vbuf->field != V4L2_FIELD_NONE) { + dev_dbg(&dw_dev->pdev->dev, "%x field isn't supported\n", + vbuf->field); + return -EINVAL; + } + } + + for (i = 0; i < pix_fmt->num_planes; i++) { + unsigned long size = pix_fmt->plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dev_dbg(&dw_dev->pdev->dev, + "User buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void dw100_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dw100_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static void dw100_return_all_buffers(struct vb2_queue *q, + enum vb2_buffer_state state) +{ + struct dw100_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + return; + v4l2_m2m_buf_done(vbuf, state); + } +} + +static int dw100_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct dw100_ctx *ctx = vb2_get_drv_priv(q); + struct dw100_q_data *q_data = dw100_get_q_data(ctx, q->type); + int ret; + + q_data->sequence = 0; + + ret = dw100_create_mapping(ctx); + if (ret) + goto err; + + ret = pm_runtime_resume_and_get(&ctx->dw_dev->pdev->dev); + if (ret) { + dw100_destroy_mapping(ctx); + goto err; + } + + return 0; +err: + dw100_return_all_buffers(q, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void dw100_stop_streaming(struct vb2_queue *q) +{ + struct dw100_ctx *ctx = vb2_get_drv_priv(q); + + dw100_return_all_buffers(q, VB2_BUF_STATE_ERROR); + + pm_runtime_put_sync(&ctx->dw_dev->pdev->dev); + + dw100_destroy_mapping(ctx); +} + +static const struct vb2_ops dw100_qops = { + .queue_setup = dw100_queue_setup, + .buf_prepare = dw100_buf_prepare, + .buf_queue = dw100_buf_queue, + .start_streaming = dw100_start_streaming, + .stop_streaming = dw100_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int dw100_m2m_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct dw100_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &dw100_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->vq_mutex; + src_vq->dev = ctx->dw_dev->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &dw100_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->vq_mutex; + dst_vq->dev = ctx->dw_dev->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int dw100_open(struct file *file) +{ + struct dw100_device *dw_dev = video_drvdata(file); + struct dw100_ctx *ctx; + struct v4l2_ctrl_handler *hdl; + struct v4l2_pix_format_mplane *pix_fmt; + int ret, i; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_init(&ctx->vq_mutex); + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + ctx->dw_dev = dw_dev; + + ctx->q_data[DW100_QUEUE_SRC].fmt = &formats[0]; + + pix_fmt = &ctx->q_data[DW100_QUEUE_SRC].pix_fmt; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_REC709; + pix_fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix_fmt->colorspace); + pix_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix_fmt->colorspace); + pix_fmt->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, pix_fmt->colorspace, + pix_fmt->ycbcr_enc); + + v4l2_fill_pixfmt_mp(pix_fmt, formats[0].fourcc, DW100_DEF_W, DW100_DEF_H); + + ctx->q_data[DW100_QUEUE_SRC].crop.top = 0; + ctx->q_data[DW100_QUEUE_SRC].crop.left = 0; + ctx->q_data[DW100_QUEUE_SRC].crop.width = DW100_DEF_W; + ctx->q_data[DW100_QUEUE_SRC].crop.height = DW100_DEF_H; + + ctx->q_data[DW100_QUEUE_DST] = ctx->q_data[DW100_QUEUE_SRC]; + + hdl = &ctx->hdl; + v4l2_ctrl_handler_init(hdl, ARRAY_SIZE(controls)); + for (i = 0; i < ARRAY_SIZE(controls); i++) { + ctx->ctrls[i] = v4l2_ctrl_new_custom(hdl, &controls[i], NULL); + if (hdl->error) { + dev_err(&ctx->dw_dev->pdev->dev, + "Adding control (%d) failed\n", i); + ret = hdl->error; + goto err; + } + } + ctx->fh.ctrl_handler = hdl; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dw_dev->m2m_dev, + ctx, &dw100_m2m_queue_init); + + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto err; + } + + v4l2_fh_add(&ctx->fh); + + return 0; + +err: + v4l2_ctrl_handler_free(hdl); + v4l2_fh_exit(&ctx->fh); + mutex_destroy(&ctx->vq_mutex); + kfree(ctx); + + return ret; +} + +static int dw100_release(struct file *file) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + mutex_destroy(&ctx->vq_mutex); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations dw100_fops = { + .owner = THIS_MODULE, + .open = dw100_open, + .release = dw100_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int dw100_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); + strscpy(cap->card, "DW100 dewarper", sizeof(cap->card)); + + return 0; +} + +static int dw100_enum_fmt_vid(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + int i, num = 0; + + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].types & to_dw100_fmt_type(f->type)) { + if (num == f->index) { + f->pixelformat = formats[i].fourcc; + return 0; + } + ++num; + } + } + + return -EINVAL; +} + +static int dw100_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + const struct dw100_fmt *fmt; + + if (fsize->index) + return -EINVAL; + + fmt = dw100_find_pixel_format(fsize->pixel_format, + DW100_FMT_OUTPUT | DW100_FMT_CAPTURE); + if (!fmt) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = dw100_frmsize_stepwise; + + return 0; +} + +static int dw100_g_fmt_vid(struct file *file, void *priv, struct v4l2_format *f) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + struct vb2_queue *vq; + struct dw100_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = dw100_get_q_data(ctx, f->type); + + f->fmt.pix_mp = q_data->pix_fmt; + + return 0; +} + +static int dw100_try_fmt(struct file *file, struct v4l2_format *f) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + const struct dw100_fmt *fmt; + + fmt = dw100_find_format(f); + if (!fmt) { + fmt = &formats[0]; + pix->pixelformat = fmt->fourcc; + } + + v4l2_apply_frmsize_constraints(&pix->width, &pix->height, + &dw100_frmsize_stepwise); + + v4l2_fill_pixfmt_mp(pix, fmt->fourcc, pix->width, pix->height); + + pix->field = V4L2_FIELD_NONE; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (pix->colorspace == V4L2_COLORSPACE_DEFAULT) + pix->colorspace = V4L2_COLORSPACE_REC709; + if (pix->xfer_func == V4L2_XFER_FUNC_DEFAULT) + pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace); + if (pix->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); + if (pix->quantization == V4L2_QUANTIZATION_DEFAULT) + pix->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, + pix->colorspace, + pix->ycbcr_enc); + } else { + /* + * The DW100 can't perform colorspace conversion, the colorspace + * on the capture queue must be identical to the output queue. + */ + const struct dw100_q_data *q_data = + dw100_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + pix->colorspace = q_data->pix_fmt.colorspace; + pix->xfer_func = q_data->pix_fmt.xfer_func; + pix->ycbcr_enc = q_data->pix_fmt.ycbcr_enc; + pix->quantization = q_data->pix_fmt.quantization; + } + + return 0; +} + +static int dw100_s_fmt(struct dw100_ctx *ctx, struct v4l2_format *f) +{ + struct dw100_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = dw100_get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + dev_dbg(&ctx->dw_dev->pdev->dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = dw100_find_format(f); + q_data->pix_fmt = f->fmt.pix_mp; + q_data->crop.top = 0; + q_data->crop.left = 0; + q_data->crop.width = f->fmt.pix_mp.width; + q_data->crop.height = f->fmt.pix_mp.height; + + /* Propagate buffers encoding */ + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct dw100_q_data *dst_q_data = + dw100_get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + dst_q_data->pix_fmt.colorspace = q_data->pix_fmt.colorspace; + dst_q_data->pix_fmt.ycbcr_enc = q_data->pix_fmt.ycbcr_enc; + dst_q_data->pix_fmt.quantization = q_data->pix_fmt.quantization; + dst_q_data->pix_fmt.xfer_func = q_data->pix_fmt.xfer_func; + } + + dev_dbg(&ctx->dw_dev->pdev->dev, + "Setting format for type %u, wxh: %ux%u, fmt: %p4cc\n", + f->type, q_data->pix_fmt.width, q_data->pix_fmt.height, + &q_data->pix_fmt.pixelformat); + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + int ret; + u32 dims[V4L2_CTRL_MAX_DIMS] = {}; + struct v4l2_ctrl *ctrl = ctx->ctrls[DW100_CTRL_DEWARPING_MAP]; + + dims[0] = dw100_get_n_vertices_from_length(q_data->pix_fmt.width); + dims[1] = dw100_get_n_vertices_from_length(q_data->pix_fmt.height); + + ret = v4l2_ctrl_modify_dimensions(ctrl, dims); + + if (ret) { + dev_err(&ctx->dw_dev->pdev->dev, + "Modifying LUT dimensions failed with error %d\n", + ret); + return ret; + } + } + + return 0; +} + +static int dw100_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + return dw100_try_fmt(file, f); +} + +static int dw100_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + int ret; + + ret = dw100_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + ret = dw100_s_fmt(ctx, f); + if (ret) + return ret; + + return 0; +} + +static int dw100_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + return dw100_try_fmt(file, f); +} + +static int dw100_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + int ret; + + ret = dw100_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = dw100_s_fmt(ctx, f); + if (ret) + return ret; + + return 0; +} + +static int dw100_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + struct dw100_q_data *src_q_data; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + src_q_data = dw100_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = src_q_data->pix_fmt.width; + sel->r.height = src_q_data->pix_fmt.height; + break; + case V4L2_SEL_TGT_CROP: + sel->r.top = src_q_data->crop.top; + sel->r.left = src_q_data->crop.left; + sel->r.width = src_q_data->crop.width; + sel->r.height = src_q_data->crop.height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dw100_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct dw100_ctx *ctx = dw100_file2ctx(file); + struct dw100_q_data *src_q_data; + u32 qscalex, qscaley, qscale; + int x, y, w, h; + unsigned int wframe, hframe; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + src_q_data = dw100_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + dev_dbg(&ctx->dw_dev->pdev->dev, + ">>> Buffer Type: %u Target: %u Rect: %ux%u@%d.%d\n", + sel->type, sel->target, + sel->r.width, sel->r.height, sel->r.left, sel->r.top); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + wframe = src_q_data->pix_fmt.width; + hframe = src_q_data->pix_fmt.height; + + sel->r.top = clamp_t(int, sel->r.top, 0, hframe - DW100_MIN_H); + sel->r.left = clamp_t(int, sel->r.left, 0, wframe - DW100_MIN_W); + sel->r.height = + clamp(sel->r.height, DW100_MIN_H, hframe - sel->r.top); + sel->r.width = + clamp(sel->r.width, DW100_MIN_W, wframe - sel->r.left); + + /* UQ16.16 for float operations */ + qscalex = (sel->r.width << 16) / wframe; + qscaley = (sel->r.height << 16) / hframe; + y = sel->r.top; + x = sel->r.left; + if (qscalex == qscaley) { + qscale = qscalex; + } else { + switch (sel->flags) { + case 0: + qscale = (qscalex + qscaley) / 2; + break; + case V4L2_SEL_FLAG_GE: + qscale = max(qscaley, qscalex); + break; + case V4L2_SEL_FLAG_LE: + qscale = min(qscaley, qscalex); + break; + case V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE: + return -ERANGE; + default: + return -EINVAL; + } + } + + w = (u32)((((u64)wframe << 16) * qscale) >> 32); + h = (u32)((((u64)hframe << 16) * qscale) >> 32); + x = x + (sel->r.width - w) / 2; + y = y + (sel->r.height - h) / 2; + x = min(wframe - w, (unsigned int)max(0, x)); + y = min(hframe - h, (unsigned int)max(0, y)); + + sel->r.top = y; + sel->r.left = x; + sel->r.width = w; + sel->r.height = h; + + src_q_data->crop.top = sel->r.top; + src_q_data->crop.left = sel->r.left; + src_q_data->crop.width = sel->r.width; + src_q_data->crop.height = sel->r.height; + break; + + default: + return -EINVAL; + } + + dev_dbg(&ctx->dw_dev->pdev->dev, + "<<< Buffer Type: %u Target: %u Rect: %ux%u@%d.%d\n", + sel->type, sel->target, + sel->r.width, sel->r.height, sel->r.left, sel->r.top); + + return 0; +} + +static const struct v4l2_ioctl_ops dw100_ioctl_ops = { + .vidioc_querycap = dw100_querycap, + + .vidioc_enum_fmt_vid_cap = dw100_enum_fmt_vid, + .vidioc_enum_framesizes = dw100_enum_framesizes, + .vidioc_g_fmt_vid_cap_mplane = dw100_g_fmt_vid, + .vidioc_try_fmt_vid_cap_mplane = dw100_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = dw100_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = dw100_enum_fmt_vid, + .vidioc_g_fmt_vid_out_mplane = dw100_g_fmt_vid, + .vidioc_try_fmt_vid_out_mplane = dw100_try_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = dw100_s_fmt_vid_out, + + .vidioc_g_selection = dw100_g_selection, + .vidioc_s_selection = dw100_s_selection, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static void dw100_job_finish(struct dw100_device *dw_dev, bool with_error) +{ + struct dw100_ctx *curr_ctx; + struct vb2_v4l2_buffer *src_vb, *dst_vb; + enum vb2_buffer_state buf_state; + + curr_ctx = v4l2_m2m_get_curr_priv(dw_dev->m2m_dev); + + if (!curr_ctx) { + dev_err(&dw_dev->pdev->dev, + "Instance released before the end of transaction\n"); + return; + } + + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); + + if (likely(!with_error)) + buf_state = VB2_BUF_STATE_DONE; + else + buf_state = VB2_BUF_STATE_ERROR; + + v4l2_m2m_buf_done(src_vb, buf_state); + v4l2_m2m_buf_done(dst_vb, buf_state); + + dev_dbg(&dw_dev->pdev->dev, "Finishing transaction with%s error(s)\n", + with_error ? "" : "out"); + + v4l2_m2m_job_finish(dw_dev->m2m_dev, curr_ctx->fh.m2m_ctx); +} + +static void dw100_hw_reset(struct dw100_device *dw_dev) +{ + u32 val; + + val = dw100_read(dw_dev, DW100_DEWARP_CTRL); + val |= DW100_DEWARP_CTRL_ENABLE; + val |= DW100_DEWARP_CTRL_SOFT_RESET; + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); + val &= ~DW100_DEWARP_CTRL_SOFT_RESET; + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); +} + +static void _dw100_hw_set_master_bus_enable(struct dw100_device *dw_dev, + unsigned int enable) +{ + u32 val; + + dev_dbg(&dw_dev->pdev->dev, "%sable master bus\n", + enable ? "En" : "Dis"); + + val = dw100_read(dw_dev, DW100_BUS_CTRL); + + if (enable) + val |= DW100_BUS_CTRL_AXI_MASTER_ENABLE; + else + val &= ~DW100_BUS_CTRL_AXI_MASTER_ENABLE; + + dw100_write(dw_dev, DW100_BUS_CTRL, val); +} + +static void dw100_hw_master_bus_enable(struct dw100_device *dw_dev) +{ + _dw100_hw_set_master_bus_enable(dw_dev, 1); +} + +static void dw100_hw_master_bus_disable(struct dw100_device *dw_dev) +{ + _dw100_hw_set_master_bus_enable(dw_dev, 0); +} + +static void dw100_hw_dewarp_start(struct dw100_device *dw_dev) +{ + u32 val; + + val = dw100_read(dw_dev, DW100_DEWARP_CTRL); + + dev_dbg(&dw_dev->pdev->dev, "Starting Hardware CTRL:0x%08x\n", val); + dw100_write(dw_dev, DW100_DEWARP_CTRL, val | DW100_DEWARP_CTRL_START); + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); +} + +static void dw100_hw_init_ctrl(struct dw100_device *dw_dev) +{ + u32 val; + /* + * Input format YUV422_SP + * Output format YUV422_SP + * No hardware handshake (SW) + * No automatic double src buffering (Single) + * No automatic double dst buffering (Single) + * No Black Line + * Prefetch image pixel traversal + */ + + val = DW100_DEWARP_CTRL_ENABLE + /* Valid only for auto prefetch mode*/ + | DW100_DEWARP_CTRL_PREFETCH_THRESHOLD(32); + + /* + * Calculation mode required to support any scaling factor, + * but x4 slower than traversal mode. + * + * DW100_DEWARP_CTRL_PREFETCH_MODE_TRAVERSAL + * DW100_DEWARP_CTRL_PREFETCH_MODE_CALCULATION + * DW100_DEWARP_CTRL_PREFETCH_MODE_AUTO + * + * TODO: Find heuristics requiring calculation mode + */ + val |= DW100_DEWARP_CTRL_PREFETCH_MODE_CALCULATION; + + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); +} + +static void dw100_hw_set_pixel_boundary(struct dw100_device *dw_dev) +{ + u32 val; + + val = DW100_BOUNDARY_PIXEL_V(128) + | DW100_BOUNDARY_PIXEL_U(128) + | DW100_BOUNDARY_PIXEL_Y(0); + + dw100_write(dw_dev, DW100_BOUNDARY_PIXEL, val); +} + +static void dw100_hw_set_scale(struct dw100_device *dw_dev, u8 scale) +{ + dev_dbg(&dw_dev->pdev->dev, "Setting scale factor to %u\n", scale); + + dw100_write(dw_dev, DW100_SCALE_FACTOR, scale); +} + +static void dw100_hw_set_roi(struct dw100_device *dw_dev, u32 x, u32 y) +{ + u32 val; + + dev_dbg(&dw_dev->pdev->dev, "Setting ROI region to %u.%u\n", x, y); + + val = DW100_ROI_START_X(x) | DW100_ROI_START_Y(y); + + dw100_write(dw_dev, DW100_ROI_START, val); +} + +static void dw100_hw_set_src_crop(struct dw100_device *dw_dev, + const struct dw100_q_data *src_q_data, + const struct dw100_q_data *dst_q_data) +{ + const struct v4l2_rect *rect = &src_q_data->crop; + u32 src_scale, qscale, left_scale, top_scale; + + /* HW Scale is UQ1.7 encoded */ + src_scale = (rect->width << 7) / src_q_data->pix_fmt.width; + dw100_hw_set_scale(dw_dev, src_scale); + + qscale = (dst_q_data->pix_fmt.width << 7) / src_q_data->pix_fmt.width; + + left_scale = ((rect->left << 7) * qscale) >> 14; + top_scale = ((rect->top << 7) * qscale) >> 14; + + dw100_hw_set_roi(dw_dev, left_scale, top_scale); +} + +static void dw100_hw_set_source(struct dw100_device *dw_dev, + const struct dw100_q_data *q_data, + struct vb2_buffer *buffer) +{ + u32 width, height, stride, fourcc, val; + const struct dw100_fmt *fmt = q_data->fmt; + dma_addr_t addr_y = vb2_dma_contig_plane_dma_addr(buffer, 0); + dma_addr_t addr_uv; + + width = q_data->pix_fmt.width; + height = q_data->pix_fmt.height; + stride = q_data->pix_fmt.plane_fmt[0].bytesperline; + fourcc = q_data->fmt->fourcc; + + if (q_data->pix_fmt.num_planes == 2) + addr_uv = vb2_dma_contig_plane_dma_addr(buffer, 1); + else + addr_uv = addr_y + (stride * height); + + dev_dbg(&dw_dev->pdev->dev, + "Set HW source registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", + width, height, stride, &fourcc, &addr_y); + + /* Pixel Format */ + val = dw100_read(dw_dev, DW100_DEWARP_CTRL); + + val &= ~DW100_DEWARP_CTRL_INPUT_FORMAT_MASK; + val |= DW100_DEWARP_CTRL_INPUT_FORMAT(fmt->reg_format); + + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); + + /* Swap */ + val = dw100_read(dw_dev, DW100_SWAP_CONTROL); + + val &= ~DW100_SWAP_CONTROL_SRC_MASK; + /* + * Data swapping is performed only on Y plane for source image. + */ + if (fmt->reg_swap_uv && + fmt->reg_format == DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED) + val |= DW100_SWAP_CONTROL_SRC(DW100_SWAP_CONTROL_Y + (DW100_SWAP_CONTROL_BYTE)); + + dw100_write(dw_dev, DW100_SWAP_CONTROL, val); + + /* Image resolution */ + dw100_write(dw_dev, DW100_SRC_IMG_SIZE, + DW100_IMG_SIZE_WIDTH(width) | DW100_IMG_SIZE_HEIGHT(height)); + + dw100_write(dw_dev, DW100_SRC_IMG_STRIDE, stride); + + /* Buffers */ + dw100_write(dw_dev, DW100_SRC_IMG_Y_BASE, DW100_IMG_Y_BASE(addr_y)); + dw100_write(dw_dev, DW100_SRC_IMG_UV_BASE, DW100_IMG_UV_BASE(addr_uv)); +} + +static void dw100_hw_set_destination(struct dw100_device *dw_dev, + const struct dw100_q_data *q_data, + const struct dw100_fmt *ifmt, + struct vb2_buffer *buffer) +{ + u32 width, height, stride, fourcc, val, size_y, size_uv; + const struct dw100_fmt *fmt = q_data->fmt; + dma_addr_t addr_y, addr_uv; + + width = q_data->pix_fmt.width; + height = q_data->pix_fmt.height; + stride = q_data->pix_fmt.plane_fmt[0].bytesperline; + fourcc = fmt->fourcc; + + addr_y = vb2_dma_contig_plane_dma_addr(buffer, 0); + size_y = q_data->pix_fmt.plane_fmt[0].sizeimage; + + if (q_data->pix_fmt.num_planes == 2) { + addr_uv = vb2_dma_contig_plane_dma_addr(buffer, 1); + size_uv = q_data->pix_fmt.plane_fmt[1].sizeimage; + } else { + addr_uv = addr_y + ALIGN(stride * height, 16); + size_uv = size_y; + if (fmt->reg_format == DW100_DEWARP_CTRL_FORMAT_YUV420_SP) + size_uv /= 2; + } + + dev_dbg(&dw_dev->pdev->dev, + "Set HW source registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n", + width, height, stride, &fourcc, &addr_y); + + /* Pixel Format */ + val = dw100_read(dw_dev, DW100_DEWARP_CTRL); + + val &= ~DW100_DEWARP_CTRL_OUTPUT_FORMAT_MASK; + val |= DW100_DEWARP_CTRL_OUTPUT_FORMAT(fmt->reg_format); + + dw100_write(dw_dev, DW100_DEWARP_CTRL, val); + + /* Swap */ + val = dw100_read(dw_dev, DW100_SWAP_CONTROL); + + val &= ~DW100_SWAP_CONTROL_DST_MASK; + + /* + * Avoid to swap twice + */ + if (fmt->reg_swap_uv ^ + (ifmt->reg_swap_uv && ifmt->reg_format != + DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED)) { + if (fmt->reg_format == DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED) + val |= DW100_SWAP_CONTROL_DST(DW100_SWAP_CONTROL_Y + (DW100_SWAP_CONTROL_BYTE)); + else + val |= DW100_SWAP_CONTROL_DST(DW100_SWAP_CONTROL_UV + (DW100_SWAP_CONTROL_BYTE)); + } + + dw100_write(dw_dev, DW100_SWAP_CONTROL, val); + + /* Image resolution */ + dw100_write(dw_dev, DW100_DST_IMG_SIZE, + DW100_IMG_SIZE_WIDTH(width) | DW100_IMG_SIZE_HEIGHT(height)); + dw100_write(dw_dev, DW100_DST_IMG_STRIDE, stride); + dw100_write(dw_dev, DW100_DST_IMG_Y_BASE, DW100_IMG_Y_BASE(addr_y)); + dw100_write(dw_dev, DW100_DST_IMG_UV_BASE, DW100_IMG_UV_BASE(addr_uv)); + dw100_write(dw_dev, DW100_DST_IMG_Y_SIZE1, DW100_DST_IMG_Y_SIZE(size_y)); + dw100_write(dw_dev, DW100_DST_IMG_UV_SIZE1, + DW100_DST_IMG_UV_SIZE(size_uv)); +} + +static void dw100_hw_set_mapping(struct dw100_device *dw_dev, dma_addr_t addr, + u32 width, u32 height) +{ + dev_dbg(&dw_dev->pdev->dev, + "Set HW mapping registers for %ux%u addr:%pad", + width, height, &addr); + + dw100_write(dw_dev, DW100_MAP_LUT_ADDR, DW100_MAP_LUT_ADDR_ADDR(addr)); + dw100_write(dw_dev, DW100_MAP_LUT_SIZE, DW100_MAP_LUT_SIZE_WIDTH(width) + | DW100_MAP_LUT_SIZE_HEIGHT(height)); +} + +static void dw100_hw_clear_irq(struct dw100_device *dw_dev, unsigned int irq) +{ + dw100_write(dw_dev, DW100_INTERRUPT_STATUS, + DW100_INTERRUPT_STATUS_INT_CLEAR(irq)); +} + +static void dw100_hw_enable_irq(struct dw100_device *dw_dev) +{ + dw100_write(dw_dev, DW100_INTERRUPT_STATUS, + DW100_INTERRUPT_STATUS_INT_ENABLE_MASK); +} + +static void dw100_hw_disable_irq(struct dw100_device *dw_dev) +{ + dw100_write(dw_dev, DW100_INTERRUPT_STATUS, 0); +} + +static u32 dw_hw_get_pending_irqs(struct dw100_device *dw_dev) +{ + u32 val; + + val = dw100_read(dw_dev, DW100_INTERRUPT_STATUS); + + return DW100_INTERRUPT_STATUS_INT_STATUS(val); +} + +static irqreturn_t dw100_irq_handler(int irq, void *dev_id) +{ + struct dw100_device *dw_dev = dev_id; + u32 pending_irqs, err_irqs, frame_done_irq; + bool with_error = true; + + pending_irqs = dw_hw_get_pending_irqs(dw_dev); + frame_done_irq = pending_irqs & DW100_INTERRUPT_STATUS_INT_FRAME_DONE; + err_irqs = DW100_INTERRUPT_STATUS_INT_ERR_STATUS(pending_irqs); + + if (frame_done_irq) { + dev_dbg(&dw_dev->pdev->dev, "Frame done interrupt\n"); + with_error = false; + err_irqs &= ~DW100_INTERRUPT_STATUS_INT_ERR_STATUS + (DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE); + } + + if (err_irqs) + dev_err(&dw_dev->pdev->dev, "Interrupt error: %#x\n", err_irqs); + + dw100_hw_disable_irq(dw_dev); + dw100_hw_master_bus_disable(dw_dev); + dw100_hw_clear_irq(dw_dev, pending_irqs | + DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT); + + dw100_job_finish(dw_dev, with_error); + + return IRQ_HANDLED; +} + +static void dw100_start(struct dw100_ctx *ctx, struct vb2_v4l2_buffer *in_vb, + struct vb2_v4l2_buffer *out_vb) +{ + struct dw100_device *dw_dev = ctx->dw_dev; + + out_vb->sequence = + dw100_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)->sequence++; + in_vb->sequence = + dw100_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)->sequence++; + + dev_dbg(&ctx->dw_dev->pdev->dev, + "Starting queues %p->%p, sequence %u->%u\n", + v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE), + v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE), + in_vb->sequence, out_vb->sequence); + + v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); + + /* Now, let's deal with hardware ... */ + dw100_hw_master_bus_disable(dw_dev); + dw100_hw_init_ctrl(dw_dev); + dw100_hw_set_pixel_boundary(dw_dev); + dw100_hw_set_src_crop(dw_dev, &ctx->q_data[DW100_QUEUE_SRC], + &ctx->q_data[DW100_QUEUE_DST]); + dw100_hw_set_source(dw_dev, &ctx->q_data[DW100_QUEUE_SRC], + &in_vb->vb2_buf); + dw100_hw_set_destination(dw_dev, &ctx->q_data[DW100_QUEUE_DST], + ctx->q_data[DW100_QUEUE_SRC].fmt, + &out_vb->vb2_buf); + dw100_hw_set_mapping(dw_dev, ctx->map_dma, + ctx->map_width, ctx->map_height); + dw100_hw_enable_irq(dw_dev); + dw100_hw_dewarp_start(dw_dev); + + /* Enable Bus */ + dw100_hw_master_bus_enable(dw_dev); +} + +static void dw100_device_run(void *priv) +{ + struct dw100_ctx *ctx = priv; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + dw100_start(ctx, src_buf, dst_buf); +} + +static const struct v4l2_m2m_ops dw100_m2m_ops = { + .device_run = dw100_device_run, +}; + +static struct video_device *dw100_init_video_device(struct dw100_device *dw_dev) +{ + struct video_device *vfd = &dw_dev->vfd; + + vfd->vfl_dir = VFL_DIR_M2M; + vfd->fops = &dw100_fops; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + vfd->ioctl_ops = &dw100_ioctl_ops; + vfd->minor = -1; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dw_dev->v4l2_dev; + vfd->lock = &dw_dev->vfd_mutex; + + strscpy(vfd->name, DRV_NAME, sizeof(vfd->name)); + mutex_init(vfd->lock); + video_set_drvdata(vfd, dw_dev); + + return vfd; +} + +static int dw100_dump_regs_show(struct seq_file *m, void *private) +{ + struct dw100_device *dw_dev = m->private; + int ret; + + ret = pm_runtime_resume_and_get(&dw_dev->pdev->dev); + if (ret < 0) + return ret; + + ret = dw100_dump_regs(m); + + pm_runtime_put_sync(&dw_dev->pdev->dev); + + return ret; +} +DEFINE_SHOW_ATTRIBUTE(dw100_dump_regs); + +static void dw100_debugfs_init(struct dw100_device *dw_dev) +{ + dw_dev->debugfs_root = + debugfs_create_dir(dev_name(&dw_dev->pdev->dev), NULL); + + debugfs_create_file("dump_regs", 0600, dw_dev->debugfs_root, dw_dev, + &dw100_dump_regs_fops); +} + +static void dw100_debugfs_exit(struct dw100_device *dw_dev) +{ + debugfs_remove_recursive(dw_dev->debugfs_root); +} + +static int dw100_probe(struct platform_device *pdev) +{ + struct dw100_device *dw_dev; + struct video_device *vfd; + struct resource *res; + int ret, irq; + + dw_dev = devm_kzalloc(&pdev->dev, sizeof(*dw_dev), GFP_KERNEL); + if (!dw_dev) + return -ENOMEM; + dw_dev->pdev = pdev; + + ret = devm_clk_bulk_get_all(&pdev->dev, &dw_dev->clks); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to get clocks: %d\n", ret); + return ret; + } + dw_dev->num_clks = ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dw_dev->mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dw_dev->mmio)) + return PTR_ERR(dw_dev->mmio); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + platform_set_drvdata(pdev, dw_dev); + + pm_runtime_enable(&pdev->dev); + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to resume the device: %d\n", ret); + goto err_pm; + } + + pm_runtime_put_sync(&pdev->dev); + + ret = devm_request_irq(&pdev->dev, irq, dw100_irq_handler, IRQF_ONESHOT, + dev_name(&pdev->dev), dw_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + return ret; + } + + ret = v4l2_device_register(&pdev->dev, &dw_dev->v4l2_dev); + if (ret) + goto err_pm; + + vfd = dw100_init_video_device(dw_dev); + + dw_dev->m2m_dev = v4l2_m2m_init(&dw100_m2m_ops); + if (IS_ERR(dw_dev->m2m_dev)) { + dev_err(&pdev->dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dw_dev->m2m_dev); + goto err_v4l2; + } + + dw_dev->mdev.dev = &pdev->dev; + strscpy(dw_dev->mdev.model, "dw100", sizeof(dw_dev->mdev.model)); + media_device_init(&dw_dev->mdev); + dw_dev->v4l2_dev.mdev = &dw_dev->mdev; + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(&pdev->dev, "Failed to register video device\n"); + goto err_m2m; + } + + ret = v4l2_m2m_register_media_controller(dw_dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + if (ret) { + dev_err(&pdev->dev, "Failed to init mem2mem media controller\n"); + goto error_v4l2; + } + + ret = media_device_register(&dw_dev->mdev); + if (ret) { + dev_err(&pdev->dev, "Failed to register mem2mem media device\n"); + goto error_m2m_mc; + } + + dw100_debugfs_init(dw_dev); + + dev_info(&pdev->dev, + "dw100 v4l2 m2m registered as /dev/video%u\n", vfd->num); + + return 0; + +error_m2m_mc: + v4l2_m2m_unregister_media_controller(dw_dev->m2m_dev); +error_v4l2: + video_unregister_device(vfd); +err_m2m: + media_device_cleanup(&dw_dev->mdev); + v4l2_m2m_release(dw_dev->m2m_dev); +err_v4l2: + v4l2_device_unregister(&dw_dev->v4l2_dev); +err_pm: + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int dw100_remove(struct platform_device *pdev) +{ + struct dw100_device *dw_dev = platform_get_drvdata(pdev); + + dw100_debugfs_exit(dw_dev); + + pm_runtime_disable(&pdev->dev); + + media_device_unregister(&dw_dev->mdev); + v4l2_m2m_unregister_media_controller(dw_dev->m2m_dev); + media_device_cleanup(&dw_dev->mdev); + + video_unregister_device(&dw_dev->vfd); + mutex_destroy(dw_dev->vfd.lock); + v4l2_m2m_release(dw_dev->m2m_dev); + v4l2_device_unregister(&dw_dev->v4l2_dev); + + return 0; +} + +static int __maybe_unused dw100_runtime_suspend(struct device *dev) +{ + struct dw100_device *dw_dev = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(dw_dev->num_clks, dw_dev->clks); + + return 0; +} + +static int __maybe_unused dw100_runtime_resume(struct device *dev) +{ + int ret; + struct dw100_device *dw_dev = dev_get_drvdata(dev); + + ret = clk_bulk_prepare_enable(dw_dev->num_clks, dw_dev->clks); + + if (ret) + return ret; + + dw100_hw_reset(dw_dev); + + return 0; +} + +static const struct dev_pm_ops dw100_pm = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(dw100_runtime_suspend, + dw100_runtime_resume, NULL) +}; + +static const struct of_device_id dw100_dt_ids[] = { + { .compatible = "nxp,imx8mp-dw100", .data = NULL }, + { }, +}; +MODULE_DEVICE_TABLE(of, dw100_dt_ids); + +static struct platform_driver dw100_driver = { + .probe = dw100_probe, + .remove = dw100_remove, + .driver = { + .name = DRV_NAME, + .pm = &dw100_pm, + .of_match_table = dw100_dt_ids, + }, +}; + +module_platform_driver(dw100_driver); + +MODULE_DESCRIPTION("DW100 Hardware dewarper"); +MODULE_AUTHOR("Xavier Roumegue <Xavier.Roumegue@oss.nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/nxp/dw100/dw100_regs.h b/drivers/media/platform/nxp/dw100/dw100_regs.h new file mode 100644 index 000000000000..e85dfeff9056 --- /dev/null +++ b/drivers/media/platform/nxp/dw100/dw100_regs.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * DW100 Hardware dewarper + * + * Copyright 2022 NXP + * Author: Xavier Roumegue (xavier.roumegue@oss.nxp.com) + */ + +#ifndef _DW100_REGS_H_ +#define _DW100_REGS_H_ + +/* AHB register offset */ +#define DW100_DEWARP_ID 0x00 +#define DW100_DEWARP_CTRL 0x04 +#define DW100_DEWARP_CTRL_ENABLE BIT(0) +#define DW100_DEWARP_CTRL_START BIT(1) +#define DW100_DEWARP_CTRL_SOFT_RESET BIT(2) +#define DW100_DEWARP_CTRL_FORMAT_YUV422_SP 0UL +#define DW100_DEWARP_CTRL_FORMAT_YUV422_PACKED 1UL +#define DW100_DEWARP_CTRL_FORMAT_YUV420_SP 2UL +#define DW100_DEWARP_CTRL_INPUT_FORMAT_MASK GENMASK(5, 4) +#define DW100_DEWARP_CTRL_INPUT_FORMAT(x) ((x) << 4) +#define DW100_DEWARP_CTRL_OUTPUT_FORMAT(x) ((x) << 6) +#define DW100_DEWARP_CTRL_OUTPUT_FORMAT_MASK GENMASK(7, 6) +#define DW100_DEWARP_CTRL_SRC_AUTO_SHADOW BIT(8) +#define DW100_DEWARP_CTRL_HW_HANDSHAKE BIT(9) +#define DW100_DEWARP_CTRL_DST_AUTO_SHADOW BIT(10) +#define DW100_DEWARP_CTRL_SPLIT_LINE BIT(11) +#define DW100_DEWARP_CTRL_PREFETCH_MODE_MASK GENMASK(17, 16) +#define DW100_DEWARP_CTRL_PREFETCH_MODE_TRAVERSAL (0UL << 16) +#define DW100_DEWARP_CTRL_PREFETCH_MODE_CALCULATION (1UL << 16) +#define DW100_DEWARP_CTRL_PREFETCH_MODE_AUTO (2UL << 16) +#define DW100_DEWARP_CTRL_PREFETCH_THRESHOLD_MASK GENMASK(24, 18) +#define DW100_DEWARP_CTRL_PREFETCH_THRESHOLD(x) ((x) << 18) + +#define DW100_MAP_LUT_ADDR 0x08 +#define DW100_MAP_LUT_ADDR_ADDR(addr) (((addr) >> 4) & GENMASK(29, 0)) +#define DW100_MAP_LUT_SIZE 0x0c +#define DW100_MAP_LUT_SIZE_WIDTH(w) (((w) & GENMASK(10, 0)) << 0) +#define DW100_MAP_LUT_SIZE_HEIGHT(h) (((h) & GENMASK(10, 0)) << 16) +#define DW100_SRC_IMG_Y_BASE 0x10 +#define DW100_IMG_Y_BASE(base) (((base) >> 4) & GENMASK(29, 0)) +#define DW100_SRC_IMG_UV_BASE 0x14 +#define DW100_IMG_UV_BASE(base) (((base) >> 4) & GENMASK(29, 0)) +#define DW100_SRC_IMG_SIZE 0x18 +#define DW100_IMG_SIZE_WIDTH(w) (((w) & GENMASK(12, 0)) << 0) +#define DW100_IMG_SIZE_HEIGHT(h) (((h) & GENMASK(12, 0)) << 16) + +#define DW100_SRC_IMG_STRIDE 0x1c +#define DW100_MAP_LUT_ADDR2 0x20 +#define DW100_MAP_LUT_SIZE2 0x24 +#define DW100_SRC_IMG_Y_BASE2 0x28 +#define DW100_SRC_IMG_UV_BASE2 0x2c +#define DW100_SRC_IMG_SIZE2 0x30 +#define DW100_SRC_IMG_STRIDE2 0x34 +#define DW100_DST_IMG_Y_BASE 0x38 +#define DW100_DST_IMG_UV_BASE 0x3c +#define DW100_DST_IMG_SIZE 0x40 +#define DW100_DST_IMG_STRIDE 0x44 +#define DW100_DST_IMG_Y_BASE2 0x48 +#define DW100_DST_IMG_UV_BASE2 0x4c +#define DW100_DST_IMG_SIZE2 0x50 +#define DW100_DST_IMG_STRIDE2 0x54 +#define DW100_SWAP_CONTROL 0x58 +#define DW100_SWAP_CONTROL_BYTE BIT(0) +#define DW100_SWAP_CONTROL_SHORT BIT(1) +#define DW100_SWAP_CONTROL_WORD BIT(2) +#define DW100_SWAP_CONTROL_LONG BIT(3) +#define DW100_SWAP_CONTROL_Y(x) (((x) & GENMASK(3, 0)) << 0) +#define DW100_SWAP_CONTROL_UV(x) (((x) & GENMASK(3, 0)) << 4) +#define DW100_SWAP_CONTROL_SRC(x) (((x) & GENMASK(7, 0)) << 0) +#define DW100_SWAP_CONTROL_DST(x) (((x) & GENMASK(7, 0)) << 8) +#define DW100_SWAP_CONTROL_SRC2(x) (((x) & GENMASK(7, 0)) << 16) +#define DW100_SWAP_CONTROL_DST2(x) (((x) & GENMASK(7, 0)) << 24) +#define DW100_SWAP_CONTROL_SRC_MASK GENMASK(7, 0) +#define DW100_SWAP_CONTROL_DST_MASK GENMASK(15, 8) +#define DW100_SWAP_CONTROL_SRC2_MASK GENMASK(23, 16) +#define DW100_SWAP_CONTROL_DST2_MASK GENMASK(31, 24) +#define DW100_VERTICAL_SPLIT_LINE 0x5c +#define DW100_HORIZON_SPLIT_LINE 0x60 +#define DW100_SCALE_FACTOR 0x64 +#define DW100_ROI_START 0x68 +#define DW100_ROI_START_X(x) (((x) & GENMASK(12, 0)) << 0) +#define DW100_ROI_START_Y(y) (((y) & GENMASK(12, 0)) << 16) +#define DW100_BOUNDARY_PIXEL 0x6c +#define DW100_BOUNDARY_PIXEL_V(v) (((v) & GENMASK(7, 0)) << 0) +#define DW100_BOUNDARY_PIXEL_U(u) (((u) & GENMASK(7, 0)) << 8) +#define DW100_BOUNDARY_PIXEL_Y(y) (((y) & GENMASK(7, 0)) << 16) + +#define DW100_INTERRUPT_STATUS 0x70 +#define DW100_INTERRUPT_STATUS_INT_FRAME_DONE BIT(0) +#define DW100_INTERRUPT_STATUS_INT_ERR_TIME_OUT BIT(1) +#define DW100_INTERRUPT_STATUS_INT_ERR_AXI_RESP BIT(2) +#define DW100_INTERRUPT_STATUS_INT_ERR_X BIT(3) +#define DW100_INTERRUPT_STATUS_INT_ERR_MB_FETCH BIT(4) +#define DW100_INTERRUPT_STATUS_INT_ERR_FRAME2 BIT(5) +#define DW100_INTERRUPT_STATUS_INT_ERR_FRAME3 BIT(6) +#define DW100_INTERRUPT_STATUS_INT_ERR_FRAME_DONE BIT(7) +#define DW100_INTERRUPT_STATUS_INT_ERR_STATUS(x) (((x) >> 1) & 0x7f) +#define DW100_INTERRUPT_STATUS_INT_STATUS(x) ((x) & 0xff) + +#define DW100_INTERRUPT_STATUS_INT_ENABLE_MASK GENMASK(15, 8) +#define DW100_INTERRUPT_STATUS_INT_ENABLE(x) (((x) & GENMASK(7, 0)) << 8) +#define DW100_INTERRUPT_STATUS_FRAME_BUSY BIT(16) +#define DW100_INTERRUPT_STATUS_INT_CLEAR(x) (((x) & GENMASK(7, 0)) << 24) +#define DW100_BUS_CTRL 0x74 +#define DW100_BUS_CTRL_AXI_MASTER_ENABLE BIT(31) +#define DW100_BUS_CTRL1 0x78 +#define DW100_BUS_TIME_OUT_CYCLE 0x7c +#define DW100_DST_IMG_Y_SIZE1 0x80 +#define DW100_DST_IMG_Y_SIZE(sz) (((sz) >> 4) & GENMASK(29, 0)) +#define DW100_DST_IMG_UV_SIZE(sz) (((sz) >> 4) & GENMASK(29, 0)) +#define DW100_DST_IMG_UV_SIZE1 0x84 +#define DW100_DST_IMG_Y_SIZE2 0x88 +#define DW100_DST_IMG_UV_SIZE2 0x8c + +#endif /* _DW100_REGS_H_ */ diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 290df04c4d02..81fb3a5bc1d5 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -493,7 +493,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) struct v4l2_subdev *subdev; int ret; - ret = media_pipeline_start(&vdev->entity, &video->pipe); + ret = video_device_pipeline_start(vdev, &video->pipe); if (ret < 0) return ret; @@ -522,7 +522,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count) return 0; error: - media_pipeline_stop(&vdev->entity); + video_device_pipeline_stop(vdev); video->ops->flush_buffers(video, VB2_BUF_STATE_QUEUED); @@ -553,7 +553,7 @@ static void video_stop_streaming(struct vb2_queue *q) v4l2_subdev_call(subdev, video, s_stream, 0); } - media_pipeline_stop(&vdev->entity); + video_device_pipeline_stop(vdev); video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); } diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 60de4200375d..ab6a29ffc81e 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1800,7 +1800,7 @@ bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) struct venus_core *core = inst->core; u32 fmt = to_hfi_raw_fmt(v4l2_pixfmt); struct hfi_plat_caps *caps; - u32 buftype; + bool found; if (!fmt) return false; @@ -1809,12 +1809,13 @@ bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) if (!caps) return false; - if (inst->session_type == VIDC_SESSION_TYPE_DEC) - buftype = HFI_BUFFER_OUTPUT2; - else - buftype = HFI_BUFFER_OUTPUT; + found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, fmt); + if (found) + goto done; - return find_fmt_from_caps(caps, buftype, fmt); + found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, fmt); +done: + return found; } EXPORT_SYMBOL_GPL(venus_helper_check_format); diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 1968f09ad177..e00aedb41d16 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -569,8 +569,6 @@ irqreturn_t hfi_isr(int irq, void *dev) int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops) { - int ret; - if (!ops) return -EINVAL; @@ -579,9 +577,8 @@ int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops) core->state = CORE_UNINIT; init_completion(&core->done); pkt_set_version(core->res->hfi_version); - ret = venus_hfi_create(core); - return ret; + return venus_hfi_create(core); } void hfi_destroy(struct venus_core *core) diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index ac0bb45d07f4..4ceaba37e2e5 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -183,6 +183,8 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) else return NULL; fmt = find_format(inst, pixmp->pixelformat, f->type); + if (!fmt) + return NULL; } pixmp->width = clamp(pixmp->width, frame_width_min(inst), diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 86918aea1d24..cdb12546c4fa 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -192,10 +192,8 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) pixmp->height = clamp(pixmp->height, frame_height_min(inst), frame_height_max(inst)); - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - pixmp->width = ALIGN(pixmp->width, 128); - pixmp->height = ALIGN(pixmp->height, 32); - } + pixmp->width = ALIGN(pixmp->width, 128); + pixmp->height = ALIGN(pixmp->height, 32); pixmp->width = ALIGN(pixmp->width, 2); pixmp->height = ALIGN(pixmp->height, 2); @@ -392,7 +390,7 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) struct v4l2_fract *timeperframe = &out->timeperframe; u64 us_per_frame, fps; - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; @@ -424,7 +422,7 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct venus_inst *inst = to_inst(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; @@ -509,6 +507,19 @@ static int venc_enum_frameintervals(struct file *file, void *fh, return 0; } +static int venc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_querycap = venc_querycap, .vidioc_enum_fmt_vid_cap = venc_enum_fmt, @@ -534,8 +545,9 @@ static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_g_parm = venc_g_parm, .vidioc_enum_framesizes = venc_enum_framesizes, .vidioc_enum_frameintervals = venc_enum_frameintervals, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_subscribe_event = venc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, }; static int venc_pm_get(struct venus_inst *inst) @@ -686,7 +698,8 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } - if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC && + ctr->profile.hevc == V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) { struct hfi_hdr10_pq_sei hdr10; unsigned int c; diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ed44e5800759..7468e43800a9 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -8,6 +8,7 @@ #include "core.h" #include "venc.h" +#include "helpers.h" #define BITRATE_MIN 32000 #define BITRATE_MAX 160000000 @@ -336,8 +337,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) * if we disable 8x8 transform for HP. */ - if (ctrl->val == 0) - return -EINVAL; ctr->h264_8x8_transform = ctrl->val; break; @@ -348,15 +347,41 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } +static int venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct venus_inst *inst = ctrl_to_inst(ctrl); + struct hfi_buffer_requirements bufreq; + enum hfi_version ver = inst->core->res->hfi_version; + int ret; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); + if (!ret) + ctrl->val = HFI_BUFREQ_COUNT_MIN(&bufreq, ver); + break; + default: + return -EINVAL; + } + + return 0; +} + static const struct v4l2_ctrl_ops venc_ctrl_ops = { .s_ctrl = venc_op_s_ctrl, + .g_volatile_ctrl = venc_op_g_volatile_ctrl, }; int venc_ctrl_init(struct venus_inst *inst) { int ret; + struct v4l2_ctrl_hdr10_mastering_display p_hdr10_mastering = { + { 34000, 13250, 7500 }, + { 16000, 34500, 3000 }, 15635, 16450, 10000000, 500, + }; + struct v4l2_ctrl_hdr10_cll_info p_hdr10_cll = { 1000, 400 }; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 59); if (ret) return ret; @@ -437,6 +462,9 @@ int venc_ctrl_init(struct venus_inst *inst) 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0); v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 4, 11, 1, 4); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_BITRATE, BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT); @@ -579,11 +607,11 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_COLORIMETRY_HDR10_CLL_INFO, - v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_ptr_create(&p_hdr10_cll)); v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, - v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_ptr_create((void *)&p_hdr10_mastering)); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 968a74234e92..2f7daa853ed8 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -786,9 +786,8 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags, return 0; /* - * Don't allow link changes if any entity in the graph is - * streaming, modifying the CHSEL register fields can disrupt - * running streams. + * Don't allow link changes if any stream in the graph is active as + * modifying the CHSEL register fields can disrupt running streams. */ media_device_for_each_entity(entity, &group->mdev) if (media_entity_is_streaming(entity)) diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 8d37fbdc266a..3aea96d85165 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -1244,8 +1244,6 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, static int rvin_set_stream(struct rvin_dev *vin, int on) { - struct media_pipeline *pipe; - struct media_device *mdev; struct v4l2_subdev *sd; struct media_pad *pad; int ret; @@ -1265,7 +1263,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) sd = media_entity_to_v4l2_subdev(pad->entity); if (!on) { - media_pipeline_stop(&vin->vdev.entity); + video_device_pipeline_stop(&vin->vdev); return v4l2_subdev_call(sd, video, s_stream, 0); } @@ -1273,17 +1271,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) if (ret) return ret; - /* - * The graph lock needs to be taken to protect concurrent - * starts of multiple VIN instances as they might share - * a common subdevice down the line and then should use - * the same pipe. - */ - mdev = vin->vdev.entity.graph_obj.mdev; - mutex_lock(&mdev->graph_mutex); - pipe = sd->entity.pipe ? sd->entity.pipe : &vin->vdev.pipe; - ret = __media_pipeline_start(&vin->vdev.entity, pipe); - mutex_unlock(&mdev->graph_mutex); + ret = video_device_pipeline_alloc_start(&vin->vdev); if (ret) return ret; @@ -1291,7 +1279,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) if (ret == -ENOIOCTLCMD) ret = 0; if (ret) - media_pipeline_stop(&vin->vdev.entity); + video_device_pipeline_stop(&vin->vdev); return ret; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1.h b/drivers/media/platform/renesas/vsp1/vsp1.h index 37cf33c7e6ca..2f6f0c6ae555 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1.h +++ b/drivers/media/platform/renesas/vsp1/vsp1.h @@ -22,6 +22,7 @@ struct clk; struct device; struct rcar_fcp_device; +struct reset_control; struct vsp1_drm; struct vsp1_entity; @@ -54,6 +55,7 @@ struct vsp1_uif; #define VSP1_HAS_HGT BIT(8) #define VSP1_HAS_BRS BIT(9) #define VSP1_HAS_EXT_DL BIT(10) +#define VSP1_HAS_NON_ZERO_LBA BIT(11) struct vsp1_device_info { u32 version; @@ -66,6 +68,7 @@ struct vsp1_device_info { unsigned int uif_count; unsigned int wpf_count; unsigned int num_bru_inputs; + u8 soc; bool uapi; }; @@ -79,6 +82,7 @@ struct vsp1_device { void __iomem *mmio; struct rcar_fcp_device *fcp; struct device *bus_master; + struct reset_control *rstc; struct vsp1_brx *brs; struct vsp1_brx *bru; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 1f73c48eb738..c260d318d298 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -16,6 +16,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/videodev2.h> #include <media/rcar-fcp.h> @@ -622,6 +623,7 @@ static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev) struct vsp1_device *vsp1 = dev_get_drvdata(dev); rcar_fcp_disable(vsp1->fcp); + reset_control_assert(vsp1->rstc); return 0; } @@ -631,13 +633,31 @@ static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev) struct vsp1_device *vsp1 = dev_get_drvdata(dev); int ret; + ret = reset_control_deassert(vsp1->rstc); + if (ret < 0) + return ret; + if (vsp1->info) { + /* + * On R-Car Gen2 and RZ/G1, vsp1 register access after deassert + * can cause lock-up. It is a special case and needs some delay + * to avoid this lock-up. + */ + if (vsp1->info->gen == 2) + udelay(1); + ret = vsp1_device_init(vsp1); if (ret < 0) - return ret; + goto done; } - return rcar_fcp_enable(vsp1->fcp); + ret = rcar_fcp_enable(vsp1->fcp); + +done: + if (ret < 0) + reset_control_assert(vsp1->rstc); + + return ret; } static const struct dev_pm_ops vsp1_pm_ops = { @@ -768,6 +788,7 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, { .version = VI6_IP_VERSION_MODEL_VSPD_V3, .model = "VSP2-D", + .soc = VI6_IP_VERSION_SOC_V3H, .gen = 3, .features = VSP1_HAS_BRS | VSP1_HAS_BRU, .lif_count = 1, @@ -776,6 +797,17 @@ static const struct vsp1_device_info vsp1_device_infos[] = { .wpf_count = 1, .num_bru_inputs = 5, }, { + .version = VI6_IP_VERSION_MODEL_VSPD_V3, + .model = "VSP2-D", + .soc = VI6_IP_VERSION_SOC_V3M, + .gen = 3, + .features = VSP1_HAS_BRS | VSP1_HAS_BRU | VSP1_HAS_NON_ZERO_LBA, + .lif_count = 1, + .rpf_count = 5, + .uif_count = 1, + .wpf_count = 1, + .num_bru_inputs = 5, + }, { .version = VI6_IP_VERSION_MODEL_VSPDL_GEN3, .model = "VSP2-DL", .gen = 3, @@ -798,11 +830,55 @@ static const struct vsp1_device_info vsp1_device_infos[] = { }, }; +static const struct vsp1_device_info rzg2l_vsp2_device_info = { + .version = VI6_IP_VERSION_MODEL_VSPD_RZG2L, + .model = "VSP2-D", + .soc = VI6_IP_VERSION_SOC_RZG2L, + .gen = 3, + .features = VSP1_HAS_BRS | VSP1_HAS_WPF_VFLIP | VSP1_HAS_EXT_DL + | VSP1_HAS_NON_ZERO_LBA, + .lif_count = 1, + .rpf_count = 2, + .wpf_count = 1, +}; + +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; + + /* + * Try the info stored in match data first for devices that don't have + * a version register. + */ + info = of_device_get_match_data(vsp1->dev); + if (info) { + vsp1->version = VI6_IP_VERSION_VSP_SW | info->version | info->soc; + return info; + } + + vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); + 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) { + info = &vsp1_device_infos[i]; + + if (model == info->version && (!info->soc || soc == info->soc)) + return info; + } + + dev_err(vsp1->dev, "unsupported IP version 0x%08x\n", vsp1->version); + + return NULL; +} + static int vsp1_probe(struct platform_device *pdev) { struct vsp1_device *vsp1; struct device_node *fcp_node; - unsigned int i; int ret; int irq; @@ -825,6 +901,11 @@ static int vsp1_probe(struct platform_device *pdev) if (irq < 0) return irq; + vsp1->rstc = devm_reset_control_get_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"); + /* FCP (optional). */ fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); if (fcp_node) { @@ -853,19 +934,8 @@ static int vsp1_probe(struct platform_device *pdev) if (ret < 0) goto done; - vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION); - - for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { - if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) == - vsp1_device_infos[i].version) { - vsp1->info = &vsp1_device_infos[i]; - break; - } - } - + vsp1->info = vsp1_lookup_info(vsp1); if (!vsp1->info) { - dev_err(&pdev->dev, "unsupported IP version 0x%08x\n", - vsp1->version); vsp1_device_put(vsp1); ret = -ENXIO; goto done; @@ -922,6 +992,7 @@ static int vsp1_remove(struct platform_device *pdev) static const struct of_device_id vsp1_of_match[] = { { .compatible = "renesas,vsp1" }, { .compatible = "renesas,vsp2" }, + { .compatible = "renesas,r9a07g044-vsp2", .data = &rzg2l_vsp2_device_info }, { }, }; MODULE_DEVICE_TABLE(of, vsp1_of_match); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c index 6a6857ac9327..186a5730e1e3 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c @@ -107,6 +107,7 @@ static void lif_configure_stream(struct vsp1_entity *entity, case VI6_IP_VERSION_MODEL_VSPDL_GEN3: case VI6_IP_VERSION_MODEL_VSPD_V3: + case VI6_IP_VERSION_MODEL_VSPD_RZG2L: hbth = 0; obth = 1500; lbth = 0; @@ -130,13 +131,12 @@ static void lif_configure_stream(struct vsp1_entity *entity, VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); /* - * On R-Car V3M the LIF0 buffer attribute register has to be set to a - * non-default value to guarantee proper operation (otherwise artifacts - * may appear on the output). The value required by the manual is not - * explained but is likely a buffer size or threshold. + * On R-Car V3M and RZ/G2L the LIF0 buffer attribute register has to be + * set to a non-default value to guarantee proper operation (otherwise + * artifacts may appear on the output). The value required by the + * manual is not explained but is likely a buffer size or threshold. */ - if ((entity->vsp1->version & VI6_IP_VERSION_MASK) == - (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M)) + if (vsp1_feature(entity->vsp1, VSP1_HAS_NON_ZERO_LBA)) vsp1_lif_write(lif, dlb, VI6_LIF_LBA, VI6_LIF_LBA_LBA0 | (1536 << VI6_LIF_LBA_LBA1_SHIFT)); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_regs.h b/drivers/media/platform/renesas/vsp1/vsp1_regs.h index fae7286eb01e..8928f4c6bb55 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_regs.h +++ b/drivers/media/platform/renesas/vsp1/vsp1_regs.h @@ -767,6 +767,8 @@ #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) #define VI6_IP_VERSION_MODEL_VSPD_V3U (0x1c << 8) +/* RZ/G2L SoCs have no version register, So use 0x80 as the model version */ +#define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8) #define VI6_IP_VERSION_SOC_MASK (0xff << 0) #define VI6_IP_VERSION_SOC_H2 (0x01 << 0) @@ -780,6 +782,10 @@ #define VI6_IP_VERSION_SOC_M3N (0x04 << 0) #define VI6_IP_VERSION_SOC_E3 (0x04 << 0) #define VI6_IP_VERSION_SOC_V3U (0x05 << 0) +/* RZ/G2L SoCs have no version register, So use 0x80 for SoC Identification */ +#define VI6_IP_VERSION_SOC_RZG2L (0x80 << 0) + +#define VI6_IP_VERSION_VSP_SW (0xfffe << 16) /* SW VSP version */ /* ----------------------------------------------------------------------------- * RPF CLUT Registers diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index e8e0ee5f2277..9d24647c8f32 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -305,7 +305,7 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) * @video: the video node * * This function completes the current buffer by filling its sequence number, - * time stamp and payload size, and hands it back to the videobuf core. + * time stamp and payload size, and hands it back to the vb2 core. * * Return the next queued buffer or NULL if the queue is empty. */ @@ -927,7 +927,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq) } mutex_unlock(&pipe->lock); - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); vsp1_video_release_buffers(video); vsp1_video_pipeline_put(pipe); } @@ -1046,7 +1046,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return PTR_ERR(pipe); } - ret = __media_pipeline_start(&video->video.entity, &pipe->pipe); + ret = __video_device_pipeline_start(&video->video, &pipe->pipe); if (ret < 0) { mutex_unlock(&mdev->graph_mutex); goto err_pipe; @@ -1070,7 +1070,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return 0; err_stop: - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); err_pipe: vsp1_video_pipeline_put(pipe); return ret; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 2f8df74ad0fd..61b25fcf826e 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -816,7 +816,7 @@ static int rga_probe(struct platform_device *pdev) ret = rga_parse_dt(rga); if (ret) - dev_err(&pdev->dev, "Unable to parse OF data\n"); + return dev_err_probe(&pdev->dev, ret, "Unable to parse OF data\n"); pm_runtime_enable(rga->dev); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index d5904c96ff3f..d4540684ea9a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -913,7 +913,7 @@ static void rkisp1_cap_stream_disable(struct rkisp1_capture *cap) * * Call s_stream(false) in the reverse order from * rkisp1_pipeline_stream_enable() and disable the DMA engine. - * Should be called before media_pipeline_stop() + * Should be called before video_device_pipeline_stop() */ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) __must_hold(&cap->rkisp1->stream_lock) @@ -926,7 +926,7 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes shouldn't * be disabled, skip them. */ - if (rkisp1->pipe.streaming_count < 2) + if (rkisp1->pipe.start_count < 2) v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false); v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream, @@ -937,7 +937,7 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap) * rkisp1_pipeline_stream_enable - enable nodes in the pipeline * * Enable the DMA Engine and call s_stream(true) through the pipeline. - * Should be called after media_pipeline_start() + * Should be called after video_device_pipeline_start() */ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) __must_hold(&cap->rkisp1->stream_lock) @@ -956,7 +956,7 @@ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap) * If the other capture is streaming, isp and sensor nodes are already * enabled, skip them. */ - if (rkisp1->pipe.streaming_count > 1) + if (rkisp1->pipe.start_count > 1) return 0; ret = v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, true); @@ -994,7 +994,7 @@ static void rkisp1_vb2_stop_streaming(struct vb2_queue *queue) rkisp1_dummy_buf_destroy(cap); - media_pipeline_stop(&node->vdev.entity); + video_device_pipeline_stop(&node->vdev); mutex_unlock(&cap->rkisp1->stream_lock); } @@ -1008,7 +1008,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) mutex_lock(&cap->rkisp1->stream_lock); - ret = media_pipeline_start(entity, &cap->rkisp1->pipe); + ret = video_device_pipeline_start(&cap->vnode.vdev, &cap->rkisp1->pipe); if (ret) { dev_err(cap->rkisp1->dev, "start pipeline failed %d\n", ret); goto err_ret_buffers; @@ -1044,7 +1044,7 @@ err_pipe_pm_put: err_destroy_dummy: rkisp1_dummy_buf_destroy(cap); err_pipeline_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&cap->vnode.vdev); err_ret_buffers: rkisp1_return_all_buffers(cap, VB2_BUF_STATE_QUEUED); mutex_unlock(&cap->rkisp1->stream_lock); @@ -1273,11 +1273,12 @@ static int rkisp1_capture_link_validate(struct media_link *link) struct rkisp1_capture *cap = video_get_drvdata(vdev); const struct rkisp1_capture_fmt_cfg *fmt = rkisp1_find_fmt_cfg(cap, cap->pix.fmt.pixelformat); - struct v4l2_subdev_format sd_fmt; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; int ret; - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = link->source->index; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 8056997d5c29..a1293c45aae1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -378,6 +378,7 @@ struct rkisp1_params { struct v4l2_format vdev_fmt; enum v4l2_quantization quantization; + enum v4l2_ycbcr_encoding ycbcr_encoding; enum rkisp1_fmt_raw_pat_type raw_type; }; @@ -556,17 +557,32 @@ void rkisp1_sd_adjust_crop(struct v4l2_rect *crop, */ const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code); -/* rkisp1_params_configure - configure the params when stream starts. - * This function is called by the isp entity upon stream starts. - * The function applies the initial configuration of the parameters. +/* + * rkisp1_params_pre_configure - Configure the params before stream start * - * @params: pointer to rkisp1_params. + * @params: pointer to rkisp1_params * @bayer_pat: the bayer pattern on the isp video sink pad * @quantization: the quantization configured on the isp's src pad + * @ycbcr_encoding: the ycbcr_encoding configured on the isp's src pad + * + * This function is called by the ISP entity just before the ISP gets started. + * It applies the initial ISP parameters from the first params buffer, but + * skips LSC as it needs to be configured after the ISP is started. + */ +void rkisp1_params_pre_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding); + +/* + * rkisp1_params_post_configure - Configure the params after stream start + * + * @params: pointer to rkisp1_params + * + * This function is called by the ISP entity just after the ISP gets started. + * It applies the initial ISP LSC parameters from the first params buffer. */ -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization); +void rkisp1_params_post_configure(struct rkisp1_params *params); /* rkisp1_params_disable - disable all parameters. * This function is called by the isp entity upon stream start diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 383a3ec83ca9..585cf3f53469 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -231,10 +231,11 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *src_frm; src_frm = rkisp1_isp_get_pad_fmt(isp, NULL, - RKISP1_ISP_PAD_SINK_VIDEO, + RKISP1_ISP_PAD_SOURCE_VIDEO, V4L2_SUBDEV_FORMAT_ACTIVE); - rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat, - src_frm->quantization); + rkisp1_params_pre_configure(&rkisp1->params, sink_fmt->bayer_pat, + src_frm->quantization, + src_frm->ycbcr_enc); } return 0; @@ -340,6 +341,9 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp) RKISP1_CIF_ISP_CTRL_ISP_ENABLE | RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE; rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val); + + if (isp->src_fmt->pixel_enc != V4L2_PIXEL_ENC_BAYER) + rkisp1_params_post_configure(&rkisp1->params); } /* ---------------------------------------------------------------------------- @@ -431,12 +435,17 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop, *src_crop; + /* Video. */ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); sink_fmt->width = RKISP1_DEFAULT_WIDTH; sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT; + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; + sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_ISP_PAD_SINK_VIDEO); @@ -449,11 +458,16 @@ static int rkisp1_isp_init_config(struct v4l2_subdev *sd, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_fmt = *sink_fmt; src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; + src_fmt->colorspace = V4L2_COLORSPACE_SRGB; + src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; src_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO); *src_crop = *sink_crop; + /* Parameters and statistics. */ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, RKISP1_ISP_PAD_SINK_PARAMS); src_fmt = v4l2_subdev_get_try_format(sd, sd_state, @@ -472,40 +486,105 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_mbus_info *mbus_info; + const struct rkisp1_mbus_info *sink_info; + const struct rkisp1_mbus_info *src_info; + struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_mbus_framefmt *src_fmt; const struct v4l2_rect *src_crop; + bool set_csc; + sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, + RKISP1_ISP_PAD_SINK_VIDEO, which); src_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO, which); src_crop = rkisp1_isp_get_pad_crop(isp, sd_state, RKISP1_ISP_PAD_SOURCE_VIDEO, which); + /* + * Media bus code. The ISP can operate in pass-through mode (Bayer in, + * Bayer out or YUV in, YUV out) or process Bayer data to YUV, but + * can't convert from YUV to Bayer. + */ + sink_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); + src_fmt->code = format->code; - mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); - if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) { + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + if (!src_info || !(src_info->direction & RKISP1_ISP_SD_SRC)) { src_fmt->code = RKISP1_DEF_SRC_PAD_FMT; - mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code); + src_info = rkisp1_mbus_info_get_by_code(src_fmt->code); } - if (which == V4L2_SUBDEV_FORMAT_ACTIVE) - isp->src_fmt = mbus_info; + + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_YUV && + src_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + src_fmt->code = sink_fmt->code; + src_info = sink_info; + } + + /* + * The source width and height must be identical to the source crop + * size. + */ src_fmt->width = src_crop->width; src_fmt->height = src_crop->height; /* - * The CSC API is used to allow userspace to force full - * quantization on YUV formats. + * Copy the color space for the sink pad. When converting from Bayer to + * YUV, default to a limited quantization range. */ - if (format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC && - format->quantization == V4L2_QUANTIZATION_FULL_RANGE && - mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; - else if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV) + src_fmt->colorspace = sink_fmt->colorspace; + src_fmt->xfer_func = sink_fmt->xfer_func; + src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc; + + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER && + src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; else - src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + src_fmt->quantization = sink_fmt->quantization; + + /* + * Allow setting the source color space fields when the SET_CSC flag is + * set and the source format is YUV. If the sink format is YUV, don't + * set the color primaries, transfer function or YCbCr encoding as the + * ISP is bypassed in that case and passes YUV data through without + * modifications. + * + * The color primaries and transfer function are configured through the + * cross-talk matrix and tone curve respectively. Settings for those + * hardware blocks are conveyed through the ISP parameters buffer, as + * they need to combine color space information with other image tuning + * characteristics and can't thus be computed by the kernel based on the + * color space. The source pad colorspace and xfer_func fields are thus + * ignored by the driver, but can be set by userspace to propagate + * accurate color space information down the pipeline. + */ + set_csc = format->flags & V4L2_MBUS_FRAMEFMT_SET_CSC; + + if (set_csc && src_info->pixel_enc == V4L2_PIXEL_ENC_YUV) { + if (sink_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if (format->colorspace != V4L2_COLORSPACE_DEFAULT) + src_fmt->colorspace = format->colorspace; + if (format->xfer_func != V4L2_XFER_FUNC_DEFAULT) + src_fmt->xfer_func = format->xfer_func; + if (format->ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT) + src_fmt->ycbcr_enc = format->ycbcr_enc; + } + + if (format->quantization != V4L2_QUANTIZATION_DEFAULT) + src_fmt->quantization = format->quantization; + } *format = *src_fmt; + + /* + * Restore the SET_CSC flag if it was set to indicate support for the + * CSC setting API. + */ + if (set_csc) + format->flags |= V4L2_MBUS_FRAMEFMT_SET_CSC; + + /* Store the source format info when setting the active format. */ + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) + isp->src_fmt = src_info; } static void rkisp1_isp_set_src_crop(struct rkisp1_isp *isp, @@ -573,6 +652,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt; struct v4l2_rect *sink_crop; + bool is_yuv; sink_fmt = rkisp1_isp_get_pad_fmt(isp, sd_state, RKISP1_ISP_PAD_SINK_VIDEO, @@ -593,6 +673,36 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp, RKISP1_ISP_MIN_HEIGHT, RKISP1_ISP_MAX_HEIGHT); + /* + * Adjust the color space fields. Accept any color primaries and + * transfer function for both YUV and Bayer. For YUV any YCbCr encoding + * and quantization range is also accepted. For Bayer formats, the YCbCr + * encoding isn't applicable, and the quantization range can only be + * full. + */ + is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV; + + sink_fmt->colorspace = format->colorspace ? : + (is_yuv ? V4L2_COLORSPACE_SRGB : + V4L2_COLORSPACE_RAW); + sink_fmt->xfer_func = format->xfer_func ? : + V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + if (is_yuv) { + sink_fmt->ycbcr_enc = format->ycbcr_enc ? : + V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = format->quantization ? : + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + } else { + /* + * The YCbCr encoding isn't applicable for non-YUV formats, but + * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it + * should be ignored by userspace. + */ + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } + *format = *sink_fmt; /* Propagate to in crop */ diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 9da7dc1bc690..d8731ebbf479 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -18,6 +18,8 @@ #define RKISP1_ISP_PARAMS_REQ_BUFS_MIN 2 #define RKISP1_ISP_PARAMS_REQ_BUFS_MAX 8 +#define RKISP1_ISP_DPCC_METHODS_SET(n) \ + (RKISP1_CIF_ISP_DPCC_METHODS_SET_1 + 0x4 * (n)) #define RKISP1_ISP_DPCC_LINE_THRESH(n) \ (RKISP1_CIF_ISP_DPCC_LINE_THRESH_1 + 0x14 * (n)) #define RKISP1_ISP_DPCC_LINE_MAD_FAC(n) \ @@ -56,39 +58,47 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params, unsigned int i; u32 mode; - /* avoid to override the old enable value */ + /* + * The enable bit is controlled in rkisp1_isp_isr_other_config() and + * must be preserved. The grayscale mode should be configured + * automatically based on the media bus code on the ISP sink pad, so + * only the STAGE1_ENABLE bit can be set by userspace. + */ mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE); - mode &= RKISP1_CIF_ISP_DPCC_ENA; - mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA; + mode &= RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE; + mode |= arg->mode & RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE; rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE, mode); + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE, - arg->output_mode); + arg->output_mode & RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_MASK); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE, - arg->set_use); - - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1, - arg->methods[0].method); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2, - arg->methods[1].method); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3, - arg->methods[2].method); + arg->set_use & RKISP1_CIF_ISP_DPCC_SET_USE_MASK); + for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) { + rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_METHODS_SET(i), + arg->methods[i].method & + RKISP1_CIF_ISP_DPCC_METHODS_SET_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i), - arg->methods[i].line_thresh); + arg->methods[i].line_thresh & + RKISP1_CIF_ISP_DPCC_LINE_THRESH_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i), - arg->methods[i].line_mad_fac); + arg->methods[i].line_mad_fac & + RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i), - arg->methods[i].pg_fac); + arg->methods[i].pg_fac & + RKISP1_CIF_ISP_DPCC_PG_FAC_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i), - arg->methods[i].rnd_thresh); + arg->methods[i].rnd_thresh & + RKISP1_CIF_ISP_DPCC_RND_THRESH_MASK); rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i), - arg->methods[i].rg_fac); + arg->methods[i].rg_fac & + RKISP1_CIF_ISP_DPCC_RG_FAC_MASK); } rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS, - arg->rnd_offs); + arg->rnd_offs & RKISP1_CIF_ISP_DPCC_RND_OFFS_MASK); rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS, - arg->ro_limits); + arg->ro_limits & RKISP1_CIF_ISP_DPCC_RO_LIMIT_MASK); } /* ISP black level subtraction interface function */ @@ -188,149 +198,131 @@ static void rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { - unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + struct rkisp1_device *rkisp1 = params->rkisp1; + u32 lsc_status, sram_addr, lsc_table_sel; + unsigned int i, j; - isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ - sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? + sram_addr = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + const __u16 *r_tbl = pconfig->r_data_tbl[i]; + const __u16 *gr_tbl = pconfig->gr_data_tbl[i]; + const __u16 *gb_tbl = pconfig->gb_data_tbl[i]; + const __u16 *b_tbl = pconfig->b_data_tbl[i]; + /* * 17 sectors with 2 values in one DWORD = 9 * DWORDs (2nd value of last DWORD unused) */ for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + r_tbl[j], r_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + gr_tbl[j], gr_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + gb_tbl[j], gb_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10( + b_tbl[j], b_tbl[j + 1])); } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, - data); - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, - data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(r_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(gr_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(gb_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(b_tbl[j], 0)); } - isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_0 : - RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, - isp_lsc_table_sel); + + lsc_table_sel = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, lsc_table_sel); } static void rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *pconfig) { - unsigned int isp_lsc_status, sram_addr, isp_lsc_table_sel, i, j, data; + struct rkisp1_device *rkisp1 = params->rkisp1; + u32 lsc_status, sram_addr, lsc_table_sel; + unsigned int i, j; - isp_lsc_status = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_STATUS); + lsc_status = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_STATUS); /* RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */ - sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : - RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); + sram_addr = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 : + RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr); /* program data tables (table size is 9 * 17 = 153) */ for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) { + const __u16 *r_tbl = pconfig->r_data_tbl[i]; + const __u16 *gr_tbl = pconfig->gr_data_tbl[i]; + const __u16 *gb_tbl = pconfig->gb_data_tbl[i]; + const __u16 *b_tbl = pconfig->b_data_tbl[i]; + /* * 17 sectors with 2 values in one DWORD = 9 * DWORDs (2nd value of last DWORD unused) */ for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) { - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->r_data_tbl[i][j], - pconfig->r_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->gr_data_tbl[i][j], - pconfig->gr_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->gb_data_tbl[i][j], - pconfig->gb_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( - pconfig->b_data_tbl[i][j], - pconfig->b_data_tbl[i][j + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + r_tbl[j], r_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + gr_tbl[j], gr_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + gb_tbl[j], gb_tbl[j + 1])); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12( + b_tbl[j], b_tbl[j + 1])); } - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, - data); - - data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0); - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, - data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(r_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(gr_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(gb_tbl[j], 0)); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA, + RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(b_tbl[j], 0)); } - isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ? - RKISP1_CIF_ISP_LSC_TABLE_0 : - RKISP1_CIF_ISP_LSC_TABLE_1; - rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, - isp_lsc_table_sel); + + lsc_table_sel = lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE ? + RKISP1_CIF_ISP_LSC_TABLE_0 : RKISP1_CIF_ISP_LSC_TABLE_1; + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL, lsc_table_sel); } static void rkisp1_lsc_config(struct rkisp1_params *params, const struct rkisp1_cif_isp_lsc_config *arg) { - unsigned int i, data; - u32 lsc_ctrl; + struct rkisp1_device *rkisp1 = params->rkisp1; + u32 lsc_ctrl, data; + unsigned int i; /* To config must be off , store the current status firstly */ - lsc_ctrl = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_LSC_CTRL); + lsc_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_ISP_LSC_CTRL); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); params->ops->lsc_matrix_config(params, arg); @@ -339,38 +331,31 @@ static void rkisp1_lsc_config(struct rkisp1_params *params, /* program x size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2], arg->x_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XSIZE(i), data); /* program x grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2], + data = RKISP1_CIF_ISP_LSC_SECT_GRAD(arg->x_grad_tbl[i * 2], arg->x_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_XGRAD(i), data); /* program y size tables */ data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2], arg->y_size_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YSIZE(i), data); /* program y grad tables */ - data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2], + data = RKISP1_CIF_ISP_LSC_SECT_GRAD(arg->y_grad_tbl[i * 2], arg->y_grad_tbl[i * 2 + 1]); - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data); + rkisp1_write(rkisp1, RKISP1_CIF_ISP_LSC_YGRAD(i), data); } /* restore the lsc ctrl status */ - if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) { - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, + if (lsc_ctrl & RKISP1_CIF_ISP_LSC_CTRL_ENA) + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); - } else { - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, + else + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); - } } /* ISP Filtering function */ @@ -1066,39 +1051,96 @@ static void rkisp1_ie_enable(struct rkisp1_params *params, bool en) } } -static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range) +static void rkisp1_csm_config(struct rkisp1_params *params) { - static const u16 full_range_coeff[] = { - 0x0026, 0x004b, 0x000f, - 0x01ea, 0x01d6, 0x0040, - 0x0040, 0x01ca, 0x01f6 + struct csm_coeffs { + u16 limited[9]; + u16 full[9]; + }; + static const struct csm_coeffs rec601_coeffs = { + .limited = { + 0x0021, 0x0042, 0x000d, + 0x01ed, 0x01db, 0x0038, + 0x0038, 0x01d1, 0x01f7, + }, + .full = { + 0x0026, 0x004b, 0x000f, + 0x01ea, 0x01d6, 0x0040, + 0x0040, 0x01ca, 0x01f6, + }, }; - static const u16 limited_range_coeff[] = { - 0x0021, 0x0040, 0x000d, - 0x01ed, 0x01db, 0x0038, - 0x0038, 0x01d1, 0x01f7, + static const struct csm_coeffs rec709_coeffs = { + .limited = { + 0x0018, 0x0050, 0x0008, + 0x01f3, 0x01d5, 0x0038, + 0x0038, 0x01cd, 0x01fb, + }, + .full = { + 0x001b, 0x005c, 0x0009, + 0x01f1, 0x01cf, 0x0040, + 0x0040, 0x01c6, 0x01fa, + }, }; + static const struct csm_coeffs rec2020_coeffs = { + .limited = { + 0x001d, 0x004c, 0x0007, + 0x01f0, 0x01d8, 0x0038, + 0x0038, 0x01cd, 0x01fb, + }, + .full = { + 0x0022, 0x0057, 0x0008, + 0x01ee, 0x01d2, 0x0040, + 0x0040, 0x01c5, 0x01fb, + }, + }; + static const struct csm_coeffs smpte240m_coeffs = { + .limited = { + 0x0018, 0x004f, 0x000a, + 0x01f3, 0x01d5, 0x0038, + 0x0038, 0x01ce, 0x01fa, + }, + .full = { + 0x001b, 0x005a, 0x000b, + 0x01f1, 0x01cf, 0x0040, + 0x0040, 0x01c7, 0x01f9, + }, + }; + + const struct csm_coeffs *coeffs; + const u16 *csm; unsigned int i; - if (full_range) { - for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, - full_range_coeff[i]); + switch (params->ycbcr_encoding) { + case V4L2_YCBCR_ENC_601: + default: + coeffs = &rec601_coeffs; + break; + case V4L2_YCBCR_ENC_709: + coeffs = &rec709_coeffs; + break; + case V4L2_YCBCR_ENC_BT2020: + coeffs = &rec2020_coeffs; + break; + case V4L2_YCBCR_ENC_SMPTE240M: + coeffs = &smpte240m_coeffs; + break; + } + if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) { + csm = coeffs->full; rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } else { - for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++) - rkisp1_write(params->rkisp1, - RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, - limited_range_coeff[i]); - + csm = coeffs->limited; rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA | RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA); } + + for (i = 0; i < 9; i++) + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CC_COEFF_0 + i * 4, + csm[i]); } /* ISP De-noise Pre-Filter(DPF) function */ @@ -1216,11 +1258,11 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); else rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); } /* update bls config */ @@ -1255,22 +1297,6 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); } - /* update lsc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_lsc_config(params, - &new_params->others.lsc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } - /* update awb gains */ if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) params->ops->awb_gain_config(params, &new_params->others.awb_gain_config); @@ -1387,6 +1413,33 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, } } +static void +rkisp1_isp_isr_lsc_config(struct rkisp1_params *params, + const struct rkisp1_params_cfg *new_params) +{ + unsigned int module_en_update, module_cfg_update, module_ens; + + module_en_update = new_params->module_en_update; + module_cfg_update = new_params->module_cfg_update; + module_ens = new_params->module_ens; + + /* update lsc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_lsc_config(params, + &new_params->others.lsc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + } +} + static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, struct rkisp1_params_cfg *new_params) { @@ -1448,47 +1501,60 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, } } -static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, - unsigned int frame_sequence) +static bool rkisp1_params_get_buffer(struct rkisp1_params *params, + struct rkisp1_buffer **buf, + struct rkisp1_params_cfg **cfg) { - struct rkisp1_params_cfg *new_params; - struct rkisp1_buffer *cur_buf = NULL; - if (list_empty(¶ms->params)) - return; - - cur_buf = list_first_entry(¶ms->params, - struct rkisp1_buffer, queue); + return false; - new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); + *buf = list_first_entry(¶ms->params, struct rkisp1_buffer, queue); + *cfg = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0); - rkisp1_isp_isr_other_config(params, new_params); - rkisp1_isp_isr_meas_config(params, new_params); - - /* update shadow register immediately */ - rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + return true; +} - list_del(&cur_buf->queue); +static void rkisp1_params_complete_buffer(struct rkisp1_params *params, + struct rkisp1_buffer *buf, + unsigned int frame_sequence) +{ + list_del(&buf->queue); - cur_buf->vb.sequence = frame_sequence; - vb2_buffer_done(&cur_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + buf->vb.sequence = frame_sequence; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } void rkisp1_params_isr(struct rkisp1_device *rkisp1) { - /* - * This isr is called when the ISR finishes processing a frame (RKISP1_CIF_ISP_FRAME). - * Configurations performed here will be applied on the next frame. - * Since frame_sequence is updated on the vertical sync signal, we should use - * frame_sequence + 1 here to indicate to userspace on which frame these parameters - * are being applied. - */ - unsigned int frame_sequence = rkisp1->isp.frame_sequence + 1; struct rkisp1_params *params = &rkisp1->params; + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; spin_lock(¶ms->config_lock); - rkisp1_params_apply_params_cfg(params, frame_sequence); + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_lsc_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + + /* + * This isr is called when the ISR finishes processing a frame + * (RKISP1_CIF_ISP_FRAME). Configurations performed here will be + * applied on the next frame. Since frame_sequence is updated on the + * vertical sync signal, we should use frame_sequence + 1 here to + * indicate to userspace on which frame these parameters are being + * applied. + */ + rkisp1_params_complete_buffer(params, cur_buf, + rkisp1->isp.frame_sequence + 1); + +unlock: spin_unlock(¶ms->config_lock); } @@ -1531,9 +1597,18 @@ static const struct rkisp1_cif_isp_afc_config rkisp1_afc_params_default_config = 14 }; -static void rkisp1_params_config_parameter(struct rkisp1_params *params) +void rkisp1_params_pre_configure(struct rkisp1_params *params, + enum rkisp1_fmt_raw_pat_type bayer_pat, + enum v4l2_quantization quantization, + enum v4l2_ycbcr_encoding ycbcr_encoding) { struct rkisp1_cif_isp_hst_config hst = rkisp1_hst_params_default_config; + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; + + params->quantization = quantization; + params->ycbcr_encoding = ycbcr_encoding; + params->raw_type = bayer_pat; params->ops->awb_meas_config(params, &rkisp1_awb_params_default_config); params->ops->awb_meas_enable(params, &rkisp1_awb_params_default_config, @@ -1552,27 +1627,55 @@ static void rkisp1_params_config_parameter(struct rkisp1_params *params) rkisp1_param_set_bits(params, RKISP1_CIF_ISP_HIST_PROP_V10, rkisp1_hst_params_default_config.mode); - /* set the range */ - if (params->quantization == V4L2_QUANTIZATION_FULL_RANGE) - rkisp1_csm_config(params, true); - else - rkisp1_csm_config(params, false); + rkisp1_csm_config(params); spin_lock_irq(¶ms->config_lock); /* apply the first buffer if there is one already */ - rkisp1_params_apply_params_cfg(params, 0); + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_other_config(params, new_params); + rkisp1_isp_isr_meas_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + +unlock: spin_unlock_irq(¶ms->config_lock); } -void rkisp1_params_configure(struct rkisp1_params *params, - enum rkisp1_fmt_raw_pat_type bayer_pat, - enum v4l2_quantization quantization) +void rkisp1_params_post_configure(struct rkisp1_params *params) { - params->quantization = quantization; - params->raw_type = bayer_pat; - rkisp1_params_config_parameter(params); + struct rkisp1_params_cfg *new_params; + struct rkisp1_buffer *cur_buf; + + spin_lock_irq(¶ms->config_lock); + + /* + * Apply LSC parameters from the first buffer (if any is already + * available. This must be done after the ISP gets started in the + * ISP8000Nano v18.02 (found in the i.MX8MP) as access to the LSC RAM + * is gated by the ISP_CTRL.ISP_ENABLE bit. As this initialization + * ordering doesn't affect other ISP versions negatively, do so + * unconditionally. + */ + + if (!rkisp1_params_get_buffer(params, &cur_buf, &new_params)) + goto unlock; + + rkisp1_isp_isr_lsc_config(params, new_params); + + /* update shadow register immediately */ + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD); + + rkisp1_params_complete_buffer(params, cur_buf, 0); + +unlock: + spin_unlock_irq(¶ms->config_lock); } /* @@ -1582,7 +1685,7 @@ void rkisp1_params_configure(struct rkisp1_params *params, void rkisp1_params_disable(struct rkisp1_params *params) { rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); + RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_LSC_CTRL, RKISP1_CIF_ISP_LSC_CTRL_ENA); rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_BLS_CTRL, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index dd3e6c38be67..421cc73355db 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -576,7 +576,7 @@ (((v0) & 0x1FFF) | (((v1) & 0x1FFF) << 13)) #define RKISP1_CIF_ISP_LSC_SECT_SIZE(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) -#define RKISP1_CIF_ISP_LSC_GRAD_SIZE(v0, v1) \ +#define RKISP1_CIF_ISP_LSC_SECT_GRAD(v0, v1) \ (((v0) & 0xFFF) | (((v1) & 0xFFF) << 16)) /* LSC: ISP_LSC_TABLE_SEL */ @@ -618,19 +618,18 @@ #define RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA_READ(x) (((x) >> 11) & 1) /* DPCC */ -/* ISP_DPCC_MODE */ -#define RKISP1_CIF_ISP_DPCC_ENA BIT(0) -#define RKISP1_CIF_ISP_DPCC_MODE_MAX 0x07 -#define RKISP1_CIF_ISP_DPCC_OUTPUTMODE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_SETUSE_MAX 0x0F -#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RESERVED 0xFFFFE000 -#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_PG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RESERVED 0xFFFF0000 -#define RKISP1_CIF_ISP_DPCC_RG_FAC_RESERVED 0xFFFFC0C0 -#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_RESERVED 0xFFFFF000 -#define RKISP1_CIF_ISP_DPCC_RND_OFFS_RESERVED 0xFFFFF000 +#define RKISP1_CIF_ISP_DPCC_MODE_DPCC_ENABLE BIT(0) +#define RKISP1_CIF_ISP_DPCC_MODE_GRAYSCALE_MODE BIT(1) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_MASK GENMASK(3, 0) +#define RKISP1_CIF_ISP_DPCC_SET_USE_MASK GENMASK(3, 0) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_MASK 0x00001f1f +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_MASK 0x0000ffff +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_PG_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_MASK 0x0000ffff +#define RKISP1_CIF_ISP_DPCC_RG_FAC_MASK 0x00003f3f +#define RKISP1_CIF_ISP_DPCC_RO_LIMIT_MASK 0x00000fff +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_MASK 0x00000fff /* BLS */ /* ISP_BLS_CTRL */ @@ -1073,22 +1072,10 @@ #define RKISP1_CIF_ISP_LSC_GR_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000018) #define RKISP1_CIF_ISP_LSC_B_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x0000001C) #define RKISP1_CIF_ISP_LSC_GB_TABLE_DATA (RKISP1_CIF_ISP_LSC_BASE + 0x00000020) -#define RKISP1_CIF_ISP_LSC_XGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000024) -#define RKISP1_CIF_ISP_LSC_XGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000028) -#define RKISP1_CIF_ISP_LSC_XGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000002C) -#define RKISP1_CIF_ISP_LSC_XGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000030) -#define RKISP1_CIF_ISP_LSC_YGRAD_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000034) -#define RKISP1_CIF_ISP_LSC_YGRAD_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000038) -#define RKISP1_CIF_ISP_LSC_YGRAD_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000003C) -#define RKISP1_CIF_ISP_LSC_YGRAD_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000040) -#define RKISP1_CIF_ISP_LSC_XSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000044) -#define RKISP1_CIF_ISP_LSC_XSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000048) -#define RKISP1_CIF_ISP_LSC_XSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000004C) -#define RKISP1_CIF_ISP_LSC_XSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000050) -#define RKISP1_CIF_ISP_LSC_YSIZE_01 (RKISP1_CIF_ISP_LSC_BASE + 0x00000054) -#define RKISP1_CIF_ISP_LSC_YSIZE_23 (RKISP1_CIF_ISP_LSC_BASE + 0x00000058) -#define RKISP1_CIF_ISP_LSC_YSIZE_45 (RKISP1_CIF_ISP_LSC_BASE + 0x0000005C) -#define RKISP1_CIF_ISP_LSC_YSIZE_67 (RKISP1_CIF_ISP_LSC_BASE + 0x00000060) +#define RKISP1_CIF_ISP_LSC_XGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000024 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_YGRAD(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000034 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_XSIZE(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000044 + (n) * 4) +#define RKISP1_CIF_ISP_LSC_YSIZE(n) (RKISP1_CIF_ISP_LSC_BASE + 0x00000054 + (n) * 4) #define RKISP1_CIF_ISP_LSC_TABLE_SEL (RKISP1_CIF_ISP_LSC_BASE + 0x00000064) #define RKISP1_CIF_ISP_LSC_STATUS (RKISP1_CIF_ISP_LSC_BASE + 0x00000068) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index f4caa8f684aa..f76afd8112b2 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -411,6 +411,10 @@ static int rkisp1_rsz_init_config(struct v4l2_subdev *sd, sink_fmt->height = RKISP1_DEFAULT_HEIGHT; sink_fmt->field = V4L2_FIELD_NONE; sink_fmt->code = RKISP1_DEF_FMT; + sink_fmt->colorspace = V4L2_COLORSPACE_SRGB; + sink_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; sink_crop = v4l2_subdev_get_try_crop(sd, sd_state, RKISP1_RSZ_PAD_SINK); @@ -503,6 +507,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, const struct rkisp1_mbus_info *mbus_info; struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; struct v4l2_rect *sink_crop; + bool is_yuv; sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK, which); @@ -524,9 +529,6 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, if (which == V4L2_SUBDEV_FORMAT_ACTIVE) rsz->pixel_enc = mbus_info->pixel_enc; - /* Propagete to source pad */ - src_fmt->code = sink_fmt->code; - sink_fmt->width = clamp_t(u32, format->width, RKISP1_ISP_MIN_WIDTH, RKISP1_ISP_MAX_WIDTH); @@ -534,8 +536,45 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz, RKISP1_ISP_MIN_HEIGHT, RKISP1_ISP_MAX_HEIGHT); + /* + * Adjust the color space fields. Accept any color primaries and + * transfer function for both YUV and Bayer. For YUV any YCbCr encoding + * and quantization range is also accepted. For Bayer formats, the YCbCr + * encoding isn't applicable, and the quantization range can only be + * full. + */ + is_yuv = mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV; + + sink_fmt->colorspace = format->colorspace ? : + (is_yuv ? V4L2_COLORSPACE_SRGB : + V4L2_COLORSPACE_RAW); + sink_fmt->xfer_func = format->xfer_func ? : + V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + if (is_yuv) { + sink_fmt->ycbcr_enc = format->ycbcr_enc ? : + V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = format->quantization ? : + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + } else { + /* + * The YCbCr encoding isn't applicable for non-YUV formats, but + * V4L2 has no "no encoding" value. Hardcode it to Rec. 601, it + * should be ignored by userspace. + */ + sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } + *format = *sink_fmt; + /* Propagate the media bus code and color space to the source pad. */ + src_fmt->code = sink_fmt->code; + src_fmt->colorspace = sink_fmt->colorspace; + src_fmt->xfer_func = sink_fmt->xfer_func; + src_fmt->ycbcr_enc = sink_fmt->ycbcr_enc; + src_fmt->quantization = sink_fmt->quantization; + /* Update sink crop */ rkisp1_rsz_set_sink_crop(rsz, sd_state, sink_crop, which); } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index 03638c8f772d..e3b95a2b7e04 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -524,7 +524,7 @@ static int fimc_capture_release(struct file *file) mutex_lock(&fimc->lock); if (close && vc->streaming) { - media_pipeline_stop(&vc->ve.vdev.entity); + video_device_pipeline_stop(&vc->ve.vdev); vc->streaming = false; } @@ -1176,7 +1176,6 @@ static int fimc_cap_streamon(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_vid_cap *vc = &fimc->vid_cap; - struct media_entity *entity = &vc->ve.vdev.entity; struct fimc_source_info *si = NULL; struct v4l2_subdev *sd; int ret; @@ -1184,7 +1183,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, if (fimc_capture_active(fimc)) return -EBUSY; - ret = media_pipeline_start(entity, &vc->ve.pipe->mp); + ret = video_device_pipeline_start(&vc->ve.vdev, &vc->ve.pipe->mp); if (ret < 0) return ret; @@ -1218,7 +1217,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, } err_p_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&vc->ve.vdev); return ret; } @@ -1234,7 +1233,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv, return ret; if (vc->streaming) { - media_pipeline_stop(&vc->ve.vdev.entity); + video_device_pipeline_stop(&vc->ve.vdev); vc->streaming = false; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.h b/drivers/media/platform/samsung/exynos4-is/fimc-core.h index 7a058f3e6298..2b0760add092 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.h @@ -215,7 +215,7 @@ struct fimc_addr { /** * struct fimc_vid_buffer - the driver's video buffer - * @vb: v4l videobuf buffer + * @vb: v4l vb2 buffer * @list: linked list structure for buffer queue * @addr: precalculated DMA address set * @index: buffer index for the output DMA engine diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index e3072d69c49f..a7704ff069d6 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -213,6 +213,7 @@ static int fimc_is_register_subdevs(struct fimc_is *is) if (ret < 0 || index >= FIMC_IS_SENSORS_NUM) { of_node_put(child); + of_node_put(i2c_bus); return ret; } index++; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 8f12240b0eb7..f6a302fa8d37 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -312,7 +312,7 @@ static int isp_video_release(struct file *file) is_singular_file = v4l2_fh_is_singular_file(file); if (is_singular_file && ivc->streaming) { - media_pipeline_stop(entity); + video_device_pipeline_stop(&ivc->ve.vdev); ivc->streaming = 0; } @@ -490,10 +490,9 @@ static int isp_video_streamon(struct file *file, void *priv, { struct fimc_isp *isp = video_drvdata(file); struct exynos_video_entity *ve = &isp->video_capture.ve; - struct media_entity *me = &ve->vdev.entity; int ret; - ret = media_pipeline_start(me, &ve->pipe->mp); + ret = video_device_pipeline_start(&ve->vdev, &ve->pipe->mp); if (ret < 0) return ret; @@ -508,7 +507,7 @@ static int isp_video_streamon(struct file *file, void *priv, isp->video_capture.streaming = 1; return 0; p_stop: - media_pipeline_stop(me); + video_device_pipeline_stop(&ve->vdev); return ret; } @@ -523,7 +522,7 @@ static int isp_video_streamoff(struct file *file, void *priv, if (ret < 0) return ret; - media_pipeline_stop(&video->ve.vdev.entity); + video_device_pipeline_stop(&video->ve.vdev); video->streaming = 0; return 0; } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 41b0a4a5929a..e185a40305a8 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -516,7 +516,7 @@ static int fimc_lite_release(struct file *file) if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { if (fimc->streaming) { - media_pipeline_stop(entity); + video_device_pipeline_stop(&fimc->ve.vdev); fimc->streaming = false; } fimc_lite_stop_capture(fimc, false); @@ -812,13 +812,12 @@ static int fimc_lite_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_lite *fimc = video_drvdata(file); - struct media_entity *entity = &fimc->ve.vdev.entity; int ret; if (fimc_lite_active(fimc)) return -EBUSY; - ret = media_pipeline_start(entity, &fimc->ve.pipe->mp); + ret = video_device_pipeline_start(&fimc->ve.vdev, &fimc->ve.pipe->mp); if (ret < 0) return ret; @@ -835,7 +834,7 @@ static int fimc_lite_streamon(struct file *file, void *priv, } err_p_stop: - media_pipeline_stop(entity); + video_device_pipeline_stop(&fimc->ve.vdev); return 0; } @@ -849,7 +848,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv, if (ret < 0) return ret; - media_pipeline_stop(&fimc->ve.vdev.entity); + video_device_pipeline_stop(&fimc->ve.vdev); fimc->streaming = false; return 0; } diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index c2d8f1e425d8..db106ebdf870 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -848,13 +848,13 @@ static int s3c_camif_streamon(struct file *file, void *priv, if (s3c_vp_active(vp)) return 0; - ret = media_pipeline_start(sensor, camif->m_pipeline); + ret = media_pipeline_start(sensor->pads, camif->m_pipeline); if (ret < 0) return ret; ret = camif_pipeline_validate(camif); if (ret < 0) { - media_pipeline_stop(sensor); + media_pipeline_stop(sensor->pads); return ret; } @@ -878,7 +878,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv, ret = vb2_streamoff(&vp->vb_queue, type); if (ret == 0) - media_pipeline_stop(&camif->sensor.sd->entity); + media_pipeline_stop(camif->sensor.sd->entity.pads); return ret; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 761341934925..fca5c6405eec 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -323,7 +323,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) } ctx->sequence++; /* The MFC returns address of the buffer, now we have to - * check which videobuf does it correspond to */ + * check which vb2_buffer does it correspond to */ list_for_each_entry(dst_buf, &ctx->dst_queue, list) { u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); @@ -1399,6 +1399,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) /* Deinit MFC if probe had failed */ err_enc_reg: video_unregister_device(dev->vfd_dec); + dev->vfd_dec = NULL; err_dec_reg: video_device_release(dev->vfd_enc); err_enc_alloc: @@ -1444,8 +1445,6 @@ static int s5p_mfc_remove(struct platform_device *pdev) video_unregister_device(dev->vfd_enc); video_unregister_device(dev->vfd_dec); - video_device_release(dev->vfd_enc); - video_device_release(dev->vfd_dec); v4l2_device_unregister(&dev->v4l2_dev); s5p_mfc_unconfigure_dma_memory(dev); diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index 2ca95ab2b0fe..37458d4d9564 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -751,7 +751,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_unlocked; } - ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); + ret = video_device_pipeline_start(dcmi->vdev, &dcmi->pipeline); if (ret < 0) { dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", __func__, ret); @@ -865,7 +865,7 @@ err_pipeline_stop: dcmi_pipeline_stop(dcmi); err_media_pipeline_stop: - media_pipeline_stop(&dcmi->vdev->entity); + video_device_pipeline_stop(dcmi->vdev); err_pm_put: pm_runtime_put(dcmi->dev); @@ -892,7 +892,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) dcmi_pipeline_stop(dcmi); - media_pipeline_stop(&dcmi->vdev->entity); + video_device_pipeline_stop(dcmi->vdev); spin_lock_irq(&dcmi->irqlock); diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig index 7960e6836f41..60610c04d6a7 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN4I_CSI tristate "Allwinner A10 CMOS Sensor Interface Support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && RESET_CONTROLLER && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index 0912a1b6d525..a3e826a755fc 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -266,7 +266,7 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_clear_dma_queue; } - ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe); + ret = video_device_pipeline_alloc_start(&csi->vdev); if (ret < 0) goto err_free_scratch_buffer; @@ -330,7 +330,7 @@ err_disable_device: sun4i_csi_capture_stop(csi); err_disable_pipeline: - media_pipeline_stop(&csi->vdev.entity); + video_device_pipeline_stop(&csi->vdev); err_free_scratch_buffer: dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, @@ -359,7 +359,7 @@ static void sun4i_csi_stop_streaming(struct vb2_queue *vq) return_all_buffers(csi, VB2_BUF_STATE_ERROR); spin_unlock_irqrestore(&csi->qlock, flags); - media_pipeline_stop(&csi->vdev.entity); + video_device_pipeline_stop(&csi->vdev); dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr, csi->scratch.paddr); diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 0345901617d4..886006f6a48a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,13 +1,15 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI - tristate "Allwinner V3s Camera Sensor Interface driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && COMMON_CLK && HAS_DMA + tristate "Allwinner A31 Camera Sensor Interface (CSI) Driver" + depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST + depends on PM && COMMON_CLK && RESET_CONTROLLER && HAS_DMA select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG - select REGMAP_MMIO select V4L2_FWNODE + select REGMAP_MMIO help - Support for the Allwinner Camera Sensor Interface Controller on V3s. + Support for the Allwinner A31 Camera Sensor Interface (CSI) + controller, also found on other platforms such as the A83T, H3, + V3/V3s or A64. diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index a971587dbbd1..8b99c17e8403 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -23,43 +23,27 @@ #include <linux/sched.h> #include <linux/sizes.h> #include <linux/slab.h> +#include <media/v4l2-mc.h> #include "sun6i_csi.h" #include "sun6i_csi_reg.h" -#define MODULE_NAME "sun6i-csi" - -struct sun6i_csi_dev { - struct sun6i_csi csi; - struct device *dev; - - struct regmap *regmap; - struct clk *clk_mod; - struct clk *clk_ram; - struct reset_control *rstc_bus; - - int planar_offset[3]; -}; - -static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi) -{ - return container_of(csi, struct sun6i_csi_dev, csi); -} +/* Helpers */ /* TODO add 10&12 bit YUV, RGB support */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, u32 pixformat, u32 mbus_code) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; /* * Some video receivers have the ability to be compatible with * 8bit and 16bit bus width. * Identify the media bus format from device tree. */ - if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL - || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656) - && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) { + if ((v4l2->v4l2_ep.bus_type == V4L2_MBUS_PARALLEL + || v4l2->v4l2_ep.bus_type == V4L2_MBUS_BT656) + && v4l2->v4l2_ep.bus.parallel.bus_width == 16) { switch (pixformat) { case V4L2_PIX_FMT_NV12_16L16: case V4L2_PIX_FMT_NV12: @@ -76,13 +60,14 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_1X16: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, + "Unsupported mbus code: 0x%x\n", mbus_code); break; } break; default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } @@ -139,7 +124,7 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, case MEDIA_BUS_FMT_YVYU8_2X8: return true; default: - dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_dbg(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -154,67 +139,37 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8); default: - dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_dbg(csi_dev->dev, "Unsupported pixformat: 0x%x\n", + pixformat); break; } return false; } -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable) +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct device *dev = sdev->dev; - struct regmap *regmap = sdev->regmap; + struct device *dev = csi_dev->dev; + struct regmap *regmap = csi_dev->regmap; int ret; if (!enable) { regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); + pm_runtime_put(dev); - clk_disable_unprepare(sdev->clk_ram); - if (of_device_is_compatible(dev->of_node, - "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); - reset_control_assert(sdev->rstc_bus); return 0; } - ret = clk_prepare_enable(sdev->clk_mod); - if (ret) { - dev_err(sdev->dev, "Enable csi clk err %d\n", ret); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) return ret; - } - - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_set_rate_exclusive(sdev->clk_mod, 300000000); - - ret = clk_prepare_enable(sdev->clk_ram); - if (ret) { - dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret); - goto clk_mod_disable; - } - - ret = reset_control_deassert(sdev->rstc_bus); - if (ret) { - dev_err(sdev->dev, "reset err %d\n", ret); - goto clk_ram_disable; - } regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN); return 0; - -clk_ram_disable: - clk_disable_unprepare(sdev->clk_ram); -clk_mod_disable: - if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi")) - clk_rate_exclusive_put(sdev->clk_mod); - clk_disable_unprepare(sdev->clk_mod); - return ret; } -static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, +static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* non-YUV */ @@ -232,12 +187,13 @@ static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev, } /* not support YUV420 input format yet */ - dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n"); + dev_dbg(csi_dev->dev, "Select YUV422 as default input format of CSI.\n"); return CSI_INPUT_FORMAT_YUV422; } -static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, - u32 pixformat, u32 field) +static enum csi_output_fmt +get_csi_output_format(struct sun6i_csi_device *csi_dev, u32 pixformat, + u32 field) { bool buf_interlaced = false; @@ -296,14 +252,14 @@ static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev, return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat); + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x\n", pixformat); break; } return CSI_FIELD_RAW_8; } -static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, +static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_device *csi_dev, u32 mbus_code, u32 pixformat) { /* Input sequence does not apply to non-YUV formats */ @@ -330,7 +286,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YVYU; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -352,7 +308,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, case MEDIA_BUS_FMT_YVYU8_2X8: return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n", + dev_warn(csi_dev->dev, "Unsupported mbus code: 0x%x\n", mbus_code); break; } @@ -362,7 +318,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; default: - dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", + dev_warn(csi_dev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n", pixformat); break; } @@ -370,23 +326,23 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, return CSI_INPUT_SEQ_YUYV; } -static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) +static void sun6i_csi_setup_bus(struct sun6i_csi_device *csi_dev) { - struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep; - struct sun6i_csi *csi = &sdev->csi; + struct v4l2_fwnode_endpoint *endpoint = &csi_dev->v4l2.v4l2_ep; + struct sun6i_csi_config *config = &csi_dev->config; unsigned char bus_width; u32 flags; u32 cfg; bool input_interlaced = false; - if (csi->config.field == V4L2_FIELD_INTERLACED - || csi->config.field == V4L2_FIELD_INTERLACED_TB - || csi->config.field == V4L2_FIELD_INTERLACED_BT) + if (config->field == V4L2_FIELD_INTERLACED + || config->field == V4L2_FIELD_INTERLACED_TB + || config->field == V4L2_FIELD_INTERLACED_BT) input_interlaced = true; bus_width = endpoint->bus.parallel.bus_width; - regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_IF_CFG_REG, &cfg); cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK | CSI_IF_CFG_IF_DATA_WIDTH_MASK | @@ -434,7 +390,7 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; break; default: - dev_warn(sdev->dev, "Unsupported bus type: %d\n", + dev_warn(csi_dev->dev, "Unsupported bus type: %d\n", endpoint->bus_type); break; } @@ -452,54 +408,54 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) case 16: /* No need to configure DATA_WIDTH for 16bit */ break; default: - dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width); + dev_warn(csi_dev->dev, "Unsupported bus width: %u\n", bus_width); break; } - regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_IF_CFG_REG, cfg); } -static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_format(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi *csi = &sdev->csi; + struct sun6i_csi_config *config = &csi_dev->config; u32 cfg; u32 val; - regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg); + regmap_read(csi_dev->regmap, CSI_CH_CFG_REG, &cfg); cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK | CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN | CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK | CSI_CH_CFG_INPUT_SEQ_MASK); - val = get_csi_input_format(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_format(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_FMT(val); - val = get_csi_output_format(sdev, csi->config.pixelformat, - csi->config.field); + val = get_csi_output_format(csi_dev, config->pixelformat, + config->field); cfg |= CSI_CH_CFG_OUTPUT_FMT(val); - val = get_csi_input_seq(sdev, csi->config.code, - csi->config.pixelformat); + val = get_csi_input_seq(csi_dev, config->code, + config->pixelformat); cfg |= CSI_CH_CFG_INPUT_SEQ(val); - if (csi->config.field == V4L2_FIELD_TOP) + if (config->field == V4L2_FIELD_TOP) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0; - else if (csi->config.field == V4L2_FIELD_BOTTOM) + else if (config->field == V4L2_FIELD_BOTTOM) cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1; else cfg |= CSI_CH_CFG_FIELD_SEL_BOTH; - regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg); + regmap_write(csi_dev->regmap, CSI_CH_CFG_REG, cfg); } -static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) +static void sun6i_csi_set_window(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_config *config = &sdev->csi.config; + struct sun6i_csi_config *config = &csi_dev->config; u32 bytesperline_y; u32 bytesperline_c; - int *planar_offset = sdev->planar_offset; + int *planar_offset = csi_dev->planar_offset; u32 width = config->width; u32 height = config->height; u32 hor_len = width; @@ -509,7 +465,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Horizontal length should be 2 times of width for packed YUV formats!\n"); hor_len = width * 2; break; @@ -517,10 +473,10 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_HSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_HSIZE_REG, CSI_CH_HSIZE_HOR_LEN(hor_len) | CSI_CH_HSIZE_HOR_START(0)); - regmap_write(sdev->regmap, CSI_CH_VSIZE_REG, + regmap_write(csi_dev->regmap, CSI_CH_VSIZE_REG, CSI_CH_VSIZE_VER_LEN(height) | CSI_CH_VSIZE_VER_START(0)); @@ -552,7 +508,7 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) bytesperline_c * height; break; default: /* raw */ - dev_dbg(sdev->dev, + dev_dbg(csi_dev->dev, "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n", config->pixelformat); bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) * @@ -563,46 +519,42 @@ static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev) break; } - regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG, + regmap_write(csi_dev->regmap, CSI_CH_BUF_LEN_REG, CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) | CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y)); } -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - if (!config) return -EINVAL; - memcpy(&csi->config, config, sizeof(csi->config)); + memcpy(&csi_dev->config, config, sizeof(csi_dev->config)); - sun6i_csi_setup_bus(sdev); - sun6i_csi_set_format(sdev); - sun6i_csi_set_window(sdev); + sun6i_csi_setup_bus(csi_dev); + sun6i_csi_set_format(csi_dev); + sun6i_csi_set_window(csi_dev); return 0; } -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr) +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - - regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG, - (addr + sdev->planar_offset[0]) >> 2); - if (sdev->planar_offset[1] != -1) - regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG, - (addr + sdev->planar_offset[1]) >> 2); - if (sdev->planar_offset[2] != -1) - regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG, - (addr + sdev->planar_offset[2]) >> 2); + regmap_write(csi_dev->regmap, CSI_CH_F0_BUFA_REG, + (addr + csi_dev->planar_offset[0]) >> 2); + if (csi_dev->planar_offset[1] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F1_BUFA_REG, + (addr + csi_dev->planar_offset[1]) >> 2); + if (csi_dev->planar_offset[2] != -1) + regmap_write(csi_dev->regmap, CSI_CH_F2_BUFA_REG, + (addr + csi_dev->planar_offset[2]) >> 2); } -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable) { - struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); - struct regmap *regmap = sdev->regmap; + struct regmap *regmap = csi_dev->regmap; if (!enable) { regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0); @@ -623,10 +575,15 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) CSI_CAP_CH0_VCAP_ON); } -/* ----------------------------------------------------------------------------- - * Media Controller and V4L2 - */ -static int sun6i_csi_link_entity(struct sun6i_csi *csi, +/* Media */ + +static const struct media_device_ops sun6i_csi_media_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + +/* V4L2 */ + +static int sun6i_csi_link_entity(struct sun6i_csi_device *csi_dev, struct media_entity *entity, struct fwnode_handle *fwnode) { @@ -637,24 +594,25 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE); if (ret < 0) { - dev_err(csi->dev, "%s: no source pad in external entity %s\n", - __func__, entity->name); + dev_err(csi_dev->dev, + "%s: no source pad in external entity %s\n", __func__, + entity->name); return -EINVAL; } src_pad_index = ret; - sink = &csi->video.vdev.entity; - sink_pad = &csi->video.pad; + sink = &csi_dev->video.video_dev.entity; + sink_pad = &csi_dev->video.pad; - dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n", + dev_dbg(csi_dev->dev, "creating %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); ret = media_create_pad_link(entity, src_pad_index, sink, sink_pad->index, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); if (ret < 0) { - dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n", + dev_err(csi_dev->dev, "failed to create %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); return ret; @@ -665,27 +623,29 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) { - struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi, - notifier); - struct v4l2_device *v4l2_dev = &csi->v4l2_dev; + struct sun6i_csi_device *csi_dev = + container_of(notifier, struct sun6i_csi_device, + v4l2.notifier); + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; struct v4l2_subdev *sd; int ret; - dev_dbg(csi->dev, "notify complete, all subdevs registered\n"); + dev_dbg(csi_dev->dev, "notify complete, all subdevs registered\n"); sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); if (!sd) return -EINVAL; - ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode); + ret = sun6i_csi_link_entity(csi_dev, &sd->entity, sd->fwnode); if (ret < 0) return ret; - ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); + ret = v4l2_device_register_subdev_nodes(v4l2_dev); if (ret < 0) return ret; - return media_device_register(&csi->media_dev); + return 0; } static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { @@ -696,7 +656,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd) { - struct sun6i_csi *csi = dev_get_drvdata(dev); + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); if (vep->base.port || vep->base.id) { dev_warn(dev, "Only support a single port with one endpoint\n"); @@ -706,7 +666,7 @@ static int sun6i_csi_fwnode_parse(struct device *dev, switch (vep->bus_type) { case V4L2_MBUS_PARALLEL: case V4L2_MBUS_BT656: - csi->v4l2_ep = *vep; + csi_dev->v4l2.v4l2_ep = *vep; return 0; default: dev_err(dev, "Unsupported media bus type\n"); @@ -714,87 +674,102 @@ static int sun6i_csi_fwnode_parse(struct device *dev, } } -static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) -{ - media_device_unregister(&csi->media_dev); - v4l2_async_nf_unregister(&csi->notifier); - v4l2_async_nf_cleanup(&csi->notifier); - sun6i_video_cleanup(&csi->video); - v4l2_device_unregister(&csi->v4l2_dev); - v4l2_ctrl_handler_free(&csi->ctrl_handler); - media_device_cleanup(&csi->media_dev); -} - -static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) +static int sun6i_csi_v4l2_setup(struct sun6i_csi_device *csi_dev) { + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + struct media_device *media_dev = &v4l2->media_dev; + struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev; + struct v4l2_async_notifier *notifier = &v4l2->notifier; + struct device *dev = csi_dev->dev; int ret; - csi->media_dev.dev = csi->dev; - strscpy(csi->media_dev.model, "Allwinner Video Capture Device", - sizeof(csi->media_dev.model)); - csi->media_dev.hw_revision = 0; + /* Media Device */ + + strscpy(media_dev->model, SUN6I_CSI_DESCRIPTION, + sizeof(media_dev->model)); + media_dev->hw_revision = 0; + media_dev->ops = &sun6i_csi_media_ops; + media_dev->dev = dev; - media_device_init(&csi->media_dev); - v4l2_async_nf_init(&csi->notifier); + media_device_init(media_dev); - ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0); + ret = media_device_register(media_dev); if (ret) { - dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n", - ret); - goto clean_media; + dev_err(dev, "failed to register media device: %d\n", ret); + goto error_media; } - csi->v4l2_dev.mdev = &csi->media_dev; - csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler; - ret = v4l2_device_register(csi->dev, &csi->v4l2_dev); + /* V4L2 Device */ + + v4l2_dev->mdev = media_dev; + + ret = v4l2_device_register(dev, v4l2_dev); if (ret) { - dev_err(csi->dev, "V4L2 device registration failed (%d)\n", - ret); - goto free_ctrl; + dev_err(dev, "failed to register v4l2 device: %d\n", ret); + goto error_media; } - ret = sun6i_video_init(&csi->video, csi, "sun6i-csi"); + /* Video */ + + ret = sun6i_video_setup(csi_dev); if (ret) - goto unreg_v4l2; + goto error_v4l2_device; - ret = v4l2_async_nf_parse_fwnode_endpoints(csi->dev, - &csi->notifier, + /* V4L2 Async */ + + v4l2_async_nf_init(notifier); + notifier->ops = &sun6i_csi_async_ops; + + ret = v4l2_async_nf_parse_fwnode_endpoints(dev, notifier, sizeof(struct v4l2_async_subdev), sun6i_csi_fwnode_parse); if (ret) - goto clean_video; + goto error_video; - csi->notifier.ops = &sun6i_csi_async_ops; - - ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); + ret = v4l2_async_nf_register(v4l2_dev, notifier); if (ret) { - dev_err(csi->dev, "notifier registration failed\n"); - goto clean_video; + dev_err(dev, "failed to register v4l2 async notifier: %d\n", + ret); + goto error_v4l2_async_notifier; } return 0; -clean_video: - sun6i_video_cleanup(&csi->video); -unreg_v4l2: - v4l2_device_unregister(&csi->v4l2_dev); -free_ctrl: - v4l2_ctrl_handler_free(&csi->ctrl_handler); -clean_media: - v4l2_async_nf_cleanup(&csi->notifier); - media_device_cleanup(&csi->media_dev); +error_v4l2_async_notifier: + v4l2_async_nf_cleanup(notifier); + +error_video: + sun6i_video_cleanup(csi_dev); + +error_v4l2_device: + v4l2_device_unregister(&v4l2->v4l2_dev); + +error_media: + media_device_unregister(media_dev); + media_device_cleanup(media_dev); return ret; } -/* ----------------------------------------------------------------------------- - * Resources and IRQ - */ -static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) +static void sun6i_csi_v4l2_cleanup(struct sun6i_csi_device *csi_dev) { - struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id; - struct regmap *regmap = sdev->regmap; + struct sun6i_csi_v4l2 *v4l2 = &csi_dev->v4l2; + + media_device_unregister(&v4l2->media_dev); + v4l2_async_nf_unregister(&v4l2->notifier); + v4l2_async_nf_cleanup(&v4l2->notifier); + sun6i_video_cleanup(csi_dev); + v4l2_device_unregister(&v4l2->v4l2_dev); + media_device_cleanup(&v4l2->media_dev); +} + +/* Platform */ + +static irqreturn_t sun6i_csi_interrupt(int irq, void *private) +{ + struct sun6i_csi_device *csi_dev = private; + struct regmap *regmap = csi_dev->regmap; u32 status; regmap_read(regmap, CSI_CH_INT_STA_REG, &status); @@ -814,13 +789,63 @@ static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) } if (status & CSI_CH_INT_STA_FD_PD) - sun6i_video_frame_done(&sdev->csi.video); + sun6i_video_frame_done(csi_dev); regmap_write(regmap, CSI_CH_INT_STA_REG, status); return IRQ_HANDLED; } +static int sun6i_csi_suspend(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + + reset_control_assert(csi_dev->reset); + clk_disable_unprepare(csi_dev->clock_ram); + clk_disable_unprepare(csi_dev->clock_mod); + + return 0; +} + +static int sun6i_csi_resume(struct device *dev) +{ + struct sun6i_csi_device *csi_dev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(csi_dev->reset); + if (ret) { + dev_err(dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(csi_dev->clock_mod); + if (ret) { + dev_err(dev, "failed to enable module clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(csi_dev->clock_ram); + if (ret) { + dev_err(dev, "failed to enable ram clock\n"); + goto error_clock_mod; + } + + return 0; + +error_clock_mod: + clk_disable_unprepare(csi_dev->clock_mod); + +error_reset: + reset_control_assert(csi_dev->reset); + + return ret; +} + +static const struct dev_pm_ops sun6i_csi_pm_ops = { + .runtime_suspend = sun6i_csi_suspend, + .runtime_resume = sun6i_csi_resume, +}; + static const struct regmap_config sun6i_csi_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -828,106 +853,181 @@ static const struct regmap_config sun6i_csi_regmap_config = { .max_register = 0x9c, }; -static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, - struct platform_device *pdev) +static int sun6i_csi_resources_setup(struct sun6i_csi_device *csi_dev, + struct platform_device *platform_dev) { + struct device *dev = csi_dev->dev; + const struct sun6i_csi_variant *variant; void __iomem *io_base; int ret; int irq; - io_base = devm_platform_ioremap_resource(pdev, 0); + variant = of_device_get_match_data(dev); + if (!variant) + return -EINVAL; + + /* Registers */ + + io_base = devm_platform_ioremap_resource(platform_dev, 0); if (IS_ERR(io_base)) return PTR_ERR(io_base); - sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, - &sun6i_csi_regmap_config); - if (IS_ERR(sdev->regmap)) { - dev_err(&pdev->dev, "Failed to init register map\n"); - return PTR_ERR(sdev->regmap); + csi_dev->regmap = devm_regmap_init_mmio_clk(dev, "bus", io_base, + &sun6i_csi_regmap_config); + if (IS_ERR(csi_dev->regmap)) { + dev_err(dev, "failed to init register map\n"); + return PTR_ERR(csi_dev->regmap); } - sdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); - if (IS_ERR(sdev->clk_mod)) { - dev_err(&pdev->dev, "Unable to acquire csi clock\n"); - return PTR_ERR(sdev->clk_mod); + /* Clocks */ + + csi_dev->clock_mod = devm_clk_get(dev, "mod"); + if (IS_ERR(csi_dev->clock_mod)) { + dev_err(dev, "failed to acquire module clock\n"); + return PTR_ERR(csi_dev->clock_mod); } - sdev->clk_ram = devm_clk_get(&pdev->dev, "ram"); - if (IS_ERR(sdev->clk_ram)) { - dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); - return PTR_ERR(sdev->clk_ram); + csi_dev->clock_ram = devm_clk_get(dev, "ram"); + if (IS_ERR(csi_dev->clock_ram)) { + dev_err(dev, "failed to acquire ram clock\n"); + return PTR_ERR(csi_dev->clock_ram); } - sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL); - if (IS_ERR(sdev->rstc_bus)) { - dev_err(&pdev->dev, "Cannot get reset controller\n"); - return PTR_ERR(sdev->rstc_bus); + ret = clk_set_rate_exclusive(csi_dev->clock_mod, + variant->clock_mod_rate); + if (ret) { + dev_err(dev, "failed to set mod clock rate\n"); + return ret; + } + + /* Reset */ + + csi_dev->reset = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(csi_dev->reset)) { + dev_err(dev, "failed to acquire reset\n"); + ret = PTR_ERR(csi_dev->reset); + goto error_clock_rate_exclusive; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return -ENXIO; + /* Interrupt */ - ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME, - sdev); + irq = platform_get_irq(platform_dev, 0); + if (irq < 0) { + dev_err(dev, "failed to get interrupt\n"); + ret = -ENXIO; + goto error_clock_rate_exclusive; + } + + ret = devm_request_irq(dev, irq, sun6i_csi_interrupt, 0, SUN6I_CSI_NAME, + csi_dev); if (ret) { - dev_err(&pdev->dev, "Cannot request csi IRQ\n"); - return ret; + dev_err(dev, "failed to request interrupt\n"); + goto error_clock_rate_exclusive; } + /* Runtime PM */ + + pm_runtime_enable(dev); + return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi_dev->clock_mod); + + return ret; +} + +static void sun6i_csi_resources_cleanup(struct sun6i_csi_device *csi_dev) +{ + pm_runtime_disable(csi_dev->dev); + clk_rate_exclusive_put(csi_dev->clock_mod); } -static int sun6i_csi_probe(struct platform_device *pdev) +static int sun6i_csi_probe(struct platform_device *platform_dev) { - struct sun6i_csi_dev *sdev; + struct sun6i_csi_device *csi_dev; + struct device *dev = &platform_dev->dev; int ret; - sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); - if (!sdev) + csi_dev = devm_kzalloc(dev, sizeof(*csi_dev), GFP_KERNEL); + if (!csi_dev) return -ENOMEM; - sdev->dev = &pdev->dev; + csi_dev->dev = &platform_dev->dev; + platform_set_drvdata(platform_dev, csi_dev); - ret = sun6i_csi_resource_request(sdev, pdev); + ret = sun6i_csi_resources_setup(csi_dev, platform_dev); if (ret) return ret; - platform_set_drvdata(pdev, sdev); + ret = sun6i_csi_v4l2_setup(csi_dev); + if (ret) + goto error_resources; + + return 0; - sdev->csi.dev = &pdev->dev; - return sun6i_csi_v4l2_init(&sdev->csi); +error_resources: + sun6i_csi_resources_cleanup(csi_dev); + + return ret; } static int sun6i_csi_remove(struct platform_device *pdev) { - struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev); + struct sun6i_csi_device *csi_dev = platform_get_drvdata(pdev); - sun6i_csi_v4l2_cleanup(&sdev->csi); + sun6i_csi_v4l2_cleanup(csi_dev); + sun6i_csi_resources_cleanup(csi_dev); return 0; } +static const struct sun6i_csi_variant sun6i_a31_csi_variant = { + .clock_mod_rate = 297000000, +}; + +static const struct sun6i_csi_variant sun50i_a64_csi_variant = { + .clock_mod_rate = 300000000, +}; + static const struct of_device_id sun6i_csi_of_match[] = { - { .compatible = "allwinner,sun6i-a31-csi", }, - { .compatible = "allwinner,sun8i-a83t-csi", }, - { .compatible = "allwinner,sun8i-h3-csi", }, - { .compatible = "allwinner,sun8i-v3s-csi", }, - { .compatible = "allwinner,sun50i-a64-csi", }, + { + .compatible = "allwinner,sun6i-a31-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-a83t-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-h3-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun8i-v3s-csi", + .data = &sun6i_a31_csi_variant, + }, + { + .compatible = "allwinner,sun50i-a64-csi", + .data = &sun50i_a64_csi_variant, + }, {}, }; + MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); static struct platform_driver sun6i_csi_platform_driver = { - .probe = sun6i_csi_probe, - .remove = sun6i_csi_remove, - .driver = { - .name = MODULE_NAME, - .of_match_table = of_match_ptr(sun6i_csi_of_match), + .probe = sun6i_csi_probe, + .remove = sun6i_csi_remove, + .driver = { + .name = SUN6I_CSI_NAME, + .of_match_table = of_match_ptr(sun6i_csi_of_match), + .pm = &sun6i_csi_pm_ops, }, }; + module_platform_driver(sun6i_csi_platform_driver); -MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver"); +MODULE_DESCRIPTION("Allwinner A31 Camera Sensor Interface driver"); MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 3a38d107ae3f..bab705678280 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -8,13 +8,22 @@ #ifndef __SUN6I_CSI_H__ #define __SUN6I_CSI_H__ -#include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> +#include <media/videobuf2-v4l2.h> #include "sun6i_video.h" -struct sun6i_csi; +#define SUN6I_CSI_NAME "sun6i-csi" +#define SUN6I_CSI_DESCRIPTION "Allwinner A31 CSI Device" + +struct sun6i_csi_buffer { + struct vb2_v4l2_buffer v4l2_buffer; + struct list_head list; + + dma_addr_t dma_addr; + bool queued_to_csi; +}; /** * struct sun6i_csi_config - configs for sun6i csi @@ -32,59 +41,78 @@ struct sun6i_csi_config { u32 height; }; -struct sun6i_csi { - struct device *dev; - struct v4l2_ctrl_handler ctrl_handler; +struct sun6i_csi_v4l2 { struct v4l2_device v4l2_dev; struct media_device media_dev; struct v4l2_async_notifier notifier; - /* video port settings */ struct v4l2_fwnode_endpoint v4l2_ep; +}; - struct sun6i_csi_config config; +struct sun6i_csi_device { + struct device *dev; + struct sun6i_csi_config config; + struct sun6i_csi_v4l2 v4l2; struct sun6i_video video; + + struct regmap *regmap; + struct clk *clock_mod; + struct clk *clock_ram; + struct reset_control *reset; + + int planar_offset[3]; +}; + +struct sun6i_csi_variant { + unsigned long clock_mod_rate; }; /** * sun6i_csi_is_format_supported() - check if the format supported by csi - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @pixformat: v4l2 pixel format (V4L2_PIX_FMT_*) * @mbus_code: media bus format code (MEDIA_BUS_FMT_*) + * + * Return: true if format is supported, false otherwise. */ -bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat, - u32 mbus_code); +bool sun6i_csi_is_format_supported(struct sun6i_csi_device *csi_dev, + u32 pixformat, u32 mbus_code); /** * sun6i_csi_set_power() - power on/off the csi - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @enable: on/off + * + * Return: 0 if successful, error code otherwise. */ -int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable); +int sun6i_csi_set_power(struct sun6i_csi_device *csi_dev, bool enable); /** * sun6i_csi_update_config() - update the csi register settings - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @config: see struct sun6i_csi_config + * + * Return: 0 if successful, error code otherwise. */ -int sun6i_csi_update_config(struct sun6i_csi *csi, +int sun6i_csi_update_config(struct sun6i_csi_device *csi_dev, struct sun6i_csi_config *config); /** * sun6i_csi_update_buf_addr() - update the csi frame buffer address - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @addr: frame buffer's physical address */ -void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr); +void sun6i_csi_update_buf_addr(struct sun6i_csi_device *csi_dev, + dma_addr_t addr); /** * sun6i_csi_set_stream() - start/stop csi streaming - * @csi: pointer to the csi + * @csi_dev: pointer to the csi device * @enable: start/stop */ -void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable); +void sun6i_csi_set_stream(struct sun6i_csi_device *csi_dev, bool enable); /* get bpp form v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 1d46e113d01d..791583d23a65 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -23,15 +23,27 @@ #define MAX_WIDTH (4800) #define MAX_HEIGHT (4800) -struct sun6i_csi_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; +/* Helpers */ - dma_addr_t dma_addr; - bool queued_to_csi; -}; +static struct v4l2_subdev * +sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) +{ + struct media_pad *remote; + + remote = media_pad_remote_pad_first(&video->pad); + + if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) + return NULL; + + if (pad) + *pad = remote->index; -static const u32 supported_pixformats[] = { + return media_entity_to_v4l2_subdev(remote->entity); +} + +/* Format */ + +static const u32 sun6i_video_formats[] = { V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SGBRG8, V4L2_PIX_FMT_SGRBG8, @@ -61,123 +73,142 @@ static const u32 supported_pixformats[] = { V4L2_PIX_FMT_JPEG, }; -static bool is_pixformat_valid(unsigned int pixformat) +static bool sun6i_video_format_check(u32 format) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++) - if (supported_pixformats[i] == pixformat) + for (i = 0; i < ARRAY_SIZE(sun6i_video_formats); i++) + if (sun6i_video_formats[i] == format) return true; return false; } -static struct v4l2_subdev * -sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) -{ - struct media_pad *remote; +/* Video */ - remote = media_pad_remote_pad_first(&video->pad); +static void sun6i_video_buffer_configure(struct sun6i_csi_device *csi_dev, + struct sun6i_csi_buffer *csi_buffer) +{ + csi_buffer->queued_to_csi = true; + sun6i_csi_update_buf_addr(csi_dev, csi_buffer->dma_addr); +} - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; +static void sun6i_video_configure(struct sun6i_csi_device *csi_dev) +{ + struct sun6i_video *video = &csi_dev->video; + struct sun6i_csi_config config = { 0 }; - if (pad) - *pad = remote->index; + config.pixelformat = video->format.fmt.pix.pixelformat; + config.code = video->mbus_code; + config.field = video->format.fmt.pix.field; + config.width = video->format.fmt.pix.width; + config.height = video->format.fmt.pix.height; - return media_entity_to_v4l2_subdev(remote->entity); + sun6i_csi_update_config(csi_dev, &config); } -static int sun6i_video_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, +/* Queue */ + +static int sun6i_video_queue_setup(struct vb2_queue *queue, + unsigned int *buffers_count, + unsigned int *planes_count, unsigned int sizes[], struct device *alloc_devs[]) { - struct sun6i_video *video = vb2_get_drv_priv(vq); - unsigned int size = video->fmt.fmt.pix.sizeimage; + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; + unsigned int size = video->format.fmt.pix.sizeimage; - if (*nplanes) + if (*planes_count) return sizes[0] < size ? -EINVAL : 0; - *nplanes = 1; + *planes_count = 1; sizes[0] = size; return 0; } -static int sun6i_video_buffer_prepare(struct vb2_buffer *vb) +static int sun6i_video_buffer_prepare(struct vb2_buffer *buffer) { - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = video->fmt.fmt.pix.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long size = video->format.fmt.pix.sizeimage; + + if (vb2_plane_size(buffer, 0) < size) { + v4l2_err(v4l2_dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(buffer, 0), size); return -EINVAL; } - vb2_set_plane_payload(vb, 0, size); - - buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + vb2_set_plane_payload(buffer, 0, size); - vbuf->field = video->fmt.fmt.pix.field; + csi_buffer->dma_addr = vb2_dma_contig_plane_dma_addr(buffer, 0); + v4l2_buffer->field = video->format.fmt.pix.field; return 0; } -static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) +static void sun6i_video_buffer_queue(struct vb2_buffer *buffer) +{ + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(buffer->vb2_queue); + struct sun6i_video *video = &csi_dev->video; + struct vb2_v4l2_buffer *v4l2_buffer = to_vb2_v4l2_buffer(buffer); + struct sun6i_csi_buffer *csi_buffer = + container_of(v4l2_buffer, struct sun6i_csi_buffer, v4l2_buffer); + unsigned long flags; + + spin_lock_irqsave(&video->dma_queue_lock, flags); + csi_buffer->queued_to_csi = false; + list_add_tail(&csi_buffer->list, &video->dma_queue); + spin_unlock_irqrestore(&video->dma_queue_lock, flags); +} + +static int sun6i_video_start_streaming(struct vb2_queue *queue, + unsigned int count) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; + struct video_device *video_dev = &video->video_dev; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct sun6i_csi_config config; struct v4l2_subdev *subdev; unsigned long flags; int ret; video->sequence = 0; - ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe); + ret = video_device_pipeline_alloc_start(video_dev); if (ret < 0) - goto clear_dma_queue; + goto error_dma_queue_flush; if (video->mbus_code == 0) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } subdev = sun6i_video_remote_subdev(video, NULL); if (!subdev) { ret = -EINVAL; - goto stop_media_pipeline; + goto error_media_pipeline; } - config.pixelformat = video->fmt.fmt.pix.pixelformat; - config.code = video->mbus_code; - config.field = video->fmt.fmt.pix.field; - config.width = video->fmt.fmt.pix.width; - config.height = video->fmt.fmt.pix.height; - - ret = sun6i_csi_update_config(video->csi, &config); - if (ret < 0) - goto stop_media_pipeline; + sun6i_video_configure(csi_dev); spin_lock_irqsave(&video->dma_queue_lock, flags); buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); - buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, buf); - sun6i_csi_set_stream(video->csi, true); + sun6i_csi_set_stream(csi_dev, true); /* * CSI will lookup the next dma buffer for next frame before the - * the current frame done IRQ triggered. This is not documented + * current frame done IRQ triggered. This is not documented * but reported by Ondřej Jirman. * The BSP code has workaround for this too. It skip to mark the * first buffer as frame done for VB2 and pass the second buffer @@ -193,34 +224,37 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) * would also drop frame when lacking of queued buffer. */ next_buf = list_next_entry(buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); spin_unlock_irqrestore(&video->dma_queue_lock, flags); ret = v4l2_subdev_call(subdev, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) - goto stop_csi_stream; + goto error_stream; return 0; -stop_csi_stream: - sun6i_csi_set_stream(video->csi, false); -stop_media_pipeline: - media_pipeline_stop(&video->vdev.entity); -clear_dma_queue: +error_stream: + sun6i_csi_set_stream(csi_dev, false); + +error_media_pipeline: + video_device_pipeline_stop(video_dev); + +error_dma_queue_flush: spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, + VB2_BUF_STATE_QUEUED); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); return ret; } -static void sun6i_video_stop_streaming(struct vb2_queue *vq) +static void sun6i_video_stop_streaming(struct vb2_queue *queue) { - struct sun6i_video *video = vb2_get_drv_priv(vq); + struct sun6i_csi_device *csi_dev = vb2_get_drv_priv(queue); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev *subdev; unsigned long flags; struct sun6i_csi_buffer *buf; @@ -229,45 +263,32 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); - sun6i_csi_set_stream(video->csi, false); + sun6i_csi_set_stream(csi_dev, false); - media_pipeline_stop(&video->vdev.entity); + video_device_pipeline_stop(&video->video_dev); /* Release all active buffers */ spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&buf->v4l2_buffer.vb2_buf, VB2_BUF_STATE_ERROR); INIT_LIST_HEAD(&video->dma_queue); spin_unlock_irqrestore(&video->dma_queue_lock, flags); } -static void sun6i_video_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct sun6i_csi_buffer *buf = - container_of(vbuf, struct sun6i_csi_buffer, vb); - struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&video->dma_queue_lock, flags); - buf->queued_to_csi = false; - list_add_tail(&buf->list, &video->dma_queue); - spin_unlock_irqrestore(&video->dma_queue_lock, flags); -} - -void sun6i_video_frame_done(struct sun6i_video *video) +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev) { + struct sun6i_video *video = &csi_dev->video; struct sun6i_csi_buffer *buf; struct sun6i_csi_buffer *next_buf; - struct vb2_v4l2_buffer *vbuf; + struct vb2_v4l2_buffer *v4l2_buffer; spin_lock(&video->dma_queue_lock); buf = list_first_entry(&video->dma_queue, struct sun6i_csi_buffer, list); if (list_is_last(&buf->list, &video->dma_queue)) { - dev_dbg(video->csi->dev, "Frame dropped!\n"); - goto unlock; + dev_dbg(csi_dev->dev, "Frame dropped!\n"); + goto complete; } next_buf = list_next_entry(buf, list); @@ -277,200 +298,204 @@ void sun6i_video_frame_done(struct sun6i_video *video) * for next ISR call. */ if (!next_buf->queued_to_csi) { - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); - dev_dbg(video->csi->dev, "Frame dropped!\n"); - goto unlock; + sun6i_video_buffer_configure(csi_dev, next_buf); + dev_dbg(csi_dev->dev, "Frame dropped!\n"); + goto complete; } list_del(&buf->list); - vbuf = &buf->vb; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vbuf->sequence = video->sequence; - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + v4l2_buffer = &buf->v4l2_buffer; + v4l2_buffer->vb2_buf.timestamp = ktime_get_ns(); + v4l2_buffer->sequence = video->sequence; + vb2_buffer_done(&v4l2_buffer->vb2_buf, VB2_BUF_STATE_DONE); /* Prepare buffer for next frame but one. */ if (!list_is_last(&next_buf->list, &video->dma_queue)) { next_buf = list_next_entry(next_buf, list); - next_buf->queued_to_csi = true; - sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr); + sun6i_video_buffer_configure(csi_dev, next_buf); } else { - dev_dbg(video->csi->dev, "Next frame will be dropped!\n"); + dev_dbg(csi_dev->dev, "Next frame will be dropped!\n"); } -unlock: +complete: video->sequence++; spin_unlock(&video->dma_queue_lock); } -static const struct vb2_ops sun6i_csi_vb2_ops = { +static const struct vb2_ops sun6i_video_queue_ops = { .queue_setup = sun6i_video_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, .buf_prepare = sun6i_video_buffer_prepare, + .buf_queue = sun6i_video_buffer_queue, .start_streaming = sun6i_video_start_streaming, .stop_streaming = sun6i_video_stop_streaming, - .buf_queue = sun6i_video_buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) +/* V4L2 Device */ + +static int sun6i_video_querycap(struct file *file, void *private, + struct v4l2_capability *capability) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct video_device *video_dev = &csi_dev->video.video_dev; - strscpy(cap->driver, "sun6i-video", sizeof(cap->driver)); - strscpy(cap->card, video->vdev.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - video->csi->dev->of_node->name); + strscpy(capability->driver, SUN6I_CSI_NAME, sizeof(capability->driver)); + strscpy(capability->card, video_dev->name, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", dev_name(csi_dev->dev)); return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int sun6i_video_enum_fmt(struct file *file, void *private, + struct v4l2_fmtdesc *fmtdesc) { - u32 index = f->index; + u32 index = fmtdesc->index; - if (index >= ARRAY_SIZE(supported_pixformats)) + if (index >= ARRAY_SIZE(sun6i_video_formats)) return -EINVAL; - f->pixelformat = supported_pixformats[index]; + fmtdesc->pixelformat = sun6i_video_formats[index]; return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sun6i_video_g_fmt(struct file *file, void *private, + struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; - *fmt = video->fmt; + *format = video->format; return 0; } -static int sun6i_video_try_fmt(struct sun6i_video *video, - struct v4l2_format *f) +static int sun6i_video_format_try(struct sun6i_video *video, + struct v4l2_format *format) { - struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_pix_format *pix_format = &format->fmt.pix; int bpp; - if (!is_pixformat_valid(pixfmt->pixelformat)) - pixfmt->pixelformat = supported_pixformats[0]; + if (!sun6i_video_format_check(pix_format->pixelformat)) + pix_format->pixelformat = sun6i_video_formats[0]; - v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1, - &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); + v4l_bound_align_image(&pix_format->width, MIN_WIDTH, MAX_WIDTH, 1, + &pix_format->height, MIN_HEIGHT, MAX_WIDTH, 1, 1); - bpp = sun6i_csi_get_bpp(pixfmt->pixelformat); - pixfmt->bytesperline = (pixfmt->width * bpp) >> 3; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + bpp = sun6i_csi_get_bpp(pix_format->pixelformat); + pix_format->bytesperline = (pix_format->width * bpp) >> 3; + pix_format->sizeimage = pix_format->bytesperline * pix_format->height; - if (pixfmt->field == V4L2_FIELD_ANY) - pixfmt->field = V4L2_FIELD_NONE; + if (pix_format->field == V4L2_FIELD_ANY) + pix_format->field = V4L2_FIELD_NONE; - if (pixfmt->pixelformat == V4L2_PIX_FMT_JPEG) - pixfmt->colorspace = V4L2_COLORSPACE_JPEG; + if (pix_format->pixelformat == V4L2_PIX_FMT_JPEG) + pix_format->colorspace = V4L2_COLORSPACE_JPEG; else - pixfmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_format->colorspace = V4L2_COLORSPACE_SRGB; - pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT; - pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix_format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_format->quantization = V4L2_QUANTIZATION_DEFAULT; + pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; return 0; } -static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f) +static int sun6i_video_format_set(struct sun6i_video *video, + struct v4l2_format *format) { int ret; - ret = sun6i_video_try_fmt(video, f); + ret = sun6i_video_format_try(video, format); if (ret) return ret; - video->fmt = *f; + video->format = *format; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_s_fmt(struct file *file, void *private, + struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; - if (vb2_is_busy(&video->vb2_vidq)) + if (vb2_is_busy(&video->queue)) return -EBUSY; - return sun6i_video_set_fmt(video, f); + return sun6i_video_format_set(video, format); } -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int sun6i_video_try_fmt(struct file *file, void *private, + struct v4l2_format *format) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; - return sun6i_video_try_fmt(video, f); + return sun6i_video_format_try(video, format); } -static int vidioc_enum_input(struct file *file, void *fh, - struct v4l2_input *inp) +static int sun6i_video_enum_input(struct file *file, void *private, + struct v4l2_input *input) { - if (inp->index != 0) + if (input->index != 0) return -EINVAL; - strscpy(inp->name, "camera", sizeof(inp->name)); - inp->type = V4L2_INPUT_TYPE_CAMERA; + input->type = V4L2_INPUT_TYPE_CAMERA; + strscpy(input->name, "Camera", sizeof(input->name)); return 0; } -static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) +static int sun6i_video_g_input(struct file *file, void *private, + unsigned int *index) { - *i = 0; + *index = 0; return 0; } -static int vidioc_s_input(struct file *file, void *fh, unsigned int i) +static int sun6i_video_s_input(struct file *file, void *private, + unsigned int index) { - if (i != 0) + if (index != 0) return -EINVAL; return 0; } static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_querycap = sun6i_video_querycap, + + .vidioc_enum_fmt_vid_cap = sun6i_video_enum_fmt, + .vidioc_g_fmt_vid_cap = sun6i_video_g_fmt, + .vidioc_s_fmt_vid_cap = sun6i_video_s_fmt, + .vidioc_try_fmt_vid_cap = sun6i_video_try_fmt, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_input = vidioc_g_input, + .vidioc_enum_input = sun6i_video_enum_input, + .vidioc_g_input = sun6i_video_g_input, + .vidioc_s_input = sun6i_video_s_input, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_qbuf = vb2_ioctl_qbuf, .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, - - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -/* ----------------------------------------------------------------------------- - * V4L2 file operations - */ +/* V4L2 File */ + static int sun6i_video_open(struct file *file) { - struct sun6i_video *video = video_drvdata(file); + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; int ret = 0; if (mutex_lock_interruptible(&video->lock)) @@ -478,45 +503,48 @@ static int sun6i_video_open(struct file *file) ret = v4l2_fh_open(file); if (ret < 0) - goto unlock; + goto error_lock; - ret = v4l2_pipeline_pm_get(&video->vdev.entity); + ret = v4l2_pipeline_pm_get(&video->video_dev.entity); if (ret < 0) - goto fh_release; - - /* check if already powered */ - if (!v4l2_fh_is_singular_file(file)) - goto unlock; + goto error_v4l2_fh; - ret = sun6i_csi_set_power(video->csi, true); - if (ret < 0) - goto fh_release; + /* Power on at first open. */ + if (v4l2_fh_is_singular_file(file)) { + ret = sun6i_csi_set_power(csi_dev, true); + if (ret < 0) + goto error_v4l2_fh; + } mutex_unlock(&video->lock); + return 0; -fh_release: +error_v4l2_fh: v4l2_fh_release(file); -unlock: + +error_lock: mutex_unlock(&video->lock); + return ret; } static int sun6i_video_close(struct file *file) { - struct sun6i_video *video = video_drvdata(file); - bool last_fh; + struct sun6i_csi_device *csi_dev = video_drvdata(file); + struct sun6i_video *video = &csi_dev->video; + bool last_close; mutex_lock(&video->lock); - last_fh = v4l2_fh_is_singular_file(file); + last_close = v4l2_fh_is_singular_file(file); _vb2_fop_release(file, NULL); + v4l2_pipeline_pm_put(&video->video_dev.entity); - v4l2_pipeline_pm_put(&video->vdev.entity); - - if (last_fh) - sun6i_csi_set_power(video->csi, false); + /* Power off at last close. */ + if (last_close) + sun6i_csi_set_power(csi_dev, false); mutex_unlock(&video->lock); @@ -532,9 +560,8 @@ static const struct v4l2_file_operations sun6i_video_fops = { .poll = vb2_fop_poll }; -/* ----------------------------------------------------------------------------- - * Media Operations - */ +/* Media Entity */ + static int sun6i_video_link_validate_get_format(struct media_pad *pad, struct v4l2_subdev_format *fmt) { @@ -554,15 +581,16 @@ static int sun6i_video_link_validate(struct media_link *link) { struct video_device *vdev = container_of(link->sink->entity, struct video_device, entity); - struct sun6i_video *video = video_get_drvdata(vdev); + struct sun6i_csi_device *csi_dev = video_get_drvdata(vdev); + struct sun6i_video *video = &csi_dev->video; struct v4l2_subdev_format source_fmt; int ret; video->mbus_code = 0; if (!media_pad_remote_pad_first(link->sink->entity->pads)) { - dev_info(video->csi->dev, - "video node %s pad not connected\n", vdev->name); + dev_info(csi_dev->dev, "video node %s pad not connected\n", + vdev->name); return -ENOLINK; } @@ -570,21 +598,21 @@ static int sun6i_video_link_validate(struct media_link *link) if (ret < 0) return ret; - if (!sun6i_csi_is_format_supported(video->csi, - video->fmt.fmt.pix.pixelformat, + if (!sun6i_csi_is_format_supported(csi_dev, + video->format.fmt.pix.pixelformat, source_fmt.format.code)) { - dev_err(video->csi->dev, + dev_err(csi_dev->dev, "Unsupported pixformat: 0x%x with mbus code: 0x%x!\n", - video->fmt.fmt.pix.pixelformat, + video->format.fmt.pix.pixelformat, source_fmt.format.code); return -EPIPE; } - if (source_fmt.format.width != video->fmt.fmt.pix.width || - source_fmt.format.height != video->fmt.fmt.pix.height) { - dev_err(video->csi->dev, + if (source_fmt.format.width != video->format.fmt.pix.width || + source_fmt.format.height != video->format.fmt.pix.height) { + dev_err(csi_dev->dev, "Wrong width or height %ux%u (%ux%u expected)\n", - video->fmt.fmt.pix.width, video->fmt.fmt.pix.height, + video->format.fmt.pix.width, video->format.fmt.pix.height, source_fmt.format.width, source_fmt.format.height); return -EPIPE; } @@ -598,88 +626,108 @@ static const struct media_entity_operations sun6i_video_media_ops = { .link_validate = sun6i_video_link_validate }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name) +/* Video */ + +int sun6i_video_setup(struct sun6i_csi_device *csi_dev) { - struct video_device *vdev = &video->vdev; - struct vb2_queue *vidq = &video->vb2_vidq; - struct v4l2_format fmt = { 0 }; + struct sun6i_video *video = &csi_dev->video; + struct v4l2_device *v4l2_dev = &csi_dev->v4l2.v4l2_dev; + struct video_device *video_dev = &video->video_dev; + struct vb2_queue *queue = &video->queue; + struct media_pad *pad = &video->pad; + struct v4l2_format format = { 0 }; + struct v4l2_pix_format *pix_format = &format.fmt.pix; int ret; - video->csi = csi; + /* Media Entity */ - /* Initialize the media entity... */ - video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; - vdev->entity.ops = &sun6i_video_media_ops; - ret = media_entity_pads_init(&vdev->entity, 1, &video->pad); + video_dev->entity.ops = &sun6i_video_media_ops; + + /* Media Pad */ + + pad->flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + + ret = media_entity_pads_init(&video_dev->entity, 1, pad); if (ret < 0) return ret; - mutex_init(&video->lock); + /* DMA queue */ INIT_LIST_HEAD(&video->dma_queue); spin_lock_init(&video->dma_queue_lock); video->sequence = 0; - /* Setup default format */ - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.pixelformat = supported_pixformats[0]; - fmt.fmt.pix.width = 1280; - fmt.fmt.pix.height = 720; - fmt.fmt.pix.field = V4L2_FIELD_NONE; - sun6i_video_set_fmt(video, &fmt); - - /* Initialize videobuf2 queue */ - vidq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - vidq->io_modes = VB2_MMAP | VB2_DMABUF; - vidq->drv_priv = video; - vidq->buf_struct_size = sizeof(struct sun6i_csi_buffer); - vidq->ops = &sun6i_csi_vb2_ops; - vidq->mem_ops = &vb2_dma_contig_memops; - vidq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - vidq->lock = &video->lock; - /* Make sure non-dropped frame */ - vidq->min_buffers_needed = 3; - vidq->dev = csi->dev; - - ret = vb2_queue_init(vidq); + /* Queue */ + + mutex_init(&video->lock); + + queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + queue->io_modes = VB2_MMAP | VB2_DMABUF; + queue->buf_struct_size = sizeof(struct sun6i_csi_buffer); + queue->ops = &sun6i_video_queue_ops; + queue->mem_ops = &vb2_dma_contig_memops; + queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + queue->lock = &video->lock; + queue->dev = csi_dev->dev; + queue->drv_priv = csi_dev; + + /* Make sure non-dropped frame. */ + queue->min_buffers_needed = 3; + + ret = vb2_queue_init(queue); if (ret) { - v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to initialize vb2 queue: %d\n", ret); + goto error_media_entity; } - /* Register video device */ - strscpy(vdev->name, name, sizeof(vdev->name)); - vdev->release = video_device_release_empty; - vdev->fops = &sun6i_video_fops; - vdev->ioctl_ops = &sun6i_video_ioctl_ops; - vdev->vfl_type = VFL_TYPE_VIDEO; - vdev->vfl_dir = VFL_DIR_RX; - vdev->v4l2_dev = &csi->v4l2_dev; - vdev->queue = vidq; - vdev->lock = &video->lock; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - video_set_drvdata(vdev, video); - - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + /* V4L2 Format */ + + format.type = queue->type; + pix_format->pixelformat = sun6i_video_formats[0]; + pix_format->width = 1280; + pix_format->height = 720; + pix_format->field = V4L2_FIELD_NONE; + + sun6i_video_format_set(video, &format); + + /* Video Device */ + + strscpy(video_dev->name, SUN6I_CSI_NAME, sizeof(video_dev->name)); + video_dev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + video_dev->vfl_dir = VFL_DIR_RX; + video_dev->release = video_device_release_empty; + video_dev->fops = &sun6i_video_fops; + video_dev->ioctl_ops = &sun6i_video_ioctl_ops; + video_dev->v4l2_dev = v4l2_dev; + video_dev->queue = queue; + video_dev->lock = &video->lock; + + video_set_drvdata(video_dev, csi_dev); + + ret = video_register_device(video_dev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - v4l2_err(&csi->v4l2_dev, - "video_register_device failed: %d\n", ret); - goto clean_entity; + v4l2_err(v4l2_dev, "failed to register video device: %d\n", + ret); + goto error_media_entity; } return 0; -clean_entity: - media_entity_cleanup(&video->vdev.entity); +error_media_entity: + media_entity_cleanup(&video_dev->entity); + mutex_destroy(&video->lock); + return ret; } -void sun6i_video_cleanup(struct sun6i_video *video) +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev) { - vb2_video_unregister_device(&video->vdev); - media_entity_cleanup(&video->vdev.entity); + struct sun6i_video *video = &csi_dev->video; + struct video_device *video_dev = &video->video_dev; + + vb2_video_unregister_device(video_dev); + media_entity_cleanup(&video_dev->entity); mutex_destroy(&video->lock); } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index b9cd919c24ac..a917d2da6deb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -11,28 +11,25 @@ #include <media/v4l2-dev.h> #include <media/videobuf2-core.h> -struct sun6i_csi; +struct sun6i_csi_device; struct sun6i_video { - struct video_device vdev; + struct video_device video_dev; + struct vb2_queue queue; + struct mutex lock; /* Queue lock. */ struct media_pad pad; - struct sun6i_csi *csi; - struct mutex lock; - - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; struct list_head dma_queue; + spinlock_t dma_queue_lock; /* DMA queue lock. */ - unsigned int sequence; - struct v4l2_format fmt; + struct v4l2_format format; u32 mbus_code; + unsigned int sequence; }; -int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, - const char *name); -void sun6i_video_cleanup(struct sun6i_video *video); +int sun6i_video_setup(struct sun6i_csi_device *csi_dev); +void sun6i_video_cleanup(struct sun6i_csi_device *csi_dev); -void sun6i_video_frame_done(struct sun6i_video *video); +void sun6i_video_frame_done(struct sun6i_csi_device *csi_dev); #endif /* __SUN6I_VIDEO_H__ */ diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig index eb982466abd3..08852f63692b 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -3,11 +3,11 @@ config VIDEO_SUN6I_MIPI_CSI2 tristate "Allwinner A31 MIPI CSI-2 Controller Driver" depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on PM && COMMON_CLK + depends on PM && COMMON_CLK && RESET_CONTROLLER + depends on PHY_SUN6I_MIPI_DPHY select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - select PHY_SUN6I_MIPI_DPHY select GENERIC_PHY_MIPI_DPHY select REGMAP_MMIO help diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c index a4e3f9a6b2ff..30d6c0c5161f 100644 --- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -661,7 +661,8 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi2_dev->reset)) { dev_err(dev, "failed to get reset controller\n"); - return PTR_ERR(csi2_dev->reset); + ret = PTR_ERR(csi2_dev->reset); + goto error_clock_rate_exclusive; } /* D-PHY */ @@ -669,13 +670,14 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, csi2_dev->dphy = devm_phy_get(dev, "dphy"); if (IS_ERR(csi2_dev->dphy)) { dev_err(dev, "failed to get MIPI D-PHY\n"); - return PTR_ERR(csi2_dev->dphy); + ret = PTR_ERR(csi2_dev->dphy); + goto error_clock_rate_exclusive; } ret = phy_init(csi2_dev->dphy); if (ret) { dev_err(dev, "failed to initialize MIPI D-PHY\n"); - return ret; + goto error_clock_rate_exclusive; } /* Runtime PM */ @@ -683,6 +685,11 @@ sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev, pm_runtime_enable(dev); return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi2_dev->clock_mod); + + return ret; } static void @@ -712,9 +719,14 @@ static int sun6i_mipi_csi2_probe(struct platform_device *platform_dev) ret = sun6i_mipi_csi2_bridge_setup(csi2_dev); if (ret) - return ret; + goto error_resources; return 0; + +error_resources: + sun6i_mipi_csi2_resources_cleanup(csi2_dev); + + return ret; } static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev) diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig index 789d58ee12ea..47a8c0fb7eb9 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN8I_A83T_MIPI_CSI2 tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver" depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on PM && COMMON_CLK + depends on PM && COMMON_CLK && RESET_CONTROLLER select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c index d052ee77ef0a..b032ec13a683 100644 --- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -719,13 +719,15 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de csi2_dev->clock_mipi = devm_clk_get(dev, "mipi"); if (IS_ERR(csi2_dev->clock_mipi)) { dev_err(dev, "failed to acquire mipi clock\n"); - return PTR_ERR(csi2_dev->clock_mipi); + ret = PTR_ERR(csi2_dev->clock_mipi); + goto error_clock_rate_exclusive; } csi2_dev->clock_misc = devm_clk_get(dev, "misc"); if (IS_ERR(csi2_dev->clock_misc)) { dev_err(dev, "failed to acquire misc clock\n"); - return PTR_ERR(csi2_dev->clock_misc); + ret = PTR_ERR(csi2_dev->clock_misc); + goto error_clock_rate_exclusive; } /* Reset */ @@ -733,7 +735,8 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de csi2_dev->reset = devm_reset_control_get_shared(dev, NULL); if (IS_ERR(csi2_dev->reset)) { dev_err(dev, "failed to get reset controller\n"); - return PTR_ERR(csi2_dev->reset); + ret = PTR_ERR(csi2_dev->reset); + goto error_clock_rate_exclusive; } /* D-PHY */ @@ -741,7 +744,7 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de ret = sun8i_a83t_dphy_register(csi2_dev); if (ret) { dev_err(dev, "failed to initialize MIPI D-PHY\n"); - return ret; + goto error_clock_rate_exclusive; } /* Runtime PM */ @@ -749,6 +752,11 @@ sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_de pm_runtime_enable(dev); return 0; + +error_clock_rate_exclusive: + clk_rate_exclusive_put(csi2_dev->clock_mod); + + return ret; } static void @@ -778,9 +786,14 @@ static int sun8i_a83t_mipi_csi2_probe(struct platform_device *platform_dev) ret = sun8i_a83t_mipi_csi2_bridge_setup(csi2_dev); if (ret) - return ret; + goto error_resources; return 0; + +error_resources: + sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev); + + return ret; } static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev) diff --git a/drivers/media/platform/sunxi/sun8i-di/Kconfig b/drivers/media/platform/sunxi/sun8i-di/Kconfig index ff71e06ee2df..f688396913b7 100644 --- a/drivers/media/platform/sunxi/sun8i-di/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-di/Kconfig @@ -4,7 +4,7 @@ config VIDEO_SUN8I_DEINTERLACE depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on COMMON_CLK && OF + depends on COMMON_CLK && RESET_CONTROLLER && OF depends on PM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig index cfba29072d75..ee2c1f248c64 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig @@ -5,7 +5,7 @@ config VIDEO_SUN8I_ROTATE depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST - depends on COMMON_CLK && OF + depends on COMMON_CLK && RESET_CONTROLLER && OF depends on PM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.h b/drivers/media/platform/ti/am437x/am437x-vpfe.h index 05ee37db0273..f8b4e917b91a 100644 --- a/drivers/media/platform/ti/am437x/am437x-vpfe.h +++ b/drivers/media/platform/ti/am437x/am437x-vpfe.h @@ -267,7 +267,7 @@ struct vpfe_device { * is different from the image window */ struct v4l2_rect crop; - /* Buffer queue used in video-buf */ + /* Buffer queue used in vb2 */ struct vb2_queue buffer_queue; /* Queue of filled frames */ struct list_head dma_queue; diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index e136d70b4048..16ae52879a79 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -622,12 +622,12 @@ static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd) static struct v4l2_mbus_framefmt * cal_camerarx_get_pad_format(struct cal_camerarx *phy, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, unsigned int pad, u32 which) { switch (which) { case V4L2_SUBDEV_FORMAT_TRY: - return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad); + return v4l2_subdev_get_try_format(&phy->subdev, state, pad); case V4L2_SUBDEV_FORMAT_ACTIVE: return &phy->formats[pad]; default: @@ -653,7 +653,7 @@ static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable) } static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) { struct cal_camerarx *phy = to_cal_camerarx(sd); @@ -670,7 +670,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, goto out; } - fmt = cal_camerarx_get_pad_format(phy, sd_state, + fmt = cal_camerarx_get_pad_format(phy, state, CAL_CAMERARX_PAD_SINK, code->which); code->code = fmt->code; @@ -690,7 +690,7 @@ out: } static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_frame_size_enum *fse) { struct cal_camerarx *phy = to_cal_camerarx(sd); @@ -706,7 +706,7 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, if (cal_rx_pad_is_source(fse->pad)) { struct v4l2_mbus_framefmt *fmt; - fmt = cal_camerarx_get_pad_format(phy, sd_state, + fmt = cal_camerarx_get_pad_format(phy, state, CAL_CAMERARX_PAD_SINK, fse->which); if (fse->code != fmt->code) { @@ -738,7 +738,7 @@ out: } static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) { struct cal_camerarx *phy = to_cal_camerarx(sd); @@ -746,7 +746,7 @@ static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, mutex_lock(&phy->mutex); - fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad, + fmt = cal_camerarx_get_pad_format(phy, state, format->pad, format->which); format->format = *fmt; @@ -756,7 +756,7 @@ static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, } static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) { struct cal_camerarx *phy = to_cal_camerarx(sd); @@ -766,7 +766,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, /* No transcoding, source and sink formats must match. */ if (cal_rx_pad_is_source(format->pad)) - return cal_camerarx_sd_get_fmt(sd, sd_state, format); + return cal_camerarx_sd_get_fmt(sd, state, format); /* * Default to the first format if the requested media bus code isn't @@ -792,12 +792,12 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, mutex_lock(&phy->mutex); - fmt = cal_camerarx_get_pad_format(phy, sd_state, + fmt = cal_camerarx_get_pad_format(phy, state, CAL_CAMERARX_PAD_SINK, format->which); *fmt = format->format; - fmt = cal_camerarx_get_pad_format(phy, sd_state, + fmt = cal_camerarx_get_pad_format(phy, state, CAL_CAMERARX_PAD_FIRST_SOURCE, format->which); *fmt = format->format; @@ -808,10 +808,10 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, } static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) + struct v4l2_subdev_state *state) { struct v4l2_subdev_format format = { - .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY + .which = state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE, .pad = CAL_CAMERARX_PAD_SINK, .format = { @@ -826,7 +826,7 @@ static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd, }, }; - return cal_camerarx_sd_set_fmt(sd, sd_state, &format); + return cal_camerarx_sd_set_fmt(sd, state, &format); } static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = { @@ -871,6 +871,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, phy->cal = cal; phy->instance = instance; + spin_lock_init(&phy->vc_lock); mutex_init(&phy->mutex); phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 776da0cfcdbe..4eade409d5d3 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -191,7 +191,7 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; struct v4l2_subdev_frame_size_enum fse; - int ret, found; + int found; fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat); if (!fmtinfo) { @@ -206,12 +206,13 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.field = ctx->v_fmt.fmt.pix.field; /* check for/find a valid width/height */ - ret = 0; found = false; fse.pad = 0; fse.code = fmtinfo->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; for (fse.index = 0; ; fse.index++) { + int ret; + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, &fse); if (ret) @@ -707,7 +708,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) dma_addr_t addr; int ret; - ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe); + ret = video_device_pipeline_alloc_start(&ctx->vdev); if (ret < 0) { ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); goto error_release_buffers; @@ -760,7 +761,7 @@ error_stop: cal_ctx_unprepare(ctx); error_pipeline: - media_pipeline_stop(&ctx->vdev.entity); + video_device_pipeline_stop(&ctx->vdev); error_release_buffers: cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED); @@ -781,7 +782,7 @@ static void cal_stop_streaming(struct vb2_queue *vq) cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); - media_pipeline_stop(&ctx->vdev.entity); + video_device_pipeline_stop(&ctx->vdev); } static const struct vb2_ops cal_video_qops = { diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 425b4f4b7ed7..56b61c0583cf 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -543,7 +543,22 @@ void cal_ctx_unprepare(struct cal_ctx *ctx) void cal_ctx_start(struct cal_ctx *ctx) { - ctx->sequence = 0; + struct cal_camerarx *phy = ctx->phy; + + /* + * Reset the frame number & sequence number, but only if the + * virtual channel is not already in use. + */ + + spin_lock(&phy->vc_lock); + + if (phy->vc_enable_count[ctx->vc]++ == 0) { + phy->vc_frame_number[ctx->vc] = 0; + phy->vc_sequence[ctx->vc] = 0; + } + + spin_unlock(&phy->vc_lock); + ctx->dma.state = CAL_DMA_RUNNING; /* Configure the CSI-2, pixel processing and write DMA contexts. */ @@ -563,8 +578,15 @@ void cal_ctx_start(struct cal_ctx *ctx) void cal_ctx_stop(struct cal_ctx *ctx) { + struct cal_camerarx *phy = ctx->phy; long timeout; + WARN_ON(phy->vc_enable_count[ctx->vc] == 0); + + spin_lock(&phy->vc_lock); + phy->vc_enable_count[ctx->vc]--; + spin_unlock(&phy->vc_lock); + /* * Request DMA stop and wait until it completes. If completion times * out, forcefully disable the DMA. @@ -601,6 +623,34 @@ void cal_ctx_stop(struct cal_ctx *ctx) * ------------------------------------------------------------------ */ +/* + * Track a sequence number for each virtual channel, which is shared by + * all contexts using the same virtual channel. This is done using the + * CSI-2 frame number as a base. + */ +static void cal_update_seq_number(struct cal_ctx *ctx) +{ + struct cal_dev *cal = ctx->cal; + struct cal_camerarx *phy = ctx->phy; + u16 prev_frame_num, frame_num; + u8 vc = ctx->vc; + + frame_num = + cal_read(cal, CAL_CSI2_STATUS(phy->instance, ctx->csi2_ctx)) & + 0xffff; + + if (phy->vc_frame_number[vc] != frame_num) { + prev_frame_num = phy->vc_frame_number[vc]; + + if (prev_frame_num >= frame_num) + phy->vc_sequence[vc] += 1; + else + phy->vc_sequence[vc] += frame_num - prev_frame_num; + + phy->vc_frame_number[vc] = frame_num; + } +} + static inline void cal_irq_wdma_start(struct cal_ctx *ctx) { spin_lock(&ctx->dma.lock); @@ -631,6 +681,8 @@ static inline void cal_irq_wdma_start(struct cal_ctx *ctx) } spin_unlock(&ctx->dma.lock); + + cal_update_seq_number(ctx); } static inline void cal_irq_wdma_end(struct cal_ctx *ctx) @@ -657,27 +709,62 @@ static inline void cal_irq_wdma_end(struct cal_ctx *ctx) if (buf) { buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.field = ctx->v_fmt.fmt.pix.field; - buf->vb.sequence = ctx->sequence++; + buf->vb.sequence = ctx->phy->vc_sequence[ctx->vc]; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } } +static void cal_irq_handle_wdma(struct cal_ctx *ctx, bool start, bool end) +{ + /* + * CAL HW interrupts are inherently racy. If we get both start and end + * interrupts, we don't know what has happened: did the DMA for a single + * frame start and end, or did one frame end and a new frame start? + * + * Usually for normal pixel frames we get the interrupts separately. If + * we do get both, we have to guess. The assumption in the code below is + * that the active vertical area is larger than the blanking vertical + * area, and thus it is more likely that we get the end of the old frame + * and the start of a new frame. + * + * However, for embedded data, which is only a few lines high, we always + * get both interrupts. Here the assumption is that we get both for the + * same frame. + */ + if (ctx->v_fmt.fmt.pix.height < 10) { + if (start) + cal_irq_wdma_start(ctx); + + if (end) + cal_irq_wdma_end(ctx); + } else { + if (end) + cal_irq_wdma_end(ctx); + + if (start) + cal_irq_wdma_start(ctx); + } +} + static irqreturn_t cal_irq(int irq_cal, void *data) { struct cal_dev *cal = data; - u32 status; - - status = cal_read(cal, CAL_HL_IRQSTATUS(0)); - if (status) { - unsigned int i; + u32 status[3]; + unsigned int i; - cal_write(cal, CAL_HL_IRQSTATUS(0), status); + for (i = 0; i < 3; ++i) { + status[i] = cal_read(cal, CAL_HL_IRQSTATUS(i)); + if (status[i]) + cal_write(cal, CAL_HL_IRQSTATUS(i), status[i]); + } - if (status & CAL_HL_IRQ_OCPO_ERR_MASK) + if (status[0]) { + if (status[0] & CAL_HL_IRQ_OCPO_ERR_MASK) dev_err_ratelimited(cal->dev, "OCPO ERROR\n"); for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (status & CAL_HL_IRQ_CIO_MASK(i)) { + if (status[0] & CAL_HL_IRQ_CIO_MASK(i)) { u32 cio_stat = cal_read(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i)); @@ -688,7 +775,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cio_stat); } - if (status & CAL_HL_IRQ_VC_MASK(i)) { + if (status[0] & CAL_HL_IRQ_VC_MASK(i)) { u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); dev_err_ratelimited(cal->dev, @@ -700,32 +787,12 @@ static irqreturn_t cal_irq(int irq_cal, void *data) } } - /* Check which DMA just finished */ - status = cal_read(cal, CAL_HL_IRQSTATUS(1)); - if (status) { - unsigned int i; - - /* Clear Interrupt status */ - cal_write(cal, CAL_HL_IRQSTATUS(1), status); - - for (i = 0; i < cal->num_contexts; ++i) { - if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) - cal_irq_wdma_end(cal->ctx[i]); - } - } - - /* Check which DMA just started */ - status = cal_read(cal, CAL_HL_IRQSTATUS(2)); - if (status) { - unsigned int i; - - /* Clear Interrupt status */ - cal_write(cal, CAL_HL_IRQSTATUS(2), status); + for (i = 0; i < cal->num_contexts; ++i) { + bool end = !!(status[1] & CAL_HL_IRQ_WDMA_END_MASK(i)); + bool start = !!(status[2] & CAL_HL_IRQ_WDMA_START_MASK(i)); - for (i = 0; i < cal->num_contexts; ++i) { - if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) - cal_irq_wdma_start(cal->ctx[i]); - } + if (start || end) + cal_irq_handle_wdma(cal->ctx[i], start, end); } return IRQ_HANDLED; diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h index 61409ddced98..de73d6d21b6f 100644 --- a/drivers/media/platform/ti/cal/cal.h +++ b/drivers/media/platform/ti/cal/cal.h @@ -174,12 +174,17 @@ struct cal_camerarx { struct device_node *source_ep_node; struct device_node *source_node; struct v4l2_subdev *source; - struct media_pipeline pipe; struct v4l2_subdev subdev; struct media_pad pads[CAL_CAMERARX_NUM_PADS]; struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS]; + /* protects the vc_* fields below */ + spinlock_t vc_lock; + u8 vc_enable_count[4]; + u16 vc_frame_number[4]; + u32 vc_sequence[4]; + /* * Lock for camerarx ops. Protects: * - formats @@ -242,7 +247,6 @@ struct cal_ctx { const struct cal_format_info **active_fmt; unsigned int num_active_fmt; - unsigned int sequence; struct vb2_queue vb_vidq; u8 dma_ctx; u8 cport; diff --git a/drivers/media/platform/ti/davinci/Kconfig b/drivers/media/platform/ti/davinci/Kconfig index c61e697aeb12..96d4bed7fe9e 100644 --- a/drivers/media/platform/ti/davinci/Kconfig +++ b/drivers/media/platform/ti/davinci/Kconfig @@ -32,55 +32,6 @@ config VIDEO_DAVINCI_VPIF_CAPTURE To compile this driver as a module, choose M here. There will be two modules called vpif.ko and vpif_capture.ko -config VIDEO_DM6446_CCDC - tristate "TI DM6446 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from slave decoders. - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and dm644x_ccdc.ko - -config VIDEO_DM355_CCDC - tristate "TI DM355 CCDC video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DM355 CCD hw module. DM355 CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from a slave decoders - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and dm355_ccdc.ko - -config VIDEO_DM365_ISIF - tristate "TI DM365 ISIF video capture driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV - depends on ARCH_DAVINCI || COMPILE_TEST - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and isif.ko - config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/ti/davinci/Makefile b/drivers/media/platform/ti/davinci/Makefile index 05c45bf371aa..b20a91653162 100644 --- a/drivers/media/platform/ti/davinci/Makefile +++ b/drivers/media/platform/ti/davinci/Makefile @@ -8,9 +8,5 @@ obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif.o vpif_display.o #VPIF Capture driver obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif.o vpif_capture.o -# Capture: DM6446 and DM355 -obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o vpss.o dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o vpss.o dm355_ccdc.o -obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o vpss.o isif.o obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpss.o vpbe.o vpbe_osd.o \ vpbe_venc.o vpbe_display.o diff --git a/drivers/media/platform/ti/davinci/vpbe.c b/drivers/media/platform/ti/davinci/vpbe.c index 5f0aeb744e81..509ecc84624e 100644 --- a/drivers/media/platform/ti/davinci/vpbe.c +++ b/drivers/media/platform/ti/davinci/vpbe.c @@ -280,7 +280,7 @@ static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) * vpbe_get_output - Get output * @vpbe_dev: vpbe device ptr * - * return current vpbe output to the the index + * return current vpbe output to the index */ static unsigned int vpbe_get_output(struct vpbe_device *vpbe_dev) { diff --git a/drivers/media/platform/ti/davinci/vpif.h b/drivers/media/platform/ti/davinci/vpif.h index 651943e3e375..52ecc2562216 100644 --- a/drivers/media/platform/ti/davinci/vpif.h +++ b/drivers/media/platform/ti/davinci/vpif.h @@ -322,10 +322,10 @@ static inline void channel1_intr_enable(int enable) } /* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch0_set_video_buf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); @@ -334,10 +334,10 @@ static inline void ch0_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, } /* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch0_set_video_buf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH0_TOP_STRT_ADD_LUMA); regw(btm_strt_luma, VPIF_CH0_BTM_STRT_ADD_LUMA); @@ -345,10 +345,10 @@ static inline void ch0_set_videobuf_addr(unsigned long top_strt_luma, regw(btm_strt_chroma, VPIF_CH0_BTM_STRT_ADD_CHROMA); } -static inline void ch1_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch1_set_video_buf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH1_TOP_STRT_ADD_LUMA); @@ -538,10 +538,10 @@ static inline void channel3_clipping_enable(int enable) } /* inline function to set buffer addresses in case of Y/C non mux mode */ -static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch2_set_video_buf_addr_yc_nmux(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); @@ -550,10 +550,10 @@ static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, } /* inline function to set buffer addresses in VPIF registers for video data */ -static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch2_set_video_buf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_LUMA); regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_LUMA); @@ -561,10 +561,10 @@ static inline void ch2_set_videobuf_addr(unsigned long top_strt_luma, regw(btm_strt_chroma, VPIF_CH2_BTM_STRT_ADD_CHROMA); } -static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) +static inline void ch3_set_video_buf_addr(unsigned long top_strt_luma, + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_LUMA); regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_LUMA); @@ -574,18 +574,18 @@ static inline void ch3_set_videobuf_addr(unsigned long top_strt_luma, /* inline function to set buffer addresses in VPIF registers for vbi data */ static inline void ch2_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH2_TOP_STRT_ADD_VANC); regw(btm_strt_luma, VPIF_CH2_BTM_STRT_ADD_VANC); } static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, - unsigned long btm_strt_luma, - unsigned long top_strt_chroma, - unsigned long btm_strt_chroma) + unsigned long btm_strt_luma, + unsigned long top_strt_chroma, + unsigned long btm_strt_chroma) { regw(top_strt_luma, VPIF_CH3_TOP_STRT_ADD_VANC); regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index b91eec899eb5..580723333fcc 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -632,11 +632,11 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode) common = &(ch->common[VPIF_VIDEO_INDEX]); if (VPIF_CHANNEL1_VIDEO == ch->channel_id) - common->set_addr = ch1_set_videobuf_addr; + common->set_addr = ch1_set_video_buf_addr; else if (2 == muxmode) - common->set_addr = ch0_set_videobuf_addr_yc_nmux; + common->set_addr = ch0_set_video_buf_addr_yc_nmux; else - common->set_addr = ch0_set_videobuf_addr; + common->set_addr = ch0_set_video_buf_addr; } /** diff --git a/drivers/media/platform/ti/davinci/vpif_capture.h b/drivers/media/platform/ti/davinci/vpif_capture.h index d5951f61df47..6191056500cf 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.h +++ b/drivers/media/platform/ti/davinci/vpif_capture.h @@ -50,7 +50,7 @@ struct common_obj { struct vpif_cap_buffer *next_frm; /* Used to store pixel format */ struct v4l2_format fmt; - /* Buffer queue used in video-buf */ + /* Buffer queue used in vb2 */ struct vb2_queue buffer_queue; /* Queue of filled frames */ struct list_head dma_queue; diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 5d524acc995d..b2df81603f62 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -563,12 +563,12 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; if (VPIF_CHANNEL3_VIDEO == ch->channel_id) { - common->set_addr = ch3_set_videobuf_addr; + common->set_addr = ch3_set_video_buf_addr; } else { if (2 == muxmode) - common->set_addr = ch2_set_videobuf_addr_yc_nmux; + common->set_addr = ch2_set_video_buf_addr_yc_nmux; else - common->set_addr = ch2_set_videobuf_addr; + common->set_addr = ch2_set_video_buf_addr; } } diff --git a/drivers/media/platform/ti/davinci/vpif_display.h b/drivers/media/platform/ti/davinci/vpif_display.h index f27474e0fc36..dae20053dd73 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.h +++ b/drivers/media/platform/ti/davinci/vpif_display.h @@ -64,11 +64,11 @@ struct common_obj { struct vpif_disp_buffer *next_frm; /* Pointer pointing to next * vb2_buffer */ struct v4l2_format fmt; /* Used to store the format */ - struct vb2_queue buffer_queue; /* Buffer queue used in - * video-buf */ + struct vb2_queue buffer_queue; /* Buffer queue used in vb2 */ struct list_head dma_queue; /* Queue of filled frames */ - spinlock_t irqlock; /* Used in video-buf */ + spinlock_t irqlock; /* Used for video buffer + * handling */ /* channel specific parameters */ struct mutex lock; /* lock used to access this diff --git a/drivers/media/platform/ti/omap/omap_voutlib.c b/drivers/media/platform/ti/omap/omap_voutlib.c index fdea2309ee37..0ac46458e41c 100644 --- a/drivers/media/platform/ti/omap/omap_voutlib.c +++ b/drivers/media/platform/ti/omap/omap_voutlib.c @@ -107,7 +107,7 @@ EXPORT_SYMBOL_GPL(omap_vout_try_window); /* Given a new render window in new_win, adjust the window to the * nearest supported configuration. The image cropping window in crop * will also be adjusted if necessary. Preference is given to keeping the - * the window as close to the requested configuration as possible. If + * window as close to the requested configuration as possible. If * successful, new_win, vout->win, and crop are updated. * Returns zero if successful, or -EINVAL if the requested preview window is * impossible and cannot reasonably be adjusted. diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index d251736eb420..24d2383400b0 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -937,10 +937,8 @@ static int isp_pipeline_is_last(struct media_entity *me) struct isp_pipeline *pipe; struct media_pad *pad; - if (!me->pipe) - return 0; pipe = to_isp_pipeline(me); - if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) + if (!pipe || pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED) return 0; pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; @@ -1528,7 +1526,7 @@ void omap3isp_print_status(struct isp_device *isp) * To solve this problem power management support is split into prepare/complete * and suspend/resume operations. The pipelines are stopped in prepare() and the * ISP clocks get disabled in suspend(). Similarly, the clocks are re-enabled in - * resume(), and the the pipelines are restarted in complete(). + * resume(), and the pipelines are restarted in complete(). * * TODO: PM dependencies between the ISP and sensors are not modelled explicitly * yet. diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index d7059180e80e..3e5348c63773 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -1071,7 +1071,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, * processing might be possible but requires more testing. * * Stream start must be delayed until buffers are available at both the input - * and output. The pipeline must be started in the videobuf queue callback with + * and output. The pipeline must be started in the vb2 queue callback with * the buffers queue spinlock held. The modules subdev set stream operation must * not sleep. */ @@ -1093,8 +1093,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) /* Start streaming on the pipeline. No link touching an entity in the * pipeline can be activated or deactivated once streaming is started. */ - pipe = video->video.entity.pipe - ? to_isp_pipeline(&video->video.entity) : &video->pipe; + pipe = to_isp_pipeline(&video->video.entity) ? : &video->pipe; ret = media_entity_enum_init(&pipe->ent_enum, &video->isp->media_dev); if (ret) @@ -1104,7 +1103,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]); pipe->max_rate = pipe->l3_ick; - ret = media_pipeline_start(&video->video.entity, &pipe->pipe); + ret = video_device_pipeline_start(&video->video, &pipe->pipe); if (ret < 0) goto err_pipeline_start; @@ -1161,7 +1160,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) return 0; err_check_format: - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); err_pipeline_start: /* TODO: Implement PM QoS */ /* The DMA queue must be emptied here, otherwise CCDC interrupts that @@ -1228,7 +1227,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) video->error = false; /* TODO: Implement PM QoS */ - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); media_entity_enum_cleanup(&pipe->ent_enum); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.h b/drivers/media/platform/ti/omap3isp/ispvideo.h index a0908670c0cf..1d23df576e6b 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.h +++ b/drivers/media/platform/ti/omap3isp/ispvideo.h @@ -99,8 +99,15 @@ struct isp_pipeline { unsigned int external_width; }; -#define to_isp_pipeline(__e) \ - container_of((__e)->pipe, struct isp_pipeline, pipe) +static inline struct isp_pipeline *to_isp_pipeline(struct media_entity *entity) +{ + struct media_pipeline *pipe = media_entity_pipeline(entity); + + if (!pipe) + return NULL; + + return container_of(pipe, struct isp_pipeline, pipe); +} static inline int isp_pipeline_ready(struct isp_pipeline *pipe) { diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/media/platform/verisilicon/Kconfig index 0172a6822ec2..e65b836b9d78 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/media/platform/verisilicon/Kconfig @@ -1,7 +1,11 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0-only + +comment "Verisilicon media platform drivers" + config VIDEO_HANTRO tristate "Hantro VPU driver" depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || ARCH_SUNXI || COMPILE_TEST + depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API diff --git a/drivers/staging/media/hantro/Makefile b/drivers/media/platform/verisilicon/Makefile index ebd5ede7bef7..ebd5ede7bef7 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/media/platform/verisilicon/Makefile diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 2989ebc631cc..2989ebc631cc 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 2036f72eeb4a..8cb4a68c9119 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -251,6 +251,11 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) { + struct hantro_ctx *ctx; + + ctx = container_of(ctrl->handler, + struct hantro_ctx, ctrl_handler); + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; @@ -266,12 +271,11 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl) } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) { const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) - /* Luma and chroma bit depth mismatch */ - return -EINVAL; - if (sps->bit_depth_luma_minus8 != 0) - /* Only 8-bit is supported */ + if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) + /* Only 8-bit and 10-bit are supported */ return -EINVAL; + + ctx->bit_depth = sps->bit_depth_luma_minus8 + 8; } else if (ctrl->id == V4L2_CID_STATELESS_VP9_FRAME) { const struct v4l2_ctrl_vp9_frame *dec_params = ctrl->p_new.p_vp9_frame; diff --git a/drivers/staging/media/hantro/hantro_g1.c b/drivers/media/platform/verisilicon/hantro_g1.c index 0ab1cee62218..0ab1cee62218 100644 --- a/drivers/staging/media/hantro/hantro_g1.c +++ b/drivers/media/platform/verisilicon/hantro_g1.c diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c index 9de7f05eff2a..9de7f05eff2a 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c index 9aea331e1a3c..9aea331e1a3c 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g1_mpeg2_dec.c diff --git a/drivers/staging/media/hantro/hantro_g1_regs.h b/drivers/media/platform/verisilicon/hantro_g1_regs.h index c623b3b0be18..c623b3b0be18 100644 --- a/drivers/staging/media/hantro/hantro_g1_regs.h +++ b/drivers/media/platform/verisilicon/hantro_g1_regs.h diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/media/platform/verisilicon/hantro_g1_vp8_dec.c index 851eb67f19f5..851eb67f19f5 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g1_vp8_dec.c diff --git a/drivers/staging/media/hantro/hantro_g2.c b/drivers/media/platform/verisilicon/hantro_g2.c index ee5f14c5f8f2..ee5f14c5f8f2 100644 --- a/drivers/staging/media/hantro/hantro_g2.c +++ b/drivers/media/platform/verisilicon/hantro_g2.c diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index 233ecd863d5f..a9d4ac84a8d8 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -12,7 +12,7 @@ static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx) { - return ctx->dst_fmt.width * ctx->dst_fmt.height; + return ctx->dst_fmt.width * ctx->dst_fmt.height * ctx->bit_depth / 8; } static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx) @@ -167,8 +167,6 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_bit_depth_y_minus8, sps->bit_depth_luma_minus8); hantro_reg_write(vpu, &g2_bit_depth_c_minus8, sps->bit_depth_chroma_minus8); - hantro_reg_write(vpu, &g2_output_8_bits, 0); - hantro_reg_write(vpu, &g2_hdr_skip_length, compute_header_skip_length(ctx)); min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3; diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/media/platform/verisilicon/hantro_g2_regs.h index 82606783591a..82606783591a 100644 --- a/drivers/staging/media/hantro/hantro_g2_regs.h +++ b/drivers/media/platform/verisilicon/hantro_g2_regs.h diff --git a/drivers/staging/media/hantro/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c index 6fc4b555517f..6fc4b555517f 100644 --- a/drivers/staging/media/hantro/hantro_g2_vp9_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c index 12d69503d6ba..12d69503d6ba 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/media/platform/verisilicon/hantro_h1_jpeg_enc.c diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/media/platform/verisilicon/hantro_h1_regs.h index 30e7e7b920b5..30e7e7b920b5 100644 --- a/drivers/staging/media/hantro/hantro_h1_regs.h +++ b/drivers/media/platform/verisilicon/hantro_h1_regs.h diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/media/platform/verisilicon/hantro_h264.c index 4e9a0ecf5c13..4e9a0ecf5c13 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/media/platform/verisilicon/hantro_h264.c diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/media/platform/verisilicon/hantro_hevc.c index b990bc98164c..9383fb7081f6 100644 --- a/drivers/staging/media/hantro/hantro_hevc.c +++ b/drivers/media/platform/verisilicon/hantro_hevc.c @@ -104,7 +104,7 @@ static int tile_buffer_reallocate(struct hantro_ctx *ctx) hevc_dec->tile_bsd.cpu = NULL; } - size = VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1); + size = (VERT_FILTER_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8; hevc_dec->tile_filter.cpu = dma_alloc_coherent(vpu->dev, size, &hevc_dec->tile_filter.dma, GFP_KERNEL); @@ -112,7 +112,7 @@ static int tile_buffer_reallocate(struct hantro_ctx *ctx) goto err_free_tile_buffers; hevc_dec->tile_filter.size = size; - size = VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1); + size = (VERT_SAO_RAM_SIZE * height64 * (num_tile_cols - 1) * ctx->bit_depth) / 8; hevc_dec->tile_sao.cpu = dma_alloc_coherent(vpu->dev, size, &hevc_dec->tile_sao.dma, GFP_KERNEL); diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index e83f0c523a30..e83f0c523a30 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/media/platform/verisilicon/hantro_jpeg.c index d07b1b449b61..d07b1b449b61 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.c +++ b/drivers/media/platform/verisilicon/hantro_jpeg.c diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/media/platform/verisilicon/hantro_jpeg.h index 0b49d0b82caa..0b49d0b82caa 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.h +++ b/drivers/media/platform/verisilicon/hantro_jpeg.h diff --git a/drivers/staging/media/hantro/hantro_mpeg2.c b/drivers/media/platform/verisilicon/hantro_mpeg2.c index 04e545eb0a83..04e545eb0a83 100644 --- a/drivers/staging/media/hantro/hantro_mpeg2.c +++ b/drivers/media/platform/verisilicon/hantro_mpeg2.c diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/media/platform/verisilicon/hantro_postproc.c index a0928c508434..09d8cf942689 100644 --- a/drivers/staging/media/hantro/hantro_postproc.c +++ b/drivers/media/platform/verisilicon/hantro_postproc.c @@ -114,6 +114,7 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *dst_buf; int down_scale = down_scale_factor(ctx); + int out_depth; size_t chroma_offset; dma_addr_t dst_dma; @@ -132,8 +133,9 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma); hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset); } + + out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat); if (ctx->dev->variant->legacy_regs) { - int out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat); u8 pp_shift = 0; if (out_depth > 8) @@ -141,6 +143,9 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, out_depth); hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift); + } else { + hantro_reg_write(vpu, &g2_output_8_bits, out_depth > 8 ? 0 : 1); + hantro_reg_write(vpu, &g2_output_format, out_depth > 8 ? 1 : 0); } hantro_reg_write(vpu, &g2_out_rs_e, 1); } diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 2c7a805289e7..2c7a805289e7 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c diff --git a/drivers/staging/media/hantro/hantro_v4l2.h b/drivers/media/platform/verisilicon/hantro_v4l2.h index 64f6f57e9d7a..64f6f57e9d7a 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.h +++ b/drivers/media/platform/verisilicon/hantro_v4l2.h diff --git a/drivers/staging/media/hantro/hantro_vp8.c b/drivers/media/platform/verisilicon/hantro_vp8.c index 381bc1d3bfda..381bc1d3bfda 100644 --- a/drivers/staging/media/hantro/hantro_vp8.c +++ b/drivers/media/platform/verisilicon/hantro_vp8.c diff --git a/drivers/staging/media/hantro/hantro_vp9.c b/drivers/media/platform/verisilicon/hantro_vp9.c index 566cd376c097..566cd376c097 100644 --- a/drivers/staging/media/hantro/hantro_vp9.c +++ b/drivers/media/platform/verisilicon/hantro_vp9.c diff --git a/drivers/staging/media/hantro/hantro_vp9.h b/drivers/media/platform/verisilicon/hantro_vp9.h index 26b69275f098..26b69275f098 100644 --- a/drivers/staging/media/hantro/hantro_vp9.h +++ b/drivers/media/platform/verisilicon/hantro_vp9.h diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c index 77f574fdfa77..b390228fd3b4 100644 --- a/drivers/staging/media/hantro/imx8m_vpu_hw.c +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c @@ -162,12 +162,39 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = { .step_height = MB_DIM, }, }, + { + .fourcc = V4L2_PIX_FMT_P010, + .codec_mode = HANTRO_MODE_NONE, + .postprocessed = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = MB_DIM, + }, + }, }; static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV12_4L4, .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_UHD_WIDTH, + .step_width = TILE_MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_UHD_HEIGHT, + .step_height = TILE_MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_P010_4L4, + .codec_mode = HANTRO_MODE_NONE, + .match_depth = true, .frmsize = { .min_width = FMT_MIN_WIDTH, .max_width = FMT_UHD_WIDTH, diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c index 46c1a83bcc4e..46c1a83bcc4e 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c index 8395c4d48dd0..8395c4d48dd0 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_jpeg_enc.c diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_mpeg2_dec.c index b66737fab46b..b66737fab46b 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_mpeg2_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_mpeg2_dec.c diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_vp8_dec.c index d079075448c9..d079075448c9 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_vp8_dec.c diff --git a/drivers/staging/media/hantro/rockchip_vpu2_regs.h b/drivers/media/platform/verisilicon/rockchip_vpu2_regs.h index 49e40889545b..49e40889545b 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_regs.h +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_regs.h diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c index 8de6fd2e8eef..8de6fd2e8eef 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu_hw.c diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/media/platform/verisilicon/sama5d4_vdec_hw.c index b205e2db5b04..b205e2db5b04 100644 --- a/drivers/staging/media/hantro/sama5d4_vdec_hw.c +++ b/drivers/media/platform/verisilicon/sama5d4_vdec_hw.c diff --git a/drivers/staging/media/hantro/sunxi_vpu_hw.c b/drivers/media/platform/verisilicon/sunxi_vpu_hw.c index 02ce8b064a8f..02ce8b064a8f 100644 --- a/drivers/staging/media/hantro/sunxi_vpu_hw.c +++ b/drivers/media/platform/verisilicon/sunxi_vpu_hw.c diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c index cf8e892c47f0..29b53febc2e7 100644 --- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c +++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c @@ -188,6 +188,7 @@ static const u32 xcsi2dt_mbus_lut[][2] = { { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SBGGR12_1X12 }, { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SGBRG12_1X12 }, { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SGRBG12_1X12 }, + { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_Y12_1X12 }, { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SRGGB16_1X16 }, { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SBGGR16_1X16 }, { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SGBRG16_1X16 }, diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 2d1ef7a25c33..0a7fd8642a65 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -402,10 +402,9 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) * Use the pipeline object embedded in the first DMA object that starts * streaming. */ - pipe = dma->video.entity.pipe - ? to_xvip_pipeline(&dma->video.entity) : &dma->pipe; + pipe = to_xvip_pipeline(&dma->video) ? : &dma->pipe; - ret = media_pipeline_start(&dma->video.entity, &pipe->pipe); + ret = video_device_pipeline_start(&dma->video, &pipe->pipe); if (ret < 0) goto error; @@ -431,7 +430,7 @@ static int xvip_dma_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; error_stop: - media_pipeline_stop(&dma->video.entity); + video_device_pipeline_stop(&dma->video); error: /* Give back all queued buffers to videobuf2. */ @@ -448,7 +447,7 @@ error: static void xvip_dma_stop_streaming(struct vb2_queue *vq) { struct xvip_dma *dma = vb2_get_drv_priv(vq); - struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video.entity); + struct xvip_pipeline *pipe = to_xvip_pipeline(&dma->video); struct xvip_dma_buffer *buf, *nbuf; /* Stop the pipeline. */ @@ -459,7 +458,7 @@ static void xvip_dma_stop_streaming(struct vb2_queue *vq) /* Cleanup the pipeline and mark it as being stopped. */ xvip_pipeline_cleanup(pipe); - media_pipeline_stop(&dma->video.entity); + video_device_pipeline_stop(&dma->video); /* Give back all queued buffers to videobuf2. */ spin_lock_irq(&dma->queued_lock); diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h index 2378bdae57ae..9c6d4c18d1a9 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.h +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -45,9 +45,14 @@ struct xvip_pipeline { struct xvip_dma *output; }; -static inline struct xvip_pipeline *to_xvip_pipeline(struct media_entity *e) +static inline struct xvip_pipeline *to_xvip_pipeline(struct video_device *vdev) { - return container_of(e->pipe, struct xvip_pipeline, pipe); + struct media_pipeline *pipe = video_device_pipeline(vdev); + + if (!pipe) + return NULL; + + return container_of(pipe, struct xvip_pipeline, pipe); } /** diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c index a0073122798f..5b214bf7f93a 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.c +++ b/drivers/media/platform/xilinx/xilinx-vip.c @@ -40,6 +40,8 @@ static const struct xvip_video_format xvip_video_formats[] = { 1, V4L2_PIX_FMT_SGBRG8 }, { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8, 1, V4L2_PIX_FMT_SBGGR8 }, + { XVIP_VF_MONO_SENSOR, 12, "mono", MEDIA_BUS_FMT_Y12_1X12, + 2, V4L2_PIX_FMT_Y12 }, }; /** diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index f34f8b077e03..0a16c218a50a 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -471,7 +471,7 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev) { struct device_node *ports; struct device_node *port; - int ret; + int ret = 0; ports = of_get_child_by_name(xdev->dev->of_node, "ports"); if (ports == NULL) { @@ -481,13 +481,14 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev) for_each_child_of_node(ports, port) { ret = xvip_graph_dma_init_one(xdev, port); - if (ret < 0) { + if (ret) { of_node_put(port); - return ret; + break; } } - return 0; + of_node_put(ports); + return ret; } static void xvip_graph_cleanup(struct xvip_composite_device *xdev) diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 0bf99e1cd1d8..171f9cc9ee5e 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -1072,7 +1072,6 @@ done: static int si476x_radio_fops_release(struct file *file) { - int err; struct si476x_radio *radio = video_drvdata(file); if (v4l2_fh_is_singular_file(file) && @@ -1080,9 +1079,7 @@ static int si476x_radio_fops_release(struct file *file) si476x_core_set_power_state(radio->core, SI476X_POWER_DOWN); - err = v4l2_fh_release(file); - - return err; + return v4l2_fh_release(file); } static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index adbf43ff6a21..60e72c8c643b 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -14,7 +14,7 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/slab.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 735b925da998..5edfd8a9e849 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -684,7 +684,6 @@ static int send_packet(struct imon_context *ictx) */ static int send_associate_24g(struct imon_context *ictx) { - int retval; const unsigned char packet[8] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20 }; @@ -699,9 +698,8 @@ static int send_associate_24g(struct imon_context *ictx) } memcpy(ictx->usb_tx_buf, packet, sizeof(packet)); - retval = send_packet(ictx); - return retval; + return send_packet(ictx); } /* diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 0834d5f866fd..c76ba24c1f55 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1077,7 +1077,7 @@ static int mceusb_set_timeout(struct rc_dev *dev, unsigned int timeout) struct mceusb_dev *ir = dev->priv; unsigned int units; - units = DIV_ROUND_CLOSEST(timeout, MCE_TIME_UNIT); + units = DIV_ROUND_UP(timeout, MCE_TIME_UNIT); cmdbuf[2] = units >> 8; cmdbuf[3] = units; @@ -1416,42 +1416,37 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) { int ret; struct device *dev = ir->dev; - char *data; - - data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL); - if (!data) { - dev_err(dev, "%s: memory allocation failed!", __func__); - return; - } + char data[USB_CTRL_MSG_SZ]; /* * This is a strange one. Windows issues a set address to the device * on the receive control pipe and expect a certain value pair back */ - ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0), - USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0, - data, USB_CTRL_MSG_SZ, 3000); + ret = usb_control_msg_recv(ir->usbdev, 0, USB_REQ_SET_ADDRESS, + USB_DIR_IN | USB_TYPE_VENDOR, + 0, 0, data, USB_CTRL_MSG_SZ, 3000, + GFP_KERNEL); dev_dbg(dev, "set address - ret = %d", ret); dev_dbg(dev, "set address - data[0] = %d, data[1] = %d", data[0], data[1]); /* set feature: bit rate 38400 bps */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, - 0xc04e, 0x0000, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + USB_REQ_SET_FEATURE, USB_TYPE_VENDOR, + 0xc04e, 0x0000, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set feature - ret = %d", ret); /* bRequest 4: set char length to 8 bits */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 4, USB_TYPE_VENDOR, - 0x0808, 0x0000, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + 4, USB_TYPE_VENDOR, + 0x0808, 0x0000, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set char length - retB = %d", ret); /* bRequest 2: set handshaking to use DTR/DSR */ - ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0), - 2, USB_TYPE_VENDOR, - 0x0000, 0x0100, NULL, 0, 3000); + ret = usb_control_msg_send(ir->usbdev, 0, + 2, USB_TYPE_VENDOR, + 0x0000, 0x0100, NULL, 0, 3000, GFP_KERNEL); dev_dbg(dev, "set handshake - retC = %d", ret); /* device resume */ @@ -1459,8 +1454,6 @@ static void mceusb_gen1_init(struct mceusb_dev *ir) /* get hw/sw revision? */ mce_command_out(ir, GET_REVISION, sizeof(GET_REVISION)); - - kfree(data); } static void mceusb_gen2_init(struct mceusb_dev *ir) diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 47575490e74a..7964426bf2f7 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -2,7 +2,7 @@ /* * A virtual v4l2-mem2mem example device. * - * This is a virtual device driver for testing mem-to-mem videobuf framework. + * This is a virtual device driver for testing mem-to-mem vb2 framework. * It simulates a device that uses memory buffers for both source and * destination, processes the data and issues an "irq" (simulated by a delayed * workqueue). diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 6c437802f91f..aa944270e716 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -241,13 +241,12 @@ static void vimc_capture_return_all_buffers(struct vimc_capture_device *vcapture static int vimc_capture_start_streaming(struct vb2_queue *vq, unsigned int count) { struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq); - struct media_entity *entity = &vcapture->vdev.entity; int ret; vcapture->sequence = 0; /* Start the media pipeline */ - ret = media_pipeline_start(entity, &vcapture->stream.pipe); + ret = video_device_pipeline_start(&vcapture->vdev, &vcapture->stream.pipe); if (ret) { vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; @@ -255,7 +254,7 @@ static int vimc_capture_start_streaming(struct vb2_queue *vq, unsigned int count ret = vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 1); if (ret) { - media_pipeline_stop(entity); + video_device_pipeline_stop(&vcapture->vdev); vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED); return ret; } @@ -274,7 +273,7 @@ static void vimc_capture_stop_streaming(struct vb2_queue *vq) vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 0); /* Stop the media pipeline */ - media_pipeline_stop(&vcapture->vdev.entity); + video_device_pipeline_stop(&vcapture->vdev); /* Release all active buffers */ vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_ERROR); diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h index 176b72cb143b..bfcfb3515901 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.h +++ b/drivers/media/test-drivers/vivid/vivid-core.h @@ -35,7 +35,9 @@ #define MAX_HEIGHT 2160 /* The minimum image width/height */ #define MIN_WIDTH 16 -#define MIN_HEIGHT 16 +#define MIN_HEIGHT MIN_WIDTH +/* Pixel Array control divider */ +#define PIXEL_ARRAY_DIV MIN_WIDTH /* The data_offset of plane 0 for the multiplanar formats */ #define PLANE0_DATA_OFFSET 128 @@ -227,6 +229,7 @@ struct vivid_dev { struct v4l2_ctrl *bitmask; struct v4l2_ctrl *int_menu; struct v4l2_ctrl *ro_int32; + struct v4l2_ctrl *pixel_array; struct v4l2_ctrl *test_pattern; struct v4l2_ctrl *colorspace; struct v4l2_ctrl *rgb_range_cap; diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c index a78d676575bc..92b1a7598470 100644 --- a/drivers/media/test-drivers/vivid/vivid-ctrls.c +++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c @@ -35,6 +35,7 @@ #define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) #define VIVID_CID_RO_INTEGER (VIVID_CID_CUSTOM_BASE + 12) #define VIVID_CID_U32_DYN_ARRAY (VIVID_CID_CUSTOM_BASE + 13) +#define VIVID_CID_U8_PIXEL_ARRAY (VIVID_CID_CUSTOM_BASE + 14) #define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) #define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) @@ -228,6 +229,18 @@ static const struct v4l2_ctrl_config vivid_ctrl_u8_4d_array = { .dims = { 2, 3, 4, 5 }, }; +static const struct v4l2_ctrl_config vivid_ctrl_u8_pixel_array = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_U8_PIXEL_ARRAY, + .name = "U8 Pixel Array", + .type = V4L2_CTRL_TYPE_U8, + .def = 0x80, + .min = 0x00, + .max = 0xff, + .step = 1, + .dims = { 640 / PIXEL_ARRAY_DIV, 360 / PIXEL_ARRAY_DIV }, +}; + static const char * const vivid_ctrl_menu_strings[] = { "Menu Item 0 (Skipped)", "Menu Item 1", @@ -1642,6 +1655,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_dyn_array, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); + dev->pixel_array = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_pixel_array, NULL); if (dev->has_vid_cap) { /* Image Processing Controls */ diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index b9caa4b26209..86b158eeb2d8 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -381,6 +381,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) { struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + u32 dims[V4L2_CTRL_MAX_DIMS] = {}; unsigned size; u64 pixelclock; @@ -459,6 +460,9 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev)); tpg_update_mv_step(&dev->tpg); + dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV); + dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV); + v4l2_ctrl_modify_dimensions(dev->pixel_array, dims); } /* Map the field to something that is valid for the current input */ diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index a04dfd5799f7..d59b4ab77430 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -282,15 +282,13 @@ static int xc4000_tuner_reset(struct dvb_frontend *fe) static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) { u8 buf[4]; - int result; buf[0] = (regAddr >> 8) & 0xFF; buf[1] = regAddr & 0xFF; buf[2] = (i2cData >> 8) & 0xFF; buf[3] = i2cData & 0xFF; - result = xc_send_i2c_data(priv, buf, 4); - return result; + return xc_send_i2c_data(priv, buf, 4); } static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index af88e0766388..813171d25ac5 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -13,13 +13,11 @@ if MEDIA_USB_SUPPORT if MEDIA_CAMERA_SUPPORT comment "Webcam devices" -source "drivers/media/usb/cpia2/Kconfig" source "drivers/media/usb/gspca/Kconfig" source "drivers/media/usb/pwc/Kconfig" source "drivers/media/usb/s2255/Kconfig" source "drivers/media/usb/usbtv/Kconfig" source "drivers/media/usb/uvc/Kconfig" -source "drivers/media/usb/zr364xx/Kconfig" endif @@ -38,7 +36,6 @@ if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) source "drivers/media/usb/au0828/Kconfig" source "drivers/media/usb/cx231xx/Kconfig" -source "drivers/media/usb/tm6000/Kconfig" endif diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 25fa2015b179..6d171beea20d 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -12,7 +12,6 @@ obj-y += s2255/ obj-y += siano/ obj-y += ttusb-budget/ obj-y += ttusb-dec/ -obj-y += zr364xx/ # Please keep it alphabetically sorted by Kconfig name # (e. g. LC_ALL=C sort Makefile) @@ -24,12 +23,10 @@ obj-$(CONFIG_USB_MSI2500) += msi2500/ obj-$(CONFIG_USB_PWC) += pwc/ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ obj-$(CONFIG_VIDEO_AU0828) += au0828/ -obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_STK1160) += stk1160/ -obj-$(CONFIG_VIDEO_TM6000) += tm6000/ obj-$(CONFIG_VIDEO_USBTV) += usbtv/ diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 240a7cc56777..462eb8423506 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -294,7 +294,7 @@ static void airspy_urb_complete(struct urb *urb) if (unlikely(fbuf == NULL)) { s->vb_full++; dev_notice_ratelimited(s->dev, - "videobuf is full, %d packets dropped\n", + "video buffer is full, %d packets dropped\n", s->vb_full); goto skip; } @@ -1070,6 +1070,10 @@ static int airspy_probe(struct usb_interface *intf, ret); goto err_free_controls; } + + /* Free buf if success*/ + kfree(buf); + dev_info(s->dev, "Registered as %s\n", video_device_node_name(&s->vdev)); dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n"); diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index caefac07af92..877e85a451cb 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -410,7 +410,7 @@ static int au0828_enable_source(struct media_entity *entity, goto end; } - ret = __media_pipeline_start(entity, pipe); + ret = __media_pipeline_start(entity->pads, pipe); if (ret) { pr_err("Start Pipeline: %s->%s Error %d\n", source->name, entity->name, ret); @@ -501,12 +501,12 @@ static void au0828_disable_source(struct media_entity *entity) return; /* stop pipeline */ - __media_pipeline_stop(dev->active_link_owner); + __media_pipeline_stop(dev->active_link_owner->pads); pr_debug("Pipeline stop for %s\n", dev->active_link_owner->name); ret = __media_pipeline_start( - dev->active_link_user, + dev->active_link_user->pads, dev->active_link_user_pipe); if (ret) { pr_err("Start Pipeline: %s->%s %d\n", @@ -532,7 +532,7 @@ static void au0828_disable_source(struct media_entity *entity) return; /* stop pipeline */ - __media_pipeline_stop(dev->active_link_owner); + __media_pipeline_stop(dev->active_link_owner->pads); pr_debug("Pipeline stop for %s\n", dev->active_link_owner->name); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index c0f118563c7d..eb303e94cceb 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -384,7 +384,7 @@ static void au0828_copy_video(struct au0828_dev *dev, } /* - * video-buf generic routine to get the next available buffer + * generic routine to get the next available buffer */ static inline void get_next_buf(struct au0828_dmaqueue *dma_q, struct au0828_buffer **buf) @@ -459,7 +459,7 @@ static void au0828_copy_vbi(struct au0828_dev *dev, /* - * video-buf generic routine to get the next available VBI buffer + * generic routine to get the next available VBI buffer */ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q, struct au0828_buffer **buf) diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index fdc8b7f7b0c1..33431d9f54c2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -558,7 +558,7 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, } /* - * video-buf generic routine to get the next available buffer + * generic routine to get the next available buffer */ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, struct cx231xx_buffer **buf) diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 425e470b0fd3..e23b8ccd79d4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -220,7 +220,7 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) } /* - * video-buf generic routine to get the next available buffer + * generic routine to get the next available buffer */ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, struct cx231xx_buffer **buf) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 5eef37b00a52..1e9c8d01523b 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1497,7 +1497,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) /* * AF9035 gpiot2 = FC0012 enable * XXX: there seems to be something on gpioh8 too, but on my - * my test I didn't find any difference. + * test I didn't find any difference. */ if (adap->id == 0) { diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 9c77911fcad4..df90c6c5f3b9 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -786,7 +786,7 @@ static void technisat_usb2_disconnect(struct usb_interface *intf) { struct dvb_usb_device *dev = usb_get_intfdata(intf); - /* work and stuff was only created when the device is is hot-state */ + /* work and stuff was only created when the device is hot-state */ if (dev != NULL) { struct technisat_usb2_state *state = dev->priv; if (state != NULL) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8181c0e6a25b..25e0620deff1 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -440,7 +440,7 @@ static inline void finish_buffer(struct em28xx *dev, } /* - * Copy picture data from USB buffer to videobuf buffer + * Copy picture data from USB buffer to video buffer */ static void em28xx_copy_video(struct em28xx *dev, struct em28xx_buffer *buf, @@ -521,7 +521,7 @@ static void em28xx_copy_video(struct em28xx *dev, } /* - * Copy VBI data from USB buffer to videobuf buffer + * Copy VBI data from USB buffer to video buffer */ static void em28xx_copy_vbi(struct em28xx *dev, struct em28xx_buffer *buf, diff --git a/drivers/media/usb/gspca/finepix.c b/drivers/media/usb/gspca/finepix.c index 66c8e5122a0a..bc6133b525e3 100644 --- a/drivers/media/usb/gspca/finepix.c +++ b/drivers/media/usb/gspca/finepix.c @@ -129,7 +129,7 @@ again: * for, then it's the end of the * frame. Sometimes the jpeg is not complete, * but there's nothing we can do. We also end - * here if the the jpeg ends right at the end + * here if the jpeg ends right at the end * of the frame. */ gspca_frame_add(gspca_dev, LAST_PACKET, data, len); diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 71de6b4c4e4c..9759996ee6a4 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -209,7 +209,7 @@ leave: * * Control bits for previous samples is 32-bit field, containing 16 x 2-bit * numbers. This results one 2-bit number for 8 samples. It is likely used for - * for bit shifting sample by given bits, increasing actual sampling resolution. + * bit shifting sample by given bits, increasing actual sampling resolution. * Number 2 (0b10) was never seen. * * 6 * 16 * 2 * 4 = 768 samples. 768 * 4 = 3072 bytes @@ -411,7 +411,7 @@ static void msi2500_isoc_handler(struct urb *urb) if (unlikely(fbuf == NULL)) { dev->vb_full++; dev_dbg_ratelimited(dev->dev, - "videobuf is full, %d packets dropped\n", + "video buffer is full, %d packets dropped\n", dev->vb_full); continue; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c index 6954584526a3..26811efe0fb5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c @@ -80,7 +80,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) static int pvr2_dvb_feed_thread(void *data) { int stat = pvr2_dvb_feed_func(data); - /* from videobuf-dvb.c: */ + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); schedule(); diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 8c208db9600b..97f312020516 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -985,36 +985,56 @@ static s32 __uvc_ctrl_get_value(struct uvc_control_mapping *mapping, return value; } -static int __uvc_ctrl_get(struct uvc_video_chain *chain, - struct uvc_control *ctrl, struct uvc_control_mapping *mapping, - s32 *value) +static int __uvc_ctrl_load_cur(struct uvc_video_chain *chain, + struct uvc_control *ctrl) { + u8 *data; int ret; - if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) - return -EACCES; + if (ctrl->loaded) + return 0; - if (!ctrl->loaded) { - if (ctrl->entity->get_cur) { - ret = ctrl->entity->get_cur(chain->dev, - ctrl->entity, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - } else { - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, - ctrl->entity->id, - chain->dev->intfnum, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - } - if (ret < 0) - return ret; + data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT); + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) { + memset(data, 0, ctrl->info.size); ctrl->loaded = 1; + + return 0; } + if (ctrl->entity->get_cur) + ret = ctrl->entity->get_cur(chain->dev, ctrl->entity, + ctrl->info.selector, data, + ctrl->info.size); + else + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, + ctrl->entity->id, chain->dev->intfnum, + ctrl->info.selector, data, + ctrl->info.size); + + if (ret < 0) + return ret; + + ctrl->loaded = 1; + + return ret; +} + +static int __uvc_ctrl_get(struct uvc_video_chain *chain, + struct uvc_control *ctrl, + struct uvc_control_mapping *mapping, + s32 *value) +{ + int ret; + + if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) + return -EACCES; + + ret = __uvc_ctrl_load_cur(chain, ctrl); + if (ret < 0) + return ret; + *value = __uvc_ctrl_get_value(mapping, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT)); @@ -1810,21 +1830,10 @@ int uvc_ctrl_set(struct uvc_fh *handle, * needs to be loaded from the device to perform the read-modify-write * operation. */ - if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) { - if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) { - memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - 0, ctrl->info.size); - } else { - ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, - ctrl->entity->id, chain->dev->intfnum, - ctrl->info.selector, - uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), - ctrl->info.size); - if (ret < 0) - return ret; - } - - ctrl->loaded = 1; + if ((ctrl->info.size * 8) != mapping->size) { + ret = __uvc_ctrl_load_cur(chain, ctrl); + if (ret < 0) + return ret; } /* Backup the current value in case we need to rollback later. */ @@ -2411,10 +2420,9 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev, static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, struct uvc_control *ctrl) { - const struct uvc_control_info *info = uvc_ctrls; - const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls); - const struct uvc_control_mapping *mapping; - const struct uvc_control_mapping *mend; + const struct uvc_control_mapping *mappings; + unsigned int num_mappings; + unsigned int i; /* * XU controls initialization requires querying the device for control @@ -2425,7 +2433,9 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) return; - for (; info < iend; ++info) { + for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { + const struct uvc_control_info *info = &uvc_ctrls[i]; + if (uvc_entity_match_guid(ctrl->entity, info->entity) && ctrl->index == info->index) { uvc_ctrl_add_info(chain->dev, ctrl, info); @@ -2452,9 +2462,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, */ if (chain->dev->info->mappings) { bool custom = false; - unsigned int i; - for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) { + for (i = 0; chain->dev->info->mappings[i]; ++i) { + const struct uvc_control_mapping *mapping = + chain->dev->info->mappings[i]; + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) { __uvc_ctrl_add_mapping(chain, ctrl, mapping); @@ -2467,10 +2479,9 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, } /* Process common mappings next. */ - mapping = uvc_ctrl_mappings; - mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings); + for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) { + const struct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i]; - for (; mapping < mend; ++mapping) { if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) __uvc_ctrl_add_mapping(chain, ctrl, mapping); @@ -2478,14 +2489,16 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, /* Finally process version-specific mappings. */ if (chain->dev->uvc_version < 0x0150) { - mapping = uvc_ctrl_mappings_uvc11; - mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11); + mappings = uvc_ctrl_mappings_uvc11; + num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc11); } else { - mapping = uvc_ctrl_mappings_uvc15; - mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc15); + mappings = uvc_ctrl_mappings_uvc15; + num_mappings = ARRAY_SIZE(uvc_ctrl_mappings_uvc15); } - for (; mapping < mend; ++mapping) { + for (i = 0; i < num_mappings; ++i) { + const struct uvc_control_mapping *mapping = &mappings[i]; + if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) __uvc_ctrl_add_mapping(chain, ctrl, mapping); diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index d509a4a2f08e..744051b52e12 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1553,10 +1553,6 @@ static int uvc_gpio_parse(struct uvc_device *dev) if (IS_ERR_OR_NULL(gpio_privacy)) return PTR_ERR_OR_ZERO(gpio_privacy); - unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); - if (!unit) - return -ENOMEM; - irq = gpiod_to_irq(gpio_privacy); if (irq < 0) { if (irq != EPROBE_DEFER) @@ -1565,6 +1561,10 @@ static int uvc_gpio_parse(struct uvc_device *dev) return irq; } + unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (!unit) + return -ENOMEM; + unit->gpio.gpio_privacy = gpio_privacy; unit->gpio.irq = irq; unit->gpio.bControlSize = 1; @@ -3264,6 +3264,15 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) }, + /* Sonix Technology USB 2.0 Camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x3277, + .idProduct = 0x0072, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited }, /* Acer EasyCamera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 170a008f4006..d2eb9066e4dc 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1095,7 +1095,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, /* * Synchronize to the input stream by waiting for the FID bit to be - * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. + * toggled when the buffer state is not UVC_BUF_STATE_ACTIVE. * stream->last_fid is initialized to -1, so the first isochronous * frame will always be in sync. * diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index 50d012ba3c02..d0a3aa3806fb 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -89,10 +89,7 @@ static int req_to_user(struct v4l2_ext_control *c, /* Helper function: copy the initial control value back to the caller */ static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) { - int idx; - - for (idx = 0; idx < ctrl->elems; idx++) - ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + ctrl->type_ops->init(ctrl, 0, ctrl->p_new); return ptr_to_user(c, ctrl, ctrl->p_new); } @@ -105,8 +102,8 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) ctrl->is_new = 0; if (ctrl->is_dyn_array && - c->size > ctrl->p_dyn_alloc_elems * ctrl->elem_size) { - void *old = ctrl->p_dyn; + c->size > ctrl->p_array_alloc_elems * ctrl->elem_size) { + void *old = ctrl->p_array; void *tmp = kvzalloc(2 * c->size, GFP_KERNEL); if (!tmp) @@ -115,14 +112,13 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size); ctrl->p_new.p = tmp; ctrl->p_cur.p = tmp + c->size; - ctrl->p_dyn = tmp; - ctrl->p_dyn_alloc_elems = c->size / ctrl->elem_size; + ctrl->p_array = tmp; + ctrl->p_array_alloc_elems = c->size / ctrl->elem_size; kvfree(old); } if (ctrl->is_ptr && !ctrl->is_string) { unsigned int elems = c->size / ctrl->elem_size; - unsigned int idx; if (copy_from_user(ctrl->p_new.p, c->ptr, c->size)) return -EFAULT; @@ -130,8 +126,7 @@ static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl) if (ctrl->is_dyn_array) ctrl->new_elems = elems; else if (ctrl->is_array) - for (idx = elems; idx < ctrl->elems; idx++) - ctrl->type_ops->init(ctrl, idx, ctrl->p_new); + ctrl->type_ops->init(ctrl, elems, ctrl->p_new); return 0; } @@ -467,7 +462,7 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, if (is_default) ret = def_to_user(cs->controls + idx, ref->ctrl); - else if (is_request && ref->p_req_dyn_enomem) + else if (is_request && ref->p_req_array_enomem) ret = -ENOMEM; else if (is_request && ref->p_req_valid) ret = req_to_user(cs->controls + idx, ref); @@ -499,12 +494,7 @@ EXPORT_SYMBOL(v4l2_g_ext_ctrls); /* Validate a new control */ static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) { - unsigned int idx; - int err = 0; - - for (idx = 0; !err && idx < ctrl->new_elems; idx++) - err = ctrl->type_ops->validate(ctrl, idx, p_new); - return err; + return ctrl->type_ops->validate(ctrl, p_new); } /* Validate controls. */ @@ -989,6 +979,42 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, } EXPORT_SYMBOL(__v4l2_ctrl_modify_range); +int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, + u32 dims[V4L2_CTRL_MAX_DIMS]) +{ + unsigned int elems = 1; + unsigned int i; + void *p_array; + + lockdep_assert_held(ctrl->handler->lock); + + if (!ctrl->is_array || ctrl->is_dyn_array) + return -EINVAL; + + for (i = 0; i < ctrl->nr_of_dims; i++) + elems *= dims[i]; + if (elems == 0) + return -EINVAL; + p_array = kvzalloc(2 * elems * ctrl->elem_size, GFP_KERNEL); + if (!p_array) + return -ENOMEM; + kvfree(ctrl->p_array); + ctrl->p_array_alloc_elems = elems; + ctrl->elems = elems; + ctrl->new_elems = elems; + ctrl->p_array = p_array; + ctrl->p_new.p = p_array; + ctrl->p_cur.p = p_array + elems * ctrl->elem_size; + for (i = 0; i < ctrl->nr_of_dims; i++) + ctrl->dims[i] = dims[i]; + ctrl->type_ops->init(ctrl, 0, ctrl->p_cur); + cur_to_new(ctrl); + send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_VALUE | + V4L2_EVENT_CTRL_CH_DIMENSIONS); + return 0; +} +EXPORT_SYMBOL(__v4l2_ctrl_modify_dimensions); + /* Implement VIDIOC_QUERY_EXT_CTRL */ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctrl *qc) { diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 1f85828d6694..0dab1d7b90f0 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -65,33 +65,29 @@ void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes) v4l2_event_queue_fh(sev->fh, &ev); } -static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr1, - union v4l2_ctrl_ptr ptr2) +bool v4l2_ctrl_type_op_equal(const struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2) { + unsigned int i; + switch (ctrl->type) { case V4L2_CTRL_TYPE_BUTTON: return false; case V4L2_CTRL_TYPE_STRING: - idx *= ctrl->elem_size; - /* strings are always 0-terminated */ - return !strcmp(ptr1.p_char + idx, ptr2.p_char + idx); - case V4L2_CTRL_TYPE_INTEGER64: - return ptr1.p_s64[idx] == ptr2.p_s64[idx]; - case V4L2_CTRL_TYPE_U8: - return ptr1.p_u8[idx] == ptr2.p_u8[idx]; - case V4L2_CTRL_TYPE_U16: - return ptr1.p_u16[idx] == ptr2.p_u16[idx]; - case V4L2_CTRL_TYPE_U32: - return ptr1.p_u32[idx] == ptr2.p_u32[idx]; + for (i = 0; i < ctrl->elems; i++) { + unsigned int idx = i * ctrl->elem_size; + + /* strings are always 0-terminated */ + if (strcmp(ptr1.p_char + idx, ptr2.p_char + idx)) + return false; + } + return true; default: - if (ctrl->is_int) - return ptr1.p_s32[idx] == ptr2.p_s32[idx]; - idx *= ctrl->elem_size; - return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx, - ctrl->elem_size); + return !memcmp(ptr1.p_const, ptr2.p_const, + ctrl->elems * ctrl->elem_size); } } +EXPORT_SYMBOL(v4l2_ctrl_type_op_equal); /* Default intra MPEG-2 quantisation coefficients, from the specification. */ static const u8 mpeg2_intra_quant_matrix[64] = { @@ -181,45 +177,77 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, } } -static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) +void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx, + union v4l2_ctrl_ptr ptr) { + unsigned int i; + u32 tot_elems = ctrl->elems; + u32 elems = tot_elems - from_idx; + + if (from_idx >= tot_elems) + return; + switch (ctrl->type) { case V4L2_CTRL_TYPE_STRING: - idx *= ctrl->elem_size; - memset(ptr.p_char + idx, ' ', ctrl->minimum); - ptr.p_char[idx + ctrl->minimum] = '\0'; + for (i = from_idx; i < tot_elems; i++) { + unsigned int offset = i * ctrl->elem_size; + + memset(ptr.p_char + offset, ' ', ctrl->minimum); + ptr.p_char[offset + ctrl->minimum] = '\0'; + } break; case V4L2_CTRL_TYPE_INTEGER64: - ptr.p_s64[idx] = ctrl->default_value; + if (ctrl->default_value) { + for (i = from_idx; i < tot_elems; i++) + ptr.p_s64[i] = ctrl->default_value; + } else { + memset(ptr.p_s64 + from_idx, 0, elems * sizeof(s64)); + } break; case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_BITMASK: case V4L2_CTRL_TYPE_BOOLEAN: - ptr.p_s32[idx] = ctrl->default_value; + if (ctrl->default_value) { + for (i = from_idx; i < tot_elems; i++) + ptr.p_s32[i] = ctrl->default_value; + } else { + memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32)); + } break; case V4L2_CTRL_TYPE_BUTTON: case V4L2_CTRL_TYPE_CTRL_CLASS: - ptr.p_s32[idx] = 0; + memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32)); break; case V4L2_CTRL_TYPE_U8: - ptr.p_u8[idx] = ctrl->default_value; + memset(ptr.p_u8 + from_idx, ctrl->default_value, elems); break; case V4L2_CTRL_TYPE_U16: - ptr.p_u16[idx] = ctrl->default_value; + if (ctrl->default_value) { + for (i = from_idx; i < tot_elems; i++) + ptr.p_u16[i] = ctrl->default_value; + } else { + memset(ptr.p_u16 + from_idx, 0, elems * sizeof(u16)); + } break; case V4L2_CTRL_TYPE_U32: - ptr.p_u32[idx] = ctrl->default_value; + if (ctrl->default_value) { + for (i = from_idx; i < tot_elems; i++) + ptr.p_u32[i] = ctrl->default_value; + } else { + memset(ptr.p_u32 + from_idx, 0, elems * sizeof(u32)); + } break; default: - std_init_compound(ctrl, idx, ptr); + for (i = from_idx; i < tot_elems; i++) + std_init_compound(ctrl, i, ptr); break; } } +EXPORT_SYMBOL(v4l2_ctrl_type_op_init); -static void std_log(const struct v4l2_ctrl *ctrl) +void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl) { union v4l2_ctrl_ptr ptr = ctrl->p_cur; @@ -327,6 +355,7 @@ static void std_log(const struct v4l2_ctrl *ctrl) break; } } +EXPORT_SYMBOL(v4l2_ctrl_type_op_log); /* * Round towards the closest legal value. Be careful when we are @@ -520,7 +549,8 @@ validate_vp9_frame(struct v4l2_ctrl_vp9_frame *frame) /* * Compound controls validation requires setting unused fields/flags to zero - * in order to properly detect unchanged controls with std_equal's memcmp. + * in order to properly detect unchanged controls with v4l2_ctrl_type_op_equal's + * memcmp. */ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) @@ -895,8 +925,8 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, return 0; } -static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) +static int std_validate_elem(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) { size_t len; u64 offset; @@ -966,11 +996,43 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, } } +int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr) +{ + unsigned int i; + int ret = 0; + + switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_U8: + if (ctrl->maximum == 0xff && ctrl->minimum == 0 && ctrl->step == 1) + return 0; + break; + case V4L2_CTRL_TYPE_U16: + if (ctrl->maximum == 0xffff && ctrl->minimum == 0 && ctrl->step == 1) + return 0; + break; + case V4L2_CTRL_TYPE_U32: + if (ctrl->maximum == 0xffffffff && ctrl->minimum == 0 && ctrl->step == 1) + return 0; + break; + + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + memset(ptr.p_s32, 0, ctrl->new_elems * sizeof(s32)); + return 0; + } + + for (i = 0; !ret && i < ctrl->new_elems; i++) + ret = std_validate_elem(ctrl, i, ptr); + return ret; +} +EXPORT_SYMBOL(v4l2_ctrl_type_op_validate); + static const struct v4l2_ctrl_type_ops std_type_ops = { - .equal = std_equal, - .init = std_init, - .log = std_log, - .validate = std_validate, + .equal = v4l2_ctrl_type_op_equal, + .init = v4l2_ctrl_type_op_init, + .log = v4l2_ctrl_type_op_log, + .validate = v4l2_ctrl_type_op_validate, }; void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv) @@ -1048,23 +1110,26 @@ void cur_to_new(struct v4l2_ctrl *ctrl) ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems); } -static bool req_alloc_dyn_array(struct v4l2_ctrl_ref *ref, u32 elems) +static bool req_alloc_array(struct v4l2_ctrl_ref *ref, u32 elems) { void *tmp; - if (elems < ref->p_req_dyn_alloc_elems) + if (elems == ref->p_req_array_alloc_elems) + return true; + if (ref->ctrl->is_dyn_array && + elems < ref->p_req_array_alloc_elems) return true; tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL); if (!tmp) { - ref->p_req_dyn_enomem = true; + ref->p_req_array_enomem = true; return false; } - ref->p_req_dyn_enomem = false; + ref->p_req_array_enomem = false; kvfree(ref->p_req.p); ref->p_req.p = tmp; - ref->p_req_dyn_alloc_elems = elems; + ref->p_req_array_alloc_elems = elems; return true; } @@ -1077,7 +1142,7 @@ void new_to_req(struct v4l2_ctrl_ref *ref) return; ctrl = ref->ctrl; - if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->new_elems)) + if (ctrl->is_array && !req_alloc_array(ref, ctrl->new_elems)) return; ref->p_req_elems = ctrl->new_elems; @@ -1094,7 +1159,7 @@ void cur_to_req(struct v4l2_ctrl_ref *ref) return; ctrl = ref->ctrl; - if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->elems)) + if (ctrl->is_array && !req_alloc_array(ref, ctrl->elems)) return; ref->p_req_elems = ctrl->elems; @@ -1123,26 +1188,30 @@ int req_to_new(struct v4l2_ctrl_ref *ref) return 0; } - /* Not a dynamic array, so just copy the request value */ - if (!ctrl->is_dyn_array) { + /* Not an array, so just copy the request value */ + if (!ctrl->is_array) { ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems); return 0; } /* Sanity check, should never happen */ - if (WARN_ON(!ref->p_req_dyn_alloc_elems)) + if (WARN_ON(!ref->p_req_array_alloc_elems)) + return -ENOMEM; + + if (!ctrl->is_dyn_array && + ref->p_req_elems != ctrl->p_array_alloc_elems) return -ENOMEM; /* * Check if the number of elements in the request is more than the - * elements in ctrl->p_dyn. If so, attempt to realloc ctrl->p_dyn. - * Note that p_dyn is allocated with twice the number of elements + * elements in ctrl->p_array. If so, attempt to realloc ctrl->p_array. + * Note that p_array is allocated with twice the number of elements * in the dynamic array since it has to store both the current and * new value of such a control. */ - if (ref->p_req_elems > ctrl->p_dyn_alloc_elems) { + if (ref->p_req_elems > ctrl->p_array_alloc_elems) { unsigned int sz = ref->p_req_elems * ctrl->elem_size; - void *old = ctrl->p_dyn; + void *old = ctrl->p_array; void *tmp = kvzalloc(2 * sz, GFP_KERNEL); if (!tmp) @@ -1151,8 +1220,8 @@ int req_to_new(struct v4l2_ctrl_ref *ref) memcpy(tmp + sz, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size); ctrl->p_new.p = tmp; ctrl->p_cur.p = tmp + sz; - ctrl->p_dyn = tmp; - ctrl->p_dyn_alloc_elems = ref->p_req_elems; + ctrl->p_array = tmp; + ctrl->p_array_alloc_elems = ref->p_req_elems; kvfree(old); } @@ -1243,7 +1312,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) /* Free all nodes */ list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) { list_del(&ref->node); - if (ref->p_req_dyn_alloc_elems) + if (ref->p_req_array_alloc_elems) kvfree(ref->p_req.p); kfree(ref); } @@ -1252,7 +1321,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) list_del(&ctrl->node); list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node) list_del(&sev->node); - kvfree(ctrl->p_dyn); + kvfree(ctrl->p_array); kvfree(ctrl); } kvfree(hdl->buckets); @@ -1368,7 +1437,7 @@ int handler_new_ref(struct v4l2_ctrl_handler *hdl, if (hdl->error) return hdl->error; - if (allocate_req && !ctrl->is_dyn_array) + if (allocate_req && !ctrl->is_array) size_extra_req = ctrl->elems * ctrl->elem_size; new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL); if (!new_ref) @@ -1442,7 +1511,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, unsigned elems = 1; bool is_array; unsigned tot_ctrl_size; - unsigned idx; void *data; int err; @@ -1584,11 +1652,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; else if (type == V4L2_CTRL_TYPE_CTRL_CLASS) flags |= V4L2_CTRL_FLAG_READ_ONLY; - else if (!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) && + else if (!is_array && (type == V4L2_CTRL_TYPE_INTEGER64 || type == V4L2_CTRL_TYPE_STRING || - type >= V4L2_CTRL_COMPOUND_TYPES || - is_array)) + type >= V4L2_CTRL_COMPOUND_TYPES)) sz_extra += 2 * tot_ctrl_size; if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) @@ -1632,14 +1699,14 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ctrl->cur.val = ctrl->val = def; data = &ctrl[1]; - if (ctrl->is_dyn_array) { - ctrl->p_dyn_alloc_elems = elems; - ctrl->p_dyn = kvzalloc(2 * elems * elem_size, GFP_KERNEL); - if (!ctrl->p_dyn) { + if (ctrl->is_array) { + ctrl->p_array_alloc_elems = elems; + ctrl->p_array = kvzalloc(2 * elems * elem_size, GFP_KERNEL); + if (!ctrl->p_array) { kvfree(ctrl); return NULL; } - data = ctrl->p_dyn; + data = ctrl->p_array; } if (!ctrl->is_int) { @@ -1651,20 +1718,18 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, } if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) { - if (ctrl->is_dyn_array) + if (ctrl->is_array) ctrl->p_def.p = &ctrl[1]; else ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; memcpy(ctrl->p_def.p, p_def.p_const, elem_size); } - for (idx = 0; idx < elems; idx++) { - ctrl->type_ops->init(ctrl, idx, ctrl->p_cur); - ctrl->type_ops->init(ctrl, idx, ctrl->p_new); - } + ctrl->type_ops->init(ctrl, 0, ctrl->p_cur); + cur_to_new(ctrl); if (handler_new_ref(hdl, ctrl, NULL, false, false)) { - kvfree(ctrl->p_dyn); + kvfree(ctrl->p_array); kvfree(ctrl); return NULL; } @@ -1978,7 +2043,6 @@ void update_from_auto_cluster(struct v4l2_ctrl *master) static int cluster_changed(struct v4l2_ctrl *master) { bool changed = false; - unsigned int idx; int i; for (i = 0; i < master->ncontrols; i++) { @@ -2004,9 +2068,8 @@ static int cluster_changed(struct v4l2_ctrl *master) if (ctrl->elems != ctrl->new_elems) ctrl_changed = true; - - for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++) - ctrl_changed = !ctrl->type_ops->equal(ctrl, idx, + if (!ctrl_changed) + ctrl_changed = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new); ctrl->has_changed = ctrl_changed; changed |= ctrl->has_changed; diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index d00237ee4cae..397d553177fa 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -1095,6 +1095,78 @@ void video_unregister_device(struct video_device *vdev) } EXPORT_SYMBOL(video_unregister_device); +#if defined(CONFIG_MEDIA_CONTROLLER) + +__must_check int video_device_pipeline_start(struct video_device *vdev, + struct media_pipeline *pipe) +{ + struct media_entity *entity = &vdev->entity; + + if (entity->num_pads != 1) + return -ENODEV; + + return media_pipeline_start(&entity->pads[0], pipe); +} +EXPORT_SYMBOL_GPL(video_device_pipeline_start); + +__must_check int __video_device_pipeline_start(struct video_device *vdev, + struct media_pipeline *pipe) +{ + struct media_entity *entity = &vdev->entity; + + if (entity->num_pads != 1) + return -ENODEV; + + return __media_pipeline_start(&entity->pads[0], pipe); +} +EXPORT_SYMBOL_GPL(__video_device_pipeline_start); + +void video_device_pipeline_stop(struct video_device *vdev) +{ + struct media_entity *entity = &vdev->entity; + + if (WARN_ON(entity->num_pads != 1)) + return; + + return media_pipeline_stop(&entity->pads[0]); +} +EXPORT_SYMBOL_GPL(video_device_pipeline_stop); + +void __video_device_pipeline_stop(struct video_device *vdev) +{ + struct media_entity *entity = &vdev->entity; + + if (WARN_ON(entity->num_pads != 1)) + return; + + return __media_pipeline_stop(&entity->pads[0]); +} +EXPORT_SYMBOL_GPL(__video_device_pipeline_stop); + +__must_check int video_device_pipeline_alloc_start(struct video_device *vdev) +{ + struct media_entity *entity = &vdev->entity; + + if (entity->num_pads != 1) + return -ENODEV; + + return media_pipeline_alloc_start(&entity->pads[0]); +} +EXPORT_SYMBOL_GPL(video_device_pipeline_alloc_start); + +struct media_pipeline *video_device_pipeline(struct video_device *vdev) +{ + struct media_entity *entity = &vdev->entity; + + if (WARN_ON(entity->num_pads != 1)) + return NULL; + + return media_pad_pipeline(&entity->pads[0]); +} +EXPORT_SYMBOL_GPL(video_device_pipeline); + +#endif /* CONFIG_MEDIA_CONTROLLER */ + /* * Initialise video for linux */ diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index e70e128ccc9c..355595a0fefa 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -94,7 +94,7 @@ static int v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, * brightness <-> intensity conversion, it also must have defined * related v4l2 control step == 1. In such a case a backward conversion * from led brightness to v4l2 intensity is required to find out the - * the aligned intensity value. + * aligned intensity value. */ if (has_flash_op(v4l2_flash, led_brightness_to_intensity)) ctrl->val = call_flash_op(v4l2_flash, diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index e6fd355a2e92..fddba75d9074 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1045,7 +1045,7 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) /* * The v4l2_pix_format structure has been extended with fields that were * not previously required to be set to zero by applications. The priv - * field, when set to a magic value, indicates the the extended fields + * field, when set to a magic value, indicates that the extended fields * are valid. Otherwise they will contain undefined values. To simplify * the API towards drivers zero the extended fields and set the priv * field to the magic value when the extended pixel format structure diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 837e1855f94b..be7fde1ed3ea 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Memory-to-memory device framework for Video for Linux 2 and videobuf. + * Memory-to-memory device framework for Video for Linux 2 and vb2. * - * Helper functions for devices that use videobuf buffers for both their + * Helper functions for devices that use vb2 buffers for both their * source and destination. * * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. @@ -21,7 +21,7 @@ #include <media/v4l2-fh.h> #include <media/v4l2-event.h> -MODULE_DESCRIPTION("Mem to mem device framework for videobuf"); +MODULE_DESCRIPTION("Mem to mem device framework for vb2"); MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 421ce9dbf44c..d4f03b203ae5 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -22,10 +22,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/atomisp/Kconfig" -source "drivers/staging/media/av7110/Kconfig" - -source "drivers/staging/media/hantro/Kconfig" - source "drivers/staging/media/imx/Kconfig" source "drivers/staging/media/ipu3/Kconfig" @@ -38,12 +34,31 @@ source "drivers/staging/media/omap4iss/Kconfig" source "drivers/staging/media/rkvdec/Kconfig" -source "drivers/staging/media/stkwebcam/Kconfig" - source "drivers/staging/media/sunxi/Kconfig" source "drivers/staging/media/tegra-video/Kconfig" -source "drivers/staging/media/zoran/Kconfig" +menuconfig STAGING_MEDIA_DEPRECATED + bool "Media staging drivers (DEPRECATED)" + default n + help + This option enables deprecated media drivers that are + scheduled for future removal from the kernel. + + If you wish to work on these drivers to prevent their removal, + then contact the linux-media@vger.kernel.org mailing list. + + If in doubt, say N here. + +if STAGING_MEDIA_DEPRECATED +source "drivers/staging/media/deprecated/cpia2/Kconfig" +source "drivers/staging/media/deprecated/fsl-viu/Kconfig" +source "drivers/staging/media/deprecated/meye/Kconfig" +source "drivers/staging/media/deprecated/saa7146/Kconfig" +source "drivers/staging/media/deprecated/stkwebcam/Kconfig" +source "drivers/staging/media/deprecated/tm6000/Kconfig" +source "drivers/staging/media/deprecated/vpfe_capture/Kconfig" +source "drivers/staging/media/deprecated/zr364xx/Kconfig" +endif endif diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 950e96f10aad..a387692b84f2 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,14 +1,18 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ +obj-$(CONFIG_VIDEO_CPIA2) += deprecated/cpia2/ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ obj-$(CONFIG_VIDEO_MAX96712) += max96712/ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ +obj-$(CONFIG_VIDEO_MEYE) += deprecated/meye/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ -obj-$(CONFIG_VIDEO_STKWEBCAM) += stkwebcam/ +obj-$(CONFIG_VIDEO_STKWEBCAM) += deprecated/stkwebcam/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ -obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ -obj-$(CONFIG_VIDEO_ZORAN) += zoran/ -obj-$(CONFIG_DVB_AV7110) += av7110/ +obj-$(CONFIG_VIDEO_TM6000) += deprecated/tm6000/ +obj-$(CONFIG_VIDEO_VIU) += deprecated/fsl-viu/ +obj-$(CONFIG_USB_ZR364XX) += deprecated/zr364xx/ +obj-y += deprecated/vpfe_capture/ +obj-y += deprecated/saa7146/ diff --git a/drivers/staging/media/atomisp/Makefile b/drivers/staging/media/atomisp/Makefile index fb7b406f50bf..532e12ed72e6 100644 --- a/drivers/staging/media/atomisp/Makefile +++ b/drivers/staging/media/atomisp/Makefile @@ -17,7 +17,6 @@ atomisp-objs += \ pci/atomisp_compat_css20.o \ pci/atomisp_csi2.o \ pci/atomisp_drvfs.o \ - pci/atomisp_file.o \ pci/atomisp_fops.o \ pci/atomisp_ioctl.o \ pci/atomisp_subdev.o \ diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 4ba99c660681..5ba4c52a06a2 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -841,8 +841,6 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, if (!ov2680_info) return -EINVAL; - mutex_lock(&dev->input_lock); - res = v4l2_find_nearest_size(ov2680_res_preview, ARRAY_SIZE(ov2680_res_preview), width, height, fmt->width, fmt->height); @@ -855,19 +853,22 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; if (format->which == V4L2_SUBDEV_FORMAT_TRY) { sd_state->pads->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); return 0; } dev_dbg(&client->dev, "%s: %dx%d\n", __func__, fmt->width, fmt->height); + mutex_lock(&dev->input_lock); + /* s_power has not been called yet for std v4l2 clients (camorama) */ power_up(sd); ret = ov2680_write_reg_array(client, dev->res->regs); - if (ret) + if (ret) { dev_err(&client->dev, "ov2680 write resolution register err: %d\n", ret); + goto err; + } vts = dev->res->lines_per_frame; @@ -876,8 +877,10 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, vts = dev->exposure + OV2680_INTEGRATION_TIME_MARGIN; ret = ov2680_write_reg(client, 2, OV2680_TIMING_VTS_H, vts); - if (ret) + if (ret) { dev_err(&client->dev, "ov2680 write vts err: %d\n", ret); + goto err; + } ret = ov2680_get_intg_factor(client, ov2680_info, res); if (ret) { @@ -894,11 +897,7 @@ static int ov2680_set_fmt(struct v4l2_subdev *sd, if (v_flag) ov2680_v_flip(sd, v_flag); - /* - * ret = startup(sd); - * if (ret) - * dev_err(&client->dev, "ov2680 startup err\n"); - */ + dev->res = res; err: mutex_unlock(&dev->input_lock); return ret; diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h index 385e22fc4a46..c5cbae1d9cf9 100644 --- a/drivers/staging/media/atomisp/include/hmm/hmm_bo.h +++ b/drivers/staging/media/atomisp/include/hmm/hmm_bo.h @@ -65,9 +65,6 @@ #define check_bo_null_return_void(bo) \ check_null_return_void(bo, "NULL hmm buffer object.\n") -#define HMM_MAX_ORDER 3 -#define HMM_MIN_ORDER 0 - #define ISP_VM_START 0x0 #define ISP_VM_SIZE (0x7FFFFFFF) /* 2G address space */ #define ISP_PTR_NULL NULL @@ -89,8 +86,6 @@ enum hmm_bo_type { #define HMM_BO_VMAPED 0x10 #define HMM_BO_VMAPED_CACHED 0x20 #define HMM_BO_ACTIVE 0x1000 -#define HMM_BO_MEM_TYPE_USER 0x1 -#define HMM_BO_MEM_TYPE_PFN 0x2 struct hmm_bo_device { struct isp_mmu mmu; @@ -126,7 +121,6 @@ struct hmm_buffer_object { enum hmm_bo_type type; int mmap_count; int status; - int mem_type; void *vmap_addr; /* kernel virtual address by vmap */ struct rb_node node; diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index f96f5adbd9de..3f602b5aaff9 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -740,20 +740,6 @@ enum atomisp_frame_status { ATOMISP_FRAME_STATUS_FLASH_FAILED, }; -/* ISP memories, isp2400 */ -enum atomisp_acc_memory { - ATOMISP_ACC_MEMORY_PMEM0 = 0, - ATOMISP_ACC_MEMORY_DMEM0, - /* for backward compatibility */ - ATOMISP_ACC_MEMORY_DMEM = ATOMISP_ACC_MEMORY_DMEM0, - ATOMISP_ACC_MEMORY_VMEM0, - ATOMISP_ACC_MEMORY_VAMEM0, - ATOMISP_ACC_MEMORY_VAMEM1, - ATOMISP_ACC_MEMORY_VAMEM2, - ATOMISP_ACC_MEMORY_HMEM0, - ATOMISP_ACC_NR_MEMORY -}; - enum atomisp_ext_isp_id { EXT_ISP_CID_ISO = 0, EXT_ISP_CID_CAPTURE_HDR, diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h index 58e0ea5355a3..5463d11d4295 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h @@ -26,8 +26,6 @@ struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd); int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def); -int camera_sensor_csi(struct v4l2_subdev *sd, u32 port, - u32 lanes, u32 format, u32 bayer_order, int flag); struct camera_sensor_platform_data * gmin_camera_platform_data( struct v4l2_subdev *subdev, diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 8c65733e0255..0253661d4332 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -141,23 +141,6 @@ struct atomisp_platform_data { struct intel_v4l2_subdev_table *subdevs; }; -/* Describe the capacities of one single sensor. */ -struct atomisp_sensor_caps { - /* The number of streams this sensor can output. */ - int stream_num; - bool is_slave; -}; - -/* Describe the capacities of sensors connected to one camera port. */ -struct atomisp_camera_caps { - /* The number of sensors connected to this camera port. */ - int sensor_num; - /* The capacities of each sensor. */ - struct atomisp_sensor_caps sensor[MAX_SENSORS_PER_PORT]; - /* Define whether stream control is required for multiple streams. */ - bool multi_stream_ctrl; -}; - /* * Sensor of external ISP can send multiple steams with different mipi data * type in the same virtual channel. This information needs to come from the @@ -235,7 +218,6 @@ struct camera_mipi_info { }; const struct atomisp_platform_data *atomisp_get_platform_data(void); -const struct atomisp_camera_caps *atomisp_get_default_camera_caps(void); /* API from old platform_camera.h, new CPUID implementation */ #define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \ diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt index d128b792e05f..d3cf6ed547ae 100644 --- a/drivers/staging/media/atomisp/notes.txt +++ b/drivers/staging/media/atomisp/notes.txt @@ -28,3 +28,22 @@ Since getting a picture requires multiple processing steps, this means that unlike in fixed pipelines the soft pipelines on the ISP can do multiple processing steps in a single pipeline element (in a single binary). + +### + +The sensor drivers use of v4l2_get_subdev_hostdata(), which returns +a camera_mipi_info struct. This struct is allocated/managed by +the core atomisp code. The most important parts of the struct +are filled by the atomisp core itself, like e.g. the port number. + +The sensor drivers on a set_fmt call do fill in camera_mipi_info.data +which is a atomisp_sensor_mode_data struct. This gets filled from +a function called <sensor_name>_get_intg_factor(). This struct is not +used by the atomisp code at all. It is returned to userspace by +a ATOMISP_IOC_G_SENSOR_MODE_DATA and the Android userspace does use this. + +Other members of camera_mipi_info which are set by some drivers are: +-metadata_width, metadata_height, metadata_effective_width, set by + the ov5693 driver (and used by the atomisp core) +-raw_bayer_order, adjusted by the ov2680 driver when flipping since + flipping can change the bayer order diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index c932f340068f..c72d0e344671 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -80,6 +80,8 @@ union host { } ptr; }; +static int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id); + /* * get sensor:dis71430/ov2720 related info from v4l2_subdev->priv data field. * subdev->priv is set in mrst.c @@ -98,15 +100,6 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev) container_of(dev, struct atomisp_video_pipe, vdev); } -/* - * get struct atomisp_acc_pipe from v4l2 video_device - */ -struct atomisp_acc_pipe *atomisp_to_acc_pipe(struct video_device *dev) -{ - return (struct atomisp_acc_pipe *) - container_of(dev, struct atomisp_acc_pipe, vdev); -} - static unsigned short atomisp_get_sensor_fps(struct atomisp_sub_device *asd) { struct v4l2_subdev_frame_interval fi = { 0 }; @@ -777,24 +770,6 @@ static struct atomisp_video_pipe *__atomisp_get_pipe( enum ia_css_pipe_id css_pipe_id, enum ia_css_buffer_type buf_type) { - struct atomisp_device *isp = asd->isp; - - if (css_pipe_id == IA_CSS_PIPE_ID_COPY && - isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num > 1) { - switch (stream_id) { - case ATOMISP_INPUT_STREAM_PREVIEW: - return &asd->video_out_preview; - case ATOMISP_INPUT_STREAM_POSTVIEW: - return &asd->video_out_vf; - case ATOMISP_INPUT_STREAM_VIDEO: - return &asd->video_out_video_capture; - case ATOMISP_INPUT_STREAM_CAPTURE: - default: - return &asd->video_out_capture; - } - } - /* video is same in online as in continuouscapture mode */ if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_LOWLAT) { /* @@ -906,7 +881,8 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, enum atomisp_metadata_type md_type; struct atomisp_device *isp = asd->isp; struct v4l2_control ctrl; - bool reset_wdt_timer = false; + + lockdep_assert_held(&isp->mutex); if ( buf_type != IA_CSS_BUFFER_TYPE_METADATA && @@ -1013,9 +989,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, break; case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: - if (IS_ISP2401) - reset_wdt_timer = true; - pipe->buffers_in_css--; frame = buffer.css_buffer.data.frame; if (!frame) { @@ -1068,9 +1041,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, break; case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: - if (IS_ISP2401) - reset_wdt_timer = true; - pipe->buffers_in_css--; frame = buffer.css_buffer.data.frame; if (!frame) { @@ -1238,8 +1208,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, */ wake_up(&vb->done); } - if (IS_ISP2401) - atomic_set(&pipe->wdt_count, 0); /* * Requeue should only be done for 3a and dis buffers. @@ -1256,19 +1224,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, } if (!error && q_buffers) atomisp_qbuffers_to_css(asd); - - if (IS_ISP2401) { - /* If there are no buffers queued then - * delete wdt timer. */ - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - return; - if (!atomisp_buffers_queued_pipe(pipe)) - atomisp_wdt_stop_pipe(pipe, false); - else if (reset_wdt_timer) - /* SOF irq should not reset wdt timer. */ - atomisp_wdt_refresh_pipe(pipe, - ATOMISP_WDT_KEEP_CURRENT_DELAY); - } } void atomisp_delayed_init_work(struct work_struct *work) @@ -1307,10 +1262,14 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) bool stream_restart[MAX_STREAM_NUM] = {0}; bool depth_mode = false; int i, ret, depth_cnt = 0; + unsigned long flags; - if (!isp->sw_contex.file_input) - atomisp_css_irq_enable(isp, - IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); + lockdep_assert_held(&isp->mutex); + + if (!atomisp_streaming_count(isp)) + return; + + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); BUG_ON(isp->num_of_streams > MAX_STREAM_NUM); @@ -1331,7 +1290,9 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) stream_restart[asd->index] = true; + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING; + spin_unlock_irqrestore(&isp->lock, flags); /* stream off sensor */ ret = v4l2_subdev_call( @@ -1346,7 +1307,9 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) css_pipe_id = atomisp_get_css_pipe_id(asd); atomisp_css_stop(asd, css_pipe_id, true); + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; + spin_unlock_irqrestore(&isp->lock, flags); asd->preview_exp_id = 1; asd->postview_exp_id = 1; @@ -1387,25 +1350,23 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) IA_CSS_INPUT_MODE_BUFFERED_SENSOR); css_pipe_id = atomisp_get_css_pipe_id(asd); - if (atomisp_css_start(asd, css_pipe_id, true)) + if (atomisp_css_start(asd, css_pipe_id, true)) { dev_warn(isp->dev, "start SP failed, so do not set streaming to be enable!\n"); - else + } else { + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED; + spin_unlock_irqrestore(&isp->lock, flags); + } atomisp_csi2_configure(asd); } - if (!isp->sw_contex.file_input) { - atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, - atomisp_css_valid_sof(isp)); + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, + atomisp_css_valid_sof(isp)); - if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0) - dev_dbg(isp->dev, "DFS auto failed while recovering!\n"); - } else { - if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, true) < 0) - dev_dbg(isp->dev, "DFS max failed while recovering!\n"); - } + if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, true) < 0) + dev_dbg(isp->dev, "DFS auto failed while recovering!\n"); for (i = 0; i < isp->num_of_streams; i++) { struct atomisp_sub_device *asd; @@ -1454,361 +1415,24 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout) } } -void atomisp_wdt_work(struct work_struct *work) +void atomisp_assert_recovery_work(struct work_struct *work) { struct atomisp_device *isp = container_of(work, struct atomisp_device, - wdt_work); - int i; - unsigned int pipe_wdt_cnt[MAX_STREAM_NUM][4] = { {0} }; - bool css_recover = true; - - rt_mutex_lock(&isp->mutex); - if (!atomisp_streaming_count(isp)) { - atomic_set(&isp->wdt_work_queued, 0); - rt_mutex_unlock(&isp->mutex); - return; - } - - if (!IS_ISP2401) { - dev_err(isp->dev, "timeout %d of %d\n", - atomic_read(&isp->wdt_count) + 1, - ATOMISP_ISP_MAX_TIMEOUT_COUNT); - } else { - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - pipe_wdt_cnt[i][0] += - atomic_read(&asd->video_out_capture.wdt_count); - pipe_wdt_cnt[i][1] += - atomic_read(&asd->video_out_vf.wdt_count); - pipe_wdt_cnt[i][2] += - atomic_read(&asd->video_out_preview.wdt_count); - pipe_wdt_cnt[i][3] += - atomic_read(&asd->video_out_video_capture.wdt_count); - css_recover = - (pipe_wdt_cnt[i][0] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && - pipe_wdt_cnt[i][1] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && - pipe_wdt_cnt[i][2] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT && - pipe_wdt_cnt[i][3] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT) - ? true : false; - dev_err(isp->dev, - "pipe on asd%d timeout cnt: (%d, %d, %d, %d) of %d, recover = %d\n", - asd->index, pipe_wdt_cnt[i][0], pipe_wdt_cnt[i][1], - pipe_wdt_cnt[i][2], pipe_wdt_cnt[i][3], - ATOMISP_ISP_MAX_TIMEOUT_COUNT, css_recover); - } - } - - if (css_recover) { - ia_css_debug_dump_sp_sw_debug_info(); - ia_css_debug_dump_debug_info(__func__); - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - continue; - dev_err(isp->dev, "%s, vdev %s buffers in css: %d\n", - __func__, - asd->video_out_capture.vdev.name, - asd->video_out_capture. - buffers_in_css); - dev_err(isp->dev, - "%s, vdev %s buffers in css: %d\n", - __func__, - asd->video_out_vf.vdev.name, - asd->video_out_vf. - buffers_in_css); - dev_err(isp->dev, - "%s, vdev %s buffers in css: %d\n", - __func__, - asd->video_out_preview.vdev.name, - asd->video_out_preview. - buffers_in_css); - dev_err(isp->dev, - "%s, vdev %s buffers in css: %d\n", - __func__, - asd->video_out_video_capture.vdev.name, - asd->video_out_video_capture. - buffers_in_css); - dev_err(isp->dev, - "%s, s3a buffers in css preview pipe:%d\n", - __func__, - asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_PREVIEW]); - dev_err(isp->dev, - "%s, s3a buffers in css capture pipe:%d\n", - __func__, - asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_CAPTURE]); - dev_err(isp->dev, - "%s, s3a buffers in css video pipe:%d\n", - __func__, - asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_VIDEO]); - dev_err(isp->dev, - "%s, dis buffers in css: %d\n", - __func__, asd->dis_bufs_in_css); - dev_err(isp->dev, - "%s, metadata buffers in css preview pipe:%d\n", - __func__, - asd->metadata_bufs_in_css - [ATOMISP_INPUT_STREAM_GENERAL] - [IA_CSS_PIPE_ID_PREVIEW]); - dev_err(isp->dev, - "%s, metadata buffers in css capture pipe:%d\n", - __func__, - asd->metadata_bufs_in_css - [ATOMISP_INPUT_STREAM_GENERAL] - [IA_CSS_PIPE_ID_CAPTURE]); - dev_err(isp->dev, - "%s, metadata buffers in css video pipe:%d\n", - __func__, - asd->metadata_bufs_in_css - [ATOMISP_INPUT_STREAM_GENERAL] - [IA_CSS_PIPE_ID_VIDEO]); - if (asd->enable_raw_buffer_lock->val) { - unsigned int j; - - dev_err(isp->dev, "%s, raw_buffer_locked_count %d\n", - __func__, asd->raw_buffer_locked_count); - for (j = 0; j <= ATOMISP_MAX_EXP_ID / 32; j++) - dev_err(isp->dev, "%s, raw_buffer_bitmap[%d]: 0x%x\n", - __func__, j, - asd->raw_buffer_bitmap[j]); - } - } - - /*sh_css_dump_sp_state();*/ - /*sh_css_dump_isp_state();*/ - } else { - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - if (asd->streaming == - ATOMISP_DEVICE_STREAMING_ENABLED) { - atomisp_clear_css_buffer_counters(asd); - atomisp_flush_bufs_and_wakeup(asd); - complete(&asd->init_done); - } - if (IS_ISP2401) - atomisp_wdt_stop(asd, false); - } - - if (!IS_ISP2401) { - atomic_set(&isp->wdt_count, 0); - } else { - isp->isp_fatal_error = true; - atomic_set(&isp->wdt_work_queued, 0); - - rt_mutex_unlock(&isp->mutex); - return; - } - } + assert_recovery_work); + mutex_lock(&isp->mutex); __atomisp_css_recover(isp, true); - if (IS_ISP2401) { - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - continue; - - atomisp_wdt_refresh(asd, - isp->sw_contex.file_input ? - ATOMISP_ISP_FILE_TIMEOUT_DURATION : - ATOMISP_ISP_TIMEOUT_DURATION); - } - } - - dev_err(isp->dev, "timeout recovery handling done\n"); - atomic_set(&isp->wdt_work_queued, 0); - - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); } void atomisp_css_flush(struct atomisp_device *isp) { - int i; - - if (!atomisp_streaming_count(isp)) - return; - - /* Disable wdt */ - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - atomisp_wdt_stop(asd, true); - } - /* Start recover */ __atomisp_css_recover(isp, false); - /* Restore wdt */ - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - if (asd->streaming != - ATOMISP_DEVICE_STREAMING_ENABLED) - continue; - atomisp_wdt_refresh(asd, - isp->sw_contex.file_input ? - ATOMISP_ISP_FILE_TIMEOUT_DURATION : - ATOMISP_ISP_TIMEOUT_DURATION); - } dev_dbg(isp->dev, "atomisp css flush done\n"); } -void atomisp_wdt(struct timer_list *t) -{ - struct atomisp_sub_device *asd; - struct atomisp_device *isp; - - if (!IS_ISP2401) { - asd = from_timer(asd, t, wdt); - isp = asd->isp; - } else { - struct atomisp_video_pipe *pipe = from_timer(pipe, t, wdt); - - asd = pipe->asd; - isp = asd->isp; - - atomic_inc(&pipe->wdt_count); - dev_warn(isp->dev, - "[WARNING]asd %d pipe %s ISP timeout %d!\n", - asd->index, pipe->vdev.name, - atomic_read(&pipe->wdt_count)); - } - - if (atomic_read(&isp->wdt_work_queued)) { - dev_dbg(isp->dev, "ISP watchdog was put into workqueue\n"); - return; - } - atomic_set(&isp->wdt_work_queued, 1); - queue_work(isp->wdt_work_queue, &isp->wdt_work); -} - -/* ISP2400 */ -void atomisp_wdt_start(struct atomisp_sub_device *asd) -{ - atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION); -} - -/* ISP2401 */ -void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe, - unsigned int delay) -{ - unsigned long next; - - if (!pipe->asd) { - dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, pipe->vdev.name); - return; - } - - if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY) - pipe->wdt_duration = delay; - - next = jiffies + pipe->wdt_duration; - - /* Override next if it has been pushed beyon the "next" time */ - if (atomisp_is_wdt_running(pipe) && time_after(pipe->wdt_expires, next)) - next = pipe->wdt_expires; - - pipe->wdt_expires = next; - - if (atomisp_is_wdt_running(pipe)) - dev_dbg(pipe->asd->isp->dev, "WDT will hit after %d ms (%s)\n", - ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name); - else - dev_dbg(pipe->asd->isp->dev, "WDT starts with %d ms period (%s)\n", - ((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name); - - mod_timer(&pipe->wdt, next); -} - -void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay) -{ - if (!IS_ISP2401) { - unsigned long next; - - if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY) - asd->wdt_duration = delay; - - next = jiffies + asd->wdt_duration; - - /* Override next if it has been pushed beyon the "next" time */ - if (atomisp_is_wdt_running(asd) && time_after(asd->wdt_expires, next)) - next = asd->wdt_expires; - - asd->wdt_expires = next; - - if (atomisp_is_wdt_running(asd)) - dev_dbg(asd->isp->dev, "WDT will hit after %d ms\n", - ((int)(next - jiffies) * 1000 / HZ)); - else - dev_dbg(asd->isp->dev, "WDT starts with %d ms period\n", - ((int)(next - jiffies) * 1000 / HZ)); - - mod_timer(&asd->wdt, next); - atomic_set(&asd->isp->wdt_count, 0); - } else { - dev_dbg(asd->isp->dev, "WDT refresh all:\n"); - if (atomisp_is_wdt_running(&asd->video_out_capture)) - atomisp_wdt_refresh_pipe(&asd->video_out_capture, delay); - if (atomisp_is_wdt_running(&asd->video_out_preview)) - atomisp_wdt_refresh_pipe(&asd->video_out_preview, delay); - if (atomisp_is_wdt_running(&asd->video_out_vf)) - atomisp_wdt_refresh_pipe(&asd->video_out_vf, delay); - if (atomisp_is_wdt_running(&asd->video_out_video_capture)) - atomisp_wdt_refresh_pipe(&asd->video_out_video_capture, delay); - } -} - -/* ISP2401 */ -void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync) -{ - if (!pipe->asd) { - dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, pipe->vdev.name); - return; - } - - if (!atomisp_is_wdt_running(pipe)) - return; - - dev_dbg(pipe->asd->isp->dev, - "WDT stop asd %d (%s)\n", pipe->asd->index, pipe->vdev.name); - - if (sync) { - del_timer_sync(&pipe->wdt); - cancel_work_sync(&pipe->asd->isp->wdt_work); - } else { - del_timer(&pipe->wdt); - } -} - -/* ISP 2401 */ -void atomisp_wdt_start_pipe(struct atomisp_video_pipe *pipe) -{ - atomisp_wdt_refresh_pipe(pipe, ATOMISP_ISP_TIMEOUT_DURATION); -} - -void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync) -{ - dev_dbg(asd->isp->dev, "WDT stop:\n"); - - if (!IS_ISP2401) { - if (sync) { - del_timer_sync(&asd->wdt); - cancel_work_sync(&asd->isp->wdt_work); - } else { - del_timer(&asd->wdt); - } - } else { - atomisp_wdt_stop_pipe(&asd->video_out_capture, sync); - atomisp_wdt_stop_pipe(&asd->video_out_preview, sync); - atomisp_wdt_stop_pipe(&asd->video_out_vf, sync); - atomisp_wdt_stop_pipe(&asd->video_out_video_capture, sync); - } -} - void atomisp_setup_flash(struct atomisp_sub_device *asd) { struct atomisp_device *isp = asd->isp; @@ -1884,7 +1508,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) * For CSS2.0: we change the way to not dequeue all the event at one * time, instead, dequue one and process one, then another */ - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); if (atomisp_css_isr_thread(isp, frame_done_found, css_pipe_done)) goto out; @@ -1895,15 +1519,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr) atomisp_setup_flash(asd); } out: - rt_mutex_unlock(&isp->mutex); - for (i = 0; i < isp->num_of_streams; i++) { - asd = &isp->asd[i]; - if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED - && css_pipe_done[asd->index] - && isp->sw_contex.file_input) - v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - video, s_stream, 1); - } + mutex_unlock(&isp->mutex); dev_dbg(isp->dev, "<%s\n", __func__); return IRQ_HANDLED; @@ -2322,7 +1938,6 @@ static void atomisp_update_grid_info(struct atomisp_sub_device *asd, { struct atomisp_device *isp = asd->isp; int err; - u16 stream_id = atomisp_source_pad_to_stream_id(asd, source_pad); if (atomisp_css_get_grid_info(asd, pipe_id, source_pad)) return; @@ -2331,7 +1946,7 @@ static void atomisp_update_grid_info(struct atomisp_sub_device *asd, the grid size. */ atomisp_css_free_stat_buffers(asd); - err = atomisp_alloc_css_stat_bufs(asd, stream_id); + err = atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL); if (err) { dev_err(isp->dev, "stat_buf allocate error\n"); goto err; @@ -4077,6 +3692,8 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe) unsigned long irqflags; bool need_to_enqueue_buffer = false; + lockdep_assert_held(&asd->isp->mutex); + if (!asd) { dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", __func__, pipe->vdev.name); @@ -4143,19 +3760,6 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe) return; atomisp_qbuffers_to_css(asd); - - if (!IS_ISP2401) { - if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd)) - atomisp_wdt_start(asd); - } else { - if (atomisp_buffers_queued_pipe(pipe)) { - if (!atomisp_is_wdt_running(pipe)) - atomisp_wdt_start_pipe(pipe); - else - atomisp_wdt_refresh_pipe(pipe, - ATOMISP_WDT_KEEP_CURRENT_DELAY); - } - } } /* @@ -4170,6 +3774,8 @@ int atomisp_set_parameters(struct video_device *vdev, struct atomisp_css_params *css_param = &asd->params.css_param; int ret; + lockdep_assert_held(&asd->isp->mutex); + if (!asd) { dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", __func__, vdev->name); @@ -4824,8 +4430,6 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, const struct atomisp_format_bridge *fmt; struct atomisp_input_stream_info *stream_info = (struct atomisp_input_stream_info *)snr_mbus_fmt->reserved; - u16 stream_index; - int source_pad = atomisp_subdev_source_pad(vdev); int ret; if (!asd) { @@ -4837,7 +4441,6 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, if (!isp->inputs[asd->input_curr].camera) return -EINVAL; - stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); fmt = atomisp_get_format_bridge(f->pixelformat); if (!fmt) { dev_err(isp->dev, "unsupported pixelformat!\n"); @@ -4851,7 +4454,7 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, snr_mbus_fmt->width = f->width; snr_mbus_fmt->height = f->height; - __atomisp_init_stream_info(stream_index, stream_info); + __atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info); dev_dbg(isp->dev, "try_mbus_fmt: asking for %ux%u\n", snr_mbus_fmt->width, snr_mbus_fmt->height); @@ -4886,8 +4489,8 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, return 0; } - if (snr_mbus_fmt->width < f->width - && snr_mbus_fmt->height < f->height) { + if (!res_overflow || (snr_mbus_fmt->width < f->width && + snr_mbus_fmt->height < f->height)) { f->width = snr_mbus_fmt->width; f->height = snr_mbus_fmt->height; /* Set the flag when resolution requested is @@ -4906,41 +4509,6 @@ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, return 0; } -static int -atomisp_try_fmt_file(struct atomisp_device *isp, struct v4l2_format *f) -{ - u32 width = f->fmt.pix.width; - u32 height = f->fmt.pix.height; - u32 pixelformat = f->fmt.pix.pixelformat; - enum v4l2_field field = f->fmt.pix.field; - u32 depth; - - if (!atomisp_get_format_bridge(pixelformat)) { - dev_err(isp->dev, "Wrong output pixelformat\n"); - return -EINVAL; - } - - depth = atomisp_get_pixel_depth(pixelformat); - - if (field == V4L2_FIELD_ANY) { - field = V4L2_FIELD_NONE; - } else if (field != V4L2_FIELD_NONE) { - dev_err(isp->dev, "Wrong output field\n"); - return -EINVAL; - } - - f->fmt.pix.field = field; - f->fmt.pix.width = clamp_t(u32, - rounddown(width, (u32)ATOM_ISP_STEP_WIDTH), - ATOM_ISP_MIN_WIDTH, ATOM_ISP_MAX_WIDTH); - f->fmt.pix.height = clamp_t(u32, rounddown(height, - (u32)ATOM_ISP_STEP_HEIGHT), - ATOM_ISP_MIN_HEIGHT, ATOM_ISP_MAX_HEIGHT); - f->fmt.pix.bytesperline = (width * depth) >> 3; - - return 0; -} - enum mipi_port_id __get_mipi_port(struct atomisp_device *isp, enum atomisp_camera_port port) { @@ -5171,7 +4739,6 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, int (*configure_pp_input)(struct atomisp_sub_device *asd, unsigned int width, unsigned int height) = configure_pp_input_nop; - u16 stream_index; const struct atomisp_in_fmt_conv *fc; int ret, i; @@ -5180,7 +4747,6 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, __func__, vdev->name); return -EINVAL; } - stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); v4l2_fh_init(&fh.vfh, vdev); @@ -5200,7 +4766,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, dev_err(isp->dev, "mipi_info is NULL\n"); return -EINVAL; } - if (atomisp_set_sensor_mipi_to_isp(asd, stream_index, + if (atomisp_set_sensor_mipi_to_isp(asd, ATOMISP_INPUT_STREAM_GENERAL, mipi_info)) return -EINVAL; fc = atomisp_find_in_fmt_conv_by_atomisp_in_fmt( @@ -5284,7 +4850,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, /* ISP2401 new input system need to use copy pipe */ if (asd->copy_mode) { pipe_id = IA_CSS_PIPE_ID_COPY; - atomisp_css_capture_enable_online(asd, stream_index, false); + atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, false); } else if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { /* video same in continuouscapture and online modes */ configure_output = atomisp_css_video_configure_output; @@ -5316,7 +4882,9 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, pipe_id = IA_CSS_PIPE_ID_CAPTURE; atomisp_update_capture_mode(asd); - atomisp_css_capture_enable_online(asd, stream_index, false); + atomisp_css_capture_enable_online(asd, + ATOMISP_INPUT_STREAM_GENERAL, + false); } } } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) { @@ -5341,7 +4909,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, if (!asd->continuous_mode->val) /* in case of ANR, force capture pipe to offline mode */ - atomisp_css_capture_enable_online(asd, stream_index, + atomisp_css_capture_enable_online(asd, ATOMISP_INPUT_STREAM_GENERAL, asd->params.low_light ? false : asd->params.online_process); @@ -5372,7 +4940,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, pipe_id = IA_CSS_PIPE_ID_YUVPP; if (asd->copy_mode) - ret = atomisp_css_copy_configure_output(asd, stream_index, + ret = atomisp_css_copy_configure_output(asd, ATOMISP_INPUT_STREAM_GENERAL, pix->width, pix->height, format->planar ? pix->bytesperline : pix->bytesperline * 8 / format->depth, @@ -5396,8 +4964,9 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, return -EINVAL; } if (asd->copy_mode) - ret = atomisp_css_copy_get_output_frame_info(asd, stream_index, - output_info); + ret = atomisp_css_copy_get_output_frame_info(asd, + ATOMISP_INPUT_STREAM_GENERAL, + output_info); else ret = get_frame_info(asd, output_info); if (ret) { @@ -5412,8 +4981,7 @@ static int atomisp_set_fmt_to_isp(struct video_device *vdev, ia_css_frame_free(asd->raw_output_frame); asd->raw_output_frame = NULL; - if (!asd->continuous_mode->val && - !asd->params.online_process && !isp->sw_contex.file_input && + if (!asd->continuous_mode->val && !asd->params.online_process && ia_css_frame_allocate_from_info(&asd->raw_output_frame, raw_output_info)) return -ENOMEM; @@ -5462,12 +5030,7 @@ static void atomisp_check_copy_mode(struct atomisp_sub_device *asd, src = atomisp_subdev_get_ffmt(&asd->subdev, NULL, V4L2_SUBDEV_FORMAT_ACTIVE, source_pad); - if ((sink->code == src->code && - sink->width == f->width && - sink->height == f->height) || - ((asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) && - (asd->isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num > 1))) + if (sink->code == src->code && sink->width == f->width && sink->height == f->height) asd->copy_mode = true; else asd->copy_mode = false; @@ -5495,7 +5058,6 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, struct atomisp_device *isp; struct atomisp_input_stream_info *stream_info = (struct atomisp_input_stream_info *)ffmt->reserved; - u16 stream_index = ATOMISP_INPUT_STREAM_GENERAL; int source_pad = atomisp_subdev_source_pad(vdev); struct v4l2_subdev_fh fh; int ret; @@ -5510,8 +5072,6 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, v4l2_fh_init(&fh.vfh, vdev); - stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); - format = atomisp_get_format_bridge(pixelformat); if (!format) return -EINVAL; @@ -5524,7 +5084,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, ffmt->width, ffmt->height, padding_w, padding_h, dvs_env_w, dvs_env_h); - __atomisp_init_stream_info(stream_index, stream_info); + __atomisp_init_stream_info(ATOMISP_INPUT_STREAM_GENERAL, stream_info); req_ffmt = ffmt; @@ -5556,7 +5116,7 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, if (ret) return ret; - __atomisp_update_stream_env(asd, stream_index, stream_info); + __atomisp_update_stream_env(asd, ATOMISP_INPUT_STREAM_GENERAL, stream_info); dev_dbg(isp->dev, "sensor width: %d, height: %d\n", ffmt->width, ffmt->height); @@ -5580,8 +5140,9 @@ static int atomisp_set_fmt_to_snr(struct video_device *vdev, return css_input_resolution_changed(asd, ffmt); } -int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) +int atomisp_set_fmt(struct file *file, void *unused, struct v4l2_format *f) { + struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); struct atomisp_sub_device *asd = pipe->asd; @@ -5604,20 +5165,13 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) struct v4l2_subdev_fh fh; int ret; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } + ret = atomisp_pipe_check(pipe, true); + if (ret) + return ret; if (source_pad >= ATOMISP_SUBDEV_PADS_NUM) return -EINVAL; - if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { - dev_warn(isp->dev, "ISP does not support set format while at streaming!\n"); - return -EBUSY; - } - dev_dbg(isp->dev, "setting resolution %ux%u on pad %u for asd%d, bytesperline %u\n", f->fmt.pix.width, f->fmt.pix.height, source_pad, @@ -5699,58 +5253,7 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) f->fmt.pix.height = r.height; } - if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && - (asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) && - (asd->isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num > 1)) { - /* For M10MO outputing YUV preview images. */ - u16 video_index = - atomisp_source_pad_to_stream_id(asd, - ATOMISP_SUBDEV_PAD_SOURCE_VIDEO); - - ret = atomisp_css_copy_get_output_frame_info(asd, - video_index, &output_info); - if (ret) { - dev_err(isp->dev, - "copy_get_output_frame_info ret %i", ret); - return -EINVAL; - } - if (!asd->yuvpp_mode) { - /* - * If viewfinder was configured into copy_mode, - * we switch to using yuvpp pipe instead. - */ - asd->yuvpp_mode = true; - ret = atomisp_css_copy_configure_output( - asd, video_index, 0, 0, 0, 0); - if (ret) { - dev_err(isp->dev, - "failed to disable copy pipe"); - return -EINVAL; - } - ret = atomisp_css_yuvpp_configure_output( - asd, video_index, - output_info.res.width, - output_info.res.height, - output_info.padded_width, - output_info.format); - if (ret) { - dev_err(isp->dev, - "failed to set up yuvpp pipe\n"); - return -EINVAL; - } - atomisp_css_video_enable_online(asd, false); - atomisp_css_preview_enable_online(asd, - ATOMISP_INPUT_STREAM_GENERAL, false); - } - atomisp_css_yuvpp_configure_viewfinder(asd, video_index, - f->fmt.pix.width, f->fmt.pix.height, - format_bridge->planar ? f->fmt.pix.bytesperline - : f->fmt.pix.bytesperline * 8 - / format_bridge->depth, format_bridge->sh_fmt); - atomisp_css_yuvpp_get_viewfinder_frame_info( - asd, video_index, &output_info); - } else if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) { + if (source_pad == ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW) { atomisp_css_video_configure_viewfinder(asd, f->fmt.pix.width, f->fmt.pix.height, format_bridge->planar ? f->fmt.pix.bytesperline @@ -6078,55 +5581,6 @@ done: return 0; } -int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f) -{ - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - struct atomisp_sub_device *asd = pipe->asd; - struct v4l2_mbus_framefmt ffmt = {0}; - const struct atomisp_format_bridge *format_bridge; - struct v4l2_subdev_fh fh; - int ret; - - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - - v4l2_fh_init(&fh.vfh, vdev); - - dev_dbg(isp->dev, "setting fmt %ux%u 0x%x for file inject\n", - f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat); - ret = atomisp_try_fmt_file(isp, f); - if (ret) { - dev_err(isp->dev, "atomisp_try_fmt_file err: %d\n", ret); - return ret; - } - - format_bridge = atomisp_get_format_bridge(f->fmt.pix.pixelformat); - if (!format_bridge) { - dev_dbg(isp->dev, "atomisp_get_format_bridge err! fmt:0x%x\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - - pipe->pix = f->fmt.pix; - atomisp_css_input_set_mode(asd, IA_CSS_INPUT_MODE_FIFO); - atomisp_css_input_configure_port(asd, - __get_mipi_port(isp, ATOMISP_CAMERA_PORT_PRIMARY), 2, 0xffff4, - 0, 0, 0, 0); - ffmt.width = f->fmt.pix.width; - ffmt.height = f->fmt.pix.height; - ffmt.code = format_bridge->mbus_code; - - atomisp_subdev_set_ffmt(&asd->subdev, fh.state, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK, &ffmt); - - return 0; -} - int atomisp_set_shading_table(struct atomisp_sub_device *asd, struct atomisp_shading_table *user_shading_table) { @@ -6275,6 +5729,8 @@ int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, { struct v4l2_ctrl *c; + lockdep_assert_held(&asd->isp->mutex); + /* * In case of M10MO ZSL capture case, we need to issue a separate * capture request to M10MO which will output captured jpeg image @@ -6379,36 +5835,6 @@ int atomisp_flash_enable(struct atomisp_sub_device *asd, int num_frames) return 0; } -int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd, - uint16_t source_pad) -{ - int stream_id; - struct atomisp_device *isp = asd->isp; - - if (isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num == 1) - return ATOMISP_INPUT_STREAM_GENERAL; - - switch (source_pad) { - case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: - stream_id = ATOMISP_INPUT_STREAM_CAPTURE; - break; - case ATOMISP_SUBDEV_PAD_SOURCE_VF: - stream_id = ATOMISP_INPUT_STREAM_POSTVIEW; - break; - case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW: - stream_id = ATOMISP_INPUT_STREAM_PREVIEW; - break; - case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO: - stream_id = ATOMISP_INPUT_STREAM_VIDEO; - break; - default: - stream_id = ATOMISP_INPUT_STREAM_GENERAL; - } - - return stream_id; -} - bool atomisp_is_vf_pipe(struct atomisp_video_pipe *pipe) { struct atomisp_sub_device *asd = pipe->asd; @@ -6459,7 +5885,7 @@ void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd) spin_unlock_irqrestore(&asd->raw_buffer_bitmap_lock, flags); } -int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) +static int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id) { int *bitmap, bit; unsigned long flags; @@ -6549,6 +5975,8 @@ int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id) int value = *exp_id; int ret; + lockdep_assert_held(&isp->mutex); + ret = __is_raw_buffer_locked(asd, value); if (ret) { dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); @@ -6570,6 +5998,8 @@ int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id) int value = *exp_id; int ret; + lockdep_assert_held(&isp->mutex); + ret = __clear_raw_buffer_bitmap(asd, value); if (ret) { dev_err(isp->dev, "%s exp_id %d invalid %d.\n", __func__, value, ret); @@ -6605,6 +6035,8 @@ int atomisp_inject_a_fake_event(struct atomisp_sub_device *asd, int *event) if (!event || asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) return -EINVAL; + lockdep_assert_held(&asd->isp->mutex); + dev_dbg(asd->isp->dev, "%s: trying to inject a fake event 0x%x\n", __func__, *event); @@ -6675,19 +6107,6 @@ int atomisp_get_invalid_frame_num(struct video_device *vdev, struct ia_css_pipe_info p_info; int ret; - if (!asd) { - dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - - if (asd->isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num > 1) { - /* External ISP */ - *invalid_frame_num = 0; - return 0; - } - pipe_id = atomisp_get_pipe_id(pipe); if (!asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id]) { dev_warn(asd->isp->dev, diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index ebc729468f87..c9f92f1326b6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -54,7 +54,6 @@ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr, unsigned int size); struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd); struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); -struct atomisp_acc_pipe *atomisp_to_acc_pipe(struct video_device *dev); int atomisp_reset(struct atomisp_device *isp); void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd); void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd); @@ -66,8 +65,7 @@ bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe); /* Interrupt functions */ void atomisp_msi_irq_init(struct atomisp_device *isp); void atomisp_msi_irq_uninit(struct atomisp_device *isp); -void atomisp_wdt_work(struct work_struct *work); -void atomisp_wdt(struct timer_list *t); +void atomisp_assert_recovery_work(struct work_struct *work); void atomisp_setup_flash(struct atomisp_sub_device *asd); irqreturn_t atomisp_isr(int irq, void *dev); irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr); @@ -268,8 +266,7 @@ int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, bool *res_overflow); -int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f); -int atomisp_set_fmt_file(struct video_device *vdev, struct v4l2_format *f); +int atomisp_set_fmt(struct file *file, void *fh, struct v4l2_format *f); int atomisp_set_shading_table(struct atomisp_sub_device *asd, struct atomisp_shading_table *shading_table); @@ -300,8 +297,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error, bool q_buffers, enum atomisp_input_stream_id stream_id); void atomisp_css_flush(struct atomisp_device *isp); -int atomisp_source_pad_to_stream_id(struct atomisp_sub_device *asd, - uint16_t source_pad); /* Events. Only one event has to be exported for now. */ void atomisp_eof_event(struct atomisp_sub_device *asd, uint8_t exp_id); @@ -324,8 +319,6 @@ void atomisp_flush_params_queue(struct atomisp_video_pipe *asd); int atomisp_exp_id_unlock(struct atomisp_sub_device *asd, int *exp_id); int atomisp_exp_id_capture(struct atomisp_sub_device *asd, int *exp_id); -/* Function to update Raw Buffer bitmap */ -int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id); void atomisp_init_raw_buffer_bitmap(struct atomisp_sub_device *asd); /* Function to enable/disable zoom for capture pipe */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index 3393ae6824f0..a6d85d0f9ae5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -129,10 +129,6 @@ int atomisp_alloc_metadata_output_buf(struct atomisp_sub_device *asd); void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd); -void atomisp_css_get_dis_statistics(struct atomisp_sub_device *asd, - struct atomisp_css_buffer *isp_css_buffer, - struct ia_css_isp_dvs_statistics_map *dvs_map); - void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd, struct atomisp_css_event *current_event); @@ -434,17 +430,11 @@ void atomisp_css_get_morph_table(struct atomisp_sub_device *asd, void atomisp_css_morph_table_free(struct ia_css_morph_table *table); -void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp, - unsigned int overlap); - int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, struct atomisp_dis_statistics *stats); int atomisp_css_update_stream(struct atomisp_sub_device *asd); -struct atomisp_acc_fw; -int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw); - int atomisp_css_isr_thread(struct atomisp_device *isp, bool *frame_done_found, bool *css_pipe_done); diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index 5aa108a1724c..fdc05548d972 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -1427,7 +1427,6 @@ int atomisp_css_get_grid_info(struct atomisp_sub_device *asd, struct ia_css_pipe_info p_info; struct ia_css_grid_info old_info; struct atomisp_device *isp = asd->isp; - int stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); int md_width = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]. stream_config.metadata_config.resolution.width; @@ -1435,7 +1434,7 @@ int atomisp_css_get_grid_info(struct atomisp_sub_device *asd, memset(&old_info, 0, sizeof(struct ia_css_grid_info)); if (ia_css_pipe_get_info( - asd->stream_env[stream_index].pipes[pipe_id], + asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].pipes[pipe_id], &p_info) != 0) { dev_err(isp->dev, "ia_css_pipe_get_info failed\n"); return -EINVAL; @@ -1574,20 +1573,6 @@ void atomisp_free_metadata_output_buf(struct atomisp_sub_device *asd) } } -void atomisp_css_get_dis_statistics(struct atomisp_sub_device *asd, - struct atomisp_css_buffer *isp_css_buffer, - struct ia_css_isp_dvs_statistics_map *dvs_map) -{ - if (asd->params.dvs_stat) { - if (dvs_map) - ia_css_translate_dvs2_statistics( - asd->params.dvs_stat, dvs_map); - else - ia_css_get_dvs2_statistics(asd->params.dvs_stat, - isp_css_buffer->css_buffer.data.stats_dvs); - } -} - void atomisp_css_temp_pipe_to_pipe_id(struct atomisp_sub_device *asd, struct atomisp_css_event *current_event) { @@ -2694,11 +2679,11 @@ int atomisp_get_css_frame_info(struct atomisp_sub_device *asd, struct atomisp_device *isp = asd->isp; if (ATOMISP_SOC_CAMERA(asd)) { - stream_index = atomisp_source_pad_to_stream_id(asd, source_pad); + stream_index = ATOMISP_INPUT_STREAM_GENERAL; } else { stream_index = (pipe_index == IA_CSS_PIPE_ID_YUVPP) ? ATOMISP_INPUT_STREAM_VIDEO : - atomisp_source_pad_to_stream_id(asd, source_pad); + ATOMISP_INPUT_STREAM_GENERAL; } if (0 != ia_css_pipe_get_info(asd->stream_env[stream_index] @@ -3626,6 +3611,8 @@ int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, struct atomisp_dis_buf *dis_buf; unsigned long flags; + lockdep_assert_held(&isp->mutex); + if (!asd->params.dvs_stat->hor_prod.odd_real || !asd->params.dvs_stat->hor_prod.odd_imag || !asd->params.dvs_stat->hor_prod.even_real || @@ -3637,12 +3624,8 @@ int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd, return -EINVAL; /* isp needs to be streaming to get DIS statistics */ - spin_lock_irqsave(&isp->lock, flags); - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) { - spin_unlock_irqrestore(&isp->lock, flags); + if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) return -EINVAL; - } - spin_unlock_irqrestore(&isp->lock, flags); if (atomisp_compare_dvs_grid(asd, &stats->dvs2_stat.grid_info) != 0) /* If the grid info in the argument differs from the current @@ -3763,32 +3746,6 @@ void atomisp_css_morph_table_free(struct ia_css_morph_table *table) ia_css_morph_table_free(table); } -void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp, - unsigned int overlap) -{ - /* CSS 2.0 doesn't support this API. */ - dev_dbg(isp->dev, "set cont prev start time is not supported.\n"); - return; -} - -/* Set the ACC binary arguments */ -int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw) -{ - unsigned int mem; - - for (mem = 0; mem < ATOMISP_ACC_NR_MEMORY; mem++) { - if (acc_fw->args[mem].length == 0) - continue; - - ia_css_isp_param_set_css_mem_init(&acc_fw->fw->mem_initializers, - IA_CSS_PARAM_CLASS_PARAM, mem, - acc_fw->args[mem].css_ptr, - acc_fw->args[mem].length); - } - - return 0; -} - static struct atomisp_sub_device *__get_atomisp_subdev( struct ia_css_pipe *css_pipe, struct atomisp_device *isp, @@ -3824,8 +3781,8 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, enum atomisp_input_stream_id stream_id = 0; struct atomisp_css_event current_event; struct atomisp_sub_device *asd; - bool reset_wdt_timer[MAX_STREAM_NUM] = {false}; - int i; + + lockdep_assert_held(&isp->mutex); while (!ia_css_dequeue_psys_event(¤t_event.event)) { if (current_event.event.type == @@ -3839,14 +3796,8 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, __func__, current_event.event.fw_assert_module_id, current_event.event.fw_assert_line_no); - for (i = 0; i < isp->num_of_streams; i++) - atomisp_wdt_stop(&isp->asd[i], 0); - - if (!IS_ISP2401) - atomisp_wdt(&isp->asd[0].wdt); - else - queue_work(isp->wdt_work_queue, &isp->wdt_work); + queue_work(system_long_wq, &isp->assert_recovery_work); return -EINVAL; } else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) { dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n", @@ -3875,20 +3826,12 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, frame_done_found[asd->index] = true; atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, current_event.pipe, true, stream_id); - - if (!IS_ISP2401) - reset_wdt_timer[asd->index] = true; /* ISP running */ - break; case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE: dev_dbg(isp->dev, "event: Second output frame done"); frame_done_found[asd->index] = true; atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME, current_event.pipe, true, stream_id); - - if (!IS_ISP2401) - reset_wdt_timer[asd->index] = true; /* ISP running */ - break; case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE: dev_dbg(isp->dev, "event: 3A stats frame done"); @@ -3909,19 +3852,12 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME, current_event.pipe, true, stream_id); - - if (!IS_ISP2401) - reset_wdt_timer[asd->index] = true; /* ISP running */ - break; case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE: dev_dbg(isp->dev, "event: second VF output frame done"); atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME, current_event.pipe, true, stream_id); - if (!IS_ISP2401) - reset_wdt_timer[asd->index] = true; /* ISP running */ - break; case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE: dev_dbg(isp->dev, "event: dis stats frame done"); @@ -3944,24 +3880,6 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, } } - if (IS_ISP2401) - return 0; - - /* ISP2400: If there are no buffers queued then delete wdt timer. */ - for (i = 0; i < isp->num_of_streams; i++) { - asd = &isp->asd[i]; - if (!asd) - continue; - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - continue; - if (!atomisp_buffers_queued(asd)) - atomisp_wdt_stop(asd, false); - else if (reset_wdt_timer[i]) - /* SOF irq should not reset wdt timer. */ - atomisp_wdt_refresh(asd, - ATOMISP_WDT_KEEP_CURRENT_DELAY); - } - return 0; } diff --git a/drivers/staging/media/atomisp/pci/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp_file.c deleted file mode 100644 index 4570a9ab100b..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_file.c +++ /dev/null @@ -1,229 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#include <media/v4l2-event.h> -#include <media/v4l2-mediabus.h> - -#include <media/videobuf-vmalloc.h> -#include <linux/delay.h> - -#include "ia_css.h" - -#include "atomisp_cmd.h" -#include "atomisp_common.h" -#include "atomisp_file.h" -#include "atomisp_internal.h" -#include "atomisp_ioctl.h" - -static void file_work(struct work_struct *work) -{ - struct atomisp_file_device *file_dev = - container_of(work, struct atomisp_file_device, work); - struct atomisp_device *isp = file_dev->isp; - /* only support file injection on subdev0 */ - struct atomisp_sub_device *asd = &isp->asd[0]; - struct atomisp_video_pipe *out_pipe = &asd->video_in; - unsigned short *buf = videobuf_to_vmalloc(out_pipe->outq.bufs[0]); - struct v4l2_mbus_framefmt isp_sink_fmt; - - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - return; - - dev_dbg(isp->dev, ">%s: ready to start streaming\n", __func__); - isp_sink_fmt = *atomisp_subdev_get_ffmt(&asd->subdev, NULL, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK); - - while (!ia_css_isp_has_started()) - usleep_range(1000, 1500); - - ia_css_stream_send_input_frame(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].stream, - buf, isp_sink_fmt.width, - isp_sink_fmt.height); - dev_dbg(isp->dev, "<%s: streaming done\n", __func__); -} - -static int file_input_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); - struct atomisp_device *isp = file_dev->isp; - /* only support file injection on subdev0 */ - struct atomisp_sub_device *asd = &isp->asd[0]; - - dev_dbg(isp->dev, "%s: enable %d\n", __func__, enable); - if (enable) { - if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED) - return 0; - - queue_work(file_dev->work_queue, &file_dev->work); - return 0; - } - cancel_work_sync(&file_dev->work); - return 0; -} - -static int file_input_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd); - struct atomisp_device *isp = file_dev->isp; - /* only support file injection on subdev0 */ - struct atomisp_sub_device *asd = &isp->asd[0]; - struct v4l2_mbus_framefmt *isp_sink_fmt; - - if (format->pad) - return -EINVAL; - isp_sink_fmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK); - - fmt->width = isp_sink_fmt->width; - fmt->height = isp_sink_fmt->height; - fmt->code = isp_sink_fmt->code; - - return 0; -} - -static int file_input_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - - if (format->pad) - return -EINVAL; - file_input_get_fmt(sd, sd_state, format); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - sd_state->pads->try_fmt = *fmt; - return 0; -} - -static int file_input_log_status(struct v4l2_subdev *sd) -{ - /*to fake*/ - return 0; -} - -static int file_input_s_power(struct v4l2_subdev *sd, int on) -{ - /* to fake */ - return 0; -} - -static int file_input_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - /*to fake*/ - return 0; -} - -static int file_input_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_size_enum *fse) -{ - /*to fake*/ - return 0; -} - -static int file_input_enum_frame_ival(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval_enum - *fie) -{ - /*to fake*/ - return 0; -} - -static const struct v4l2_subdev_video_ops file_input_video_ops = { - .s_stream = file_input_s_stream, -}; - -static const struct v4l2_subdev_core_ops file_input_core_ops = { - .log_status = file_input_log_status, - .s_power = file_input_s_power, -}; - -static const struct v4l2_subdev_pad_ops file_input_pad_ops = { - .enum_mbus_code = file_input_enum_mbus_code, - .enum_frame_size = file_input_enum_frame_size, - .enum_frame_interval = file_input_enum_frame_ival, - .get_fmt = file_input_get_fmt, - .set_fmt = file_input_set_fmt, -}; - -static const struct v4l2_subdev_ops file_input_ops = { - .core = &file_input_core_ops, - .video = &file_input_video_ops, - .pad = &file_input_pad_ops, -}; - -void -atomisp_file_input_unregister_entities(struct atomisp_file_device *file_dev) -{ - media_entity_cleanup(&file_dev->sd.entity); - v4l2_device_unregister_subdev(&file_dev->sd); -} - -int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev, - struct v4l2_device *vdev) -{ - /* Register the subdev and video nodes. */ - return v4l2_device_register_subdev(vdev, &file_dev->sd); -} - -void atomisp_file_input_cleanup(struct atomisp_device *isp) -{ - struct atomisp_file_device *file_dev = &isp->file_dev; - - if (file_dev->work_queue) { - destroy_workqueue(file_dev->work_queue); - file_dev->work_queue = NULL; - } -} - -int atomisp_file_input_init(struct atomisp_device *isp) -{ - struct atomisp_file_device *file_dev = &isp->file_dev; - struct v4l2_subdev *sd = &file_dev->sd; - struct media_pad *pads = file_dev->pads; - struct media_entity *me = &sd->entity; - - file_dev->isp = isp; - file_dev->work_queue = alloc_workqueue(isp->v4l2_dev.name, 0, 1); - if (!file_dev->work_queue) { - dev_err(isp->dev, "Failed to initialize file inject workq\n"); - return -ENOMEM; - } - - INIT_WORK(&file_dev->work, file_work); - - v4l2_subdev_init(sd, &file_input_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - strscpy(sd->name, "file_input_subdev", sizeof(sd->name)); - v4l2_set_subdevdata(sd, file_dev); - - pads[0].flags = MEDIA_PAD_FL_SINK; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; - - return media_entity_pads_init(me, 1, pads); -} diff --git a/drivers/staging/media/atomisp/pci/atomisp_file.h b/drivers/staging/media/atomisp/pci/atomisp_file.h deleted file mode 100644 index f166a2aefff1..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp_file.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support for Medifield PNW Camera Imaging ISP subsystem. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * Copyright (c) 2010 Silicon Hive www.siliconhive.com. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -#ifndef __ATOMISP_FILE_H__ -#define __ATOMISP_FILE_H__ - -#include <media/media-entity.h> -#include <media/v4l2-subdev.h> - -struct atomisp_device; - -struct atomisp_file_device { - struct v4l2_subdev sd; - struct atomisp_device *isp; - struct media_pad pads[1]; - - struct workqueue_struct *work_queue; - struct work_struct work; -}; - -void atomisp_file_input_cleanup(struct atomisp_device *isp); -int atomisp_file_input_init(struct atomisp_device *isp); -void atomisp_file_input_unregister_entities( - struct atomisp_file_device *file_dev); -int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev, - struct v4l2_device *vdev); -#endif /* __ATOMISP_FILE_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index 77150e4ae144..84a84e0cdeef 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -369,45 +369,6 @@ static int atomisp_get_css_buf_type(struct atomisp_sub_device *asd, return IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME; } -static int atomisp_qbuffers_to_css_for_all_pipes(struct atomisp_sub_device *asd) -{ - enum ia_css_buffer_type buf_type; - enum ia_css_pipe_id css_capture_pipe_id = IA_CSS_PIPE_ID_COPY; - enum ia_css_pipe_id css_preview_pipe_id = IA_CSS_PIPE_ID_COPY; - enum ia_css_pipe_id css_video_pipe_id = IA_CSS_PIPE_ID_COPY; - enum atomisp_input_stream_id input_stream_id; - struct atomisp_video_pipe *capture_pipe; - struct atomisp_video_pipe *preview_pipe; - struct atomisp_video_pipe *video_pipe; - - capture_pipe = &asd->video_out_capture; - preview_pipe = &asd->video_out_preview; - video_pipe = &asd->video_out_video_capture; - - buf_type = atomisp_get_css_buf_type( - asd, css_preview_pipe_id, - atomisp_subdev_source_pad(&preview_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_PREVIEW; - atomisp_q_video_buffers_to_css(asd, preview_pipe, - input_stream_id, - buf_type, css_preview_pipe_id); - - buf_type = atomisp_get_css_buf_type(asd, css_capture_pipe_id, - atomisp_subdev_source_pad(&capture_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_GENERAL; - atomisp_q_video_buffers_to_css(asd, capture_pipe, - input_stream_id, - buf_type, css_capture_pipe_id); - - buf_type = atomisp_get_css_buf_type(asd, css_video_pipe_id, - atomisp_subdev_source_pad(&video_pipe->vdev)); - input_stream_id = ATOMISP_INPUT_STREAM_VIDEO; - atomisp_q_video_buffers_to_css(asd, video_pipe, - input_stream_id, - buf_type, css_video_pipe_id); - return 0; -} - /* queue all available buffers to css */ int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd) { @@ -423,11 +384,6 @@ int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd) bool raw_mode = atomisp_is_mbuscode_raw( asd->fmt[asd->capture_pad].fmt.code); - if (asd->isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num == 2 && - !asd->yuvpp_mode) - return atomisp_qbuffers_to_css_for_all_pipes(asd); - if (asd->vfpp->val == ATOMISP_VFPP_DISABLE_SCALER) { video_pipe = &asd->video_out_video_capture; css_video_pipe_id = IA_CSS_PIPE_ID_VIDEO; @@ -593,47 +549,6 @@ static void atomisp_buf_release(struct videobuf_queue *vq, atomisp_videobuf_free_buf(vb); } -static int atomisp_buf_setup_output(struct videobuf_queue *vq, - unsigned int *count, unsigned int *size) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - *size = pipe->pix.sizeimage; - - return 0; -} - -static int atomisp_buf_prepare_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - vb->size = pipe->pix.sizeimage; - vb->width = pipe->pix.width; - vb->height = pipe->pix.height; - vb->field = field; - vb->state = VIDEOBUF_PREPARED; - - return 0; -} - -static void atomisp_buf_queue_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct atomisp_video_pipe *pipe = vq->priv_data; - - list_add_tail(&vb->queue, &pipe->activeq_out); - vb->state = VIDEOBUF_QUEUED; -} - -static void atomisp_buf_release_output(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - videobuf_vmalloc_free(vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - static const struct videobuf_queue_ops videobuf_qops = { .buf_setup = atomisp_buf_setup, .buf_prepare = atomisp_buf_prepare, @@ -641,13 +556,6 @@ static const struct videobuf_queue_ops videobuf_qops = { .buf_release = atomisp_buf_release, }; -static const struct videobuf_queue_ops videobuf_qops_output = { - .buf_setup = atomisp_buf_setup_output, - .buf_prepare = atomisp_buf_prepare_output, - .buf_queue = atomisp_buf_queue_output, - .buf_release = atomisp_buf_release_output, -}; - static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) { /* init locks */ @@ -660,15 +568,7 @@ static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) sizeof(struct atomisp_buffer), pipe, NULL); /* ext_lock: NULL */ - videobuf_queue_vmalloc_init(&pipe->outq, &videobuf_qops_output, NULL, - &pipe->irq_lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct atomisp_buffer), pipe, - NULL); /* ext_lock: NULL */ - INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->activeq_out); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->per_frame_params); memset(pipe->frame_request_config_id, 0, @@ -684,7 +584,6 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp) { unsigned int i; - isp->sw_contex.file_input = false; isp->need_gfx_throttle = true; isp->isp_fatal_error = false; isp->mipi_frame_size = 0; @@ -741,9 +640,7 @@ static unsigned int atomisp_subdev_users(struct atomisp_sub_device *asd) return asd->video_out_preview.users + asd->video_out_vf.users + asd->video_out_capture.users + - asd->video_out_video_capture.users + - asd->video_acc.users + - asd->video_in.users; + asd->video_out_video_capture.users; } unsigned int atomisp_dev_users(struct atomisp_device *isp) @@ -760,48 +657,18 @@ static int atomisp_open(struct file *file) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = NULL; - struct atomisp_acc_pipe *acc_pipe = NULL; - struct atomisp_sub_device *asd; - bool acc_node = false; + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_sub_device *asd = pipe->asd; int ret; dev_dbg(isp->dev, "open device %s\n", vdev->name); - /* - * Ensure that if we are still loading we block. Once the loading - * is over we can proceed. We can't blindly hold the lock until - * that occurs as if the load fails we'll deadlock the unload - */ - rt_mutex_lock(&isp->loading); - /* - * FIXME: revisit this with a better check once the code structure - * is cleaned up a bit more - */ ret = v4l2_fh_open(file); - if (ret) { - dev_err(isp->dev, - "%s: v4l2_fh_open() returned error %d\n", - __func__, ret); - rt_mutex_unlock(&isp->loading); + if (ret) return ret; - } - if (!isp->ready) { - rt_mutex_unlock(&isp->loading); - return -ENXIO; - } - rt_mutex_unlock(&isp->loading); - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); - acc_node = !strcmp(vdev->name, "ATOMISP ISP ACC"); - if (acc_node) { - acc_pipe = atomisp_to_acc_pipe(vdev); - asd = acc_pipe->asd; - } else { - pipe = atomisp_to_video_pipe(vdev); - asd = pipe->asd; - } asd->subdev.devnode = vdev; /* Deferred firmware loading case. */ if (isp->css_env.isp_css_fw.bytes == 0) { @@ -823,14 +690,6 @@ static int atomisp_open(struct file *file) isp->css_env.isp_css_fw.data = NULL; } - if (acc_node && acc_pipe->users) { - dev_dbg(isp->dev, "acc node already opened\n"); - rt_mutex_unlock(&isp->mutex); - return -EBUSY; - } else if (acc_node) { - goto dev_init; - } - if (!isp->input_cnt) { dev_err(isp->dev, "no camera attached\n"); ret = -EINVAL; @@ -842,7 +701,7 @@ static int atomisp_open(struct file *file) */ if (pipe->users) { dev_dbg(isp->dev, "video node already opened\n"); - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return -EBUSY; } @@ -850,7 +709,6 @@ static int atomisp_open(struct file *file) if (ret) goto error; -dev_init: if (atomisp_dev_users(isp)) { dev_dbg(isp->dev, "skip init isp in open\n"); goto init_subdev; @@ -885,16 +743,11 @@ init_subdev: atomisp_subdev_init_struct(asd); done: - - if (acc_node) - acc_pipe->users++; - else - pipe->users++; - rt_mutex_unlock(&isp->mutex); + pipe->users++; + mutex_unlock(&isp->mutex); /* Ensure that a mode is set */ - if (!acc_node) - v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); + v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); return 0; @@ -902,7 +755,8 @@ css_error: atomisp_css_uninit(isp); pm_runtime_put(vdev->v4l2_dev->dev); error: - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); + v4l2_fh_release(file); return ret; } @@ -910,13 +764,12 @@ static int atomisp_release(struct file *file) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe; - struct atomisp_acc_pipe *acc_pipe; - struct atomisp_sub_device *asd; - bool acc_node; + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_sub_device *asd = pipe->asd; struct v4l2_requestbuffers req; struct v4l2_subdev_fh fh; struct v4l2_rect clear_compose = {0}; + unsigned long flags; int ret = 0; v4l2_fh_init(&fh.vfh, vdev); @@ -925,23 +778,12 @@ static int atomisp_release(struct file *file) if (!isp) return -EBADF; - mutex_lock(&isp->streamoff_mutex); - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); dev_dbg(isp->dev, "release device %s\n", vdev->name); - acc_node = !strcmp(vdev->name, "ATOMISP ISP ACC"); - if (acc_node) { - acc_pipe = atomisp_to_acc_pipe(vdev); - asd = acc_pipe->asd; - } else { - pipe = atomisp_to_video_pipe(vdev); - asd = pipe->asd; - } + asd->subdev.devnode = vdev; - if (acc_node) { - acc_pipe->users--; - goto subdev_uninit; - } + pipe->users--; if (pipe->capq.streaming) @@ -950,27 +792,19 @@ static int atomisp_release(struct file *file) __func__); if (pipe->capq.streaming && - __atomisp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE)) { - dev_err(isp->dev, - "atomisp_streamoff failed on release, driver bug"); + atomisp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE)) { + dev_err(isp->dev, "atomisp_streamoff failed on release, driver bug"); goto done; } if (pipe->users) goto done; - if (__atomisp_reqbufs(file, NULL, &req)) { - dev_err(isp->dev, - "atomisp_reqbufs failed on release, driver bug"); + if (atomisp_reqbufs(file, NULL, &req)) { + dev_err(isp->dev, "atomisp_reqbufs failed on release, driver bug"); goto done; } - if (pipe->outq.bufs[0]) { - mutex_lock(&pipe->outq.vb_lock); - videobuf_queue_cancel(&pipe->outq); - mutex_unlock(&pipe->outq.vb_lock); - } - /* * A little trick here: * file injection input resolution is recorded in the sink pad, @@ -978,26 +812,17 @@ static int atomisp_release(struct file *file) * The sink pad setting can only be cleared when all device nodes * get released. */ - if (!isp->sw_contex.file_input && asd->fmt_auto->val) { + if (asd->fmt_auto->val) { struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; atomisp_subdev_set_ffmt(&asd->subdev, fh.state, V4L2_SUBDEV_FORMAT_ACTIVE, ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); } -subdev_uninit: + if (atomisp_subdev_users(asd)) goto done; - /* clear the sink pad for file input */ - if (isp->sw_contex.file_input && asd->fmt_auto->val) { - struct v4l2_mbus_framefmt isp_sink_fmt = { 0 }; - - atomisp_subdev_set_ffmt(&asd->subdev, fh.state, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK, &isp_sink_fmt); - } - atomisp_css_free_stat_buffers(asd); atomisp_free_internal_buffers(asd); ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, @@ -1007,7 +832,9 @@ subdev_uninit: /* clear the asd field to show this camera is not used */ isp->inputs[asd->input_curr].asd = NULL; + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; + spin_unlock_irqrestore(&isp->lock, flags); if (atomisp_dev_users(isp)) goto done; @@ -1029,15 +856,12 @@ subdev_uninit: dev_err(isp->dev, "Failed to power off device\n"); done: - if (!acc_node) { - atomisp_subdev_set_selection(&asd->subdev, fh.state, - V4L2_SUBDEV_FORMAT_ACTIVE, - atomisp_subdev_source_pad(vdev), - V4L2_SEL_TGT_COMPOSE, 0, - &clear_compose); - } - rt_mutex_unlock(&isp->mutex); - mutex_unlock(&isp->streamoff_mutex); + atomisp_subdev_set_selection(&asd->subdev, fh.state, + V4L2_SUBDEV_FORMAT_ACTIVE, + atomisp_subdev_source_pad(vdev), + V4L2_SEL_TGT_COMPOSE, 0, + &clear_compose); + mutex_unlock(&isp->mutex); return v4l2_fh_release(file); } @@ -1194,7 +1018,7 @@ static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & (VM_WRITE | VM_READ))) return -EACCES; - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); if (!(vma->vm_flags & VM_SHARED)) { /* Map private buffer. @@ -1205,7 +1029,7 @@ static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) */ vma->vm_flags |= VM_SHARED; ret = hmm_mmap(vma, vma->vm_pgoff << PAGE_SHIFT); - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return ret; } @@ -1248,7 +1072,7 @@ static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) } raw_virt_addr->data_bytes = origin_size; vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return 0; } @@ -1260,24 +1084,16 @@ static int atomisp_mmap(struct file *file, struct vm_area_struct *vma) ret = -EINVAL; goto error; } - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return atomisp_videobuf_mmap_mapper(&pipe->capq, vma); error: - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return ret; } -static int atomisp_file_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - return videobuf_mmap_mapper(&pipe->outq, vma); -} - static __poll_t atomisp_poll(struct file *file, struct poll_table_struct *pt) { @@ -1285,12 +1101,12 @@ static __poll_t atomisp_poll(struct file *file, struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); if (pipe->capq.streaming != 1) { - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return EPOLLERR; } - rt_mutex_unlock(&isp->mutex); + mutex_unlock(&isp->mutex); return videobuf_poll_stream(file, &pipe->capq, pt); } @@ -1310,15 +1126,3 @@ const struct v4l2_file_operations atomisp_fops = { #endif .poll = atomisp_poll, }; - -const struct v4l2_file_operations atomisp_file_fops = { - .owner = THIS_MODULE, - .open = atomisp_open, - .release = atomisp_release, - .mmap = atomisp_file_mmap, - .unlocked_ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - /* .compat_ioctl32 = atomisp_compat_ioctl32, */ -#endif - .poll = atomisp_poll, -}; diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index bf527b366ab3..3d41fab661cf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -134,24 +134,6 @@ static DEFINE_MUTEX(vcm_lock); static struct gmin_subdev *find_gmin_subdev(struct v4l2_subdev *subdev); -/* - * Legacy/stub behavior copied from upstream platform_camera.c. The - * atomisp driver relies on these values being non-NULL in a few - * places, even though they are hard-coded in all current - * implementations. - */ -const struct atomisp_camera_caps *atomisp_get_default_camera_caps(void) -{ - static const struct atomisp_camera_caps caps = { - .sensor_num = 1, - .sensor = { - { .stream_num = 1, }, - }, - }; - return ∩︀ -} -EXPORT_SYMBOL_GPL(atomisp_get_default_camera_caps); - const struct atomisp_platform_data *atomisp_get_platform_data(void) { return &pdata; @@ -1066,6 +1048,38 @@ static int gmin_flisclk_ctrl(struct v4l2_subdev *subdev, int on) return ret; } +static int camera_sensor_csi_alloc(struct v4l2_subdev *sd, u32 port, u32 lanes, + u32 format, u32 bayer_order) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *csi; + + csi = kzalloc(sizeof(*csi), GFP_KERNEL); + if (!csi) + return -ENOMEM; + + csi->port = port; + csi->num_lanes = lanes; + csi->input_format = format; + csi->raw_bayer_order = bayer_order; + v4l2_set_subdev_hostdata(sd, csi); + csi->metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED; + csi->metadata_effective_width = NULL; + dev_info(&client->dev, + "camera pdata: port: %d lanes: %d order: %8.8x\n", + port, lanes, bayer_order); + + return 0; +} + +static void camera_sensor_csi_free(struct v4l2_subdev *sd) +{ + struct camera_mipi_info *csi; + + csi = v4l2_get_subdev_hostdata(sd); + kfree(csi); +} + static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1074,8 +1088,11 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) if (!client || !gs) return -ENODEV; - return camera_sensor_csi(sd, gs->csi_port, gs->csi_lanes, - gs->csi_fmt, gs->csi_bayer, flag); + if (flag) + return camera_sensor_csi_alloc(sd, gs->csi_port, gs->csi_lanes, + gs->csi_fmt, gs->csi_bayer); + camera_sensor_csi_free(sd); + return 0; } static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev, @@ -1207,16 +1224,14 @@ static int gmin_get_config_dsm_var(struct device *dev, if (!strcmp(var, "CamClk")) return -EINVAL; - obj = acpi_evaluate_dsm(handle, &atomisp_dsm_guid, 0, 0, NULL); + /* Return on unexpected object type */ + obj = acpi_evaluate_dsm_typed(handle, &atomisp_dsm_guid, 0, 0, NULL, + ACPI_TYPE_PACKAGE); if (!obj) { dev_info_once(dev, "Didn't find ACPI _DSM table.\n"); return -EINVAL; } - /* Return on unexpected object type */ - if (obj->type != ACPI_TYPE_PACKAGE) - return -EINVAL; - #if 0 /* Just for debugging purposes */ for (i = 0; i < obj->package.count; i++) { union acpi_object *cur = &obj->package.elements[i]; @@ -1360,35 +1375,6 @@ int gmin_get_var_int(struct device *dev, bool is_gmin, const char *var, int def) } EXPORT_SYMBOL_GPL(gmin_get_var_int); -int camera_sensor_csi(struct v4l2_subdev *sd, u32 port, - u32 lanes, u32 format, u32 bayer_order, int flag) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *csi = NULL; - - if (flag) { - csi = kzalloc(sizeof(*csi), GFP_KERNEL); - if (!csi) - return -ENOMEM; - csi->port = port; - csi->num_lanes = lanes; - csi->input_format = format; - csi->raw_bayer_order = bayer_order; - v4l2_set_subdev_hostdata(sd, (void *)csi); - csi->metadata_format = ATOMISP_INPUT_FORMAT_EMBEDDED; - csi->metadata_effective_width = NULL; - dev_info(&client->dev, - "camera pdata: port: %d lanes: %d order: %8.8x\n", - port, lanes, bayer_order); - } else { - csi = v4l2_get_subdev_hostdata(sd); - kfree(csi); - } - - return 0; -} -EXPORT_SYMBOL_GPL(camera_sensor_csi); - /* PCI quirk: The BYT ISP advertises PCI runtime PM but it doesn't * work. Disable so the kernel framework doesn't hang the device * trying. The driver itself does direct calls to the PUNIT to manage diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index f71ab1ee6e19..d9d158cdf09e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -34,7 +34,6 @@ #include "sh_css_legacy.h" #include "atomisp_csi2.h" -#include "atomisp_file.h" #include "atomisp_subdev.h" #include "atomisp_tpg.h" #include "atomisp_compat.h" @@ -86,13 +85,12 @@ #define ATOM_ISP_POWER_DOWN 0 #define ATOM_ISP_POWER_UP 1 -#define ATOM_ISP_MAX_INPUTS 4 +#define ATOM_ISP_MAX_INPUTS 3 #define ATOMISP_SC_TYPE_SIZE 2 #define ATOMISP_ISP_TIMEOUT_DURATION (2 * HZ) #define ATOMISP_EXT_ISP_TIMEOUT_DURATION (6 * HZ) -#define ATOMISP_ISP_FILE_TIMEOUT_DURATION (60 * HZ) #define ATOMISP_WDT_KEEP_CURRENT_DELAY 0 #define ATOMISP_ISP_MAX_TIMEOUT_COUNT 2 #define ATOMISP_CSS_STOP_TIMEOUT_US 200000 @@ -107,9 +105,6 @@ #define ATOMISP_DELAYED_INIT_QUEUED 1 #define ATOMISP_DELAYED_INIT_DONE 2 -#define ATOMISP_CALC_CSS_PREV_OVERLAP(lines) \ - ((lines) * 38 / 100 & 0xfffffe) - /* * Define how fast CPU should be able to serve ISP interrupts. * The bigger the value, the higher risk that the ISP is not @@ -132,9 +127,7 @@ * Moorefield/Baytrail platform. */ #define ATOMISP_SOC_CAMERA(asd) \ - (asd->isp->inputs[asd->input_curr].type == SOC_CAMERA \ - && asd->isp->inputs[asd->input_curr].camera_caps-> \ - sensor[asd->sensor_curr].stream_num == 1) + (asd->isp->inputs[asd->input_curr].type == SOC_CAMERA) #define ATOMISP_USE_YUVPP(asd) \ (ATOMISP_SOC_CAMERA(asd) && ATOMISP_CSS_SUPPORT_YUVPP && \ @@ -167,7 +160,6 @@ struct atomisp_input_subdev { */ struct atomisp_sub_device *asd; - const struct atomisp_camera_caps *camera_caps; int sensor_index; }; @@ -203,7 +195,6 @@ struct atomisp_regs { }; struct atomisp_sw_contex { - bool file_input; int power_state; int running_freq; }; @@ -241,24 +232,10 @@ struct atomisp_device { struct atomisp_mipi_csi2_device csi2_port[ATOMISP_CAMERA_NR_PORTS]; struct atomisp_tpg_device tpg; - struct atomisp_file_device file_dev; /* Purpose of mutex is to protect and serialize use of isp data * structures and css API calls. */ - struct rt_mutex mutex; - /* - * This mutex ensures that we don't allow an open to succeed while - * the initialization process is incomplete - */ - struct rt_mutex loading; - /* Set once the ISP is ready to allow opens */ - bool ready; - /* - * Serialise streamoff: mutex is dropped during streamoff to - * cancel the watchdog queue. MUST be acquired BEFORE - * "mutex". - */ - struct mutex streamoff_mutex; + struct mutex mutex; unsigned int input_cnt; struct atomisp_input_subdev inputs[ATOM_ISP_MAX_INPUTS]; @@ -272,15 +249,9 @@ struct atomisp_device { /* isp timeout status flag */ bool isp_timeout; bool isp_fatal_error; - struct workqueue_struct *wdt_work_queue; - struct work_struct wdt_work; - - /* ISP2400 */ - atomic_t wdt_count; - - atomic_t wdt_work_queued; + struct work_struct assert_recovery_work; - spinlock_t lock; /* Just for streaming below */ + spinlock_t lock; /* Protects asd[i].streaming */ bool need_gfx_throttle; @@ -296,20 +267,4 @@ struct atomisp_device { extern struct device *atomisp_dev; -#define atomisp_is_wdt_running(a) timer_pending(&(a)->wdt) - -/* ISP2401 */ -void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe, - unsigned int delay); -void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay); - -/* ISP2400 */ -void atomisp_wdt_start(struct atomisp_sub_device *asd); - -/* ISP2401 */ -void atomisp_wdt_start_pipe(struct atomisp_video_pipe *pipe); -void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync); - -void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync); - #endif /* __ATOMISP_INTERNAL_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index 459645c2e2a7..0ddb0ed42dd9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -535,6 +535,32 @@ atomisp_get_format_bridge_from_mbus(u32 mbus_code) return NULL; } +int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool settings_change) +{ + lockdep_assert_held(&pipe->isp->mutex); + + if (pipe->isp->isp_fatal_error) + return -EIO; + + switch (pipe->asd->streaming) { + case ATOMISP_DEVICE_STREAMING_DISABLED: + break; + case ATOMISP_DEVICE_STREAMING_ENABLED: + if (settings_change) { + dev_err(pipe->isp->dev, "Set fmt/input IOCTL while streaming\n"); + return -EBUSY; + } + break; + case ATOMISP_DEVICE_STREAMING_STOPPING: + dev_err(pipe->isp->dev, "IOCTL issued while stopping\n"); + return -EBUSY; + default: + return -EINVAL; + } + + return 0; +} + /* * v4l2 ioctls * return ISP capabilities @@ -609,8 +635,7 @@ atomisp_subdev_streaming_count(struct atomisp_sub_device *asd) return asd->video_out_preview.capq.streaming + asd->video_out_capture.capq.streaming + asd->video_out_video_capture.capq.streaming - + asd->video_out_vf.capq.streaming - + asd->video_in.capq.streaming; + + asd->video_out_vf.capq.streaming; } unsigned int atomisp_streaming_count(struct atomisp_device *isp) @@ -630,19 +655,9 @@ unsigned int atomisp_streaming_count(struct atomisp_device *isp) static int atomisp_g_input(struct file *file, void *fh, unsigned int *input) { struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - - rt_mutex_lock(&isp->mutex); *input = asd->input_curr; - rt_mutex_unlock(&isp->mutex); - return 0; } @@ -653,22 +668,19 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; + struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); + struct atomisp_sub_device *asd = pipe->asd; struct v4l2_subdev *camera = NULL; struct v4l2_subdev *motor; int ret; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } + ret = atomisp_pipe_check(pipe, true); + if (ret) + return ret; - rt_mutex_lock(&isp->mutex); if (input >= ATOM_ISP_MAX_INPUTS || input >= isp->input_cnt) { dev_dbg(isp->dev, "input_cnt: %d\n", isp->input_cnt); - ret = -EINVAL; - goto error; + return -EINVAL; } /* @@ -680,22 +692,13 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) dev_err(isp->dev, "%s, camera is already used by stream: %d\n", __func__, isp->inputs[input].asd->index); - ret = -EBUSY; - goto error; + return -EBUSY; } camera = isp->inputs[input].camera; if (!camera) { dev_err(isp->dev, "%s, no camera\n", __func__); - ret = -EINVAL; - goto error; - } - - if (atomisp_subdev_streaming_count(asd)) { - dev_err(isp->dev, - "ISP is still streaming, stop first\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } /* power off the current owned sensor, as it is not used this time */ @@ -714,7 +717,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1); if (ret) { dev_err(isp->dev, "Failed to power-on sensor\n"); - goto error; + return ret; } /* * Some sensor driver resets the run mode during power-on, thus force @@ -727,7 +730,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) 0, isp->inputs[input].sensor_index, 0); if (ret && (ret != -ENOIOCTLCMD)) { dev_err(isp->dev, "Failed to select sensor\n"); - goto error; + return ret; } if (!IS_ISP2401) { @@ -738,20 +741,14 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) ret = v4l2_subdev_call(motor, core, s_power, 1); } - if (!isp->sw_contex.file_input && motor) + if (motor) ret = v4l2_subdev_call(motor, core, init, 1); asd->input_curr = input; /* mark this camera is used by the current stream */ isp->inputs[input].asd = asd; - rt_mutex_unlock(&isp->mutex); return 0; - -error: - rt_mutex_unlock(&isp->mutex); - - return ret; } static int atomisp_enum_framesizes(struct file *file, void *priv, @@ -819,12 +816,6 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh, unsigned int i, fi = 0; int rval; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - camera = isp->inputs[asd->input_curr].camera; if(!camera) { dev_err(isp->dev, "%s(): camera is NULL, device is %s\n", @@ -832,15 +823,12 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh, return -EINVAL; } - rt_mutex_lock(&isp->mutex); - rval = v4l2_subdev_call(camera, pad, enum_mbus_code, NULL, &code); if (rval == -ENOIOCTLCMD) { dev_warn(isp->dev, "enum_mbus_code pad op not supported by %s. Please fix your sensor driver!\n", camera->name); } - rt_mutex_unlock(&isp->mutex); if (rval) return rval; @@ -872,20 +860,6 @@ static int atomisp_enum_fmt_cap(struct file *file, void *fh, return -EINVAL; } -static int atomisp_g_fmt_file(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - rt_mutex_lock(&isp->mutex); - f->fmt.pix = pipe->pix; - rt_mutex_unlock(&isp->mutex); - - return 0; -} - static int atomisp_adjust_fmt(struct v4l2_format *f) { const struct atomisp_format_bridge *format_bridge; @@ -957,13 +931,16 @@ static int atomisp_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); int ret; - rt_mutex_lock(&isp->mutex); - ret = atomisp_try_fmt(vdev, &f->fmt.pix, NULL); - rt_mutex_unlock(&isp->mutex); + /* + * atomisp_try_fmt() gived results with padding included, note + * (this gets removed again by the atomisp_adjust_fmt() call below. + */ + f->fmt.pix.width += pad_w; + f->fmt.pix.height += pad_h; + ret = atomisp_try_fmt(vdev, &f->fmt.pix, NULL); if (ret) return ret; @@ -974,12 +951,9 @@ static int atomisp_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe; - rt_mutex_lock(&isp->mutex); pipe = atomisp_to_video_pipe(vdev); - rt_mutex_unlock(&isp->mutex); f->fmt.pix = pipe->pix; @@ -994,37 +968,6 @@ static int atomisp_g_fmt_cap(struct file *file, void *fh, return atomisp_try_fmt_cap(file, fh, f); } -static int atomisp_s_fmt_cap(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - int ret; - - rt_mutex_lock(&isp->mutex); - if (isp->isp_fatal_error) { - ret = -EIO; - rt_mutex_unlock(&isp->mutex); - return ret; - } - ret = atomisp_set_fmt(vdev, f); - rt_mutex_unlock(&isp->mutex); - return ret; -} - -static int atomisp_s_fmt_file(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - int ret; - - rt_mutex_lock(&isp->mutex); - ret = atomisp_set_fmt_file(vdev, f); - rt_mutex_unlock(&isp->mutex); - return ret; -} - /* * Free videobuffer buffer priv data */ @@ -1160,8 +1103,7 @@ error: /* * Initiate Memory Mapping or User Pointer I/O */ -int __atomisp_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) +int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req) { struct video_device *vdev = video_devdata(file); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); @@ -1170,16 +1112,8 @@ int __atomisp_reqbufs(struct file *file, void *fh, struct ia_css_frame *frame; struct videobuf_vmalloc_memory *vm_mem; u16 source_pad = atomisp_subdev_source_pad(vdev); - u16 stream_id; int ret = 0, i = 0; - if (!asd) { - dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - stream_id = atomisp_source_pad_to_stream_id(asd, source_pad); - if (req->count == 0) { mutex_lock(&pipe->capq.vb_lock); if (!list_empty(&pipe->capq.stream)) @@ -1200,7 +1134,7 @@ int __atomisp_reqbufs(struct file *file, void *fh, if (ret) return ret; - atomisp_alloc_css_stat_bufs(asd, stream_id); + atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL); /* * for user pointer type, buffers are not really allocated here, @@ -1238,36 +1172,6 @@ error: return -ENOMEM; } -int atomisp_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - int ret; - - rt_mutex_lock(&isp->mutex); - ret = __atomisp_reqbufs(file, fh, req); - rt_mutex_unlock(&isp->mutex); - - return ret; -} - -static int atomisp_reqbufs_file(struct file *file, void *fh, - struct v4l2_requestbuffers *req) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - if (req->count == 0) { - mutex_lock(&pipe->outq.vb_lock); - atomisp_videobuf_free_queue(&pipe->outq); - mutex_unlock(&pipe->outq.vb_lock); - return 0; - } - - return videobuf_reqbufs(&pipe->outq, req); -} - /* application query the status of a buffer */ static int atomisp_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) @@ -1278,15 +1182,6 @@ static int atomisp_querybuf(struct file *file, void *fh, return videobuf_querybuf(&pipe->capq, buf); } -static int atomisp_querybuf_file(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - - return videobuf_querybuf(&pipe->outq, buf); -} - /* * Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or * filled (output) buffer in the drivers incoming queue. @@ -1305,32 +1200,16 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) struct ia_css_frame *handle = NULL; u32 length; u32 pgnr; - int ret = 0; - - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - - rt_mutex_lock(&isp->mutex); - if (isp->isp_fatal_error) { - ret = -EIO; - goto error; - } + int ret; - if (asd->streaming == ATOMISP_DEVICE_STREAMING_STOPPING) { - dev_err(isp->dev, "%s: reject, as ISP at stopping.\n", - __func__); - ret = -EIO; - goto error; - } + ret = atomisp_pipe_check(pipe, false); + if (ret) + return ret; if (!buf || buf->index >= VIDEO_MAX_FRAME || !pipe->capq.bufs[buf->index]) { dev_err(isp->dev, "Invalid index for qbuf.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } /* @@ -1338,12 +1217,15 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) * address and reprograme out page table properly */ if (buf->memory == V4L2_MEMORY_USERPTR) { + if (offset_in_page(buf->m.userptr)) { + dev_err(isp->dev, "Error userptr is not page aligned.\n"); + return -EINVAL; + } + vb = pipe->capq.bufs[buf->index]; vm_mem = vb->priv; - if (!vm_mem) { - ret = -EINVAL; - goto error; - } + if (!vm_mem) + return -EINVAL; length = vb->bsize; pgnr = (length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; @@ -1352,17 +1234,15 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) goto done; if (atomisp_get_css_frame_info(asd, - atomisp_subdev_source_pad(vdev), &frame_info)) { - ret = -EIO; - goto error; - } + atomisp_subdev_source_pad(vdev), &frame_info)) + return -EIO; ret = ia_css_frame_map(&handle, &frame_info, (void __user *)buf->m.userptr, pgnr); if (ret) { dev_err(isp->dev, "Failed to map user buffer\n"); - goto error; + return ret; } if (vm_mem->vaddr) { @@ -1406,12 +1286,11 @@ done: pipe->frame_params[buf->index] = NULL; - rt_mutex_unlock(&isp->mutex); - + mutex_unlock(&isp->mutex); ret = videobuf_qbuf(&pipe->capq, buf); - rt_mutex_lock(&isp->mutex); + mutex_lock(&isp->mutex); if (ret) - goto error; + return ret; /* TODO: do this better, not best way to queue to css */ if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { @@ -1419,15 +1298,6 @@ done: atomisp_handle_parameter_and_buffer(pipe); } else { atomisp_qbuffers_to_css(asd); - - if (!IS_ISP2401) { - if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd)) - atomisp_wdt_start(asd); - } else { - if (!atomisp_is_wdt_running(pipe) && - atomisp_buffers_queued_pipe(pipe)) - atomisp_wdt_start_pipe(pipe); - } } } @@ -1449,58 +1319,11 @@ done: asd->pending_capture_request++; dev_dbg(isp->dev, "Add one pending capture request.\n"); } - rt_mutex_unlock(&isp->mutex); dev_dbg(isp->dev, "qbuf buffer %d (%s) for asd%d\n", buf->index, vdev->name, asd->index); - return ret; - -error: - rt_mutex_unlock(&isp->mutex); - return ret; -} - -static int atomisp_qbuf_file(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - int ret; - - rt_mutex_lock(&isp->mutex); - if (isp->isp_fatal_error) { - ret = -EIO; - goto error; - } - - if (!buf || buf->index >= VIDEO_MAX_FRAME || - !pipe->outq.bufs[buf->index]) { - dev_err(isp->dev, "Invalid index for qbuf.\n"); - ret = -EINVAL; - goto error; - } - - if (buf->memory != V4L2_MEMORY_MMAP) { - dev_err(isp->dev, "Unsupported memory method\n"); - ret = -EINVAL; - goto error; - } - - if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - dev_err(isp->dev, "Unsupported buffer type\n"); - ret = -EINVAL; - goto error; - } - rt_mutex_unlock(&isp->mutex); - - return videobuf_qbuf(&pipe->outq, buf); - -error: - rt_mutex_unlock(&isp->mutex); - - return ret; + return 0; } static int __get_frame_exp_id(struct atomisp_video_pipe *pipe, @@ -1529,37 +1352,21 @@ static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); struct atomisp_sub_device *asd = pipe->asd; struct atomisp_device *isp = video_get_drvdata(vdev); - int ret = 0; - - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - - rt_mutex_lock(&isp->mutex); - - if (isp->isp_fatal_error) { - rt_mutex_unlock(&isp->mutex); - return -EIO; - } - - if (asd->streaming == ATOMISP_DEVICE_STREAMING_STOPPING) { - rt_mutex_unlock(&isp->mutex); - dev_err(isp->dev, "%s: reject, as ISP at stopping.\n", - __func__); - return -EIO; - } + int ret; - rt_mutex_unlock(&isp->mutex); + ret = atomisp_pipe_check(pipe, false); + if (ret) + return ret; + mutex_unlock(&isp->mutex); ret = videobuf_dqbuf(&pipe->capq, buf, file->f_flags & O_NONBLOCK); + mutex_lock(&isp->mutex); if (ret) { if (ret != -EAGAIN) dev_dbg(isp->dev, "<%s: %d\n", __func__, ret); return ret; } - rt_mutex_lock(&isp->mutex); + buf->bytesused = pipe->pix.sizeimage; buf->reserved = asd->frame_status[buf->index]; @@ -1573,7 +1380,6 @@ static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) if (!(buf->flags & V4L2_BUF_FLAG_ERROR)) buf->reserved |= __get_frame_exp_id(pipe, buf) << 16; buf->reserved2 = pipe->frame_config_id[buf->index]; - rt_mutex_unlock(&isp->mutex); dev_dbg(isp->dev, "dqbuf buffer %d (%s) for asd%d with exp_id %d, isp_config_id %d\n", @@ -1622,16 +1428,6 @@ enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device *asd) static unsigned int atomisp_sensor_start_stream(struct atomisp_sub_device *asd) { - struct atomisp_device *isp = asd->isp; - - if (isp->inputs[asd->input_curr].camera_caps-> - sensor[asd->sensor_curr].stream_num > 1) { - if (asd->high_speed_mode) - return 1; - else - return 2; - } - if (asd->vfpp->val != ATOMISP_VFPP_ENABLE || asd->copy_mode) return 1; @@ -1650,31 +1446,15 @@ static unsigned int atomisp_sensor_start_stream(struct atomisp_sub_device *asd) int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp, bool isp_timeout) { - unsigned int master = -1, slave = -1, delay_slave = 0; - int i, ret; - - /* - * ISP only support 2 streams now so ignore multiple master/slave - * case to reduce the delay between 2 stream_on calls. - */ - for (i = 0; i < isp->num_of_streams; i++) { - int sensor_index = isp->asd[i].input_curr; - - if (isp->inputs[sensor_index].camera_caps-> - sensor[isp->asd[i].sensor_curr].is_slave) - slave = sensor_index; - else - master = sensor_index; - } + unsigned int master, slave, delay_slave = 0; + int ret; - if (master == -1 || slave == -1) { - master = ATOMISP_DEPTH_DEFAULT_MASTER_SENSOR; - slave = ATOMISP_DEPTH_DEFAULT_SLAVE_SENSOR; - dev_warn(isp->dev, - "depth mode use default master=%s.slave=%s.\n", - isp->inputs[master].camera->name, - isp->inputs[slave].camera->name); - } + master = ATOMISP_DEPTH_DEFAULT_MASTER_SENSOR; + slave = ATOMISP_DEPTH_DEFAULT_SLAVE_SENSOR; + dev_warn(isp->dev, + "depth mode use default master=%s.slave=%s.\n", + isp->inputs[master].camera->name, + isp->inputs[slave].camera->name); ret = v4l2_subdev_call(isp->inputs[master].camera, core, ioctl, ATOMISP_IOC_G_DEPTH_SYNC_COMP, @@ -1708,51 +1488,6 @@ int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp, return 0; } -/* FIXME! ISP2400 */ -static void __wdt_on_master_slave_sensor(struct atomisp_device *isp, - unsigned int wdt_duration) -{ - if (atomisp_buffers_queued(&isp->asd[0])) - atomisp_wdt_refresh(&isp->asd[0], wdt_duration); - if (atomisp_buffers_queued(&isp->asd[1])) - atomisp_wdt_refresh(&isp->asd[1], wdt_duration); -} - -/* FIXME! ISP2401 */ -static void __wdt_on_master_slave_sensor_pipe(struct atomisp_video_pipe *pipe, - unsigned int wdt_duration, - bool enable) -{ - static struct atomisp_video_pipe *pipe0; - - if (enable) { - if (atomisp_buffers_queued_pipe(pipe0)) - atomisp_wdt_refresh_pipe(pipe0, wdt_duration); - if (atomisp_buffers_queued_pipe(pipe)) - atomisp_wdt_refresh_pipe(pipe, wdt_duration); - } else { - pipe0 = pipe; - } -} - -static void atomisp_pause_buffer_event(struct atomisp_device *isp) -{ - struct v4l2_event event = {0}; - int i; - - event.type = V4L2_EVENT_ATOMISP_PAUSE_BUFFER; - - for (i = 0; i < isp->num_of_streams; i++) { - int sensor_index = isp->asd[i].input_curr; - - if (isp->inputs[sensor_index].camera_caps-> - sensor[isp->asd[i].sensor_curr].is_slave) { - v4l2_event_queue(isp->asd[i].subdev.devnode, &event); - break; - } - } -} - /* Input system HW workaround */ /* Input system address translation corrupts burst during */ /* invalidate. SW workaround for this is to set burst length */ @@ -1784,15 +1519,8 @@ static int atomisp_streamon(struct file *file, void *fh, struct pci_dev *pdev = to_pci_dev(isp->dev); enum ia_css_pipe_id css_pipe_id; unsigned int sensor_start_stream; - unsigned int wdt_duration = ATOMISP_ISP_TIMEOUT_DURATION; - int ret = 0; unsigned long irqflags; - - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } + int ret; dev_dbg(isp->dev, "Start stream on pad %d for asd%d\n", atomisp_subdev_source_pad(vdev), asd->index); @@ -1802,19 +1530,12 @@ static int atomisp_streamon(struct file *file, void *fh, return -EINVAL; } - rt_mutex_lock(&isp->mutex); - if (isp->isp_fatal_error) { - ret = -EIO; - goto out; - } - - if (asd->streaming == ATOMISP_DEVICE_STREAMING_STOPPING) { - ret = -EBUSY; - goto out; - } + ret = atomisp_pipe_check(pipe, false); + if (ret) + return ret; if (pipe->capq.streaming) - goto out; + return 0; /* Input system HW workaround */ atomisp_dma_burst_len_cfg(asd); @@ -1829,20 +1550,18 @@ static int atomisp_streamon(struct file *file, void *fh, if (list_empty(&pipe->capq.stream)) { spin_unlock_irqrestore(&pipe->irq_lock, irqflags); dev_dbg(isp->dev, "no buffer in the queue\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } spin_unlock_irqrestore(&pipe->irq_lock, irqflags); ret = videobuf_streamon(&pipe->capq); if (ret) - goto out; + return ret; /* Reset pending capture request count. */ asd->pending_capture_request = 0; - if ((atomisp_subdev_streaming_count(asd) > sensor_start_stream) && - (!isp->inputs[asd->input_curr].camera_caps->multi_stream_ctrl)) { + if (atomisp_subdev_streaming_count(asd) > sensor_start_stream) { /* trigger still capture */ if (asd->continuous_mode->val && atomisp_subdev_source_pad(vdev) @@ -1856,11 +1575,11 @@ static int atomisp_streamon(struct file *file, void *fh, if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED) { flush_work(&asd->delayed_init_work); - rt_mutex_unlock(&isp->mutex); - if (wait_for_completion_interruptible( - &asd->init_done) != 0) + mutex_unlock(&isp->mutex); + ret = wait_for_completion_interruptible(&asd->init_done); + mutex_lock(&isp->mutex); + if (ret != 0) return -ERESTARTSYS; - rt_mutex_lock(&isp->mutex); } /* handle per_frame_setting parameter and buffers */ @@ -1882,16 +1601,12 @@ static int atomisp_streamon(struct file *file, void *fh, asd->params.offline_parm.num_captures, asd->params.offline_parm.skip_frames, asd->params.offline_parm.offset); - if (ret) { - ret = -EINVAL; - goto out; - } - if (asd->depth_mode->val) - atomisp_pause_buffer_event(isp); + if (ret) + return -EINVAL; } } atomisp_qbuffers_to_css(asd); - goto out; + return 0; } if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { @@ -1917,14 +1632,14 @@ static int atomisp_streamon(struct file *file, void *fh, ret = atomisp_css_start(asd, css_pipe_id, false); if (ret) - goto out; + return ret; + spin_lock_irqsave(&isp->lock, irqflags); asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED; + spin_unlock_irqrestore(&isp->lock, irqflags); atomic_set(&asd->sof_count, -1); atomic_set(&asd->sequence, -1); atomic_set(&asd->sequence_temp, -1); - if (isp->sw_contex.file_input) - wdt_duration = ATOMISP_ISP_FILE_TIMEOUT_DURATION; asd->params.dis_proj_data_valid = false; asd->latest_preview_exp_id = 0; @@ -1938,7 +1653,7 @@ static int atomisp_streamon(struct file *file, void *fh, /* Only start sensor when the last streaming instance started */ if (atomisp_subdev_streaming_count(asd) < sensor_start_stream) - goto out; + return 0; start_sensor: if (isp->flash) { @@ -1947,26 +1662,21 @@ start_sensor: atomisp_setup_flash(asd); } - if (!isp->sw_contex.file_input) { - atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, - atomisp_css_valid_sof(isp)); - atomisp_csi2_configure(asd); - /* - * set freq to max when streaming count > 1 which indicate - * dual camera would run - */ - if (atomisp_streaming_count(isp) > 1) { - if (atomisp_freq_scaling(isp, - ATOMISP_DFS_MODE_MAX, false) < 0) - dev_dbg(isp->dev, "DFS max mode failed!\n"); - } else { - if (atomisp_freq_scaling(isp, - ATOMISP_DFS_MODE_AUTO, false) < 0) - dev_dbg(isp->dev, "DFS auto mode failed!\n"); - } - } else { - if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false) < 0) + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, + atomisp_css_valid_sof(isp)); + atomisp_csi2_configure(asd); + /* + * set freq to max when streaming count > 1 which indicate + * dual camera would run + */ + if (atomisp_streaming_count(isp) > 1) { + if (atomisp_freq_scaling(isp, + ATOMISP_DFS_MODE_MAX, false) < 0) dev_dbg(isp->dev, "DFS max mode failed!\n"); + } else { + if (atomisp_freq_scaling(isp, + ATOMISP_DFS_MODE_AUTO, false) < 0) + dev_dbg(isp->dev, "DFS auto mode failed!\n"); } if (asd->depth_mode->val && atomisp_streaming_count(isp) == @@ -1974,17 +1684,11 @@ start_sensor: ret = atomisp_stream_on_master_slave_sensor(isp, false); if (ret) { dev_err(isp->dev, "master slave sensor stream on failed!\n"); - goto out; + return ret; } - if (!IS_ISP2401) - __wdt_on_master_slave_sensor(isp, wdt_duration); - else - __wdt_on_master_slave_sensor_pipe(pipe, wdt_duration, true); goto start_delay_wq; } else if (asd->depth_mode->val && (atomisp_streaming_count(isp) < ATOMISP_DEPTH_SENSOR_STREAMON_COUNT)) { - if (IS_ISP2401) - __wdt_on_master_slave_sensor_pipe(pipe, wdt_duration, false); goto start_delay_wq; } @@ -1999,41 +1703,29 @@ start_sensor: ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, video, s_stream, 1); if (ret) { + spin_lock_irqsave(&isp->lock, irqflags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; - ret = -EINVAL; - goto out; - } - - if (!IS_ISP2401) { - if (atomisp_buffers_queued(asd)) - atomisp_wdt_refresh(asd, wdt_duration); - } else { - if (atomisp_buffers_queued_pipe(pipe)) - atomisp_wdt_refresh_pipe(pipe, wdt_duration); + spin_unlock_irqrestore(&isp->lock, irqflags); + return -EINVAL; } start_delay_wq: if (asd->continuous_mode->val) { - struct v4l2_mbus_framefmt *sink; - - sink = atomisp_subdev_get_ffmt(&asd->subdev, NULL, - V4L2_SUBDEV_FORMAT_ACTIVE, - ATOMISP_SUBDEV_PAD_SINK); + atomisp_subdev_get_ffmt(&asd->subdev, NULL, + V4L2_SUBDEV_FORMAT_ACTIVE, + ATOMISP_SUBDEV_PAD_SINK); reinit_completion(&asd->init_done); asd->delayed_init = ATOMISP_DELAYED_INIT_QUEUED; queue_work(asd->delayed_init_workq, &asd->delayed_init_work); - atomisp_css_set_cont_prev_start_time(isp, - ATOMISP_CALC_CSS_PREV_OVERLAP(sink->height)); } else { asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED; } -out: - rt_mutex_unlock(&isp->mutex); - return ret; + + return 0; } -int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); @@ -2050,17 +1742,10 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) unsigned long flags; bool first_streamoff = false; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - dev_dbg(isp->dev, "Stop stream on pad %d for asd%d\n", atomisp_subdev_source_pad(vdev), asd->index); lockdep_assert_held(&isp->mutex); - lockdep_assert_held(&isp->streamoff_mutex); if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { dev_dbg(isp->dev, "unsupported v4l2 buf type\n"); @@ -2071,17 +1756,10 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) * do only videobuf_streamoff for capture & vf pipes in * case of continuous capture */ - if ((asd->continuous_mode->val || - isp->inputs[asd->input_curr].camera_caps->multi_stream_ctrl) && - atomisp_subdev_source_pad(vdev) != - ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && - atomisp_subdev_source_pad(vdev) != - ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) { - if (isp->inputs[asd->input_curr].camera_caps->multi_stream_ctrl) { - v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - video, s_stream, 0); - } else if (atomisp_subdev_source_pad(vdev) - == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) { + if (asd->continuous_mode->val && + atomisp_subdev_source_pad(vdev) != ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW && + atomisp_subdev_source_pad(vdev) != ATOMISP_SUBDEV_PAD_SOURCE_VIDEO) { + if (atomisp_subdev_source_pad(vdev) == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE) { /* stop continuous still capture if needed */ if (asd->params.offline_parm.num_captures == -1) atomisp_css_offline_capture_configure(asd, @@ -2118,32 +1796,14 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) if (!pipe->capq.streaming) return 0; - spin_lock_irqsave(&isp->lock, flags); - if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { - asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING; + if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) first_streamoff = true; - } - spin_unlock_irqrestore(&isp->lock, flags); - - if (first_streamoff) { - /* if other streams are running, should not disable watch dog */ - rt_mutex_unlock(&isp->mutex); - atomisp_wdt_stop(asd, true); - - /* - * must stop sending pixels into GP_FIFO before stop - * the pipeline. - */ - if (isp->sw_contex.file_input) - v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - video, s_stream, 0); - - rt_mutex_lock(&isp->mutex); - } spin_lock_irqsave(&isp->lock, flags); if (atomisp_subdev_streaming_count(asd) == 1) asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; + else + asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING; spin_unlock_irqrestore(&isp->lock, flags); if (!first_streamoff) { @@ -2154,19 +1814,16 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) } atomisp_clear_css_buffer_counters(asd); - - if (!isp->sw_contex.file_input) - atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, - false); + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED) { cancel_work_sync(&asd->delayed_init_work); asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED; } - if (first_streamoff) { - css_pipe_id = atomisp_get_css_pipe_id(asd); - atomisp_css_stop(asd, css_pipe_id, false); - } + + css_pipe_id = atomisp_get_css_pipe_id(asd); + atomisp_css_stop(asd, css_pipe_id, false); + /* cancel work queue*/ if (asd->video_out_capture.users) { capture_pipe = &asd->video_out_capture; @@ -2210,9 +1867,8 @@ stopsensor: != atomisp_sensor_start_stream(asd)) return 0; - if (!isp->sw_contex.file_input) - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - video, s_stream, 0); + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, + video, s_stream, 0); if (isp->flash) { asd->params.num_flash_frames = 0; @@ -2284,22 +1940,6 @@ stopsensor: return ret; } -static int atomisp_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - int rval; - - mutex_lock(&isp->streamoff_mutex); - rt_mutex_lock(&isp->mutex); - rval = __atomisp_streamoff(file, fh, type); - rt_mutex_unlock(&isp->mutex); - mutex_unlock(&isp->streamoff_mutex); - - return rval; -} - /* * To get the current value of a control. * applications initialize the id field of a struct v4l2_control and @@ -2313,12 +1953,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, struct atomisp_device *isp = video_get_drvdata(vdev); int i, ret = -EINVAL; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - for (i = 0; i < ctrls_num; i++) { if (ci_v4l2_controls[i].id == control->id) { ret = 0; @@ -2329,8 +1963,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, if (ret) return ret; - rt_mutex_lock(&isp->mutex); - switch (control->id) { case V4L2_CID_IRIS_ABSOLUTE: case V4L2_CID_EXPOSURE_ABSOLUTE: @@ -2352,7 +1984,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, case V4L2_CID_TEST_PATTERN_COLOR_GR: case V4L2_CID_TEST_PATTERN_COLOR_GB: case V4L2_CID_TEST_PATTERN_COLOR_B: - rt_mutex_unlock(&isp->mutex); return v4l2_g_ctrl(isp->inputs[asd->input_curr].camera-> ctrl_handler, control); case V4L2_CID_COLORFX: @@ -2381,7 +2012,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, break; } - rt_mutex_unlock(&isp->mutex); return ret; } @@ -2398,12 +2028,6 @@ static int atomisp_s_ctrl(struct file *file, void *fh, struct atomisp_device *isp = video_get_drvdata(vdev); int i, ret = -EINVAL; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - for (i = 0; i < ctrls_num; i++) { if (ci_v4l2_controls[i].id == control->id) { ret = 0; @@ -2414,7 +2038,6 @@ static int atomisp_s_ctrl(struct file *file, void *fh, if (ret) return ret; - rt_mutex_lock(&isp->mutex); switch (control->id) { case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: case V4L2_CID_EXPOSURE: @@ -2435,7 +2058,6 @@ static int atomisp_s_ctrl(struct file *file, void *fh, case V4L2_CID_TEST_PATTERN_COLOR_GR: case V4L2_CID_TEST_PATTERN_COLOR_GB: case V4L2_CID_TEST_PATTERN_COLOR_B: - rt_mutex_unlock(&isp->mutex); return v4l2_s_ctrl(NULL, isp->inputs[asd->input_curr].camera-> ctrl_handler, control); @@ -2467,7 +2089,6 @@ static int atomisp_s_ctrl(struct file *file, void *fh, ret = -EINVAL; break; } - rt_mutex_unlock(&isp->mutex); return ret; } @@ -2485,12 +2106,6 @@ static int atomisp_queryctl(struct file *file, void *fh, struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; struct atomisp_device *isp = video_get_drvdata(vdev); - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - switch (qc->id) { case V4L2_CID_FOCUS_ABSOLUTE: case V4L2_CID_FOCUS_RELATIVE: @@ -2536,12 +2151,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, int i; int ret = 0; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - if (!IS_ISP2401) motor = isp->inputs[asd->input_curr].motor; else @@ -2592,9 +2201,7 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, &ctrl); break; case V4L2_CID_ZOOM_ABSOLUTE: - rt_mutex_lock(&isp->mutex); ret = atomisp_digital_zoom(asd, 0, &ctrl.value); - rt_mutex_unlock(&isp->mutex); break; case V4L2_CID_G_SKIP_FRAMES: ret = v4l2_subdev_call( @@ -2653,12 +2260,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, int i; int ret = 0; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - if (!IS_ISP2401) motor = isp->inputs[asd->input_curr].motor; else @@ -2707,7 +2308,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, case V4L2_CID_FLASH_STROBE: case V4L2_CID_FLASH_MODE: case V4L2_CID_FLASH_STATUS_REGISTER: - rt_mutex_lock(&isp->mutex); if (isp->flash) { ret = v4l2_s_ctrl(NULL, isp->flash->ctrl_handler, @@ -2722,12 +2322,9 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, asd->params.num_flash_frames = 0; } } - rt_mutex_unlock(&isp->mutex); break; case V4L2_CID_ZOOM_ABSOLUTE: - rt_mutex_lock(&isp->mutex); ret = atomisp_digital_zoom(asd, 1, &ctrl.value); - rt_mutex_unlock(&isp->mutex); break; default: ctr = v4l2_ctrl_find(&asd->ctrl_handler, ctrl.id); @@ -2784,20 +2381,12 @@ static int atomisp_g_parm(struct file *file, void *fh, struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; struct atomisp_device *isp = video_get_drvdata(vdev); - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { dev_err(isp->dev, "unsupported v4l2 buf type\n"); return -EINVAL; } - rt_mutex_lock(&isp->mutex); parm->parm.capture.capturemode = asd->run_mode->val; - rt_mutex_unlock(&isp->mutex); return 0; } @@ -2812,19 +2401,11 @@ static int atomisp_s_parm(struct file *file, void *fh, int rval; int fps; - if (!asd) { - dev_err(isp->dev, "%s(): asd is NULL, device is %s\n", - __func__, vdev->name); - return -EINVAL; - } - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { dev_err(isp->dev, "unsupported v4l2 buf type\n"); return -EINVAL; } - rt_mutex_lock(&isp->mutex); - asd->high_speed_mode = false; switch (parm->parm.capture.capturemode) { case CI_MODE_NONE: { @@ -2843,7 +2424,7 @@ static int atomisp_s_parm(struct file *file, void *fh, asd->high_speed_mode = true; } - goto out; + return rval == -ENOIOCTLCMD ? 0 : rval; } case CI_MODE_VIDEO: mode = ATOMISP_RUN_MODE_VIDEO; @@ -2858,76 +2439,29 @@ static int atomisp_s_parm(struct file *file, void *fh, mode = ATOMISP_RUN_MODE_PREVIEW; break; default: - rval = -EINVAL; - goto out; + return -EINVAL; } rval = v4l2_ctrl_s_ctrl(asd->run_mode, mode); -out: - rt_mutex_unlock(&isp->mutex); - return rval == -ENOIOCTLCMD ? 0 : rval; } -static int atomisp_s_parm_file(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct video_device *vdev = video_devdata(file); - struct atomisp_device *isp = video_get_drvdata(vdev); - - if (parm->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - dev_err(isp->dev, "unsupported v4l2 buf type for output\n"); - return -EINVAL; - } - - rt_mutex_lock(&isp->mutex); - isp->sw_contex.file_input = true; - rt_mutex_unlock(&isp->mutex); - - return 0; -} - static long atomisp_vidioc_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); - struct atomisp_sub_device *asd; + struct atomisp_sub_device *asd = atomisp_to_video_pipe(vdev)->asd; struct v4l2_subdev *motor; - bool acc_node; int err; - acc_node = !strcmp(vdev->name, "ATOMISP ISP ACC"); - if (acc_node) - asd = atomisp_to_acc_pipe(vdev)->asd; - else - asd = atomisp_to_video_pipe(vdev)->asd; - if (!IS_ISP2401) motor = isp->inputs[asd->input_curr].motor; else motor = isp->motor; switch (cmd) { - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: - case ATOMISP_IOC_S_EXPOSURE: - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP: - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - case ATOMISP_IOC_EXT_ISP_CTRL: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_INFO: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT: - case ATOMISP_IOC_S_SENSOR_EE_CONFIG: - case ATOMISP_IOC_G_UPDATE_EXPOSURE: - /* we do not need take isp->mutex for these IOCTLs */ - break; - default: - rt_mutex_lock(&isp->mutex); - break; - } - switch (cmd) { case ATOMISP_IOC_S_SENSOR_RUNMODE: if (IS_ISP2401) err = atomisp_set_sensor_runmode(asd, arg); @@ -3173,22 +2707,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, break; } - switch (cmd) { - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: - case ATOMISP_IOC_S_EXPOSURE: - case ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP: - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - case ATOMISP_IOC_EXT_ISP_CTRL: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_INFO: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_G_SENSOR_AE_BRACKETING_MODE: - case ATOMISP_IOC_S_SENSOR_AE_BRACKETING_LUT: - case ATOMISP_IOC_G_UPDATE_EXPOSURE: - break; - default: - rt_mutex_unlock(&isp->mutex); - break; - } return err; } @@ -3207,7 +2725,7 @@ const struct v4l2_ioctl_ops atomisp_ioctl_ops = { .vidioc_enum_fmt_vid_cap = atomisp_enum_fmt_cap, .vidioc_try_fmt_vid_cap = atomisp_try_fmt_cap, .vidioc_g_fmt_vid_cap = atomisp_g_fmt_cap, - .vidioc_s_fmt_vid_cap = atomisp_s_fmt_cap, + .vidioc_s_fmt_vid_cap = atomisp_set_fmt, .vidioc_reqbufs = atomisp_reqbufs, .vidioc_querybuf = atomisp_querybuf, .vidioc_qbuf = atomisp_qbuf, @@ -3218,13 +2736,3 @@ const struct v4l2_ioctl_ops atomisp_ioctl_ops = { .vidioc_s_parm = atomisp_s_parm, .vidioc_g_parm = atomisp_g_parm, }; - -const struct v4l2_ioctl_ops atomisp_file_ioctl_ops = { - .vidioc_querycap = atomisp_querycap, - .vidioc_g_fmt_vid_out = atomisp_g_fmt_file, - .vidioc_s_fmt_vid_out = atomisp_s_fmt_file, - .vidioc_s_parm = atomisp_s_parm_file, - .vidioc_reqbufs = atomisp_reqbufs_file, - .vidioc_querybuf = atomisp_querybuf_file, - .vidioc_qbuf = atomisp_qbuf_file, -}; diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h index d85e0d697a4e..c660f631d371 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.h +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.h @@ -34,27 +34,21 @@ atomisp_format_bridge *atomisp_get_format_bridge(unsigned int pixelformat); const struct atomisp_format_bridge *atomisp_get_format_bridge_from_mbus(u32 mbus_code); +int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool streaming_ok); + int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, uint16_t stream_id); -int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type); -int __atomisp_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req); - -int atomisp_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req); +int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type); +int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req); enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device *asd); void atomisp_videobuf_free_buf(struct videobuf_buffer *vb); -extern const struct v4l2_file_operations atomisp_file_fops; - extern const struct v4l2_ioctl_ops atomisp_ioctl_ops; -extern const struct v4l2_ioctl_ops atomisp_file_ioctl_ops; - unsigned int atomisp_streaming_count(struct atomisp_device *isp); /* compat_ioctl for 32bit userland app and 64bit kernel */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 394fe6959033..847dfee6ad78 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -373,16 +373,12 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); struct atomisp_device *isp = isp_sd->isp; struct v4l2_mbus_framefmt *ffmt[ATOMISP_SUBDEV_PADS_NUM]; - u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode); struct v4l2_rect *crop[ATOMISP_SUBDEV_PADS_NUM], *comp[ATOMISP_SUBDEV_PADS_NUM]; - enum atomisp_input_stream_id stream_id; unsigned int i; unsigned int padding_w = pad_w; unsigned int padding_h = pad_h; - stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad); - isp_get_fmt_rect(sd, sd_state, which, ffmt, crop, comp); dev_dbg(isp->dev, @@ -478,9 +474,10 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, dvs_w = dvs_h = 0; } atomisp_css_video_set_dis_envelope(isp_sd, dvs_w, dvs_h); - atomisp_css_input_set_effective_resolution(isp_sd, stream_id, - crop[pad]->width, crop[pad]->height); - + atomisp_css_input_set_effective_resolution(isp_sd, + ATOMISP_INPUT_STREAM_GENERAL, + crop[pad]->width, + crop[pad]->height); break; } case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE: @@ -523,14 +520,14 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, if (r->width * crop[ATOMISP_SUBDEV_PAD_SINK]->height < crop[ATOMISP_SUBDEV_PAD_SINK]->width * r->height) atomisp_css_input_set_effective_resolution(isp_sd, - stream_id, + ATOMISP_INPUT_STREAM_GENERAL, rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> height * r->width / r->height, ATOM_ISP_STEP_WIDTH), crop[ATOMISP_SUBDEV_PAD_SINK]->height); else atomisp_css_input_set_effective_resolution(isp_sd, - stream_id, + ATOMISP_INPUT_STREAM_GENERAL, crop[ATOMISP_SUBDEV_PAD_SINK]->width, rounddown(crop[ATOMISP_SUBDEV_PAD_SINK]-> width * r->height / r->width, @@ -620,16 +617,12 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, struct atomisp_device *isp = isp_sd->isp; struct v4l2_mbus_framefmt *__ffmt = atomisp_subdev_get_ffmt(sd, sd_state, which, pad); - u16 vdev_pad = atomisp_subdev_source_pad(sd->devnode); - enum atomisp_input_stream_id stream_id; dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n", atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code, which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" : "V4L2_SUBDEV_FORMAT_ACTIVE"); - stream_id = atomisp_source_pad_to_stream_id(isp_sd, vdev_pad); - switch (pad) { case ATOMISP_SUBDEV_PAD_SINK: { const struct atomisp_in_fmt_conv *fc = @@ -649,15 +642,15 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { atomisp_css_input_set_resolution(isp_sd, - stream_id, ffmt); + ATOMISP_INPUT_STREAM_GENERAL, ffmt); atomisp_css_input_set_binning_factor(isp_sd, - stream_id, + ATOMISP_INPUT_STREAM_GENERAL, atomisp_get_sensor_bin_factor(isp_sd)); - atomisp_css_input_set_bayer_order(isp_sd, stream_id, + atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, fc->bayer_order); - atomisp_css_input_set_format(isp_sd, stream_id, + atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, fc->atomisp_in_fmt); - atomisp_css_set_default_isys_config(isp_sd, stream_id, + atomisp_css_set_default_isys_config(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, ffmt); } @@ -874,12 +867,18 @@ static int s_ctrl(struct v4l2_ctrl *ctrl) { struct atomisp_sub_device *asd = container_of( ctrl->handler, struct atomisp_sub_device, ctrl_handler); + unsigned int streaming; + unsigned long flags; switch (ctrl->id) { case V4L2_CID_RUN_MODE: return __atomisp_update_run_mode(asd); case V4L2_CID_DEPTH_MODE: - if (asd->streaming != ATOMISP_DEVICE_STREAMING_DISABLED) { + /* Use spinlock instead of mutex to avoid possible locking issues */ + spin_lock_irqsave(&asd->isp->lock, flags); + streaming = asd->streaming; + spin_unlock_irqrestore(&asd->isp->lock, flags); + if (streaming != ATOMISP_DEVICE_STREAMING_DISABLED) { dev_err(asd->isp->dev, "ISP is streaming, it is not supported to change the depth mode\n"); return -EINVAL; @@ -1066,7 +1065,6 @@ static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, pipe->isp = asd->isp; spin_lock_init(&pipe->irq_lock); INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->activeq_out); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->per_frame_params); memset(pipe->frame_request_config_id, @@ -1076,13 +1074,6 @@ static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, sizeof(struct atomisp_css_params_with_list *)); } -static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd, - struct atomisp_acc_pipe *pipe) -{ - pipe->asd = asd; - pipe->isp = asd->isp; -} - /* * isp_subdev_init_entities - Initialize V4L2 subdev and media entity * @asd: ISP CCDC module @@ -1126,9 +1117,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) if (ret < 0) return ret; - atomisp_init_subdev_pipe(asd, &asd->video_in, - V4L2_BUF_TYPE_VIDEO_OUTPUT); - atomisp_init_subdev_pipe(asd, &asd->video_out_preview, V4L2_BUF_TYPE_VIDEO_CAPTURE); @@ -1141,13 +1129,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, V4L2_BUF_TYPE_VIDEO_CAPTURE); - atomisp_init_acc_pipe(asd, &asd->video_acc); - - ret = atomisp_video_init(&asd->video_in, "MEMORY", - ATOMISP_RUN_MODE_SDV); - if (ret < 0) - return ret; - ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE", ATOMISP_RUN_MODE_STILL_CAPTURE); if (ret < 0) @@ -1168,8 +1149,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) if (ret < 0) return ret; - atomisp_acc_init(&asd->video_acc, "ACC"); - ret = v4l2_ctrl_handler_init(&asd->ctrl_handler, 1); if (ret) return ret; @@ -1226,7 +1205,11 @@ int atomisp_create_pads_links(struct atomisp_device *isp) return ret; } } - for (i = 0; i < isp->input_cnt - 2; i++) { + for (i = 0; i < isp->input_cnt; i++) { + /* Don't create links for the test-pattern-generator */ + if (isp->inputs[i].type == TEST_PATTERN) + continue; + ret = media_create_pad_link(&isp->inputs[i].camera->entity, 0, &isp->csi2_port[isp->inputs[i]. port].subdev.entity, @@ -1262,17 +1245,6 @@ int atomisp_create_pads_links(struct atomisp_device *isp) entity, 0, 0); if (ret < 0) return ret; - /* - * file input only supported on subdev0 - * so do not create pad link for subdevs other then subdev0 - */ - if (asd->index) - return 0; - ret = media_create_pad_link(&asd->video_in.vdev.entity, - 0, &asd->subdev.entity, - ATOMISP_SUBDEV_PAD_SINK, 0); - if (ret < 0) - return ret; } return 0; } @@ -1302,87 +1274,55 @@ void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd) { atomisp_subdev_cleanup_entities(asd); v4l2_device_unregister_subdev(&asd->subdev); - atomisp_video_unregister(&asd->video_in); atomisp_video_unregister(&asd->video_out_preview); atomisp_video_unregister(&asd->video_out_vf); atomisp_video_unregister(&asd->video_out_capture); atomisp_video_unregister(&asd->video_out_video_capture); - atomisp_acc_unregister(&asd->video_acc); } -int atomisp_subdev_register_entities(struct atomisp_sub_device *asd, - struct v4l2_device *vdev) +int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd, + struct v4l2_device *vdev) +{ + return v4l2_device_register_subdev(vdev, &asd->subdev); +} + +int atomisp_subdev_register_video_nodes(struct atomisp_sub_device *asd, + struct v4l2_device *vdev) { int ret; - u32 device_caps; /* * FIXME: check if all device caps are properly initialized. - * Should any of those use V4L2_CAP_META_OUTPUT? Probably yes. + * Should any of those use V4L2_CAP_META_CAPTURE? Probably yes. */ - device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; - - /* Register the subdev and video node. */ - - ret = v4l2_device_register_subdev(vdev, &asd->subdev); - if (ret < 0) - goto error; - asd->video_out_preview.vdev.v4l2_dev = vdev; - asd->video_out_preview.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_OUTPUT; + asd->video_out_preview.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ret = video_register_device(&asd->video_out_preview.vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) goto error; asd->video_out_capture.vdev.v4l2_dev = vdev; - asd->video_out_capture.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_OUTPUT; + asd->video_out_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ret = video_register_device(&asd->video_out_capture.vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) goto error; asd->video_out_vf.vdev.v4l2_dev = vdev; - asd->video_out_vf.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_OUTPUT; + asd->video_out_vf.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ret = video_register_device(&asd->video_out_vf.vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) goto error; asd->video_out_video_capture.vdev.v4l2_dev = vdev; - asd->video_out_video_capture.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_OUTPUT; + asd->video_out_video_capture.vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; ret = video_register_device(&asd->video_out_video_capture.vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) goto error; - asd->video_acc.vdev.v4l2_dev = vdev; - asd->video_acc.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_OUTPUT; - ret = video_register_device(&asd->video_acc.vdev, - VFL_TYPE_VIDEO, -1); - if (ret < 0) - goto error; - - /* - * file input only supported on subdev0 - * so do not create video node for subdevs other then subdev0 - */ - if (asd->index) - return 0; - - asd->video_in.vdev.v4l2_dev = vdev; - asd->video_in.vdev.device_caps = device_caps | - V4L2_CAP_VIDEO_CAPTURE; - ret = video_register_device(&asd->video_in.vdev, - VFL_TYPE_VIDEO, -1); - if (ret < 0) - goto error; return 0; @@ -1415,7 +1355,6 @@ int atomisp_subdev_init(struct atomisp_device *isp) return -ENOMEM; for (i = 0; i < isp->num_of_streams; i++) { asd = &isp->asd[i]; - spin_lock_init(&asd->lock); asd->isp = isp; isp_subdev_init_params(asd); asd->index = i; diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index 798a93793a9a..a1f4da35235d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -70,9 +70,7 @@ struct atomisp_video_pipe { enum v4l2_buf_type type; struct media_pad pad; struct videobuf_queue capq; - struct videobuf_queue outq; struct list_head activeq; - struct list_head activeq_out; /* * the buffers waiting for per-frame parameters, this is only valid * in per-frame setting mode. @@ -86,9 +84,10 @@ struct atomisp_video_pipe { unsigned int buffers_in_css; - /* irq_lock is used to protect video buffer state change operations and - * also to make activeq, activeq_out, capq and outq list - * operations atomic. */ + /* + * irq_lock is used to protect video buffer state change operations and + * also to make activeq and capq operations atomic. + */ spinlock_t irq_lock; unsigned int users; @@ -109,23 +108,6 @@ struct atomisp_video_pipe { */ unsigned int frame_request_config_id[VIDEO_MAX_FRAME]; struct atomisp_css_params_with_list *frame_params[VIDEO_MAX_FRAME]; - - /* - * move wdt from asd struct to create wdt for each pipe - */ - /* ISP2401 */ - struct timer_list wdt; - unsigned int wdt_duration; /* in jiffies */ - unsigned long wdt_expires; - atomic_t wdt_count; -}; - -struct atomisp_acc_pipe { - struct video_device vdev; - unsigned int users; - bool running; - struct atomisp_sub_device *asd; - struct atomisp_device *isp; }; struct atomisp_pad_format { @@ -267,28 +249,6 @@ struct atomisp_css_params_with_list { struct list_head list; }; -struct atomisp_acc_fw { - struct ia_css_fw_info *fw; - unsigned int handle; - unsigned int flags; - unsigned int type; - struct { - size_t length; - unsigned long css_ptr; - } args[ATOMISP_ACC_NR_MEMORY]; - struct list_head list; -}; - -struct atomisp_map { - ia_css_ptr ptr; - size_t length; - struct list_head list; - /* FIXME: should keep book which maps are currently used - * by binaries and not allow releasing those - * which are in use. Implement by reference counting. - */ -}; - struct atomisp_sub_device { struct v4l2_subdev subdev; struct media_pad pads[ATOMISP_SUBDEV_PADS_NUM]; @@ -297,15 +257,12 @@ struct atomisp_sub_device { enum atomisp_subdev_input_entity input; unsigned int output; - struct atomisp_video_pipe video_in; struct atomisp_video_pipe video_out_capture; /* capture output */ struct atomisp_video_pipe video_out_vf; /* viewfinder output */ struct atomisp_video_pipe video_out_preview; /* preview output */ - struct atomisp_acc_pipe video_acc; /* video pipe main output */ struct atomisp_video_pipe video_out_video_capture; /* struct isp_subdev_params params; */ - spinlock_t lock; struct atomisp_device *isp; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *fmt_auto; @@ -356,15 +313,16 @@ struct atomisp_sub_device { /* This field specifies which camera (v4l2 input) is selected. */ int input_curr; - /* This field specifies which sensor is being selected when there - are multiple sensors connected to the same MIPI port. */ - int sensor_curr; atomic_t sof_count; atomic_t sequence; /* Sequence value that is assigned to buffer. */ atomic_t sequence_temp; - unsigned int streaming; /* Hold both mutex and lock to change this */ + /* + * Writers of streaming must hold both isp->mutex and isp->lock. + * Readers of streaming need to hold only one of the two locks. + */ + unsigned int streaming; bool stream_prepared; /* whether css stream is created */ /* subdev index: will be used to show which subdev is holding the @@ -390,11 +348,6 @@ struct atomisp_sub_device { int raw_buffer_locked_count; spinlock_t raw_buffer_bitmap_lock; - /* ISP 2400 */ - struct timer_list wdt; - unsigned int wdt_duration; /* in jiffies */ - unsigned long wdt_expires; - /* ISP2401 */ bool re_trigger_capture; @@ -450,8 +403,10 @@ int atomisp_update_run_mode(struct atomisp_sub_device *asd); void atomisp_subdev_cleanup_pending_events(struct atomisp_sub_device *asd); void atomisp_subdev_unregister_entities(struct atomisp_sub_device *asd); -int atomisp_subdev_register_entities(struct atomisp_sub_device *asd, - struct v4l2_device *vdev); +int atomisp_subdev_register_subdev(struct atomisp_sub_device *asd, + struct v4l2_device *vdev); +int atomisp_subdev_register_video_nodes(struct atomisp_sub_device *asd, + struct v4l2_device *vdev); int atomisp_subdev_init(struct atomisp_device *isp); void atomisp_subdev_cleanup(struct atomisp_device *isp); int atomisp_create_pads_links(struct atomisp_device *isp); diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 643ba981601b..d5bb9906ca6f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -34,7 +34,6 @@ #include "atomisp_cmd.h" #include "atomisp_common.h" #include "atomisp_fops.h" -#include "atomisp_file.h" #include "atomisp_ioctl.h" #include "atomisp_internal.h" #include "atomisp-regs.h" @@ -442,12 +441,7 @@ int atomisp_video_init(struct atomisp_video_pipe *video, const char *name, video->pad.flags = MEDIA_PAD_FL_SINK; video->vdev.fops = &atomisp_fops; video->vdev.ioctl_ops = &atomisp_ioctl_ops; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - direction = "input"; - video->pad.flags = MEDIA_PAD_FL_SOURCE; - video->vdev.fops = &atomisp_file_fops; - video->vdev.ioctl_ops = &atomisp_file_ioctl_ops; + video->vdev.lock = &video->isp->mutex; break; default: return -EINVAL; @@ -467,18 +461,6 @@ int atomisp_video_init(struct atomisp_video_pipe *video, const char *name, return 0; } -void atomisp_acc_init(struct atomisp_acc_pipe *video, const char *name) -{ - video->vdev.fops = &atomisp_fops; - video->vdev.ioctl_ops = &atomisp_ioctl_ops; - - /* Initialize the video device. */ - snprintf(video->vdev.name, sizeof(video->vdev.name), - "ATOMISP ISP %s", name); - video->vdev.release = video_device_release_empty; - video_set_drvdata(&video->vdev, video->isp); -} - void atomisp_video_unregister(struct atomisp_video_pipe *video) { if (video_is_registered(&video->vdev)) { @@ -487,12 +469,6 @@ void atomisp_video_unregister(struct atomisp_video_pipe *video) } } -void atomisp_acc_unregister(struct atomisp_acc_pipe *video) -{ - if (video_is_registered(&video->vdev)) - video_unregister_device(&video->vdev); -} - static int atomisp_save_iunit_reg(struct atomisp_device *isp) { struct pci_dev *pdev = to_pci_dev(isp->dev); @@ -1031,7 +1007,6 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) &subdevs->v4l2_subdev.board_info; struct i2c_adapter *adapter = i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); - int sensor_num, i; dev_info(isp->dev, "Probing Subdev %s\n", board_info->type); @@ -1090,22 +1065,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) * pixel_format. */ isp->inputs[isp->input_cnt].frame_size.pixel_format = 0; - isp->inputs[isp->input_cnt].camera_caps = - atomisp_get_default_camera_caps(); - sensor_num = isp->inputs[isp->input_cnt] - .camera_caps->sensor_num; isp->input_cnt++; - for (i = 1; i < sensor_num; i++) { - if (isp->input_cnt >= ATOM_ISP_MAX_INPUTS) { - dev_warn(isp->dev, - "atomisp inputs out of range\n"); - break; - } - isp->inputs[isp->input_cnt] = - isp->inputs[isp->input_cnt - 1]; - isp->inputs[isp->input_cnt].sensor_index = i; - isp->input_cnt++; - } break; case CAMERA_MOTOR: if (isp->motor) { @@ -1158,7 +1118,6 @@ static void atomisp_unregister_entities(struct atomisp_device *isp) for (i = 0; i < isp->num_of_streams; i++) atomisp_subdev_unregister_entities(&isp->asd[i]); atomisp_tpg_unregister_entities(&isp->tpg); - atomisp_file_input_unregister_entities(&isp->file_dev); for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]); @@ -1210,13 +1169,6 @@ static int atomisp_register_entities(struct atomisp_device *isp) goto csi_and_subdev_probe_failed; } - ret = - atomisp_file_input_register_entities(&isp->file_dev, &isp->v4l2_dev); - if (ret < 0) { - dev_err(isp->dev, "atomisp_file_input_register_entities\n"); - goto file_input_register_failed; - } - ret = atomisp_tpg_register_entities(&isp->tpg, &isp->v4l2_dev); if (ret < 0) { dev_err(isp->dev, "atomisp_tpg_register_entities\n"); @@ -1226,10 +1178,9 @@ static int atomisp_register_entities(struct atomisp_device *isp) for (i = 0; i < isp->num_of_streams; i++) { struct atomisp_sub_device *asd = &isp->asd[i]; - ret = atomisp_subdev_register_entities(asd, &isp->v4l2_dev); + ret = atomisp_subdev_register_subdev(asd, &isp->v4l2_dev); if (ret < 0) { - dev_err(isp->dev, - "atomisp_subdev_register_entities fail\n"); + dev_err(isp->dev, "atomisp_subdev_register_subdev fail\n"); for (; i > 0; i--) atomisp_subdev_unregister_entities( &isp->asd[i - 1]); @@ -1267,31 +1218,17 @@ static int atomisp_register_entities(struct atomisp_device *isp) } } - dev_dbg(isp->dev, - "FILE_INPUT enable, camera_cnt: %d\n", isp->input_cnt); - isp->inputs[isp->input_cnt].type = FILE_INPUT; - isp->inputs[isp->input_cnt].port = -1; - isp->inputs[isp->input_cnt].camera_caps = - atomisp_get_default_camera_caps(); - isp->inputs[isp->input_cnt++].camera = &isp->file_dev.sd; - if (isp->input_cnt < ATOM_ISP_MAX_INPUTS) { dev_dbg(isp->dev, "TPG detected, camera_cnt: %d\n", isp->input_cnt); isp->inputs[isp->input_cnt].type = TEST_PATTERN; isp->inputs[isp->input_cnt].port = -1; - isp->inputs[isp->input_cnt].camera_caps = - atomisp_get_default_camera_caps(); isp->inputs[isp->input_cnt++].camera = &isp->tpg.sd; } else { dev_warn(isp->dev, "too many atomisp inputs, TPG ignored.\n"); } - ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); - if (ret < 0) - goto link_failed; - - return media_device_register(&isp->media_dev); + return 0; link_failed: for (i = 0; i < isp->num_of_streams; i++) @@ -1304,8 +1241,6 @@ wq_alloc_failed: subdev_register_failed: atomisp_tpg_unregister_entities(&isp->tpg); tpg_register_failed: - atomisp_file_input_unregister_entities(&isp->file_dev); -file_input_register_failed: for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) atomisp_mipi_csi2_unregister_entities(&isp->csi2_port[i]); csi_and_subdev_probe_failed: @@ -1316,6 +1251,27 @@ v4l2_device_failed: return ret; } +static int atomisp_register_device_nodes(struct atomisp_device *isp) +{ + int i, err; + + for (i = 0; i < isp->num_of_streams; i++) { + err = atomisp_subdev_register_video_nodes(&isp->asd[i], &isp->v4l2_dev); + if (err) + return err; + } + + err = atomisp_create_pads_links(isp); + if (err) + return err; + + err = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); + if (err) + return err; + + return media_device_register(&isp->media_dev); +} + static int atomisp_initialize_modules(struct atomisp_device *isp) { int ret; @@ -1326,13 +1282,6 @@ static int atomisp_initialize_modules(struct atomisp_device *isp) goto error_mipi_csi2; } - ret = atomisp_file_input_init(isp); - if (ret < 0) { - dev_err(isp->dev, - "file input device initialization failed\n"); - goto error_file_input; - } - ret = atomisp_tpg_init(isp); if (ret < 0) { dev_err(isp->dev, "tpg initialization failed\n"); @@ -1350,8 +1299,6 @@ static int atomisp_initialize_modules(struct atomisp_device *isp) error_isp_subdev: error_tpg: atomisp_tpg_cleanup(isp); -error_file_input: - atomisp_file_input_cleanup(isp); error_mipi_csi2: atomisp_mipi_csi2_cleanup(isp); return ret; @@ -1360,7 +1307,6 @@ error_mipi_csi2: static void atomisp_uninitialize_modules(struct atomisp_device *isp) { atomisp_tpg_cleanup(isp); - atomisp_file_input_cleanup(isp); atomisp_mipi_csi2_cleanup(isp); } @@ -1470,39 +1416,6 @@ static bool is_valid_device(struct pci_dev *pdev, const struct pci_device_id *id return true; } -static int init_atomisp_wdts(struct atomisp_device *isp) -{ - int i, err; - - atomic_set(&isp->wdt_work_queued, 0); - isp->wdt_work_queue = alloc_workqueue(isp->v4l2_dev.name, 0, 1); - if (!isp->wdt_work_queue) { - dev_err(isp->dev, "Failed to initialize wdt work queue\n"); - err = -ENOMEM; - goto alloc_fail; - } - INIT_WORK(&isp->wdt_work, atomisp_wdt_work); - - for (i = 0; i < isp->num_of_streams; i++) { - struct atomisp_sub_device *asd = &isp->asd[i]; - - if (!IS_ISP2401) { - timer_setup(&asd->wdt, atomisp_wdt, 0); - } else { - timer_setup(&asd->video_out_capture.wdt, - atomisp_wdt, 0); - timer_setup(&asd->video_out_preview.wdt, - atomisp_wdt, 0); - timer_setup(&asd->video_out_vf.wdt, atomisp_wdt, 0); - timer_setup(&asd->video_out_video_capture.wdt, - atomisp_wdt, 0); - } - } - return 0; -alloc_fail: - return err; -} - #define ATOM_ISP_PCI_BAR 0 static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -1551,9 +1464,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i dev_dbg(&pdev->dev, "atomisp mmio base: %p\n", isp->base); - rt_mutex_init(&isp->mutex); - rt_mutex_init(&isp->loading); - mutex_init(&isp->streamoff_mutex); + mutex_init(&isp->mutex); spin_lock_init(&isp->lock); /* This is not a true PCI device on SoC, so the delay is not needed. */ @@ -1725,8 +1636,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i pci_write_config_dword(pdev, MRFLD_PCI_CSI_AFE_TRIM_CONTROL, csi_afe_trim); } - rt_mutex_lock(&isp->loading); - err = atomisp_initialize_modules(isp); if (err < 0) { dev_err(&pdev->dev, "atomisp_initialize_modules (%d)\n", err); @@ -1738,13 +1647,8 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i dev_err(&pdev->dev, "atomisp_register_entities failed (%d)\n", err); goto register_entities_fail; } - err = atomisp_create_pads_links(isp); - if (err < 0) - goto register_entities_fail; - /* init atomisp wdts */ - err = init_atomisp_wdts(isp); - if (err != 0) - goto wdt_work_queue_fail; + + INIT_WORK(&isp->assert_recovery_work, atomisp_assert_recovery_work); /* save the iunit context only once after all the values are init'ed. */ atomisp_save_iunit_reg(isp); @@ -1777,8 +1681,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i release_firmware(isp->firmware); isp->firmware = NULL; isp->css_env.isp_css_fw.data = NULL; - isp->ready = true; - rt_mutex_unlock(&isp->loading); + + err = atomisp_register_device_nodes(isp); + if (err) + goto css_init_fail; atomisp_drvfs_init(isp); @@ -1789,13 +1695,10 @@ css_init_fail: request_irq_fail: hmm_cleanup(); pm_runtime_get_noresume(&pdev->dev); - destroy_workqueue(isp->wdt_work_queue); -wdt_work_queue_fail: atomisp_unregister_entities(isp); register_entities_fail: atomisp_uninitialize_modules(isp); initialize_modules_fail: - rt_mutex_unlock(&isp->loading); cpu_latency_qos_remove_request(&isp->pm_qos); atomisp_msi_irq_uninit(isp); pci_free_irq_vectors(pdev); @@ -1851,9 +1754,6 @@ static void atomisp_pci_remove(struct pci_dev *pdev) atomisp_msi_irq_uninit(isp); atomisp_unregister_entities(isp); - destroy_workqueue(isp->wdt_work_queue); - atomisp_file_input_cleanup(isp); - release_firmware(isp->firmware); } diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.h b/drivers/staging/media/atomisp/pci/atomisp_v4l2.h index 72611b8286a4..ccf1c0ac17b2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.h @@ -22,16 +22,13 @@ #define __ATOMISP_V4L2_H__ struct atomisp_video_pipe; -struct atomisp_acc_pipe; struct v4l2_device; struct atomisp_device; struct firmware; int atomisp_video_init(struct atomisp_video_pipe *video, const char *name, unsigned int run_mode); -void atomisp_acc_init(struct atomisp_acc_pipe *video, const char *name); void atomisp_video_unregister(struct atomisp_video_pipe *video); -void atomisp_acc_unregister(struct atomisp_acc_pipe *video); const struct firmware *atomisp_load_firmware(struct atomisp_device *isp); int atomisp_csi_lane_config(struct atomisp_device *isp); diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c index f50494123f03..a5fd6d38d3c4 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c @@ -44,16 +44,6 @@ #include "hmm/hmm_common.h" #include "hmm/hmm_bo.h" -static unsigned int order_to_nr(unsigned int order) -{ - return 1U << order; -} - -static unsigned int nr_to_order_bottom(unsigned int nr) -{ - return fls(nr) - 1; -} - static int __bo_init(struct hmm_bo_device *bdev, struct hmm_buffer_object *bo, unsigned int pgnr) { @@ -625,136 +615,40 @@ found: return bo; } -static void free_private_bo_pages(struct hmm_buffer_object *bo, - int free_pgnr) +static void free_pages_bulk_array(unsigned long nr_pages, struct page **page_array) { - int i, ret; + unsigned long i; - for (i = 0; i < free_pgnr; i++) { - ret = set_pages_wb(bo->pages[i], 1); - if (ret) - dev_err(atomisp_dev, - "set page to WB err ...ret = %d\n", - ret); - /* - W/A: set_pages_wb seldom return value = -EFAULT - indicate that address of page is not in valid - range(0xffff880000000000~0xffffc7ffffffffff) - then, _free_pages would panic; Do not know why page - address be valid,it maybe memory corruption by lowmemory - */ - if (!ret) { - __free_pages(bo->pages[i], 0); - } - } + for (i = 0; i < nr_pages; i++) + __free_pages(page_array[i], 0); +} + +static void free_private_bo_pages(struct hmm_buffer_object *bo) +{ + set_pages_array_wb(bo->pages, bo->pgnr); + free_pages_bulk_array(bo->pgnr, bo->pages); } /*Allocate pages which will be used only by ISP*/ static int alloc_private_pages(struct hmm_buffer_object *bo) { + const gfp_t gfp = __GFP_NOWARN | __GFP_RECLAIM | __GFP_FS; int ret; - unsigned int pgnr, order, blk_pgnr, alloc_pgnr; - struct page *pages; - gfp_t gfp = GFP_NOWAIT | __GFP_NOWARN; /* REVISIT: need __GFP_FS too? */ - int i, j; - int failure_number = 0; - bool reduce_order = false; - bool lack_mem = true; - - pgnr = bo->pgnr; - - i = 0; - alloc_pgnr = 0; - - while (pgnr) { - order = nr_to_order_bottom(pgnr); - /* - * if be short of memory, we will set order to 0 - * everytime. - */ - if (lack_mem) - order = HMM_MIN_ORDER; - else if (order > HMM_MAX_ORDER) - order = HMM_MAX_ORDER; -retry: - /* - * When order > HMM_MIN_ORDER, for performance reasons we don't - * want alloc_pages() to sleep. In case it fails and fallbacks - * to HMM_MIN_ORDER or in case the requested order is originally - * the minimum value, we can allow alloc_pages() to sleep for - * robustness purpose. - * - * REVISIT: why __GFP_FS is necessary? - */ - if (order == HMM_MIN_ORDER) { - gfp &= ~GFP_NOWAIT; - gfp |= __GFP_RECLAIM | __GFP_FS; - } - - pages = alloc_pages(gfp, order); - if (unlikely(!pages)) { - /* - * in low memory case, if allocation page fails, - * we turn to try if order=0 allocation could - * succeed. if order=0 fails too, that means there is - * no memory left. - */ - if (order == HMM_MIN_ORDER) { - dev_err(atomisp_dev, - "%s: cannot allocate pages\n", - __func__); - goto cleanup; - } - order = HMM_MIN_ORDER; - failure_number++; - reduce_order = true; - /* - * if fail two times continuously, we think be short - * of memory now. - */ - if (failure_number == 2) { - lack_mem = true; - failure_number = 0; - } - goto retry; - } else { - blk_pgnr = order_to_nr(order); - - /* - * set memory to uncacheable -- UC_MINUS - */ - ret = set_pages_uc(pages, blk_pgnr); - if (ret) { - dev_err(atomisp_dev, - "set page uncacheablefailed.\n"); - - __free_pages(pages, order); - goto cleanup; - } - - for (j = 0; j < blk_pgnr; j++, i++) { - bo->pages[i] = pages + j; - } - - pgnr -= blk_pgnr; + ret = alloc_pages_bulk_array(gfp, bo->pgnr, bo->pages); + if (ret != bo->pgnr) { + free_pages_bulk_array(ret, bo->pages); + return -ENOMEM; + } - /* - * if order is not reduced this time, clear - * failure_number. - */ - if (reduce_order) - reduce_order = false; - else - failure_number = 0; - } + ret = set_pages_array_uc(bo->pages, bo->pgnr); + if (ret) { + dev_err(atomisp_dev, "set pages uncacheable failed.\n"); + free_pages_bulk_array(bo->pgnr, bo->pages); + return ret; } return 0; -cleanup: - alloc_pgnr = i; - free_private_bo_pages(bo, alloc_pgnr); - return -ENOMEM; } static void free_user_pages(struct hmm_buffer_object *bo, @@ -762,12 +656,8 @@ static void free_user_pages(struct hmm_buffer_object *bo, { int i; - if (bo->mem_type == HMM_BO_MEM_TYPE_PFN) { - unpin_user_pages(bo->pages, page_nr); - } else { - for (i = 0; i < page_nr; i++) - put_page(bo->pages[i]); - } + for (i = 0; i < page_nr; i++) + put_page(bo->pages[i]); } /* @@ -777,43 +667,13 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, const void __user *userptr) { int page_nr; - struct vm_area_struct *vma; - - mutex_unlock(&bo->mutex); - mmap_read_lock(current->mm); - vma = find_vma(current->mm, (unsigned long)userptr); - mmap_read_unlock(current->mm); - if (!vma) { - dev_err(atomisp_dev, "find_vma failed\n"); - mutex_lock(&bo->mutex); - return -EFAULT; - } - mutex_lock(&bo->mutex); - /* - * Handle frame buffer allocated in other kerenl space driver - * and map to user space - */ userptr = untagged_addr(userptr); - if (vma->vm_flags & (VM_IO | VM_PFNMAP)) { - page_nr = pin_user_pages((unsigned long)userptr, bo->pgnr, - FOLL_LONGTERM | FOLL_WRITE, - bo->pages, NULL); - bo->mem_type = HMM_BO_MEM_TYPE_PFN; - } else { - /*Handle frame buffer allocated in user space*/ - mutex_unlock(&bo->mutex); - page_nr = get_user_pages_fast((unsigned long)userptr, - (int)(bo->pgnr), 1, bo->pages); - mutex_lock(&bo->mutex); - bo->mem_type = HMM_BO_MEM_TYPE_USER; - } - - dev_dbg(atomisp_dev, "%s: %d %s pages were allocated as 0x%08x\n", - __func__, - bo->pgnr, - bo->mem_type == HMM_BO_MEM_TYPE_USER ? "user" : "pfn", page_nr); + /* Handle frame buffer allocated in user space */ + mutex_unlock(&bo->mutex); + page_nr = get_user_pages_fast((unsigned long)userptr, bo->pgnr, 1, bo->pages); + mutex_lock(&bo->mutex); /* can be written by caller, not forced */ if (page_nr != bo->pgnr) { @@ -854,7 +714,7 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo, mutex_lock(&bo->mutex); check_bo_status_no_goto(bo, HMM_BO_PAGE_ALLOCED, status_err); - bo->pages = kmalloc_array(bo->pgnr, sizeof(struct page *), GFP_KERNEL); + bo->pages = kcalloc(bo->pgnr, sizeof(struct page *), GFP_KERNEL); if (unlikely(!bo->pages)) { ret = -ENOMEM; goto alloc_err; @@ -910,7 +770,7 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo) bo->status &= (~HMM_BO_PAGE_ALLOCED); if (bo->type == HMM_BO_PRIVATE) - free_private_bo_pages(bo, bo->pgnr); + free_private_bo_pages(bo); else if (bo->type == HMM_BO_USER) free_user_pages(bo, bo->pgnr); else diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 0e7c38b2bfe3..67915d76a87f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -950,8 +950,8 @@ sh_css_set_black_frame(struct ia_css_stream *stream, params->fpn_config.data = NULL; } if (!params->fpn_config.data) { - params->fpn_config.data = kvmalloc(height * width * - sizeof(short), GFP_KERNEL); + params->fpn_config.data = kvmalloc(array3_size(height, width, sizeof(short)), + GFP_KERNEL); if (!params->fpn_config.data) { IA_CSS_ERROR("out of memory"); IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO deleted file mode 100644 index 60062d8441b3..000000000000 --- a/drivers/staging/media/av7110/TODO +++ /dev/null @@ -1,3 +0,0 @@ -- This driver is too old and relies on a different API. - Drop it from Kernel on a couple of versions. -- Cleanup patches for the drivers here won't be accepted. diff --git a/drivers/media/usb/cpia2/Kconfig b/drivers/staging/media/deprecated/cpia2/Kconfig index da2c6862b4a2..ee3b25a759d4 100644 --- a/drivers/media/usb/cpia2/Kconfig +++ b/drivers/staging/media/deprecated/cpia2/Kconfig @@ -1,10 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CPIA2 - tristate "CPiA2 Video For Linux" + tristate "CPiA2 Video For Linux (DEPRECATED)" depends on USB && VIDEO_DEV help This is the video4linux driver for cameras based on Vision's CPiA2 (Colour Processor Interface ASIC), such as the Digital Blue QX5 Microscope. If you have one of these cameras, say Y here + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + This driver is also available as a module (cpia2). diff --git a/drivers/media/usb/cpia2/Makefile b/drivers/staging/media/deprecated/cpia2/Makefile index 05664141f4d7..05664141f4d7 100644 --- a/drivers/media/usb/cpia2/Makefile +++ b/drivers/staging/media/deprecated/cpia2/Makefile diff --git a/drivers/staging/media/deprecated/cpia2/TODO b/drivers/staging/media/deprecated/cpia2/TODO new file mode 100644 index 000000000000..92ac8718d164 --- /dev/null +++ b/drivers/staging/media/deprecated/cpia2/TODO @@ -0,0 +1,6 @@ +The cpia2 driver does not use the vb2 framework for streaming +video, instead it implements this in the driver. + +To prevent removal of this driver early 2023 it has to be +converted to use vb2. Contact the linux-media@vger.kernel.org +mailing list if you want to do this. diff --git a/drivers/media/usb/cpia2/cpia2.h b/drivers/staging/media/deprecated/cpia2/cpia2.h index 57b7f1ea68da..57b7f1ea68da 100644 --- a/drivers/media/usb/cpia2/cpia2.h +++ b/drivers/staging/media/deprecated/cpia2/cpia2.h diff --git a/drivers/media/usb/cpia2/cpia2_core.c b/drivers/staging/media/deprecated/cpia2/cpia2_core.c index b5a2d06fb356..b5a2d06fb356 100644 --- a/drivers/media/usb/cpia2/cpia2_core.c +++ b/drivers/staging/media/deprecated/cpia2/cpia2_core.c diff --git a/drivers/media/usb/cpia2/cpia2_registers.h b/drivers/staging/media/deprecated/cpia2/cpia2_registers.h index 8c73812a15c9..8c73812a15c9 100644 --- a/drivers/media/usb/cpia2/cpia2_registers.h +++ b/drivers/staging/media/deprecated/cpia2/cpia2_registers.h diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/staging/media/deprecated/cpia2/cpia2_usb.c index cba03b286473..cba03b286473 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/staging/media/deprecated/cpia2/cpia2_usb.c diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c index 926ecfc9b64a..926ecfc9b64a 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/staging/media/deprecated/cpia2/cpia2_v4l.c diff --git a/drivers/staging/media/deprecated/fsl-viu/Kconfig b/drivers/staging/media/deprecated/fsl-viu/Kconfig new file mode 100644 index 000000000000..399892c69a18 --- /dev/null +++ b/drivers/staging/media/deprecated/fsl-viu/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_VIU + tristate "NXP VIU Video Driver (DEPRECATED)" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C + select VIDEOBUF_DMA_CONTIG + help + Support for Freescale VIU video driver. This device captures + video data, or overlays video on DIU frame buffer. + + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + + Say Y here if you want to enable VIU device on MPC5121e Rev2+. + In doubt, say N. diff --git a/drivers/staging/media/deprecated/fsl-viu/Makefile b/drivers/staging/media/deprecated/fsl-viu/Makefile new file mode 100644 index 000000000000..931ec56ad08c --- /dev/null +++ b/drivers/staging/media/deprecated/fsl-viu/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o diff --git a/drivers/staging/media/deprecated/fsl-viu/TODO b/drivers/staging/media/deprecated/fsl-viu/TODO new file mode 100644 index 000000000000..ecb30a429689 --- /dev/null +++ b/drivers/staging/media/deprecated/fsl-viu/TODO @@ -0,0 +1,7 @@ +This is one of the few drivers still not using the vb2 +framework, so this driver is now deprecated with the intent of +removing it altogether by the beginning of 2023. + +In order to keep this driver it has to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/platform/nxp/fsl-viu.c b/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c index afc96f6db2a1..afc96f6db2a1 100644 --- a/drivers/media/platform/nxp/fsl-viu.c +++ b/drivers/staging/media/deprecated/fsl-viu/fsl-viu.c diff --git a/drivers/media/pci/meye/Kconfig b/drivers/staging/media/deprecated/meye/Kconfig index 3e69b66f1a5b..f135f8568c85 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/staging/media/deprecated/meye/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_MEYE - tristate "Sony Vaio Picturebook Motion Eye Video For Linux" + tristate "Sony Vaio Picturebook Motion Eye Video For Linux (DEPRECATED)" depends on PCI && VIDEO_DEV depends on SONY_LAPTOP depends on X86 || COMPILE_TEST @@ -12,5 +12,8 @@ config VIDEO_MEYE If you say Y or M here, you need to say Y or M to "Sony Laptop Extras" in the misc device section. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called meye. diff --git a/drivers/media/pci/meye/Makefile b/drivers/staging/media/deprecated/meye/Makefile index 36f1f86f0d58..36f1f86f0d58 100644 --- a/drivers/media/pci/meye/Makefile +++ b/drivers/staging/media/deprecated/meye/Makefile diff --git a/drivers/staging/media/deprecated/meye/TODO b/drivers/staging/media/deprecated/meye/TODO new file mode 100644 index 000000000000..6d1d1433d5a0 --- /dev/null +++ b/drivers/staging/media/deprecated/meye/TODO @@ -0,0 +1,6 @@ +The meye driver does not use the vb2 framework for streaming +video, instead it implements this in the driver. + +To prevent removal of this driver early 2023 it has to be +converted to use vb2. Contact the linux-media@vger.kernel.org +mailing list if you want to do this. diff --git a/drivers/media/pci/meye/meye.c b/drivers/staging/media/deprecated/meye/meye.c index 5d87efd9b95c..5d87efd9b95c 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/staging/media/deprecated/meye/meye.c diff --git a/drivers/media/pci/meye/meye.h b/drivers/staging/media/deprecated/meye/meye.h index 5fa6552cf93d..5fa6552cf93d 100644 --- a/drivers/media/pci/meye/meye.h +++ b/drivers/staging/media/deprecated/meye/meye.h diff --git a/drivers/staging/media/deprecated/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/Kconfig new file mode 100644 index 000000000000..54154da79f59 --- /dev/null +++ b/drivers/staging/media/deprecated/saa7146/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +source "drivers/staging/media/deprecated/saa7146/common/Kconfig" +source "drivers/staging/media/deprecated/saa7146/av7110/Kconfig" +source "drivers/staging/media/deprecated/saa7146/saa7146/Kconfig" +source "drivers/staging/media/deprecated/saa7146/ttpci/Kconfig" diff --git a/drivers/staging/media/deprecated/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/Makefile new file mode 100644 index 000000000000..68e7aa10c639 --- /dev/null +++ b/drivers/staging/media/deprecated/saa7146/Makefile @@ -0,0 +1,2 @@ + # SPDX-License-Identifier: GPL-2.0-only +obj-y += common/ av7110/ saa7146/ ttpci/ diff --git a/drivers/staging/media/av7110/Kconfig b/drivers/staging/media/deprecated/saa7146/av7110/Kconfig index 9faf9d2d4001..1571eab31926 100644 --- a/drivers/staging/media/av7110/Kconfig +++ b/drivers/staging/media/deprecated/saa7146/av7110/Kconfig @@ -5,7 +5,7 @@ config DVB_AV7110_IR default DVB_AV7110 config DVB_AV7110 - tristate "AV7110 cards" + tristate "AV7110 cards (DEPRECATED)" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV @@ -35,10 +35,13 @@ config DVB_AV7110 kernel image by adding the filename to the EXTRA_FIRMWARE configuration option string. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a card and want to use it. config DVB_AV7110_OSD - bool "AV7110 OSD support" + bool "AV7110 OSD support (DEPRECATED)" depends on DVB_AV7110 default y if DVB_AV7110=y || DVB_AV7110=m help @@ -49,10 +52,13 @@ config DVB_AV7110_OSD Anyway, some popular DVB software like VDR uses this OSD to render its menus, so say Y if you want to use this software. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + All other people say N. config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch" + tristate "AV7110 cards with Budget Patch (DEPRECATED)" depends on DVB_BUDGET_CORE && I2C depends on DVB_AV7110 select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -68,6 +74,9 @@ config DVB_BUDGET_PATCH standard AV7110 driver prior to loading this driver. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the @@ -80,7 +89,7 @@ if DVB_AV7110 # it if we drop support for AV7110, as no other driver will use it. config DVB_SP8870 - tristate "Spase sp8870 based" + tristate "Spase sp8870 based (DEPRECATED)" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -91,4 +100,7 @@ config DVB_SP8870 download/extract it, and then copy it to /usr/lib/hotplug/firmware or /lib/firmware (depending on configuration of firmware hotplug). + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + endif diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/deprecated/saa7146/av7110/Makefile index 307b267598ea..c04cd0a59109 100644 --- a/drivers/staging/media/av7110/Makefile +++ b/drivers/staging/media/deprecated/saa7146/av7110/Makefile @@ -18,5 +18,6 @@ obj-$(CONFIG_DVB_SP8870) += sp8870.o ccflags-y += -I $(srctree)/drivers/media/dvb-frontends ccflags-y += -I $(srctree)/drivers/media/tuners -ccflags-y += -I $(srctree)/drivers/media/pci/ttpci ccflags-y += -I $(srctree)/drivers/media/common +ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/ttpci +ccflags-y += -I $(srctree)/drivers/staging/media/deprecated/saa7146/common diff --git a/drivers/staging/media/deprecated/saa7146/av7110/TODO b/drivers/staging/media/deprecated/saa7146/av7110/TODO new file mode 100644 index 000000000000..38817e04bb67 --- /dev/null +++ b/drivers/staging/media/deprecated/saa7146/av7110/TODO @@ -0,0 +1,9 @@ +- This driver is too old and relies on a different API. + Drop it from Kernel on a couple of versions. +- Cleanup patches for the drivers here won't be accepted. + +These drivers are now deprecated with the intent of +removing them altogether by the beginning of 2023. + +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst index 33b5363317f1..33b5363317f1 100644 --- a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-bilingual-channel-select.rst diff --git a/drivers/staging/media/av7110/audio-channel-select.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst index 74093df92a68..74093df92a68 100644 --- a/drivers/staging/media/av7110/audio-channel-select.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-channel-select.rst diff --git a/drivers/staging/media/av7110/audio-clear-buffer.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst index a0ebb0278260..a0ebb0278260 100644 --- a/drivers/staging/media/av7110/audio-clear-buffer.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-clear-buffer.rst diff --git a/drivers/staging/media/av7110/audio-continue.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst index a2e9850f37f2..a2e9850f37f2 100644 --- a/drivers/staging/media/av7110/audio-continue.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-continue.rst diff --git a/drivers/staging/media/av7110/audio-fclose.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst index 77857d578e83..77857d578e83 100644 --- a/drivers/staging/media/av7110/audio-fclose.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-fclose.rst diff --git a/drivers/staging/media/av7110/audio-fopen.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst index 774daaab3bad..774daaab3bad 100644 --- a/drivers/staging/media/av7110/audio-fopen.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-fopen.rst diff --git a/drivers/staging/media/av7110/audio-fwrite.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst index 7b096ac2b6c4..7b096ac2b6c4 100644 --- a/drivers/staging/media/av7110/audio-fwrite.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-fwrite.rst diff --git a/drivers/staging/media/av7110/audio-get-capabilities.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst index 6d9eb71dad17..6d9eb71dad17 100644 --- a/drivers/staging/media/av7110/audio-get-capabilities.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-get-capabilities.rst diff --git a/drivers/staging/media/av7110/audio-get-status.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst index 7ae8db2e65e9..7ae8db2e65e9 100644 --- a/drivers/staging/media/av7110/audio-get-status.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-get-status.rst diff --git a/drivers/staging/media/av7110/audio-pause.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst index d37d1ddce4df..d37d1ddce4df 100644 --- a/drivers/staging/media/av7110/audio-pause.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-pause.rst diff --git a/drivers/staging/media/av7110/audio-play.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst index e591930b6ca7..e591930b6ca7 100644 --- a/drivers/staging/media/av7110/audio-play.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-play.rst diff --git a/drivers/staging/media/av7110/audio-select-source.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst index 6a0c0f365eb1..6a0c0f365eb1 100644 --- a/drivers/staging/media/av7110/audio-select-source.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-select-source.rst diff --git a/drivers/staging/media/av7110/audio-set-av-sync.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst index 85a8016bf025..85a8016bf025 100644 --- a/drivers/staging/media/av7110/audio-set-av-sync.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-av-sync.rst diff --git a/drivers/staging/media/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst index 80d551a2053a..80d551a2053a 100644 --- a/drivers/staging/media/av7110/audio-set-bypass-mode.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-bypass-mode.rst diff --git a/drivers/staging/media/av7110/audio-set-id.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst index 39ad846d412d..39ad846d412d 100644 --- a/drivers/staging/media/av7110/audio-set-id.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-id.rst diff --git a/drivers/staging/media/av7110/audio-set-mixer.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst index 45dbdf4801e0..45dbdf4801e0 100644 --- a/drivers/staging/media/av7110/audio-set-mixer.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mixer.rst diff --git a/drivers/staging/media/av7110/audio-set-mute.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst index 987751f92967..987751f92967 100644 --- a/drivers/staging/media/av7110/audio-set-mute.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-mute.rst diff --git a/drivers/staging/media/av7110/audio-set-streamtype.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst index 77d73c74882f..77d73c74882f 100644 --- a/drivers/staging/media/av7110/audio-set-streamtype.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-set-streamtype.rst diff --git a/drivers/staging/media/av7110/audio-stop.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst index d77f786fd797..d77f786fd797 100644 --- a/drivers/staging/media/av7110/audio-stop.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio-stop.rst diff --git a/drivers/staging/media/av7110/audio.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio.rst index aa753336b31f..aa753336b31f 100644 --- a/drivers/staging/media/av7110/audio.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio.rst diff --git a/drivers/staging/media/av7110/audio_data_types.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst index 4744529136a8..4744529136a8 100644 --- a/drivers/staging/media/av7110/audio_data_types.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio_data_types.rst diff --git a/drivers/staging/media/av7110/audio_function_calls.rst b/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst index fa5ba9539caf..fa5ba9539caf 100644 --- a/drivers/staging/media/av7110/audio_function_calls.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/audio_function_calls.rst diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110.c index df81a9b744c2..df81a9b744c2 100644 --- a/drivers/staging/media/av7110/av7110.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110.c diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/deprecated/saa7146/av7110/av7110.h index 809d938ae166..9fde69b38f1c 100644 --- a/drivers/staging/media/av7110/av7110.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110.h @@ -33,7 +33,7 @@ #include "stv0297.h" #include "l64781.h" -#include <media/drv-intf/saa7146_vv.h> +#include "saa7146_vv.h" #define ANALOG_TUNER_VES1820 1 diff --git a/drivers/staging/media/av7110/av7110_av.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c index ab7cf496b454..0bf513c26b6b 100644 --- a/drivers/staging/media/av7110/av7110_av.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.c @@ -106,7 +106,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av, int ret = 0; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); + dprintk(2, "av7110:%p, dvb_demux_feed:%p\n", av7110, dvbdmxfeed); if (av7110->playing || (av7110->rec_mode & av)) return -EBUSY; diff --git a/drivers/staging/media/av7110/av7110_av.h b/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h index 71bbd4391f57..71bbd4391f57 100644 --- a/drivers/staging/media/av7110/av7110_av.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_av.h diff --git a/drivers/staging/media/av7110/av7110_ca.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c index c1338e074a3d..c1338e074a3d 100644 --- a/drivers/staging/media/av7110/av7110_ca.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.c diff --git a/drivers/staging/media/av7110/av7110_ca.h b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h index a6e3f2955730..a6e3f2955730 100644 --- a/drivers/staging/media/av7110/av7110_ca.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ca.h diff --git a/drivers/staging/media/av7110/av7110_hw.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c index 93ca31e38ddd..93ca31e38ddd 100644 --- a/drivers/staging/media/av7110/av7110_hw.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.c diff --git a/drivers/staging/media/av7110/av7110_hw.h b/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h index 6380d8950c69..6380d8950c69 100644 --- a/drivers/staging/media/av7110/av7110_hw.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_hw.h diff --git a/drivers/staging/media/av7110/av7110_ipack.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c index 30330ed01ce8..30330ed01ce8 100644 --- a/drivers/staging/media/av7110/av7110_ipack.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.c diff --git a/drivers/staging/media/av7110/av7110_ipack.h b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h index 943ec899bb93..943ec899bb93 100644 --- a/drivers/staging/media/av7110/av7110_ipack.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ipack.h diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c index a851ba328e4a..a851ba328e4a 100644 --- a/drivers/staging/media/av7110/av7110_ir.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_ir.c diff --git a/drivers/staging/media/av7110/av7110_v4l.c b/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c index c89f536f699c..c89f536f699c 100644 --- a/drivers/staging/media/av7110/av7110_v4l.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/av7110_v4l.c diff --git a/drivers/staging/media/av7110/budget-patch.c b/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c index d173c8ade6a7..d173c8ade6a7 100644 --- a/drivers/staging/media/av7110/budget-patch.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/budget-patch.c diff --git a/drivers/staging/media/av7110/dvb_filter.c b/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c index 8c2eca5dcdc9..8c2eca5dcdc9 100644 --- a/drivers/staging/media/av7110/dvb_filter.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.c diff --git a/drivers/staging/media/av7110/dvb_filter.h b/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h index 67a3c6333bca..67a3c6333bca 100644 --- a/drivers/staging/media/av7110/dvb_filter.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/dvb_filter.h diff --git a/drivers/staging/media/av7110/sp8870.c b/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c index 9767159aeb9b..9767159aeb9b 100644 --- a/drivers/staging/media/av7110/sp8870.c +++ b/drivers/staging/media/deprecated/saa7146/av7110/sp8870.c diff --git a/drivers/staging/media/av7110/sp8870.h b/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h index 5eacf39f425e..5eacf39f425e 100644 --- a/drivers/staging/media/av7110/sp8870.h +++ b/drivers/staging/media/deprecated/saa7146/av7110/sp8870.h diff --git a/drivers/staging/media/av7110/video-clear-buffer.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst index a7730559bbb2..a7730559bbb2 100644 --- a/drivers/staging/media/av7110/video-clear-buffer.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-clear-buffer.rst diff --git a/drivers/staging/media/av7110/video-command.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst index cae9445eb3af..cae9445eb3af 100644 --- a/drivers/staging/media/av7110/video-command.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-command.rst diff --git a/drivers/staging/media/av7110/video-continue.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst index bc34bf3989e4..bc34bf3989e4 100644 --- a/drivers/staging/media/av7110/video-continue.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-continue.rst diff --git a/drivers/staging/media/av7110/video-fast-forward.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst index e71fa8d6965b..e71fa8d6965b 100644 --- a/drivers/staging/media/av7110/video-fast-forward.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-fast-forward.rst diff --git a/drivers/staging/media/av7110/video-fclose.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst index 01d24d548439..01d24d548439 100644 --- a/drivers/staging/media/av7110/video-fclose.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-fclose.rst diff --git a/drivers/staging/media/av7110/video-fopen.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst index 1371b083e4e8..1371b083e4e8 100644 --- a/drivers/staging/media/av7110/video-fopen.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-fopen.rst diff --git a/drivers/staging/media/av7110/video-freeze.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst index 4321f257cb70..4321f257cb70 100644 --- a/drivers/staging/media/av7110/video-freeze.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-freeze.rst diff --git a/drivers/staging/media/av7110/video-fwrite.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst index a07fd7d7a40e..a07fd7d7a40e 100644 --- a/drivers/staging/media/av7110/video-fwrite.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-fwrite.rst diff --git a/drivers/staging/media/av7110/video-get-capabilities.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst index 01e09f56656c..01e09f56656c 100644 --- a/drivers/staging/media/av7110/video-get-capabilities.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-capabilities.rst diff --git a/drivers/staging/media/av7110/video-get-event.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst index 90382bc36cfe..90382bc36cfe 100644 --- a/drivers/staging/media/av7110/video-get-event.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-event.rst diff --git a/drivers/staging/media/av7110/video-get-frame-count.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst index b48ac8c58a41..b48ac8c58a41 100644 --- a/drivers/staging/media/av7110/video-get-frame-count.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-frame-count.rst diff --git a/drivers/staging/media/av7110/video-get-pts.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst index fedaff41be0b..fedaff41be0b 100644 --- a/drivers/staging/media/av7110/video-get-pts.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-pts.rst diff --git a/drivers/staging/media/av7110/video-get-size.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst index de34331c5bd1..de34331c5bd1 100644 --- a/drivers/staging/media/av7110/video-get-size.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-size.rst diff --git a/drivers/staging/media/av7110/video-get-status.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst index 9b86fbf411d4..9b86fbf411d4 100644 --- a/drivers/staging/media/av7110/video-get-status.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-get-status.rst diff --git a/drivers/staging/media/av7110/video-play.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst index 35ac8b98fdbf..35ac8b98fdbf 100644 --- a/drivers/staging/media/av7110/video-play.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-play.rst diff --git a/drivers/staging/media/av7110/video-select-source.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst index 929a20985d53..929a20985d53 100644 --- a/drivers/staging/media/av7110/video-select-source.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-select-source.rst diff --git a/drivers/staging/media/av7110/video-set-blank.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst index 70249a6ba125..70249a6ba125 100644 --- a/drivers/staging/media/av7110/video-set-blank.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-set-blank.rst diff --git a/drivers/staging/media/av7110/video-set-display-format.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst index 1de4f40ae732..1de4f40ae732 100644 --- a/drivers/staging/media/av7110/video-set-display-format.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-set-display-format.rst diff --git a/drivers/staging/media/av7110/video-set-format.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst index bb64e37ae081..bb64e37ae081 100644 --- a/drivers/staging/media/av7110/video-set-format.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-set-format.rst diff --git a/drivers/staging/media/av7110/video-set-streamtype.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst index 1f31c048bdbc..1f31c048bdbc 100644 --- a/drivers/staging/media/av7110/video-set-streamtype.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-set-streamtype.rst diff --git a/drivers/staging/media/av7110/video-slowmotion.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst index 1478fcc30cb8..1478fcc30cb8 100644 --- a/drivers/staging/media/av7110/video-slowmotion.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-slowmotion.rst diff --git a/drivers/staging/media/av7110/video-stillpicture.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst index d25384222a20..d25384222a20 100644 --- a/drivers/staging/media/av7110/video-stillpicture.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-stillpicture.rst diff --git a/drivers/staging/media/av7110/video-stop.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst index 96f61c5b48a2..96f61c5b48a2 100644 --- a/drivers/staging/media/av7110/video-stop.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-stop.rst diff --git a/drivers/staging/media/av7110/video-try-command.rst b/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst index 79bf3dfb8a32..79bf3dfb8a32 100644 --- a/drivers/staging/media/av7110/video-try-command.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video-try-command.rst diff --git a/drivers/staging/media/av7110/video.rst b/drivers/staging/media/deprecated/saa7146/av7110/video.rst index 808705b769a1..808705b769a1 100644 --- a/drivers/staging/media/av7110/video.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video.rst diff --git a/drivers/staging/media/av7110/video_function_calls.rst b/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst index 20a897be5dca..20a897be5dca 100644 --- a/drivers/staging/media/av7110/video_function_calls.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video_function_calls.rst diff --git a/drivers/staging/media/av7110/video_types.rst b/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst index c4557d328b7a..c4557d328b7a 100644 --- a/drivers/staging/media/av7110/video_types.rst +++ b/drivers/staging/media/deprecated/saa7146/av7110/video_types.rst diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/common/Kconfig index a0aa155e5d85..a0aa155e5d85 100644 --- a/drivers/media/common/saa7146/Kconfig +++ b/drivers/staging/media/deprecated/saa7146/common/Kconfig diff --git a/drivers/media/common/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/common/Makefile index 2a6337feaec8..2a6337feaec8 100644 --- a/drivers/media/common/saa7146/Makefile +++ b/drivers/staging/media/deprecated/saa7146/common/Makefile diff --git a/include/media/drv-intf/saa7146.h b/drivers/staging/media/deprecated/saa7146/common/saa7146.h index 71ce63c99cb4..71ce63c99cb4 100644 --- a/include/media/drv-intf/saa7146.h +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146.h diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c index e50fa0ff7c5d..da21d346b870 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_core.c @@ -8,8 +8,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/drv-intf/saa7146.h> #include <linux/module.h> +#include "saa7146.h" static int saa7146_num; diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c index e9a15de6126e..aa14698a9c54 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_fops.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> +#include "saa7146_vv.h" /****************************************************************************/ /* resource management functions, shamelessly stolen from saa7134 driver */ diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c index 6c9946a402ee..b1222a4cfa4a 100644 --- a/drivers/media/common/saa7146/saa7146_hlp.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_hlp.c @@ -3,7 +3,7 @@ #include <linux/kernel.h> #include <linux/export.h> -#include <media/drv-intf/saa7146_vv.h> +#include "saa7146_vv.h" static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format) { diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c index df9ebe2a168c..7a33fe51775a 100644 --- a/drivers/media/common/saa7146/saa7146_i2c.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_i2c.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/drv-intf/saa7146_vv.h> +#include "saa7146_vv.h" static u32 saa7146_i2c_func(struct i2c_adapter *adapter) { diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c index bd442b984423..2d4a05d7bc5b 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_vbi.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include <media/drv-intf/saa7146_vv.h> +#include "saa7146_vv.h" static int vbi_pixel_to_capture = 720 * 2; diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c index 2296765079a4..4598a44231fa 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_video.c @@ -1,10 +1,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <media/drv-intf/saa7146_vv.h> #include <media/v4l2-event.h> #include <media/v4l2-ctrls.h> #include <linux/module.h> #include <linux/kernel.h> +#include "saa7146_vv.h" static int max_memory = 32; diff --git a/include/media/drv-intf/saa7146_vv.h b/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h index 635805fb35e8..d7bd916fe3ad 100644 --- a/include/media/drv-intf/saa7146_vv.h +++ b/drivers/staging/media/deprecated/saa7146/common/saa7146_vv.h @@ -5,8 +5,8 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-fh.h> -#include <media/drv-intf/saa7146.h> #include <media/videobuf-dma-sg.h> +#include "saa7146.h" #define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */ #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig index 3bbb68a0ed7b..228e8d3f8d2b 100644 --- a/drivers/media/pci/saa7146/Kconfig +++ b/drivers/staging/media/deprecated/saa7146/saa7146/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" + tristate "Hexium Gemini frame grabber (DEPRECATED)" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help @@ -8,22 +8,28 @@ config VIDEO_HEXIUM_GEMINI grabber card by Hexium. Please note that the Gemini Dual card is *not* fully supported. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called hexium_gemini. config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" + tristate "Hexium HV-PCI6 and Orion frame grabber (DEPRECATED)" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help This is a video4linux driver for the Hexium HV-PCI6 and Orion frame grabber cards by Hexium. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called hexium_orion. config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" + tristate "Siemens-Nixdorf 'Multimedia eXtension Board' (DEPRECATED)" depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV select VIDEO_TUNER @@ -35,5 +41,8 @@ config VIDEO_MXB This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called mxb. diff --git a/drivers/media/pci/saa7146/Makefile b/drivers/staging/media/deprecated/saa7146/saa7146/Makefile index 37c9336f83d5..37c9336f83d5 100644 --- a/drivers/media/pci/saa7146/Makefile +++ b/drivers/staging/media/deprecated/saa7146/saa7146/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/saa7146/TODO b/drivers/staging/media/deprecated/saa7146/saa7146/TODO new file mode 100644 index 000000000000..c9ae2ec79cea --- /dev/null +++ b/drivers/staging/media/deprecated/saa7146/saa7146/TODO @@ -0,0 +1,7 @@ +The saa7146-based drivers are one of the few drivers still not using +the vb2 framework, so these drivers are now deprecated with the intent of +removing them altogether by the beginning of 2023. + +In order to keep these drivers they have to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c index 3947701cd6c7..124e82bd4507 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/staging/media/deprecated/saa7146/saa7146/hexium_gemini.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug -#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/kernel.h> +#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c index 2eb4bee16b71..ebd63998ac79 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/staging/media/deprecated/saa7146/saa7146/hexium_orion.c @@ -13,9 +13,9 @@ #define DEBUG_VARIABLE debug -#include <media/drv-intf/saa7146_vv.h> #include <linux/module.h> #include <linux/kernel.h> +#include "../common/saa7146_vv.h" static int debug; module_param(debug, int, 0); diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c index 7ded8f5b05cb..3e568f952dae 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/staging/media/deprecated/saa7146/saa7146/mxb.c @@ -13,13 +13,13 @@ #define DEBUG_VARIABLE debug -#include <media/drv-intf/saa7146_vv.h> #include <media/tuner.h> #include <media/v4l2-common.h> #include <media/i2c/saa7115.h> #include <linux/module.h> #include <linux/kernel.h> +#include "../common/saa7146_vv.h" #include "tea6415c.h" #include "tea6420.h" diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig index 65a6832a6b96..8c85ed58e938 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/staging/media/deprecated/saa7146/ttpci/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" + tristate "SAA7146 DVB cards (aka Budget, Nova-PCI) (DEPRECATED)" depends on DVB_CORE && PCI && I2C select VIDEO_SAA7146 select TTPCI_EEPROM @@ -10,7 +10,7 @@ config DVB_BUDGET_CORE MPEG2 decoder. config DVB_BUDGET - tristate "Budget cards" + tristate "Budget cards (DEPRECATED)" depends on DVB_BUDGET_CORE && I2C select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT @@ -30,13 +30,16 @@ config DVB_BUDGET or Nova-PCI cards) without onboard MPEG2 decoder, and without analog inputs or an onboard Common Interface connector. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget. config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector" + tristate "Budget cards with onboard CI connector (DEPRECATED)" depends on DVB_BUDGET_CORE && I2C select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT @@ -57,13 +60,16 @@ config DVB_BUDGET_CI Note: The Common Interface is not yet supported by this driver due to lack of information from the vendor. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the module will be called budget-ci. config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs" + tristate "Budget cards with analog video inputs (DEPRECATED)" depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV @@ -80,6 +86,9 @@ config DVB_BUDGET_AV (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, but with one or more analog video inputs. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a card and want to use it. To compile this driver as a module, choose M here: the diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/staging/media/deprecated/saa7146/ttpci/Makefile index b0708f6e40cc..b0708f6e40cc 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/staging/media/deprecated/saa7146/ttpci/Makefile diff --git a/drivers/staging/media/deprecated/saa7146/ttpci/TODO b/drivers/staging/media/deprecated/saa7146/ttpci/TODO new file mode 100644 index 000000000000..c9ae2ec79cea --- /dev/null +++ b/drivers/staging/media/deprecated/saa7146/ttpci/TODO @@ -0,0 +1,7 @@ +The saa7146-based drivers are one of the few drivers still not using +the vb2 framework, so these drivers are now deprecated with the intent of +removing them altogether by the beginning of 2023. + +In order to keep these drivers they have to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c index 3cb83005cf09..0c61a2dec221 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/staging/media/deprecated/saa7146/ttpci/budget-av.c @@ -29,7 +29,7 @@ #include "tda1004x.h" #include "tua6100.h" #include "dvb-pll.h" -#include <media/drv-intf/saa7146_vv.h> +#include "../common/saa7146_vv.h" #include <linux/module.h> #include <linux/errno.h> #include <linux/slab.h> diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c index d59d18647371..d59d18647371 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/staging/media/deprecated/saa7146/ttpci/budget-ci.c diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c index 5d5796f24469..5d5796f24469 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/staging/media/deprecated/saa7146/ttpci/budget-core.c diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/staging/media/deprecated/saa7146/ttpci/budget.c index a88711a3ac7f..a88711a3ac7f 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/staging/media/deprecated/saa7146/ttpci/budget.c diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/staging/media/deprecated/saa7146/ttpci/budget.h index bd87432e6cde..82cc0df492b3 100644 --- a/drivers/media/pci/ttpci/budget.h +++ b/drivers/staging/media/deprecated/saa7146/ttpci/budget.h @@ -13,7 +13,7 @@ #include <linux/module.h> #include <linux/mutex.h> -#include <media/drv-intf/saa7146.h> +#include "../common/saa7146.h" extern int budget_debug; diff --git a/drivers/staging/media/stkwebcam/Kconfig b/drivers/staging/media/deprecated/stkwebcam/Kconfig index 4450403dff41..4450403dff41 100644 --- a/drivers/staging/media/stkwebcam/Kconfig +++ b/drivers/staging/media/deprecated/stkwebcam/Kconfig diff --git a/drivers/staging/media/stkwebcam/Makefile b/drivers/staging/media/deprecated/stkwebcam/Makefile index 17ad7b6f43d0..17ad7b6f43d0 100644 --- a/drivers/staging/media/stkwebcam/Makefile +++ b/drivers/staging/media/deprecated/stkwebcam/Makefile diff --git a/drivers/staging/media/stkwebcam/TODO b/drivers/staging/media/deprecated/stkwebcam/TODO index 735304a72729..735304a72729 100644 --- a/drivers/staging/media/stkwebcam/TODO +++ b/drivers/staging/media/deprecated/stkwebcam/TODO diff --git a/drivers/staging/media/stkwebcam/stk-sensor.c b/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c index 94aa6a27f934..94aa6a27f934 100644 --- a/drivers/staging/media/stkwebcam/stk-sensor.c +++ b/drivers/staging/media/deprecated/stkwebcam/stk-sensor.c diff --git a/drivers/staging/media/stkwebcam/stk-webcam.c b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c index 787edb3d47c2..787edb3d47c2 100644 --- a/drivers/staging/media/stkwebcam/stk-webcam.c +++ b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.c diff --git a/drivers/staging/media/stkwebcam/stk-webcam.h b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h index 136decffe9ce..136decffe9ce 100644 --- a/drivers/staging/media/stkwebcam/stk-webcam.h +++ b/drivers/staging/media/deprecated/stkwebcam/stk-webcam.h diff --git a/drivers/media/usb/tm6000/Kconfig b/drivers/staging/media/deprecated/tm6000/Kconfig index 56e977deba81..73d72e49eb28 100644 --- a/drivers/media/usb/tm6000/Kconfig +++ b/drivers/staging/media/deprecated/tm6000/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_TM6000 - tristate "TV Master TM5600/6000/6010 driver" + tristate "TV Master TM5600/6000/6010 driver (DEPRECATED)" depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB select VIDEO_TUNER select MEDIA_TUNER_XC2028 @@ -13,6 +13,9 @@ config VIDEO_TM6000 only compressed MPEG data over the usb bus, so you need an external software decoder to watch TV on your computer. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + Say Y if you own such a device and want to use it. config VIDEO_TM6000_ALSA diff --git a/drivers/media/usb/tm6000/Makefile b/drivers/staging/media/deprecated/tm6000/Makefile index 75247a02a485..75247a02a485 100644 --- a/drivers/media/usb/tm6000/Makefile +++ b/drivers/staging/media/deprecated/tm6000/Makefile diff --git a/drivers/staging/media/deprecated/tm6000/TODO b/drivers/staging/media/deprecated/tm6000/TODO new file mode 100644 index 000000000000..ecb30a429689 --- /dev/null +++ b/drivers/staging/media/deprecated/tm6000/TODO @@ -0,0 +1,7 @@ +This is one of the few drivers still not using the vb2 +framework, so this driver is now deprecated with the intent of +removing it altogether by the beginning of 2023. + +In order to keep this driver it has to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c index a19a46770c2b..a19a46770c2b 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-alsa.c diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/staging/media/deprecated/tm6000/tm6000-cards.c index 98f4a63adc2a..98f4a63adc2a 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-cards.c diff --git a/drivers/media/usb/tm6000/tm6000-core.c b/drivers/staging/media/deprecated/tm6000/tm6000-core.c index 5c8cbc5d6f72..5c8cbc5d6f72 100644 --- a/drivers/media/usb/tm6000/tm6000-core.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-core.c diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c index ee04973cbf93..ee04973cbf93 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-dvb.c diff --git a/drivers/media/usb/tm6000/tm6000-i2c.c b/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c index 7554b93b82e6..7554b93b82e6 100644 --- a/drivers/media/usb/tm6000/tm6000-i2c.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-i2c.c diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/staging/media/deprecated/tm6000/tm6000-input.c index 5136e9e202f1..5136e9e202f1 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-input.c diff --git a/drivers/media/usb/tm6000/tm6000-regs.h b/drivers/staging/media/deprecated/tm6000/tm6000-regs.h index 6a181f2e7ef2..6a181f2e7ef2 100644 --- a/drivers/media/usb/tm6000/tm6000-regs.h +++ b/drivers/staging/media/deprecated/tm6000/tm6000-regs.h diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/staging/media/deprecated/tm6000/tm6000-stds.c index 858cb4f3a9ca..858cb4f3a9ca 100644 --- a/drivers/media/usb/tm6000/tm6000-stds.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-stds.c diff --git a/drivers/media/usb/tm6000/tm6000-usb-isoc.h b/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h index e3c6933f854d..e3c6933f854d 100644 --- a/drivers/media/usb/tm6000/tm6000-usb-isoc.h +++ b/drivers/staging/media/deprecated/tm6000/tm6000-usb-isoc.h diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/staging/media/deprecated/tm6000/tm6000-video.c index d855a19551f3..e06ed21edbdd 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/staging/media/deprecated/tm6000/tm6000-video.c @@ -916,8 +916,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } - field = f->fmt.pix.field; - field = V4L2_FIELD_INTERLACED; tm6000_get_std_res(dev); diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/staging/media/deprecated/tm6000/tm6000.h index c08c95312739..c08c95312739 100644 --- a/drivers/media/usb/tm6000/tm6000.h +++ b/drivers/staging/media/deprecated/tm6000/tm6000.h diff --git a/drivers/staging/media/deprecated/vpfe_capture/Kconfig b/drivers/staging/media/deprecated/vpfe_capture/Kconfig new file mode 100644 index 000000000000..10250e7e566b --- /dev/null +++ b/drivers/staging/media/deprecated/vpfe_capture/Kconfig @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_DM6446_CCDC + tristate "TI DM6446 CCDC video capture driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST + depends on I2C + select VIDEOBUF_DMA_CONTIG + help + Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces + with decoder modules such as TVP5146 over BT656 or + sensor module such as MT9T001 over a raw interface. This + module configures the interface and CCDC/ISIF to do + video frame capture from slave decoders. + + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + + To compile this driver as a module, choose M here. There will + be two modules called vpfe_capture.ko and dm644x_ccdc.ko + +config VIDEO_DM355_CCDC + tristate "TI DM355 CCDC video capture driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST + depends on I2C + select VIDEOBUF_DMA_CONTIG + help + Enables DM355 CCD hw module. DM355 CCDC hw interfaces + with decoder modules such as TVP5146 over BT656 or + sensor module such as MT9T001 over a raw interface. This + module configures the interface and CCDC/ISIF to do + video frame capture from a slave decoders + + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + + To compile this driver as a module, choose M here. There will + be two modules called vpfe_capture.ko and dm355_ccdc.ko + +config VIDEO_DM365_ISIF + tristate "TI DM365 ISIF video capture driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_DAVINCI || COMPILE_TEST + depends on I2C + select VIDEOBUF_DMA_CONTIG + help + Enables ISIF hw module. This is the hardware module for + configuring ISIF in VPFE to capture Raw Bayer RGB data from + a image sensor or YUV data from a YUV source. + + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + + To compile this driver as a module, choose M here. There will + be two modules called vpfe_capture.ko and isif.ko diff --git a/drivers/staging/media/deprecated/vpfe_capture/Makefile b/drivers/staging/media/deprecated/vpfe_capture/Makefile new file mode 100644 index 000000000000..609e8dc09ce7 --- /dev/null +++ b/drivers/staging/media/deprecated/vpfe_capture/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o dm644x_ccdc.o +obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o dm355_ccdc.o +obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o isif.o diff --git a/drivers/staging/media/deprecated/vpfe_capture/TODO b/drivers/staging/media/deprecated/vpfe_capture/TODO new file mode 100644 index 000000000000..ce654d7337af --- /dev/null +++ b/drivers/staging/media/deprecated/vpfe_capture/TODO @@ -0,0 +1,7 @@ +These are one of the few drivers still not using the vb2 +framework, so these drivers are now deprecated with the intent of +removing them altogether by the beginning of 2023. + +In order to keep these drivers they have to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/platform/ti/davinci/ccdc_hw_device.h b/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h index a545052a95a9..a545052a95a9 100644 --- a/drivers/media/platform/ti/davinci/ccdc_hw_device.h +++ b/drivers/staging/media/deprecated/vpfe_capture/ccdc_hw_device.h diff --git a/drivers/media/platform/ti/davinci/dm355_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c index 8fe55d1b972c..da8db53e9498 100644 --- a/drivers/media/platform/ti/davinci/dm355_ccdc.c +++ b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include <linux/module.h> -#include <media/davinci/dm355_ccdc.h> +#include "dm355_ccdc.h" #include <media/davinci/vpss.h> #include "dm355_ccdc_regs.h" diff --git a/include/media/davinci/dm355_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h index 1f3d00aa46d1..1f3d00aa46d1 100644 --- a/include/media/davinci/dm355_ccdc.h +++ b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc.h diff --git a/drivers/media/platform/ti/davinci/dm355_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h index eb381f075245..eb381f075245 100644 --- a/drivers/media/platform/ti/davinci/dm355_ccdc_regs.h +++ b/drivers/staging/media/deprecated/vpfe_capture/dm355_ccdc_regs.h diff --git a/drivers/media/platform/ti/davinci/dm644x_ccdc.c b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c index e4073e99914c..4a93e5ad6415 100644 --- a/drivers/media/platform/ti/davinci/dm644x_ccdc.c +++ b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.c @@ -24,7 +24,7 @@ #include <linux/err.h> #include <linux/module.h> -#include <media/davinci/dm644x_ccdc.h> +#include "dm644x_ccdc.h" #include <media/davinci/vpss.h> #include "dm644x_ccdc_regs.h" diff --git a/include/media/davinci/dm644x_ccdc.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h index c20dba3d76d6..c20dba3d76d6 100644 --- a/include/media/davinci/dm644x_ccdc.h +++ b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc.h diff --git a/drivers/media/platform/ti/davinci/dm644x_ccdc_regs.h b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h index c4894f6a254e..c4894f6a254e 100644 --- a/drivers/media/platform/ti/davinci/dm644x_ccdc_regs.h +++ b/drivers/staging/media/deprecated/vpfe_capture/dm644x_ccdc_regs.h diff --git a/drivers/media/platform/ti/davinci/isif.c b/drivers/staging/media/deprecated/vpfe_capture/isif.c index 69e862de014f..4059891c2824 100644 --- a/drivers/media/platform/ti/davinci/isif.c +++ b/drivers/staging/media/deprecated/vpfe_capture/isif.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include <linux/module.h> -#include <media/davinci/isif.h> +#include "isif.h" #include <media/davinci/vpss.h> #include "isif_regs.h" diff --git a/include/media/davinci/isif.h b/drivers/staging/media/deprecated/vpfe_capture/isif.h index 8369acd26e7e..8369acd26e7e 100644 --- a/include/media/davinci/isif.h +++ b/drivers/staging/media/deprecated/vpfe_capture/isif.h diff --git a/drivers/media/platform/ti/davinci/isif_regs.h b/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h index d68d38841ae7..d68d38841ae7 100644 --- a/drivers/media/platform/ti/davinci/isif_regs.h +++ b/drivers/staging/media/deprecated/vpfe_capture/isif_regs.h diff --git a/drivers/media/platform/ti/davinci/vpfe_capture.c b/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c index 0a2226b321d7..0a2226b321d7 100644 --- a/drivers/media/platform/ti/davinci/vpfe_capture.c +++ b/drivers/staging/media/deprecated/vpfe_capture/vpfe_capture.c diff --git a/drivers/media/usb/zr364xx/Kconfig b/drivers/staging/media/deprecated/zr364xx/Kconfig index a9fb02566c4b..ea29c9d8dca2 100644 --- a/drivers/media/usb/zr364xx/Kconfig +++ b/drivers/staging/media/deprecated/zr364xx/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on VIDEO_DEV + tristate "USB ZR364XX Camera support (DEPRECATED)" + depends on USB && VIDEO_DEV select VIDEOBUF_GEN select VIDEOBUF_VMALLOC help @@ -10,6 +10,9 @@ config USB_ZR364XX See <file:Documentation/admin-guide/media/zr364xx.rst> for more info and list of supported cameras. + This driver is deprecated and is scheduled for removal by + the beginning of 2023. See the TODO file for more information. + To compile this driver as a module, choose M here: the module will be called zr364xx. diff --git a/drivers/media/usb/zr364xx/Makefile b/drivers/staging/media/deprecated/zr364xx/Makefile index edab017d499c..edab017d499c 100644 --- a/drivers/media/usb/zr364xx/Makefile +++ b/drivers/staging/media/deprecated/zr364xx/Makefile diff --git a/drivers/staging/media/deprecated/zr364xx/TODO b/drivers/staging/media/deprecated/zr364xx/TODO new file mode 100644 index 000000000000..ecb30a429689 --- /dev/null +++ b/drivers/staging/media/deprecated/zr364xx/TODO @@ -0,0 +1,7 @@ +This is one of the few drivers still not using the vb2 +framework, so this driver is now deprecated with the intent of +removing it altogether by the beginning of 2023. + +In order to keep this driver it has to be converted to vb2. +If someone is interested in doing this work, then contact the +linux-media mailinglist (https://linuxtv.org/lists.php). diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/staging/media/deprecated/zr364xx/zr364xx.c index 538a330046ec..538a330046ec 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/staging/media/deprecated/zr364xx/zr364xx.c diff --git a/drivers/staging/media/hantro/TODO b/drivers/staging/media/hantro/TODO deleted file mode 100644 index 8483ff482146..000000000000 --- a/drivers/staging/media/hantro/TODO +++ /dev/null @@ -1,2 +0,0 @@ -The V4L controls for the HEVC CODEC are not yet part of the stable uABI, -we are keeping this driver in staging until the HEVC uABI has been merged. diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 294c808b2ebe..3e7462112649 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -863,16 +863,16 @@ int imx_media_pipeline_set_stream(struct imx_media_dev *imxmd, mutex_lock(&imxmd->md.graph_mutex); if (on) { - ret = __media_pipeline_start(entity, &imxmd->pipe); + ret = __media_pipeline_start(entity->pads, &imxmd->pipe); if (ret) goto out; ret = v4l2_subdev_call(sd, video, s_stream, 1); if (ret) - __media_pipeline_stop(entity); + __media_pipeline_stop(entity->pads); } else { v4l2_subdev_call(sd, video, s_stream, 0); - if (entity->pipe) - __media_pipeline_stop(entity); + if (media_pad_pipeline(entity->pads)) + __media_pipeline_stop(entity->pads); } out: diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index a0553c24cce4..e5b550ccfa22 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -160,7 +160,7 @@ #define IMX7_CSI_VIDEO_NAME "imx-capture" /* In bytes, per queue */ -#define IMX7_CSI_VIDEO_MEM_LIMIT SZ_64M +#define IMX7_CSI_VIDEO_MEM_LIMIT SZ_512M #define IMX7_CSI_VIDEO_EOF_TIMEOUT 2000 #define IMX7_CSI_DEF_MBUS_CODE MEDIA_BUS_FMT_UYVY8_2X8 @@ -1360,7 +1360,7 @@ static int imx7_csi_video_start_streaming(struct vb2_queue *vq, mutex_lock(&csi->mdev.graph_mutex); - ret = __media_pipeline_start(&csi->sd.entity, &csi->pipe); + ret = __video_device_pipeline_start(csi->vdev, &csi->pipe); if (ret) goto err_unlock; @@ -1373,7 +1373,7 @@ static int imx7_csi_video_start_streaming(struct vb2_queue *vq, return 0; err_stop: - __media_pipeline_stop(&csi->sd.entity); + __video_device_pipeline_stop(csi->vdev); err_unlock: mutex_unlock(&csi->mdev.graph_mutex); dev_err(csi->dev, "pipeline start failed with %d\n", ret); @@ -1396,7 +1396,7 @@ static void imx7_csi_video_stop_streaming(struct vb2_queue *vq) mutex_lock(&csi->mdev.graph_mutex); v4l2_subdev_call(&csi->sd, video, s_stream, 0); - __media_pipeline_stop(&csi->sd.entity); + __video_device_pipeline_stop(csi->vdev); mutex_unlock(&csi->mdev.graph_mutex); /* release all active buffers */ diff --git a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h index dbdd015ce220..caa358e0bae4 100644 --- a/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/uapi/intel-ipu3.h @@ -626,8 +626,11 @@ struct ipu3_uapi_stats_3a { * @b: white balance gain for B channel. * @gb: white balance gain for Gb channel. * - * Precision u3.13, range [0, 8). White balance correction is done by applying - * a multiplicative gain to each color channels prior to BNR. + * For BNR parameters WB gain factor for the three channels [Ggr, Ggb, Gb, Gr]. + * Their precision is U3.13 and the range is (0, 8) and the actual gain is + * Gx + 1, it is typically Gx = 1. + * + * Pout = {Pin * (1 + Gx)}. */ struct ipu3_uapi_bnr_static_config_wb_gains_config { __u16 gr; diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index d1c539cefba8..ce13e746c15f 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -192,33 +192,30 @@ static int imgu_subdev_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_selection *sel) { - struct v4l2_rect *try_sel, *r; - struct imgu_v4l2_subdev *imgu_sd = container_of(sd, - struct imgu_v4l2_subdev, - subdev); + struct imgu_v4l2_subdev *imgu_sd = + container_of(sd, struct imgu_v4l2_subdev, subdev); if (sel->pad != IMGU_NODE_IN) return -EINVAL; switch (sel->target) { case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(sd, sd_state, sel->pad); - r = &imgu_sd->rect.eff; - break; + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) + sel->r = *v4l2_subdev_get_try_crop(sd, sd_state, + sel->pad); + else + sel->r = imgu_sd->rect.eff; + return 0; case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(sd, sd_state, sel->pad); - r = &imgu_sd->rect.bds; - break; + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) + sel->r = *v4l2_subdev_get_try_compose(sd, sd_state, + sel->pad); + else + sel->r = imgu_sd->rect.bds; + return 0; default: return -EINVAL; } - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) - sel->r = *try_sel; - else - sel->r = *r; - - return 0; } static int imgu_subdev_set_selection(struct v4l2_subdev *sd, @@ -486,7 +483,7 @@ static int imgu_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) pipe = node->pipe; imgu_pipe = &imgu->imgu_pipe[pipe]; atomic_set(&node->sequence, 0); - r = media_pipeline_start(&node->vdev.entity, &imgu_pipe->pipeline); + r = video_device_pipeline_start(&node->vdev, &imgu_pipe->pipeline); if (r < 0) goto fail_return_bufs; @@ -511,7 +508,7 @@ static int imgu_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; fail_stop_pipeline: - media_pipeline_stop(&node->vdev.entity); + video_device_pipeline_stop(&node->vdev); fail_return_bufs: imgu_return_all_buffers(imgu, node, VB2_BUF_STATE_QUEUED); @@ -551,7 +548,7 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) imgu_return_all_buffers(imgu, node, VB2_BUF_STATE_ERROR); mutex_unlock(&imgu->streaming_lock); - media_pipeline_stop(&node->vdev.entity); + video_device_pipeline_stop(&node->vdev); } /******************** v4l2_ioctl_ops ********************/ diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 8549d95be0f2..52f224d8def1 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -1102,6 +1102,7 @@ static int vdec_probe(struct platform_device *pdev) err_vdev_release: video_device_release(vdev); + v4l2_device_unregister(&core->v4l2_dev); return ret; } @@ -1110,6 +1111,7 @@ static int vdec_remove(struct platform_device *pdev) struct amvdec_core *core = platform_get_drvdata(pdev); video_unregister_device(core->vdev_dec); + v4l2_device_unregister(&core->v4l2_dev); return 0; } diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c index 9530e580e57a..afced435c907 100644 --- a/drivers/staging/media/meson/vdec/vdec_hevc.c +++ b/drivers/staging/media/meson/vdec/vdec_hevc.c @@ -167,8 +167,12 @@ static int vdec_hevc_start(struct amvdec_session *sess) clk_set_rate(core->vdec_hevc_clk, 666666666); ret = clk_prepare_enable(core->vdec_hevc_clk); - if (ret) + if (ret) { + if (core->platform->revision == VDEC_REVISION_G12A || + core->platform->revision == VDEC_REVISION_SM1) + clk_disable_unprepare(core->vdec_hevcf_clk); return ret; + } if (core->platform->revision == VDEC_REVISION_SM1) regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index 28aacda0f5a7..fa2a36d829d3 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -548,10 +548,8 @@ static int iss_pipeline_is_last(struct media_entity *me) struct iss_pipeline *pipe; struct media_pad *pad; - if (!me->pipe) - return 0; pipe = to_iss_pipeline(me); - if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED) + if (!pipe || pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED) return 0; pad = media_pad_remote_pad_first(&pipe->output->pad); return pad->entity == me; diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 9512cd3314f2..60f3d84be828 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -843,7 +843,7 @@ iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) * processing might be possible but requires more testing. * * Stream start must be delayed until buffers are available at both the input - * and output. The pipeline must be started in the videobuf queue callback with + * and output. The pipeline must be started in the vb2 queue callback with * the buffers queue spinlock held. The modules subdev set stream operation must * not sleep. */ @@ -870,8 +870,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) * Start streaming on the pipeline. No link touching an entity in the * pipeline can be activated or deactivated once streaming is started. */ - pipe = entity->pipe - ? to_iss_pipeline(entity) : &video->pipe; + pipe = to_iss_pipeline(&video->video.entity) ? : &video->pipe; pipe->external = NULL; pipe->external_rate = 0; pipe->external_bpp = 0; @@ -887,7 +886,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) if (video->iss->pdata->set_constraints) video->iss->pdata->set_constraints(video->iss, true); - ret = media_pipeline_start(entity, &pipe->pipe); + ret = video_device_pipeline_start(&video->video, &pipe->pipe); if (ret < 0) goto err_media_pipeline_start; @@ -978,7 +977,7 @@ iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) err_omap4iss_set_stream: vb2_streamoff(&vfh->queue, type); err_iss_video_check_format: - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); err_media_pipeline_start: if (video->iss->pdata->set_constraints) video->iss->pdata->set_constraints(video->iss, false); @@ -1032,7 +1031,7 @@ iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) if (video->iss->pdata->set_constraints) video->iss->pdata->set_constraints(video->iss, false); - media_pipeline_stop(&video->video.entity); + video_device_pipeline_stop(&video->video); done: mutex_unlock(&video->stream_lock); diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h index 526281bf0051..ca2d5edb6261 100644 --- a/drivers/staging/media/omap4iss/iss_video.h +++ b/drivers/staging/media/omap4iss/iss_video.h @@ -90,8 +90,15 @@ struct iss_pipeline { int external_bpp; }; -#define to_iss_pipeline(__e) \ - container_of((__e)->pipe, struct iss_pipeline, pipe) +static inline struct iss_pipeline *to_iss_pipeline(struct media_entity *entity) +{ + struct media_pipeline *pipe = media_entity_pipeline(entity); + + if (!pipe) + return NULL; + + return container_of(pipe, struct iss_pipeline, pipe); +} static inline int iss_pipeline_ready(struct iss_pipeline *pipe) { diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig index 21c13f9b6e33..621944f9907a 100644 --- a/drivers/staging/media/sunxi/cedrus/Kconfig +++ b/drivers/staging/media/sunxi/cedrus/Kconfig @@ -2,6 +2,7 @@ config VIDEO_SUNXI_CEDRUS tristate "Allwinner Cedrus VPU driver" depends on VIDEO_DEV + depends on RESET_CONTROLLER depends on HAS_DMA depends on OF select MEDIA_CONTROLLER diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 960a0130cd62..55c54dfdc585 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -448,6 +448,8 @@ static int cedrus_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; + platform_set_drvdata(pdev, dev); + dev->vfd = cedrus_video_device; dev->dev = &pdev->dev; dev->pdev = pdev; @@ -521,8 +523,6 @@ static int cedrus_probe(struct platform_device *pdev) goto err_m2m_mc; } - platform_set_drvdata(pdev, dev); - return 0; err_m2m_mc: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 084193019350..93a2196006f7 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -237,19 +237,23 @@ static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf, } static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx, - int index, unsigned int plane) + struct vb2_buffer *buf, + unsigned int plane) { - struct vb2_buffer *buf = NULL; - struct vb2_queue *vq; - - if (index < 0) - return 0; + return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; +} - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (vq) - buf = vb2_get_buffer(vq, index); +static inline void cedrus_write_ref_buf_addr(struct cedrus_ctx *ctx, + struct vb2_queue *q, + u64 timestamp, + u32 luma_reg, + u32 chroma_reg) +{ + struct cedrus_dev *dev = ctx->dev; + struct vb2_buffer *buf = vb2_find_buffer(q, timestamp); - return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; + cedrus_write(dev, luma_reg, cedrus_dst_buf_addr(ctx, buf, 0)); + cedrus_write(dev, chroma_reg, cedrus_dst_buf_addr(ctx, buf, 1)); } static inline struct cedrus_buffer * diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 3b6aa78a2985..e7f7602a5ab4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -106,11 +106,11 @@ void cedrus_device_run(void *priv) /* Trigger decoding if setup went well, bail out otherwise. */ if (!error) { - dev->dec_ops[ctx->current_codec]->trigger(ctx); - /* Start the watchdog timer. */ schedule_delayed_work(&dev->watchdog_work, msecs_to_jiffies(2000)); + + dev->dec_ops[ctx->current_codec]->trigger(ctx); } else { v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index c345e67ba9bc..a8b236cd3800 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -111,16 +111,16 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) { const struct v4l2_h264_dpb_entry *dpb = &decode->dpb[i]; struct cedrus_buffer *cedrus_buf; - int buf_idx; + struct vb2_buffer *buf; if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) continue; - buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0); - if (buf_idx < 0) + buf = vb2_find_buffer(cap_q, dpb->reference_ts); + if (!buf) continue; - cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); + cedrus_buf = vb2_to_cedrus_buffer(buf); position = cedrus_buf->codec.h264.position; used_dpbs |= BIT(position); @@ -186,7 +186,7 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, const struct v4l2_h264_dpb_entry *dpb; const struct cedrus_buffer *cedrus_buf; unsigned int position; - int buf_idx; + struct vb2_buffer *buf; u8 dpb_idx; dpb_idx = ref_list[i].index; @@ -195,11 +195,11 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) continue; - buf_idx = vb2_find_timestamp(cap_q, dpb->reference_ts, 0); - if (buf_idx < 0) + buf = vb2_find_buffer(cap_q, dpb->reference_ts); + if (!buf) continue; - cedrus_buf = vb2_to_cedrus_buffer(cap_q->bufs[buf_idx]); + cedrus_buf = vb2_to_cedrus_buffer(buf); position = cedrus_buf->codec.h264.position; sram_array[i] |= position << 1; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 687f87598f78..4952fc17f3e6 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -102,14 +102,14 @@ static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx, unsigned int index, bool field_pic, u32 pic_order_cnt[], - int buffer_index) + struct vb2_buffer *buf) { struct cedrus_dev *dev = ctx->dev; - dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 0); - dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 1); + dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buf, 0); + dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buf, 1); dma_addr_t mv_col_buf_addr[2] = { - cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, 0), - cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, + cedrus_h265_frame_info_mv_col_buf_addr(ctx, buf->index, 0), + cedrus_h265_frame_info_mv_col_buf_addr(ctx, buf->index, field_pic ? 1 : 0) }; u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO + @@ -141,18 +141,18 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, unsigned int i; for (i = 0; i < num_active_dpb_entries; i++) { - int buffer_index = vb2_find_timestamp(vq, dpb[i].timestamp, 0); + struct vb2_buffer *buf = vb2_find_buffer(vq, dpb[i].timestamp); u32 pic_order_cnt[2] = { dpb[i].pic_order_cnt_val, dpb[i].pic_order_cnt_val }; - if (buffer_index < 0) + if (!buf) continue; cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic, pic_order_cnt, - buffer_index); + buf); } } @@ -234,8 +234,9 @@ static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num) cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_FLUSH_BITS | VE_DEC_H265_TRIGGER_TYPE_N_BITS(tmp)); - while (cedrus_read(dev, VE_DEC_H265_STATUS) & VE_DEC_H265_STATUS_VLD_BUSY) - udelay(1); + + if (cedrus_wait_for(dev, VE_DEC_H265_STATUS, VE_DEC_H265_STATUS_VLD_BUSY)) + dev_err_ratelimited(dev->dev, "timed out waiting to skip bits\n"); count += tmp; } @@ -751,7 +752,7 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_h265_frame_info_write_single(ctx, output_pic_list_index, slice_params->pic_struct != 0, pic_order_cnt, - run->dst->vb2_buf.index); + &run->dst->vb2_buf); cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 4cfc4a3c8a7f..c1128d2cd555 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -54,13 +54,9 @@ static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) const struct v4l2_ctrl_mpeg2_picture *pic; const struct v4l2_ctrl_mpeg2_quantisation *quantisation; dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr; - dma_addr_t fwd_luma_addr, fwd_chroma_addr; - dma_addr_t bwd_luma_addr, bwd_chroma_addr; struct cedrus_dev *dev = ctx->dev; struct vb2_queue *vq; const u8 *matrix; - int forward_idx; - int backward_idx; unsigned int i; u32 reg; @@ -123,27 +119,19 @@ static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) cedrus_write(dev, VE_DEC_MPEG_PICBOUNDSIZE, reg); /* Forward and backward prediction reference buffers. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - forward_idx = vb2_find_timestamp(vq, pic->forward_ref_ts, 0); - fwd_luma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 0); - fwd_chroma_addr = cedrus_dst_buf_addr(ctx, forward_idx, 1); - - cedrus_write(dev, VE_DEC_MPEG_FWD_REF_LUMA_ADDR, fwd_luma_addr); - cedrus_write(dev, VE_DEC_MPEG_FWD_REF_CHROMA_ADDR, fwd_chroma_addr); - - backward_idx = vb2_find_timestamp(vq, pic->backward_ref_ts, 0); - bwd_luma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 0); - bwd_chroma_addr = cedrus_dst_buf_addr(ctx, backward_idx, 1); - - cedrus_write(dev, VE_DEC_MPEG_BWD_REF_LUMA_ADDR, bwd_luma_addr); - cedrus_write(dev, VE_DEC_MPEG_BWD_REF_CHROMA_ADDR, bwd_chroma_addr); + cedrus_write_ref_buf_addr(ctx, vq, pic->forward_ref_ts, + VE_DEC_MPEG_FWD_REF_LUMA_ADDR, + VE_DEC_MPEG_FWD_REF_CHROMA_ADDR); + cedrus_write_ref_buf_addr(ctx, vq, pic->backward_ref_ts, + VE_DEC_MPEG_BWD_REF_LUMA_ADDR, + VE_DEC_MPEG_BWD_REF_CHROMA_ADDR); /* Destination luma and chroma buffers. */ - dst_luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0); - dst_chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1); + dst_luma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 0); + dst_chroma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 1); cedrus_write(dev, VE_DEC_MPEG_REC_LUMA, dst_luma_addr); cedrus_write(dev, VE_DEC_MPEG_REC_CHROMA, dst_chroma_addr); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c index 3f750d1795b6..f7714baae37d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c @@ -660,7 +660,6 @@ static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) dma_addr_t luma_addr, chroma_addr; dma_addr_t src_buf_addr; int header_size; - int qindex; u32 reg; cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8); @@ -804,43 +803,17 @@ static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) reg |= VE_VP8_LF_DELTA0(slice->lf.mb_mode_delta[0]); cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg); - luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0); - chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1); + luma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, &run->dst->vb2_buf, 1); cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr); cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr); - qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0); - if (qindex >= 0) { - luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); - chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); - cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr); - cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr); - } else { - cedrus_write(dev, VE_VP8_FWD_LUMA, 0); - cedrus_write(dev, VE_VP8_FWD_CHROMA, 0); - } - - qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0); - if (qindex >= 0) { - luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); - chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); - cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr); - cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr); - } else { - cedrus_write(dev, VE_VP8_BWD_LUMA, 0); - cedrus_write(dev, VE_VP8_BWD_CHROMA, 0); - } - - qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0); - if (qindex >= 0) { - luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); - chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); - cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr); - cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr); - } else { - cedrus_write(dev, VE_VP8_ALT_LUMA, 0); - cedrus_write(dev, VE_VP8_ALT_CHROMA, 0); - } + cedrus_write_ref_buf_addr(ctx, cap_q, slice->last_frame_ts, + VE_VP8_FWD_LUMA, VE_VP8_FWD_CHROMA); + cedrus_write_ref_buf_addr(ctx, cap_q, slice->golden_frame_ts, + VE_VP8_BWD_LUMA, VE_VP8_BWD_CHROMA); + cedrus_write_ref_buf_addr(ctx, cap_q, slice->alt_frame_ts, + VE_VP8_ALT_LUMA, VE_VP8_ALT_CHROMA); cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 | VE_H264_CTRL_DECODE_ERR_INT | diff --git a/drivers/staging/media/tegra-video/tegra210.c b/drivers/staging/media/tegra-video/tegra210.c index f10a041e3e6c..d58370a84737 100644 --- a/drivers/staging/media/tegra-video/tegra210.c +++ b/drivers/staging/media/tegra-video/tegra210.c @@ -547,7 +547,7 @@ static int tegra210_vi_start_streaming(struct vb2_queue *vq, u32 count) VI_INCR_SYNCPT_NO_STALL); /* start the pipeline */ - ret = media_pipeline_start(&chan->video.entity, pipe); + ret = video_device_pipeline_start(&chan->video, pipe); if (ret < 0) goto error_pipeline_start; @@ -595,7 +595,7 @@ error_kthread_done: error_kthread_start: tegra_channel_set_stream(chan, false); error_set_stream: - media_pipeline_stop(&chan->video.entity); + video_device_pipeline_stop(&chan->video); error_pipeline_start: tegra_channel_release_buffers(chan, VB2_BUF_STATE_QUEUED); return ret; @@ -617,7 +617,7 @@ static void tegra210_vi_stop_streaming(struct vb2_queue *vq) tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR); tegra_channel_set_stream(chan, false); - media_pipeline_stop(&chan->video.entity); + video_device_pipeline_stop(&chan->video); } /* diff --git a/drivers/staging/media/zoran/TODO b/drivers/staging/media/zoran/TODO deleted file mode 100644 index 6992540d3e53..000000000000 --- a/drivers/staging/media/zoran/TODO +++ /dev/null @@ -1,19 +0,0 @@ - -How to test the zoran driver: -- RAW capture - mplayer tv:///dev/video0 -tv driver=v4l2 - -- MJPEG capture (compression) - mplayer tv:///dev/video0 -tv driver=v4l2:outfmt=mjpeg - TODO: need two test for both Dcim path - -- MJPEG play (decompression) - ffmpeg -i test.avi -vcodec mjpeg -an -f v4l2 /dev/video0 - Note: only recent ffmpeg has the ability of sending non-raw video via v4l2 - - The original way of sending video was via mplayer vo_zr/vo_zr2, but it does not compile - anymore and is a dead end (usage of some old private ffmpeg structures). - -TODO -- fix the v4l compliance "TRY_FMT cannot handle an invalid pixelformat" -- Filter JPEG data to made output work diff --git a/drivers/staging/media/zoran/zoran_device.h b/drivers/staging/media/zoran/zoran_device.h deleted file mode 100644 index 322b04c55d41..000000000000 --- a/drivers/staging/media/zoran/zoran_device.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - */ - -#ifndef __ZORAN_DEVICE_H__ -#define __ZORAN_DEVICE_H__ - -/* general purpose I/O */ -extern void GPIO(struct zoran *zr, int bit, unsigned int value); - -/* codec (or actually: guest bus) access */ -extern int post_office_wait(struct zoran *zr); -extern int post_office_write(struct zoran *zr, unsigned int guest, unsigned int reg, unsigned int value); -extern int post_office_read(struct zoran *zr, unsigned int guest, unsigned int reg); - -extern void jpeg_codec_sleep(struct zoran *zr, int sleep); -extern int jpeg_codec_reset(struct zoran *zr); - -/* zr360x7 access to raw capture */ -extern void zr36057_overlay(struct zoran *zr, int on); -extern void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count); -extern void zr36057_set_memgrab(struct zoran *zr, int mode); -extern int wait_grab_pending(struct zoran *zr); - -/* interrupts */ -extern void print_interrupts(struct zoran *zr); -extern void clear_interrupt_counters(struct zoran *zr); -extern irqreturn_t zoran_irq(int irq, void *dev_id); - -/* JPEG codec access */ -extern void jpeg_start(struct zoran *zr); -extern void zr36057_enable_jpg(struct zoran *zr, - enum zoran_codec_mode mode); -extern void zoran_feed_stat_com(struct zoran *zr); - -/* general */ -extern void zoran_set_pci_master(struct zoran *zr, int set_master); -extern void zoran_init_hardware(struct zoran *zr); -extern void zr36057_restart(struct zoran *zr); - -extern const struct zoran_format zoran_formats[]; - -extern int v4l_bufsize; -extern int jpg_bufsize; -extern int pass_through; - -/* i2c */ -#define decoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->decoder, o, f, ##args) -#define encoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->encoder, o, f, ##args) - -#endif /* __ZORAN_DEVICE_H__ */ diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h index 6d2a93740130..d8751ea926a2 100644 --- a/include/media/davinci/vpbe_display.h +++ b/include/media/davinci/vpbe_display.h @@ -69,13 +69,13 @@ struct vpbe_layer { struct vpbe_disp_buffer *cur_frm; /* Pointer pointing to next v4l2_buffer */ struct vpbe_disp_buffer *next_frm; - /* videobuf specific parameters - * Buffer queue used in video-buf + /* vb2 specific parameters + * Buffer queue used in vb2 */ struct vb2_queue buffer_queue; /* Queue of filled frames */ struct list_head dma_queue; - /* Used in video-buf */ + /* Used for video buffer handling */ spinlock_t irqlock; /* V4l2 specific parameters */ /* Identifies video device for this layer */ diff --git a/include/media/i2c/ir-kbd-i2c.h b/include/media/i2c/ir-kbd-i2c.h index 9f47d6a48cff..0b58f8b9e7a4 100644 --- a/include/media/i2c/ir-kbd-i2c.h +++ b/include/media/i2c/ir-kbd-i2c.h @@ -35,6 +35,7 @@ enum ir_kbd_get_key_fn { IR_KBD_GET_KEY_PIXELVIEW, IR_KBD_GET_KEY_HAUP, IR_KBD_GET_KEY_KNC1, + IR_KBD_GET_KEY_GENIATECH, IR_KBD_GET_KEY_FUSIONHDTV, IR_KBD_GET_KEY_HAUP_XVR, IR_KBD_GET_KEY_AVERMEDIA_CARDBUS, diff --git a/include/media/media-device.h b/include/media/media-device.h index a10b30507524..86716ee7cc6c 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -192,21 +192,6 @@ struct usb_device; #define MEDIA_DEV_NOTIFY_POST_LINK_CH 1 /** - * media_entity_enum_init - Initialise an entity enumeration - * - * @ent_enum: Entity enumeration to be initialised - * @mdev: The related media device - * - * Return: zero on success or a negative error code. - */ -static inline __must_check int media_entity_enum_init( - struct media_entity_enum *ent_enum, struct media_device *mdev) -{ - return __media_entity_enum_init(ent_enum, - mdev->entity_internal_idx_max + 1); -} - -/** * media_device_init() - Initializes a media device element * * @mdev: pointer to struct &media_device diff --git a/include/media/media-entity.h b/include/media/media-entity.h index f16ffe70f7a6..28c9de8a1f34 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -17,6 +17,7 @@ #include <linux/fwnode.h> #include <linux/list.h> #include <linux/media.h> +#include <linux/minmax.h> #include <linux/types.h> /* Enums used internally at the media controller to represent graphs */ @@ -99,12 +100,34 @@ struct media_graph { /** * struct media_pipeline - Media pipeline related information * - * @streaming_count: Streaming start count - streaming stop count - * @graph: Media graph walk during pipeline start / stop + * @allocated: Media pipeline allocated and freed by the framework + * @mdev: The media device the pipeline is part of + * @pads: List of media_pipeline_pad + * @start_count: Media pipeline start - stop count */ struct media_pipeline { - int streaming_count; - struct media_graph graph; + bool allocated; + struct media_device *mdev; + struct list_head pads; + int start_count; +}; + +/** + * struct media_pipeline_pad - A pad part of a media pipeline + * + * @list: Entry in the media_pad pads list + * @pipe: The media_pipeline that the pad is part of + * @pad: The media pad + * + * This structure associate a pad with a media pipeline. Instances of + * media_pipeline_pad are created by media_pipeline_start() when it builds the + * pipeline, and stored in the &media_pad.pads list. media_pipeline_stop() + * removes the entries from the list and deletes them. + */ +struct media_pipeline_pad { + struct list_head list; + struct media_pipeline *pipe; + struct media_pad *pad; }; /** @@ -186,6 +209,8 @@ enum media_pad_signal_type { * @flags: Pad flags, as defined in * :ref:`include/uapi/linux/media.h <media_header>` * (seek for ``MEDIA_PAD_FL_*``) + * @pipe: Pipeline this pad belongs to. Use media_entity_pipeline() to + * access this field. */ struct media_pad { struct media_gobj graph_obj; /* must be first field in struct */ @@ -193,6 +218,12 @@ struct media_pad { u16 index; enum media_pad_signal_type sig_type; unsigned long flags; + + /* + * The fields below are private, and should only be accessed via + * appropriate functions. + */ + struct media_pipeline *pipe; }; /** @@ -206,6 +237,14 @@ struct media_pad { * @link_validate: Return whether a link is valid from the entity point of * view. The media_pipeline_start() function * validates all links by calling this operation. Optional. + * @has_pad_interdep: Return whether a two pads inside the entity are + * interdependent. If two pads are interdependent they are + * part of the same pipeline and enabling one of the pads + * means that the other pad will become "locked" and + * doesn't allow configuration changes. pad0 and pad1 are + * guaranteed to not both be sinks or sources. + * Optional: If the operation isn't implemented all pads + * will be considered as interdependent. * * .. note:: * @@ -219,6 +258,8 @@ struct media_entity_operations { const struct media_pad *local, const struct media_pad *remote, u32 flags); int (*link_validate)(struct media_link *link); + bool (*has_pad_interdep)(struct media_entity *entity, unsigned int pad0, + unsigned int pad1); }; /** @@ -269,7 +310,6 @@ enum media_entity_type { * @links: List of data links. * @ops: Entity operations. * @use_count: Use count for the entity. - * @pipe: Pipeline this entity belongs to. * @info: Union with devnode information. Kept just for backward * compatibility. * @info.dev: Contains device major and minor info. @@ -305,8 +345,6 @@ struct media_entity { int use_count; - struct media_pipeline *pipe; - union { struct { u32 major; @@ -316,6 +354,18 @@ struct media_entity { }; /** + * media_entity_for_each_pad - Iterate on all pads in an entity + * @entity: The entity the pads belong to + * @iter: The iterator pad + * + * Iterate on all pads in a media entity. + */ +#define media_entity_for_each_pad(entity, iter) \ + for (iter = (entity)->pads; \ + iter < &(entity)->pads[(entity)->num_pads]; \ + ++iter) + +/** * struct media_interface - A media interface graph object. * * @graph_obj: embedded graph object @@ -426,15 +476,15 @@ static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity) } /** - * __media_entity_enum_init - Initialise an entity enumeration + * media_entity_enum_init - Initialise an entity enumeration * * @ent_enum: Entity enumeration to be initialised - * @idx_max: Maximum number of entities in the enumeration + * @mdev: The related media device * - * Return: Returns zero on success or a negative error code. + * Return: zero on success or a negative error code. */ -__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, - int idx_max); +__must_check int media_entity_enum_init(struct media_entity_enum *ent_enum, + struct media_device *mdev); /** * media_entity_enum_cleanup - Release resources of an entity enumeration @@ -924,6 +974,18 @@ media_entity_remote_source_pad_unique(const struct media_entity *entity) } /** + * media_pad_is_streaming - Test if a pad is part of a streaming pipeline + * @pad: The pad + * + * Return: True if the pad is part of a pipeline started with the + * media_pipeline_start() function, false otherwise. + */ +static inline bool media_pad_is_streaming(const struct media_pad *pad) +{ + return pad->pipe; +} + +/** * media_entity_is_streaming - Test if an entity is part of a streaming pipeline * @entity: The entity * @@ -932,10 +994,50 @@ media_entity_remote_source_pad_unique(const struct media_entity *entity) */ static inline bool media_entity_is_streaming(const struct media_entity *entity) { - return entity->pipe; + struct media_pad *pad; + + media_entity_for_each_pad(entity, pad) { + if (media_pad_is_streaming(pad)) + return true; + } + + return false; } /** + * media_entity_pipeline - Get the media pipeline an entity is part of + * @entity: The entity + * + * DEPRECATED: use media_pad_pipeline() instead. + * + * This function returns the media pipeline that an entity has been associated + * with when constructing the pipeline with media_pipeline_start(). The pointer + * remains valid until media_pipeline_stop() is called. + * + * In general, entities can be part of multiple pipelines, when carrying + * multiple streams (either on different pads, or on the same pad using + * multiplexed streams). This function is to be used only for entities that + * do not support multiple pipelines. + * + * Return: The media_pipeline the entity is part of, or NULL if the entity is + * not part of any pipeline. + */ +struct media_pipeline *media_entity_pipeline(struct media_entity *entity); + +/** + * media_pad_pipeline - Get the media pipeline a pad is part of + * @pad: The pad + * + * This function returns the media pipeline that a pad has been associated + * with when constructing the pipeline with media_pipeline_start(). The pointer + * remains valid until media_pipeline_stop() is called. + * + * Return: The media_pipeline the pad is part of, or NULL if the pad is + * not part of any pipeline. + */ +struct media_pipeline *media_pad_pipeline(struct media_pad *pad); + +/** * media_entity_get_fwnode_pad - Get pad number from fwnode * * @entity: The entity @@ -1013,53 +1115,66 @@ struct media_entity *media_graph_walk_next(struct media_graph *graph); /** * media_pipeline_start - Mark a pipeline as streaming - * @entity: Starting entity - * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * @pad: Starting pad + * @pipe: Media pipeline to be assigned to all pads in the pipeline. * - * Mark all entities connected to a given entity through enabled links, either + * Mark all pads connected to a given pad through enabled links, either * directly or indirectly, as streaming. The given pipeline object is assigned - * to every entity in the pipeline and stored in the media_entity pipe field. + * to every pad in the pipeline and stored in the media_pad pipe field. * * Calls to this function can be nested, in which case the same number of * media_pipeline_stop() calls will be required to stop streaming. The * pipeline pointer must be identical for all nested calls to * media_pipeline_start(). */ -__must_check int media_pipeline_start(struct media_entity *entity, +__must_check int media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe); /** * __media_pipeline_start - Mark a pipeline as streaming * - * @entity: Starting entity - * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * @pad: Starting pad + * @pipe: Media pipeline to be assigned to all pads in the pipeline. * * ..note:: This is the non-locking version of media_pipeline_start() */ -__must_check int __media_pipeline_start(struct media_entity *entity, +__must_check int __media_pipeline_start(struct media_pad *pad, struct media_pipeline *pipe); /** * media_pipeline_stop - Mark a pipeline as not streaming - * @entity: Starting entity + * @pad: Starting pad * - * Mark all entities connected to a given entity through enabled links, either - * directly or indirectly, as not streaming. The media_entity pipe field is + * Mark all pads connected to a given pads through enabled links, either + * directly or indirectly, as not streaming. The media_pad pipe field is * reset to %NULL. * * If multiple calls to media_pipeline_start() have been made, the same * number of calls to this function are required to mark the pipeline as not * streaming. */ -void media_pipeline_stop(struct media_entity *entity); +void media_pipeline_stop(struct media_pad *pad); /** * __media_pipeline_stop - Mark a pipeline as not streaming * - * @entity: Starting entity + * @pad: Starting pad * * .. note:: This is the non-locking version of media_pipeline_stop() */ -void __media_pipeline_stop(struct media_entity *entity); +void __media_pipeline_stop(struct media_pad *pad); + +/** + * media_pipeline_alloc_start - Mark a pipeline as streaming + * @pad: Starting pad + * + * media_pipeline_alloc_start() is similar to media_pipeline_start() but instead + * of working on a given pipeline the function will use an existing pipeline if + * the pad is already part of a pipeline, or allocate a new pipeline. + * + * Calls to media_pipeline_alloc_start() must be matched with + * media_pipeline_stop(). + */ +__must_check int media_pipeline_alloc_start(struct media_pad *pad); /** * media_devnode_create() - creates and initializes a device node interface diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index b708d63995f4..2ae2be4c87e5 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -175,7 +175,8 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, * * @sd: pointer to &struct v4l2_subdev * @client: pointer to struct i2c_client - * @devname: the name of the device; if NULL, the I²C device's name will be used + * @devname: the name of the device; if NULL, the I²C device drivers's name + * will be used * @postfix: sub-device specific string to put right after the I²C device name; * may be NULL */ diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 00828a4f9404..e59d9a234631 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -121,21 +121,19 @@ struct v4l2_ctrl_ops { * struct v4l2_ctrl_type_ops - The control type operations that the driver * has to provide. * - * @equal: return true if both values are equal. - * @init: initialize the value. + * @equal: return true if all ctrl->elems array elements are equal. + * @init: initialize the value for array elements from from_idx to ctrl->elems. * @log: log the value. - * @validate: validate the value. Return 0 on success and a negative value - * otherwise. + * @validate: validate the value for ctrl->new_elems array elements. + * Return 0 on success and a negative value otherwise. */ struct v4l2_ctrl_type_ops { - bool (*equal)(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr1, - union v4l2_ctrl_ptr ptr2); - void (*init)(const struct v4l2_ctrl *ctrl, u32 idx, + bool (*equal)(const struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2); + void (*init)(const struct v4l2_ctrl *ctrl, u32 from_idx, union v4l2_ctrl_ptr ptr); void (*log)(const struct v4l2_ctrl *ctrl); - int (*validate)(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr); + int (*validate)(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr); }; /** @@ -203,7 +201,7 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv); * @elem_size: The size in bytes of the control. * @new_elems: The number of elements in p_new. This is the same as @elems, * except for dynamic arrays. In that case it is in the range of - * 1 to @p_dyn_alloc_elems. + * 1 to @p_array_alloc_elems. * @dims: The size of each dimension. * @nr_of_dims:The number of dimensions in @dims. * @menu_skip_mask: The control's skip mask for menu controls. This makes it @@ -227,12 +225,11 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv); * not freed when the control is deleted. Should this be needed * then a new internal bitfield can be added to tell the framework * to free this pointer. - * @p_dyn: Pointer to the dynamically allocated array. Only valid if - * @is_dyn_array is true. - * @p_dyn_alloc_elems: The number of elements in the dynamically allocated - * array for both the cur and new values. So @p_dyn is actually - * sized for 2 * @p_dyn_alloc_elems * @elem_size. Only valid if - * @is_dyn_array is true. + * @p_array: Pointer to the allocated array. Only valid if @is_array is true. + * @p_array_alloc_elems: The number of elements in the allocated + * array for both the cur and new values. So @p_array is actually + * sized for 2 * @p_array_alloc_elems * @elem_size. Only valid if + * @is_array is true. * @cur: Structure to store the current value. * @cur.val: The control's current value, if the @type is represented via * a u32 integer (see &enum v4l2_ctrl_type). @@ -291,8 +288,8 @@ struct v4l2_ctrl { }; unsigned long flags; void *priv; - void *p_dyn; - u32 p_dyn_alloc_elems; + void *p_array; + u32 p_array_alloc_elems; s32 val; struct { s32 val; @@ -319,15 +316,15 @@ struct v4l2_ctrl { * from a cluster with multiple controls twice (when the first * control of a cluster is applied, they all are). * @p_req_valid: If set, then p_req contains the control value for the request. - * @p_req_dyn_enomem: If set, then p_req is invalid since allocating space for - * a dynamic array failed. Attempting to read this value shall - * result in ENOMEM. Only valid if ctrl->is_dyn_array is true. - * @p_req_dyn_alloc_elems: The number of elements allocated for the dynamic - * array. Only valid if @p_req_valid and ctrl->is_dyn_array are + * @p_req_array_enomem: If set, then p_req is invalid since allocating space for + * an array failed. Attempting to read this value shall + * result in ENOMEM. Only valid if ctrl->is_array is true. + * @p_req_array_alloc_elems: The number of elements allocated for the + * array. Only valid if @p_req_valid and ctrl->is_array are * true. * @p_req_elems: The number of elements in @p_req. This is the same as * ctrl->elems, except for dynamic arrays. In that case it is in - * the range of 1 to @p_req_dyn_alloc_elems. Only valid if + * the range of 1 to @p_req_array_alloc_elems. Only valid if * @p_req_valid is true. * @p_req: If the control handler containing this control reference * is bound to a media request, then this points to the @@ -349,8 +346,8 @@ struct v4l2_ctrl_ref { bool from_other_dev; bool req_done; bool p_req_valid; - bool p_req_dyn_enomem; - u32 p_req_dyn_alloc_elems; + bool p_req_array_enomem; + u32 p_req_array_alloc_elems; u32 p_req_elems; union v4l2_ctrl_ptr p_req; }; @@ -959,6 +956,59 @@ static inline int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl, } /** + *__v4l2_ctrl_modify_dimensions() - Unlocked variant of v4l2_ctrl_modify_dimensions() + * + * @ctrl: The control to update. + * @dims: The control's new dimensions. + * + * Update the dimensions of an array control on the fly. The elements of the + * array are reset to their default value, even if the dimensions are + * unchanged. + * + * An error is returned if @dims is invalid for this control. + * + * The caller is responsible for acquiring the control handler mutex on behalf + * of __v4l2_ctrl_modify_dimensions(). + * + * Note: calling this function when the same control is used in pending requests + * is untested. It should work (a request with the wrong size of the control + * will drop that control silently), but it will be very confusing. + */ +int __v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, + u32 dims[V4L2_CTRL_MAX_DIMS]); + +/** + * v4l2_ctrl_modify_dimensions() - Update the dimensions of an array control. + * + * @ctrl: The control to update. + * @dims: The control's new dimensions. + * + * Update the dimensions of an array control on the fly. The elements of the + * array are reset to their default value, even if the dimensions are + * unchanged. + * + * An error is returned if @dims is invalid for this control type. + * + * This function assumes that the control handler is not locked and will + * take the lock itself. + * + * Note: calling this function when the same control is used in pending requests + * is untested. It should work (a request with the wrong size of the control + * will drop that control silently), but it will be very confusing. + */ +static inline int v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl, + u32 dims[V4L2_CTRL_MAX_DIMS]) +{ + int rval; + + v4l2_ctrl_lock(ctrl); + rval = __v4l2_ctrl_modify_dimensions(ctrl, dims); + v4l2_ctrl_unlock(ctrl); + + return rval; +} + +/** * v4l2_ctrl_notify() - Function to set a notify callback for a control. * * @ctrl: The control. @@ -1486,4 +1536,48 @@ int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd); int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ctrl_ops, const struct v4l2_fwnode_device_properties *p); + +/** + * v4l2_ctrl_type_op_equal - Default v4l2_ctrl_type_ops equal callback. + * + * @ctrl: The v4l2_ctrl pointer. + * @ptr1: A v4l2 control value. + * @ptr2: A v4l2 control value. + * + * Return: true if values are equal, otherwise false. + */ +bool v4l2_ctrl_type_op_equal(const struct v4l2_ctrl *ctrl, + union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2); + +/** + * v4l2_ctrl_type_op_init - Default v4l2_ctrl_type_ops init callback. + * + * @ctrl: The v4l2_ctrl pointer. + * @from_idx: Starting element index. + * @ptr: The v4l2 control value. + * + * Return: void + */ +void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx, + union v4l2_ctrl_ptr ptr); + +/** + * v4l2_ctrl_type_op_log - Default v4l2_ctrl_type_ops log callback. + * + * @ctrl: The v4l2_ctrl pointer. + * + * Return: void + */ +void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl); + +/** + * v4l2_ctrl_type_op_validate - Default v4l2_ctrl_type_ops validate callback. + * + * @ctrl: The v4l2_ctrl pointer. + * @ptr: The v4l2 control value. + * + * Return: 0 on success, a negative error code on failure. + */ +int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr ptr); + #endif diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 5cf1edefb822..e0a13505f88d 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -539,4 +539,106 @@ static inline int video_is_registered(struct video_device *vdev) return test_bit(V4L2_FL_REGISTERED, &vdev->flags); } +#if defined(CONFIG_MEDIA_CONTROLLER) + +/** + * video_device_pipeline_start - Mark a pipeline as streaming + * @vdev: Starting video device + * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * + * Mark all entities connected to a given video device through enabled links, + * either directly or indirectly, as streaming. The given pipeline object is + * assigned to every pad in the pipeline and stored in the media_pad pipe + * field. + * + * Calls to this function can be nested, in which case the same number of + * video_device_pipeline_stop() calls will be required to stop streaming. The + * pipeline pointer must be identical for all nested calls to + * video_device_pipeline_start(). + * + * The video device must contain a single pad. + * + * This is a convenience wrapper around media_pipeline_start(). + */ +__must_check int video_device_pipeline_start(struct video_device *vdev, + struct media_pipeline *pipe); + +/** + * __video_device_pipeline_start - Mark a pipeline as streaming + * @vdev: Starting video device + * @pipe: Media pipeline to be assigned to all entities in the pipeline. + * + * ..note:: This is the non-locking version of video_device_pipeline_start() + * + * The video device must contain a single pad. + * + * This is a convenience wrapper around __media_pipeline_start(). + */ +__must_check int __video_device_pipeline_start(struct video_device *vdev, + struct media_pipeline *pipe); + +/** + * video_device_pipeline_stop - Mark a pipeline as not streaming + * @vdev: Starting video device + * + * Mark all entities connected to a given video device through enabled links, + * either directly or indirectly, as not streaming. The media_pad pipe field + * is reset to %NULL. + * + * If multiple calls to media_pipeline_start() have been made, the same + * number of calls to this function are required to mark the pipeline as not + * streaming. + * + * The video device must contain a single pad. + * + * This is a convenience wrapper around media_pipeline_stop(). + */ +void video_device_pipeline_stop(struct video_device *vdev); + +/** + * __video_device_pipeline_stop - Mark a pipeline as not streaming + * @vdev: Starting video device + * + * .. note:: This is the non-locking version of media_pipeline_stop() + * + * The video device must contain a single pad. + * + * This is a convenience wrapper around __media_pipeline_stop(). + */ +void __video_device_pipeline_stop(struct video_device *vdev); + +/** + * video_device_pipeline_alloc_start - Mark a pipeline as streaming + * @vdev: Starting video device + * + * video_device_pipeline_alloc_start() is similar to video_device_pipeline_start() + * but instead of working on a given pipeline the function will use an + * existing pipeline if the video device is already part of a pipeline, or + * allocate a new pipeline. + * + * Calls to video_device_pipeline_alloc_start() must be matched with + * video_device_pipeline_stop(). + */ +__must_check int video_device_pipeline_alloc_start(struct video_device *vdev); + +/** + * video_device_pipeline - Get the media pipeline a video device is part of + * @vdev: The video device + * + * This function returns the media pipeline that a video device has been + * associated with when constructing the pipeline with + * video_device_pipeline_start(). The pointer remains valid until + * video_device_pipeline_stop() is called. + * + * Return: The media_pipeline the video device is part of, or NULL if the video + * device is not part of any pipeline. + * + * The video device must contain a single pad. + * + * This is a convenience wrapper around media_entity_pipeline(). + */ +struct media_pipeline *video_device_pipeline(struct video_device *vdev); + +#endif /* CONFIG_MEDIA_CONTROLLER */ + #endif /* _V4L2_DEV_H */ diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 15e4ab672223..394d798f3dfa 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -45,10 +45,6 @@ struct v4l2_async_subdev; */ struct v4l2_fwnode_endpoint { struct fwnode_endpoint base; - /* - * Fields below this line will be zeroed by - * v4l2_fwnode_endpoint_parse() - */ enum v4l2_mbus_type bus_type; struct { struct v4l2_mbus_config_parallel parallel; diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index fdbd5257e020..bb9de6a899e0 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -486,10 +486,10 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, * @vma: pointer to struct &vm_area_struct * * Call from driver's mmap() function. Will handle mmap() for both queues - * seamlessly for videobuffer, which will receive normal per-queue offsets and - * proper videobuf queue pointers. The differentiation is made outside videobuf - * by adding a predefined offset to buffers from one of the queues and - * subtracting it before passing it back to videobuf. Only drivers (and + * seamlessly for the video buffer, which will receive normal per-queue offsets + * and proper vb2 queue pointers. The differentiation is made outside + * vb2 by adding a predefined offset to buffers from one of the queues + * and subtracting it before passing it back to vb2. Only drivers (and * thus applications) receive modified offsets. */ int v4l2_m2m_mmap(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, @@ -544,7 +544,7 @@ void v4l2_m2m_release(struct v4l2_m2m_dev *m2m_dev); * @m2m_dev: opaque pointer to the internal data to handle M2M context * @drv_priv: driver's instance private data * @queue_init: a callback for queue type-specific initialization function - * to be used for initializing videobuf_queues + * to be used for initializing vb2_queues * * Usually called from driver's ``open()`` function. */ @@ -579,7 +579,7 @@ void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx); * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx * @vbuf: pointer to struct &vb2_v4l2_buffer * - * Call from videobuf_queue_ops->ops->buf_queue, videobuf_queue_ops callback. + * Call from vb2_queue_ops->ops->buf_queue, vb2_queue_ops callback. */ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_v4l2_buffer *vbuf); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 9689f38a0af1..2f80c9c818ed 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -358,7 +358,11 @@ struct v4l2_mbus_frame_desc_entry { } bus; }; -#define V4L2_FRAME_DESC_ENTRY_MAX 4 + /* + * If this number is too small, it should be dropped altogether and the + * API switched to a dynamic number of frame descriptor entries. + */ +#define V4L2_FRAME_DESC_ENTRY_MAX 8 /** * enum v4l2_mbus_frame_desc_type - media bus frame description type @@ -1046,6 +1050,8 @@ v4l2_subdev_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { + if (WARN_ON(!state)) + return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; return &state->pads[pad].try_fmt; @@ -1064,6 +1070,8 @@ v4l2_subdev_get_pad_crop(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { + if (WARN_ON(!state)) + return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; return &state->pads[pad].try_crop; @@ -1082,6 +1090,8 @@ v4l2_subdev_get_pad_compose(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, unsigned int pad) { + if (WARN_ON(!state)) + return NULL; if (WARN_ON(pad >= sd->entity.num_pads)) pad = 0; return &state->pads[pad].try_compose; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 5468b633b9d2..3253bd2f6fee 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -65,7 +65,7 @@ struct vb2_buffer; * DMABUF memory types. * @get_userptr: acquire userspace memory for a hardware operation; used for * USERPTR memory types; vaddr is the address passed to the - * videobuf layer when queuing a video buffer of USERPTR type; + * videobuf2 layer when queuing a video buffer of USERPTR type; * should return an allocator private per-buffer structure * associated with the buffer on success, ERR_PTR() on failure; * the returned private structure will then be passed as @buf_priv @@ -97,7 +97,7 @@ struct vb2_buffer; * associated with the passed private structure or NULL if not * available. * @num_users: return the current number of users of a memory buffer; - * return 1 if the videobuf layer (or actually the driver using + * return 1 if the videobuf2 layer (or actually the driver using * it) is the only user. * @mmap: setup a userspace mapping for a given memory buffer under * the provided virtual memory region. @@ -210,11 +210,11 @@ enum vb2_io_modes { * enum vb2_buffer_state - current video buffer state. * @VB2_BUF_STATE_DEQUEUED: buffer under userspace control. * @VB2_BUF_STATE_IN_REQUEST: buffer is queued in media request. - * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf. - * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver. + * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf2. + * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf2, but not in driver. * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used * in a hardware operation. - * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but + * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf2, but * not yet dequeued to userspace. * @VB2_BUF_STATE_ERROR: same as above, but the operation on the buffer * has ended with an error, which will be reported @@ -466,7 +466,7 @@ struct vb2_buf_ops { }; /** - * struct vb2_queue - a videobuf queue. + * struct vb2_queue - a videobuf2 queue. * * @type: private buffer type whose content is defined by the vb2-core * caller. For example, for V4L2, it should match @@ -544,7 +544,7 @@ struct vb2_buf_ops { * @mmap_lock: private mutex used when buffers are allocated/freed/mmapped * @memory: current memory type used * @dma_dir: DMA mapping direction. - * @bufs: videobuf buffer structures + * @bufs: videobuf2 buffer structures * @num_buffers: number of allocated/used buffers * @queued_list: list of buffers currently queued from userspace * @queued_count: number of buffers queued and ready for streaming. @@ -683,7 +683,7 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no); void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); /** - * vb2_buffer_done() - inform videobuf that an operation on a buffer + * vb2_buffer_done() - inform videobuf2 that an operation on a buffer * is finished. * @vb: pointer to &struct vb2_buffer to be used. * @state: state of the buffer, as defined by &enum vb2_buffer_state. diff --git a/include/media/videobuf2-dvb.h b/include/media/videobuf2-dvb.h index 8605366ec87c..2d577b945637 100644 --- a/include/media/videobuf2-dvb.h +++ b/include/media/videobuf2-dvb.h @@ -24,7 +24,7 @@ struct vb2_dvb { struct dvb_frontend *frontend; struct vb2_queue dvbq; - /* video-buf-dvb state info */ + /* vb2-dvb state info */ struct mutex lock; int nfeeds; diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 76e405c0b003..5a845887850b 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -63,22 +63,6 @@ struct vb2_v4l2_buffer { container_of(vb, struct vb2_v4l2_buffer, vb2_buf) /** - * vb2_find_timestamp() - Find buffer with given timestamp in the queue - * - * @q: pointer to &struct vb2_queue with videobuf2 queue. - * @timestamp: the timestamp to find. - * @start_idx: the start index (usually 0) in the buffer array to start - * searching from. Note that there may be multiple buffers - * with the same timestamp value, so you can restart the search - * by setting @start_idx to the previously found index + 1. - * - * Returns the buffer index of the buffer with the given @timestamp, or - * -1 if no buffer with @timestamp was found. - */ -int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp, - unsigned int start_idx); - -/** * vb2_find_buffer() - Find a buffer with given timestamp * * @q: pointer to &struct vb2_queue with videobuf2 queue. diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h index c3baaea0b8ef..d58fa1cdcb08 100644 --- a/include/uapi/linux/cec-funcs.h +++ b/include/uapi/linux/cec-funcs.h @@ -1568,6 +1568,20 @@ static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg * } } +static inline void cec_msg_set_audio_volume_level(struct cec_msg *msg, + __u8 audio_volume_level) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_AUDIO_VOLUME_LEVEL; + msg->msg[2] = audio_volume_level; +} + +static inline void cec_ops_set_audio_volume_level(const struct cec_msg *msg, + __u8 *audio_volume_level) +{ + *audio_volume_level = msg->msg[2]; +} + /* Audio Rate Control Feature */ static inline void cec_msg_set_audio_rate(struct cec_msg *msg, diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 1d48da926216..b8e071abaea5 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -768,6 +768,7 @@ struct cec_event { #define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08 #define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04 #define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02 +#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_VOLUME_LEVEL 0x01 #define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */ @@ -1059,6 +1060,7 @@ struct cec_event { #define CEC_OP_AUD_FMT_ID_CEA861 0 #define CEC_OP_AUD_FMT_ID_CEA861_CXT 1 +#define CEC_MSG_SET_AUDIO_VOLUME_LEVEL 0x73 /* Audio Rate Control Feature */ #define CEC_MSG_SET_AUDIO_RATE 0x9a diff --git a/include/uapi/linux/dw100.h b/include/uapi/linux/dw100.h new file mode 100644 index 000000000000..3356496edd6b --- /dev/null +++ b/include/uapi/linux/dw100.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* Copyright 2022 NXP */ + +#ifndef __UAPI_DW100_H__ +#define __UAPI_DW100_H__ + +#include <linux/v4l2-controls.h> + +/* + * Check Documentation/userspace-api/media/drivers/dw100.rst for control details. + */ +#define V4L2_CID_DW100_DEWARPING_16x16_VERTEX_MAP (V4L2_CID_USER_DW100_BASE + 1) + +#endif diff --git a/include/uapi/linux/rkisp1-config.h b/include/uapi/linux/rkisp1-config.h index 583ca0d9a79d..730673ecc63d 100644 --- a/include/uapi/linux/rkisp1-config.h +++ b/include/uapi/linux/rkisp1-config.h @@ -117,7 +117,46 @@ /* * Defect Pixel Cluster Correction */ -#define RKISP1_CIF_ISP_DPCC_METHODS_MAX 3 +#define RKISP1_CIF_ISP_DPCC_METHODS_MAX 3 + +#define RKISP1_CIF_ISP_DPCC_MODE_STAGE1_ENABLE (1U << 2) + +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_G_CENTER (1U << 0) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_INCL_RB_CENTER (1U << 1) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_G_3X3 (1U << 2) +#define RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_STAGE1_RB_3X3 (1U << 3) + +/* 0-2 for sets 1-3 */ +#define RKISP1_CIF_ISP_DPCC_SET_USE_STAGE1_USE_SET(n) ((n) << 0) +#define RKISP1_CIF_ISP_DPCC_SET_USE_STAGE1_USE_FIX_SET (1U << 3) + +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_PG_GREEN_ENABLE (1U << 0) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_LC_GREEN_ENABLE (1U << 1) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RO_GREEN_ENABLE (1U << 2) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RND_GREEN_ENABLE (1U << 3) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RG_GREEN_ENABLE (1U << 4) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_PG_RED_BLUE_ENABLE (1U << 8) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_LC_RED_BLUE_ENABLE (1U << 9) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RO_RED_BLUE_ENABLE (1U << 10) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RND_RED_BLUE_ENABLE (1U << 11) +#define RKISP1_CIF_ISP_DPCC_METHODS_SET_RG_RED_BLUE_ENABLE (1U << 12) + +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_G(v) ((v) << 0) +#define RKISP1_CIF_ISP_DPCC_LINE_THRESH_RB(v) ((v) << 8) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_G(v) ((v) << 0) +#define RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_RB(v) ((v) << 8) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_G(v) ((v) << 0) +#define RKISP1_CIF_ISP_DPCC_PG_FAC_RB(v) ((v) << 8) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_G(v) ((v) << 0) +#define RKISP1_CIF_ISP_DPCC_RND_THRESH_RB(v) ((v) << 8) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_G(v) ((v) << 0) +#define RKISP1_CIF_ISP_DPCC_RG_FAC_RB(v) ((v) << 8) + +#define RKISP1_CIF_ISP_DPCC_RO_LIMITS_n_G(n, v) ((v) << ((n) * 4)) +#define RKISP1_CIF_ISP_DPCC_RO_LIMITS_n_RB(n, v) ((v) << ((n) * 4 + 2)) + +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_n_G(n, v) ((v) << ((n) * 4)) +#define RKISP1_CIF_ISP_DPCC_RND_OFFS_n_RB(n, v) ((v) << ((n) * 4 + 2)) /* * Denoising pre filter @@ -249,16 +288,20 @@ struct rkisp1_cif_isp_bls_config { }; /** - * struct rkisp1_cif_isp_dpcc_methods_config - Methods Configuration used by DPCC + * struct rkisp1_cif_isp_dpcc_methods_config - DPCC methods set configuration * - * Methods Configuration used by Defect Pixel Cluster Correction + * This structure stores the configuration of one set of methods for the DPCC + * algorithm. Multiple methods can be selected in each set (independently for + * the Green and Red/Blue components) through the @method field, the result is + * the logical AND of all enabled methods. The remaining fields set thresholds + * and factors for each method. * - * @method: Method enable bits - * @line_thresh: Line threshold - * @line_mad_fac: Line MAD factor - * @pg_fac: Peak gradient factor - * @rnd_thresh: Rank Neighbor Difference threshold - * @rg_fac: Rank gradient factor + * @method: Method enable bits (RKISP1_CIF_ISP_DPCC_METHODS_SET_*) + * @line_thresh: Line threshold (RKISP1_CIF_ISP_DPCC_LINE_THRESH_*) + * @line_mad_fac: Line Mean Absolute Difference factor (RKISP1_CIF_ISP_DPCC_LINE_MAD_FAC_*) + * @pg_fac: Peak gradient factor (RKISP1_CIF_ISP_DPCC_PG_FAC_*) + * @rnd_thresh: Rank Neighbor Difference threshold (RKISP1_CIF_ISP_DPCC_RND_THRESH_*) + * @rg_fac: Rank gradient factor (RKISP1_CIF_ISP_DPCC_RG_FAC_*) */ struct rkisp1_cif_isp_dpcc_methods_config { __u32 method; @@ -272,14 +315,16 @@ struct rkisp1_cif_isp_dpcc_methods_config { /** * struct rkisp1_cif_isp_dpcc_config - Configuration used by DPCC * - * Configuration used by Defect Pixel Cluster Correction + * Configuration used by Defect Pixel Cluster Correction. Three sets of methods + * can be configured and selected through the @set_use field. The result is the + * logical OR of all enabled sets. * - * @mode: dpcc output mode - * @output_mode: whether use hard coded methods - * @set_use: stage1 methods set - * @methods: methods config - * @ro_limits: rank order limits - * @rnd_offs: differential rank offsets for rank neighbor difference + * @mode: DPCC mode (RKISP1_CIF_ISP_DPCC_MODE_*) + * @output_mode: Interpolation output mode (RKISP1_CIF_ISP_DPCC_OUTPUT_MODE_*) + * @set_use: Methods sets selection (RKISP1_CIF_ISP_DPCC_SET_USE_*) + * @methods: Methods sets configuration + * @ro_limits: Rank order limits (RKISP1_CIF_ISP_DPCC_RO_LIMITS_*) + * @rnd_offs: Differential rank offsets for rank neighbor difference (RKISP1_CIF_ISP_DPCC_RND_OFFS_*) */ struct rkisp1_cif_isp_dpcc_config { __u32 mode; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 5f46bf4a570c..b5e7d082b8ad 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -225,6 +225,12 @@ enum v4l2_colorfx { */ #define V4L2_CID_USER_ISL7998X_BASE (V4L2_CID_USER_BASE + 0x1180) +/* + * The base for DW100 driver controls. + * We reserve 16 controls for this driver. + */ +#define V4L2_CID_USER_DW100_BASE (V4L2_CID_USER_BASE + 0x1190) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ @@ -1730,7 +1736,7 @@ struct v4l2_vp8_segment { * @sharpness_level: matches sharpness_level syntax element. * @level: matches loop_filter_level syntax element. * @padding: padding field. Should be zeroed by applications. - * @flags: see V4L2_VP8_LF_FLAG_{}. + * @flags: see V4L2_VP8_LF_{}. * * This structure contains loop filter related parameters. * See the 'mb_lf_adjustments()' part of the frame header syntax, diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 01e630f2ec78..86cae23cc446 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -502,7 +502,6 @@ struct v4l2_capability { #define V4L2_CAP_META_CAPTURE 0x00800000 /* Is a metadata capture device */ #define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ -#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ #define V4L2_CAP_META_OUTPUT 0x08000000 /* Is a metadata output device */ @@ -2435,6 +2434,7 @@ struct v4l2_event_vsync { #define V4L2_EVENT_CTRL_CH_VALUE (1 << 0) #define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1) #define V4L2_EVENT_CTRL_CH_RANGE (1 << 2) +#define V4L2_EVENT_CTRL_CH_DIMENSIONS (1 << 3) struct v4l2_event_ctrl { __u32 changes; @@ -2682,6 +2682,11 @@ struct v4l2_create_buffers { #ifndef __KERNEL__ #define V4L2_PIX_FMT_HM12 V4L2_PIX_FMT_NV12_16L16 #define V4L2_PIX_FMT_SUNXI_TILED_NV12 V4L2_PIX_FMT_NV12_32L32 +/* + * This capability was never implemented, anyone using this cap should drop it + * from their code. + */ +#define V4L2_CAP_ASYNCIO 0x02000000 #endif #endif /* _UAPI__LINUX_VIDEODEV2_H */ |