Pull media updates from Mauro Carvalho Chehab: - v4l2 core: - sub-device framework routing improvements - NV12M tiled variants added to v4l2_format_info - some fixes at control handler freeing logic - fixed H264 SEPARATE_COLOUR_PLANE check - new staging driver: Intel IPU7 PCI - Rockchip video decoder driver got promoted from staging - iris: added HEVC/VP9 encoder/decoder support - vsp1: driver has gained Renesas VSPX support - uvc: - switched to vb2 ioctl helpers - added MSXU 1.5 metadata support - atomisp: GC0310 sensor driver cleanups in preparation for moving it out of staging - Lots of cleanup, fixes and improvements * tag 'media/v6.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (310 commits) media: rkvdec: Unstage the driver media: rkvdec: Remove TODO file media: dt-bindings: rockchip: Add RK3576 Video Decoder bindings media: dt-bindings: rockchip: Document RK3588 Video Decoder bindings media: amphion: Support dmabuf and v4l2 buffer without binding media: verisilicon: postproc: 4K support media: v4l2: Add support for NV12M tiled variants to v4l2_format_info() media: uvcvideo: Use a count variable for meta_formats instead of 0 terminating media: uvcvideo: Auto-set UVC_QUIRK_MSXU_META media: uvcvideo: Introduce V4L2_META_FMT_UVC_MSXU_1_5 media: uvcvideo: Introduce dev->meta_formats media: Documentation: Add note about UVCH length field media: uvcvideo: Do not mark valid metadata as invalid media: uvcvideo: uvc_v4l2_unlocked_ioctl: Invert PM logic media: core: export v4l2_translate_cmd media: uvcvideo: Turn on the camera if V4L2_EVENT_SUB_FL_SEND_INITIAL media: uvcvideo: Remove stream->is_streaming field media: uvcvideo: Split uvc_stop_streaming() media: uvcvideo: Handle locks in uvc_queue_return_buffers media: uvcvideo: Use vb2 ioctl and fop helpers ...
Unified · Split
| @@ -287,8 +287,9 @@ Gustavo Padovan <padovan@profusion.mobi> · 286 unmodified lines | ||
| 287 | 287 | Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com> |
| 288 | 288 | Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org> |
| 289 | 289 | Hans de Goede <hansg@kernel.org> <hdegoede@redhat.com> |
| 290 | −Hans Verkuil <hverkuil@xs4all.nl> <hansverk@cisco.com> | |
| 291 | −Hans Verkuil <hverkuil@xs4all.nl> <hverkuil-cisco@xs4all.nl> | |
| 290 | +Hans Verkuil <hverkuil@kernel.org> <hverkuil@xs4all.nl> | |
| 291 | +Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl> | |
| 292 | +Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com> | |
| 292 | 293 | Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com> |
| 293 | 294 | Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com> |
| 294 | 295 | Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com> |
| @@ -24,6 +24,14 @@ properties: · 23 unmodified lines | ||
| 24 | 24 | reg: |
| 25 | 25 | maxItems: 1 |
| 26 | 26 | |
| 27 | + interrupts: | |
| 28 | + maxItems: 2 | |
| 29 | + | |
| 30 | + interrupt-names: | |
| 31 | + items: | |
| 32 | + - const: error_irq | |
| 33 | + - const: irq | |
| 34 | + | |
| 27 | 35 | clocks: |
| 28 | 36 | items: |
| 29 | 37 | - description: CSI2Rx system clock |
| @@ -0,0 +1,42 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/fsl,imx6q-vdoa.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Freescale Video Data Order Adapter | |
| 8 | + | |
| 9 | +description: | |
| 10 | + The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose | |
| 11 | + is to reorder video data from the macroblock tiled order produced by the CODA | |
| 12 | + 960 VPU to the conventional raster-scan order for scanout. | |
| 13 | + | |
| 14 | +maintainers: | |
| 15 | + - Frank Li <Frank.Li@nxp.com> | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: "fsl,imx6q-vdoa" | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | +additionalProperties: false | |
| 31 | + | |
| 32 | +examples: | |
| 33 | + - | | |
| 34 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 35 | + #include <dt-bindings/clock/imx6qdl-clock.h> | |
| 36 | + | |
| 37 | + vdoa@21e4000 { | |
| 38 | + compatible = "fsl,imx6q-vdoa"; | |
| 39 | + reg = <0x021e4000 0x4000>; | |
| 40 | + interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; | |
| 41 | + clocks = <&clks IMX6QDL_CLK_VDOA>; | |
| 42 | + }; | |
| @@ -0,0 +1,117 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/fsl,imx8qm-isi.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: i.MX8QM Image Sensing Interface | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Frank Li <Frank.Li@nxp.com> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + The Image Sensing Interface (ISI) combines image processing pipelines with | |
| 14 | + DMA engines to process and capture frames originating from a variety of | |
| 15 | + sources. The inputs to the ISI go through Pixel Link interfaces, and their | |
| 16 | + number and nature is SoC-dependent. They cover both capture interfaces (MIPI | |
| 17 | + CSI-2 RX, HDMI RX, ...) and display engine outputs for writeback support. | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + enum: | |
| 22 | + - fsl,imx8qm-isi | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 8 | |
| 29 | + | |
| 30 | + clock-names: | |
| 31 | + items: | |
| 32 | + - const: per0 | |
| 33 | + - const: per1 | |
| 34 | + - const: per2 | |
| 35 | + - const: per3 | |
| 36 | + - const: per4 | |
| 37 | + - const: per5 | |
| 38 | + - const: per6 | |
| 39 | + - const: per7 | |
| 40 | + | |
| 41 | + interrupts: | |
| 42 | + maxItems: 8 | |
| 43 | + | |
| 44 | + power-domains: | |
| 45 | + maxItems: 8 | |
| 46 | + | |
| 47 | + ports: | |
| 48 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 49 | + properties: | |
| 50 | + port@2: | |
| 51 | + $ref: /schemas/graph.yaml#/properties/port | |
| 52 | + description: MIPI CSI-2 RX 0 | |
| 53 | + port@3: | |
| 54 | + $ref: /schemas/graph.yaml#/properties/port | |
| 55 | + description: MIPI CSI-2 RX 1 | |
| 56 | + port@4: | |
| 57 | + $ref: /schemas/graph.yaml#/properties/port | |
| 58 | + description: HDMI RX | |
| 59 | + | |
| 60 | +required: | |
| 61 | + - compatible | |
| 62 | + - reg | |
| 63 | + - clocks | |
| 64 | + - clock-names | |
| 65 | + - interrupts | |
| 66 | + - power-domains | |
| 67 | + - ports | |
| 68 | + | |
| 69 | +additionalProperties: false | |
| 70 | + | |
| 71 | +examples: | |
| 72 | + - | | |
| 73 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 74 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 75 | + #include <dt-bindings/clock/imx8-clock.h> | |
| 76 | + #include <dt-bindings/clock/imx8-lpcg.h> | |
| 77 | + #include <dt-bindings/firmware/imx/rsrc.h> | |
| 78 | + | |
| 79 | + image-controller@58100000 { | |
| 80 | + compatible = "fsl,imx8qm-isi"; | |
| 81 | + reg = <0x58100000 0x80000>; | |
| 82 | + interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>, | |
| 83 | + <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>, | |
| 84 | + <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>, | |
| 85 | + <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>, | |
| 86 | + <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>, | |
| 87 | + <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>, | |
| 88 | + <GIC_SPI 303 IRQ_TYPE_LEVEL_HIGH>, | |
| 89 | + <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>; | |
| 90 | + clocks = <&pdma0_lpcg IMX_LPCG_CLK_0>, | |
| 91 | + <&pdma1_lpcg IMX_LPCG_CLK_0>, | |
| 92 | + <&pdma2_lpcg IMX_LPCG_CLK_0>, | |
| 93 | + <&pdma3_lpcg IMX_LPCG_CLK_0>, | |
| 94 | + <&pdma4_lpcg IMX_LPCG_CLK_0>, | |
| 95 | + <&pdma5_lpcg IMX_LPCG_CLK_0>, | |
| 96 | + <&pdma6_lpcg IMX_LPCG_CLK_0>, | |
| 97 | + <&pdma7_lpcg IMX_LPCG_CLK_0>; | |
| 98 | + clock-names = "per0", "per1", "per2", "per3", | |
| 99 | + "per4", "per5", "per6", "per7"; | |
| 100 | + power-domains = <&pd IMX_SC_R_ISI_CH0>, <&pd IMX_SC_R_ISI_CH1>, | |
| 101 | + <&pd IMX_SC_R_ISI_CH2>, <&pd IMX_SC_R_ISI_CH3>, | |
| 102 | + <&pd IMX_SC_R_ISI_CH4>, <&pd IMX_SC_R_ISI_CH5>, | |
| 103 | + <&pd IMX_SC_R_ISI_CH6>, <&pd IMX_SC_R_ISI_CH7>; | |
| 104 | + | |
| 105 | + ports { | |
| 106 | + #address-cells = <1>; | |
| 107 | + #size-cells = <0>; | |
| 108 | + | |
| 109 | + port@2 { | |
| 110 | + reg = <2>; | |
| 111 | + endpoint { | |
| 112 | + remote-endpoint = <&mipi_csi0_out>; | |
| 113 | + }; | |
| 114 | + }; | |
| 115 | + }; | |
| 116 | + }; | |
| 117 | +... | |
| @@ -0,0 +1,106 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/fsl,imx8qxp-isi.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: i.MX8QXP Image Sensing Interface | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Frank Li <Frank.Li@nxp.com> | |
| 11 | + | |
| 12 | +description: | |
| 13 | + The Image Sensing Interface (ISI) combines image processing pipelines with | |
| 14 | + DMA engines to process and capture frames originating from a variety of | |
| 15 | + sources. The inputs to the ISI go through Pixel Link interfaces, and their | |
| 16 | + number and nature is SoC-dependent. They cover both capture interfaces (MIPI | |
| 17 | + CSI-2 RX, HDMI RX, ...) and display engine outputs for writeback support. | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + enum: | |
| 22 | + - fsl,imx8qxp-isi | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 6 | |
| 29 | + | |
| 30 | + clock-names: | |
| 31 | + items: | |
| 32 | + - const: per0 | |
| 33 | + - const: per1 | |
| 34 | + - const: per2 | |
| 35 | + - const: per3 | |
| 36 | + - const: per4 | |
| 37 | + - const: per5 | |
| 38 | + | |
| 39 | + interrupts: | |
| 40 | + maxItems: 6 | |
| 41 | + | |
| 42 | + power-domains: | |
| 43 | + maxItems: 6 | |
| 44 | + | |
| 45 | + ports: | |
| 46 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 47 | + properties: | |
| 48 | + port@2: | |
| 49 | + $ref: /schemas/graph.yaml#/properties/port | |
| 50 | + description: MIPI CSI-2 RX 0 | |
| 51 | + port@6: | |
| 52 | + $ref: /schemas/graph.yaml#/properties/port | |
| 53 | + description: CSI-2 Parallel RX | |
| 54 | + | |
| 55 | +required: | |
| 56 | + - compatible | |
| 57 | + - reg | |
| 58 | + - clocks | |
| 59 | + - clock-names | |
| 60 | + - interrupts | |
| 61 | + - power-domains | |
| 62 | + - ports | |
| 63 | + | |
| 64 | +additionalProperties: false | |
| 65 | + | |
| 66 | +examples: | |
| 67 | + - | | |
| 68 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 69 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 70 | + #include <dt-bindings/clock/imx8-clock.h> | |
| 71 | + #include <dt-bindings/clock/imx8-lpcg.h> | |
| 72 | + #include <dt-bindings/firmware/imx/rsrc.h> | |
| 73 | + | |
| 74 | + image-controller@58100000 { | |
| 75 | + compatible = "fsl,imx8qxp-isi"; | |
| 76 | + reg = <0x58100000 0x60000>; | |
| 77 | + interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>, | |
| 78 | + <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>, | |
| 79 | + <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>, | |
| 80 | + <GIC_SPI 300 IRQ_TYPE_LEVEL_HIGH>, | |
| 81 | + <GIC_SPI 301 IRQ_TYPE_LEVEL_HIGH>, | |
| 82 | + <GIC_SPI 302 IRQ_TYPE_LEVEL_HIGH>; | |
| 83 | + clocks = <&pdma0_lpcg IMX_LPCG_CLK_0>, | |
| 84 | + <&pdma1_lpcg IMX_LPCG_CLK_0>, | |
| 85 | + <&pdma2_lpcg IMX_LPCG_CLK_0>, | |
| 86 | + <&pdma3_lpcg IMX_LPCG_CLK_0>, | |
| 87 | + <&pdma4_lpcg IMX_LPCG_CLK_0>, | |
| 88 | + <&pdma5_lpcg IMX_LPCG_CLK_0>; | |
| 89 | + clock-names = "per0", "per1", "per2", "per3", "per4", "per5"; | |
| 90 | + power-domains = <&pd IMX_SC_R_ISI_CH0>, <&pd IMX_SC_R_ISI_CH1>, | |
| 91 | + <&pd IMX_SC_R_ISI_CH2>, <&pd IMX_SC_R_ISI_CH3>, | |
| 92 | + <&pd IMX_SC_R_ISI_CH4>, <&pd IMX_SC_R_ISI_CH5>; | |
| 93 | + | |
| 94 | + ports { | |
| 95 | + #address-cells = <1>; | |
| 96 | + #size-cells = <0>; | |
| 97 | + | |
| 98 | + port@2 { | |
| 99 | + reg = <2>; | |
| 100 | + endpoint { | |
| 101 | + remote-endpoint = <&mipi_csi0_out>; | |
| 102 | + }; | |
| 103 | + }; | |
| 104 | + }; | |
| 105 | + }; | |
| 106 | +... | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −Freescale Video Data Order Adapter | |
| 2 | −================================== | |
| 3 | − | |
| 4 | −The Video Data Order Adapter (VDOA) is present on the i.MX6q. Its sole purpose | |
| 5 | −is to reorder video data from the macroblock tiled order produced by the CODA | |
| 6 | −960 VPU to the conventional raster-scan order for scanout. | |
| 7 | − | |
| 8 | −Required properties: | |
| 9 | −- compatible: must be "fsl,imx6q-vdoa" | |
| 10 | −- reg: the register base and size for the device registers | |
| 11 | −- interrupts: the VDOA interrupt | |
| 12 | −- clocks: the vdoa clock | |
| 13 | − | |
| 14 | −Example: | |
| 15 | − | |
| 16 | −vdoa@21e4000 { | |
| 17 | − compatible = "fsl,imx6q-vdoa"; | |
| 18 | − reg = <0x021e4000 0x4000>; | |
| 19 | − interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>; | |
| 20 | − clocks = <&clks IMX6QDL_CLK_VDOA>; | |
| 21 | −}; | |
| @@ -23,6 +23,9 @@ description: · 22 unmodified lines | ||
| 23 | 23 | More detailed documentation can be found in |
| 24 | 24 | Documentation/devicetree/bindings/media/video-interfaces.txt . |
| 25 | 25 | |
| 26 | +allOf: | |
| 27 | + - $ref: /schemas/media/video-interface-devices.yaml# | |
| 28 | + | |
| 26 | 29 | properties: |
| 27 | 30 | compatible: |
| 28 | 31 | oneOf: |
| @@ -58,16 +61,10 @@ properties: · 29 unmodified lines | ||
| 58 | 61 | documentation. |
| 59 | 62 | maxItems: 1 |
| 60 | 63 | |
| 61 | − flash-leds: | |
| 62 | − description: Flash LED phandles. See ../video-interfaces.txt for details. | |
| 63 | − | |
| 64 | − lens-focus: | |
| 65 | − description: Lens focus controller phandles. See ../video-interfaces.txt | |
| 66 | − for details. | |
| 64 | + flash-leds: true | |
| 65 | + lens-focus: true | |
| 67 | 66 | |
| 68 | 67 | rotation: |
| 69 | − description: Rotation of the sensor. See ../video-interfaces.txt for | |
| 70 | − details. | |
| 71 | 68 | enum: [ 0, 180 ] |
| 72 | 69 | |
| 73 | 70 | port: |
| @@ -70,6 +70,15 @@ properties: · 69 unmodified lines | ||
| 70 | 70 | - bus-type |
| 71 | 71 | - link-frequencies |
| 72 | 72 | |
| 73 | + slew-rate: | |
| 74 | + $ref: /schemas/types.yaml#/definitions/uint32 | |
| 75 | + description: | |
| 76 | + Slew rate ot the output pads DOUT[7:0], LINE_VALID, FRAME_VALID and | |
| 77 | + PIXCLK. Higher values imply steeper voltage-flanks on the pads. | |
| 78 | + minimum: 0 | |
| 79 | + maximum: 7 | |
| 80 | + default: 7 | |
| 81 | + | |
| 73 | 82 | required: |
| 74 | 83 | - compatible |
| 75 | 84 | - reg |
| @@ -15,6 +15,8 @@ description: | · 14 unmodified lines | ||
| 15 | 15 | controlled through an I2C-compatible SCCB bus. The sensor transmits images |
| 16 | 16 | on a MIPI CSI-2 output interface with up to 4 data lanes. |
| 17 | 17 | |
| 18 | +$ref: /schemas/media/video-interface-devices.yaml# | |
| 19 | + | |
| 18 | 20 | properties: |
| 19 | 21 | compatible: |
| 20 | 22 | const: ovti,ov8858 |
| @@ -69,7 +71,7 @@ required: · 48 unmodified lines | ||
| 69 | 71 | - clocks |
| 70 | 72 | - port |
| 71 | 73 | |
| 72 | −additionalProperties: false | |
| 74 | +unevaluatedProperties: false | |
| 73 | 75 | |
| 74 | 76 | examples: |
| 75 | 77 | - | |
| @@ -33,20 +33,21 @@ properties: · 32 unmodified lines | ||
| 33 | 33 | |
| 34 | 34 | clock-frequency: |
| 35 | 35 | description: Frequency of the xclk clock in Hz. |
| 36 | + deprecated: true | |
| 36 | 37 | |
| 37 | 38 | enable-gpios: |
| 38 | 39 | description: GPIO descriptor for the enable pin. |
| 39 | 40 | maxItems: 1 |
| 40 | 41 | |
| 41 | − vdddo-supply: | |
| 42 | − description: Chip digital IO regulator (1.8V). | |
| 43 | − | |
| 44 | 42 | vdda-supply: |
| 45 | 43 | description: Chip analog regulator (2.7V). |
| 46 | 44 | |
| 47 | 45 | vddd-supply: |
| 48 | 46 | description: Chip digital core regulator (1.12V). |
| 49 | 47 | |
| 48 | + vdddo-supply: | |
| 49 | + description: Chip digital IO regulator (1.8V). | |
| 50 | + | |
| 50 | 51 | flash-leds: true |
| 51 | 52 | lens-focus: true |
| 52 | 53 | |
| @@ -84,11 +85,10 @@ required: · 31 unmodified lines | ||
| 84 | 85 | - compatible |
| 85 | 86 | - reg |
| 86 | 87 | - clocks |
| 87 | − - clock-frequency | |
| 88 | 88 | - enable-gpios |
| 89 | − - vdddo-supply | |
| 90 | 89 | - vdda-supply |
| 91 | 90 | - vddd-supply |
| 91 | + - vdddo-supply | |
| 92 | 92 | - port |
| 93 | 93 | |
| 94 | 94 | unevaluatedProperties: false |
| @@ -104,22 +104,25 @@ examples: · 9 unmodified lines | ||
| 104 | 104 | camera-sensor@1a { |
| 105 | 105 | compatible = "sony,imx214"; |
| 106 | 106 | reg = <0x1a>; |
| 107 | − vdddo-supply = <&pm8994_lvs1>; | |
| 108 | − vddd-supply = <&camera_vddd_1v12>; | |
| 107 | + | |
| 108 | + clocks = <&camera_clk>; | |
| 109 | + assigned-clocks = <&camera_clk>; | |
| 110 | + assigned-clock-rates = <24000000>; | |
| 111 | + | |
| 112 | + enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; | |
| 113 | + | |
| 109 | 114 | vdda-supply = <&pm8994_l17>; |
| 115 | + vddd-supply = <&camera_vddd_1v12>; | |
| 116 | + vdddo-supply = <&pm8994_lvs1>; | |
| 117 | + | |
| 110 | 118 | lens-focus = <&ad5820>; |
| 111 | − enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; | |
| 112 | − clocks = <&camera_clk>; | |
| 113 | − clock-frequency = <24000000>; | |
| 114 | 119 | |
| 115 | 120 | port { |
| 116 | 121 | imx214_ep: endpoint { |
| 117 | 122 | data-lanes = <1 2 3 4>; |
| 118 | − link-frequencies = /bits/ 64 <480000000>; | |
| 123 | + link-frequencies = /bits/ 64 <600000000>; | |
| 119 | 124 | remote-endpoint = <&csiphy0_ep>; |
| 120 | 125 | }; |
| 121 | 126 | }; |
| 122 | 127 | }; |
| 123 | 128 | }; |
| 124 | − | |
| 125 | −... | |
| @@ -18,6 +18,8 @@ description: |- · 17 unmodified lines | ||
| 18 | 18 | The camera module does not expose the model through registers, so the |
| 19 | 19 | exact model needs to be specified. |
| 20 | 20 | |
| 21 | +$ref: /schemas/media/video-interface-devices.yaml# | |
| 22 | + | |
| 21 | 23 | properties: |
| 22 | 24 | compatible: |
| 23 | 25 | enum: |
| @@ -81,7 +83,7 @@ required: · 57 unmodified lines | ||
| 81 | 83 | - reg |
| 82 | 84 | - port |
| 83 | 85 | |
| 84 | −additionalProperties: false | |
| 86 | +unevaluatedProperties: false | |
| 85 | 87 | |
| 86 | 88 | examples: |
| 87 | 89 | - | |
| @@ -22,10 +22,14 @@ properties: · 21 unmodified lines | ||
| 22 | 22 | - nxp,imx8qxp-jpgdec |
| 23 | 23 | - nxp,imx8qxp-jpgenc |
| 24 | 24 | - items: |
| 25 | − - const: nxp,imx8qm-jpgdec | |
| 25 | + - enum: | |
| 26 | + - nxp,imx8qm-jpgdec | |
| 27 | + - nxp,imx95-jpgdec | |
| 26 | 28 | - const: nxp,imx8qxp-jpgdec |
| 27 | 29 | - items: |
| 28 | − - const: nxp,imx8qm-jpgenc | |
| 30 | + - enum: | |
| 31 | + - nxp,imx8qm-jpgenc | |
| 32 | + - nxp,imx95-jpgenc | |
| 29 | 33 | - const: nxp,imx8qxp-jpgenc |
| 30 | 34 | |
| 31 | 35 | reg: |
| @@ -48,7 +52,7 @@ properties: · 16 unmodified lines | ||
| 48 | 52 | description: |
| 49 | 53 | List of phandle and PM domain specifier as documented in |
| 50 | 54 | Documentation/devicetree/bindings/power/power_domain.txt |
| 51 | − minItems: 2 # Wrapper and 1 slot | |
| 55 | + minItems: 1 # Wrapper and all slots | |
| 52 | 56 | maxItems: 5 # Wrapper and 4 slots |
| 53 | 57 | |
| 54 | 58 | required: |
| @@ -58,6 +62,24 @@ required: · 3 unmodified lines | ||
| 58 | 62 | - interrupts |
| 59 | 63 | - power-domains |
| 60 | 64 | |
| 65 | +allOf: | |
| 66 | + - if: | |
| 67 | + properties: | |
| 68 | + compatible: | |
| 69 | + contains: | |
| 70 | + enum: | |
| 71 | + - nxp,imx95-jpgenc | |
| 72 | + - nxp,imx95-jpgdec | |
| 73 | + then: | |
| 74 | + properties: | |
| 75 | + power-domains: | |
| 76 | + maxItems: 1 | |
| 77 | + else: | |
| 78 | + properties: | |
| 79 | + power-domains: | |
| 80 | + minItems: 2 # Wrapper and 1 slot | |
| 81 | + | |
| 82 | + | |
| 61 | 83 | additionalProperties: false |
| 62 | 84 | |
| 63 | 85 | examples: |
| @@ -16,11 +16,19 @@ description: |- · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | properties: |
| 18 | 18 | compatible: |
| 19 | − enum: | |
| 20 | − - fsl,imx8mq-mipi-csi2 | |
| 19 | + oneOf: | |
| 20 | + - enum: | |
| 21 | + - fsl,imx8mq-mipi-csi2 | |
| 22 | + - fsl,imx8qxp-mipi-csi2 | |
| 23 | + - items: | |
| 24 | + - const: fsl,imx8qm-mipi-csi2 | |
| 25 | + - const: fsl,imx8qxp-mipi-csi2 | |
| 21 | 26 | |
| 22 | 27 | reg: |
| 23 | − maxItems: 1 | |
| 28 | + items: | |
| 29 | + - description: MIPI CSI-2 RX host controller register. | |
| 30 | + - description: MIPI CSI-2 control and status register (csr). | |
| 31 | + minItems: 1 | |
| 24 | 32 | |
| 25 | 33 | clocks: |
| 26 | 34 | items: |
| @@ -46,6 +54,7 @@ properties: · 19 unmodified lines | ||
| 46 | 54 | - description: CORE_RESET reset register bit definition |
| 47 | 55 | - description: PHY_REF_RESET reset register bit definition |
| 48 | 56 | - description: ESC_RESET reset register bit definition |
| 57 | + minItems: 1 | |
| 49 | 58 | |
| 50 | 59 | fsl,mipi-phy-gpr: |
| 51 | 60 | description: | |
| @@ -113,9 +122,30 @@ required: · 61 unmodified lines | ||
| 113 | 122 | - clock-names |
| 114 | 123 | - power-domains |
| 115 | 124 | - resets |
| 116 | − - fsl,mipi-phy-gpr | |
| 117 | 125 | - ports |
| 118 | 126 | |
| 127 | +allOf: | |
| 128 | + - if: | |
| 129 | + properties: | |
| 130 | + compatible: | |
| 131 | + contains: | |
| 132 | + enum: | |
| 133 | + - fsl,imx8qxp-mipi-csi2 | |
| 134 | + then: | |
| 135 | + properties: | |
| 136 | + reg: | |
| 137 | + minItems: 2 | |
| 138 | + resets: | |
| 139 | + maxItems: 1 | |
| 140 | + else: | |
| 141 | + properties: | |
| 142 | + reg: | |
| 143 | + maxItems: 1 | |
| 144 | + resets: | |
| 145 | + minItems: 3 | |
| 146 | + required: | |
| 147 | + - fsl,mipi-phy-gpr | |
| 148 | + | |
| 119 | 149 | additionalProperties: false |
| 120 | 150 | |
| 121 | 151 | examples: |
| @@ -133,7 +133,7 @@ properties: · 132 unmodified lines | ||
| 133 | 133 | CSI input ports. |
| 134 | 134 | |
| 135 | 135 | patternProperties: |
| 136 | − "^port@[0-3]+$": | |
| 136 | + "^port@[0-3]$": | |
| 137 | 137 | $ref: /schemas/graph.yaml#/$defs/port-base |
| 138 | 138 | unevaluatedProperties: false |
| 139 | 139 | |
| @@ -146,15 +146,16 @@ properties: · 6 unmodified lines | ||
| 146 | 146 | unevaluatedProperties: false |
| 147 | 147 | |
| 148 | 148 | properties: |
| 149 | − clock-lanes: | |
| 150 | − maxItems: 1 | |
| 151 | − | |
| 152 | 149 | data-lanes: |
| 153 | 150 | minItems: 1 |
| 154 | 151 | maxItems: 4 |
| 155 | 152 | |
| 153 | + bus-type: | |
| 154 | + enum: | |
| 155 | + - 1 # MEDIA_BUS_TYPE_CSI2_CPHY | |
| 156 | + - 4 # MEDIA_BUS_TYPE_CSI2_DPHY | |
| 157 | + | |
| 156 | 158 | required: |
| 157 | − - clock-lanes | |
| 158 | 159 | - data-lanes |
| 159 | 160 | |
| 160 | 161 | required: |
| @@ -189,7 +190,7 @@ examples: · 28 unmodified lines | ||
| 189 | 190 | #address-cells = <2>; |
| 190 | 191 | #size-cells = <2>; |
| 191 | 192 | |
| 192 | − camss: isp@acb6000 { | |
| 193 | + camss: isp@acb7000 { | |
| 193 | 194 | compatible = "qcom,x1e80100-camss"; |
| 194 | 195 | |
| 195 | 196 | reg = <0 0x0acb7000 0 0x2000>, |
| @@ -357,7 +358,6 @@ examples: · 161 unmodified lines | ||
| 357 | 358 | port@0 { |
| 358 | 359 | reg = <0>; |
| 359 | 360 | csiphy_ep0: endpoint { |
| 360 | − clock-lanes = <7>; | |
| 361 | 361 | data-lanes = <0 1>; |
| 362 | 362 | remote-endpoint = <&sensor_ep>; |
| 363 | 363 | }; |
| @@ -30,6 +30,7 @@ properties: · 29 unmodified lines | ||
| 30 | 30 | - renesas,r9a07g043u-fcpvd # RZ/G2UL |
| 31 | 31 | - renesas,r9a07g044-fcpvd # RZ/G2{L,LC} |
| 32 | 32 | - renesas,r9a07g054-fcpvd # RZ/V2L |
| 33 | + - renesas,r9a09g056-fcpvd # RZ/V2N | |
| 33 | 34 | - renesas,r9a09g057-fcpvd # RZ/V2H(P) |
| 34 | 35 | - const: renesas,fcpv # Generic FCP for VSP fallback |
| 35 | 36 | |
| @@ -25,6 +25,7 @@ properties: · 24 unmodified lines | ||
| 25 | 25 | - enum: |
| 26 | 26 | - renesas,r9a07g043u-vsp2 # RZ/G2UL |
| 27 | 27 | - renesas,r9a07g054-vsp2 # RZ/V2L |
| 28 | + - renesas,r9a09g056-vsp2 # RZ/V2N | |
| 28 | 29 | - renesas,r9a09g057-vsp2 # RZ/V2H(P) |
| 29 | 30 | - const: renesas,r9a07g044-vsp2 # RZ/G2L fallback |
| 30 | 31 | |
| @@ -10,13 +10,15 @@ maintainers: · 9 unmodified lines | ||
| 10 | 10 | - Heiko Stuebner <heiko@sntech.de> |
| 11 | 11 | |
| 12 | 12 | description: |- |
| 13 | − The Rockchip rk3399 has a stateless Video Decoder that can decodes H.264, | |
| 14 | − HEVC an VP9 streams. | |
| 13 | + Rockchip SoCs have variants of the same stateless Video Decoder that can | |
| 14 | + decodes H.264, HEVC, VP9 and AV1 streams, depending on the variant. | |
| 15 | 15 | |
| 16 | 16 | properties: |
| 17 | 17 | compatible: |
| 18 | 18 | oneOf: |
| 19 | 19 | - const: rockchip,rk3399-vdec |
| 20 | + - const: rockchip,rk3576-vdec | |
| 21 | + - const: rockchip,rk3588-vdec | |
| 20 | 22 | - items: |
| 21 | 23 | - enum: |
| 22 | 24 | - rockchip,rk3228-vdec |
| @@ -24,35 +26,72 @@ properties: · 1 unmodified line | ||
| 24 | 26 | - const: rockchip,rk3399-vdec |
| 25 | 27 | |
| 26 | 28 | reg: |
| 27 | − maxItems: 1 | |
| 29 | + minItems: 1 | |
| 30 | + items: | |
| 31 | + - description: The function configuration registers base | |
| 32 | + - description: The link table configuration registers base | |
| 33 | + - description: The cache configuration registers base | |
| 34 | + | |
| 35 | + reg-names: | |
| 36 | + items: | |
| 37 | + - const: function | |
| 38 | + - const: link | |
| 39 | + - const: cache | |
| 28 | 40 | |
| 29 | 41 | interrupts: |
| 30 | 42 | maxItems: 1 |
| 31 | 43 | |
| 32 | 44 | clocks: |
| 45 | + minItems: 4 | |
| 33 | 46 | items: |
| 34 | 47 | - description: The Video Decoder AXI interface clock |
| 35 | 48 | - description: The Video Decoder AHB interface clock |
| 36 | 49 | - description: The Video Decoded CABAC clock |
| 37 | 50 | - description: The Video Decoder core clock |
| 51 | + - description: The Video decoder HEVC CABAC clock | |
| 38 | 52 | |
| 39 | 53 | clock-names: |
| 54 | + minItems: 4 | |
| 40 | 55 | items: |
| 41 | 56 | - const: axi |
| 42 | 57 | - const: ahb |
| 43 | 58 | - const: cabac |
| 44 | 59 | - const: core |
| 60 | + - const: hevc_cabac | |
| 45 | 61 | |
| 46 | 62 | assigned-clocks: true |
| 47 | 63 | |
| 48 | 64 | assigned-clock-rates: true |
| 49 | 65 | |
| 66 | + resets: | |
| 67 | + items: | |
| 68 | + - description: The Video Decoder AXI interface reset | |
| 69 | + - description: The Video Decoder AHB interface reset | |
| 70 | + - description: The Video Decoded CABAC reset | |
| 71 | + - description: The Video Decoder core reset | |
| 72 | + - description: The Video decoder HEVC CABAC reset | |
| 73 | + | |
| 74 | + reset-names: | |
| 75 | + items: | |
| 76 | + - const: axi | |
| 77 | + - const: ahb | |
| 78 | + - const: cabac | |
| 79 | + - const: core | |
| 80 | + - const: hevc_cabac | |
| 81 | + | |
| 50 | 82 | power-domains: |
| 51 | 83 | maxItems: 1 |
| 52 | 84 | |
| 53 | 85 | iommus: |
| 54 | 86 | maxItems: 1 |
| 55 | 87 | |
| 88 | + sram: | |
| 89 | + $ref: /schemas/types.yaml#/definitions/phandle | |
| 90 | + description: | | |
| 91 | + phandle to a reserved on-chip SRAM regions. | |
| 92 | + Some SoCs, like rk3588 provide on-chip SRAM to store temporary | |
| 93 | + buffers during decoding. | |
| 94 | + | |
| 56 | 95 | required: |
| 57 | 96 | - compatible |
| 58 | 97 | - reg |
| @@ -61,6 +100,41 @@ required: · 2 unmodified lines | ||
| 61 | 100 | - clock-names |
| 62 | 101 | - power-domains |
| 63 | 102 | |
| 103 | +allOf: | |
| 104 | + - if: | |
| 105 | + properties: | |
| 106 | + compatible: | |
| 107 | + contains: | |
| 108 | + enum: | |
| 109 | + - rockchip,rk3576-vdec | |
| 110 | + - rockchip,rk3588-vdec | |
| 111 | + then: | |
| 112 | + properties: | |
| 113 | + reg: | |
| 114 | + minItems: 3 | |
| 115 | + reg-names: | |
| 116 | + minItems: 3 | |
| 117 | + clocks: | |
| 118 | + minItems: 5 | |
| 119 | + clock-names: | |
| 120 | + minItems: 5 | |
| 121 | + resets: | |
| 122 | + minItems: 5 | |
| 123 | + reset-names: | |
| 124 | + minItems: 5 | |
| 125 | + else: | |
| 126 | + properties: | |
| 127 | + reg: | |
| 128 | + maxItems: 1 | |
| 129 | + reg-names: false | |
| 130 | + clocks: | |
| 131 | + maxItems: 4 | |
| 132 | + clock-names: | |
| 133 | + maxItems: 4 | |
| 134 | + resets: false | |
| 135 | + reset-names: false | |
| 136 | + sram: false | |
| 137 | + | |
| 64 | 138 | additionalProperties: false |
| 65 | 139 | |
| 66 | 140 | examples: |
| @@ -110,6 +110,7 @@ For sub-device drivers: · 109 unmodified lines | ||
| 110 | 110 | |
| 111 | 111 | v4l2_ctrl_handler_free(&foo->ctrl_handler); |
| 112 | 112 | |
| 113 | +:c:func:`v4l2_ctrl_handler_free` does not touch the handler's ``error`` field. | |
| 113 | 114 | |
| 114 | 115 | 2) Add controls: |
| 115 | 116 | |
| @@ -191,12 +192,8 @@ These functions are typically called right after the · 75 unmodified lines | ||
| 191 | 192 | V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, |
| 192 | 193 | 0, test_pattern); |
| 193 | 194 | ... |
| 194 | − if (foo->ctrl_handler.error) { | |
| 195 | − int err = foo->ctrl_handler.error; | |
| 196 | − | |
| 197 | − v4l2_ctrl_handler_free(&foo->ctrl_handler); | |
| 198 | − return err; | |
| 199 | − } | |
| 195 | + if (foo->ctrl_handler.error) | |
| 196 | + return v4l2_ctrl_handler_free(&foo->ctrl_handler); | |
| 200 | 197 | |
| 201 | 198 | The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to |
| 202 | 199 | the new control, but if you do not need to access the pointer outside the |
| @@ -41,6 +41,9 @@ error injection status:: · 40 unmodified lines | ||
| 41 | 41 | # <op> rx-clear clear all rx error injections for <op> |
| 42 | 42 | # <op> tx-clear clear all tx error injections for <op> |
| 43 | 43 | # |
| 44 | + # RX error injection settings: | |
| 45 | + # rx-no-low-drive do not generate low-drive pulses | |
| 46 | + # | |
| 44 | 47 | # RX error injection: |
| 45 | 48 | # <op>[,<mode>] rx-nack NACK the message instead of sending an ACK |
| 46 | 49 | # <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position |
| @@ -53,6 +56,10 @@ error injection status:: · 6 unmodified lines | ||
| 53 | 56 | # tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse |
| 54 | 57 | # tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse |
| 55 | 58 | # tx-custom-pulse transmit the custom pulse once the bus is idle |
| 59 | + # tx-glitch-low-usecs <usecs> define the 'low' time for the glitch pulse | |
| 60 | + # tx-glitch-high-usecs <usecs> define the 'high' time for the glitch pulse | |
| 61 | + # tx-glitch-falling-edge send the glitch pulse after every falling edge | |
| 62 | + # tx-glitch-rising-edge send the glitch pulse after every rising edge | |
| 56 | 63 | # |
| 57 | 64 | # TX error injection: |
| 58 | 65 | # <op>[,<mode>] tx-no-eom don't set the EOM bit |
| @@ -193,6 +200,14 @@ Receive Messages · 134 unmodified lines | ||
| 193 | 200 | This does not work if the remote CEC transmitter has logical address |
| 194 | 201 | 0 ('TV') since that will always win. |
| 195 | 202 | |
| 203 | +``rx-no-low-drive`` | |
| 204 | + The receiver will ignore situations that would normally generate a | |
| 205 | + Low Drive pulse (3.6 ms). This is typically done if a spurious pulse is | |
| 206 | + detected when receiving a message, and it indicates to the transmitter that | |
| 207 | + the message has to be retransmitted since the receiver got confused. | |
| 208 | + Disabling this is useful to test how other CEC devices handle glitches | |
| 209 | + by ensuring we will not be the one that generates a Low Drive. | |
| 210 | + | |
| 196 | 211 | Transmit Messages |
| 197 | 212 | ----------------- |
| 198 | 213 | |
| @@ -327,3 +342,30 @@ Custom Pulses · 128 unmodified lines | ||
| 327 | 342 | |
| 328 | 343 | ``tx-custom-pulse`` |
| 329 | 344 | Transmit a single custom pulse as soon as the CEC bus is idle. |
| 345 | + | |
| 346 | +Glitch Pulses | |
| 347 | +------------- | |
| 348 | + | |
| 349 | +This emulates what happens if the signal on the CEC line is seeing spurious | |
| 350 | +pulses. Typically this happens after the falling or rising edge where there | |
| 351 | +is a short voltage fluctuation that, if the CEC hardware doesn't do | |
| 352 | +deglitching, can be seen as a spurious pulse and can cause a Low Drive | |
| 353 | +condition or corrupt data. | |
| 354 | + | |
| 355 | +``tx-glitch-low-usecs <usecs>`` | |
| 356 | + This defines the duration in microseconds that the glitch pulse pulls | |
| 357 | + the CEC line low. The default is 1 microsecond. The range is 0-100 | |
| 358 | + microseconds. If 0, then no glitch pulse will be generated. | |
| 359 | + | |
| 360 | +``tx-glitch-high-usecs <usecs>`` | |
| 361 | + This defines the duration in microseconds that the glitch pulse keeps the | |
| 362 | + CEC line high (unless another CEC adapter pulls it low in that time). | |
| 363 | + The default is 1 microseconds. The range is 0-100 microseconds. If 0, then | |
| 364 | + no glitch pulse will be generated.The total period of the glitch pulse is | |
| 365 | + ``tx-custom-low-usecs + tx-custom-high-usecs``. | |
| 366 | + | |
| 367 | +``tx-glitch-falling-edge`` | |
| 368 | + Send the glitch pulse right after the falling edge. | |
| 369 | + | |
| 370 | +``tx-glitch-rising-edge`` | |
| 371 | + Send the glitch pulse right after the rising edge. | |
| @@ -150,7 +150,7 @@ ITU-T.81 · 149 unmodified lines | ||
| 150 | 150 | ======== |
| 151 | 151 | |
| 152 | 152 | |
| 153 | −:title: ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continous-Tone Still Images --- Requirements and Guidelines" | |
| 153 | +:title: ITU-T Recommendation T.81 "Information Technology --- Digital Compression and Coding of Continuous-Tone Still Images --- Requirements and Guidelines" | |
| 154 | 154 | |
| 155 | 155 | :author: International Telecommunication Union (http://www.itu.int) |
| 156 | 156 | |
| @@ -48,7 +48,7 @@ capabilities, and they may support :ref:`control` ioctls. · 47 unmodified lines | ||
| 48 | 48 | The :ref:`video standard <standard>` ioctls provide information vital |
| 49 | 49 | to program a sliced VBI device, therefore must be supported. |
| 50 | 50 | |
| 51 | −.. _sliced-vbi-format-negotitation: | |
| 51 | +.. _sliced-vbi-format-negotiation: | |
| 52 | 52 | |
| 53 | 53 | Sliced VBI Format Negotiation |
| 54 | 54 | ============================= |
| @@ -377,7 +377,7 @@ Sliced VBI Data in MPEG Streams · 322 unmodified lines | ||
| 377 | 377 | |
| 378 | 378 | If a device can produce an MPEG output stream, it may be capable of |
| 379 | 379 | providing |
| 380 | −:ref:`negotiated sliced VBI services <sliced-vbi-format-negotitation>` | |
| 380 | +:ref:`negotiated sliced VBI services <sliced-vbi-format-negotiation>` | |
| 381 | 381 | as data embedded in the MPEG stream. Users or applications control this |
| 382 | 382 | sliced VBI data insertion with the |
| 383 | 383 | :ref:`V4L2_CID_MPEG_STREAM_VBI_FMT <v4l2-mpeg-stream-vbi-fmt>` |
| @@ -64,17 +64,12 @@ FM_RX Control IDs · 63 unmodified lines | ||
| 64 | 64 | broadcasts speech. If the transmitter doesn't make this distinction, |
| 65 | 65 | then it will be set. |
| 66 | 66 | |
| 67 | −``V4L2_CID_TUNE_DEEMPHASIS`` | |
| 68 | − (enum) | |
| 69 | − | |
| 70 | −enum v4l2_deemphasis - | |
| 67 | +``V4L2_CID_TUNE_DEEMPHASIS (enum)`` | |
| 71 | 68 | Configures the de-emphasis value for reception. A de-emphasis filter |
| 72 | 69 | is applied to the broadcast to accentuate the high audio |
| 73 | 70 | frequencies. Depending on the region, a time constant of either 50 |
| 74 | − or 75 useconds is used. The enum v4l2_deemphasis defines possible | |
| 75 | − values for de-emphasis. Here they are: | |
| 76 | − | |
| 77 | − | |
| 71 | + or 75 microseconds is used. The enum v4l2_deemphasis defines possible | |
| 72 | + values for de-emphasis. They are: | |
| 78 | 73 | |
| 79 | 74 | .. flat-table:: |
| 80 | 75 | :header-rows: 0 |
| @@ -104,7 +104,7 @@ FM_TX Control IDs · 103 unmodified lines | ||
| 104 | 104 | |
| 105 | 105 | ``V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (integer)`` |
| 106 | 106 | Sets the audio deviation limiter feature release time. Unit is in |
| 107 | − useconds. Step and range are driver-specific. | |
| 107 | + microseconds. Step and range are driver-specific. | |
| 108 | 108 | |
| 109 | 109 | ``V4L2_CID_AUDIO_LIMITER_DEVIATION (integer)`` |
| 110 | 110 | Configures audio frequency deviation level in Hz. The range and step |
| @@ -121,16 +121,16 @@ FM_TX Control IDs · 10 unmodified lines | ||
| 121 | 121 | range and step are driver-specific. |
| 122 | 122 | |
| 123 | 123 | ``V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (integer)`` |
| 124 | − Sets the threshold level for audio compression freature. It is a dB | |
| 124 | + Sets the threshold level for audio compression feature. It is a dB | |
| 125 | 125 | value. The range and step are driver-specific. |
| 126 | 126 | |
| 127 | 127 | ``V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (integer)`` |
| 128 | − Sets the attack time for audio compression feature. It is a useconds | |
| 128 | + Sets the attack time for audio compression feature. It is a microseconds | |
| 129 | 129 | value. The range and step are driver-specific. |
| 130 | 130 | |
| 131 | 131 | ``V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (integer)`` |
| 132 | 132 | Sets the release time for audio compression feature. It is a |
| 133 | − useconds value. The range and step are driver-specific. | |
| 133 | + microseconds value. The range and step are driver-specific. | |
| 134 | 134 | |
| 135 | 135 | ``V4L2_CID_PILOT_TONE_ENABLED (boolean)`` |
| 136 | 136 | Enables or disables the pilot tone generation feature. |
| @@ -143,17 +143,12 @@ FM_TX Control IDs · 6 unmodified lines | ||
| 143 | 143 | Configures pilot tone frequency value. Unit is in Hz. The range and |
| 144 | 144 | step are driver-specific. |
| 145 | 145 | |
| 146 | −``V4L2_CID_TUNE_PREEMPHASIS`` | |
| 147 | − (enum) | |
| 148 | − | |
| 149 | −enum v4l2_preemphasis - | |
| 146 | +``V4L2_CID_TUNE_PREEMPHASIS (enum)`` | |
| 150 | 147 | Configures the pre-emphasis value for broadcasting. A pre-emphasis |
| 151 | 148 | filter is applied to the broadcast to accentuate the high audio |
| 152 | 149 | frequencies. Depending on the region, a time constant of either 50 |
| 153 | − or 75 useconds is used. The enum v4l2_preemphasis defines possible | |
| 154 | − values for pre-emphasis. Here they are: | |
| 155 | − | |
| 156 | − | |
| 150 | + or 75 microseconds is used. The enum v4l2_preemphasis defines possible | |
| 151 | + values for pre-emphasis. They are: | |
| 157 | 152 | |
| 158 | 153 | .. flat-table:: |
| 159 | 154 | :header-rows: 0 |
| @@ -166,8 +161,6 @@ enum v4l2_preemphasis - · 6 unmodified lines | ||
| 166 | 161 | * - ``V4L2_PREEMPHASIS_75_uS`` |
| 167 | 162 | - A pre-emphasis of 75 uS is used. |
| 168 | 163 | |
| 169 | − | |
| 170 | − | |
| 171 | 164 | ``V4L2_CID_TUNE_POWER_LEVEL (integer)`` |
| 172 | 165 | Sets the output power level for signal transmission. Unit is in |
| 173 | 166 | dBuV. Range and step are driver-specific. |
| @@ -20,6 +20,7 @@ These formats are used for the :ref:`metadata` interface only. · 19 unmodified lines | ||
| 20 | 20 | metafmt-pisp-fe |
| 21 | 21 | metafmt-rkisp1 |
| 22 | 22 | metafmt-uvc |
| 23 | + metafmt-uvc-msxu-1-5 | |
| 23 | 24 | metafmt-vivid |
| 24 | 25 | metafmt-vsp1-hgo |
| 25 | 26 | metafmt-vsp1-hgt |
| @@ -0,0 +1,23 @@ | ||
| 1 | +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later | |
| 2 | + | |
| 3 | +.. _v4l2-meta-fmt-uvc-msxu-1-5: | |
| 4 | + | |
| 5 | +*********************************** | |
| 6 | +V4L2_META_FMT_UVC_MSXU_1_5 ('UVCM') | |
| 7 | +*********************************** | |
| 8 | + | |
| 9 | +Microsoft(R)'s UVC Payload Metadata. | |
| 10 | + | |
| 11 | + | |
| 12 | +Description | |
| 13 | +=========== | |
| 14 | + | |
| 15 | +V4L2_META_FMT_UVC_MSXU_1_5 buffers follow the metadata buffer layout of | |
| 16 | +V4L2_META_FMT_UVC with the only difference that it includes all the UVC | |
| 17 | +metadata in the `buffer[]` field, not just the first 2-12 bytes. | |
| 18 | + | |
| 19 | +The metadata format follows the specification from Microsoft(R) [1]. | |
| 20 | + | |
| 21 | +.. _1: | |
| 22 | + | |
| 23 | +[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5 | |
| @@ -44,7 +44,9 @@ Each individual block contains the following fields: · 43 unmodified lines | ||
| 44 | 44 | them |
| 45 | 45 | * - :cspan:`1` *The rest is an exact copy of the UVC payload header:* |
| 46 | 46 | * - __u8 length; |
| 47 | − - length of the rest of the block, including this field | |
| 47 | + - length of the rest of the block, including this field. Please note that | |
| 48 | + regardless of this value, for V4L2_META_FMT_UVC the kernel will never | |
| 49 | + copy more than 2-12 bytes. | |
| 48 | 50 | * - __u8 flags; |
| 49 | 51 | - Flags, indicating presence of other standard UVC fields |
| 50 | 52 | * - __u8 buf[]; |
| @@ -19,6 +19,7 @@ orders. See also `the Wikipedia article on Bayer filter · 18 unmodified lines | ||
| 19 | 19 | .. toctree:: |
| 20 | 20 | :maxdepth: 1 |
| 21 | 21 | |
| 22 | + pixfmt-rawnn-cru | |
| 22 | 23 | pixfmt-srggb8 |
| 23 | 24 | pixfmt-srggb8-pisp-comp |
| 24 | 25 | pixfmt-srggb10 |
| @@ -0,0 +1,143 @@ | ||
| 1 | +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later | |
| 2 | + | |
| 3 | +.. _v4l2-pix-fmt-raw-cru10: | |
| 4 | +.. _v4l2-pix-fmt-raw-cru12: | |
| 5 | +.. _v4l2-pix-fmt-raw-cru14: | |
| 6 | +.. _v4l2-pix-fmt-raw-cru20: | |
| 7 | + | |
| 8 | +********************************************************************************************************************************** | |
| 9 | +V4L2_PIX_FMT_RAW_CRU10 ('CR10'), V4L2_PIX_FMT_RAW_CRU12 ('CR12'), V4L2_PIX_FMT_RAW_CRU14 ('CR14'), V4L2_PIX_FMT_RAW_CRU20 ('CR20') | |
| 10 | +********************************************************************************************************************************** | |
| 11 | + | |
| 12 | +=============================================================== | |
| 13 | +Renesas RZ/V2H Camera Receiver Unit 64-bit packed pixel formats | |
| 14 | +=============================================================== | |
| 15 | + | |
| 16 | +| V4L2_PIX_FMT_RAW_CRU10 (CR10) | |
| 17 | +| V4L2_PIX_FMT_RAW_CRU12 (CR12) | |
| 18 | +| V4L2_PIX_FMT_RAW_CRU14 (CR14) | |
| 19 | +| V4L2_PIX_FMT_RAW_CRU20 (CR20) | |
| 20 | + | |
| 21 | +Description | |
| 22 | +=========== | |
| 23 | + | |
| 24 | +These pixel formats are some of the RAW outputs for the Camera Receiver Unit in | |
| 25 | +the Renesas RZ/V2H SoC. They are raw formats which pack pixels contiguously into | |
| 26 | +64-bit units, with the 4 or 8 most significant bits padded. | |
| 27 | + | |
| 28 | +**Byte Order** | |
| 29 | + | |
| 30 | +.. flat-table:: RAW formats | |
| 31 | + :header-rows: 2 | |
| 32 | + :stub-columns: 0 | |
| 33 | + :widths: 36 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 | |
| 34 | + :fill-cells: | |
| 35 | + | |
| 36 | + * - :rspan:`1` Pixel Format Code | |
| 37 | + - :cspan:`63` Data organization | |
| 38 | + * - 63 | |
| 39 | + - 62 | |
| 40 | + - 61 | |
| 41 | + - 60 | |
| 42 | + - 59 | |
| 43 | + - 58 | |
| 44 | + - 57 | |
| 45 | + - 56 | |
| 46 | + - 55 | |
| 47 | + - 54 | |
| 48 | + - 53 | |
| 49 | + - 52 | |
| 50 | + - 51 | |
| 51 | + - 50 | |
| 52 | + - 49 | |
| 53 | + - 48 | |
| 54 | + - 47 | |
| 55 | + - 46 | |
| 56 | + - 45 | |
| 57 | + - 44 | |
| 58 | + - 43 | |
| 59 | + - 42 | |
| 60 | + - 41 | |
| 61 | + - 40 | |
| 62 | + - 39 | |
| 63 | + - 38 | |
| 64 | + - 37 | |
| 65 | + - 36 | |
| 66 | + - 35 | |
| 67 | + - 34 | |
| 68 | + - 33 | |
| 69 | + - 32 | |
| 70 | + - 31 | |
| 71 | + - 30 | |
| 72 | + - 29 | |
| 73 | + - 28 | |
| 74 | + - 27 | |
| 75 | + - 26 | |
| 76 | + - 25 | |
| 77 | + - 24 | |
| 78 | + - 23 | |
| 79 | + - 22 | |
| 80 | + - 21 | |
| 81 | + - 20 | |
| 82 | + - 19 | |
| 83 | + - 18 | |
| 84 | + - 17 | |
| 85 | + - 16 | |
| 86 | + - 15 | |
| 87 | + - 14 | |
| 88 | + - 13 | |
| 89 | + - 12 | |
| 90 | + - 11 | |
| 91 | + - 10 | |
| 92 | + - 9 | |
| 93 | + - 8 | |
| 94 | + - 7 | |
| 95 | + - 6 | |
| 96 | + - 5 | |
| 97 | + - 4 | |
| 98 | + - 3 | |
| 99 | + - 2 | |
| 100 | + - 1 | |
| 101 | + - 0 | |
| 102 | + * - V4L2_PIX_FMT_RAW_CRU10 | |
| 103 | + - 0 | |
| 104 | + - 0 | |
| 105 | + - 0 | |
| 106 | + - 0 | |
| 107 | + - :cspan:`9` P5 | |
| 108 | + - :cspan:`9` P4 | |
| 109 | + - :cspan:`9` P3 | |
| 110 | + - :cspan:`9` P2 | |
| 111 | + - :cspan:`9` P1 | |
| 112 | + - :cspan:`9` P0 | |
| 113 | + * - V4L2_PIX_FMT_RAW_CRU12 | |
| 114 | + - 0 | |
| 115 | + - 0 | |
| 116 | + - 0 | |
| 117 | + - 0 | |
| 118 | + - :cspan:`11` P4 | |
| 119 | + - :cspan:`11` P3 | |
| 120 | + - :cspan:`11` P2 | |
| 121 | + - :cspan:`11` P1 | |
| 122 | + - :cspan:`11` P0 | |
| 123 | + * - V4L2_PIX_FMT_RAW_CRU14 | |
| 124 | + - 0 | |
| 125 | + - 0 | |
| 126 | + - 0 | |
| 127 | + - 0 | |
| 128 | + - 0 | |
| 129 | + - 0 | |
| 130 | + - 0 | |
| 131 | + - 0 | |
| 132 | + - :cspan:`13` P3 | |
| 133 | + - :cspan:`13` P2 | |
| 134 | + - :cspan:`13` P1 | |
| 135 | + - :cspan:`13` P0 | |
| 136 | + * - V4L2_PIX_FMT_RAW_CRU20 | |
| 137 | + - 0 | |
| 138 | + - 0 | |
| 139 | + - 0 | |
| 140 | + - 0 | |
| 141 | + - :cspan:`19` P2 | |
| 142 | + - :cspan:`19` P1 | |
| 143 | + - :cspan:`19` P0 | |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | .. _v4l2-pix-fmt-sgrbg12p: |
| 7 | 7 | |
| 8 | 8 | ******************************************************************************************************************************* |
| 9 | −V4L2_PIX_FMT_SRGGB12P ('pRCC'), V4L2_PIX_FMT_SGRBG12P ('pgCC'), V4L2_PIX_FMT_SGBRG12P ('pGCC'), V4L2_PIX_FMT_SBGGR12P ('pBCC'), | |
| 9 | +V4L2_PIX_FMT_SRGGB12P ('pRCC'), V4L2_PIX_FMT_SGRBG12P ('pgCC'), V4L2_PIX_FMT_SGBRG12P ('pGCC'), V4L2_PIX_FMT_SBGGR12P ('pBCC') | |
| 10 | 10 | ******************************************************************************************************************************* |
| 11 | 11 | |
| 12 | 12 | |
| @@ -20,7 +20,7 @@ Description · 7 unmodified lines | ||
| 20 | 20 | These four pixel formats are packed raw sRGB / Bayer formats with 12 |
| 21 | 21 | bits per colour. Every two consecutive samples are packed into three |
| 22 | 22 | bytes. Each of the first two bytes contain the 8 high order bits of |
| 23 | −the pixels, and the third byte contains the four least significants | |
| 23 | +the pixels, and the third byte contains the four least significant | |
| 24 | 24 | bits of each pixel, in the same order. |
| 25 | 25 | |
| 26 | 26 | Each n-pixel row contains n/2 green samples and n/2 blue or red |
| @@ -24,7 +24,7 @@ These four pixel formats are packed raw sRGB / Bayer formats with 14 · 23 unmodified lines | ||
| 24 | 24 | bits per colour. Every four consecutive samples are packed into seven |
| 25 | 25 | bytes. Each of the first four bytes contain the eight high order bits |
| 26 | 26 | of the pixels, and the three following bytes contains the six least |
| 27 | −significants bits of each pixel, in the same order. | |
| 27 | +significant bits of each pixel, in the same order. | |
| 28 | 28 | |
| 29 | 29 | Each n-pixel row contains n/2 green samples and n/2 blue or red samples, |
| 30 | 30 | with alternating green-red and green-blue rows. They are conventionally |
| @@ -824,7 +824,7 @@ F: drivers/media/platform/allegro-dvt/ · 823 unmodified lines | ||
| 824 | 824 | |
| 825 | 825 | ALLIED VISION ALVIUM CAMERA DRIVER |
| 826 | 826 | M: Tommaso Merciai <tomm.merciai@gmail.com> |
| 827 | −M: Martin Hecht <martin.hecht@avnet.eu> | |
| 827 | +M: Martin Hecht <mhecht73@gmail.com> | |
| 828 | 828 | L: linux-media@vger.kernel.org |
| 829 | 829 | S: Maintained |
| 830 | 830 | F: Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml |
| @@ -12397,6 +12397,15 @@ T: git git://linuxtv.org/media.git · 11566 unmodified lines | ||
| 12397 | 12397 | F: Documentation/admin-guide/media/ipu6-isys.rst |
| 12398 | 12398 | F: drivers/media/pci/intel/ipu6/ |
| 12399 | 12399 | |
| 12400 | +INTEL IPU7 INPUT SYSTEM DRIVER | |
| 12401 | +M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 12402 | +R: Bingbu Cao <bingbu.cao@intel.com> | |
| 12403 | +R: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com> | |
| 12404 | +L: linux-media@vger.kernel.org | |
| 12405 | +S: Maintained | |
| 12406 | +T: git git://linuxtv.org/media.git | |
| 12407 | +F: drivers/staging/media/ipu7/ | |
| 12408 | + | |
| 12400 | 12409 | INTEL ISHTP ECLITE DRIVER |
| 12401 | 12410 | M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> |
| 12402 | 12411 | L: platform-driver-x86@vger.kernel.org |
| @@ -12684,6 +12693,16 @@ W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi · 281 unmodified lines | ||
| 12684 | 12693 | T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/ |
| 12685 | 12694 | F: drivers/net/wireless/intel/iwlwifi/ |
| 12686 | 12695 | |
| 12696 | +INTEL VISION SENSING CONTROLLER DRIVER | |
| 12697 | +M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 12698 | +R: Bingbu Cao <bingbu.cao@intel.com> | |
| 12699 | +R: Lixu Zhang <lixu.zhang@intel.com> | |
| 12700 | +R: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com> | |
| 12701 | +L: linux-media@vger.kernel.org | |
| 12702 | +S: Maintained | |
| 12703 | +T: git git://linuxtv.org/media.git | |
| 12704 | +F: drivers/media/pci/intel/ivsc/ | |
| 12705 | + | |
| 12687 | 12706 | INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER |
| 12688 | 12707 | S: Orphan |
| 12689 | 12708 | W: https://slimbootloader.github.io/security/firmware-update.html |
| @@ -18134,6 +18153,7 @@ NXP i.MX 8M ISI DRIVER · 5444 unmodified lines | ||
| 18134 | 18153 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 18135 | 18154 | L: linux-media@vger.kernel.org |
| 18136 | 18155 | S: Maintained |
| 18156 | +F: Documentation/devicetree/bindings/media/fsl,imx8*-isi.yaml | |
| 18137 | 18157 | F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml |
| 18138 | 18158 | F: drivers/media/platform/nxp/imx8-isi/ |
| 18139 | 18159 | |
| @@ -20548,6 +20568,7 @@ QUALCOMM CAMERA SUBSYSTEM DRIVER · 2408 unmodified lines | ||
| 20548 | 20568 | M: Robert Foss <rfoss@kernel.org> |
| 20549 | 20569 | M: Todor Tomov <todor.too@gmail.com> |
| 20550 | 20570 | M: Bryan O'Donoghue <bryan.odonoghue@linaro.org> |
| 20571 | +R: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> | |
| 20551 | 20572 | L: linux-media@vger.kernel.org |
| 20552 | 20573 | S: Maintained |
| 20553 | 20574 | F: Documentation/admin-guide/media/qcom_camss.rst |
| @@ -21693,6 +21714,14 @@ S: Maintained · 1139 unmodified lines | ||
| 21693 | 21714 | F: Documentation/devicetree/bindings/media/rockchip-rga.yaml |
| 21694 | 21715 | F: drivers/media/platform/rockchip/rga/ |
| 21695 | 21716 | |
| 21717 | +ROCKCHIP RKVDEC VIDEO DECODER DRIVER | |
| 21718 | +M: Detlev Casanova <detlev.casanova@collabora.com> | |
| 21719 | +L: linux-media@vger.kernel.org | |
| 21720 | +L: linux-rockchip@lists.infradead.org | |
| 21721 | +S: Maintained | |
| 21722 | +F: Documentation/devicetree/bindings/media/rockchip,vdec.yaml | |
| 21723 | +F: drivers/media/platform/rockchip/rkvdec/ | |
| 21724 | + | |
| 21696 | 21725 | ROCKCHIP RK3308 INTERNAL AUDIO CODEC |
| 21697 | 21726 | M: Luca Ceresoli <luca.ceresoli@bootlin.com> |
| 21698 | 21727 | S: Maintained |
| @@ -26081,6 +26110,7 @@ S: Maintained · 4382 unmodified lines | ||
| 26081 | 26110 | W: http://www.ideasonboard.org/uvc/ |
| 26082 | 26111 | T: git git://linuxtv.org/media.git |
| 26083 | 26112 | F: Documentation/userspace-api/media/drivers/uvcvideo.rst |
| 26113 | +F: Documentation/userspace-api/media/v4l/metafmt-uvc-msxu-1-5.rst | |
| 26084 | 26114 | F: Documentation/userspace-api/media/v4l/metafmt-uvc.rst |
| 26085 | 26115 | F: drivers/media/common/uvc.c |
| 26086 | 26116 | F: drivers/media/usb/uvc/ |
| @@ -91,16 +91,22 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 90 unmodified lines | ||
| 91 | 91 | if (!strcmp(token, "clear")) { |
| 92 | 92 | memset(pin->error_inj, 0, sizeof(pin->error_inj)); |
| 93 | 93 | pin->rx_toggle = pin->tx_toggle = false; |
| 94 | + pin->rx_no_low_drive = false; | |
| 94 | 95 | pin->tx_ignore_nack_until_eom = false; |
| 95 | 96 | pin->tx_custom_pulse = false; |
| 96 | 97 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 97 | 98 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 99 | + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 100 | + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 101 | + pin->tx_glitch_falling_edge = false; | |
| 102 | + pin->tx_glitch_rising_edge = false; | |
| 98 | 103 | return true; |
| 99 | 104 | } |
| 100 | 105 | if (!strcmp(token, "rx-clear")) { |
| 101 | 106 | for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) |
| 102 | 107 | pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; |
| 103 | 108 | pin->rx_toggle = false; |
| 109 | + pin->rx_no_low_drive = false; | |
| 104 | 110 | return true; |
| 105 | 111 | } |
| 106 | 112 | if (!strcmp(token, "tx-clear")) { |
| @@ -111,6 +117,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 4 unmodified lines | ||
| 111 | 117 | pin->tx_custom_pulse = false; |
| 112 | 118 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 113 | 119 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 120 | + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 121 | + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 122 | + pin->tx_glitch_falling_edge = false; | |
| 123 | + pin->tx_glitch_rising_edge = false; | |
| 124 | + return true; | |
| 125 | + } | |
| 126 | + if (!strcmp(token, "rx-no-low-drive")) { | |
| 127 | + pin->rx_no_low_drive = true; | |
| 114 | 128 | return true; |
| 115 | 129 | } |
| 116 | 130 | if (!strcmp(token, "tx-ignore-nack-until-eom")) { |
| @@ -122,6 +136,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 5 unmodified lines | ||
| 122 | 136 | cec_pin_start_timer(pin); |
| 123 | 137 | return true; |
| 124 | 138 | } |
| 139 | + if (!strcmp(token, "tx-glitch-falling-edge")) { | |
| 140 | + pin->tx_glitch_falling_edge = true; | |
| 141 | + return true; | |
| 142 | + } | |
| 143 | + if (!strcmp(token, "tx-glitch-rising-edge")) { | |
| 144 | + pin->tx_glitch_rising_edge = true; | |
| 145 | + return true; | |
| 146 | + } | |
| 125 | 147 | if (!p) |
| 126 | 148 | return false; |
| 127 | 149 | |
| @@ -139,7 +161,23 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, char *line) · 11 unmodified lines | ||
| 139 | 161 | |
| 140 | 162 | if (kstrtou32(p, 0, &usecs) || usecs > 10000000) |
| 141 | 163 | return false; |
| 142 | − pin->tx_custom_high_usecs = usecs; | |
| 164 | + pin->tx_glitch_high_usecs = usecs; | |
| 165 | + return true; | |
| 166 | + } | |
| 167 | + if (!strcmp(token, "tx-glitch-low-usecs")) { | |
| 168 | + u32 usecs; | |
| 169 | + | |
| 170 | + if (kstrtou32(p, 0, &usecs) || usecs > 100) | |
| 171 | + return false; | |
| 172 | + pin->tx_glitch_low_usecs = usecs; | |
| 173 | + return true; | |
| 174 | + } | |
| 175 | + if (!strcmp(token, "tx-glitch-high-usecs")) { | |
| 176 | + u32 usecs; | |
| 177 | + | |
| 178 | + if (kstrtou32(p, 0, &usecs) || usecs > 100) | |
| 179 | + return false; | |
| 180 | + pin->tx_glitch_high_usecs = usecs; | |
| 143 | 181 | return true; |
| 144 | 182 | } |
| 145 | 183 | |
| @@ -273,6 +311,9 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) · 127 unmodified lines | ||
| 273 | 311 | seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n"); |
| 274 | 312 | seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n"); |
| 275 | 313 | seq_puts(sf, "#\n"); |
| 314 | + seq_puts(sf, "# RX error injection settings:\n"); | |
| 315 | + seq_puts(sf, "# rx-no-low-drive do not generate low-drive pulses\n"); | |
| 316 | + seq_puts(sf, "#\n"); | |
| 276 | 317 | seq_puts(sf, "# RX error injection:\n"); |
| 277 | 318 | seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n"); |
| 278 | 319 | seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n"); |
| @@ -285,6 +326,10 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) · 6 unmodified lines | ||
| 285 | 326 | seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n"); |
| 286 | 327 | seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n"); |
| 287 | 328 | seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n"); |
| 329 | + seq_puts(sf, "# tx-glitch-low-usecs <usecs> define the 'low' time for the glitch pulse\n"); | |
| 330 | + seq_puts(sf, "# tx-glitch-high-usecs <usecs> define the 'high' time for the glitch pulse\n"); | |
| 331 | + seq_puts(sf, "# tx-glitch-falling-edge send the glitch pulse after every falling edge\n"); | |
| 332 | + seq_puts(sf, "# tx-glitch-rising-edge send the glitch pulse after every rising edge\n"); | |
| 288 | 333 | seq_puts(sf, "#\n"); |
| 289 | 334 | seq_puts(sf, "# TX error injection:\n"); |
| 290 | 335 | seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n"); |
| @@ -332,8 +377,14 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) · 41 unmodified lines | ||
| 332 | 377 | } |
| 333 | 378 | } |
| 334 | 379 | |
| 380 | + if (pin->rx_no_low_drive) | |
| 381 | + seq_puts(sf, "rx-no-low-drive\n"); | |
| 335 | 382 | if (pin->tx_ignore_nack_until_eom) |
| 336 | 383 | seq_puts(sf, "tx-ignore-nack-until-eom\n"); |
| 384 | + if (pin->tx_glitch_falling_edge) | |
| 385 | + seq_puts(sf, "tx-glitch-falling-edge\n"); | |
| 386 | + if (pin->tx_glitch_rising_edge) | |
| 387 | + seq_puts(sf, "tx-glitch-rising-edge\n"); | |
| 337 | 388 | if (pin->tx_custom_pulse) |
| 338 | 389 | seq_puts(sf, "tx-custom-pulse\n"); |
| 339 | 390 | if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT) |
| @@ -342,5 +393,11 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) · 2 unmodified lines | ||
| 342 | 393 | if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) |
| 343 | 394 | seq_printf(sf, "tx-custom-high-usecs %u\n", |
| 344 | 395 | pin->tx_custom_high_usecs); |
| 396 | + if (pin->tx_glitch_low_usecs != CEC_TIM_GLITCH_DEFAULT) | |
| 397 | + seq_printf(sf, "tx-glitch-low-usecs %u\n", | |
| 398 | + pin->tx_glitch_low_usecs); | |
| 399 | + if (pin->tx_glitch_high_usecs != CEC_TIM_GLITCH_DEFAULT) | |
| 400 | + seq_printf(sf, "tx-glitch-high-usecs %u\n", | |
| 401 | + pin->tx_glitch_high_usecs); | |
| 345 | 402 | return 0; |
| 346 | 403 | } |
| @@ -164,6 +164,9 @@ enum cec_pin_state { · 163 unmodified lines | ||
| 164 | 164 | /* The default for the low/high time of the custom pulse */ |
| 165 | 165 | #define CEC_TIM_CUSTOM_DEFAULT 1000 |
| 166 | 166 | |
| 167 | +/* The default for the low/high time of the glitch pulse */ | |
| 168 | +#define CEC_TIM_GLITCH_DEFAULT 1 | |
| 169 | + | |
| 167 | 170 | #define CEC_NUM_PIN_EVENTS 128 |
| 168 | 171 | #define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) |
| 169 | 172 | #define CEC_PIN_EVENT_FL_DROPPED (1 << 1) |
| @@ -225,12 +228,17 @@ struct cec_pin { · 55 unmodified lines | ||
| 225 | 228 | u32 timer_max_overrun; |
| 226 | 229 | u32 timer_sum_overrun; |
| 227 | 230 | |
| 231 | + bool rx_no_low_drive; | |
| 228 | 232 | u32 tx_custom_low_usecs; |
| 229 | 233 | u32 tx_custom_high_usecs; |
| 234 | + u32 tx_glitch_low_usecs; | |
| 235 | + u32 tx_glitch_high_usecs; | |
| 230 | 236 | bool tx_ignore_nack_until_eom; |
| 231 | 237 | bool tx_custom_pulse; |
| 232 | 238 | bool tx_generated_poll; |
| 233 | 239 | bool tx_post_eom; |
| 240 | + bool tx_glitch_falling_edge; | |
| 241 | + bool tx_glitch_rising_edge; | |
| 234 | 242 | u8 tx_extra_bytes; |
| 235 | 243 | u32 tx_low_drive_cnt; |
| 236 | 244 | #ifdef CONFIG_CEC_PIN_ERROR_INJ |
| @@ -142,15 +142,42 @@ static bool cec_pin_read(struct cec_pin *pin) · 141 unmodified lines | ||
| 142 | 142 | return v; |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | +static void cec_pin_insert_glitch(struct cec_pin *pin, bool rising_edge) | |
| 146 | +{ | |
| 147 | + /* | |
| 148 | + * Insert a short glitch after the falling or rising edge to | |
| 149 | + * simulate reflections on the CEC line. This can be used to | |
| 150 | + * test deglitch filters, which should be present in CEC devices | |
| 151 | + * to deal with noise on the line. | |
| 152 | + */ | |
| 153 | + if (!pin->tx_glitch_high_usecs || !pin->tx_glitch_low_usecs) | |
| 154 | + return; | |
| 155 | + if (rising_edge) { | |
| 156 | + udelay(pin->tx_glitch_high_usecs); | |
| 157 | + call_void_pin_op(pin, low); | |
| 158 | + udelay(pin->tx_glitch_low_usecs); | |
| 159 | + call_void_pin_op(pin, high); | |
| 160 | + } else { | |
| 161 | + udelay(pin->tx_glitch_low_usecs); | |
| 162 | + call_void_pin_op(pin, high); | |
| 163 | + udelay(pin->tx_glitch_high_usecs); | |
| 164 | + call_void_pin_op(pin, low); | |
| 165 | + } | |
| 166 | +} | |
| 167 | + | |
| 145 | 168 | static void cec_pin_low(struct cec_pin *pin) |
| 146 | 169 | { |
| 147 | 170 | call_void_pin_op(pin, low); |
| 171 | + if (pin->tx_glitch_falling_edge && pin->adap->cec_pin_is_high) | |
| 172 | + cec_pin_insert_glitch(pin, false); | |
| 148 | 173 | cec_pin_update(pin, false, false); |
| 149 | 174 | } |
| 150 | 175 | |
| 151 | 176 | static bool cec_pin_high(struct cec_pin *pin) |
| 152 | 177 | { |
| 153 | 178 | call_void_pin_op(pin, high); |
| 179 | + if (pin->tx_glitch_rising_edge && !pin->adap->cec_pin_is_high) | |
| 180 | + cec_pin_insert_glitch(pin, true); | |
| 154 | 181 | return cec_pin_read(pin); |
| 155 | 182 | } |
| 156 | 183 | |
| @@ -770,7 +797,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) · 613 unmodified lines | ||
| 770 | 797 | * Go to low drive state when the total bit time is |
| 771 | 798 | * too short. |
| 772 | 799 | */ |
| 773 | − if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN) { | |
| 800 | + if (delta < CEC_TIM_DATA_BIT_TOTAL_MIN && !pin->rx_no_low_drive) { | |
| 774 | 801 | if (!pin->rx_data_bit_too_short_cnt++) { |
| 775 | 802 | pin->rx_data_bit_too_short_ts = ktime_to_ns(pin->ts); |
| 776 | 803 | pin->rx_data_bit_too_short_delta = delta; |
| @@ -1350,6 +1377,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, · 573 unmodified lines | ||
| 1350 | 1377 | init_waitqueue_head(&pin->kthread_waitq); |
| 1351 | 1378 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 1352 | 1379 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 1380 | + pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 1381 | + pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT; | |
| 1353 | 1382 | |
| 1354 | 1383 | adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, |
| 1355 | 1384 | caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, |
| @@ -61,49 +61,51 @@ static void cec_gpio_low(struct cec_adapter *adap) · 60 unmodified lines | ||
| 61 | 61 | gpiod_set_value(cec->cec_gpio, 0); |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | −static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) | |
| 64 | +static irqreturn_t cec_gpio_5v_irq_handler_thread(int irq, void *priv) | |
| 65 | 65 | { |
| 66 | 66 | struct cec_gpio *cec = priv; |
| 67 | + int val = gpiod_get_value_cansleep(cec->v5_gpio); | |
| 68 | + bool is_high = val > 0; | |
| 67 | 69 | |
| 68 | − cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts); | |
| 70 | + if (val < 0 || is_high == cec->v5_is_high) | |
| 71 | + return IRQ_HANDLED; | |
| 72 | + | |
| 73 | + cec->v5_is_high = is_high; | |
| 74 | + cec_queue_pin_5v_event(cec->adap, cec->v5_is_high, cec->v5_ts); | |
| 69 | 75 | return IRQ_HANDLED; |
| 70 | 76 | } |
| 71 | 77 | |
| 72 | −static irqreturn_t cec_5v_gpio_irq_handler(int irq, void *priv) | |
| 78 | +static irqreturn_t cec_gpio_5v_irq_handler(int irq, void *priv) | |
| 73 | 79 | { |
| 74 | 80 | struct cec_gpio *cec = priv; |
| 75 | − int val = gpiod_get_value(cec->v5_gpio); | |
| 76 | − bool is_high = val > 0; | |
| 77 | 81 | |
| 78 | − if (val < 0 || is_high == cec->v5_is_high) | |
| 79 | − return IRQ_HANDLED; | |
| 80 | 82 | cec->v5_ts = ktime_get(); |
| 81 | − cec->v5_is_high = is_high; | |
| 82 | 83 | return IRQ_WAKE_THREAD; |
| 83 | 84 | } |
| 84 | 85 | |
| 85 | −static irqreturn_t cec_5v_gpio_irq_handler_thread(int irq, void *priv) | |
| 86 | +static irqreturn_t cec_gpio_hpd_irq_handler_thread(int irq, void *priv) | |
| 86 | 87 | { |
| 87 | 88 | struct cec_gpio *cec = priv; |
| 89 | + int val = gpiod_get_value_cansleep(cec->hpd_gpio); | |
| 90 | + bool is_high = val > 0; | |
| 88 | 91 | |
| 89 | − cec_queue_pin_5v_event(cec->adap, cec->v5_is_high, cec->v5_ts); | |
| 92 | + if (val < 0 || is_high == cec->hpd_is_high) | |
| 93 | + return IRQ_HANDLED; | |
| 94 | + | |
| 95 | + cec->hpd_is_high = is_high; | |
| 96 | + cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts); | |
| 90 | 97 | return IRQ_HANDLED; |
| 91 | 98 | } |
| 92 | 99 | |
| 93 | −static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) | |
| 100 | +static irqreturn_t cec_gpio_hpd_irq_handler(int irq, void *priv) | |
| 94 | 101 | { |
| 95 | 102 | struct cec_gpio *cec = priv; |
| 96 | − int val = gpiod_get_value(cec->hpd_gpio); | |
| 97 | − bool is_high = val > 0; | |
| 98 | 103 | |
| 99 | − if (val < 0 || is_high == cec->hpd_is_high) | |
| 100 | − return IRQ_HANDLED; | |
| 101 | 104 | cec->hpd_ts = ktime_get(); |
| 102 | − cec->hpd_is_high = is_high; | |
| 103 | 105 | return IRQ_WAKE_THREAD; |
| 104 | 106 | } |
| 105 | 107 | |
| 106 | −static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) | |
| 108 | +static irqreturn_t cec_gpio_cec_irq_handler(int irq, void *priv) | |
| 107 | 109 | { |
| 108 | 110 | struct cec_gpio *cec = priv; |
| 109 | 111 | int val = gpiod_get_value(cec->cec_gpio); |
| @@ -113,7 +115,7 @@ static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) · 3 unmodified lines | ||
| 113 | 115 | return IRQ_HANDLED; |
| 114 | 116 | } |
| 115 | 117 | |
| 116 | −static bool cec_gpio_enable_irq(struct cec_adapter *adap) | |
| 118 | +static bool cec_gpio_cec_enable_irq(struct cec_adapter *adap) | |
| 117 | 119 | { |
| 118 | 120 | struct cec_gpio *cec = cec_get_drvdata(adap); |
| 119 | 121 | |
| @@ -121,7 +123,7 @@ static bool cec_gpio_enable_irq(struct cec_adapter *adap) · 1 unmodified line | ||
| 121 | 123 | return true; |
| 122 | 124 | } |
| 123 | 125 | |
| 124 | −static void cec_gpio_disable_irq(struct cec_adapter *adap) | |
| 126 | +static void cec_gpio_cec_disable_irq(struct cec_adapter *adap) | |
| 125 | 127 | { |
| 126 | 128 | struct cec_gpio *cec = cec_get_drvdata(adap); |
| 127 | 129 | |
| @@ -148,7 +150,7 @@ static int cec_gpio_read_hpd(struct cec_adapter *adap) · 20 unmodified lines | ||
| 148 | 150 | |
| 149 | 151 | if (!cec->hpd_gpio) |
| 150 | 152 | return -ENOTTY; |
| 151 | − return gpiod_get_value(cec->hpd_gpio); | |
| 153 | + return gpiod_get_value_cansleep(cec->hpd_gpio); | |
| 152 | 154 | } |
| 153 | 155 | |
| 154 | 156 | static int cec_gpio_read_5v(struct cec_adapter *adap) |
| @@ -157,15 +159,15 @@ static int cec_gpio_read_5v(struct cec_adapter *adap) · 2 unmodified lines | ||
| 157 | 159 | |
| 158 | 160 | if (!cec->v5_gpio) |
| 159 | 161 | return -ENOTTY; |
| 160 | − return gpiod_get_value(cec->v5_gpio); | |
| 162 | + return gpiod_get_value_cansleep(cec->v5_gpio); | |
| 161 | 163 | } |
| 162 | 164 | |
| 163 | 165 | static const struct cec_pin_ops cec_gpio_pin_ops = { |
| 164 | 166 | .read = cec_gpio_read, |
| 165 | 167 | .low = cec_gpio_low, |
| 166 | 168 | .high = cec_gpio_high, |
| 167 | − .enable_irq = cec_gpio_enable_irq, | |
| 168 | − .disable_irq = cec_gpio_disable_irq, | |
| 169 | + .enable_irq = cec_gpio_cec_enable_irq, | |
| 170 | + .disable_irq = cec_gpio_cec_disable_irq, | |
| 169 | 171 | .status = cec_gpio_status, |
| 170 | 172 | .read_hpd = cec_gpio_read_hpd, |
| 171 | 173 | .read_5v = cec_gpio_read_5v, |
| @@ -209,7 +211,7 @@ static int cec_gpio_probe(struct platform_device *pdev) · 37 unmodified lines | ||
| 209 | 211 | if (IS_ERR(cec->adap)) |
| 210 | 212 | return PTR_ERR(cec->adap); |
| 211 | 213 | |
| 212 | − ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler, | |
| 214 | + ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_cec_irq_handler, | |
| 213 | 215 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, |
| 214 | 216 | cec->adap->name, cec); |
| 215 | 217 | if (ret) |
| @@ -218,8 +220,8 @@ static int cec_gpio_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 218 | 220 | if (cec->hpd_gpio) { |
| 219 | 221 | cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); |
| 220 | 222 | ret = devm_request_threaded_irq(dev, cec->hpd_irq, |
| 221 | − cec_hpd_gpio_irq_handler, | |
| 222 | − cec_hpd_gpio_irq_handler_thread, | |
| 223 | + cec_gpio_hpd_irq_handler, | |
| 224 | + cec_gpio_hpd_irq_handler_thread, | |
| 223 | 225 | IRQF_ONESHOT | |
| 224 | 226 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
| 225 | 227 | "hpd-gpio", cec); |
| @@ -230,8 +232,8 @@ static int cec_gpio_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 230 | 232 | if (cec->v5_gpio) { |
| 231 | 233 | cec->v5_irq = gpiod_to_irq(cec->v5_gpio); |
| 232 | 234 | ret = devm_request_threaded_irq(dev, cec->v5_irq, |
| 233 | − cec_5v_gpio_irq_handler, | |
| 234 | − cec_5v_gpio_irq_handler_thread, | |
| 235 | + cec_gpio_5v_irq_handler, | |
| 236 | + cec_gpio_5v_irq_handler_thread, | |
| 235 | 237 | IRQF_ONESHOT | |
| 236 | 238 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
| 237 | 239 | "v5-gpio", cec); |
| @@ -171,11 +171,12 @@ static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data, · 170 unmodified lines | ||
| 171 | 171 | { |
| 172 | 172 | struct rain *rain = serio_get_drvdata(serio); |
| 173 | 173 | |
| 174 | + spin_lock(&rain->buf_lock); | |
| 174 | 175 | if (rain->buf_len == DATA_SIZE) { |
| 176 | + spin_unlock(&rain->buf_lock); | |
| 175 | 177 | dev_warn_once(rain->dev, "buffer overflow\n"); |
| 176 | 178 | return IRQ_HANDLED; |
| 177 | 179 | } |
| 178 | − spin_lock(&rain->buf_lock); | |
| 179 | 180 | rain->buf_len++; |
| 180 | 181 | rain->buf[rain->buf_wr_idx] = data; |
| 181 | 182 | rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff; |
| @@ -209,7 +209,7 @@ static u32 flexcop_i2c_func(struct i2c_adapter *adapter) · 208 unmodified lines | ||
| 209 | 209 | return I2C_FUNC_I2C; |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | −static struct i2c_algorithm flexcop_algo = { | |
| 212 | +static const struct i2c_algorithm flexcop_algo = { | |
| 213 | 213 | .master_xfer = flexcop_master_xfer, |
| 214 | 214 | .functionality = flexcop_i2c_func, |
| 215 | 215 | }; |
| @@ -433,7 +433,7 @@ static int cxd2820r_gpio_direction_output(struct gpio_chip *chip, unsigned nr, · 432 unmodified lines | ||
| 433 | 433 | return cxd2820r_gpio(&priv->fe, gpio); |
| 434 | 434 | } |
| 435 | 435 | |
| 436 | −static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) | |
| 436 | +static int cxd2820r_gpio_set(struct gpio_chip *chip, unsigned int nr, int val) | |
| 437 | 437 | { |
| 438 | 438 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); |
| 439 | 439 | struct i2c_client *client = priv->client[0]; |
| @@ -446,7 +446,7 @@ static void cxd2820r_gpio_set(struct gpio_chip *chip, unsigned nr, int val) · 6 unmodified lines | ||
| 446 | 446 | |
| 447 | 447 | (void) cxd2820r_gpio(&priv->fe, gpio); |
| 448 | 448 | |
| 449 | − return; | |
| 449 | + return 0; | |
| 450 | 450 | } |
| 451 | 451 | |
| 452 | 452 | static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr) |
| @@ -651,7 +651,7 @@ static int cxd2820r_probe(struct i2c_client *client) · 198 unmodified lines | ||
| 651 | 651 | priv->gpio_chip.parent = &client->dev; |
| 652 | 652 | priv->gpio_chip.owner = THIS_MODULE; |
| 653 | 653 | priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output; |
| 654 | − priv->gpio_chip.set = cxd2820r_gpio_set; | |
| 654 | + priv->gpio_chip.set_rv = cxd2820r_gpio_set; | |
| 655 | 655 | priv->gpio_chip.get = cxd2820r_gpio_get; |
| 656 | 656 | priv->gpio_chip.base = -1; /* Dynamic allocation */ |
| 657 | 657 | priv->gpio_chip.ngpio = GPIO_COUNT; |
| @@ -2193,6 +2193,8 @@ static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_ms · 2192 unmodified lines | ||
| 2193 | 2193 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); |
| 2194 | 2194 | u8 n_overflow = 1; |
| 2195 | 2195 | u16 i = 1000; |
| 2196 | + if (msg[0].len < 3) | |
| 2197 | + return -EOPNOTSUPP; | |
| 2196 | 2198 | u16 serpar_num = msg[0].buf[0]; |
| 2197 | 2199 | |
| 2198 | 2200 | while (n_overflow == 1 && i) { |
| @@ -2212,6 +2214,8 @@ static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg · 13 unmodified lines | ||
| 2212 | 2214 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); |
| 2213 | 2215 | u8 n_overflow = 1, n_empty = 1; |
| 2214 | 2216 | u16 i = 1000; |
| 2217 | + if (msg[0].len < 1 || msg[1].len < 2) | |
| 2218 | + return -EOPNOTSUPP; | |
| 2215 | 2219 | u16 serpar_num = msg[0].buf[0]; |
| 2216 | 2220 | u16 read_word; |
| 2217 | 2221 | |
| @@ -2256,8 +2260,12 @@ static int dib7090p_rw_on_apb(struct i2c_adapter *i2c_adap, · 38 unmodified lines | ||
| 2256 | 2260 | u16 word; |
| 2257 | 2261 | |
| 2258 | 2262 | if (num == 1) { /* write */ |
| 2263 | + if (msg[0].len < 3) | |
| 2264 | + return -EOPNOTSUPP; | |
| 2259 | 2265 | dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); |
| 2260 | 2266 | } else { |
| 2267 | + if (msg[1].len < 2) | |
| 2268 | + return -EOPNOTSUPP; | |
| 2261 | 2269 | word = dib7000p_read_word(state, apb_address); |
| 2262 | 2270 | msg[1].buf[0] = (word >> 8) & 0xff; |
| 2263 | 2271 | msg[1].buf[1] = (word) & 0xff; |
| @@ -141,6 +141,7 @@ config VIDEO_IMX214 · 140 unmodified lines | ||
| 141 | 141 | depends on GPIOLIB |
| 142 | 142 | select REGMAP_I2C |
| 143 | 143 | select V4L2_CCI_I2C |
| 144 | + select VIDEO_CCS_PLL | |
| 144 | 145 | help |
| 145 | 146 | This is a Video4Linux2 sensor driver for the Sony |
| 146 | 147 | IMX214 camera. |
| @@ -765,24 +766,25 @@ config VIDEO_THP7312 · 618 unmodified lines | ||
| 765 | 766 | |
| 766 | 767 | endmenu |
| 767 | 768 | |
| 768 | −menu "Lens drivers" | |
| 769 | − visible if MEDIA_CAMERA_SUPPORT | |
| 769 | +menuconfig VIDEO_CAMERA_LENS | |
| 770 | + bool "Lens drivers" | |
| 771 | + depends on MEDIA_CAMERA_SUPPORT && I2C | |
| 772 | + select MEDIA_CONTROLLER | |
| 773 | + select V4L2_FWNODE | |
| 774 | + select VIDEO_V4L2_SUBDEV_API | |
| 775 | + default y | |
| 776 | + | |
| 777 | +if VIDEO_CAMERA_LENS | |
| 770 | 778 | |
| 771 | 779 | config VIDEO_AD5820 |
| 772 | 780 | tristate "AD5820 lens voice coil support" |
| 773 | − depends on GPIOLIB && I2C && VIDEO_DEV | |
| 774 | − select MEDIA_CONTROLLER | |
| 775 | − select V4L2_ASYNC | |
| 781 | + depends on GPIOLIB | |
| 776 | 782 | help |
| 777 | 783 | This is a driver for the AD5820 camera lens voice coil. |
| 778 | 784 | It is used for example in Nokia N900 (RX-51). |
| 779 | 785 | |
| 780 | 786 | config VIDEO_AK7375 |
| 781 | 787 | tristate "AK7375 lens voice coil support" |
| 782 | − depends on I2C && VIDEO_DEV | |
| 783 | − select MEDIA_CONTROLLER | |
| 784 | − select VIDEO_V4L2_SUBDEV_API | |
| 785 | − select V4L2_ASYNC | |
| 786 | 788 | help |
| 787 | 789 | This is a driver for the AK7375 camera lens voice coil. |
| 788 | 790 | AK7375 is a 12 bit DAC with 120mA output current sink |
| @@ -791,10 +793,7 @@ config VIDEO_AK7375 · 2 unmodified lines | ||
| 791 | 793 | |
| 792 | 794 | config VIDEO_DW9714 |
| 793 | 795 | tristate "DW9714 lens voice coil support" |
| 794 | − depends on I2C && VIDEO_DEV | |
| 795 | − select MEDIA_CONTROLLER | |
| 796 | − select VIDEO_V4L2_SUBDEV_API | |
| 797 | − select V4L2_ASYNC | |
| 796 | + depends on GPIOLIB | |
| 798 | 797 | help |
| 799 | 798 | This is a driver for the DW9714 camera lens voice coil. |
| 800 | 799 | DW9714 is a 10 bit DAC with 120mA output current sink |
| @@ -803,10 +802,6 @@ config VIDEO_DW9714 · 2 unmodified lines | ||
| 803 | 802 | |
| 804 | 803 | config VIDEO_DW9719 |
| 805 | 804 | tristate "DW9719 lens voice coil support" |
| 806 | − depends on I2C && VIDEO_DEV | |
| 807 | − select MEDIA_CONTROLLER | |
| 808 | − select VIDEO_V4L2_SUBDEV_API | |
| 809 | − select V4L2_ASYNC | |
| 810 | 805 | select V4L2_CCI_I2C |
| 811 | 806 | help |
| 812 | 807 | This is a driver for the DW9719 camera lens voice coil. |
| @@ -815,10 +810,6 @@ config VIDEO_DW9719 · 2 unmodified lines | ||
| 815 | 810 | |
| 816 | 811 | config VIDEO_DW9768 |
| 817 | 812 | tristate "DW9768 lens voice coil support" |
| 818 | − depends on I2C && VIDEO_DEV | |
| 819 | − select MEDIA_CONTROLLER | |
| 820 | − select VIDEO_V4L2_SUBDEV_API | |
| 821 | − select V4L2_FWNODE | |
| 822 | 813 | help |
| 823 | 814 | This is a driver for the DW9768 camera lens voice coil. |
| 824 | 815 | DW9768 is a 10 bit DAC with 100mA output current sink |
| @@ -827,17 +818,13 @@ config VIDEO_DW9768 · 2 unmodified lines | ||
| 827 | 818 | |
| 828 | 819 | config VIDEO_DW9807_VCM |
| 829 | 820 | tristate "DW9807 lens voice coil support" |
| 830 | − depends on I2C && VIDEO_DEV | |
| 831 | − select MEDIA_CONTROLLER | |
| 832 | − select VIDEO_V4L2_SUBDEV_API | |
| 833 | − select V4L2_ASYNC | |
| 834 | 821 | help |
| 835 | 822 | This is a driver for the DW9807 camera lens voice coil. |
| 836 | 823 | DW9807 is a 10 bit DAC with 100mA output current sink |
| 837 | 824 | capability. This is designed for linear control of |
| 838 | 825 | voice coil motors, controlled via I2C serial interface. |
| 839 | 826 | |
| 840 | −endmenu | |
| 827 | +endif | |
| 841 | 828 | |
| 842 | 829 | menu "Flash devices" |
| 843 | 830 | visible if MEDIA_CAMERA_SUPPORT |
| @@ -1684,7 +1671,7 @@ config VIDEO_MAX96714 · 840 unmodified lines | ||
| 1684 | 1671 | |
| 1685 | 1672 | config VIDEO_MAX96717 |
| 1686 | 1673 | tristate "Maxim MAX96717 GMSL2 Serializer support" |
| 1687 | − depends on OF && I2C && VIDEO_DEV && COMMON_CLK | |
| 1674 | + depends on I2C && VIDEO_DEV && COMMON_CLK | |
| 1688 | 1675 | select I2C_MUX |
| 1689 | 1676 | select MEDIA_CONTROLLER |
| 1690 | 1677 | select GPIOLIB |
| @@ -868,21 +868,6 @@ static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) · 867 unmodified lines | ||
| 868 | 868 | return 0; |
| 869 | 869 | } |
| 870 | 870 | |
| 871 | −static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect) | |
| 872 | −{ | |
| 873 | − struct adv7180_state *state = to_state(sd); | |
| 874 | − | |
| 875 | − if (state->curr_norm & V4L2_STD_525_60) { | |
| 876 | − aspect->numerator = 11; | |
| 877 | − aspect->denominator = 10; | |
| 878 | − } else { | |
| 879 | − aspect->numerator = 54; | |
| 880 | − aspect->denominator = 59; | |
| 881 | − } | |
| 882 | − | |
| 883 | − return 0; | |
| 884 | −} | |
| 885 | − | |
| 886 | 871 | static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) |
| 887 | 872 | { |
| 888 | 873 | *norm = V4L2_STD_ALL; |
| @@ -929,7 +914,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { · 40 unmodified lines | ||
| 929 | 914 | .querystd = adv7180_querystd, |
| 930 | 915 | .g_input_status = adv7180_g_input_status, |
| 931 | 916 | .s_routing = adv7180_s_routing, |
| 932 | − .g_pixelaspect = adv7180_g_pixelaspect, | |
| 933 | 917 | .g_tvnorms = adv7180_g_tvnorms, |
| 934 | 918 | .s_stream = adv7180_s_stream, |
| 935 | 919 | }; |
| @@ -161,22 +161,6 @@ int adv748x_afe_s_input(struct adv748x_afe *afe, unsigned int input) · 160 unmodified lines | ||
| 161 | 161 | return sdp_write(state, ADV748X_SDP_INSEL, input); |
| 162 | 162 | } |
| 163 | 163 | |
| 164 | −static int adv748x_afe_g_pixelaspect(struct v4l2_subdev *sd, | |
| 165 | − struct v4l2_fract *aspect) | |
| 166 | −{ | |
| 167 | − struct adv748x_afe *afe = adv748x_sd_to_afe(sd); | |
| 168 | − | |
| 169 | − if (afe->curr_norm & V4L2_STD_525_60) { | |
| 170 | − aspect->numerator = 11; | |
| 171 | − aspect->denominator = 10; | |
| 172 | − } else { | |
| 173 | − aspect->numerator = 54; | |
| 174 | − aspect->denominator = 59; | |
| 175 | − } | |
| 176 | − | |
| 177 | − return 0; | |
| 178 | −} | |
| 179 | − | |
| 180 | 164 | /* ----------------------------------------------------------------------------- |
| 181 | 165 | * v4l2_subdev_video_ops |
| 182 | 166 | */ |
| @@ -307,7 +291,6 @@ static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = { · 124 unmodified lines | ||
| 307 | 291 | .g_tvnorms = adv748x_afe_g_tvnorms, |
| 308 | 292 | .g_input_status = adv748x_afe_g_input_status, |
| 309 | 293 | .s_stream = adv748x_afe_s_stream, |
| 310 | − .g_pixelaspect = adv748x_afe_g_pixelaspect, | |
| 311 | 294 | }; |
| 312 | 295 | |
| 313 | 296 | /* ----------------------------------------------------------------------------- |
| @@ -382,19 +382,9 @@ done: · 381 unmodified lines | ||
| 382 | 382 | return ret; |
| 383 | 383 | } |
| 384 | 384 | |
| 385 | −static int adv748x_hdmi_g_pixelaspect(struct v4l2_subdev *sd, | |
| 386 | − struct v4l2_fract *aspect) | |
| 387 | −{ | |
| 388 | − aspect->numerator = 1; | |
| 389 | − aspect->denominator = 1; | |
| 390 | − | |
| 391 | − return 0; | |
| 392 | −} | |
| 393 | − | |
| 394 | 385 | static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = { |
| 395 | 386 | .g_input_status = adv748x_hdmi_g_input_status, |
| 396 | 387 | .s_stream = adv748x_hdmi_s_stream, |
| 397 | − .g_pixelaspect = adv748x_hdmi_g_pixelaspect, | |
| 398 | 388 | }; |
| 399 | 389 | |
| 400 | 390 | /* ----------------------------------------------------------------------------- |
| @@ -2448,8 +2448,8 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) · 2447 unmodified lines | ||
| 2448 | 2448 | } |
| 2449 | 2449 | cec_s_phys_addr(state->cec_adap, parent_pa, false); |
| 2450 | 2450 | |
| 2451 | − /* enable hotplug after 100 ms */ | |
| 2452 | − schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); | |
| 2451 | + /* enable hotplug after 143 ms */ | |
| 2452 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 7); | |
| 2453 | 2453 | return 0; |
| 2454 | 2454 | } |
| 2455 | 2455 | |
| @@ -203,9 +203,9 @@ static int ub913_gpio_direction_out(struct gpio_chip *gc, unsigned int offset, · 202 unmodified lines | ||
| 203 | 203 | 0)); |
| 204 | 204 | } |
| 205 | 205 | |
| 206 | −static void ub913_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) | |
| 206 | +static int ub913_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) | |
| 207 | 207 | { |
| 208 | − ub913_gpio_direction_out(gc, offset, value); | |
| 208 | + return ub913_gpio_direction_out(gc, offset, value); | |
| 209 | 209 | } |
| 210 | 210 | |
| 211 | 211 | static int ub913_gpio_of_xlate(struct gpio_chip *gc, |
| @@ -235,7 +235,7 @@ static int ub913_gpiochip_probe(struct ub913_data *priv) · 23 unmodified lines | ||
| 235 | 235 | gc->ngpio = UB913_NUM_GPIOS; |
| 236 | 236 | gc->get_direction = ub913_gpio_get_direction; |
| 237 | 237 | gc->direction_output = ub913_gpio_direction_out; |
| 238 | − gc->set = ub913_gpio_set; | |
| 238 | + gc->set_rv = ub913_gpio_set; | |
| 239 | 239 | gc->of_xlate = ub913_gpio_of_xlate; |
| 240 | 240 | gc->of_gpio_n_cells = 2; |
| 241 | 241 | |
| @@ -337,14 +337,6 @@ static int _ub913_set_routing(struct v4l2_subdev *sd, · 95 unmodified lines | ||
| 337 | 337 | unsigned int i; |
| 338 | 338 | int ret; |
| 339 | 339 | |
| 340 | − /* | |
| 341 | − * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until | |
| 342 | − * frame desc is made dynamically allocated. | |
| 343 | − */ | |
| 344 | − | |
| 345 | − if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 346 | − return -EINVAL; | |
| 347 | − | |
| 348 | 340 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 349 | 341 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 350 | 342 | if (ret) |
| @@ -317,14 +317,13 @@ static int ub953_gpio_get(struct gpio_chip *gc, unsigned int offset) · 316 unmodified lines | ||
| 317 | 317 | return !!(v & UB953_REG_GPIO_PIN_STS_GPIO_STS(offset)); |
| 318 | 318 | } |
| 319 | 319 | |
| 320 | −static void ub953_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) | |
| 320 | +static int ub953_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) | |
| 321 | 321 | { |
| 322 | 322 | struct ub953_data *priv = gpiochip_get_data(gc); |
| 323 | 323 | |
| 324 | − regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA, | |
| 325 | − UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset), | |
| 326 | − value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : | |
| 327 | − 0); | |
| 324 | + return regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA, | |
| 325 | + UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset), | |
| 326 | + value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : 0); | |
| 328 | 327 | } |
| 329 | 328 | |
| 330 | 329 | static int ub953_gpio_of_xlate(struct gpio_chip *gc, |
| @@ -362,7 +361,7 @@ static int ub953_gpiochip_probe(struct ub953_data *priv) · 31 unmodified lines | ||
| 362 | 361 | gc->direction_input = ub953_gpio_direction_in; |
| 363 | 362 | gc->direction_output = ub953_gpio_direction_out; |
| 364 | 363 | gc->get = ub953_gpio_get; |
| 365 | − gc->set = ub953_gpio_set; | |
| 364 | + gc->set_rv = ub953_gpio_set; | |
| 366 | 365 | gc->of_xlate = ub953_gpio_of_xlate; |
| 367 | 366 | gc->of_gpio_n_cells = 2; |
| 368 | 367 | |
| @@ -400,14 +399,6 @@ static int _ub953_set_routing(struct v4l2_subdev *sd, · 31 unmodified lines | ||
| 400 | 399 | }; |
| 401 | 400 | int ret; |
| 402 | 401 | |
| 403 | − /* | |
| 404 | − * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until | |
| 405 | − * frame desc is made dynamically allocated. | |
| 406 | − */ | |
| 407 | − | |
| 408 | − if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 409 | − return -EINVAL; | |
| 410 | − | |
| 411 | 402 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 412 | 403 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 413 | 404 | if (ret) |
| @@ -3861,14 +3861,6 @@ static int _ub960_set_routing(struct v4l2_subdev *sd, · 3860 unmodified lines | ||
| 3861 | 3861 | }; |
| 3862 | 3862 | int ret; |
| 3863 | 3863 | |
| 3864 | − /* | |
| 3865 | − * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until | |
| 3866 | − * frame desc is made dynamically allocated. | |
| 3867 | − */ | |
| 3868 | − | |
| 3869 | − if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 3870 | − return -E2BIG; | |
| 3871 | − | |
| 3872 | 3864 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 3873 | 3865 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | |
| 3874 | 3866 | V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX); |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | // Copyright (c) 2015--2017 Intel Corporation. |
| 3 | 3 | |
| 4 | 4 | #include <linux/delay.h> |
| 5 | +#include <linux/gpio/consumer.h> | |
| 5 | 6 | #include <linux/i2c.h> |
| 6 | 7 | #include <linux/module.h> |
| 7 | 8 | #include <linux/pm_runtime.h> |
| @@ -38,6 +39,7 @@ struct dw9714_device { · 30 unmodified lines | ||
| 38 | 39 | struct v4l2_subdev sd; |
| 39 | 40 | u16 current_val; |
| 40 | 41 | struct regulator *vcc; |
| 42 | + struct gpio_desc *powerdown_gpio; | |
| 41 | 43 | }; |
| 42 | 44 | |
| 43 | 45 | static inline struct dw9714_device *to_dw9714_vcm(struct v4l2_ctrl *ctrl) |
| @@ -137,6 +139,28 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm) · 93 unmodified lines | ||
| 137 | 139 | return hdl->error; |
| 138 | 140 | } |
| 139 | 141 | |
| 142 | +static int dw9714_power_up(struct dw9714_device *dw9714_dev) | |
| 143 | +{ | |
| 144 | + int ret; | |
| 145 | + | |
| 146 | + ret = regulator_enable(dw9714_dev->vcc); | |
| 147 | + if (ret) | |
| 148 | + return ret; | |
| 149 | + | |
| 150 | + gpiod_set_value_cansleep(dw9714_dev->powerdown_gpio, 0); | |
| 151 | + | |
| 152 | + usleep_range(1000, 2000); | |
| 153 | + | |
| 154 | + return 0; | |
| 155 | +} | |
| 156 | + | |
| 157 | +static int dw9714_power_down(struct dw9714_device *dw9714_dev) | |
| 158 | +{ | |
| 159 | + gpiod_set_value_cansleep(dw9714_dev->powerdown_gpio, 1); | |
| 160 | + | |
| 161 | + return regulator_disable(dw9714_dev->vcc); | |
| 162 | +} | |
| 163 | + | |
| 140 | 164 | static int dw9714_probe(struct i2c_client *client) |
| 141 | 165 | { |
| 142 | 166 | struct dw9714_device *dw9714_dev; |
| @@ -144,20 +168,25 @@ static int dw9714_probe(struct i2c_client *client) · 1 unmodified line | ||
| 144 | 168 | |
| 145 | 169 | dw9714_dev = devm_kzalloc(&client->dev, sizeof(*dw9714_dev), |
| 146 | 170 | GFP_KERNEL); |
| 147 | − if (dw9714_dev == NULL) | |
| 171 | + if (!dw9714_dev) | |
| 148 | 172 | return -ENOMEM; |
| 149 | 173 | |
| 150 | 174 | dw9714_dev->vcc = devm_regulator_get(&client->dev, "vcc"); |
| 151 | 175 | if (IS_ERR(dw9714_dev->vcc)) |
| 152 | 176 | return PTR_ERR(dw9714_dev->vcc); |
| 153 | 177 | |
| 154 | − rval = regulator_enable(dw9714_dev->vcc); | |
| 155 | − if (rval < 0) { | |
| 156 | − dev_err(&client->dev, "failed to enable vcc: %d\n", rval); | |
| 157 | − return rval; | |
| 158 | − } | |
| 178 | + dw9714_dev->powerdown_gpio = devm_gpiod_get_optional(&client->dev, | |
| 179 | + "powerdown", | |
| 180 | + GPIOD_OUT_HIGH); | |
| 181 | + if (IS_ERR(dw9714_dev->powerdown_gpio)) | |
| 182 | + return dev_err_probe(&client->dev, | |
| 183 | + PTR_ERR(dw9714_dev->powerdown_gpio), | |
| 184 | + "could not get powerdown gpio\n"); | |
| 159 | 185 | |
| 160 | − usleep_range(1000, 2000); | |
| 186 | + rval = dw9714_power_up(dw9714_dev); | |
| 187 | + if (rval) | |
| 188 | + return dev_err_probe(&client->dev, rval, | |
| 189 | + "failed to power up: %d\n", rval); | |
| 161 | 190 | |
| 162 | 191 | v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); |
| 163 | 192 | dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | |
| @@ -185,7 +214,7 @@ static int dw9714_probe(struct i2c_client *client) · 21 unmodified lines | ||
| 185 | 214 | return 0; |
| 186 | 215 | |
| 187 | 216 | err_cleanup: |
| 188 | − regulator_disable(dw9714_dev->vcc); | |
| 217 | + dw9714_power_down(dw9714_dev); | |
| 189 | 218 | v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm); |
| 190 | 219 | media_entity_cleanup(&dw9714_dev->sd.entity); |
| 191 | 220 | |
| @@ -200,10 +229,10 @@ static void dw9714_remove(struct i2c_client *client) · 8 unmodified lines | ||
| 200 | 229 | |
| 201 | 230 | pm_runtime_disable(&client->dev); |
| 202 | 231 | if (!pm_runtime_status_suspended(&client->dev)) { |
| 203 | − ret = regulator_disable(dw9714_dev->vcc); | |
| 232 | + ret = dw9714_power_down(dw9714_dev); | |
| 204 | 233 | if (ret) { |
| 205 | 234 | dev_err(&client->dev, |
| 206 | − "Failed to disable vcc: %d\n", ret); | |
| 235 | + "Failed to power down: %d\n", ret); | |
| 207 | 236 | } |
| 208 | 237 | } |
| 209 | 238 | pm_runtime_set_suspended(&client->dev); |
| @@ -234,9 +263,9 @@ static int __maybe_unused dw9714_vcm_suspend(struct device *dev) · 24 unmodified lines | ||
| 234 | 263 | usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10); |
| 235 | 264 | } |
| 236 | 265 | |
| 237 | − ret = regulator_disable(dw9714_dev->vcc); | |
| 266 | + ret = dw9714_power_down(dw9714_dev); | |
| 238 | 267 | if (ret) |
| 239 | − dev_err(dev, "Failed to disable vcc: %d\n", ret); | |
| 268 | + dev_err(dev, "Failed to power down: %d\n", ret); | |
| 240 | 269 | |
| 241 | 270 | return ret; |
| 242 | 271 | } |
| @@ -247,7 +276,7 @@ static int __maybe_unused dw9714_vcm_suspend(struct device *dev) · 4 unmodified lines | ||
| 247 | 276 | * The lens position is gradually moved in units of DW9714_CTRL_STEPS, |
| 248 | 277 | * to make the movements smoothly. |
| 249 | 278 | */ |
| 250 | −static int __maybe_unused dw9714_vcm_resume(struct device *dev) | |
| 279 | +static int __maybe_unused dw9714_vcm_resume(struct device *dev) | |
| 251 | 280 | { |
| 252 | 281 | struct i2c_client *client = to_i2c_client(dev); |
| 253 | 282 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| @@ -257,12 +286,11 @@ static int __maybe_unused dw9714_vcm_resume(struct device *dev) · 3 unmodified lines | ||
| 257 | 286 | if (pm_runtime_suspended(&client->dev)) |
| 258 | 287 | return 0; |
| 259 | 288 | |
| 260 | − ret = regulator_enable(dw9714_dev->vcc); | |
| 289 | + ret = dw9714_power_up(dw9714_dev); | |
| 261 | 290 | if (ret) { |
| 262 | − dev_err(dev, "Failed to enable vcc: %d\n", ret); | |
| 291 | + dev_err(dev, "Failed to power up: %d\n", ret); | |
| 263 | 292 | return ret; |
| 264 | 293 | } |
| 265 | − usleep_range(1000, 2000); | |
| 266 | 294 | |
| 267 | 295 | for (val = dw9714_dev->current_val % DW9714_CTRL_STEPS; |
| 268 | 296 | val < dw9714_dev->current_val + DW9714_CTRL_STEPS - 1; |
| @@ -271,7 +299,7 @@ static int __maybe_unused dw9714_vcm_resume(struct device *dev) · 2 unmodified lines | ||
| 271 | 299 | DW9714_VAL(val, DW9714_DEFAULT_S)); |
| 272 | 300 | if (ret) |
| 273 | 301 | dev_err_ratelimited(dev, "%s I2C failure: %d", |
| 274 | − __func__, ret); | |
| 302 | + __func__, ret); | |
| 275 | 303 | usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10); |
| 276 | 304 | } |
| 277 | 305 | |
| @@ -624,6 +624,12 @@ static const struct hi556_mode supported_modes[] = { · 623 unmodified lines | ||
| 624 | 624 | }, |
| 625 | 625 | }; |
| 626 | 626 | |
| 627 | +static const char * const hi556_supply_names[] = { | |
| 628 | + "dovdd", /* Digital I/O power */ | |
| 629 | + "avdd", /* Analog power */ | |
| 630 | + "dvdd", /* Digital core power */ | |
| 631 | +}; | |
| 632 | + | |
| 627 | 633 | struct hi556 { |
| 628 | 634 | struct v4l2_subdev sd; |
| 629 | 635 | struct media_pad pad; |
| @@ -639,7 +645,7 @@ struct hi556 { · 9 unmodified lines | ||
| 639 | 645 | /* GPIOs, clocks, etc. */ |
| 640 | 646 | struct gpio_desc *reset_gpio; |
| 641 | 647 | struct clk *clk; |
| 642 | − struct regulator *avdd; | |
| 648 | + struct regulator_bulk_data supplies[ARRAY_SIZE(hi556_supply_names)]; | |
| 643 | 649 | |
| 644 | 650 | /* Current mode */ |
| 645 | 651 | const struct hi556_mode *cur_mode; |
| @@ -756,21 +762,23 @@ static int hi556_test_pattern(struct hi556 *hi556, u32 pattern) · 110 unmodified lines | ||
| 756 | 762 | int ret; |
| 757 | 763 | u32 val; |
| 758 | 764 | |
| 759 | − if (pattern) { | |
| 760 | − ret = hi556_read_reg(hi556, HI556_REG_ISP, | |
| 761 | − HI556_REG_VALUE_08BIT, &val); | |
| 762 | − if (ret) | |
| 763 | − return ret; | |
| 765 | + ret = hi556_read_reg(hi556, HI556_REG_ISP, | |
| 766 | + HI556_REG_VALUE_08BIT, &val); | |
| 767 | + if (ret) | |
| 768 | + return ret; | |
| 764 | 769 | |
| 765 | − ret = hi556_write_reg(hi556, HI556_REG_ISP, | |
| 766 | − HI556_REG_VALUE_08BIT, | |
| 767 | − val | HI556_REG_ISP_TPG_EN); | |
| 768 | − if (ret) | |
| 769 | − return ret; | |
| 770 | − } | |
| 770 | + val = pattern ? (val | HI556_REG_ISP_TPG_EN) : | |
| 771 | + (val & ~HI556_REG_ISP_TPG_EN); | |
| 772 | + | |
| 773 | + ret = hi556_write_reg(hi556, HI556_REG_ISP, | |
| 774 | + HI556_REG_VALUE_08BIT, val); | |
| 775 | + if (ret) | |
| 776 | + return ret; | |
| 777 | + | |
| 778 | + val = pattern ? BIT(pattern - 1) : 0; | |
| 771 | 779 | |
| 772 | 780 | return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN, |
| 773 | − HI556_REG_VALUE_08BIT, pattern); | |
| 781 | + HI556_REG_VALUE_08BIT, val); | |
| 774 | 782 | } |
| 775 | 783 | |
| 776 | 784 | static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) |
| @@ -1289,17 +1297,10 @@ static int hi556_suspend(struct device *dev) · 512 unmodified lines | ||
| 1289 | 1297 | { |
| 1290 | 1298 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
| 1291 | 1299 | struct hi556 *hi556 = to_hi556(sd); |
| 1292 | − int ret; | |
| 1293 | 1300 | |
| 1294 | 1301 | gpiod_set_value_cansleep(hi556->reset_gpio, 1); |
| 1295 | − | |
| 1296 | − ret = regulator_disable(hi556->avdd); | |
| 1297 | − if (ret) { | |
| 1298 | − dev_err(dev, "failed to disable avdd: %d\n", ret); | |
| 1299 | − gpiod_set_value_cansleep(hi556->reset_gpio, 0); | |
| 1300 | − return ret; | |
| 1301 | − } | |
| 1302 | − | |
| 1302 | + regulator_bulk_disable(ARRAY_SIZE(hi556_supply_names), | |
| 1303 | + hi556->supplies); | |
| 1303 | 1304 | clk_disable_unprepare(hi556->clk); |
| 1304 | 1305 | return 0; |
| 1305 | 1306 | } |
| @@ -1314,14 +1315,20 @@ static int hi556_resume(struct device *dev) · 8 unmodified lines | ||
| 1314 | 1315 | if (ret) |
| 1315 | 1316 | return ret; |
| 1316 | 1317 | |
| 1317 | − ret = regulator_enable(hi556->avdd); | |
| 1318 | + ret = regulator_bulk_enable(ARRAY_SIZE(hi556_supply_names), | |
| 1319 | + hi556->supplies); | |
| 1318 | 1320 | if (ret) { |
| 1319 | − dev_err(dev, "failed to enable avdd: %d\n", ret); | |
| 1321 | + dev_err(dev, "failed to enable regulators: %d", ret); | |
| 1320 | 1322 | clk_disable_unprepare(hi556->clk); |
| 1321 | 1323 | return ret; |
| 1322 | 1324 | } |
| 1323 | 1325 | |
| 1324 | − gpiod_set_value_cansleep(hi556->reset_gpio, 0); | |
| 1326 | + if (hi556->reset_gpio) { | |
| 1327 | + /* Assert reset for at least 2ms on back to back off-on */ | |
| 1328 | + usleep_range(2000, 2200); | |
| 1329 | + gpiod_set_value_cansleep(hi556->reset_gpio, 0); | |
| 1330 | + } | |
| 1331 | + | |
| 1325 | 1332 | usleep_range(5000, 5500); |
| 1326 | 1333 | return 0; |
| 1327 | 1334 | } |
| @@ -1330,7 +1337,7 @@ static int hi556_probe(struct i2c_client *client) · 2 unmodified lines | ||
| 1330 | 1337 | { |
| 1331 | 1338 | struct hi556 *hi556; |
| 1332 | 1339 | bool full_power; |
| 1333 | − int ret; | |
| 1340 | + int i, ret; | |
| 1334 | 1341 | |
| 1335 | 1342 | ret = hi556_check_hwcfg(&client->dev); |
| 1336 | 1343 | if (ret) |
| @@ -1353,11 +1360,15 @@ static int hi556_probe(struct i2c_client *client) · 16 unmodified lines | ||
| 1353 | 1360 | return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), |
| 1354 | 1361 | "failed to get clock\n"); |
| 1355 | 1362 | |
| 1356 | − /* The regulator core will provide a "dummy" regulator if necessary */ | |
| 1357 | − hi556->avdd = devm_regulator_get(&client->dev, "avdd"); | |
| 1358 | − if (IS_ERR(hi556->avdd)) | |
| 1359 | − return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd), | |
| 1360 | − "failed to get avdd regulator\n"); | |
| 1363 | + for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++) | |
| 1364 | + hi556->supplies[i].supply = hi556_supply_names[i]; | |
| 1365 | + | |
| 1366 | + ret = devm_regulator_bulk_get(&client->dev, | |
| 1367 | + ARRAY_SIZE(hi556_supply_names), | |
| 1368 | + hi556->supplies); | |
| 1369 | + if (ret) | |
| 1370 | + return dev_err_probe(&client->dev, ret, | |
| 1371 | + "failed to get regulators\n"); | |
| 1361 | 1372 | |
| 1362 | 1373 | full_power = acpi_dev_state_d0(&client->dev); |
| 1363 | 1374 | if (full_power) { |
| @@ -20,6 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <media/v4l2-fwnode.h> |
| 21 | 21 | #include <media/v4l2-subdev.h> |
| 22 | 22 | |
| 23 | +#include "ccs-pll.h" | |
| 24 | + | |
| 23 | 25 | /* Chip ID */ |
| 24 | 26 | #define IMX214_REG_CHIP_ID CCI_REG16(0x0016) |
| 25 | 27 | #define IMX214_CHIP_ID 0x0214 |
| @@ -30,11 +32,9 @@ · 4 unmodified lines | ||
| 30 | 32 | |
| 31 | 33 | #define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106) |
| 32 | 34 | |
| 33 | −#define IMX214_DEFAULT_CLK_FREQ 24000000 | |
| 34 | 35 | #define IMX214_DEFAULT_LINK_FREQ 600000000 |
| 35 | 36 | /* Keep wrong link frequency for backward compatibility */ |
| 36 | 37 | #define IMX214_DEFAULT_LINK_FREQ_LEGACY 480000000 |
| 37 | −#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10) | |
| 38 | 38 | #define IMX214_FPS 30 |
| 39 | 39 | |
| 40 | 40 | /* V-TIMING internal */ |
| @@ -84,6 +84,7 @@ · 43 unmodified lines | ||
| 84 | 84 | #define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A |
| 85 | 85 | #define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06 |
| 86 | 86 | #define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08 |
| 87 | +#define IMX214_BITS_PER_PIXEL_MASK 0xFF | |
| 87 | 88 | |
| 88 | 89 | #define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114) |
| 89 | 90 | #define IMX214_CSI_2_LANE_MODE 1 |
| @@ -249,6 +250,10 @@ struct imx214 { · 159 unmodified lines | ||
| 249 | 250 | struct clk *xclk; |
| 250 | 251 | struct regmap *regmap; |
| 251 | 252 | |
| 253 | + struct ccs_pll pll; | |
| 254 | + | |
| 255 | + struct v4l2_fwnode_endpoint bus_cfg; | |
| 256 | + | |
| 252 | 257 | struct v4l2_subdev sd; |
| 253 | 258 | struct media_pad pad; |
| 254 | 259 | |
| @@ -299,16 +304,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = { · 44 unmodified lines | ||
| 299 | 304 | { IMX214_REG_DIG_CROP_WIDTH, 4096 }, |
| 300 | 305 | { IMX214_REG_DIG_CROP_HEIGHT, 2304 }, |
| 301 | 306 | |
| 302 | − { IMX214_REG_VTPXCK_DIV, 5 }, | |
| 303 | − { IMX214_REG_VTSYCK_DIV, 2 }, | |
| 304 | − { IMX214_REG_PREPLLCK_VT_DIV, 3 }, | |
| 305 | − { IMX214_REG_PLL_VT_MPY, 150 }, | |
| 306 | − { IMX214_REG_OPPXCK_DIV, 10 }, | |
| 307 | − { IMX214_REG_OPSYCK_DIV, 1 }, | |
| 308 | − { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE }, | |
| 309 | − | |
| 310 | − { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) }, | |
| 311 | − | |
| 312 | 307 | { CCI_REG8(0x3A03), 0x09 }, |
| 313 | 308 | { CCI_REG8(0x3A04), 0x50 }, |
| 314 | 309 | { CCI_REG8(0x3A05), 0x01 }, |
| @@ -362,16 +357,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = { · 47 unmodified lines | ||
| 362 | 357 | { IMX214_REG_DIG_CROP_WIDTH, 1920 }, |
| 363 | 358 | { IMX214_REG_DIG_CROP_HEIGHT, 1080 }, |
| 364 | 359 | |
| 365 | − { IMX214_REG_VTPXCK_DIV, 5 }, | |
| 366 | − { IMX214_REG_VTSYCK_DIV, 2 }, | |
| 367 | − { IMX214_REG_PREPLLCK_VT_DIV, 3 }, | |
| 368 | − { IMX214_REG_PLL_VT_MPY, 150 }, | |
| 369 | − { IMX214_REG_OPPXCK_DIV, 10 }, | |
| 370 | − { IMX214_REG_OPSYCK_DIV, 1 }, | |
| 371 | − { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE }, | |
| 372 | − | |
| 373 | − { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) }, | |
| 374 | − | |
| 375 | 360 | { CCI_REG8(0x3A03), 0x04 }, |
| 376 | 361 | { CCI_REG8(0x3A04), 0xF8 }, |
| 377 | 362 | { CCI_REG8(0x3A05), 0x02 }, |
| @@ -405,9 +390,6 @@ static const struct cci_reg_sequence mode_table_common[] = { · 27 unmodified lines | ||
| 405 | 390 | /* ATR setting */ |
| 406 | 391 | { IMX214_REG_ATR_FAST_MOVE, 2 }, |
| 407 | 392 | |
| 408 | − /* external clock setting */ | |
| 409 | − { IMX214_REG_EXCK_FREQ, IMX214_EXCK_FREQ(IMX214_DEFAULT_CLK_FREQ / 1000000) }, | |
| 410 | − | |
| 411 | 393 | /* global setting */ |
| 412 | 394 | /* basic config */ |
| 413 | 395 | { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK }, |
| @@ -777,6 +759,30 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev, · 363 unmodified lines | ||
| 777 | 759 | return 0; |
| 778 | 760 | } |
| 779 | 761 | |
| 762 | +static int imx214_configure_pll(struct imx214 *imx214) | |
| 763 | +{ | |
| 764 | + int ret = 0; | |
| 765 | + | |
| 766 | + cci_write(imx214->regmap, IMX214_REG_VTPXCK_DIV, | |
| 767 | + imx214->pll.vt_bk.pix_clk_div, &ret); | |
| 768 | + cci_write(imx214->regmap, IMX214_REG_VTSYCK_DIV, | |
| 769 | + imx214->pll.vt_bk.sys_clk_div, &ret); | |
| 770 | + cci_write(imx214->regmap, IMX214_REG_PREPLLCK_VT_DIV, | |
| 771 | + imx214->pll.vt_fr.pre_pll_clk_div, &ret); | |
| 772 | + cci_write(imx214->regmap, IMX214_REG_PLL_VT_MPY, | |
| 773 | + imx214->pll.vt_fr.pll_multiplier, &ret); | |
| 774 | + cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, | |
| 775 | + imx214->pll.op_bk.pix_clk_div, &ret); | |
| 776 | + cci_write(imx214->regmap, IMX214_REG_OPSYCK_DIV, | |
| 777 | + imx214->pll.op_bk.sys_clk_div, &ret); | |
| 778 | + cci_write(imx214->regmap, IMX214_REG_PLL_MULT_DRIV, | |
| 779 | + IMX214_PLL_SINGLE, &ret); | |
| 780 | + cci_write(imx214->regmap, IMX214_REG_EXCK_FREQ, | |
| 781 | + IMX214_EXCK_FREQ(imx214->pll.ext_clk_freq_hz / 1000000), &ret); | |
| 782 | + | |
| 783 | + return ret; | |
| 784 | +} | |
| 785 | + | |
| 780 | 786 | static int imx214_update_digital_gain(struct imx214 *imx214, u32 val) |
| 781 | 787 | { |
| 782 | 788 | int ret = 0; |
| @@ -877,9 +883,6 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = { · 94 unmodified lines | ||
| 877 | 883 | |
| 878 | 884 | static int imx214_ctrls_init(struct imx214 *imx214) |
| 879 | 885 | { |
| 880 | − static const s64 link_freq[] = { | |
| 881 | − IMX214_DEFAULT_LINK_FREQ | |
| 882 | − }; | |
| 883 | 886 | static const struct v4l2_area unit_size = { |
| 884 | 887 | .width = 1120, |
| 885 | 888 | .height = 1120, |
| @@ -900,15 +903,14 @@ static int imx214_ctrls_init(struct imx214 *imx214) · 14 unmodified lines | ||
| 900 | 903 | if (ret) |
| 901 | 904 | return ret; |
| 902 | 905 | |
| 903 | − imx214->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL, | |
| 904 | − V4L2_CID_PIXEL_RATE, 0, | |
| 905 | − IMX214_DEFAULT_PIXEL_RATE, 1, | |
| 906 | − IMX214_DEFAULT_PIXEL_RATE); | |
| 906 | + imx214->pixel_rate = | |
| 907 | + v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_PIXEL_RATE, 1, | |
| 908 | + INT_MAX, 1, 1); | |
| 907 | 909 | |
| 908 | 910 | imx214->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, |
| 909 | 911 | V4L2_CID_LINK_FREQ, |
| 910 | − ARRAY_SIZE(link_freq) - 1, | |
| 911 | − 0, link_freq); | |
| 912 | + imx214->bus_cfg.nr_of_link_frequencies - 1, | |
| 913 | + 0, imx214->bus_cfg.link_frequencies); | |
| 912 | 914 | if (imx214->link_freq) |
| 913 | 915 | imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 914 | 916 | |
| @@ -1011,6 +1013,7 @@ static int imx214_start_streaming(struct imx214 *imx214) · 96 unmodified lines | ||
| 1011 | 1013 | const struct v4l2_mbus_framefmt *fmt; |
| 1012 | 1014 | struct v4l2_subdev_state *state; |
| 1013 | 1015 | const struct imx214_mode *mode; |
| 1016 | + int bit_rate_mbps; | |
| 1014 | 1017 | int ret; |
| 1015 | 1018 | |
| 1016 | 1019 | ret = cci_multi_reg_write(imx214->regmap, mode_table_common, |
| @@ -1020,6 +1023,21 @@ static int imx214_start_streaming(struct imx214 *imx214) · 3 unmodified lines | ||
| 1020 | 1023 | return ret; |
| 1021 | 1024 | } |
| 1022 | 1025 | |
| 1026 | + ret = imx214_configure_pll(imx214); | |
| 1027 | + if (ret) { | |
| 1028 | + dev_err(imx214->dev, "failed to configure PLL: %d\n", ret); | |
| 1029 | + return ret; | |
| 1030 | + } | |
| 1031 | + | |
| 1032 | + bit_rate_mbps = (imx214->pll.pixel_rate_csi / 1000000) | |
| 1033 | + * imx214->pll.bits_per_pixel; | |
| 1034 | + ret = cci_write(imx214->regmap, IMX214_REG_REQ_LINK_BIT_RATE, | |
| 1035 | + IMX214_LINK_BIT_RATE_MBPS(bit_rate_mbps), NULL); | |
| 1036 | + if (ret) { | |
| 1037 | + dev_err(imx214->dev, "failed to configure link bit rate\n"); | |
| 1038 | + return ret; | |
| 1039 | + } | |
| 1040 | + | |
| 1023 | 1041 | ret = cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE, |
| 1024 | 1042 | IMX214_CSI_4_LANE_MODE, NULL); |
| 1025 | 1043 | if (ret) { |
| @@ -1097,6 +1115,109 @@ err_rpm_put: · 71 unmodified lines | ||
| 1097 | 1115 | return ret; |
| 1098 | 1116 | } |
| 1099 | 1117 | |
| 1118 | +static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll, | |
| 1119 | + unsigned int link_freq) | |
| 1120 | +{ | |
| 1121 | + struct ccs_pll_limits limits = { | |
| 1122 | + .min_ext_clk_freq_hz = 6000000, | |
| 1123 | + .max_ext_clk_freq_hz = 27000000, | |
| 1124 | + | |
| 1125 | + .vt_fr = { | |
| 1126 | + .min_pre_pll_clk_div = 1, | |
| 1127 | + .max_pre_pll_clk_div = 15, | |
| 1128 | + /* Value is educated guess as we don't have a spec */ | |
| 1129 | + .min_pll_ip_clk_freq_hz = 6000000, | |
| 1130 | + /* Value is educated guess as we don't have a spec */ | |
| 1131 | + .max_pll_ip_clk_freq_hz = 12000000, | |
| 1132 | + .min_pll_multiplier = 12, | |
| 1133 | + .max_pll_multiplier = 1200, | |
| 1134 | + .min_pll_op_clk_freq_hz = 338000000, | |
| 1135 | + .max_pll_op_clk_freq_hz = 1200000000, | |
| 1136 | + }, | |
| 1137 | + .vt_bk = { | |
| 1138 | + .min_sys_clk_div = 2, | |
| 1139 | + .max_sys_clk_div = 4, | |
| 1140 | + .min_pix_clk_div = 5, | |
| 1141 | + .max_pix_clk_div = 10, | |
| 1142 | + .min_pix_clk_freq_hz = 30000000, | |
| 1143 | + .max_pix_clk_freq_hz = 120000000, | |
| 1144 | + }, | |
| 1145 | + .op_bk = { | |
| 1146 | + .min_sys_clk_div = 1, | |
| 1147 | + .max_sys_clk_div = 2, | |
| 1148 | + .min_pix_clk_div = 6, | |
| 1149 | + .max_pix_clk_div = 10, | |
| 1150 | + .min_pix_clk_freq_hz = 30000000, | |
| 1151 | + .max_pix_clk_freq_hz = 120000000, | |
| 1152 | + }, | |
| 1153 | + | |
| 1154 | + .min_line_length_pck_bin = IMX214_PPL_DEFAULT, | |
| 1155 | + .min_line_length_pck = IMX214_PPL_DEFAULT, | |
| 1156 | + }; | |
| 1157 | + unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes; | |
| 1158 | + | |
| 1159 | + /* | |
| 1160 | + * There are no documented constraints on the sys clock frequency, for | |
| 1161 | + * either branch. Recover them based on the PLL output clock frequency | |
| 1162 | + * and sys_clk_div limits on one hand, and the pix clock frequency and | |
| 1163 | + * the pix_clk_div limits on the other hand. | |
| 1164 | + */ | |
| 1165 | + limits.vt_bk.min_sys_clk_freq_hz = | |
| 1166 | + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div, | |
| 1167 | + limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div); | |
| 1168 | + limits.vt_bk.max_sys_clk_freq_hz = | |
| 1169 | + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div, | |
| 1170 | + limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div); | |
| 1171 | + | |
| 1172 | + limits.op_bk.min_sys_clk_freq_hz = | |
| 1173 | + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div, | |
| 1174 | + limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div); | |
| 1175 | + limits.op_bk.max_sys_clk_freq_hz = | |
| 1176 | + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div, | |
| 1177 | + limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div); | |
| 1178 | + | |
| 1179 | + memset(pll, 0, sizeof(*pll)); | |
| 1180 | + | |
| 1181 | + pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; | |
| 1182 | + pll->op_lanes = num_lanes; | |
| 1183 | + pll->vt_lanes = num_lanes; | |
| 1184 | + pll->csi2.lanes = num_lanes; | |
| 1185 | + | |
| 1186 | + pll->binning_horizontal = 1; | |
| 1187 | + pll->binning_vertical = 1; | |
| 1188 | + pll->scale_m = 1; | |
| 1189 | + pll->scale_n = 1; | |
| 1190 | + pll->bits_per_pixel = | |
| 1191 | + IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK; | |
| 1192 | + pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL; | |
| 1193 | + pll->link_freq = link_freq; | |
| 1194 | + pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk); | |
| 1195 | + | |
| 1196 | + return ccs_pll_calculate(imx214->dev, &limits, pll); | |
| 1197 | +} | |
| 1198 | + | |
| 1199 | +static int imx214_pll_update(struct imx214 *imx214) | |
| 1200 | +{ | |
| 1201 | + u64 link_freq; | |
| 1202 | + int ret; | |
| 1203 | + | |
| 1204 | + link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val]; | |
| 1205 | + ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq); | |
| 1206 | + if (ret) { | |
| 1207 | + dev_err(imx214->dev, "PLL calculations failed: %d\n", ret); | |
| 1208 | + return ret; | |
| 1209 | + } | |
| 1210 | + | |
| 1211 | + ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate, | |
| 1212 | + imx214->pll.pixel_rate_pixel_array); | |
| 1213 | + if (ret) { | |
| 1214 | + dev_err(imx214->dev, "failed to set pixel rate\n"); | |
| 1215 | + return ret; | |
| 1216 | + } | |
| 1217 | + | |
| 1218 | + return 0; | |
| 1219 | +} | |
| 1220 | + | |
| 1100 | 1221 | static int imx214_get_frame_interval(struct v4l2_subdev *subdev, |
| 1101 | 1222 | struct v4l2_subdev_state *sd_state, |
| 1102 | 1223 | struct v4l2_subdev_frame_interval *fival) |
| @@ -1203,12 +1324,10 @@ static int imx214_identify_module(struct imx214 *imx214) · 100 unmodified lines | ||
| 1203 | 1324 | return 0; |
| 1204 | 1325 | } |
| 1205 | 1326 | |
| 1206 | −static int imx214_parse_fwnode(struct device *dev) | |
| 1327 | +static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) | |
| 1207 | 1328 | { |
| 1329 | + struct v4l2_fwnode_endpoint *bus_cfg = &imx214->bus_cfg; | |
| 1208 | 1330 | struct fwnode_handle *endpoint; |
| 1209 | − struct v4l2_fwnode_endpoint bus_cfg = { | |
| 1210 | − .bus_type = V4L2_MBUS_CSI2_DPHY, | |
| 1211 | − }; | |
| 1212 | 1331 | unsigned int i; |
| 1213 | 1332 | int ret; |
| 1214 | 1333 | |
| @@ -1216,42 +1335,52 @@ static int imx214_parse_fwnode(struct device *dev) · 1 unmodified line | ||
| 1216 | 1335 | if (!endpoint) |
| 1217 | 1336 | return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); |
| 1218 | 1337 | |
| 1219 | − ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | |
| 1338 | + bus_cfg->bus_type = V4L2_MBUS_CSI2_DPHY; | |
| 1339 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, bus_cfg); | |
| 1340 | + fwnode_handle_put(endpoint); | |
| 1220 | 1341 | if (ret) { |
| 1221 | 1342 | dev_err_probe(dev, ret, "parsing endpoint node failed\n"); |
| 1222 | − goto done; | |
| 1343 | + goto error; | |
| 1223 | 1344 | } |
| 1224 | 1345 | |
| 1225 | 1346 | /* Check the number of MIPI CSI2 data lanes */ |
| 1226 | − if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { | |
| 1347 | + if (bus_cfg->bus.mipi_csi2.num_data_lanes != 4) { | |
| 1227 | 1348 | ret = dev_err_probe(dev, -EINVAL, |
| 1228 | 1349 | "only 4 data lanes are currently supported\n"); |
| 1229 | − goto done; | |
| 1350 | + goto error; | |
| 1230 | 1351 | } |
| 1231 | 1352 | |
| 1232 | − if (bus_cfg.nr_of_link_frequencies != 1) | |
| 1353 | + if (bus_cfg->nr_of_link_frequencies != 1) | |
| 1233 | 1354 | dev_warn(dev, "Only one link-frequency supported, please review your DT. Continuing anyway\n"); |
| 1234 | 1355 | |
| 1235 | − for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { | |
| 1236 | − if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ) | |
| 1356 | + for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { | |
| 1357 | + u64 freq = bus_cfg->link_frequencies[i]; | |
| 1358 | + struct ccs_pll pll; | |
| 1359 | + | |
| 1360 | + if (!imx214_pll_calculate(imx214, &pll, freq)) | |
| 1237 | 1361 | break; |
| 1238 | − if (bus_cfg.link_frequencies[i] == | |
| 1239 | − IMX214_DEFAULT_LINK_FREQ_LEGACY) { | |
| 1362 | + if (freq == IMX214_DEFAULT_LINK_FREQ_LEGACY) { | |
| 1240 | 1363 | dev_warn(dev, |
| 1241 | 1364 | "link-frequencies %d not supported, please review your DT. Continuing anyway\n", |
| 1242 | 1365 | IMX214_DEFAULT_LINK_FREQ); |
| 1366 | + freq = IMX214_DEFAULT_LINK_FREQ; | |
| 1367 | + if (imx214_pll_calculate(imx214, &pll, freq)) | |
| 1368 | + continue; | |
| 1369 | + bus_cfg->link_frequencies[i] = freq; | |
| 1243 | 1370 | break; |
| 1244 | 1371 | } |
| 1245 | 1372 | } |
| 1246 | 1373 | |
| 1247 | − if (i == bus_cfg.nr_of_link_frequencies) | |
| 1374 | + if (i == bus_cfg->nr_of_link_frequencies) | |
| 1248 | 1375 | ret = dev_err_probe(dev, -EINVAL, |
| 1249 | − "link-frequencies %d not supported, please review your DT\n", | |
| 1250 | − IMX214_DEFAULT_LINK_FREQ); | |
| 1376 | + "link-frequencies %lld not supported, please review your DT\n", | |
| 1377 | + bus_cfg->nr_of_link_frequencies ? | |
| 1378 | + bus_cfg->link_frequencies[0] : 0); | |
| 1251 | 1379 | |
| 1252 | −done: | |
| 1253 | − v4l2_fwnode_endpoint_free(&bus_cfg); | |
| 1254 | − fwnode_handle_put(endpoint); | |
| 1380 | + return 0; | |
| 1381 | + | |
| 1382 | +error: | |
| 1383 | + v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | |
| 1255 | 1384 | return ret; |
| 1256 | 1385 | } |
| 1257 | 1386 | |
| @@ -1261,10 +1390,6 @@ static int imx214_probe(struct i2c_client *client) · 3 unmodified lines | ||
| 1261 | 1390 | struct imx214 *imx214; |
| 1262 | 1391 | int ret; |
| 1263 | 1392 | |
| 1264 | − ret = imx214_parse_fwnode(dev); | |
| 1265 | − if (ret) | |
| 1266 | − return ret; | |
| 1267 | − | |
| 1268 | 1393 | imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL); |
| 1269 | 1394 | if (!imx214) |
| 1270 | 1395 | return -ENOMEM; |
| @@ -1276,11 +1401,6 @@ static int imx214_probe(struct i2c_client *client) · 5 unmodified lines | ||
| 1276 | 1401 | return dev_err_probe(dev, PTR_ERR(imx214->xclk), |
| 1277 | 1402 | "failed to get xclk\n"); |
| 1278 | 1403 | |
| 1279 | − ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ); | |
| 1280 | − if (ret) | |
| 1281 | − return dev_err_probe(dev, ret, | |
| 1282 | − "failed to set xclk frequency\n"); | |
| 1283 | − | |
| 1284 | 1404 | ret = imx214_get_regulators(dev, imx214); |
| 1285 | 1405 | if (ret < 0) |
| 1286 | 1406 | return dev_err_probe(dev, ret, "failed to get regulators\n"); |
| @@ -1295,6 +1415,10 @@ static int imx214_probe(struct i2c_client *client) · 8 unmodified lines | ||
| 1295 | 1415 | return dev_err_probe(dev, PTR_ERR(imx214->regmap), |
| 1296 | 1416 | "failed to initialize CCI\n"); |
| 1297 | 1417 | |
| 1418 | + ret = imx214_parse_fwnode(dev, imx214); | |
| 1419 | + if (ret) | |
| 1420 | + return ret; | |
| 1421 | + | |
| 1298 | 1422 | v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); |
| 1299 | 1423 | imx214->sd.internal_ops = &imx214_internal_ops; |
| 1300 | 1424 | |
| @@ -1302,7 +1426,9 @@ static int imx214_probe(struct i2c_client *client) · 1 unmodified line | ||
| 1302 | 1426 | * Enable power initially, to avoid warnings |
| 1303 | 1427 | * from clk_disable on power_off |
| 1304 | 1428 | */ |
| 1305 | − imx214_power_on(imx214->dev); | |
| 1429 | + ret = imx214_power_on(imx214->dev); | |
| 1430 | + if (ret < 0) | |
| 1431 | + goto error_fwnode; | |
| 1306 | 1432 | |
| 1307 | 1433 | ret = imx214_identify_module(imx214); |
| 1308 | 1434 | if (ret) |
| @@ -1333,6 +1459,12 @@ static int imx214_probe(struct i2c_client *client) · 24 unmodified lines | ||
| 1333 | 1459 | pm_runtime_set_active(imx214->dev); |
| 1334 | 1460 | pm_runtime_enable(imx214->dev); |
| 1335 | 1461 | |
| 1462 | + ret = imx214_pll_update(imx214); | |
| 1463 | + if (ret < 0) { | |
| 1464 | + dev_err_probe(dev, ret, "failed to update PLL\n"); | |
| 1465 | + goto error_subdev_cleanup; | |
| 1466 | + } | |
| 1467 | + | |
| 1336 | 1468 | ret = v4l2_async_register_subdev_sensor(&imx214->sd); |
| 1337 | 1469 | if (ret < 0) { |
| 1338 | 1470 | dev_err_probe(dev, ret, |
| @@ -1358,6 +1490,9 @@ free_ctrl: · 19 unmodified lines | ||
| 1358 | 1490 | error_power_off: |
| 1359 | 1491 | imx214_power_off(imx214->dev); |
| 1360 | 1492 | |
| 1493 | +error_fwnode: | |
| 1494 | + v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | |
| 1495 | + | |
| 1361 | 1496 | return ret; |
| 1362 | 1497 | } |
| 1363 | 1498 | |
| @@ -1370,6 +1505,8 @@ static void imx214_remove(struct i2c_client *client) · 6 unmodified lines | ||
| 1370 | 1505 | v4l2_subdev_cleanup(sd); |
| 1371 | 1506 | media_entity_cleanup(&imx214->sd.entity); |
| 1372 | 1507 | v4l2_ctrl_handler_free(&imx214->ctrls); |
| 1508 | + v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | |
| 1509 | + | |
| 1373 | 1510 | pm_runtime_disable(&client->dev); |
| 1374 | 1511 | if (!pm_runtime_status_suspended(&client->dev)) { |
| 1375 | 1512 | imx214_power_off(imx214->dev); |
| @@ -1294,7 +1294,6 @@ static int imx290_subdev_init(struct imx290 *imx290) · 1293 unmodified lines | ||
| 1294 | 1294 | * will already be prevented even before the delay. |
| 1295 | 1295 | */ |
| 1296 | 1296 | v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); |
| 1297 | − imx290->sd.dev = imx290->dev; | |
| 1298 | 1297 | pm_runtime_mark_last_busy(imx290->dev); |
| 1299 | 1298 | pm_runtime_put_autosuspend(imx290->dev); |
| 1300 | 1299 | |
| @@ -1251,7 +1251,7 @@ static int imx415_parse_hw_config(struct imx415 *sensor) · 1250 unmodified lines | ||
| 1251 | 1251 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), |
| 1252 | 1252 | "failed to get reset GPIO\n"); |
| 1253 | 1253 | |
| 1254 | − sensor->clk = devm_clk_get(sensor->dev, "inck"); | |
| 1254 | + sensor->clk = devm_clk_get(sensor->dev, NULL); | |
| 1255 | 1255 | if (IS_ERR(sensor->clk)) |
| 1256 | 1256 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), |
| 1257 | 1257 | "failed to get clock\n"); |
| @@ -600,7 +600,7 @@ static int lt6911uxe_probe(struct i2c_client *client) · 599 unmodified lines | ||
| 600 | 600 | |
| 601 | 601 | v4l2_i2c_subdev_init(<6911uxe->sd, client, <6911uxe_subdev_ops); |
| 602 | 602 | |
| 603 | − lt6911uxe->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_IN); | |
| 603 | + lt6911uxe->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 604 | 604 | if (IS_ERR(lt6911uxe->reset_gpio)) |
| 605 | 605 | return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio), |
| 606 | 606 | "failed to get reset gpio\n"); |
| @@ -1193,12 +1193,12 @@ static int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset, · 1192 unmodified lines | ||
| 1193 | 1193 | MAX9286_0X0F_RESERVED | priv->gpio_state); |
| 1194 | 1194 | } |
| 1195 | 1195 | |
| 1196 | −static void max9286_gpiochip_set(struct gpio_chip *chip, | |
| 1197 | − unsigned int offset, int value) | |
| 1196 | +static int max9286_gpiochip_set(struct gpio_chip *chip, | |
| 1197 | + unsigned int offset, int value) | |
| 1198 | 1198 | { |
| 1199 | 1199 | struct max9286_priv *priv = gpiochip_get_data(chip); |
| 1200 | 1200 | |
| 1201 | − max9286_gpio_set(priv, offset, value); | |
| 1201 | + return max9286_gpio_set(priv, offset, value); | |
| 1202 | 1202 | } |
| 1203 | 1203 | |
| 1204 | 1204 | static int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset) |
| @@ -1220,7 +1220,7 @@ static int max9286_register_gpio(struct max9286_priv *priv) · 15 unmodified lines | ||
| 1220 | 1220 | gpio->owner = THIS_MODULE; |
| 1221 | 1221 | gpio->ngpio = 2; |
| 1222 | 1222 | gpio->base = -1; |
| 1223 | − gpio->set = max9286_gpiochip_set; | |
| 1223 | + gpio->set_rv = max9286_gpiochip_set; | |
| 1224 | 1224 | gpio->get = max9286_gpiochip_get; |
| 1225 | 1225 | gpio->can_sleep = true; |
| 1226 | 1226 | |
| @@ -370,13 +370,6 @@ static int _max96714_set_routing(struct v4l2_subdev *sd, · 369 unmodified lines | ||
| 370 | 370 | }; |
| 371 | 371 | int ret; |
| 372 | 372 | |
| 373 | − /* | |
| 374 | − * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until | |
| 375 | − * frame desc is made dynamically allocated. | |
| 376 | − */ | |
| 377 | − if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 378 | − return -EINVAL; | |
| 379 | − | |
| 380 | 373 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 381 | 374 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 382 | 375 | if (ret) |
| @@ -297,13 +297,13 @@ static int max96717_gpiochip_get(struct gpio_chip *gpiochip, · 296 unmodified lines | ||
| 297 | 297 | return !!(val & MAX96717_GPIO_OUT); |
| 298 | 298 | } |
| 299 | 299 | |
| 300 | −static void max96717_gpiochip_set(struct gpio_chip *gpiochip, | |
| 301 | − unsigned int offset, int value) | |
| 300 | +static int max96717_gpiochip_set(struct gpio_chip *gpiochip, | |
| 301 | + unsigned int offset, int value) | |
| 302 | 302 | { |
| 303 | 303 | struct max96717_priv *priv = gpiochip_get_data(gpiochip); |
| 304 | 304 | |
| 305 | − cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 306 | − MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL); | |
| 305 | + return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 306 | + MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL); | |
| 307 | 307 | } |
| 308 | 308 | |
| 309 | 309 | static int max96717_gpio_get_direction(struct gpio_chip *gpiochip, |
| @@ -355,9 +355,8 @@ static int max96717_gpiochip_probe(struct max96717_priv *priv) · 45 unmodified lines | ||
| 355 | 355 | gc->get_direction = max96717_gpio_get_direction; |
| 356 | 356 | gc->direction_input = max96717_gpio_direction_in; |
| 357 | 357 | gc->direction_output = max96717_gpio_direction_out; |
| 358 | − gc->set = max96717_gpiochip_set; | |
| 358 | + gc->set_rv = max96717_gpiochip_set; | |
| 359 | 359 | gc->get = max96717_gpiochip_get; |
| 360 | − gc->of_gpio_n_cells = 2; | |
| 361 | 360 | |
| 362 | 361 | /* Disable GPIO forwarding */ |
| 363 | 362 | for (i = 0; i < gc->ngpio; i++) |
| @@ -261,6 +261,7 @@ · 260 unmodified lines | ||
| 261 | 261 | #define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) |
| 262 | 262 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) |
| 263 | 263 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) |
| 264 | +#define MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE 0x00 | |
| 264 | 265 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) |
| 265 | 266 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) |
| 266 | 267 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) |
| @@ -377,6 +378,7 @@ struct mt9m114 { · 110 unmodified lines | ||
| 377 | 378 | struct gpio_desc *reset; |
| 378 | 379 | struct regulator_bulk_data supplies[3]; |
| 379 | 380 | struct v4l2_fwnode_endpoint bus_cfg; |
| 381 | + bool bypass_pll; | |
| 380 | 382 | |
| 381 | 383 | struct { |
| 382 | 384 | unsigned int m; |
| @@ -743,14 +745,21 @@ static int mt9m114_initialize(struct mt9m114 *sensor) · 360 unmodified lines | ||
| 743 | 745 | } |
| 744 | 746 | |
| 745 | 747 | /* Configure the PLL. */ |
| 746 | − cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, | |
| 747 | − MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); | |
| 748 | − cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, | |
| 749 | − MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, | |
| 750 | − sensor->pll.n), | |
| 751 | − &ret); | |
| 752 | − cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, | |
| 753 | − MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), &ret); | |
| 748 | + if (sensor->bypass_pll) { | |
| 749 | + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, | |
| 750 | + MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE, &ret); | |
| 751 | + } else { | |
| 752 | + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, | |
| 753 | + MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); | |
| 754 | + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, | |
| 755 | + MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, | |
| 756 | + sensor->pll.n), | |
| 757 | + &ret); | |
| 758 | + cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, | |
| 759 | + MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), | |
| 760 | + &ret); | |
| 761 | + } | |
| 762 | + | |
| 754 | 763 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, |
| 755 | 764 | sensor->pixrate, &ret); |
| 756 | 765 | |
| @@ -781,41 +790,25 @@ static int mt9m114_initialize(struct mt9m114 *sensor) · 24 unmodified lines | ||
| 781 | 790 | return 0; |
| 782 | 791 | } |
| 783 | 792 | |
| 784 | −static int mt9m114_configure(struct mt9m114 *sensor, | |
| 785 | − struct v4l2_subdev_state *pa_state, | |
| 786 | − struct v4l2_subdev_state *ifp_state) | |
| 793 | +static int mt9m114_configure_pa(struct mt9m114 *sensor, | |
| 794 | + struct v4l2_subdev_state *state) | |
| 787 | 795 | { |
| 788 | − const struct v4l2_mbus_framefmt *pa_format; | |
| 789 | − const struct v4l2_rect *pa_crop; | |
| 790 | − const struct mt9m114_format_info *ifp_info; | |
| 791 | − const struct v4l2_mbus_framefmt *ifp_format; | |
| 792 | − const struct v4l2_rect *ifp_crop; | |
| 793 | − const struct v4l2_rect *ifp_compose; | |
| 796 | + const struct v4l2_mbus_framefmt *format; | |
| 797 | + const struct v4l2_rect *crop; | |
| 794 | 798 | unsigned int hratio, vratio; |
| 795 | − u64 output_format; | |
| 796 | 799 | u64 read_mode; |
| 797 | − int ret = 0; | |
| 798 | − | |
| 799 | − pa_format = v4l2_subdev_state_get_format(pa_state, 0); | |
| 800 | − pa_crop = v4l2_subdev_state_get_crop(pa_state, 0); | |
| 800 | + int ret; | |
| 801 | 801 | |
| 802 | − ifp_format = v4l2_subdev_state_get_format(ifp_state, 1); | |
| 803 | − ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code); | |
| 804 | − ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0); | |
| 805 | − ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0); | |
| 802 | + format = v4l2_subdev_state_get_format(state, 0); | |
| 803 | + crop = v4l2_subdev_state_get_crop(state, 0); | |
| 806 | 804 | |
| 807 | 805 | ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
| 808 | 806 | &read_mode, NULL); |
| 809 | 807 | if (ret < 0) |
| 810 | 808 | return ret; |
| 811 | 809 | |
| 812 | − ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, | |
| 813 | − &output_format, NULL); | |
| 814 | − if (ret < 0) | |
| 815 | − return ret; | |
| 816 | − | |
| 817 | − hratio = pa_crop->width / pa_format->width; | |
| 818 | − vratio = pa_crop->height / pa_format->height; | |
| 810 | + hratio = crop->width / format->width; | |
| 811 | + vratio = crop->height / format->height; | |
| 819 | 812 | |
| 820 | 813 | /* |
| 821 | 814 | * Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW |
| @@ -824,15 +817,15 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 2 unmodified lines | ||
| 824 | 817 | * example sensor modes. |
| 825 | 818 | */ |
| 826 | 819 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, |
| 827 | − pa_crop->left, &ret); | |
| 820 | + crop->left, &ret); | |
| 828 | 821 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, |
| 829 | − pa_crop->top, &ret); | |
| 822 | + crop->top, &ret); | |
| 830 | 823 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END, |
| 831 | − pa_crop->width + pa_crop->left - 1, &ret); | |
| 824 | + crop->width + crop->left - 1, &ret); | |
| 832 | 825 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, |
| 833 | − pa_crop->height + pa_crop->top - 1, &ret); | |
| 826 | + crop->height + crop->top - 1, &ret); | |
| 834 | 827 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, |
| 835 | − (pa_crop->height - 4) / vratio - 1, &ret); | |
| 828 | + (crop->height - 4) / vratio - 1, &ret); | |
| 836 | 829 | |
| 837 | 830 | read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | |
| 838 | 831 | MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); |
| @@ -845,6 +838,29 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 6 unmodified lines | ||
| 845 | 838 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
| 846 | 839 | read_mode, &ret); |
| 847 | 840 | |
| 841 | + return ret; | |
| 842 | +} | |
| 843 | + | |
| 844 | +static int mt9m114_configure_ifp(struct mt9m114 *sensor, | |
| 845 | + struct v4l2_subdev_state *state) | |
| 846 | +{ | |
| 847 | + const struct mt9m114_format_info *info; | |
| 848 | + const struct v4l2_mbus_framefmt *format; | |
| 849 | + const struct v4l2_rect *crop; | |
| 850 | + const struct v4l2_rect *compose; | |
| 851 | + u64 output_format; | |
| 852 | + int ret = 0; | |
| 853 | + | |
| 854 | + format = v4l2_subdev_state_get_format(state, 1); | |
| 855 | + info = mt9m114_format_info(sensor, 1, format->code); | |
| 856 | + crop = v4l2_subdev_state_get_crop(state, 0); | |
| 857 | + compose = v4l2_subdev_state_get_compose(state, 0); | |
| 858 | + | |
| 859 | + ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, | |
| 860 | + &output_format, NULL); | |
| 861 | + if (ret < 0) | |
| 862 | + return ret; | |
| 863 | + | |
| 848 | 864 | /* |
| 849 | 865 | * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left |
| 850 | 866 | * and top coordinates to compensate for the lines and columns removed |
| @@ -852,18 +868,18 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 1 unmodified line | ||
| 852 | 868 | * not in the hardware. |
| 853 | 869 | */ |
| 854 | 870 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, |
| 855 | − ifp_crop->left - 4, &ret); | |
| 871 | + crop->left - 4, &ret); | |
| 856 | 872 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, |
| 857 | − ifp_crop->top - 4, &ret); | |
| 873 | + crop->top - 4, &ret); | |
| 858 | 874 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, |
| 859 | − ifp_crop->width, &ret); | |
| 875 | + crop->width, &ret); | |
| 860 | 876 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, |
| 861 | − ifp_crop->height, &ret); | |
| 877 | + crop->height, &ret); | |
| 862 | 878 | |
| 863 | 879 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, |
| 864 | − ifp_compose->width, &ret); | |
| 880 | + compose->width, &ret); | |
| 865 | 881 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, |
| 866 | − ifp_compose->height, &ret); | |
| 882 | + compose->height, &ret); | |
| 867 | 883 | |
| 868 | 884 | /* AWB and AE windows, use the full frame. */ |
| 869 | 885 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART, |
| @@ -871,18 +887,18 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 1 unmodified line | ||
| 871 | 887 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, |
| 872 | 888 | 0, &ret); |
| 873 | 889 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, |
| 874 | − ifp_compose->width - 1, &ret); | |
| 890 | + compose->width - 1, &ret); | |
| 875 | 891 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, |
| 876 | − ifp_compose->height - 1, &ret); | |
| 892 | + compose->height - 1, &ret); | |
| 877 | 893 | |
| 878 | 894 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, |
| 879 | 895 | 0, &ret); |
| 880 | 896 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, |
| 881 | 897 | 0, &ret); |
| 882 | 898 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, |
| 883 | − ifp_compose->width / 5 - 1, &ret); | |
| 899 | + compose->width / 5 - 1, &ret); | |
| 884 | 900 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, |
| 885 | − ifp_compose->height / 5 - 1, &ret); | |
| 901 | + compose->height / 5 - 1, &ret); | |
| 886 | 902 | |
| 887 | 903 | cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE, |
| 888 | 904 | MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | |
| @@ -894,7 +910,7 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 5 unmodified lines | ||
| 894 | 910 | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | |
| 895 | 911 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | |
| 896 | 912 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); |
| 897 | − output_format |= ifp_info->output_format; | |
| 913 | + output_format |= info->output_format; | |
| 898 | 914 | |
| 899 | 915 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, |
| 900 | 916 | output_format, &ret); |
| @@ -925,7 +941,11 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor, · 24 unmodified lines | ||
| 925 | 941 | if (ret) |
| 926 | 942 | return ret; |
| 927 | 943 | |
| 928 | − ret = mt9m114_configure(sensor, pa_state, ifp_state); | |
| 944 | + ret = mt9m114_configure_ifp(sensor, ifp_state); | |
| 945 | + if (ret) | |
| 946 | + goto error; | |
| 947 | + | |
| 948 | + ret = mt9m114_configure_pa(sensor, pa_state); | |
| 929 | 949 | if (ret) |
| 930 | 950 | goto error; |
| 931 | 951 | |
| @@ -1599,13 +1619,9 @@ static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd, · 667 unmodified lines | ||
| 1599 | 1619 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
| 1600 | 1620 | return -EINVAL; |
| 1601 | 1621 | |
| 1602 | − mutex_lock(sensor->ifp.hdl.lock); | |
| 1603 | − | |
| 1604 | 1622 | ival->numerator = 1; |
| 1605 | 1623 | ival->denominator = sensor->ifp.frame_rate; |
| 1606 | 1624 | |
| 1607 | − mutex_unlock(sensor->ifp.hdl.lock); | |
| 1608 | − | |
| 1609 | 1625 | return 0; |
| 1610 | 1626 | } |
| 1611 | 1627 | |
| @@ -1624,8 +1640,6 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd, · 12 unmodified lines | ||
| 1624 | 1640 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
| 1625 | 1641 | return -EINVAL; |
| 1626 | 1642 | |
| 1627 | − mutex_lock(sensor->ifp.hdl.lock); | |
| 1628 | − | |
| 1629 | 1643 | if (ival->numerator != 0 && ival->denominator != 0) |
| 1630 | 1644 | sensor->ifp.frame_rate = min_t(unsigned int, |
| 1631 | 1645 | ival->denominator / ival->numerator, |
| @@ -1639,8 +1653,6 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd, · 7 unmodified lines | ||
| 1639 | 1653 | if (sensor->streaming) |
| 1640 | 1654 | ret = mt9m114_set_frame_rate(sensor); |
| 1641 | 1655 | |
| 1642 | − mutex_unlock(sensor->ifp.hdl.lock); | |
| 1643 | − | |
| 1644 | 1656 | return ret; |
| 1645 | 1657 | } |
| 1646 | 1658 | |
| @@ -2235,9 +2247,22 @@ static const struct dev_pm_ops mt9m114_pm_ops = { · 588 unmodified lines | ||
| 2235 | 2247 | * Probe & Remove |
| 2236 | 2248 | */ |
| 2237 | 2249 | |
| 2250 | +static int mt9m114_verify_link_frequency(struct mt9m114 *sensor, | |
| 2251 | + unsigned int pixrate) | |
| 2252 | +{ | |
| 2253 | + unsigned int link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY | |
| 2254 | + ? pixrate * 8 : pixrate * 2; | |
| 2255 | + | |
| 2256 | + if (sensor->bus_cfg.nr_of_link_frequencies != 1 || | |
| 2257 | + sensor->bus_cfg.link_frequencies[0] != link_freq) | |
| 2258 | + return -EINVAL; | |
| 2259 | + | |
| 2260 | + return 0; | |
| 2261 | +} | |
| 2262 | + | |
| 2238 | 2263 | static int mt9m114_clk_init(struct mt9m114 *sensor) |
| 2239 | 2264 | { |
| 2240 | − unsigned int link_freq; | |
| 2265 | + unsigned int pixrate; | |
| 2241 | 2266 | |
| 2242 | 2267 | /* Hardcode the PLL multiplier and dividers to default settings. */ |
| 2243 | 2268 | sensor->pll.m = 32; |
| @@ -2249,19 +2274,29 @@ static int mt9m114_clk_init(struct mt9m114 *sensor) · 5 unmodified lines | ||
| 2249 | 2274 | * for 16-bit per pixel, transmitted in DDR over a single lane. For |
| 2250 | 2275 | * parallel mode, the sensor ouputs one pixel in two PIXCLK cycles. |
| 2251 | 2276 | */ |
| 2252 | − sensor->pixrate = clk_get_rate(sensor->clk) * sensor->pll.m | |
| 2253 | − / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); | |
| 2254 | 2277 | |
| 2255 | − link_freq = sensor->bus_cfg.bus_type == V4L2_MBUS_CSI2_DPHY | |
| 2256 | − ? sensor->pixrate * 8 : sensor->pixrate * 2; | |
| 2278 | + /* | |
| 2279 | + * Check if EXTCLK fits the configured link frequency. Bypass the PLL | |
| 2280 | + * in this case. | |
| 2281 | + */ | |
| 2282 | + pixrate = clk_get_rate(sensor->clk) / 2; | |
| 2283 | + if (mt9m114_verify_link_frequency(sensor, pixrate) == 0) { | |
| 2284 | + sensor->pixrate = pixrate; | |
| 2285 | + sensor->bypass_pll = true; | |
| 2286 | + return 0; | |
| 2287 | + } | |
| 2257 | 2288 | |
| 2258 | − if (sensor->bus_cfg.nr_of_link_frequencies != 1 || | |
| 2259 | − sensor->bus_cfg.link_frequencies[0] != link_freq) { | |
| 2260 | − dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); | |
| 2261 | − return -EINVAL; | |
| 2289 | + /* Check if the PLL configuration fits the configured link frequency. */ | |
| 2290 | + pixrate = clk_get_rate(sensor->clk) * sensor->pll.m | |
| 2291 | + / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); | |
| 2292 | + if (mt9m114_verify_link_frequency(sensor, pixrate) == 0) { | |
| 2293 | + sensor->pixrate = pixrate; | |
| 2294 | + sensor->bypass_pll = false; | |
| 2295 | + return 0; | |
| 2262 | 2296 | } |
| 2263 | 2297 | |
| 2264 | − return 0; | |
| 2298 | + dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); | |
| 2299 | + return -EINVAL; | |
| 2265 | 2300 | } |
| 2266 | 2301 | |
| 2267 | 2302 | static int mt9m114_identify(struct mt9m114 *sensor) |
| @@ -1469,14 +1469,15 @@ static int ov2659_probe(struct i2c_client *client) · 1468 unmodified lines | ||
| 1469 | 1469 | V4L2_CID_TEST_PATTERN, |
| 1470 | 1470 | ARRAY_SIZE(ov2659_test_pattern_menu) - 1, |
| 1471 | 1471 | 0, 0, ov2659_test_pattern_menu); |
| 1472 | − ov2659->sd.ctrl_handler = &ov2659->ctrls; | |
| 1473 | 1472 | |
| 1474 | 1473 | if (ov2659->ctrls.error) { |
| 1475 | 1474 | dev_err(&client->dev, "%s: control initialization error %d\n", |
| 1476 | 1475 | __func__, ov2659->ctrls.error); |
| 1476 | + v4l2_ctrl_handler_free(&ov2659->ctrls); | |
| 1477 | 1477 | return ov2659->ctrls.error; |
| 1478 | 1478 | } |
| 1479 | 1479 | |
| 1480 | + ov2659->sd.ctrl_handler = &ov2659->ctrls; | |
| 1480 | 1481 | sd = &ov2659->sd; |
| 1481 | 1482 | client->flags |= I2C_CLIENT_SCCB; |
| 1482 | 1483 | |
| @@ -766,11 +766,9 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 765 unmodified lines | ||
| 766 | 766 | { |
| 767 | 767 | struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); |
| 768 | 768 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 769 | − const struct ov2740_mode *cur_mode; | |
| 770 | 769 | s64 exposure_max, h_blank, pixel_rate; |
| 771 | 770 | u32 vblank_min, vblank_max, vblank_default; |
| 772 | 771 | struct v4l2_fwnode_device_properties props; |
| 773 | − int size; | |
| 774 | 772 | int ret; |
| 775 | 773 | |
| 776 | 774 | ctrl_hdlr = &ov2740->ctrl_handler; |
| @@ -778,12 +776,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 1 unmodified line | ||
| 778 | 776 | if (ret) |
| 779 | 777 | return ret; |
| 780 | 778 | |
| 781 | − cur_mode = ov2740->cur_mode; | |
| 782 | − size = ARRAY_SIZE(link_freq_menu_items); | |
| 783 | − | |
| 784 | 779 | ov2740->link_freq = |
| 785 | 780 | v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops, |
| 786 | − V4L2_CID_LINK_FREQ, size - 1, | |
| 781 | + V4L2_CID_LINK_FREQ, | |
| 782 | + ARRAY_SIZE(link_freq_menu_items) - 1, | |
| 787 | 783 | ov2740->supported_modes->link_freq_index, |
| 788 | 784 | link_freq_menu_items); |
| 789 | 785 | if (ov2740->link_freq) |
| @@ -794,14 +790,14 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 4 unmodified lines | ||
| 794 | 790 | V4L2_CID_PIXEL_RATE, 0, |
| 795 | 791 | pixel_rate, 1, pixel_rate); |
| 796 | 792 | |
| 797 | − vblank_min = cur_mode->vts_min - cur_mode->height; | |
| 798 | − vblank_max = cur_mode->vts_max - cur_mode->height; | |
| 799 | − vblank_default = cur_mode->vts_def - cur_mode->height; | |
| 793 | + vblank_min = ov2740->cur_mode->vts_min - ov2740->cur_mode->height; | |
| 794 | + vblank_max = ov2740->cur_mode->vts_max - ov2740->cur_mode->height; | |
| 795 | + vblank_default = ov2740->cur_mode->vts_def - ov2740->cur_mode->height; | |
| 800 | 796 | ov2740->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 801 | 797 | V4L2_CID_VBLANK, vblank_min, |
| 802 | 798 | vblank_max, 1, vblank_default); |
| 803 | 799 | |
| 804 | − h_blank = cur_mode->hts - cur_mode->width; | |
| 800 | + h_blank = ov2740->cur_mode->hts - ov2740->cur_mode->width; | |
| 805 | 801 | ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 806 | 802 | V4L2_CID_HBLANK, h_blank, h_blank, 1, |
| 807 | 803 | h_blank); |
| @@ -814,7 +810,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 6 unmodified lines | ||
| 814 | 810 | v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_DIGITAL_GAIN, |
| 815 | 811 | OV2740_DGTL_GAIN_MIN, OV2740_DGTL_GAIN_MAX, |
| 816 | 812 | OV2740_DGTL_GAIN_STEP, OV2740_DGTL_GAIN_DEFAULT); |
| 817 | − exposure_max = cur_mode->vts_def - OV2740_EXPOSURE_MAX_MARGIN; | |
| 813 | + exposure_max = ov2740->cur_mode->vts_def - OV2740_EXPOSURE_MAX_MARGIN; | |
| 818 | 814 | ov2740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 819 | 815 | V4L2_CID_EXPOSURE, |
| 820 | 816 | OV2740_EXPOSURE_MIN, exposure_max, |
| @@ -2688,10 +2688,15 @@ static int ov5670_probe(struct i2c_client *client) · 2687 unmodified lines | ||
| 2688 | 2688 | if (ret) |
| 2689 | 2689 | return dev_err_probe(&client->dev, ret, "GPIO probe failed\n"); |
| 2690 | 2690 | |
| 2691 | − /* Graph Endpoint */ | |
| 2691 | + /* | |
| 2692 | + * Graph Endpoint. If it's missing we defer rather than fail, as this | |
| 2693 | + * sensor is known to co-exist on systems with the IPU3 and so it might | |
| 2694 | + * be created by the ipu-bridge. | |
| 2695 | + */ | |
| 2692 | 2696 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); |
| 2693 | 2697 | if (!handle) |
| 2694 | − return dev_err_probe(&client->dev, -ENXIO, "Endpoint for node get failed\n"); | |
| 2698 | + return dev_err_probe(&client->dev, -EPROBE_DEFER, | |
| 2699 | + "Endpoint for node get failed\n"); | |
| 2695 | 2700 | |
| 2696 | 2701 | ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; |
| 2697 | 2702 | ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2; |
| @@ -1222,9 +1222,14 @@ static int ov5693_check_hwcfg(struct ov5693_device *ov5693) · 1221 unmodified lines | ||
| 1222 | 1222 | unsigned int i; |
| 1223 | 1223 | int ret; |
| 1224 | 1224 | |
| 1225 | + /* | |
| 1226 | + * Sometimes the fwnode graph is initialized by the bridge driver | |
| 1227 | + * Bridge drivers doing this may also add GPIO mappings, wait for this. | |
| 1228 | + */ | |
| 1225 | 1229 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); |
| 1226 | 1230 | if (!endpoint) |
| 1227 | − return -EPROBE_DEFER; /* Could be provided by cio2-bridge */ | |
| 1231 | + return dev_err_probe(ov5693->dev, -EPROBE_DEFER, | |
| 1232 | + "waiting for fwnode graph endpoint\n"); | |
| 1228 | 1233 | |
| 1229 | 1234 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); |
| 1230 | 1235 | fwnode_handle_put(endpoint); |
| @@ -1486,9 +1486,14 @@ static int ov7251_check_hwcfg(struct ov7251 *ov7251) · 1485 unmodified lines | ||
| 1486 | 1486 | unsigned int i, j; |
| 1487 | 1487 | int ret; |
| 1488 | 1488 | |
| 1489 | + /* | |
| 1490 | + * Sometimes the fwnode graph is initialized by the bridge driver | |
| 1491 | + * Bridge drivers doing this may also add GPIO mappings, wait for this. | |
| 1492 | + */ | |
| 1489 | 1493 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); |
| 1490 | 1494 | if (!endpoint) |
| 1491 | − return -EPROBE_DEFER; /* could be provided by cio2-bridge */ | |
| 1495 | + return dev_err_probe(ov7251->dev, -EPROBE_DEFER, | |
| 1496 | + "waiting for fwnode graph endpoint\n"); | |
| 1492 | 1497 | |
| 1493 | 1498 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); |
| 1494 | 1499 | fwnode_handle_put(endpoint); |
| @@ -2991,7 +2991,8 @@ static int ov8865_probe(struct i2c_client *client) · 2990 unmodified lines | ||
| 2991 | 2991 | |
| 2992 | 2992 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); |
| 2993 | 2993 | if (!handle) |
| 2994 | − return -EPROBE_DEFER; | |
| 2994 | + return dev_err_probe(dev, -EPROBE_DEFER, | |
| 2995 | + "waiting for fwnode graph endpoint\n"); | |
| 2995 | 2996 | |
| 2996 | 2997 | sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; |
| 2997 | 2998 | |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | |
| 26 | 26 | #include "saa711x_regs.h" |
| 27 | 27 | |
| 28 | +#include <linux/bitops.h> | |
| 28 | 29 | #include <linux/kernel.h> |
| 29 | 30 | #include <linux/module.h> |
| 30 | 31 | #include <linux/slab.h> |
| @@ -664,15 +665,6 @@ static const unsigned char saa7115_init_misc[] = { · 633 unmodified lines | ||
| 664 | 665 | 0x00, 0x00 |
| 665 | 666 | }; |
| 666 | 667 | |
| 667 | −static int saa711x_odd_parity(u8 c) | |
| 668 | −{ | |
| 669 | − c ^= (c >> 4); | |
| 670 | − c ^= (c >> 2); | |
| 671 | − c ^= (c >> 1); | |
| 672 | − | |
| 673 | − return c & 1; | |
| 674 | −} | |
| 675 | − | |
| 676 | 668 | static int saa711x_decode_vps(u8 *dst, u8 *p) |
| 677 | 669 | { |
| 678 | 670 | static const u8 biphase_tbl[] = { |
| @@ -1227,7 +1219,7 @@ static int saa711x_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vb · 548 unmodified lines | ||
| 1227 | 1219 | vbi->type = V4L2_SLICED_TELETEXT_B; |
| 1228 | 1220 | break; |
| 1229 | 1221 | case 4: |
| 1230 | − if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1])) | |
| 1222 | + if (!parity8(p[0]) || !parity8(p[1])) | |
| 1231 | 1223 | return 0; |
| 1232 | 1224 | vbi->type = V4L2_SLICED_CAPTION_525; |
| 1233 | 1225 | break; |
| @@ -114,7 +114,7 @@ static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) · 113 unmodified lines | ||
| 114 | 114 | |
| 115 | 115 | /* --------------- I2C --------------- */ |
| 116 | 116 | |
| 117 | −static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | |
| 117 | +static int i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | |
| 118 | 118 | { |
| 119 | 119 | struct tc358743_state *state = to_state(sd); |
| 120 | 120 | struct i2c_client *client = state->i2c_client; |
| @@ -140,6 +140,7 @@ static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) · 19 unmodified lines | ||
| 140 | 140 | v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n", |
| 141 | 141 | __func__, reg, client->addr, err); |
| 142 | 142 | } |
| 143 | + return err != ARRAY_SIZE(msgs); | |
| 143 | 144 | } |
| 144 | 145 | |
| 145 | 146 | static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) |
| @@ -196,15 +197,24 @@ static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) · 50 unmodified lines | ||
| 196 | 197 | } |
| 197 | 198 | } |
| 198 | 199 | |
| 199 | −static noinline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) | |
| 200 | +static noinline u32 i2c_rdreg_err(struct v4l2_subdev *sd, u16 reg, u32 n, | |
| 201 | + int *err) | |
| 200 | 202 | { |
| 203 | + int error; | |
| 201 | 204 | __le32 val = 0; |
| 202 | 205 | |
| 203 | − i2c_rd(sd, reg, (u8 __force *)&val, n); | |
| 206 | + error = i2c_rd(sd, reg, (u8 __force *)&val, n); | |
| 207 | + if (err) | |
| 208 | + *err = error; | |
| 204 | 209 | |
| 205 | 210 | return le32_to_cpu(val); |
| 206 | 211 | } |
| 207 | 212 | |
| 213 | +static inline u32 i2c_rdreg(struct v4l2_subdev *sd, u16 reg, u32 n) | |
| 214 | +{ | |
| 215 | + return i2c_rdreg_err(sd, reg, n, NULL); | |
| 216 | +} | |
| 217 | + | |
| 208 | 218 | static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) |
| 209 | 219 | { |
| 210 | 220 | __le32 raw = cpu_to_le32(val); |
| @@ -233,6 +243,13 @@ static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) · 22 unmodified lines | ||
| 233 | 243 | return i2c_rdreg(sd, reg, 2); |
| 234 | 244 | } |
| 235 | 245 | |
| 246 | +static int i2c_rd16_err(struct v4l2_subdev *sd, u16 reg, u16 *value) | |
| 247 | +{ | |
| 248 | + int err; | |
| 249 | + *value = i2c_rdreg_err(sd, reg, 2, &err); | |
| 250 | + return err; | |
| 251 | +} | |
| 252 | + | |
| 236 | 253 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) |
| 237 | 254 | { |
| 238 | 255 | i2c_wrreg(sd, reg, val, 2); |
| @@ -420,9 +437,9 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd) · 181 unmodified lines | ||
| 420 | 437 | |
| 421 | 438 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); |
| 422 | 439 | |
| 423 | − /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when | |
| 440 | + /* Enable hotplug after 143 ms. DDC access to EDID is also enabled when | |
| 424 | 441 | * hotplug is enabled. See register DDC_CTL */ |
| 425 | − schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); | |
| 442 | + schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 7); | |
| 426 | 443 | |
| 427 | 444 | tc358743_enable_interrupts(sd, true); |
| 428 | 445 | tc358743_s_ctrl_detect_tx_5v(sd); |
| @@ -1691,12 +1708,23 @@ static int tc358743_enum_mbus_code(struct v4l2_subdev *sd, · 1262 unmodified lines | ||
| 1691 | 1708 | return 0; |
| 1692 | 1709 | } |
| 1693 | 1710 | |
| 1711 | +static u32 tc358743_g_colorspace(u32 code) | |
| 1712 | +{ | |
| 1713 | + switch (code) { | |
| 1714 | + case MEDIA_BUS_FMT_RGB888_1X24: | |
| 1715 | + return V4L2_COLORSPACE_SRGB; | |
| 1716 | + case MEDIA_BUS_FMT_UYVY8_1X16: | |
| 1717 | + return V4L2_COLORSPACE_SMPTE170M; | |
| 1718 | + default: | |
| 1719 | + return 0; | |
| 1720 | + } | |
| 1721 | +} | |
| 1722 | + | |
| 1694 | 1723 | static int tc358743_get_fmt(struct v4l2_subdev *sd, |
| 1695 | 1724 | struct v4l2_subdev_state *sd_state, |
| 1696 | 1725 | struct v4l2_subdev_format *format) |
| 1697 | 1726 | { |
| 1698 | 1727 | struct tc358743_state *state = to_state(sd); |
| 1699 | − u8 vi_rep = i2c_rd8(sd, VI_REP); | |
| 1700 | 1728 | |
| 1701 | 1729 | if (format->pad != 0) |
| 1702 | 1730 | return -EINVAL; |
| @@ -1706,23 +1734,7 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd, · 3 unmodified lines | ||
| 1706 | 1734 | format->format.height = state->timings.bt.height; |
| 1707 | 1735 | format->format.field = V4L2_FIELD_NONE; |
| 1708 | 1736 | |
| 1709 | − switch (vi_rep & MASK_VOUT_COLOR_SEL) { | |
| 1710 | − case MASK_VOUT_COLOR_RGB_FULL: | |
| 1711 | − case MASK_VOUT_COLOR_RGB_LIMITED: | |
| 1712 | − format->format.colorspace = V4L2_COLORSPACE_SRGB; | |
| 1713 | − break; | |
| 1714 | − case MASK_VOUT_COLOR_601_YCBCR_LIMITED: | |
| 1715 | − case MASK_VOUT_COLOR_601_YCBCR_FULL: | |
| 1716 | − format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; | |
| 1717 | − break; | |
| 1718 | − case MASK_VOUT_COLOR_709_YCBCR_FULL: | |
| 1719 | − case MASK_VOUT_COLOR_709_YCBCR_LIMITED: | |
| 1720 | − format->format.colorspace = V4L2_COLORSPACE_REC709; | |
| 1721 | − break; | |
| 1722 | − default: | |
| 1723 | − format->format.colorspace = 0; | |
| 1724 | − break; | |
| 1725 | − } | |
| 1737 | + format->format.colorspace = tc358743_g_colorspace(format->format.code); | |
| 1726 | 1738 | |
| 1727 | 1739 | return 0; |
| 1728 | 1740 | } |
| @@ -1736,19 +1748,14 @@ static int tc358743_set_fmt(struct v4l2_subdev *sd, · 7 unmodified lines | ||
| 1736 | 1748 | u32 code = format->format.code; /* is overwritten by get_fmt */ |
| 1737 | 1749 | int ret = tc358743_get_fmt(sd, sd_state, format); |
| 1738 | 1750 | |
| 1739 | − format->format.code = code; | |
| 1751 | + if (code == MEDIA_BUS_FMT_RGB888_1X24 || | |
| 1752 | + code == MEDIA_BUS_FMT_UYVY8_1X16) | |
| 1753 | + format->format.code = code; | |
| 1754 | + format->format.colorspace = tc358743_g_colorspace(format->format.code); | |
| 1740 | 1755 | |
| 1741 | 1756 | if (ret) |
| 1742 | 1757 | return ret; |
| 1743 | 1758 | |
| 1744 | − switch (code) { | |
| 1745 | − case MEDIA_BUS_FMT_RGB888_1X24: | |
| 1746 | − case MEDIA_BUS_FMT_UYVY8_1X16: | |
| 1747 | − break; | |
| 1748 | − default: | |
| 1749 | − return -EINVAL; | |
| 1750 | − } | |
| 1751 | − | |
| 1752 | 1759 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) |
| 1753 | 1760 | return 0; |
| 1754 | 1761 | |
| @@ -1972,8 +1979,19 @@ static int tc358743_probe_of(struct tc358743_state *state) · 217 unmodified lines | ||
| 1972 | 1979 | state->pdata.refclk_hz = clk_get_rate(refclk); |
| 1973 | 1980 | state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; |
| 1974 | 1981 | state->pdata.enable_hdcp = false; |
| 1975 | − /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ | |
| 1976 | − state->pdata.fifo_level = 16; | |
| 1982 | + /* | |
| 1983 | + * Ideally the FIFO trigger level should be set based on the input and | |
| 1984 | + * output data rates, but the calculations required are buried in | |
| 1985 | + * Toshiba's register settings spreadsheet. | |
| 1986 | + * A value of 16 works with a 594Mbps data rate for 720p60 (using 2 | |
| 1987 | + * lanes) and 1080p60 (using 4 lanes), but fails when the data rate | |
| 1988 | + * is increased, or a lower pixel clock is used that result in CSI | |
| 1989 | + * reading out faster than the data is arriving. | |
| 1990 | + * | |
| 1991 | + * A value of 374 works with both those modes at 594Mbps, and with most | |
| 1992 | + * modes on 972Mbps. | |
| 1993 | + */ | |
| 1994 | + state->pdata.fifo_level = 374; | |
| 1977 | 1995 | /* |
| 1978 | 1996 | * The PLL input clock is obtained by dividing refclk by pll_prd. |
| 1979 | 1997 | * It must be between 6 MHz and 40 MHz, lower frequency is better. |
| @@ -1993,6 +2011,7 @@ static int tc358743_probe_of(struct tc358743_state *state) · 13 unmodified lines | ||
| 1993 | 2011 | /* |
| 1994 | 2012 | * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. |
| 1995 | 2013 | * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. |
| 2014 | + * 972 Mbps allows 1080P50 UYVY over 2-lane. | |
| 1996 | 2015 | */ |
| 1997 | 2016 | bps_pr_lane = 2 * endpoint.link_frequencies[0]; |
| 1998 | 2017 | if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { |
| @@ -2006,23 +2025,42 @@ static int tc358743_probe_of(struct tc358743_state *state) · 7 unmodified lines | ||
| 2006 | 2025 | state->pdata.refclk_hz * state->pdata.pll_prd; |
| 2007 | 2026 | |
| 2008 | 2027 | /* |
| 2009 | − * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz | |
| 2010 | − * link frequency). In principle it should be possible to calculate | |
| 2028 | + * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane | |
| 2029 | + * (297 MHz or 486 MHz link frequency). | |
| 2030 | + * In principle it should be possible to calculate | |
| 2011 | 2031 | * them based on link frequency and resolution. |
| 2012 | 2032 | */ |
| 2013 | − if (bps_pr_lane != 594000000U) | |
| 2033 | + switch (bps_pr_lane) { | |
| 2034 | + default: | |
| 2014 | 2035 | dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); |
| 2015 | − state->pdata.lineinitcnt = 0xe80; | |
| 2016 | − state->pdata.lptxtimecnt = 0x003; | |
| 2017 | − /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ | |
| 2018 | − state->pdata.tclk_headercnt = 0x1403; | |
| 2019 | − state->pdata.tclk_trailcnt = 0x00; | |
| 2020 | − /* ths-preparecnt: 3, ths-zerocnt: 1 */ | |
| 2021 | − state->pdata.ths_headercnt = 0x0103; | |
| 2022 | − state->pdata.twakeup = 0x4882; | |
| 2023 | − state->pdata.tclk_postcnt = 0x008; | |
| 2024 | − state->pdata.ths_trailcnt = 0x2; | |
| 2025 | − state->pdata.hstxvregcnt = 0; | |
| 2036 | + fallthrough; | |
| 2037 | + case 594000000U: | |
| 2038 | + state->pdata.lineinitcnt = 0xe80; | |
| 2039 | + state->pdata.lptxtimecnt = 0x003; | |
| 2040 | + /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ | |
| 2041 | + state->pdata.tclk_headercnt = 0x1403; | |
| 2042 | + state->pdata.tclk_trailcnt = 0x00; | |
| 2043 | + /* ths-preparecnt: 3, ths-zerocnt: 1 */ | |
| 2044 | + state->pdata.ths_headercnt = 0x0103; | |
| 2045 | + state->pdata.twakeup = 0x4882; | |
| 2046 | + state->pdata.tclk_postcnt = 0x008; | |
| 2047 | + state->pdata.ths_trailcnt = 0x2; | |
| 2048 | + state->pdata.hstxvregcnt = 0; | |
| 2049 | + break; | |
| 2050 | + case 972000000U: | |
| 2051 | + state->pdata.lineinitcnt = 0x1b58; | |
| 2052 | + state->pdata.lptxtimecnt = 0x007; | |
| 2053 | + /* tclk-preparecnt: 6, tclk-zerocnt: 40 */ | |
| 2054 | + state->pdata.tclk_headercnt = 0x2806; | |
| 2055 | + state->pdata.tclk_trailcnt = 0x00; | |
| 2056 | + /* ths-preparecnt: 6, ths-zerocnt: 8 */ | |
| 2057 | + state->pdata.ths_headercnt = 0x0806; | |
| 2058 | + state->pdata.twakeup = 0x4268; | |
| 2059 | + state->pdata.tclk_postcnt = 0x008; | |
| 2060 | + state->pdata.ths_trailcnt = 0x5; | |
| 2061 | + state->pdata.hstxvregcnt = 0; | |
| 2062 | + break; | |
| 2063 | + } | |
| 2026 | 2064 | |
| 2027 | 2065 | state->reset_gpio = devm_gpiod_get_optional(dev, "reset", |
| 2028 | 2066 | GPIOD_OUT_LOW); |
| @@ -2061,6 +2099,7 @@ static int tc358743_probe(struct i2c_client *client) · 32 unmodified lines | ||
| 2061 | 2099 | struct tc358743_platform_data *pdata = client->dev.platform_data; |
| 2062 | 2100 | struct v4l2_subdev *sd; |
| 2063 | 2101 | u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; |
| 2102 | + u16 chipid; | |
| 2064 | 2103 | int err; |
| 2065 | 2104 | |
| 2066 | 2105 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
| @@ -2092,7 +2131,8 @@ static int tc358743_probe(struct i2c_client *client) · 25 unmodified lines | ||
| 2092 | 2131 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 2093 | 2132 | |
| 2094 | 2133 | /* i2c access */ |
| 2095 | − if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { | |
| 2134 | + if (i2c_rd16_err(sd, CHIPID, &chipid) || | |
| 2135 | + (chipid & MASK_CHIPID) != 0) { | |
| 2096 | 2136 | v4l2_info(sd, "not a TC358743 on address 0x%x\n", |
| 2097 | 2137 | client->addr << 1); |
| 2098 | 2138 | return -ENODEV; |
| @@ -589,8 +589,8 @@ static void tda1997x_enable_edid(struct v4l2_subdev *sd) · 588 unmodified lines | ||
| 589 | 589 | |
| 590 | 590 | v4l2_dbg(1, debug, sd, "%s\n", __func__); |
| 591 | 591 | |
| 592 | − /* Enable hotplug after 100ms */ | |
| 593 | − schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10); | |
| 592 | + /* Enable hotplug after 143ms */ | |
| 593 | + schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 7); | |
| 594 | 594 | } |
| 595 | 595 | |
| 596 | 596 | /* ----------------------------------------------------------------------------- |
| @@ -111,9 +111,9 @@ · 110 unmodified lines | ||
| 111 | 111 | |
| 112 | 112 | #define VD55G1_WIDTH 804 |
| 113 | 113 | #define VD55G1_HEIGHT 704 |
| 114 | −#define VD55G1_DEFAULT_MODE 0 | |
| 114 | +#define VD55G1_MODE_DEF 0 | |
| 115 | 115 | #define VD55G1_NB_GPIOS 4 |
| 116 | −#define VD55G1_MEDIA_BUS_FMT_DEF MEDIA_BUS_FMT_Y8_1X8 | |
| 116 | +#define VD55G1_MBUS_CODE_DEF 0 | |
| 117 | 117 | #define VD55G1_DGAIN_DEF 256 |
| 118 | 118 | #define VD55G1_AGAIN_DEF 19 |
| 119 | 119 | #define VD55G1_EXPO_MAX_TERM 64 |
| @@ -129,8 +129,8 @@ · 9 unmodified lines | ||
| 129 | 129 | #define VD55G1_FWPATCH_REVISION_MINOR 9 |
| 130 | 130 | #define VD55G1_XCLK_FREQ_MIN (6 * HZ_PER_MHZ) |
| 131 | 131 | #define VD55G1_XCLK_FREQ_MAX (27 * HZ_PER_MHZ) |
| 132 | −#define VD55G1_MIPI_RATE_MIN (250 * HZ_PER_MHZ) | |
| 133 | −#define VD55G1_MIPI_RATE_MAX (1200 * HZ_PER_MHZ) | |
| 132 | +#define VD55G1_MIPI_RATE_MIN (250 * MEGA) | |
| 133 | +#define VD55G1_MIPI_RATE_MAX (1200 * MEGA) | |
| 134 | 134 | |
| 135 | 135 | static const u8 patch_array[] = { |
| 136 | 136 | 0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, |
| @@ -883,10 +883,9 @@ static int vd55g1_apply_cold_start(struct vd55g1 *sensor, · 746 unmodified lines | ||
| 883 | 883 | return ret; |
| 884 | 884 | } |
| 885 | 885 | |
| 886 | −static void vd55g1_update_img_pad_format(struct vd55g1 *sensor, | |
| 887 | − const struct vd55g1_mode *mode, | |
| 888 | − u32 code, | |
| 889 | − struct v4l2_mbus_framefmt *fmt) | |
| 886 | +static void vd55g1_update_pad_fmt(struct vd55g1 *sensor, | |
| 887 | + const struct vd55g1_mode *mode, u32 code, | |
| 888 | + struct v4l2_mbus_framefmt *fmt) | |
| 890 | 889 | { |
| 891 | 890 | fmt->code = code; |
| 892 | 891 | fmt->width = mode->width; |
| @@ -1038,8 +1037,6 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd, · 145 unmodified lines | ||
| 1038 | 1037 | if (ret < 0) |
| 1039 | 1038 | return ret; |
| 1040 | 1039 | |
| 1041 | − vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret); | |
| 1042 | − | |
| 1043 | 1040 | /* Configure output */ |
| 1044 | 1041 | vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE, |
| 1045 | 1042 | sensor->mipi_rate, &ret); |
| @@ -1084,7 +1081,7 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd, · 38 unmodified lines | ||
| 1084 | 1081 | |
| 1085 | 1082 | err_rpm_put: |
| 1086 | 1083 | pm_runtime_put(sensor->dev); |
| 1087 | − return 0; | |
| 1084 | + return -EINVAL; | |
| 1088 | 1085 | } |
| 1089 | 1086 | |
| 1090 | 1087 | static int vd55g1_disable_streams(struct v4l2_subdev *sd, |
| @@ -1231,8 +1228,8 @@ static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd, · 140 unmodified lines | ||
| 1231 | 1228 | width, height, sd_fmt->format.width, |
| 1232 | 1229 | sd_fmt->format.height); |
| 1233 | 1230 | |
| 1234 | − vd55g1_update_img_pad_format(sensor, new_mode, sd_fmt->format.code, | |
| 1235 | − &sd_fmt->format); | |
| 1231 | + vd55g1_update_pad_fmt(sensor, new_mode, sd_fmt->format.code, | |
| 1232 | + &sd_fmt->format); | |
| 1236 | 1233 | |
| 1237 | 1234 | /* |
| 1238 | 1235 | * Use binning to maximize the crop rectangle size, and centre it in the |
| @@ -1262,7 +1259,6 @@ static int vd55g1_set_pad_fmt(struct v4l2_subdev *sd, · 23 unmodified lines | ||
| 1262 | 1259 | static int vd55g1_init_state(struct v4l2_subdev *sd, |
| 1263 | 1260 | struct v4l2_subdev_state *sd_state) |
| 1264 | 1261 | { |
| 1265 | − unsigned int def_mode = VD55G1_DEFAULT_MODE; | |
| 1266 | 1262 | struct vd55g1 *sensor = to_vd55g1(sd); |
| 1267 | 1263 | struct v4l2_subdev_format fmt = { 0 }; |
| 1268 | 1264 | struct v4l2_subdev_route routes[] = { |
| @@ -1279,8 +1275,9 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, · 10 unmodified lines | ||
| 1279 | 1275 | if (ret) |
| 1280 | 1276 | return ret; |
| 1281 | 1277 | |
| 1282 | − vd55g1_update_img_pad_format(sensor, &vd55g1_supported_modes[def_mode], | |
| 1283 | − VD55G1_MEDIA_BUS_FMT_DEF, &fmt.format); | |
| 1278 | + vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF], | |
| 1279 | + vd55g1_mbus_codes[VD55G1_MBUS_CODE_DEF].code, | |
| 1280 | + &fmt.format); | |
| 1284 | 1281 | |
| 1285 | 1282 | return vd55g1_set_pad_fmt(sd, sd_state, &fmt); |
| 1286 | 1283 | } |
| @@ -1613,6 +1610,9 @@ static int vd55g1_power_on(struct device *dev) · 326 unmodified lines | ||
| 1613 | 1610 | goto disable_clock; |
| 1614 | 1611 | } |
| 1615 | 1612 | |
| 1613 | + /* Setup clock now to advance through system FSM states */ | |
| 1614 | + vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret); | |
| 1615 | + | |
| 1616 | 1616 | ret = vd55g1_patch(sensor); |
| 1617 | 1617 | if (ret) { |
| 1618 | 1618 | dev_err(dev, "Sensor patch failed %d\n", ret); |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | 10 | |
| 11 | +#include <linux/bitops.h> | |
| 11 | 12 | #include "cx18-driver.h" |
| 12 | 13 | |
| 13 | 14 | /* |
| @@ -56,15 +57,6 @@ struct vbi_anc_data { · 42 unmodified lines | ||
| 56 | 57 | /* u8 fill[]; Variable number of fill bytes */ |
| 57 | 58 | }; |
| 58 | 59 | |
| 59 | −static int odd_parity(u8 c) | |
| 60 | −{ | |
| 61 | − c ^= (c >> 4); | |
| 62 | − c ^= (c >> 2); | |
| 63 | − c ^= (c >> 1); | |
| 64 | − | |
| 65 | − return c & 1; | |
| 66 | −} | |
| 67 | − | |
| 68 | 60 | static int decode_vps(u8 *dst, u8 *p) |
| 69 | 61 | { |
| 70 | 62 | static const u8 biphase_tbl[] = { |
| @@ -278,7 +270,7 @@ int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, · 207 unmodified lines | ||
| 278 | 270 | break; |
| 279 | 271 | case 6: |
| 280 | 272 | sdid = V4L2_SLICED_CAPTION_525; |
| 281 | − err = !odd_parity(p[0]) || !odd_parity(p[1]); | |
| 273 | + err = !parity8(p[0]) || !parity8(p[1]); | |
| 282 | 274 | break; |
| 283 | 275 | case 9: |
| 284 | 276 | sdid = V4L2_SLICED_VPS; |
| @@ -271,18 +271,6 @@ struct cx18_options { · 270 unmodified lines | ||
| 271 | 271 | #define CX18_SLICED_TYPE_WSS_625 (5) |
| 272 | 272 | #define CX18_SLICED_TYPE_VPS (7) |
| 273 | 273 | |
| 274 | −/** | |
| 275 | − * list_entry_is_past_end - check if a previous loop cursor is off list end | |
| 276 | − * @pos: the type * previously used as a loop cursor. | |
| 277 | − * @head: the head for your list. | |
| 278 | − * @member: the name of the list_head within the struct. | |
| 279 | − * | |
| 280 | − * Check if the entry's list_head is the head of the list, thus it's not a | |
| 281 | − * real entry but was the loop cursor that walked past the end | |
| 282 | − */ | |
| 283 | −#define list_entry_is_past_end(pos, head, member) \ | |
| 284 | − (&pos->member == (head)) | |
| 285 | − | |
| 286 | 274 | struct cx18_vb2_buffer { |
| 287 | 275 | /* Common video buffer sub-system struct */ |
| 288 | 276 | struct vb2_v4l2_buffer vb; |
| @@ -371,7 +371,7 @@ static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, · 370 unmodified lines | ||
| 371 | 371 | mdl->curr_buf = list_first_entry(&mdl->buf_list, |
| 372 | 372 | struct cx18_buffer, list); |
| 373 | 373 | |
| 374 | − if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { | |
| 374 | + if (list_entry_is_head(mdl->curr_buf, &mdl->buf_list, list)) { | |
| 375 | 375 | /* |
| 376 | 376 | * For some reason we've exhausted the buffers, but the MDL |
| 377 | 377 | * object still said some data was unread. |
| @@ -764,7 +764,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, · 763 unmodified lines | ||
| 764 | 764 | mdl->curr_buf = list_first_entry(&mdl->buf_list, |
| 765 | 765 | struct cx18_buffer, list); |
| 766 | 766 | |
| 767 | − if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { | |
| 767 | + if (list_entry_is_head(mdl->curr_buf, &mdl->buf_list, list)) { | |
| 768 | 768 | /* |
| 769 | 769 | * For some reason we've exhausted the buffers, but the MDL |
| 770 | 770 | * object still said some data was unread. |
| @@ -55,11 +55,15 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { · 54 unmodified lines | ||
| 55 | 55 | /* Himax HM2172 */ |
| 56 | 56 | IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000), |
| 57 | 57 | /* GalaxyCore GC0310 */ |
| 58 | − IPU_SENSOR_CONFIG("INT0310", 0), | |
| 58 | + IPU_SENSOR_CONFIG("INT0310", 1, 55692000), | |
| 59 | 59 | /* Omnivision OV5693 */ |
| 60 | 60 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), |
| 61 | + /* Onsemi MT9M114 */ | |
| 62 | + IPU_SENSOR_CONFIG("INT33F0", 1, 384000000), | |
| 61 | 63 | /* Omnivision OV2740 */ |
| 62 | 64 | IPU_SENSOR_CONFIG("INT3474", 1, 180000000), |
| 65 | + /* Omnivision OV5670 */ | |
| 66 | + IPU_SENSOR_CONFIG("INT3479", 1, 422400000), | |
| 63 | 67 | /* Omnivision OV8865 */ |
| 64 | 68 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), |
| 65 | 69 | /* Omnivision OV7251 */ |
| @@ -78,7 +82,7 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { · 12 unmodified lines | ||
| 78 | 82 | /* Omnivision OV08A10 */ |
| 79 | 83 | IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000), |
| 80 | 84 | /* Omnivision OV08x40 */ |
| 81 | − IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000), | |
| 85 | + IPU_SENSOR_CONFIG("OVTI08F4", 3, 400000000, 749000000, 800000000), | |
| 82 | 86 | /* Omnivision OV13B10 */ |
| 83 | 87 | IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000), |
| 84 | 88 | IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), |
| @@ -86,6 +90,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { · 1 unmodified line | ||
| 86 | 90 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), |
| 87 | 91 | /* Omnivision OV8856 */ |
| 88 | 92 | IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), |
| 93 | + /* Toshiba T4KA3 */ | |
| 94 | + IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), | |
| 89 | 95 | }; |
| 90 | 96 | |
| 91 | 97 | static const struct ipu_property_names prop_names = { |
| @@ -809,7 +815,8 @@ int ipu_bridge_init(struct device *dev, · 717 unmodified lines | ||
| 809 | 815 | return 0; |
| 810 | 816 | |
| 811 | 817 | if (!ipu_bridge_ivsc_is_ready()) |
| 812 | − return -EPROBE_DEFER; | |
| 818 | + return dev_err_probe(dev, -EPROBE_DEFER, | |
| 819 | + "waiting for IVSC to become ready\n"); | |
| 813 | 820 | |
| 814 | 821 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); |
| 815 | 822 | if (!bridge) |
| @@ -358,6 +358,8 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q) · 357 unmodified lines | ||
| 358 | 358 | static const int FBPT_WIDTH = DIV_ROUND_UP(CIO2_MAX_LOPS, |
| 359 | 359 | CIO2_FBPT_SUBENTRY_UNIT); |
| 360 | 360 | const u32 num_buffers1 = CIO2_MAX_BUFFERS - 1; |
| 361 | + struct v4l2_subdev_state *state; | |
| 362 | + const struct v4l2_mbus_framefmt *format; | |
| 361 | 363 | const struct ipu3_cio2_fmt *fmt; |
| 362 | 364 | void __iomem *const base = cio2->base; |
| 363 | 365 | u8 lanes, csi2bus = q->csi2.port; |
| @@ -365,7 +367,13 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q) · 1 unmodified line | ||
| 365 | 367 | struct cio2_csi2_timing timing = { 0 }; |
| 366 | 368 | int i, r; |
| 367 | 369 | |
| 368 | − fmt = cio2_find_format(NULL, &q->subdev_fmt.code); | |
| 370 | + state = v4l2_subdev_lock_and_get_active_state(&q->subdev); | |
| 371 | + format = v4l2_subdev_state_get_format(state, CIO2_PAD_SINK); | |
| 372 | + | |
| 373 | + fmt = cio2_find_format(NULL, &format->code); | |
| 374 | + | |
| 375 | + v4l2_subdev_unlock_state(state); | |
| 376 | + | |
| 369 | 377 | if (!fmt) |
| 370 | 378 | return -EINVAL; |
| 371 | 379 | |
| @@ -1194,9 +1202,9 @@ static int cio2_subdev_subscribe_event(struct v4l2_subdev *sd, · 822 unmodified lines | ||
| 1194 | 1202 | return v4l2_event_subscribe(fh, sub, 0, NULL); |
| 1195 | 1203 | } |
| 1196 | 1204 | |
| 1197 | −static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 1205 | +static int cio2_subdev_init_state(struct v4l2_subdev *sd, | |
| 1206 | + struct v4l2_subdev_state *state) | |
| 1198 | 1207 | { |
| 1199 | − struct v4l2_mbus_framefmt *format; | |
| 1200 | 1208 | const struct v4l2_mbus_framefmt fmt_default = { |
| 1201 | 1209 | .width = 1936, |
| 1202 | 1210 | .height = 1096, |
| @@ -1207,42 +1215,23 @@ static int cio2_subdev_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) · 4 unmodified lines | ||
| 1207 | 1215 | .quantization = V4L2_QUANTIZATION_DEFAULT, |
| 1208 | 1216 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, |
| 1209 | 1217 | }; |
| 1218 | + struct v4l2_mbus_framefmt *format; | |
| 1210 | 1219 | |
| 1211 | − /* Initialize try_fmt */ | |
| 1212 | − format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SINK); | |
| 1220 | + /* Initialize the format on the sink and source pads. */ | |
| 1221 | + format = v4l2_subdev_state_get_format(state, CIO2_PAD_SINK); | |
| 1213 | 1222 | *format = fmt_default; |
| 1214 | 1223 | |
| 1215 | 1224 | /* same as sink */ |
| 1216 | − format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SOURCE); | |
| 1225 | + format = v4l2_subdev_state_get_format(state, CIO2_PAD_SOURCE); | |
| 1217 | 1226 | *format = fmt_default; |
| 1218 | 1227 | |
| 1219 | 1228 | return 0; |
| 1220 | 1229 | } |
| 1221 | 1230 | |
| 1222 | −static int cio2_subdev_get_fmt(struct v4l2_subdev *sd, | |
| 1223 | − struct v4l2_subdev_state *sd_state, | |
| 1224 | − struct v4l2_subdev_format *fmt) | |
| 1225 | −{ | |
| 1226 | − struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); | |
| 1227 | − | |
| 1228 | − mutex_lock(&q->subdev_lock); | |
| 1229 | − | |
| 1230 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 1231 | − fmt->format = *v4l2_subdev_state_get_format(sd_state, | |
| 1232 | − fmt->pad); | |
| 1233 | − else | |
| 1234 | − fmt->format = q->subdev_fmt; | |
| 1235 | − | |
| 1236 | − mutex_unlock(&q->subdev_lock); | |
| 1237 | − | |
| 1238 | − return 0; | |
| 1239 | −} | |
| 1240 | − | |
| 1241 | 1231 | static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, |
| 1242 | 1232 | struct v4l2_subdev_state *sd_state, |
| 1243 | 1233 | struct v4l2_subdev_format *fmt) |
| 1244 | 1234 | { |
| 1245 | − struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); | |
| 1246 | 1235 | struct v4l2_mbus_framefmt *mbus; |
| 1247 | 1236 | u32 mbus_code = fmt->format.code; |
| 1248 | 1237 | unsigned int i; |
| @@ -1252,12 +1241,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, · 3 unmodified lines | ||
| 1252 | 1241 | * source always propagates from sink |
| 1253 | 1242 | */ |
| 1254 | 1243 | if (fmt->pad == CIO2_PAD_SOURCE) |
| 1255 | − return cio2_subdev_get_fmt(sd, sd_state, fmt); | |
| 1256 | − | |
| 1257 | − if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 1258 | − mbus = v4l2_subdev_state_get_format(sd_state, fmt->pad); | |
| 1259 | − else | |
| 1260 | − mbus = &q->subdev_fmt; | |
| 1244 | + return v4l2_subdev_get_fmt(sd, sd_state, fmt); | |
| 1261 | 1245 | |
| 1262 | 1246 | fmt->format.code = formats[0].mbus_code; |
| 1263 | 1247 | |
| @@ -1272,9 +1256,12 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, · 8 unmodified lines | ||
| 1272 | 1256 | fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT); |
| 1273 | 1257 | fmt->format.field = V4L2_FIELD_NONE; |
| 1274 | 1258 | |
| 1275 | − mutex_lock(&q->subdev_lock); | |
| 1259 | + mbus = v4l2_subdev_state_get_format(sd_state, CIO2_PAD_SINK); | |
| 1260 | + *mbus = fmt->format; | |
| 1261 | + | |
| 1262 | + /* Propagate the format to the source pad. */ | |
| 1263 | + mbus = v4l2_subdev_state_get_format(sd_state, CIO2_PAD_SOURCE); | |
| 1276 | 1264 | *mbus = fmt->format; |
| 1277 | − mutex_unlock(&q->subdev_lock); | |
| 1278 | 1265 | |
| 1279 | 1266 | return 0; |
| 1280 | 1267 | } |
| @@ -1345,12 +1332,12 @@ static const struct v4l2_subdev_core_ops cio2_subdev_core_ops = { · 64 unmodified lines | ||
| 1345 | 1332 | }; |
| 1346 | 1333 | |
| 1347 | 1334 | static const struct v4l2_subdev_internal_ops cio2_subdev_internal_ops = { |
| 1348 | − .open = cio2_subdev_open, | |
| 1335 | + .init_state = cio2_subdev_init_state, | |
| 1349 | 1336 | }; |
| 1350 | 1337 | |
| 1351 | 1338 | static const struct v4l2_subdev_pad_ops cio2_subdev_pad_ops = { |
| 1352 | 1339 | .link_validate = v4l2_subdev_link_validate_default, |
| 1353 | − .get_fmt = cio2_subdev_get_fmt, | |
| 1340 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 1354 | 1341 | .set_fmt = cio2_subdev_set_fmt, |
| 1355 | 1342 | .enum_mbus_code = cio2_subdev_enum_mbus_code, |
| 1356 | 1343 | }; |
| @@ -1502,28 +1489,18 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) · 145 unmodified lines | ||
| 1502 | 1489 | { |
| 1503 | 1490 | static const u32 default_width = 1936; |
| 1504 | 1491 | static const u32 default_height = 1096; |
| 1505 | − const struct ipu3_cio2_fmt dflt_fmt = formats[0]; | |
| 1506 | 1492 | struct device *dev = &cio2->pci_dev->dev; |
| 1507 | 1493 | struct video_device *vdev = &q->vdev; |
| 1508 | 1494 | struct vb2_queue *vbq = &q->vbq; |
| 1509 | 1495 | struct v4l2_subdev *subdev = &q->subdev; |
| 1510 | − struct v4l2_mbus_framefmt *fmt; | |
| 1511 | 1496 | int r; |
| 1512 | 1497 | |
| 1513 | 1498 | /* Initialize miscellaneous variables */ |
| 1514 | 1499 | mutex_init(&q->lock); |
| 1515 | − mutex_init(&q->subdev_lock); | |
| 1516 | − | |
| 1517 | − /* Initialize formats to default values */ | |
| 1518 | − fmt = &q->subdev_fmt; | |
| 1519 | − fmt->width = default_width; | |
| 1520 | − fmt->height = default_height; | |
| 1521 | − fmt->code = dflt_fmt.mbus_code; | |
| 1522 | − fmt->field = V4L2_FIELD_NONE; | |
| 1523 | 1500 | |
| 1524 | 1501 | q->format.width = default_width; |
| 1525 | 1502 | q->format.height = default_height; |
| 1526 | − q->format.pixelformat = dflt_fmt.fourcc; | |
| 1503 | + q->format.pixelformat = formats[0].fourcc; | |
| 1527 | 1504 | q->format.colorspace = V4L2_COLORSPACE_RAW; |
| 1528 | 1505 | q->format.field = V4L2_FIELD_NONE; |
| 1529 | 1506 | q->format.num_planes = 1; |
| @@ -1567,9 +1544,16 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) · 37 unmodified lines | ||
| 1567 | 1544 | CIO2_ENTITY_NAME " %td", q - cio2->queue); |
| 1568 | 1545 | subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; |
| 1569 | 1546 | v4l2_set_subdevdata(subdev, cio2); |
| 1547 | + | |
| 1548 | + r = v4l2_subdev_init_finalize(subdev); | |
| 1549 | + if (r) { | |
| 1550 | + dev_err(dev, "failed to initialize subdev (%d)\n", r); | |
| 1551 | + goto fail_subdev; | |
| 1552 | + } | |
| 1553 | + | |
| 1570 | 1554 | r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); |
| 1571 | 1555 | if (r) { |
| 1572 | − dev_err(dev, "failed initialize subdev (%d)\n", r); | |
| 1556 | + dev_err(dev, "failed to register subdev (%d)\n", r); | |
| 1573 | 1557 | goto fail_subdev; |
| 1574 | 1558 | } |
| 1575 | 1559 | |
| @@ -1626,7 +1610,6 @@ fail_vdev_media_entity: · 50 unmodified lines | ||
| 1626 | 1610 | fail_subdev_media_entity: |
| 1627 | 1611 | cio2_fbpt_exit(q, dev); |
| 1628 | 1612 | fail_fbpt: |
| 1629 | − mutex_destroy(&q->subdev_lock); | |
| 1630 | 1613 | mutex_destroy(&q->lock); |
| 1631 | 1614 | |
| 1632 | 1615 | return r; |
| @@ -1639,7 +1622,6 @@ static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q) · 6 unmodified lines | ||
| 1639 | 1622 | v4l2_device_unregister_subdev(&q->subdev); |
| 1640 | 1623 | media_entity_cleanup(&q->subdev.entity); |
| 1641 | 1624 | cio2_fbpt_exit(q, &cio2->pci_dev->dev); |
| 1642 | − mutex_destroy(&q->subdev_lock); | |
| 1643 | 1625 | mutex_destroy(&q->lock); |
| 1644 | 1626 | } |
| 1645 | 1627 | |
| @@ -351,9 +351,7 @@ struct cio2_queue { · 350 unmodified lines | ||
| 351 | 351 | |
| 352 | 352 | /* Subdev, /dev/v4l-subdevX */ |
| 353 | 353 | struct v4l2_subdev subdev; |
| 354 | − struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */ | |
| 355 | 354 | struct media_pad subdev_pads[CIO2_PADS]; |
| 356 | − struct v4l2_mbus_framefmt subdev_fmt; | |
| 357 | 355 | atomic_t frame_sequence; |
| 358 | 356 | |
| 359 | 357 | /* Video device, /dev/videoX */ |
| @@ -354,9 +354,9 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd, · 353 unmodified lines | ||
| 354 | 354 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); |
| 355 | 355 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); |
| 356 | 356 | |
| 357 | − sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC, | |
| 358 | − CSI2_PAD_SINK, | |
| 359 | − &streams_mask); | |
| 357 | + sink_streams = | |
| 358 | + v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK, | |
| 359 | + &streams_mask); | |
| 360 | 360 | |
| 361 | 361 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); |
| 362 | 362 | if (ret) |
| @@ -384,9 +384,9 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd, · 21 unmodified lines | ||
| 384 | 384 | struct media_pad *remote_pad; |
| 385 | 385 | u64 sink_streams; |
| 386 | 386 | |
| 387 | − sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC, | |
| 388 | − CSI2_PAD_SINK, | |
| 389 | − &streams_mask); | |
| 387 | + sink_streams = | |
| 388 | + v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK, | |
| 389 | + &streams_mask); | |
| 390 | 390 | |
| 391 | 391 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); |
| 392 | 392 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); |
| @@ -40,7 +40,7 @@ struct ipu6_bus_device; · 39 unmodified lines | ||
| 40 | 40 | #define IPU6_ISYS_NUM_RECV_QUEUE 1 |
| 41 | 41 | |
| 42 | 42 | #define IPU6_ISYS_MIN_WIDTH 2U |
| 43 | −#define IPU6_ISYS_MIN_HEIGHT 2U | |
| 43 | +#define IPU6_ISYS_MIN_HEIGHT 1U | |
| 44 | 44 | #define IPU6_ISYS_MAX_WIDTH 4672U |
| 45 | 45 | #define IPU6_ISYS_MAX_HEIGHT 3416U |
| 46 | 46 | |
| @@ -529,6 +529,8 @@ static void mei_ace_remove(struct mei_cl_device *cldev) · 528 unmodified lines | ||
| 529 | 529 | |
| 530 | 530 | ace_set_camera_owner(ace, ACE_CAMERA_IVSC); |
| 531 | 531 | |
| 532 | + mei_cldev_disable(cldev); | |
| 533 | + | |
| 532 | 534 | mutex_destroy(&ace->lock); |
| 533 | 535 | } |
| 534 | 536 | |
| @@ -574,7 +576,7 @@ static struct mei_cl_driver mei_ace_driver = { · 39 unmodified lines | ||
| 574 | 576 | |
| 575 | 577 | module_mei_cl_driver(mei_ace_driver); |
| 576 | 578 | |
| 577 | −MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); | |
| 579 | +MODULE_AUTHOR("Wentong Wu"); | |
| 578 | 580 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); |
| 579 | 581 | MODULE_DESCRIPTION("Device driver for IVSC ACE"); |
| 580 | 582 | MODULE_LICENSE("GPL"); |
| @@ -760,6 +760,8 @@ static void mei_csi_remove(struct mei_cl_device *cldev) · 759 unmodified lines | ||
| 760 | 760 | |
| 761 | 761 | pm_runtime_disable(&cldev->dev); |
| 762 | 762 | |
| 763 | + mei_cldev_disable(cldev); | |
| 764 | + | |
| 763 | 765 | mutex_destroy(&csi->lock); |
| 764 | 766 | } |
| 765 | 767 | |
| @@ -783,7 +785,7 @@ static struct mei_cl_driver mei_csi_driver = { · 17 unmodified lines | ||
| 783 | 785 | module_mei_cl_driver(mei_csi_driver); |
| 784 | 786 | |
| 785 | 787 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); |
| 786 | −MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); | |
| 788 | +MODULE_AUTHOR("Wentong Wu"); | |
| 787 | 789 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); |
| 788 | 790 | MODULE_DESCRIPTION("Device driver for IVSC CSI"); |
| 789 | 791 | MODULE_LICENSE("GPL"); |
| @@ -492,7 +492,14 @@ static int vidioc_s_dv_timings(struct file *file, void *fh, · 491 unmodified lines | ||
| 492 | 492 | static int vidioc_enum_dv_timings(struct file *file, void *fh, |
| 493 | 493 | struct v4l2_enum_dv_timings *timings) |
| 494 | 494 | { |
| 495 | − return v4l2_enum_dv_timings_cap(timings, &video_timings_cap, NULL, NULL); | |
| 495 | + struct mgb4_vout_dev *voutdev = video_drvdata(file); | |
| 496 | + | |
| 497 | + if (timings->index != 0) | |
| 498 | + return -EINVAL; | |
| 499 | + | |
| 500 | + get_timings(voutdev, &timings->timings); | |
| 501 | + | |
| 502 | + return 0; | |
| 496 | 503 | } |
| 497 | 504 | |
| 498 | 505 | static int vidioc_dv_timings_cap(struct file *file, void *fh, |
| @@ -52,26 +52,6 @@ · 51 unmodified lines | ||
| 52 | 52 | * | etc |
| 53 | 53 | */ |
| 54 | 54 | |
| 55 | −void saa7164_buffer_display(struct saa7164_buffer *buf) | |
| 56 | −{ | |
| 57 | − struct saa7164_dev *dev = buf->port->dev; | |
| 58 | − int i; | |
| 59 | − | |
| 60 | − dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n", | |
| 61 | − __func__, buf, buf->idx); | |
| 62 | − dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n", | |
| 63 | − buf->cpu, (long long)buf->dma, buf->pci_size); | |
| 64 | − dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n", | |
| 65 | − buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size); | |
| 66 | − | |
| 67 | − /* Format the Page Table Entries to point into the data buffer */ | |
| 68 | − for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) { | |
| 69 | − | |
| 70 | − dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n", | |
| 71 | − i, buf->pt_cpu, (u64)*(buf->pt_cpu)); | |
| 72 | − | |
| 73 | − } | |
| 74 | −} | |
| 75 | 55 | /* Allocate a new buffer structure and associated PCI space in bytes. |
| 76 | 56 | * len must be a multiple of sizeof(u64) |
| 77 | 57 | */ |
| @@ -295,34 +295,6 @@ static int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) · 294 unmodified lines | ||
| 295 | 295 | return ret; |
| 296 | 296 | } |
| 297 | 297 | |
| 298 | −void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno) | |
| 299 | −{ | |
| 300 | − int i; | |
| 301 | − dprintk(DBGLVL_CMD, "%s()\n", __func__); | |
| 302 | − | |
| 303 | − mutex_lock(&dev->lock); | |
| 304 | − for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | |
| 305 | − if (dev->cmds[i].inuse == 1) { | |
| 306 | − dprintk(DBGLVL_CMD, | |
| 307 | − "seqno %d inuse, sig = %d, t/out = %d\n", | |
| 308 | − dev->cmds[i].seqno, | |
| 309 | − dev->cmds[i].signalled, | |
| 310 | − dev->cmds[i].timeout); | |
| 311 | − } | |
| 312 | − } | |
| 313 | − | |
| 314 | − for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) { | |
| 315 | − if ((dev->cmds[i].inuse == 1) && ((i == 0) || | |
| 316 | − (dev->cmds[i].signalled) || (dev->cmds[i].timeout))) { | |
| 317 | − dprintk(DBGLVL_CMD, "%s(seqno=%d) calling wake_up\n", | |
| 318 | − __func__, i); | |
| 319 | − dev->cmds[i].signalled = 1; | |
| 320 | − wake_up(&dev->cmds[i].wait); | |
| 321 | − } | |
| 322 | − } | |
| 323 | − mutex_unlock(&dev->lock); | |
| 324 | −} | |
| 325 | − | |
| 326 | 298 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, |
| 327 | 299 | u16 controlselector, u16 size, void *buf) |
| 328 | 300 | { |
| @@ -508,7 +508,6 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, · 507 unmodified lines | ||
| 508 | 508 | int saa7164_cmd_send(struct saa7164_dev *dev, |
| 509 | 509 | u8 id, enum tmComResCmd command, u16 controlselector, |
| 510 | 510 | u16 size, void *buf); |
| 511 | −void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); | |
| 512 | 511 | int saa7164_irq_dequeue(struct saa7164_dev *dev); |
| 513 | 512 | |
| 514 | 513 | /* ----------------------------------------------------------- */ |
| @@ -570,7 +569,6 @@ extern int saa7164_dvb_unregister(struct saa7164_port *port); · 55 unmodified lines | ||
| 570 | 569 | extern struct saa7164_buffer *saa7164_buffer_alloc( |
| 571 | 570 | struct saa7164_port *port, u32 len); |
| 572 | 571 | extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf); |
| 573 | −extern void saa7164_buffer_display(struct saa7164_buffer *buf); | |
| 574 | 572 | extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i); |
| 575 | 573 | extern int saa7164_buffer_cfg_port(struct saa7164_port *port); |
| 576 | 574 | extern struct saa7164_user_buffer *saa7164_buffer_alloc_user( |
| @@ -116,18 +116,6 @@ static int solo_gpiochip_get_direction(struct gpio_chip *chip, · 115 unmodified lines | ||
| 116 | 116 | return -1; |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | −static int solo_gpiochip_direction_input(struct gpio_chip *chip, | |
| 120 | − unsigned int offset) | |
| 121 | −{ | |
| 122 | − return -1; | |
| 123 | −} | |
| 124 | − | |
| 125 | −static int solo_gpiochip_direction_output(struct gpio_chip *chip, | |
| 126 | − unsigned int offset, int value) | |
| 127 | −{ | |
| 128 | − return -1; | |
| 129 | −} | |
| 130 | − | |
| 131 | 119 | static int solo_gpiochip_get(struct gpio_chip *chip, |
| 132 | 120 | unsigned int offset) |
| 133 | 121 | { |
| @@ -139,8 +127,8 @@ static int solo_gpiochip_get(struct gpio_chip *chip, · 5 unmodified lines | ||
| 139 | 127 | return 1 & (ret >> (offset + 8)); |
| 140 | 128 | } |
| 141 | 129 | |
| 142 | −static void solo_gpiochip_set(struct gpio_chip *chip, | |
| 143 | − unsigned int offset, int value) | |
| 130 | +static int solo_gpiochip_set(struct gpio_chip *chip, | |
| 131 | + unsigned int offset, int value) | |
| 144 | 132 | { |
| 145 | 133 | struct solo_dev *solo_dev = gpiochip_get_data(chip); |
| 146 | 134 | |
| @@ -148,6 +136,8 @@ static void solo_gpiochip_set(struct gpio_chip *chip, · 1 unmodified line | ||
| 148 | 136 | solo_gpio_set(solo_dev, 1 << (offset + 8)); |
| 149 | 137 | else |
| 150 | 138 | solo_gpio_clear(solo_dev, 1 << (offset + 8)); |
| 139 | + | |
| 140 | + return 0; | |
| 151 | 141 | } |
| 152 | 142 | #endif |
| 153 | 143 | |
| @@ -167,10 +157,8 @@ int solo_gpio_init(struct solo_dev *solo_dev) · 13 unmodified lines | ||
| 167 | 157 | solo_dev->gpio_dev.can_sleep = 0; |
| 168 | 158 | |
| 169 | 159 | solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction; |
| 170 | − solo_dev->gpio_dev.direction_input = solo_gpiochip_direction_input; | |
| 171 | − solo_dev->gpio_dev.direction_output = solo_gpiochip_direction_output; | |
| 172 | 160 | solo_dev->gpio_dev.get = solo_gpiochip_get; |
| 173 | − solo_dev->gpio_dev.set = solo_gpiochip_set; | |
| 161 | + solo_dev->gpio_dev.set_rv = solo_gpiochip_set; | |
| 174 | 162 | |
| 175 | 163 | ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); |
| 176 | 164 | |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include "vpu_cmds.h" |
| 27 | 27 | #include "vpu_rpc.h" |
| 28 | 28 | |
| 29 | +#define VDEC_SLOT_CNT_DFT 32 | |
| 29 | 30 | #define VDEC_MIN_BUFFER_CAP 8 |
| 30 | 31 | #define VDEC_MIN_BUFFER_OUT 8 |
| 31 | 32 | |
| @@ -41,6 +42,14 @@ struct vdec_fs_info { · 9 unmodified lines | ||
| 41 | 42 | u32 tag; |
| 42 | 43 | }; |
| 43 | 44 | |
| 45 | +struct vdec_frame_store_t { | |
| 46 | + struct vpu_vb2_buffer *curr; | |
| 47 | + struct vpu_vb2_buffer *pend; | |
| 48 | + dma_addr_t addr; | |
| 49 | + unsigned int state; | |
| 50 | + u32 tag; | |
| 51 | +}; | |
| 52 | + | |
| 44 | 53 | struct vdec_t { |
| 45 | 54 | u32 seq_hdr_found; |
| 46 | 55 | struct vpu_buffer udata; |
| @@ -48,7 +57,8 @@ struct vdec_t { · 1 unmodified line | ||
| 48 | 57 | struct vpu_dec_codec_info codec_info; |
| 49 | 58 | enum vpu_codec_state state; |
| 50 | 59 | |
| 51 | − struct vpu_vb2_buffer *slots[VB2_MAX_FRAME]; | |
| 60 | + struct vdec_frame_store_t *slots; | |
| 61 | + u32 slot_count; | |
| 52 | 62 | u32 req_frame_count; |
| 53 | 63 | struct vdec_fs_info mbi; |
| 54 | 64 | struct vdec_fs_info dcp; |
| @@ -232,6 +242,35 @@ static int vdec_ctrl_init(struct vpu_inst *inst) · 177 unmodified lines | ||
| 232 | 242 | V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, |
| 233 | 243 | 0, 1, 1, 0); |
| 234 | 244 | |
| 245 | + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, | |
| 246 | + V4L2_CID_MPEG_VIDEO_H264_PROFILE, | |
| 247 | + V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, | |
| 248 | + ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | | |
| 249 | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | | |
| 250 | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | |
| 251 | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED) | | |
| 252 | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), | |
| 253 | + V4L2_MPEG_VIDEO_H264_PROFILE_MAIN); | |
| 254 | + | |
| 255 | + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, | |
| 256 | + V4L2_CID_MPEG_VIDEO_H264_LEVEL, | |
| 257 | + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, | |
| 258 | + 0, | |
| 259 | + V4L2_MPEG_VIDEO_H264_LEVEL_4_0); | |
| 260 | + | |
| 261 | + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, | |
| 262 | + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, | |
| 263 | + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, | |
| 264 | + ~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | | |
| 265 | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)), | |
| 266 | + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); | |
| 267 | + | |
| 268 | + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, NULL, | |
| 269 | + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, | |
| 270 | + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, | |
| 271 | + 0, | |
| 272 | + V4L2_MPEG_VIDEO_HEVC_LEVEL_4); | |
| 273 | + | |
| 235 | 274 | ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, |
| 236 | 275 | V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2); |
| 237 | 276 | if (ctrl) |
| @@ -258,6 +297,63 @@ static int vdec_ctrl_init(struct vpu_inst *inst) · 20 unmodified lines | ||
| 258 | 297 | return 0; |
| 259 | 298 | } |
| 260 | 299 | |
| 300 | +static void vdec_attach_frame_store(struct vpu_inst *inst, struct vb2_buffer *vb) | |
| 301 | +{ | |
| 302 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 303 | + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 304 | + struct vdec_t *vdec = inst->priv; | |
| 305 | + struct vdec_frame_store_t *new_slots = NULL; | |
| 306 | + dma_addr_t addr; | |
| 307 | + int i; | |
| 308 | + | |
| 309 | + addr = vpu_get_vb_phy_addr(vb, 0); | |
| 310 | + for (i = 0; i < vdec->slot_count; i++) { | |
| 311 | + if (addr == vdec->slots[i].addr) { | |
| 312 | + if (vdec->slots[i].curr && vdec->slots[i].curr != vpu_buf) { | |
| 313 | + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED); | |
| 314 | + vdec->slots[i].pend = vpu_buf; | |
| 315 | + } else { | |
| 316 | + vpu_set_buffer_state(vbuf, vdec->slots[i].state); | |
| 317 | + } | |
| 318 | + vpu_buf->fs_id = i; | |
| 319 | + return; | |
| 320 | + } | |
| 321 | + } | |
| 322 | + | |
| 323 | + for (i = 0; i < vdec->slot_count; i++) { | |
| 324 | + if (!vdec->slots[i].addr) { | |
| 325 | + vdec->slots[i].addr = addr; | |
| 326 | + vpu_buf->fs_id = i; | |
| 327 | + return; | |
| 328 | + } | |
| 329 | + } | |
| 330 | + | |
| 331 | + new_slots = krealloc_array(vdec->slots, vdec->slot_count * 2, | |
| 332 | + sizeof(*vdec->slots), | |
| 333 | + GFP_KERNEL | __GFP_ZERO); | |
| 334 | + if (!new_slots) { | |
| 335 | + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_ERROR); | |
| 336 | + return; | |
| 337 | + } | |
| 338 | + | |
| 339 | + vdec->slots = new_slots; | |
| 340 | + vdec->slot_count *= 2; | |
| 341 | + | |
| 342 | + vdec->slots[i].addr = addr; | |
| 343 | + vpu_buf->fs_id = i; | |
| 344 | +} | |
| 345 | + | |
| 346 | +static void vdec_reset_frame_store(struct vpu_inst *inst) | |
| 347 | +{ | |
| 348 | + struct vdec_t *vdec = inst->priv; | |
| 349 | + | |
| 350 | + if (!vdec->slots || !vdec->slot_count) | |
| 351 | + return; | |
| 352 | + | |
| 353 | + vpu_trace(inst->dev, "inst[%d] reset slots\n", inst->id); | |
| 354 | + memset(vdec->slots, 0, sizeof(*vdec->slots) * vdec->slot_count); | |
| 355 | +} | |
| 356 | + | |
| 261 | 357 | static void vdec_handle_resolution_change(struct vpu_inst *inst) |
| 262 | 358 | { |
| 263 | 359 | struct vdec_t *vdec = inst->priv; |
| @@ -714,11 +810,11 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) · 450 unmodified lines | ||
| 714 | 810 | struct vb2_v4l2_buffer *src_buf; |
| 715 | 811 | int ret = 0; |
| 716 | 812 | |
| 717 | − if (!info || info->id >= ARRAY_SIZE(vdec->slots)) | |
| 813 | + if (!info || info->id >= vdec->slot_count) | |
| 718 | 814 | return -EINVAL; |
| 719 | 815 | |
| 720 | 816 | vpu_inst_lock(inst); |
| 721 | − vpu_buf = vdec->slots[info->id]; | |
| 817 | + vpu_buf = vdec->slots[info->id].curr; | |
| 722 | 818 | if (!vpu_buf) { |
| 723 | 819 | dev_err(inst->dev, "[%d] decoded invalid frame[%d]\n", inst->id, info->id); |
| 724 | 820 | ret = -EINVAL; |
| @@ -739,11 +835,13 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) · 14 unmodified lines | ||
| 739 | 835 | if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) |
| 740 | 836 | dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); |
| 741 | 837 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); |
| 838 | + vdec->slots[info->id].state = VPU_BUF_STATE_DECODED; | |
| 742 | 839 | vdec->decoded_frame_count++; |
| 743 | 840 | if (vdec->params.display_delay_enable) { |
| 744 | 841 | struct vpu_format *cur_fmt; |
| 745 | 842 | |
| 746 | 843 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); |
| 844 | + vdec->slots[info->id].state = VPU_BUF_STATE_READY; | |
| 747 | 845 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); |
| 748 | 846 | for (int i = 0; i < vbuf->vb2_buf.num_planes; i++) |
| 749 | 847 | vb2_set_plane_payload(&vbuf->vb2_buf, |
| @@ -766,11 +864,11 @@ static struct vpu_vb2_buffer *vdec_find_buffer(struct vpu_inst *inst, u32 luma) · 16 unmodified lines | ||
| 766 | 864 | struct vdec_t *vdec = inst->priv; |
| 767 | 865 | int i; |
| 768 | 866 | |
| 769 | − for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { | |
| 770 | − if (!vdec->slots[i]) | |
| 867 | + for (i = 0; i < vdec->slot_count; i++) { | |
| 868 | + if (!vdec->slots[i].curr) | |
| 771 | 869 | continue; |
| 772 | − if (luma == vdec->slots[i]->luma) | |
| 773 | − return vdec->slots[i]; | |
| 870 | + if (luma == vdec->slots[i].addr) | |
| 871 | + return vdec->slots[i].curr; | |
| 774 | 872 | } |
| 775 | 873 | |
| 776 | 874 | return NULL; |
| @@ -804,11 +902,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) · 27 unmodified lines | ||
| 804 | 902 | |
| 805 | 903 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); |
| 806 | 904 | vbuf = &vpu_buf->m2m_buf.vb; |
| 807 | − if (vbuf->vb2_buf.index != frame->id) | |
| 808 | − dev_err(inst->dev, "[%d] buffer id(%d, %d) mismatch\n", | |
| 809 | − inst->id, vbuf->vb2_buf.index, frame->id); | |
| 905 | + if (vpu_buf->fs_id != frame->id) | |
| 906 | + dev_err(inst->dev, "[%d] buffer id(%d(%d), %d) mismatch\n", | |
| 907 | + inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index, frame->id); | |
| 810 | 908 | |
| 811 | − if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_READY && vdec->params.display_delay_enable) | |
| 909 | + if (vdec->params.display_delay_enable) | |
| 812 | 910 | return; |
| 813 | 911 | |
| 814 | 912 | if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED) |
| @@ -821,10 +919,11 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) · 6 unmodified lines | ||
| 821 | 919 | vbuf->sequence = vdec->sequence; |
| 822 | 920 | dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); |
| 823 | 921 | |
| 824 | − v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); | |
| 825 | 922 | vpu_inst_lock(inst); |
| 923 | + vdec->slots[vpu_buf->fs_id].state = VPU_BUF_STATE_READY; | |
| 826 | 924 | vdec->display_frame_count++; |
| 827 | 925 | vpu_inst_unlock(inst); |
| 926 | + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); | |
| 828 | 927 | dev_dbg(inst->dev, "[%d] decoded : %d, display : %d, sequence : %d\n", |
| 829 | 928 | inst->id, vdec->decoded_frame_count, vdec->display_frame_count, vdec->sequence); |
| 830 | 929 | } |
| @@ -1052,18 +1151,30 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb · 221 unmodified lines | ||
| 1052 | 1151 | if (!vbuf) |
| 1053 | 1152 | return -EINVAL; |
| 1054 | 1153 | |
| 1055 | − if (vdec->slots[vbuf->vb2_buf.index]) { | |
| 1056 | − dev_err(inst->dev, "[%d] repeat alloc fs %d\n", | |
| 1057 | − inst->id, vbuf->vb2_buf.index); | |
| 1154 | + vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 1155 | + if (vpu_buf->fs_id < 0 || vpu_buf->fs_id >= vdec->slot_count) { | |
| 1156 | + dev_err(inst->dev, "invalid fs %d for v4l2 buffer %d\n", | |
| 1157 | + vpu_buf->fs_id, vbuf->vb2_buf.index); | |
| 1058 | 1158 | return -EINVAL; |
| 1059 | 1159 | } |
| 1060 | 1160 | |
| 1161 | + if (vdec->slots[vpu_buf->fs_id].curr) { | |
| 1162 | + if (vdec->slots[vpu_buf->fs_id].curr != vpu_buf) { | |
| 1163 | + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_CHANGED); | |
| 1164 | + vdec->slots[vpu_buf->fs_id].pend = vpu_buf; | |
| 1165 | + } else { | |
| 1166 | + vpu_set_buffer_state(vbuf, vdec->slots[vpu_buf->fs_id].state); | |
| 1167 | + } | |
| 1168 | + dev_err(inst->dev, "[%d] repeat alloc fs %d (v4l2 index %d)\n", | |
| 1169 | + inst->id, vpu_buf->fs_id, vbuf->vb2_buf.index); | |
| 1170 | + return -EAGAIN; | |
| 1171 | + } | |
| 1172 | + | |
| 1061 | 1173 | dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n", |
| 1062 | 1174 | inst->id, vpu_codec_state_name(inst->state), vbuf->vb2_buf.index, vdec->seq_tag); |
| 1063 | − vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 1064 | 1175 | |
| 1065 | 1176 | memset(&info, 0, sizeof(info)); |
| 1066 | − info.id = vbuf->vb2_buf.index; | |
| 1177 | + info.id = vpu_buf->fs_id; | |
| 1067 | 1178 | info.type = MEM_RES_FRAME; |
| 1068 | 1179 | info.tag = vdec->seq_tag; |
| 1069 | 1180 | info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0); |
| @@ -1078,12 +1189,13 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb · 8 unmodified lines | ||
| 1078 | 1189 | if (ret) |
| 1079 | 1190 | return ret; |
| 1080 | 1191 | |
| 1081 | − vpu_buf->tag = info.tag; | |
| 1082 | 1192 | vpu_buf->luma = info.luma_addr; |
| 1083 | 1193 | vpu_buf->chroma_u = info.chroma_addr; |
| 1084 | 1194 | vpu_buf->chroma_v = 0; |
| 1085 | 1195 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); |
| 1086 | − vdec->slots[info.id] = vpu_buf; | |
| 1196 | + vdec->slots[info.id].tag = info.tag; | |
| 1197 | + vdec->slots[info.id].curr = vpu_buf; | |
| 1198 | + vdec->slots[info.id].state = VPU_BUF_STATE_INUSE; | |
| 1087 | 1199 | vdec->req_frame_count--; |
| 1088 | 1200 | |
| 1089 | 1201 | return 0; |
| @@ -1144,25 +1256,76 @@ static void vdec_recycle_buffer(struct vpu_inst *inst, struct vb2_v4l2_buffer *v · 54 unmodified lines | ||
| 1144 | 1256 | v4l2_m2m_buf_queue(inst->fh.m2m_ctx, vbuf); |
| 1145 | 1257 | } |
| 1146 | 1258 | |
| 1147 | −static void vdec_clear_slots(struct vpu_inst *inst) | |
| 1259 | +static void vdec_release_curr_frame_store(struct vpu_inst *inst, u32 id) | |
| 1148 | 1260 | { |
| 1149 | 1261 | struct vdec_t *vdec = inst->priv; |
| 1150 | 1262 | struct vpu_vb2_buffer *vpu_buf; |
| 1151 | 1263 | struct vb2_v4l2_buffer *vbuf; |
| 1264 | + | |
| 1265 | + if (id >= vdec->slot_count) | |
| 1266 | + return; | |
| 1267 | + if (!vdec->slots[id].curr) | |
| 1268 | + return; | |
| 1269 | + | |
| 1270 | + vpu_buf = vdec->slots[id].curr; | |
| 1271 | + vbuf = &vpu_buf->m2m_buf.vb; | |
| 1272 | + | |
| 1273 | + vdec_response_fs_release(inst, id, vdec->slots[id].tag); | |
| 1274 | + if (vpu_buf->fs_id == id) { | |
| 1275 | + if (vpu_buf->state != VPU_BUF_STATE_READY) | |
| 1276 | + vdec_recycle_buffer(inst, vbuf); | |
| 1277 | + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); | |
| 1278 | + } | |
| 1279 | + | |
| 1280 | + vdec->slots[id].curr = NULL; | |
| 1281 | + vdec->slots[id].state = VPU_BUF_STATE_IDLE; | |
| 1282 | + | |
| 1283 | + if (vdec->slots[id].pend) { | |
| 1284 | + vpu_set_buffer_state(&vdec->slots[id].pend->m2m_buf.vb, VPU_BUF_STATE_IDLE); | |
| 1285 | + vdec->slots[id].pend = NULL; | |
| 1286 | + } | |
| 1287 | +} | |
| 1288 | + | |
| 1289 | +static void vdec_clear_slots(struct vpu_inst *inst) | |
| 1290 | +{ | |
| 1291 | + struct vdec_t *vdec = inst->priv; | |
| 1152 | 1292 | int i; |
| 1153 | 1293 | |
| 1154 | − for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { | |
| 1155 | − if (!vdec->slots[i]) | |
| 1294 | + for (i = 0; i < vdec->slot_count; i++) { | |
| 1295 | + if (!vdec->slots[i].curr) | |
| 1156 | 1296 | continue; |
| 1157 | 1297 | |
| 1158 | − vpu_buf = vdec->slots[i]; | |
| 1159 | − vbuf = &vpu_buf->m2m_buf.vb; | |
| 1160 | − | |
| 1161 | 1298 | vpu_trace(inst->dev, "clear slot %d\n", i); |
| 1162 | − vdec_response_fs_release(inst, i, vpu_buf->tag); | |
| 1163 | − vdec_recycle_buffer(inst, vbuf); | |
| 1164 | − vdec->slots[i]->state = VPU_BUF_STATE_IDLE; | |
| 1165 | − vdec->slots[i] = NULL; | |
| 1299 | + vdec_release_curr_frame_store(inst, i); | |
| 1300 | + } | |
| 1301 | +} | |
| 1302 | + | |
| 1303 | +static void vdec_update_v4l2_ctrl(struct vpu_inst *inst, u32 id, u32 val) | |
| 1304 | +{ | |
| 1305 | + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id); | |
| 1306 | + | |
| 1307 | + if (ctrl) | |
| 1308 | + v4l2_ctrl_s_ctrl(ctrl, val); | |
| 1309 | +} | |
| 1310 | + | |
| 1311 | +static void vdec_update_v4l2_profile_level(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr) | |
| 1312 | +{ | |
| 1313 | + switch (inst->out_format.pixfmt) { | |
| 1314 | + case V4L2_PIX_FMT_H264: | |
| 1315 | + case V4L2_PIX_FMT_H264_MVC: | |
| 1316 | + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_PROFILE, | |
| 1317 | + vpu_get_h264_v4l2_profile(hdr)); | |
| 1318 | + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_H264_LEVEL, | |
| 1319 | + vpu_get_h264_v4l2_level(hdr)); | |
| 1320 | + break; | |
| 1321 | + case V4L2_PIX_FMT_HEVC: | |
| 1322 | + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, | |
| 1323 | + vpu_get_hevc_v4l2_profile(hdr)); | |
| 1324 | + vdec_update_v4l2_ctrl(inst, V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, | |
| 1325 | + vpu_get_hevc_v4l2_level(hdr)); | |
| 1326 | + break; | |
| 1327 | + default: | |
| 1328 | + return; | |
| 1166 | 1329 | } |
| 1167 | 1330 | } |
| 1168 | 1331 | |
| @@ -1189,6 +1352,7 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info · 20 unmodified lines | ||
| 1189 | 1352 | vdec_init_crop(inst); |
| 1190 | 1353 | vdec_init_mbi(inst); |
| 1191 | 1354 | vdec_init_dcp(inst); |
| 1355 | + vdec_update_v4l2_profile_level(inst, hdr); | |
| 1192 | 1356 | if (!vdec->seq_hdr_found) { |
| 1193 | 1357 | vdec->seq_tag = vdec->codec_info.tag; |
| 1194 | 1358 | if (vdec->is_source_changed) { |
| @@ -1263,39 +1427,29 @@ static void vdec_event_req_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) · 68 unmodified lines | ||
| 1263 | 1427 | static void vdec_evnet_rel_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) |
| 1264 | 1428 | { |
| 1265 | 1429 | struct vdec_t *vdec = inst->priv; |
| 1266 | − struct vpu_vb2_buffer *vpu_buf; | |
| 1267 | − struct vb2_v4l2_buffer *vbuf; | |
| 1268 | 1430 | |
| 1269 | − if (!fs || fs->id >= ARRAY_SIZE(vdec->slots)) | |
| 1431 | + if (!fs || fs->id >= vdec->slot_count) | |
| 1270 | 1432 | return; |
| 1271 | 1433 | if (fs->type != MEM_RES_FRAME) |
| 1272 | 1434 | return; |
| 1273 | 1435 | |
| 1274 | − if (fs->id >= vpu_get_num_buffers(inst, inst->cap_format.type)) { | |
| 1436 | + if (fs->id >= vdec->slot_count) { | |
| 1275 | 1437 | dev_err(inst->dev, "[%d] invalid fs(%d) to release\n", inst->id, fs->id); |
| 1276 | 1438 | return; |
| 1277 | 1439 | } |
| 1278 | 1440 | |
| 1279 | 1441 | vpu_inst_lock(inst); |
| 1280 | − vpu_buf = vdec->slots[fs->id]; | |
| 1281 | − vdec->slots[fs->id] = NULL; | |
| 1282 | − | |
| 1283 | − if (!vpu_buf) { | |
| 1442 | + if (!vdec->slots[fs->id].curr) { | |
| 1284 | 1443 | dev_dbg(inst->dev, "[%d] fs[%d] has bee released\n", inst->id, fs->id); |
| 1285 | 1444 | goto exit; |
| 1286 | 1445 | } |
| 1287 | 1446 | |
| 1288 | − vbuf = &vpu_buf->m2m_buf.vb; | |
| 1289 | − if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) { | |
| 1447 | + if (vdec->slots[fs->id].state == VPU_BUF_STATE_DECODED) { | |
| 1290 | 1448 | dev_dbg(inst->dev, "[%d] frame skip\n", inst->id); |
| 1291 | 1449 | vdec->sequence++; |
| 1292 | 1450 | } |
| 1293 | 1451 | |
| 1294 | − vdec_response_fs_release(inst, fs->id, vpu_buf->tag); | |
| 1295 | − if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_READY) | |
| 1296 | − vdec_recycle_buffer(inst, vbuf); | |
| 1297 | − | |
| 1298 | − vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); | |
| 1452 | + vdec_release_curr_frame_store(inst, fs->id); | |
| 1299 | 1453 | vpu_process_capture_buffer(inst); |
| 1300 | 1454 | |
| 1301 | 1455 | exit: |
| @@ -1485,6 +1639,11 @@ static void vdec_cleanup(struct vpu_inst *inst) · 183 unmodified lines | ||
| 1485 | 1639 | return; |
| 1486 | 1640 | |
| 1487 | 1641 | vdec = inst->priv; |
| 1642 | + if (vdec) { | |
| 1643 | + kfree(vdec->slots); | |
| 1644 | + vdec->slots = NULL; | |
| 1645 | + vdec->slot_count = 0; | |
| 1646 | + } | |
| 1488 | 1647 | vfree(vdec); |
| 1489 | 1648 | inst->priv = NULL; |
| 1490 | 1649 | vfree(inst); |
| @@ -1606,11 +1765,43 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) · 115 unmodified lines | ||
| 1606 | 1765 | return 0; |
| 1607 | 1766 | } |
| 1608 | 1767 | |
| 1609 | −static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) | |
| 1768 | +static int vdec_get_slot_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) | |
| 1610 | 1769 | { |
| 1611 | 1770 | struct vdec_t *vdec = inst->priv; |
| 1771 | + struct vpu_vb2_buffer *vpu_buf; | |
| 1612 | 1772 | int num = -1; |
| 1613 | 1773 | |
| 1774 | + vpu_inst_lock(inst); | |
| 1775 | + if (i >= vdec->slot_count || !vdec->slots[i].addr) | |
| 1776 | + goto exit; | |
| 1777 | + | |
| 1778 | + vpu_buf = vdec->slots[i].curr; | |
| 1779 | + | |
| 1780 | + num = scnprintf(str, size, "slot[%2d] :", i); | |
| 1781 | + if (vpu_buf) { | |
| 1782 | + num += scnprintf(str + num, size - num, " %2d", | |
| 1783 | + vpu_buf->m2m_buf.vb.vb2_buf.index); | |
| 1784 | + num += scnprintf(str + num, size - num, "; state = %d", vdec->slots[i].state); | |
| 1785 | + } else { | |
| 1786 | + num += scnprintf(str + num, size - num, " -1"); | |
| 1787 | + } | |
| 1788 | + | |
| 1789 | + if (vdec->slots[i].pend) | |
| 1790 | + num += scnprintf(str + num, size - num, "; %d", | |
| 1791 | + vdec->slots[i].pend->m2m_buf.vb.vb2_buf.index); | |
| 1792 | + | |
| 1793 | + num += scnprintf(str + num, size - num, "\n"); | |
| 1794 | +exit: | |
| 1795 | + vpu_inst_unlock(inst); | |
| 1796 | + | |
| 1797 | + return num; | |
| 1798 | +} | |
| 1799 | + | |
| 1800 | +static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i) | |
| 1801 | +{ | |
| 1802 | + struct vdec_t *vdec = inst->priv; | |
| 1803 | + int num; | |
| 1804 | + | |
| 1614 | 1805 | switch (i) { |
| 1615 | 1806 | case 0: |
| 1616 | 1807 | num = scnprintf(str, size, |
| @@ -1664,6 +1855,7 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i · 47 unmodified lines | ||
| 1664 | 1855 | vdec->codec_info.vui_present); |
| 1665 | 1856 | break; |
| 1666 | 1857 | default: |
| 1858 | + num = vdec_get_slot_debug_info(inst, str, size, i - 10); | |
| 1667 | 1859 | break; |
| 1668 | 1860 | } |
| 1669 | 1861 | |
| @@ -1687,6 +1879,8 @@ static struct vpu_inst_ops vdec_inst_ops = { · 17 unmodified lines | ||
| 1687 | 1879 | .get_debug_info = vdec_get_debug_info, |
| 1688 | 1880 | .wait_prepare = vpu_inst_unlock, |
| 1689 | 1881 | .wait_finish = vpu_inst_lock, |
| 1882 | + .attach_frame_store = vdec_attach_frame_store, | |
| 1883 | + .reset_frame_store = vdec_reset_frame_store, | |
| 1690 | 1884 | }; |
| 1691 | 1885 | |
| 1692 | 1886 | static void vdec_init(struct file *file) |
| @@ -1727,6 +1921,16 @@ static int vdec_open(struct file *file) · 34 unmodified lines | ||
| 1727 | 1921 | return -ENOMEM; |
| 1728 | 1922 | } |
| 1729 | 1923 | |
| 1924 | + vdec->slots = kmalloc_array(VDEC_SLOT_CNT_DFT, | |
| 1925 | + sizeof(*vdec->slots), | |
| 1926 | + GFP_KERNEL | __GFP_ZERO); | |
| 1927 | + if (!vdec->slots) { | |
| 1928 | + vfree(vdec); | |
| 1929 | + vfree(inst); | |
| 1930 | + return -ENOMEM; | |
| 1931 | + } | |
| 1932 | + vdec->slot_count = VDEC_SLOT_CNT_DFT; | |
| 1933 | + | |
| 1730 | 1934 | inst->ops = &vdec_inst_ops; |
| 1731 | 1935 | inst->formats = vdec_formats; |
| 1732 | 1936 | inst->type = VPU_CORE_TYPE_DEC; |
| @@ -222,6 +222,8 @@ struct vpu_inst_ops { · 221 unmodified lines | ||
| 222 | 222 | int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i); |
| 223 | 223 | void (*wait_prepare)(struct vpu_inst *inst); |
| 224 | 224 | void (*wait_finish)(struct vpu_inst *inst); |
| 225 | + void (*attach_frame_store)(struct vpu_inst *inst, struct vb2_buffer *vb); | |
| 226 | + void (*reset_frame_store)(struct vpu_inst *inst); | |
| 225 | 227 | }; |
| 226 | 228 | |
| 227 | 229 | struct vpu_inst { |
| @@ -295,7 +297,8 @@ enum { · 67 unmodified lines | ||
| 295 | 297 | VPU_BUF_STATE_DECODED, |
| 296 | 298 | VPU_BUF_STATE_READY, |
| 297 | 299 | VPU_BUF_STATE_SKIP, |
| 298 | − VPU_BUF_STATE_ERROR | |
| 300 | + VPU_BUF_STATE_ERROR, | |
| 301 | + VPU_BUF_STATE_CHANGED | |
| 299 | 302 | }; |
| 300 | 303 | |
| 301 | 304 | struct vpu_vb2_buffer { |
| @@ -304,8 +307,8 @@ struct vpu_vb2_buffer { · 2 unmodified lines | ||
| 304 | 307 | dma_addr_t chroma_u; |
| 305 | 308 | dma_addr_t chroma_v; |
| 306 | 309 | unsigned int state; |
| 307 | − u32 tag; | |
| 308 | 310 | u32 average_qp; |
| 311 | + s32 fs_id; | |
| 309 | 312 | }; |
| 310 | 313 | |
| 311 | 314 | void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val); |
| @@ -108,76 +108,3 @@ u32 vpu_color_cvrt_full_range_i2v(u32 full_range) · 107 unmodified lines | ||
| 108 | 108 | |
| 109 | 109 | return V4L2_QUANTIZATION_LIM_RANGE; |
| 110 | 110 | } |
| 111 | − | |
| 112 | −int vpu_color_check_primaries(u32 primaries) | |
| 113 | −{ | |
| 114 | − return vpu_color_cvrt_primaries_v2i(primaries) ? 0 : -EINVAL; | |
| 115 | −} | |
| 116 | − | |
| 117 | −int vpu_color_check_transfers(u32 transfers) | |
| 118 | −{ | |
| 119 | − return vpu_color_cvrt_transfers_v2i(transfers) ? 0 : -EINVAL; | |
| 120 | −} | |
| 121 | − | |
| 122 | −int vpu_color_check_matrix(u32 matrix) | |
| 123 | −{ | |
| 124 | − return vpu_color_cvrt_matrix_v2i(matrix) ? 0 : -EINVAL; | |
| 125 | −} | |
| 126 | − | |
| 127 | −int vpu_color_check_full_range(u32 full_range) | |
| 128 | −{ | |
| 129 | − int ret = -EINVAL; | |
| 130 | − | |
| 131 | − switch (full_range) { | |
| 132 | − case V4L2_QUANTIZATION_FULL_RANGE: | |
| 133 | − case V4L2_QUANTIZATION_LIM_RANGE: | |
| 134 | − ret = 0; | |
| 135 | − break; | |
| 136 | − default: | |
| 137 | − break; | |
| 138 | − } | |
| 139 | − | |
| 140 | − return ret; | |
| 141 | −} | |
| 142 | − | |
| 143 | −int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range) | |
| 144 | −{ | |
| 145 | − u32 transfers; | |
| 146 | − u32 matrix; | |
| 147 | − u32 full_range; | |
| 148 | − | |
| 149 | − switch (primaries) { | |
| 150 | − case V4L2_COLORSPACE_REC709: | |
| 151 | − transfers = V4L2_XFER_FUNC_709; | |
| 152 | − matrix = V4L2_YCBCR_ENC_709; | |
| 153 | − break; | |
| 154 | − case V4L2_COLORSPACE_470_SYSTEM_M: | |
| 155 | − case V4L2_COLORSPACE_470_SYSTEM_BG: | |
| 156 | − case V4L2_COLORSPACE_SMPTE170M: | |
| 157 | − transfers = V4L2_XFER_FUNC_709; | |
| 158 | − matrix = V4L2_YCBCR_ENC_601; | |
| 159 | − break; | |
| 160 | − case V4L2_COLORSPACE_SMPTE240M: | |
| 161 | − transfers = V4L2_XFER_FUNC_SMPTE240M; | |
| 162 | − matrix = V4L2_YCBCR_ENC_SMPTE240M; | |
| 163 | − break; | |
| 164 | − case V4L2_COLORSPACE_BT2020: | |
| 165 | − transfers = V4L2_XFER_FUNC_709; | |
| 166 | − matrix = V4L2_YCBCR_ENC_BT2020; | |
| 167 | − break; | |
| 168 | − default: | |
| 169 | − transfers = V4L2_XFER_FUNC_DEFAULT; | |
| 170 | − matrix = V4L2_YCBCR_ENC_DEFAULT; | |
| 171 | − break; | |
| 172 | − } | |
| 173 | − full_range = V4L2_QUANTIZATION_LIM_RANGE; | |
| 174 | − | |
| 175 | − if (ptransfers) | |
| 176 | − *ptransfers = transfers; | |
| 177 | − if (pmatrix) | |
| 178 | − *pmatrix = matrix; | |
| 179 | − if (pfull_range) | |
| 180 | − *pfull_range = full_range; | |
| 181 | − | |
| 182 | − return 0; | |
| 183 | −} | |
| @@ -48,6 +48,7 @@ static char *vpu_stat_name[] = { · 47 unmodified lines | ||
| 48 | 48 | [VPU_BUF_STATE_READY] = "ready", |
| 49 | 49 | [VPU_BUF_STATE_SKIP] = "skip", |
| 50 | 50 | [VPU_BUF_STATE_ERROR] = "error", |
| 51 | + [VPU_BUF_STATE_CHANGED] = "changed", | |
| 51 | 52 | }; |
| 52 | 53 | |
| 53 | 54 | static inline const char *to_vpu_stat_name(int state) |
| @@ -164,6 +165,7 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) · 110 unmodified lines | ||
| 164 | 165 | for (i = 0; i < vb2_get_num_buffers(vq); i++) { |
| 165 | 166 | struct vb2_buffer *vb; |
| 166 | 167 | struct vb2_v4l2_buffer *vbuf; |
| 168 | + struct vpu_vb2_buffer *vpu_buf; | |
| 167 | 169 | |
| 168 | 170 | vb = vb2_get_buffer(vq, i); |
| 169 | 171 | if (!vb) |
| @@ -173,13 +175,24 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) · 3 unmodified lines | ||
| 173 | 175 | continue; |
| 174 | 176 | |
| 175 | 177 | vbuf = to_vb2_v4l2_buffer(vb); |
| 178 | + vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 176 | 179 | |
| 177 | 180 | num = scnprintf(str, sizeof(str), |
| 178 | − "capture[%2d] state = %10s, %8s\n", | |
| 181 | + "capture[%2d] state = %10s, %8s", | |
| 179 | 182 | i, vb2_stat_name[vb->state], |
| 180 | 183 | to_vpu_stat_name(vpu_get_buffer_state(vbuf))); |
| 181 | 184 | if (seq_write(s, str, num)) |
| 182 | 185 | return 0; |
| 186 | + | |
| 187 | + if (vpu_buf->fs_id >= 0) { | |
| 188 | + num = scnprintf(str, sizeof(str), "; fs %d", vpu_buf->fs_id); | |
| 189 | + if (seq_write(s, str, num)) | |
| 190 | + return 0; | |
| 191 | + } | |
| 192 | + | |
| 193 | + num = scnprintf(str, sizeof(str), "\n"); | |
| 194 | + if (seq_write(s, str, num)) | |
| 195 | + return 0; | |
| 183 | 196 | } |
| 184 | 197 | |
| 185 | 198 | num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence); |
| @@ -134,6 +134,7 @@ struct vpu_dec_codec_info { · 133 unmodified lines | ||
| 134 | 134 | u32 decoded_height; |
| 135 | 135 | struct v4l2_fract frame_rate; |
| 136 | 136 | u32 dsp_asp_ratio; |
| 137 | + u32 profile_idc; | |
| 137 | 138 | u32 level_idc; |
| 138 | 139 | u32 bit_depth_luma; |
| 139 | 140 | u32 bit_depth_chroma; |
| @@ -147,6 +148,17 @@ struct vpu_dec_codec_info { · 7 unmodified lines | ||
| 147 | 148 | u32 mbi_size; |
| 148 | 149 | u32 dcp_size; |
| 149 | 150 | u32 stride; |
| 151 | + union { | |
| 152 | + struct { | |
| 153 | + u32 constraint_set5_flag : 1; | |
| 154 | + u32 constraint_set4_flag : 1; | |
| 155 | + u32 constraint_set3_flag : 1; | |
| 156 | + u32 constraint_set2_flag : 1; | |
| 157 | + u32 constraint_set1_flag : 1; | |
| 158 | + u32 constraint_set0_flag : 1; | |
| 159 | + }; | |
| 160 | + u32 constraint_set_flags; | |
| 161 | + }; | |
| 150 | 162 | }; |
| 151 | 163 | |
| 152 | 164 | struct vpu_dec_pic_info { |
| @@ -509,3 +509,126 @@ const char *vpu_codec_state_name(enum vpu_codec_state state) · 508 unmodified lines | ||
| 509 | 509 | } |
| 510 | 510 | return "<unknown>"; |
| 511 | 511 | } |
| 512 | + | |
| 513 | +struct codec_id_mapping { | |
| 514 | + u32 id; | |
| 515 | + u32 v4l2_id; | |
| 516 | +}; | |
| 517 | + | |
| 518 | +static struct codec_id_mapping h264_profiles[] = { | |
| 519 | + {66, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE}, | |
| 520 | + {77, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN}, | |
| 521 | + {88, V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED}, | |
| 522 | + {100, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH} | |
| 523 | +}; | |
| 524 | + | |
| 525 | +static struct codec_id_mapping h264_levels[] = { | |
| 526 | + {10, V4L2_MPEG_VIDEO_H264_LEVEL_1_0}, | |
| 527 | + {9, V4L2_MPEG_VIDEO_H264_LEVEL_1B}, | |
| 528 | + {11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1}, | |
| 529 | + {12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2}, | |
| 530 | + {13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3}, | |
| 531 | + {20, V4L2_MPEG_VIDEO_H264_LEVEL_2_0}, | |
| 532 | + {21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1}, | |
| 533 | + {22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2}, | |
| 534 | + {30, V4L2_MPEG_VIDEO_H264_LEVEL_3_0}, | |
| 535 | + {31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1}, | |
| 536 | + {32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2}, | |
| 537 | + {40, V4L2_MPEG_VIDEO_H264_LEVEL_4_0}, | |
| 538 | + {41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1}, | |
| 539 | + {42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2}, | |
| 540 | + {50, V4L2_MPEG_VIDEO_H264_LEVEL_5_0}, | |
| 541 | + {51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1}, | |
| 542 | + {52, V4L2_MPEG_VIDEO_H264_LEVEL_5_2}, | |
| 543 | + {60, V4L2_MPEG_VIDEO_H264_LEVEL_6_0}, | |
| 544 | + {61, V4L2_MPEG_VIDEO_H264_LEVEL_6_1}, | |
| 545 | + {62, V4L2_MPEG_VIDEO_H264_LEVEL_6_2} | |
| 546 | +}; | |
| 547 | + | |
| 548 | +static struct codec_id_mapping hevc_profiles[] = { | |
| 549 | + {1, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN}, | |
| 550 | + {2, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10} | |
| 551 | +}; | |
| 552 | + | |
| 553 | +static struct codec_id_mapping hevc_levels[] = { | |
| 554 | + {30, V4L2_MPEG_VIDEO_HEVC_LEVEL_1}, | |
| 555 | + {60, V4L2_MPEG_VIDEO_HEVC_LEVEL_2}, | |
| 556 | + {63, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1}, | |
| 557 | + {90, V4L2_MPEG_VIDEO_HEVC_LEVEL_3}, | |
| 558 | + {93, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1}, | |
| 559 | + {120, V4L2_MPEG_VIDEO_HEVC_LEVEL_4}, | |
| 560 | + {123, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1}, | |
| 561 | + {150, V4L2_MPEG_VIDEO_HEVC_LEVEL_5}, | |
| 562 | + {153, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1}, | |
| 563 | + {156, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2}, | |
| 564 | + {180, V4L2_MPEG_VIDEO_HEVC_LEVEL_6}, | |
| 565 | + {183, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1}, | |
| 566 | + {186, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2} | |
| 567 | +}; | |
| 568 | + | |
| 569 | +static u32 vpu_find_v4l2_id(u32 id, struct codec_id_mapping *array, u32 array_sz) | |
| 570 | +{ | |
| 571 | + u32 i; | |
| 572 | + | |
| 573 | + if (!array || !array_sz) | |
| 574 | + return 0; | |
| 575 | + | |
| 576 | + for (i = 0; i < array_sz; i++) { | |
| 577 | + if (id == array[i].id) | |
| 578 | + return array[i].v4l2_id; | |
| 579 | + } | |
| 580 | + | |
| 581 | + return 0; | |
| 582 | +} | |
| 583 | + | |
| 584 | +u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr) | |
| 585 | +{ | |
| 586 | + if (!hdr) | |
| 587 | + return 0; | |
| 588 | + | |
| 589 | + /* | |
| 590 | + * In H.264 Document section A.2.1.1 Constrained Baseline profile | |
| 591 | + * Conformance of a bitstream to the Constrained Baseline profile is indicated by | |
| 592 | + * profile_idc being equal to 66 with constraint_set1_flag being equal to 1. | |
| 593 | + */ | |
| 594 | + if (hdr->profile_idc == 66 && hdr->constraint_set1_flag) | |
| 595 | + return V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; | |
| 596 | + | |
| 597 | + return vpu_find_v4l2_id(hdr->profile_idc, h264_profiles, ARRAY_SIZE(h264_profiles)); | |
| 598 | +} | |
| 599 | + | |
| 600 | +u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr) | |
| 601 | +{ | |
| 602 | + if (!hdr) | |
| 603 | + return 0; | |
| 604 | + | |
| 605 | + /* | |
| 606 | + * In H.264 Document section 7.4.2.1.1 Sequence parameter set data semantics | |
| 607 | + * If profile_idc is equal to 66, 77, or 88 and level_idc is equal to 11, | |
| 608 | + * constraint_set3_flag equal to 1 indicates that the coded video sequence | |
| 609 | + * obeys all constraints specified in Annex A for level 1b | |
| 610 | + * and constraint_set3_flag equal to 0 indicates that the coded video sequence | |
| 611 | + * obeys all constraints specified in Annex A for level 1.1. | |
| 612 | + */ | |
| 613 | + if (hdr->level_idc == 11 && hdr->constraint_set3_flag && | |
| 614 | + (hdr->profile_idc == 66 || hdr->profile_idc == 77 || hdr->profile_idc == 88)) | |
| 615 | + return V4L2_MPEG_VIDEO_H264_LEVEL_1B; | |
| 616 | + | |
| 617 | + return vpu_find_v4l2_id(hdr->level_idc, h264_levels, ARRAY_SIZE(h264_levels)); | |
| 618 | +} | |
| 619 | + | |
| 620 | +u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr) | |
| 621 | +{ | |
| 622 | + if (!hdr) | |
| 623 | + return 0; | |
| 624 | + | |
| 625 | + return vpu_find_v4l2_id(hdr->profile_idc, hevc_profiles, ARRAY_SIZE(hevc_profiles)); | |
| 626 | +} | |
| 627 | + | |
| 628 | +u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr) | |
| 629 | +{ | |
| 630 | + if (!hdr) | |
| 631 | + return 0; | |
| 632 | + | |
| 633 | + return vpu_find_v4l2_id(hdr->level_idc, hevc_levels, ARRAY_SIZE(hevc_levels)); | |
| 634 | +} | |
| @@ -6,6 +6,8 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef _AMPHION_VPU_HELPERS_H |
| 7 | 7 | #define _AMPHION_VPU_HELPERS_H |
| 8 | 8 | |
| 9 | +#include "vpu_defs.h" | |
| 10 | + | |
| 9 | 11 | struct vpu_pair { |
| 10 | 12 | u32 src; |
| 11 | 13 | u32 dst; |
| @@ -54,10 +56,6 @@ static inline u8 vpu_helper_read_byte(struct vpu_buffer *stream_buffer, u32 pos) · 42 unmodified lines | ||
| 54 | 56 | return pdata[pos % stream_buffer->length]; |
| 55 | 57 | } |
| 56 | 58 | |
| 57 | −int vpu_color_check_primaries(u32 primaries); | |
| 58 | −int vpu_color_check_transfers(u32 transfers); | |
| 59 | −int vpu_color_check_matrix(u32 matrix); | |
| 60 | −int vpu_color_check_full_range(u32 full_range); | |
| 61 | 59 | u32 vpu_color_cvrt_primaries_v2i(u32 primaries); |
| 62 | 60 | u32 vpu_color_cvrt_primaries_i2v(u32 primaries); |
| 63 | 61 | u32 vpu_color_cvrt_transfers_v2i(u32 transfers); |
| @@ -66,8 +64,12 @@ u32 vpu_color_cvrt_matrix_v2i(u32 matrix); · 2 unmodified lines | ||
| 66 | 64 | u32 vpu_color_cvrt_matrix_i2v(u32 matrix); |
| 67 | 65 | u32 vpu_color_cvrt_full_range_v2i(u32 full_range); |
| 68 | 66 | u32 vpu_color_cvrt_full_range_i2v(u32 full_range); |
| 69 | −int vpu_color_get_default(u32 primaries, u32 *ptransfers, u32 *pmatrix, u32 *pfull_range); | |
| 70 | 67 | |
| 71 | 68 | int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src); |
| 72 | 69 | int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst); |
| 70 | + | |
| 71 | +u32 vpu_get_h264_v4l2_profile(struct vpu_dec_codec_info *hdr); | |
| 72 | +u32 vpu_get_h264_v4l2_level(struct vpu_dec_codec_info *hdr); | |
| 73 | +u32 vpu_get_hevc_v4l2_profile(struct vpu_dec_codec_info *hdr); | |
| 74 | +u32 vpu_get_hevc_v4l2_level(struct vpu_dec_codec_info *hdr); | |
| 73 | 75 | #endif |
| @@ -908,7 +908,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt, · 907 unmodified lines | ||
| 908 | 908 | info->frame_rate.numerator = 1000; |
| 909 | 909 | info->frame_rate.denominator = pkt->data[8]; |
| 910 | 910 | info->dsp_asp_ratio = pkt->data[9]; |
| 911 | − info->level_idc = pkt->data[10]; | |
| 911 | + info->profile_idc = (pkt->data[10] >> 8) & 0xff; | |
| 912 | + info->level_idc = pkt->data[10] & 0xff; | |
| 912 | 913 | info->bit_depth_luma = pkt->data[13]; |
| 913 | 914 | info->bit_depth_chroma = pkt->data[14]; |
| 914 | 915 | info->chroma_fmt = pkt->data[15]; |
| @@ -925,6 +926,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt, · 10 unmodified lines | ||
| 925 | 926 | info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128; |
| 926 | 927 | else |
| 927 | 928 | info->pixfmt = V4L2_PIX_FMT_NV12M_8L128; |
| 929 | + if (pkt->hdr.num > 28) | |
| 930 | + info->constraint_set_flags = pkt->data[28]; | |
| 928 | 931 | if (info->frame_rate.numerator && info->frame_rate.denominator) { |
| 929 | 932 | unsigned long n, d; |
| 930 | 933 | |
| @@ -109,7 +109,3 @@ void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data) · 108 unmodified lines | ||
| 109 | 109 | mbox_send_message(core->tx_data.ch, &data); |
| 110 | 110 | mbox_send_message(core->tx_type.ch, &type); |
| 111 | 111 | } |
| 112 | − | |
| 113 | −void vpu_mbox_enable_rx(struct vpu_dev *dev) | |
| 114 | −{ | |
| 115 | −} | |
| @@ -11,6 +11,5 @@ int vpu_mbox_request(struct vpu_core *core); · 10 unmodified lines | ||
| 11 | 11 | void vpu_mbox_free(struct vpu_core *core); |
| 12 | 12 | void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data); |
| 13 | 13 | void vpu_mbox_send_type(struct vpu_core *core, u32 type); |
| 14 | −void vpu_mbox_enable_rx(struct vpu_dev *dev); | |
| 15 | 14 | |
| 16 | 15 | #endif |
| @@ -501,14 +501,25 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, · 500 unmodified lines | ||
| 501 | 501 | call_void_vop(inst, release); |
| 502 | 502 | } |
| 503 | 503 | |
| 504 | + if (V4L2_TYPE_IS_CAPTURE(vq->type)) | |
| 505 | + call_void_vop(inst, reset_frame_store); | |
| 506 | + | |
| 504 | 507 | return 0; |
| 505 | 508 | } |
| 506 | 509 | |
| 507 | 510 | static int vpu_vb2_buf_init(struct vb2_buffer *vb) |
| 508 | 511 | { |
| 509 | 512 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
| 513 | + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 514 | + struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); | |
| 510 | 515 | |
| 516 | + vpu_buf->fs_id = -1; | |
| 511 | 517 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); |
| 518 | + | |
| 519 | + if (!inst->ops->attach_frame_store || V4L2_TYPE_IS_OUTPUT(vb->type)) | |
| 520 | + return 0; | |
| 521 | + | |
| 522 | + call_void_vop(inst, attach_frame_store, vb); | |
| 512 | 523 | return 0; |
| 513 | 524 | } |
| 514 | 525 | |
| @@ -57,6 +57,25 @@ · 56 unmodified lines | ||
| 57 | 57 | #define CSI2RX_LANES_MAX 4 |
| 58 | 58 | #define CSI2RX_STREAMS_MAX 4 |
| 59 | 59 | |
| 60 | +#define CSI2RX_ERROR_IRQS_REG 0x28 | |
| 61 | +#define CSI2RX_ERROR_IRQS_MASK_REG 0x2C | |
| 62 | + | |
| 63 | +#define CSI2RX_STREAM3_FIFO_OVERFLOW_IRQ BIT(19) | |
| 64 | +#define CSI2RX_STREAM2_FIFO_OVERFLOW_IRQ BIT(18) | |
| 65 | +#define CSI2RX_STREAM1_FIFO_OVERFLOW_IRQ BIT(17) | |
| 66 | +#define CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ BIT(16) | |
| 67 | +#define CSI2RX_FRONT_TRUNC_HDR_IRQ BIT(12) | |
| 68 | +#define CSI2RX_PROT_TRUNCATED_PACKET_IRQ BIT(11) | |
| 69 | +#define CSI2RX_FRONT_LP_NO_PAYLOAD_IRQ BIT(10) | |
| 70 | +#define CSI2RX_SP_INVALID_RCVD_IRQ BIT(9) | |
| 71 | +#define CSI2RX_DATA_ID_IRQ BIT(7) | |
| 72 | +#define CSI2RX_HEADER_CORRECTED_ECC_IRQ BIT(6) | |
| 73 | +#define CSI2RX_HEADER_ECC_IRQ BIT(5) | |
| 74 | +#define CSI2RX_PAYLOAD_CRC_IRQ BIT(4) | |
| 75 | + | |
| 76 | +#define CSI2RX_ECC_ERRORS GENMASK(7, 4) | |
| 77 | +#define CSI2RX_PACKET_ERRORS GENMASK(12, 9) | |
| 78 | + | |
| 60 | 79 | enum csi2rx_pads { |
| 61 | 80 | CSI2RX_PAD_SINK, |
| 62 | 81 | CSI2RX_PAD_SOURCE_STREAM0, |
| @@ -71,9 +90,32 @@ struct csi2rx_fmt { · 8 unmodified lines | ||
| 71 | 90 | u8 bpp; |
| 72 | 91 | }; |
| 73 | 92 | |
| 93 | +struct csi2rx_event { | |
| 94 | + u32 mask; | |
| 95 | + const char *name; | |
| 96 | +}; | |
| 97 | + | |
| 98 | +static const struct csi2rx_event csi2rx_events[] = { | |
| 99 | + { CSI2RX_STREAM3_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 3 FIFO detected" }, | |
| 100 | + { CSI2RX_STREAM2_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 2 FIFO detected" }, | |
| 101 | + { CSI2RX_STREAM1_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 1 FIFO detected" }, | |
| 102 | + { CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ, "Overflow of the Stream 0 FIFO detected" }, | |
| 103 | + { CSI2RX_FRONT_TRUNC_HDR_IRQ, "A truncated header [short or long] has been received" }, | |
| 104 | + { CSI2RX_PROT_TRUNCATED_PACKET_IRQ, "A truncated long packet has been received" }, | |
| 105 | + { CSI2RX_FRONT_LP_NO_PAYLOAD_IRQ, "A truncated long packet has been received. No payload" }, | |
| 106 | + { CSI2RX_SP_INVALID_RCVD_IRQ, "A reserved or invalid short packet has been received" }, | |
| 107 | + { CSI2RX_DATA_ID_IRQ, "Data ID error in the header packet" }, | |
| 108 | + { CSI2RX_HEADER_CORRECTED_ECC_IRQ, "ECC error detected and corrected" }, | |
| 109 | + { CSI2RX_HEADER_ECC_IRQ, "Unrecoverable ECC error" }, | |
| 110 | + { CSI2RX_PAYLOAD_CRC_IRQ, "CRC error" }, | |
| 111 | +}; | |
| 112 | + | |
| 113 | +#define CSI2RX_NUM_EVENTS ARRAY_SIZE(csi2rx_events) | |
| 114 | + | |
| 74 | 115 | struct csi2rx_priv { |
| 75 | 116 | struct device *dev; |
| 76 | 117 | unsigned int count; |
| 118 | + int error_irq; | |
| 77 | 119 | |
| 78 | 120 | /* |
| 79 | 121 | * Used to prevent race conditions between multiple, |
| @@ -95,6 +137,7 @@ struct csi2rx_priv { · 15 unmodified lines | ||
| 95 | 137 | u8 max_lanes; |
| 96 | 138 | u8 max_streams; |
| 97 | 139 | bool has_internal_dphy; |
| 140 | + u32 events[CSI2RX_NUM_EVENTS]; | |
| 98 | 141 | |
| 99 | 142 | struct v4l2_subdev subdev; |
| 100 | 143 | struct v4l2_async_notifier notifier; |
| @@ -124,6 +167,54 @@ static const struct csi2rx_fmt formats[] = { · 23 unmodified lines | ||
| 124 | 167 | { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, |
| 125 | 168 | }; |
| 126 | 169 | |
| 170 | +static void csi2rx_configure_error_irq_mask(void __iomem *base, | |
| 171 | + struct csi2rx_priv *csi2rx) | |
| 172 | +{ | |
| 173 | + u32 error_irq_mask = 0; | |
| 174 | + | |
| 175 | + error_irq_mask |= CSI2RX_ECC_ERRORS; | |
| 176 | + error_irq_mask |= CSI2RX_PACKET_ERRORS; | |
| 177 | + | |
| 178 | + /* | |
| 179 | + * Iterate through all source pads and check if they are linked | |
| 180 | + * to an active remote pad. If an active remote pad is found, | |
| 181 | + * calculate the corresponding bit position and set it in | |
| 182 | + * mask, enabling the stream overflow error in the mask. | |
| 183 | + */ | |
| 184 | + for (int i = CSI2RX_PAD_SOURCE_STREAM0; i < CSI2RX_PAD_MAX; i++) { | |
| 185 | + struct media_pad *remote_pad; | |
| 186 | + | |
| 187 | + remote_pad = media_pad_remote_pad_first(&csi2rx->pads[i]); | |
| 188 | + if (remote_pad) { | |
| 189 | + int pad = i - CSI2RX_PAD_SOURCE_STREAM0; | |
| 190 | + u32 bit_mask = CSI2RX_STREAM0_FIFO_OVERFLOW_IRQ << pad; | |
| 191 | + | |
| 192 | + error_irq_mask |= bit_mask; | |
| 193 | + } | |
| 194 | + } | |
| 195 | + | |
| 196 | + writel(error_irq_mask, base + CSI2RX_ERROR_IRQS_MASK_REG); | |
| 197 | +} | |
| 198 | + | |
| 199 | +static irqreturn_t csi2rx_irq_handler(int irq, void *dev_id) | |
| 200 | +{ | |
| 201 | + struct csi2rx_priv *csi2rx = dev_id; | |
| 202 | + int i; | |
| 203 | + u32 error_status, error_mask; | |
| 204 | + | |
| 205 | + error_status = readl(csi2rx->base + CSI2RX_ERROR_IRQS_REG); | |
| 206 | + error_mask = readl(csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG); | |
| 207 | + | |
| 208 | + for (i = 0; i < CSI2RX_NUM_EVENTS; i++) | |
| 209 | + if ((error_status & csi2rx_events[i].mask) && | |
| 210 | + (error_mask & csi2rx_events[i].mask)) | |
| 211 | + csi2rx->events[i]++; | |
| 212 | + | |
| 213 | + writel(error_status, csi2rx->base + CSI2RX_ERROR_IRQS_REG); | |
| 214 | + | |
| 215 | + return IRQ_HANDLED; | |
| 216 | +} | |
| 217 | + | |
| 127 | 218 | static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) |
| 128 | 219 | { |
| 129 | 220 | unsigned int i; |
| @@ -220,6 +311,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) · 90 unmodified lines | ||
| 220 | 311 | reset_control_deassert(csi2rx->p_rst); |
| 221 | 312 | csi2rx_reset(csi2rx); |
| 222 | 313 | |
| 314 | + if (csi2rx->error_irq >= 0) | |
| 315 | + csi2rx_configure_error_irq_mask(csi2rx->base, csi2rx); | |
| 316 | + | |
| 223 | 317 | reg = csi2rx->num_lanes << 8; |
| 224 | 318 | for (i = 0; i < csi2rx->num_lanes; i++) { |
| 225 | 319 | reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csi2rx->lanes[i]); |
| @@ -332,6 +426,8 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) · 106 unmodified lines | ||
| 332 | 426 | reset_control_assert(csi2rx->sys_rst); |
| 333 | 427 | clk_disable_unprepare(csi2rx->sys_clk); |
| 334 | 428 | |
| 429 | + writel(0, csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG); | |
| 430 | + | |
| 335 | 431 | for (i = 0; i < csi2rx->max_streams; i++) { |
| 336 | 432 | writel(CSI2RX_STREAM_CTRL_STOP, |
| 337 | 433 | csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); |
| @@ -363,6 +459,21 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx) · 25 unmodified lines | ||
| 363 | 459 | } |
| 364 | 460 | } |
| 365 | 461 | |
| 462 | +static int csi2rx_log_status(struct v4l2_subdev *sd) | |
| 463 | +{ | |
| 464 | + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(sd); | |
| 465 | + unsigned int i; | |
| 466 | + | |
| 467 | + for (i = 0; i < CSI2RX_NUM_EVENTS; i++) { | |
| 468 | + if (csi2rx->events[i]) | |
| 469 | + dev_info(csi2rx->dev, "%s events: %d\n", | |
| 470 | + csi2rx_events[i].name, | |
| 471 | + csi2rx->events[i]); | |
| 472 | + } | |
| 473 | + | |
| 474 | + return 0; | |
| 475 | +} | |
| 476 | + | |
| 366 | 477 | static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) |
| 367 | 478 | { |
| 368 | 479 | struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); |
| @@ -468,7 +579,12 @@ static const struct v4l2_subdev_video_ops csi2rx_video_ops = { · 99 unmodified lines | ||
| 468 | 579 | .s_stream = csi2rx_s_stream, |
| 469 | 580 | }; |
| 470 | 581 | |
| 582 | +static const struct v4l2_subdev_core_ops csi2rx_core_ops = { | |
| 583 | + .log_status = csi2rx_log_status, | |
| 584 | +}; | |
| 585 | + | |
| 471 | 586 | static const struct v4l2_subdev_ops csi2rx_subdev_ops = { |
| 587 | + .core = &csi2rx_core_ops, | |
| 472 | 588 | .video = &csi2rx_video_ops, |
| 473 | 589 | .pad = &csi2rx_pad_ops, |
| 474 | 590 | }; |
| @@ -705,6 +821,21 @@ static int csi2rx_probe(struct platform_device *pdev) · 230 unmodified lines | ||
| 705 | 821 | if (ret) |
| 706 | 822 | goto err_cleanup; |
| 707 | 823 | |
| 824 | + csi2rx->error_irq = platform_get_irq_byname_optional(pdev, "error_irq"); | |
| 825 | + | |
| 826 | + if (csi2rx->error_irq < 0) { | |
| 827 | + dev_dbg(csi2rx->dev, "Optional interrupt not defined, proceeding without it\n"); | |
| 828 | + } else { | |
| 829 | + ret = devm_request_irq(csi2rx->dev, csi2rx->error_irq, | |
| 830 | + csi2rx_irq_handler, 0, | |
| 831 | + dev_name(&pdev->dev), csi2rx); | |
| 832 | + if (ret) { | |
| 833 | + dev_err(csi2rx->dev, | |
| 834 | + "Unable to request interrupt: %d\n", ret); | |
| 835 | + goto err_cleanup; | |
| 836 | + } | |
| 837 | + } | |
| 838 | + | |
| 708 | 839 | ret = v4l2_subdev_init_finalize(&csi2rx->subdev); |
| 709 | 840 | if (ret) |
| 710 | 841 | goto err_cleanup; |
| @@ -598,6 +598,27 @@ static void _bswap16(u16 *a) · 597 unmodified lines | ||
| 598 | 598 | *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); |
| 599 | 599 | } |
| 600 | 600 | |
| 601 | +static dma_addr_t mxc_jpeg_get_plane_dma_addr(struct vb2_buffer *buf, unsigned int plane_no) | |
| 602 | +{ | |
| 603 | + if (plane_no >= buf->num_planes) | |
| 604 | + return 0; | |
| 605 | + return vb2_dma_contig_plane_dma_addr(buf, plane_no) + buf->planes[plane_no].data_offset; | |
| 606 | +} | |
| 607 | + | |
| 608 | +static void *mxc_jpeg_get_plane_vaddr(struct vb2_buffer *buf, unsigned int plane_no) | |
| 609 | +{ | |
| 610 | + if (plane_no >= buf->num_planes) | |
| 611 | + return NULL; | |
| 612 | + return vb2_plane_vaddr(buf, plane_no) + buf->planes[plane_no].data_offset; | |
| 613 | +} | |
| 614 | + | |
| 615 | +static unsigned long mxc_jpeg_get_plane_payload(struct vb2_buffer *buf, unsigned int plane_no) | |
| 616 | +{ | |
| 617 | + if (plane_no >= buf->num_planes) | |
| 618 | + return 0; | |
| 619 | + return vb2_get_plane_payload(buf, plane_no) - buf->planes[plane_no].data_offset; | |
| 620 | +} | |
| 621 | + | |
| 601 | 622 | static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, |
| 602 | 623 | unsigned long len) |
| 603 | 624 | { |
| @@ -610,11 +631,11 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, · 6 unmodified lines | ||
| 610 | 631 | return; |
| 611 | 632 | |
| 612 | 633 | for (plane_no = 0; plane_no < buf->num_planes; plane_no++) { |
| 613 | − payload = vb2_get_plane_payload(buf, plane_no); | |
| 634 | + payload = mxc_jpeg_get_plane_payload(buf, plane_no); | |
| 614 | 635 | if (len == 0) |
| 615 | 636 | len = payload; |
| 616 | − dma_addr = vb2_dma_contig_plane_dma_addr(buf, plane_no); | |
| 617 | − vaddr = vb2_plane_vaddr(buf, plane_no); | |
| 637 | + dma_addr = mxc_jpeg_get_plane_dma_addr(buf, plane_no); | |
| 638 | + vaddr = mxc_jpeg_get_plane_vaddr(buf, plane_no); | |
| 618 | 639 | v4l2_dbg(3, debug, &jpeg->v4l2_dev, |
| 619 | 640 | "plane %d (vaddr=%p dma_addr=%x payload=%ld):", |
| 620 | 641 | plane_no, vaddr, dma_addr, payload); |
| @@ -712,16 +733,15 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc, · 91 unmodified lines | ||
| 712 | 733 | struct mxc_jpeg_q_data *q_data; |
| 713 | 734 | |
| 714 | 735 | q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type); |
| 715 | − desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0); | |
| 736 | + desc->buf_base0 = mxc_jpeg_get_plane_dma_addr(raw_buf, 0); | |
| 716 | 737 | desc->buf_base1 = 0; |
| 717 | 738 | if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { |
| 718 | 739 | if (raw_buf->num_planes == 2) |
| 719 | − desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); | |
| 740 | + desc->buf_base1 = mxc_jpeg_get_plane_dma_addr(raw_buf, 1); | |
| 720 | 741 | else |
| 721 | 742 | desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0]; |
| 722 | 743 | } |
| 723 | − desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) + | |
| 724 | − offset; | |
| 744 | + desc->stm_bufbase = mxc_jpeg_get_plane_dma_addr(jpeg_buf, 0) + offset; | |
| 725 | 745 | } |
| 726 | 746 | |
| 727 | 747 | static bool mxc_jpeg_is_extended_sequential(const struct mxc_jpeg_fmt *fmt) |
| @@ -1029,8 +1049,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) · 301 unmodified lines | ||
| 1029 | 1049 | vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); |
| 1030 | 1050 | } |
| 1031 | 1051 | dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", |
| 1032 | − vb2_get_plane_payload(&dst_buf->vb2_buf, 0), | |
| 1033 | − vb2_get_plane_payload(&dst_buf->vb2_buf, 1)); | |
| 1052 | + mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 0), | |
| 1053 | + mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 1)); | |
| 1034 | 1054 | } |
| 1035 | 1055 | |
| 1036 | 1056 | /* short preview of the results */ |
| @@ -1889,8 +1909,8 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) · 852 unmodified lines | ||
| 1889 | 1909 | struct mxc_jpeg_sof *psof = NULL; |
| 1890 | 1910 | struct mxc_jpeg_sos *psos = NULL; |
| 1891 | 1911 | struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); |
| 1892 | − u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0); | |
| 1893 | − u32 size = vb2_get_plane_payload(vb, 0); | |
| 1912 | + u8 *src_addr = (u8 *)mxc_jpeg_get_plane_vaddr(vb, 0); | |
| 1913 | + u32 size = mxc_jpeg_get_plane_payload(vb, 0); | |
| 1894 | 1914 | int ret; |
| 1895 | 1915 | |
| 1896 | 1916 | memset(&header, 0, sizeof(header)); |
| @@ -2027,6 +2047,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) · 130 unmodified lines | ||
| 2027 | 2047 | i, vb2_plane_size(vb, i), sizeimage); |
| 2028 | 2048 | return -EINVAL; |
| 2029 | 2049 | } |
| 2050 | + if (!IS_ALIGNED(mxc_jpeg_get_plane_dma_addr(vb, i), MXC_JPEG_ADDR_ALIGNMENT)) { | |
| 2051 | + dev_err(dev, "planes[%d] address is not %d aligned\n", | |
| 2052 | + i, MXC_JPEG_ADDR_ALIGNMENT); | |
| 2053 | + return -EINVAL; | |
| 2054 | + } | |
| 2030 | 2055 | } |
| 2031 | 2056 | if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { |
| 2032 | 2057 | vb2_set_plane_payload(vb, 0, 0); |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | #define MXC_JPEG_MAX_PLANES 2 |
| 31 | 31 | #define MXC_JPEG_PATTERN_WIDTH 128 |
| 32 | 32 | #define MXC_JPEG_PATTERN_HEIGHT 64 |
| 33 | +#define MXC_JPEG_ADDR_ALIGNMENT 16 | |
| 33 | 34 | |
| 34 | 35 | enum mxc_jpeg_enc_state { |
| 35 | 36 | MXC_JPEG_ENCODING = 0, /* jpeg encode phase */ |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/reset.h> |
| 29 | 29 | #include <linux/spinlock.h> |
| 30 | 30 | |
| 31 | +#include <media/mipi-csi2.h> | |
| 31 | 32 | #include <media/v4l2-common.h> |
| 32 | 33 | #include <media/v4l2-device.h> |
| 33 | 34 | #include <media/v4l2-event.h> |
| @@ -229,25 +230,6 @@ · 195 unmodified lines | ||
| 229 | 230 | |
| 230 | 231 | #define DEFAULT_SCLK_CSIS_FREQ 166000000UL |
| 231 | 232 | |
| 232 | −/* MIPI CSI-2 Data Types */ | |
| 233 | −#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18 | |
| 234 | −#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19 | |
| 235 | −#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a | |
| 236 | −#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c | |
| 237 | −#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d | |
| 238 | −#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e | |
| 239 | −#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f | |
| 240 | −#define MIPI_CSI2_DATA_TYPE_RGB565 0x22 | |
| 241 | −#define MIPI_CSI2_DATA_TYPE_RGB666 0x23 | |
| 242 | −#define MIPI_CSI2_DATA_TYPE_RGB888 0x24 | |
| 243 | −#define MIPI_CSI2_DATA_TYPE_RAW6 0x28 | |
| 244 | −#define MIPI_CSI2_DATA_TYPE_RAW7 0x29 | |
| 245 | −#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a | |
| 246 | −#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b | |
| 247 | −#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c | |
| 248 | −#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d | |
| 249 | −#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) | |
| 250 | − | |
| 251 | 233 | struct mipi_csis_event { |
| 252 | 234 | bool debug; |
| 253 | 235 | u32 mask; |
| @@ -357,116 +339,116 @@ static const struct csis_pix_format mipi_csis_formats[] = { · 103 unmodified lines | ||
| 357 | 339 | { |
| 358 | 340 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
| 359 | 341 | .output = MEDIA_BUS_FMT_UYVY8_1X16, |
| 360 | − .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8, | |
| 342 | + .data_type = MIPI_CSI2_DT_YUV422_8B, | |
| 361 | 343 | .width = 16, |
| 362 | 344 | }, |
| 363 | 345 | /* RGB formats. */ |
| 364 | 346 | { |
| 365 | 347 | .code = MEDIA_BUS_FMT_RGB565_1X16, |
| 366 | 348 | .output = MEDIA_BUS_FMT_RGB565_1X16, |
| 367 | − .data_type = MIPI_CSI2_DATA_TYPE_RGB565, | |
| 349 | + .data_type = MIPI_CSI2_DT_RGB565, | |
| 368 | 350 | .width = 16, |
| 369 | 351 | }, { |
| 370 | 352 | .code = MEDIA_BUS_FMT_BGR888_1X24, |
| 371 | 353 | .output = MEDIA_BUS_FMT_RGB888_1X24, |
| 372 | − .data_type = MIPI_CSI2_DATA_TYPE_RGB888, | |
| 354 | + .data_type = MIPI_CSI2_DT_RGB888, | |
| 373 | 355 | .width = 24, |
| 374 | 356 | }, |
| 375 | 357 | /* RAW (Bayer and greyscale) formats. */ |
| 376 | 358 | { |
| 377 | 359 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, |
| 378 | 360 | .output = MEDIA_BUS_FMT_SBGGR8_1X8, |
| 379 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 361 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 380 | 362 | .width = 8, |
| 381 | 363 | }, { |
| 382 | 364 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, |
| 383 | 365 | .output = MEDIA_BUS_FMT_SGBRG8_1X8, |
| 384 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 366 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 385 | 367 | .width = 8, |
| 386 | 368 | }, { |
| 387 | 369 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, |
| 388 | 370 | .output = MEDIA_BUS_FMT_SGRBG8_1X8, |
| 389 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 371 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 390 | 372 | .width = 8, |
| 391 | 373 | }, { |
| 392 | 374 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, |
| 393 | 375 | .output = MEDIA_BUS_FMT_SRGGB8_1X8, |
| 394 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 376 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 395 | 377 | .width = 8, |
| 396 | 378 | }, { |
| 397 | 379 | .code = MEDIA_BUS_FMT_Y8_1X8, |
| 398 | 380 | .output = MEDIA_BUS_FMT_Y8_1X8, |
| 399 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 381 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 400 | 382 | .width = 8, |
| 401 | 383 | }, { |
| 402 | 384 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| 403 | 385 | .output = MEDIA_BUS_FMT_SBGGR10_1X10, |
| 404 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | |
| 386 | + .data_type = MIPI_CSI2_DT_RAW10, | |
| 405 | 387 | .width = 10, |
| 406 | 388 | }, { |
| 407 | 389 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, |
| 408 | 390 | .output = MEDIA_BUS_FMT_SGBRG10_1X10, |
| 409 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | |
| 391 | + .data_type = MIPI_CSI2_DT_RAW10, | |
| 410 | 392 | .width = 10, |
| 411 | 393 | }, { |
| 412 | 394 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, |
| 413 | 395 | .output = MEDIA_BUS_FMT_SGRBG10_1X10, |
| 414 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | |
| 396 | + .data_type = MIPI_CSI2_DT_RAW10, | |
| 415 | 397 | .width = 10, |
| 416 | 398 | }, { |
| 417 | 399 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, |
| 418 | 400 | .output = MEDIA_BUS_FMT_SRGGB10_1X10, |
| 419 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | |
| 401 | + .data_type = MIPI_CSI2_DT_RAW10, | |
| 420 | 402 | .width = 10, |
| 421 | 403 | }, { |
| 422 | 404 | .code = MEDIA_BUS_FMT_Y10_1X10, |
| 423 | 405 | .output = MEDIA_BUS_FMT_Y10_1X10, |
| 424 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | |
| 406 | + .data_type = MIPI_CSI2_DT_RAW10, | |
| 425 | 407 | .width = 10, |
| 426 | 408 | }, { |
| 427 | 409 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, |
| 428 | 410 | .output = MEDIA_BUS_FMT_SBGGR12_1X12, |
| 429 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | |
| 411 | + .data_type = MIPI_CSI2_DT_RAW12, | |
| 430 | 412 | .width = 12, |
| 431 | 413 | }, { |
| 432 | 414 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, |
| 433 | 415 | .output = MEDIA_BUS_FMT_SGBRG12_1X12, |
| 434 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | |
| 416 | + .data_type = MIPI_CSI2_DT_RAW12, | |
| 435 | 417 | .width = 12, |
| 436 | 418 | }, { |
| 437 | 419 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, |
| 438 | 420 | .output = MEDIA_BUS_FMT_SGRBG12_1X12, |
| 439 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | |
| 421 | + .data_type = MIPI_CSI2_DT_RAW12, | |
| 440 | 422 | .width = 12, |
| 441 | 423 | }, { |
| 442 | 424 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, |
| 443 | 425 | .output = MEDIA_BUS_FMT_SRGGB12_1X12, |
| 444 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | |
| 426 | + .data_type = MIPI_CSI2_DT_RAW12, | |
| 445 | 427 | .width = 12, |
| 446 | 428 | }, { |
| 447 | 429 | .code = MEDIA_BUS_FMT_Y12_1X12, |
| 448 | 430 | .output = MEDIA_BUS_FMT_Y12_1X12, |
| 449 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | |
| 431 | + .data_type = MIPI_CSI2_DT_RAW12, | |
| 450 | 432 | .width = 12, |
| 451 | 433 | }, { |
| 452 | 434 | .code = MEDIA_BUS_FMT_SBGGR14_1X14, |
| 453 | 435 | .output = MEDIA_BUS_FMT_SBGGR14_1X14, |
| 454 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | |
| 436 | + .data_type = MIPI_CSI2_DT_RAW14, | |
| 455 | 437 | .width = 14, |
| 456 | 438 | }, { |
| 457 | 439 | .code = MEDIA_BUS_FMT_SGBRG14_1X14, |
| 458 | 440 | .output = MEDIA_BUS_FMT_SGBRG14_1X14, |
| 459 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | |
| 441 | + .data_type = MIPI_CSI2_DT_RAW14, | |
| 460 | 442 | .width = 14, |
| 461 | 443 | }, { |
| 462 | 444 | .code = MEDIA_BUS_FMT_SGRBG14_1X14, |
| 463 | 445 | .output = MEDIA_BUS_FMT_SGRBG14_1X14, |
| 464 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | |
| 446 | + .data_type = MIPI_CSI2_DT_RAW14, | |
| 465 | 447 | .width = 14, |
| 466 | 448 | }, { |
| 467 | 449 | .code = MEDIA_BUS_FMT_SRGGB14_1X14, |
| 468 | 450 | .output = MEDIA_BUS_FMT_SRGGB14_1X14, |
| 469 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | |
| 451 | + .data_type = MIPI_CSI2_DT_RAW14, | |
| 470 | 452 | .width = 14, |
| 471 | 453 | }, |
| 472 | 454 | /* JPEG */ |
| @@ -494,7 +476,7 @@ static const struct csis_pix_format mipi_csis_formats[] = { · 21 unmodified lines | ||
| 494 | 476 | * SoC that can support quad pixel mode, this will have to be |
| 495 | 477 | * revisited. |
| 496 | 478 | */ |
| 497 | − .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | |
| 479 | + .data_type = MIPI_CSI2_DT_RAW8, | |
| 498 | 480 | .width = 8, |
| 499 | 481 | } |
| 500 | 482 | }; |
| @@ -583,7 +565,7 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis, · 82 unmodified lines | ||
| 583 | 565 | * |
| 584 | 566 | * TODO: Verify which other formats require DUAL (or QUAD) modes. |
| 585 | 567 | */ |
| 586 | − if (csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) | |
| 568 | + if (csis_fmt->data_type == MIPI_CSI2_DT_YUV422_8B) | |
| 587 | 569 | val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; |
| 588 | 570 | |
| 589 | 571 | val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright 2019-2020 NXP |
| 4 | 4 | */ |
| 5 | 5 | |
| 6 | +#include <linux/bits.h> | |
| 6 | 7 | #include <linux/clk.h> |
| 7 | 8 | #include <linux/device.h> |
| 8 | 9 | #include <linux/errno.h> |
| @@ -245,26 +246,41 @@ static void mxc_isi_v4l2_cleanup(struct mxc_isi_dev *isi) · 236 unmodified lines | ||
| 245 | 246 | |
| 246 | 247 | /* Panic will assert when the buffers are 50% full */ |
| 247 | 248 | |
| 248 | −/* For i.MX8QXP C0 and i.MX8MN ISI IER version */ | |
| 249 | +/* For i.MX8MN ISI IER version */ | |
| 249 | 250 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = { |
| 250 | − .oflw_y_buf_en = { .offset = 19, .mask = 0x80000 }, | |
| 251 | − .oflw_u_buf_en = { .offset = 21, .mask = 0x200000 }, | |
| 252 | − .oflw_v_buf_en = { .offset = 23, .mask = 0x800000 }, | |
| 251 | + .oflw_y_buf_en = { .mask = BIT(19) }, | |
| 252 | + .oflw_u_buf_en = { .mask = BIT(21) }, | |
| 253 | + .oflw_v_buf_en = { .mask = BIT(23) }, | |
| 253 | 254 | |
| 254 | − .panic_y_buf_en = {.offset = 20, .mask = 0x100000 }, | |
| 255 | − .panic_u_buf_en = {.offset = 22, .mask = 0x400000 }, | |
| 256 | − .panic_v_buf_en = {.offset = 24, .mask = 0x1000000 }, | |
| 255 | + .panic_y_buf_en = { .mask = BIT(20) }, | |
| 256 | + .panic_u_buf_en = { .mask = BIT(22) }, | |
| 257 | + .panic_v_buf_en = { .mask = BIT(24) }, | |
| 257 | 258 | }; |
| 258 | 259 | |
| 259 | −/* For i.MX8MP ISI IER version */ | |
| 260 | +/* For i.MX8QXP C0 and i.MX8MP ISI IER version */ | |
| 260 | 261 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = { |
| 261 | − .oflw_y_buf_en = { .offset = 18, .mask = 0x40000 }, | |
| 262 | − .oflw_u_buf_en = { .offset = 20, .mask = 0x100000 }, | |
| 263 | − .oflw_v_buf_en = { .offset = 22, .mask = 0x400000 }, | |
| 262 | + .oflw_y_buf_en = { .mask = BIT(18) }, | |
| 263 | + .oflw_u_buf_en = { .mask = BIT(20) }, | |
| 264 | + .oflw_v_buf_en = { .mask = BIT(22) }, | |
| 264 | 265 | |
| 265 | − .panic_y_buf_en = {.offset = 19, .mask = 0x80000 }, | |
| 266 | − .panic_u_buf_en = {.offset = 21, .mask = 0x200000 }, | |
| 267 | − .panic_v_buf_en = {.offset = 23, .mask = 0x800000 }, | |
| 266 | + .panic_y_buf_en = { .mask = BIT(19) }, | |
| 267 | + .panic_u_buf_en = { .mask = BIT(21) }, | |
| 268 | + .panic_v_buf_en = { .mask = BIT(23) }, | |
| 269 | +}; | |
| 270 | + | |
| 271 | +/* For i.MX8QM ISI IER version */ | |
| 272 | +static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_qm = { | |
| 273 | + .oflw_y_buf_en = { .mask = BIT(16) }, | |
| 274 | + .oflw_u_buf_en = { .mask = BIT(19) }, | |
| 275 | + .oflw_v_buf_en = { .mask = BIT(22) }, | |
| 276 | + | |
| 277 | + .excs_oflw_y_buf_en = { .mask = BIT(17) }, | |
| 278 | + .excs_oflw_u_buf_en = { .mask = BIT(20) }, | |
| 279 | + .excs_oflw_v_buf_en = { .mask = BIT(23) }, | |
| 280 | + | |
| 281 | + .panic_y_buf_en = { .mask = BIT(18) }, | |
| 282 | + .panic_u_buf_en = { .mask = BIT(21) }, | |
| 283 | + .panic_v_buf_en = { .mask = BIT(24) }, | |
| 268 | 284 | }; |
| 269 | 285 | |
| 270 | 286 | /* Panic will assert when the buffers are 50% full */ |
| @@ -274,11 +290,6 @@ static const struct mxc_isi_set_thd mxc_imx8_isi_thd_v1 = { · 3 unmodified lines | ||
| 274 | 290 | .panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 }, |
| 275 | 291 | }; |
| 276 | 292 | |
| 277 | −static const struct clk_bulk_data mxc_imx8mn_clks[] = { | |
| 278 | − { .id = "axi" }, | |
| 279 | − { .id = "apb" }, | |
| 280 | −}; | |
| 281 | − | |
| 282 | 293 | static const struct mxc_isi_plat_data mxc_imx8mn_data = { |
| 283 | 294 | .model = MXC_ISI_IMX8MN, |
| 284 | 295 | .num_ports = 1, |
| @@ -286,8 +297,6 @@ static const struct mxc_isi_plat_data mxc_imx8mn_data = { · 1 unmodified line | ||
| 286 | 297 | .reg_offset = 0, |
| 287 | 298 | .ier_reg = &mxc_imx8_isi_ier_v1, |
| 288 | 299 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 289 | − .clks = mxc_imx8mn_clks, | |
| 290 | − .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | |
| 291 | 300 | .buf_active_reverse = false, |
| 292 | 301 | .gasket_ops = &mxc_imx8_gasket_ops, |
| 293 | 302 | .has_36bit_dma = false, |
| @@ -300,8 +309,6 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = { · 6 unmodified lines | ||
| 300 | 309 | .reg_offset = 0x2000, |
| 301 | 310 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 302 | 311 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 303 | − .clks = mxc_imx8mn_clks, | |
| 304 | − .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | |
| 305 | 312 | .buf_active_reverse = true, |
| 306 | 313 | .gasket_ops = &mxc_imx8_gasket_ops, |
| 307 | 314 | .has_36bit_dma = true, |
| @@ -314,8 +321,6 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = { · 6 unmodified lines | ||
| 314 | 321 | .reg_offset = 0x0, |
| 315 | 322 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 316 | 323 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 317 | − .clks = mxc_imx8mn_clks, | |
| 318 | − .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | |
| 319 | 324 | .buf_active_reverse = true, |
| 320 | 325 | .has_36bit_dma = false, |
| 321 | 326 | }; |
| @@ -327,13 +332,33 @@ static const struct mxc_isi_plat_data mxc_imx93_data = { · 5 unmodified lines | ||
| 327 | 332 | .reg_offset = 0, |
| 328 | 333 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 329 | 334 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 330 | − .clks = mxc_imx8mn_clks, | |
| 331 | − .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | |
| 332 | 335 | .buf_active_reverse = true, |
| 333 | 336 | .gasket_ops = &mxc_imx93_gasket_ops, |
| 334 | 337 | .has_36bit_dma = false, |
| 335 | 338 | }; |
| 336 | 339 | |
| 340 | +static const struct mxc_isi_plat_data mxc_imx8qm_data = { | |
| 341 | + .model = MXC_ISI_IMX8QM, | |
| 342 | + .num_ports = 5, | |
| 343 | + .num_channels = 8, | |
| 344 | + .reg_offset = 0x10000, | |
| 345 | + .ier_reg = &mxc_imx8_isi_ier_qm, | |
| 346 | + .set_thd = &mxc_imx8_isi_thd_v1, | |
| 347 | + .buf_active_reverse = true, | |
| 348 | + .has_36bit_dma = false, | |
| 349 | +}; | |
| 350 | + | |
| 351 | +static const struct mxc_isi_plat_data mxc_imx8qxp_data = { | |
| 352 | + .model = MXC_ISI_IMX8QXP, | |
| 353 | + .num_ports = 5, | |
| 354 | + .num_channels = 6, | |
| 355 | + .reg_offset = 0x10000, | |
| 356 | + .ier_reg = &mxc_imx8_isi_ier_v2, | |
| 357 | + .set_thd = &mxc_imx8_isi_thd_v1, | |
| 358 | + .buf_active_reverse = true, | |
| 359 | + .has_36bit_dma = false, | |
| 360 | +}; | |
| 361 | + | |
| 337 | 362 | /* ----------------------------------------------------------------------------- |
| 338 | 363 | * Power management |
| 339 | 364 | */ |
| @@ -385,7 +410,7 @@ static int mxc_isi_runtime_suspend(struct device *dev) · 45 unmodified lines | ||
| 385 | 410 | { |
| 386 | 411 | struct mxc_isi_dev *isi = dev_get_drvdata(dev); |
| 387 | 412 | |
| 388 | − clk_bulk_disable_unprepare(isi->pdata->num_clks, isi->clks); | |
| 413 | + clk_bulk_disable_unprepare(isi->num_clks, isi->clks); | |
| 389 | 414 | |
| 390 | 415 | return 0; |
| 391 | 416 | } |
| @@ -395,7 +420,7 @@ static int mxc_isi_runtime_resume(struct device *dev) · 3 unmodified lines | ||
| 395 | 420 | struct mxc_isi_dev *isi = dev_get_drvdata(dev); |
| 396 | 421 | int ret; |
| 397 | 422 | |
| 398 | − ret = clk_bulk_prepare_enable(isi->pdata->num_clks, isi->clks); | |
| 423 | + ret = clk_bulk_prepare_enable(isi->num_clks, isi->clks); | |
| 399 | 424 | if (ret) { |
| 400 | 425 | dev_err(dev, "Failed to enable clocks (%d)\n", ret); |
| 401 | 426 | return ret; |
| @@ -413,27 +438,6 @@ static const struct dev_pm_ops mxc_isi_pm_ops = { · 11 unmodified lines | ||
| 413 | 438 | * Probe, remove & driver |
| 414 | 439 | */ |
| 415 | 440 | |
| 416 | −static int mxc_isi_clk_get(struct mxc_isi_dev *isi) | |
| 417 | −{ | |
| 418 | − unsigned int size = isi->pdata->num_clks | |
| 419 | − * sizeof(*isi->clks); | |
| 420 | − int ret; | |
| 421 | − | |
| 422 | − isi->clks = devm_kmemdup(isi->dev, isi->pdata->clks, size, GFP_KERNEL); | |
| 423 | − if (!isi->clks) | |
| 424 | − return -ENOMEM; | |
| 425 | − | |
| 426 | − ret = devm_clk_bulk_get(isi->dev, isi->pdata->num_clks, | |
| 427 | − isi->clks); | |
| 428 | − if (ret < 0) { | |
| 429 | − dev_err(isi->dev, "Failed to acquire clocks: %d\n", | |
| 430 | − ret); | |
| 431 | − return ret; | |
| 432 | − } | |
| 433 | − | |
| 434 | − return 0; | |
| 435 | −} | |
| 436 | − | |
| 437 | 441 | static int mxc_isi_probe(struct platform_device *pdev) |
| 438 | 442 | { |
| 439 | 443 | struct device *dev = &pdev->dev; |
| @@ -456,34 +460,25 @@ static int mxc_isi_probe(struct platform_device *pdev) · 16 unmodified lines | ||
| 456 | 460 | if (!isi->pipes) |
| 457 | 461 | return -ENOMEM; |
| 458 | 462 | |
| 459 | − ret = mxc_isi_clk_get(isi); | |
| 460 | − if (ret < 0) { | |
| 461 | − dev_err(dev, "Failed to get clocks\n"); | |
| 462 | − return ret; | |
| 463 | − } | |
| 463 | + isi->num_clks = devm_clk_bulk_get_all(dev, &isi->clks); | |
| 464 | + if (isi->num_clks < 0) | |
| 465 | + return dev_err_probe(dev, isi->num_clks, "Failed to get clocks\n"); | |
| 464 | 466 | |
| 465 | 467 | isi->regs = devm_platform_ioremap_resource(pdev, 0); |
| 466 | − if (IS_ERR(isi->regs)) { | |
| 467 | − dev_err(dev, "Failed to get ISI register map\n"); | |
| 468 | − return PTR_ERR(isi->regs); | |
| 469 | − } | |
| 468 | + if (IS_ERR(isi->regs)) | |
| 469 | + return dev_err_probe(dev, PTR_ERR(isi->regs), | |
| 470 | + "Failed to get ISI register map\n"); | |
| 470 | 471 | |
| 471 | 472 | if (isi->pdata->gasket_ops) { |
| 472 | 473 | isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node, |
| 473 | 474 | "fsl,blk-ctrl"); |
| 474 | − if (IS_ERR(isi->gasket)) { | |
| 475 | − ret = PTR_ERR(isi->gasket); | |
| 476 | − dev_err(dev, "failed to get gasket: %d\n", ret); | |
| 477 | − return ret; | |
| 478 | − } | |
| 475 | + if (IS_ERR(isi->gasket)) | |
| 476 | + return dev_err_probe(dev, PTR_ERR(isi->gasket), | |
| 477 | + "failed to get gasket\n"); | |
| 479 | 478 | } |
| 480 | 479 | |
| 481 | 480 | dma_size = isi->pdata->has_36bit_dma ? 36 : 32; |
| 482 | − ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size)); | |
| 483 | − if (ret) { | |
| 484 | − dev_err(dev, "failed to set DMA mask\n"); | |
| 485 | − return ret; | |
| 486 | − } | |
| 481 | + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size)); | |
| 487 | 482 | |
| 488 | 483 | pm_runtime_enable(dev); |
| 489 | 484 | |
| @@ -541,6 +536,8 @@ static void mxc_isi_remove(struct platform_device *pdev) · 51 unmodified lines | ||
| 541 | 536 | static const struct of_device_id mxc_isi_of_match[] = { |
| 542 | 537 | { .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data }, |
| 543 | 538 | { .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data }, |
| 539 | + { .compatible = "fsl,imx8qm-isi", .data = &mxc_imx8qm_data }, | |
| 540 | + { .compatible = "fsl,imx8qxp-isi", .data = &mxc_imx8qxp_data }, | |
| 544 | 541 | { .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data }, |
| 545 | 542 | { .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data }, |
| 546 | 543 | { /* sentinel */ }, |
| @@ -114,7 +114,6 @@ struct mxc_isi_buffer { · 113 unmodified lines | ||
| 114 | 114 | }; |
| 115 | 115 | |
| 116 | 116 | struct mxc_isi_reg { |
| 117 | − u32 offset; | |
| 118 | 117 | u32 mask; |
| 119 | 118 | }; |
| 120 | 119 | |
| @@ -158,6 +157,8 @@ struct mxc_gasket_ops { · 37 unmodified lines | ||
| 158 | 157 | enum model { |
| 159 | 158 | MXC_ISI_IMX8MN, |
| 160 | 159 | MXC_ISI_IMX8MP, |
| 160 | + MXC_ISI_IMX8QM, | |
| 161 | + MXC_ISI_IMX8QXP, | |
| 161 | 162 | MXC_ISI_IMX8ULP, |
| 162 | 163 | MXC_ISI_IMX93, |
| 163 | 164 | }; |
| @@ -170,8 +171,6 @@ struct mxc_isi_plat_data { · 6 unmodified lines | ||
| 170 | 171 | const struct mxc_isi_ier_reg *ier_reg; |
| 171 | 172 | const struct mxc_isi_set_thd *set_thd; |
| 172 | 173 | const struct mxc_gasket_ops *gasket_ops; |
| 173 | − const struct clk_bulk_data *clks; | |
| 174 | − unsigned int num_clks; | |
| 175 | 174 | bool buf_active_reverse; |
| 176 | 175 | bool has_36bit_dma; |
| 177 | 176 | }; |
| @@ -283,6 +282,7 @@ struct mxc_isi_dev { · 105 unmodified lines | ||
| 283 | 282 | |
| 284 | 283 | void __iomem *regs; |
| 285 | 284 | struct clk_bulk_data *clks; |
| 285 | + int num_clks; | |
| 286 | 286 | struct regmap *gasket; |
| 287 | 287 | |
| 288 | 288 | struct mxc_isi_crossbar crossbar; |
| @@ -188,11 +188,12 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, · 187 unmodified lines | ||
| 188 | 188 | * Create a 1:1 mapping between pixel link inputs and outputs to |
| 189 | 189 | * pipelines by default. |
| 190 | 190 | */ |
| 191 | − routes = kcalloc(xbar->num_sources, sizeof(*routes), GFP_KERNEL); | |
| 191 | + routing.num_routes = min(xbar->num_sinks - 1, xbar->num_sources); | |
| 192 | + routes = kcalloc(routing.num_routes, sizeof(*routes), GFP_KERNEL); | |
| 192 | 193 | if (!routes) |
| 193 | 194 | return -ENOMEM; |
| 194 | 195 | |
| 195 | − for (i = 0; i < xbar->num_sources; ++i) { | |
| 196 | + for (i = 0; i < routing.num_routes; ++i) { | |
| 196 | 197 | struct v4l2_subdev_route *route = &routes[i]; |
| 197 | 198 | |
| 198 | 199 | route->sink_pad = i; |
| @@ -200,7 +201,6 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, · 1 unmodified line | ||
| 200 | 201 | route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; |
| 201 | 202 | } |
| 202 | 203 | |
| 203 | − routing.num_routes = xbar->num_sources; | |
| 204 | 204 | routing.routes = routes; |
| 205 | 205 | |
| 206 | 206 | ret = __mxc_isi_crossbar_set_routing(sd, state, &routing); |
| @@ -352,9 +352,8 @@ static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, · 145 unmodified lines | ||
| 352 | 352 | sink_streams); |
| 353 | 353 | if (ret) { |
| 354 | 354 | dev_err(xbar->isi->dev, |
| 355 | − "failed to %s streams 0x%llx on '%s':%u: %d\n", | |
| 356 | − "enable", sink_streams, remote_sd->name, | |
| 357 | − remote_pad, ret); | |
| 355 | + "failed to enable streams 0x%llx on '%s':%u: %d\n", | |
| 356 | + sink_streams, remote_sd->name, remote_pad, ret); | |
| 358 | 357 | mxc_isi_crossbar_gasket_disable(xbar, sink_pad); |
| 359 | 358 | return ret; |
| 360 | 359 | } |
| @@ -392,9 +391,8 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, · 31 unmodified lines | ||
| 392 | 391 | sink_streams); |
| 393 | 392 | if (ret) |
| 394 | 393 | dev_err(xbar->isi->dev, |
| 395 | − "failed to %s streams 0x%llx on '%s':%u: %d\n", | |
| 396 | − "disable", sink_streams, remote_sd->name, | |
| 397 | − remote_pad, ret); | |
| 394 | + "failed to disable streams 0x%llx on '%s':%u: %d\n", | |
| 395 | + sink_streams, remote_sd->name, remote_pad, ret); | |
| 398 | 396 | |
| 399 | 397 | mxc_isi_crossbar_gasket_disable(xbar, sink_pad); |
| 400 | 398 | } |
| @@ -453,7 +451,7 @@ int mxc_isi_crossbar_init(struct mxc_isi_dev *isi) · 52 unmodified lines | ||
| 453 | 451 | * the memory input. |
| 454 | 452 | */ |
| 455 | 453 | xbar->num_sinks = isi->pdata->num_ports + 1; |
| 456 | − xbar->num_sources = isi->pdata->num_ports; | |
| 454 | + xbar->num_sources = isi->pdata->num_channels; | |
| 457 | 455 | num_pads = xbar->num_sinks + xbar->num_sources; |
| 458 | 456 | |
| 459 | 457 | xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL); |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright (C) 2021 Purism SPC |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | +#include <linux/bitfield.h> | |
| 8 | 9 | #include <linux/clk.h> |
| 9 | 10 | #include <linux/clk-provider.h> |
| 10 | 11 | #include <linux/delay.h> |
| @@ -62,6 +63,8 @@ · 51 unmodified lines | ||
| 62 | 63 | #define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 |
| 63 | 64 | #define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 |
| 64 | 65 | |
| 66 | +struct csi_state; | |
| 67 | + | |
| 65 | 68 | enum { |
| 66 | 69 | ST_POWERED = 1, |
| 67 | 70 | ST_STREAMING = 2, |
| @@ -83,11 +86,11 @@ static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { · 15 unmodified lines | ||
| 83 | 86 | |
| 84 | 87 | #define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) |
| 85 | 88 | |
| 86 | −#define GPR_CSI2_1_RX_ENABLE BIT(13) | |
| 87 | −#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) | |
| 88 | −#define GPR_CSI2_1_HSEL BIT(10) | |
| 89 | −#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) | |
| 90 | −#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) | |
| 89 | +struct imx8mq_plat_data { | |
| 90 | + int (*enable)(struct csi_state *state, u32 hs_settle); | |
| 91 | + void (*disable)(struct csi_state *state); | |
| 92 | + bool use_reg_csr; | |
| 93 | +}; | |
| 91 | 94 | |
| 92 | 95 | /* |
| 93 | 96 | * The send level configures the number of entries that must accumulate in |
| @@ -106,6 +109,7 @@ static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { · 12 unmodified lines | ||
| 106 | 109 | |
| 107 | 110 | struct csi_state { |
| 108 | 111 | struct device *dev; |
| 112 | + const struct imx8mq_plat_data *pdata; | |
| 109 | 113 | void __iomem *regs; |
| 110 | 114 | struct clk_bulk_data clks[CSI2_NUM_CLKS]; |
| 111 | 115 | struct reset_control *rst; |
| @@ -137,6 +141,123 @@ struct csi2_pix_format { · 25 unmodified lines | ||
| 137 | 141 | u8 width; |
| 138 | 142 | }; |
| 139 | 143 | |
| 144 | +/* ----------------------------------------------------------------------------- | |
| 145 | + * i.MX8MQ GPR | |
| 146 | + */ | |
| 147 | + | |
| 148 | +#define GPR_CSI2_1_RX_ENABLE BIT(13) | |
| 149 | +#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) | |
| 150 | +#define GPR_CSI2_1_HSEL BIT(10) | |
| 151 | +#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) | |
| 152 | +#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) | |
| 153 | + | |
| 154 | +static int imx8mq_gpr_enable(struct csi_state *state, u32 hs_settle) | |
| 155 | +{ | |
| 156 | + regmap_update_bits(state->phy_gpr, | |
| 157 | + state->phy_gpr_reg, | |
| 158 | + 0x3fff, | |
| 159 | + GPR_CSI2_1_RX_ENABLE | | |
| 160 | + GPR_CSI2_1_VID_INTFC_ENB | | |
| 161 | + GPR_CSI2_1_HSEL | | |
| 162 | + GPR_CSI2_1_CONT_CLK_MODE | | |
| 163 | + GPR_CSI2_1_S_PRG_RXHS_SETTLE(hs_settle)); | |
| 164 | + | |
| 165 | + return 0; | |
| 166 | +} | |
| 167 | + | |
| 168 | +static const struct imx8mq_plat_data imx8mq_data = { | |
| 169 | + .enable = imx8mq_gpr_enable, | |
| 170 | +}; | |
| 171 | + | |
| 172 | +/* ----------------------------------------------------------------------------- | |
| 173 | + * i.MX8QXP | |
| 174 | + */ | |
| 175 | + | |
| 176 | +#define CSI2SS_PL_CLK_INTERVAL_US 100 | |
| 177 | +#define CSI2SS_PL_CLK_TIMEOUT_US 100000 | |
| 178 | + | |
| 179 | +#define CSI2SS_PLM_CTRL 0x0 | |
| 180 | +#define CSI2SS_PLM_CTRL_ENABLE_PL BIT(0) | |
| 181 | +#define CSI2SS_PLM_CTRL_VSYNC_OVERRIDE BIT(9) | |
| 182 | +#define CSI2SS_PLM_CTRL_HSYNC_OVERRIDE BIT(10) | |
| 183 | +#define CSI2SS_PLM_CTRL_VALID_OVERRIDE BIT(11) | |
| 184 | +#define CSI2SS_PLM_CTRL_POLARITY_HIGH BIT(12) | |
| 185 | +#define CSI2SS_PLM_CTRL_PL_CLK_RUN BIT(31) | |
| 186 | + | |
| 187 | +#define CSI2SS_PHY_CTRL 0x4 | |
| 188 | +#define CSI2SS_PHY_CTRL_RX_ENABLE BIT(0) | |
| 189 | +#define CSI2SS_PHY_CTRL_AUTO_PD_EN BIT(1) | |
| 190 | +#define CSI2SS_PHY_CTRL_DDRCLK_EN BIT(2) | |
| 191 | +#define CSI2SS_PHY_CTRL_CONT_CLK_MODE BIT(3) | |
| 192 | +#define CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK GENMASK(9, 4) | |
| 193 | +#define CSI2SS_PHY_CTRL_RTERM_SEL BIT(21) | |
| 194 | +#define CSI2SS_PHY_CTRL_PD BIT(22) | |
| 195 | + | |
| 196 | +#define CSI2SS_DATA_TYPE_DISABLE_BF 0x38 | |
| 197 | +#define CSI2SS_DATA_TYPE_DISABLE_BF_MASK GENMASK(23, 0) | |
| 198 | + | |
| 199 | +#define CSI2SS_CTRL_CLK_RESET 0x44 | |
| 200 | +#define CSI2SS_CTRL_CLK_RESET_EN BIT(0) | |
| 201 | + | |
| 202 | +static int imx8qxp_gpr_enable(struct csi_state *state, u32 hs_settle) | |
| 203 | +{ | |
| 204 | + int ret; | |
| 205 | + u32 val; | |
| 206 | + | |
| 207 | + /* Clear format */ | |
| 208 | + regmap_clear_bits(state->phy_gpr, CSI2SS_DATA_TYPE_DISABLE_BF, | |
| 209 | + CSI2SS_DATA_TYPE_DISABLE_BF_MASK); | |
| 210 | + | |
| 211 | + regmap_write(state->phy_gpr, CSI2SS_PLM_CTRL, 0x0); | |
| 212 | + | |
| 213 | + regmap_write(state->phy_gpr, CSI2SS_PHY_CTRL, | |
| 214 | + FIELD_PREP(CSI2SS_PHY_CTRL_RX_HS_SETTLE_MASK, hs_settle) | | |
| 215 | + CSI2SS_PHY_CTRL_RX_ENABLE | CSI2SS_PHY_CTRL_DDRCLK_EN | | |
| 216 | + CSI2SS_PHY_CTRL_CONT_CLK_MODE | CSI2SS_PHY_CTRL_PD | | |
| 217 | + CSI2SS_PHY_CTRL_RTERM_SEL | CSI2SS_PHY_CTRL_AUTO_PD_EN); | |
| 218 | + | |
| 219 | + ret = regmap_read_poll_timeout(state->phy_gpr, CSI2SS_PLM_CTRL, | |
| 220 | + val, !(val & CSI2SS_PLM_CTRL_PL_CLK_RUN), | |
| 221 | + CSI2SS_PL_CLK_INTERVAL_US, | |
| 222 | + CSI2SS_PL_CLK_TIMEOUT_US); | |
| 223 | + | |
| 224 | + if (ret) { | |
| 225 | + dev_err(state->dev, "Timeout waiting for Pixel-Link clock\n"); | |
| 226 | + return ret; | |
| 227 | + } | |
| 228 | + | |
| 229 | + /* Enable Pixel link Master */ | |
| 230 | + regmap_set_bits(state->phy_gpr, CSI2SS_PLM_CTRL, | |
| 231 | + CSI2SS_PLM_CTRL_ENABLE_PL | CSI2SS_PLM_CTRL_VALID_OVERRIDE); | |
| 232 | + | |
| 233 | + /* PHY Enable */ | |
| 234 | + regmap_clear_bits(state->phy_gpr, CSI2SS_PHY_CTRL, | |
| 235 | + CSI2SS_PHY_CTRL_PD | CSI2SS_PLM_CTRL_POLARITY_HIGH); | |
| 236 | + | |
| 237 | + /* Release Reset */ | |
| 238 | + regmap_set_bits(state->phy_gpr, CSI2SS_CTRL_CLK_RESET, CSI2SS_CTRL_CLK_RESET_EN); | |
| 239 | + | |
| 240 | + return ret; | |
| 241 | +} | |
| 242 | + | |
| 243 | +static void imx8qxp_gpr_disable(struct csi_state *state) | |
| 244 | +{ | |
| 245 | + /* Disable Pixel Link */ | |
| 246 | + regmap_write(state->phy_gpr, CSI2SS_PLM_CTRL, 0x0); | |
| 247 | + | |
| 248 | + /* Disable PHY */ | |
| 249 | + regmap_write(state->phy_gpr, CSI2SS_PHY_CTRL, 0x0); | |
| 250 | + | |
| 251 | + regmap_clear_bits(state->phy_gpr, CSI2SS_CTRL_CLK_RESET, | |
| 252 | + CSI2SS_CTRL_CLK_RESET_EN); | |
| 253 | +}; | |
| 254 | + | |
| 255 | +static const struct imx8mq_plat_data imx8qxp_data = { | |
| 256 | + .enable = imx8qxp_gpr_enable, | |
| 257 | + .disable = imx8qxp_gpr_disable, | |
| 258 | + .use_reg_csr = true, | |
| 259 | +}; | |
| 260 | + | |
| 140 | 261 | static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { |
| 141 | 262 | /* RAW (Bayer and greyscale) formats. */ |
| 142 | 263 | { |
| @@ -371,14 +492,9 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, · 228 unmodified lines | ||
| 371 | 492 | if (ret) |
| 372 | 493 | return ret; |
| 373 | 494 | |
| 374 | − regmap_update_bits(state->phy_gpr, | |
| 375 | − state->phy_gpr_reg, | |
| 376 | − 0x3fff, | |
| 377 | − GPR_CSI2_1_RX_ENABLE | | |
| 378 | − GPR_CSI2_1_VID_INTFC_ENB | | |
| 379 | − GPR_CSI2_1_HSEL | | |
| 380 | − GPR_CSI2_1_CONT_CLK_MODE | | |
| 381 | − GPR_CSI2_1_S_PRG_RXHS_SETTLE(hs_settle)); | |
| 495 | + ret = state->pdata->enable(state, hs_settle); | |
| 496 | + if (ret) | |
| 497 | + return ret; | |
| 382 | 498 | |
| 383 | 499 | return 0; |
| 384 | 500 | } |
| @@ -386,6 +502,9 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, · 1 unmodified line | ||
| 386 | 502 | static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) |
| 387 | 503 | { |
| 388 | 504 | imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, 0xf); |
| 505 | + | |
| 506 | + if (state->pdata->disable) | |
| 507 | + state->pdata->disable(state); | |
| 389 | 508 | } |
| 390 | 509 | |
| 391 | 510 | /* ----------------------------------------------------------------------------- |
| @@ -837,6 +956,25 @@ static int imx8mq_mipi_csi_parse_dt(struct csi_state *state) · 445 unmodified lines | ||
| 837 | 956 | return PTR_ERR(state->rst); |
| 838 | 957 | } |
| 839 | 958 | |
| 959 | + if (state->pdata->use_reg_csr) { | |
| 960 | + const struct regmap_config regmap_config = { | |
| 961 | + .reg_bits = 32, | |
| 962 | + .val_bits = 32, | |
| 963 | + .reg_stride = 4, | |
| 964 | + }; | |
| 965 | + void __iomem *base; | |
| 966 | + | |
| 967 | + base = devm_platform_ioremap_resource(to_platform_device(dev), 1); | |
| 968 | + if (IS_ERR(base)) | |
| 969 | + return dev_err_probe(dev, PTR_ERR(base), "Missing CSR register\n"); | |
| 970 | + | |
| 971 | + state->phy_gpr = devm_regmap_init_mmio(dev, base, ®map_config); | |
| 972 | + if (IS_ERR(state->phy_gpr)) | |
| 973 | + return dev_err_probe(dev, PTR_ERR(state->phy_gpr), | |
| 974 | + "Failed to init CSI MMIO regmap\n"); | |
| 975 | + return 0; | |
| 976 | + } | |
| 977 | + | |
| 840 | 978 | ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, |
| 841 | 979 | ARRAY_SIZE(out_val)); |
| 842 | 980 | if (ret) { |
| @@ -876,6 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev) · 33 unmodified lines | ||
| 876 | 1014 | |
| 877 | 1015 | state->dev = dev; |
| 878 | 1016 | |
| 1017 | + state->pdata = of_device_get_match_data(dev); | |
| 1018 | + | |
| 879 | 1019 | ret = imx8mq_mipi_csi_parse_dt(state); |
| 880 | 1020 | if (ret < 0) { |
| 881 | 1021 | dev_err(dev, "Failed to parse device tree: %d\n", ret); |
| @@ -953,7 +1093,8 @@ static void imx8mq_mipi_csi_remove(struct platform_device *pdev) · 71 unmodified lines | ||
| 953 | 1093 | } |
| 954 | 1094 | |
| 955 | 1095 | static const struct of_device_id imx8mq_mipi_csi_of_match[] = { |
| 956 | − { .compatible = "fsl,imx8mq-mipi-csi2", }, | |
| 1096 | + { .compatible = "fsl,imx8mq-mipi-csi2", .data = &imx8mq_data }, | |
| 1097 | + { .compatible = "fsl,imx8qxp-mipi-csi2", .data = &imx8qxp_data }, | |
| 957 | 1098 | { /* sentinel */ }, |
| 958 | 1099 | }; |
| 959 | 1100 | MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); |
| @@ -849,8 +849,7 @@ static int csiphy_init(struct csiphy_device *csiphy) · 848 unmodified lines | ||
| 849 | 849 | regs->offset = 0x1000; |
| 850 | 850 | break; |
| 851 | 851 | default: |
| 852 | − WARN(1, "unknown csiphy version\n"); | |
| 853 | − return -ENODEV; | |
| 852 | + break; | |
| 854 | 853 | } |
| 855 | 854 | |
| 856 | 855 | return 0; |
| @@ -103,11 +103,6 @@ const struct csiphy_formats csiphy_formats_8x96 = { · 102 unmodified lines | ||
| 103 | 103 | .formats = formats_8x96 |
| 104 | 104 | }; |
| 105 | 105 | |
| 106 | −const struct csiphy_formats csiphy_formats_sc7280 = { | |
| 107 | − .nformats = ARRAY_SIZE(formats_sdm845), | |
| 108 | − .formats = formats_sdm845 | |
| 109 | −}; | |
| 110 | − | |
| 111 | 106 | const struct csiphy_formats csiphy_formats_sdm845 = { |
| 112 | 107 | .nformats = ARRAY_SIZE(formats_sdm845), |
| 113 | 108 | .formats = formats_sdm845 |
| @@ -126,7 +126,6 @@ void msm_csiphy_unregister_entity(struct csiphy_device *csiphy); · 125 unmodified lines | ||
| 126 | 126 | |
| 127 | 127 | extern const struct csiphy_formats csiphy_formats_8x16; |
| 128 | 128 | extern const struct csiphy_formats csiphy_formats_8x96; |
| 129 | −extern const struct csiphy_formats csiphy_formats_sc7280; | |
| 130 | 129 | extern const struct csiphy_formats csiphy_formats_sdm845; |
| 131 | 130 | |
| 132 | 131 | extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0; |
| @@ -225,6 +225,21 @@ static int video_check_format(struct camss_video *video) · 224 unmodified lines | ||
| 225 | 225 | return 0; |
| 226 | 226 | } |
| 227 | 227 | |
| 228 | +static int video_prepare_streaming(struct vb2_queue *q) | |
| 229 | +{ | |
| 230 | + struct camss_video *video = vb2_get_drv_priv(q); | |
| 231 | + struct video_device *vdev = &video->vdev; | |
| 232 | + int ret; | |
| 233 | + | |
| 234 | + ret = v4l2_pipeline_pm_get(&vdev->entity); | |
| 235 | + if (ret < 0) { | |
| 236 | + dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", | |
| 237 | + ret); | |
| 238 | + } | |
| 239 | + | |
| 240 | + return ret; | |
| 241 | +} | |
| 242 | + | |
| 228 | 243 | static int video_start_streaming(struct vb2_queue *q, unsigned int count) |
| 229 | 244 | { |
| 230 | 245 | struct camss_video *video = vb2_get_drv_priv(q); |
| @@ -308,13 +323,23 @@ static void video_stop_streaming(struct vb2_queue *q) · 77 unmodified lines | ||
| 308 | 323 | video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); |
| 309 | 324 | } |
| 310 | 325 | |
| 326 | +static void video_unprepare_streaming(struct vb2_queue *q) | |
| 327 | +{ | |
| 328 | + struct camss_video *video = vb2_get_drv_priv(q); | |
| 329 | + struct video_device *vdev = &video->vdev; | |
| 330 | + | |
| 331 | + v4l2_pipeline_pm_put(&vdev->entity); | |
| 332 | +} | |
| 333 | + | |
| 311 | 334 | static const struct vb2_ops msm_video_vb2_q_ops = { |
| 312 | 335 | .queue_setup = video_queue_setup, |
| 313 | 336 | .buf_init = video_buf_init, |
| 314 | 337 | .buf_prepare = video_buf_prepare, |
| 315 | 338 | .buf_queue = video_buf_queue, |
| 339 | + .prepare_streaming = video_prepare_streaming, | |
| 316 | 340 | .start_streaming = video_start_streaming, |
| 317 | 341 | .stop_streaming = video_stop_streaming, |
| 342 | + .unprepare_streaming = video_unprepare_streaming, | |
| 318 | 343 | }; |
| 319 | 344 | |
| 320 | 345 | /* ----------------------------------------------------------------------------- |
| @@ -599,20 +624,10 @@ static int video_open(struct file *file) · 278 unmodified lines | ||
| 599 | 624 | |
| 600 | 625 | file->private_data = vfh; |
| 601 | 626 | |
| 602 | − ret = v4l2_pipeline_pm_get(&vdev->entity); | |
| 603 | − if (ret < 0) { | |
| 604 | − dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", | |
| 605 | − ret); | |
| 606 | − goto error_pm_use; | |
| 607 | − } | |
| 608 | − | |
| 609 | 627 | mutex_unlock(&video->lock); |
| 610 | 628 | |
| 611 | 629 | return 0; |
| 612 | 630 | |
| 613 | −error_pm_use: | |
| 614 | − v4l2_fh_release(file); | |
| 615 | − | |
| 616 | 631 | error_alloc: |
| 617 | 632 | mutex_unlock(&video->lock); |
| 618 | 633 | |
| @@ -621,12 +636,8 @@ error_alloc: · 2 unmodified lines | ||
| 621 | 636 | |
| 622 | 637 | static int video_release(struct file *file) |
| 623 | 638 | { |
| 624 | − struct video_device *vdev = video_devdata(file); | |
| 625 | − | |
| 626 | 639 | vb2_fop_release(file); |
| 627 | 640 | |
| 628 | − v4l2_pipeline_pm_put(&vdev->entity); | |
| 629 | − | |
| 630 | 641 | file->private_data = NULL; |
| 631 | 642 | |
| 632 | 643 | return 0; |
| @@ -1481,7 +1481,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 1480 unmodified lines | ||
| 1481 | 1481 | .csiphy = { |
| 1482 | 1482 | .id = 0, |
| 1483 | 1483 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1484 | − .formats = &csiphy_formats_sc7280 | |
| 1484 | + .formats = &csiphy_formats_sdm845, | |
| 1485 | 1485 | } |
| 1486 | 1486 | }, |
| 1487 | 1487 | /* CSIPHY1 */ |
| @@ -1496,7 +1496,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | ||
| 1496 | 1496 | .csiphy = { |
| 1497 | 1497 | .id = 1, |
| 1498 | 1498 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1499 | − .formats = &csiphy_formats_sc7280 | |
| 1499 | + .formats = &csiphy_formats_sdm845, | |
| 1500 | 1500 | } |
| 1501 | 1501 | }, |
| 1502 | 1502 | /* CSIPHY2 */ |
| @@ -1511,7 +1511,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | ||
| 1511 | 1511 | .csiphy = { |
| 1512 | 1512 | .id = 2, |
| 1513 | 1513 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1514 | − .formats = &csiphy_formats_sc7280 | |
| 1514 | + .formats = &csiphy_formats_sdm845, | |
| 1515 | 1515 | } |
| 1516 | 1516 | }, |
| 1517 | 1517 | /* CSIPHY3 */ |
| @@ -1526,7 +1526,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | ||
| 1526 | 1526 | .csiphy = { |
| 1527 | 1527 | .id = 3, |
| 1528 | 1528 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1529 | − .formats = &csiphy_formats_sc7280 | |
| 1529 | + .formats = &csiphy_formats_sdm845, | |
| 1530 | 1530 | } |
| 1531 | 1531 | }, |
| 1532 | 1532 | /* CSIPHY4 */ |
| @@ -1541,7 +1541,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | ||
| 1541 | 1541 | .csiphy = { |
| 1542 | 1542 | .id = 4, |
| 1543 | 1543 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1544 | − .formats = &csiphy_formats_sc7280 | |
| 1544 | + .formats = &csiphy_formats_sdm845, | |
| 1545 | 1545 | } |
| 1546 | 1546 | }, |
| 1547 | 1547 | }; |
| @@ -2486,8 +2486,8 @@ static const struct resources_icc icc_res_sm8550[] = { · 938 unmodified lines | ||
| 2486 | 2486 | static const struct camss_subdev_resources csiphy_res_x1e80100[] = { |
| 2487 | 2487 | /* CSIPHY0 */ |
| 2488 | 2488 | { |
| 2489 | − .regulators = { "vdd-csiphy-0p8-supply", | |
| 2490 | − "vdd-csiphy-1p2-supply" }, | |
| 2489 | + .regulators = { "vdd-csiphy-0p8", | |
| 2490 | + "vdd-csiphy-1p2" }, | |
| 2491 | 2491 | .clock = { "csiphy0", "csiphy0_timer" }, |
| 2492 | 2492 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2493 | 2493 | { 266666667, 400000000 } }, |
| @@ -2501,8 +2501,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | ||
| 2501 | 2501 | }, |
| 2502 | 2502 | /* CSIPHY1 */ |
| 2503 | 2503 | { |
| 2504 | − .regulators = { "vdd-csiphy-0p8-supply", | |
| 2505 | − "vdd-csiphy-1p2-supply" }, | |
| 2504 | + .regulators = { "vdd-csiphy-0p8", | |
| 2505 | + "vdd-csiphy-1p2" }, | |
| 2506 | 2506 | .clock = { "csiphy1", "csiphy1_timer" }, |
| 2507 | 2507 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2508 | 2508 | { 266666667, 400000000 } }, |
| @@ -2516,8 +2516,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | ||
| 2516 | 2516 | }, |
| 2517 | 2517 | /* CSIPHY2 */ |
| 2518 | 2518 | { |
| 2519 | − .regulators = { "vdd-csiphy-0p8-supply", | |
| 2520 | − "vdd-csiphy-1p2-supply" }, | |
| 2519 | + .regulators = { "vdd-csiphy-0p8", | |
| 2520 | + "vdd-csiphy-1p2" }, | |
| 2521 | 2521 | .clock = { "csiphy2", "csiphy2_timer" }, |
| 2522 | 2522 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2523 | 2523 | { 266666667, 400000000 } }, |
| @@ -2531,8 +2531,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | ||
| 2531 | 2531 | }, |
| 2532 | 2532 | /* CSIPHY4 */ |
| 2533 | 2533 | { |
| 2534 | − .regulators = { "vdd-csiphy-0p8-supply", | |
| 2535 | − "vdd-csiphy-1p2-supply" }, | |
| 2534 | + .regulators = { "vdd-csiphy-0p8", | |
| 2535 | + "vdd-csiphy-1p2" }, | |
| 2536 | 2536 | .clock = { "csiphy4", "csiphy4_timer" }, |
| 2537 | 2537 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2538 | 2538 | { 266666667, 400000000 } }, |
| @@ -3386,43 +3386,39 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) · 847 unmodified lines | ||
| 3386 | 3386 | struct camss *camss = container_of(async, struct camss, notifier); |
| 3387 | 3387 | struct v4l2_device *v4l2_dev = &camss->v4l2_dev; |
| 3388 | 3388 | struct v4l2_subdev *sd; |
| 3389 | − int ret; | |
| 3390 | 3389 | |
| 3391 | 3390 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { |
| 3392 | − if (sd->host_priv) { | |
| 3393 | − struct media_entity *sensor = &sd->entity; | |
| 3394 | − struct csiphy_device *csiphy = | |
| 3395 | − (struct csiphy_device *) sd->host_priv; | |
| 3396 | − struct media_entity *input = &csiphy->subdev.entity; | |
| 3397 | − unsigned int i; | |
| 3398 | − | |
| 3399 | − for (i = 0; i < sensor->num_pads; i++) { | |
| 3400 | − if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) | |
| 3401 | − break; | |
| 3402 | − } | |
| 3403 | − if (i == sensor->num_pads) { | |
| 3404 | − dev_err(camss->dev, | |
| 3405 | − "No source pad in external entity\n"); | |
| 3406 | − return -EINVAL; | |
| 3407 | − } | |
| 3391 | + struct csiphy_device *csiphy = sd->host_priv; | |
| 3392 | + struct media_entity *input, *sensor; | |
| 3393 | + unsigned int i; | |
| 3394 | + int ret; | |
| 3408 | 3395 | |
| 3409 | − ret = media_create_pad_link(sensor, i, | |
| 3410 | − input, MSM_CSIPHY_PAD_SINK, | |
| 3411 | − MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); | |
| 3412 | − if (ret < 0) { | |
| 3413 | − camss_link_err(camss, sensor->name, | |
| 3414 | − input->name, | |
| 3415 | − ret); | |
| 3416 | − return ret; | |
| 3417 | − } | |
| 3396 | + if (!csiphy) | |
| 3397 | + continue; | |
| 3398 | + | |
| 3399 | + input = &csiphy->subdev.entity; | |
| 3400 | + sensor = &sd->entity; | |
| 3401 | + | |
| 3402 | + for (i = 0; i < sensor->num_pads; i++) { | |
| 3403 | + if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) | |
| 3404 | + break; | |
| 3405 | + } | |
| 3406 | + if (i == sensor->num_pads) { | |
| 3407 | + dev_err(camss->dev, | |
| 3408 | + "No source pad in external entity\n"); | |
| 3409 | + return -EINVAL; | |
| 3418 | 3410 | } |
| 3419 | − } | |
| 3420 | 3411 | |
| 3421 | − ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); | |
| 3422 | − if (ret < 0) | |
| 3423 | − return ret; | |
| 3412 | + ret = media_create_pad_link(sensor, i, input, | |
| 3413 | + MSM_CSIPHY_PAD_SINK, | |
| 3414 | + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); | |
| 3415 | + if (ret < 0) { | |
| 3416 | + camss_link_err(camss, sensor->name, input->name, ret); | |
| 3417 | + return ret; | |
| 3418 | + } | |
| 3419 | + } | |
| 3424 | 3420 | |
| 3425 | − return media_device_register(&camss->media_dev); | |
| 3421 | + return v4l2_device_register_subdev_nodes(&camss->v4l2_dev); | |
| 3426 | 3422 | } |
| 3427 | 3423 | |
| 3428 | 3424 | static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { |
| @@ -3625,7 +3621,7 @@ static int camss_probe(struct platform_device *pdev) · 196 unmodified lines | ||
| 3625 | 3621 | ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); |
| 3626 | 3622 | if (ret < 0) { |
| 3627 | 3623 | dev_err(dev, "Failed to register V4L2 device: %d\n", ret); |
| 3628 | − goto err_genpd_cleanup; | |
| 3624 | + goto err_media_device_cleanup; | |
| 3629 | 3625 | } |
| 3630 | 3626 | |
| 3631 | 3627 | v4l2_async_nf_init(&camss->notifier, &camss->v4l2_dev); |
| @@ -3646,6 +3642,12 @@ static int camss_probe(struct platform_device *pdev) · 14 unmodified lines | ||
| 3646 | 3642 | if (ret < 0) |
| 3647 | 3643 | goto err_register_subdevs; |
| 3648 | 3644 | |
| 3645 | + ret = media_device_register(&camss->media_dev); | |
| 3646 | + if (ret < 0) { | |
| 3647 | + dev_err(dev, "Failed to register media device: %d\n", ret); | |
| 3648 | + goto err_register_subdevs; | |
| 3649 | + } | |
| 3650 | + | |
| 3649 | 3651 | if (num_subdevs) { |
| 3650 | 3652 | camss->notifier.ops = &camss_subdev_notifier_ops; |
| 3651 | 3653 | |
| @@ -3654,32 +3656,29 @@ static int camss_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 3654 | 3656 | dev_err(dev, |
| 3655 | 3657 | "Failed to register async subdev nodes: %d\n", |
| 3656 | 3658 | ret); |
| 3657 | − goto err_register_subdevs; | |
| 3659 | + goto err_media_device_unregister; | |
| 3658 | 3660 | } |
| 3659 | 3661 | } else { |
| 3660 | 3662 | ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); |
| 3661 | 3663 | if (ret < 0) { |
| 3662 | 3664 | dev_err(dev, "Failed to register subdev nodes: %d\n", |
| 3663 | 3665 | ret); |
| 3664 | − goto err_register_subdevs; | |
| 3665 | − } | |
| 3666 | − | |
| 3667 | − ret = media_device_register(&camss->media_dev); | |
| 3668 | − if (ret < 0) { | |
| 3669 | − dev_err(dev, "Failed to register media device: %d\n", | |
| 3670 | − ret); | |
| 3671 | − goto err_register_subdevs; | |
| 3666 | + goto err_media_device_unregister; | |
| 3672 | 3667 | } |
| 3673 | 3668 | } |
| 3674 | 3669 | |
| 3675 | 3670 | return 0; |
| 3676 | 3671 | |
| 3672 | +err_media_device_unregister: | |
| 3673 | + media_device_unregister(&camss->media_dev); | |
| 3677 | 3674 | err_register_subdevs: |
| 3678 | 3675 | camss_unregister_entities(camss); |
| 3679 | 3676 | err_v4l2_device_unregister: |
| 3680 | 3677 | v4l2_device_unregister(&camss->v4l2_dev); |
| 3681 | 3678 | v4l2_async_nf_cleanup(&camss->notifier); |
| 3682 | 3679 | pm_runtime_disable(dev); |
| 3680 | +err_media_device_cleanup: | |
| 3681 | + media_device_cleanup(&camss->media_dev); | |
| 3683 | 3682 | err_genpd_cleanup: |
| 3684 | 3683 | camss_genpd_cleanup(camss); |
| 3685 | 3684 | |
| @@ -205,6 +205,9 @@ static u32 iris_bitstream_buffer_size(struct iris_inst *inst) · 204 unmodified lines | ||
| 205 | 205 | if (num_mbs > NUM_MBS_4K) { |
| 206 | 206 | div_factor = 4; |
| 207 | 207 | base_res_mbs = caps->max_mbpf; |
| 208 | + } else { | |
| 209 | + if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 210 | + div_factor = 1; | |
| 208 | 211 | } |
| 209 | 212 | |
| 210 | 213 | /* |
| @@ -376,7 +379,7 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf · 165 unmodified lines | ||
| 376 | 379 | return 0; |
| 377 | 380 | } |
| 378 | 381 | |
| 379 | −int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) | |
| 382 | +static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force) | |
| 380 | 383 | { |
| 381 | 384 | const struct iris_platform_data *platform_data = inst->core->iris_platform_data; |
| 382 | 385 | struct iris_buffer *buf, *next; |
| @@ -396,6 +399,14 @@ int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) · 13 unmodified lines | ||
| 396 | 399 | for (i = 0; i < len; i++) { |
| 397 | 400 | buffers = &inst->buffers[internal_buf_type[i]]; |
| 398 | 401 | list_for_each_entry_safe(buf, next, &buffers->list, list) { |
| 402 | + /* | |
| 403 | + * during stream on, skip destroying internal(DPB) buffer | |
| 404 | + * if firmware did not return it. | |
| 405 | + * during close, destroy all buffers irrespectively. | |
| 406 | + */ | |
| 407 | + if (!force && buf->attr & BUF_ATTR_QUEUED) | |
| 408 | + continue; | |
| 409 | + | |
| 399 | 410 | ret = iris_destroy_internal_buffer(inst, buf); |
| 400 | 411 | if (ret) |
| 401 | 412 | return ret; |
| @@ -405,6 +416,16 @@ int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) · 3 unmodified lines | ||
| 405 | 416 | return 0; |
| 406 | 417 | } |
| 407 | 418 | |
| 419 | +int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane) | |
| 420 | +{ | |
| 421 | + return iris_destroy_internal_buffers(inst, plane, true); | |
| 422 | +} | |
| 423 | + | |
| 424 | +int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane) | |
| 425 | +{ | |
| 426 | + return iris_destroy_internal_buffers(inst, plane, false); | |
| 427 | +} | |
| 428 | + | |
| 408 | 429 | static int iris_release_internal_buffers(struct iris_inst *inst, |
| 409 | 430 | enum iris_buffer_type buffer_type) |
| 410 | 431 | { |
| @@ -593,10 +614,13 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) · 182 unmodified lines | ||
| 593 | 614 | |
| 594 | 615 | vb2 = &vbuf->vb2_buf; |
| 595 | 616 | |
| 596 | − if (buf->flags & V4L2_BUF_FLAG_ERROR) | |
| 617 | + if (buf->flags & V4L2_BUF_FLAG_ERROR) { | |
| 597 | 618 | state = VB2_BUF_STATE_ERROR; |
| 598 | − else | |
| 599 | − state = VB2_BUF_STATE_DONE; | |
| 619 | + vb2_set_plane_payload(vb2, 0, 0); | |
| 620 | + vb2->timestamp = 0; | |
| 621 | + v4l2_m2m_buf_done(vbuf, state); | |
| 622 | + return 0; | |
| 623 | + } | |
| 600 | 624 | |
| 601 | 625 | vbuf->flags |= buf->flags; |
| 602 | 626 | |
| @@ -615,7 +639,10 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) · 12 unmodified lines | ||
| 615 | 639 | v4l2_event_queue_fh(&inst->fh, &ev); |
| 616 | 640 | v4l2_m2m_mark_stopped(m2m_ctx); |
| 617 | 641 | } |
| 642 | + inst->last_buffer_dequeued = true; | |
| 618 | 643 | } |
| 644 | + | |
| 645 | + state = VB2_BUF_STATE_DONE; | |
| 619 | 646 | vb2->timestamp = buf->timestamp; |
| 620 | 647 | v4l2_m2m_buf_done(vbuf, state); |
| 621 | 648 | |
| @@ -106,7 +106,8 @@ void iris_get_internal_buffers(struct iris_inst *inst, u32 plane); · 105 unmodified lines | ||
| 106 | 106 | int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); |
| 107 | 107 | int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); |
| 108 | 108 | int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); |
| 109 | −int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane); | |
| 109 | +int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane); | |
| 110 | +int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane); | |
| 110 | 111 | int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst); |
| 111 | 112 | int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst); |
| 112 | 113 | int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf); |
| @@ -17,12 +17,20 @@ static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) · 16 unmodified lines | ||
| 17 | 17 | static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) |
| 18 | 18 | { |
| 19 | 19 | switch (id) { |
| 20 | − case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: | |
| 21 | − return DEBLOCK; | |
| 22 | 20 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: |
| 23 | − return PROFILE; | |
| 21 | + return PROFILE_H264; | |
| 22 | + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: | |
| 23 | + return PROFILE_HEVC; | |
| 24 | + case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: | |
| 25 | + return PROFILE_VP9; | |
| 24 | 26 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: |
| 25 | − return LEVEL; | |
| 27 | + return LEVEL_H264; | |
| 28 | + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: | |
| 29 | + return LEVEL_HEVC; | |
| 30 | + case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: | |
| 31 | + return LEVEL_VP9; | |
| 32 | + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: | |
| 33 | + return TIER; | |
| 26 | 34 | default: |
| 27 | 35 | return INST_FW_CAP_MAX; |
| 28 | 36 | } |
| @@ -34,12 +42,20 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) · 5 unmodified lines | ||
| 34 | 42 | return 0; |
| 35 | 43 | |
| 36 | 44 | switch (cap_id) { |
| 37 | − case DEBLOCK: | |
| 38 | − return V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER; | |
| 39 | − case PROFILE: | |
| 45 | + case PROFILE_H264: | |
| 40 | 46 | return V4L2_CID_MPEG_VIDEO_H264_PROFILE; |
| 41 | − case LEVEL: | |
| 47 | + case PROFILE_HEVC: | |
| 48 | + return V4L2_CID_MPEG_VIDEO_HEVC_PROFILE; | |
| 49 | + case PROFILE_VP9: | |
| 50 | + return V4L2_CID_MPEG_VIDEO_VP9_PROFILE; | |
| 51 | + case LEVEL_H264: | |
| 42 | 52 | return V4L2_CID_MPEG_VIDEO_H264_LEVEL; |
| 53 | + case LEVEL_HEVC: | |
| 54 | + return V4L2_CID_MPEG_VIDEO_HEVC_LEVEL; | |
| 55 | + case LEVEL_VP9: | |
| 56 | + return V4L2_CID_MPEG_VIDEO_VP9_LEVEL; | |
| 57 | + case TIER: | |
| 58 | + return V4L2_CID_MPEG_VIDEO_HEVC_TIER; | |
| 43 | 59 | default: |
| 44 | 60 | return 0; |
| 45 | 61 | } |
| @@ -84,8 +100,6 @@ int iris_ctrls_init(struct iris_inst *inst) · 38 unmodified lines | ||
| 84 | 100 | if (iris_get_v4l2_id(cap[idx].cap_id)) |
| 85 | 101 | num_ctrls++; |
| 86 | 102 | } |
| 87 | − if (!num_ctrls) | |
| 88 | − return -EINVAL; | |
| 89 | 103 | |
| 90 | 104 | /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ |
| 91 | 105 | |
| @@ -163,6 +177,7 @@ void iris_session_init_caps(struct iris_core *core) · 71 unmodified lines | ||
| 163 | 177 | core->inst_fw_caps[cap_id].value = caps[i].value; |
| 164 | 178 | core->inst_fw_caps[cap_id].flags = caps[i].flags; |
| 165 | 179 | core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; |
| 180 | + core->inst_fw_caps[cap_id].set = caps[i].set; | |
| 166 | 181 | } |
| 167 | 182 | } |
| 168 | 183 | |
| @@ -140,6 +140,7 @@ struct hfi_subscription_params { · 139 unmodified lines | ||
| 140 | 140 | u32 color_info; |
| 141 | 141 | u32 profile; |
| 142 | 142 | u32 level; |
| 143 | + u32 tier; | |
| 143 | 144 | }; |
| 144 | 145 | |
| 145 | 146 | u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries); |
| @@ -88,16 +88,29 @@ static int iris_hfi_gen1_sys_pc_prep(struct iris_core *core) · 87 unmodified lines | ||
| 88 | 88 | static int iris_hfi_gen1_session_open(struct iris_inst *inst) |
| 89 | 89 | { |
| 90 | 90 | struct hfi_session_open_pkt packet; |
| 91 | + u32 codec = 0; | |
| 91 | 92 | int ret; |
| 92 | 93 | |
| 93 | 94 | if (inst->state != IRIS_INST_DEINIT) |
| 94 | 95 | return -EALREADY; |
| 95 | 96 | |
| 97 | + switch (inst->codec) { | |
| 98 | + case V4L2_PIX_FMT_H264: | |
| 99 | + codec = HFI_VIDEO_CODEC_H264; | |
| 100 | + break; | |
| 101 | + case V4L2_PIX_FMT_HEVC: | |
| 102 | + codec = HFI_VIDEO_CODEC_HEVC; | |
| 103 | + break; | |
| 104 | + case V4L2_PIX_FMT_VP9: | |
| 105 | + codec = HFI_VIDEO_CODEC_VP9; | |
| 106 | + break; | |
| 107 | + } | |
| 108 | + | |
| 96 | 109 | packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); |
| 97 | 110 | packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; |
| 98 | 111 | packet.shdr.session_id = inst->session_id; |
| 99 | 112 | packet.session_domain = HFI_SESSION_TYPE_DEC; |
| 100 | − packet.session_codec = HFI_VIDEO_CODEC_H264; | |
| 113 | + packet.session_codec = codec; | |
| 101 | 114 | |
| 102 | 115 | reinit_completion(&inst->completion); |
| 103 | 116 | |
| @@ -208,8 +221,10 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) · 104 unmodified lines | ||
| 208 | 221 | flush_pkt.flush_type = flush_type; |
| 209 | 222 | |
| 210 | 223 | ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); |
| 211 | − if (!ret) | |
| 224 | + if (!ret) { | |
| 225 | + inst->flush_responses_pending++; | |
| 212 | 226 | ret = iris_wait_for_session_response(inst, true); |
| 227 | + } | |
| 213 | 228 | } |
| 214 | 229 | |
| 215 | 230 | return ret; |
| @@ -386,6 +401,8 @@ static int iris_hfi_gen1_session_drain(struct iris_inst *inst, u32 plane) · 170 unmodified lines | ||
| 386 | 401 | ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; |
| 387 | 402 | ip_pkt.shdr.session_id = inst->session_id; |
| 388 | 403 | ip_pkt.flags = HFI_BUFFERFLAG_EOS; |
| 404 | + if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 405 | + ip_pkt.packet_buffer = 0xdeadb000; | |
| 389 | 406 | |
| 390 | 407 | return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); |
| 391 | 408 | } |
| @@ -490,14 +507,6 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p · 98 unmodified lines | ||
| 490 | 507 | packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); |
| 491 | 508 | break; |
| 492 | 509 | } |
| 493 | − case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: { | |
| 494 | − struct hfi_enable *en = prop_data; | |
| 495 | − u32 *in = pdata; | |
| 496 | − | |
| 497 | − en->enable = *in; | |
| 498 | − packet->shdr.hdr.size += sizeof(u32) + sizeof(*en); | |
| 499 | − break; | |
| 500 | − } | |
| 501 | 510 | default: |
| 502 | 511 | return -EINVAL; |
| 503 | 512 | } |
| @@ -546,14 +555,15 @@ static int iris_hfi_gen1_set_resolution(struct iris_inst *inst) · 42 unmodified lines | ||
| 546 | 555 | struct hfi_framesize fs; |
| 547 | 556 | int ret; |
| 548 | 557 | |
| 549 | − fs.buffer_type = HFI_BUFFER_INPUT; | |
| 550 | − fs.width = inst->fmt_src->fmt.pix_mp.width; | |
| 551 | − fs.height = inst->fmt_src->fmt.pix_mp.height; | |
| 552 | − | |
| 553 | − ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); | |
| 554 | − if (ret) | |
| 555 | − return ret; | |
| 558 | + if (!iris_drc_pending(inst)) { | |
| 559 | + fs.buffer_type = HFI_BUFFER_INPUT; | |
| 560 | + fs.width = inst->fmt_src->fmt.pix_mp.width; | |
| 561 | + fs.height = inst->fmt_src->fmt.pix_mp.height; | |
| 556 | 562 | |
| 563 | + ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); | |
| 564 | + if (ret) | |
| 565 | + return ret; | |
| 566 | + } | |
| 557 | 567 | fs.buffer_type = HFI_BUFFER_OUTPUT2; |
| 558 | 568 | fs.width = inst->fmt_dst->fmt.pix_mp.width; |
| 559 | 569 | fs.height = inst->fmt_dst->fmt.pix_mp.height; |
| @@ -768,8 +778,8 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p · 208 unmodified lines | ||
| 768 | 778 | iris_hfi_gen1_set_bufsize}, |
| 769 | 779 | }; |
| 770 | 780 | |
| 771 | − config_params = core->iris_platform_data->input_config_params; | |
| 772 | − config_params_size = core->iris_platform_data->input_config_params_size; | |
| 781 | + config_params = core->iris_platform_data->input_config_params_default; | |
| 782 | + config_params_size = core->iris_platform_data->input_config_params_default_size; | |
| 773 | 783 | |
| 774 | 784 | if (V4L2_TYPE_IS_OUTPUT(plane)) { |
| 775 | 785 | for (i = 0; i < config_params_size; i++) { |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | ||
| 13 | 13 | #define HFI_SESSION_TYPE_DEC 2 |
| 14 | 14 | |
| 15 | 15 | #define HFI_VIDEO_CODEC_H264 0x00000002 |
| 16 | +#define HFI_VIDEO_CODEC_HEVC 0x00002000 | |
| 17 | +#define HFI_VIDEO_CODEC_VP9 0x00004000 | |
| 16 | 18 | |
| 17 | 19 | #define HFI_ERR_NONE 0x0 |
| 18 | 20 | |
| @@ -65,7 +67,6 @@ · 46 unmodified lines | ||
| 65 | 67 | |
| 66 | 68 | #define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 |
| 67 | 69 | |
| 68 | −#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER 0x1200001 | |
| 69 | 70 | #define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e |
| 70 | 71 | #define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 |
| 71 | 72 | |
| @@ -117,6 +118,8 @@ · 45 unmodified lines | ||
| 117 | 118 | #define HFI_FRAME_NOTCODED 0x7f002000 |
| 118 | 119 | #define HFI_FRAME_YUV 0x7f004000 |
| 119 | 120 | #define HFI_UNUSED_PICT 0x10000000 |
| 121 | +#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 | |
| 122 | +#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 | |
| 120 | 123 | |
| 121 | 124 | struct hfi_pkt_hdr { |
| 122 | 125 | u32 size; |
| @@ -200,14 +200,14 @@ static void iris_hfi_gen1_event_seq_changed(struct iris_inst *inst, · 199 unmodified lines | ||
| 200 | 200 | |
| 201 | 201 | iris_hfi_gen1_read_changed_params(inst, pkt); |
| 202 | 202 | |
| 203 | − if (inst->state != IRIS_INST_ERROR) { | |
| 204 | − reinit_completion(&inst->flush_completion); | |
| 203 | + if (inst->state != IRIS_INST_ERROR && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { | |
| 205 | 204 | |
| 206 | 205 | flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); |
| 207 | 206 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; |
| 208 | 207 | flush_pkt.shdr.session_id = inst->session_id; |
| 209 | 208 | flush_pkt.flush_type = HFI_FLUSH_OUTPUT; |
| 210 | − iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size); | |
| 209 | + if (!iris_hfi_queue_cmd_write(inst->core, &flush_pkt, flush_pkt.shdr.hdr.size)) | |
| 210 | + inst->flush_responses_pending++; | |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | iris_vdec_src_change(inst); |
| @@ -348,6 +348,10 @@ static void iris_hfi_gen1_session_etb_done(struct iris_inst *inst, void *packet) · 134 unmodified lines | ||
| 348 | 348 | struct iris_buffer *buf = NULL; |
| 349 | 349 | bool found = false; |
| 350 | 350 | |
| 351 | + /* EOS buffer sent via drain won't be in v4l2 buffer list */ | |
| 352 | + if (pkt->packet_buffer == 0xdeadb000) | |
| 353 | + return; | |
| 354 | + | |
| 351 | 355 | v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { |
| 352 | 356 | buf = to_iris_buffer(&m2m_buffer->vb); |
| 353 | 357 | if (buf->index == pkt->input_tag) { |
| @@ -408,7 +412,9 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) · 54 unmodified lines | ||
| 408 | 412 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; |
| 409 | 413 | flush_pkt.shdr.session_id = inst->session_id; |
| 410 | 414 | flush_pkt.flush_type = HFI_FLUSH_OUTPUT; |
| 411 | − iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); | |
| 415 | + if (!iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size)) | |
| 416 | + inst->flush_responses_pending++; | |
| 417 | + | |
| 412 | 418 | iris_inst_sub_state_change_drain_last(inst); |
| 413 | 419 | |
| 414 | 420 | return; |
| @@ -455,7 +461,12 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) · 40 unmodified lines | ||
| 455 | 461 | timestamp_us = timestamp_hi; |
| 456 | 462 | timestamp_us = (timestamp_us << 32) | timestamp_lo; |
| 457 | 463 | } else { |
| 458 | − flags |= V4L2_BUF_FLAG_LAST; | |
| 464 | + if (pkt->stream_id == 1 && !inst->last_buffer_dequeued) { | |
| 465 | + if (iris_drc_pending(inst)) { | |
| 466 | + flags |= V4L2_BUF_FLAG_LAST; | |
| 467 | + inst->last_buffer_dequeued = true; | |
| 468 | + } | |
| 469 | + } | |
| 459 | 470 | } |
| 460 | 471 | buf->timestamp = timestamp_us; |
| 461 | 472 | |
| @@ -481,6 +492,12 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) · 19 unmodified lines | ||
| 481 | 492 | buf->attr |= BUF_ATTR_DEQUEUED; |
| 482 | 493 | buf->attr |= BUF_ATTR_BUFFER_DONE; |
| 483 | 494 | |
| 495 | + if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT) | |
| 496 | + flags |= V4L2_BUF_FLAG_ERROR; | |
| 497 | + | |
| 498 | + if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) | |
| 499 | + flags |= V4L2_BUF_FLAG_ERROR; | |
| 500 | + | |
| 484 | 501 | buf->flags |= flags; |
| 485 | 502 | |
| 486 | 503 | iris_vb2_buffer_done(inst, buf); |
| @@ -558,7 +575,6 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response · 71 unmodified lines | ||
| 558 | 575 | const struct iris_hfi_gen1_response_pkt_info *pkt_info; |
| 559 | 576 | struct device *dev = core->dev; |
| 560 | 577 | struct hfi_session_pkt *pkt; |
| 561 | − struct completion *done; | |
| 562 | 578 | struct iris_inst *inst; |
| 563 | 579 | bool found = false; |
| 564 | 580 | u32 i; |
| @@ -619,9 +635,12 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response · 54 unmodified lines | ||
| 619 | 635 | if (shdr->error_type != HFI_ERR_NONE) |
| 620 | 636 | iris_inst_change_state(inst, IRIS_INST_ERROR); |
| 621 | 637 | |
| 622 | − done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ? | |
| 623 | − &inst->flush_completion : &inst->completion; | |
| 624 | − complete(done); | |
| 638 | + if (pkt_info->pkt == HFI_MSG_SESSION_FLUSH) { | |
| 639 | + if (!(--inst->flush_responses_pending)) | |
| 640 | + complete(&inst->flush_completion); | |
| 641 | + } else { | |
| 642 | + complete(&inst->completion); | |
| 643 | + } | |
| 625 | 644 | } |
| 626 | 645 | mutex_unlock(&inst->lock); |
| 627 | 646 | |
| @@ -178,7 +178,7 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst) · 177 unmodified lines | ||
| 178 | 178 | sizeof(u64)); |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | −static int iris_hfi_gen2_set_bit_dpeth(struct iris_inst *inst) | |
| 181 | +static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst) | |
| 182 | 182 | { |
| 183 | 183 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 184 | 184 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| @@ -295,7 +295,19 @@ static int iris_hfi_gen2_set_profile(struct iris_inst *inst) · 110 unmodified lines | ||
| 295 | 295 | { |
| 296 | 296 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 297 | 297 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| 298 | − u32 profile = inst->fw_caps[PROFILE].value; | |
| 298 | + u32 profile = 0; | |
| 299 | + | |
| 300 | + switch (inst->codec) { | |
| 301 | + case V4L2_PIX_FMT_HEVC: | |
| 302 | + profile = inst->fw_caps[PROFILE_HEVC].value; | |
| 303 | + break; | |
| 304 | + case V4L2_PIX_FMT_VP9: | |
| 305 | + profile = inst->fw_caps[PROFILE_VP9].value; | |
| 306 | + break; | |
| 307 | + case V4L2_PIX_FMT_H264: | |
| 308 | + profile = inst->fw_caps[PROFILE_H264].value; | |
| 309 | + break; | |
| 310 | + } | |
| 299 | 311 | |
| 300 | 312 | inst_hfi_gen2->src_subcr_params.profile = profile; |
| 301 | 313 | |
| @@ -312,7 +324,19 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst) · 10 unmodified lines | ||
| 312 | 324 | { |
| 313 | 325 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 314 | 326 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| 315 | − u32 level = inst->fw_caps[LEVEL].value; | |
| 327 | + u32 level = 0; | |
| 328 | + | |
| 329 | + switch (inst->codec) { | |
| 330 | + case V4L2_PIX_FMT_HEVC: | |
| 331 | + level = inst->fw_caps[LEVEL_HEVC].value; | |
| 332 | + break; | |
| 333 | + case V4L2_PIX_FMT_VP9: | |
| 334 | + level = inst->fw_caps[LEVEL_VP9].value; | |
| 335 | + break; | |
| 336 | + case V4L2_PIX_FMT_H264: | |
| 337 | + level = inst->fw_caps[LEVEL_H264].value; | |
| 338 | + break; | |
| 339 | + } | |
| 316 | 340 | |
| 317 | 341 | inst_hfi_gen2->src_subcr_params.level = level; |
| 318 | 342 | |
| @@ -367,18 +391,35 @@ static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst) · 48 unmodified lines | ||
| 367 | 391 | sizeof(u64)); |
| 368 | 392 | } |
| 369 | 393 | |
| 394 | +static int iris_hfi_gen2_set_tier(struct iris_inst *inst) | |
| 395 | +{ | |
| 396 | + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | |
| 397 | + u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 398 | + u32 tier = inst->fw_caps[TIER].value; | |
| 399 | + | |
| 400 | + inst_hfi_gen2->src_subcr_params.tier = tier; | |
| 401 | + | |
| 402 | + return iris_hfi_gen2_session_set_property(inst, | |
| 403 | + HFI_PROP_TIER, | |
| 404 | + HFI_HOST_FLAGS_NONE, | |
| 405 | + port, | |
| 406 | + HFI_PAYLOAD_U32_ENUM, | |
| 407 | + &tier, | |
| 408 | + sizeof(u32)); | |
| 409 | +} | |
| 410 | + | |
| 370 | 411 | static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) |
| 371 | 412 | { |
| 372 | 413 | struct iris_core *core = inst->core; |
| 373 | − u32 config_params_size, i, j; | |
| 374 | − const u32 *config_params; | |
| 414 | + u32 config_params_size = 0, i, j; | |
| 415 | + const u32 *config_params = NULL; | |
| 375 | 416 | int ret; |
| 376 | 417 | |
| 377 | 418 | static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = { |
| 378 | 419 | {HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution }, |
| 379 | 420 | {HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets }, |
| 380 | 421 | {HFI_PROP_CODED_FRAMES, iris_hfi_gen2_set_coded_frames }, |
| 381 | − {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, iris_hfi_gen2_set_bit_dpeth }, | |
| 422 | + {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, iris_hfi_gen2_set_bit_depth }, | |
| 382 | 423 | {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, iris_hfi_gen2_set_min_output_count }, |
| 383 | 424 | {HFI_PROP_PIC_ORDER_CNT_TYPE, iris_hfi_gen2_set_picture_order_count }, |
| 384 | 425 | {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, |
| @@ -386,11 +427,27 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p · 1 unmodified line | ||
| 386 | 427 | {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, |
| 387 | 428 | {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, |
| 388 | 429 | {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, |
| 430 | + {HFI_PROP_TIER, iris_hfi_gen2_set_tier }, | |
| 389 | 431 | }; |
| 390 | 432 | |
| 391 | 433 | if (V4L2_TYPE_IS_OUTPUT(plane)) { |
| 392 | − config_params = core->iris_platform_data->input_config_params; | |
| 393 | − config_params_size = core->iris_platform_data->input_config_params_size; | |
| 434 | + switch (inst->codec) { | |
| 435 | + case V4L2_PIX_FMT_H264: | |
| 436 | + config_params = core->iris_platform_data->input_config_params_default; | |
| 437 | + config_params_size = | |
| 438 | + core->iris_platform_data->input_config_params_default_size; | |
| 439 | + break; | |
| 440 | + case V4L2_PIX_FMT_HEVC: | |
| 441 | + config_params = core->iris_platform_data->input_config_params_hevc; | |
| 442 | + config_params_size = | |
| 443 | + core->iris_platform_data->input_config_params_hevc_size; | |
| 444 | + break; | |
| 445 | + case V4L2_PIX_FMT_VP9: | |
| 446 | + config_params = core->iris_platform_data->input_config_params_vp9; | |
| 447 | + config_params_size = | |
| 448 | + core->iris_platform_data->input_config_params_vp9_size; | |
| 449 | + break; | |
| 450 | + } | |
| 394 | 451 | } else { |
| 395 | 452 | config_params = core->iris_platform_data->output_config_params; |
| 396 | 453 | config_params_size = core->iris_platform_data->output_config_params_size; |
| @@ -416,7 +473,19 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p · 19 unmodified lines | ||
| 416 | 473 | static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) |
| 417 | 474 | { |
| 418 | 475 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 419 | − u32 codec = HFI_CODEC_DECODE_AVC; | |
| 476 | + u32 codec = 0; | |
| 477 | + | |
| 478 | + switch (inst->codec) { | |
| 479 | + case V4L2_PIX_FMT_H264: | |
| 480 | + codec = HFI_CODEC_DECODE_AVC; | |
| 481 | + break; | |
| 482 | + case V4L2_PIX_FMT_HEVC: | |
| 483 | + codec = HFI_CODEC_DECODE_HEVC; | |
| 484 | + break; | |
| 485 | + case V4L2_PIX_FMT_VP9: | |
| 486 | + codec = HFI_CODEC_DECODE_VP9; | |
| 487 | + break; | |
| 488 | + } | |
| 420 | 489 | |
| 421 | 490 | iris_hfi_gen2_packet_session_property(inst, |
| 422 | 491 | HFI_PROP_CODEC, |
| @@ -548,8 +617,8 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan · 125 unmodified lines | ||
| 548 | 617 | struct hfi_subscription_params subsc_params; |
| 549 | 618 | u32 prop_type, payload_size, payload_type; |
| 550 | 619 | struct iris_core *core = inst->core; |
| 551 | − const u32 *change_param; | |
| 552 | − u32 change_param_size; | |
| 620 | + const u32 *change_param = NULL; | |
| 621 | + u32 change_param_size = 0; | |
| 553 | 622 | u32 payload[32] = {0}; |
| 554 | 623 | u32 hfi_port = 0, i; |
| 555 | 624 | int ret; |
| @@ -560,8 +629,23 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan · 4 unmodified lines | ||
| 560 | 629 | return 0; |
| 561 | 630 | } |
| 562 | 631 | |
| 563 | − change_param = core->iris_platform_data->input_config_params; | |
| 564 | − change_param_size = core->iris_platform_data->input_config_params_size; | |
| 632 | + switch (inst->codec) { | |
| 633 | + case V4L2_PIX_FMT_H264: | |
| 634 | + change_param = core->iris_platform_data->input_config_params_default; | |
| 635 | + change_param_size = | |
| 636 | + core->iris_platform_data->input_config_params_default_size; | |
| 637 | + break; | |
| 638 | + case V4L2_PIX_FMT_HEVC: | |
| 639 | + change_param = core->iris_platform_data->input_config_params_hevc; | |
| 640 | + change_param_size = | |
| 641 | + core->iris_platform_data->input_config_params_hevc_size; | |
| 642 | + break; | |
| 643 | + case V4L2_PIX_FMT_VP9: | |
| 644 | + change_param = core->iris_platform_data->input_config_params_vp9; | |
| 645 | + change_param_size = | |
| 646 | + core->iris_platform_data->input_config_params_vp9_size; | |
| 647 | + break; | |
| 648 | + } | |
| 565 | 649 | |
| 566 | 650 | payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; |
| 567 | 651 | |
| @@ -608,6 +692,11 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan · 40 unmodified lines | ||
| 608 | 692 | payload_size = sizeof(u32); |
| 609 | 693 | payload_type = HFI_PAYLOAD_U32; |
| 610 | 694 | break; |
| 695 | + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: | |
| 696 | + payload[0] = subsc_params.bit_depth; | |
| 697 | + payload_size = sizeof(u32); | |
| 698 | + payload_type = HFI_PAYLOAD_U32; | |
| 699 | + break; | |
| 611 | 700 | case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: |
| 612 | 701 | payload[0] = subsc_params.fw_min_count; |
| 613 | 702 | payload_size = sizeof(u32); |
| @@ -633,6 +722,11 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan · 19 unmodified lines | ||
| 633 | 722 | payload_size = sizeof(u32); |
| 634 | 723 | payload_type = HFI_PAYLOAD_U32; |
| 635 | 724 | break; |
| 725 | + case HFI_PROP_TIER: | |
| 726 | + payload[0] = subsc_params.tier; | |
| 727 | + payload_size = sizeof(u32); | |
| 728 | + payload_type = HFI_PAYLOAD_U32; | |
| 729 | + break; | |
| 636 | 730 | default: |
| 637 | 731 | prop_type = 0; |
| 638 | 732 | ret = -EINVAL; |
| @@ -659,8 +753,8 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan · 20 unmodified lines | ||
| 659 | 753 | static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) |
| 660 | 754 | { |
| 661 | 755 | struct iris_core *core = inst->core; |
| 662 | − u32 subscribe_prop_size, i; | |
| 663 | − const u32 *subcribe_prop; | |
| 756 | + u32 subscribe_prop_size = 0, i; | |
| 757 | + const u32 *subcribe_prop = NULL; | |
| 664 | 758 | u32 payload[32] = {0}; |
| 665 | 759 | |
| 666 | 760 | payload[0] = HFI_MODE_PROPERTY; |
| @@ -669,8 +763,23 @@ static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) · 2 unmodified lines | ||
| 669 | 763 | subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; |
| 670 | 764 | subcribe_prop = core->iris_platform_data->dec_input_prop; |
| 671 | 765 | } else { |
| 672 | − subscribe_prop_size = core->iris_platform_data->dec_output_prop_size; | |
| 673 | − subcribe_prop = core->iris_platform_data->dec_output_prop; | |
| 766 | + switch (inst->codec) { | |
| 767 | + case V4L2_PIX_FMT_H264: | |
| 768 | + subcribe_prop = core->iris_platform_data->dec_output_prop_avc; | |
| 769 | + subscribe_prop_size = | |
| 770 | + core->iris_platform_data->dec_output_prop_avc_size; | |
| 771 | + break; | |
| 772 | + case V4L2_PIX_FMT_HEVC: | |
| 773 | + subcribe_prop = core->iris_platform_data->dec_output_prop_hevc; | |
| 774 | + subscribe_prop_size = | |
| 775 | + core->iris_platform_data->dec_output_prop_hevc_size; | |
| 776 | + break; | |
| 777 | + case V4L2_PIX_FMT_VP9: | |
| 778 | + subcribe_prop = core->iris_platform_data->dec_output_prop_vp9; | |
| 779 | + subscribe_prop_size = | |
| 780 | + core->iris_platform_data->dec_output_prop_vp9_size; | |
| 781 | + break; | |
| 782 | + } | |
| 674 | 783 | } |
| 675 | 784 | |
| 676 | 785 | for (i = 0; i < subscribe_prop_size; i++) |
| @@ -46,6 +46,7 @@ · 45 unmodified lines | ||
| 46 | 46 | #define HFI_PROP_CROP_OFFSETS 0x03000105 |
| 47 | 47 | #define HFI_PROP_PROFILE 0x03000107 |
| 48 | 48 | #define HFI_PROP_LEVEL 0x03000108 |
| 49 | +#define HFI_PROP_TIER 0x03000109 | |
| 49 | 50 | #define HFI_PROP_STAGE 0x0300010a |
| 50 | 51 | #define HFI_PROP_PIPE 0x0300010b |
| 51 | 52 | #define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f |
| @@ -104,6 +105,9 @@ enum hfi_color_format { · 52 unmodified lines | ||
| 104 | 105 | enum hfi_codec_type { |
| 105 | 106 | HFI_CODEC_DECODE_AVC = 1, |
| 106 | 107 | HFI_CODEC_ENCODE_AVC = 2, |
| 108 | + HFI_CODEC_DECODE_HEVC = 3, | |
| 109 | + HFI_CODEC_ENCODE_HEVC = 4, | |
| 110 | + HFI_CODEC_DECODE_VP9 = 5, | |
| 107 | 111 | }; |
| 108 | 112 | |
| 109 | 113 | enum hfi_picture_type { |
| @@ -113,6 +117,7 @@ enum hfi_picture_type { · 3 unmodified lines | ||
| 113 | 117 | HFI_PICTURE_I = 0x00000008, |
| 114 | 118 | HFI_PICTURE_CRA = 0x00000010, |
| 115 | 119 | HFI_PICTURE_BLA = 0x00000020, |
| 120 | + HFI_PICTURE_NOSHOW = 0x00000040, | |
| 116 | 121 | }; |
| 117 | 122 | |
| 118 | 123 | enum hfi_buffer_type { |
| @@ -91,7 +91,9 @@ static int iris_hfi_gen2_get_driver_buffer_flags(struct iris_inst *inst, u32 hfi · 90 unmodified lines | ||
| 91 | 91 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 92 | 92 | u32 driver_flags = 0; |
| 93 | 93 | |
| 94 | − if (inst_hfi_gen2->hfi_frame_info.picture_type & keyframe) | |
| 94 | + if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_NOSHOW) | |
| 95 | + driver_flags |= V4L2_BUF_FLAG_ERROR; | |
| 96 | + else if (inst_hfi_gen2->hfi_frame_info.picture_type & keyframe) | |
| 95 | 97 | driver_flags |= V4L2_BUF_FLAG_KEYFRAME; |
| 96 | 98 | else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_P) |
| 97 | 99 | driver_flags |= V4L2_BUF_FLAG_PFRAME; |
| @@ -265,7 +267,8 @@ static int iris_hfi_gen2_handle_system_error(struct iris_core *core, · 167 unmodified lines | ||
| 265 | 267 | { |
| 266 | 268 | struct iris_inst *instance; |
| 267 | 269 | |
| 268 | − dev_err(core->dev, "received system error of type %#x\n", pkt->type); | |
| 270 | + if (pkt) | |
| 271 | + dev_err(core->dev, "received system error of type %#x\n", pkt->type); | |
| 269 | 272 | |
| 270 | 273 | core->state = IRIS_CORE_ERROR; |
| 271 | 274 | |
| @@ -377,6 +380,11 @@ static int iris_hfi_gen2_handle_output_buffer(struct iris_inst *inst, · 105 unmodified lines | ||
| 377 | 380 | |
| 378 | 381 | buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags); |
| 379 | 382 | |
| 383 | + if (!buf->data_size && inst->state == IRIS_INST_STREAMING && | |
| 384 | + !(hfi_buffer->flags & HFI_BUF_FW_FLAG_LAST)) { | |
| 385 | + buf->flags |= V4L2_BUF_FLAG_ERROR; | |
| 386 | + } | |
| 387 | + | |
| 380 | 388 | return 0; |
| 381 | 389 | } |
| 382 | 390 | |
| @@ -563,9 +571,23 @@ static void iris_hfi_gen2_read_input_subcr_params(struct iris_inst *inst) · 180 unmodified lines | ||
| 563 | 571 | inst->crop.width = pixmp_ip->width - |
| 564 | 572 | ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; |
| 565 | 573 | |
| 566 | − inst->fw_caps[PROFILE].value = subsc_params.profile; | |
| 567 | − inst->fw_caps[LEVEL].value = subsc_params.level; | |
| 574 | + switch (inst->codec) { | |
| 575 | + case V4L2_PIX_FMT_HEVC: | |
| 576 | + inst->fw_caps[PROFILE_HEVC].value = subsc_params.profile; | |
| 577 | + inst->fw_caps[LEVEL_HEVC].value = subsc_params.level; | |
| 578 | + break; | |
| 579 | + case V4L2_PIX_FMT_VP9: | |
| 580 | + inst->fw_caps[PROFILE_VP9].value = subsc_params.profile; | |
| 581 | + inst->fw_caps[LEVEL_VP9].value = subsc_params.level; | |
| 582 | + break; | |
| 583 | + case V4L2_PIX_FMT_H264: | |
| 584 | + inst->fw_caps[PROFILE_H264].value = subsc_params.profile; | |
| 585 | + inst->fw_caps[LEVEL_H264].value = subsc_params.level; | |
| 586 | + break; | |
| 587 | + } | |
| 588 | + | |
| 568 | 589 | inst->fw_caps[POC].value = subsc_params.pic_order_cnt; |
| 590 | + inst->fw_caps[TIER].value = subsc_params.tier; | |
| 569 | 591 | |
| 570 | 592 | if (subsc_params.bit_depth != BIT_DEPTH_8 || |
| 571 | 593 | !(subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)) { |
| @@ -636,9 +658,6 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, · 64 unmodified lines | ||
| 636 | 658 | { |
| 637 | 659 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 638 | 660 | |
| 639 | − if (pkt->port != HFI_PORT_BITSTREAM) | |
| 640 | − return 0; | |
| 641 | − | |
| 642 | 661 | if (pkt->flags & HFI_FW_FLAGS_INFORMATION) |
| 643 | 662 | return 0; |
| 644 | 663 | |
| @@ -650,6 +669,9 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, · 5 unmodified lines | ||
| 650 | 669 | inst_hfi_gen2->src_subcr_params.crop_offsets[0] = pkt->payload[0]; |
| 651 | 670 | inst_hfi_gen2->src_subcr_params.crop_offsets[1] = pkt->payload[1]; |
| 652 | 671 | break; |
| 672 | + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: | |
| 673 | + inst_hfi_gen2->src_subcr_params.bit_depth = pkt->payload[0]; | |
| 674 | + break; | |
| 653 | 675 | case HFI_PROP_CODED_FRAMES: |
| 654 | 676 | inst_hfi_gen2->src_subcr_params.coded_frames = pkt->payload[0]; |
| 655 | 677 | break; |
| @@ -668,6 +690,9 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, · 12 unmodified lines | ||
| 668 | 690 | case HFI_PROP_LEVEL: |
| 669 | 691 | inst_hfi_gen2->src_subcr_params.level = pkt->payload[0]; |
| 670 | 692 | break; |
| 693 | + case HFI_PROP_TIER: | |
| 694 | + inst_hfi_gen2->src_subcr_params.tier = pkt->payload[0]; | |
| 695 | + break; | |
| 671 | 696 | case HFI_PROP_PICTURE_TYPE: |
| 672 | 697 | inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; |
| 673 | 698 | break; |
| @@ -791,8 +816,21 @@ static void iris_hfi_gen2_init_src_change_param(struct iris_inst *inst) · 117 unmodified lines | ||
| 791 | 816 | full_range, video_format, |
| 792 | 817 | video_signal_type_present_flag); |
| 793 | 818 | |
| 794 | − subsc_params->profile = inst->fw_caps[PROFILE].value; | |
| 795 | − subsc_params->level = inst->fw_caps[LEVEL].value; | |
| 819 | + switch (inst->codec) { | |
| 820 | + case V4L2_PIX_FMT_HEVC: | |
| 821 | + subsc_params->profile = inst->fw_caps[PROFILE_HEVC].value; | |
| 822 | + subsc_params->level = inst->fw_caps[LEVEL_HEVC].value; | |
| 823 | + break; | |
| 824 | + case V4L2_PIX_FMT_VP9: | |
| 825 | + subsc_params->profile = inst->fw_caps[PROFILE_VP9].value; | |
| 826 | + subsc_params->level = inst->fw_caps[LEVEL_VP9].value; | |
| 827 | + break; | |
| 828 | + case V4L2_PIX_FMT_H264: | |
| 829 | + subsc_params->profile = inst->fw_caps[PROFILE_H264].value; | |
| 830 | + subsc_params->level = inst->fw_caps[LEVEL_H264].value; | |
| 831 | + break; | |
| 832 | + } | |
| 833 | + | |
| 796 | 834 | subsc_params->pic_order_cnt = inst->fw_caps[POC].value; |
| 797 | 835 | subsc_params->bit_depth = inst->fw_caps[BIT_DEPTH].value; |
| 798 | 836 | if (inst->fw_caps[CODED_FRAMES].value == |
| @@ -113,7 +113,7 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s · 112 unmodified lines | ||
| 113 | 113 | { |
| 114 | 114 | struct iris_iface_q_info *q_info = &core->command_queue; |
| 115 | 115 | |
| 116 | − if (core->state == IRIS_CORE_ERROR) | |
| 116 | + if (core->state == IRIS_CORE_ERROR || core->state == IRIS_CORE_DEINIT) | |
| 117 | 117 | return -EINVAL; |
| 118 | 118 | |
| 119 | 119 | if (!iris_hfi_queue_write(q_info, pkt, pkt_size)) { |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | * @crop: structure of crop info |
| 28 | 28 | * @completion: structure of signal completions |
| 29 | 29 | * @flush_completion: structure of signal completions for flush cmd |
| 30 | + * @flush_responses_pending: counter to track number of pending flush responses | |
| 30 | 31 | * @fw_caps: array of supported instance firmware capabilities |
| 31 | 32 | * @buffers: array of different iris buffers |
| 32 | 33 | * @fw_min_count: minimnum count of buffers needed by fw |
| @@ -42,6 +43,8 @@ · 9 unmodified lines | ||
| 42 | 43 | * @sequence_out: a sequence counter for output queue |
| 43 | 44 | * @tss: timestamp metadata |
| 44 | 45 | * @metadata_idx: index for metadata buffer |
| 46 | + * @codec: codec type | |
| 47 | + * @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver | |
| 45 | 48 | */ |
| 46 | 49 | |
| 47 | 50 | struct iris_inst { |
| @@ -57,6 +60,7 @@ struct iris_inst { · 9 unmodified lines | ||
| 57 | 60 | struct iris_hfi_rect_desc crop; |
| 58 | 61 | struct completion completion; |
| 59 | 62 | struct completion flush_completion; |
| 63 | + u32 flush_responses_pending; | |
| 60 | 64 | struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; |
| 61 | 65 | struct iris_buffers buffers[BUF_TYPE_MAX]; |
| 62 | 66 | u32 fw_min_count; |
| @@ -72,6 +76,8 @@ struct iris_inst { · 9 unmodified lines | ||
| 72 | 76 | u32 sequence_out; |
| 73 | 77 | struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; |
| 74 | 78 | u32 metadata_idx; |
| 79 | + u32 codec; | |
| 80 | + bool last_buffer_dequeued; | |
| 75 | 81 | }; |
| 76 | 82 | |
| 77 | 83 | #endif |
| @@ -21,6 +21,7 @@ struct iris_inst; · 20 unmodified lines | ||
| 21 | 21 | #define DEFAULT_MAX_HOST_BUF_COUNT 64 |
| 22 | 22 | #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 |
| 23 | 23 | #define DEFAULT_FPS 30 |
| 24 | +#define NUM_MBS_8K ((8192 * 4352) / 256) | |
| 24 | 25 | |
| 25 | 26 | enum stage_type { |
| 26 | 27 | STAGE_1 = 1, |
| @@ -80,8 +81,12 @@ struct platform_inst_caps { · 53 unmodified lines | ||
| 80 | 81 | }; |
| 81 | 82 | |
| 82 | 83 | enum platform_inst_fw_cap_type { |
| 83 | − PROFILE = 1, | |
| 84 | − LEVEL, | |
| 84 | + PROFILE_H264 = 1, | |
| 85 | + PROFILE_HEVC, | |
| 86 | + PROFILE_VP9, | |
| 87 | + LEVEL_H264, | |
| 88 | + LEVEL_HEVC, | |
| 89 | + LEVEL_VP9, | |
| 85 | 90 | INPUT_BUF_HOST_MAX_COUNT, |
| 86 | 91 | STAGE, |
| 87 | 92 | PIPE, |
| @@ -89,7 +94,7 @@ enum platform_inst_fw_cap_type { · 1 unmodified line | ||
| 89 | 94 | CODED_FRAMES, |
| 90 | 95 | BIT_DEPTH, |
| 91 | 96 | RAP_FRAME, |
| 92 | − DEBLOCK, | |
| 97 | + TIER, | |
| 93 | 98 | INST_FW_CAP_MAX, |
| 94 | 99 | }; |
| 95 | 100 | |
| @@ -172,15 +177,24 @@ struct iris_platform_data { · 76 unmodified lines | ||
| 172 | 177 | struct ubwc_config_data *ubwc_config; |
| 173 | 178 | u32 num_vpp_pipe; |
| 174 | 179 | u32 max_session_count; |
| 180 | + /* max number of macroblocks per frame supported */ | |
| 175 | 181 | u32 max_core_mbpf; |
| 176 | − const u32 *input_config_params; | |
| 177 | − unsigned int input_config_params_size; | |
| 182 | + const u32 *input_config_params_default; | |
| 183 | + unsigned int input_config_params_default_size; | |
| 184 | + const u32 *input_config_params_hevc; | |
| 185 | + unsigned int input_config_params_hevc_size; | |
| 186 | + const u32 *input_config_params_vp9; | |
| 187 | + unsigned int input_config_params_vp9_size; | |
| 178 | 188 | const u32 *output_config_params; |
| 179 | 189 | unsigned int output_config_params_size; |
| 180 | 190 | const u32 *dec_input_prop; |
| 181 | 191 | unsigned int dec_input_prop_size; |
| 182 | − const u32 *dec_output_prop; | |
| 183 | − unsigned int dec_output_prop_size; | |
| 192 | + const u32 *dec_output_prop_avc; | |
| 193 | + unsigned int dec_output_prop_avc_size; | |
| 194 | + const u32 *dec_output_prop_hevc; | |
| 195 | + unsigned int dec_output_prop_hevc_size; | |
| 196 | + const u32 *dec_output_prop_vp9; | |
| 197 | + unsigned int dec_output_prop_vp9_size; | |
| 184 | 198 | const u32 *dec_ip_int_buf_tbl; |
| 185 | 199 | unsigned int dec_ip_int_buf_tbl_size; |
| 186 | 200 | const u32 *dec_op_int_buf_tbl; |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { |
| 19 | 19 | { |
| 20 | − .cap_id = PROFILE, | |
| 20 | + .cap_id = PROFILE_H264, | |
| 21 | 21 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, |
| 22 | 22 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, |
| 23 | 23 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | |
| @@ -31,7 +31,29 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { · 7 unmodified lines | ||
| 31 | 31 | .set = iris_set_u32_enum, |
| 32 | 32 | }, |
| 33 | 33 | { |
| 34 | − .cap_id = LEVEL, | |
| 34 | + .cap_id = PROFILE_HEVC, | |
| 35 | + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, | |
| 36 | + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, | |
| 37 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | | |
| 38 | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), | |
| 39 | + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, | |
| 40 | + .hfi_id = HFI_PROP_PROFILE, | |
| 41 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 42 | + .set = iris_set_u32_enum, | |
| 43 | + }, | |
| 44 | + { | |
| 45 | + .cap_id = PROFILE_VP9, | |
| 46 | + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, | |
| 47 | + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, | |
| 48 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | | |
| 49 | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), | |
| 50 | + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, | |
| 51 | + .hfi_id = HFI_PROP_PROFILE, | |
| 52 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 53 | + .set = iris_set_u32_enum, | |
| 54 | + }, | |
| 55 | + { | |
| 56 | + .cap_id = LEVEL_H264, | |
| 35 | 57 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, |
| 36 | 58 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, |
| 37 | 59 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | |
| @@ -59,6 +81,60 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { · 21 unmodified lines | ||
| 59 | 81 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 60 | 82 | .set = iris_set_u32_enum, |
| 61 | 83 | }, |
| 84 | + { | |
| 85 | + .cap_id = LEVEL_HEVC, | |
| 86 | + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, | |
| 87 | + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, | |
| 88 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | | |
| 89 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | | |
| 90 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | | |
| 91 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | | |
| 92 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | | |
| 93 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | | |
| 94 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | | |
| 95 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | | |
| 96 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | | |
| 97 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | | |
| 98 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | | |
| 99 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | | |
| 100 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), | |
| 101 | + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, | |
| 102 | + .hfi_id = HFI_PROP_LEVEL, | |
| 103 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 104 | + .set = iris_set_u32_enum, | |
| 105 | + }, | |
| 106 | + { | |
| 107 | + .cap_id = LEVEL_VP9, | |
| 108 | + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, | |
| 109 | + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, | |
| 110 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | | |
| 111 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | | |
| 112 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | | |
| 113 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | | |
| 114 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | | |
| 115 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | | |
| 116 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | | |
| 117 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | | |
| 118 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | | |
| 119 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | | |
| 120 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | | |
| 121 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), | |
| 122 | + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, | |
| 123 | + .hfi_id = HFI_PROP_LEVEL, | |
| 124 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 125 | + .set = iris_set_u32_enum, | |
| 126 | + }, | |
| 127 | + { | |
| 128 | + .cap_id = TIER, | |
| 129 | + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, | |
| 130 | + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, | |
| 131 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | | |
| 132 | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), | |
| 133 | + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, | |
| 134 | + .hfi_id = HFI_PROP_TIER, | |
| 135 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 136 | + .set = iris_set_u32_enum, | |
| 137 | + }, | |
| 62 | 138 | { |
| 63 | 139 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, |
| 64 | 140 | .min = DEFAULT_MAX_HOST_BUF_COUNT, |
| @@ -181,9 +257,10 @@ static struct tz_cp_config tz_cp_config_sm8550 = { · 116 unmodified lines | ||
| 181 | 257 | .cp_nonpixel_size = 0x24800000, |
| 182 | 258 | }; |
| 183 | 259 | |
| 184 | −static const u32 sm8550_vdec_input_config_params[] = { | |
| 260 | +static const u32 sm8550_vdec_input_config_params_default[] = { | |
| 185 | 261 | HFI_PROP_BITSTREAM_RESOLUTION, |
| 186 | 262 | HFI_PROP_CROP_OFFSETS, |
| 263 | + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, | |
| 187 | 264 | HFI_PROP_CODED_FRAMES, |
| 188 | 265 | HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, |
| 189 | 266 | HFI_PROP_PIC_ORDER_CNT_TYPE, |
| @@ -192,6 +269,26 @@ static const u32 sm8550_vdec_input_config_params[] = { · 2 unmodified lines | ||
| 192 | 269 | HFI_PROP_SIGNAL_COLOR_INFO, |
| 193 | 270 | }; |
| 194 | 271 | |
| 272 | +static const u32 sm8550_vdec_input_config_param_hevc[] = { | |
| 273 | + HFI_PROP_BITSTREAM_RESOLUTION, | |
| 274 | + HFI_PROP_CROP_OFFSETS, | |
| 275 | + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, | |
| 276 | + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, | |
| 277 | + HFI_PROP_PROFILE, | |
| 278 | + HFI_PROP_LEVEL, | |
| 279 | + HFI_PROP_TIER, | |
| 280 | + HFI_PROP_SIGNAL_COLOR_INFO, | |
| 281 | +}; | |
| 282 | + | |
| 283 | +static const u32 sm8550_vdec_input_config_param_vp9[] = { | |
| 284 | + HFI_PROP_BITSTREAM_RESOLUTION, | |
| 285 | + HFI_PROP_CROP_OFFSETS, | |
| 286 | + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, | |
| 287 | + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, | |
| 288 | + HFI_PROP_PROFILE, | |
| 289 | + HFI_PROP_LEVEL, | |
| 290 | +}; | |
| 291 | + | |
| 195 | 292 | static const u32 sm8550_vdec_output_config_params[] = { |
| 196 | 293 | HFI_PROP_COLOR_FORMAT, |
| 197 | 294 | HFI_PROP_LINEAR_STRIDE_SCANLINE, |
| @@ -201,11 +298,19 @@ static const u32 sm8550_vdec_subscribe_input_properties[] = { · 3 unmodified lines | ||
| 201 | 298 | HFI_PROP_NO_OUTPUT, |
| 202 | 299 | }; |
| 203 | 300 | |
| 204 | −static const u32 sm8550_vdec_subscribe_output_properties[] = { | |
| 301 | +static const u32 sm8550_vdec_subscribe_output_properties_avc[] = { | |
| 205 | 302 | HFI_PROP_PICTURE_TYPE, |
| 206 | 303 | HFI_PROP_CABAC_SESSION, |
| 207 | 304 | }; |
| 208 | 305 | |
| 306 | +static const u32 sm8550_vdec_subscribe_output_properties_hevc[] = { | |
| 307 | + HFI_PROP_PICTURE_TYPE, | |
| 308 | +}; | |
| 309 | + | |
| 310 | +static const u32 sm8550_vdec_subscribe_output_properties_vp9[] = { | |
| 311 | + HFI_PROP_PICTURE_TYPE, | |
| 312 | +}; | |
| 313 | + | |
| 209 | 314 | static const u32 sm8550_dec_ip_int_buf_tbl[] = { |
| 210 | 315 | BUF_BIN, |
| 211 | 316 | BUF_COMV, |
| @@ -248,19 +353,34 @@ struct iris_platform_data sm8550_data = { · 36 unmodified lines | ||
| 248 | 353 | .ubwc_config = &ubwc_config_sm8550, |
| 249 | 354 | .num_vpp_pipe = 4, |
| 250 | 355 | .max_session_count = 16, |
| 251 | − .max_core_mbpf = ((8192 * 4352) / 256) * 2, | |
| 252 | − .input_config_params = | |
| 253 | − sm8550_vdec_input_config_params, | |
| 254 | − .input_config_params_size = | |
| 255 | − ARRAY_SIZE(sm8550_vdec_input_config_params), | |
| 356 | + .max_core_mbpf = NUM_MBS_8K * 2, | |
| 357 | + .input_config_params_default = | |
| 358 | + sm8550_vdec_input_config_params_default, | |
| 359 | + .input_config_params_default_size = | |
| 360 | + ARRAY_SIZE(sm8550_vdec_input_config_params_default), | |
| 361 | + .input_config_params_hevc = | |
| 362 | + sm8550_vdec_input_config_param_hevc, | |
| 363 | + .input_config_params_hevc_size = | |
| 364 | + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), | |
| 365 | + .input_config_params_vp9 = | |
| 366 | + sm8550_vdec_input_config_param_vp9, | |
| 367 | + .input_config_params_vp9_size = | |
| 368 | + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), | |
| 256 | 369 | .output_config_params = |
| 257 | 370 | sm8550_vdec_output_config_params, |
| 258 | 371 | .output_config_params_size = |
| 259 | 372 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 260 | 373 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 261 | 374 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 262 | − .dec_output_prop = sm8550_vdec_subscribe_output_properties, | |
| 263 | − .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | |
| 375 | + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, | |
| 376 | + .dec_output_prop_avc_size = | |
| 377 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), | |
| 378 | + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, | |
| 379 | + .dec_output_prop_hevc_size = | |
| 380 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), | |
| 381 | + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, | |
| 382 | + .dec_output_prop_vp9_size = | |
| 383 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), | |
| 264 | 384 | |
| 265 | 385 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 266 | 386 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), |
| @@ -308,19 +428,34 @@ struct iris_platform_data sm8650_data = { · 41 unmodified lines | ||
| 308 | 428 | .ubwc_config = &ubwc_config_sm8550, |
| 309 | 429 | .num_vpp_pipe = 4, |
| 310 | 430 | .max_session_count = 16, |
| 311 | − .max_core_mbpf = ((8192 * 4352) / 256) * 2, | |
| 312 | − .input_config_params = | |
| 313 | − sm8550_vdec_input_config_params, | |
| 314 | − .input_config_params_size = | |
| 315 | − ARRAY_SIZE(sm8550_vdec_input_config_params), | |
| 431 | + .max_core_mbpf = NUM_MBS_8K * 2, | |
| 432 | + .input_config_params_default = | |
| 433 | + sm8550_vdec_input_config_params_default, | |
| 434 | + .input_config_params_default_size = | |
| 435 | + ARRAY_SIZE(sm8550_vdec_input_config_params_default), | |
| 436 | + .input_config_params_hevc = | |
| 437 | + sm8550_vdec_input_config_param_hevc, | |
| 438 | + .input_config_params_hevc_size = | |
| 439 | + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), | |
| 440 | + .input_config_params_vp9 = | |
| 441 | + sm8550_vdec_input_config_param_vp9, | |
| 442 | + .input_config_params_vp9_size = | |
| 443 | + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), | |
| 316 | 444 | .output_config_params = |
| 317 | 445 | sm8550_vdec_output_config_params, |
| 318 | 446 | .output_config_params_size = |
| 319 | 447 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 320 | 448 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 321 | 449 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 322 | − .dec_output_prop = sm8550_vdec_subscribe_output_properties, | |
| 323 | − .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | |
| 450 | + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, | |
| 451 | + .dec_output_prop_avc_size = | |
| 452 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), | |
| 453 | + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, | |
| 454 | + .dec_output_prop_hevc_size = | |
| 455 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), | |
| 456 | + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, | |
| 457 | + .dec_output_prop_vp9_size = | |
| 458 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), | |
| 324 | 459 | |
| 325 | 460 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 326 | 461 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), |
| @@ -365,18 +500,33 @@ struct iris_platform_data qcs8300_data = { · 38 unmodified lines | ||
| 365 | 500 | .num_vpp_pipe = 2, |
| 366 | 501 | .max_session_count = 16, |
| 367 | 502 | .max_core_mbpf = ((4096 * 2176) / 256) * 4, |
| 368 | − .input_config_params = | |
| 369 | − sm8550_vdec_input_config_params, | |
| 370 | − .input_config_params_size = | |
| 371 | − ARRAY_SIZE(sm8550_vdec_input_config_params), | |
| 503 | + .input_config_params_default = | |
| 504 | + sm8550_vdec_input_config_params_default, | |
| 505 | + .input_config_params_default_size = | |
| 506 | + ARRAY_SIZE(sm8550_vdec_input_config_params_default), | |
| 507 | + .input_config_params_hevc = | |
| 508 | + sm8550_vdec_input_config_param_hevc, | |
| 509 | + .input_config_params_hevc_size = | |
| 510 | + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), | |
| 511 | + .input_config_params_vp9 = | |
| 512 | + sm8550_vdec_input_config_param_vp9, | |
| 513 | + .input_config_params_vp9_size = | |
| 514 | + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), | |
| 372 | 515 | .output_config_params = |
| 373 | 516 | sm8550_vdec_output_config_params, |
| 374 | 517 | .output_config_params_size = |
| 375 | 518 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 376 | 519 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 377 | 520 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 378 | − .dec_output_prop = sm8550_vdec_subscribe_output_properties, | |
| 379 | − .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | |
| 521 | + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, | |
| 522 | + .dec_output_prop_avc_size = | |
| 523 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), | |
| 524 | + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, | |
| 525 | + .dec_output_prop_hevc_size = | |
| 526 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), | |
| 527 | + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, | |
| 528 | + .dec_output_prop_vp9_size = | |
| 529 | + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), | |
| 380 | 530 | |
| 381 | 531 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 382 | 532 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), |
| @@ -5,48 +5,124 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { |
| 7 | 7 | { |
| 8 | − .cap_id = PROFILE, | |
| 8 | + .cap_id = PROFILE_H264, | |
| 9 | 9 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, |
| 10 | 10 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, |
| 11 | 11 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | |
| 12 | − BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | | |
| 13 | − BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | | |
| 14 | − BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | |
| 15 | − BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), | |
| 12 | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | | |
| 13 | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | |
| 14 | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | | |
| 15 | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), | |
| 16 | 16 | .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, |
| 17 | 17 | .hfi_id = HFI_PROP_PROFILE, |
| 18 | 18 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 19 | 19 | .set = iris_set_u32_enum, |
| 20 | 20 | }, |
| 21 | 21 | { |
| 22 | − .cap_id = LEVEL, | |
| 22 | + .cap_id = PROFILE_HEVC, | |
| 23 | + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, | |
| 24 | + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, | |
| 25 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | | |
| 26 | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), | |
| 27 | + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, | |
| 28 | + .hfi_id = HFI_PROP_PROFILE, | |
| 29 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 30 | + .set = iris_set_u32_enum, | |
| 31 | + }, | |
| 32 | + { | |
| 33 | + .cap_id = PROFILE_VP9, | |
| 34 | + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, | |
| 35 | + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, | |
| 36 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | | |
| 37 | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), | |
| 38 | + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, | |
| 39 | + .hfi_id = HFI_PROP_PROFILE, | |
| 40 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 41 | + .set = iris_set_u32_enum, | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + .cap_id = LEVEL_H264, | |
| 23 | 45 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, |
| 24 | 46 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, |
| 25 | 47 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | |
| 26 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | | |
| 27 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | | |
| 28 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | | |
| 29 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | | |
| 30 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | | |
| 31 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | | |
| 32 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | | |
| 33 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | | |
| 34 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | | |
| 35 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | | |
| 36 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | | |
| 37 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | | |
| 38 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | | |
| 39 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | | |
| 40 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | | |
| 41 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | | |
| 42 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | | |
| 43 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | | |
| 44 | − BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), | |
| 48 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | | |
| 49 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | | |
| 50 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | | |
| 51 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | | |
| 52 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | | |
| 53 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | | |
| 54 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | | |
| 55 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | | |
| 56 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | | |
| 57 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | | |
| 58 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | | |
| 59 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | | |
| 60 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | | |
| 61 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | | |
| 62 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | | |
| 63 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | | |
| 64 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | | |
| 65 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | | |
| 66 | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), | |
| 45 | 67 | .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, |
| 46 | 68 | .hfi_id = HFI_PROP_LEVEL, |
| 47 | 69 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 48 | 70 | .set = iris_set_u32_enum, |
| 49 | 71 | }, |
| 72 | + { | |
| 73 | + .cap_id = LEVEL_HEVC, | |
| 74 | + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, | |
| 75 | + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, | |
| 76 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | | |
| 77 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | | |
| 78 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | | |
| 79 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | | |
| 80 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | | |
| 81 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | | |
| 82 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | | |
| 83 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | | |
| 84 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | | |
| 85 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | | |
| 86 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | | |
| 87 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | | |
| 88 | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), | |
| 89 | + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, | |
| 90 | + .hfi_id = HFI_PROP_LEVEL, | |
| 91 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 92 | + .set = iris_set_u32_enum, | |
| 93 | + }, | |
| 94 | + { | |
| 95 | + .cap_id = LEVEL_VP9, | |
| 96 | + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, | |
| 97 | + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, | |
| 98 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | | |
| 99 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | | |
| 100 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | | |
| 101 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | | |
| 102 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | | |
| 103 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | | |
| 104 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | | |
| 105 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | | |
| 106 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | | |
| 107 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | | |
| 108 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | | |
| 109 | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), | |
| 110 | + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, | |
| 111 | + .hfi_id = HFI_PROP_LEVEL, | |
| 112 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 113 | + .set = iris_set_u32_enum, | |
| 114 | + }, | |
| 115 | + { | |
| 116 | + .cap_id = TIER, | |
| 117 | + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, | |
| 118 | + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, | |
| 119 | + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | | |
| 120 | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), | |
| 121 | + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, | |
| 122 | + .hfi_id = HFI_PROP_TIER, | |
| 123 | + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | |
| 124 | + .set = iris_set_u32_enum, | |
| 125 | + }, | |
| 50 | 126 | { |
| 51 | 127 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, |
| 52 | 128 | .min = DEFAULT_MAX_HOST_BUF_COUNT, |
| @@ -30,15 +30,6 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8250[] = { · 29 unmodified lines | ||
| 30 | 30 | .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, |
| 31 | 31 | .set = iris_set_stage, |
| 32 | 32 | }, |
| 33 | − { | |
| 34 | − .cap_id = DEBLOCK, | |
| 35 | − .min = 0, | |
| 36 | − .max = 1, | |
| 37 | − .step_or_mask = 1, | |
| 38 | − .value = 0, | |
| 39 | − .hfi_id = HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER, | |
| 40 | − .set = iris_set_u32, | |
| 41 | − }, | |
| 42 | 33 | }; |
| 43 | 34 | |
| 44 | 35 | static struct platform_inst_caps platform_inst_cap_sm8250 = { |
| @@ -136,10 +127,10 @@ struct iris_platform_data sm8250_data = { · 91 unmodified lines | ||
| 136 | 127 | .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, |
| 137 | 128 | .num_vpp_pipe = 4, |
| 138 | 129 | .max_session_count = 16, |
| 139 | − .max_core_mbpf = (8192 * 4352) / 256, | |
| 140 | − .input_config_params = | |
| 130 | + .max_core_mbpf = NUM_MBS_8K, | |
| 131 | + .input_config_params_default = | |
| 141 | 132 | sm8250_vdec_input_config_param_default, |
| 142 | − .input_config_params_size = | |
| 133 | + .input_config_params_default_size = | |
| 143 | 134 | ARRAY_SIZE(sm8250_vdec_input_config_param_default), |
| 144 | 135 | |
| 145 | 136 | .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, |
| @@ -53,7 +53,7 @@ static int iris_init_power_domains(struct iris_core *core) · 52 unmodified lines | ||
| 53 | 53 | struct dev_pm_domain_attach_data iris_opp_pd_data = { |
| 54 | 54 | .pd_names = core->iris_platform_data->opp_pd_tbl, |
| 55 | 55 | .num_pd_names = core->iris_platform_data->opp_pd_tbl_size, |
| 56 | − .pd_flags = PD_FLAG_DEV_LINK_ON, | |
| 56 | + .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP, | |
| 57 | 57 | }; |
| 58 | 58 | |
| 59 | 59 | ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); |
| @@ -245,7 +245,7 @@ int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane) · 244 unmodified lines | ||
| 245 | 245 | return iris_inst_change_sub_state(inst, 0, set_sub_state); |
| 246 | 246 | } |
| 247 | 247 | |
| 248 | −static inline bool iris_drc_pending(struct iris_inst *inst) | |
| 248 | +bool iris_drc_pending(struct iris_inst *inst) | |
| 249 | 249 | { |
| 250 | 250 | return inst->sub_state & IRIS_INST_SUB_DRC && |
| 251 | 251 | inst->sub_state & IRIS_INST_SUB_DRC_LAST; |
| @@ -140,5 +140,6 @@ int iris_inst_sub_state_change_drain_last(struct iris_inst *inst); · 139 unmodified lines | ||
| 140 | 140 | int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); |
| 141 | 141 | int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane); |
| 142 | 142 | bool iris_allow_cmd(struct iris_inst *inst, u32 cmd); |
| 143 | +bool iris_drc_pending(struct iris_inst *inst); | |
| 143 | 144 | |
| 144 | 145 | #endif |
| @@ -259,13 +259,14 @@ int iris_vb2_buf_prepare(struct vb2_buffer *vb) · 258 unmodified lines | ||
| 259 | 259 | return -EINVAL; |
| 260 | 260 | } |
| 261 | 261 | |
| 262 | − if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
| 263 | − vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) | |
| 264 | − return -EINVAL; | |
| 265 | − if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | |
| 266 | − vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) | |
| 267 | − return -EINVAL; | |
| 268 | − | |
| 262 | + if (!(inst->sub_state & IRIS_INST_SUB_DRC)) { | |
| 263 | + if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | |
| 264 | + vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) | |
| 265 | + return -EINVAL; | |
| 266 | + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | |
| 267 | + vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) | |
| 268 | + return -EINVAL; | |
| 269 | + } | |
| 269 | 270 | return 0; |
| 270 | 271 | } |
| 271 | 272 | |
| @@ -304,7 +305,7 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) · 32 unmodified lines | ||
| 304 | 305 | goto exit; |
| 305 | 306 | } |
| 306 | 307 | |
| 307 | − if (V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) { | |
| 308 | + if (!inst->last_buffer_dequeued && V4L2_TYPE_IS_CAPTURE(vb2->vb2_queue->type)) { | |
| 308 | 309 | if ((inst->sub_state & IRIS_INST_SUB_DRC && |
| 309 | 310 | inst->sub_state & IRIS_INST_SUB_DRC_LAST) || |
| 310 | 311 | (inst->sub_state & IRIS_INST_SUB_DRAIN && |
| @@ -318,6 +319,7 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) · 7 unmodified lines | ||
| 318 | 319 | v4l2_event_queue_fh(&inst->fh, &eos); |
| 319 | 320 | v4l2_m2m_mark_stopped(m2m_ctx); |
| 320 | 321 | } |
| 322 | + inst->last_buffer_dequeued = true; | |
| 321 | 323 | goto exit; |
| 322 | 324 | } |
| 323 | 325 | } |
| @@ -32,6 +32,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) · 31 unmodified lines | ||
| 32 | 32 | f->fmt.pix_mp.width = DEFAULT_WIDTH; |
| 33 | 33 | f->fmt.pix_mp.height = DEFAULT_HEIGHT; |
| 34 | 34 | f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; |
| 35 | + inst->codec = f->fmt.pix_mp.pixelformat; | |
| 35 | 36 | f->fmt.pix_mp.num_planes = 1; |
| 36 | 37 | f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; |
| 37 | 38 | f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); |
| @@ -67,14 +68,67 @@ void iris_vdec_inst_deinit(struct iris_inst *inst) · 29 unmodified lines | ||
| 67 | 68 | kfree(inst->fmt_src); |
| 68 | 69 | } |
| 69 | 70 | |
| 71 | +static const struct iris_fmt iris_vdec_formats[] = { | |
| 72 | + [IRIS_FMT_H264] = { | |
| 73 | + .pixfmt = V4L2_PIX_FMT_H264, | |
| 74 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 75 | + }, | |
| 76 | + [IRIS_FMT_HEVC] = { | |
| 77 | + .pixfmt = V4L2_PIX_FMT_HEVC, | |
| 78 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 79 | + }, | |
| 80 | + [IRIS_FMT_VP9] = { | |
| 81 | + .pixfmt = V4L2_PIX_FMT_VP9, | |
| 82 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 83 | + }, | |
| 84 | +}; | |
| 85 | + | |
| 86 | +static const struct iris_fmt * | |
| 87 | +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) | |
| 88 | +{ | |
| 89 | + unsigned int size = ARRAY_SIZE(iris_vdec_formats); | |
| 90 | + const struct iris_fmt *fmt = iris_vdec_formats; | |
| 91 | + unsigned int i; | |
| 92 | + | |
| 93 | + for (i = 0; i < size; i++) { | |
| 94 | + if (fmt[i].pixfmt == pixfmt) | |
| 95 | + break; | |
| 96 | + } | |
| 97 | + | |
| 98 | + if (i == size || fmt[i].type != type) | |
| 99 | + return NULL; | |
| 100 | + | |
| 101 | + return &fmt[i]; | |
| 102 | +} | |
| 103 | + | |
| 104 | +static const struct iris_fmt * | |
| 105 | +find_format_by_index(struct iris_inst *inst, u32 index, u32 type) | |
| 106 | +{ | |
| 107 | + const struct iris_fmt *fmt = iris_vdec_formats; | |
| 108 | + unsigned int size = ARRAY_SIZE(iris_vdec_formats); | |
| 109 | + | |
| 110 | + if (index >= size || fmt[index].type != type) | |
| 111 | + return NULL; | |
| 112 | + | |
| 113 | + return &fmt[index]; | |
| 114 | +} | |
| 115 | + | |
| 70 | 116 | int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) |
| 71 | 117 | { |
| 118 | + const struct iris_fmt *fmt; | |
| 119 | + | |
| 72 | 120 | switch (f->type) { |
| 73 | 121 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
| 74 | − f->pixelformat = V4L2_PIX_FMT_H264; | |
| 122 | + fmt = find_format_by_index(inst, f->index, f->type); | |
| 123 | + if (!fmt) | |
| 124 | + return -EINVAL; | |
| 125 | + | |
| 126 | + f->pixelformat = fmt->pixfmt; | |
| 75 | 127 | f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; |
| 76 | 128 | break; |
| 77 | 129 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
| 130 | + if (f->index) | |
| 131 | + return -EINVAL; | |
| 78 | 132 | f->pixelformat = V4L2_PIX_FMT_NV12; |
| 79 | 133 | break; |
| 80 | 134 | default: |
| @@ -88,13 +142,15 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) · 7 unmodified lines | ||
| 88 | 142 | { |
| 89 | 143 | struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; |
| 90 | 144 | struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; |
| 145 | + const struct iris_fmt *fmt; | |
| 91 | 146 | struct v4l2_format *f_inst; |
| 92 | 147 | struct vb2_queue *src_q; |
| 93 | 148 | |
| 94 | 149 | memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); |
| 150 | + fmt = find_format(inst, pixmp->pixelformat, f->type); | |
| 95 | 151 | switch (f->type) { |
| 96 | 152 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
| 97 | − if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) { | |
| 153 | + if (!fmt) { | |
| 98 | 154 | f_inst = inst->fmt_src; |
| 99 | 155 | f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; |
| 100 | 156 | f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; |
| @@ -102,7 +158,7 @@ int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f) · 1 unmodified line | ||
| 102 | 158 | } |
| 103 | 159 | break; |
| 104 | 160 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
| 105 | − if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) { | |
| 161 | + if (!fmt) { | |
| 106 | 162 | f_inst = inst->fmt_dst; |
| 107 | 163 | f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; |
| 108 | 164 | f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; |
| @@ -145,13 +201,14 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) · 36 unmodified lines | ||
| 145 | 201 | |
| 146 | 202 | switch (f->type) { |
| 147 | 203 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
| 148 | − if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) | |
| 204 | + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) | |
| 149 | 205 | return -EINVAL; |
| 150 | 206 | |
| 151 | 207 | fmt = inst->fmt_src; |
| 152 | 208 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 153 | − | |
| 154 | − codec_align = DEFAULT_CODEC_ALIGNMENT; | |
| 209 | + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; | |
| 210 | + inst->codec = fmt->fmt.pix_mp.pixelformat; | |
| 211 | + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; | |
| 155 | 212 | fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); |
| 156 | 213 | fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); |
| 157 | 214 | fmt->fmt.pix_mp.num_planes = 1; |
| @@ -171,6 +228,11 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) · 13 unmodified lines | ||
| 171 | 228 | output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; |
| 172 | 229 | output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; |
| 173 | 230 | |
| 231 | + /* Update capture format based on new ip w/h */ | |
| 232 | + output_fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); | |
| 233 | + output_fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); | |
| 234 | + inst->buffers[BUF_OUTPUT].size = iris_get_buffer_size(inst, BUF_OUTPUT); | |
| 235 | + | |
| 174 | 236 | inst->crop.left = 0; |
| 175 | 237 | inst->crop.top = 0; |
| 176 | 238 | inst->crop.width = f->fmt.pix_mp.width; |
| @@ -239,35 +301,6 @@ void iris_vdec_src_change(struct iris_inst *inst) · 62 unmodified lines | ||
| 239 | 301 | v4l2_event_queue_fh(&inst->fh, &event); |
| 240 | 302 | } |
| 241 | 303 | |
| 242 | −static int iris_vdec_get_num_queued_buffers(struct iris_inst *inst, | |
| 243 | − enum iris_buffer_type type) | |
| 244 | −{ | |
| 245 | − struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; | |
| 246 | − struct v4l2_m2m_buffer *buffer, *n; | |
| 247 | − struct iris_buffer *buf; | |
| 248 | − u32 count = 0; | |
| 249 | − | |
| 250 | − switch (type) { | |
| 251 | − case BUF_INPUT: | |
| 252 | − v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { | |
| 253 | − buf = to_iris_buffer(&buffer->vb); | |
| 254 | − if (!(buf->attr & BUF_ATTR_QUEUED)) | |
| 255 | − continue; | |
| 256 | − count++; | |
| 257 | − } | |
| 258 | − return count; | |
| 259 | − case BUF_OUTPUT: | |
| 260 | − v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { | |
| 261 | − buf = to_iris_buffer(&buffer->vb); | |
| 262 | − if (!(buf->attr & BUF_ATTR_QUEUED)) | |
| 263 | − continue; | |
| 264 | − count++; | |
| 265 | − } | |
| 266 | − return count; | |
| 267 | − default: | |
| 268 | − return count; | |
| 269 | − } | |
| 270 | −} | |
| 271 | 304 | |
| 272 | 305 | static void iris_vdec_flush_deferred_buffers(struct iris_inst *inst, |
| 273 | 306 | enum iris_buffer_type type) |
| @@ -316,7 +349,6 @@ int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) · 42 unmodified lines | ||
| 316 | 349 | { |
| 317 | 350 | const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; |
| 318 | 351 | enum iris_buffer_type buffer_type; |
| 319 | − u32 count; | |
| 320 | 352 | int ret; |
| 321 | 353 | |
| 322 | 354 | switch (plane) { |
| @@ -334,12 +366,6 @@ int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) · 11 unmodified lines | ||
| 334 | 366 | if (ret) |
| 335 | 367 | goto error; |
| 336 | 368 | |
| 337 | − count = iris_vdec_get_num_queued_buffers(inst, buffer_type); | |
| 338 | − if (count) { | |
| 339 | − ret = -EINVAL; | |
| 340 | − goto error; | |
| 341 | − } | |
| 342 | − | |
| 343 | 369 | ret = iris_inst_state_change_streamoff(inst, plane); |
| 344 | 370 | if (ret) |
| 345 | 371 | goto error; |
| @@ -408,7 +434,7 @@ int iris_vdec_streamon_input(struct iris_inst *inst) · 62 unmodified lines | ||
| 408 | 434 | |
| 409 | 435 | iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| 410 | 436 | |
| 411 | − ret = iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 437 | + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 412 | 438 | if (ret) |
| 413 | 439 | return ret; |
| 414 | 440 | |
| @@ -482,6 +508,8 @@ static int iris_vdec_process_streamon_output(struct iris_inst *inst) · 67 unmodified lines | ||
| 482 | 508 | if (ret) |
| 483 | 509 | return ret; |
| 484 | 510 | |
| 511 | + inst->last_buffer_dequeued = false; | |
| 512 | + | |
| 485 | 513 | return iris_inst_change_sub_state(inst, clear_sub_state, 0); |
| 486 | 514 | } |
| 487 | 515 | |
| @@ -496,7 +524,7 @@ int iris_vdec_streamon_output(struct iris_inst *inst) · 8 unmodified lines | ||
| 496 | 524 | |
| 497 | 525 | iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); |
| 498 | 526 | |
| 499 | − ret = iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 527 | + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 500 | 528 | if (ret) |
| 501 | 529 | return ret; |
| 502 | 530 | |
| @@ -8,6 +8,17 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | struct iris_inst; |
| 10 | 10 | |
| 11 | +enum iris_fmt_type { | |
| 12 | + IRIS_FMT_H264, | |
| 13 | + IRIS_FMT_HEVC, | |
| 14 | + IRIS_FMT_VP9, | |
| 15 | +}; | |
| 16 | + | |
| 17 | +struct iris_fmt { | |
| 18 | + u32 pixfmt; | |
| 19 | + u32 type; | |
| 20 | +}; | |
| 21 | + | |
| 11 | 22 | int iris_vdec_inst_init(struct iris_inst *inst); |
| 12 | 23 | void iris_vdec_inst_deinit(struct iris_inst *inst); |
| 13 | 24 | int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); |
| @@ -221,6 +221,33 @@ static void iris_session_close(struct iris_inst *inst) · 220 unmodified lines | ||
| 221 | 221 | iris_wait_for_session_response(inst, false); |
| 222 | 222 | } |
| 223 | 223 | |
| 224 | +static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 plane) | |
| 225 | +{ | |
| 226 | + const struct iris_platform_data *platform_data = inst->core->iris_platform_data; | |
| 227 | + struct iris_buffer *buf, *next; | |
| 228 | + struct iris_buffers *buffers; | |
| 229 | + const u32 *internal_buf_type; | |
| 230 | + u32 internal_buffer_count, i; | |
| 231 | + u32 count = 0; | |
| 232 | + | |
| 233 | + if (V4L2_TYPE_IS_OUTPUT(plane)) { | |
| 234 | + internal_buf_type = platform_data->dec_ip_int_buf_tbl; | |
| 235 | + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; | |
| 236 | + } else { | |
| 237 | + internal_buf_type = platform_data->dec_op_int_buf_tbl; | |
| 238 | + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; | |
| 239 | + } | |
| 240 | + | |
| 241 | + for (i = 0; i < internal_buffer_count; i++) { | |
| 242 | + buffers = &inst->buffers[internal_buf_type[i]]; | |
| 243 | + list_for_each_entry_safe(buf, next, &buffers->list, list) | |
| 244 | + count++; | |
| 245 | + if (count) | |
| 246 | + dev_err(inst->core->dev, "%d buffer of type %d not released", | |
| 247 | + count, internal_buf_type[i]); | |
| 248 | + } | |
| 249 | +} | |
| 250 | + | |
| 224 | 251 | int iris_close(struct file *filp) |
| 225 | 252 | { |
| 226 | 253 | struct iris_inst *inst = iris_get_inst(filp, NULL); |
| @@ -233,8 +260,10 @@ int iris_close(struct file *filp) · 6 unmodified lines | ||
| 233 | 260 | iris_session_close(inst); |
| 234 | 261 | iris_inst_change_state(inst, IRIS_INST_DEINIT); |
| 235 | 262 | iris_v4l2_fh_deinit(inst); |
| 236 | − iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 237 | − iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 263 | + iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 264 | + iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 265 | + iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 266 | + iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 238 | 267 | iris_remove_session(inst); |
| 239 | 268 | mutex_unlock(&inst->lock); |
| 240 | 269 | mutex_destroy(&inst->ctx_q_lock); |
| @@ -249,9 +278,6 @@ static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) · 8 unmodified lines | ||
| 249 | 278 | { |
| 250 | 279 | struct iris_inst *inst = iris_get_inst(filp, NULL); |
| 251 | 280 | |
| 252 | − if (f->index) | |
| 253 | − return -EINVAL; | |
| 254 | − | |
| 255 | 281 | return iris_vdec_enum_fmt(inst, f); |
| 256 | 282 | } |
| 257 | 283 | |
| @@ -31,6 +31,42 @@ static u32 hfi_buffer_bin_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_p · 30 unmodified lines | ||
| 31 | 31 | return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | +static u32 size_h265d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | |
| 35 | +{ | |
| 36 | + u32 product = frame_width * frame_height; | |
| 37 | + u32 size_yuv, size_bin_hdr, size_bin_res; | |
| 38 | + | |
| 39 | + size_yuv = (product <= BIN_BUFFER_THRESHOLD) ? | |
| 40 | + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : ((product * 3) >> 1); | |
| 41 | + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; | |
| 42 | + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; | |
| 43 | + size_bin_hdr = ALIGN(size_bin_hdr / num_vpp_pipes, DMA_ALIGNMENT) * num_vpp_pipes; | |
| 44 | + size_bin_res = ALIGN(size_bin_res / num_vpp_pipes, DMA_ALIGNMENT) * num_vpp_pipes; | |
| 45 | + | |
| 46 | + return size_bin_hdr + size_bin_res; | |
| 47 | +} | |
| 48 | + | |
| 49 | +static u32 hfi_buffer_bin_vp9d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | |
| 50 | +{ | |
| 51 | + u32 _size_yuv = ALIGN(frame_width, 16) * ALIGN(frame_height, 16) * 3 / 2; | |
| 52 | + u32 _size = ALIGN(((max_t(u32, _size_yuv, ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * | |
| 53 | + VPX_DECODER_FRAME_BIN_HDR_BUDGET / VPX_DECODER_FRAME_BIN_DENOMINATOR * | |
| 54 | + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), DMA_ALIGNMENT) + | |
| 55 | + ALIGN(((max_t(u32, _size_yuv, ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * | |
| 56 | + VPX_DECODER_FRAME_BIN_RES_BUDGET / VPX_DECODER_FRAME_BIN_DENOMINATOR * | |
| 57 | + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), DMA_ALIGNMENT); | |
| 58 | + | |
| 59 | + return _size * num_vpp_pipes; | |
| 60 | +} | |
| 61 | + | |
| 62 | +static u32 hfi_buffer_bin_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | |
| 63 | +{ | |
| 64 | + u32 n_aligned_w = ALIGN(frame_width, 16); | |
| 65 | + u32 n_aligned_h = ALIGN(frame_height, 16); | |
| 66 | + | |
| 67 | + return size_h265d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); | |
| 68 | +} | |
| 69 | + | |
| 34 | 70 | static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) |
| 35 | 71 | { |
| 36 | 72 | u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16); |
| @@ -55,6 +91,17 @@ static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bu · 18 unmodified lines | ||
| 55 | 91 | return (size_colloc * (_comv_bufcount)) + 512; |
| 56 | 92 | } |
| 57 | 93 | |
| 94 | +static u32 hfi_buffer_comv_h265d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) | |
| 95 | +{ | |
| 96 | + u32 frame_height_in_mbs = (frame_height + 15) >> 4; | |
| 97 | + u32 frame_width_in_mbs = (frame_width + 15) >> 4; | |
| 98 | + u32 _size; | |
| 99 | + | |
| 100 | + _size = ALIGN(((frame_width_in_mbs * frame_height_in_mbs) << 8), 512); | |
| 101 | + | |
| 102 | + return (_size * (_comv_bufcount)) + 512; | |
| 103 | +} | |
| 104 | + | |
| 58 | 105 | static u32 size_h264d_bse_cmd_buf(u32 frame_height) |
| 59 | 106 | { |
| 60 | 107 | u32 height = ALIGN(frame_height, 32); |
| @@ -63,6 +110,44 @@ static u32 size_h264d_bse_cmd_buf(u32 frame_height) · 2 unmodified lines | ||
| 63 | 110 | SIZE_H264D_BSE_CMD_PER_BUF; |
| 64 | 111 | } |
| 65 | 112 | |
| 113 | +static u32 size_h265d_bse_cmd_buf(u32 frame_width, u32 frame_height) | |
| 114 | +{ | |
| 115 | + u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * | |
| 116 | + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * | |
| 117 | + NUM_HW_PIC_BUF, DMA_ALIGNMENT); | |
| 118 | + _size = min_t(u32, _size, H265D_MAX_SLICE + 1); | |
| 119 | + _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; | |
| 120 | + | |
| 121 | + return _size; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static u32 hfi_buffer_persist_h265d(u32 rpu_enabled) | |
| 125 | +{ | |
| 126 | + return ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + | |
| 127 | + H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + | |
| 128 | + H265_NUM_TILE * sizeof(u32) + | |
| 129 | + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + | |
| 130 | + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), | |
| 131 | + DMA_ALIGNMENT); | |
| 132 | +} | |
| 133 | + | |
| 134 | +static inline | |
| 135 | +u32 hfi_iris3_vp9d_comv_size(void) | |
| 136 | +{ | |
| 137 | + return (((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8); | |
| 138 | +} | |
| 139 | + | |
| 140 | +static u32 hfi_buffer_persist_vp9d(void) | |
| 141 | +{ | |
| 142 | + return ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, DMA_ALIGNMENT) + | |
| 143 | + ALIGN(hfi_iris3_vp9d_comv_size(), DMA_ALIGNMENT) + | |
| 144 | + ALIGN(MAX_SUPERFRAME_HEADER_LEN, DMA_ALIGNMENT) + | |
| 145 | + ALIGN(VP9_UDC_HEADER_BUF_SIZE, DMA_ALIGNMENT) + | |
| 146 | + ALIGN(VP9_NUM_FRAME_INFO_BUF * CCE_TILE_OFFSET_SIZE, DMA_ALIGNMENT) + | |
| 147 | + ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, DMA_ALIGNMENT) + | |
| 148 | + HDR10_HIST_EXTRADATA_SIZE; | |
| 149 | +} | |
| 150 | + | |
| 66 | 151 | static u32 size_h264d_vpp_cmd_buf(u32 frame_height) |
| 67 | 152 | { |
| 68 | 153 | u32 size, height = ALIGN(frame_height, 32); |
| @@ -83,17 +168,45 @@ static u32 hfi_buffer_persist_h264d(void) · 14 unmodified lines | ||
| 83 | 168 | |
| 84 | 169 | static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) |
| 85 | 170 | { |
| 86 | − u32 size_bse, size_vpp, size; | |
| 87 | − | |
| 88 | − size_bse = size_h264d_bse_cmd_buf(frame_height); | |
| 89 | − size_vpp = size_h264d_vpp_cmd_buf(frame_height); | |
| 90 | − size = ALIGN(size_bse, DMA_ALIGNMENT) + | |
| 171 | + u32 size_bse = size_h264d_bse_cmd_buf(frame_height); | |
| 172 | + u32 size_vpp = size_h264d_vpp_cmd_buf(frame_height); | |
| 173 | + u32 size = ALIGN(size_bse, DMA_ALIGNMENT) + | |
| 91 | 174 | ALIGN(size_vpp, DMA_ALIGNMENT) + |
| 92 | 175 | ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT); |
| 93 | 176 | |
| 94 | 177 | return ALIGN(size, DMA_ALIGNMENT); |
| 95 | 178 | } |
| 96 | 179 | |
| 180 | +static u32 size_h265d_vpp_cmd_buf(u32 frame_width, u32 frame_height) | |
| 181 | +{ | |
| 182 | + u32 _size = ALIGN(((ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * | |
| 183 | + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * | |
| 184 | + NUM_HW_PIC_BUF, DMA_ALIGNMENT); | |
| 185 | + _size = min_t(u32, _size, H265D_MAX_SLICE + 1); | |
| 186 | + _size = ALIGN(_size, 4); | |
| 187 | + _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; | |
| 188 | + if (_size > VPP_CMD_MAX_SIZE) | |
| 189 | + _size = VPP_CMD_MAX_SIZE; | |
| 190 | + | |
| 191 | + return _size; | |
| 192 | +} | |
| 193 | + | |
| 194 | +static u32 hfi_buffer_non_comv_h265d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | |
| 195 | +{ | |
| 196 | + u32 _size_bse = size_h265d_bse_cmd_buf(frame_width, frame_height); | |
| 197 | + u32 _size_vpp = size_h265d_vpp_cmd_buf(frame_width, frame_height); | |
| 198 | + u32 _size = ALIGN(_size_bse, DMA_ALIGNMENT) + | |
| 199 | + ALIGN(_size_vpp, DMA_ALIGNMENT) + | |
| 200 | + ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, DMA_ALIGNMENT) + | |
| 201 | + ALIGN(2 * sizeof(u16) * | |
| 202 | + (ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * | |
| 203 | + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), DMA_ALIGNMENT) + | |
| 204 | + ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), DMA_ALIGNMENT) + | |
| 205 | + HDR10_HIST_EXTRADATA_SIZE; | |
| 206 | + | |
| 207 | + return ALIGN(_size, DMA_ALIGNMENT); | |
| 208 | +} | |
| 209 | + | |
| 97 | 210 | static u32 size_vpss_lb(u32 frame_width, u32 frame_height) |
| 98 | 211 | { |
| 99 | 212 | u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size; |
| @@ -119,6 +232,203 @@ static u32 size_vpss_lb(u32 frame_width, u32 frame_height) · 19 unmodified lines | ||
| 119 | 232 | opb_lb_wr_llb_y_buffer_size; |
| 120 | 233 | } |
| 121 | 234 | |
| 235 | +static inline | |
| 236 | +u32 size_h265d_lb_fe_top_data(u32 frame_width, u32 frame_height) | |
| 237 | +{ | |
| 238 | + return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * | |
| 239 | + (ALIGN(frame_width, 64) + 8) * 2; | |
| 240 | +} | |
| 241 | + | |
| 242 | +static inline | |
| 243 | +u32 size_h265d_lb_fe_top_ctrl(u32 frame_width, u32 frame_height) | |
| 244 | +{ | |
| 245 | + return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * | |
| 246 | + (ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS); | |
| 247 | +} | |
| 248 | + | |
| 249 | +static inline | |
| 250 | +u32 size_h265d_lb_fe_left_ctrl(u32 frame_width, u32 frame_height) | |
| 251 | +{ | |
| 252 | + return MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * | |
| 253 | + (ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS); | |
| 254 | +} | |
| 255 | + | |
| 256 | +static inline | |
| 257 | +u32 size_h265d_lb_se_top_ctrl(u32 frame_width, u32 frame_height) | |
| 258 | +{ | |
| 259 | + return (LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4); | |
| 260 | +} | |
| 261 | + | |
| 262 | +static inline | |
| 263 | +u32 size_h265d_lb_se_left_ctrl(u32 frame_width, u32 frame_height) | |
| 264 | +{ | |
| 265 | + return max_t(u32, ((frame_height + 16 - 1) / 8) * | |
| 266 | + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, | |
| 267 | + max_t(u32, ((frame_height + 32 - 1) / 8) * | |
| 268 | + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, | |
| 269 | + ((frame_height + 64 - 1) / 8) * | |
| 270 | + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); | |
| 271 | +} | |
| 272 | + | |
| 273 | +static inline | |
| 274 | +u32 size_h265d_lb_pe_top_data(u32 frame_width, u32 frame_height) | |
| 275 | +{ | |
| 276 | + return MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * | |
| 277 | + (ALIGN(frame_width, LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS); | |
| 278 | +} | |
| 279 | + | |
| 280 | +static inline | |
| 281 | +u32 size_h265d_lb_vsp_top(u32 frame_width, u32 frame_height) | |
| 282 | +{ | |
| 283 | + return ((frame_width + 63) >> 6) * 128; | |
| 284 | +} | |
| 285 | + | |
| 286 | +static inline | |
| 287 | +u32 size_h265d_lb_vsp_left(u32 frame_width, u32 frame_height) | |
| 288 | +{ | |
| 289 | + return ((frame_height + 63) >> 6) * 128; | |
| 290 | +} | |
| 291 | + | |
| 292 | +static inline | |
| 293 | +u32 size_h265d_lb_recon_dma_metadata_wr(u32 frame_width, u32 frame_height) | |
| 294 | +{ | |
| 295 | + return size_h264d_lb_recon_dma_metadata_wr(frame_height); | |
| 296 | +} | |
| 297 | + | |
| 298 | +static inline | |
| 299 | +u32 size_h265d_qp(u32 frame_width, u32 frame_height) | |
| 300 | +{ | |
| 301 | + return size_h264d_qp(frame_width, frame_height); | |
| 302 | +} | |
| 303 | + | |
| 304 | +static inline | |
| 305 | +u32 hfi_buffer_line_h265d(u32 frame_width, u32 frame_height, bool is_opb, u32 num_vpp_pipes) | |
| 306 | +{ | |
| 307 | + u32 vpss_lb_size = 0, _size; | |
| 308 | + | |
| 309 | + _size = ALIGN(size_h265d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 310 | + ALIGN(size_h265d_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 311 | + ALIGN(size_h265d_lb_fe_left_ctrl(frame_width, frame_height), | |
| 312 | + DMA_ALIGNMENT) * num_vpp_pipes + | |
| 313 | + ALIGN(size_h265d_lb_se_left_ctrl(frame_width, frame_height), | |
| 314 | + DMA_ALIGNMENT) * num_vpp_pipes + | |
| 315 | + ALIGN(size_h265d_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 316 | + ALIGN(size_h265d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 317 | + ALIGN(size_h265d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 318 | + ALIGN(size_h265d_lb_vsp_left(frame_width, frame_height), | |
| 319 | + DMA_ALIGNMENT) * num_vpp_pipes + | |
| 320 | + ALIGN(size_h265d_lb_recon_dma_metadata_wr(frame_width, frame_height), | |
| 321 | + DMA_ALIGNMENT) * 4 + | |
| 322 | + ALIGN(size_h265d_qp(frame_width, frame_height), DMA_ALIGNMENT); | |
| 323 | + if (is_opb) | |
| 324 | + vpss_lb_size = size_vpss_lb(frame_width, frame_height); | |
| 325 | + | |
| 326 | + return ALIGN((_size + vpss_lb_size), DMA_ALIGNMENT); | |
| 327 | +} | |
| 328 | + | |
| 329 | +static inline | |
| 330 | +u32 size_vpxd_lb_fe_left_ctrl(u32 frame_width, u32 frame_height) | |
| 331 | +{ | |
| 332 | + return max_t(u32, ((frame_height + 15) >> 4) * | |
| 333 | + MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, | |
| 334 | + max_t(u32, ((frame_height + 31) >> 5) * | |
| 335 | + MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, | |
| 336 | + ((frame_height + 63) >> 6) * | |
| 337 | + MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); | |
| 338 | +} | |
| 339 | + | |
| 340 | +static inline | |
| 341 | +u32 size_vpxd_lb_fe_top_ctrl(u32 frame_width, u32 frame_height) | |
| 342 | +{ | |
| 343 | + return ((ALIGN(frame_width, 64) + 8) * 10 * 2); | |
| 344 | +} | |
| 345 | + | |
| 346 | +static inline | |
| 347 | +u32 size_vpxd_lb_se_top_ctrl(u32 frame_width, u32 frame_height) | |
| 348 | +{ | |
| 349 | + return ((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE; | |
| 350 | +} | |
| 351 | + | |
| 352 | +static inline | |
| 353 | +u32 size_vpxd_lb_se_left_ctrl(u32 frame_width, u32 frame_height) | |
| 354 | +{ | |
| 355 | + return max_t(u32, ((frame_height + 15) >> 4) * | |
| 356 | + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, | |
| 357 | + max_t(u32, ((frame_height + 31) >> 5) * | |
| 358 | + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, | |
| 359 | + ((frame_height + 63) >> 6) * | |
| 360 | + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)); | |
| 361 | +} | |
| 362 | + | |
| 363 | +static inline | |
| 364 | +u32 size_vpxd_lb_recon_dma_metadata_wr(u32 frame_width, u32 frame_height) | |
| 365 | +{ | |
| 366 | + return ALIGN((ALIGN(frame_height, 8) / (4 / 2)) * 64, | |
| 367 | + BUFFER_ALIGNMENT_32_BYTES); | |
| 368 | +} | |
| 369 | + | |
| 370 | +static inline __maybe_unused | |
| 371 | +u32 size_mp2d_lb_fe_top_data(u32 frame_width, u32 frame_height) | |
| 372 | +{ | |
| 373 | + return ((ALIGN(frame_width, 16) + 8) * 10 * 2); | |
| 374 | +} | |
| 375 | + | |
| 376 | +static inline | |
| 377 | +u32 size_vp9d_lb_fe_top_data(u32 frame_width, u32 frame_height) | |
| 378 | +{ | |
| 379 | + return (ALIGN(ALIGN(frame_width, 8), 64) + 8) * 10 * 2; | |
| 380 | +} | |
| 381 | + | |
| 382 | +static inline | |
| 383 | +u32 size_vp9d_lb_pe_top_data(u32 frame_width, u32 frame_height) | |
| 384 | +{ | |
| 385 | + return ((ALIGN(ALIGN(frame_width, 8), 64) >> 6) * 176); | |
| 386 | +} | |
| 387 | + | |
| 388 | +static inline | |
| 389 | +u32 size_vp9d_lb_vsp_top(u32 frame_width, u32 frame_height) | |
| 390 | +{ | |
| 391 | + return (((ALIGN(ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256); | |
| 392 | +} | |
| 393 | + | |
| 394 | +static inline | |
| 395 | +u32 size_vp9d_qp(u32 frame_width, u32 frame_height) | |
| 396 | +{ | |
| 397 | + return size_h264d_qp(frame_width, frame_height); | |
| 398 | +} | |
| 399 | + | |
| 400 | +static inline | |
| 401 | +u32 hfi_iris3_vp9d_lb_size(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | |
| 402 | +{ | |
| 403 | + return ALIGN(size_vpxd_lb_fe_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) * | |
| 404 | + num_vpp_pipes + | |
| 405 | + ALIGN(size_vpxd_lb_se_left_ctrl(frame_width, frame_height), DMA_ALIGNMENT) * | |
| 406 | + num_vpp_pipes + | |
| 407 | + ALIGN(size_vp9d_lb_vsp_top(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 408 | + ALIGN(size_vpxd_lb_fe_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 409 | + 2 * ALIGN(size_vpxd_lb_recon_dma_metadata_wr(frame_width, frame_height), | |
| 410 | + DMA_ALIGNMENT) + | |
| 411 | + ALIGN(size_vpxd_lb_se_top_ctrl(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 412 | + ALIGN(size_vp9d_lb_pe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 413 | + ALIGN(size_vp9d_lb_fe_top_data(frame_width, frame_height), DMA_ALIGNMENT) + | |
| 414 | + ALIGN(size_vp9d_qp(frame_width, frame_height), DMA_ALIGNMENT); | |
| 415 | +} | |
| 416 | + | |
| 417 | +static inline | |
| 418 | +u32 hfi_buffer_line_vp9d(u32 frame_width, u32 frame_height, u32 _yuv_bufcount_min, bool is_opb, | |
| 419 | + u32 num_vpp_pipes) | |
| 420 | +{ | |
| 421 | + u32 vpss_lb_size = 0; | |
| 422 | + u32 _lb_size; | |
| 423 | + | |
| 424 | + _lb_size = hfi_iris3_vp9d_lb_size(frame_width, frame_height, num_vpp_pipes); | |
| 425 | + | |
| 426 | + if (is_opb) | |
| 427 | + vpss_lb_size = size_vpss_lb(frame_width, frame_height); | |
| 428 | + | |
| 429 | + return _lb_size + vpss_lb_size + 4096; | |
| 430 | +} | |
| 431 | + | |
| 122 | 432 | static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height, |
| 123 | 433 | bool is_opb, u32 num_vpp_pipes) |
| 124 | 434 | { |
| @@ -148,7 +458,14 @@ static u32 iris_vpu_dec_bin_size(struct iris_inst *inst) · 23 unmodified lines | ||
| 148 | 458 | u32 height = f->fmt.pix_mp.height; |
| 149 | 459 | u32 width = f->fmt.pix_mp.width; |
| 150 | 460 | |
| 151 | − return hfi_buffer_bin_h264d(width, height, num_vpp_pipes); | |
| 461 | + if (inst->codec == V4L2_PIX_FMT_H264) | |
| 462 | + return hfi_buffer_bin_h264d(width, height, num_vpp_pipes); | |
| 463 | + else if (inst->codec == V4L2_PIX_FMT_HEVC) | |
| 464 | + return hfi_buffer_bin_h265d(width, height, num_vpp_pipes); | |
| 465 | + else if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 466 | + return hfi_buffer_bin_vp9d(width, height, num_vpp_pipes); | |
| 467 | + | |
| 468 | + return 0; | |
| 152 | 469 | } |
| 153 | 470 | |
| 154 | 471 | static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) |
| @@ -158,12 +475,24 @@ static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) · 3 unmodified lines | ||
| 158 | 475 | u32 height = f->fmt.pix_mp.height; |
| 159 | 476 | u32 width = f->fmt.pix_mp.width; |
| 160 | 477 | |
| 161 | − return hfi_buffer_comv_h264d(width, height, num_comv); | |
| 478 | + if (inst->codec == V4L2_PIX_FMT_H264) | |
| 479 | + return hfi_buffer_comv_h264d(width, height, num_comv); | |
| 480 | + else if (inst->codec == V4L2_PIX_FMT_HEVC) | |
| 481 | + return hfi_buffer_comv_h265d(width, height, num_comv); | |
| 482 | + | |
| 483 | + return 0; | |
| 162 | 484 | } |
| 163 | 485 | |
| 164 | 486 | static u32 iris_vpu_dec_persist_size(struct iris_inst *inst) |
| 165 | 487 | { |
| 166 | − return hfi_buffer_persist_h264d(); | |
| 488 | + if (inst->codec == V4L2_PIX_FMT_H264) | |
| 489 | + return hfi_buffer_persist_h264d(); | |
| 490 | + else if (inst->codec == V4L2_PIX_FMT_HEVC) | |
| 491 | + return hfi_buffer_persist_h265d(0); | |
| 492 | + else if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 493 | + return hfi_buffer_persist_vp9d(); | |
| 494 | + | |
| 495 | + return 0; | |
| 167 | 496 | } |
| 168 | 497 | |
| 169 | 498 | static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst) |
| @@ -181,7 +510,12 @@ static u32 iris_vpu_dec_non_comv_size(struct iris_inst *inst) · 11 unmodified lines | ||
| 181 | 510 | u32 height = f->fmt.pix_mp.height; |
| 182 | 511 | u32 width = f->fmt.pix_mp.width; |
| 183 | 512 | |
| 184 | − return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes); | |
| 513 | + if (inst->codec == V4L2_PIX_FMT_H264) | |
| 514 | + return hfi_buffer_non_comv_h264d(width, height, num_vpp_pipes); | |
| 515 | + else if (inst->codec == V4L2_PIX_FMT_HEVC) | |
| 516 | + return hfi_buffer_non_comv_h265d(width, height, num_vpp_pipes); | |
| 517 | + | |
| 518 | + return 0; | |
| 185 | 519 | } |
| 186 | 520 | |
| 187 | 521 | static u32 iris_vpu_dec_line_size(struct iris_inst *inst) |
| @@ -191,11 +525,20 @@ static u32 iris_vpu_dec_line_size(struct iris_inst *inst) · 3 unmodified lines | ||
| 191 | 525 | u32 height = f->fmt.pix_mp.height; |
| 192 | 526 | u32 width = f->fmt.pix_mp.width; |
| 193 | 527 | bool is_opb = false; |
| 528 | + u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count; | |
| 194 | 529 | |
| 195 | 530 | if (iris_split_mode_enabled(inst)) |
| 196 | 531 | is_opb = true; |
| 197 | 532 | |
| 198 | − return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); | |
| 533 | + if (inst->codec == V4L2_PIX_FMT_H264) | |
| 534 | + return hfi_buffer_line_h264d(width, height, is_opb, num_vpp_pipes); | |
| 535 | + else if (inst->codec == V4L2_PIX_FMT_HEVC) | |
| 536 | + return hfi_buffer_line_h265d(width, height, is_opb, num_vpp_pipes); | |
| 537 | + else if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 538 | + return hfi_buffer_line_vp9d(width, height, out_min_count, is_opb, | |
| 539 | + num_vpp_pipes); | |
| 540 | + | |
| 541 | + return 0; | |
| 199 | 542 | } |
| 200 | 543 | |
| 201 | 544 | static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) |
| @@ -205,6 +548,24 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) · 3 unmodified lines | ||
| 205 | 548 | iris_vpu_dec_line_size(inst); |
| 206 | 549 | } |
| 207 | 550 | |
| 551 | +static int output_min_count(struct iris_inst *inst) | |
| 552 | +{ | |
| 553 | + int output_min_count = 4; | |
| 554 | + | |
| 555 | + /* fw_min_count > 0 indicates reconfig event has already arrived */ | |
| 556 | + if (inst->fw_min_count) { | |
| 557 | + if (iris_split_mode_enabled(inst) && inst->codec == V4L2_PIX_FMT_VP9) | |
| 558 | + return min_t(u32, 4, inst->fw_min_count); | |
| 559 | + else | |
| 560 | + return inst->fw_min_count; | |
| 561 | + } | |
| 562 | + | |
| 563 | + if (inst->codec == V4L2_PIX_FMT_VP9) | |
| 564 | + output_min_count = 9; | |
| 565 | + | |
| 566 | + return output_min_count; | |
| 567 | +} | |
| 568 | + | |
| 208 | 569 | struct iris_vpu_buf_type_handle { |
| 209 | 570 | enum iris_buffer_type type; |
| 210 | 571 | u32 (*handle)(struct iris_inst *inst); |
| @@ -238,6 +599,19 @@ int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) · 27 unmodified lines | ||
| 238 | 599 | return size; |
| 239 | 600 | } |
| 240 | 601 | |
| 602 | +static u32 internal_buffer_count(struct iris_inst *inst, | |
| 603 | + enum iris_buffer_type buffer_type) | |
| 604 | +{ | |
| 605 | + if (buffer_type == BUF_BIN || buffer_type == BUF_LINE || | |
| 606 | + buffer_type == BUF_PERSIST) { | |
| 607 | + return 1; | |
| 608 | + } else if (buffer_type == BUF_COMV || buffer_type == BUF_NON_COMV) { | |
| 609 | + if (inst->codec == V4L2_PIX_FMT_H264 || inst->codec == V4L2_PIX_FMT_HEVC) | |
| 610 | + return 1; | |
| 611 | + } | |
| 612 | + return 0; | |
| 613 | +} | |
| 614 | + | |
| 241 | 615 | static inline int iris_vpu_dpb_count(struct iris_inst *inst) |
| 242 | 616 | { |
| 243 | 617 | if (iris_split_mode_enabled(inst)) { |
| @@ -254,12 +628,13 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type · 10 unmodified lines | ||
| 254 | 628 | case BUF_INPUT: |
| 255 | 629 | return MIN_BUFFERS; |
| 256 | 630 | case BUF_OUTPUT: |
| 257 | − return inst->fw_min_count; | |
| 631 | + return output_min_count(inst); | |
| 258 | 632 | case BUF_BIN: |
| 259 | 633 | case BUF_COMV: |
| 260 | 634 | case BUF_NON_COMV: |
| 261 | 635 | case BUF_LINE: |
| 262 | 636 | case BUF_PERSIST: |
| 637 | + return internal_buffer_count(inst, buffer_type); | |
| 263 | 638 | case BUF_SCRATCH_1: |
| 264 | 639 | return 1; /* internal buffer count needed by firmware is 1 */ |
| 265 | 640 | case BUF_DPB: |
| @@ -13,6 +13,10 @@ struct iris_inst; · 12 unmodified lines | ||
| 13 | 13 | #define DMA_ALIGNMENT 256 |
| 14 | 14 | |
| 15 | 15 | #define NUM_HW_PIC_BUF 32 |
| 16 | +#define LCU_MAX_SIZE_PELS 64 | |
| 17 | +#define LCU_MIN_SIZE_PELS 16 | |
| 18 | +#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024) | |
| 19 | + | |
| 16 | 20 | #define SIZE_HW_PIC(size_per_buf) (NUM_HW_PIC_BUF * (size_per_buf)) |
| 17 | 21 | |
| 18 | 22 | #define MAX_TILE_COLUMNS 32 |
| @@ -28,11 +32,47 @@ struct iris_inst; · 9 unmodified lines | ||
| 28 | 32 | #define SIZE_SLIST_BUF_H264 512 |
| 29 | 33 | #define H264_DISPLAY_BUF_SIZE 3328 |
| 30 | 34 | #define H264_NUM_FRM_INFO 66 |
| 31 | − | |
| 32 | −#define SIZE_SEI_USERDATA 4096 | |
| 33 | − | |
| 35 | +#define H265_NUM_TILE_COL 32 | |
| 36 | +#define H265_NUM_TILE_ROW 128 | |
| 37 | +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) | |
| 38 | +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(u32)) | |
| 39 | + | |
| 40 | +#define NUM_SLIST_BUF_H265 (80 + 20) | |
| 41 | +#define SIZE_SLIST_BUF_H265 (BIT(10)) | |
| 42 | +#define H265_DISPLAY_BUF_SIZE (3072) | |
| 43 | +#define H265_NUM_FRM_INFO (48) | |
| 44 | + | |
| 45 | +#define VP9_NUM_FRAME_INFO_BUF 32 | |
| 46 | +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) | |
| 47 | +#define VP9_PROB_TABLE_SIZE (3840) | |
| 48 | +#define VP9_FRAME_INFO_BUF_SIZE (6144) | |
| 49 | +#define BUFFER_ALIGNMENT_32_BYTES 32 | |
| 50 | +#define CCE_TILE_OFFSET_SIZE ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) | |
| 51 | +#define MAX_SUPERFRAME_HEADER_LEN (34) | |
| 52 | +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 | |
| 53 | +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 | |
| 54 | +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 | |
| 55 | +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) | |
| 56 | +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) | |
| 57 | +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) | |
| 58 | + | |
| 59 | +#define SIZE_SEI_USERDATA 4096 | |
| 60 | +#define SIZE_DOLBY_RPU_METADATA (41 * 1024) | |
| 34 | 61 | #define H264_CABAC_HDR_RATIO_HD_TOT 1 |
| 35 | 62 | #define H264_CABAC_RES_RATIO_HD_TOT 3 |
| 63 | +#define H265D_MAX_SLICE 1200 | |
| 64 | +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T | |
| 65 | +#define H265_CABAC_HDR_RATIO_HD_TOT 2 | |
| 66 | +#define H265_CABAC_RES_RATIO_HD_TOT 2 | |
| 67 | +#define SIZE_H265D_VPP_CMD_PER_BUF (256) | |
| 68 | + | |
| 69 | +#define VPX_DECODER_FRAME_CONCURENCY_LVL (2) | |
| 70 | +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET 1 | |
| 71 | +#define VPX_DECODER_FRAME_BIN_RES_BUDGET 3 | |
| 72 | +#define VPX_DECODER_FRAME_BIN_DENOMINATOR 2 | |
| 73 | + | |
| 74 | +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO (3 / 2) | |
| 75 | + | |
| 36 | 76 | #define SIZE_H264D_HW_PIC_T (BIT(11)) |
| 37 | 77 | |
| 38 | 78 | #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 |
| @@ -424,13 +424,13 @@ static int venus_probe(struct platform_device *pdev) · 423 unmodified lines | ||
| 424 | 424 | INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); |
| 425 | 425 | init_waitqueue_head(&core->sys_err_done); |
| 426 | 426 | |
| 427 | − ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, | |
| 428 | − IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | |
| 429 | − "venus", core); | |
| 427 | + ret = hfi_create(core, &venus_core_ops); | |
| 430 | 428 | if (ret) |
| 431 | 429 | goto err_core_put; |
| 432 | 430 | |
| 433 | − ret = hfi_create(core, &venus_core_ops); | |
| 431 | + ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, | |
| 432 | + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | |
| 433 | + "venus", core); | |
| 434 | 434 | if (ret) |
| 435 | 435 | goto err_core_put; |
| 436 | 436 | |
| @@ -709,11 +709,11 @@ static const struct venus_resources msm8996_res = { · 272 unmodified lines | ||
| 709 | 709 | }; |
| 710 | 710 | |
| 711 | 711 | static const struct freq_tbl msm8998_freq_table[] = { |
| 712 | − { 1944000, 465000000 }, /* 4k UHD @ 60 (decode only) */ | |
| 713 | − { 972000, 465000000 }, /* 4k UHD @ 30 */ | |
| 714 | − { 489600, 360000000 }, /* 1080p @ 60 */ | |
| 715 | − { 244800, 186000000 }, /* 1080p @ 30 */ | |
| 716 | − { 108000, 100000000 }, /* 720p @ 30 */ | |
| 712 | + { 1728000, 533000000 }, /* 4k UHD @ 60 (decode only) */ | |
| 713 | + { 1036800, 444000000 }, /* 2k @ 120 */ | |
| 714 | + { 829440, 355200000 }, /* 4k @ 44 */ | |
| 715 | + { 489600, 269330000 },/* 4k @ 30 */ | |
| 716 | + { 108000, 200000000 }, /* 1080p @ 60 */ | |
| 717 | 717 | }; |
| 718 | 718 | |
| 719 | 719 | static const struct reg_val msm8998_reg_preset[] = { |
| @@ -28,6 +28,8 @@ · 27 unmodified lines | ||
| 28 | 28 | #define VIDC_RESETS_NUM_MAX 2 |
| 29 | 29 | #define VIDC_MAX_HIER_CODING_LAYER 6 |
| 30 | 30 | |
| 31 | +#define VENUS_MAX_FPS 240 | |
| 32 | + | |
| 31 | 33 | extern int venus_fw_debug; |
| 32 | 34 | |
| 33 | 35 | struct freq_tbl { |
| @@ -33,8 +33,9 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, · 32 unmodified lines | ||
| 33 | 33 | struct hfi_buffer_requirements *bufreq; |
| 34 | 34 | struct hfi_extradata_input_crop *crop; |
| 35 | 35 | struct hfi_dpb_counts *dpb_count; |
| 36 | + u32 ptype, rem_bytes; | |
| 37 | + u32 size_read = 0; | |
| 36 | 38 | u8 *data_ptr; |
| 37 | − u32 ptype; | |
| 38 | 39 | |
| 39 | 40 | inst->error = HFI_ERR_NONE; |
| 40 | 41 | |
| @@ -44,86 +45,118 @@ static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, · 3 unmodified lines | ||
| 44 | 45 | break; |
| 45 | 46 | default: |
| 46 | 47 | inst->error = HFI_ERR_SESSION_INVALID_PARAMETER; |
| 47 | − goto done; | |
| 48 | + inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
| 49 | + return; | |
| 48 | 50 | } |
| 49 | 51 | |
| 50 | 52 | event.event_type = pkt->event_data1; |
| 51 | 53 | |
| 52 | 54 | num_properties_changed = pkt->event_data2; |
| 53 | − if (!num_properties_changed) { | |
| 54 | − inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
| 55 | − goto done; | |
| 56 | − } | |
| 55 | + if (!num_properties_changed) | |
| 56 | + goto error; | |
| 57 | 57 | |
| 58 | 58 | data_ptr = (u8 *)&pkt->ext_event_data[0]; |
| 59 | + rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | |
| 60 | + | |
| 59 | 61 | do { |
| 62 | + if (rem_bytes < sizeof(u32)) | |
| 63 | + goto error; | |
| 60 | 64 | ptype = *((u32 *)data_ptr); |
| 65 | + | |
| 66 | + data_ptr += sizeof(u32); | |
| 67 | + rem_bytes -= sizeof(u32); | |
| 68 | + | |
| 61 | 69 | switch (ptype) { |
| 62 | 70 | case HFI_PROPERTY_PARAM_FRAME_SIZE: |
| 63 | − data_ptr += sizeof(u32); | |
| 71 | + if (rem_bytes < sizeof(struct hfi_framesize)) | |
| 72 | + goto error; | |
| 73 | + | |
| 64 | 74 | frame_sz = (struct hfi_framesize *)data_ptr; |
| 65 | 75 | event.width = frame_sz->width; |
| 66 | 76 | event.height = frame_sz->height; |
| 67 | − data_ptr += sizeof(*frame_sz); | |
| 77 | + size_read = sizeof(struct hfi_framesize); | |
| 68 | 78 | break; |
| 69 | 79 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: |
| 70 | − data_ptr += sizeof(u32); | |
| 80 | + if (rem_bytes < sizeof(struct hfi_profile_level)) | |
| 81 | + goto error; | |
| 82 | + | |
| 71 | 83 | profile_level = (struct hfi_profile_level *)data_ptr; |
| 72 | 84 | event.profile = profile_level->profile; |
| 73 | 85 | event.level = profile_level->level; |
| 74 | − data_ptr += sizeof(*profile_level); | |
| 86 | + size_read = sizeof(struct hfi_profile_level); | |
| 75 | 87 | break; |
| 76 | 88 | case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: |
| 77 | − data_ptr += sizeof(u32); | |
| 89 | + if (rem_bytes < sizeof(struct hfi_bit_depth)) | |
| 90 | + goto error; | |
| 91 | + | |
| 78 | 92 | pixel_depth = (struct hfi_bit_depth *)data_ptr; |
| 79 | 93 | event.bit_depth = pixel_depth->bit_depth; |
| 80 | − data_ptr += sizeof(*pixel_depth); | |
| 94 | + size_read = sizeof(struct hfi_bit_depth); | |
| 81 | 95 | break; |
| 82 | 96 | case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: |
| 83 | − data_ptr += sizeof(u32); | |
| 97 | + if (rem_bytes < sizeof(struct hfi_pic_struct)) | |
| 98 | + goto error; | |
| 99 | + | |
| 84 | 100 | pic_struct = (struct hfi_pic_struct *)data_ptr; |
| 85 | 101 | event.pic_struct = pic_struct->progressive_only; |
| 86 | − data_ptr += sizeof(*pic_struct); | |
| 102 | + size_read = sizeof(struct hfi_pic_struct); | |
| 87 | 103 | break; |
| 88 | 104 | case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: |
| 89 | − data_ptr += sizeof(u32); | |
| 105 | + if (rem_bytes < sizeof(struct hfi_colour_space)) | |
| 106 | + goto error; | |
| 107 | + | |
| 90 | 108 | colour_info = (struct hfi_colour_space *)data_ptr; |
| 91 | 109 | event.colour_space = colour_info->colour_space; |
| 92 | − data_ptr += sizeof(*colour_info); | |
| 110 | + size_read = sizeof(struct hfi_colour_space); | |
| 93 | 111 | break; |
| 94 | 112 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: |
| 95 | − data_ptr += sizeof(u32); | |
| 113 | + if (rem_bytes < sizeof(u32)) | |
| 114 | + goto error; | |
| 115 | + | |
| 96 | 116 | event.entropy_mode = *(u32 *)data_ptr; |
| 97 | − data_ptr += sizeof(u32); | |
| 117 | + size_read = sizeof(u32); | |
| 98 | 118 | break; |
| 99 | 119 | case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: |
| 100 | − data_ptr += sizeof(u32); | |
| 120 | + if (rem_bytes < sizeof(struct hfi_buffer_requirements)) | |
| 121 | + goto error; | |
| 122 | + | |
| 101 | 123 | bufreq = (struct hfi_buffer_requirements *)data_ptr; |
| 102 | 124 | event.buf_count = hfi_bufreq_get_count_min(bufreq, ver); |
| 103 | − data_ptr += sizeof(*bufreq); | |
| 125 | + size_read = sizeof(struct hfi_buffer_requirements); | |
| 104 | 126 | break; |
| 105 | 127 | case HFI_INDEX_EXTRADATA_INPUT_CROP: |
| 106 | − data_ptr += sizeof(u32); | |
| 128 | + if (rem_bytes < sizeof(struct hfi_extradata_input_crop)) | |
| 129 | + goto error; | |
| 130 | + | |
| 107 | 131 | crop = (struct hfi_extradata_input_crop *)data_ptr; |
| 108 | 132 | event.input_crop.left = crop->left; |
| 109 | 133 | event.input_crop.top = crop->top; |
| 110 | 134 | event.input_crop.width = crop->width; |
| 111 | 135 | event.input_crop.height = crop->height; |
| 112 | − data_ptr += sizeof(*crop); | |
| 136 | + size_read = sizeof(struct hfi_extradata_input_crop); | |
| 113 | 137 | break; |
| 114 | 138 | case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: |
| 115 | − data_ptr += sizeof(u32); | |
| 139 | + if (rem_bytes < sizeof(struct hfi_dpb_counts)) | |
| 140 | + goto error; | |
| 141 | + | |
| 116 | 142 | dpb_count = (struct hfi_dpb_counts *)data_ptr; |
| 117 | 143 | event.buf_count = dpb_count->fw_min_cnt; |
| 118 | − data_ptr += sizeof(*dpb_count); | |
| 144 | + size_read = sizeof(struct hfi_dpb_counts); | |
| 119 | 145 | break; |
| 120 | 146 | default: |
| 147 | + size_read = 0; | |
| 121 | 148 | break; |
| 122 | 149 | } |
| 150 | + data_ptr += size_read; | |
| 151 | + rem_bytes -= size_read; | |
| 123 | 152 | num_properties_changed--; |
| 124 | 153 | } while (num_properties_changed > 0); |
| 125 | 154 | |
| 126 | −done: | |
| 155 | + inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | |
| 156 | + return; | |
| 157 | + | |
| 158 | +error: | |
| 159 | + inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | |
| 127 | 160 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); |
| 128 | 161 | } |
| 129 | 162 | |
| @@ -239,6 +239,7 @@ static int venus_write_queue(struct venus_hfi_device *hdev, · 238 unmodified lines | ||
| 239 | 239 | static int venus_read_queue(struct venus_hfi_device *hdev, |
| 240 | 240 | struct iface_queue *queue, void *pkt, u32 *tx_req) |
| 241 | 241 | { |
| 242 | + struct hfi_pkt_hdr *pkt_hdr = NULL; | |
| 242 | 243 | struct hfi_queue_header *qhdr; |
| 243 | 244 | u32 dwords, new_rd_idx; |
| 244 | 245 | u32 rd_idx, wr_idx, type, qsize; |
| @@ -304,6 +305,9 @@ static int venus_read_queue(struct venus_hfi_device *hdev, · 59 unmodified lines | ||
| 304 | 305 | memcpy(pkt, rd_ptr, len); |
| 305 | 306 | memcpy(pkt + len, queue->qmem.kva, new_rd_idx << 2); |
| 306 | 307 | } |
| 308 | + pkt_hdr = (struct hfi_pkt_hdr *)(pkt); | |
| 309 | + if ((pkt_hdr->size >> 2) != dwords) | |
| 310 | + return -EINVAL; | |
| 307 | 311 | } else { |
| 308 | 312 | /* bad packet received, dropping */ |
| 309 | 313 | new_rd_idx = qhdr->write_idx; |
| @@ -1678,6 +1682,7 @@ void venus_hfi_destroy(struct venus_core *core) · 1368 unmodified lines | ||
| 1678 | 1682 | venus_interface_queues_release(hdev); |
| 1679 | 1683 | mutex_destroy(&hdev->lock); |
| 1680 | 1684 | kfree(hdev); |
| 1685 | + disable_irq(core->irq); | |
| 1681 | 1686 | core->ops = NULL; |
| 1682 | 1687 | } |
| 1683 | 1688 | |
| @@ -41,16 +41,14 @@ static int core_clks_get(struct venus_core *core) · 40 unmodified lines | ||
| 41 | 41 | static int core_clks_enable(struct venus_core *core) |
| 42 | 42 | { |
| 43 | 43 | const struct venus_resources *res = core->res; |
| 44 | − const struct freq_tbl *freq_tbl = core->res->freq_tbl; | |
| 45 | − unsigned int freq_tbl_size = core->res->freq_tbl_size; | |
| 46 | − unsigned long freq; | |
| 44 | + struct device *dev = core->dev; | |
| 45 | + unsigned long freq = 0; | |
| 46 | + struct dev_pm_opp *opp; | |
| 47 | 47 | unsigned int i; |
| 48 | 48 | int ret; |
| 49 | 49 | |
| 50 | − if (!freq_tbl) | |
| 51 | − return -EINVAL; | |
| 52 | − | |
| 53 | − freq = freq_tbl[freq_tbl_size - 1].freq; | |
| 50 | + opp = dev_pm_opp_find_freq_ceil(dev, &freq); | |
| 51 | + dev_pm_opp_put(opp); | |
| 54 | 52 | |
| 55 | 53 | for (i = 0; i < res->clks_num; i++) { |
| 56 | 54 | if (IS_V6(core)) { |
| @@ -636,7 +634,9 @@ static int decide_core(struct venus_inst *inst) · 579 unmodified lines | ||
| 636 | 634 | u32 min_coreid, min_load, cur_inst_load; |
| 637 | 635 | u32 min_lp_coreid, min_lp_load, cur_inst_lp_load; |
| 638 | 636 | struct hfi_videocores_usage_type cu; |
| 639 | − unsigned long max_freq; | |
| 637 | + unsigned long max_freq = ULONG_MAX; | |
| 638 | + struct device *dev = core->dev; | |
| 639 | + struct dev_pm_opp *opp; | |
| 640 | 640 | int ret = 0; |
| 641 | 641 | |
| 642 | 642 | if (legacy_binding) { |
| @@ -659,7 +659,8 @@ static int decide_core(struct venus_inst *inst) · 16 unmodified lines | ||
| 659 | 659 | cur_inst_lp_load *= inst->clk_data.low_power_freq; |
| 660 | 660 | /*TODO : divide this inst->load by work_route */ |
| 661 | 661 | |
| 662 | − max_freq = core->res->freq_tbl[0].freq; | |
| 662 | + opp = dev_pm_opp_find_freq_floor(dev, &max_freq); | |
| 663 | + dev_pm_opp_put(opp); | |
| 663 | 664 | |
| 664 | 665 | min_loaded_core(inst, &min_coreid, &min_load, false); |
| 665 | 666 | min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true); |
| @@ -949,7 +950,10 @@ static int core_resets_get(struct venus_core *core) · 283 unmodified lines | ||
| 949 | 950 | static int core_get_v4(struct venus_core *core) |
| 950 | 951 | { |
| 951 | 952 | struct device *dev = core->dev; |
| 953 | + const struct freq_tbl *freq_tbl = core->res->freq_tbl; | |
| 954 | + unsigned int num_rows = core->res->freq_tbl_size; | |
| 952 | 955 | const struct venus_resources *res = core->res; |
| 956 | + unsigned int i; | |
| 953 | 957 | int ret; |
| 954 | 958 | |
| 955 | 959 | ret = core_clks_get(core); |
| @@ -986,9 +990,17 @@ static int core_get_v4(struct venus_core *core) · 30 unmodified lines | ||
| 986 | 990 | |
| 987 | 991 | if (core->res->opp_pmdomain) { |
| 988 | 992 | ret = devm_pm_opp_of_add_table(dev); |
| 989 | − if (ret && ret != -ENODEV) { | |
| 990 | − dev_err(dev, "invalid OPP table in device tree\n"); | |
| 991 | − return ret; | |
| 993 | + if (ret) { | |
| 994 | + if (ret == -ENODEV) { | |
| 995 | + for (i = 0; i < num_rows; i++) { | |
| 996 | + ret = dev_pm_opp_add(dev, freq_tbl[i].freq, 0); | |
| 997 | + if (ret) | |
| 998 | + return ret; | |
| 999 | + } | |
| 1000 | + } else { | |
| 1001 | + dev_err(dev, "invalid OPP table in device tree\n"); | |
| 1002 | + return ret; | |
| 1003 | + } | |
| 992 | 1004 | } |
| 993 | 1005 | } |
| 994 | 1006 | |
| @@ -1078,11 +1090,11 @@ static unsigned long calculate_inst_freq(struct venus_inst *inst, · 83 unmodified lines | ||
| 1078 | 1090 | static int load_scale_v4(struct venus_inst *inst) |
| 1079 | 1091 | { |
| 1080 | 1092 | struct venus_core *core = inst->core; |
| 1081 | − const struct freq_tbl *table = core->res->freq_tbl; | |
| 1082 | − unsigned int num_rows = core->res->freq_tbl_size; | |
| 1083 | 1093 | struct device *dev = core->dev; |
| 1084 | 1094 | unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; |
| 1095 | + unsigned long max_freq = ULONG_MAX; | |
| 1085 | 1096 | unsigned long filled_len = 0; |
| 1097 | + struct dev_pm_opp *opp; | |
| 1086 | 1098 | int i, ret = 0; |
| 1087 | 1099 | |
| 1088 | 1100 | for (i = 0; i < inst->num_input_bufs; i++) |
| @@ -1108,20 +1120,18 @@ static int load_scale_v4(struct venus_inst *inst) · 19 unmodified lines | ||
| 1108 | 1120 | |
| 1109 | 1121 | freq = max(freq_core1, freq_core2); |
| 1110 | 1122 | |
| 1111 | − if (freq > table[0].freq) { | |
| 1112 | − dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n", | |
| 1113 | − freq, table[0].freq); | |
| 1123 | + opp = dev_pm_opp_find_freq_floor(dev, &max_freq); | |
| 1124 | + dev_pm_opp_put(opp); | |
| 1114 | 1125 | |
| 1115 | − freq = table[0].freq; | |
| 1126 | + if (freq > max_freq) { | |
| 1127 | + dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n", | |
| 1128 | + freq, max_freq); | |
| 1129 | + freq = max_freq; | |
| 1116 | 1130 | goto set_freq; |
| 1117 | 1131 | } |
| 1118 | 1132 | |
| 1119 | − for (i = num_rows - 1 ; i >= 0; i--) { | |
| 1120 | − if (freq <= table[i].freq) { | |
| 1121 | − freq = table[i].freq; | |
| 1122 | − break; | |
| 1123 | − } | |
| 1124 | − } | |
| 1133 | + opp = dev_pm_opp_find_freq_ceil(dev, &freq); | |
| 1134 | + dev_pm_opp_put(opp); | |
| 1125 | 1135 | |
| 1126 | 1136 | set_freq: |
| 1127 | 1137 | |
| @@ -481,11 +481,9 @@ static int vdec_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) · 480 unmodified lines | ||
| 481 | 481 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; |
| 482 | 482 | do_div(us_per_frame, timeperframe->denominator); |
| 483 | 483 | |
| 484 | − if (!us_per_frame) | |
| 485 | − return -EINVAL; | |
| 486 | − | |
| 487 | − fps = (u64)USEC_PER_SEC; | |
| 488 | − do_div(fps, us_per_frame); | |
| 484 | + us_per_frame = clamp(us_per_frame, 1, USEC_PER_SEC); | |
| 485 | + fps = USEC_PER_SEC / (u32)us_per_frame; | |
| 486 | + fps = min(VENUS_MAX_FPS, fps); | |
| 489 | 487 | |
| 490 | 488 | inst->fps = fps; |
| 491 | 489 | inst->timeperframe = *timeperframe; |
| @@ -411,11 +411,9 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) · 410 unmodified lines | ||
| 411 | 411 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; |
| 412 | 412 | do_div(us_per_frame, timeperframe->denominator); |
| 413 | 413 | |
| 414 | − if (!us_per_frame) | |
| 415 | − return -EINVAL; | |
| 416 | − | |
| 417 | − fps = (u64)USEC_PER_SEC; | |
| 418 | − do_div(fps, us_per_frame); | |
| 414 | + us_per_frame = clamp(us_per_frame, 1, USEC_PER_SEC); | |
| 415 | + fps = USEC_PER_SEC / (u32)us_per_frame; | |
| 416 | + fps = min(VENUS_MAX_FPS, fps); | |
| 419 | 417 | |
| 420 | 418 | inst->timeperframe = *timeperframe; |
| 421 | 419 | inst->fps = fps; |
| @@ -3,6 +3,7 @@ config VIDEO_RASPBERRYPI_PISP_BE · 2 unmodified lines | ||
| 3 | 3 | depends on V4L_PLATFORM_DRIVERS |
| 4 | 4 | depends on VIDEO_DEV |
| 5 | 5 | depends on ARCH_BCM2835 || COMPILE_TEST |
| 6 | + depends on PM | |
| 6 | 7 | select VIDEO_V4L2_SUBDEV_API |
| 7 | 8 | select MEDIA_CONTROLLER |
| 8 | 9 | select VIDEOBUF2_DMA_CONTIG |
| @@ -9,9 +9,11 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/io.h> |
| 10 | 10 | #include <linux/kernel.h> |
| 11 | 11 | #include <linux/lockdep.h> |
| 12 | +#include <linux/minmax.h> | |
| 12 | 13 | #include <linux/module.h> |
| 13 | 14 | #include <linux/platform_device.h> |
| 14 | 15 | #include <linux/pm_runtime.h> |
| 16 | +#include <linux/slab.h> | |
| 15 | 17 | #include <media/v4l2-device.h> |
| 16 | 18 | #include <media/v4l2-ioctl.h> |
| 17 | 19 | #include <media/videobuf2-dma-contig.h> |
| @@ -161,8 +163,6 @@ struct pispbe_node { · 143 unmodified lines | ||
| 161 | 163 | struct mutex node_lock; |
| 162 | 164 | /* vb2_queue lock */ |
| 163 | 165 | struct mutex queue_lock; |
| 164 | − /* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */ | |
| 165 | − spinlock_t ready_lock; | |
| 166 | 166 | struct list_head ready_queue; |
| 167 | 167 | struct vb2_queue queue; |
| 168 | 168 | struct v4l2_format format; |
| @@ -190,6 +190,8 @@ struct pispbe_hw_enables { · 21 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | /* Records a job configuration and memory addresses. */ |
| 192 | 192 | struct pispbe_job_descriptor { |
| 193 | + struct list_head queue; | |
| 194 | + struct pispbe_buffer *buffers[PISPBE_NUM_NODES]; | |
| 193 | 195 | dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; |
| 194 | 196 | struct pisp_be_tiles_config *config; |
| 195 | 197 | struct pispbe_hw_enables hw_enables; |
| @@ -215,8 +217,10 @@ struct pispbe_dev { · 19 unmodified lines | ||
| 215 | 217 | unsigned int sequence; |
| 216 | 218 | u32 streaming_map; |
| 217 | 219 | struct pispbe_job queued_job, running_job; |
| 218 | − spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */ | |
| 220 | + /* protects "hw_busy" flag, streaming_map and job_queue */ | |
| 221 | + spinlock_t hw_lock; | |
| 219 | 222 | bool hw_busy; /* non-zero if a job is queued or is being started */ |
| 223 | + struct list_head job_queue; | |
| 220 | 224 | int irq; |
| 221 | 225 | u32 hw_version; |
| 222 | 226 | u8 done, started; |
| @@ -368,10 +372,7 @@ static void pispbe_xlate_addrs(struct pispbe_dev *pispbe, · 145 unmodified lines | ||
| 368 | 372 | ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE], |
| 369 | 373 | &pispbe->node[MAIN_INPUT_NODE]); |
| 370 | 374 | if (ret <= 0) { |
| 371 | − /* | |
| 372 | − * This shouldn't happen; pispbe_schedule_internal should insist | |
| 373 | − * on an input. | |
| 374 | − */ | |
| 375 | + /* Shouldn't happen, we have validated an input is available. */ | |
| 375 | 376 | dev_warn(pispbe->dev, "ISP-BE missing input\n"); |
| 376 | 377 | hw_en->bayer_enables = 0; |
| 377 | 378 | hw_en->rgb_enables = 0; |
| @@ -443,42 +444,48 @@ static void pispbe_xlate_addrs(struct pispbe_dev *pispbe, · 65 unmodified lines | ||
| 443 | 444 | * For Output0, Output1, Tdn and Stitch, a buffer only needs to be |
| 444 | 445 | * available if the blocks are enabled in the config. |
| 445 | 446 | * |
| 446 | − * Needs to be called with hw_lock held. | |
| 447 | + * If all the buffers required to form a job are available, append the | |
| 448 | + * job descriptor to the job queue to be later queued to the HW. | |
| 447 | 449 | * |
| 448 | 450 | * Returns 0 if a job has been successfully prepared, < 0 otherwise. |
| 449 | 451 | */ |
| 450 | −static int pispbe_prepare_job(struct pispbe_dev *pispbe, | |
| 451 | − struct pispbe_job_descriptor *job) | |
| 452 | +static int pispbe_prepare_job(struct pispbe_dev *pispbe) | |
| 452 | 453 | { |
| 454 | + struct pispbe_job_descriptor __free(kfree) *job = NULL; | |
| 453 | 455 | struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {}; |
| 456 | + unsigned int streaming_map; | |
| 454 | 457 | unsigned int config_index; |
| 455 | 458 | struct pispbe_node *node; |
| 456 | − unsigned long flags; | |
| 457 | 459 | |
| 458 | − lockdep_assert_held(&pispbe->hw_lock); | |
| 460 | + lockdep_assert_irqs_enabled(); | |
| 459 | 461 | |
| 460 | − memset(job, 0, sizeof(struct pispbe_job_descriptor)); | |
| 462 | + scoped_guard(spinlock_irq, &pispbe->hw_lock) { | |
| 463 | + static const u32 mask = BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE); | |
| 461 | 464 | |
| 462 | − if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) & | |
| 463 | − pispbe->streaming_map) != | |
| 464 | − (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) | |
| 465 | − return -ENODEV; | |
| 465 | + if ((pispbe->streaming_map & mask) != mask) | |
| 466 | + return -ENODEV; | |
| 467 | + | |
| 468 | + /* | |
| 469 | + * Take a copy of streaming_map: nodes activated after this | |
| 470 | + * point are ignored when preparing this job. | |
| 471 | + */ | |
| 472 | + streaming_map = pispbe->streaming_map; | |
| 473 | + } | |
| 474 | + | |
| 475 | + job = kzalloc(sizeof(*job), GFP_KERNEL); | |
| 476 | + if (!job) | |
| 477 | + return -ENOMEM; | |
| 466 | 478 | |
| 467 | 479 | node = &pispbe->node[CONFIG_NODE]; |
| 468 | − spin_lock_irqsave(&node->ready_lock, flags); | |
| 469 | 480 | buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue, |
| 470 | 481 | struct pispbe_buffer, |
| 471 | 482 | ready_list); |
| 472 | − if (buf[CONFIG_NODE]) { | |
| 473 | − list_del(&buf[CONFIG_NODE]->ready_list); | |
| 474 | − pispbe->queued_job.buf[CONFIG_NODE] = buf[CONFIG_NODE]; | |
| 475 | − } | |
| 476 | − spin_unlock_irqrestore(&node->ready_lock, flags); | |
| 477 | − | |
| 478 | − /* Exit early if no config buffer has been queued. */ | |
| 479 | 483 | if (!buf[CONFIG_NODE]) |
| 480 | 484 | return -ENODEV; |
| 481 | 485 | |
| 486 | + list_del(&buf[CONFIG_NODE]->ready_list); | |
| 487 | + job->buffers[CONFIG_NODE] = buf[CONFIG_NODE]; | |
| 488 | + | |
| 482 | 489 | config_index = buf[CONFIG_NODE]->vb.vb2_buf.index; |
| 483 | 490 | job->config = &pispbe->config[config_index]; |
| 484 | 491 | job->tiles = pispbe->config_dma_addr + |
| @@ -498,7 +505,7 @@ static int pispbe_prepare_job(struct pispbe_dev *pispbe, · 13 unmodified lines | ||
| 498 | 505 | continue; |
| 499 | 506 | |
| 500 | 507 | buf[i] = NULL; |
| 501 | − if (!(pispbe->streaming_map & BIT(i))) | |
| 508 | + if (!(streaming_map & BIT(i))) | |
| 502 | 509 | continue; |
| 503 | 510 | |
| 504 | 511 | if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) && |
| @@ -525,25 +532,28 @@ static int pispbe_prepare_job(struct pispbe_dev *pispbe, · 20 unmodified lines | ||
| 525 | 532 | node = &pispbe->node[i]; |
| 526 | 533 | |
| 527 | 534 | /* Pull a buffer from each V4L2 queue to form the queued job */ |
| 528 | − spin_lock_irqsave(&node->ready_lock, flags); | |
| 529 | 535 | buf[i] = list_first_entry_or_null(&node->ready_queue, |
| 530 | 536 | struct pispbe_buffer, |
| 531 | 537 | ready_list); |
| 532 | 538 | if (buf[i]) { |
| 533 | 539 | list_del(&buf[i]->ready_list); |
| 534 | − pispbe->queued_job.buf[i] = buf[i]; | |
| 540 | + job->buffers[i] = buf[i]; | |
| 535 | 541 | } |
| 536 | − spin_unlock_irqrestore(&node->ready_lock, flags); | |
| 537 | 542 | |
| 538 | 543 | if (!buf[i] && !ignore_buffers) |
| 539 | 544 | goto err_return_buffers; |
| 540 | 545 | } |
| 541 | 546 | |
| 542 | − pispbe->queued_job.valid = true; | |
| 543 | − | |
| 544 | 547 | /* Convert buffers to DMA addresses for the hardware */ |
| 545 | 548 | pispbe_xlate_addrs(pispbe, job, buf); |
| 546 | 549 | |
| 550 | + scoped_guard(spinlock_irq, &pispbe->hw_lock) { | |
| 551 | + list_add_tail(&job->queue, &pispbe->job_queue); | |
| 552 | + } | |
| 553 | + | |
| 554 | + /* Set job to NULL to avoid automatic release due to __free(). */ | |
| 555 | + job = NULL; | |
| 556 | + | |
| 547 | 557 | return 0; |
| 548 | 558 | |
| 549 | 559 | err_return_buffers: |
| @@ -554,33 +564,37 @@ err_return_buffers: · 4 unmodified lines | ||
| 554 | 564 | continue; |
| 555 | 565 | |
| 556 | 566 | /* Return the buffer to the ready_list queue */ |
| 557 | − spin_lock_irqsave(&n->ready_lock, flags); | |
| 558 | 567 | list_add(&buf[i]->ready_list, &n->ready_queue); |
| 559 | − spin_unlock_irqrestore(&n->ready_lock, flags); | |
| 560 | 568 | } |
| 561 | 569 | |
| 562 | − memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job)); | |
| 563 | − | |
| 564 | 570 | return -ENODEV; |
| 565 | 571 | } |
| 566 | 572 | |
| 567 | 573 | static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy) |
| 568 | 574 | { |
| 569 | − struct pispbe_job_descriptor job; | |
| 570 | − unsigned long flags; | |
| 571 | − int ret; | |
| 575 | + struct pispbe_job_descriptor *job; | |
| 572 | 576 | |
| 573 | − spin_lock_irqsave(&pispbe->hw_lock, flags); | |
| 577 | + scoped_guard(spinlock_irqsave, &pispbe->hw_lock) { | |
| 578 | + if (clear_hw_busy) | |
| 579 | + pispbe->hw_busy = false; | |
| 574 | 580 | |
| 575 | − if (clear_hw_busy) | |
| 576 | − pispbe->hw_busy = false; | |
| 581 | + if (pispbe->hw_busy) | |
| 582 | + return; | |
| 577 | 583 | |
| 578 | − if (pispbe->hw_busy) | |
| 579 | − goto unlock_and_return; | |
| 584 | + job = list_first_entry_or_null(&pispbe->job_queue, | |
| 585 | + struct pispbe_job_descriptor, | |
| 586 | + queue); | |
| 587 | + if (!job) | |
| 588 | + return; | |
| 580 | 589 | |
| 581 | − ret = pispbe_prepare_job(pispbe, &job); | |
| 582 | − if (ret) | |
| 583 | − goto unlock_and_return; | |
| 590 | + list_del(&job->queue); | |
| 591 | + | |
| 592 | + for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) | |
| 593 | + pispbe->queued_job.buf[i] = job->buffers[i]; | |
| 594 | + pispbe->queued_job.valid = true; | |
| 595 | + | |
| 596 | + pispbe->hw_busy = true; | |
| 597 | + } | |
| 584 | 598 | |
| 585 | 599 | /* |
| 586 | 600 | * We can kick the job off without the hw_lock, as this can |
| @@ -588,34 +602,8 @@ static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy) · 1 unmodified line | ||
| 588 | 602 | * only when the following job has been queued and an interrupt |
| 589 | 603 | * is rised. |
| 590 | 604 | */ |
| 591 | − pispbe->hw_busy = true; | |
| 592 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 593 | − | |
| 594 | − if (job.config->num_tiles <= 0 || | |
| 595 | − job.config->num_tiles > PISP_BACK_END_NUM_TILES || | |
| 596 | − !((job.hw_enables.bayer_enables | job.hw_enables.rgb_enables) & | |
| 597 | − PISP_BE_BAYER_ENABLE_INPUT)) { | |
| 598 | − /* | |
| 599 | − * Bad job. We can't let it proceed as it could lock up | |
| 600 | − * the hardware, or worse! | |
| 601 | − * | |
| 602 | − * For now, just force num_tiles to 0, which causes the | |
| 603 | − * H/W to do something bizarre but survivable. It | |
| 604 | − * increments (started,done) counters by more than 1, | |
| 605 | − * but we seem to survive... | |
| 606 | − */ | |
| 607 | − dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n", | |
| 608 | − job.config->num_tiles); | |
| 609 | − job.config->num_tiles = 0; | |
| 610 | − } | |
| 611 | − | |
| 612 | − pispbe_queue_job(pispbe, &job); | |
| 613 | − | |
| 614 | − return; | |
| 615 | − | |
| 616 | −unlock_and_return: | |
| 617 | − /* No job has been queued, just release the lock and return. */ | |
| 618 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 605 | + pispbe_queue_job(pispbe, job); | |
| 606 | + kfree(job); | |
| 619 | 607 | } |
| 620 | 608 | |
| 621 | 609 | static void pispbe_isr_jobdone(struct pispbe_dev *pispbe, |
| @@ -706,6 +694,13 @@ static int pisp_be_validate_config(struct pispbe_dev *pispbe, · 84 unmodified lines | ||
| 706 | 694 | return -EIO; |
| 707 | 695 | } |
| 708 | 696 | |
| 697 | + if (config->num_tiles == 0 || | |
| 698 | + config->num_tiles > PISP_BACK_END_NUM_TILES) { | |
| 699 | + dev_dbg(dev, "%s: Invalid number of tiles: %d\n", __func__, | |
| 700 | + config->num_tiles); | |
| 701 | + return -EINVAL; | |
| 702 | + } | |
| 703 | + | |
| 709 | 704 | /* Ensure output config strides and buffer sizes match the V4L2 formats. */ |
| 710 | 705 | fmt = &pispbe->node[TDN_OUTPUT_NODE].format; |
| 711 | 706 | if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) { |
| @@ -860,18 +855,16 @@ static void pispbe_node_buffer_queue(struct vb2_buffer *buf) · 148 unmodified lines | ||
| 860 | 855 | container_of(vbuf, struct pispbe_buffer, vb); |
| 861 | 856 | struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue); |
| 862 | 857 | struct pispbe_dev *pispbe = node->pispbe; |
| 863 | − unsigned long flags; | |
| 864 | 858 | |
| 865 | 859 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); |
| 866 | − spin_lock_irqsave(&node->ready_lock, flags); | |
| 867 | 860 | list_add_tail(&buffer->ready_list, &node->ready_queue); |
| 868 | − spin_unlock_irqrestore(&node->ready_lock, flags); | |
| 869 | 861 | |
| 870 | 862 | /* |
| 871 | 863 | * Every time we add a buffer, check if there's now some work for the hw |
| 872 | 864 | * to do. |
| 873 | 865 | */ |
| 874 | − pispbe_schedule(pispbe, false); | |
| 866 | + if (!pispbe_prepare_job(pispbe)) | |
| 867 | + pispbe_schedule(pispbe, false); | |
| 875 | 868 | } |
| 876 | 869 | |
| 877 | 870 | static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) |
| @@ -879,17 +872,16 @@ static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) · 1 unmodified line | ||
| 879 | 872 | struct pispbe_node *node = vb2_get_drv_priv(q); |
| 880 | 873 | struct pispbe_dev *pispbe = node->pispbe; |
| 881 | 874 | struct pispbe_buffer *buf, *tmp; |
| 882 | − unsigned long flags; | |
| 883 | 875 | int ret; |
| 884 | 876 | |
| 885 | 877 | ret = pm_runtime_resume_and_get(pispbe->dev); |
| 886 | 878 | if (ret < 0) |
| 887 | 879 | goto err_return_buffers; |
| 888 | 880 | |
| 889 | − spin_lock_irqsave(&pispbe->hw_lock, flags); | |
| 890 | − node->pispbe->streaming_map |= BIT(node->id); | |
| 891 | − node->pispbe->sequence = 0; | |
| 892 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 881 | + scoped_guard(spinlock_irq, &pispbe->hw_lock) { | |
| 882 | + node->pispbe->streaming_map |= BIT(node->id); | |
| 883 | + node->pispbe->sequence = 0; | |
| 884 | + } | |
| 893 | 885 | |
| 894 | 886 | dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n", |
| 895 | 887 | __func__, NODE_NAME(node), count); |
| @@ -897,17 +889,16 @@ static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) · 1 unmodified line | ||
| 897 | 889 | node->pispbe->streaming_map); |
| 898 | 890 | |
| 899 | 891 | /* Maybe we're ready to run. */ |
| 900 | − pispbe_schedule(pispbe, false); | |
| 892 | + if (!pispbe_prepare_job(pispbe)) | |
| 893 | + pispbe_schedule(pispbe, false); | |
| 901 | 894 | |
| 902 | 895 | return 0; |
| 903 | 896 | |
| 904 | 897 | err_return_buffers: |
| 905 | − spin_lock_irqsave(&pispbe->hw_lock, flags); | |
| 906 | 898 | list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) { |
| 907 | 899 | list_del(&buf->ready_list); |
| 908 | 900 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); |
| 909 | 901 | } |
| 910 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 911 | 902 | |
| 912 | 903 | return ret; |
| 913 | 904 | } |
| @@ -916,8 +907,9 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) · 2 unmodified lines | ||
| 916 | 907 | { |
| 917 | 908 | struct pispbe_node *node = vb2_get_drv_priv(q); |
| 918 | 909 | struct pispbe_dev *pispbe = node->pispbe; |
| 910 | + struct pispbe_job_descriptor *job, *temp; | |
| 919 | 911 | struct pispbe_buffer *buf; |
| 920 | − unsigned long flags; | |
| 912 | + LIST_HEAD(tmp_list); | |
| 921 | 913 | |
| 922 | 914 | /* |
| 923 | 915 | * Now this is a bit awkward. In a simple M2M device we could just wait |
| @@ -929,11 +921,7 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) · 5 unmodified lines | ||
| 929 | 921 | * This may return buffers out of order. |
| 930 | 922 | */ |
| 931 | 923 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); |
| 932 | − spin_lock_irqsave(&pispbe->hw_lock, flags); | |
| 933 | 924 | do { |
| 934 | − unsigned long flags1; | |
| 935 | − | |
| 936 | − spin_lock_irqsave(&node->ready_lock, flags1); | |
| 937 | 925 | buf = list_first_entry_or_null(&node->ready_queue, |
| 938 | 926 | struct pispbe_buffer, |
| 939 | 927 | ready_list); |
| @@ -941,15 +929,26 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) · 1 unmodified line | ||
| 941 | 929 | list_del(&buf->ready_list); |
| 942 | 930 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); |
| 943 | 931 | } |
| 944 | − spin_unlock_irqrestore(&node->ready_lock, flags1); | |
| 945 | 932 | } while (buf); |
| 946 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 947 | 933 | |
| 948 | 934 | vb2_wait_for_all_buffers(&node->queue); |
| 949 | 935 | |
| 950 | − spin_lock_irqsave(&pispbe->hw_lock, flags); | |
| 936 | + spin_lock_irq(&pispbe->hw_lock); | |
| 951 | 937 | pispbe->streaming_map &= ~BIT(node->id); |
| 952 | − spin_unlock_irqrestore(&pispbe->hw_lock, flags); | |
| 938 | + | |
| 939 | + if (pispbe->streaming_map == 0) { | |
| 940 | + /* | |
| 941 | + * If all nodes have stopped streaming release all jobs | |
| 942 | + * without holding the lock. | |
| 943 | + */ | |
| 944 | + list_splice_init(&pispbe->job_queue, &tmp_list); | |
| 945 | + } | |
| 946 | + spin_unlock_irq(&pispbe->hw_lock); | |
| 947 | + | |
| 948 | + list_for_each_entry_safe(job, temp, &tmp_list, queue) { | |
| 949 | + list_del(&job->queue); | |
| 950 | + kfree(job); | |
| 951 | + } | |
| 953 | 952 | |
| 954 | 953 | pm_runtime_mark_last_busy(pispbe->dev); |
| 955 | 954 | pm_runtime_put_autosuspend(pispbe->dev); |
| @@ -1114,10 +1113,12 @@ static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node) · 158 unmodified lines | ||
| 1114 | 1113 | f->fmt.pix_mp.pixelformat = fmt->fourcc; |
| 1115 | 1114 | f->fmt.pix_mp.num_planes = fmt->num_planes; |
| 1116 | 1115 | f->fmt.pix_mp.field = V4L2_FIELD_NONE; |
| 1117 | − f->fmt.pix_mp.width = max(min(f->fmt.pix_mp.width, 65536u), | |
| 1118 | − PISP_BACK_END_MIN_TILE_WIDTH); | |
| 1119 | − f->fmt.pix_mp.height = max(min(f->fmt.pix_mp.height, 65536u), | |
| 1120 | − PISP_BACK_END_MIN_TILE_HEIGHT); | |
| 1116 | + f->fmt.pix_mp.width = clamp(f->fmt.pix_mp.width, | |
| 1117 | + PISP_BACK_END_MIN_TILE_WIDTH, | |
| 1118 | + PISP_BACK_END_MAX_TILE_WIDTH); | |
| 1119 | + f->fmt.pix_mp.height = clamp(f->fmt.pix_mp.height, | |
| 1120 | + PISP_BACK_END_MIN_TILE_HEIGHT, | |
| 1121 | + PISP_BACK_END_MAX_TILE_HEIGHT); | |
| 1121 | 1122 | |
| 1122 | 1123 | /* |
| 1123 | 1124 | * Fill in the actual colour space when the requested one was |
| @@ -1407,7 +1408,6 @@ static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id) · 283 unmodified lines | ||
| 1407 | 1408 | mutex_init(&node->node_lock); |
| 1408 | 1409 | mutex_init(&node->queue_lock); |
| 1409 | 1410 | INIT_LIST_HEAD(&node->ready_queue); |
| 1410 | − spin_lock_init(&node->ready_lock); | |
| 1411 | 1411 | |
| 1412 | 1412 | node->format.type = node->buf_type; |
| 1413 | 1413 | pispbe_node_def_fmt(node); |
| @@ -1691,6 +1691,8 @@ static int pispbe_probe(struct platform_device *pdev) · 277 unmodified lines | ||
| 1691 | 1691 | if (!pispbe) |
| 1692 | 1692 | return -ENOMEM; |
| 1693 | 1693 | |
| 1694 | + INIT_LIST_HEAD(&pispbe->job_queue); | |
| 1695 | + | |
| 1694 | 1696 | dev_set_drvdata(&pdev->dev, pispbe); |
| 1695 | 1697 | pispbe->dev = &pdev->dev; |
| 1696 | 1698 | platform_set_drvdata(pdev, pispbe); |
| @@ -1726,7 +1728,7 @@ static int pispbe_probe(struct platform_device *pdev) · 29 unmodified lines | ||
| 1726 | 1728 | pm_runtime_use_autosuspend(pispbe->dev); |
| 1727 | 1729 | pm_runtime_enable(pispbe->dev); |
| 1728 | 1730 | |
| 1729 | − ret = pispbe_runtime_resume(pispbe->dev); | |
| 1731 | + ret = pm_runtime_resume_and_get(pispbe->dev); | |
| 1730 | 1732 | if (ret) |
| 1731 | 1733 | goto pm_runtime_disable_err; |
| 1732 | 1734 | |
| @@ -1748,7 +1750,7 @@ static int pispbe_probe(struct platform_device *pdev) · 15 unmodified lines | ||
| 1748 | 1750 | disable_devs_err: |
| 1749 | 1751 | pispbe_destroy_devices(pispbe); |
| 1750 | 1752 | pm_runtime_suspend_err: |
| 1751 | − pispbe_runtime_suspend(pispbe->dev); | |
| 1753 | + pm_runtime_put(pispbe->dev); | |
| 1752 | 1754 | pm_runtime_disable_err: |
| 1753 | 1755 | pm_runtime_dont_use_autosuspend(pispbe->dev); |
| 1754 | 1756 | pm_runtime_disable(pispbe->dev); |
| @@ -1762,7 +1764,6 @@ static void pispbe_remove(struct platform_device *pdev) · 7 unmodified lines | ||
| 1762 | 1764 | |
| 1763 | 1765 | pispbe_destroy_devices(pispbe); |
| 1764 | 1766 | |
| 1765 | − pispbe_runtime_suspend(pispbe->dev); | |
| 1766 | 1767 | pm_runtime_dont_use_autosuspend(pispbe->dev); |
| 1767 | 1768 | pm_runtime_disable(pispbe->dev); |
| 1768 | 1769 | } |
| @@ -1024,9 +1024,6 @@ static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, · 1023 unmodified lines | ||
| 1024 | 1024 | cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, |
| 1025 | 1025 | node->buffer_queue.type); |
| 1026 | 1026 | |
| 1027 | − if (vq->max_num_buffers + *nbuffers < 3) | |
| 1028 | − *nbuffers = 3 - vq->max_num_buffers; | |
| 1029 | − | |
| 1030 | 1027 | if (*nplanes) { |
| 1031 | 1028 | if (sizes[0] < size) { |
| 1032 | 1029 | cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size); |
| @@ -1998,6 +1995,7 @@ static int cfe_register_node(struct cfe_device *cfe, int id) · 965 unmodified lines | ||
| 1998 | 1995 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1999 | 1996 | q->lock = &node->lock; |
| 2000 | 1997 | q->min_queued_buffers = 1; |
| 1998 | + q->min_reqbufs_allocation = 3; | |
| 2001 | 1999 | q->dev = &cfe->pdev->dev; |
| 2002 | 2000 | |
| 2003 | 2001 | ret = vb2_queue_init(q); |
| @@ -172,20 +172,27 @@ struct rcar_csi2; · 171 unmodified lines | ||
| 172 | 172 | #define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a |
| 173 | 173 | #define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c |
| 174 | 174 | #define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG 0x21c10 |
| 175 | +#define V4H_PPI_RW_DDLCAL_CFG_n_REG(n) (0x21c40 + ((n) * 2)) /* n = 0 - 7 */ | |
| 175 | 176 | #define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c |
| 176 | 177 | #define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 |
| 177 | 178 | #define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 |
| 178 | 179 | |
| 179 | 180 | /* V4H CORE registers */ |
| 180 | −#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n) (0x22040 + ((n) * 2)) /* n = 0 - 15 */ | |
| 181 | −#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(n) (0x22440 + ((n) * 2)) /* n = 0 - 15 */ | |
| 182 | −#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(n) (0x22840 + ((n) * 2)) /* n = 0 - 15 */ | |
| 183 | −#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(n) (0x22c40 + ((n) * 2)) /* n = 0 - 15 */ | |
| 184 | −#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n) (0x23040 + ((n) * 2)) /* n = 0 - 15 */ | |
| 181 | + | |
| 182 | +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, n) (0x22040 + ((l) * 0x400) + ((n) * 2)) | |
| 183 | +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_3_REG(l, n) (0x22060 + ((l) * 0x400) + ((n) * 2)) | |
| 184 | +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_4_REG(l, n) (0x22080 + ((l) * 0x400) + ((n) * 2)) | |
| 185 | + | |
| 185 | 186 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ |
| 186 | 187 | #define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ |
| 187 | 188 | #define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */ |
| 188 | −#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c | |
| 189 | +#define V4H_CORE_DIG_COMMON_RW_DESKEW_FINE_MEM_REG 0x23fe0 | |
| 190 | + | |
| 191 | +#define V4H_CORE_DIG_DLANE_l_RW_CFG_n_REG(l, n) (0x26000 + ((l) * 0x400) + ((n) * 2)) | |
| 192 | +#define V4H_CORE_DIG_DLANE_l_RW_LP_n_REG(l, n) (0x26080 + ((l) * 0x400) + ((n) * 2)) | |
| 193 | +#define V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, n) (0x26100 + ((l) * 0x400) + ((n) * 2)) | |
| 194 | +#define V4H_CORE_DIG_DLANE_CLK_RW_LP_n_REG(n) V4H_CORE_DIG_DLANE_l_RW_LP_n_REG(4, (n)) | |
| 195 | +#define V4H_CORE_DIG_DLANE_CLK_RW_HS_RX_n_REG(n) V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(4, (n)) | |
| 189 | 196 | |
| 190 | 197 | /* V4H C-PHY */ |
| 191 | 198 | #define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */ |
| @@ -197,6 +204,7 @@ struct rcar_csi2; · 5 unmodified lines | ||
| 197 | 204 | #define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 |
| 198 | 205 | #define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 |
| 199 | 206 | #define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */ |
| 207 | +#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c | |
| 200 | 208 | #define V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG 0x2a800 |
| 201 | 209 | #define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 |
| 202 | 210 | #define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */ |
| @@ -954,6 +962,7 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) · 751 unmodified lines | ||
| 954 | 962 | static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, |
| 955 | 963 | unsigned int lanes) |
| 956 | 964 | { |
| 965 | + struct media_pad *remote_pad; | |
| 957 | 966 | struct v4l2_subdev *source; |
| 958 | 967 | s64 freq; |
| 959 | 968 | u64 mbps; |
| @@ -962,8 +971,9 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, · 2 unmodified lines | ||
| 962 | 971 | return -ENODEV; |
| 963 | 972 | |
| 964 | 973 | source = priv->remote; |
| 974 | + remote_pad = &source->entity.pads[priv->remote_pad]; | |
| 965 | 975 | |
| 966 | − freq = v4l2_get_link_freq(source->ctrl_handler, bpp, 2 * lanes); | |
| 976 | + freq = v4l2_get_link_freq(remote_pad, bpp, 2 * lanes); | |
| 967 | 977 | if (freq < 0) { |
| 968 | 978 | int ret = (int)freq; |
| 969 | 979 | |
| @@ -975,10 +985,6 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, · 5 unmodified lines | ||
| 975 | 985 | |
| 976 | 986 | mbps = div_u64(freq * 2, MEGA); |
| 977 | 987 | |
| 978 | − /* Adjust for C-PHY, divide by 2.8. */ | |
| 979 | − if (priv->cphy) | |
| 980 | − mbps = div_u64(mbps * 5, 14); | |
| 981 | − | |
| 982 | 988 | return mbps; |
| 983 | 989 | } |
| 984 | 990 | |
| @@ -1203,9 +1209,14 @@ static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match) · 218 unmodified lines | ||
| 1203 | 1209 | return -ETIMEDOUT; |
| 1204 | 1210 | } |
| 1205 | 1211 | |
| 1206 | −static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) | |
| 1212 | +static const struct rcsi2_cphy_setting * | |
| 1213 | +rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int mbps) | |
| 1207 | 1214 | { |
| 1208 | 1215 | const struct rcsi2_cphy_setting *conf; |
| 1216 | + int msps; | |
| 1217 | + | |
| 1218 | + /* Adjust for C-PHY symbols, divide by 2.8. */ | |
| 1219 | + msps = div_u64(mbps * 5, 14); | |
| 1209 | 1220 | |
| 1210 | 1221 | for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { |
| 1211 | 1222 | if (conf->msps > msps) |
| @@ -1214,7 +1225,7 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) · 2 unmodified lines | ||
| 1214 | 1225 | |
| 1215 | 1226 | if (!conf->msps) { |
| 1216 | 1227 | dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps); |
| 1217 | − return -ERANGE; | |
| 1228 | + return NULL; | |
| 1218 | 1229 | } |
| 1219 | 1230 | |
| 1220 | 1231 | /* C-PHY specific */ |
| @@ -1246,11 +1257,11 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) · 25 unmodified lines | ||
| 1246 | 1257 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2); |
| 1247 | 1258 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2); |
| 1248 | 1259 | |
| 1249 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), 0x0001); | |
| 1250 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0); | |
| 1251 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001); | |
| 1252 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001); | |
| 1253 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0); | |
| 1260 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(0, 2), 0x0001); | |
| 1261 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(1, 2), 0); | |
| 1262 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(2, 2), 0x0001); | |
| 1263 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(3, 2), 0x0001); | |
| 1264 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(4, 2), 0); | |
| 1254 | 1265 | |
| 1255 | 1266 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0); |
| 1256 | 1267 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0); |
| @@ -1267,30 +1278,198 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) · 10 unmodified lines | ||
| 1267 | 1278 | /* Configure data line order. */ |
| 1268 | 1279 | rsci2_set_line_order(priv, priv->line_orders[0], |
| 1269 | 1280 | V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG, |
| 1270 | − V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9)); | |
| 1281 | + V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(0, 9)); | |
| 1271 | 1282 | rsci2_set_line_order(priv, priv->line_orders[1], |
| 1272 | 1283 | V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, |
| 1273 | − V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(9)); | |
| 1284 | + V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(1, 9)); | |
| 1274 | 1285 | rsci2_set_line_order(priv, priv->line_orders[2], |
| 1275 | 1286 | V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG, |
| 1276 | − V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(9)); | |
| 1287 | + V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(2, 9)); | |
| 1277 | 1288 | |
| 1278 | 1289 | /* TODO: This registers is not documented. */ |
| 1279 | 1290 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000); |
| 1280 | 1291 | |
| 1281 | − /* Leave Shutdown mode */ | |
| 1282 | − rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); | |
| 1283 | − rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); | |
| 1292 | + return conf; | |
| 1293 | +} | |
| 1284 | 1294 | |
| 1285 | − /* Wait for calibration */ | |
| 1286 | − if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { | |
| 1287 | − dev_err(priv->dev, "PHY calibration failed\n"); | |
| 1288 | − return -ETIMEDOUT; | |
| 1295 | +struct rcsi2_d_phy_setting_v4h_lut_value { | |
| 1296 | + unsigned int mbps; | |
| 1297 | + unsigned char cfg_1; | |
| 1298 | + unsigned char cfg_5_94; | |
| 1299 | + unsigned char cfg_5_30; | |
| 1300 | + unsigned char lane_ctrl_2_8; | |
| 1301 | + unsigned char rw_hs_rx_3_83; | |
| 1302 | + unsigned char rw_hs_rx_3_20; | |
| 1303 | + unsigned char rw_hs_rx_6; | |
| 1304 | + unsigned char rw_hs_rx_1; | |
| 1305 | +}; | |
| 1306 | + | |
| 1307 | +static const struct rcsi2_d_phy_setting_v4h_lut_value * | |
| 1308 | +rcsi2_d_phy_setting_v4h_lut_lookup(int mbps) | |
| 1309 | +{ | |
| 1310 | + static const struct rcsi2_d_phy_setting_v4h_lut_value values[] = { | |
| 1311 | + { 4500, 0x3f, 0x07, 0x00, 0x01, 0x02, 0x01, 0x0d, 0x10 }, | |
| 1312 | + { 4000, 0x47, 0x08, 0x01, 0x01, 0x05, 0x01, 0x0f, 0x0d }, | |
| 1313 | + { 3600, 0x4f, 0x09, 0x01, 0x01, 0x06, 0x01, 0x10, 0x0b }, | |
| 1314 | + { 3230, 0x57, 0x0a, 0x01, 0x01, 0x06, 0x01, 0x12, 0x09 }, | |
| 1315 | + { 3000, 0x47, 0x08, 0x00, 0x00, 0x03, 0x01, 0x0f, 0x0c }, | |
| 1316 | + { 2700, 0x4f, 0x09, 0x01, 0x00, 0x06, 0x01, 0x10, 0x0b }, | |
| 1317 | + { 2455, 0x57, 0x0a, 0x01, 0x00, 0x06, 0x01, 0x12, 0x09 }, | |
| 1318 | + { 2250, 0x5f, 0x0b, 0x01, 0x00, 0x08, 0x01, 0x13, 0x08 }, | |
| 1319 | + { 2077, 0x67, 0x0c, 0x01, 0x00, 0x06, 0x02, 0x15, 0x0d }, | |
| 1320 | + { 1929, 0x6f, 0x0d, 0x02, 0x00, 0x06, 0x02, 0x17, 0x0d }, | |
| 1321 | + { 1800, 0x77, 0x0e, 0x02, 0x00, 0x06, 0x02, 0x18, 0x0d }, | |
| 1322 | + { 1688, 0x7f, 0x0f, 0x02, 0x00, 0x08, 0x02, 0x1a, 0x0d }, | |
| 1323 | + { 1588, 0x87, 0x10, 0x02, 0x00, 0x08, 0x02, 0x1b, 0x0d }, | |
| 1324 | + { 1500, 0x8f, 0x11, 0x03, 0x00, 0x08, 0x02, 0x1d, 0x0c }, | |
| 1325 | + }; | |
| 1326 | + | |
| 1327 | + for (unsigned int i = 0; i < ARRAY_SIZE(values); i++) | |
| 1328 | + if (mbps >= values[i].mbps) | |
| 1329 | + return &values[i]; | |
| 1330 | + | |
| 1331 | + return NULL; | |
| 1332 | +} | |
| 1333 | + | |
| 1334 | +static int rcsi2_d_phy_setting_v4h(struct rcar_csi2 *priv, int mbps) | |
| 1335 | +{ | |
| 1336 | + const struct rcsi2_d_phy_setting_v4h_lut_value *lut = | |
| 1337 | + rcsi2_d_phy_setting_v4h_lut_lookup(mbps); | |
| 1338 | + u16 val; | |
| 1339 | + | |
| 1340 | + rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), 0x0000); | |
| 1341 | + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), mbps > 1500 ? 0x0028 : 0x0068); | |
| 1342 | + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), 0x0050); | |
| 1343 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(0), 0x0063); | |
| 1344 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(7), 0x1132); | |
| 1345 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(1), 0x1340); | |
| 1346 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(2), 0x4b13); | |
| 1347 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(4), 0x000a); | |
| 1348 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(6), 0x800a); | |
| 1349 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(7), 0x1109); | |
| 1350 | + | |
| 1351 | + if (mbps > 1500) { | |
| 1352 | + val = DIV_ROUND_UP(5 * mbps, 64); | |
| 1353 | + rcsi2_write16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(3), val); | |
| 1354 | + } | |
| 1355 | + | |
| 1356 | + if (lut) { | |
| 1357 | + rcsi2_modify16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(1), | |
| 1358 | + lut->cfg_1, 0x00ff); | |
| 1359 | + rcsi2_modify16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(5), | |
| 1360 | + lut->cfg_5_94 << 4, 0x03f0); | |
| 1361 | + rcsi2_modify16(priv, V4H_PPI_RW_DDLCAL_CFG_n_REG(5), | |
| 1362 | + lut->cfg_5_30 << 0, 0x000f); | |
| 1363 | + | |
| 1364 | + for (unsigned int l = 0; l < 5; l++) | |
| 1365 | + rcsi2_modify16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 8), | |
| 1366 | + lut->lane_ctrl_2_8 << 12, 0x1000); | |
| 1367 | + } | |
| 1368 | + | |
| 1369 | + for (unsigned int l = 0; l < 4; l++) | |
| 1370 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_LP_n_REG(l, 0), 0x463c); | |
| 1371 | + | |
| 1372 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(0, 2), 0x0000); | |
| 1373 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(1, 2), 0x0000); | |
| 1374 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(2, 2), 0x0001); | |
| 1375 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(3, 2), 0x0000); | |
| 1376 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(4, 2), 0x0000); | |
| 1377 | + | |
| 1378 | + rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(6), 0x0009); | |
| 1379 | + | |
| 1380 | + val = mbps > 1500 ? 0x0800 : 0x0802; | |
| 1381 | + for (unsigned int l = 0; l < 5; l++) | |
| 1382 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 12), val); | |
| 1383 | + | |
| 1384 | + val = mbps > 1500 ? 0x0000 : 0x0002; | |
| 1385 | + for (unsigned int l = 0; l < 5; l++) | |
| 1386 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 13), val); | |
| 1387 | + | |
| 1388 | + if (mbps >= 80) { | |
| 1389 | + /* 2560: 6, 1280: 5, 640: 4, 320: 3, 160: 2, 80: 1 */ | |
| 1390 | + val = ilog2(mbps / 80) + 1; | |
| 1391 | + rcsi2_modify16(priv, | |
| 1392 | + V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(2, 9), | |
| 1393 | + val << 5, 0xe0); | |
| 1394 | + } | |
| 1395 | + | |
| 1396 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_CLK_RW_HS_RX_n_REG(0), 0x091c); | |
| 1397 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_CLK_RW_HS_RX_n_REG(7), 0x3b06); | |
| 1398 | + | |
| 1399 | + val = DIV_ROUND_UP(1200, mbps) + 12; | |
| 1400 | + for (unsigned int l = 0; l < 4; l++) | |
| 1401 | + rcsi2_modify16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 0), val << 8, 0xf0); | |
| 1402 | + | |
| 1403 | + val = mbps > 1500 ? 0x0004 : 0x0008; | |
| 1404 | + for (unsigned int l = 0; l < 4; l++) | |
| 1405 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_CFG_n_REG(l, 1), val); | |
| 1406 | + | |
| 1407 | + val = mbps > 2500 ? 0x669a : mbps > 1500 ? 0xe69a : 0xe69b; | |
| 1408 | + for (unsigned int l = 0; l < 4; l++) | |
| 1409 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 2), val); | |
| 1410 | + | |
| 1411 | + for (unsigned int l = 0; l < 4; l++) | |
| 1412 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_LP_n_REG(l, 0), 0x163c); | |
| 1413 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_CLK_RW_LP_n_REG(0), 0x163c); | |
| 1414 | + | |
| 1415 | + if (lut) { | |
| 1416 | + for (unsigned int l = 0; l < 4; l++) | |
| 1417 | + rcsi2_modify16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 1), | |
| 1418 | + lut->rw_hs_rx_1, 0xff); | |
| 1419 | + } | |
| 1420 | + | |
| 1421 | + for (unsigned int l = 0; l < 4; l++) | |
| 1422 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 3), 0x9209); | |
| 1423 | + | |
| 1424 | + for (unsigned int l = 0; l < 4; l++) | |
| 1425 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 4), 0x0096); | |
| 1426 | + | |
| 1427 | + for (unsigned int l = 0; l < 4; l++) | |
| 1428 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 5), 0x0100); | |
| 1429 | + | |
| 1430 | + for (unsigned int l = 0; l < 4; l++) | |
| 1431 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 6), 0x2d02); | |
| 1432 | + | |
| 1433 | + for (unsigned int l = 0; l < 4; l++) | |
| 1434 | + rcsi2_write16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 7), 0x1b06); | |
| 1435 | + | |
| 1436 | + if (lut) { | |
| 1437 | + /* | |
| 1438 | + * Documentation LUT have two values but document writing both | |
| 1439 | + * values in a single write. | |
| 1440 | + */ | |
| 1441 | + for (unsigned int l = 0; l < 4; l++) | |
| 1442 | + rcsi2_modify16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 3), | |
| 1443 | + lut->rw_hs_rx_3_83 << 3 | lut->rw_hs_rx_3_20, 0x1ff); | |
| 1444 | + | |
| 1445 | + for (unsigned int l = 0; l < 4; l++) | |
| 1446 | + rcsi2_modify16(priv, V4H_CORE_DIG_DLANE_l_RW_HS_RX_n_REG(l, 6), | |
| 1447 | + lut->rw_hs_rx_6 << 8, 0xff00); | |
| 1289 | 1448 | } |
| 1290 | 1449 | |
| 1291 | − /* C-PHY setting - analog programing*/ | |
| 1292 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29); | |
| 1293 | − rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27); | |
| 1450 | + static const u16 deskew_fine[] = { | |
| 1451 | + 0x0404, 0x040c, 0x0414, 0x041c, 0x0423, 0x0429, 0x0430, 0x043a, | |
| 1452 | + 0x0445, 0x044a, 0x0450, 0x045a, 0x0465, 0x0469, 0x0472, 0x047a, | |
| 1453 | + 0x0485, 0x0489, 0x0490, 0x049a, 0x04a4, 0x04ac, 0x04b4, 0x04bc, | |
| 1454 | + 0x04c4, 0x04cc, 0x04d4, 0x04dc, 0x04e4, 0x04ec, 0x04f4, 0x04fc, | |
| 1455 | + 0x0504, 0x050c, 0x0514, 0x051c, 0x0523, 0x0529, 0x0530, 0x053a, | |
| 1456 | + 0x0545, 0x054a, 0x0550, 0x055a, 0x0565, 0x0569, 0x0572, 0x057a, | |
| 1457 | + 0x0585, 0x0589, 0x0590, 0x059a, 0x05a4, 0x05ac, 0x05b4, 0x05bc, | |
| 1458 | + 0x05c4, 0x05cc, 0x05d4, 0x05dc, 0x05e4, 0x05ec, 0x05f4, 0x05fc, | |
| 1459 | + 0x0604, 0x060c, 0x0614, 0x061c, 0x0623, 0x0629, 0x0632, 0x063a, | |
| 1460 | + 0x0645, 0x064a, 0x0650, 0x065a, 0x0665, 0x0669, 0x0672, 0x067a, | |
| 1461 | + 0x0685, 0x0689, 0x0690, 0x069a, 0x06a4, 0x06ac, 0x06b4, 0x06bc, | |
| 1462 | + 0x06c4, 0x06cc, 0x06d4, 0x06dc, 0x06e4, 0x06ec, 0x06f4, 0x06fc, | |
| 1463 | + 0x0704, 0x070c, 0x0714, 0x071c, 0x0723, 0x072a, 0x0730, 0x073a, | |
| 1464 | + 0x0745, 0x074a, 0x0750, 0x075a, 0x0765, 0x0769, 0x0772, 0x077a, | |
| 1465 | + 0x0785, 0x0789, 0x0790, 0x079a, 0x07a4, 0x07ac, 0x07b4, 0x07bc, | |
| 1466 | + 0x07c4, 0x07cc, 0x07d4, 0x07dc, 0x07e4, 0x07ec, 0x07f4, 0x07fc, | |
| 1467 | + }; | |
| 1468 | + | |
| 1469 | + for (unsigned int i = 0; i < ARRAY_SIZE(deskew_fine); i++) { | |
| 1470 | + rcsi2_write16(priv, V4H_CORE_DIG_COMMON_RW_DESKEW_FINE_MEM_REG, | |
| 1471 | + deskew_fine[i]); | |
| 1472 | + } | |
| 1294 | 1473 | |
| 1295 | 1474 | return 0; |
| 1296 | 1475 | } |
| @@ -1298,10 +1477,11 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) · 1 unmodified line | ||
| 1298 | 1477 | static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, |
| 1299 | 1478 | struct v4l2_subdev_state *state) |
| 1300 | 1479 | { |
| 1480 | + const struct rcsi2_cphy_setting *cphy = NULL; | |
| 1301 | 1481 | const struct rcar_csi2_format *format; |
| 1302 | 1482 | const struct v4l2_mbus_framefmt *fmt; |
| 1303 | 1483 | unsigned int lanes; |
| 1304 | − int msps; | |
| 1484 | + int mbps; | |
| 1305 | 1485 | int ret; |
| 1306 | 1486 | |
| 1307 | 1487 | /* Use the format on the sink pad to compute the receiver config. */ |
| @@ -1314,28 +1494,40 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, · 6 unmodified lines | ||
| 1314 | 1494 | if (ret) |
| 1315 | 1495 | return ret; |
| 1316 | 1496 | |
| 1317 | − msps = rcsi2_calc_mbps(priv, format->bpp, lanes); | |
| 1318 | − if (msps < 0) | |
| 1319 | − return msps; | |
| 1497 | + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); | |
| 1498 | + if (mbps < 0) | |
| 1499 | + return mbps; | |
| 1320 | 1500 | |
| 1321 | − /* Reset LINK and PHY*/ | |
| 1501 | + /* T0: Reset LINK and PHY*/ | |
| 1322 | 1502 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); |
| 1323 | 1503 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); |
| 1324 | 1504 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); |
| 1325 | 1505 | |
| 1326 | − /* PHY static setting */ | |
| 1327 | − rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); | |
| 1506 | + /* T1: PHY static setting */ | |
| 1507 | + rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK | | |
| 1508 | + V4H_PHY_EN_ENABLE_0 | V4H_PHY_EN_ENABLE_1 | | |
| 1509 | + V4H_PHY_EN_ENABLE_2 | V4H_PHY_EN_ENABLE_3); | |
| 1328 | 1510 | rcsi2_write(priv, V4H_FLDC_REG, 0); |
| 1329 | 1511 | rcsi2_write(priv, V4H_FLDD_REG, 0); |
| 1330 | 1512 | rcsi2_write(priv, V4H_IDIC_REG, 0); |
| 1331 | − rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_CPHY); | |
| 1513 | + rcsi2_write(priv, V4H_PHY_MODE_REG, | |
| 1514 | + priv->cphy ? V4H_PHY_MODE_CPHY : V4H_PHY_MODE_DPHY); | |
| 1332 | 1515 | rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); |
| 1333 | 1516 | |
| 1334 | − /* Reset CSI2 */ | |
| 1517 | + rcsi2_write(priv, V4M_FRXM_REG, | |
| 1518 | + V4M_FRXM_FORCERXMODE_0 | V4M_FRXM_FORCERXMODE_1 | | |
| 1519 | + V4M_FRXM_FORCERXMODE_2 | V4M_FRXM_FORCERXMODE_3); | |
| 1520 | + rcsi2_write(priv, V4M_OVR1_REG, | |
| 1521 | + V4M_OVR1_FORCERXMODE_0 | V4M_OVR1_FORCERXMODE_1 | | |
| 1522 | + V4M_OVR1_FORCERXMODE_2 | V4M_OVR1_FORCERXMODE_3); | |
| 1523 | + | |
| 1524 | + /* T2: Reset CSI2 */ | |
| 1335 | 1525 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); |
| 1336 | 1526 | |
| 1337 | 1527 | /* Registers static setting through APB */ |
| 1338 | 1528 | /* Common setting */ |
| 1529 | + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(10), 0x0030); | |
| 1530 | + rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(2), 0x1444); | |
| 1339 | 1531 | rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd); |
| 1340 | 1532 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233); |
| 1341 | 1533 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), 0x0027); |
| @@ -1350,20 +1542,71 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, · 8 unmodified lines | ||
| 1350 | 1542 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105); |
| 1351 | 1543 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000); |
| 1352 | 1544 | rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, 0x0003); |
| 1545 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(0), 0x0000); | |
| 1546 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(1), 0x0400); | |
| 1547 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(3), 0x41f6); | |
| 1548 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(0), 0x0000); | |
| 1549 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(3), 0x43f6); | |
| 1550 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x3000); | |
| 1551 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(7), 0x0000); | |
| 1552 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x7000); | |
| 1553 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(7), 0x0000); | |
| 1554 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(5), 0x4000); | |
| 1555 | + | |
| 1556 | + /* T3: PHY settings */ | |
| 1557 | + if (priv->cphy) { | |
| 1558 | + cphy = rcsi2_c_phy_setting_v4h(priv, mbps); | |
| 1559 | + if (!cphy) | |
| 1560 | + return -ERANGE; | |
| 1561 | + } else { | |
| 1562 | + ret = rcsi2_d_phy_setting_v4h(priv, mbps); | |
| 1563 | + if (ret) | |
| 1564 | + return ret; | |
| 1565 | + } | |
| 1353 | 1566 | |
| 1354 | − /* C-PHY settings */ | |
| 1355 | − ret = rcsi2_c_phy_setting_v4h(priv, msps); | |
| 1356 | − if (ret) | |
| 1357 | − return ret; | |
| 1567 | + /* T4: Leave Shutdown mode */ | |
| 1568 | + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); | |
| 1569 | + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); | |
| 1570 | + | |
| 1571 | + /* T5: Wait for calibration */ | |
| 1572 | + if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { | |
| 1573 | + dev_err(priv->dev, "PHY calibration failed\n"); | |
| 1574 | + return -ETIMEDOUT; | |
| 1575 | + } | |
| 1576 | + | |
| 1577 | + /* T6: Analog programming */ | |
| 1578 | + if (priv->cphy) { | |
| 1579 | + for (unsigned int l = 0; l < 3; l++) { | |
| 1580 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 9), | |
| 1581 | + cphy->lane29); | |
| 1582 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 7), | |
| 1583 | + cphy->lane27); | |
| 1584 | + } | |
| 1585 | + } else { | |
| 1586 | + u16 val_2_9 = mbps > 2500 ? 0x14 : mbps > 1500 ? 0x04 : 0x00; | |
| 1587 | + u16 val_2_15 = mbps > 1500 ? 0x03 : 0x00; | |
| 1588 | + | |
| 1589 | + for (unsigned int l = 0; l < 5; l++) { | |
| 1590 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 9), | |
| 1591 | + val_2_9); | |
| 1592 | + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(l, 15), | |
| 1593 | + val_2_15); | |
| 1594 | + } | |
| 1595 | + } | |
| 1358 | 1596 | |
| 1597 | + /* T7: Wait for stop state */ | |
| 1359 | 1598 | rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | |
| 1360 | 1599 | V4H_ST_PHYST_ST_STOPSTATE_1 | |
| 1361 | − V4H_ST_PHYST_ST_STOPSTATE_2); | |
| 1600 | + V4H_ST_PHYST_ST_STOPSTATE_2 | | |
| 1601 | + V4H_ST_PHYST_ST_STOPSTATE_3); | |
| 1602 | + | |
| 1603 | + /* T8: De-assert FRXM */ | |
| 1604 | + rcsi2_write(priv, V4M_FRXM_REG, 0); | |
| 1362 | 1605 | |
| 1363 | 1606 | return 0; |
| 1364 | 1607 | } |
| 1365 | 1608 | |
| 1366 | −static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int data_rate) | |
| 1609 | +static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int mbps) | |
| 1367 | 1610 | { |
| 1368 | 1611 | unsigned int timeout; |
| 1369 | 1612 | int ret; |
| @@ -2213,6 +2456,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { · 843 unmodified lines | ||
| 2213 | 2456 | .start_receiver = rcsi2_start_receiver_v4h, |
| 2214 | 2457 | .use_isp = true, |
| 2215 | 2458 | .support_cphy = true, |
| 2459 | + .support_dphy = true, | |
| 2216 | 2460 | }; |
| 2217 | 2461 | |
| 2218 | 2462 | static const struct rcsi2_register_layout rcsi2_registers_v4m = { |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/device.h> |
| 11 | 11 | #include <linux/dma-mapping.h> |
| 12 | +#include <linux/io.h> | |
| 13 | +#include <linux/iopoll.h> | |
| 12 | 14 | #include <linux/list.h> |
| 13 | 15 | #include <linux/module.h> |
| 14 | 16 | #include <linux/mod_devicetable.h> |
| @@ -19,14 +21,25 @@ · 4 unmodified lines | ||
| 19 | 21 | |
| 20 | 22 | #include <media/rcar-fcp.h> |
| 21 | 23 | |
| 24 | +#define RCAR_FCP_REG_RST 0x0010 | |
| 25 | +#define RCAR_FCP_REG_RST_SOFTRST BIT(0) | |
| 26 | +#define RCAR_FCP_REG_STA 0x0018 | |
| 27 | +#define RCAR_FCP_REG_STA_ACT BIT(0) | |
| 28 | + | |
| 22 | 29 | struct rcar_fcp_device { |
| 23 | 30 | struct list_head list; |
| 24 | 31 | struct device *dev; |
| 32 | + void __iomem *base; | |
| 25 | 33 | }; |
| 26 | 34 | |
| 27 | 35 | static LIST_HEAD(fcp_devices); |
| 28 | 36 | static DEFINE_MUTEX(fcp_lock); |
| 29 | 37 | |
| 38 | +static inline void rcar_fcp_write(struct rcar_fcp_device *fcp, u32 reg, u32 val) | |
| 39 | +{ | |
| 40 | + iowrite32(val, fcp->base + reg); | |
| 41 | +} | |
| 42 | + | |
| 30 | 43 | /* ----------------------------------------------------------------------------- |
| 31 | 44 | * Public API |
| 32 | 45 | */ |
| @@ -117,6 +130,25 @@ void rcar_fcp_disable(struct rcar_fcp_device *fcp) · 84 unmodified lines | ||
| 117 | 130 | } |
| 118 | 131 | EXPORT_SYMBOL_GPL(rcar_fcp_disable); |
| 119 | 132 | |
| 133 | +int rcar_fcp_soft_reset(struct rcar_fcp_device *fcp) | |
| 134 | +{ | |
| 135 | + u32 value; | |
| 136 | + int ret; | |
| 137 | + | |
| 138 | + if (!fcp) | |
| 139 | + return 0; | |
| 140 | + | |
| 141 | + rcar_fcp_write(fcp, RCAR_FCP_REG_RST, RCAR_FCP_REG_RST_SOFTRST); | |
| 142 | + ret = readl_poll_timeout(fcp->base + RCAR_FCP_REG_STA, | |
| 143 | + value, !(value & RCAR_FCP_REG_STA_ACT), | |
| 144 | + 1, 100); | |
| 145 | + if (ret) | |
| 146 | + dev_err(fcp->dev, "Failed to soft-reset\n"); | |
| 147 | + | |
| 148 | + return ret; | |
| 149 | +} | |
| 150 | +EXPORT_SYMBOL_GPL(rcar_fcp_soft_reset); | |
| 151 | + | |
| 120 | 152 | /* ----------------------------------------------------------------------------- |
| 121 | 153 | * Platform Driver |
| 122 | 154 | */ |
| @@ -131,6 +163,10 @@ static int rcar_fcp_probe(struct platform_device *pdev) · 8 unmodified lines | ||
| 131 | 163 | |
| 132 | 164 | fcp->dev = &pdev->dev; |
| 133 | 165 | |
| 166 | + fcp->base = devm_platform_ioremap_resource(pdev, 0); | |
| 167 | + if (IS_ERR(fcp->base)) | |
| 168 | + return PTR_ERR(fcp->base); | |
| 169 | + | |
| 134 | 170 | dma_set_max_seg_size(fcp->dev, UINT_MAX); |
| 135 | 171 | |
| 136 | 172 | pm_runtime_enable(&pdev->dev); |
| @@ -2,14 +2,14 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Driver for Renesas R-Car VIN |
| 4 | 4 | * |
| 5 | + * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | |
| 5 | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | − * | |
| 10 | − * Based on the soc-camera rcar_vin driver | |
| 11 | 10 | */ |
| 12 | 11 | |
| 12 | +#include <linux/idr.h> | |
| 13 | 13 | #include <linux/module.h> |
| 14 | 14 | #include <linux/of.h> |
| 15 | 15 | #include <linux/of_graph.h> |
| @@ -55,6 +55,7 @@ · 39 unmodified lines | ||
| 55 | 55 | * be only one group for all instances. |
| 56 | 56 | */ |
| 57 | 57 | |
| 58 | +static DEFINE_IDA(rvin_ida); | |
| 58 | 59 | static DEFINE_MUTEX(rvin_group_lock); |
| 59 | 60 | static struct rvin_group *rvin_group_data; |
| 60 | 61 | |
| @@ -65,7 +66,7 @@ static void rvin_group_cleanup(struct rvin_group *group) · 4 unmodified lines | ||
| 65 | 66 | } |
| 66 | 67 | |
| 67 | 68 | static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, |
| 68 | − int (*link_setup)(struct rvin_dev *), | |
| 69 | + int (*link_setup)(struct rvin_group *), | |
| 69 | 70 | const struct media_device_ops *ops) |
| 70 | 71 | { |
| 71 | 72 | struct media_device *mdev = &group->mdev; |
| @@ -115,27 +116,12 @@ static void rvin_group_release(struct kref *kref) · 43 unmodified lines | ||
| 115 | 116 | } |
| 116 | 117 | |
| 117 | 118 | static int rvin_group_get(struct rvin_dev *vin, |
| 118 | − int (*link_setup)(struct rvin_dev *), | |
| 119 | + int (*link_setup)(struct rvin_group *), | |
| 119 | 120 | const struct media_device_ops *ops) |
| 120 | 121 | { |
| 121 | 122 | struct rvin_group *group; |
| 122 | − u32 id; | |
| 123 | 123 | int ret; |
| 124 | 124 | |
| 125 | − /* Make sure VIN id is present and sane */ | |
| 126 | − ret = of_property_read_u32(vin->dev->of_node, "renesas,id", &id); | |
| 127 | − if (ret) { | |
| 128 | − vin_err(vin, "%pOF: No renesas,id property found\n", | |
| 129 | − vin->dev->of_node); | |
| 130 | − return -EINVAL; | |
| 131 | − } | |
| 132 | − | |
| 133 | − if (id >= RCAR_VIN_NUM) { | |
| 134 | − vin_err(vin, "%pOF: Invalid renesas,id '%u'\n", | |
| 135 | − vin->dev->of_node, id); | |
| 136 | − return -EINVAL; | |
| 137 | − } | |
| 138 | − | |
| 139 | 125 | /* Join or create a VIN group */ |
| 140 | 126 | mutex_lock(&rvin_group_lock); |
| 141 | 127 | if (rvin_group_data) { |
| @@ -156,6 +142,7 @@ static int rvin_group_get(struct rvin_dev *vin, · 14 unmodified lines | ||
| 156 | 142 | } |
| 157 | 143 | |
| 158 | 144 | kref_init(&group->refcount); |
| 145 | + group->info = vin->info; | |
| 159 | 146 | |
| 160 | 147 | rvin_group_data = group; |
| 161 | 148 | } |
| @@ -164,16 +151,15 @@ static int rvin_group_get(struct rvin_dev *vin, · 2 unmodified lines | ||
| 164 | 151 | /* Add VIN to group */ |
| 165 | 152 | mutex_lock(&group->lock); |
| 166 | 153 | |
| 167 | − if (group->vin[id]) { | |
| 168 | − vin_err(vin, "Duplicate renesas,id property value %u\n", id); | |
| 154 | + if (group->vin[vin->id]) { | |
| 155 | + vin_err(vin, "Duplicate renesas,id property value %u\n", vin->id); | |
| 169 | 156 | mutex_unlock(&group->lock); |
| 170 | 157 | kref_put(&group->refcount, rvin_group_release); |
| 171 | 158 | return -EINVAL; |
| 172 | 159 | } |
| 173 | 160 | |
| 174 | − group->vin[id] = vin; | |
| 161 | + group->vin[vin->id] = vin; | |
| 175 | 162 | |
| 176 | − vin->id = id; | |
| 177 | 163 | vin->group = group; |
| 178 | 164 | vin->v4l2_dev.mdev = &group->mdev; |
| 179 | 165 | |
| @@ -213,7 +199,7 @@ static int rvin_group_entity_to_remote_id(struct rvin_group *group, · 33 unmodified lines | ||
| 213 | 199 | |
| 214 | 200 | sd = media_entity_to_v4l2_subdev(entity); |
| 215 | 201 | |
| 216 | − for (i = 0; i < RVIN_REMOTES_MAX; i++) | |
| 202 | + for (i = 0; i < ARRAY_SIZE(group->remotes); i++) | |
| 217 | 203 | if (group->remotes[i].subdev == sd) |
| 218 | 204 | return i; |
| 219 | 205 | |
| @@ -246,7 +232,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) · 26 unmodified lines | ||
| 246 | 232 | } |
| 247 | 233 | } |
| 248 | 234 | |
| 249 | − return vin->group->link_setup(vin); | |
| 235 | + return vin->group->link_setup(vin->group); | |
| 250 | 236 | } |
| 251 | 237 | |
| 252 | 238 | static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, |
| @@ -254,20 +240,32 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, · 1 unmodified line | ||
| 254 | 240 | struct v4l2_async_connection *asc) |
| 255 | 241 | { |
| 256 | 242 | struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); |
| 257 | − unsigned int i; | |
| 243 | + struct rvin_group *group = vin->group; | |
| 258 | 244 | |
| 259 | − for (i = 0; i < RCAR_VIN_NUM; i++) | |
| 260 | − if (vin->group->vin[i]) | |
| 261 | − rvin_v4l2_unregister(vin->group->vin[i]); | |
| 245 | + for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { | |
| 246 | + if (group->vin[i]) | |
| 247 | + rvin_v4l2_unregister(group->vin[i]); | |
| 248 | + } | |
| 262 | 249 | |
| 263 | 250 | mutex_lock(&vin->group->lock); |
| 264 | 251 | |
| 265 | − for (i = 0; i < RVIN_CSI_MAX; i++) { | |
| 266 | − if (vin->group->remotes[i].asc != asc) | |
| 252 | + for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { | |
| 253 | + if (!group->vin[i] || group->vin[i]->parallel.asc != asc) | |
| 267 | 254 | continue; |
| 268 | − vin->group->remotes[i].subdev = NULL; | |
| 255 | + | |
| 256 | + group->vin[i]->parallel.subdev = NULL; | |
| 257 | + | |
| 258 | + vin_dbg(group->vin[i], "Unbind parallel subdev %s\n", | |
| 259 | + subdev->name); | |
| 260 | + } | |
| 261 | + | |
| 262 | + for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { | |
| 263 | + if (group->remotes[i].asc != asc) | |
| 264 | + continue; | |
| 265 | + | |
| 266 | + group->remotes[i].subdev = NULL; | |
| 267 | + | |
| 269 | 268 | vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); |
| 270 | − break; | |
| 271 | 269 | } |
| 272 | 270 | |
| 273 | 271 | mutex_unlock(&vin->group->lock); |
| @@ -280,21 +278,38 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, · 6 unmodified lines | ||
| 280 | 278 | struct v4l2_async_connection *asc) |
| 281 | 279 | { |
| 282 | 280 | struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); |
| 283 | − unsigned int i; | |
| 281 | + struct rvin_group *group = vin->group; | |
| 284 | 282 | |
| 285 | − mutex_lock(&vin->group->lock); | |
| 283 | + guard(mutex)(&group->lock); | |
| 286 | 284 | |
| 287 | − for (i = 0; i < RVIN_CSI_MAX; i++) { | |
| 285 | + for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { | |
| 286 | + struct rvin_dev *pvin = group->vin[i]; | |
| 287 | + | |
| 288 | + if (!pvin || pvin->parallel.asc != asc) | |
| 289 | + continue; | |
| 290 | + | |
| 291 | + pvin->parallel.source_pad = 0; | |
| 292 | + for (unsigned int pad = 0; pad < subdev->entity.num_pads; pad++) | |
| 293 | + if (subdev->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE) | |
| 294 | + pvin->parallel.source_pad = pad; | |
| 295 | + | |
| 296 | + pvin->parallel.subdev = subdev; | |
| 297 | + vin_dbg(pvin, "Bound subdev %s\n", subdev->name); | |
| 298 | + | |
| 299 | + return 0; | |
| 300 | + } | |
| 301 | + | |
| 302 | + for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { | |
| 288 | 303 | if (vin->group->remotes[i].asc != asc) |
| 289 | 304 | continue; |
| 305 | + | |
| 290 | 306 | vin->group->remotes[i].subdev = subdev; |
| 291 | 307 | vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); |
| 292 | − break; | |
| 293 | − } | |
| 294 | 308 | |
| 295 | − mutex_unlock(&vin->group->lock); | |
| 309 | + return 0; | |
| 310 | + } | |
| 296 | 311 | |
| 297 | − return 0; | |
| 312 | + return -ENODEV; | |
| 298 | 313 | } |
| 299 | 314 | |
| 300 | 315 | static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { |
| @@ -343,12 +358,49 @@ out: · 42 unmodified lines | ||
| 343 | 358 | return ret; |
| 344 | 359 | } |
| 345 | 360 | |
| 346 | −static void rvin_group_notifier_cleanup(struct rvin_dev *vin) | |
| 361 | +static int rvin_parallel_parse_of(struct rvin_dev *vin) | |
| 347 | 362 | { |
| 348 | − if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { | |
| 349 | − v4l2_async_nf_unregister(&vin->group->notifier); | |
| 350 | − v4l2_async_nf_cleanup(&vin->group->notifier); | |
| 363 | + struct fwnode_handle *fwnode __free(fwnode_handle) = NULL; | |
| 364 | + struct fwnode_handle *ep __free(fwnode_handle) = NULL; | |
| 365 | + struct v4l2_fwnode_endpoint vep = { | |
| 366 | + .bus_type = V4L2_MBUS_UNKNOWN, | |
| 367 | + }; | |
| 368 | + struct v4l2_async_connection *asc; | |
| 369 | + | |
| 370 | + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0); | |
| 371 | + if (!ep) | |
| 372 | + return 0; | |
| 373 | + | |
| 374 | + if (v4l2_fwnode_endpoint_parse(ep, &vep)) { | |
| 375 | + vin_err(vin, "Failed to parse %pOF\n", to_of_node(ep)); | |
| 376 | + return -EINVAL; | |
| 351 | 377 | } |
| 378 | + | |
| 379 | + switch (vep.bus_type) { | |
| 380 | + case V4L2_MBUS_PARALLEL: | |
| 381 | + case V4L2_MBUS_BT656: | |
| 382 | + vin_dbg(vin, "Found %s media bus\n", | |
| 383 | + vep.bus_type == V4L2_MBUS_PARALLEL ? | |
| 384 | + "PARALLEL" : "BT656"); | |
| 385 | + vin->parallel.mbus_type = vep.bus_type; | |
| 386 | + vin->parallel.bus = vep.bus.parallel; | |
| 387 | + break; | |
| 388 | + default: | |
| 389 | + vin_err(vin, "Unknown media bus type\n"); | |
| 390 | + return -EINVAL; | |
| 391 | + } | |
| 392 | + | |
| 393 | + fwnode = fwnode_graph_get_remote_endpoint(ep); | |
| 394 | + asc = v4l2_async_nf_add_fwnode(&vin->group->notifier, fwnode, | |
| 395 | + struct v4l2_async_connection); | |
| 396 | + if (IS_ERR(asc)) | |
| 397 | + return PTR_ERR(asc); | |
| 398 | + | |
| 399 | + vin->parallel.asc = asc; | |
| 400 | + | |
| 401 | + vin_dbg(vin, "Add parallel OF device %pOF\n", to_of_node(fwnode)); | |
| 402 | + | |
| 403 | + return 0; | |
| 352 | 404 | } |
| 353 | 405 | |
| 354 | 406 | static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, |
| @@ -385,6 +437,12 @@ static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, · 30 unmodified lines | ||
| 385 | 437 | if (!(vin_mask & BIT(i))) |
| 386 | 438 | continue; |
| 387 | 439 | |
| 440 | + /* Parse local subdevice. */ | |
| 441 | + ret = rvin_parallel_parse_of(vin->group->vin[i]); | |
| 442 | + if (ret) | |
| 443 | + return ret; | |
| 444 | + | |
| 445 | + /* Parse shared subdevices. */ | |
| 388 | 446 | for (id = 0; id < max_id; id++) { |
| 389 | 447 | if (vin->group->remotes[id].asc) |
| 390 | 448 | continue; |
| @@ -437,11 +495,11 @@ static void rvin_free_controls(struct rvin_dev *vin) · 46 unmodified lines | ||
| 437 | 495 | vin->vdev.ctrl_handler = NULL; |
| 438 | 496 | } |
| 439 | 497 | |
| 440 | −static int rvin_create_controls(struct rvin_dev *vin, struct v4l2_subdev *subdev) | |
| 498 | +static int rvin_create_controls(struct rvin_dev *vin) | |
| 441 | 499 | { |
| 442 | 500 | int ret; |
| 443 | 501 | |
| 444 | − ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 16); | |
| 502 | + ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1); | |
| 445 | 503 | if (ret < 0) |
| 446 | 504 | return ret; |
| 447 | 505 | |
| @@ -455,286 +513,11 @@ static int rvin_create_controls(struct rvin_dev *vin, struct v4l2_subdev *subdev · 7 unmodified lines | ||
| 455 | 513 | return ret; |
| 456 | 514 | } |
| 457 | 515 | |
| 458 | − /* For the non-MC mode add controls from the subdevice. */ | |
| 459 | − if (subdev) { | |
| 460 | − ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, | |
| 461 | − subdev->ctrl_handler, NULL, true); | |
| 462 | − if (ret < 0) { | |
| 463 | − rvin_free_controls(vin); | |
| 464 | − return ret; | |
| 465 | − } | |
| 466 | − } | |
| 467 | − | |
| 468 | 516 | vin->vdev.ctrl_handler = &vin->ctrl_handler; |
| 469 | 517 | |
| 470 | 518 | return 0; |
| 471 | 519 | } |
| 472 | 520 | |
| 473 | −/* ----------------------------------------------------------------------------- | |
| 474 | − * Async notifier | |
| 475 | − */ | |
| 476 | − | |
| 477 | −static int rvin_find_pad(struct v4l2_subdev *sd, int direction) | |
| 478 | −{ | |
| 479 | − unsigned int pad; | |
| 480 | − | |
| 481 | − if (sd->entity.num_pads <= 1) | |
| 482 | − return 0; | |
| 483 | − | |
| 484 | − for (pad = 0; pad < sd->entity.num_pads; pad++) | |
| 485 | − if (sd->entity.pads[pad].flags & direction) | |
| 486 | − return pad; | |
| 487 | − | |
| 488 | − return -EINVAL; | |
| 489 | −} | |
| 490 | − | |
| 491 | −/* ----------------------------------------------------------------------------- | |
| 492 | − * Parallel async notifier | |
| 493 | − */ | |
| 494 | − | |
| 495 | −/* The vin lock should be held when calling the subdevice attach and detach */ | |
| 496 | −static int rvin_parallel_subdevice_attach(struct rvin_dev *vin, | |
| 497 | − struct v4l2_subdev *subdev) | |
| 498 | −{ | |
| 499 | − struct v4l2_subdev_mbus_code_enum code = { | |
| 500 | − .which = V4L2_SUBDEV_FORMAT_ACTIVE, | |
| 501 | − }; | |
| 502 | − int ret; | |
| 503 | − | |
| 504 | − /* Find source and sink pad of remote subdevice */ | |
| 505 | − ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); | |
| 506 | − if (ret < 0) | |
| 507 | − return ret; | |
| 508 | − vin->parallel.source_pad = ret; | |
| 509 | − | |
| 510 | − ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); | |
| 511 | − vin->parallel.sink_pad = ret < 0 ? 0 : ret; | |
| 512 | − | |
| 513 | − if (vin->info->use_mc) { | |
| 514 | − vin->parallel.subdev = subdev; | |
| 515 | − return 0; | |
| 516 | − } | |
| 517 | − | |
| 518 | − /* Find compatible subdevices mbus format */ | |
| 519 | − vin->mbus_code = 0; | |
| 520 | − code.index = 0; | |
| 521 | − code.pad = vin->parallel.source_pad; | |
| 522 | − while (!vin->mbus_code && | |
| 523 | − !v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) { | |
| 524 | − code.index++; | |
| 525 | − switch (code.code) { | |
| 526 | − case MEDIA_BUS_FMT_YUYV8_1X16: | |
| 527 | − case MEDIA_BUS_FMT_UYVY8_1X16: | |
| 528 | − case MEDIA_BUS_FMT_UYVY8_2X8: | |
| 529 | − case MEDIA_BUS_FMT_UYVY10_2X10: | |
| 530 | − case MEDIA_BUS_FMT_RGB888_1X24: | |
| 531 | − vin->mbus_code = code.code; | |
| 532 | − vin_dbg(vin, "Found media bus format for %s: %d\n", | |
| 533 | − subdev->name, vin->mbus_code); | |
| 534 | − break; | |
| 535 | − default: | |
| 536 | − break; | |
| 537 | − } | |
| 538 | − } | |
| 539 | − | |
| 540 | − if (!vin->mbus_code) { | |
| 541 | − vin_err(vin, "Unsupported media bus format for %s\n", | |
| 542 | − subdev->name); | |
| 543 | − return -EINVAL; | |
| 544 | − } | |
| 545 | − | |
| 546 | − /* Read tvnorms */ | |
| 547 | − ret = v4l2_subdev_call(subdev, video, g_tvnorms, &vin->vdev.tvnorms); | |
| 548 | − if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | |
| 549 | − return ret; | |
| 550 | − | |
| 551 | − /* Read standard */ | |
| 552 | − vin->std = V4L2_STD_UNKNOWN; | |
| 553 | − ret = v4l2_subdev_call(subdev, video, g_std, &vin->std); | |
| 554 | − if (ret < 0 && ret != -ENOIOCTLCMD) | |
| 555 | − return ret; | |
| 556 | − | |
| 557 | − /* Add the controls */ | |
| 558 | − ret = rvin_create_controls(vin, subdev); | |
| 559 | − if (ret < 0) | |
| 560 | − return ret; | |
| 561 | − | |
| 562 | − vin->parallel.subdev = subdev; | |
| 563 | − | |
| 564 | − return 0; | |
| 565 | −} | |
| 566 | − | |
| 567 | −static void rvin_parallel_subdevice_detach(struct rvin_dev *vin) | |
| 568 | −{ | |
| 569 | − rvin_v4l2_unregister(vin); | |
| 570 | − vin->parallel.subdev = NULL; | |
| 571 | − | |
| 572 | − if (!vin->info->use_mc) | |
| 573 | − rvin_free_controls(vin); | |
| 574 | −} | |
| 575 | − | |
| 576 | −static int rvin_parallel_notify_complete(struct v4l2_async_notifier *notifier) | |
| 577 | −{ | |
| 578 | − struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); | |
| 579 | − struct media_entity *source; | |
| 580 | − struct media_entity *sink; | |
| 581 | − int ret; | |
| 582 | − | |
| 583 | − ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); | |
| 584 | − if (ret < 0) { | |
| 585 | − vin_err(vin, "Failed to register subdev nodes\n"); | |
| 586 | − return ret; | |
| 587 | − } | |
| 588 | − | |
| 589 | − if (!video_is_registered(&vin->vdev)) { | |
| 590 | − ret = rvin_v4l2_register(vin); | |
| 591 | − if (ret < 0) | |
| 592 | − return ret; | |
| 593 | − } | |
| 594 | − | |
| 595 | − if (!vin->info->use_mc) | |
| 596 | − return 0; | |
| 597 | − | |
| 598 | − /* If we're running with media-controller, link the subdevs. */ | |
| 599 | − source = &vin->parallel.subdev->entity; | |
| 600 | − sink = &vin->vdev.entity; | |
| 601 | − | |
| 602 | − ret = media_create_pad_link(source, vin->parallel.source_pad, | |
| 603 | − sink, vin->parallel.sink_pad, 0); | |
| 604 | − if (ret) | |
| 605 | − vin_err(vin, "Error adding link from %s to %s: %d\n", | |
| 606 | − source->name, sink->name, ret); | |
| 607 | − | |
| 608 | − return ret; | |
| 609 | −} | |
| 610 | − | |
| 611 | −static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier, | |
| 612 | − struct v4l2_subdev *subdev, | |
| 613 | − struct v4l2_async_connection *asc) | |
| 614 | −{ | |
| 615 | − struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); | |
| 616 | − | |
| 617 | − vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name); | |
| 618 | − | |
| 619 | − mutex_lock(&vin->lock); | |
| 620 | − rvin_parallel_subdevice_detach(vin); | |
| 621 | − mutex_unlock(&vin->lock); | |
| 622 | −} | |
| 623 | − | |
| 624 | −static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, | |
| 625 | − struct v4l2_subdev *subdev, | |
| 626 | − struct v4l2_async_connection *asc) | |
| 627 | −{ | |
| 628 | − struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); | |
| 629 | − int ret; | |
| 630 | − | |
| 631 | − mutex_lock(&vin->lock); | |
| 632 | − ret = rvin_parallel_subdevice_attach(vin, subdev); | |
| 633 | − mutex_unlock(&vin->lock); | |
| 634 | − if (ret) | |
| 635 | − return ret; | |
| 636 | − | |
| 637 | − v4l2_set_subdev_hostdata(subdev, vin); | |
| 638 | − | |
| 639 | − vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n", | |
| 640 | − subdev->name, vin->parallel.source_pad, | |
| 641 | − vin->parallel.sink_pad); | |
| 642 | − | |
| 643 | − return 0; | |
| 644 | −} | |
| 645 | − | |
| 646 | −static const struct v4l2_async_notifier_operations rvin_parallel_notify_ops = { | |
| 647 | − .bound = rvin_parallel_notify_bound, | |
| 648 | − .unbind = rvin_parallel_notify_unbind, | |
| 649 | − .complete = rvin_parallel_notify_complete, | |
| 650 | −}; | |
| 651 | − | |
| 652 | −static int rvin_parallel_parse_of(struct rvin_dev *vin) | |
| 653 | −{ | |
| 654 | − struct fwnode_handle *ep, *fwnode; | |
| 655 | − struct v4l2_fwnode_endpoint vep = { | |
| 656 | − .bus_type = V4L2_MBUS_UNKNOWN, | |
| 657 | − }; | |
| 658 | − struct v4l2_async_connection *asc; | |
| 659 | − int ret; | |
| 660 | − | |
| 661 | − ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(vin->dev), 0, 0, 0); | |
| 662 | − if (!ep) | |
| 663 | − return 0; | |
| 664 | − | |
| 665 | − fwnode = fwnode_graph_get_remote_endpoint(ep); | |
| 666 | − ret = v4l2_fwnode_endpoint_parse(ep, &vep); | |
| 667 | − fwnode_handle_put(ep); | |
| 668 | − if (ret) { | |
| 669 | − vin_err(vin, "Failed to parse %pOF\n", to_of_node(fwnode)); | |
| 670 | − ret = -EINVAL; | |
| 671 | − goto out; | |
| 672 | − } | |
| 673 | − | |
| 674 | − switch (vep.bus_type) { | |
| 675 | − case V4L2_MBUS_PARALLEL: | |
| 676 | − case V4L2_MBUS_BT656: | |
| 677 | − vin_dbg(vin, "Found %s media bus\n", | |
| 678 | − vep.bus_type == V4L2_MBUS_PARALLEL ? | |
| 679 | − "PARALLEL" : "BT656"); | |
| 680 | − vin->parallel.mbus_type = vep.bus_type; | |
| 681 | − vin->parallel.bus = vep.bus.parallel; | |
| 682 | − break; | |
| 683 | − default: | |
| 684 | − vin_err(vin, "Unknown media bus type\n"); | |
| 685 | − ret = -EINVAL; | |
| 686 | − goto out; | |
| 687 | − } | |
| 688 | − | |
| 689 | − asc = v4l2_async_nf_add_fwnode(&vin->notifier, fwnode, | |
| 690 | − struct v4l2_async_connection); | |
| 691 | − if (IS_ERR(asc)) { | |
| 692 | − ret = PTR_ERR(asc); | |
| 693 | − goto out; | |
| 694 | − } | |
| 695 | − | |
| 696 | − vin->parallel.asc = asc; | |
| 697 | − | |
| 698 | − vin_dbg(vin, "Add parallel OF device %pOF\n", to_of_node(fwnode)); | |
| 699 | −out: | |
| 700 | − fwnode_handle_put(fwnode); | |
| 701 | − | |
| 702 | − return ret; | |
| 703 | −} | |
| 704 | − | |
| 705 | −static void rvin_parallel_cleanup(struct rvin_dev *vin) | |
| 706 | −{ | |
| 707 | − v4l2_async_nf_unregister(&vin->notifier); | |
| 708 | − v4l2_async_nf_cleanup(&vin->notifier); | |
| 709 | −} | |
| 710 | − | |
| 711 | −static int rvin_parallel_init(struct rvin_dev *vin) | |
| 712 | −{ | |
| 713 | − int ret; | |
| 714 | − | |
| 715 | − v4l2_async_nf_init(&vin->notifier, &vin->v4l2_dev); | |
| 716 | − | |
| 717 | − ret = rvin_parallel_parse_of(vin); | |
| 718 | − if (ret) | |
| 719 | − return ret; | |
| 720 | − | |
| 721 | − if (!vin->parallel.asc) | |
| 722 | − return -ENODEV; | |
| 723 | − | |
| 724 | − vin_dbg(vin, "Found parallel subdevice %pOF\n", | |
| 725 | − to_of_node(vin->parallel.asc->match.fwnode)); | |
| 726 | − | |
| 727 | − vin->notifier.ops = &rvin_parallel_notify_ops; | |
| 728 | − ret = v4l2_async_nf_register(&vin->notifier); | |
| 729 | − if (ret < 0) { | |
| 730 | − vin_err(vin, "Notifier registration failed\n"); | |
| 731 | − v4l2_async_nf_cleanup(&vin->notifier); | |
| 732 | − return ret; | |
| 733 | − } | |
| 734 | − | |
| 735 | − return 0; | |
| 736 | −} | |
| 737 | − | |
| 738 | 521 | /* ----------------------------------------------------------------------------- |
| 739 | 522 | * CSI-2 |
| 740 | 523 | */ |
| @@ -909,80 +692,91 @@ static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id, · 168 unmodified lines | ||
| 909 | 692 | return 0; |
| 910 | 693 | } |
| 911 | 694 | |
| 912 | −static int rvin_csi2_setup_links(struct rvin_dev *vin) | |
| 695 | +static int rvin_parallel_setup_links(struct rvin_group *group) | |
| 696 | +{ | |
| 697 | + u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; | |
| 698 | + | |
| 699 | + guard(mutex)(&group->lock); | |
| 700 | + | |
| 701 | + /* If the group also has links don't enable the link. */ | |
| 702 | + for (unsigned int i = 0; i < ARRAY_SIZE(group->remotes); i++) { | |
| 703 | + if (group->remotes[i].subdev) { | |
| 704 | + flags = 0; | |
| 705 | + break; | |
| 706 | + } | |
| 707 | + } | |
| 708 | + | |
| 709 | + /* Create links. */ | |
| 710 | + for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { | |
| 711 | + struct rvin_dev *vin = group->vin[i]; | |
| 712 | + struct media_entity *source; | |
| 713 | + struct media_entity *sink; | |
| 714 | + int ret; | |
| 715 | + | |
| 716 | + /* Nothing to do if there is no VIN or parallel subdev. */ | |
| 717 | + if (!vin || !vin->parallel.subdev) | |
| 718 | + continue; | |
| 719 | + | |
| 720 | + source = &vin->parallel.subdev->entity; | |
| 721 | + sink = &vin->vdev.entity; | |
| 722 | + | |
| 723 | + ret = media_create_pad_link(source, vin->parallel.source_pad, | |
| 724 | + sink, 0, flags); | |
| 725 | + if (ret) | |
| 726 | + return ret; | |
| 727 | + } | |
| 728 | + | |
| 729 | + return 0; | |
| 730 | +} | |
| 731 | + | |
| 732 | +static int rvin_csi2_setup_links(struct rvin_group *group) | |
| 913 | 733 | { |
| 914 | 734 | const struct rvin_group_route *route; |
| 915 | 735 | unsigned int id; |
| 916 | − int ret = -EINVAL; | |
| 736 | + int ret; | |
| 737 | + | |
| 738 | + ret = rvin_parallel_setup_links(group); | |
| 739 | + if (ret) | |
| 740 | + return ret; | |
| 917 | 741 | |
| 918 | 742 | /* Create all media device links between VINs and CSI-2's. */ |
| 919 | − mutex_lock(&vin->group->lock); | |
| 920 | − for (route = vin->info->routes; route->chsel; route++) { | |
| 743 | + mutex_lock(&group->lock); | |
| 744 | + for (route = group->info->routes; route->chsel; route++) { | |
| 921 | 745 | /* Check that VIN' master is part of the group. */ |
| 922 | − if (!vin->group->vin[route->master]) | |
| 746 | + if (!group->vin[route->master]) | |
| 923 | 747 | continue; |
| 924 | 748 | |
| 925 | 749 | /* Check that CSI-2 is part of the group. */ |
| 926 | − if (!vin->group->remotes[route->csi].subdev) | |
| 750 | + if (!group->remotes[route->csi].subdev) | |
| 927 | 751 | continue; |
| 928 | 752 | |
| 929 | 753 | for (id = route->master; id < route->master + 4; id++) { |
| 930 | 754 | /* Check that VIN is part of the group. */ |
| 931 | − if (!vin->group->vin[id]) | |
| 755 | + if (!group->vin[id]) | |
| 932 | 756 | continue; |
| 933 | 757 | |
| 934 | − ret = rvin_csi2_create_link(vin->group, id, route); | |
| 758 | + ret = rvin_csi2_create_link(group, id, route); | |
| 935 | 759 | if (ret) |
| 936 | 760 | goto out; |
| 937 | 761 | } |
| 938 | 762 | } |
| 939 | 763 | out: |
| 940 | − mutex_unlock(&vin->group->lock); | |
| 764 | + mutex_unlock(&group->lock); | |
| 941 | 765 | |
| 942 | 766 | return ret; |
| 943 | 767 | } |
| 944 | 768 | |
| 945 | −static void rvin_csi2_cleanup(struct rvin_dev *vin) | |
| 946 | −{ | |
| 947 | − rvin_parallel_cleanup(vin); | |
| 948 | − rvin_group_notifier_cleanup(vin); | |
| 949 | − rvin_group_put(vin); | |
| 950 | − rvin_free_controls(vin); | |
| 951 | −} | |
| 952 | − | |
| 953 | 769 | static int rvin_csi2_init(struct rvin_dev *vin) |
| 954 | 770 | { |
| 955 | 771 | int ret; |
| 956 | 772 | |
| 957 | − vin->pad.flags = MEDIA_PAD_FL_SINK; | |
| 958 | − ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); | |
| 959 | − if (ret) | |
| 960 | − return ret; | |
| 961 | − | |
| 962 | − ret = rvin_create_controls(vin, NULL); | |
| 963 | − if (ret < 0) | |
| 964 | − return ret; | |
| 965 | − | |
| 966 | 773 | ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_csi2_media_ops); |
| 967 | 774 | if (ret) |
| 968 | − goto err_controls; | |
| 969 | − | |
| 970 | − /* It's OK to not have a parallel subdevice. */ | |
| 971 | − ret = rvin_parallel_init(vin); | |
| 972 | − if (ret && ret != -ENODEV) | |
| 973 | − goto err_group; | |
| 775 | + return ret; | |
| 974 | 776 | |
| 975 | 777 | ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX); |
| 976 | 778 | if (ret) |
| 977 | − goto err_parallel; | |
| 978 | − | |
| 979 | − return 0; | |
| 980 | −err_parallel: | |
| 981 | − rvin_parallel_cleanup(vin); | |
| 982 | −err_group: | |
| 983 | − rvin_group_put(vin); | |
| 984 | −err_controls: | |
| 985 | − rvin_free_controls(vin); | |
| 779 | + rvin_group_put(vin); | |
| 986 | 780 | |
| 987 | 781 | return ret; |
| 988 | 782 | } |
| @@ -991,30 +785,31 @@ err_controls: · 2 unmodified lines | ||
| 991 | 785 | * ISP |
| 992 | 786 | */ |
| 993 | 787 | |
| 994 | −static int rvin_isp_setup_links(struct rvin_dev *vin) | |
| 788 | +static int rvin_isp_setup_links(struct rvin_group *group) | |
| 995 | 789 | { |
| 996 | 790 | unsigned int i; |
| 997 | 791 | int ret = -EINVAL; |
| 998 | 792 | |
| 999 | 793 | /* Create all media device links between VINs and ISP's. */ |
| 1000 | − mutex_lock(&vin->group->lock); | |
| 794 | + mutex_lock(&group->lock); | |
| 1001 | 795 | for (i = 0; i < RCAR_VIN_NUM; i++) { |
| 1002 | 796 | struct media_pad *source_pad, *sink_pad; |
| 1003 | 797 | struct media_entity *source, *sink; |
| 1004 | 798 | unsigned int source_slot = i / 8; |
| 1005 | 799 | unsigned int source_idx = i % 8 + 1; |
| 800 | + struct rvin_dev *vin = group->vin[i]; | |
| 1006 | 801 | |
| 1007 | − if (!vin->group->vin[i]) | |
| 802 | + if (!vin) | |
| 1008 | 803 | continue; |
| 1009 | 804 | |
| 1010 | 805 | /* Check that ISP is part of the group. */ |
| 1011 | − if (!vin->group->remotes[source_slot].subdev) | |
| 806 | + if (!group->remotes[source_slot].subdev) | |
| 1012 | 807 | continue; |
| 1013 | 808 | |
| 1014 | − source = &vin->group->remotes[source_slot].subdev->entity; | |
| 809 | + source = &group->remotes[source_slot].subdev->entity; | |
| 1015 | 810 | source_pad = &source->pads[source_idx]; |
| 1016 | 811 | |
| 1017 | − sink = &vin->group->vin[i]->vdev.entity; | |
| 812 | + sink = &vin->vdev.entity; | |
| 1018 | 813 | sink_pad = &sink->pads[0]; |
| 1019 | 814 | |
| 1020 | 815 | /* Skip if link already exists. */ |
| @@ -1030,44 +825,22 @@ static int rvin_isp_setup_links(struct rvin_dev *vin) · 9 unmodified lines | ||
| 1030 | 825 | break; |
| 1031 | 826 | } |
| 1032 | 827 | } |
| 1033 | − mutex_unlock(&vin->group->lock); | |
| 828 | + mutex_unlock(&group->lock); | |
| 1034 | 829 | |
| 1035 | 830 | return ret; |
| 1036 | 831 | } |
| 1037 | 832 | |
| 1038 | −static void rvin_isp_cleanup(struct rvin_dev *vin) | |
| 1039 | −{ | |
| 1040 | − rvin_group_notifier_cleanup(vin); | |
| 1041 | − rvin_group_put(vin); | |
| 1042 | − rvin_free_controls(vin); | |
| 1043 | −} | |
| 1044 | − | |
| 1045 | 833 | static int rvin_isp_init(struct rvin_dev *vin) |
| 1046 | 834 | { |
| 1047 | 835 | int ret; |
| 1048 | 836 | |
| 1049 | − vin->pad.flags = MEDIA_PAD_FL_SINK; | |
| 1050 | − ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); | |
| 1051 | − if (ret) | |
| 1052 | − return ret; | |
| 1053 | − | |
| 1054 | − ret = rvin_create_controls(vin, NULL); | |
| 1055 | − if (ret < 0) | |
| 1056 | − return ret; | |
| 1057 | − | |
| 1058 | 837 | ret = rvin_group_get(vin, rvin_isp_setup_links, NULL); |
| 1059 | 838 | if (ret) |
| 1060 | − goto err_controls; | |
| 839 | + return ret; | |
| 1061 | 840 | |
| 1062 | 841 | ret = rvin_group_notifier_init(vin, 2, RVIN_ISP_MAX); |
| 1063 | 842 | if (ret) |
| 1064 | − goto err_group; | |
| 1065 | − | |
| 1066 | − return 0; | |
| 1067 | −err_group: | |
| 1068 | − rvin_group_put(vin); | |
| 1069 | −err_controls: | |
| 1070 | − rvin_free_controls(vin); | |
| 843 | + rvin_group_put(vin); | |
| 1071 | 844 | |
| 1072 | 845 | return ret; |
| 1073 | 846 | } |
| @@ -1102,7 +875,7 @@ static int __maybe_unused rvin_resume(struct device *dev) · 28 unmodified lines | ||
| 1102 | 875 | * as we don't know if and in which order the master VINs will |
| 1103 | 876 | * be resumed. |
| 1104 | 877 | */ |
| 1105 | − if (vin->info->use_mc) { | |
| 878 | + if (vin->info->model == RCAR_GEN3) { | |
| 1106 | 879 | unsigned int master_id = rvin_group_id_to_master(vin->id); |
| 1107 | 880 | struct rvin_dev *master = vin->group->vin[master_id]; |
| 1108 | 881 | int ret; |
| @@ -1124,7 +897,6 @@ static int __maybe_unused rvin_resume(struct device *dev) · 15 unmodified lines | ||
| 1124 | 897 | |
| 1125 | 898 | static const struct rvin_info rcar_info_h1 = { |
| 1126 | 899 | .model = RCAR_H1, |
| 1127 | − .use_mc = false, | |
| 1128 | 900 | .max_width = 2048, |
| 1129 | 901 | .max_height = 2048, |
| 1130 | 902 | .scaler = rvin_scaler_gen2, |
| @@ -1132,7 +904,6 @@ static const struct rvin_info rcar_info_h1 = { · 1 unmodified line | ||
| 1132 | 904 | |
| 1133 | 905 | static const struct rvin_info rcar_info_m1 = { |
| 1134 | 906 | .model = RCAR_M1, |
| 1135 | − .use_mc = false, | |
| 1136 | 907 | .max_width = 2048, |
| 1137 | 908 | .max_height = 2048, |
| 1138 | 909 | .scaler = rvin_scaler_gen2, |
| @@ -1140,7 +911,6 @@ static const struct rvin_info rcar_info_m1 = { · 1 unmodified line | ||
| 1140 | 911 | |
| 1141 | 912 | static const struct rvin_info rcar_info_gen2 = { |
| 1142 | 913 | .model = RCAR_GEN2, |
| 1143 | − .use_mc = false, | |
| 1144 | 914 | .max_width = 2048, |
| 1145 | 915 | .max_height = 2048, |
| 1146 | 916 | .scaler = rvin_scaler_gen2, |
| @@ -1155,7 +925,6 @@ static const struct rvin_group_route rcar_info_r8a774e1_routes[] = { · 8 unmodified lines | ||
| 1155 | 925 | |
| 1156 | 926 | static const struct rvin_info rcar_info_r8a774e1 = { |
| 1157 | 927 | .model = RCAR_GEN3, |
| 1158 | − .use_mc = true, | |
| 1159 | 928 | .max_width = 4096, |
| 1160 | 929 | .max_height = 4096, |
| 1161 | 930 | .routes = rcar_info_r8a774e1_routes, |
| @@ -1171,7 +940,6 @@ static const struct rvin_group_route rcar_info_r8a7795_routes[] = { · 9 unmodified lines | ||
| 1171 | 940 | |
| 1172 | 941 | static const struct rvin_info rcar_info_r8a7795 = { |
| 1173 | 942 | .model = RCAR_GEN3, |
| 1174 | − .use_mc = true, | |
| 1175 | 943 | .nv12 = true, |
| 1176 | 944 | .max_width = 4096, |
| 1177 | 945 | .max_height = 4096, |
| @@ -1189,7 +957,6 @@ static const struct rvin_group_route rcar_info_r8a7796_routes[] = { · 11 unmodified lines | ||
| 1189 | 957 | |
| 1190 | 958 | static const struct rvin_info rcar_info_r8a7796 = { |
| 1191 | 959 | .model = RCAR_GEN3, |
| 1192 | − .use_mc = true, | |
| 1193 | 960 | .nv12 = true, |
| 1194 | 961 | .max_width = 4096, |
| 1195 | 962 | .max_height = 4096, |
| @@ -1207,7 +974,6 @@ static const struct rvin_group_route rcar_info_r8a77965_routes[] = { · 11 unmodified lines | ||
| 1207 | 974 | |
| 1208 | 975 | static const struct rvin_info rcar_info_r8a77965 = { |
| 1209 | 976 | .model = RCAR_GEN3, |
| 1210 | − .use_mc = true, | |
| 1211 | 977 | .nv12 = true, |
| 1212 | 978 | .max_width = 4096, |
| 1213 | 979 | .max_height = 4096, |
| @@ -1222,7 +988,6 @@ static const struct rvin_group_route rcar_info_r8a77970_routes[] = { · 8 unmodified lines | ||
| 1222 | 988 | |
| 1223 | 989 | static const struct rvin_info rcar_info_r8a77970 = { |
| 1224 | 990 | .model = RCAR_GEN3, |
| 1225 | − .use_mc = true, | |
| 1226 | 991 | .max_width = 4096, |
| 1227 | 992 | .max_height = 4096, |
| 1228 | 993 | .routes = rcar_info_r8a77970_routes, |
| @@ -1236,7 +1001,6 @@ static const struct rvin_group_route rcar_info_r8a77980_routes[] = { · 7 unmodified lines | ||
| 1236 | 1001 | |
| 1237 | 1002 | static const struct rvin_info rcar_info_r8a77980 = { |
| 1238 | 1003 | .model = RCAR_GEN3, |
| 1239 | − .use_mc = true, | |
| 1240 | 1004 | .nv12 = true, |
| 1241 | 1005 | .max_width = 4096, |
| 1242 | 1006 | .max_height = 4096, |
| @@ -1250,7 +1014,6 @@ static const struct rvin_group_route rcar_info_r8a77990_routes[] = { · 7 unmodified lines | ||
| 1250 | 1014 | |
| 1251 | 1015 | static const struct rvin_info rcar_info_r8a77990 = { |
| 1252 | 1016 | .model = RCAR_GEN3, |
| 1253 | − .use_mc = true, | |
| 1254 | 1017 | .nv12 = true, |
| 1255 | 1018 | .max_width = 4096, |
| 1256 | 1019 | .max_height = 4096, |
| @@ -1264,7 +1027,6 @@ static const struct rvin_group_route rcar_info_r8a77995_routes[] = { · 7 unmodified lines | ||
| 1264 | 1027 | |
| 1265 | 1028 | static const struct rvin_info rcar_info_r8a77995 = { |
| 1266 | 1029 | .model = RCAR_GEN3, |
| 1267 | − .use_mc = true, | |
| 1268 | 1030 | .nv12 = true, |
| 1269 | 1031 | .max_width = 4096, |
| 1270 | 1032 | .max_height = 4096, |
| @@ -1274,7 +1036,6 @@ static const struct rvin_info rcar_info_r8a77995 = { · 3 unmodified lines | ||
| 1274 | 1036 | |
| 1275 | 1037 | static const struct rvin_info rcar_info_gen4 = { |
| 1276 | 1038 | .model = RCAR_GEN4, |
| 1277 | − .use_mc = true, | |
| 1278 | 1039 | .use_isp = true, |
| 1279 | 1040 | .nv12 = true, |
| 1280 | 1041 | .raw10 = true, |
| @@ -1361,6 +1122,56 @@ static const struct of_device_id rvin_of_id_table[] = { · 80 unmodified lines | ||
| 1361 | 1122 | }; |
| 1362 | 1123 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); |
| 1363 | 1124 | |
| 1125 | +static int rvin_id_get(struct rvin_dev *vin) | |
| 1126 | +{ | |
| 1127 | + u32 oid; | |
| 1128 | + int id; | |
| 1129 | + | |
| 1130 | + switch (vin->info->model) { | |
| 1131 | + case RCAR_GEN3: | |
| 1132 | + case RCAR_GEN4: | |
| 1133 | + if (of_property_read_u32(vin->dev->of_node, "renesas,id", &oid)) { | |
| 1134 | + vin_err(vin, "%pOF: No renesas,id property found\n", | |
| 1135 | + vin->dev->of_node); | |
| 1136 | + return -EINVAL; | |
| 1137 | + } | |
| 1138 | + | |
| 1139 | + if (oid < 0 || oid >= RCAR_VIN_NUM) { | |
| 1140 | + vin_err(vin, "%pOF: Invalid renesas,id '%u'\n", | |
| 1141 | + vin->dev->of_node, oid); | |
| 1142 | + return -EINVAL; | |
| 1143 | + } | |
| 1144 | + | |
| 1145 | + vin->id = oid; | |
| 1146 | + break; | |
| 1147 | + default: | |
| 1148 | + id = ida_alloc_range(&rvin_ida, 0, RCAR_VIN_NUM - 1, | |
| 1149 | + GFP_KERNEL); | |
| 1150 | + if (id < 0) { | |
| 1151 | + vin_err(vin, "%pOF: Failed to allocate VIN group ID\n", | |
| 1152 | + vin->dev->of_node); | |
| 1153 | + return -EINVAL; | |
| 1154 | + } | |
| 1155 | + | |
| 1156 | + vin->id = id; | |
| 1157 | + break; | |
| 1158 | + } | |
| 1159 | + | |
| 1160 | + return 0; | |
| 1161 | +} | |
| 1162 | + | |
| 1163 | +static void rvin_id_put(struct rvin_dev *vin) | |
| 1164 | +{ | |
| 1165 | + switch (vin->info->model) { | |
| 1166 | + case RCAR_GEN3: | |
| 1167 | + case RCAR_GEN4: | |
| 1168 | + break; | |
| 1169 | + default: | |
| 1170 | + ida_free(&rvin_ida, vin->id); | |
| 1171 | + break; | |
| 1172 | + } | |
| 1173 | +} | |
| 1174 | + | |
| 1364 | 1175 | static int rcar_vin_probe(struct platform_device *pdev) |
| 1365 | 1176 | { |
| 1366 | 1177 | struct rvin_dev *vin; |
| @@ -1388,30 +1199,59 @@ static int rcar_vin_probe(struct platform_device *pdev) · 21 unmodified lines | ||
| 1388 | 1199 | |
| 1389 | 1200 | platform_set_drvdata(pdev, vin); |
| 1390 | 1201 | |
| 1391 | − if (vin->info->use_isp) { | |
| 1392 | − ret = rvin_isp_init(vin); | |
| 1393 | − } else if (vin->info->use_mc) { | |
| 1394 | − ret = rvin_csi2_init(vin); | |
| 1202 | + if (rvin_id_get(vin)) { | |
| 1203 | + ret = -EINVAL; | |
| 1204 | + goto err_dma; | |
| 1205 | + } | |
| 1395 | 1206 | |
| 1396 | − if (vin->info->scaler && | |
| 1397 | − rvin_group_id_to_master(vin->id) == vin->id) | |
| 1398 | − vin->scaler = vin->info->scaler; | |
| 1399 | − } else { | |
| 1400 | − ret = rvin_parallel_init(vin); | |
| 1207 | + vin->pad.flags = MEDIA_PAD_FL_SINK; | |
| 1208 | + ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); | |
| 1209 | + if (ret) | |
| 1210 | + goto err_id; | |
| 1211 | + | |
| 1212 | + ret = rvin_create_controls(vin); | |
| 1213 | + if (ret < 0) | |
| 1214 | + goto err_id; | |
| 1215 | + | |
| 1216 | + switch (vin->info->model) { | |
| 1217 | + case RCAR_GEN3: | |
| 1218 | + case RCAR_GEN4: | |
| 1219 | + if (vin->info->use_isp) { | |
| 1220 | + ret = rvin_isp_init(vin); | |
| 1221 | + } else { | |
| 1222 | + ret = rvin_csi2_init(vin); | |
| 1223 | + | |
| 1224 | + if (vin->info->scaler && | |
| 1225 | + rvin_group_id_to_master(vin->id) == vin->id) | |
| 1226 | + vin->scaler = vin->info->scaler; | |
| 1227 | + } | |
| 1228 | + break; | |
| 1229 | + default: | |
| 1230 | + ret = rvin_group_get(vin, rvin_parallel_setup_links, NULL); | |
| 1231 | + if (!ret) | |
| 1232 | + ret = rvin_group_notifier_init(vin, 0, 0); | |
| 1401 | 1233 | |
| 1402 | 1234 | if (vin->info->scaler) |
| 1403 | 1235 | vin->scaler = vin->info->scaler; |
| 1236 | + break; | |
| 1404 | 1237 | } |
| 1405 | 1238 | |
| 1406 | − if (ret) { | |
| 1407 | − rvin_dma_unregister(vin); | |
| 1408 | − return ret; | |
| 1409 | − } | |
| 1239 | + if (ret) | |
| 1240 | + goto err_ctrl; | |
| 1410 | 1241 | |
| 1411 | 1242 | pm_suspend_ignore_children(&pdev->dev, true); |
| 1412 | 1243 | pm_runtime_enable(&pdev->dev); |
| 1413 | 1244 | |
| 1414 | 1245 | return 0; |
| 1246 | + | |
| 1247 | +err_ctrl: | |
| 1248 | + rvin_free_controls(vin); | |
| 1249 | +err_id: | |
| 1250 | + rvin_id_put(vin); | |
| 1251 | +err_dma: | |
| 1252 | + rvin_dma_unregister(vin); | |
| 1253 | + | |
| 1254 | + return ret; | |
| 1415 | 1255 | } |
| 1416 | 1256 | |
| 1417 | 1257 | static void rcar_vin_remove(struct platform_device *pdev) |
| @@ -1422,12 +1262,16 @@ static void rcar_vin_remove(struct platform_device *pdev) · 4 unmodified lines | ||
| 1422 | 1262 | |
| 1423 | 1263 | rvin_v4l2_unregister(vin); |
| 1424 | 1264 | |
| 1425 | − if (vin->info->use_isp) | |
| 1426 | − rvin_isp_cleanup(vin); | |
| 1427 | − else if (vin->info->use_mc) | |
| 1428 | − rvin_csi2_cleanup(vin); | |
| 1429 | − else | |
| 1430 | − rvin_parallel_cleanup(vin); | |
| 1265 | + if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { | |
| 1266 | + v4l2_async_nf_unregister(&vin->group->notifier); | |
| 1267 | + v4l2_async_nf_cleanup(&vin->group->notifier); | |
| 1268 | + } | |
| 1269 | + | |
| 1270 | + rvin_group_put(vin); | |
| 1271 | + | |
| 1272 | + rvin_free_controls(vin); | |
| 1273 | + | |
| 1274 | + rvin_id_put(vin); | |
| 1431 | 1275 | |
| 1432 | 1276 | rvin_dma_unregister(vin); |
| 1433 | 1277 | } |
| @@ -2,18 +2,18 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Driver for Renesas R-Car VIN |
| 4 | 4 | * |
| 5 | + * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | |
| 5 | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | − * | |
| 10 | − * Based on the soc-camera rcar_vin driver | |
| 11 | 10 | */ |
| 12 | 11 | |
| 13 | 12 | #include <linux/delay.h> |
| 14 | 13 | #include <linux/interrupt.h> |
| 15 | 14 | #include <linux/pm_runtime.h> |
| 16 | 15 | |
| 16 | +#include <media/v4l2-event.h> | |
| 17 | 17 | #include <media/videobuf2-dma-contig.h> |
| 18 | 18 | |
| 19 | 19 | #include "rcar-vin.h" |
| @@ -115,11 +115,16 @@ · 95 unmodified lines | ||
| 115 | 115 | #define VNFC_S_FRAME (1 << 0) |
| 116 | 116 | |
| 117 | 117 | /* Video n Interrupt Enable Register bits */ |
| 118 | −#define VNIE_FIE (1 << 4) | |
| 119 | −#define VNIE_EFE (1 << 1) | |
| 118 | +#define VNIE_VFE BIT(17) | |
| 119 | +#define VNIE_VRE BIT(16) | |
| 120 | +#define VNIE_FIE BIT(4) | |
| 121 | +#define VNIE_EFE BIT(1) | |
| 120 | 122 | |
| 121 | 123 | /* Video n Interrupt Status Register bits */ |
| 122 | −#define VNINTS_FIS (1 << 4) | |
| 124 | +#define VNINTS_VFS BIT(17) | |
| 125 | +#define VNINTS_VRS BIT(16) | |
| 126 | +#define VNINTS_FIS BIT(4) | |
| 127 | +#define VNINTS_EFS BIT(1) | |
| 123 | 128 | |
| 124 | 129 | /* Video n Data Mode Register bits */ |
| 125 | 130 | #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) |
| @@ -555,17 +560,12 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) · 429 unmodified lines | ||
| 555 | 560 | |
| 556 | 561 | void rvin_scaler_gen2(struct rvin_dev *vin) |
| 557 | 562 | { |
| 558 | − unsigned int crop_height; | |
| 559 | 563 | u32 xs, ys; |
| 560 | 564 | |
| 561 | 565 | /* Set scaling coefficient */ |
| 562 | − crop_height = vin->crop.height; | |
| 563 | − if (V4L2_FIELD_HAS_BOTH(vin->format.field)) | |
| 564 | − crop_height *= 2; | |
| 565 | − | |
| 566 | 566 | ys = 0; |
| 567 | − if (crop_height != vin->compose.height) | |
| 568 | − ys = (4096 * crop_height) / vin->compose.height; | |
| 567 | + if (vin->crop.height != vin->compose.height) | |
| 568 | + ys = (4096 * vin->crop.height) / vin->compose.height; | |
| 569 | 569 | rvin_write(vin, ys, VNYS_REG); |
| 570 | 570 | |
| 571 | 571 | xs = 0; |
| @@ -700,9 +700,6 @@ static int rvin_setup(struct rvin_dev *vin) · 128 unmodified lines | ||
| 700 | 700 | case V4L2_FIELD_INTERLACED: |
| 701 | 701 | /* Default to TB */ |
| 702 | 702 | vnmc = VNMC_IM_FULL; |
| 703 | − /* Use BT if video standard can be read and is 60 Hz format */ | |
| 704 | − if (!vin->info->use_mc && vin->std & V4L2_STD_525_60) | |
| 705 | − vnmc = VNMC_IM_FULL | VNMC_FOC; | |
| 706 | 703 | break; |
| 707 | 704 | case V4L2_FIELD_INTERLACED_TB: |
| 708 | 705 | vnmc = VNMC_IM_FULL; |
| @@ -897,6 +894,8 @@ static int rvin_setup(struct rvin_dev *vin) · 188 unmodified lines | ||
| 897 | 894 | |
| 898 | 895 | /* Progressive or interlaced mode */ |
| 899 | 896 | interrupts = progressive ? VNIE_FIE : VNIE_EFE; |
| 897 | + /* Enable VSYNC Rising Edge Detection. */ | |
| 898 | + interrupts |= VNIE_VRE; | |
| 900 | 899 | |
| 901 | 900 | /* Ack interrupts */ |
| 902 | 901 | rvin_write(vin, interrupts, VNINTS_REG); |
| @@ -912,21 +911,6 @@ static int rvin_setup(struct rvin_dev *vin) · 9 unmodified lines | ||
| 912 | 911 | return 0; |
| 913 | 912 | } |
| 914 | 913 | |
| 915 | −static void rvin_disable_interrupts(struct rvin_dev *vin) | |
| 916 | −{ | |
| 917 | − rvin_write(vin, 0, VNIE_REG); | |
| 918 | −} | |
| 919 | − | |
| 920 | −static u32 rvin_get_interrupt_status(struct rvin_dev *vin) | |
| 921 | −{ | |
| 922 | − return rvin_read(vin, VNINTS_REG); | |
| 923 | −} | |
| 924 | − | |
| 925 | −static void rvin_ack_interrupt(struct rvin_dev *vin) | |
| 926 | −{ | |
| 927 | − rvin_write(vin, rvin_read(vin, VNINTS_REG), VNINTS_REG); | |
| 928 | −} | |
| 929 | − | |
| 930 | 914 | static bool rvin_capture_active(struct rvin_dev *vin) |
| 931 | 915 | { |
| 932 | 916 | return rvin_read(vin, VNMS_REG) & VNMS_CA; |
| @@ -1049,22 +1033,35 @@ static void rvin_capture_stop(struct rvin_dev *vin) · 116 unmodified lines | ||
| 1049 | 1033 | static irqreturn_t rvin_irq(int irq, void *data) |
| 1050 | 1034 | { |
| 1051 | 1035 | struct rvin_dev *vin = data; |
| 1052 | − u32 int_status, vnms; | |
| 1036 | + u32 capture, status, vnms; | |
| 1053 | 1037 | int slot; |
| 1054 | 1038 | unsigned int handled = 0; |
| 1055 | 1039 | unsigned long flags; |
| 1056 | 1040 | |
| 1057 | 1041 | spin_lock_irqsave(&vin->qlock, flags); |
| 1058 | 1042 | |
| 1059 | − int_status = rvin_get_interrupt_status(vin); | |
| 1060 | − if (!int_status) | |
| 1043 | + status = rvin_read(vin, VNINTS_REG); | |
| 1044 | + if (!status) | |
| 1061 | 1045 | goto done; |
| 1062 | 1046 | |
| 1063 | − rvin_ack_interrupt(vin); | |
| 1047 | + rvin_write(vin, status, VNINTS_REG); | |
| 1064 | 1048 | handled = 1; |
| 1065 | 1049 | |
| 1050 | + /* Signal Start of Frame. */ | |
| 1051 | + if (status & VNINTS_VRS) { | |
| 1052 | + struct v4l2_event event = { | |
| 1053 | + .type = V4L2_EVENT_FRAME_SYNC, | |
| 1054 | + .u.frame_sync.frame_sequence = vin->sequence, | |
| 1055 | + }; | |
| 1056 | + | |
| 1057 | + v4l2_event_queue(&vin->vdev, &event); | |
| 1058 | + } | |
| 1059 | + | |
| 1066 | 1060 | /* Nothing to do if nothing was captured. */ |
| 1067 | − if (!(int_status & VNINTS_FIS)) | |
| 1061 | + capture = vin->format.field == V4L2_FIELD_NONE || | |
| 1062 | + vin->format.field == V4L2_FIELD_ALTERNATE ? | |
| 1063 | + VNINTS_FIS : VNINTS_EFS; | |
| 1064 | + if (!(status & capture)) | |
| 1068 | 1065 | goto done; |
| 1069 | 1066 | |
| 1070 | 1067 | /* Nothing to do if not running. */ |
| @@ -1297,14 +1294,6 @@ static int rvin_set_stream(struct rvin_dev *vin, int on) · 226 unmodified lines | ||
| 1297 | 1294 | struct media_pad *pad; |
| 1298 | 1295 | int ret; |
| 1299 | 1296 | |
| 1300 | − /* No media controller used, simply pass operation to subdevice. */ | |
| 1301 | − if (!vin->info->use_mc) { | |
| 1302 | − ret = v4l2_subdev_call(vin->parallel.subdev, video, s_stream, | |
| 1303 | − on); | |
| 1304 | − | |
| 1305 | − return ret == -ENOIOCTLCMD ? 0 : ret; | |
| 1306 | − } | |
| 1307 | − | |
| 1308 | 1297 | pad = media_pad_remote_pad_first(&vin->pad); |
| 1309 | 1298 | if (!pad) |
| 1310 | 1299 | return -EPIPE; |
| @@ -1417,7 +1406,7 @@ void rvin_stop_streaming(struct rvin_dev *vin) · 106 unmodified lines | ||
| 1417 | 1406 | rvin_set_stream(vin, 0); |
| 1418 | 1407 | |
| 1419 | 1408 | /* disable interrupts */ |
| 1420 | − rvin_disable_interrupts(vin); | |
| 1409 | + rvin_write(vin, 0, VNIE_REG); | |
| 1421 | 1410 | |
| 1422 | 1411 | /* Return unprocessed buffers from hardware. */ |
| 1423 | 1412 | for (unsigned int i = 0; i < HW_BUFFER_NUM; i++) { |
| @@ -2,12 +2,11 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Driver for Renesas R-Car VIN |
| 4 | 4 | * |
| 5 | + * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | |
| 5 | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | − * | |
| 10 | − * Based on the soc-camera rcar_vin driver | |
| 11 | 10 | */ |
| 12 | 11 | |
| 13 | 12 | #include <linux/pm_runtime.h> |
| @@ -230,101 +229,6 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) · 216 unmodified lines | ||
| 230 | 229 | * V4L2 |
| 231 | 230 | */ |
| 232 | 231 | |
| 233 | −static int rvin_reset_format(struct rvin_dev *vin) | |
| 234 | −{ | |
| 235 | − struct v4l2_subdev_format fmt = { | |
| 236 | − .which = V4L2_SUBDEV_FORMAT_ACTIVE, | |
| 237 | − .pad = vin->parallel.source_pad, | |
| 238 | − }; | |
| 239 | − int ret; | |
| 240 | − | |
| 241 | − ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt); | |
| 242 | − if (ret) | |
| 243 | − return ret; | |
| 244 | − | |
| 245 | − v4l2_fill_pix_format(&vin->format, &fmt.format); | |
| 246 | − | |
| 247 | − vin->crop.top = 0; | |
| 248 | − vin->crop.left = 0; | |
| 249 | − vin->crop.width = vin->format.width; | |
| 250 | − vin->crop.height = vin->format.height; | |
| 251 | − | |
| 252 | − /* Make use of the hardware interlacer by default. */ | |
| 253 | − if (vin->format.field == V4L2_FIELD_ALTERNATE) { | |
| 254 | − vin->format.field = V4L2_FIELD_INTERLACED; | |
| 255 | − vin->format.height *= 2; | |
| 256 | − } | |
| 257 | − | |
| 258 | − rvin_format_align(vin, &vin->format); | |
| 259 | − | |
| 260 | − vin->compose.top = 0; | |
| 261 | − vin->compose.left = 0; | |
| 262 | − vin->compose.width = vin->format.width; | |
| 263 | − vin->compose.height = vin->format.height; | |
| 264 | − | |
| 265 | − return 0; | |
| 266 | −} | |
| 267 | − | |
| 268 | −static int rvin_try_format(struct rvin_dev *vin, u32 which, | |
| 269 | − struct v4l2_pix_format *pix, | |
| 270 | − struct v4l2_rect *src_rect) | |
| 271 | −{ | |
| 272 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 273 | − struct v4l2_subdev_state *sd_state; | |
| 274 | − static struct lock_class_key key; | |
| 275 | − struct v4l2_subdev_format format = { | |
| 276 | − .which = which, | |
| 277 | − .pad = vin->parallel.source_pad, | |
| 278 | − }; | |
| 279 | − enum v4l2_field field; | |
| 280 | − u32 width, height; | |
| 281 | − int ret; | |
| 282 | − | |
| 283 | − /* | |
| 284 | − * FIXME: Drop this call, drivers are not supposed to use | |
| 285 | − * __v4l2_subdev_state_alloc(). | |
| 286 | − */ | |
| 287 | − sd_state = __v4l2_subdev_state_alloc(sd, "rvin:state->lock", &key); | |
| 288 | − if (IS_ERR(sd_state)) | |
| 289 | − return PTR_ERR(sd_state); | |
| 290 | − | |
| 291 | − if (!rvin_format_from_pixel(vin, pix->pixelformat)) | |
| 292 | − pix->pixelformat = RVIN_DEFAULT_FORMAT; | |
| 293 | − | |
| 294 | − v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code); | |
| 295 | − | |
| 296 | − /* Allow the video device to override field and to scale */ | |
| 297 | − field = pix->field; | |
| 298 | − width = pix->width; | |
| 299 | − height = pix->height; | |
| 300 | − | |
| 301 | − ret = v4l2_subdev_call(sd, pad, set_fmt, sd_state, &format); | |
| 302 | − if (ret < 0 && ret != -ENOIOCTLCMD) | |
| 303 | − goto done; | |
| 304 | − ret = 0; | |
| 305 | − | |
| 306 | − v4l2_fill_pix_format(pix, &format.format); | |
| 307 | − | |
| 308 | − if (src_rect) { | |
| 309 | − src_rect->top = 0; | |
| 310 | − src_rect->left = 0; | |
| 311 | − src_rect->width = pix->width; | |
| 312 | − src_rect->height = pix->height; | |
| 313 | − } | |
| 314 | − | |
| 315 | − if (field != V4L2_FIELD_ANY) | |
| 316 | − pix->field = field; | |
| 317 | − | |
| 318 | − pix->width = width; | |
| 319 | − pix->height = height; | |
| 320 | − | |
| 321 | − rvin_format_align(vin, pix); | |
| 322 | −done: | |
| 323 | − __v4l2_subdev_state_free(sd_state); | |
| 324 | − | |
| 325 | − return ret; | |
| 326 | −} | |
| 327 | − | |
| 328 | 232 | static int rvin_querycap(struct file *file, void *priv, |
| 329 | 233 | struct v4l2_capability *cap) |
| 330 | 234 | { |
| @@ -333,42 +237,6 @@ static int rvin_querycap(struct file *file, void *priv, · 2 unmodified lines | ||
| 333 | 237 | return 0; |
| 334 | 238 | } |
| 335 | 239 | |
| 336 | −static int rvin_try_fmt_vid_cap(struct file *file, void *priv, | |
| 337 | − struct v4l2_format *f) | |
| 338 | −{ | |
| 339 | − struct rvin_dev *vin = video_drvdata(file); | |
| 340 | − | |
| 341 | − return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL); | |
| 342 | −} | |
| 343 | − | |
| 344 | −static int rvin_s_fmt_vid_cap(struct file *file, void *priv, | |
| 345 | − struct v4l2_format *f) | |
| 346 | −{ | |
| 347 | − struct rvin_dev *vin = video_drvdata(file); | |
| 348 | − struct v4l2_rect fmt_rect, src_rect; | |
| 349 | − int ret; | |
| 350 | − | |
| 351 | − if (vb2_is_busy(&vin->queue)) | |
| 352 | − return -EBUSY; | |
| 353 | − | |
| 354 | − ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, | |
| 355 | − &src_rect); | |
| 356 | − if (ret) | |
| 357 | − return ret; | |
| 358 | − | |
| 359 | − vin->format = f->fmt.pix; | |
| 360 | − | |
| 361 | − fmt_rect.top = 0; | |
| 362 | − fmt_rect.left = 0; | |
| 363 | − fmt_rect.width = vin->format.width; | |
| 364 | − fmt_rect.height = vin->format.height; | |
| 365 | − | |
| 366 | − v4l2_rect_map_inside(&vin->crop, &src_rect); | |
| 367 | − v4l2_rect_map_inside(&vin->compose, &fmt_rect); | |
| 368 | − | |
| 369 | − return 0; | |
| 370 | −} | |
| 371 | − | |
| 372 | 240 | static int rvin_g_fmt_vid_cap(struct file *file, void *priv, |
| 373 | 241 | struct v4l2_format *f) |
| 374 | 242 | { |
| @@ -465,6 +333,7 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, · 90 unmodified lines | ||
| 465 | 333 | |
| 466 | 334 | static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect) |
| 467 | 335 | { |
| 336 | + struct media_pad *pad = media_pad_remote_pad_first(&vin->pad); | |
| 468 | 337 | struct v4l2_subdev_format fmt = { |
| 469 | 338 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, |
| 470 | 339 | }; |
| @@ -472,18 +341,11 @@ static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect) · 1 unmodified line | ||
| 472 | 341 | unsigned int index; |
| 473 | 342 | int ret; |
| 474 | 343 | |
| 475 | − if (vin->info->use_mc) { | |
| 476 | − struct media_pad *pad = media_pad_remote_pad_first(&vin->pad); | |
| 477 | − | |
| 478 | − if (!pad) | |
| 479 | − return -EINVAL; | |
| 344 | + if (!pad) | |
| 345 | + return -EINVAL; | |
| 480 | 346 | |
| 481 | − sd = media_entity_to_v4l2_subdev(pad->entity); | |
| 482 | − index = pad->index; | |
| 483 | − } else { | |
| 484 | − sd = vin_to_source(vin); | |
| 485 | − index = vin->parallel.source_pad; | |
| 486 | − } | |
| 347 | + sd = media_entity_to_v4l2_subdev(pad->entity); | |
| 348 | + index = pad->index; | |
| 487 | 349 | |
| 488 | 350 | fmt.pad = index; |
| 489 | 351 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); |
| @@ -623,284 +485,18 @@ static int rvin_s_selection(struct file *file, void *fh, · 133 unmodified lines | ||
| 623 | 485 | return 0; |
| 624 | 486 | } |
| 625 | 487 | |
| 626 | −static int rvin_g_parm(struct file *file, void *priv, | |
| 627 | − struct v4l2_streamparm *parm) | |
| 628 | −{ | |
| 629 | − struct rvin_dev *vin = video_drvdata(file); | |
| 630 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 631 | − | |
| 632 | − return v4l2_g_parm_cap(&vin->vdev, sd, parm); | |
| 633 | −} | |
| 634 | − | |
| 635 | −static int rvin_s_parm(struct file *file, void *priv, | |
| 636 | − struct v4l2_streamparm *parm) | |
| 637 | −{ | |
| 638 | − struct rvin_dev *vin = video_drvdata(file); | |
| 639 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 640 | − | |
| 641 | − return v4l2_s_parm_cap(&vin->vdev, sd, parm); | |
| 642 | −} | |
| 643 | − | |
| 644 | −static int rvin_g_pixelaspect(struct file *file, void *priv, | |
| 645 | − int type, struct v4l2_fract *f) | |
| 646 | −{ | |
| 647 | − struct rvin_dev *vin = video_drvdata(file); | |
| 648 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 649 | − | |
| 650 | − if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
| 651 | − return -EINVAL; | |
| 652 | − | |
| 653 | − return v4l2_subdev_call(sd, video, g_pixelaspect, f); | |
| 654 | −} | |
| 655 | − | |
| 656 | −static int rvin_enum_input(struct file *file, void *priv, | |
| 657 | − struct v4l2_input *i) | |
| 658 | −{ | |
| 659 | − struct rvin_dev *vin = video_drvdata(file); | |
| 660 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 661 | − int ret; | |
| 662 | − | |
| 663 | − if (i->index != 0) | |
| 664 | − return -EINVAL; | |
| 665 | − | |
| 666 | − ret = v4l2_subdev_call(sd, video, g_input_status, &i->status); | |
| 667 | − if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | |
| 668 | − return ret; | |
| 669 | − | |
| 670 | − i->type = V4L2_INPUT_TYPE_CAMERA; | |
| 671 | − | |
| 672 | − if (v4l2_subdev_has_op(sd, pad, dv_timings_cap)) { | |
| 673 | − i->capabilities = V4L2_IN_CAP_DV_TIMINGS; | |
| 674 | − i->std = 0; | |
| 675 | − } else { | |
| 676 | − i->capabilities = V4L2_IN_CAP_STD; | |
| 677 | − i->std = vin->vdev.tvnorms; | |
| 678 | − } | |
| 679 | − | |
| 680 | − strscpy(i->name, "Camera", sizeof(i->name)); | |
| 681 | − | |
| 682 | − return 0; | |
| 683 | −} | |
| 684 | − | |
| 685 | −static int rvin_g_input(struct file *file, void *priv, unsigned int *i) | |
| 686 | −{ | |
| 687 | − *i = 0; | |
| 688 | − return 0; | |
| 689 | −} | |
| 690 | − | |
| 691 | −static int rvin_s_input(struct file *file, void *priv, unsigned int i) | |
| 692 | −{ | |
| 693 | − if (i > 0) | |
| 694 | − return -EINVAL; | |
| 695 | − return 0; | |
| 696 | −} | |
| 697 | − | |
| 698 | −static int rvin_querystd(struct file *file, void *priv, v4l2_std_id *a) | |
| 699 | −{ | |
| 700 | − struct rvin_dev *vin = video_drvdata(file); | |
| 701 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 702 | − | |
| 703 | − return v4l2_subdev_call(sd, video, querystd, a); | |
| 704 | −} | |
| 705 | − | |
| 706 | −static int rvin_s_std(struct file *file, void *priv, v4l2_std_id a) | |
| 707 | −{ | |
| 708 | − struct rvin_dev *vin = video_drvdata(file); | |
| 709 | − int ret; | |
| 710 | − | |
| 711 | − ret = v4l2_subdev_call(vin_to_source(vin), video, s_std, a); | |
| 712 | − if (ret < 0) | |
| 713 | − return ret; | |
| 714 | − | |
| 715 | − vin->std = a; | |
| 716 | − | |
| 717 | − /* Changing the standard will change the width/height */ | |
| 718 | − return rvin_reset_format(vin); | |
| 719 | −} | |
| 720 | − | |
| 721 | −static int rvin_g_std(struct file *file, void *priv, v4l2_std_id *a) | |
| 722 | −{ | |
| 723 | − struct rvin_dev *vin = video_drvdata(file); | |
| 724 | − | |
| 725 | − if (v4l2_subdev_has_op(vin_to_source(vin), pad, dv_timings_cap)) | |
| 726 | − return -ENOIOCTLCMD; | |
| 727 | − | |
| 728 | − *a = vin->std; | |
| 729 | − | |
| 730 | − return 0; | |
| 731 | −} | |
| 732 | − | |
| 733 | 488 | static int rvin_subscribe_event(struct v4l2_fh *fh, |
| 734 | 489 | const struct v4l2_event_subscription *sub) |
| 735 | 490 | { |
| 736 | 491 | switch (sub->type) { |
| 492 | + case V4L2_EVENT_FRAME_SYNC: | |
| 493 | + return v4l2_event_subscribe(fh, sub, 2, NULL); | |
| 737 | 494 | case V4L2_EVENT_SOURCE_CHANGE: |
| 738 | 495 | return v4l2_event_subscribe(fh, sub, 4, NULL); |
| 739 | 496 | } |
| 740 | 497 | return v4l2_ctrl_subscribe_event(fh, sub); |
| 741 | 498 | } |
| 742 | 499 | |
| 743 | −static int rvin_enum_dv_timings(struct file *file, void *priv_fh, | |
| 744 | − struct v4l2_enum_dv_timings *timings) | |
| 745 | −{ | |
| 746 | − struct rvin_dev *vin = video_drvdata(file); | |
| 747 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 748 | − int ret; | |
| 749 | − | |
| 750 | − if (timings->pad) | |
| 751 | − return -EINVAL; | |
| 752 | − | |
| 753 | − timings->pad = vin->parallel.sink_pad; | |
| 754 | − | |
| 755 | − ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); | |
| 756 | − | |
| 757 | − timings->pad = 0; | |
| 758 | − | |
| 759 | − return ret; | |
| 760 | −} | |
| 761 | − | |
| 762 | −static int rvin_s_dv_timings(struct file *file, void *priv_fh, | |
| 763 | − struct v4l2_dv_timings *timings) | |
| 764 | −{ | |
| 765 | − struct rvin_dev *vin = video_drvdata(file); | |
| 766 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 767 | − int ret; | |
| 768 | − | |
| 769 | − ret = v4l2_subdev_call(sd, pad, s_dv_timings, | |
| 770 | − vin->parallel.sink_pad, timings); | |
| 771 | − if (ret) | |
| 772 | − return ret; | |
| 773 | − | |
| 774 | − /* Changing the timings will change the width/height */ | |
| 775 | − return rvin_reset_format(vin); | |
| 776 | −} | |
| 777 | − | |
| 778 | −static int rvin_g_dv_timings(struct file *file, void *priv_fh, | |
| 779 | − struct v4l2_dv_timings *timings) | |
| 780 | −{ | |
| 781 | − struct rvin_dev *vin = video_drvdata(file); | |
| 782 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 783 | − | |
| 784 | − return v4l2_subdev_call(sd, pad, g_dv_timings, | |
| 785 | − vin->parallel.sink_pad, timings); | |
| 786 | −} | |
| 787 | − | |
| 788 | −static int rvin_query_dv_timings(struct file *file, void *priv_fh, | |
| 789 | − struct v4l2_dv_timings *timings) | |
| 790 | −{ | |
| 791 | − struct rvin_dev *vin = video_drvdata(file); | |
| 792 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 793 | − | |
| 794 | − return v4l2_subdev_call(sd, pad, query_dv_timings, | |
| 795 | − vin->parallel.sink_pad, timings); | |
| 796 | −} | |
| 797 | − | |
| 798 | −static int rvin_dv_timings_cap(struct file *file, void *priv_fh, | |
| 799 | − struct v4l2_dv_timings_cap *cap) | |
| 800 | −{ | |
| 801 | − struct rvin_dev *vin = video_drvdata(file); | |
| 802 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 803 | − int ret; | |
| 804 | − | |
| 805 | − if (cap->pad) | |
| 806 | − return -EINVAL; | |
| 807 | − | |
| 808 | − cap->pad = vin->parallel.sink_pad; | |
| 809 | − | |
| 810 | − ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); | |
| 811 | − | |
| 812 | − cap->pad = 0; | |
| 813 | − | |
| 814 | − return ret; | |
| 815 | −} | |
| 816 | − | |
| 817 | −static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) | |
| 818 | −{ | |
| 819 | − struct rvin_dev *vin = video_drvdata(file); | |
| 820 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 821 | − int ret; | |
| 822 | − | |
| 823 | − if (edid->pad) | |
| 824 | − return -EINVAL; | |
| 825 | − | |
| 826 | − edid->pad = vin->parallel.sink_pad; | |
| 827 | − | |
| 828 | − ret = v4l2_subdev_call(sd, pad, get_edid, edid); | |
| 829 | − | |
| 830 | − edid->pad = 0; | |
| 831 | − | |
| 832 | − return ret; | |
| 833 | −} | |
| 834 | − | |
| 835 | −static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) | |
| 836 | −{ | |
| 837 | − struct rvin_dev *vin = video_drvdata(file); | |
| 838 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 839 | − int ret; | |
| 840 | − | |
| 841 | − if (edid->pad) | |
| 842 | − return -EINVAL; | |
| 843 | − | |
| 844 | − edid->pad = vin->parallel.sink_pad; | |
| 845 | − | |
| 846 | − ret = v4l2_subdev_call(sd, pad, set_edid, edid); | |
| 847 | − | |
| 848 | − edid->pad = 0; | |
| 849 | − | |
| 850 | − return ret; | |
| 851 | −} | |
| 852 | − | |
| 853 | −static const struct v4l2_ioctl_ops rvin_ioctl_ops = { | |
| 854 | − .vidioc_querycap = rvin_querycap, | |
| 855 | − .vidioc_try_fmt_vid_cap = rvin_try_fmt_vid_cap, | |
| 856 | − .vidioc_g_fmt_vid_cap = rvin_g_fmt_vid_cap, | |
| 857 | − .vidioc_s_fmt_vid_cap = rvin_s_fmt_vid_cap, | |
| 858 | − .vidioc_enum_fmt_vid_cap = rvin_enum_fmt_vid_cap, | |
| 859 | − | |
| 860 | − .vidioc_g_selection = rvin_g_selection, | |
| 861 | − .vidioc_s_selection = rvin_s_selection, | |
| 862 | − | |
| 863 | − .vidioc_g_parm = rvin_g_parm, | |
| 864 | − .vidioc_s_parm = rvin_s_parm, | |
| 865 | − | |
| 866 | − .vidioc_g_pixelaspect = rvin_g_pixelaspect, | |
| 867 | − | |
| 868 | − .vidioc_enum_input = rvin_enum_input, | |
| 869 | − .vidioc_g_input = rvin_g_input, | |
| 870 | − .vidioc_s_input = rvin_s_input, | |
| 871 | − | |
| 872 | − .vidioc_dv_timings_cap = rvin_dv_timings_cap, | |
| 873 | − .vidioc_enum_dv_timings = rvin_enum_dv_timings, | |
| 874 | − .vidioc_g_dv_timings = rvin_g_dv_timings, | |
| 875 | − .vidioc_s_dv_timings = rvin_s_dv_timings, | |
| 876 | − .vidioc_query_dv_timings = rvin_query_dv_timings, | |
| 877 | − | |
| 878 | − .vidioc_g_edid = rvin_g_edid, | |
| 879 | − .vidioc_s_edid = rvin_s_edid, | |
| 880 | − | |
| 881 | − .vidioc_querystd = rvin_querystd, | |
| 882 | − .vidioc_g_std = rvin_g_std, | |
| 883 | − .vidioc_s_std = rvin_s_std, | |
| 884 | − | |
| 885 | − .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
| 886 | − .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
| 887 | − .vidioc_querybuf = vb2_ioctl_querybuf, | |
| 888 | − .vidioc_qbuf = vb2_ioctl_qbuf, | |
| 889 | − .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
| 890 | − .vidioc_expbuf = vb2_ioctl_expbuf, | |
| 891 | − .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
| 892 | − .vidioc_streamon = vb2_ioctl_streamon, | |
| 893 | − .vidioc_streamoff = vb2_ioctl_streamoff, | |
| 894 | − | |
| 895 | − .vidioc_log_status = v4l2_ctrl_log_status, | |
| 896 | − .vidioc_subscribe_event = rvin_subscribe_event, | |
| 897 | − .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
| 898 | −}; | |
| 899 | − | |
| 900 | −/* ----------------------------------------------------------------------------- | |
| 901 | − * V4L2 Media Controller | |
| 902 | − */ | |
| 903 | − | |
| 904 | 500 | static void rvin_mc_try_format(struct rvin_dev *vin, |
| 905 | 501 | struct v4l2_pix_format *pix) |
| 906 | 502 | { |
| @@ -979,19 +575,6 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { · 72 unmodified lines | ||
| 979 | 575 | * File Operations |
| 980 | 576 | */ |
| 981 | 577 | |
| 982 | −static int rvin_power_parallel(struct rvin_dev *vin, bool on) | |
| 983 | −{ | |
| 984 | − struct v4l2_subdev *sd = vin_to_source(vin); | |
| 985 | − int power = on ? 1 : 0; | |
| 986 | − int ret; | |
| 987 | − | |
| 988 | − ret = v4l2_subdev_call(sd, core, s_power, power); | |
| 989 | − if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) | |
| 990 | − return ret; | |
| 991 | − | |
| 992 | − return 0; | |
| 993 | −} | |
| 994 | − | |
| 995 | 578 | static int rvin_open(struct file *file) |
| 996 | 579 | { |
| 997 | 580 | struct rvin_dev *vin = video_drvdata(file); |
| @@ -1011,11 +594,7 @@ static int rvin_open(struct file *file) · 13 unmodified lines | ||
| 1011 | 594 | if (ret) |
| 1012 | 595 | goto err_unlock; |
| 1013 | 596 | |
| 1014 | − if (vin->info->use_mc) | |
| 1015 | − ret = v4l2_pipeline_pm_get(&vin->vdev.entity); | |
| 1016 | − else if (v4l2_fh_is_singular_file(file)) | |
| 1017 | − ret = rvin_power_parallel(vin, true); | |
| 1018 | − | |
| 597 | + ret = v4l2_pipeline_pm_get(&vin->vdev.entity); | |
| 1019 | 598 | if (ret < 0) |
| 1020 | 599 | goto err_open; |
| 1021 | 600 | |
| @@ -1027,10 +606,7 @@ static int rvin_open(struct file *file) · 5 unmodified lines | ||
| 1027 | 606 | |
| 1028 | 607 | return 0; |
| 1029 | 608 | err_power: |
| 1030 | − if (vin->info->use_mc) | |
| 1031 | − v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 1032 | − else if (v4l2_fh_is_singular_file(file)) | |
| 1033 | − rvin_power_parallel(vin, false); | |
| 609 | + v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 1034 | 610 | err_open: |
| 1035 | 611 | v4l2_fh_release(file); |
| 1036 | 612 | err_unlock: |
| @@ -1044,23 +620,14 @@ err_pm: · 7 unmodified lines | ||
| 1044 | 620 | static int rvin_release(struct file *file) |
| 1045 | 621 | { |
| 1046 | 622 | struct rvin_dev *vin = video_drvdata(file); |
| 1047 | − bool fh_singular; | |
| 1048 | 623 | int ret; |
| 1049 | 624 | |
| 1050 | 625 | mutex_lock(&vin->lock); |
| 1051 | 626 | |
| 1052 | − /* Save the singular status before we call the clean-up helper */ | |
| 1053 | − fh_singular = v4l2_fh_is_singular_file(file); | |
| 1054 | − | |
| 1055 | 627 | /* the release helper will cleanup any on-going streaming */ |
| 1056 | 628 | ret = _vb2_fop_release(file, NULL); |
| 1057 | 629 | |
| 1058 | − if (vin->info->use_mc) { | |
| 1059 | − v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 1060 | − } else { | |
| 1061 | − if (fh_singular) | |
| 1062 | − rvin_power_parallel(vin, false); | |
| 1063 | − } | |
| 630 | + v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 1064 | 631 | |
| 1065 | 632 | mutex_unlock(&vin->lock); |
| 1066 | 633 | |
| @@ -1091,18 +658,6 @@ void rvin_v4l2_unregister(struct rvin_dev *vin) · 24 unmodified lines | ||
| 1091 | 658 | video_unregister_device(&vin->vdev); |
| 1092 | 659 | } |
| 1093 | 660 | |
| 1094 | −static void rvin_notify_video_device(struct rvin_dev *vin, | |
| 1095 | − unsigned int notification, void *arg) | |
| 1096 | −{ | |
| 1097 | − switch (notification) { | |
| 1098 | − case V4L2_DEVICE_NOTIFY_EVENT: | |
| 1099 | − v4l2_event_queue(&vin->vdev, arg); | |
| 1100 | − break; | |
| 1101 | − default: | |
| 1102 | − break; | |
| 1103 | − } | |
| 1104 | −} | |
| 1105 | − | |
| 1106 | 661 | static void rvin_notify(struct v4l2_subdev *sd, |
| 1107 | 662 | unsigned int notification, void *arg) |
| 1108 | 663 | { |
| @@ -1113,12 +668,6 @@ static void rvin_notify(struct v4l2_subdev *sd, · 4 unmodified lines | ||
| 1113 | 668 | container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); |
| 1114 | 669 | unsigned int i; |
| 1115 | 670 | |
| 1116 | − /* If no media controller, no need to route the event. */ | |
| 1117 | − if (!vin->info->use_mc) { | |
| 1118 | − rvin_notify_video_device(vin, notification, arg); | |
| 1119 | − return; | |
| 1120 | − } | |
| 1121 | − | |
| 1122 | 671 | group = vin->group; |
| 1123 | 672 | |
| 1124 | 673 | for (i = 0; i < RCAR_VIN_NUM; i++) { |
| @@ -1134,7 +683,13 @@ static void rvin_notify(struct v4l2_subdev *sd, · 9 unmodified lines | ||
| 1134 | 683 | if (remote != sd) |
| 1135 | 684 | continue; |
| 1136 | 685 | |
| 1137 | − rvin_notify_video_device(vin, notification, arg); | |
| 686 | + switch (notification) { | |
| 687 | + case V4L2_DEVICE_NOTIFY_EVENT: | |
| 688 | + v4l2_event_queue(&vin->vdev, arg); | |
| 689 | + break; | |
| 690 | + default: | |
| 691 | + break; | |
| 692 | + } | |
| 1138 | 693 | } |
| 1139 | 694 | } |
| 1140 | 695 | |
| @@ -1153,7 +708,8 @@ int rvin_v4l2_register(struct rvin_dev *vin) · 12 unmodified lines | ||
| 1153 | 708 | vdev->lock = &vin->lock; |
| 1154 | 709 | vdev->fops = &rvin_fops; |
| 1155 | 710 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
| 1156 | − V4L2_CAP_READWRITE; | |
| 711 | + V4L2_CAP_READWRITE | V4L2_CAP_IO_MC; | |
| 712 | + vdev->ioctl_ops = &rvin_mc_ioctl_ops; | |
| 1157 | 713 | |
| 1158 | 714 | /* Set a default format */ |
| 1159 | 715 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; |
| @@ -1162,14 +718,6 @@ int rvin_v4l2_register(struct rvin_dev *vin) · 2 unmodified lines | ||
| 1162 | 718 | vin->format.field = RVIN_DEFAULT_FIELD; |
| 1163 | 719 | vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; |
| 1164 | 720 | |
| 1165 | − if (vin->info->use_mc) { | |
| 1166 | − vdev->device_caps |= V4L2_CAP_IO_MC; | |
| 1167 | − vdev->ioctl_ops = &rvin_mc_ioctl_ops; | |
| 1168 | − } else { | |
| 1169 | − vdev->ioctl_ops = &rvin_ioctl_ops; | |
| 1170 | − rvin_reset_format(vin); | |
| 1171 | − } | |
| 1172 | − | |
| 1173 | 721 | rvin_format_align(vin, &vin->format); |
| 1174 | 722 | |
| 1175 | 723 | ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); |
| @@ -2,12 +2,11 @@ · 1 unmodified line | ||
| 2 | 2 | /* |
| 3 | 3 | * Driver for Renesas R-Car VIN |
| 4 | 4 | * |
| 5 | + * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | |
| 5 | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | − * | |
| 10 | − * Based on the soc-camera rcar_vin driver | |
| 11 | 10 | */ |
| 12 | 11 | |
| 13 | 12 | #ifndef __RCAR_VIN__ |
| @@ -79,8 +78,6 @@ struct rvin_video_format { · 65 unmodified lines | ||
| 79 | 78 | * @mbus_type: media bus type |
| 80 | 79 | * @bus: media bus parallel configuration |
| 81 | 80 | * @source_pad: source pad of remote subdevice |
| 82 | − * @sink_pad: sink pad of remote subdevice | |
| 83 | − * | |
| 84 | 81 | */ |
| 85 | 82 | struct rvin_parallel_entity { |
| 86 | 83 | struct v4l2_async_connection *asc; |
| @@ -90,7 +87,6 @@ struct rvin_parallel_entity { · 3 unmodified lines | ||
| 90 | 87 | struct v4l2_mbus_config_parallel bus; |
| 91 | 88 | |
| 92 | 89 | unsigned int source_pad; |
| 93 | − unsigned int sink_pad; | |
| 94 | 90 | }; |
| 95 | 91 | |
| 96 | 92 | /** |
| @@ -117,7 +113,6 @@ struct rvin_group_route { · 20 unmodified lines | ||
| 117 | 113 | /** |
| 118 | 114 | * struct rvin_info - Information about the particular VIN implementation |
| 119 | 115 | * @model: VIN model |
| 120 | − * @use_mc: use media controller instead of controlling subdevice | |
| 121 | 116 | * @use_isp: the VIN is connected to the ISP and not to the CSI-2 |
| 122 | 117 | * @nv12: support outputting NV12 pixel format |
| 123 | 118 | * @raw10: support outputting RAW10 pixel format |
| @@ -129,7 +124,6 @@ struct rvin_group_route { · 5 unmodified lines | ||
| 129 | 124 | */ |
| 130 | 125 | struct rvin_info { |
| 131 | 126 | enum model_id model; |
| 132 | − bool use_mc; | |
| 133 | 127 | bool use_isp; |
| 134 | 128 | bool nv12; |
| 135 | 129 | bool raw10; |
| @@ -149,7 +143,6 @@ struct rvin_info { · 13 unmodified lines | ||
| 149 | 143 | * @vdev: V4L2 video device associated with VIN |
| 150 | 144 | * @v4l2_dev: V4L2 device |
| 151 | 145 | * @ctrl_handler: V4L2 control handler |
| 152 | − * @notifier: V4L2 asynchronous subdevs notifier | |
| 153 | 146 | * |
| 154 | 147 | * @parallel: parallel input subdevice descriptor |
| 155 | 148 | * |
| @@ -177,7 +170,6 @@ struct rvin_info { · 21 unmodified lines | ||
| 177 | 170 | * @crop: active cropping |
| 178 | 171 | * @compose: active composing |
| 179 | 172 | * @scaler: Optional scaler |
| 180 | − * @std: active video standard of the video source | |
| 181 | 173 | * |
| 182 | 174 | * @alpha: Alpha component to fill in for supported pixel formats |
| 183 | 175 | */ |
| @@ -189,7 +181,6 @@ struct rvin_dev { · 5 unmodified lines | ||
| 189 | 181 | struct video_device vdev; |
| 190 | 182 | struct v4l2_device v4l2_dev; |
| 191 | 183 | struct v4l2_ctrl_handler ctrl_handler; |
| 192 | − struct v4l2_async_notifier notifier; | |
| 193 | 184 | |
| 194 | 185 | struct rvin_parallel_entity parallel; |
| 195 | 186 | |
| @@ -220,7 +211,6 @@ struct rvin_dev { · 24 unmodified lines | ||
| 220 | 211 | struct v4l2_rect crop; |
| 221 | 212 | struct v4l2_rect compose; |
| 222 | 213 | void (*scaler)(struct rvin_dev *vin); |
| 223 | − v4l2_std_id std; | |
| 224 | 214 | |
| 225 | 215 | unsigned int alpha; |
| 226 | 216 | }; |
| @@ -242,6 +232,7 @@ struct rvin_dev { · 15 unmodified lines | ||
| 242 | 232 | * @lock: protects the count, notifier, vin and csi members |
| 243 | 233 | * @count: number of enabled VIN instances found in DT |
| 244 | 234 | * @notifier: group notifier for CSI-2 async connections |
| 235 | + * @info: Platform dependent information about the VIN instances | |
| 245 | 236 | * @vin: VIN instances which are part of the group |
| 246 | 237 | * @link_setup: Callback to create all links for the media graph |
| 247 | 238 | * @remotes: array of pairs of async connection and subdev pointers |
| @@ -255,9 +246,10 @@ struct rvin_group { · 7 unmodified lines | ||
| 255 | 246 | struct mutex lock; |
| 256 | 247 | unsigned int count; |
| 257 | 248 | struct v4l2_async_notifier notifier; |
| 249 | + const struct rvin_info *info; | |
| 258 | 250 | struct rvin_dev *vin[RCAR_VIN_NUM]; |
| 259 | 251 | |
| 260 | − int (*link_setup)(struct rvin_dev *vin); | |
| 252 | + int (*link_setup)(struct rvin_group *group); | |
| 261 | 253 | |
| 262 | 254 | struct { |
| 263 | 255 | struct v4l2_async_connection *asc; |
| @@ -366,7 +366,7 @@ static const struct rzg2l_cru_info rzg3e_cru_info = { · 365 unmodified lines | ||
| 366 | 366 | .irq_handler = rzg3e_cru_irq, |
| 367 | 367 | .enable_interrupts = rzg3e_cru_enable_interrupts, |
| 368 | 368 | .disable_interrupts = rzg3e_cru_disable_interrupts, |
| 369 | − .fifo_empty = rz3e_fifo_empty, | |
| 369 | + .fifo_empty = rzg3e_fifo_empty, | |
| 370 | 370 | .csi_setup = rzg3e_cru_csi2_setup, |
| 371 | 371 | }; |
| 372 | 372 | |
| @@ -403,7 +403,7 @@ static const u16 rzg2l_cru_regs[] = { · 30 unmodified lines | ||
| 403 | 403 | [ICnDMR] = 0x26c, |
| 404 | 404 | }; |
| 405 | 405 | |
| 406 | −static const struct rzg2l_cru_info rzgl2_cru_info = { | |
| 406 | +static const struct rzg2l_cru_info rzg2l_cru_info = { | |
| 407 | 407 | .max_width = 2800, |
| 408 | 408 | .max_height = 4095, |
| 409 | 409 | .image_conv = ICnMC, |
| @@ -422,7 +422,7 @@ static const struct of_device_id rzg2l_cru_of_id_table[] = { · 12 unmodified lines | ||
| 422 | 422 | }, |
| 423 | 423 | { |
| 424 | 424 | .compatible = "renesas,rzg2l-cru", |
| 425 | − .data = &rzgl2_cru_info, | |
| 425 | + .data = &rzg2l_cru_info, | |
| 426 | 426 | }, |
| 427 | 427 | { /* sentinel */ } |
| 428 | 428 | }; |
| @@ -64,19 +64,21 @@ struct rzg2l_cru_ip { · 63 unmodified lines | ||
| 64 | 64 | |
| 65 | 65 | /** |
| 66 | 66 | * struct rzg2l_cru_ip_format - CRU IP format |
| 67 | − * @code: Media bus code | |
| 67 | + * @codes: Array of up to four media bus codes | |
| 68 | 68 | * @datatype: MIPI CSI2 data type |
| 69 | 69 | * @format: 4CC format identifier (V4L2_PIX_FMT_*) |
| 70 | 70 | * @icndmr: ICnDMR register value |
| 71 | − * @bpp: bytes per pixel | |
| 72 | 71 | * @yuv: Flag to indicate whether the format is YUV-based. |
| 73 | 72 | */ |
| 74 | 73 | struct rzg2l_cru_ip_format { |
| 75 | − u32 code; | |
| 74 | + /* | |
| 75 | + * RAW output formats might be produced by RAW media codes with any one | |
| 76 | + * of the 4 common bayer patterns. | |
| 77 | + */ | |
| 78 | + u32 codes[4]; | |
| 76 | 79 | u32 datatype; |
| 77 | 80 | u32 format; |
| 78 | 81 | u32 icndmr; |
| 79 | − u8 bpp; | |
| 80 | 82 | bool yuv; |
| 81 | 83 | }; |
| 82 | 84 | |
| @@ -192,6 +194,8 @@ struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru); · 109 unmodified lines | ||
| 192 | 194 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code); |
| 193 | 195 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format); |
| 194 | 196 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index); |
| 197 | +bool rzg2l_cru_ip_fmt_supports_mbus_code(const struct rzg2l_cru_ip_format *fmt, | |
| 198 | + unsigned int code); | |
| 195 | 199 | |
| 196 | 200 | void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru); |
| 197 | 201 | void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru); |
| @@ -199,7 +203,7 @@ void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru); · 1 unmodified line | ||
| 199 | 203 | void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru); |
| 200 | 204 | |
| 201 | 205 | bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru); |
| 202 | −bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru); | |
| 206 | +bool rzg3e_fifo_empty(struct rzg2l_cru_dev *cru); | |
| 203 | 207 | void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, |
| 204 | 208 | const struct rzg2l_cru_ip_format *ip_fmt, |
| 205 | 209 | u8 csi_vc); |
| @@ -232,6 +232,18 @@ static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = { · 231 unmodified lines | ||
| 232 | 232 | { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, |
| 233 | 233 | { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, |
| 234 | 234 | { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, |
| 235 | + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, | |
| 236 | + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, | |
| 237 | + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, | |
| 238 | + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, | |
| 239 | + { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, }, | |
| 240 | + { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, }, | |
| 241 | + { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, }, | |
| 242 | + { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, }, | |
| 243 | + { .code = MEDIA_BUS_FMT_SBGGR14_1X14, .bpp = 14, }, | |
| 244 | + { .code = MEDIA_BUS_FMT_SGBRG14_1X14, .bpp = 14, }, | |
| 245 | + { .code = MEDIA_BUS_FMT_SGRBG14_1X14, .bpp = 14, }, | |
| 246 | + { .code = MEDIA_BUS_FMT_SRGGB14_1X14, .bpp = 14, }, | |
| 235 | 247 | }; |
| 236 | 248 | |
| 237 | 249 | static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd) |
| @@ -282,15 +294,18 @@ static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2) · 44 unmodified lines | ||
| 282 | 294 | const struct rzg2l_csi2_format *format; |
| 283 | 295 | const struct v4l2_mbus_framefmt *fmt; |
| 284 | 296 | struct v4l2_subdev_state *state; |
| 285 | − struct v4l2_ctrl *ctrl; | |
| 297 | + struct media_pad *remote_pad; | |
| 286 | 298 | u64 mbps; |
| 299 | + s64 ret; | |
| 287 | 300 | |
| 288 | − /* Read the pixel rate control from remote. */ | |
| 289 | − ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); | |
| 290 | − if (!ctrl) { | |
| 291 | − dev_err(csi2->dev, "no pixel rate control in subdev %s\n", | |
| 292 | − source->name); | |
| 293 | − return -EINVAL; | |
| 301 | + if (!csi2->remote_source) | |
| 302 | + return -ENODEV; | |
| 303 | + | |
| 304 | + remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]); | |
| 305 | + if (IS_ERR(remote_pad)) { | |
| 306 | + dev_err(csi2->dev, "can't get source pad of %s (%ld)\n", | |
| 307 | + csi2->remote_source->name, PTR_ERR(remote_pad)); | |
| 308 | + return PTR_ERR(remote_pad); | |
| 294 | 309 | } |
| 295 | 310 | |
| 296 | 311 | state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev); |
| @@ -298,12 +313,16 @@ static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2) · 1 unmodified line | ||
| 298 | 313 | format = rzg2l_csi2_code_to_fmt(fmt->code); |
| 299 | 314 | v4l2_subdev_unlock_state(state); |
| 300 | 315 | |
| 301 | − /* | |
| 302 | − * Calculate hsfreq in Mbps | |
| 303 | − * hsfreq = (pixel_rate * bits_per_sample) / number_of_lanes | |
| 304 | − */ | |
| 305 | − mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * format->bpp; | |
| 306 | − do_div(mbps, csi2->lanes * 1000000); | |
| 316 | + /* Read the link frequency from remote subdevice. */ | |
| 317 | + ret = v4l2_get_link_freq(remote_pad, format->bpp, csi2->lanes * 2); | |
| 318 | + if (ret < 0) { | |
| 319 | + dev_err(csi2->dev, "can't retrieve link freq from subdev %s\n", | |
| 320 | + source->name); | |
| 321 | + return -EINVAL; | |
| 322 | + } | |
| 323 | + | |
| 324 | + mbps = ret * 2; | |
| 325 | + do_div(mbps, 1000000); | |
| 307 | 326 | |
| 308 | 327 | return mbps; |
| 309 | 328 | } |
| @@ -13,42 +13,83 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = { |
| 15 | 15 | { |
| 16 | − .code = MEDIA_BUS_FMT_UYVY8_1X16, | |
| 16 | + .codes = { | |
| 17 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 18 | + }, | |
| 17 | 19 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 18 | 20 | .format = V4L2_PIX_FMT_UYVY, |
| 19 | − .bpp = 2, | |
| 20 | 21 | .icndmr = ICnDMR_YCMODE_UYVY, |
| 21 | 22 | .yuv = true, |
| 22 | 23 | }, |
| 23 | 24 | { |
| 24 | − .code = MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 25 | + .codes = { | |
| 26 | + MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 27 | + }, | |
| 25 | 28 | .format = V4L2_PIX_FMT_SBGGR8, |
| 26 | 29 | .datatype = MIPI_CSI2_DT_RAW8, |
| 27 | − .bpp = 1, | |
| 28 | 30 | .icndmr = 0, |
| 29 | 31 | .yuv = false, |
| 30 | 32 | }, |
| 31 | 33 | { |
| 32 | − .code = MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 34 | + .codes = { | |
| 35 | + MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 36 | + }, | |
| 33 | 37 | .format = V4L2_PIX_FMT_SGBRG8, |
| 34 | 38 | .datatype = MIPI_CSI2_DT_RAW8, |
| 35 | − .bpp = 1, | |
| 36 | 39 | .icndmr = 0, |
| 37 | 40 | .yuv = false, |
| 38 | 41 | }, |
| 39 | 42 | { |
| 40 | − .code = MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 43 | + .codes = { | |
| 44 | + MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 45 | + }, | |
| 41 | 46 | .format = V4L2_PIX_FMT_SGRBG8, |
| 42 | 47 | .datatype = MIPI_CSI2_DT_RAW8, |
| 43 | − .bpp = 1, | |
| 44 | 48 | .icndmr = 0, |
| 45 | 49 | .yuv = false, |
| 46 | 50 | }, |
| 47 | 51 | { |
| 48 | − .code = MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 52 | + .codes = { | |
| 53 | + MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 54 | + }, | |
| 49 | 55 | .format = V4L2_PIX_FMT_SRGGB8, |
| 50 | 56 | .datatype = MIPI_CSI2_DT_RAW8, |
| 51 | − .bpp = 1, | |
| 57 | + .icndmr = 0, | |
| 58 | + .yuv = false, | |
| 59 | + }, | |
| 60 | + { | |
| 61 | + .codes = { | |
| 62 | + MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 63 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 64 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 65 | + MEDIA_BUS_FMT_SRGGB10_1X10 | |
| 66 | + }, | |
| 67 | + .format = V4L2_PIX_FMT_RAW_CRU10, | |
| 68 | + .datatype = MIPI_CSI2_DT_RAW10, | |
| 69 | + .icndmr = 0, | |
| 70 | + .yuv = false, | |
| 71 | + }, | |
| 72 | + { | |
| 73 | + .codes = { | |
| 74 | + MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 75 | + MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 76 | + MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 77 | + MEDIA_BUS_FMT_SRGGB12_1X12 | |
| 78 | + }, | |
| 79 | + .format = V4L2_PIX_FMT_RAW_CRU12, | |
| 80 | + .datatype = MIPI_CSI2_DT_RAW12, | |
| 81 | + .icndmr = 0, | |
| 82 | + .yuv = false, | |
| 83 | + }, | |
| 84 | + { | |
| 85 | + .codes = { | |
| 86 | + MEDIA_BUS_FMT_SBGGR14_1X14, | |
| 87 | + MEDIA_BUS_FMT_SGBRG14_1X14, | |
| 88 | + MEDIA_BUS_FMT_SGRBG14_1X14, | |
| 89 | + MEDIA_BUS_FMT_SRGGB14_1X14 | |
| 90 | + }, | |
| 91 | + .format = V4L2_PIX_FMT_RAW_CRU14, | |
| 92 | + .datatype = MIPI_CSI2_DT_RAW14, | |
| 52 | 93 | .icndmr = 0, |
| 53 | 94 | .yuv = false, |
| 54 | 95 | }, |
| @@ -56,11 +97,14 @@ static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = { · 1 unmodified line | ||
| 56 | 97 | |
| 57 | 98 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) |
| 58 | 99 | { |
| 59 | − unsigned int i; | |
| 100 | + unsigned int i, j; | |
| 60 | 101 | |
| 61 | − for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) | |
| 62 | − if (rzg2l_cru_ip_formats[i].code == code) | |
| 63 | − return &rzg2l_cru_ip_formats[i]; | |
| 102 | + for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { | |
| 103 | + for (j = 0; j < ARRAY_SIZE(rzg2l_cru_ip_formats[i].codes); j++) { | |
| 104 | + if (rzg2l_cru_ip_formats[i].codes[j] == code) | |
| 105 | + return &rzg2l_cru_ip_formats[i]; | |
| 106 | + } | |
| 107 | + } | |
| 64 | 108 | |
| 65 | 109 | return NULL; |
| 66 | 110 | } |
| @@ -85,6 +129,17 @@ const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index) · 18 unmodified lines | ||
| 85 | 129 | return &rzg2l_cru_ip_formats[index]; |
| 86 | 130 | } |
| 87 | 131 | |
| 132 | +bool rzg2l_cru_ip_fmt_supports_mbus_code(const struct rzg2l_cru_ip_format *fmt, | |
| 133 | + unsigned int code) | |
| 134 | +{ | |
| 135 | + unsigned int i; | |
| 136 | + | |
| 137 | + for (i = 0; i < ARRAY_SIZE(fmt->codes); i++) | |
| 138 | + if (fmt->codes[i] == code) | |
| 139 | + return true; | |
| 140 | + | |
| 141 | + return false; | |
| 142 | +} | |
| 88 | 143 | struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) |
| 89 | 144 | { |
| 90 | 145 | struct v4l2_subdev_state *state; |
| @@ -162,7 +217,7 @@ static int rzg2l_cru_ip_set_format(struct v4l2_subdev *sd, · 71 unmodified lines | ||
| 162 | 217 | sink_format = v4l2_subdev_state_get_format(state, fmt->pad); |
| 163 | 218 | |
| 164 | 219 | if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code)) |
| 165 | − sink_format->code = rzg2l_cru_ip_formats[0].code; | |
| 220 | + sink_format->code = rzg2l_cru_ip_formats[0].codes[0]; | |
| 166 | 221 | else |
| 167 | 222 | sink_format->code = fmt->format.code; |
| 168 | 223 | |
| @@ -188,11 +243,26 @@ static int rzg2l_cru_ip_enum_mbus_code(struct v4l2_subdev *sd, · 19 unmodified lines | ||
| 188 | 243 | struct v4l2_subdev_state *state, |
| 189 | 244 | struct v4l2_subdev_mbus_code_enum *code) |
| 190 | 245 | { |
| 191 | − if (code->index >= ARRAY_SIZE(rzg2l_cru_ip_formats)) | |
| 192 | − return -EINVAL; | |
| 246 | + unsigned int index = code->index; | |
| 247 | + unsigned int i, j; | |
| 193 | 248 | |
| 194 | − code->code = rzg2l_cru_ip_formats[code->index].code; | |
| 195 | − return 0; | |
| 249 | + for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { | |
| 250 | + const struct rzg2l_cru_ip_format *fmt = &rzg2l_cru_ip_formats[i]; | |
| 251 | + | |
| 252 | + for (j = 0; j < ARRAY_SIZE(fmt->codes); j++) { | |
| 253 | + if (!fmt->codes[j]) | |
| 254 | + continue; | |
| 255 | + | |
| 256 | + if (!index) { | |
| 257 | + code->code = fmt->codes[j]; | |
| 258 | + return 0; | |
| 259 | + } | |
| 260 | + | |
| 261 | + index--; | |
| 262 | + } | |
| 263 | + } | |
| 264 | + | |
| 265 | + return -EINVAL; | |
| 196 | 266 | } |
| 197 | 267 | |
| 198 | 268 | static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd, |
| @@ -323,7 +323,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, · 322 unmodified lines | ||
| 323 | 323 | return 0; |
| 324 | 324 | } |
| 325 | 325 | |
| 326 | −bool rz3e_fifo_empty(struct rzg2l_cru_dev *cru) | |
| 326 | +bool rzg3e_fifo_empty(struct rzg2l_cru_dev *cru) | |
| 327 | 327 | { |
| 328 | 328 | u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR); |
| 329 | 329 | |
| @@ -345,8 +345,6 @@ bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru) · 15 unmodified lines | ||
| 345 | 345 | amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR; |
| 346 | 346 | amnfifopntr_r_y = |
| 347 | 347 | (amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16; |
| 348 | − if (amnfifopntr_w == amnfifopntr_r_y) | |
| 349 | − return true; | |
| 350 | 348 | |
| 351 | 349 | return amnfifopntr_w == amnfifopntr_r_y; |
| 352 | 350 | } |
| @@ -941,15 +939,7 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, · 588 unmodified lines | ||
| 941 | 939 | v4l_bound_align_image(&pix->width, 320, info->max_width, 1, |
| 942 | 940 | &pix->height, 240, info->max_height, 2, 0); |
| 943 | 941 | |
| 944 | − if (info->has_stride) { | |
| 945 | − u32 stride = clamp(pix->bytesperline, pix->width * fmt->bpp, | |
| 946 | − RZG2L_CRU_STRIDE_MAX); | |
| 947 | − pix->bytesperline = round_up(stride, RZG2L_CRU_STRIDE_ALIGN); | |
| 948 | − } else { | |
| 949 | − pix->bytesperline = pix->width * fmt->bpp; | |
| 950 | − } | |
| 951 | − | |
| 952 | − pix->sizeimage = pix->bytesperline * pix->height; | |
| 942 | + v4l2_fill_pixfmt(pix, pix->pixelformat, pix->width, pix->height); | |
| 953 | 943 | |
| 954 | 944 | dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", |
| 955 | 945 | pix->width, pix->height, pix->bytesperline, pix->sizeimage); |
| @@ -1031,6 +1021,31 @@ static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv, · 75 unmodified lines | ||
| 1031 | 1021 | return 0; |
| 1032 | 1022 | } |
| 1033 | 1023 | |
| 1024 | +static int rzg2l_cru_enum_framesizes(struct file *file, void *fh, | |
| 1025 | + struct v4l2_frmsizeenum *fsize) | |
| 1026 | +{ | |
| 1027 | + struct rzg2l_cru_dev *cru = video_drvdata(file); | |
| 1028 | + const struct rzg2l_cru_info *info = cru->info; | |
| 1029 | + const struct rzg2l_cru_ip_format *fmt; | |
| 1030 | + | |
| 1031 | + if (fsize->index) | |
| 1032 | + return -EINVAL; | |
| 1033 | + | |
| 1034 | + fmt = rzg2l_cru_ip_format_to_fmt(fsize->pixel_format); | |
| 1035 | + if (!fmt) | |
| 1036 | + return -EINVAL; | |
| 1037 | + | |
| 1038 | + fsize->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; | |
| 1039 | + fsize->stepwise.min_width = RZG2L_CRU_MIN_INPUT_WIDTH; | |
| 1040 | + fsize->stepwise.max_width = info->max_width; | |
| 1041 | + fsize->stepwise.step_width = 1; | |
| 1042 | + fsize->stepwise.min_height = RZG2L_CRU_MIN_INPUT_HEIGHT; | |
| 1043 | + fsize->stepwise.max_height = info->max_height; | |
| 1044 | + fsize->stepwise.step_height = 1; | |
| 1045 | + | |
| 1046 | + return 0; | |
| 1047 | +} | |
| 1048 | + | |
| 1034 | 1049 | static const struct v4l2_ioctl_ops rzg2l_cru_ioctl_ops = { |
| 1035 | 1050 | .vidioc_querycap = rzg2l_cru_querycap, |
| 1036 | 1051 | .vidioc_try_fmt_vid_cap = rzg2l_cru_try_fmt_vid_cap, |
| @@ -1047,6 +1062,7 @@ static const struct v4l2_ioctl_ops rzg2l_cru_ioctl_ops = { · 10 unmodified lines | ||
| 1047 | 1062 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
| 1048 | 1063 | .vidioc_streamon = vb2_ioctl_streamon, |
| 1049 | 1064 | .vidioc_streamoff = vb2_ioctl_streamoff, |
| 1065 | + .vidioc_enum_framesizes = rzg2l_cru_enum_framesizes, | |
| 1050 | 1066 | }; |
| 1051 | 1067 | |
| 1052 | 1068 | /* ----------------------------------------------------------------------------- |
| @@ -1129,7 +1145,7 @@ static int rzg2l_cru_video_link_validate(struct media_link *link) · 76 unmodified lines | ||
| 1129 | 1145 | if (fmt.format.width != cru->format.width || |
| 1130 | 1146 | fmt.format.height != cru->format.height || |
| 1131 | 1147 | fmt.format.field != cru->format.field || |
| 1132 | − video_fmt->code != fmt.format.code) | |
| 1148 | + !rzg2l_cru_ip_fmt_supports_mbus_code(video_fmt, fmt.format.code)) | |
| 1133 | 1149 | return -EPIPE; |
| 1134 | 1150 | |
| 1135 | 1151 | return 0; |
| @@ -6,5 +6,6 @@ vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o · 5 unmodified lines | ||
| 6 | 6 | vsp1-y += vsp1_brx.o vsp1_sru.o vsp1_uds.o |
| 7 | 7 | vsp1-y += vsp1_hgo.o vsp1_hgt.o vsp1_histo.o |
| 8 | 8 | vsp1-y += vsp1_iif.o vsp1_lif.o vsp1_uif.o |
| 9 | +vsp1-y += vsp1_vspx.o | |
| 9 | 10 | |
| 10 | 11 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
| @@ -111,6 +111,7 @@ struct vsp1_device { · 110 unmodified lines | ||
| 111 | 111 | struct media_entity_operations media_ops; |
| 112 | 112 | |
| 113 | 113 | struct vsp1_drm *drm; |
| 114 | + struct vsp1_vspx *vspx; | |
| 114 | 115 | }; |
| 115 | 116 | |
| 116 | 117 | int vsp1_device_get(struct vsp1_device *vsp1); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/device.h> |
| 11 | 11 | #include <linux/dma-mapping.h> |
| 12 | 12 | #include <linux/gfp.h> |
| 13 | +#include <linux/lockdep.h> | |
| 13 | 14 | #include <linux/refcount.h> |
| 14 | 15 | #include <linux/slab.h> |
| 15 | 16 | #include <linux/workqueue.h> |
| @@ -176,6 +177,7 @@ struct vsp1_dl_cmd_pool { · 160 unmodified lines | ||
| 176 | 177 | * @bodies: list of extra display list bodies |
| 177 | 178 | * @pre_cmd: pre command to be issued through extended dl header |
| 178 | 179 | * @post_cmd: post command to be issued through extended dl header |
| 180 | + * @allocated: flag to detect double list release | |
| 179 | 181 | * @has_chain: if true, indicates that there's a partition chain |
| 180 | 182 | * @chain: entry in the display list partition chain |
| 181 | 183 | * @flags: display list flags, a combination of VSP1_DL_FRAME_END_* |
| @@ -194,6 +196,8 @@ struct vsp1_dl_list { · 12 unmodified lines | ||
| 194 | 196 | struct vsp1_dl_ext_cmd *pre_cmd; |
| 195 | 197 | struct vsp1_dl_ext_cmd *post_cmd; |
| 196 | 198 | |
| 199 | + bool allocated; | |
| 200 | + | |
| 197 | 201 | bool has_chain; |
| 198 | 202 | struct list_head chain; |
| 199 | 203 | |
| @@ -212,6 +216,7 @@ struct vsp1_dl_list { · 12 unmodified lines | ||
| 212 | 216 | * @pending: list waiting to be queued to the hardware |
| 213 | 217 | * @pool: body pool for the display list bodies |
| 214 | 218 | * @cmdpool: commands pool for extended display list |
| 219 | + * @list_count: number of allocated display lists | |
| 215 | 220 | */ |
| 216 | 221 | struct vsp1_dl_manager { |
| 217 | 222 | unsigned int index; |
| @@ -226,6 +231,8 @@ struct vsp1_dl_manager { · 8 unmodified lines | ||
| 226 | 231 | |
| 227 | 232 | struct vsp1_dl_body_pool *pool; |
| 228 | 233 | struct vsp1_dl_cmd_pool *cmdpool; |
| 234 | + | |
| 235 | + size_t list_count; | |
| 229 | 236 | }; |
| 230 | 237 | |
| 231 | 238 | /* ----------------------------------------------------------------------------- |
| @@ -606,6 +613,8 @@ struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm) · 374 unmodified lines | ||
| 606 | 613 | struct vsp1_dl_list *dl = NULL; |
| 607 | 614 | unsigned long flags; |
| 608 | 615 | |
| 616 | + lockdep_assert_not_held(&dlm->lock); | |
| 617 | + | |
| 609 | 618 | spin_lock_irqsave(&dlm->lock, flags); |
| 610 | 619 | |
| 611 | 620 | if (!list_empty(&dlm->free)) { |
| @@ -617,6 +626,7 @@ struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm) · 5 unmodified lines | ||
| 617 | 626 | * display list can assert list_empty() if it is not in a chain. |
| 618 | 627 | */ |
| 619 | 628 | INIT_LIST_HEAD(&dl->chain); |
| 629 | + dl->allocated = true; | |
| 620 | 630 | } |
| 621 | 631 | |
| 622 | 632 | spin_unlock_irqrestore(&dlm->lock, flags); |
| @@ -632,6 +642,8 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) · 9 unmodified lines | ||
| 632 | 642 | if (!dl) |
| 633 | 643 | return; |
| 634 | 644 | |
| 645 | + lockdep_assert_held(&dl->dlm->lock); | |
| 646 | + | |
| 635 | 647 | /* |
| 636 | 648 | * Release any linked display-lists which were chained for a single |
| 637 | 649 | * hardware operation. |
| @@ -657,6 +669,13 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) · 19 unmodified lines | ||
| 657 | 669 | */ |
| 658 | 670 | dl->body0->num_entries = 0; |
| 659 | 671 | |
| 672 | + /* | |
| 673 | + * Return the display list to the 'free' pool. If the list had already | |
| 674 | + * been returned be loud about it. | |
| 675 | + */ | |
| 676 | + WARN_ON_ONCE(!dl->allocated); | |
| 677 | + dl->allocated = false; | |
| 678 | + | |
| 660 | 679 | list_add_tail(&dl->list, &dl->dlm->free); |
| 661 | 680 | } |
| 662 | 681 | |
| @@ -1067,6 +1086,7 @@ void vsp1_dlm_setup(struct vsp1_device *vsp1) · 404 unmodified lines | ||
| 1067 | 1086 | void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) |
| 1068 | 1087 | { |
| 1069 | 1088 | unsigned long flags; |
| 1089 | + size_t list_count; | |
| 1070 | 1090 | |
| 1071 | 1091 | spin_lock_irqsave(&dlm->lock, flags); |
| 1072 | 1092 | |
| @@ -1074,8 +1094,11 @@ void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) · 1 unmodified line | ||
| 1074 | 1094 | __vsp1_dl_list_put(dlm->queued); |
| 1075 | 1095 | __vsp1_dl_list_put(dlm->pending); |
| 1076 | 1096 | |
| 1097 | + list_count = list_count_nodes(&dlm->free); | |
| 1077 | 1098 | spin_unlock_irqrestore(&dlm->lock, flags); |
| 1078 | 1099 | |
| 1100 | + WARN_ON_ONCE(list_count != dlm->list_count); | |
| 1101 | + | |
| 1079 | 1102 | dlm->active = NULL; |
| 1080 | 1103 | dlm->queued = NULL; |
| 1081 | 1104 | dlm->pending = NULL; |
| @@ -1145,6 +1168,8 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, · 63 unmodified lines | ||
| 1145 | 1168 | list_add_tail(&dl->list, &dlm->free); |
| 1146 | 1169 | } |
| 1147 | 1170 | |
| 1171 | + dlm->list_count = prealloc; | |
| 1172 | + | |
| 1148 | 1173 | if (vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) { |
| 1149 | 1174 | dlm->cmdpool = vsp1_dl_cmd_pool_create(vsp1, |
| 1150 | 1175 | VSP1_EXTCMD_AUTOFLD, prealloc); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/device.h> |
| 11 | 11 | #include <linux/dma-mapping.h> |
| 12 | +#include <linux/export.h> | |
| 12 | 13 | #include <linux/slab.h> |
| 13 | 14 | |
| 14 | 15 | #include <media/media-entity.h> |
| @@ -33,11 +33,13 @@ · 32 unmodified lines | ||
| 33 | 33 | #include "vsp1_lif.h" |
| 34 | 34 | #include "vsp1_lut.h" |
| 35 | 35 | #include "vsp1_pipe.h" |
| 36 | +#include "vsp1_regs.h" | |
| 36 | 37 | #include "vsp1_rwpf.h" |
| 37 | 38 | #include "vsp1_sru.h" |
| 38 | 39 | #include "vsp1_uds.h" |
| 39 | 40 | #include "vsp1_uif.h" |
| 40 | 41 | #include "vsp1_video.h" |
| 42 | +#include "vsp1_vspx.h" | |
| 41 | 43 | |
| 42 | 44 | /* ----------------------------------------------------------------------------- |
| 43 | 45 | * Interrupt Handling |
| @@ -490,7 +492,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) · 446 unmodified lines | ||
| 490 | 492 | |
| 491 | 493 | ret = media_device_register(mdev); |
| 492 | 494 | } else { |
| 493 | − ret = vsp1_drm_init(vsp1); | |
| 495 | + if (vsp1->info->version == VI6_IP_VERSION_MODEL_VSPX_GEN4) | |
| 496 | + ret = vsp1_vspx_init(vsp1); | |
| 497 | + else | |
| 498 | + ret = vsp1_drm_init(vsp1); | |
| 494 | 499 | } |
| 495 | 500 | |
| 496 | 501 | done: |
| @@ -502,7 +507,9 @@ done: · 5 unmodified lines | ||
| 502 | 507 | |
| 503 | 508 | int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) |
| 504 | 509 | { |
| 510 | + u32 version = vsp1->version & VI6_IP_VERSION_MODEL_MASK; | |
| 505 | 511 | unsigned int timeout; |
| 512 | + int ret = 0; | |
| 506 | 513 | u32 status; |
| 507 | 514 | |
| 508 | 515 | status = vsp1_read(vsp1, VI6_STATUS); |
| @@ -523,7 +530,11 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) · 14 unmodified lines | ||
| 523 | 530 | return -ETIMEDOUT; |
| 524 | 531 | } |
| 525 | 532 | |
| 526 | − return 0; | |
| 533 | + if (version == VI6_IP_VERSION_MODEL_VSPD_GEN3 || | |
| 534 | + version == VI6_IP_VERSION_MODEL_VSPD_GEN4) | |
| 535 | + ret = rcar_fcp_soft_reset(vsp1->fcp); | |
| 536 | + | |
| 537 | + return ret; | |
| 527 | 538 | } |
| 528 | 539 | |
| 529 | 540 | static int vsp1_device_init(struct vsp1_device *vsp1) |
| @@ -851,6 +862,13 @@ static const struct vsp1_device_info vsp1_device_infos[] = { · 321 unmodified lines | ||
| 851 | 862 | .uif_count = 2, |
| 852 | 863 | .wpf_count = 1, |
| 853 | 864 | .num_bru_inputs = 5, |
| 865 | + }, { | |
| 866 | + .version = VI6_IP_VERSION_MODEL_VSPX_GEN4, | |
| 867 | + .model = "VSP2-X", | |
| 868 | + .gen = 4, | |
| 869 | + .features = VSP1_HAS_IIF, | |
| 870 | + .rpf_count = 2, | |
| 871 | + .wpf_count = 1, | |
| 854 | 872 | }, |
| 855 | 873 | }; |
| 856 | 874 | |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/delay.h> |
| 11 | 11 | #include <linux/list.h> |
| 12 | +#include <linux/lockdep.h> | |
| 12 | 13 | #include <linux/sched.h> |
| 13 | 14 | #include <linux/wait.h> |
| 14 | 15 | |
| @@ -473,6 +474,8 @@ void vsp1_pipeline_run(struct vsp1_pipeline *pipe) · 458 unmodified lines | ||
| 473 | 474 | { |
| 474 | 475 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
| 475 | 476 | |
| 477 | + lockdep_assert_held(&pipe->irqlock); | |
| 478 | + | |
| 476 | 479 | if (pipe->state == VSP1_PIPELINE_STOPPED) { |
| 477 | 480 | vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index), |
| 478 | 481 | VI6_CMD_STRCMD); |
| @@ -799,6 +799,7 @@ · 798 unmodified lines | ||
| 799 | 799 | #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) |
| 800 | 800 | #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) |
| 801 | 801 | #define VI6_IP_VERSION_MODEL_VSPD_GEN4 (0x1c << 8) |
| 802 | +#define VI6_IP_VERSION_MODEL_VSPX_GEN4 (0x1d << 8) | |
| 802 | 803 | /* RZ/G2L SoCs have no version register, So use 0x80 as the model version */ |
| 803 | 804 | #define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8) |
| 804 | 805 | |
| @@ -0,0 +1,633 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +/* | |
| 3 | + * vsp1_vspx.c -- R-Car Gen 4 VSPX | |
| 4 | + * | |
| 5 | + * Copyright (C) 2025 Ideas On Board Oy | |
| 6 | + * Copyright (C) 2025 Renesas Electronics Corporation | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include "vsp1_vspx.h" | |
| 10 | + | |
| 11 | +#include <linux/cleanup.h> | |
| 12 | +#include <linux/container_of.h> | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/dma-mapping.h> | |
| 16 | +#include <linux/export.h> | |
| 17 | +#include <linux/list.h> | |
| 18 | +#include <linux/slab.h> | |
| 19 | +#include <linux/spinlock.h> | |
| 20 | + | |
| 21 | +#include <media/media-entity.h> | |
| 22 | +#include <media/v4l2-subdev.h> | |
| 23 | +#include <media/vsp1.h> | |
| 24 | + | |
| 25 | +#include "vsp1_dl.h" | |
| 26 | +#include "vsp1_iif.h" | |
| 27 | +#include "vsp1_pipe.h" | |
| 28 | +#include "vsp1_rwpf.h" | |
| 29 | + | |
| 30 | +/* | |
| 31 | + * struct vsp1_vspx_pipeline - VSPX pipeline | |
| 32 | + * @pipe: the VSP1 pipeline | |
| 33 | + * @partition: the pre-calculated partition used by the pipeline | |
| 34 | + * @mutex: protects the streaming start/stop sequences | |
| 35 | + * @lock: protect access to the enabled flag | |
| 36 | + * @enabled: the enable flag | |
| 37 | + * @vspx_frame_end: frame end callback | |
| 38 | + * @frame_end_data: data for the frame end callback | |
| 39 | + */ | |
| 40 | +struct vsp1_vspx_pipeline { | |
| 41 | + struct vsp1_pipeline pipe; | |
| 42 | + struct vsp1_partition partition; | |
| 43 | + | |
| 44 | + /* | |
| 45 | + * Protects the streaming start/stop sequences. | |
| 46 | + * | |
| 47 | + * The start/stop sequences cannot be locked with the 'lock' spinlock | |
| 48 | + * as they acquire mutexes when handling the pm runtime and the vsp1 | |
| 49 | + * pipe start/stop operations. Provide a dedicated mutex for this | |
| 50 | + * reason. | |
| 51 | + */ | |
| 52 | + struct mutex mutex; | |
| 53 | + | |
| 54 | + /* | |
| 55 | + * Protects the enable flag. | |
| 56 | + * | |
| 57 | + * The enabled flag is contended between the start/stop streaming | |
| 58 | + * routines and the job_run one, which cannot take a mutex as it is | |
| 59 | + * called from the ISP irq context. | |
| 60 | + */ | |
| 61 | + spinlock_t lock; | |
| 62 | + bool enabled; | |
| 63 | + | |
| 64 | + void (*vspx_frame_end)(void *frame_end_data); | |
| 65 | + void *frame_end_data; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +static inline struct vsp1_vspx_pipeline * | |
| 69 | +to_vsp1_vspx_pipeline(struct vsp1_pipeline *pipe) | |
| 70 | +{ | |
| 71 | + return container_of(pipe, struct vsp1_vspx_pipeline, pipe); | |
| 72 | +} | |
| 73 | + | |
| 74 | +/* | |
| 75 | + * struct vsp1_vspx - VSPX device | |
| 76 | + * @vsp1: the VSP1 device | |
| 77 | + * @pipe: the VSPX pipeline | |
| 78 | + */ | |
| 79 | +struct vsp1_vspx { | |
| 80 | + struct vsp1_device *vsp1; | |
| 81 | + struct vsp1_vspx_pipeline pipe; | |
| 82 | +}; | |
| 83 | + | |
| 84 | +/* Apply the given width, height and fourcc to the RWPF's subdevice */ | |
| 85 | +static int vsp1_vspx_rwpf_set_subdev_fmt(struct vsp1_device *vsp1, | |
| 86 | + struct vsp1_rwpf *rwpf, | |
| 87 | + u32 isp_fourcc, | |
| 88 | + unsigned int width, | |
| 89 | + unsigned int height) | |
| 90 | +{ | |
| 91 | + struct vsp1_entity *ent = &rwpf->entity; | |
| 92 | + struct v4l2_subdev_format format = {}; | |
| 93 | + u32 vspx_fourcc; | |
| 94 | + | |
| 95 | + switch (isp_fourcc) { | |
| 96 | + case V4L2_PIX_FMT_GREY: | |
| 97 | + /* 8 bit RAW Bayer image. */ | |
| 98 | + vspx_fourcc = V4L2_PIX_FMT_RGB332; | |
| 99 | + break; | |
| 100 | + case V4L2_PIX_FMT_Y10: | |
| 101 | + case V4L2_PIX_FMT_Y12: | |
| 102 | + case V4L2_PIX_FMT_Y16: | |
| 103 | + /* 10, 12 and 16 bit RAW Bayer image. */ | |
| 104 | + vspx_fourcc = V4L2_PIX_FMT_RGB565; | |
| 105 | + break; | |
| 106 | + case V4L2_META_FMT_GENERIC_8: | |
| 107 | + /* ConfigDMA parameters buffer. */ | |
| 108 | + vspx_fourcc = V4L2_PIX_FMT_XBGR32; | |
| 109 | + break; | |
| 110 | + default: | |
| 111 | + return -EINVAL; | |
| 112 | + } | |
| 113 | + | |
| 114 | + rwpf->fmtinfo = vsp1_get_format_info(vsp1, vspx_fourcc); | |
| 115 | + | |
| 116 | + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
| 117 | + format.pad = RWPF_PAD_SINK; | |
| 118 | + format.format.width = width; | |
| 119 | + format.format.height = height; | |
| 120 | + format.format.field = V4L2_FIELD_NONE; | |
| 121 | + format.format.code = rwpf->fmtinfo->mbus; | |
| 122 | + | |
| 123 | + return v4l2_subdev_call(&ent->subdev, pad, set_fmt, NULL, &format); | |
| 124 | +} | |
| 125 | + | |
| 126 | +/* Configure the RPF->IIF->WPF pipeline for ConfigDMA or RAW image transfer. */ | |
| 127 | +static int vsp1_vspx_pipeline_configure(struct vsp1_device *vsp1, | |
| 128 | + dma_addr_t addr, u32 isp_fourcc, | |
| 129 | + unsigned int width, unsigned int height, | |
| 130 | + unsigned int stride, | |
| 131 | + unsigned int iif_sink_pad, | |
| 132 | + struct vsp1_dl_list *dl, | |
| 133 | + struct vsp1_dl_body *dlb) | |
| 134 | +{ | |
| 135 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 136 | + struct vsp1_pipeline *pipe = &vspx_pipe->pipe; | |
| 137 | + struct vsp1_rwpf *rpf0 = pipe->inputs[0]; | |
| 138 | + int ret; | |
| 139 | + | |
| 140 | + ret = vsp1_vspx_rwpf_set_subdev_fmt(vsp1, rpf0, isp_fourcc, width, | |
| 141 | + height); | |
| 142 | + if (ret) | |
| 143 | + return ret; | |
| 144 | + | |
| 145 | + ret = vsp1_vspx_rwpf_set_subdev_fmt(vsp1, pipe->output, isp_fourcc, | |
| 146 | + width, height); | |
| 147 | + if (ret) | |
| 148 | + return ret; | |
| 149 | + | |
| 150 | + vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[0], width, 0); | |
| 151 | + rpf0->format.plane_fmt[0].bytesperline = stride; | |
| 152 | + rpf0->format.num_planes = 1; | |
| 153 | + rpf0->mem.addr[0] = addr; | |
| 154 | + | |
| 155 | + /* | |
| 156 | + * Connect RPF0 to the IIF sink pad corresponding to the config or image | |
| 157 | + * path. | |
| 158 | + */ | |
| 159 | + rpf0->entity.sink_pad = iif_sink_pad; | |
| 160 | + | |
| 161 | + vsp1_entity_route_setup(&rpf0->entity, pipe, dlb); | |
| 162 | + vsp1_entity_configure_stream(&rpf0->entity, rpf0->entity.state, pipe, | |
| 163 | + dl, dlb); | |
| 164 | + vsp1_entity_configure_partition(&rpf0->entity, pipe, | |
| 165 | + &pipe->part_table[0], dl, dlb); | |
| 166 | + | |
| 167 | + return 0; | |
| 168 | +} | |
| 169 | + | |
| 170 | +/* ----------------------------------------------------------------------------- | |
| 171 | + * Interrupt handling | |
| 172 | + */ | |
| 173 | + | |
| 174 | +static void vsp1_vspx_pipeline_frame_end(struct vsp1_pipeline *pipe, | |
| 175 | + unsigned int completion) | |
| 176 | +{ | |
| 177 | + struct vsp1_vspx_pipeline *vspx_pipe = to_vsp1_vspx_pipeline(pipe); | |
| 178 | + | |
| 179 | + scoped_guard(spinlock_irqsave, &pipe->irqlock) { | |
| 180 | + /* | |
| 181 | + * Operating the vsp1_pipe in singleshot mode requires to | |
| 182 | + * manually set the pipeline state to stopped when a transfer | |
| 183 | + * is completed. | |
| 184 | + */ | |
| 185 | + pipe->state = VSP1_PIPELINE_STOPPED; | |
| 186 | + } | |
| 187 | + | |
| 188 | + if (vspx_pipe->vspx_frame_end) | |
| 189 | + vspx_pipe->vspx_frame_end(vspx_pipe->frame_end_data); | |
| 190 | +} | |
| 191 | + | |
| 192 | +/* ----------------------------------------------------------------------------- | |
| 193 | + * ISP Driver API (include/media/vsp1.h) | |
| 194 | + */ | |
| 195 | + | |
| 196 | +/** | |
| 197 | + * vsp1_isp_init() - Initialize the VSPX | |
| 198 | + * @dev: The VSP1 struct device | |
| 199 | + * | |
| 200 | + * Return: %0 on success or a negative error code on failure | |
| 201 | + */ | |
| 202 | +int vsp1_isp_init(struct device *dev) | |
| 203 | +{ | |
| 204 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 205 | + | |
| 206 | + if (!vsp1) | |
| 207 | + return -EPROBE_DEFER; | |
| 208 | + | |
| 209 | + return 0; | |
| 210 | +} | |
| 211 | +EXPORT_SYMBOL_GPL(vsp1_isp_init); | |
| 212 | + | |
| 213 | +/** | |
| 214 | + * vsp1_isp_get_bus_master - Get VSPX bus master | |
| 215 | + * @dev: The VSP1 struct device | |
| 216 | + * | |
| 217 | + * The VSPX accesses memory through an FCPX instance. When allocating memory | |
| 218 | + * buffers that will have to be accessed by the VSPX the 'struct device' of | |
| 219 | + * the FCPX should be used. Use this function to get a reference to it. | |
| 220 | + * | |
| 221 | + * Return: a pointer to the bus master's device | |
| 222 | + */ | |
| 223 | +struct device *vsp1_isp_get_bus_master(struct device *dev) | |
| 224 | +{ | |
| 225 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 226 | + | |
| 227 | + if (!vsp1) | |
| 228 | + return ERR_PTR(-ENODEV); | |
| 229 | + | |
| 230 | + return vsp1->bus_master; | |
| 231 | +} | |
| 232 | +EXPORT_SYMBOL_GPL(vsp1_isp_get_bus_master); | |
| 233 | + | |
| 234 | +/** | |
| 235 | + * vsp1_isp_alloc_buffer - Allocate a buffer in the VSPX address space | |
| 236 | + * @dev: The VSP1 struct device | |
| 237 | + * @size: The size of the buffer to be allocated by the VSPX | |
| 238 | + * @buffer_desc: The buffer descriptor. Will be filled with the buffer | |
| 239 | + * CPU-mapped address, the bus address and the size of the | |
| 240 | + * allocated buffer | |
| 241 | + * | |
| 242 | + * Allocate a buffer that will be later accessed by the VSPX. Buffers allocated | |
| 243 | + * using vsp1_isp_alloc_buffer() shall be released with a call to | |
| 244 | + * vsp1_isp_free_buffer(). This function is used by the ISP driver to allocate | |
| 245 | + * memory for the ConfigDMA parameters buffer. | |
| 246 | + * | |
| 247 | + * Return: %0 on success or a negative error code on failure | |
| 248 | + */ | |
| 249 | +int vsp1_isp_alloc_buffer(struct device *dev, size_t size, | |
| 250 | + struct vsp1_isp_buffer_desc *buffer_desc) | |
| 251 | +{ | |
| 252 | + struct device *bus_master = vsp1_isp_get_bus_master(dev); | |
| 253 | + | |
| 254 | + if (IS_ERR_OR_NULL(bus_master)) | |
| 255 | + return -ENODEV; | |
| 256 | + | |
| 257 | + buffer_desc->cpu_addr = dma_alloc_coherent(bus_master, size, | |
| 258 | + &buffer_desc->dma_addr, | |
| 259 | + GFP_KERNEL); | |
| 260 | + if (!buffer_desc->cpu_addr) | |
| 261 | + return -ENOMEM; | |
| 262 | + | |
| 263 | + buffer_desc->size = size; | |
| 264 | + | |
| 265 | + return 0; | |
| 266 | +} | |
| 267 | +EXPORT_SYMBOL_GPL(vsp1_isp_alloc_buffer); | |
| 268 | + | |
| 269 | +/** | |
| 270 | + * vsp1_isp_free_buffer - Release a buffer allocated by vsp1_isp_alloc_buffer() | |
| 271 | + * @dev: The VSP1 struct device | |
| 272 | + * @buffer_desc: The descriptor of the buffer to release as returned by | |
| 273 | + * vsp1_isp_alloc_buffer() | |
| 274 | + * | |
| 275 | + * Release memory in the VSPX address space allocated by | |
| 276 | + * vsp1_isp_alloc_buffer(). | |
| 277 | + */ | |
| 278 | +void vsp1_isp_free_buffer(struct device *dev, | |
| 279 | + struct vsp1_isp_buffer_desc *buffer_desc) | |
| 280 | +{ | |
| 281 | + struct device *bus_master = vsp1_isp_get_bus_master(dev); | |
| 282 | + | |
| 283 | + if (IS_ERR_OR_NULL(bus_master)) | |
| 284 | + return; | |
| 285 | + | |
| 286 | + dma_free_coherent(bus_master, buffer_desc->size, buffer_desc->cpu_addr, | |
| 287 | + buffer_desc->dma_addr); | |
| 288 | +} | |
| 289 | + | |
| 290 | +/** | |
| 291 | + * vsp1_isp_start_streaming - Start processing VSPX jobs | |
| 292 | + * @dev: The VSP1 struct device | |
| 293 | + * @frame_end: The frame end callback description | |
| 294 | + * | |
| 295 | + * Start the VSPX and prepare for accepting buffer transfer job requests. | |
| 296 | + * The caller is responsible for tracking the started state of the VSPX. | |
| 297 | + * Attempting to start an already started VSPX instance is an error. | |
| 298 | + * | |
| 299 | + * Return: %0 on success or a negative error code on failure | |
| 300 | + */ | |
| 301 | +int vsp1_isp_start_streaming(struct device *dev, | |
| 302 | + struct vsp1_vspx_frame_end *frame_end) | |
| 303 | +{ | |
| 304 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 305 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 306 | + struct vsp1_pipeline *pipe = &vspx_pipe->pipe; | |
| 307 | + u32 value; | |
| 308 | + int ret; | |
| 309 | + | |
| 310 | + if (!frame_end) | |
| 311 | + return -EINVAL; | |
| 312 | + | |
| 313 | + guard(mutex)(&vspx_pipe->mutex); | |
| 314 | + | |
| 315 | + scoped_guard(spinlock_irq, &vspx_pipe->lock) { | |
| 316 | + if (vspx_pipe->enabled) | |
| 317 | + return -EBUSY; | |
| 318 | + } | |
| 319 | + | |
| 320 | + vspx_pipe->vspx_frame_end = frame_end->vspx_frame_end; | |
| 321 | + vspx_pipe->frame_end_data = frame_end->frame_end_data; | |
| 322 | + | |
| 323 | + /* Enable the VSP1 and prepare for streaming. */ | |
| 324 | + vsp1_pipeline_dump(pipe, "VSPX job"); | |
| 325 | + | |
| 326 | + ret = vsp1_device_get(vsp1); | |
| 327 | + if (ret < 0) | |
| 328 | + return ret; | |
| 329 | + | |
| 330 | + /* | |
| 331 | + * Make sure VSPX is not active. This should never happen in normal | |
| 332 | + * usage | |
| 333 | + */ | |
| 334 | + value = vsp1_read(vsp1, VI6_CMD(0)); | |
| 335 | + if (value & VI6_CMD_STRCMD) { | |
| 336 | + dev_err(vsp1->dev, | |
| 337 | + "%s: Starting of WPF0 already reserved\n", __func__); | |
| 338 | + ret = -EBUSY; | |
| 339 | + goto error_put; | |
| 340 | + } | |
| 341 | + | |
| 342 | + value = vsp1_read(vsp1, VI6_STATUS); | |
| 343 | + if (value & VI6_STATUS_SYS_ACT(0)) { | |
| 344 | + dev_err(vsp1->dev, | |
| 345 | + "%s: WPF0 has not entered idle state\n", __func__); | |
| 346 | + ret = -EBUSY; | |
| 347 | + goto error_put; | |
| 348 | + } | |
| 349 | + | |
| 350 | + scoped_guard(spinlock_irq, &vspx_pipe->lock) { | |
| 351 | + vspx_pipe->enabled = true; | |
| 352 | + } | |
| 353 | + | |
| 354 | + return 0; | |
| 355 | + | |
| 356 | +error_put: | |
| 357 | + vsp1_device_put(vsp1); | |
| 358 | + return ret; | |
| 359 | +} | |
| 360 | +EXPORT_SYMBOL_GPL(vsp1_isp_start_streaming); | |
| 361 | + | |
| 362 | +/** | |
| 363 | + * vsp1_isp_stop_streaming - Stop the VSPX | |
| 364 | + * @dev: The VSP1 struct device | |
| 365 | + * | |
| 366 | + * Stop the VSPX operation by stopping the vsp1 pipeline and waiting for the | |
| 367 | + * last frame in transfer, if any, to complete. | |
| 368 | + * | |
| 369 | + * The caller is responsible for tracking the stopped state of the VSPX. | |
| 370 | + * Attempting to stop an already stopped VSPX instance is a nop. | |
| 371 | + */ | |
| 372 | +void vsp1_isp_stop_streaming(struct device *dev) | |
| 373 | +{ | |
| 374 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 375 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 376 | + struct vsp1_pipeline *pipe = &vspx_pipe->pipe; | |
| 377 | + | |
| 378 | + guard(mutex)(&vspx_pipe->mutex); | |
| 379 | + | |
| 380 | + scoped_guard(spinlock_irq, &vspx_pipe->lock) { | |
| 381 | + if (!vspx_pipe->enabled) | |
| 382 | + return; | |
| 383 | + | |
| 384 | + vspx_pipe->enabled = false; | |
| 385 | + } | |
| 386 | + | |
| 387 | + WARN_ON_ONCE(vsp1_pipeline_stop(pipe)); | |
| 388 | + | |
| 389 | + vspx_pipe->vspx_frame_end = NULL; | |
| 390 | + vsp1_dlm_reset(pipe->output->dlm); | |
| 391 | + vsp1_device_put(vsp1); | |
| 392 | +} | |
| 393 | +EXPORT_SYMBOL_GPL(vsp1_isp_stop_streaming); | |
| 394 | + | |
| 395 | +/** | |
| 396 | + * vsp1_isp_job_prepare - Prepare a new buffer transfer job | |
| 397 | + * @dev: The VSP1 struct device | |
| 398 | + * @job: The job description | |
| 399 | + * | |
| 400 | + * Prepare a new buffer transfer job by populating a display list that will be | |
| 401 | + * later executed by a call to vsp1_isp_job_run(). All pending jobs must be | |
| 402 | + * released after stopping the streaming operations with a call to | |
| 403 | + * vsp1_isp_job_release(). | |
| 404 | + * | |
| 405 | + * In order for the VSPX to accept new jobs to prepare the VSPX must have been | |
| 406 | + * started. | |
| 407 | + * | |
| 408 | + * Return: %0 on success or a negative error code on failure | |
| 409 | + */ | |
| 410 | +int vsp1_isp_job_prepare(struct device *dev, struct vsp1_isp_job_desc *job) | |
| 411 | +{ | |
| 412 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 413 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 414 | + struct vsp1_pipeline *pipe = &vspx_pipe->pipe; | |
| 415 | + const struct v4l2_pix_format_mplane *pix_mp; | |
| 416 | + struct vsp1_dl_list *second_dl = NULL; | |
| 417 | + struct vsp1_dl_body *dlb; | |
| 418 | + struct vsp1_dl_list *dl; | |
| 419 | + int ret; | |
| 420 | + | |
| 421 | + /* | |
| 422 | + * Transfer the buffers described in the job: an optional ConfigDMA | |
| 423 | + * parameters buffer and a RAW image. | |
| 424 | + */ | |
| 425 | + | |
| 426 | + job->dl = vsp1_dl_list_get(pipe->output->dlm); | |
| 427 | + if (!job->dl) | |
| 428 | + return -ENOMEM; | |
| 429 | + | |
| 430 | + dl = job->dl; | |
| 431 | + dlb = vsp1_dl_list_get_body0(dl); | |
| 432 | + | |
| 433 | + /* Configure IIF routing and enable IIF function. */ | |
| 434 | + vsp1_entity_route_setup(pipe->iif, pipe, dlb); | |
| 435 | + vsp1_entity_configure_stream(pipe->iif, pipe->iif->state, pipe, | |
| 436 | + dl, dlb); | |
| 437 | + | |
| 438 | + /* Configure WPF0 to enable RPF0 as source. */ | |
| 439 | + vsp1_entity_route_setup(&pipe->output->entity, pipe, dlb); | |
| 440 | + vsp1_entity_configure_stream(&pipe->output->entity, | |
| 441 | + pipe->output->entity.state, pipe, | |
| 442 | + dl, dlb); | |
| 443 | + | |
| 444 | + if (job->config.pairs) { | |
| 445 | + /* | |
| 446 | + * Writing less than 17 pairs corrupts the output images ( < 16 | |
| 447 | + * pairs) or freezes the VSPX operations (= 16 pairs). Only | |
| 448 | + * allow more than 16 pairs to be written. | |
| 449 | + */ | |
| 450 | + if (job->config.pairs <= 16) { | |
| 451 | + ret = -EINVAL; | |
| 452 | + goto error_put_dl; | |
| 453 | + } | |
| 454 | + | |
| 455 | + /* | |
| 456 | + * Configure RPF0 for ConfigDMA data. Transfer the number of | |
| 457 | + * configuration pairs plus 2 words for the header. | |
| 458 | + */ | |
| 459 | + ret = vsp1_vspx_pipeline_configure(vsp1, job->config.mem, | |
| 460 | + V4L2_META_FMT_GENERIC_8, | |
| 461 | + job->config.pairs * 2 + 2, 1, | |
| 462 | + job->config.pairs * 2 + 2, | |
| 463 | + VSPX_IIF_SINK_PAD_CONFIG, | |
| 464 | + dl, dlb); | |
| 465 | + if (ret) | |
| 466 | + goto error_put_dl; | |
| 467 | + | |
| 468 | + second_dl = vsp1_dl_list_get(pipe->output->dlm); | |
| 469 | + if (!second_dl) { | |
| 470 | + ret = -ENOMEM; | |
| 471 | + goto error_put_dl; | |
| 472 | + } | |
| 473 | + | |
| 474 | + dl = second_dl; | |
| 475 | + dlb = vsp1_dl_list_get_body0(dl); | |
| 476 | + } | |
| 477 | + | |
| 478 | + /* Configure RPF0 for RAW image transfer. */ | |
| 479 | + pix_mp = &job->img.fmt; | |
| 480 | + ret = vsp1_vspx_pipeline_configure(vsp1, job->img.mem, | |
| 481 | + pix_mp->pixelformat, | |
| 482 | + pix_mp->width, pix_mp->height, | |
| 483 | + pix_mp->plane_fmt[0].bytesperline, | |
| 484 | + VSPX_IIF_SINK_PAD_IMG, dl, dlb); | |
| 485 | + if (ret) | |
| 486 | + goto error_put_dl; | |
| 487 | + | |
| 488 | + if (second_dl) | |
| 489 | + vsp1_dl_list_add_chain(job->dl, second_dl); | |
| 490 | + | |
| 491 | + return 0; | |
| 492 | + | |
| 493 | +error_put_dl: | |
| 494 | + if (second_dl) | |
| 495 | + vsp1_dl_list_put(second_dl); | |
| 496 | + vsp1_dl_list_put(job->dl); | |
| 497 | + job->dl = NULL; | |
| 498 | + return ret; | |
| 499 | +} | |
| 500 | +EXPORT_SYMBOL_GPL(vsp1_isp_job_prepare); | |
| 501 | + | |
| 502 | +/** | |
| 503 | + * vsp1_isp_job_run - Run a buffer transfer job | |
| 504 | + * @dev: The VSP1 struct device | |
| 505 | + * @job: The job to be run | |
| 506 | + * | |
| 507 | + * Run the display list contained in the job description provided by the caller. | |
| 508 | + * The job must have been prepared with a call to vsp1_isp_job_prepare() and | |
| 509 | + * the job's display list shall be valid. | |
| 510 | + * | |
| 511 | + * Jobs can be run only on VSPX instances which have been started. Requests | |
| 512 | + * to run a job after the VSPX has been stopped return -EINVAL and the job | |
| 513 | + * resources shall be released by the caller with vsp1_isp_job_release(). | |
| 514 | + * When a job is run successfully all the resources acquired by | |
| 515 | + * vsp1_isp_job_prepare() are released by this function and no further action | |
| 516 | + * is required to the caller. | |
| 517 | + * | |
| 518 | + * Return: %0 on success or a negative error code on failure | |
| 519 | + */ | |
| 520 | +int vsp1_isp_job_run(struct device *dev, struct vsp1_isp_job_desc *job) | |
| 521 | +{ | |
| 522 | + struct vsp1_device *vsp1 = dev_get_drvdata(dev); | |
| 523 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 524 | + struct vsp1_pipeline *pipe = &vspx_pipe->pipe; | |
| 525 | + u32 value; | |
| 526 | + | |
| 527 | + /* Make sure VSPX is not busy processing a frame. */ | |
| 528 | + value = vsp1_read(vsp1, VI6_CMD(0)); | |
| 529 | + if (value) { | |
| 530 | + dev_err(vsp1->dev, | |
| 531 | + "%s: Starting of WPF0 already reserved\n", __func__); | |
| 532 | + return -EBUSY; | |
| 533 | + } | |
| 534 | + | |
| 535 | + scoped_guard(spinlock_irqsave, &vspx_pipe->lock) { | |
| 536 | + /* | |
| 537 | + * If a new job is scheduled when the VSPX is stopped, do not | |
| 538 | + * run it. | |
| 539 | + */ | |
| 540 | + if (!vspx_pipe->enabled) | |
| 541 | + return -EINVAL; | |
| 542 | + | |
| 543 | + vsp1_dl_list_commit(job->dl, 0); | |
| 544 | + | |
| 545 | + /* | |
| 546 | + * The display list is now under control of the display list | |
| 547 | + * manager and will be released automatically when the job | |
| 548 | + * completes. | |
| 549 | + */ | |
| 550 | + job->dl = NULL; | |
| 551 | + } | |
| 552 | + | |
| 553 | + scoped_guard(spinlock_irqsave, &pipe->irqlock) { | |
| 554 | + vsp1_pipeline_run(pipe); | |
| 555 | + } | |
| 556 | + | |
| 557 | + return 0; | |
| 558 | +} | |
| 559 | +EXPORT_SYMBOL_GPL(vsp1_isp_job_run); | |
| 560 | + | |
| 561 | +/** | |
| 562 | + * vsp1_isp_job_release - Release a non processed transfer job | |
| 563 | + * @dev: The VSP1 struct device | |
| 564 | + * @job: The job to release | |
| 565 | + * | |
| 566 | + * Release a job prepared by a call to vsp1_isp_job_prepare() and not yet | |
| 567 | + * run. All pending jobs shall be released after streaming has been stopped. | |
| 568 | + */ | |
| 569 | +void vsp1_isp_job_release(struct device *dev, | |
| 570 | + struct vsp1_isp_job_desc *job) | |
| 571 | +{ | |
| 572 | + vsp1_dl_list_put(job->dl); | |
| 573 | +} | |
| 574 | +EXPORT_SYMBOL_GPL(vsp1_isp_job_release); | |
| 575 | + | |
| 576 | +/* ----------------------------------------------------------------------------- | |
| 577 | + * Initialization and cleanup | |
| 578 | + */ | |
| 579 | + | |
| 580 | +int vsp1_vspx_init(struct vsp1_device *vsp1) | |
| 581 | +{ | |
| 582 | + struct vsp1_vspx_pipeline *vspx_pipe; | |
| 583 | + struct vsp1_pipeline *pipe; | |
| 584 | + | |
| 585 | + vsp1->vspx = devm_kzalloc(vsp1->dev, sizeof(*vsp1->vspx), GFP_KERNEL); | |
| 586 | + if (!vsp1->vspx) | |
| 587 | + return -ENOMEM; | |
| 588 | + | |
| 589 | + vsp1->vspx->vsp1 = vsp1; | |
| 590 | + | |
| 591 | + vspx_pipe = &vsp1->vspx->pipe; | |
| 592 | + vspx_pipe->enabled = false; | |
| 593 | + | |
| 594 | + pipe = &vspx_pipe->pipe; | |
| 595 | + | |
| 596 | + vsp1_pipeline_init(pipe); | |
| 597 | + | |
| 598 | + pipe->partitions = 1; | |
| 599 | + pipe->part_table = &vspx_pipe->partition; | |
| 600 | + pipe->interlaced = false; | |
| 601 | + pipe->frame_end = vsp1_vspx_pipeline_frame_end; | |
| 602 | + | |
| 603 | + mutex_init(&vspx_pipe->mutex); | |
| 604 | + spin_lock_init(&vspx_pipe->lock); | |
| 605 | + | |
| 606 | + /* | |
| 607 | + * Initialize RPF0 as input for VSPX and use it unconditionally for | |
| 608 | + * now. | |
| 609 | + */ | |
| 610 | + pipe->inputs[0] = vsp1->rpf[0]; | |
| 611 | + pipe->inputs[0]->entity.pipe = pipe; | |
| 612 | + pipe->inputs[0]->entity.sink = &vsp1->iif->entity; | |
| 613 | + list_add_tail(&pipe->inputs[0]->entity.list_pipe, &pipe->entities); | |
| 614 | + | |
| 615 | + pipe->iif = &vsp1->iif->entity; | |
| 616 | + pipe->iif->pipe = pipe; | |
| 617 | + pipe->iif->sink = &vsp1->wpf[0]->entity; | |
| 618 | + pipe->iif->sink_pad = RWPF_PAD_SINK; | |
| 619 | + list_add_tail(&pipe->iif->list_pipe, &pipe->entities); | |
| 620 | + | |
| 621 | + pipe->output = vsp1->wpf[0]; | |
| 622 | + pipe->output->entity.pipe = pipe; | |
| 623 | + list_add_tail(&pipe->output->entity.list_pipe, &pipe->entities); | |
| 624 | + | |
| 625 | + return 0; | |
| 626 | +} | |
| 627 | + | |
| 628 | +void vsp1_vspx_cleanup(struct vsp1_device *vsp1) | |
| 629 | +{ | |
| 630 | + struct vsp1_vspx_pipeline *vspx_pipe = &vsp1->vspx->pipe; | |
| 631 | + | |
| 632 | + mutex_destroy(&vspx_pipe->mutex); | |
| 633 | +} | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
| 2 | +/* | |
| 3 | + * vsp1_vspx.h -- R-Car Gen 4 VSPX | |
| 4 | + * | |
| 5 | + * Copyright (C) 2025 Ideas On Board Oy | |
| 6 | + * Copyright (C) 2025 Renesas Electronics Corporation | |
| 7 | + */ | |
| 8 | +#ifndef __VSP1_VSPX_H__ | |
| 9 | +#define __VSP1_VSPX_H__ | |
| 10 | + | |
| 11 | +#include "vsp1.h" | |
| 12 | + | |
| 13 | +int vsp1_vspx_init(struct vsp1_device *vsp1); | |
| 14 | +void vsp1_vspx_cleanup(struct vsp1_device *vsp1); | |
| 15 | + | |
| 16 | +#endif /* __VSP1_VSPX_H__ */ | |
| @@ -4,3 +4,4 @@ comment "Rockchip media platform drivers" · 3 unmodified lines | ||
| 4 | 4 | |
| 5 | 5 | source "drivers/media/platform/rockchip/rga/Kconfig" |
| 6 | 6 | source "drivers/media/platform/rockchip/rkisp1/Kconfig" |
| 7 | +source "drivers/media/platform/rockchip/rkvdec/Kconfig" | |
| @@ -1,3 +1,4 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | obj-y += rga/ |
| 3 | 3 | obj-y += rkisp1/ |
| 4 | +obj-y += rkvdec/ | |
| @@ -415,6 +415,8 @@ struct rkisp1_params { · 414 unmodified lines | ||
| 415 | 415 | spinlock_t config_lock; /* locks the buffers list 'params' */ |
| 416 | 416 | struct list_head params; |
| 417 | 417 | |
| 418 | + struct v4l2_ctrl_handler ctrls; | |
| 419 | + | |
| 418 | 420 | const struct v4l2_meta_format *metafmt; |
| 419 | 421 | |
| 420 | 422 | enum v4l2_quantization quantization; |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright (C) 2017 Rockchip Electronics Co., Ltd. |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | +#include <linux/bitfield.h> | |
| 8 | 9 | #include <linux/math.h> |
| 9 | 10 | #include <linux/string.h> |
| 10 | 11 | |
| @@ -60,6 +61,7 @@ union rkisp1_ext_params_config { · 49 unmodified lines | ||
| 60 | 61 | struct rkisp1_ext_params_afc_config afc; |
| 61 | 62 | struct rkisp1_ext_params_compand_bls_config compand_bls; |
| 62 | 63 | struct rkisp1_ext_params_compand_curve_config compand_curve; |
| 64 | + struct rkisp1_ext_params_wdr_config wdr; | |
| 63 | 65 | }; |
| 64 | 66 | |
| 65 | 67 | enum rkisp1_params_formats { |
| @@ -1348,6 +1350,73 @@ rkisp1_compand_compress_config(struct rkisp1_params *params, · 1282 unmodified lines | ||
| 1348 | 1350 | arg->x); |
| 1349 | 1351 | } |
| 1350 | 1352 | |
| 1353 | +static void rkisp1_wdr_config(struct rkisp1_params *params, | |
| 1354 | + const struct rkisp1_cif_isp_wdr_config *arg) | |
| 1355 | +{ | |
| 1356 | + unsigned int i; | |
| 1357 | + u32 value; | |
| 1358 | + | |
| 1359 | + value = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_WDR_CTRL) | |
| 1360 | + & ~(RKISP1_CIF_ISP_WDR_USE_IREF | | |
| 1361 | + RKISP1_CIF_ISP_WDR_COLOR_SPACE_SELECT | | |
| 1362 | + RKISP1_CIF_ISP_WDR_CR_MAPPING_DISABLE | | |
| 1363 | + RKISP1_CIF_ISP_WDR_USE_Y9_8 | | |
| 1364 | + RKISP1_CIF_ISP_WDR_USE_RGB7_8 | | |
| 1365 | + RKISP1_CIF_ISP_WDR_DISABLE_TRANSIENT | | |
| 1366 | + RKISP1_CIF_ISP_WDR_RGB_FACTOR_MASK); | |
| 1367 | + | |
| 1368 | + /* Colorspace and chrominance mapping */ | |
| 1369 | + if (arg->use_rgb_colorspace) | |
| 1370 | + value |= RKISP1_CIF_ISP_WDR_COLOR_SPACE_SELECT; | |
| 1371 | + | |
| 1372 | + if (!arg->use_rgb_colorspace && arg->bypass_chroma_mapping) | |
| 1373 | + value |= RKISP1_CIF_ISP_WDR_CR_MAPPING_DISABLE; | |
| 1374 | + | |
| 1375 | + /* Illumination reference */ | |
| 1376 | + if (arg->use_iref) { | |
| 1377 | + value |= RKISP1_CIF_ISP_WDR_USE_IREF; | |
| 1378 | + | |
| 1379 | + if (arg->iref_config.use_y9_8) | |
| 1380 | + value |= RKISP1_CIF_ISP_WDR_USE_Y9_8; | |
| 1381 | + | |
| 1382 | + if (arg->iref_config.use_rgb7_8) | |
| 1383 | + value |= RKISP1_CIF_ISP_WDR_USE_RGB7_8; | |
| 1384 | + | |
| 1385 | + if (arg->iref_config.disable_transient) | |
| 1386 | + value |= RKISP1_CIF_ISP_WDR_DISABLE_TRANSIENT; | |
| 1387 | + | |
| 1388 | + value |= FIELD_PREP(RKISP1_CIF_ISP_WDR_RGB_FACTOR_MASK, | |
| 1389 | + min(arg->iref_config.rgb_factor, | |
| 1390 | + RKISP1_CIF_ISP_WDR_RGB_FACTOR_MAX)); | |
| 1391 | + } | |
| 1392 | + | |
| 1393 | + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_WDR_CTRL, value); | |
| 1394 | + | |
| 1395 | + /* RGB and Luminance offsets */ | |
| 1396 | + value = FIELD_PREP(RKISP1_CIF_ISP_WDR_RGB_OFFSET_MASK, | |
| 1397 | + arg->rgb_offset) | |
| 1398 | + | FIELD_PREP(RKISP1_CIF_ISP_WDR_LUM_OFFSET_MASK, | |
| 1399 | + arg->luma_offset); | |
| 1400 | + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_WDR_OFFSET, value); | |
| 1401 | + | |
| 1402 | + /* DeltaMin */ | |
| 1403 | + value = FIELD_PREP(RKISP1_CIF_ISP_WDR_DMIN_THRESH_MASK, | |
| 1404 | + arg->dmin_thresh) | |
| 1405 | + | FIELD_PREP(RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MASK, | |
| 1406 | + min(arg->dmin_strength, | |
| 1407 | + RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MAX)); | |
| 1408 | + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_WDR_DELTAMIN, value); | |
| 1409 | + | |
| 1410 | + /* Tone curve */ | |
| 1411 | + for (i = 0; i < RKISP1_CIF_ISP_WDR_CURVE_NUM_DY_REGS; i++) | |
| 1412 | + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_WDR_TONECURVE(i), | |
| 1413 | + arg->tone_curve.dY[i]); | |
| 1414 | + for (i = 0; i < RKISP1_CIF_ISP_WDR_CURVE_NUM_COEFF; i++) | |
| 1415 | + rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_WDR_TONECURVE_YM(i), | |
| 1416 | + arg->tone_curve.ym[i] & | |
| 1417 | + RKISP1_CIF_ISP_WDR_TONE_CURVE_YM_MASK); | |
| 1418 | +} | |
| 1419 | + | |
| 1351 | 1420 | static void |
| 1352 | 1421 | rkisp1_isp_isr_other_config(struct rkisp1_params *params, |
| 1353 | 1422 | const struct rkisp1_params_cfg *new_params) |
| @@ -2005,6 +2074,25 @@ static void rkisp1_ext_params_compand_compress(struct rkisp1_params *params, · 651 unmodified lines | ||
| 2005 | 2074 | RKISP1_CIF_ISP_COMPAND_CTRL_COMPRESS_ENABLE); |
| 2006 | 2075 | } |
| 2007 | 2076 | |
| 2077 | +static void rkisp1_ext_params_wdr(struct rkisp1_params *params, | |
| 2078 | + const union rkisp1_ext_params_config *block) | |
| 2079 | +{ | |
| 2080 | + const struct rkisp1_ext_params_wdr_config *wdr = &block->wdr; | |
| 2081 | + | |
| 2082 | + if (wdr->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE) { | |
| 2083 | + rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_WDR_CTRL, | |
| 2084 | + RKISP1_CIF_ISP_WDR_CTRL_ENABLE); | |
| 2085 | + return; | |
| 2086 | + } | |
| 2087 | + | |
| 2088 | + rkisp1_wdr_config(params, &wdr->config); | |
| 2089 | + | |
| 2090 | + if ((wdr->header.flags & RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE) && | |
| 2091 | + !(params->enabled_blocks & BIT(wdr->header.type))) | |
| 2092 | + rkisp1_param_set_bits(params, RKISP1_CIF_ISP_WDR_CTRL, | |
| 2093 | + RKISP1_CIF_ISP_WDR_CTRL_ENABLE); | |
| 2094 | +} | |
| 2095 | + | |
| 2008 | 2096 | typedef void (*rkisp1_block_handler)(struct rkisp1_params *params, |
| 2009 | 2097 | const union rkisp1_ext_params_config *config); |
| 2010 | 2098 | |
| @@ -2118,6 +2206,11 @@ static const struct rkisp1_ext_params_handler { · 107 unmodified lines | ||
| 2118 | 2206 | .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, |
| 2119 | 2207 | .features = RKISP1_FEATURE_COMPAND, |
| 2120 | 2208 | }, |
| 2209 | + [RKISP1_EXT_PARAMS_BLOCK_TYPE_WDR] = { | |
| 2210 | + .size = sizeof(struct rkisp1_ext_params_wdr_config), | |
| 2211 | + .handler = rkisp1_ext_params_wdr, | |
| 2212 | + .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, | |
| 2213 | + }, | |
| 2121 | 2214 | }; |
| 2122 | 2215 | |
| 2123 | 2216 | static void rkisp1_ext_params_config(struct rkisp1_params *params, |
| @@ -2736,6 +2829,44 @@ static int rkisp1_params_init_vb2_queue(struct vb2_queue *q, · 612 unmodified lines | ||
| 2736 | 2829 | return vb2_queue_init(q); |
| 2737 | 2830 | } |
| 2738 | 2831 | |
| 2832 | +static int rkisp1_params_ctrl_init(struct rkisp1_params *params) | |
| 2833 | +{ | |
| 2834 | + struct v4l2_ctrl_config ctrl_config = { | |
| 2835 | + .id = RKISP1_CID_SUPPORTED_PARAMS_BLOCKS, | |
| 2836 | + .name = "Supported Params Blocks", | |
| 2837 | + .type = V4L2_CTRL_TYPE_BITMASK, | |
| 2838 | + .flags = V4L2_CTRL_FLAG_READ_ONLY, | |
| 2839 | + }; | |
| 2840 | + int ret; | |
| 2841 | + | |
| 2842 | + v4l2_ctrl_handler_init(¶ms->ctrls, 1); | |
| 2843 | + | |
| 2844 | + for (unsigned int i = 0; i < ARRAY_SIZE(rkisp1_ext_params_handlers); i++) { | |
| 2845 | + const struct rkisp1_ext_params_handler *block_handler; | |
| 2846 | + | |
| 2847 | + block_handler = &rkisp1_ext_params_handlers[i]; | |
| 2848 | + ctrl_config.max |= BIT(i); | |
| 2849 | + | |
| 2850 | + if ((params->rkisp1->info->features & block_handler->features) != | |
| 2851 | + block_handler->features) | |
| 2852 | + continue; | |
| 2853 | + | |
| 2854 | + ctrl_config.def |= BIT(i); | |
| 2855 | + } | |
| 2856 | + | |
| 2857 | + v4l2_ctrl_new_custom(¶ms->ctrls, &ctrl_config, NULL); | |
| 2858 | + | |
| 2859 | + params->vnode.vdev.ctrl_handler = ¶ms->ctrls; | |
| 2860 | + | |
| 2861 | + if (params->ctrls.error) { | |
| 2862 | + ret = params->ctrls.error; | |
| 2863 | + v4l2_ctrl_handler_free(¶ms->ctrls); | |
| 2864 | + return ret; | |
| 2865 | + } | |
| 2866 | + | |
| 2867 | + return 0; | |
| 2868 | +} | |
| 2869 | + | |
| 2739 | 2870 | int rkisp1_params_register(struct rkisp1_device *rkisp1) |
| 2740 | 2871 | { |
| 2741 | 2872 | struct rkisp1_params *params = &rkisp1->params; |
| @@ -2763,7 +2894,9 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) · 21 unmodified lines | ||
| 2763 | 2894 | vdev->queue = &node->buf_queue; |
| 2764 | 2895 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; |
| 2765 | 2896 | vdev->vfl_dir = VFL_DIR_TX; |
| 2766 | − rkisp1_params_init_vb2_queue(vdev->queue, params); | |
| 2897 | + ret = rkisp1_params_init_vb2_queue(vdev->queue, params); | |
| 2898 | + if (ret) | |
| 2899 | + goto err_media; | |
| 2767 | 2900 | |
| 2768 | 2901 | params->metafmt = &rkisp1_params_formats[RKISP1_PARAMS_FIXED]; |
| 2769 | 2902 | |
| @@ -2777,18 +2910,26 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) · 7 unmodified lines | ||
| 2777 | 2910 | node->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 2778 | 2911 | ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); |
| 2779 | 2912 | if (ret) |
| 2780 | − goto error; | |
| 2913 | + goto err_media; | |
| 2914 | + | |
| 2915 | + ret = rkisp1_params_ctrl_init(params); | |
| 2916 | + if (ret) { | |
| 2917 | + dev_err(rkisp1->dev, "Control initialization error %d\n", ret); | |
| 2918 | + goto err_media; | |
| 2919 | + } | |
| 2781 | 2920 | |
| 2782 | 2921 | ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); |
| 2783 | 2922 | if (ret) { |
| 2784 | 2923 | dev_err(rkisp1->dev, |
| 2785 | 2924 | "failed to register %s, ret=%d\n", vdev->name, ret); |
| 2786 | − goto error; | |
| 2925 | + goto err_ctrl; | |
| 2787 | 2926 | } |
| 2788 | 2927 | |
| 2789 | 2928 | return 0; |
| 2790 | 2929 | |
| 2791 | −error: | |
| 2930 | +err_ctrl: | |
| 2931 | + v4l2_ctrl_handler_free(¶ms->ctrls); | |
| 2932 | +err_media: | |
| 2792 | 2933 | media_entity_cleanup(&vdev->entity); |
| 2793 | 2934 | mutex_destroy(&node->vlock); |
| 2794 | 2935 | return ret; |
| @@ -2804,6 +2945,7 @@ void rkisp1_params_unregister(struct rkisp1_device *rkisp1) · 9 unmodified lines | ||
| 2804 | 2945 | return; |
| 2805 | 2946 | |
| 2806 | 2947 | vb2_video_unregister_device(vdev); |
| 2948 | + v4l2_ctrl_handler_free(¶ms->ctrls); | |
| 2807 | 2949 | media_entity_cleanup(&vdev->entity); |
| 2808 | 2950 | mutex_destroy(&node->vlock); |
| 2809 | 2951 | } |
| @@ -703,6 +703,27 @@ · 702 unmodified lines | ||
| 703 | 703 | #define RKISP1_CIF_ISP_COMPAND_CTRL_SOFT_RESET_FLAG BIT(2) |
| 704 | 704 | #define RKISP1_CIF_ISP_COMPAND_CTRL_BLS_ENABLE BIT(3) |
| 705 | 705 | |
| 706 | +/* WDR */ | |
| 707 | +/* ISP_WDR_CTRL */ | |
| 708 | +#define RKISP1_CIF_ISP_WDR_CTRL_ENABLE BIT(0) | |
| 709 | +#define RKISP1_CIF_ISP_WDR_COLOR_SPACE_SELECT BIT(1) | |
| 710 | +#define RKISP1_CIF_ISP_WDR_CR_MAPPING_DISABLE BIT(2) | |
| 711 | +#define RKISP1_CIF_ISP_WDR_USE_IREF BIT(3) | |
| 712 | +#define RKISP1_CIF_ISP_WDR_USE_Y9_8 BIT(4) | |
| 713 | +#define RKISP1_CIF_ISP_WDR_USE_RGB7_8 BIT(5) | |
| 714 | +#define RKISP1_CIF_ISP_WDR_DISABLE_TRANSIENT BIT(6) | |
| 715 | +#define RKISP1_CIF_ISP_WDR_RGB_FACTOR_MASK GENMASK(11, 8) | |
| 716 | +#define RKISP1_CIF_ISP_WDR_RGB_FACTOR_MAX 8U | |
| 717 | +/* ISP_WDR_TONE_CURVE_YM */ | |
| 718 | +#define RKISP1_CIF_ISP_WDR_TONE_CURVE_YM_MASK GENMASK(12, 0) | |
| 719 | +/* ISP_WDR_OFFSET */ | |
| 720 | +#define RKISP1_CIF_ISP_WDR_RGB_OFFSET_MASK GENMASK(11, 0) | |
| 721 | +#define RKISP1_CIF_ISP_WDR_LUM_OFFSET_MASK GENMASK(27, 16) | |
| 722 | +/* ISP_WDR_DELTAMIN */ | |
| 723 | +#define RKISP1_CIF_ISP_WDR_DMIN_THRESH_MASK GENMASK(11, 0) | |
| 724 | +#define RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MASK GENMASK(20, 16) | |
| 725 | +#define RKISP1_CIF_ISP_WDR_DMIN_STRENGTH_MAX 16U | |
| 726 | + | |
| 706 | 727 | /* =================================================================== */ |
| 707 | 728 | /* CIF Registers */ |
| 708 | 729 | /* =================================================================== */ |
| @@ -1295,82 +1316,12 @@ · 586 unmodified lines | ||
| 1295 | 1316 | |
| 1296 | 1317 | #define RKISP1_CIF_ISP_WDR_BASE 0x00002a00 |
| 1297 | 1318 | #define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) |
| 1298 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000004) | |
| 1299 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) | |
| 1300 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_3 (RKISP1_CIF_ISP_WDR_BASE + 0x0000000c) | |
| 1301 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000010) | |
| 1302 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0 (RKISP1_CIF_ISP_WDR_BASE + 0x00000014) | |
| 1303 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1 (RKISP1_CIF_ISP_WDR_BASE + 0x00000018) | |
| 1304 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2 (RKISP1_CIF_ISP_WDR_BASE + 0x0000001c) | |
| 1305 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3 (RKISP1_CIF_ISP_WDR_BASE + 0x00000020) | |
| 1306 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4 (RKISP1_CIF_ISP_WDR_BASE + 0x00000024) | |
| 1307 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5 (RKISP1_CIF_ISP_WDR_BASE + 0x00000028) | |
| 1308 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6 (RKISP1_CIF_ISP_WDR_BASE + 0x0000002c) | |
| 1309 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7 (RKISP1_CIF_ISP_WDR_BASE + 0x00000030) | |
| 1310 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8 (RKISP1_CIF_ISP_WDR_BASE + 0x00000034) | |
| 1311 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9 (RKISP1_CIF_ISP_WDR_BASE + 0x00000038) | |
| 1312 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10 (RKISP1_CIF_ISP_WDR_BASE + 0x0000003c) | |
| 1313 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11 (RKISP1_CIF_ISP_WDR_BASE + 0x00000040) | |
| 1314 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12 (RKISP1_CIF_ISP_WDR_BASE + 0x00000044) | |
| 1315 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13 (RKISP1_CIF_ISP_WDR_BASE + 0x00000048) | |
| 1316 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14 (RKISP1_CIF_ISP_WDR_BASE + 0x0000004c) | |
| 1317 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15 (RKISP1_CIF_ISP_WDR_BASE + 0x00000050) | |
| 1318 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16 (RKISP1_CIF_ISP_WDR_BASE + 0x00000054) | |
| 1319 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17 (RKISP1_CIF_ISP_WDR_BASE + 0x00000058) | |
| 1320 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18 (RKISP1_CIF_ISP_WDR_BASE + 0x0000005c) | |
| 1321 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19 (RKISP1_CIF_ISP_WDR_BASE + 0x00000060) | |
| 1322 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20 (RKISP1_CIF_ISP_WDR_BASE + 0x00000064) | |
| 1323 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21 (RKISP1_CIF_ISP_WDR_BASE + 0x00000068) | |
| 1324 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22 (RKISP1_CIF_ISP_WDR_BASE + 0x0000006c) | |
| 1325 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23 (RKISP1_CIF_ISP_WDR_BASE + 0x00000070) | |
| 1326 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24 (RKISP1_CIF_ISP_WDR_BASE + 0x00000074) | |
| 1327 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25 (RKISP1_CIF_ISP_WDR_BASE + 0x00000078) | |
| 1328 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26 (RKISP1_CIF_ISP_WDR_BASE + 0x0000007c) | |
| 1329 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27 (RKISP1_CIF_ISP_WDR_BASE + 0x00000080) | |
| 1330 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28 (RKISP1_CIF_ISP_WDR_BASE + 0x00000084) | |
| 1331 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29 (RKISP1_CIF_ISP_WDR_BASE + 0x00000088) | |
| 1332 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30 (RKISP1_CIF_ISP_WDR_BASE + 0x0000008c) | |
| 1333 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31 (RKISP1_CIF_ISP_WDR_BASE + 0x00000090) | |
| 1334 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32 (RKISP1_CIF_ISP_WDR_BASE + 0x00000094) | |
| 1319 | +#define RKISP1_CIF_ISP_WDR_TONECURVE(n) (RKISP1_CIF_ISP_WDR_BASE + 0x00000004 + (n) * 4) | |
| 1320 | +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM(n) (RKISP1_CIF_ISP_WDR_BASE + 0x00000014 + (n) * 4) | |
| 1335 | 1321 | #define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) |
| 1336 | 1322 | #define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009c) |
| 1337 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a0) | |
| 1338 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a4) | |
| 1339 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a8) | |
| 1340 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ac) | |
| 1341 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_0_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b0) | |
| 1342 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_1_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b4) | |
| 1343 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000b8) | |
| 1344 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_3_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000bc) | |
| 1345 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_4_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c0) | |
| 1346 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_5_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c4) | |
| 1347 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_6_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000c8) | |
| 1348 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_7_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000cc) | |
| 1349 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_8_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d0) | |
| 1350 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_9_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d4) | |
| 1351 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_10_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000d8) | |
| 1352 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_11_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000dc) | |
| 1353 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_12_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e0) | |
| 1354 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_13_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e4) | |
| 1355 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_14_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000e8) | |
| 1356 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_15_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000ec) | |
| 1357 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_16_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f0) | |
| 1358 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_17_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f4) | |
| 1359 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_18_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000f8) | |
| 1360 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_19_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000fc) | |
| 1361 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_20_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000100) | |
| 1362 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_21_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000104) | |
| 1363 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_22_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000108) | |
| 1364 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_23_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000010c) | |
| 1365 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_24_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000110) | |
| 1366 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_25_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000114) | |
| 1367 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_26_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000118) | |
| 1368 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_27_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000011c) | |
| 1369 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_28_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000120) | |
| 1370 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_29_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000124) | |
| 1371 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_30_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000128) | |
| 1372 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_31_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x0000012c) | |
| 1373 | −#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_32_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x00000130) | |
| 1323 | +#define RKISP1_CIF_ISP_WDR_TONECURVE_SHD(n) (RKISP1_CIF_ISP_WDR_BASE + 0x000000a0 + (n) * 4) | |
| 1324 | +#define RKISP1_CIF_ISP_WDR_TONECURVE_YM_SHD(n) (RKISP1_CIF_ISP_WDR_BASE + 0x000000b0 + (n) * 4) | |
| 1374 | 1325 | |
| 1375 | 1326 | #define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002c00 |
| 1376 | 1327 | #define RKISP1_CIF_ISP_HIST_CTRL_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000) |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
| @@ -11,6 +11,7 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include <linux/clk.h> |
| 13 | 13 | #include <linux/interrupt.h> |
| 14 | +#include <linux/iommu.h> | |
| 14 | 15 | #include <linux/module.h> |
| 15 | 16 | #include <linux/of.h> |
| 16 | 17 | #include <linux/platform_device.h> |
| @@ -1055,24 +1056,42 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec) · 1038 unmodified lines | ||
| 1055 | 1056 | v4l2_device_unregister(&rkvdec->v4l2_dev); |
| 1056 | 1057 | } |
| 1057 | 1058 | |
| 1059 | +static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec) | |
| 1060 | +{ | |
| 1061 | + if (rkvdec->empty_domain) { | |
| 1062 | + /* | |
| 1063 | + * To rewrite mapping into the attached IOMMU core, attach a new empty domain that | |
| 1064 | + * will program an empty table, then detach it to restore the default domain and | |
| 1065 | + * all cached mappings. | |
| 1066 | + * This is safely done in this interrupt handler to make sure no memory get mapped | |
| 1067 | + * through the IOMMU while the empty domain is attached. | |
| 1068 | + */ | |
| 1069 | + iommu_attach_device(rkvdec->empty_domain, rkvdec->dev); | |
| 1070 | + iommu_detach_device(rkvdec->empty_domain, rkvdec->dev); | |
| 1071 | + } | |
| 1072 | +} | |
| 1073 | + | |
| 1058 | 1074 | static irqreturn_t rkvdec_irq_handler(int irq, void *priv) |
| 1059 | 1075 | { |
| 1060 | 1076 | struct rkvdec_dev *rkvdec = priv; |
| 1077 | + struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); | |
| 1061 | 1078 | enum vb2_buffer_state state; |
| 1062 | 1079 | u32 status; |
| 1063 | 1080 | |
| 1064 | 1081 | status = readl(rkvdec->regs + RKVDEC_REG_INTERRUPT); |
| 1065 | − state = (status & RKVDEC_RDY_STA) ? | |
| 1066 | − VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; | |
| 1067 | − | |
| 1068 | 1082 | writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); |
| 1069 | − if (cancel_delayed_work(&rkvdec->watchdog_work)) { | |
| 1070 | − struct rkvdec_ctx *ctx; | |
| 1071 | 1083 | |
| 1072 | − ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); | |
| 1073 | − rkvdec_job_finish(ctx, state); | |
| 1084 | + if (status & RKVDEC_RDY_STA) { | |
| 1085 | + state = VB2_BUF_STATE_DONE; | |
| 1086 | + } else { | |
| 1087 | + state = VB2_BUF_STATE_ERROR; | |
| 1088 | + if (status & RKVDEC_SOFTRESET_RDY) | |
| 1089 | + rkvdec_iommu_restore(rkvdec); | |
| 1074 | 1090 | } |
| 1075 | 1091 | |
| 1092 | + if (cancel_delayed_work(&rkvdec->watchdog_work)) | |
| 1093 | + rkvdec_job_finish(ctx, state); | |
| 1094 | + | |
| 1076 | 1095 | return IRQ_HANDLED; |
| 1077 | 1096 | } |
| 1078 | 1097 | |
| @@ -1140,6 +1159,13 @@ static int rkvdec_probe(struct platform_device *pdev) · 61 unmodified lines | ||
| 1140 | 1159 | return ret; |
| 1141 | 1160 | } |
| 1142 | 1161 | |
| 1162 | + if (iommu_get_domain_for_dev(&pdev->dev)) { | |
| 1163 | + rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); | |
| 1164 | + | |
| 1165 | + if (!rkvdec->empty_domain) | |
| 1166 | + dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); | |
| 1167 | + } | |
| 1168 | + | |
| 1143 | 1169 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); |
| 1144 | 1170 | |
| 1145 | 1171 | irq = platform_get_irq(pdev, 0); |
| @@ -1179,6 +1205,9 @@ static void rkvdec_remove(struct platform_device *pdev) · 33 unmodified lines | ||
| 1179 | 1205 | rkvdec_v4l2_cleanup(rkvdec); |
| 1180 | 1206 | pm_runtime_disable(&pdev->dev); |
| 1181 | 1207 | pm_runtime_dont_use_autosuspend(&pdev->dev); |
| 1208 | + | |
| 1209 | + if (rkvdec->empty_domain) | |
| 1210 | + iommu_domain_free(rkvdec->empty_domain); | |
| 1182 | 1211 | } |
| 1183 | 1212 | |
| 1184 | 1213 | #ifdef CONFIG_PM |
| @@ -110,6 +110,7 @@ struct rkvdec_dev { · 109 unmodified lines | ||
| 110 | 110 | void __iomem *regs; |
| 111 | 111 | struct mutex vdev_lock; /* serializes ioctls */ |
| 112 | 112 | struct delayed_work watchdog_work; |
| 113 | + struct iommu_domain *empty_domain; | |
| 113 | 114 | }; |
| 114 | 115 | |
| 115 | 116 | struct rkvdec_ctx { |
| @@ -131,7 +131,7 @@ static const struct dev_pm_ops fimc_is_i2c_pm_ops = { · 130 unmodified lines | ||
| 131 | 131 | }; |
| 132 | 132 | |
| 133 | 133 | static const struct of_device_id fimc_is_i2c_of_match[] = { |
| 134 | − { .compatible = FIMC_IS_I2C_COMPATIBLE }, | |
| 134 | + { .compatible = "samsung,exynos4212-i2c-isp" }, | |
| 135 | 135 | { }, |
| 136 | 136 | }; |
| 137 | 137 | |
| @@ -6,7 +6,5 @@ · 5 unmodified lines | ||
| 6 | 6 | * Sylwester Nawrocki <s.nawrocki@samsung.com> |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | −#define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp" | |
| 10 | − | |
| 11 | 9 | int fimc_is_register_i2c_driver(void); |
| 12 | 10 | void fimc_is_unregister_i2c_driver(void); |
| @@ -207,7 +207,7 @@ static int fimc_is_register_subdevs(struct fimc_is *is) · 206 unmodified lines | ||
| 207 | 207 | if (ret < 0) |
| 208 | 208 | return ret; |
| 209 | 209 | |
| 210 | − for_each_compatible_node(i2c_bus, NULL, FIMC_IS_I2C_COMPATIBLE) { | |
| 210 | + for_each_compatible_node(i2c_bus, NULL, "samsung,exynos4212-i2c-isp") { | |
| 211 | 211 | for_each_available_child_of_node(i2c_bus, child) { |
| 212 | 212 | ret = fimc_is_parse_sensor_config(is, index, child); |
| 213 | 213 | |
| @@ -482,15 +482,12 @@ static int fimc_md_parse_one_endpoint(struct fimc_md *fmd, · 481 unmodified lines | ||
| 482 | 482 | static int fimc_md_parse_port_node(struct fimc_md *fmd, |
| 483 | 483 | struct device_node *port) |
| 484 | 484 | { |
| 485 | − struct device_node *ep; | |
| 486 | 485 | int ret; |
| 487 | 486 | |
| 488 | − for_each_child_of_node(port, ep) { | |
| 487 | + for_each_child_of_node_scoped(port, ep) { | |
| 489 | 488 | ret = fimc_md_parse_one_endpoint(fmd, ep); |
| 490 | − if (ret < 0) { | |
| 491 | − of_node_put(ep); | |
| 489 | + if (ret < 0) | |
| 492 | 490 | return ret; |
| 493 | − } | |
| 494 | 491 | } |
| 495 | 492 | |
| 496 | 493 | return 0; |
| @@ -501,7 +498,6 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) · 4 unmodified lines | ||
| 501 | 498 | { |
| 502 | 499 | struct device_node *parent = fmd->pdev->dev.of_node; |
| 503 | 500 | struct device_node *ports = NULL; |
| 504 | − struct device_node *node; | |
| 505 | 501 | int ret; |
| 506 | 502 | |
| 507 | 503 | /* |
| @@ -518,7 +514,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) · 10 unmodified lines | ||
| 518 | 514 | fmd->num_sensors = 0; |
| 519 | 515 | |
| 520 | 516 | /* Attach sensors linked to MIPI CSI-2 receivers */ |
| 521 | − for_each_available_child_of_node(parent, node) { | |
| 517 | + for_each_available_child_of_node_scoped(parent, node) { | |
| 522 | 518 | struct device_node *port; |
| 523 | 519 | |
| 524 | 520 | if (!of_node_name_eq(node, "csis")) |
| @@ -530,10 +526,8 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) · 5 unmodified lines | ||
| 530 | 526 | |
| 531 | 527 | ret = fimc_md_parse_port_node(fmd, port); |
| 532 | 528 | of_node_put(port); |
| 533 | − if (ret < 0) { | |
| 534 | − of_node_put(node); | |
| 529 | + if (ret < 0) | |
| 535 | 530 | goto cleanup; |
| 536 | − } | |
| 537 | 531 | } |
| 538 | 532 | |
| 539 | 533 | /* Attach sensors listed in the parallel-ports node */ |
| @@ -541,12 +535,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) · 1 unmodified line | ||
| 541 | 535 | if (!ports) |
| 542 | 536 | goto rpm_put; |
| 543 | 537 | |
| 544 | − for_each_child_of_node(ports, node) { | |
| 538 | + for_each_child_of_node_scoped(ports, node) { | |
| 545 | 539 | ret = fimc_md_parse_port_node(fmd, node); |
| 546 | − if (ret < 0) { | |
| 547 | − of_node_put(node); | |
| 540 | + if (ret < 0) | |
| 548 | 541 | goto cleanup; |
| 549 | − } | |
| 550 | 542 | } |
| 551 | 543 | of_node_put(ports); |
| 552 | 544 | |
| @@ -736,10 +728,9 @@ dev_unlock: · 183 unmodified lines | ||
| 736 | 728 | static int fimc_md_register_platform_entities(struct fimc_md *fmd, |
| 737 | 729 | struct device_node *parent) |
| 738 | 730 | { |
| 739 | − struct device_node *node; | |
| 740 | 731 | int ret = 0; |
| 741 | 732 | |
| 742 | − for_each_available_child_of_node(parent, node) { | |
| 733 | + for_each_available_child_of_node_scoped(parent, node) { | |
| 743 | 734 | struct platform_device *pdev; |
| 744 | 735 | int plat_entity = -1; |
| 745 | 736 | |
| @@ -762,10 +753,8 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd, · 16 unmodified lines | ||
| 762 | 753 | ret = fimc_md_register_platform_entity(fmd, pdev, |
| 763 | 754 | plat_entity); |
| 764 | 755 | put_device(&pdev->dev); |
| 765 | − if (ret < 0) { | |
| 766 | − of_node_put(node); | |
| 756 | + if (ret < 0) | |
| 767 | 757 | break; |
| 768 | − } | |
| 769 | 758 | } |
| 770 | 759 | |
| 771 | 760 | return ret; |
| @@ -658,7 +658,7 @@ static irqreturn_t c8sectpfe_error_irq_handler(int irq, void *priv) · 657 unmodified lines | ||
| 658 | 658 | static int c8sectpfe_probe(struct platform_device *pdev) |
| 659 | 659 | { |
| 660 | 660 | struct device *dev = &pdev->dev; |
| 661 | − struct device_node *child, *np = dev->of_node; | |
| 661 | + struct device_node *np = dev->of_node; | |
| 662 | 662 | struct c8sectpfei *fei; |
| 663 | 663 | struct resource *res; |
| 664 | 664 | int ret, index = 0; |
| @@ -742,17 +742,15 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 77 unmodified lines | ||
| 742 | 742 | return PTR_ERR(fei->pinctrl); |
| 743 | 743 | } |
| 744 | 744 | |
| 745 | − for_each_child_of_node(np, child) { | |
| 745 | + for_each_child_of_node_scoped(np, child) { | |
| 746 | 746 | struct device_node *i2c_bus; |
| 747 | 747 | |
| 748 | 748 | fei->channel_data[index] = devm_kzalloc(dev, |
| 749 | 749 | sizeof(struct channel_info), |
| 750 | 750 | GFP_KERNEL); |
| 751 | 751 | |
| 752 | − if (!fei->channel_data[index]) { | |
| 753 | − ret = -ENOMEM; | |
| 754 | − goto err_node_put; | |
| 755 | − } | |
| 752 | + if (!fei->channel_data[index]) | |
| 753 | + return -ENOMEM; | |
| 756 | 754 | |
| 757 | 755 | tsin = fei->channel_data[index]; |
| 758 | 756 | |
| @@ -761,7 +759,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 761 | 759 | ret = of_property_read_u32(child, "tsin-num", &tsin->tsin_id); |
| 762 | 760 | if (ret) { |
| 763 | 761 | dev_err(&pdev->dev, "No tsin_num found\n"); |
| 764 | − goto err_node_put; | |
| 762 | + return ret; | |
| 765 | 763 | } |
| 766 | 764 | |
| 767 | 765 | /* sanity check value */ |
| @@ -769,8 +767,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 769 | 767 | dev_err(&pdev->dev, |
| 770 | 768 | "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", |
| 771 | 769 | tsin->tsin_id, fei->hw_stats.num_ib); |
| 772 | − ret = -EINVAL; | |
| 773 | − goto err_node_put; | |
| 770 | + return -EINVAL; | |
| 774 | 771 | } |
| 775 | 772 | |
| 776 | 773 | tsin->invert_ts_clk = of_property_read_bool(child, |
| @@ -786,22 +783,20 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 786 | 783 | &tsin->dvb_card); |
| 787 | 784 | if (ret) { |
| 788 | 785 | dev_err(&pdev->dev, "No dvb-card found\n"); |
| 789 | − goto err_node_put; | |
| 786 | + return ret; | |
| 790 | 787 | } |
| 791 | 788 | |
| 792 | 789 | i2c_bus = of_parse_phandle(child, "i2c-bus", 0); |
| 793 | 790 | if (!i2c_bus) { |
| 794 | 791 | dev_err(&pdev->dev, "No i2c-bus found\n"); |
| 795 | − ret = -ENODEV; | |
| 796 | − goto err_node_put; | |
| 792 | + return -ENODEV; | |
| 797 | 793 | } |
| 798 | 794 | tsin->i2c_adapter = |
| 799 | 795 | of_find_i2c_adapter_by_node(i2c_bus); |
| 800 | 796 | of_node_put(i2c_bus); |
| 801 | 797 | if (!tsin->i2c_adapter) { |
| 802 | 798 | dev_err(&pdev->dev, "No i2c adapter found\n"); |
| 803 | − ret = -ENODEV; | |
| 804 | − goto err_node_put; | |
| 799 | + return -ENODEV; | |
| 805 | 800 | } |
| 806 | 801 | |
| 807 | 802 | /* Acquire reset GPIO and activate it */ |
| @@ -813,7 +808,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 5 unmodified lines | ||
| 813 | 808 | if (ret && ret != -EBUSY) { |
| 814 | 809 | dev_err(dev, "Can't request tsin%d reset gpio\n", |
| 815 | 810 | fei->channel_data[index]->tsin_id); |
| 816 | − goto err_node_put; | |
| 811 | + return ret; | |
| 817 | 812 | } |
| 818 | 813 | |
| 819 | 814 | if (!ret) { |
| @@ -855,10 +850,6 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 35 unmodified lines | ||
| 855 | 850 | c8sectpfe_debugfs_init(fei); |
| 856 | 851 | |
| 857 | 852 | return 0; |
| 858 | − | |
| 859 | −err_node_put: | |
| 860 | − of_node_put(child); | |
| 861 | − return ret; | |
| 862 | 853 | } |
| 863 | 854 | |
| 864 | 855 | static void c8sectpfe_remove(struct platform_device *pdev) |
| @@ -897,16 +888,15 @@ static void c8sectpfe_remove(struct platform_device *pdev) · 32 unmodified lines | ||
| 897 | 888 | static int configure_channels(struct c8sectpfei *fei) |
| 898 | 889 | { |
| 899 | 890 | int index = 0, ret; |
| 900 | − struct device_node *child, *np = fei->dev->of_node; | |
| 891 | + struct device_node *np = fei->dev->of_node; | |
| 901 | 892 | |
| 902 | 893 | /* iterate round each tsin and configure memdma descriptor and IB hw */ |
| 903 | − for_each_child_of_node(np, child) { | |
| 894 | + for_each_child_of_node_scoped(np, child) { | |
| 904 | 895 | ret = configure_memdma_and_inputblock(fei, |
| 905 | 896 | fei->channel_data[index]); |
| 906 | 897 | if (ret) { |
| 907 | 898 | dev_err(fei->dev, |
| 908 | 899 | "configure_memdma_and_inputblock failed\n"); |
| 909 | − of_node_put(child); | |
| 910 | 900 | goto err_unmap; |
| 911 | 901 | } |
| 912 | 902 | index++; |
| @@ -619,6 +619,7 @@ static void ti_csi2rx_dma_callback(void *param) · 618 unmodified lines | ||
| 619 | 619 | |
| 620 | 620 | if (ti_csi2rx_start_dma(csi, buf)) { |
| 621 | 621 | dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); |
| 622 | + list_del(&buf->list); | |
| 622 | 623 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); |
| 623 | 624 | } else { |
| 624 | 625 | list_move_tail(&buf->list, &dma->submitted); |
| @@ -895,6 +896,7 @@ static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi) · 270 unmodified lines | ||
| 895 | 896 | q->dev = dmaengine_get_dma_device(csi->dma.chan); |
| 896 | 897 | q->lock = &csi->mutex; |
| 897 | 898 | q->min_queued_buffers = 1; |
| 899 | + q->allow_cache_hints = 1; | |
| 898 | 900 | |
| 899 | 901 | ret = vb2_queue_init(q); |
| 900 | 902 | if (ret) |
| @@ -552,38 +552,6 @@ EXPORT_SYMBOL(vpdma_submit_descs); · 551 unmodified lines | ||
| 552 | 552 | |
| 553 | 553 | static void dump_dtd(struct vpdma_dtd *dtd); |
| 554 | 554 | |
| 555 | −void vpdma_update_dma_addr(struct vpdma_data *vpdma, | |
| 556 | − struct vpdma_desc_list *list, dma_addr_t dma_addr, | |
| 557 | − void *write_dtd, int drop, int idx) | |
| 558 | −{ | |
| 559 | − struct vpdma_dtd *dtd = list->buf.addr; | |
| 560 | − dma_addr_t write_desc_addr; | |
| 561 | − int offset; | |
| 562 | − | |
| 563 | − dtd += idx; | |
| 564 | − vpdma_unmap_desc_buf(vpdma, &list->buf); | |
| 565 | − | |
| 566 | − dtd->start_addr = dma_addr; | |
| 567 | − | |
| 568 | − /* Calculate write address from the offset of write_dtd from start | |
| 569 | − * of the list->buf | |
| 570 | − */ | |
| 571 | − offset = (void *)write_dtd - list->buf.addr; | |
| 572 | − write_desc_addr = list->buf.dma_addr + offset; | |
| 573 | − | |
| 574 | − if (drop) | |
| 575 | − dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, | |
| 576 | − 1, 1, 0); | |
| 577 | − else | |
| 578 | − dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, | |
| 579 | − 1, 0, 0); | |
| 580 | − | |
| 581 | − vpdma_map_desc_buf(vpdma, &list->buf); | |
| 582 | − | |
| 583 | − dump_dtd(dtd); | |
| 584 | −} | |
| 585 | −EXPORT_SYMBOL(vpdma_update_dma_addr); | |
| 586 | − | |
| 587 | 555 | void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, |
| 588 | 556 | u32 width, u32 height) |
| 589 | 557 | { |
| @@ -222,9 +222,6 @@ void vpdma_free_desc_list(struct vpdma_desc_list *list); · 221 unmodified lines | ||
| 222 | 222 | int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, |
| 223 | 223 | int list_num); |
| 224 | 224 | bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); |
| 225 | −void vpdma_update_dma_addr(struct vpdma_data *vpdma, | |
| 226 | − struct vpdma_desc_list *list, dma_addr_t dma_addr, | |
| 227 | − void *write_dtd, int drop, int idx); | |
| 228 | 225 | |
| 229 | 226 | /* VPDMA hardware list funcs */ |
| 230 | 227 | int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); |
| @@ -323,6 +323,8 @@ struct hantro_postproc_regs { · 322 unmodified lines | ||
| 323 | 323 | struct hantro_reg output_fmt; |
| 324 | 324 | struct hantro_reg orig_width; |
| 325 | 325 | struct hantro_reg display_width; |
| 326 | + struct hantro_reg input_width_ext; | |
| 327 | + struct hantro_reg input_height_ext; | |
| 326 | 328 | }; |
| 327 | 329 | |
| 328 | 330 | struct hantro_vp9_decoded_buffer_info { |
| @@ -350,7 +350,7 @@ · 349 unmodified lines | ||
| 350 | 350 | #define G1_REG_PP_CONTROL_OUT_WIDTH(v) (((v) << 4) & GENMASK(14, 4)) |
| 351 | 351 | #define G1_REG_PP_MASK1_ORIG_WIDTH G1_SWREG(88) |
| 352 | 352 | #define G1_REG_PP_ORIG_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) |
| 353 | −#define G1_REG_PP_DISPLAY_WIDTH G1_SWREG(92) | |
| 353 | +#define G1_REG_PP_DISPLAY_WIDTH_IN_EXT G1_SWREG(92) | |
| 354 | 354 | #define G1_REG_PP_FUSE G1_SWREG(99) |
| 355 | 355 | |
| 356 | 356 | #endif /* HANTRO_G1_REGS_H_ */ |
| @@ -325,12 +325,12 @@ static void update_dpb(struct hantro_ctx *ctx) · 324 unmodified lines | ||
| 325 | 325 | continue; |
| 326 | 326 | |
| 327 | 327 | *cdpb = *ndpb; |
| 328 | − set_bit(j, used); | |
| 328 | + __set_bit(j, used); | |
| 329 | 329 | break; |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | 332 | if (j == ARRAY_SIZE(ctx->h264_dec.dpb)) |
| 333 | − set_bit(i, new); | |
| 333 | + __set_bit(i, new); | |
| 334 | 334 | } |
| 335 | 335 | |
| 336 | 336 | /* For entries that could not be matched, use remaining free slots. */ |
| @@ -349,7 +349,7 @@ static void update_dpb(struct hantro_ctx *ctx) · 12 unmodified lines | ||
| 349 | 349 | |
| 350 | 350 | cdpb = &ctx->h264_dec.dpb[j]; |
| 351 | 351 | *cdpb = *ndpb; |
| 352 | − set_bit(j, used); | |
| 352 | + __set_bit(j, used); | |
| 353 | 353 | } |
| 354 | 354 | } |
| 355 | 355 | |
| @@ -49,7 +49,9 @@ static const struct hantro_postproc_regs hantro_g1_postproc_regs = { · 48 unmodified lines | ||
| 49 | 49 | .input_fmt = {G1_REG_PP_CONTROL, 29, 0x7}, |
| 50 | 50 | .output_fmt = {G1_REG_PP_CONTROL, 26, 0x7}, |
| 51 | 51 | .orig_width = {G1_REG_PP_MASK1_ORIG_WIDTH, 23, 0x1ff}, |
| 52 | − .display_width = {G1_REG_PP_DISPLAY_WIDTH, 0, 0xfff}, | |
| 52 | + .display_width = {G1_REG_PP_DISPLAY_WIDTH_IN_EXT, 0, 0xfff}, | |
| 53 | + .input_width_ext = {G1_REG_PP_DISPLAY_WIDTH_IN_EXT, 26, 0x7}, | |
| 54 | + .input_height_ext = {G1_REG_PP_DISPLAY_WIDTH_IN_EXT, 29, 0x7}, | |
| 53 | 55 | }; |
| 54 | 56 | |
| 55 | 57 | bool hantro_needs_postproc(const struct hantro_ctx *ctx, |
| @@ -103,6 +105,8 @@ static void hantro_postproc_g1_enable(struct hantro_ctx *ctx) · 47 unmodified lines | ||
| 103 | 105 | HANTRO_PP_REG_WRITE(vpu, output_height, ctx->dst_fmt.height); |
| 104 | 106 | HANTRO_PP_REG_WRITE(vpu, orig_width, MB_WIDTH(ctx->dst_fmt.width)); |
| 105 | 107 | HANTRO_PP_REG_WRITE(vpu, display_width, ctx->dst_fmt.width); |
| 108 | + HANTRO_PP_REG_WRITE(vpu, input_width_ext, MB_WIDTH(ctx->dst_fmt.width) >> 9); | |
| 109 | + HANTRO_PP_REG_WRITE(vpu, input_height_ext, MB_HEIGHT(ctx->dst_fmt.height >> 8)); | |
| 106 | 110 | } |
| 107 | 111 | |
| 108 | 112 | static int down_scale_factor(struct hantro_ctx *ctx) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | #define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000) |
| 19 | 19 | #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) |
| 20 | −#define RK3588_ACLK_MAX_FREQ (300 * 1000 * 1000) | |
| 21 | 20 | |
| 22 | 21 | #define ROCKCHIP_VPU981_MIN_SIZE 64 |
| 23 | 22 | |
| @@ -454,13 +453,6 @@ static int rk3066_vpu_hw_init(struct hantro_dev *vpu) · 430 unmodified lines | ||
| 454 | 453 | return 0; |
| 455 | 454 | } |
| 456 | 455 | |
| 457 | −static int rk3588_vpu981_hw_init(struct hantro_dev *vpu) | |
| 458 | −{ | |
| 459 | − /* Bump ACLKs to max. possible freq. to improve performance. */ | |
| 460 | − clk_set_rate(vpu->clocks[0].clk, RK3588_ACLK_MAX_FREQ); | |
| 461 | − return 0; | |
| 462 | −} | |
| 463 | − | |
| 464 | 456 | static int rockchip_vpu_hw_init(struct hantro_dev *vpu) |
| 465 | 457 | { |
| 466 | 458 | /* Bump ACLK to max. possible freq. to improve performance. */ |
| @@ -821,7 +813,6 @@ const struct hantro_variant rk3588_vpu981_variant = { · 354 unmodified lines | ||
| 821 | 813 | .codec_ops = rk3588_vpu981_codec_ops, |
| 822 | 814 | .irqs = rk3588_vpu981_irqs, |
| 823 | 815 | .num_irqs = ARRAY_SIZE(rk3588_vpu981_irqs), |
| 824 | − .init = rk3588_vpu981_hw_init, | |
| 825 | 816 | .clk_names = rk3588_vpu981_vpu_clk_names, |
| 826 | 817 | .num_clocks = ARRAY_SIZE(rk3588_vpu981_vpu_clk_names) |
| 827 | 818 | }; |
| @@ -450,7 +450,6 @@ static int xvip_graph_dma_init_one(struct xvip_composite_device *xdev, · 449 unmodified lines | ||
| 450 | 450 | static int xvip_graph_dma_init(struct xvip_composite_device *xdev) |
| 451 | 451 | { |
| 452 | 452 | struct device_node *ports; |
| 453 | − struct device_node *port; | |
| 454 | 453 | int ret = 0; |
| 455 | 454 | |
| 456 | 455 | ports = of_get_child_by_name(xdev->dev->of_node, "ports"); |
| @@ -459,12 +458,10 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev) · 2 unmodified lines | ||
| 459 | 458 | return -EINVAL; |
| 460 | 459 | } |
| 461 | 460 | |
| 462 | − for_each_child_of_node(ports, port) { | |
| 461 | + for_each_child_of_node_scoped(ports, port) { | |
| 463 | 462 | ret = xvip_graph_dma_init_one(xdev, port); |
| 464 | − if (ret) { | |
| 465 | − of_node_put(port); | |
| 463 | + if (ret) | |
| 466 | 464 | break; |
| 467 | − } | |
| 468 | 465 | } |
| 469 | 466 | |
| 470 | 467 | of_node_put(ports); |
| @@ -21,13 +21,12 @@ · 20 unmodified lines | ||
| 21 | 21 | #define IR_SPI_DRIVER_NAME "ir-spi" |
| 22 | 22 | |
| 23 | 23 | #define IR_SPI_DEFAULT_FREQUENCY 38000 |
| 24 | −#define IR_SPI_MAX_BUFSIZE 4096 | |
| 24 | +#define IR_SPI_BITS_PER_PULSE 16 | |
| 25 | 25 | |
| 26 | 26 | struct ir_spi_data { |
| 27 | 27 | u32 freq; |
| 28 | 28 | bool negated; |
| 29 | 29 | |
| 30 | − u16 tx_buf[IR_SPI_MAX_BUFSIZE]; | |
| 31 | 30 | u16 pulse; |
| 32 | 31 | u16 space; |
| 33 | 32 | |
| @@ -43,17 +42,23 @@ static int ir_spi_tx(struct rc_dev *dev, unsigned int *buffer, unsigned int coun · 9 unmodified lines | ||
| 43 | 42 | unsigned int len = 0; |
| 44 | 43 | struct ir_spi_data *idata = dev->priv; |
| 45 | 44 | struct spi_transfer xfer; |
| 45 | + u16 *tx_buf; | |
| 46 | 46 | |
| 47 | 47 | /* convert the pulse/space signal to raw binary signal */ |
| 48 | 48 | for (i = 0; i < count; i++) { |
| 49 | − unsigned int periods; | |
| 50 | − int j; | |
| 51 | − u16 val; | |
| 49 | + buffer[i] = DIV_ROUND_CLOSEST_ULL((u64)buffer[i] * idata->freq, | |
| 50 | + 1000000); | |
| 51 | + len += buffer[i]; | |
| 52 | + } | |
| 52 | 53 | |
| 53 | − periods = DIV_ROUND_CLOSEST(buffer[i] * idata->freq, 1000000); | |
| 54 | + tx_buf = kmalloc_array(len, sizeof(*tx_buf), GFP_KERNEL); | |
| 55 | + if (!tx_buf) | |
| 56 | + return -ENOMEM; | |
| 54 | 57 | |
| 55 | − if (len + periods >= IR_SPI_MAX_BUFSIZE) | |
| 56 | − return -EINVAL; | |
| 58 | + len = 0; | |
| 59 | + for (i = 0; i < count; i++) { | |
| 60 | + int j; | |
| 61 | + u16 val; | |
| 57 | 62 | |
| 58 | 63 | /* |
| 59 | 64 | * The first value in buffer is a pulse, so that 0, 2, 4, ... |
| @@ -61,19 +66,19 @@ static int ir_spi_tx(struct rc_dev *dev, unsigned int *buffer, unsigned int coun · 1 unmodified line | ||
| 61 | 66 | * contain a space duration. |
| 62 | 67 | */ |
| 63 | 68 | val = (i % 2) ? idata->space : idata->pulse; |
| 64 | − for (j = 0; j < periods; j++) | |
| 65 | − idata->tx_buf[len++] = val; | |
| 69 | + for (j = 0; j < buffer[i]; j++) | |
| 70 | + tx_buf[len++] = val; | |
| 66 | 71 | } |
| 67 | 72 | |
| 68 | 73 | memset(&xfer, 0, sizeof(xfer)); |
| 69 | 74 | |
| 70 | − xfer.speed_hz = idata->freq * 16; | |
| 71 | − xfer.len = len * sizeof(*idata->tx_buf); | |
| 72 | − xfer.tx_buf = idata->tx_buf; | |
| 75 | + xfer.speed_hz = idata->freq * IR_SPI_BITS_PER_PULSE; | |
| 76 | + xfer.len = len * sizeof(*tx_buf); | |
| 77 | + xfer.tx_buf = tx_buf; | |
| 73 | 78 | |
| 74 | 79 | ret = regulator_enable(idata->regulator); |
| 75 | 80 | if (ret) |
| 76 | − return ret; | |
| 81 | + goto err_free_tx_buf; | |
| 77 | 82 | |
| 78 | 83 | ret = spi_sync_transfer(idata->spi, &xfer, 1); |
| 79 | 84 | if (ret) |
| @@ -81,6 +86,10 @@ static int ir_spi_tx(struct rc_dev *dev, unsigned int *buffer, unsigned int coun · 1 unmodified line | ||
| 81 | 86 | |
| 82 | 87 | regulator_disable(idata->regulator); |
| 83 | 88 | |
| 89 | +err_free_tx_buf: | |
| 90 | + | |
| 91 | + kfree(tx_buf); | |
| 92 | + | |
| 84 | 93 | return ret ? ret : count; |
| 85 | 94 | } |
| 86 | 95 | |
| @@ -91,6 +100,9 @@ static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) · 4 unmodified lines | ||
| 91 | 100 | if (!carrier) |
| 92 | 101 | return -EINVAL; |
| 93 | 102 | |
| 103 | + if (carrier > idata->spi->max_speed_hz / IR_SPI_BITS_PER_PULSE) | |
| 104 | + return -EINVAL; | |
| 105 | + | |
| 94 | 106 | idata->freq = carrier; |
| 95 | 107 | |
| 96 | 108 | return 0; |
| @@ -244,7 +244,8 @@ static const struct v4l2_ctrl_config vivid_ctrl_u8_pixel_array = { · 243 unmodified lines | ||
| 244 | 244 | .min = 0x00, |
| 245 | 245 | .max = 0xff, |
| 246 | 246 | .step = 1, |
| 247 | − .dims = { 640 / PIXEL_ARRAY_DIV, 360 / PIXEL_ARRAY_DIV }, | |
| 247 | + .dims = { DIV_ROUND_UP(360, PIXEL_ARRAY_DIV), | |
| 248 | + DIV_ROUND_UP(640, PIXEL_ARRAY_DIV) }, | |
| 248 | 249 | }; |
| 249 | 250 | |
| 250 | 251 | static const struct v4l2_ctrl_config vivid_ctrl_s32_array = { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | +#include <linux/bitops.h> | |
| 8 | 9 | #include <linux/errno.h> |
| 9 | 10 | #include <linux/kernel.h> |
| 10 | 11 | #include <linux/ktime.h> |
| @@ -165,12 +166,7 @@ static const u8 vivid_cc_sequence2[30] = { · 154 unmodified lines | ||
| 165 | 166 | |
| 166 | 167 | static u8 calc_parity(u8 val) |
| 167 | 168 | { |
| 168 | − unsigned i; | |
| 169 | − unsigned tot = 0; | |
| 170 | − | |
| 171 | − for (i = 0; i < 7; i++) | |
| 172 | − tot += (val & (1 << i)) ? 1 : 0; | |
| 173 | − return val | ((tot & 1) ? 0 : 0x80); | |
| 169 | + return val | (parity8(val) ? 0 : 0x80); | |
| 174 | 170 | } |
| 175 | 171 | |
| 176 | 172 | static void vivid_vbi_gen_set_time_of_day(u8 *packet) |
| @@ -454,8 +454,8 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) · 453 unmodified lines | ||
| 454 | 454 | if (keep_controls) |
| 455 | 455 | return; |
| 456 | 456 | |
| 457 | − dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV); | |
| 458 | − dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV); | |
| 457 | + dims[0] = DIV_ROUND_UP(dev->src_rect.height, PIXEL_ARRAY_DIV); | |
| 458 | + dims[1] = DIV_ROUND_UP(dev->src_rect.width, PIXEL_ARRAY_DIV); | |
| 459 | 459 | v4l2_ctrl_modify_dimensions(dev->pixel_array, dims); |
| 460 | 460 | } |
| 461 | 461 | |
| @@ -227,6 +227,7 @@ static int sd_init(struct gspca_dev *gspca_dev) · 226 unmodified lines | ||
| 227 | 227 | const struct ihex_binrec *rec; |
| 228 | 228 | const struct firmware *fw; |
| 229 | 229 | u8 *firmware_buf; |
| 230 | + int len; | |
| 230 | 231 | |
| 231 | 232 | ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, |
| 232 | 233 | &gspca_dev->dev->dev); |
| @@ -241,9 +242,14 @@ static int sd_init(struct gspca_dev *gspca_dev) · 8 unmodified lines | ||
| 241 | 242 | goto exit; |
| 242 | 243 | } |
| 243 | 244 | for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { |
| 244 | − memcpy(firmware_buf, rec->data, be16_to_cpu(rec->len)); | |
| 245 | + len = be16_to_cpu(rec->len); | |
| 246 | + if (len > PAGE_SIZE) { | |
| 247 | + ret = -EINVAL; | |
| 248 | + break; | |
| 249 | + } | |
| 250 | + memcpy(firmware_buf, rec->data, len); | |
| 245 | 251 | ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, |
| 246 | − be16_to_cpu(rec->len)); | |
| 252 | + len); | |
| 247 | 253 | if (ret < 0) |
| 248 | 254 | break; |
| 249 | 255 | } |
| @@ -124,32 +124,12 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, · 123 unmodified lines | ||
| 124 | 124 | else |
| 125 | 125 | retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, |
| 126 | 126 | msgs[0].len); |
| 127 | − } else if (num == 2) { | |
| 128 | − if (msgs[0].addr != msgs[1].addr) { | |
| 129 | − v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n"); | |
| 130 | − retval = -EINVAL; | |
| 131 | − goto out; | |
| 132 | − } | |
| 133 | − | |
| 134 | − if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { | |
| 135 | − v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n", | |
| 136 | − msgs[0].flags & I2C_M_RD, | |
| 137 | − msgs[1].flags & I2C_M_RD); | |
| 138 | − retval = -EINVAL; | |
| 139 | − goto out; | |
| 140 | − } | |
| 141 | − | |
| 142 | − /* | |
| 143 | − * Write followed by atomic read is the only complex xfer that | |
| 144 | − * we actually support here. | |
| 145 | − */ | |
| 127 | + } else { | |
| 128 | + /* do write-then-read */ | |
| 146 | 129 | retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, |
| 147 | 130 | msgs[1].buf, msgs[1].len); |
| 148 | − } else { | |
| 149 | − v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); | |
| 150 | 131 | } |
| 151 | 132 | |
| 152 | −out: | |
| 153 | 133 | mutex_unlock(&dev->i2c_mutex); |
| 154 | 134 | |
| 155 | 135 | return retval ? retval : num; |
| @@ -165,10 +145,16 @@ static const struct i2c_algorithm hdpvr_algo = { · 9 unmodified lines | ||
| 165 | 145 | .functionality = hdpvr_functionality, |
| 166 | 146 | }; |
| 167 | 147 | |
| 148 | +/* prevent invalid 0-length usb_control_msg and support only write-then-read */ | |
| 149 | +static const struct i2c_adapter_quirks hdpvr_quirks = { | |
| 150 | + .flags = I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_COMB_WRITE_THEN_READ, | |
| 151 | +}; | |
| 152 | + | |
| 168 | 153 | static const struct i2c_adapter hdpvr_i2c_adapter_template = { |
| 169 | 154 | .name = "Hauppauge HD PVR I2C", |
| 170 | 155 | .owner = THIS_MODULE, |
| 171 | 156 | .algo = &hdpvr_algo, |
| 157 | + .quirks = &hdpvr_quirks, | |
| 172 | 158 | }; |
| 173 | 159 | |
| 174 | 160 | static int hdpvr_activate_ir(struct hdpvr_device *dev) |
| @@ -73,6 +73,10 @@ static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) · 72 unmodified lines | ||
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | if (params) { |
| 76 | + if (vb2_is_busy(&usbtv->vb2q) && | |
| 77 | + (usbtv->width != params->cap_width || | |
| 78 | + usbtv->height != params->cap_height)) | |
| 79 | + return -EBUSY; | |
| 76 | 80 | usbtv->width = params->cap_width; |
| 77 | 81 | usbtv->height = params->cap_height; |
| 78 | 82 | usbtv->n_chunks = usbtv->width * usbtv->height |
| @@ -1483,14 +1483,28 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl, · 1482 unmodified lines | ||
| 1483 | 1483 | return ~0; |
| 1484 | 1484 | } |
| 1485 | 1485 | |
| 1486 | +/* | |
| 1487 | + * Maximum retry count to avoid spurious errors with controls. Increasing this | |
| 1488 | + * value does no seem to produce better results in the tested hardware. | |
| 1489 | + */ | |
| 1490 | +#define MAX_QUERY_RETRIES 2 | |
| 1491 | + | |
| 1486 | 1492 | static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain, |
| 1487 | 1493 | struct uvc_control *ctrl, |
| 1488 | 1494 | struct uvc_control_mapping *mapping, |
| 1489 | 1495 | struct v4l2_query_ext_ctrl *v4l2_ctrl) |
| 1490 | 1496 | { |
| 1491 | 1497 | if (!ctrl->cached) { |
| 1492 | − int ret = uvc_ctrl_populate_cache(chain, ctrl); | |
| 1493 | − if (ret < 0) | |
| 1498 | + unsigned int retries; | |
| 1499 | + int ret; | |
| 1500 | + | |
| 1501 | + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { | |
| 1502 | + ret = uvc_ctrl_populate_cache(chain, ctrl); | |
| 1503 | + if (ret != -EIO) | |
| 1504 | + break; | |
| 1505 | + } | |
| 1506 | + | |
| 1507 | + if (ret) | |
| 1494 | 1508 | return ret; |
| 1495 | 1509 | } |
| 1496 | 1510 | |
| @@ -1567,6 +1581,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, · 70 unmodified lines | ||
| 1567 | 1581 | { |
| 1568 | 1582 | struct uvc_control_mapping *master_map = NULL; |
| 1569 | 1583 | struct uvc_control *master_ctrl = NULL; |
| 1584 | + int ret; | |
| 1570 | 1585 | |
| 1571 | 1586 | memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); |
| 1572 | 1587 | v4l2_ctrl->id = mapping->id; |
| @@ -1587,18 +1602,31 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, · 14 unmodified lines | ||
| 1587 | 1602 | __uvc_find_control(ctrl->entity, mapping->master_id, |
| 1588 | 1603 | &master_map, &master_ctrl, 0, 0); |
| 1589 | 1604 | if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { |
| 1605 | + unsigned int retries; | |
| 1590 | 1606 | s32 val; |
| 1591 | 1607 | int ret; |
| 1592 | 1608 | |
| 1593 | 1609 | if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) |
| 1594 | 1610 | return -EIO; |
| 1595 | 1611 | |
| 1596 | − ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); | |
| 1597 | − if (ret < 0) | |
| 1598 | − return ret; | |
| 1612 | + for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { | |
| 1613 | + ret = __uvc_ctrl_get(chain, master_ctrl, master_map, | |
| 1614 | + &val); | |
| 1615 | + if (!ret) | |
| 1616 | + break; | |
| 1617 | + if (ret < 0 && ret != -EIO) | |
| 1618 | + return ret; | |
| 1619 | + } | |
| 1599 | 1620 | |
| 1600 | − if (val != mapping->master_manual) | |
| 1601 | − v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | |
| 1621 | + if (ret == -EIO) { | |
| 1622 | + dev_warn_ratelimited(&chain->dev->udev->dev, | |
| 1623 | + "UVC non compliance: Error %d querying master control %x (%s)\n", | |
| 1624 | + ret, master_map->id, | |
| 1625 | + uvc_map_get_name(master_map)); | |
| 1626 | + } else { | |
| 1627 | + if (val != mapping->master_manual) | |
| 1628 | + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | |
| 1629 | + } | |
| 1602 | 1630 | } |
| 1603 | 1631 | |
| 1604 | 1632 | v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping); |
| @@ -1613,7 +1641,18 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, · 8 unmodified lines | ||
| 1613 | 1641 | return 0; |
| 1614 | 1642 | } |
| 1615 | 1643 | |
| 1616 | − return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); | |
| 1644 | + ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); | |
| 1645 | + if (ret && !mapping->disabled) { | |
| 1646 | + dev_warn(&chain->dev->udev->dev, | |
| 1647 | + "UVC non compliance: permanently disabling control %x (%s), due to error %d\n", | |
| 1648 | + mapping->id, uvc_map_get_name(mapping), ret); | |
| 1649 | + mapping->disabled = true; | |
| 1650 | + } | |
| 1651 | + | |
| 1652 | + if (mapping->disabled) | |
| 1653 | + v4l2_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | |
| 1654 | + | |
| 1655 | + return 0; | |
| 1617 | 1656 | } |
| 1618 | 1657 | |
| 1619 | 1658 | int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, |
| @@ -1812,48 +1851,48 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain, · 192 unmodified lines | ||
| 1812 | 1851 | uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); |
| 1813 | 1852 | } |
| 1814 | 1853 | |
| 1815 | −static int uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl, | |
| 1816 | − struct uvc_fh *new_handle) | |
| 1854 | +static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) | |
| 1817 | 1855 | { |
| 1818 | − lockdep_assert_held(&handle->chain->ctrl_mutex); | |
| 1819 | − | |
| 1820 | − if (new_handle) { | |
| 1821 | − int ret; | |
| 1856 | + int ret; | |
| 1822 | 1857 | |
| 1823 | − if (ctrl->handle) | |
| 1824 | − dev_warn_ratelimited(&handle->stream->dev->udev->dev, | |
| 1825 | − "UVC non compliance: Setting an async control with a pending operation."); | |
| 1858 | + lockdep_assert_held(&handle->chain->ctrl_mutex); | |
| 1826 | 1859 | |
| 1827 | − if (new_handle == ctrl->handle) | |
| 1828 | − return 0; | |
| 1860 | + if (ctrl->handle) { | |
| 1861 | + dev_warn_ratelimited(&handle->stream->dev->udev->dev, | |
| 1862 | + "UVC non compliance: Setting an async control with a pending operation."); | |
| 1829 | 1863 | |
| 1830 | − if (ctrl->handle) { | |
| 1831 | − WARN_ON(!ctrl->handle->pending_async_ctrls); | |
| 1832 | − if (ctrl->handle->pending_async_ctrls) | |
| 1833 | − ctrl->handle->pending_async_ctrls--; | |
| 1834 | − ctrl->handle = new_handle; | |
| 1835 | − handle->pending_async_ctrls++; | |
| 1864 | + if (ctrl->handle == handle) | |
| 1836 | 1865 | return 0; |
| 1837 | − } | |
| 1838 | − | |
| 1839 | − ret = uvc_pm_get(handle->chain->dev); | |
| 1840 | − if (ret) | |
| 1841 | − return ret; | |
| 1842 | 1866 | |
| 1843 | − ctrl->handle = new_handle; | |
| 1844 | − handle->pending_async_ctrls++; | |
| 1867 | + WARN_ON(!ctrl->handle->pending_async_ctrls); | |
| 1868 | + if (ctrl->handle->pending_async_ctrls) | |
| 1869 | + ctrl->handle->pending_async_ctrls--; | |
| 1870 | + ctrl->handle = handle; | |
| 1871 | + ctrl->handle->pending_async_ctrls++; | |
| 1845 | 1872 | return 0; |
| 1846 | 1873 | } |
| 1847 | 1874 | |
| 1848 | − /* Cannot clear the handle for a control not owned by us.*/ | |
| 1849 | − if (WARN_ON(ctrl->handle != handle)) | |
| 1875 | + ret = uvc_pm_get(handle->chain->dev); | |
| 1876 | + if (ret) | |
| 1877 | + return ret; | |
| 1878 | + | |
| 1879 | + ctrl->handle = handle; | |
| 1880 | + ctrl->handle->pending_async_ctrls++; | |
| 1881 | + return 0; | |
| 1882 | +} | |
| 1883 | + | |
| 1884 | +static int uvc_ctrl_clear_handle(struct uvc_control *ctrl) | |
| 1885 | +{ | |
| 1886 | + lockdep_assert_held(&ctrl->handle->chain->ctrl_mutex); | |
| 1887 | + | |
| 1888 | + if (WARN_ON(!ctrl->handle->pending_async_ctrls)) { | |
| 1889 | + ctrl->handle = NULL; | |
| 1850 | 1890 | return -EINVAL; |
| 1891 | + } | |
| 1851 | 1892 | |
| 1893 | + ctrl->handle->pending_async_ctrls--; | |
| 1894 | + uvc_pm_put(ctrl->handle->chain->dev); | |
| 1852 | 1895 | ctrl->handle = NULL; |
| 1853 | − if (WARN_ON(!handle->pending_async_ctrls)) | |
| 1854 | − return -EINVAL; | |
| 1855 | − handle->pending_async_ctrls--; | |
| 1856 | − uvc_pm_put(handle->chain->dev); | |
| 1857 | 1896 | return 0; |
| 1858 | 1897 | } |
| 1859 | 1898 | |
| @@ -1871,7 +1910,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain, · 11 unmodified lines | ||
| 1871 | 1910 | |
| 1872 | 1911 | handle = ctrl->handle; |
| 1873 | 1912 | if (handle) |
| 1874 | − uvc_ctrl_set_handle(handle, ctrl, NULL); | |
| 1913 | + uvc_ctrl_clear_handle(ctrl); | |
| 1875 | 1914 | |
| 1876 | 1915 | list_for_each_entry(mapping, &ctrl->info.mappings, list) { |
| 1877 | 1916 | s32 value; |
| @@ -2033,18 +2072,24 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) · 155 unmodified lines | ||
| 2033 | 2072 | goto done; |
| 2034 | 2073 | } |
| 2035 | 2074 | |
| 2036 | − list_add_tail(&sev->node, &mapping->ev_subs); | |
| 2037 | 2075 | if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { |
| 2038 | 2076 | struct v4l2_event ev; |
| 2039 | 2077 | u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; |
| 2040 | 2078 | s32 val = 0; |
| 2041 | 2079 | |
| 2080 | + ret = uvc_pm_get(handle->chain->dev); | |
| 2081 | + if (ret) | |
| 2082 | + goto done; | |
| 2083 | + | |
| 2042 | 2084 | if (uvc_ctrl_mapping_is_compound(mapping) || |
| 2043 | 2085 | __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) |
| 2044 | 2086 | changes |= V4L2_EVENT_CTRL_CH_VALUE; |
| 2045 | 2087 | |
| 2046 | 2088 | uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, |
| 2047 | 2089 | changes); |
| 2090 | + | |
| 2091 | + uvc_pm_put(handle->chain->dev); | |
| 2092 | + | |
| 2048 | 2093 | /* |
| 2049 | 2094 | * Mark the queue as active, allowing this initial event to be |
| 2050 | 2095 | * accepted. |
| @@ -2053,6 +2098,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) · 2 unmodified lines | ||
| 2053 | 2098 | v4l2_event_queue_fh(sev->fh, &ev); |
| 2054 | 2099 | } |
| 2055 | 2100 | |
| 2101 | + list_add_tail(&sev->node, &mapping->ev_subs); | |
| 2102 | + | |
| 2056 | 2103 | done: |
| 2057 | 2104 | mutex_unlock(&handle->chain->ctrl_mutex); |
| 2058 | 2105 | return ret; |
| @@ -2161,7 +2208,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, · 102 unmodified lines | ||
| 2161 | 2208 | |
| 2162 | 2209 | if (!rollback && handle && !ret && |
| 2163 | 2210 | ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) |
| 2164 | − ret = uvc_ctrl_set_handle(handle, ctrl, handle); | |
| 2211 | + ret = uvc_ctrl_set_handle(ctrl, handle); | |
| 2165 | 2212 | |
| 2166 | 2213 | if (ret < 0 && !rollback) { |
| 2167 | 2214 | if (err_ctrl) |
| @@ -3271,7 +3318,7 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) · 1103 unmodified lines | ||
| 3271 | 3318 | for (unsigned int i = 0; i < entity->ncontrols; ++i) { |
| 3272 | 3319 | if (entity->controls[i].handle != handle) |
| 3273 | 3320 | continue; |
| 3274 | − uvc_ctrl_set_handle(handle, &entity->controls[i], NULL); | |
| 3321 | + uvc_ctrl_clear_handle(&entity->controls[i]); | |
| 3275 | 3322 | } |
| 3276 | 3323 | } |
| 3277 | 3324 | |
| @@ -344,6 +344,9 @@ static int uvc_parse_format(struct uvc_device *dev, · 343 unmodified lines | ||
| 344 | 344 | u8 ftype; |
| 345 | 345 | int ret; |
| 346 | 346 | |
| 347 | + if (buflen < 4) | |
| 348 | + return -EINVAL; | |
| 349 | + | |
| 347 | 350 | format->type = buffer[2]; |
| 348 | 351 | format->index = buffer[3]; |
| 349 | 352 | format->frames = frames; |
| @@ -1866,7 +1869,7 @@ static int uvc_scan_device(struct uvc_device *dev) · 1516 unmodified lines | ||
| 1866 | 1869 | |
| 1867 | 1870 | if (list_empty(&dev->chains)) { |
| 1868 | 1871 | dev_info(&dev->udev->dev, "No valid video chain found.\n"); |
| 1869 | − return -1; | |
| 1872 | + return -ENODEV; | |
| 1870 | 1873 | } |
| 1871 | 1874 | |
| 1872 | 1875 | /* Add GPIO entity to the first chain. */ |
| @@ -1958,31 +1961,7 @@ static void uvc_unregister_video(struct uvc_device *dev) · 85 unmodified lines | ||
| 1958 | 1961 | if (!video_is_registered(&stream->vdev)) |
| 1959 | 1962 | continue; |
| 1960 | 1963 | |
| 1961 | − /* | |
| 1962 | − * For stream->vdev we follow the same logic as: | |
| 1963 | − * vb2_video_unregister_device(). | |
| 1964 | − */ | |
| 1965 | − | |
| 1966 | − /* 1. Take a reference to vdev */ | |
| 1967 | − get_device(&stream->vdev.dev); | |
| 1968 | − | |
| 1969 | − /* 2. Ensure that no new ioctls can be called. */ | |
| 1970 | − video_unregister_device(&stream->vdev); | |
| 1971 | − | |
| 1972 | − /* 3. Wait for old ioctls to finish. */ | |
| 1973 | − mutex_lock(&stream->mutex); | |
| 1974 | − | |
| 1975 | − /* 4. Stop streaming. */ | |
| 1976 | − uvc_queue_release(&stream->queue); | |
| 1977 | − | |
| 1978 | − mutex_unlock(&stream->mutex); | |
| 1979 | − | |
| 1980 | − put_device(&stream->vdev.dev); | |
| 1981 | − | |
| 1982 | − /* | |
| 1983 | − * For stream->meta.vdev we can directly call: | |
| 1984 | − * vb2_video_unregister_device(). | |
| 1985 | − */ | |
| 1964 | + vb2_video_unregister_device(&stream->vdev); | |
| 1986 | 1965 | vb2_video_unregister_device(&stream->meta.vdev); |
| 1987 | 1966 | |
| 1988 | 1967 | /* |
| @@ -2030,6 +2009,8 @@ int uvc_register_video_device(struct uvc_device *dev, · 41 unmodified lines | ||
| 2030 | 2009 | vdev->ioctl_ops = ioctl_ops; |
| 2031 | 2010 | vdev->release = uvc_release; |
| 2032 | 2011 | vdev->prio = &stream->chain->prio; |
| 2012 | + vdev->queue = &queue->queue; | |
| 2013 | + vdev->lock = &queue->mutex; | |
| 2033 | 2014 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
| 2034 | 2015 | vdev->vfl_dir = VFL_DIR_TX; |
| 2035 | 2016 | else |
| @@ -2239,7 +2220,6 @@ static int uvc_probe(struct usb_interface *intf, · 203 unmodified lines | ||
| 2239 | 2220 | /* Parse the Video Class control descriptor. */ |
| 2240 | 2221 | ret = uvc_parse_control(dev); |
| 2241 | 2222 | if (ret < 0) { |
| 2242 | − ret = -ENODEV; | |
| 2243 | 2223 | uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); |
| 2244 | 2224 | goto error; |
| 2245 | 2225 | } |
| @@ -2275,22 +2255,19 @@ static int uvc_probe(struct usb_interface *intf, · 29 unmodified lines | ||
| 2275 | 2255 | goto error; |
| 2276 | 2256 | |
| 2277 | 2257 | /* Scan the device for video chains. */ |
| 2278 | − if (uvc_scan_device(dev) < 0) { | |
| 2279 | − ret = -ENODEV; | |
| 2258 | + ret = uvc_scan_device(dev); | |
| 2259 | + if (ret < 0) | |
| 2280 | 2260 | goto error; |
| 2281 | − } | |
| 2282 | 2261 | |
| 2283 | 2262 | /* Initialize controls. */ |
| 2284 | − if (uvc_ctrl_init_device(dev) < 0) { | |
| 2285 | − ret = -ENODEV; | |
| 2263 | + ret = uvc_ctrl_init_device(dev); | |
| 2264 | + if (ret < 0) | |
| 2286 | 2265 | goto error; |
| 2287 | − } | |
| 2288 | 2266 | |
| 2289 | 2267 | /* Register video device nodes. */ |
| 2290 | − if (uvc_register_chains(dev) < 0) { | |
| 2291 | − ret = -ENODEV; | |
| 2268 | + ret = uvc_register_chains(dev); | |
| 2269 | + if (ret < 0) | |
| 2292 | 2270 | goto error; |
| 2293 | − } | |
| 2294 | 2271 | |
| 2295 | 2272 | #ifdef CONFIG_MEDIA_CONTROLLER |
| 2296 | 2273 | /* Register the media device node */ |
| @@ -2316,6 +2293,13 @@ static int uvc_probe(struct usb_interface *intf, · 19 unmodified lines | ||
| 2316 | 2293 | goto error; |
| 2317 | 2294 | } |
| 2318 | 2295 | |
| 2296 | + ret = uvc_meta_init(dev); | |
| 2297 | + if (ret < 0) { | |
| 2298 | + dev_err(&dev->udev->dev, | |
| 2299 | + "Error initializing the metadata formats (%d)\n", ret); | |
| 2300 | + goto error; | |
| 2301 | + } | |
| 2302 | + | |
| 2319 | 2303 | if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) |
| 2320 | 2304 | udev->quirks &= ~USB_QUIRK_RESET_RESUME; |
| 2321 | 2305 | |
| @@ -2398,9 +2382,12 @@ static int __uvc_resume(struct usb_interface *intf, int reset) · 76 unmodified lines | ||
| 2398 | 2382 | list_for_each_entry(stream, &dev->streams, list) { |
| 2399 | 2383 | if (stream->intf == intf) { |
| 2400 | 2384 | ret = uvc_video_resume(stream, reset); |
| 2401 | − if (ret < 0) | |
| 2402 | − uvc_queue_streamoff(&stream->queue, | |
| 2403 | − stream->queue.queue.type); | |
| 2385 | + if (ret < 0) { | |
| 2386 | + mutex_lock(&stream->queue.mutex); | |
| 2387 | + vb2_streamoff(&stream->queue.queue, | |
| 2388 | + stream->queue.queue.type); | |
| 2389 | + mutex_unlock(&stream->queue.mutex); | |
| 2390 | + } | |
| 2404 | 2391 | return ret; |
| 2405 | 2392 | } |
| 2406 | 2393 | } |
| @@ -2514,6 +2501,15 @@ static const struct uvc_device_info uvc_quirk_force_y8 = { · 107 unmodified lines | ||
| 2514 | 2501 | * Sort these by vendor/product ID. |
| 2515 | 2502 | */ |
| 2516 | 2503 | static const struct usb_device_id uvc_ids[] = { |
| 2504 | + /* HP Webcam HD 2300 */ | |
| 2505 | + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| 2506 | + | USB_DEVICE_ID_MATCH_INT_INFO, | |
| 2507 | + .idVendor = 0x03f0, | |
| 2508 | + .idProduct = 0xe207, | |
| 2509 | + .bInterfaceClass = USB_CLASS_VIDEO, | |
| 2510 | + .bInterfaceSubClass = 1, | |
| 2511 | + .bInterfaceProtocol = 0, | |
| 2512 | + .driver_info = (kernel_ulong_t)&uvc_quirk_stream_no_fid }, | |
| 2517 | 2513 | /* Quanta ACER HD User Facing */ |
| 2518 | 2514 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
| 2519 | 2515 | | USB_DEVICE_ID_MATCH_INT_INFO, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/list.h> |
| 11 | 11 | #include <linux/module.h> |
| 12 | 12 | #include <linux/usb.h> |
| 13 | +#include <linux/usb/uvc.h> | |
| 13 | 14 | #include <linux/videodev2.h> |
| 14 | 15 | |
| 15 | 16 | #include <media/v4l2-ioctl.h> |
| @@ -63,15 +64,20 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, · 47 unmodified lines | ||
| 63 | 64 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); |
| 64 | 65 | struct uvc_device *dev = stream->dev; |
| 65 | 66 | struct v4l2_meta_format *fmt = &format->fmt.meta; |
| 66 | − u32 fmeta = fmt->dataformat; | |
| 67 | + u32 fmeta = V4L2_META_FMT_UVC; | |
| 67 | 68 | |
| 68 | 69 | if (format->type != vfh->vdev->queue->type) |
| 69 | 70 | return -EINVAL; |
| 70 | 71 | |
| 72 | + for (unsigned int i = 0; i < dev->nmeta_formats; i++) | |
| 73 | + if (dev->meta_formats[i] == fmt->dataformat) { | |
| 74 | + fmeta = fmt->dataformat; | |
| 75 | + break; | |
| 76 | + } | |
| 77 | + | |
| 71 | 78 | memset(fmt, 0, sizeof(*fmt)); |
| 72 | 79 | |
| 73 | − fmt->dataformat = fmeta == dev->info->meta_format | |
| 74 | − ? fmeta : V4L2_META_FMT_UVC; | |
| 80 | + fmt->dataformat = fmeta; | |
| 75 | 81 | fmt->buffersize = UVC_METADATA_BUF_SIZE; |
| 76 | 82 | |
| 77 | 83 | return 0; |
| @@ -96,7 +102,7 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, · 18 unmodified lines | ||
| 96 | 102 | */ |
| 97 | 103 | mutex_lock(&stream->mutex); |
| 98 | 104 | |
| 99 | − if (uvc_queue_allocated(&stream->queue)) | |
| 105 | + if (vb2_is_busy(&stream->meta.queue.queue)) | |
| 100 | 106 | ret = -EBUSY; |
| 101 | 107 | else |
| 102 | 108 | stream->meta.format = fmt->dataformat; |
| @@ -112,17 +118,19 @@ static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, · 9 unmodified lines | ||
| 112 | 118 | struct v4l2_fh *vfh = file->private_data; |
| 113 | 119 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); |
| 114 | 120 | struct uvc_device *dev = stream->dev; |
| 115 | − u32 index = fdesc->index; | |
| 121 | + u32 i = fdesc->index; | |
| 122 | + | |
| 123 | + if (fdesc->type != vfh->vdev->queue->type) | |
| 124 | + return -EINVAL; | |
| 116 | 125 | |
| 117 | − if (fdesc->type != vfh->vdev->queue->type || | |
| 118 | − index > 1U || (index && !dev->info->meta_format)) | |
| 126 | + if (i >= dev->nmeta_formats) | |
| 119 | 127 | return -EINVAL; |
| 120 | 128 | |
| 121 | 129 | memset(fdesc, 0, sizeof(*fdesc)); |
| 122 | 130 | |
| 123 | 131 | fdesc->type = vfh->vdev->queue->type; |
| 124 | − fdesc->index = index; | |
| 125 | − fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC; | |
| 132 | + fdesc->index = i; | |
| 133 | + fdesc->pixelformat = dev->meta_formats[i]; | |
| 126 | 134 | |
| 127 | 135 | return 0; |
| 128 | 136 | } |
| @@ -156,6 +164,71 @@ static const struct v4l2_file_operations uvc_meta_fops = { · 27 unmodified lines | ||
| 156 | 164 | .mmap = vb2_fop_mmap, |
| 157 | 165 | }; |
| 158 | 166 | |
| 167 | +static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev) | |
| 168 | +{ | |
| 169 | + static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5; | |
| 170 | + struct uvc_entity *entity; | |
| 171 | + | |
| 172 | + list_for_each_entry(entity, &dev->entities, list) { | |
| 173 | + if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid))) | |
| 174 | + return entity; | |
| 175 | + } | |
| 176 | + | |
| 177 | + return NULL; | |
| 178 | +} | |
| 179 | + | |
| 180 | +#define MSXU_CONTROL_METADATA 0x9 | |
| 181 | +static int uvc_meta_detect_msxu(struct uvc_device *dev) | |
| 182 | +{ | |
| 183 | + u32 *data __free(kfree) = NULL; | |
| 184 | + struct uvc_entity *entity; | |
| 185 | + int ret; | |
| 186 | + | |
| 187 | + entity = uvc_meta_find_msxu(dev); | |
| 188 | + if (!entity) | |
| 189 | + return 0; | |
| 190 | + | |
| 191 | + /* | |
| 192 | + * USB requires buffers aligned in a special way, simplest way is to | |
| 193 | + * make sure that query_ctrl will work is to kmalloc() them. | |
| 194 | + */ | |
| 195 | + data = kmalloc(sizeof(*data), GFP_KERNEL); | |
| 196 | + if (!data) | |
| 197 | + return -ENOMEM; | |
| 198 | + | |
| 199 | + /* Check if the metadata is already enabled. */ | |
| 200 | + ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum, | |
| 201 | + MSXU_CONTROL_METADATA, data, sizeof(*data)); | |
| 202 | + if (ret) | |
| 203 | + return 0; | |
| 204 | + | |
| 205 | + if (*data) { | |
| 206 | + dev->quirks |= UVC_QUIRK_MSXU_META; | |
| 207 | + return 0; | |
| 208 | + } | |
| 209 | + | |
| 210 | + /* | |
| 211 | + * We have seen devices that require 1 to enable the metadata, others | |
| 212 | + * requiring a value != 1 and others requiring a value >1. Luckily for | |
| 213 | + * us, the value from GET_MAX seems to work all the time. | |
| 214 | + */ | |
| 215 | + ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum, | |
| 216 | + MSXU_CONTROL_METADATA, data, sizeof(*data)); | |
| 217 | + if (ret || !*data) | |
| 218 | + return 0; | |
| 219 | + | |
| 220 | + /* | |
| 221 | + * If we can set MSXU_CONTROL_METADATA, the device will report | |
| 222 | + * metadata. | |
| 223 | + */ | |
| 224 | + ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum, | |
| 225 | + MSXU_CONTROL_METADATA, data, sizeof(*data)); | |
| 226 | + if (!ret) | |
| 227 | + dev->quirks |= UVC_QUIRK_MSXU_META; | |
| 228 | + | |
| 229 | + return 0; | |
| 230 | +} | |
| 231 | + | |
| 159 | 232 | int uvc_meta_register(struct uvc_streaming *stream) |
| 160 | 233 | { |
| 161 | 234 | struct uvc_device *dev = stream->dev; |
| @@ -164,13 +237,32 @@ int uvc_meta_register(struct uvc_streaming *stream) · 2 unmodified lines | ||
| 164 | 237 | |
| 165 | 238 | stream->meta.format = V4L2_META_FMT_UVC; |
| 166 | 239 | |
| 167 | − /* | |
| 168 | − * The video interface queue uses manual locking and thus does not set | |
| 169 | − * the queue pointer. Set it manually here. | |
| 170 | − */ | |
| 171 | − vdev->queue = &queue->queue; | |
| 172 | − | |
| 173 | 240 | return uvc_register_video_device(dev, stream, vdev, queue, |
| 174 | 241 | V4L2_BUF_TYPE_META_CAPTURE, |
| 175 | 242 | &uvc_meta_fops, &uvc_meta_ioctl_ops); |
| 176 | 243 | } |
| 244 | + | |
| 245 | +int uvc_meta_init(struct uvc_device *dev) | |
| 246 | +{ | |
| 247 | + unsigned int i = 0; | |
| 248 | + int ret; | |
| 249 | + | |
| 250 | + ret = uvc_meta_detect_msxu(dev); | |
| 251 | + if (ret) | |
| 252 | + return ret; | |
| 253 | + | |
| 254 | + dev->meta_formats[i++] = V4L2_META_FMT_UVC; | |
| 255 | + | |
| 256 | + if (dev->info->meta_format && | |
| 257 | + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC)) | |
| 258 | + dev->meta_formats[i++] = dev->info->meta_format; | |
| 259 | + | |
| 260 | + if (dev->quirks & UVC_QUIRK_MSXU_META && | |
| 261 | + !WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5)) | |
| 262 | + dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5; | |
| 263 | + | |
| 264 | + /* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */ | |
| 265 | + dev->nmeta_formats = i; | |
| 266 | + | |
| 267 | + return 0; | |
| 268 | +} | |
| @@ -42,13 +42,15 @@ static inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf) · 41 unmodified lines | ||
| 42 | 42 | * |
| 43 | 43 | * This function must be called with the queue spinlock held. |
| 44 | 44 | */ |
| 45 | −static void uvc_queue_return_buffers(struct uvc_video_queue *queue, | |
| 46 | − enum uvc_buffer_state state) | |
| 45 | +static void __uvc_queue_return_buffers(struct uvc_video_queue *queue, | |
| 46 | + enum uvc_buffer_state state) | |
| 47 | 47 | { |
| 48 | 48 | enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR |
| 49 | 49 | ? VB2_BUF_STATE_ERROR |
| 50 | 50 | : VB2_BUF_STATE_QUEUED; |
| 51 | 51 | |
| 52 | + lockdep_assert_held(&queue->irqlock); | |
| 53 | + | |
| 52 | 54 | while (!list_empty(&queue->irqqueue)) { |
| 53 | 55 | struct uvc_buffer *buf = list_first_entry(&queue->irqqueue, |
| 54 | 56 | struct uvc_buffer, |
| @@ -59,6 +61,14 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue, · 4 unmodified lines | ||
| 59 | 61 | } |
| 60 | 62 | } |
| 61 | 63 | |
| 64 | +static void uvc_queue_return_buffers(struct uvc_video_queue *queue, | |
| 65 | + enum uvc_buffer_state state) | |
| 66 | +{ | |
| 67 | + spin_lock_irq(&queue->irqlock); | |
| 68 | + __uvc_queue_return_buffers(queue, state); | |
| 69 | + spin_unlock_irq(&queue->irqlock); | |
| 70 | +} | |
| 71 | + | |
| 62 | 72 | /* ----------------------------------------------------------------------------- |
| 63 | 73 | * videobuf2 queue operations |
| 64 | 74 | */ |
| @@ -157,7 +167,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) · 92 unmodified lines | ||
| 157 | 167 | uvc_video_clock_update(stream, vbuf, buf); |
| 158 | 168 | } |
| 159 | 169 | |
| 160 | −static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) | |
| 170 | +static int uvc_start_streaming_video(struct vb2_queue *vq, unsigned int count) | |
| 161 | 171 | { |
| 162 | 172 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); |
| 163 | 173 | struct uvc_streaming *stream = uvc_queue_to_stream(queue); |
| @@ -165,31 +175,44 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) · 1 unmodified line | ||
| 165 | 175 | |
| 166 | 176 | lockdep_assert_irqs_enabled(); |
| 167 | 177 | |
| 178 | + ret = uvc_pm_get(stream->dev); | |
| 179 | + if (ret) | |
| 180 | + return ret; | |
| 181 | + | |
| 168 | 182 | queue->buf_used = 0; |
| 169 | 183 | |
| 170 | 184 | ret = uvc_video_start_streaming(stream); |
| 171 | 185 | if (ret == 0) |
| 172 | 186 | return 0; |
| 173 | 187 | |
| 174 | − spin_lock_irq(&queue->irqlock); | |
| 188 | + uvc_pm_put(stream->dev); | |
| 189 | + | |
| 175 | 190 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); |
| 176 | − spin_unlock_irq(&queue->irqlock); | |
| 177 | 191 | |
| 178 | 192 | return ret; |
| 179 | 193 | } |
| 180 | 194 | |
| 181 | −static void uvc_stop_streaming(struct vb2_queue *vq) | |
| 195 | +static void uvc_stop_streaming_video(struct vb2_queue *vq) | |
| 182 | 196 | { |
| 183 | 197 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); |
| 198 | + struct uvc_streaming *stream = uvc_queue_to_stream(queue); | |
| 184 | 199 | |
| 185 | 200 | lockdep_assert_irqs_enabled(); |
| 186 | 201 | |
| 187 | − if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) | |
| 188 | − uvc_video_stop_streaming(uvc_queue_to_stream(queue)); | |
| 202 | + uvc_video_stop_streaming(uvc_queue_to_stream(queue)); | |
| 203 | + | |
| 204 | + uvc_pm_put(stream->dev); | |
| 205 | + | |
| 206 | + uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); | |
| 207 | +} | |
| 208 | + | |
| 209 | +static void uvc_stop_streaming_meta(struct vb2_queue *vq) | |
| 210 | +{ | |
| 211 | + struct uvc_video_queue *queue = vb2_get_drv_priv(vq); | |
| 212 | + | |
| 213 | + lockdep_assert_irqs_enabled(); | |
| 189 | 214 | |
| 190 | − spin_lock_irq(&queue->irqlock); | |
| 191 | 215 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); |
| 192 | − spin_unlock_irq(&queue->irqlock); | |
| 193 | 216 | } |
| 194 | 217 | |
| 195 | 218 | static const struct vb2_ops uvc_queue_qops = { |
| @@ -197,15 +220,20 @@ static const struct vb2_ops uvc_queue_qops = { · 1 unmodified line | ||
| 197 | 220 | .buf_prepare = uvc_buffer_prepare, |
| 198 | 221 | .buf_queue = uvc_buffer_queue, |
| 199 | 222 | .buf_finish = uvc_buffer_finish, |
| 200 | − .start_streaming = uvc_start_streaming, | |
| 201 | − .stop_streaming = uvc_stop_streaming, | |
| 223 | + .start_streaming = uvc_start_streaming_video, | |
| 224 | + .stop_streaming = uvc_stop_streaming_video, | |
| 202 | 225 | }; |
| 203 | 226 | |
| 204 | 227 | static const struct vb2_ops uvc_meta_queue_qops = { |
| 205 | 228 | .queue_setup = uvc_queue_setup, |
| 206 | 229 | .buf_prepare = uvc_buffer_prepare, |
| 207 | 230 | .buf_queue = uvc_buffer_queue, |
| 208 | − .stop_streaming = uvc_stop_streaming, | |
| 231 | + /* | |
| 232 | + * .start_streaming is not provided here. Metadata relies on video | |
| 233 | + * streaming being active. If video isn't streaming, then no metadata | |
| 234 | + * will arrive either. | |
| 235 | + */ | |
| 236 | + .stop_streaming = uvc_stop_streaming_meta, | |
| 209 | 237 | }; |
| 210 | 238 | |
| 211 | 239 | int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) |
| @@ -242,153 +270,10 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) · 30 unmodified lines | ||
| 242 | 270 | return 0; |
| 243 | 271 | } |
| 244 | 272 | |
| 245 | −void uvc_queue_release(struct uvc_video_queue *queue) | |
| 246 | −{ | |
| 247 | − mutex_lock(&queue->mutex); | |
| 248 | − vb2_queue_release(&queue->queue); | |
| 249 | − mutex_unlock(&queue->mutex); | |
| 250 | −} | |
| 251 | − | |
| 252 | −/* ----------------------------------------------------------------------------- | |
| 253 | − * V4L2 queue operations | |
| 254 | − */ | |
| 255 | − | |
| 256 | −int uvc_request_buffers(struct uvc_video_queue *queue, | |
| 257 | − struct v4l2_requestbuffers *rb) | |
| 258 | −{ | |
| 259 | − int ret; | |
| 260 | − | |
| 261 | − mutex_lock(&queue->mutex); | |
| 262 | − ret = vb2_reqbufs(&queue->queue, rb); | |
| 263 | − mutex_unlock(&queue->mutex); | |
| 264 | − | |
| 265 | − return ret ? ret : rb->count; | |
| 266 | −} | |
| 267 | − | |
| 268 | −int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf) | |
| 269 | −{ | |
| 270 | − int ret; | |
| 271 | − | |
| 272 | − mutex_lock(&queue->mutex); | |
| 273 | − ret = vb2_querybuf(&queue->queue, buf); | |
| 274 | − mutex_unlock(&queue->mutex); | |
| 275 | − | |
| 276 | − return ret; | |
| 277 | −} | |
| 278 | − | |
| 279 | −int uvc_create_buffers(struct uvc_video_queue *queue, | |
| 280 | − struct v4l2_create_buffers *cb) | |
| 281 | −{ | |
| 282 | − int ret; | |
| 283 | − | |
| 284 | − mutex_lock(&queue->mutex); | |
| 285 | − ret = vb2_create_bufs(&queue->queue, cb); | |
| 286 | − mutex_unlock(&queue->mutex); | |
| 287 | − | |
| 288 | − return ret; | |
| 289 | −} | |
| 290 | − | |
| 291 | −int uvc_queue_buffer(struct uvc_video_queue *queue, | |
| 292 | − struct media_device *mdev, struct v4l2_buffer *buf) | |
| 293 | −{ | |
| 294 | − int ret; | |
| 295 | − | |
| 296 | − mutex_lock(&queue->mutex); | |
| 297 | − ret = vb2_qbuf(&queue->queue, mdev, buf); | |
| 298 | − mutex_unlock(&queue->mutex); | |
| 299 | − | |
| 300 | − return ret; | |
| 301 | −} | |
| 302 | − | |
| 303 | −int uvc_export_buffer(struct uvc_video_queue *queue, | |
| 304 | − struct v4l2_exportbuffer *exp) | |
| 305 | −{ | |
| 306 | − int ret; | |
| 307 | − | |
| 308 | − mutex_lock(&queue->mutex); | |
| 309 | − ret = vb2_expbuf(&queue->queue, exp); | |
| 310 | − mutex_unlock(&queue->mutex); | |
| 311 | − | |
| 312 | − return ret; | |
| 313 | −} | |
| 314 | − | |
| 315 | −int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf, | |
| 316 | − int nonblocking) | |
| 317 | −{ | |
| 318 | − int ret; | |
| 319 | − | |
| 320 | − mutex_lock(&queue->mutex); | |
| 321 | − ret = vb2_dqbuf(&queue->queue, buf, nonblocking); | |
| 322 | − mutex_unlock(&queue->mutex); | |
| 323 | − | |
| 324 | − return ret; | |
| 325 | −} | |
| 326 | − | |
| 327 | −int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type) | |
| 328 | −{ | |
| 329 | − int ret; | |
| 330 | − | |
| 331 | − mutex_lock(&queue->mutex); | |
| 332 | − ret = vb2_streamon(&queue->queue, type); | |
| 333 | − mutex_unlock(&queue->mutex); | |
| 334 | − | |
| 335 | − return ret; | |
| 336 | −} | |
| 337 | − | |
| 338 | −int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type) | |
| 339 | −{ | |
| 340 | − int ret; | |
| 341 | − | |
| 342 | − mutex_lock(&queue->mutex); | |
| 343 | − ret = vb2_streamoff(&queue->queue, type); | |
| 344 | − mutex_unlock(&queue->mutex); | |
| 345 | − | |
| 346 | − return ret; | |
| 347 | −} | |
| 348 | − | |
| 349 | −int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma) | |
| 350 | −{ | |
| 351 | − return vb2_mmap(&queue->queue, vma); | |
| 352 | −} | |
| 353 | − | |
| 354 | −#ifndef CONFIG_MMU | |
| 355 | −unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, | |
| 356 | − unsigned long pgoff) | |
| 357 | −{ | |
| 358 | − return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0); | |
| 359 | −} | |
| 360 | −#endif | |
| 361 | − | |
| 362 | −__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, | |
| 363 | − poll_table *wait) | |
| 364 | −{ | |
| 365 | − __poll_t ret; | |
| 366 | − | |
| 367 | − mutex_lock(&queue->mutex); | |
| 368 | − ret = vb2_poll(&queue->queue, file, wait); | |
| 369 | − mutex_unlock(&queue->mutex); | |
| 370 | − | |
| 371 | − return ret; | |
| 372 | −} | |
| 373 | − | |
| 374 | 273 | /* ----------------------------------------------------------------------------- |
| 375 | 274 | * |
| 376 | 275 | */ |
| 377 | 276 | |
| 378 | −/* | |
| 379 | − * Check if buffers have been allocated. | |
| 380 | − */ | |
| 381 | −int uvc_queue_allocated(struct uvc_video_queue *queue) | |
| 382 | −{ | |
| 383 | − int allocated; | |
| 384 | − | |
| 385 | − mutex_lock(&queue->mutex); | |
| 386 | − allocated = vb2_is_busy(&queue->queue); | |
| 387 | − mutex_unlock(&queue->mutex); | |
| 388 | − | |
| 389 | − return allocated; | |
| 390 | −} | |
| 391 | − | |
| 392 | 277 | /* |
| 393 | 278 | * Cancel the video buffers queue. |
| 394 | 279 | * |
| @@ -406,7 +291,7 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) · 11 unmodified lines | ||
| 406 | 291 | unsigned long flags; |
| 407 | 292 | |
| 408 | 293 | spin_lock_irqsave(&queue->irqlock, flags); |
| 409 | − uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); | |
| 294 | + __uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); | |
| 410 | 295 | /* |
| 411 | 296 | * This must be protected by the irqlock spinlock to avoid race |
| 412 | 297 | * conditions between uvc_buffer_queue and the disconnection event that |
| @@ -47,8 +47,6 @@ void uvc_pm_put(struct uvc_device *dev) · 46 unmodified lines | ||
| 47 | 47 | usb_autopm_put_interface(dev->intf); |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | −static int uvc_acquire_privileges(struct uvc_fh *handle); | |
| 51 | − | |
| 52 | 50 | static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, |
| 53 | 51 | struct uvc_control_mapping *map, |
| 54 | 52 | const struct uvc_xu_control_mapping *xmap) |
| @@ -436,10 +434,6 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, · 381 unmodified lines | ||
| 436 | 434 | const struct uvc_frame *frame; |
| 437 | 435 | int ret; |
| 438 | 436 | |
| 439 | − ret = uvc_acquire_privileges(handle); | |
| 440 | − if (ret < 0) | |
| 441 | − return ret; | |
| 442 | − | |
| 443 | 437 | if (fmt->type != stream->type) |
| 444 | 438 | return -EINVAL; |
| 445 | 439 | |
| @@ -448,8 +442,7 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, · 2 unmodified lines | ||
| 448 | 442 | return ret; |
| 449 | 443 | |
| 450 | 444 | mutex_lock(&stream->mutex); |
| 451 | − | |
| 452 | − if (uvc_queue_allocated(&stream->queue)) { | |
| 445 | + if (vb2_is_busy(&stream->queue.queue)) { | |
| 453 | 446 | ret = -EBUSY; |
| 454 | 447 | goto done; |
| 455 | 448 | } |
| @@ -513,10 +506,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, · 57 unmodified lines | ||
| 513 | 506 | unsigned int i; |
| 514 | 507 | int ret; |
| 515 | 508 | |
| 516 | − ret = uvc_acquire_privileges(handle); | |
| 517 | − if (ret < 0) | |
| 518 | − return ret; | |
| 519 | − | |
| 520 | 509 | if (parm->type != stream->type) |
| 521 | 510 | return -EINVAL; |
| 522 | 511 | |
| @@ -593,63 +582,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, · 70 unmodified lines | ||
| 593 | 582 | return 0; |
| 594 | 583 | } |
| 595 | 584 | |
| 596 | −/* ------------------------------------------------------------------------ | |
| 597 | − * Privilege management | |
| 598 | − */ | |
| 599 | − | |
| 600 | −/* | |
| 601 | − * Privilege management is the multiple-open implementation basis. The current | |
| 602 | − * implementation is completely transparent for the end-user and doesn't | |
| 603 | − * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls. | |
| 604 | − * Those ioctls enable finer control on the device (by making possible for a | |
| 605 | − * user to request exclusive access to a device), but are not mature yet. | |
| 606 | − * Switching to the V4L2 priority mechanism might be considered in the future | |
| 607 | − * if this situation changes. | |
| 608 | − * | |
| 609 | − * Each open instance of a UVC device can either be in a privileged or | |
| 610 | − * unprivileged state. Only a single instance can be in a privileged state at | |
| 611 | − * a given time. Trying to perform an operation that requires privileges will | |
| 612 | − * automatically acquire the required privileges if possible, or return -EBUSY | |
| 613 | − * otherwise. Privileges are dismissed when closing the instance or when | |
| 614 | − * freeing the video buffers using VIDIOC_REQBUFS. | |
| 615 | − * | |
| 616 | − * Operations that require privileges are: | |
| 617 | − * | |
| 618 | − * - VIDIOC_S_INPUT | |
| 619 | − * - VIDIOC_S_PARM | |
| 620 | − * - VIDIOC_S_FMT | |
| 621 | − * - VIDIOC_CREATE_BUFS | |
| 622 | − * - VIDIOC_REQBUFS | |
| 623 | − */ | |
| 624 | −static int uvc_acquire_privileges(struct uvc_fh *handle) | |
| 625 | −{ | |
| 626 | − /* Always succeed if the handle is already privileged. */ | |
| 627 | − if (handle->state == UVC_HANDLE_ACTIVE) | |
| 628 | − return 0; | |
| 629 | − | |
| 630 | − /* Check if the device already has a privileged handle. */ | |
| 631 | − if (atomic_inc_return(&handle->stream->active) != 1) { | |
| 632 | − atomic_dec(&handle->stream->active); | |
| 633 | − return -EBUSY; | |
| 634 | − } | |
| 635 | − | |
| 636 | − handle->state = UVC_HANDLE_ACTIVE; | |
| 637 | − return 0; | |
| 638 | −} | |
| 639 | − | |
| 640 | −static void uvc_dismiss_privileges(struct uvc_fh *handle) | |
| 641 | −{ | |
| 642 | − if (handle->state == UVC_HANDLE_ACTIVE) | |
| 643 | − atomic_dec(&handle->stream->active); | |
| 644 | − | |
| 645 | − handle->state = UVC_HANDLE_PASSIVE; | |
| 646 | −} | |
| 647 | − | |
| 648 | −static int uvc_has_privileges(struct uvc_fh *handle) | |
| 649 | −{ | |
| 650 | − return handle->state == UVC_HANDLE_ACTIVE; | |
| 651 | −} | |
| 652 | − | |
| 653 | 585 | /* ------------------------------------------------------------------------ |
| 654 | 586 | * V4L2 file operations |
| 655 | 587 | */ |
| @@ -671,7 +603,6 @@ static int uvc_v4l2_open(struct file *file) · 15 unmodified lines | ||
| 671 | 603 | v4l2_fh_add(&handle->vfh); |
| 672 | 604 | handle->chain = stream->chain; |
| 673 | 605 | handle->stream = stream; |
| 674 | − handle->state = UVC_HANDLE_PASSIVE; | |
| 675 | 606 | file->private_data = handle; |
| 676 | 607 | |
| 677 | 608 | return 0; |
| @@ -686,19 +617,8 @@ static int uvc_v4l2_release(struct file *file) · 8 unmodified lines | ||
| 686 | 617 | |
| 687 | 618 | uvc_ctrl_cleanup_fh(handle); |
| 688 | 619 | |
| 689 | − /* Only free resources if this is a privileged handle. */ | |
| 690 | − if (uvc_has_privileges(handle)) | |
| 691 | − uvc_queue_release(&stream->queue); | |
| 692 | − | |
| 693 | − if (handle->is_streaming) | |
| 694 | − uvc_pm_put(stream->dev); | |
| 695 | − | |
| 696 | 620 | /* Release the file handle. */ |
| 697 | − uvc_dismiss_privileges(handle); | |
| 698 | − v4l2_fh_del(&handle->vfh); | |
| 699 | − v4l2_fh_exit(&handle->vfh); | |
| 700 | − kfree(handle); | |
| 701 | − file->private_data = NULL; | |
| 621 | + vb2_fop_release(file); | |
| 702 | 622 | |
| 703 | 623 | return 0; |
| 704 | 624 | } |
| @@ -753,140 +673,6 @@ static int uvc_ioctl_try_fmt(struct file *file, void *fh, · 48 unmodified lines | ||
| 753 | 673 | return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); |
| 754 | 674 | } |
| 755 | 675 | |
| 756 | −static int uvc_ioctl_reqbufs(struct file *file, void *fh, | |
| 757 | − struct v4l2_requestbuffers *rb) | |
| 758 | −{ | |
| 759 | − struct uvc_fh *handle = fh; | |
| 760 | − struct uvc_streaming *stream = handle->stream; | |
| 761 | − int ret; | |
| 762 | − | |
| 763 | − ret = uvc_acquire_privileges(handle); | |
| 764 | − if (ret < 0) | |
| 765 | − return ret; | |
| 766 | − | |
| 767 | − mutex_lock(&stream->mutex); | |
| 768 | − ret = uvc_request_buffers(&stream->queue, rb); | |
| 769 | − mutex_unlock(&stream->mutex); | |
| 770 | − if (ret < 0) | |
| 771 | − return ret; | |
| 772 | − | |
| 773 | − if (ret == 0) | |
| 774 | − uvc_dismiss_privileges(handle); | |
| 775 | − | |
| 776 | − return 0; | |
| 777 | −} | |
| 778 | − | |
| 779 | −static int uvc_ioctl_querybuf(struct file *file, void *fh, | |
| 780 | − struct v4l2_buffer *buf) | |
| 781 | −{ | |
| 782 | − struct uvc_fh *handle = fh; | |
| 783 | − struct uvc_streaming *stream = handle->stream; | |
| 784 | − | |
| 785 | − if (!uvc_has_privileges(handle)) | |
| 786 | − return -EBUSY; | |
| 787 | − | |
| 788 | − return uvc_query_buffer(&stream->queue, buf); | |
| 789 | −} | |
| 790 | − | |
| 791 | −static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) | |
| 792 | −{ | |
| 793 | − struct uvc_fh *handle = fh; | |
| 794 | − struct uvc_streaming *stream = handle->stream; | |
| 795 | − | |
| 796 | − if (!uvc_has_privileges(handle)) | |
| 797 | − return -EBUSY; | |
| 798 | − | |
| 799 | − return uvc_queue_buffer(&stream->queue, | |
| 800 | − stream->vdev.v4l2_dev->mdev, buf); | |
| 801 | −} | |
| 802 | − | |
| 803 | −static int uvc_ioctl_expbuf(struct file *file, void *fh, | |
| 804 | − struct v4l2_exportbuffer *exp) | |
| 805 | −{ | |
| 806 | − struct uvc_fh *handle = fh; | |
| 807 | − struct uvc_streaming *stream = handle->stream; | |
| 808 | − | |
| 809 | − if (!uvc_has_privileges(handle)) | |
| 810 | − return -EBUSY; | |
| 811 | − | |
| 812 | − return uvc_export_buffer(&stream->queue, exp); | |
| 813 | −} | |
| 814 | − | |
| 815 | −static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) | |
| 816 | −{ | |
| 817 | − struct uvc_fh *handle = fh; | |
| 818 | − struct uvc_streaming *stream = handle->stream; | |
| 819 | − | |
| 820 | − if (!uvc_has_privileges(handle)) | |
| 821 | − return -EBUSY; | |
| 822 | − | |
| 823 | − return uvc_dequeue_buffer(&stream->queue, buf, | |
| 824 | − file->f_flags & O_NONBLOCK); | |
| 825 | −} | |
| 826 | − | |
| 827 | −static int uvc_ioctl_create_bufs(struct file *file, void *fh, | |
| 828 | − struct v4l2_create_buffers *cb) | |
| 829 | −{ | |
| 830 | − struct uvc_fh *handle = fh; | |
| 831 | − struct uvc_streaming *stream = handle->stream; | |
| 832 | − int ret; | |
| 833 | − | |
| 834 | − ret = uvc_acquire_privileges(handle); | |
| 835 | − if (ret < 0) | |
| 836 | − return ret; | |
| 837 | − | |
| 838 | − return uvc_create_buffers(&stream->queue, cb); | |
| 839 | −} | |
| 840 | − | |
| 841 | −static int uvc_ioctl_streamon(struct file *file, void *fh, | |
| 842 | − enum v4l2_buf_type type) | |
| 843 | −{ | |
| 844 | − struct uvc_fh *handle = fh; | |
| 845 | − struct uvc_streaming *stream = handle->stream; | |
| 846 | − int ret; | |
| 847 | − | |
| 848 | − if (!uvc_has_privileges(handle)) | |
| 849 | − return -EBUSY; | |
| 850 | − | |
| 851 | − guard(mutex)(&stream->mutex); | |
| 852 | − | |
| 853 | − if (handle->is_streaming) | |
| 854 | − return 0; | |
| 855 | − | |
| 856 | − ret = uvc_queue_streamon(&stream->queue, type); | |
| 857 | − if (ret) | |
| 858 | − return ret; | |
| 859 | − | |
| 860 | − ret = uvc_pm_get(stream->dev); | |
| 861 | − if (ret) { | |
| 862 | − uvc_queue_streamoff(&stream->queue, type); | |
| 863 | − return ret; | |
| 864 | − } | |
| 865 | − handle->is_streaming = true; | |
| 866 | − | |
| 867 | − return 0; | |
| 868 | −} | |
| 869 | − | |
| 870 | −static int uvc_ioctl_streamoff(struct file *file, void *fh, | |
| 871 | − enum v4l2_buf_type type) | |
| 872 | −{ | |
| 873 | − struct uvc_fh *handle = fh; | |
| 874 | − struct uvc_streaming *stream = handle->stream; | |
| 875 | − | |
| 876 | − if (!uvc_has_privileges(handle)) | |
| 877 | − return -EBUSY; | |
| 878 | − | |
| 879 | − guard(mutex)(&stream->mutex); | |
| 880 | − | |
| 881 | − uvc_queue_streamoff(&stream->queue, type); | |
| 882 | − if (handle->is_streaming) { | |
| 883 | − handle->is_streaming = false; | |
| 884 | − uvc_pm_put(stream->dev); | |
| 885 | − } | |
| 886 | − | |
| 887 | − return 0; | |
| 888 | −} | |
| 889 | − | |
| 890 | 676 | static int uvc_ioctl_enum_input(struct file *file, void *fh, |
| 891 | 677 | struct v4l2_input *input) |
| 892 | 678 | { |
| @@ -961,13 +747,13 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) · 68 unmodified lines | ||
| 961 | 747 | static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) |
| 962 | 748 | { |
| 963 | 749 | struct uvc_fh *handle = fh; |
| 750 | + struct uvc_streaming *stream = handle->stream; | |
| 964 | 751 | struct uvc_video_chain *chain = handle->chain; |
| 965 | 752 | u8 *buf; |
| 966 | 753 | int ret; |
| 967 | 754 | |
| 968 | − ret = uvc_acquire_privileges(handle); | |
| 969 | − if (ret < 0) | |
| 970 | − return ret; | |
| 755 | + if (vb2_is_busy(&stream->queue.queue)) | |
| 756 | + return -EBUSY; | |
| 971 | 757 | |
| 972 | 758 | if (chain->selector == NULL || |
| 973 | 759 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { |
| @@ -1381,11 +1167,9 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, · 407 unmodified lines | ||
| 1381 | 1167 | #define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) |
| 1382 | 1168 | #define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) |
| 1383 | 1169 | |
| 1384 | −DEFINE_FREE(uvc_pm_put, struct uvc_device *, if (_T) uvc_pm_put(_T)) | |
| 1385 | 1170 | static long uvc_v4l2_compat_ioctl32(struct file *file, |
| 1386 | 1171 | unsigned int cmd, unsigned long arg) |
| 1387 | 1172 | { |
| 1388 | − struct uvc_device *uvc_device __free(uvc_pm_put) = NULL; | |
| 1389 | 1173 | struct uvc_fh *handle = file->private_data; |
| 1390 | 1174 | union { |
| 1391 | 1175 | struct uvc_xu_control_mapping xmap; |
| @@ -1398,38 +1182,38 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, · 6 unmodified lines | ||
| 1398 | 1182 | if (ret) |
| 1399 | 1183 | return ret; |
| 1400 | 1184 | |
| 1401 | − uvc_device = handle->stream->dev; | |
| 1402 | − | |
| 1403 | 1185 | switch (cmd) { |
| 1404 | 1186 | case UVCIOC_CTRL_MAP32: |
| 1405 | 1187 | ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); |
| 1406 | 1188 | if (ret) |
| 1407 | − return ret; | |
| 1189 | + break; | |
| 1408 | 1190 | ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); |
| 1409 | 1191 | if (ret) |
| 1410 | − return ret; | |
| 1192 | + break; | |
| 1411 | 1193 | ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); |
| 1412 | 1194 | if (ret) |
| 1413 | − return ret; | |
| 1414 | − | |
| 1195 | + break; | |
| 1415 | 1196 | break; |
| 1416 | 1197 | |
| 1417 | 1198 | case UVCIOC_CTRL_QUERY32: |
| 1418 | 1199 | ret = uvc_v4l2_get_xu_query(&karg.xqry, up); |
| 1419 | 1200 | if (ret) |
| 1420 | − return ret; | |
| 1201 | + break; | |
| 1421 | 1202 | ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); |
| 1422 | 1203 | if (ret) |
| 1423 | − return ret; | |
| 1204 | + break; | |
| 1424 | 1205 | ret = uvc_v4l2_put_xu_query(&karg.xqry, up); |
| 1425 | 1206 | if (ret) |
| 1426 | − return ret; | |
| 1207 | + break; | |
| 1427 | 1208 | break; |
| 1428 | 1209 | |
| 1429 | 1210 | default: |
| 1430 | − return -ENOIOCTLCMD; | |
| 1211 | + ret = -ENOIOCTLCMD; | |
| 1212 | + break; | |
| 1431 | 1213 | } |
| 1432 | 1214 | |
| 1215 | + uvc_pm_put(handle->stream->dev); | |
| 1216 | + | |
| 1433 | 1217 | return ret; |
| 1434 | 1218 | } |
| 1435 | 1219 | #endif |
| @@ -1438,81 +1222,37 @@ static long uvc_v4l2_unlocked_ioctl(struct file *file, · 2 unmodified lines | ||
| 1438 | 1222 | unsigned int cmd, unsigned long arg) |
| 1439 | 1223 | { |
| 1440 | 1224 | struct uvc_fh *handle = file->private_data; |
| 1225 | + unsigned int converted_cmd = v4l2_translate_cmd(cmd); | |
| 1441 | 1226 | int ret; |
| 1442 | 1227 | |
| 1443 | − /* The following IOCTLs do not need to turn on the camera. */ | |
| 1444 | − switch (cmd) { | |
| 1445 | − case VIDIOC_CREATE_BUFS: | |
| 1446 | − case VIDIOC_DQBUF: | |
| 1447 | − case VIDIOC_ENUM_FMT: | |
| 1448 | − case VIDIOC_ENUM_FRAMEINTERVALS: | |
| 1449 | − case VIDIOC_ENUM_FRAMESIZES: | |
| 1450 | − case VIDIOC_ENUMINPUT: | |
| 1451 | − case VIDIOC_EXPBUF: | |
| 1452 | − case VIDIOC_G_FMT: | |
| 1453 | − case VIDIOC_G_PARM: | |
| 1454 | − case VIDIOC_G_SELECTION: | |
| 1455 | − case VIDIOC_QBUF: | |
| 1456 | − case VIDIOC_QUERYCAP: | |
| 1457 | − case VIDIOC_REQBUFS: | |
| 1458 | − case VIDIOC_SUBSCRIBE_EVENT: | |
| 1459 | − case VIDIOC_UNSUBSCRIBE_EVENT: | |
| 1460 | − return video_ioctl2(file, cmd, arg); | |
| 1461 | − } | |
| 1462 | − | |
| 1463 | − ret = uvc_pm_get(handle->stream->dev); | |
| 1464 | − if (ret) | |
| 1228 | + /* The following IOCTLs need to turn on the camera. */ | |
| 1229 | + switch (converted_cmd) { | |
| 1230 | + case UVCIOC_CTRL_MAP: | |
| 1231 | + case UVCIOC_CTRL_QUERY: | |
| 1232 | + case VIDIOC_G_CTRL: | |
| 1233 | + case VIDIOC_G_EXT_CTRLS: | |
| 1234 | + case VIDIOC_G_INPUT: | |
| 1235 | + case VIDIOC_QUERYCTRL: | |
| 1236 | + case VIDIOC_QUERYMENU: | |
| 1237 | + case VIDIOC_QUERY_EXT_CTRL: | |
| 1238 | + case VIDIOC_S_CTRL: | |
| 1239 | + case VIDIOC_S_EXT_CTRLS: | |
| 1240 | + case VIDIOC_S_FMT: | |
| 1241 | + case VIDIOC_S_INPUT: | |
| 1242 | + case VIDIOC_S_PARM: | |
| 1243 | + case VIDIOC_TRY_EXT_CTRLS: | |
| 1244 | + case VIDIOC_TRY_FMT: | |
| 1245 | + ret = uvc_pm_get(handle->stream->dev); | |
| 1246 | + if (ret) | |
| 1247 | + return ret; | |
| 1248 | + ret = video_ioctl2(file, cmd, arg); | |
| 1249 | + uvc_pm_put(handle->stream->dev); | |
| 1465 | 1250 | return ret; |
| 1251 | + } | |
| 1466 | 1252 | |
| 1467 | − ret = video_ioctl2(file, cmd, arg); | |
| 1468 | − | |
| 1469 | − uvc_pm_put(handle->stream->dev); | |
| 1470 | − return ret; | |
| 1471 | −} | |
| 1472 | − | |
| 1473 | −static ssize_t uvc_v4l2_read(struct file *file, char __user *data, | |
| 1474 | − size_t count, loff_t *ppos) | |
| 1475 | −{ | |
| 1476 | − struct uvc_fh *handle = file->private_data; | |
| 1477 | − struct uvc_streaming *stream = handle->stream; | |
| 1478 | − | |
| 1479 | − uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__); | |
| 1480 | − return -EINVAL; | |
| 1481 | −} | |
| 1482 | − | |
| 1483 | −static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) | |
| 1484 | −{ | |
| 1485 | − struct uvc_fh *handle = file->private_data; | |
| 1486 | − struct uvc_streaming *stream = handle->stream; | |
| 1487 | − | |
| 1488 | − uvc_dbg(stream->dev, CALLS, "%s\n", __func__); | |
| 1489 | − | |
| 1490 | − return uvc_queue_mmap(&stream->queue, vma); | |
| 1491 | −} | |
| 1492 | − | |
| 1493 | −static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait) | |
| 1494 | −{ | |
| 1495 | − struct uvc_fh *handle = file->private_data; | |
| 1496 | − struct uvc_streaming *stream = handle->stream; | |
| 1497 | − | |
| 1498 | − uvc_dbg(stream->dev, CALLS, "%s\n", __func__); | |
| 1499 | − | |
| 1500 | − return uvc_queue_poll(&stream->queue, file, wait); | |
| 1501 | −} | |
| 1502 | − | |
| 1503 | −#ifndef CONFIG_MMU | |
| 1504 | −static unsigned long uvc_v4l2_get_unmapped_area(struct file *file, | |
| 1505 | − unsigned long addr, unsigned long len, unsigned long pgoff, | |
| 1506 | − unsigned long flags) | |
| 1507 | −{ | |
| 1508 | − struct uvc_fh *handle = file->private_data; | |
| 1509 | − struct uvc_streaming *stream = handle->stream; | |
| 1510 | − | |
| 1511 | − uvc_dbg(stream->dev, CALLS, "%s\n", __func__); | |
| 1512 | − | |
| 1513 | − return uvc_queue_get_unmapped_area(&stream->queue, pgoff); | |
| 1253 | + /* The other IOCTLs can run with the camera off. */ | |
| 1254 | + return video_ioctl2(file, cmd, arg); | |
| 1514 | 1255 | } |
| 1515 | −#endif | |
| 1516 | 1256 | |
| 1517 | 1257 | const struct v4l2_ioctl_ops uvc_ioctl_ops = { |
| 1518 | 1258 | .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt, |
| @@ -1526,14 +1266,15 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = { · 7 unmodified lines | ||
| 1526 | 1266 | .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt, |
| 1527 | 1267 | .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt, |
| 1528 | 1268 | .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt, |
| 1529 | − .vidioc_reqbufs = uvc_ioctl_reqbufs, | |
| 1530 | − .vidioc_querybuf = uvc_ioctl_querybuf, | |
| 1531 | − .vidioc_qbuf = uvc_ioctl_qbuf, | |
| 1532 | − .vidioc_expbuf = uvc_ioctl_expbuf, | |
| 1533 | − .vidioc_dqbuf = uvc_ioctl_dqbuf, | |
| 1534 | − .vidioc_create_bufs = uvc_ioctl_create_bufs, | |
| 1535 | − .vidioc_streamon = uvc_ioctl_streamon, | |
| 1536 | − .vidioc_streamoff = uvc_ioctl_streamoff, | |
| 1269 | + .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
| 1270 | + .vidioc_querybuf = vb2_ioctl_querybuf, | |
| 1271 | + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
| 1272 | + .vidioc_qbuf = vb2_ioctl_qbuf, | |
| 1273 | + .vidioc_expbuf = vb2_ioctl_expbuf, | |
| 1274 | + .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
| 1275 | + .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
| 1276 | + .vidioc_streamon = vb2_ioctl_streamon, | |
| 1277 | + .vidioc_streamoff = vb2_ioctl_streamoff, | |
| 1537 | 1278 | .vidioc_enum_input = uvc_ioctl_enum_input, |
| 1538 | 1279 | .vidioc_g_input = uvc_ioctl_g_input, |
| 1539 | 1280 | .vidioc_s_input = uvc_ioctl_s_input, |
| @@ -1558,11 +1299,10 @@ const struct v4l2_file_operations uvc_fops = { · 18 unmodified lines | ||
| 1558 | 1299 | #ifdef CONFIG_COMPAT |
| 1559 | 1300 | .compat_ioctl32 = uvc_v4l2_compat_ioctl32, |
| 1560 | 1301 | #endif |
| 1561 | − .read = uvc_v4l2_read, | |
| 1562 | − .mmap = uvc_v4l2_mmap, | |
| 1563 | − .poll = uvc_v4l2_poll, | |
| 1302 | + .mmap = vb2_fop_mmap, | |
| 1303 | + .poll = vb2_fop_poll, | |
| 1564 | 1304 | #ifndef CONFIG_MMU |
| 1565 | − .get_unmapped_area = uvc_v4l2_get_unmapped_area, | |
| 1305 | + .get_unmapped_area = vb2_fop_get_unmapped_area, | |
| 1566 | 1306 | #endif |
| 1567 | 1307 | }; |
| 1568 | 1308 | |
| @@ -262,6 +262,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, · 261 unmodified lines | ||
| 262 | 262 | |
| 263 | 263 | ctrl->dwMaxPayloadTransferSize = bandwidth; |
| 264 | 264 | } |
| 265 | + | |
| 266 | + if (stream->intf->num_altsetting > 1 && | |
| 267 | + ctrl->dwMaxPayloadTransferSize > stream->maxpsize) { | |
| 268 | + dev_warn_ratelimited(&stream->intf->dev, | |
| 269 | + "UVC non compliance: the max payload transmission size (%u) exceeds the size of the ep max packet (%u). Using the max size.\n", | |
| 270 | + ctrl->dwMaxPayloadTransferSize, | |
| 271 | + stream->maxpsize); | |
| 272 | + ctrl->dwMaxPayloadTransferSize = stream->maxpsize; | |
| 273 | + } | |
| 265 | 274 | } |
| 266 | 275 | |
| 267 | 276 | static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) |
| @@ -1419,12 +1428,6 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, · 1151 unmodified lines | ||
| 1419 | 1428 | if (!meta_buf || length == 2) |
| 1420 | 1429 | return; |
| 1421 | 1430 | |
| 1422 | − if (meta_buf->length - meta_buf->bytesused < | |
| 1423 | − length + sizeof(meta->ns) + sizeof(meta->sof)) { | |
| 1424 | − meta_buf->error = 1; | |
| 1425 | − return; | |
| 1426 | − } | |
| 1427 | − | |
| 1428 | 1431 | has_pts = mem[1] & UVC_STREAM_PTS; |
| 1429 | 1432 | has_scr = mem[1] & UVC_STREAM_SCR; |
| 1430 | 1433 | |
| @@ -1445,6 +1448,12 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream, · 14 unmodified lines | ||
| 1445 | 1448 | !memcmp(scr, stream->clock.last_scr, 6))) |
| 1446 | 1449 | return; |
| 1447 | 1450 | |
| 1451 | + if (meta_buf->length - meta_buf->bytesused < | |
| 1452 | + length + sizeof(meta->ns) + sizeof(meta->sof)) { | |
| 1453 | + meta_buf->error = 1; | |
| 1454 | + return; | |
| 1455 | + } | |
| 1456 | + | |
| 1448 | 1457 | meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused); |
| 1449 | 1458 | local_irq_save(flags); |
| 1450 | 1459 | time = uvc_video_get_time(); |
| @@ -77,6 +77,7 @@ · 76 unmodified lines | ||
| 77 | 77 | #define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 |
| 78 | 78 | #define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 |
| 79 | 79 | #define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 |
| 80 | +#define UVC_QUIRK_MSXU_META 0x00040000 | |
| 80 | 81 | |
| 81 | 82 | /* Format flags */ |
| 82 | 83 | #define UVC_FMT_FLAG_COMPRESSED 0x00000001 |
| @@ -134,6 +135,8 @@ struct uvc_control_mapping { · 51 unmodified lines | ||
| 134 | 135 | s32 master_manual; |
| 135 | 136 | u32 slave_ids[2]; |
| 136 | 137 | |
| 138 | + bool disabled; | |
| 139 | + | |
| 137 | 140 | const struct uvc_control_mapping *(*filter_mapping) |
| 138 | 141 | (struct uvc_video_chain *chain, |
| 139 | 142 | struct uvc_control *ctrl); |
| @@ -326,7 +329,10 @@ struct uvc_buffer { · 186 unmodified lines | ||
| 326 | 329 | |
| 327 | 330 | struct uvc_video_queue { |
| 328 | 331 | struct vb2_queue queue; |
| 329 | − struct mutex mutex; /* Protects queue */ | |
| 332 | + struct mutex mutex; /* | |
| 333 | + * Serializes vb2_queue and | |
| 334 | + * fops | |
| 335 | + */ | |
| 330 | 336 | |
| 331 | 337 | unsigned int flags; |
| 332 | 338 | unsigned int buf_used; |
| @@ -570,6 +576,8 @@ struct uvc_status { · 237 unmodified lines | ||
| 570 | 576 | }; |
| 571 | 577 | } __packed; |
| 572 | 578 | |
| 579 | +#define UVC_MAX_META_DATA_FORMATS 3 | |
| 580 | + | |
| 573 | 581 | struct uvc_device { |
| 574 | 582 | struct usb_device *udev; |
| 575 | 583 | struct usb_interface *intf; |
| @@ -580,6 +588,9 @@ struct uvc_device { · 4 unmodified lines | ||
| 580 | 588 | |
| 581 | 589 | const struct uvc_device_info *info; |
| 582 | 590 | |
| 591 | + u32 meta_formats[UVC_MAX_META_DATA_FORMATS]; | |
| 592 | + unsigned int nmeta_formats; | |
| 593 | + | |
| 583 | 594 | atomic_t nmappings; |
| 584 | 595 | |
| 585 | 596 | /* Video control interface */ |
| @@ -619,18 +630,11 @@ struct uvc_device { · 33 unmodified lines | ||
| 619 | 630 | struct uvc_entity *gpio_unit; |
| 620 | 631 | }; |
| 621 | 632 | |
| 622 | −enum uvc_handle_state { | |
| 623 | − UVC_HANDLE_PASSIVE = 0, | |
| 624 | − UVC_HANDLE_ACTIVE = 1, | |
| 625 | −}; | |
| 626 | − | |
| 627 | 633 | struct uvc_fh { |
| 628 | 634 | struct v4l2_fh vfh; |
| 629 | 635 | struct uvc_video_chain *chain; |
| 630 | 636 | struct uvc_streaming *stream; |
| 631 | − enum uvc_handle_state state; | |
| 632 | 637 | unsigned int pending_async_ctrls; |
| 633 | − bool is_streaming; | |
| 634 | 638 | }; |
| 635 | 639 | |
| 636 | 640 | /* ------------------------------------------------------------------------ |
| @@ -687,36 +691,11 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); · 50 unmodified lines | ||
| 687 | 691 | |
| 688 | 692 | /* Video buffers queue management. */ |
| 689 | 693 | int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); |
| 690 | −void uvc_queue_release(struct uvc_video_queue *queue); | |
| 691 | −int uvc_request_buffers(struct uvc_video_queue *queue, | |
| 692 | − struct v4l2_requestbuffers *rb); | |
| 693 | −int uvc_query_buffer(struct uvc_video_queue *queue, | |
| 694 | − struct v4l2_buffer *v4l2_buf); | |
| 695 | −int uvc_create_buffers(struct uvc_video_queue *queue, | |
| 696 | − struct v4l2_create_buffers *v4l2_cb); | |
| 697 | −int uvc_queue_buffer(struct uvc_video_queue *queue, | |
| 698 | − struct media_device *mdev, | |
| 699 | − struct v4l2_buffer *v4l2_buf); | |
| 700 | −int uvc_export_buffer(struct uvc_video_queue *queue, | |
| 701 | − struct v4l2_exportbuffer *exp); | |
| 702 | −int uvc_dequeue_buffer(struct uvc_video_queue *queue, | |
| 703 | − struct v4l2_buffer *v4l2_buf, int nonblocking); | |
| 704 | −int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type); | |
| 705 | −int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); | |
| 706 | 694 | void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); |
| 707 | 695 | struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, |
| 708 | 696 | struct uvc_buffer *buf); |
| 709 | 697 | struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); |
| 710 | 698 | void uvc_queue_buffer_release(struct uvc_buffer *buf); |
| 711 | −int uvc_queue_mmap(struct uvc_video_queue *queue, | |
| 712 | − struct vm_area_struct *vma); | |
| 713 | −__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, | |
| 714 | − poll_table *wait); | |
| 715 | −#ifndef CONFIG_MMU | |
| 716 | −unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue, | |
| 717 | − unsigned long pgoff); | |
| 718 | −#endif | |
| 719 | −int uvc_queue_allocated(struct uvc_video_queue *queue); | |
| 720 | 699 | static inline int uvc_queue_streaming(struct uvc_video_queue *queue) |
| 721 | 700 | { |
| 722 | 701 | return vb2_is_streaming(&queue->queue); |
| @@ -749,6 +728,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, · 26 unmodified lines | ||
| 749 | 728 | void uvc_video_clock_update(struct uvc_streaming *stream, |
| 750 | 729 | struct vb2_v4l2_buffer *vbuf, |
| 751 | 730 | struct uvc_buffer *buf); |
| 731 | +int uvc_meta_init(struct uvc_device *dev); | |
| 752 | 732 | int uvc_meta_register(struct uvc_streaming *stream); |
| 753 | 733 | |
| 754 | 734 | int uvc_register_video_device(struct uvc_device *dev, |
| @@ -323,6 +323,12 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) · 322 unmodified lines | ||
| 323 | 323 | { .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 }, |
| 324 | 324 | { .format = V4L2_PIX_FMT_P012M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 }, |
| 325 | 325 | |
| 326 | + /* Tiled YUV formats, non contiguous variant */ | |
| 327 | + { .format = V4L2_PIX_FMT_NV12MT, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2, | |
| 328 | + .block_w = { 64, 32, 0, 0 }, .block_h = { 32, 16, 0, 0 }}, | |
| 329 | + { .format = V4L2_PIX_FMT_NV12MT_16X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2, | |
| 330 | + .block_w = { 16, 8, 0, 0 }, .block_h = { 16, 8, 0, 0 }}, | |
| 331 | + | |
| 326 | 332 | /* Bayer RGB formats */ |
| 327 | 333 | { .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 328 | 334 | { .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| @@ -332,6 +338,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) · 3 unmodified lines | ||
| 332 | 338 | { .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 333 | 339 | { .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 334 | 340 | { .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 341 | + { .format = V4L2_PIX_FMT_SBGGR10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 342 | + { .format = V4L2_PIX_FMT_SGBRG10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 343 | + { .format = V4L2_PIX_FMT_SGRBG10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 344 | + { .format = V4L2_PIX_FMT_SRGGB10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 335 | 345 | { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 336 | 346 | { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 337 | 347 | { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| @@ -344,6 +354,28 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) · 6 unmodified lines | ||
| 344 | 354 | { .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 345 | 355 | { .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 346 | 356 | { .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, |
| 357 | + { .format = V4L2_PIX_FMT_SBGGR12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 358 | + { .format = V4L2_PIX_FMT_SGBRG12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 359 | + { .format = V4L2_PIX_FMT_SGRBG12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 360 | + { .format = V4L2_PIX_FMT_SRGGB12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 361 | + { .format = V4L2_PIX_FMT_SBGGR14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 362 | + { .format = V4L2_PIX_FMT_SGBRG14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 363 | + { .format = V4L2_PIX_FMT_SGRBG14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 364 | + { .format = V4L2_PIX_FMT_SRGGB14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 365 | + { .format = V4L2_PIX_FMT_SBGGR14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 366 | + { .format = V4L2_PIX_FMT_SGBRG14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 367 | + { .format = V4L2_PIX_FMT_SGRBG14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 368 | + { .format = V4L2_PIX_FMT_SRGGB14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 369 | + { .format = V4L2_PIX_FMT_SBGGR16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 370 | + { .format = V4L2_PIX_FMT_SGBRG16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 371 | + { .format = V4L2_PIX_FMT_SGRBG16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 372 | + { .format = V4L2_PIX_FMT_SRGGB16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 373 | + | |
| 374 | + /* Renesas Camera Data Receiver Unit formats, bayer order agnostic */ | |
| 375 | + { .format = V4L2_PIX_FMT_RAW_CRU10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 6, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 376 | + { .format = V4L2_PIX_FMT_RAW_CRU12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 5, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 377 | + { .format = V4L2_PIX_FMT_RAW_CRU14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 378 | + { .format = V4L2_PIX_FMT_RAW_CRU20, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 3, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 }, | |
| 347 | 379 | }; |
| 348 | 380 | unsigned int i; |
| 349 | 381 | |
| @@ -505,10 +537,10 @@ s64 __v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler, · 155 unmodified lines | ||
| 505 | 537 | |
| 506 | 538 | freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div); |
| 507 | 539 | |
| 508 | − pr_warn("%s: Link frequency estimated using pixel rate: result might be inaccurate\n", | |
| 509 | − __func__); | |
| 510 | − pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", | |
| 511 | − __func__); | |
| 540 | + pr_warn_once("%s: Link frequency estimated using pixel rate: result might be inaccurate\n", | |
| 541 | + __func__); | |
| 542 | + pr_warn_once("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", | |
| 543 | + __func__); | |
| 512 | 544 | } |
| 513 | 545 | |
| 514 | 546 | return freq > 0 ? freq : -EINVAL; |
| @@ -968,12 +968,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, · 967 unmodified lines | ||
| 968 | 968 | |
| 969 | 969 | p_h264_sps->flags &= |
| 970 | 970 | ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; |
| 971 | − | |
| 972 | − if (p_h264_sps->chroma_format_idc < 3) | |
| 973 | − p_h264_sps->flags &= | |
| 974 | − ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; | |
| 975 | 971 | } |
| 976 | 972 | |
| 973 | + if (p_h264_sps->chroma_format_idc < 3) | |
| 974 | + p_h264_sps->flags &= | |
| 975 | + ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE; | |
| 976 | + | |
| 977 | 977 | if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) |
| 978 | 978 | p_h264_sps->flags &= |
| 979 | 979 | ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; |
| @@ -1631,14 +1631,17 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, · 651 unmodified lines | ||
| 1631 | 1631 | EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); |
| 1632 | 1632 | |
| 1633 | 1633 | /* Free all controls and control refs */ |
| 1634 | −void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) | |
| 1634 | +int v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) | |
| 1635 | 1635 | { |
| 1636 | 1636 | struct v4l2_ctrl_ref *ref, *next_ref; |
| 1637 | 1637 | struct v4l2_ctrl *ctrl, *next_ctrl; |
| 1638 | 1638 | struct v4l2_subscribed_event *sev, *next_sev; |
| 1639 | 1639 | |
| 1640 | − if (hdl == NULL || hdl->buckets == NULL) | |
| 1641 | − return; | |
| 1640 | + if (!hdl) | |
| 1641 | + return 0; | |
| 1642 | + | |
| 1643 | + if (!hdl->buckets) | |
| 1644 | + return hdl->error; | |
| 1642 | 1645 | |
| 1643 | 1646 | v4l2_ctrl_handler_free_request(hdl); |
| 1644 | 1647 | |
| @@ -1661,9 +1664,10 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) · 16 unmodified lines | ||
| 1661 | 1664 | kvfree(hdl->buckets); |
| 1662 | 1665 | hdl->buckets = NULL; |
| 1663 | 1666 | hdl->cached = NULL; |
| 1664 | − hdl->error = 0; | |
| 1665 | 1667 | mutex_unlock(hdl->lock); |
| 1666 | 1668 | mutex_destroy(&hdl->_lock); |
| 1669 | + | |
| 1670 | + return hdl->error; | |
| 1667 | 1671 | } |
| 1668 | 1672 | EXPORT_SYMBOL(v4l2_ctrl_handler_free); |
| 1669 | 1673 | |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | #include <linux/i2c.h> |
| 7 | 7 | #include <linux/module.h> |
| 8 | +#include <linux/property.h> | |
| 8 | 9 | #include <media/v4l2-common.h> |
| 9 | 10 | #include <media/v4l2-device.h> |
| 10 | 11 | |
| @@ -24,7 +25,7 @@ void v4l2_i2c_subdev_unregister(struct v4l2_subdev *sd) · 13 unmodified lines | ||
| 24 | 25 | * registered by us, and would not be |
| 25 | 26 | * re-created by just probing the V4L2 driver. |
| 26 | 27 | */ |
| 27 | − if (client && !client->dev.of_node && !client->dev.fwnode) | |
| 28 | + if (client && !dev_fwnode(&client->dev)) | |
| 28 | 29 | i2c_unregister_device(client); |
| 29 | 30 | } |
| 30 | 31 | |
| @@ -1413,6 +1413,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 1412 unmodified lines | ||
| 1413 | 1413 | case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; |
| 1414 | 1414 | case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; |
| 1415 | 1415 | case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break; |
| 1416 | + case V4L2_PIX_FMT_RAW_CRU10: descr = "10-bit Raw CRU Packed"; break; | |
| 1416 | 1417 | case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; |
| 1417 | 1418 | case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; |
| 1418 | 1419 | case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break; |
| @@ -1421,6 +1422,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 2 unmodified lines | ||
| 1421 | 1422 | case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; |
| 1422 | 1423 | case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; |
| 1423 | 1424 | case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break; |
| 1425 | + case V4L2_PIX_FMT_RAW_CRU12: descr = "12-bit Raw CRU Packed"; break; | |
| 1424 | 1426 | case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break; |
| 1425 | 1427 | case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break; |
| 1426 | 1428 | case V4L2_PIX_FMT_SGRBG14: descr = "14-bit Bayer GRGR/BGBG"; break; |
| @@ -1429,10 +1431,12 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 2 unmodified lines | ||
| 1429 | 1431 | case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break; |
| 1430 | 1432 | case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break; |
| 1431 | 1433 | case V4L2_PIX_FMT_SRGGB14P: descr = "14-bit Bayer RGRG/GBGB Packed"; break; |
| 1434 | + case V4L2_PIX_FMT_RAW_CRU14: descr = "14-bit Raw CRU Packed"; break; | |
| 1432 | 1435 | case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break; |
| 1433 | 1436 | case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; |
| 1434 | 1437 | case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; |
| 1435 | 1438 | case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break; |
| 1439 | + case V4L2_PIX_FMT_RAW_CRU20: descr = "14-bit Raw CRU Packed"; break; | |
| 1436 | 1440 | case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; |
| 1437 | 1441 | case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; |
| 1438 | 1442 | case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; |
| @@ -1459,6 +1463,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 20 unmodified lines | ||
| 1459 | 1463 | case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; |
| 1460 | 1464 | case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; |
| 1461 | 1465 | case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; |
| 1466 | + case V4L2_META_FMT_UVC_MSXU_1_5: descr = "UVC MSXU Metadata"; break; | |
| 1462 | 1467 | case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; |
| 1463 | 1468 | case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; |
| 1464 | 1469 | case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break; |
| @@ -3245,7 +3250,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, · 1780 unmodified lines | ||
| 3245 | 3250 | return ret; |
| 3246 | 3251 | } |
| 3247 | 3252 | |
| 3248 | −static unsigned int video_translate_cmd(unsigned int cmd) | |
| 3253 | +unsigned int v4l2_translate_cmd(unsigned int cmd) | |
| 3249 | 3254 | { |
| 3250 | 3255 | #if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME) |
| 3251 | 3256 | switch (cmd) { |
| @@ -3266,6 +3271,7 @@ static unsigned int video_translate_cmd(unsigned int cmd) · 14 unmodified lines | ||
| 3266 | 3271 | |
| 3267 | 3272 | return cmd; |
| 3268 | 3273 | } |
| 3274 | +EXPORT_SYMBOL_GPL(v4l2_translate_cmd); | |
| 3269 | 3275 | |
| 3270 | 3276 | static int video_get_user(void __user *arg, void *parg, |
| 3271 | 3277 | unsigned int real_cmd, unsigned int cmd, |
| @@ -3426,7 +3432,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg, · 154 unmodified lines | ||
| 3426 | 3432 | size_t array_size = 0; |
| 3427 | 3433 | void __user *user_ptr = NULL; |
| 3428 | 3434 | void **kernel_ptr = NULL; |
| 3429 | − unsigned int cmd = video_translate_cmd(orig_cmd); | |
| 3435 | + unsigned int cmd = v4l2_translate_cmd(orig_cmd); | |
| 3430 | 3436 | const size_t ioc_size = _IOC_SIZE(cmd); |
| 3431 | 3437 | |
| 3432 | 3438 | /* Copy arguments into temp kernel buffer */ |
| @@ -711,83 +711,3 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out) · 710 unmodified lines | ||
| 711 | 711 | return marker; |
| 712 | 712 | } |
| 713 | 713 | EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_header); |
| 714 | − | |
| 715 | −/** | |
| 716 | − * v4l2_jpeg_parse_frame_header - parse frame header | |
| 717 | − * @buf: address of the frame header, after the SOF0 marker | |
| 718 | − * @len: length of the frame header | |
| 719 | − * @frame_header: returns the parsed frame header | |
| 720 | − * | |
| 721 | − * Returns 0 or negative error if parsing failed. | |
| 722 | − */ | |
| 723 | −int v4l2_jpeg_parse_frame_header(void *buf, size_t len, | |
| 724 | − struct v4l2_jpeg_frame_header *frame_header) | |
| 725 | −{ | |
| 726 | − struct jpeg_stream stream; | |
| 727 | − | |
| 728 | − stream.curr = buf; | |
| 729 | − stream.end = stream.curr + len; | |
| 730 | − return jpeg_parse_frame_header(&stream, SOF0, frame_header); | |
| 731 | −} | |
| 732 | −EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_frame_header); | |
| 733 | − | |
| 734 | −/** | |
| 735 | − * v4l2_jpeg_parse_scan_header - parse scan header | |
| 736 | − * @buf: address of the scan header, after the SOS marker | |
| 737 | − * @len: length of the scan header | |
| 738 | − * @scan_header: returns the parsed scan header | |
| 739 | − * | |
| 740 | − * Returns 0 or negative error if parsing failed. | |
| 741 | − */ | |
| 742 | −int v4l2_jpeg_parse_scan_header(void *buf, size_t len, | |
| 743 | − struct v4l2_jpeg_scan_header *scan_header) | |
| 744 | −{ | |
| 745 | − struct jpeg_stream stream; | |
| 746 | − | |
| 747 | − stream.curr = buf; | |
| 748 | − stream.end = stream.curr + len; | |
| 749 | − return jpeg_parse_scan_header(&stream, scan_header); | |
| 750 | −} | |
| 751 | −EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_scan_header); | |
| 752 | − | |
| 753 | −/** | |
| 754 | − * v4l2_jpeg_parse_quantization_tables - parse quantization tables segment | |
| 755 | − * @buf: address of the quantization table segment, after the DQT marker | |
| 756 | − * @len: length of the quantization table segment | |
| 757 | − * @precision: sample precision (P) in bits per component | |
| 758 | − * @q_tables: returns four references into the buffer for the | |
| 759 | − * four possible quantization table destinations | |
| 760 | − * | |
| 761 | − * Returns 0 or negative error if parsing failed. | |
| 762 | − */ | |
| 763 | −int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len, u8 precision, | |
| 764 | − struct v4l2_jpeg_reference *q_tables) | |
| 765 | −{ | |
| 766 | − struct jpeg_stream stream; | |
| 767 | − | |
| 768 | − stream.curr = buf; | |
| 769 | − stream.end = stream.curr + len; | |
| 770 | − return jpeg_parse_quantization_tables(&stream, precision, q_tables); | |
| 771 | −} | |
| 772 | −EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_quantization_tables); | |
| 773 | − | |
| 774 | −/** | |
| 775 | − * v4l2_jpeg_parse_huffman_tables - parse huffman tables segment | |
| 776 | − * @buf: address of the Huffman table segment, after the DHT marker | |
| 777 | − * @len: length of the Huffman table segment | |
| 778 | − * @huffman_tables: returns four references into the buffer for the | |
| 779 | − * four possible Huffman table destinations, in | |
| 780 | − * the order DC0, DC1, AC0, AC1 | |
| 781 | − * | |
| 782 | − * Returns 0 or negative error if parsing failed. | |
| 783 | − */ | |
| 784 | −int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len, | |
| 785 | − struct v4l2_jpeg_reference *huffman_tables) | |
| 786 | −{ | |
| 787 | − struct jpeg_stream stream; | |
| 788 | − | |
| 789 | − stream.curr = buf; | |
| 790 | − stream.end = stream.curr + len; | |
| 791 | − return jpeg_parse_huffman_tables(&stream, huffman_tables); | |
| 792 | −} | |
| 793 | −EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_huffman_tables); | |
| @@ -1004,6 +1004,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, · 1003 unmodified lines | ||
| 1004 | 1004 | struct v4l2_subdev_route *routes = |
| 1005 | 1005 | (struct v4l2_subdev_route *)(uintptr_t)routing->routes; |
| 1006 | 1006 | struct v4l2_subdev_krouting krouting = {}; |
| 1007 | + unsigned int num_active_routes = 0; | |
| 1007 | 1008 | unsigned int i; |
| 1008 | 1009 | |
| 1009 | 1010 | if (!v4l2_subdev_enable_streams_api) |
| @@ -1041,8 +1042,21 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, · 31 unmodified lines | ||
| 1041 | 1042 | if (!(pads[route->source_pad].flags & |
| 1042 | 1043 | MEDIA_PAD_FL_SOURCE)) |
| 1043 | 1044 | return -EINVAL; |
| 1045 | + | |
| 1046 | + if (route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE) | |
| 1047 | + num_active_routes++; | |
| 1044 | 1048 | } |
| 1045 | 1049 | |
| 1050 | + /* | |
| 1051 | + * Drivers that implement routing need to report a frame | |
| 1052 | + * descriptor accordingly, with up to one entry per route. Until | |
| 1053 | + * the frame descriptors entries get allocated dynamically, | |
| 1054 | + * limit the number of active routes to | |
| 1055 | + * V4L2_FRAME_DESC_ENTRY_MAX. | |
| 1056 | + */ | |
| 1057 | + if (num_active_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 1058 | + return -E2BIG; | |
| 1059 | + | |
| 1046 | 1060 | /* |
| 1047 | 1061 | * If the driver doesn't support setting routing, just return |
| 1048 | 1062 | * the routing table. |
| @@ -2219,6 +2233,9 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd, · 1170 unmodified lines | ||
| 2219 | 2233 | *found_streams = BIT_ULL(0); |
| 2220 | 2234 | *enabled_streams = |
| 2221 | 2235 | (sd->enabled_pads & BIT_ULL(pad)) ? BIT_ULL(0) : 0; |
| 2236 | + dev_dbg(sd->dev, | |
| 2237 | + "collect_streams: sub-device \"%s\" does not support streams\n", | |
| 2238 | + sd->entity.name); | |
| 2222 | 2239 | return; |
| 2223 | 2240 | } |
| 2224 | 2241 | |
| @@ -2236,6 +2253,10 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd, · 11 unmodified lines | ||
| 2236 | 2253 | if (cfg->enabled) |
| 2237 | 2254 | *enabled_streams |= BIT_ULL(cfg->stream); |
| 2238 | 2255 | } |
| 2256 | + | |
| 2257 | + dev_dbg(sd->dev, | |
| 2258 | + "collect_streams: \"%s\":%u: found %#llx enabled %#llx\n", | |
| 2259 | + sd->entity.name, pad, *found_streams, *enabled_streams); | |
| 2239 | 2260 | } |
| 2240 | 2261 | |
| 2241 | 2262 | static void v4l2_subdev_set_streams_enabled(struct v4l2_subdev *sd, |
| @@ -2271,6 +2292,9 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, · 29 unmodified lines | ||
| 2271 | 2292 | bool use_s_stream; |
| 2272 | 2293 | int ret; |
| 2273 | 2294 | |
| 2295 | + dev_dbg(dev, "enable streams \"%s\":%u/%#llx\n", sd->entity.name, pad, | |
| 2296 | + streams_mask); | |
| 2297 | + | |
| 2274 | 2298 | /* A few basic sanity checks first. */ |
| 2275 | 2299 | if (pad >= sd->entity.num_pads) |
| 2276 | 2300 | return -EINVAL; |
| @@ -2318,8 +2342,6 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, · 41 unmodified lines | ||
| 2318 | 2342 | goto done; |
| 2319 | 2343 | } |
| 2320 | 2344 | |
| 2321 | − dev_dbg(dev, "enable streams %u:%#llx\n", pad, streams_mask); | |
| 2322 | − | |
| 2323 | 2345 | already_streaming = v4l2_subdev_is_streaming(sd); |
| 2324 | 2346 | |
| 2325 | 2347 | if (!use_s_stream) { |
| @@ -2371,6 +2393,9 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, · 45 unmodified lines | ||
| 2371 | 2393 | bool use_s_stream; |
| 2372 | 2394 | int ret; |
| 2373 | 2395 | |
| 2396 | + dev_dbg(dev, "disable streams \"%s\":%u/%#llx\n", sd->entity.name, pad, | |
| 2397 | + streams_mask); | |
| 2398 | + | |
| 2374 | 2399 | /* A few basic sanity checks first. */ |
| 2375 | 2400 | if (pad >= sd->entity.num_pads) |
| 2376 | 2401 | return -EINVAL; |
| @@ -2418,8 +2443,6 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, · 41 unmodified lines | ||
| 2418 | 2443 | goto done; |
| 2419 | 2444 | } |
| 2420 | 2445 | |
| 2421 | − dev_dbg(dev, "disable streams %u:%#llx\n", pad, streams_mask); | |
| 2422 | − | |
| 2423 | 2446 | if (!use_s_stream) { |
| 2424 | 2447 | /* Call the .disable_streams() operation. */ |
| 2425 | 2448 | ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad, |
| @@ -129,6 +129,109 @@ static const struct tps68470_regulator_platform_data surface_go_tps68470_pdata = · 128 unmodified lines | ||
| 129 | 129 | }, |
| 130 | 130 | }; |
| 131 | 131 | |
| 132 | +/* Settings for Dell 7212 Tablet */ | |
| 133 | + | |
| 134 | +static struct regulator_consumer_supply int3479_vsio_consumer_supplies[] = { | |
| 135 | + REGULATOR_SUPPLY("avdd", "i2c-INT3479:00"), | |
| 136 | +}; | |
| 137 | + | |
| 138 | +static struct regulator_consumer_supply int3479_aux1_consumer_supplies[] = { | |
| 139 | + REGULATOR_SUPPLY("dvdd", "i2c-INT3479:00"), | |
| 140 | +}; | |
| 141 | + | |
| 142 | +static struct regulator_consumer_supply int3479_aux2_consumer_supplies[] = { | |
| 143 | + REGULATOR_SUPPLY("dovdd", "i2c-INT3479:00"), | |
| 144 | +}; | |
| 145 | + | |
| 146 | +static const struct regulator_init_data dell_7212_tps68470_core_reg_init_data = { | |
| 147 | + .constraints = { | |
| 148 | + .min_uV = 1200000, | |
| 149 | + .max_uV = 1200000, | |
| 150 | + .apply_uV = 1, | |
| 151 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 152 | + }, | |
| 153 | + .num_consumer_supplies = 0, | |
| 154 | + .consumer_supplies = NULL, | |
| 155 | +}; | |
| 156 | + | |
| 157 | +static const struct regulator_init_data dell_7212_tps68470_ana_reg_init_data = { | |
| 158 | + .constraints = { | |
| 159 | + .min_uV = 2815200, | |
| 160 | + .max_uV = 2815200, | |
| 161 | + .apply_uV = 1, | |
| 162 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 163 | + }, | |
| 164 | + .num_consumer_supplies = 0, | |
| 165 | + .consumer_supplies = NULL, | |
| 166 | +}; | |
| 167 | + | |
| 168 | +static const struct regulator_init_data dell_7212_tps68470_vcm_reg_init_data = { | |
| 169 | + .constraints = { | |
| 170 | + .min_uV = 2815200, | |
| 171 | + .max_uV = 2815200, | |
| 172 | + .apply_uV = 1, | |
| 173 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 174 | + }, | |
| 175 | + .num_consumer_supplies = 0, | |
| 176 | + .consumer_supplies = NULL, | |
| 177 | +}; | |
| 178 | + | |
| 179 | +static const struct regulator_init_data dell_7212_tps68470_vio_reg_init_data = { | |
| 180 | + .constraints = { | |
| 181 | + .min_uV = 1800600, | |
| 182 | + .max_uV = 1800600, | |
| 183 | + .apply_uV = 1, | |
| 184 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 185 | + }, | |
| 186 | + .num_consumer_supplies = 0, | |
| 187 | + .consumer_supplies = NULL, | |
| 188 | +}; | |
| 189 | + | |
| 190 | +static const struct regulator_init_data dell_7212_tps68470_vsio_reg_init_data = { | |
| 191 | + .constraints = { | |
| 192 | + .min_uV = 1800600, | |
| 193 | + .max_uV = 1800600, | |
| 194 | + .apply_uV = 1, | |
| 195 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 196 | + }, | |
| 197 | + .num_consumer_supplies = ARRAY_SIZE(int3479_vsio_consumer_supplies), | |
| 198 | + .consumer_supplies = int3479_vsio_consumer_supplies, | |
| 199 | +}; | |
| 200 | + | |
| 201 | +static const struct regulator_init_data dell_7212_tps68470_aux1_reg_init_data = { | |
| 202 | + .constraints = { | |
| 203 | + .min_uV = 1213200, | |
| 204 | + .max_uV = 1213200, | |
| 205 | + .apply_uV = 1, | |
| 206 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 207 | + }, | |
| 208 | + .num_consumer_supplies = ARRAY_SIZE(int3479_aux1_consumer_supplies), | |
| 209 | + .consumer_supplies = int3479_aux1_consumer_supplies, | |
| 210 | +}; | |
| 211 | + | |
| 212 | +static const struct regulator_init_data dell_7212_tps68470_aux2_reg_init_data = { | |
| 213 | + .constraints = { | |
| 214 | + .min_uV = 1800600, | |
| 215 | + .max_uV = 1800600, | |
| 216 | + .apply_uV = 1, | |
| 217 | + .valid_ops_mask = REGULATOR_CHANGE_STATUS, | |
| 218 | + }, | |
| 219 | + .num_consumer_supplies = ARRAY_SIZE(int3479_aux2_consumer_supplies), | |
| 220 | + .consumer_supplies = int3479_aux2_consumer_supplies, | |
| 221 | +}; | |
| 222 | + | |
| 223 | +static const struct tps68470_regulator_platform_data dell_7212_tps68470_pdata = { | |
| 224 | + .reg_init_data = { | |
| 225 | + [TPS68470_CORE] = &dell_7212_tps68470_core_reg_init_data, | |
| 226 | + [TPS68470_ANA] = &dell_7212_tps68470_ana_reg_init_data, | |
| 227 | + [TPS68470_VCM] = &dell_7212_tps68470_vcm_reg_init_data, | |
| 228 | + [TPS68470_VIO] = &dell_7212_tps68470_vio_reg_init_data, | |
| 229 | + [TPS68470_VSIO] = &dell_7212_tps68470_vsio_reg_init_data, | |
| 230 | + [TPS68470_AUX1] = &dell_7212_tps68470_aux1_reg_init_data, | |
| 231 | + [TPS68470_AUX2] = &dell_7212_tps68470_aux2_reg_init_data, | |
| 232 | + }, | |
| 233 | +}; | |
| 234 | + | |
| 132 | 235 | static struct gpiod_lookup_table surface_go_int347a_gpios = { |
| 133 | 236 | .dev_id = "i2c-INT347A:00", |
| 134 | 237 | .table = { |
| @@ -146,6 +249,15 @@ static struct gpiod_lookup_table surface_go_int347e_gpios = { · 11 unmodified lines | ||
| 146 | 249 | } |
| 147 | 250 | }; |
| 148 | 251 | |
| 252 | +static struct gpiod_lookup_table dell_7212_int3479_gpios = { | |
| 253 | + .dev_id = "i2c-INT3479:00", | |
| 254 | + .table = { | |
| 255 | + GPIO_LOOKUP("tps68470-gpio", 3, "reset", GPIO_ACTIVE_LOW), | |
| 256 | + GPIO_LOOKUP("tps68470-gpio", 4, "powerdown", GPIO_ACTIVE_LOW), | |
| 257 | + { } | |
| 258 | + } | |
| 259 | +}; | |
| 260 | + | |
| 149 | 261 | static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = { |
| 150 | 262 | .dev_name = "i2c-INT3472:05", |
| 151 | 263 | .tps68470_regulator_pdata = &surface_go_tps68470_pdata, |
| @@ -166,6 +278,15 @@ static const struct int3472_tps68470_board_data surface_go3_tps68470_board_data · 14 unmodified lines | ||
| 166 | 278 | }, |
| 167 | 279 | }; |
| 168 | 280 | |
| 281 | +static const struct int3472_tps68470_board_data dell_7212_tps68470_board_data = { | |
| 282 | + .dev_name = "i2c-INT3472:05", | |
| 283 | + .tps68470_regulator_pdata = &dell_7212_tps68470_pdata, | |
| 284 | + .n_gpiod_lookups = 1, | |
| 285 | + .tps68470_gpio_lookup_tables = { | |
| 286 | + &dell_7212_int3479_gpios, | |
| 287 | + }, | |
| 288 | +}; | |
| 289 | + | |
| 169 | 290 | static const struct dmi_system_id int3472_tps68470_board_data_table[] = { |
| 170 | 291 | { |
| 171 | 292 | .matches = { |
| @@ -188,6 +309,13 @@ static const struct dmi_system_id int3472_tps68470_board_data_table[] = { · 16 unmodified lines | ||
| 188 | 309 | }, |
| 189 | 310 | .driver_data = (void *)&surface_go3_tps68470_board_data, |
| 190 | 311 | }, |
| 312 | + { | |
| 313 | + .matches = { | |
| 314 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | |
| 315 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Latitude 7212 Rugged Extreme Tablet"), | |
| 316 | + }, | |
| 317 | + .driver_data = (void *)&dell_7212_tps68470_board_data, | |
| 318 | + }, | |
| 191 | 319 | { } |
| 192 | 320 | }; |
| 193 | 321 | |
| @@ -28,12 +28,12 @@ source "drivers/staging/media/imx/Kconfig" · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | source "drivers/staging/media/ipu3/Kconfig" |
| 30 | 30 | |
| 31 | +source "drivers/staging/media/ipu7/Kconfig" | |
| 32 | + | |
| 31 | 33 | source "drivers/staging/media/max96712/Kconfig" |
| 32 | 34 | |
| 33 | 35 | source "drivers/staging/media/meson/vdec/Kconfig" |
| 34 | 36 | |
| 35 | −source "drivers/staging/media/rkvdec/Kconfig" | |
| 36 | − | |
| 37 | 37 | source "drivers/staging/media/starfive/Kconfig" |
| 38 | 38 | |
| 39 | 39 | source "drivers/staging/media/sunxi/Kconfig" |
| @@ -4,9 +4,9 @@ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ · 3 unmodified lines | ||
| 4 | 4 | obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ |
| 5 | 5 | obj-$(CONFIG_VIDEO_MAX96712) += max96712/ |
| 6 | 6 | obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ |
| 7 | −obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ | |
| 8 | 7 | obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ |
| 9 | 8 | obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ |
| 10 | 9 | obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ |
| 11 | 10 | obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ |
| 11 | +obj-$(CONFIG_VIDEO_INTEL_IPU7) += ipu7/ | |
| 12 | 12 | obj-$(CONFIG_DVB_AV7110) += av7110/ |
| @@ -12,6 +12,7 @@ menuconfig INTEL_ATOMISP · 11 unmodified lines | ||
| 12 | 12 | config VIDEO_ATOMISP |
| 13 | 13 | tristate "Intel Atom Image Signal Processor Driver" |
| 14 | 14 | depends on VIDEO_DEV && INTEL_ATOMISP |
| 15 | + depends on INTEL_SKL_INT3472 | |
| 15 | 16 | depends on IPU_BRIDGE |
| 16 | 17 | depends on MEDIA_PCI_SUPPORT |
| 17 | 18 | depends on PMIC_OPREGION |
| @@ -17,7 +17,6 @@ atomisp-objs += \ · 16 unmodified lines | ||
| 17 | 17 | pci/atomisp_compat_css20.o \ |
| 18 | 18 | pci/atomisp_csi2.o \ |
| 19 | 19 | pci/atomisp_csi2_bridge.o \ |
| 20 | − pci/atomisp_drvfs.o \ | |
| 21 | 20 | pci/atomisp_fops.o \ |
| 22 | 21 | pci/atomisp_ioctl.o \ |
| 23 | 22 | pci/atomisp_subdev.o \ |
| @@ -7,8 +7,6 @@ TODO · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | * Remove/disable custom v4l2-ctrls |
| 9 | 9 | |
| 10 | −* Remove custom sysfs files created by atomisp_drvfs.c | |
| 11 | − | |
| 12 | 10 | * Remove unnecessary/unwanted module parameters |
| 13 | 11 | |
| 14 | 12 | * Remove abuse of priv field in various v4l2 userspace API structs |
| @@ -31,6 +31,7 @@ config VIDEO_ATOMISP_GC0310 · 30 unmodified lines | ||
| 31 | 31 | tristate "GC0310 sensor support" |
| 32 | 32 | depends on ACPI |
| 33 | 33 | depends on I2C && VIDEO_DEV |
| 34 | + select V4L2_CCI_I2C | |
| 34 | 35 | help |
| 35 | 36 | This is a Video4Linux2 sensor-level driver for the Galaxycore |
| 36 | 37 | GC0310 0.3MP sensor. |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | * Support for GalaxyCore GC0310 VGA camera sensor. |
| 4 | 4 | * |
| 5 | 5 | * Copyright (c) 2013 Intel Corporation. All Rights Reserved. |
| 6 | − * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com> | |
| 6 | + * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> | |
| 7 | 7 | */ |
| 8 | 8 | |
| 9 | 9 | #include <linux/delay.h> |
| @@ -13,77 +13,92 @@ · 3 unmodified lines | ||
| 13 | 13 | #include <linux/kernel.h> |
| 14 | 14 | #include <linux/module.h> |
| 15 | 15 | #include <linux/pm_runtime.h> |
| 16 | +#include <linux/regmap.h> | |
| 16 | 17 | #include <linux/string.h> |
| 17 | 18 | #include <linux/types.h> |
| 18 | 19 | |
| 20 | +#include <media/v4l2-cci.h> | |
| 19 | 21 | #include <media/v4l2-ctrls.h> |
| 20 | 22 | #include <media/v4l2-device.h> |
| 23 | +#include <media/v4l2-fwnode.h> | |
| 21 | 24 | |
| 22 | 25 | #define GC0310_NATIVE_WIDTH 656 |
| 23 | 26 | #define GC0310_NATIVE_HEIGHT 496 |
| 24 | 27 | |
| 28 | +/* | |
| 29 | + * The actual PLL output rate is unknown, the datasheet | |
| 30 | + * says that the formula for the frame-time in pixels is: | |
| 31 | + * rowtime = win-width + hblank + sh-delay + 4 | |
| 32 | + * frametime = rowtime * (win-height + vblank) | |
| 33 | + * Filling this in and multiplying by 30 fps gives: | |
| 34 | + * pixelrate = (660 + 178 + 42 + 4) * (498 + 27) * 30 = 13923000 | |
| 35 | + */ | |
| 36 | +#define GC0310_PIXELRATE 13923000 | |
| 37 | +/* single lane, bus-format is 8 bpp, CSI-2 is double data rate */ | |
| 38 | +#define GC0310_LINK_FREQ (GC0310_PIXELRATE * 8 / 2) | |
| 39 | +#define GC0310_MCLK_FREQ 19200000 | |
| 25 | 40 | #define GC0310_FPS 30 |
| 26 | 41 | #define GC0310_SKIP_FRAMES 3 |
| 27 | 42 | |
| 28 | −#define GC0310_FOCAL_LENGTH_NUM 278 /* 2.78mm */ | |
| 29 | − | |
| 30 | 43 | #define GC0310_ID 0xa310 |
| 31 | 44 | |
| 32 | −#define GC0310_RESET_RELATED 0xFE | |
| 45 | +#define GC0310_RESET_RELATED_REG CCI_REG8(0xfe) | |
| 33 | 46 | #define GC0310_REGISTER_PAGE_0 0x0 |
| 34 | 47 | #define GC0310_REGISTER_PAGE_3 0x3 |
| 35 | 48 | |
| 36 | 49 | /* |
| 37 | 50 | * GC0310 System control registers |
| 38 | 51 | */ |
| 39 | −#define GC0310_SW_STREAM 0x10 | |
| 40 | − | |
| 41 | −#define GC0310_SC_CMMN_CHIP_ID_H 0xf0 | |
| 42 | −#define GC0310_SC_CMMN_CHIP_ID_L 0xf1 | |
| 43 | − | |
| 44 | −#define GC0310_AEC_PK_EXPO_H 0x03 | |
| 45 | −#define GC0310_AEC_PK_EXPO_L 0x04 | |
| 46 | −#define GC0310_AGC_ADJ 0x48 | |
| 47 | −#define GC0310_DGC_ADJ 0x71 | |
| 48 | −#define GC0310_GROUP_ACCESS 0x3208 | |
| 49 | − | |
| 50 | −#define GC0310_H_CROP_START_H 0x09 | |
| 51 | −#define GC0310_H_CROP_START_L 0x0A | |
| 52 | −#define GC0310_V_CROP_START_H 0x0B | |
| 53 | −#define GC0310_V_CROP_START_L 0x0C | |
| 54 | −#define GC0310_H_OUTSIZE_H 0x0F | |
| 55 | −#define GC0310_H_OUTSIZE_L 0x10 | |
| 56 | −#define GC0310_V_OUTSIZE_H 0x0D | |
| 57 | −#define GC0310_V_OUTSIZE_L 0x0E | |
| 58 | −#define GC0310_H_BLANKING_H 0x05 | |
| 59 | −#define GC0310_H_BLANKING_L 0x06 | |
| 60 | −#define GC0310_V_BLANKING_H 0x07 | |
| 61 | −#define GC0310_V_BLANKING_L 0x08 | |
| 62 | −#define GC0310_SH_DELAY 0x11 | |
| 52 | +#define GC0310_SW_STREAM_REG CCI_REG8(0x10) | |
| 63 | 53 | |
| 64 | 54 | #define GC0310_START_STREAMING 0x94 /* 8-bit enable */ |
| 65 | 55 | #define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */ |
| 66 | 56 | |
| 57 | +#define GC0310_SC_CMMN_CHIP_ID_REG CCI_REG16(0xf0) | |
| 58 | + | |
| 59 | +#define GC0310_AEC_PK_EXPO_REG CCI_REG16(0x03) | |
| 60 | +#define GC0310_AGC_ADJ_REG CCI_REG8(0x48) | |
| 61 | +#define GC0310_DGC_ADJ_REG CCI_REG8(0x71) | |
| 62 | + | |
| 63 | +#define GC0310_H_CROP_START_REG CCI_REG16(0x09) | |
| 64 | +#define GC0310_V_CROP_START_REG CCI_REG16(0x0b) | |
| 65 | +#define GC0310_H_OUTSIZE_REG CCI_REG16(0x0f) | |
| 66 | +#define GC0310_V_OUTSIZE_REG CCI_REG16(0x0d) | |
| 67 | + | |
| 68 | +#define GC0310_H_BLANKING_REG CCI_REG16(0x05) | |
| 69 | +/* Hblank-register + sh-delay + H-crop + 4 (from hw) */ | |
| 70 | +#define GC0310_H_BLANK_DEFAULT (178 + 42 + 4 + 4) | |
| 71 | + | |
| 72 | +#define GC0310_V_BLANKING_REG CCI_REG16(0x07) | |
| 73 | +/* Vblank needs an offset compensate for the small V-crop done */ | |
| 74 | +#define GC0310_V_BLANK_OFFSET 2 | |
| 75 | +/* Vsync start time + 1 row vsync + vsync end time + offset */ | |
| 76 | +#define GC0310_V_BLANK_MIN (9 + 1 + 4 + GC0310_V_BLANK_OFFSET) | |
| 77 | +#define GC0310_V_BLANK_DEFAULT (27 + GC0310_V_BLANK_OFFSET) | |
| 78 | +#define GC0310_V_BLANK_MAX (4095 - GC0310_NATIVE_HEIGHT) | |
| 79 | + | |
| 80 | +#define GC0310_SH_DELAY_REG CCI_REG8(0x11) | |
| 81 | +#define GC0310_VS_START_TIME_REG CCI_REG8(0x12) | |
| 82 | +#define GC0310_VS_END_TIME_REG CCI_REG8(0x13) | |
| 83 | + | |
| 67 | 84 | #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) |
| 68 | 85 | |
| 69 | 86 | struct gc0310_device { |
| 70 | 87 | struct v4l2_subdev sd; |
| 71 | 88 | struct media_pad pad; |
| 72 | − /* Protect against concurrent changes to controls */ | |
| 73 | − struct mutex input_lock; | |
| 74 | − bool is_streaming; | |
| 75 | 89 | |
| 90 | + struct regmap *regmap; | |
| 76 | 91 | struct gpio_desc *reset; |
| 77 | 92 | struct gpio_desc *powerdown; |
| 78 | 93 | |
| 79 | − struct gc0310_mode { | |
| 80 | − struct v4l2_mbus_framefmt fmt; | |
| 81 | − } mode; | |
| 82 | − | |
| 83 | 94 | struct gc0310_ctrls { |
| 84 | 95 | struct v4l2_ctrl_handler handler; |
| 85 | 96 | struct v4l2_ctrl *exposure; |
| 86 | 97 | struct v4l2_ctrl *gain; |
| 98 | + struct v4l2_ctrl *link_freq; | |
| 99 | + struct v4l2_ctrl *pixel_rate; | |
| 100 | + struct v4l2_ctrl *vblank; | |
| 101 | + struct v4l2_ctrl *hblank; | |
| 87 | 102 | } ctrls; |
| 88 | 103 | }; |
| 89 | 104 | |
| @@ -92,7 +107,7 @@ struct gc0310_reg { · 2 unmodified lines | ||
| 92 | 107 | u8 val; |
| 93 | 108 | }; |
| 94 | 109 | |
| 95 | −static const struct gc0310_reg gc0310_reset_register[] = { | |
| 110 | +static const struct reg_sequence gc0310_reset_register[] = { | |
| 96 | 111 | /* System registers */ |
| 97 | 112 | { 0xfe, 0xf0 }, |
| 98 | 113 | { 0xfe, 0xf0 }, |
| @@ -142,8 +157,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { · 43 unmodified lines | ||
| 142 | 157 | { 0x04, 0xc0 }, /* 0xe8 //58 */ |
| 143 | 158 | { 0x05, 0x00 }, |
| 144 | 159 | { 0x06, 0xb2 }, /* 0x0a //HB */ |
| 145 | − { 0x07, 0x00 }, | |
| 146 | − { 0x08, 0x0c }, /* 0x89 //VB */ | |
| 160 | + /* Vblank (reg 0x07 + 0x08) gets set by the vblank ctrl */ | |
| 147 | 161 | { 0x09, 0x00 }, /* row start */ |
| 148 | 162 | { 0x0a, 0x00 }, |
| 149 | 163 | { 0x0b, 0x00 }, /* col start */ |
| @@ -235,7 +249,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { · 85 unmodified lines | ||
| 235 | 249 | { 0xfe, 0x00 }, |
| 236 | 250 | }; |
| 237 | 251 | |
| 238 | −static const struct gc0310_reg gc0310_VGA_30fps[] = { | |
| 252 | +static const struct reg_sequence gc0310_VGA_30fps[] = { | |
| 239 | 253 | { 0xfe, 0x00 }, |
| 240 | 254 | { 0x0d, 0x01 }, /* height */ |
| 241 | 255 | { 0x0e, 0xf2 }, /* 0xf7 //height */ |
| @@ -259,41 +273,14 @@ static const struct gc0310_reg gc0310_VGA_30fps[] = { · 17 unmodified lines | ||
| 259 | 273 | { 0xfe, 0x00 }, |
| 260 | 274 | }; |
| 261 | 275 | |
| 262 | −/* | |
| 263 | − * gc0310_write_reg_array - Initializes a list of GC0310 registers | |
| 264 | − * @client: i2c driver client structure | |
| 265 | − * @reglist: list of registers to be written | |
| 266 | − * @count: number of register, value pairs in the list | |
| 267 | − */ | |
| 268 | −static int gc0310_write_reg_array(struct i2c_client *client, | |
| 269 | − const struct gc0310_reg *reglist, int count) | |
| 270 | −{ | |
| 271 | − int i, err; | |
| 272 | − | |
| 273 | − for (i = 0; i < count; i++) { | |
| 274 | − err = i2c_smbus_write_byte_data(client, reglist[i].reg, reglist[i].val); | |
| 275 | − if (err) { | |
| 276 | − dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", | |
| 277 | − reglist[i].val, reglist[i].reg, err); | |
| 278 | − return err; | |
| 279 | − } | |
| 280 | − } | |
| 281 | − | |
| 282 | − return 0; | |
| 283 | −} | |
| 284 | − | |
| 285 | −static int gc0310_exposure_set(struct gc0310_device *dev, u32 exp) | |
| 286 | −{ | |
| 287 | − struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); | |
| 288 | − | |
| 289 | − return i2c_smbus_write_word_swapped(client, GC0310_AEC_PK_EXPO_H, exp); | |
| 290 | −} | |
| 276 | +static const s64 link_freq_menu_items[] = { | |
| 277 | + GC0310_LINK_FREQ, | |
| 278 | +}; | |
| 291 | 279 | |
| 292 | −static int gc0310_gain_set(struct gc0310_device *dev, u32 gain) | |
| 280 | +static int gc0310_gain_set(struct gc0310_device *sensor, u32 gain) | |
| 293 | 281 | { |
| 294 | − struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); | |
| 295 | 282 | u8 again, dgain; |
| 296 | − int ret; | |
| 283 | + int ret = 0; | |
| 297 | 284 | |
| 298 | 285 | /* Taken from original driver, this never sets dgain lower then 32? */ |
| 299 | 286 | |
| @@ -308,36 +295,55 @@ static int gc0310_gain_set(struct gc0310_device *dev, u32 gain) · 8 unmodified lines | ||
| 308 | 295 | dgain = gain / 2; |
| 309 | 296 | } |
| 310 | 297 | |
| 311 | − ret = i2c_smbus_write_byte_data(client, GC0310_AGC_ADJ, again); | |
| 312 | − if (ret) | |
| 313 | − return ret; | |
| 298 | + cci_write(sensor->regmap, GC0310_AGC_ADJ_REG, again, &ret); | |
| 299 | + cci_write(sensor->regmap, GC0310_DGC_ADJ_REG, dgain, &ret); | |
| 300 | + return ret; | |
| 301 | +} | |
| 302 | + | |
| 303 | +static int gc0310_exposure_update_range(struct gc0310_device *sensor) | |
| 304 | +{ | |
| 305 | + int exp_max = GC0310_NATIVE_HEIGHT + sensor->ctrls.vblank->val; | |
| 314 | 306 | |
| 315 | − return i2c_smbus_write_byte_data(client, GC0310_DGC_ADJ, dgain); | |
| 307 | + return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max, | |
| 308 | + 1, exp_max); | |
| 316 | 309 | } |
| 317 | 310 | |
| 318 | 311 | static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) |
| 319 | 312 | { |
| 320 | − struct gc0310_device *dev = | |
| 313 | + struct gc0310_device *sensor = | |
| 321 | 314 | container_of(ctrl->handler, struct gc0310_device, ctrls.handler); |
| 322 | 315 | int ret; |
| 323 | 316 | |
| 317 | + /* Update exposure range on vblank changes */ | |
| 318 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 319 | + ret = gc0310_exposure_update_range(sensor); | |
| 320 | + if (ret) | |
| 321 | + return ret; | |
| 322 | + } | |
| 323 | + | |
| 324 | 324 | /* Only apply changes to the controls if the device is powered up */ |
| 325 | − if (!pm_runtime_get_if_in_use(dev->sd.dev)) | |
| 325 | + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) | |
| 326 | 326 | return 0; |
| 327 | 327 | |
| 328 | 328 | switch (ctrl->id) { |
| 329 | 329 | case V4L2_CID_EXPOSURE: |
| 330 | − ret = gc0310_exposure_set(dev, ctrl->val); | |
| 330 | + ret = cci_write(sensor->regmap, GC0310_AEC_PK_EXPO_REG, | |
| 331 | + ctrl->val, NULL); | |
| 331 | 332 | break; |
| 332 | − case V4L2_CID_GAIN: | |
| 333 | − ret = gc0310_gain_set(dev, ctrl->val); | |
| 333 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 334 | + ret = gc0310_gain_set(sensor, ctrl->val); | |
| 335 | + break; | |
| 336 | + case V4L2_CID_VBLANK: | |
| 337 | + ret = cci_write(sensor->regmap, GC0310_V_BLANKING_REG, | |
| 338 | + ctrl->val - GC0310_V_BLANK_OFFSET, | |
| 339 | + NULL); | |
| 334 | 340 | break; |
| 335 | 341 | default: |
| 336 | 342 | ret = -EINVAL; |
| 337 | 343 | break; |
| 338 | 344 | } |
| 339 | 345 | |
| 340 | − pm_runtime_put(dev->sd.dev); | |
| 346 | + pm_runtime_put(sensor->sd.dev); | |
| 341 | 347 | return ret; |
| 342 | 348 | } |
| 343 | 349 | |
| @@ -345,17 +351,6 @@ static const struct v4l2_ctrl_ops ctrl_ops = { · 1 unmodified line | ||
| 345 | 351 | .s_ctrl = gc0310_s_ctrl, |
| 346 | 352 | }; |
| 347 | 353 | |
| 348 | −static struct v4l2_mbus_framefmt * | |
| 349 | −gc0310_get_pad_format(struct gc0310_device *dev, | |
| 350 | − struct v4l2_subdev_state *state, | |
| 351 | − unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 352 | −{ | |
| 353 | − if (which == V4L2_SUBDEV_FORMAT_TRY) | |
| 354 | − return v4l2_subdev_state_get_format(state, pad); | |
| 355 | − | |
| 356 | − return &dev->mode.fmt; | |
| 357 | −} | |
| 358 | − | |
| 359 | 354 | /* The GC0310 currently only supports 1 fixed fmt */ |
| 360 | 355 | static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) |
| 361 | 356 | { |
| @@ -366,54 +361,72 @@ static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) · 4 unmodified lines | ||
| 366 | 361 | fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; |
| 367 | 362 | } |
| 368 | 363 | |
| 369 | −static int gc0310_set_fmt(struct v4l2_subdev *sd, | |
| 370 | − struct v4l2_subdev_state *sd_state, | |
| 371 | − struct v4l2_subdev_format *format) | |
| 364 | +static int gc0310_get_selection(struct v4l2_subdev *sd, | |
| 365 | + struct v4l2_subdev_state *state, | |
| 366 | + struct v4l2_subdev_selection *sel) | |
| 372 | 367 | { |
| 373 | − struct gc0310_device *dev = to_gc0310_sensor(sd); | |
| 374 | − struct v4l2_mbus_framefmt *fmt; | |
| 368 | + /* Only the single fixed 656x496 mode is supported, without croping */ | |
| 369 | + switch (sel->target) { | |
| 370 | + case V4L2_SEL_TGT_CROP: | |
| 371 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 372 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 373 | + case V4L2_SEL_TGT_NATIVE_SIZE: | |
| 374 | + sel->r.top = 0; | |
| 375 | + sel->r.left = 0; | |
| 376 | + sel->r.width = GC0310_NATIVE_WIDTH; | |
| 377 | + sel->r.height = GC0310_NATIVE_HEIGHT; | |
| 378 | + break; | |
| 379 | + default: | |
| 380 | + return -EINVAL; | |
| 381 | + } | |
| 382 | + | |
| 383 | + return 0; | |
| 384 | +} | |
| 375 | 385 | |
| 376 | − fmt = gc0310_get_pad_format(dev, sd_state, format->pad, format->which); | |
| 377 | − gc0310_fill_format(fmt); | |
| 386 | +static int gc0310_power_off(struct device *dev) | |
| 387 | +{ | |
| 388 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 389 | + struct gc0310_device *sensor = to_gc0310_sensor(sd); | |
| 378 | 390 | |
| 379 | − format->format = *fmt; | |
| 391 | + gpiod_set_value_cansleep(sensor->powerdown, 1); | |
| 392 | + gpiod_set_value_cansleep(sensor->reset, 1); | |
| 380 | 393 | return 0; |
| 381 | 394 | } |
| 382 | 395 | |
| 383 | −static int gc0310_get_fmt(struct v4l2_subdev *sd, | |
| 384 | − struct v4l2_subdev_state *sd_state, | |
| 385 | − struct v4l2_subdev_format *format) | |
| 396 | +static int gc0310_power_on(struct device *dev) | |
| 386 | 397 | { |
| 387 | − struct gc0310_device *dev = to_gc0310_sensor(sd); | |
| 388 | − struct v4l2_mbus_framefmt *fmt; | |
| 398 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 399 | + struct gc0310_device *sensor = to_gc0310_sensor(sd); | |
| 400 | + | |
| 401 | + fsleep(10 * USEC_PER_MSEC); | |
| 402 | + gpiod_set_value_cansleep(sensor->reset, 0); | |
| 403 | + fsleep(10 * USEC_PER_MSEC); | |
| 404 | + gpiod_set_value_cansleep(sensor->powerdown, 0); | |
| 405 | + fsleep(10 * USEC_PER_MSEC); | |
| 389 | 406 | |
| 390 | − fmt = gc0310_get_pad_format(dev, sd_state, format->pad, format->which); | |
| 391 | − format->format = *fmt; | |
| 392 | 407 | return 0; |
| 393 | 408 | } |
| 394 | 409 | |
| 395 | −static int gc0310_detect(struct i2c_client *client) | |
| 410 | +static int gc0310_detect(struct gc0310_device *sensor) | |
| 396 | 411 | { |
| 397 | − struct i2c_adapter *adapter = client->adapter; | |
| 412 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); | |
| 413 | + u64 val; | |
| 398 | 414 | int ret; |
| 399 | 415 | |
| 400 | − if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | |
| 416 | + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) | |
| 401 | 417 | return -ENODEV; |
| 402 | 418 | |
| 403 | − ret = pm_runtime_get_sync(&client->dev); | |
| 404 | − if (ret >= 0) | |
| 405 | − ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H); | |
| 406 | − pm_runtime_put(&client->dev); | |
| 419 | + ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL); | |
| 407 | 420 | if (ret < 0) { |
| 408 | 421 | dev_err(&client->dev, "read sensor_id failed: %d\n", ret); |
| 409 | 422 | return -ENODEV; |
| 410 | 423 | } |
| 411 | 424 | |
| 412 | − dev_dbg(&client->dev, "sensor ID = 0x%x\n", ret); | |
| 425 | + dev_dbg(&client->dev, "sensor ID = 0x%llx\n", val); | |
| 413 | 426 | |
| 414 | − if (ret != GC0310_ID) { | |
| 415 | − dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", | |
| 416 | − ret, GC0310_ID); | |
| 427 | + if (val != GC0310_ID) { | |
| 428 | + dev_err(&client->dev, "sensor ID error, read id = 0x%llx, target id = 0x%x\n", | |
| 429 | + val, GC0310_ID); | |
| 417 | 430 | return -ENODEV; |
| 418 | 431 | } |
| 419 | 432 | |
| @@ -422,85 +435,67 @@ static int gc0310_detect(struct i2c_client *client) · 2 unmodified lines | ||
| 422 | 435 | return 0; |
| 423 | 436 | } |
| 424 | 437 | |
| 425 | −static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) | |
| 438 | +static int gc0310_enable_streams(struct v4l2_subdev *sd, | |
| 439 | + struct v4l2_subdev_state *state, | |
| 440 | + u32 pad, u64 streams_mask) | |
| 426 | 441 | { |
| 427 | − struct gc0310_device *dev = to_gc0310_sensor(sd); | |
| 442 | + struct gc0310_device *sensor = to_gc0310_sensor(sd); | |
| 428 | 443 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 429 | − int ret = 0; | |
| 430 | − | |
| 431 | − dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable); | |
| 432 | − mutex_lock(&dev->input_lock); | |
| 433 | − | |
| 434 | − if (enable) { | |
| 435 | − ret = pm_runtime_get_sync(&client->dev); | |
| 436 | − if (ret < 0) | |
| 437 | − goto error_power_down; | |
| 438 | − | |
| 439 | − msleep(100); | |
| 440 | − | |
| 441 | − ret = gc0310_write_reg_array(client, gc0310_reset_register, | |
| 442 | − ARRAY_SIZE(gc0310_reset_register)); | |
| 443 | − if (ret) | |
| 444 | − goto error_power_down; | |
| 445 | − | |
| 446 | − ret = gc0310_write_reg_array(client, gc0310_VGA_30fps, | |
| 447 | − ARRAY_SIZE(gc0310_VGA_30fps)); | |
| 448 | − if (ret) | |
| 449 | − goto error_power_down; | |
| 450 | − | |
| 451 | − /* restore value of all ctrls */ | |
| 452 | − ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler); | |
| 453 | − if (ret) | |
| 454 | − goto error_power_down; | |
| 455 | − | |
| 456 | − /* enable per frame MIPI and sensor ctrl reset */ | |
| 457 | − ret = i2c_smbus_write_byte_data(client, 0xFE, 0x30); | |
| 458 | − if (ret) | |
| 459 | − goto error_power_down; | |
| 460 | − } | |
| 444 | + int ret; | |
| 461 | 445 | |
| 462 | − ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); | |
| 446 | + ret = pm_runtime_resume_and_get(&client->dev); | |
| 463 | 447 | if (ret) |
| 464 | − goto error_power_down; | |
| 448 | + return ret; | |
| 465 | 449 | |
| 466 | − ret = i2c_smbus_write_byte_data(client, GC0310_SW_STREAM, | |
| 467 | − enable ? GC0310_START_STREAMING : GC0310_STOP_STREAMING); | |
| 450 | + ret = regmap_multi_reg_write(sensor->regmap, | |
| 451 | + gc0310_reset_register, | |
| 452 | + ARRAY_SIZE(gc0310_reset_register)); | |
| 468 | 453 | if (ret) |
| 469 | 454 | goto error_power_down; |
| 470 | 455 | |
| 471 | − ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); | |
| 456 | + ret = regmap_multi_reg_write(sensor->regmap, | |
| 457 | + gc0310_VGA_30fps, | |
| 458 | + ARRAY_SIZE(gc0310_VGA_30fps)); | |
| 472 | 459 | if (ret) |
| 473 | 460 | goto error_power_down; |
| 474 | 461 | |
| 475 | − if (!enable) | |
| 476 | − pm_runtime_put(&client->dev); | |
| 462 | + /* restore value of all ctrls */ | |
| 463 | + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); | |
| 477 | 464 | |
| 478 | − dev->is_streaming = enable; | |
| 479 | − mutex_unlock(&dev->input_lock); | |
| 480 | − return 0; | |
| 465 | + /* enable per frame MIPI and sensor ctrl reset */ | |
| 466 | + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, 0x30, &ret); | |
| 467 | + | |
| 468 | + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, | |
| 469 | + GC0310_REGISTER_PAGE_3, &ret); | |
| 470 | + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, | |
| 471 | + GC0310_START_STREAMING, &ret); | |
| 472 | + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, | |
| 473 | + GC0310_REGISTER_PAGE_0, &ret); | |
| 481 | 474 | |
| 482 | 475 | error_power_down: |
| 483 | − pm_runtime_put(&client->dev); | |
| 484 | − dev->is_streaming = false; | |
| 485 | − mutex_unlock(&dev->input_lock); | |
| 476 | + if (ret) | |
| 477 | + pm_runtime_put(&client->dev); | |
| 478 | + | |
| 486 | 479 | return ret; |
| 487 | 480 | } |
| 488 | 481 | |
| 489 | −static int gc0310_get_frame_interval(struct v4l2_subdev *sd, | |
| 490 | − struct v4l2_subdev_state *sd_state, | |
| 491 | − struct v4l2_subdev_frame_interval *interval) | |
| 482 | +static int gc0310_disable_streams(struct v4l2_subdev *sd, | |
| 483 | + struct v4l2_subdev_state *state, | |
| 484 | + u32 pad, u64 streams_mask) | |
| 492 | 485 | { |
| 493 | − /* | |
| 494 | − * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 | |
| 495 | − * subdev active state API. | |
| 496 | − */ | |
| 497 | − if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 498 | − return -EINVAL; | |
| 486 | + struct gc0310_device *sensor = to_gc0310_sensor(sd); | |
| 487 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 488 | + int ret = 0; | |
| 499 | 489 | |
| 500 | − interval->interval.numerator = 1; | |
| 501 | − interval->interval.denominator = GC0310_FPS; | |
| 490 | + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, | |
| 491 | + GC0310_REGISTER_PAGE_3, &ret); | |
| 492 | + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, | |
| 493 | + GC0310_STOP_STREAMING, &ret); | |
| 494 | + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, | |
| 495 | + GC0310_REGISTER_PAGE_0, &ret); | |
| 502 | 496 | |
| 503 | − return 0; | |
| 497 | + pm_runtime_put(&client->dev); | |
| 498 | + return ret; | |
| 504 | 499 | } |
| 505 | 500 | |
| 506 | 501 | static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, |
| @@ -531,164 +526,239 @@ static int gc0310_enum_frame_size(struct v4l2_subdev *sd, · 24 unmodified lines | ||
| 531 | 526 | return 0; |
| 532 | 527 | } |
| 533 | 528 | |
| 534 | −static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) | |
| 535 | −{ | |
| 536 | − *frames = GC0310_SKIP_FRAMES; | |
| 537 | − return 0; | |
| 538 | −} | |
| 539 | − | |
| 540 | −static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { | |
| 541 | − .g_skip_frames = gc0310_g_skip_frames, | |
| 542 | −}; | |
| 543 | − | |
| 544 | 529 | static const struct v4l2_subdev_video_ops gc0310_video_ops = { |
| 545 | − .s_stream = gc0310_s_stream, | |
| 530 | + .s_stream = v4l2_subdev_s_stream_helper, | |
| 546 | 531 | }; |
| 547 | 532 | |
| 548 | 533 | static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { |
| 549 | 534 | .enum_mbus_code = gc0310_enum_mbus_code, |
| 550 | 535 | .enum_frame_size = gc0310_enum_frame_size, |
| 551 | − .get_fmt = gc0310_get_fmt, | |
| 552 | − .set_fmt = gc0310_set_fmt, | |
| 553 | − .get_frame_interval = gc0310_get_frame_interval, | |
| 536 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 537 | + .set_fmt = v4l2_subdev_get_fmt, /* Only 1 fixed mode supported */ | |
| 538 | + .get_selection = gc0310_get_selection, | |
| 539 | + .set_selection = gc0310_get_selection, | |
| 540 | + .enable_streams = gc0310_enable_streams, | |
| 541 | + .disable_streams = gc0310_disable_streams, | |
| 554 | 542 | }; |
| 555 | 543 | |
| 556 | 544 | static const struct v4l2_subdev_ops gc0310_ops = { |
| 557 | 545 | .video = &gc0310_video_ops, |
| 558 | 546 | .pad = &gc0310_pad_ops, |
| 559 | − .sensor = &gc0310_sensor_ops, | |
| 560 | 547 | }; |
| 561 | 548 | |
| 562 | −static int gc0310_init_controls(struct gc0310_device *dev) | |
| 549 | +static int gc0310_init_state(struct v4l2_subdev *sd, | |
| 550 | + struct v4l2_subdev_state *sd_state) | |
| 563 | 551 | { |
| 564 | − struct v4l2_ctrl_handler *hdl = &dev->ctrls.handler; | |
| 552 | + gc0310_fill_format(v4l2_subdev_state_get_format(sd_state, 0)); | |
| 553 | + return 0; | |
| 554 | +} | |
| 565 | 555 | |
| 566 | − v4l2_ctrl_handler_init(hdl, 2); | |
| 556 | +static const struct v4l2_subdev_internal_ops gc0310_internal_ops = { | |
| 557 | + .init_state = gc0310_init_state, | |
| 558 | +}; | |
| 559 | + | |
| 560 | +static int gc0310_init_controls(struct gc0310_device *sensor) | |
| 561 | +{ | |
| 562 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); | |
| 563 | + struct v4l2_ctrl_handler *hdl = &sensor->ctrls.handler; | |
| 564 | + struct v4l2_fwnode_device_properties props; | |
| 565 | + int exp_max, ret; | |
| 566 | + | |
| 567 | + v4l2_ctrl_handler_init(hdl, 8); | |
| 567 | 568 | |
| 568 | 569 | /* Use the same lock for controls as for everything else */ |
| 569 | − hdl->lock = &dev->input_lock; | |
| 570 | − dev->sd.ctrl_handler = hdl; | |
| 570 | + sensor->sd.ctrl_handler = hdl; | |
| 571 | 571 | |
| 572 | − dev->ctrls.exposure = | |
| 573 | − v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, 4095, 1, 1023); | |
| 572 | + exp_max = GC0310_NATIVE_HEIGHT + GC0310_V_BLANK_DEFAULT; | |
| 573 | + sensor->ctrls.exposure = | |
| 574 | + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, | |
| 575 | + exp_max, 1, exp_max); | |
| 574 | 576 | |
| 575 | 577 | /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ |
| 576 | − dev->ctrls.gain = | |
| 577 | − v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_GAIN, 0, 95, 1, 31); | |
| 578 | + sensor->ctrls.gain = | |
| 579 | + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 0, 95, 1, 31); | |
| 580 | + | |
| 581 | + sensor->ctrls.link_freq = | |
| 582 | + v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ, | |
| 583 | + 0, 0, link_freq_menu_items); | |
| 584 | + sensor->ctrls.pixel_rate = | |
| 585 | + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE, 0, | |
| 586 | + GC0310_PIXELRATE, 1, GC0310_PIXELRATE); | |
| 587 | + | |
| 588 | + sensor->ctrls.vblank = | |
| 589 | + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_VBLANK, | |
| 590 | + GC0310_V_BLANK_MIN, | |
| 591 | + GC0310_V_BLANK_MAX, 1, | |
| 592 | + GC0310_V_BLANK_DEFAULT); | |
| 593 | + | |
| 594 | + sensor->ctrls.hblank = | |
| 595 | + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK, | |
| 596 | + GC0310_H_BLANK_DEFAULT, | |
| 597 | + GC0310_H_BLANK_DEFAULT, 1, | |
| 598 | + GC0310_H_BLANK_DEFAULT); | |
| 599 | + | |
| 600 | + ret = v4l2_fwnode_device_parse(&client->dev, &props); | |
| 601 | + if (ret) | |
| 602 | + return ret; | |
| 603 | + | |
| 604 | + v4l2_ctrl_new_fwnode_properties(hdl, &ctrl_ops, &props); | |
| 578 | 605 | |
| 579 | − return hdl->error; | |
| 606 | + if (hdl->error) | |
| 607 | + return hdl->error; | |
| 608 | + | |
| 609 | + sensor->ctrls.pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 610 | + sensor->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 611 | + sensor->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 612 | + return 0; | |
| 580 | 613 | } |
| 581 | 614 | |
| 582 | 615 | static void gc0310_remove(struct i2c_client *client) |
| 583 | 616 | { |
| 584 | 617 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 585 | − struct gc0310_device *dev = to_gc0310_sensor(sd); | |
| 586 | − | |
| 587 | − dev_dbg(&client->dev, "gc0310_remove...\n"); | |
| 618 | + struct gc0310_device *sensor = to_gc0310_sensor(sd); | |
| 588 | 619 | |
| 589 | 620 | v4l2_async_unregister_subdev(sd); |
| 590 | − media_entity_cleanup(&dev->sd.entity); | |
| 591 | − v4l2_ctrl_handler_free(&dev->ctrls.handler); | |
| 592 | − mutex_destroy(&dev->input_lock); | |
| 621 | + v4l2_subdev_cleanup(sd); | |
| 622 | + media_entity_cleanup(&sensor->sd.entity); | |
| 623 | + v4l2_ctrl_handler_free(&sensor->ctrls.handler); | |
| 593 | 624 | pm_runtime_disable(&client->dev); |
| 625 | + if (!pm_runtime_status_suspended(&client->dev)) { | |
| 626 | + gc0310_power_off(&client->dev); | |
| 627 | + pm_runtime_set_suspended(&client->dev); | |
| 628 | + } | |
| 594 | 629 | } |
| 595 | 630 | |
| 596 | −static int gc0310_probe(struct i2c_client *client) | |
| 631 | +static int gc0310_check_hwcfg(struct device *dev) | |
| 597 | 632 | { |
| 633 | + struct v4l2_fwnode_endpoint bus_cfg = { | |
| 634 | + .bus_type = V4L2_MBUS_CSI2_DPHY, | |
| 635 | + }; | |
| 598 | 636 | struct fwnode_handle *ep_fwnode; |
| 599 | − struct gc0310_device *dev; | |
| 637 | + unsigned long link_freq_bitmap; | |
| 638 | + u32 mclk; | |
| 600 | 639 | int ret; |
| 601 | 640 | |
| 602 | 641 | /* |
| 603 | 642 | * Sometimes the fwnode graph is initialized by the bridge driver. |
| 604 | 643 | * Bridge drivers doing this may also add GPIO mappings, wait for this. |
| 605 | 644 | */ |
| 606 | − ep_fwnode = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); | |
| 645 | + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); | |
| 607 | 646 | if (!ep_fwnode) |
| 608 | − return dev_err_probe(&client->dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); | |
| 647 | + return dev_err_probe(dev, -EPROBE_DEFER, | |
| 648 | + "waiting for fwnode graph endpoint\n"); | |
| 649 | + | |
| 650 | + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", | |
| 651 | + &mclk); | |
| 652 | + if (ret) { | |
| 653 | + fwnode_handle_put(ep_fwnode); | |
| 654 | + return dev_err_probe(dev, ret, | |
| 655 | + "reading clock-frequency property\n"); | |
| 656 | + } | |
| 657 | + | |
| 658 | + if (mclk != GC0310_MCLK_FREQ) { | |
| 659 | + fwnode_handle_put(ep_fwnode); | |
| 660 | + return dev_err_probe(dev, -EINVAL, | |
| 661 | + "external clock %u is not supported\n", | |
| 662 | + mclk); | |
| 663 | + } | |
| 609 | 664 | |
| 665 | + ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); | |
| 610 | 666 | fwnode_handle_put(ep_fwnode); |
| 667 | + if (ret) | |
| 668 | + return dev_err_probe(dev, ret, "parsing endpoint failed\n"); | |
| 669 | + | |
| 670 | + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, | |
| 671 | + bus_cfg.nr_of_link_frequencies, | |
| 672 | + link_freq_menu_items, | |
| 673 | + ARRAY_SIZE(link_freq_menu_items), | |
| 674 | + &link_freq_bitmap); | |
| 675 | + | |
| 676 | + if (ret == 0 && bus_cfg.bus.mipi_csi2.num_data_lanes != 1) | |
| 677 | + ret = dev_err_probe(dev, -EINVAL, | |
| 678 | + "number of CSI2 data lanes %u is not supported\n", | |
| 679 | + bus_cfg.bus.mipi_csi2.num_data_lanes); | |
| 680 | + | |
| 681 | + v4l2_fwnode_endpoint_free(&bus_cfg); | |
| 682 | + return ret; | |
| 683 | +} | |
| 684 | + | |
| 685 | +static int gc0310_probe(struct i2c_client *client) | |
| 686 | +{ | |
| 687 | + struct gc0310_device *sensor; | |
| 688 | + int ret; | |
| 611 | 689 | |
| 612 | − dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); | |
| 613 | − if (!dev) | |
| 690 | + ret = gc0310_check_hwcfg(&client->dev); | |
| 691 | + if (ret) | |
| 692 | + return ret; | |
| 693 | + | |
| 694 | + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); | |
| 695 | + if (!sensor) | |
| 614 | 696 | return -ENOMEM; |
| 615 | 697 | |
| 616 | − dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); | |
| 617 | − if (IS_ERR(dev->reset)) { | |
| 618 | − return dev_err_probe(&client->dev, PTR_ERR(dev->reset), | |
| 698 | + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); | |
| 699 | + if (IS_ERR(sensor->reset)) { | |
| 700 | + return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), | |
| 619 | 701 | "getting reset GPIO\n"); |
| 620 | 702 | } |
| 621 | 703 | |
| 622 | − dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); | |
| 623 | − if (IS_ERR(dev->powerdown)) { | |
| 624 | − return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown), | |
| 704 | + sensor->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); | |
| 705 | + if (IS_ERR(sensor->powerdown)) { | |
| 706 | + return dev_err_probe(&client->dev, PTR_ERR(sensor->powerdown), | |
| 625 | 707 | "getting powerdown GPIO\n"); |
| 626 | 708 | } |
| 627 | 709 | |
| 628 | − mutex_init(&dev->input_lock); | |
| 629 | − v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops); | |
| 630 | − gc0310_fill_format(&dev->mode.fmt); | |
| 710 | + v4l2_i2c_subdev_init(&sensor->sd, client, &gc0310_ops); | |
| 631 | 711 | |
| 632 | − pm_runtime_set_suspended(&client->dev); | |
| 633 | − pm_runtime_enable(&client->dev); | |
| 634 | − pm_runtime_set_autosuspend_delay(&client->dev, 1000); | |
| 635 | − pm_runtime_use_autosuspend(&client->dev); | |
| 712 | + sensor->regmap = devm_cci_regmap_init_i2c(client, 8); | |
| 713 | + if (IS_ERR(sensor->regmap)) | |
| 714 | + return PTR_ERR(sensor->regmap); | |
| 636 | 715 | |
| 637 | − ret = gc0310_detect(client); | |
| 638 | − if (ret) { | |
| 639 | − gc0310_remove(client); | |
| 640 | − return ret; | |
| 641 | − } | |
| 716 | + gc0310_power_on(&client->dev); | |
| 642 | 717 | |
| 643 | − dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 644 | − dev->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 645 | − dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 646 | − | |
| 647 | − ret = gc0310_init_controls(dev); | |
| 648 | − if (ret) { | |
| 649 | − gc0310_remove(client); | |
| 650 | − return ret; | |
| 651 | − } | |
| 718 | + pm_runtime_set_active(&client->dev); | |
| 719 | + pm_runtime_get_noresume(&client->dev); | |
| 720 | + pm_runtime_enable(&client->dev); | |
| 652 | 721 | |
| 653 | − ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); | |
| 654 | − if (ret) { | |
| 655 | − gc0310_remove(client); | |
| 656 | − return ret; | |
| 657 | − } | |
| 722 | + ret = gc0310_detect(sensor); | |
| 723 | + if (ret) | |
| 724 | + goto err_power_down; | |
| 658 | 725 | |
| 659 | − ret = v4l2_async_register_subdev_sensor(&dev->sd); | |
| 660 | − if (ret) { | |
| 661 | − gc0310_remove(client); | |
| 662 | − return ret; | |
| 663 | − } | |
| 726 | + sensor->sd.internal_ops = &gc0310_internal_ops; | |
| 727 | + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 728 | + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 729 | + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 664 | 730 | |
| 665 | − return 0; | |
| 666 | −} | |
| 731 | + ret = gc0310_init_controls(sensor); | |
| 732 | + if (ret) | |
| 733 | + goto err_power_down; | |
| 667 | 734 | |
| 668 | −static int gc0310_suspend(struct device *dev) | |
| 669 | −{ | |
| 670 | − struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 671 | − struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); | |
| 735 | + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); | |
| 736 | + if (ret) | |
| 737 | + goto err_power_down; | |
| 672 | 738 | |
| 673 | − gpiod_set_value_cansleep(gc0310_dev->powerdown, 1); | |
| 674 | − gpiod_set_value_cansleep(gc0310_dev->reset, 1); | |
| 675 | − return 0; | |
| 676 | −} | |
| 739 | + sensor->sd.state_lock = sensor->ctrls.handler.lock; | |
| 740 | + ret = v4l2_subdev_init_finalize(&sensor->sd); | |
| 741 | + if (ret) | |
| 742 | + goto err_power_down; | |
| 677 | 743 | |
| 678 | −static int gc0310_resume(struct device *dev) | |
| 679 | −{ | |
| 680 | − struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 681 | − struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); | |
| 744 | + ret = v4l2_async_register_subdev_sensor(&sensor->sd); | |
| 745 | + if (ret) | |
| 746 | + goto err_power_down; | |
| 682 | 747 | |
| 683 | − usleep_range(10000, 15000); | |
| 684 | − gpiod_set_value_cansleep(gc0310_dev->reset, 0); | |
| 685 | − usleep_range(10000, 15000); | |
| 686 | − gpiod_set_value_cansleep(gc0310_dev->powerdown, 0); | |
| 748 | + pm_runtime_set_autosuspend_delay(&client->dev, 1000); | |
| 749 | + pm_runtime_use_autosuspend(&client->dev); | |
| 750 | + pm_runtime_put_autosuspend(&client->dev); | |
| 687 | 751 | |
| 688 | 752 | return 0; |
| 753 | + | |
| 754 | +err_power_down: | |
| 755 | + pm_runtime_put_noidle(&client->dev); | |
| 756 | + gc0310_remove(client); | |
| 757 | + return ret; | |
| 689 | 758 | } |
| 690 | 759 | |
| 691 | −static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, gc0310_suspend, gc0310_resume, NULL); | |
| 760 | +static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, | |
| 761 | + gc0310_power_off, gc0310_power_on, NULL); | |
| 692 | 762 | |
| 693 | 763 | static const struct acpi_device_id gc0310_acpi_match[] = { |
| 694 | 764 | {"INT0310"}, |
| @@ -708,5 +778,6 @@ static struct i2c_driver gc0310_driver = { · 13 unmodified lines | ||
| 708 | 778 | module_i2c_driver(gc0310_driver); |
| 709 | 779 | |
| 710 | 780 | MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); |
| 781 | +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); | |
| 711 | 782 | MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); |
| 712 | 783 | MODULE_LICENSE("GPL"); |
| @@ -779,8 +779,6 @@ static void gc2235_remove(struct i2c_client *client) · 778 unmodified lines | ||
| 779 | 779 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 780 | 780 | struct gc2235_device *dev = to_gc2235_sensor(sd); |
| 781 | 781 | |
| 782 | − dev_dbg(&client->dev, "gc2235_remove...\n"); | |
| 783 | − | |
| 784 | 782 | dev->platform_data->csi_cfg(sd, 0); |
| 785 | 783 | |
| 786 | 784 | v4l2_device_unregister_subdev(sd); |
| @@ -179,21 +179,21 @@ struct gc2235_write_ctrl { · 178 unmodified lines | ||
| 179 | 179 | struct gc2235_write_buffer buffer; |
| 180 | 180 | }; |
| 181 | 181 | |
| 182 | −static struct gc2235_reg const gc2235_stream_on[] = { | |
| 182 | +static const struct gc2235_reg gc2235_stream_on[] = { | |
| 183 | 183 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ |
| 184 | 184 | { GC2235_8BIT, 0x10, 0x91}, /* start mipi */ |
| 185 | 185 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ |
| 186 | 186 | { GC2235_TOK_TERM, 0, 0 } |
| 187 | 187 | }; |
| 188 | 188 | |
| 189 | −static struct gc2235_reg const gc2235_stream_off[] = { | |
| 189 | +static const struct gc2235_reg gc2235_stream_off[] = { | |
| 190 | 190 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ |
| 191 | 191 | { GC2235_8BIT, 0x10, 0x01}, /* stop mipi */ |
| 192 | 192 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ |
| 193 | 193 | { GC2235_TOK_TERM, 0, 0 } |
| 194 | 194 | }; |
| 195 | 195 | |
| 196 | −static struct gc2235_reg const gc2235_init_settings[] = { | |
| 196 | +static const struct gc2235_reg gc2235_init_settings[] = { | |
| 197 | 197 | /* System */ |
| 198 | 198 | { GC2235_8BIT, 0xfe, 0x80 }, |
| 199 | 199 | { GC2235_8BIT, 0xfe, 0x80 }, |
| @@ -268,7 +268,7 @@ static struct gc2235_reg const gc2235_init_settings[] = { · 68 unmodified lines | ||
| 268 | 268 | * Register settings for various resolution |
| 269 | 269 | */ |
| 270 | 270 | #if ENABLE_NON_PREVIEW |
| 271 | −static struct gc2235_reg const gc2235_1296_736_30fps[] = { | |
| 271 | +static const struct gc2235_reg gc2235_1296_736_30fps[] = { | |
| 272 | 272 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 273 | 273 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 274 | 274 | |
| @@ -321,7 +321,7 @@ static struct gc2235_reg const gc2235_1296_736_30fps[] = { · 46 unmodified lines | ||
| 321 | 321 | { GC2235_TOK_TERM, 0, 0 } |
| 322 | 322 | }; |
| 323 | 323 | |
| 324 | −static struct gc2235_reg const gc2235_960_640_30fps[] = { | |
| 324 | +static const struct gc2235_reg gc2235_960_640_30fps[] = { | |
| 325 | 325 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 326 | 326 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 327 | 327 | |
| @@ -373,7 +373,7 @@ static struct gc2235_reg const gc2235_960_640_30fps[] = { · 45 unmodified lines | ||
| 373 | 373 | }; |
| 374 | 374 | #endif |
| 375 | 375 | |
| 376 | −static struct gc2235_reg const gc2235_1600_900_30fps[] = { | |
| 376 | +static const struct gc2235_reg gc2235_1600_900_30fps[] = { | |
| 377 | 377 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 378 | 378 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 379 | 379 | |
| @@ -418,7 +418,7 @@ static struct gc2235_reg const gc2235_1600_900_30fps[] = { · 38 unmodified lines | ||
| 418 | 418 | { GC2235_TOK_TERM, 0, 0 } |
| 419 | 419 | }; |
| 420 | 420 | |
| 421 | −static struct gc2235_reg const gc2235_1616_1082_30fps[] = { | |
| 421 | +static const struct gc2235_reg gc2235_1616_1082_30fps[] = { | |
| 422 | 422 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 423 | 423 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 424 | 424 | |
| @@ -463,7 +463,7 @@ static struct gc2235_reg const gc2235_1616_1082_30fps[] = { · 38 unmodified lines | ||
| 463 | 463 | { GC2235_TOK_TERM, 0, 0 } |
| 464 | 464 | }; |
| 465 | 465 | |
| 466 | −static struct gc2235_reg const gc2235_1616_1216_30fps[] = { | |
| 466 | +static const struct gc2235_reg gc2235_1616_1216_30fps[] = { | |
| 467 | 467 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 468 | 468 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 469 | 469 | |
| @@ -236,7 +236,7 @@ struct ov2722_write_ctrl { · 235 unmodified lines | ||
| 236 | 236 | * Register settings for various resolution |
| 237 | 237 | */ |
| 238 | 238 | #if 0 |
| 239 | −static struct ov2722_reg const ov2722_QVGA_30fps[] = { | |
| 239 | +static const struct ov2722_reg ov2722_QVGA_30fps[] = { | |
| 240 | 240 | {OV2722_8BIT, 0x3718, 0x10}, |
| 241 | 241 | {OV2722_8BIT, 0x3702, 0x0c}, |
| 242 | 242 | {OV2722_8BIT, 0x373a, 0x1c}, |
| @@ -346,7 +346,7 @@ static struct ov2722_reg const ov2722_QVGA_30fps[] = { · 103 unmodified lines | ||
| 346 | 346 | |
| 347 | 347 | }; |
| 348 | 348 | |
| 349 | −static struct ov2722_reg const ov2722_480P_30fps[] = { | |
| 349 | +static const struct ov2722_reg ov2722_480P_30fps[] = { | |
| 350 | 350 | {OV2722_8BIT, 0x3718, 0x10}, |
| 351 | 351 | {OV2722_8BIT, 0x3702, 0x18}, |
| 352 | 352 | {OV2722_8BIT, 0x373a, 0x3c}, |
| @@ -455,7 +455,7 @@ static struct ov2722_reg const ov2722_480P_30fps[] = { · 102 unmodified lines | ||
| 455 | 455 | {OV2722_TOK_TERM, 0, 0}, |
| 456 | 456 | }; |
| 457 | 457 | |
| 458 | −static struct ov2722_reg const ov2722_VGA_30fps[] = { | |
| 458 | +static const struct ov2722_reg ov2722_VGA_30fps[] = { | |
| 459 | 459 | {OV2722_8BIT, 0x3718, 0x10}, |
| 460 | 460 | {OV2722_8BIT, 0x3702, 0x18}, |
| 461 | 461 | {OV2722_8BIT, 0x373a, 0x3c}, |
| @@ -565,7 +565,7 @@ static struct ov2722_reg const ov2722_VGA_30fps[] = { · 103 unmodified lines | ||
| 565 | 565 | }; |
| 566 | 566 | #endif |
| 567 | 567 | |
| 568 | −static struct ov2722_reg const ov2722_1632_1092_30fps[] = { | |
| 568 | +static const struct ov2722_reg ov2722_1632_1092_30fps[] = { | |
| 569 | 569 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for |
| 570 | 570 | a whole frame complete.(vblank) */ |
| 571 | 571 | {OV2722_8BIT, 0x3718, 0x10}, |
| @@ -667,7 +667,7 @@ static struct ov2722_reg const ov2722_1632_1092_30fps[] = { · 95 unmodified lines | ||
| 667 | 667 | {OV2722_TOK_TERM, 0, 0} |
| 668 | 668 | }; |
| 669 | 669 | |
| 670 | −static struct ov2722_reg const ov2722_1452_1092_30fps[] = { | |
| 670 | +static const struct ov2722_reg ov2722_1452_1092_30fps[] = { | |
| 671 | 671 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for |
| 672 | 672 | a whole frame complete.(vblank) */ |
| 673 | 673 | {OV2722_8BIT, 0x3718, 0x10}, |
| @@ -769,7 +769,7 @@ static struct ov2722_reg const ov2722_1452_1092_30fps[] = { · 95 unmodified lines | ||
| 769 | 769 | }; |
| 770 | 770 | |
| 771 | 771 | #if 0 |
| 772 | −static struct ov2722_reg const ov2722_1M3_30fps[] = { | |
| 772 | +static const struct ov2722_reg ov2722_1M3_30fps[] = { | |
| 773 | 773 | {OV2722_8BIT, 0x3718, 0x10}, |
| 774 | 774 | {OV2722_8BIT, 0x3702, 0x24}, |
| 775 | 775 | {OV2722_8BIT, 0x373a, 0x60}, |
| @@ -877,7 +877,7 @@ static struct ov2722_reg const ov2722_1M3_30fps[] = { · 101 unmodified lines | ||
| 877 | 877 | }; |
| 878 | 878 | #endif |
| 879 | 879 | |
| 880 | −static struct ov2722_reg const ov2722_1080p_30fps[] = { | |
| 880 | +static const struct ov2722_reg ov2722_1080p_30fps[] = { | |
| 881 | 881 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole |
| 882 | 882 | frame complete.(vblank) */ |
| 883 | 883 | {OV2722_8BIT, 0x3718, 0x10}, |
| @@ -983,7 +983,7 @@ static struct ov2722_reg const ov2722_1080p_30fps[] = { · 99 unmodified lines | ||
| 983 | 983 | }; |
| 984 | 984 | |
| 985 | 985 | #if 0 /* Currently unused */ |
| 986 | −static struct ov2722_reg const ov2722_720p_30fps[] = { | |
| 986 | +static const struct ov2722_reg ov2722_720p_30fps[] = { | |
| 987 | 987 | {OV2722_8BIT, 0x3021, 0x03}, |
| 988 | 988 | {OV2722_8BIT, 0x3718, 0x10}, |
| 989 | 989 | {OV2722_8BIT, 0x3702, 0x24}, |
| @@ -387,7 +387,7 @@ static int __destroy_stream(struct atomisp_sub_device *asd, · 386 unmodified lines | ||
| 387 | 387 | } |
| 388 | 388 | |
| 389 | 389 | if (stream_env->stream_state == CSS_STREAM_STARTED) { |
| 390 | − timeout = jiffies + msecs_to_jiffies(40); | |
| 390 | + timeout = jiffies + msecs_to_jiffies(200); | |
| 391 | 391 | while (1) { |
| 392 | 392 | if (ia_css_stream_has_stopped(stream_env->stream)) |
| 393 | 393 | break; |
| @@ -19,28 +19,11 @@ · 18 unmodified lines | ||
| 19 | 19 | #define CSI2_PAD_SOURCE 1 |
| 20 | 20 | #define CSI2_PADS_NUM 2 |
| 21 | 21 | |
| 22 | −#define CSI2_MAX_ACPI_GPIOS 2u | |
| 23 | − | |
| 24 | −struct acpi_device; | |
| 25 | 22 | struct v4l2_device; |
| 26 | 23 | |
| 27 | 24 | struct atomisp_device; |
| 28 | 25 | struct atomisp_sub_device; |
| 29 | 26 | |
| 30 | −struct atomisp_csi2_acpi_gpio_map { | |
| 31 | − struct acpi_gpio_params params[CSI2_MAX_ACPI_GPIOS]; | |
| 32 | − struct acpi_gpio_mapping mapping[CSI2_MAX_ACPI_GPIOS + 1]; | |
| 33 | −}; | |
| 34 | − | |
| 35 | −struct atomisp_csi2_acpi_gpio_parsing_data { | |
| 36 | − struct acpi_device *adev; | |
| 37 | − struct atomisp_csi2_acpi_gpio_map *map; | |
| 38 | − u32 settings[CSI2_MAX_ACPI_GPIOS]; | |
| 39 | − unsigned int settings_count; | |
| 40 | − unsigned int res_count; | |
| 41 | − unsigned int map_count; | |
| 42 | −}; | |
| 43 | − | |
| 44 | 27 | struct atomisp_mipi_csi2_device { |
| 45 | 28 | struct v4l2_subdev subdev; |
| 46 | 29 | struct media_pad pads[CSI2_PADS_NUM]; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/clk.h> |
| 14 | 14 | #include <linux/device.h> |
| 15 | 15 | #include <linux/dmi.h> |
| 16 | +#include <linux/platform_data/x86/int3472.h> | |
| 16 | 17 | #include <linux/property.h> |
| 17 | 18 | |
| 18 | 19 | #include <media/ipu-bridge.h> |
| @@ -24,39 +25,6 @@ · 5 unmodified lines | ||
| 24 | 25 | |
| 25 | 26 | #define PMC_CLK_RATE_19_2MHZ 19200000 |
| 26 | 27 | |
| 27 | −/* | |
| 28 | − * 79234640-9e10-4fea-a5c1-b5aa8b19756f | |
| 29 | − * This _DSM GUID returns information about the GPIO lines mapped to a sensor. | |
| 30 | − * Function number 1 returns a count of the GPIO lines that are mapped. | |
| 31 | − * Subsequent functions return 32 bit ints encoding information about the GPIO. | |
| 32 | − */ | |
| 33 | −static const guid_t intel_sensor_gpio_info_guid = | |
| 34 | − GUID_INIT(0x79234640, 0x9e10, 0x4fea, | |
| 35 | − 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f); | |
| 36 | − | |
| 37 | −#define INTEL_GPIO_DSM_TYPE_SHIFT 0 | |
| 38 | −#define INTEL_GPIO_DSM_TYPE_MASK GENMASK(7, 0) | |
| 39 | −#define INTEL_GPIO_DSM_PIN_SHIFT 8 | |
| 40 | −#define INTEL_GPIO_DSM_PIN_MASK GENMASK(15, 8) | |
| 41 | −#define INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT 24 | |
| 42 | −#define INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK GENMASK(31, 24) | |
| 43 | − | |
| 44 | −#define INTEL_GPIO_DSM_TYPE(x) \ | |
| 45 | − (((x) & INTEL_GPIO_DSM_TYPE_MASK) >> INTEL_GPIO_DSM_TYPE_SHIFT) | |
| 46 | −#define INTEL_GPIO_DSM_PIN(x) \ | |
| 47 | − (((x) & INTEL_GPIO_DSM_PIN_MASK) >> INTEL_GPIO_DSM_PIN_SHIFT) | |
| 48 | −#define INTEL_GPIO_DSM_SENSOR_ON_VAL(x) \ | |
| 49 | − (((x) & INTEL_GPIO_DSM_SENSOR_ON_VAL_MASK) >> INTEL_GPIO_DSM_SENSOR_ON_VAL_SHIFT) | |
| 50 | − | |
| 51 | −/* | |
| 52 | − * 822ace8f-2814-4174-a56b-5f029fe079ee | |
| 53 | − * This _DSM GUID returns a string from the sensor device, which acts as a | |
| 54 | − * module identifier. | |
| 55 | − */ | |
| 56 | −static const guid_t intel_sensor_module_guid = | |
| 57 | − GUID_INIT(0x822ace8f, 0x2814, 0x4174, | |
| 58 | − 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee); | |
| 59 | − | |
| 60 | 28 | /* |
| 61 | 29 | * dc2f6c4f-045b-4f1d-97b9-882a6860a4be |
| 62 | 30 | * This _DSM GUID returns a package with n*2 strings, with each set of 2 strings |
| @@ -323,196 +291,45 @@ static int atomisp_csi2_get_port(struct acpi_device *adev, int clock_num) · 260 unmodified lines | ||
| 323 | 291 | return gmin_cfg_get_int(adev, "CsiPort", port); |
| 324 | 292 | } |
| 325 | 293 | |
| 326 | −/* Note this always returns 1 to continue looping so that res_count is accurate */ | |
| 327 | −static int atomisp_csi2_handle_acpi_gpio_res(struct acpi_resource *ares, void *_data) | |
| 328 | −{ | |
| 329 | − struct atomisp_csi2_acpi_gpio_parsing_data *data = _data; | |
| 330 | − struct acpi_resource_gpio *agpio; | |
| 331 | − const char *name; | |
| 332 | − bool active_low; | |
| 333 | − unsigned int i; | |
| 334 | − u32 settings = 0; | |
| 335 | − u16 pin; | |
| 336 | − | |
| 337 | − if (!acpi_gpio_get_io_resource(ares, &agpio)) | |
| 338 | − return 1; /* Not a GPIO, continue the loop */ | |
| 339 | − | |
| 340 | − data->res_count++; | |
| 341 | − | |
| 342 | − pin = agpio->pin_table[0]; | |
| 343 | − for (i = 0; i < data->settings_count; i++) { | |
| 344 | − if (INTEL_GPIO_DSM_PIN(data->settings[i]) == pin) { | |
| 345 | − settings = data->settings[i]; | |
| 346 | − break; | |
| 347 | − } | |
| 348 | − } | |
| 349 | − | |
| 350 | − if (i == data->settings_count) { | |
| 351 | − acpi_handle_warn(data->adev->handle, | |
| 352 | − "%s: Could not find DSM GPIO settings for pin %u\n", | |
| 353 | − dev_name(&data->adev->dev), pin); | |
| 354 | − return 1; | |
| 355 | − } | |
| 356 | − | |
| 357 | − switch (INTEL_GPIO_DSM_TYPE(settings)) { | |
| 358 | − case 0: | |
| 359 | − name = "reset-gpios"; | |
| 360 | − break; | |
| 361 | − case 1: | |
| 362 | − name = "powerdown-gpios"; | |
| 363 | − break; | |
| 364 | − default: | |
| 365 | − acpi_handle_warn(data->adev->handle, "%s: Unknown GPIO type 0x%02lx for pin %u\n", | |
| 366 | − dev_name(&data->adev->dev), | |
| 367 | − INTEL_GPIO_DSM_TYPE(settings), pin); | |
| 368 | − return 1; | |
| 369 | − } | |
| 370 | − | |
| 371 | − /* | |
| 372 | − * Both reset and power-down need to be logical false when the sensor | |
| 373 | − * is on (sensor should not be in reset and not be powered-down). So | |
| 374 | − * when the sensor-on-value (which is the physical pin value) is high, | |
| 375 | − * then the signal is active-low. | |
| 376 | − */ | |
| 377 | − active_low = INTEL_GPIO_DSM_SENSOR_ON_VAL(settings); | |
| 378 | − | |
| 379 | − i = data->map_count; | |
| 380 | − if (i == CSI2_MAX_ACPI_GPIOS) | |
| 381 | − return 1; | |
| 382 | − | |
| 383 | − /* res_count is already incremented */ | |
| 384 | − data->map->params[i].crs_entry_index = data->res_count - 1; | |
| 385 | − data->map->params[i].active_low = active_low; | |
| 386 | − data->map->mapping[i].name = name; | |
| 387 | − data->map->mapping[i].data = &data->map->params[i]; | |
| 388 | − data->map->mapping[i].size = 1; | |
| 389 | − data->map_count++; | |
| 390 | − | |
| 391 | − acpi_handle_info(data->adev->handle, "%s: %s crs %d %s pin %u active-%s\n", | |
| 392 | − dev_name(&data->adev->dev), name, | |
| 393 | − data->res_count - 1, agpio->resource_source.string_ptr, | |
| 394 | − pin, active_low ? "low" : "high"); | |
| 395 | − | |
| 396 | − return 1; | |
| 397 | −} | |
| 398 | − | |
| 399 | 294 | /* |
| 400 | − * Helper function to create an ACPI GPIO lookup table for sensor reset and | |
| 401 | − * powerdown signals on Intel Bay Trail (BYT) and Cherry Trail (CHT) devices, | |
| 402 | − * including setting the correct polarity for the GPIO. | |
| 403 | − * | |
| 404 | − * This uses the "79234640-9e10-4fea-a5c1-b5aa8b19756f" DSM method directly | |
| 405 | − * on the sensor device's ACPI node. This is different from later Intel | |
| 406 | − * hardware which has a separate INT3472 acpi_device with this info. | |
| 407 | − * | |
| 408 | − * This function must be called before creating the sw-noded describing | |
| 409 | − * the fwnode graph endpoint. And sensor drivers used on these devices | |
| 410 | − * must return -EPROBE_DEFER when there is no endpoint description yet. | |
| 411 | − * Together this guarantees that the GPIO lookups are in place before | |
| 412 | − * the sensor driver tries to get GPIOs with gpiod_get(). | |
| 295 | + * Alloc and fill an int3472_discrete_device struct so that we can re-use | |
| 296 | + * the INT3472 sensor GPIO mapping code. | |
| 413 | 297 | * |
| 414 | − * Note this code uses the same DSM GUID as the int3472_gpio_guid in | |
| 415 | − * the INT3472 discrete.c code and there is some overlap, but there are | |
| 416 | − * enough differences that it is difficult to share the code. | |
| 298 | + * This gets called from ipu_bridge_init() which runs only once per boot, | |
| 299 | + * the created faux int3472 device is leaked on purpose to keep the created | |
| 300 | + * GPIO mappings around permanently. | |
| 417 | 301 | */ |
| 418 | 302 | static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev) |
| 419 | 303 | { |
| 420 | − struct atomisp_csi2_acpi_gpio_parsing_data data = { }; | |
| 421 | − LIST_HEAD(resource_list); | |
| 422 | − union acpi_object *obj; | |
| 423 | − unsigned int i, j; | |
| 304 | + struct int3472_discrete_device *int3472; | |
| 424 | 305 | int ret; |
| 425 | 306 | |
| 426 | − obj = acpi_evaluate_dsm_typed(adev->handle, &intel_sensor_module_guid, | |
| 427 | − 0x00, 1, NULL, ACPI_TYPE_STRING); | |
| 428 | − if (obj) { | |
| 429 | − acpi_handle_info(adev->handle, "%s: Sensor module id: '%s'\n", | |
| 430 | − dev_name(&adev->dev), obj->string.pointer); | |
| 431 | − ACPI_FREE(obj); | |
| 432 | − } | |
| 307 | + /* Max num GPIOs we've seen plus a terminator */ | |
| 308 | + int3472 = kzalloc(struct_size(int3472, gpios.table, INT3472_MAX_SENSOR_GPIOS + 1), | |
| 309 | + GFP_KERNEL); | |
| 310 | + if (!int3472) | |
| 311 | + return -ENOMEM; | |
| 433 | 312 | |
| 434 | 313 | /* |
| 435 | − * First get the GPIO-settings count and then get count GPIO-settings | |
| 436 | − * values. Note the order of these may differ from the order in which | |
| 437 | − * the GPIOs are listed on the ACPI resources! So we first store them all | |
| 438 | − * and then enumerate the ACPI resources and match them up by pin number. | |
| 314 | + * On atomisp the _DSM to get the GPIO type must be made on the sensor | |
| 315 | + * adev, rather than on a separate INT3472 adev. | |
| 439 | 316 | */ |
| 440 | − obj = acpi_evaluate_dsm_typed(adev->handle, | |
| 441 | − &intel_sensor_gpio_info_guid, 0x00, 1, | |
| 442 | − NULL, ACPI_TYPE_INTEGER); | |
| 443 | − if (!obj) { | |
| 444 | − acpi_handle_err(adev->handle, "%s: No _DSM entry for GPIO pin count\n", | |
| 445 | − dev_name(&adev->dev)); | |
| 446 | − return -EIO; | |
| 447 | − } | |
| 448 | − | |
| 449 | − data.settings_count = obj->integer.value; | |
| 450 | − ACPI_FREE(obj); | |
| 317 | + int3472->adev = adev; | |
| 318 | + int3472->dev = &adev->dev; | |
| 319 | + int3472->sensor = adev; | |
| 451 | 320 | |
| 452 | − if (data.settings_count > CSI2_MAX_ACPI_GPIOS) { | |
| 453 | − acpi_handle_err(adev->handle, "%s: Too many GPIOs %u > %u\n", | |
| 454 | − dev_name(&adev->dev), data.settings_count, | |
| 455 | − CSI2_MAX_ACPI_GPIOS); | |
| 456 | − return -EOVERFLOW; | |
| 321 | + int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev)); | |
| 322 | + if (!int3472->sensor_name) { | |
| 323 | + kfree(int3472); | |
| 324 | + return -ENOMEM; | |
| 457 | 325 | } |
| 458 | 326 | |
| 459 | − for (i = 0; i < data.settings_count; i++) { | |
| 460 | − /* | |
| 461 | − * i + 2 because the index of this _DSM function is 1-based | |
| 462 | − * and the first function is just a count. | |
| 463 | − */ | |
| 464 | − obj = acpi_evaluate_dsm_typed(adev->handle, | |
| 465 | − &intel_sensor_gpio_info_guid, | |
| 466 | − 0x00, i + 2, | |
| 467 | − NULL, ACPI_TYPE_INTEGER); | |
| 468 | − if (!obj) { | |
| 469 | − acpi_handle_err(adev->handle, "%s: No _DSM entry for pin %u\n", | |
| 470 | − dev_name(&adev->dev), i); | |
| 471 | − return -EIO; | |
| 472 | − } | |
| 473 | − | |
| 474 | − data.settings[i] = obj->integer.value; | |
| 475 | − ACPI_FREE(obj); | |
| 327 | + ret = int3472_discrete_parse_crs(int3472); | |
| 328 | + if (ret) { | |
| 329 | + int3472_discrete_cleanup(int3472); | |
| 330 | + kfree(int3472); | |
| 476 | 331 | } |
| 477 | 332 | |
| 478 | − /* Since we match up by pin-number the pin-numbers must be unique */ | |
| 479 | − for (i = 0; i < data.settings_count; i++) { | |
| 480 | − for (j = i + 1; j < data.settings_count; j++) { | |
| 481 | − if (INTEL_GPIO_DSM_PIN(data.settings[i]) != | |
| 482 | − INTEL_GPIO_DSM_PIN(data.settings[j])) | |
| 483 | − continue; | |
| 484 | − | |
| 485 | − acpi_handle_err(adev->handle, "%s: Duplicate pin number %lu\n", | |
| 486 | − dev_name(&adev->dev), | |
| 487 | − INTEL_GPIO_DSM_PIN(data.settings[i])); | |
| 488 | − return -EIO; | |
| 489 | − } | |
| 490 | − } | |
| 491 | − | |
| 492 | − data.map = kzalloc(sizeof(*data.map), GFP_KERNEL); | |
| 493 | − if (!data.map) | |
| 494 | − return -ENOMEM; | |
| 495 | − | |
| 496 | − /* Now parse the ACPI resources and build the lookup table */ | |
| 497 | − data.adev = adev; | |
| 498 | − ret = acpi_dev_get_resources(adev, &resource_list, | |
| 499 | − atomisp_csi2_handle_acpi_gpio_res, &data); | |
| 500 | − if (ret < 0) | |
| 501 | − return ret; | |
| 502 | − | |
| 503 | − acpi_dev_free_resource_list(&resource_list); | |
| 504 | − | |
| 505 | − if (data.map_count != data.settings_count || | |
| 506 | − data.res_count != data.settings_count) | |
| 507 | − acpi_handle_warn(adev->handle, "%s: ACPI GPIO resources vs DSM GPIO-info count mismatch (dsm: %d res: %d map %d\n", | |
| 508 | − dev_name(&adev->dev), data.settings_count, | |
| 509 | − data.res_count, data.map_count); | |
| 510 | − | |
| 511 | − ret = acpi_dev_add_driver_gpios(adev, data.map->mapping); | |
| 512 | − if (ret) | |
| 513 | − acpi_handle_err(adev->handle, "%s: Error adding driver GPIOs: %d\n", | |
| 514 | − dev_name(&adev->dev), ret); | |
| 515 | − | |
| 516 | 333 | return ret; |
| 517 | 334 | } |
| 518 | 335 | |
| @@ -1,155 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Support for atomisp driver sysfs interface | |
| 4 | − * | |
| 5 | − * Copyright (c) 2014 Intel Corporation. All Rights Reserved. | |
| 6 | − */ | |
| 7 | − | |
| 8 | −#include <linux/device.h> | |
| 9 | −#include <linux/err.h> | |
| 10 | −#include <linux/kernel.h> | |
| 11 | − | |
| 12 | −#include "atomisp_compat.h" | |
| 13 | −#include "atomisp_internal.h" | |
| 14 | −#include "atomisp_ioctl.h" | |
| 15 | −#include "atomisp_drvfs.h" | |
| 16 | −#include "hmm/hmm.h" | |
| 17 | −#include "ia_css_debug.h" | |
| 18 | − | |
| 19 | −#define OPTION_BIN_LIST BIT(0) | |
| 20 | −#define OPTION_BIN_RUN BIT(1) | |
| 21 | −#define OPTION_VALID (OPTION_BIN_LIST | OPTION_BIN_RUN) | |
| 22 | − | |
| 23 | −/* | |
| 24 | − * dbgopt: iunit debug option: | |
| 25 | − * bit 0: binary list | |
| 26 | − * bit 1: running binary | |
| 27 | − * bit 2: memory statistic | |
| 28 | − */ | |
| 29 | −static unsigned int dbgopt = OPTION_BIN_LIST; | |
| 30 | − | |
| 31 | −static inline int iunit_dump_dbgopt(struct atomisp_device *isp, | |
| 32 | − unsigned int opt) | |
| 33 | −{ | |
| 34 | − int ret = 0; | |
| 35 | − | |
| 36 | − if (opt & OPTION_VALID) { | |
| 37 | − if (opt & OPTION_BIN_LIST) { | |
| 38 | − ret = atomisp_css_dump_blob_infor(isp); | |
| 39 | − if (ret) { | |
| 40 | − dev_err(isp->dev, "%s dump blob infor err[ret:%d]\n", | |
| 41 | − __func__, ret); | |
| 42 | − goto opt_err; | |
| 43 | − } | |
| 44 | − } | |
| 45 | − | |
| 46 | − if (opt & OPTION_BIN_RUN) { | |
| 47 | − if (isp->asd.streaming) { | |
| 48 | − atomisp_css_dump_sp_raw_copy_linecount(true); | |
| 49 | − atomisp_css_debug_dump_isp_binary(); | |
| 50 | − } else { | |
| 51 | − ret = -EPERM; | |
| 52 | − dev_err(isp->dev, "%s dump running bin err[ret:%d]\n", | |
| 53 | − __func__, ret); | |
| 54 | − goto opt_err; | |
| 55 | − } | |
| 56 | − } | |
| 57 | − } else { | |
| 58 | − ret = -EINVAL; | |
| 59 | − dev_err(isp->dev, "%s dump nothing[ret=%d]\n", __func__, ret); | |
| 60 | − } | |
| 61 | − | |
| 62 | −opt_err: | |
| 63 | − return ret; | |
| 64 | −} | |
| 65 | − | |
| 66 | −static ssize_t dbglvl_show(struct device *dev, struct device_attribute *attr, | |
| 67 | − char *buf) | |
| 68 | −{ | |
| 69 | − unsigned int dbglvl = ia_css_debug_get_dtrace_level(); | |
| 70 | − | |
| 71 | − return sysfs_emit(buf, "dtrace level:%u\n", dbglvl); | |
| 72 | −} | |
| 73 | − | |
| 74 | −static ssize_t dbglvl_store(struct device *dev, struct device_attribute *attr, | |
| 75 | − const char *buf, size_t size) | |
| 76 | −{ | |
| 77 | − unsigned int dbglvl; | |
| 78 | − int ret; | |
| 79 | − | |
| 80 | − ret = kstrtouint(buf, 10, &dbglvl); | |
| 81 | − if (ret) | |
| 82 | − return ret; | |
| 83 | − | |
| 84 | − if (dbglvl < 1 || dbglvl > 9) | |
| 85 | − return -ERANGE; | |
| 86 | − | |
| 87 | − ia_css_debug_set_dtrace_level(dbglvl); | |
| 88 | − return size; | |
| 89 | −} | |
| 90 | −static DEVICE_ATTR_RW(dbglvl); | |
| 91 | − | |
| 92 | −static ssize_t dbgfun_show(struct device *dev, struct device_attribute *attr, | |
| 93 | − char *buf) | |
| 94 | −{ | |
| 95 | − unsigned int dbgfun = atomisp_get_css_dbgfunc(); | |
| 96 | − | |
| 97 | − return sysfs_emit(buf, "dbgfun opt:%u\n", dbgfun); | |
| 98 | −} | |
| 99 | − | |
| 100 | −static ssize_t dbgfun_store(struct device *dev, struct device_attribute *attr, | |
| 101 | − const char *buf, size_t size) | |
| 102 | −{ | |
| 103 | − struct atomisp_device *isp = dev_get_drvdata(dev); | |
| 104 | − unsigned int opt; | |
| 105 | − int ret; | |
| 106 | − | |
| 107 | − ret = kstrtouint(buf, 10, &opt); | |
| 108 | − if (ret) | |
| 109 | − return ret; | |
| 110 | − | |
| 111 | − return atomisp_set_css_dbgfunc(isp, opt); | |
| 112 | −} | |
| 113 | −static DEVICE_ATTR_RW(dbgfun); | |
| 114 | − | |
| 115 | −static ssize_t dbgopt_show(struct device *dev, struct device_attribute *attr, | |
| 116 | − char *buf) | |
| 117 | −{ | |
| 118 | − return sysfs_emit(buf, "option:0x%x\n", dbgopt); | |
| 119 | −} | |
| 120 | − | |
| 121 | −static ssize_t dbgopt_store(struct device *dev, struct device_attribute *attr, | |
| 122 | − const char *buf, size_t size) | |
| 123 | −{ | |
| 124 | − struct atomisp_device *isp = dev_get_drvdata(dev); | |
| 125 | − unsigned int opt; | |
| 126 | − int ret; | |
| 127 | − | |
| 128 | − ret = kstrtouint(buf, 10, &opt); | |
| 129 | − if (ret) | |
| 130 | − return ret; | |
| 131 | − | |
| 132 | − dbgopt = opt; | |
| 133 | − ret = iunit_dump_dbgopt(isp, dbgopt); | |
| 134 | − if (ret) | |
| 135 | − return ret; | |
| 136 | − | |
| 137 | − return size; | |
| 138 | −} | |
| 139 | −static DEVICE_ATTR_RW(dbgopt); | |
| 140 | − | |
| 141 | −static struct attribute *dbg_attrs[] = { | |
| 142 | − &dev_attr_dbglvl.attr, | |
| 143 | − &dev_attr_dbgfun.attr, | |
| 144 | − &dev_attr_dbgopt.attr, | |
| 145 | − NULL | |
| 146 | −}; | |
| 147 | − | |
| 148 | −static const struct attribute_group dbg_attr_group = { | |
| 149 | − .attrs = dbg_attrs, | |
| 150 | −}; | |
| 151 | − | |
| 152 | −const struct attribute_group *dbg_attr_groups[] = { | |
| 153 | − &dbg_attr_group, | |
| 154 | − NULL | |
| 155 | −}; | |
| @@ -1,15 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −/* | |
| 3 | − * Support for atomisp driver sysfs interface. | |
| 4 | − * | |
| 5 | − * Copyright (c) 2014 Intel Corporation. All Rights Reserved. | |
| 6 | − */ | |
| 7 | − | |
| 8 | −#ifndef __ATOMISP_DRVFS_H__ | |
| 9 | −#define __ATOMISP_DRVFS_H__ | |
| 10 | − | |
| 11 | −#include <linux/sysfs.h> | |
| 12 | − | |
| 13 | −extern const struct attribute_group *dbg_attr_groups[]; | |
| 14 | − | |
| 15 | −#endif /* __ATOMISP_DRVFS_H__ */ | |
| @@ -234,9 +234,6 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd, · 233 unmodified lines | ||
| 234 | 234 | if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM)) |
| 235 | 235 | return -EINVAL; |
| 236 | 236 | |
| 237 | − if (pipe->stopping) | |
| 238 | − return -EINVAL; | |
| 239 | − | |
| 240 | 237 | space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); |
| 241 | 238 | while (space--) { |
| 242 | 239 | struct ia_css_frame *frame; |
| @@ -367,7 +364,7 @@ static void atomisp_buf_queue(struct vb2_buffer *vb) · 124 unmodified lines | ||
| 367 | 364 | mutex_lock(&asd->isp->mutex); |
| 368 | 365 | |
| 369 | 366 | ret = atomisp_pipe_check(pipe, false); |
| 370 | − if (ret || pipe->stopping) { | |
| 367 | + if (ret) { | |
| 371 | 368 | spin_lock_irqsave(&pipe->irq_lock, irqflags); |
| 372 | 369 | atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); |
| 373 | 370 | spin_unlock_irqrestore(&pipe->irq_lock, irqflags); |
| @@ -856,6 +856,62 @@ static void atomisp_dma_burst_len_cfg(struct atomisp_sub_device *asd) · 855 unmodified lines | ||
| 856 | 856 | atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00); |
| 857 | 857 | } |
| 858 | 858 | |
| 859 | +static void atomisp_stop_stream(struct atomisp_video_pipe *pipe, | |
| 860 | + bool stop_sensor, enum vb2_buffer_state state) | |
| 861 | +{ | |
| 862 | + struct atomisp_sub_device *asd = pipe->asd; | |
| 863 | + struct atomisp_device *isp = asd->isp; | |
| 864 | + struct pci_dev *pdev = to_pci_dev(isp->dev); | |
| 865 | + unsigned long flags; | |
| 866 | + int ret; | |
| 867 | + | |
| 868 | + spin_lock_irqsave(&isp->lock, flags); | |
| 869 | + asd->streaming = false; | |
| 870 | + spin_unlock_irqrestore(&isp->lock, flags); | |
| 871 | + | |
| 872 | + atomisp_clear_css_buffer_counters(asd); | |
| 873 | + atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); | |
| 874 | + | |
| 875 | + atomisp_css_stop(asd, false); | |
| 876 | + | |
| 877 | + atomisp_subdev_cleanup_pending_events(asd); | |
| 878 | + | |
| 879 | + if (stop_sensor) { | |
| 880 | + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].csi_remote_source, | |
| 881 | + video, s_stream, 0); | |
| 882 | + if (ret) | |
| 883 | + dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret); | |
| 884 | + } | |
| 885 | + | |
| 886 | + /* Disable the CSI interface on ANN B0/K0 */ | |
| 887 | + if (isp->media_dev.hw_revision >= ((ATOMISP_HW_REVISION_ISP2401 << | |
| 888 | + ATOMISP_HW_REVISION_SHIFT) | ATOMISP_HW_STEPPING_B0)) { | |
| 889 | + pci_write_config_word(pdev, MRFLD_PCI_CSI_CONTROL, | |
| 890 | + isp->saved_regs.csi_control & ~MRFLD_PCI_CSI_CONTROL_CSI_READY); | |
| 891 | + } | |
| 892 | + | |
| 893 | + if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, false)) | |
| 894 | + dev_warn(isp->dev, "DFS failed.\n"); | |
| 895 | + | |
| 896 | + /* | |
| 897 | + * ISP work around, need to reset ISP to allow next stream on to work. | |
| 898 | + * Streams have already been destroyed by atomisp_css_stop(). | |
| 899 | + * Disable PUNIT/ISP acknowledge/handshake - SRSE=3 and then reset. | |
| 900 | + */ | |
| 901 | + pci_write_config_dword(pdev, PCI_I_CONTROL, | |
| 902 | + isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); | |
| 903 | + atomisp_reset(isp); | |
| 904 | + | |
| 905 | + atomisp_flush_video_pipe(pipe, state, false); | |
| 906 | + | |
| 907 | + /* Streams were destroyed by atomisp_css_stop(), recreate them. */ | |
| 908 | + ret = atomisp_create_pipes_stream(&isp->asd); | |
| 909 | + if (ret) | |
| 910 | + dev_warn(isp->dev, "Recreating streams failed: %d\n", ret); | |
| 911 | + | |
| 912 | + media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); | |
| 913 | +} | |
| 914 | + | |
| 859 | 915 | int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) |
| 860 | 916 | { |
| 861 | 917 | struct atomisp_video_pipe *pipe = vq_to_pipe(vq); |
| @@ -910,6 +966,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) · 48 unmodified lines | ||
| 910 | 966 | ret = atomisp_css_start(asd); |
| 911 | 967 | if (ret) { |
| 912 | 968 | atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); |
| 969 | + media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); | |
| 913 | 970 | goto out_unlock; |
| 914 | 971 | } |
| 915 | 972 | |
| @@ -949,11 +1006,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) · 33 unmodified lines | ||
| 949 | 1006 | video, s_stream, 1); |
| 950 | 1007 | if (ret) { |
| 951 | 1008 | dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret); |
| 952 | − spin_lock_irqsave(&isp->lock, irqflags); | |
| 953 | − asd->streaming = false; | |
| 954 | − spin_unlock_irqrestore(&isp->lock, irqflags); | |
| 955 | − ret = -EINVAL; | |
| 956 | − goto out_unlock; | |
| 1009 | + atomisp_stop_stream(pipe, false, VB2_BUF_STATE_QUEUED); | |
| 957 | 1010 | } |
| 958 | 1011 | |
| 959 | 1012 | out_unlock: |
| @@ -964,74 +1017,12 @@ out_unlock: · 4 unmodified lines | ||
| 964 | 1017 | void atomisp_stop_streaming(struct vb2_queue *vq) |
| 965 | 1018 | { |
| 966 | 1019 | struct atomisp_video_pipe *pipe = vq_to_pipe(vq); |
| 967 | − struct atomisp_sub_device *asd = pipe->asd; | |
| 968 | − struct atomisp_device *isp = asd->isp; | |
| 969 | − struct pci_dev *pdev = to_pci_dev(isp->dev); | |
| 970 | − unsigned long flags; | |
| 971 | − int ret; | |
| 1020 | + struct atomisp_device *isp = pipe->asd->isp; | |
| 972 | 1021 | |
| 973 | 1022 | dev_dbg(isp->dev, "Stop stream\n"); |
| 974 | 1023 | |
| 975 | 1024 | mutex_lock(&isp->mutex); |
| 976 | − /* | |
| 977 | − * There is no guarantee that the buffers queued to / owned by the ISP | |
| 978 | − * will properly be returned to the queue when stopping. Set a flag to | |
| 979 | − * avoid new buffers getting queued and then wait for all the current | |
| 980 | − * buffers to finish. | |
| 981 | − */ | |
| 982 | − pipe->stopping = true; | |
| 983 | − mutex_unlock(&isp->mutex); | |
| 984 | − /* wait max 1 second */ | |
| 985 | − ret = wait_event_timeout(pipe->vb_queue.done_wq, | |
| 986 | − atomisp_buffers_in_css(pipe) == 0, HZ); | |
| 987 | − mutex_lock(&isp->mutex); | |
| 988 | − pipe->stopping = false; | |
| 989 | − if (ret == 0) | |
| 990 | − dev_warn(isp->dev, "Warning timeout waiting for CSS to return buffers\n"); | |
| 991 | − | |
| 992 | − spin_lock_irqsave(&isp->lock, flags); | |
| 993 | − asd->streaming = false; | |
| 994 | − spin_unlock_irqrestore(&isp->lock, flags); | |
| 995 | − | |
| 996 | − atomisp_clear_css_buffer_counters(asd); | |
| 997 | − atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); | |
| 998 | − | |
| 999 | − atomisp_css_stop(asd, false); | |
| 1000 | − | |
| 1001 | − atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true); | |
| 1002 | − | |
| 1003 | − atomisp_subdev_cleanup_pending_events(asd); | |
| 1004 | − | |
| 1005 | − ret = v4l2_subdev_call(isp->inputs[asd->input_curr].csi_remote_source, | |
| 1006 | − video, s_stream, 0); | |
| 1007 | − if (ret) | |
| 1008 | − dev_warn(isp->dev, "Stopping sensor stream failed: %d\n", ret); | |
| 1009 | − | |
| 1010 | − /* Disable the CSI interface on ANN B0/K0 */ | |
| 1011 | − if (isp->media_dev.hw_revision >= ((ATOMISP_HW_REVISION_ISP2401 << | |
| 1012 | − ATOMISP_HW_REVISION_SHIFT) | ATOMISP_HW_STEPPING_B0)) { | |
| 1013 | − pci_write_config_word(pdev, MRFLD_PCI_CSI_CONTROL, | |
| 1014 | − isp->saved_regs.csi_control & ~MRFLD_PCI_CSI_CONTROL_CSI_READY); | |
| 1015 | − } | |
| 1016 | − | |
| 1017 | − if (atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_LOW, false)) | |
| 1018 | − dev_warn(isp->dev, "DFS failed.\n"); | |
| 1019 | − | |
| 1020 | − /* | |
| 1021 | − * ISP work around, need to reset ISP to allow next stream on to work. | |
| 1022 | − * Streams have already been destroyed by atomisp_css_stop(). | |
| 1023 | − * Disable PUNIT/ISP acknowledge/handshake - SRSE=3 and then reset. | |
| 1024 | − */ | |
| 1025 | − pci_write_config_dword(pdev, PCI_I_CONTROL, | |
| 1026 | − isp->saved_regs.i_control | MRFLD_PCI_I_CONTROL_SRSE_RESET_MASK); | |
| 1027 | − atomisp_reset(isp); | |
| 1028 | − | |
| 1029 | − /* Streams were destroyed by atomisp_css_stop(), recreate them. */ | |
| 1030 | − ret = atomisp_create_pipes_stream(&isp->asd); | |
| 1031 | − if (ret) | |
| 1032 | − dev_warn(isp->dev, "Recreating streams failed: %d\n", ret); | |
| 1033 | − | |
| 1034 | − media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); | |
| 1025 | + atomisp_stop_stream(pipe, true, VB2_BUF_STATE_ERROR); | |
| 1035 | 1026 | mutex_unlock(&isp->mutex); |
| 1036 | 1027 | } |
| 1037 | 1028 | |
| @@ -57,9 +57,6 @@ struct atomisp_video_pipe { · 56 unmodified lines | ||
| 57 | 57 | /* Filled through atomisp_get_css_frame_info() on queue setup */ |
| 58 | 58 | struct ia_css_frame_info frame_info; |
| 59 | 59 | |
| 60 | − /* Set from streamoff to disallow queuing further buffers in CSS */ | |
| 61 | − bool stopping; | |
| 62 | − | |
| 63 | 60 | /* |
| 64 | 61 | * irq_lock is used to protect video buffer state change operations and |
| 65 | 62 | * also to make activeq and capq operations atomic. |
| @@ -29,7 +29,6 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "atomisp_internal.h" |
| 30 | 30 | #include "atomisp-regs.h" |
| 31 | 31 | #include "atomisp_dfs_tables.h" |
| 32 | −#include "atomisp_drvfs.h" | |
| 33 | 32 | #include "hmm/hmm.h" |
| 34 | 33 | #include "atomisp_trace_event.h" |
| 35 | 34 | |
| @@ -1497,9 +1496,6 @@ static const struct pci_device_id atomisp_pci_tbl[] = { · 1461 unmodified lines | ||
| 1497 | 1496 | MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); |
| 1498 | 1497 | |
| 1499 | 1498 | static struct pci_driver atomisp_pci_driver = { |
| 1500 | − .driver = { | |
| 1501 | − .dev_groups = dbg_attr_groups, | |
| 1502 | − }, | |
| 1503 | 1499 | .name = "atomisp-isp2", |
| 1504 | 1500 | .id_table = atomisp_pci_tbl, |
| 1505 | 1501 | .probe = atomisp_pci_probe, |
| @@ -1513,3 +1509,4 @@ MODULE_AUTHOR("Xiaolin Zhang <xiaolin.zhang@intel.com>"); · 7 unmodified lines | ||
| 1513 | 1509 | MODULE_LICENSE("GPL"); |
| 1514 | 1510 | MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); |
| 1515 | 1511 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); |
| 1512 | +MODULE_IMPORT_NS("INTEL_INT3472_DISCRETE"); | |
| @@ -10,14 +10,9 @@ · 9 unmodified lines | ||
| 10 | 10 | /* Override the definition of max/min from Linux kernel */ |
| 11 | 11 | #include <linux/minmax.h> |
| 12 | 12 | |
| 13 | −/* force a value to a lower even value */ | |
| 14 | −#define EVEN_FLOOR(x) ((x) & ~1) | |
| 15 | − | |
| 16 | 13 | #define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0) |
| 17 | 14 | #define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) |
| 18 | −#define CEIL_MUL2(a, b) (((a) + (b) - 1) & ~((b) - 1)) | |
| 19 | 15 | #define CEIL_SHIFT(a, b) (((a) + (1 << (b)) - 1) >> (b)) |
| 20 | −#define CEIL_SHIFT_MUL(a, b) (CEIL_SHIFT(a, b) << (b)) | |
| 21 | 16 | |
| 22 | 17 | /* |
| 23 | 18 | * For SP and ISP, SDK provides the definition of OP_std_modadd. |
| @@ -28,88 +28,6 @@ struct hmm_bo_device bo_device; · 27 unmodified lines | ||
| 28 | 28 | static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; |
| 29 | 29 | static bool hmm_initialized; |
| 30 | 30 | |
| 31 | −/* | |
| 32 | − * p: private | |
| 33 | − * v: vmalloc | |
| 34 | − */ | |
| 35 | −static const char hmm_bo_type_string[] = "pv"; | |
| 36 | − | |
| 37 | −static ssize_t bo_show(struct device *dev, struct device_attribute *attr, | |
| 38 | − char *buf, struct list_head *bo_list, bool active) | |
| 39 | −{ | |
| 40 | − ssize_t ret = 0; | |
| 41 | − struct hmm_buffer_object *bo; | |
| 42 | − unsigned long flags; | |
| 43 | − int i; | |
| 44 | − long total[HMM_BO_LAST] = { 0 }; | |
| 45 | − long count[HMM_BO_LAST] = { 0 }; | |
| 46 | − int index1 = 0; | |
| 47 | − int index2 = 0; | |
| 48 | − | |
| 49 | − ret = scnprintf(buf, PAGE_SIZE, "type pgnr\n"); | |
| 50 | − if (ret <= 0) | |
| 51 | − return 0; | |
| 52 | − | |
| 53 | − index1 += ret; | |
| 54 | − | |
| 55 | − spin_lock_irqsave(&bo_device.list_lock, flags); | |
| 56 | − list_for_each_entry(bo, bo_list, list) { | |
| 57 | − if ((active && (bo->status & HMM_BO_ALLOCED)) || | |
| 58 | − (!active && !(bo->status & HMM_BO_ALLOCED))) { | |
| 59 | − ret = scnprintf(buf + index1, PAGE_SIZE - index1, | |
| 60 | − "%c %d\n", | |
| 61 | − hmm_bo_type_string[bo->type], bo->pgnr); | |
| 62 | − | |
| 63 | − total[bo->type] += bo->pgnr; | |
| 64 | − count[bo->type]++; | |
| 65 | − if (ret > 0) | |
| 66 | − index1 += ret; | |
| 67 | − } | |
| 68 | − } | |
| 69 | − spin_unlock_irqrestore(&bo_device.list_lock, flags); | |
| 70 | − | |
| 71 | − for (i = 0; i < HMM_BO_LAST; i++) { | |
| 72 | − if (count[i]) { | |
| 73 | − ret = scnprintf(buf + index1 + index2, | |
| 74 | − PAGE_SIZE - index1 - index2, | |
| 75 | − "%ld %c buffer objects: %ld KB\n", | |
| 76 | − count[i], hmm_bo_type_string[i], | |
| 77 | − total[i] * 4); | |
| 78 | − if (ret > 0) | |
| 79 | − index2 += ret; | |
| 80 | − } | |
| 81 | − } | |
| 82 | − | |
| 83 | − /* Add trailing zero, not included by scnprintf */ | |
| 84 | − return index1 + index2 + 1; | |
| 85 | −} | |
| 86 | − | |
| 87 | −static ssize_t active_bo_show(struct device *dev, struct device_attribute *attr, | |
| 88 | − char *buf) | |
| 89 | −{ | |
| 90 | − return bo_show(dev, attr, buf, &bo_device.entire_bo_list, true); | |
| 91 | −} | |
| 92 | − | |
| 93 | −static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr, | |
| 94 | − char *buf) | |
| 95 | −{ | |
| 96 | − return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false); | |
| 97 | −} | |
| 98 | − | |
| 99 | − | |
| 100 | −static DEVICE_ATTR_RO(active_bo); | |
| 101 | −static DEVICE_ATTR_RO(free_bo); | |
| 102 | − | |
| 103 | −static struct attribute *sysfs_attrs_ctrl[] = { | |
| 104 | − &dev_attr_active_bo.attr, | |
| 105 | − &dev_attr_free_bo.attr, | |
| 106 | − NULL | |
| 107 | −}; | |
| 108 | − | |
| 109 | −static struct attribute_group atomisp_attribute_group[] = { | |
| 110 | − {.attrs = sysfs_attrs_ctrl }, | |
| 111 | −}; | |
| 112 | − | |
| 113 | 31 | int hmm_init(void) |
| 114 | 32 | { |
| 115 | 33 | int ret; |
| @@ -130,14 +48,6 @@ int hmm_init(void) · 14 unmodified lines | ||
| 130 | 48 | */ |
| 131 | 49 | dummy_ptr = hmm_alloc(1); |
| 132 | 50 | |
| 133 | − if (!ret) { | |
| 134 | − ret = sysfs_create_group(&atomisp_dev->kobj, | |
| 135 | − atomisp_attribute_group); | |
| 136 | − if (ret) | |
| 137 | − dev_err(atomisp_dev, | |
| 138 | − "%s Failed to create sysfs\n", __func__); | |
| 139 | − } | |
| 140 | − | |
| 141 | 51 | return ret; |
| 142 | 52 | } |
| 143 | 53 | |
| @@ -145,7 +55,6 @@ void hmm_cleanup(void) · 1 unmodified line | ||
| 145 | 55 | { |
| 146 | 56 | if (dummy_ptr == mmgr_EXCEPTION) |
| 147 | 57 | return; |
| 148 | − sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); | |
| 149 | 58 | |
| 150 | 59 | /* free dummy memory first */ |
| 151 | 60 | hmm_free(dummy_ptr); |
| @@ -37,8 +37,6 @@ static int __bo_init(struct hmm_bo_device *bdev, struct hmm_buffer_object *bo, · 36 unmodified lines | ||
| 37 | 37 | unsigned int pgnr) |
| 38 | 38 | { |
| 39 | 39 | check_bodev_null_return(bdev, -EINVAL); |
| 40 | − var_equal_return(hmm_bo_device_inited(bdev), 0, -EINVAL, | |
| 41 | − "hmm_bo_device not inited yet.\n"); | |
| 42 | 40 | /* prevent zero size buffer object */ |
| 43 | 41 | if (pgnr == 0) { |
| 44 | 42 | dev_err(atomisp_dev, "0 size buffer is not allowed.\n"); |
| @@ -341,7 +339,6 @@ int hmm_bo_device_init(struct hmm_bo_device *bdev, · 296 unmodified lines | ||
| 341 | 339 | spin_lock_init(&bdev->list_lock); |
| 342 | 340 | mutex_init(&bdev->rbtree_mutex); |
| 343 | 341 | |
| 344 | − bdev->flag = HMM_BO_DEVICE_INITED; | |
| 345 | 342 | |
| 346 | 343 | INIT_LIST_HEAD(&bdev->entire_bo_list); |
| 347 | 344 | bdev->allocated_rbtree = RB_ROOT; |
| @@ -376,6 +373,8 @@ int hmm_bo_device_init(struct hmm_bo_device *bdev, · 28 unmodified lines | ||
| 376 | 373 | |
| 377 | 374 | __bo_insert_to_free_rbtree(&bdev->free_rbtree, bo); |
| 378 | 375 | |
| 376 | + bdev->flag = HMM_BO_DEVICE_INITED; | |
| 377 | + | |
| 379 | 378 | return 0; |
| 380 | 379 | } |
| 381 | 380 | |
| @@ -102,8 +102,6 @@ struct ia_css_yuvpp_settings { · 101 unmodified lines | ||
| 102 | 102 | struct osys_object; |
| 103 | 103 | |
| 104 | 104 | struct ia_css_pipe { |
| 105 | − /* TODO: Remove stop_requested and use stop_requested in the pipeline */ | |
| 106 | − bool stop_requested; | |
| 107 | 105 | struct ia_css_pipe_config config; |
| 108 | 106 | struct ia_css_pipe_extra_config extra_config; |
| 109 | 107 | struct ia_css_pipe_info info; |
| @@ -11,9 +11,11 @@ · 10 unmodified lines | ||
| 11 | 11 | * CSS-API header file for Advanced Noise Reduction kernel v1 |
| 12 | 12 | */ |
| 13 | 13 | |
| 14 | +#include <linux/math.h> | |
| 15 | + | |
| 14 | 16 | /* Application specific DMA settings */ |
| 15 | 17 | #define ANR_BPP 10 |
| 16 | −#define ANR_ELEMENT_BITS ((CEIL_DIV(ANR_BPP, 8)) * 8) | |
| 18 | +#define ANR_ELEMENT_BITS round_up(ANR_BPP, 8) | |
| 17 | 19 | |
| 18 | 20 | /* Advanced Noise Reduction configuration. |
| 19 | 21 | * This is also known as Low-Light. |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef __IA_CSS_DPC2_PARAM_H |
| 8 | 8 | #define __IA_CSS_DPC2_PARAM_H |
| 9 | 9 | |
| 10 | +#include <linux/math.h> | |
| 11 | + | |
| 10 | 12 | #include "type_support.h" |
| 11 | 13 | #include "vmem.h" /* for VMEM_ARRAY*/ |
| 12 | 14 | |
| @@ -19,12 +21,12 @@ · 6 unmodified lines | ||
| 19 | 21 | /* 3 lines state per color plane input_line_state */ |
| 20 | 22 | #define DPC2_STATE_INPUT_BUFFER_HEIGHT (3 * NUM_PLANES) |
| 21 | 23 | /* Each plane has width equal to half frame line */ |
| 22 | −#define DPC2_STATE_INPUT_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 24 | +#define DPC2_STATE_INPUT_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 23 | 25 | |
| 24 | 26 | /* 1 line state per color plane for local deviation state*/ |
| 25 | 27 | #define DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT (1 * NUM_PLANES) |
| 26 | 28 | /* Each plane has width equal to half frame line */ |
| 27 | −#define DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 29 | +#define DPC2_STATE_LOCAL_DEVIATION_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 28 | 30 | |
| 29 | 31 | /* MINMAX state buffer stores 1 full input line (GR-R color line) */ |
| 30 | 32 | #define DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT 1 |
| @@ -141,10 +141,10 @@ convert_coords_to_ispparams( · 140 unmodified lines | ||
| 141 | 141 | |
| 142 | 142 | /* similar to topleft_y calculation, but round up if ymax |
| 143 | 143 | * has any fraction bits */ |
| 144 | − bottom_y = CEIL_DIV(ymax, 1 << DVS_COORD_FRAC_BITS); | |
| 144 | + bottom_y = DIV_ROUND_UP(ymax, BIT(DVS_COORD_FRAC_BITS)); | |
| 145 | 145 | s.in_block_height = bottom_y - topleft_y + dvs_interp_envelope; |
| 146 | 146 | |
| 147 | − bottom_x = CEIL_DIV(xmax, 1 << DVS_COORD_FRAC_BITS); | |
| 147 | + bottom_x = DIV_ROUND_UP(xmax, BIT(DVS_COORD_FRAC_BITS)); | |
| 148 | 148 | s.in_block_width = bottom_x - topleft_x + dvs_interp_envelope; |
| 149 | 149 | |
| 150 | 150 | topleft_x_frac = topleft_x << (DVS_COORD_FRAC_BITS); |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef __IA_CSS_EED1_8_PARAM_H |
| 8 | 8 | #define __IA_CSS_EED1_8_PARAM_H |
| 9 | 9 | |
| 10 | +#include <linux/math.h> | |
| 11 | + | |
| 10 | 12 | #include "type_support.h" |
| 11 | 13 | #include "vmem.h" /* needed for VMEM_ARRAY */ |
| 12 | 14 | |
| @@ -35,35 +37,35 @@ · 22 unmodified lines | ||
| 35 | 37 | #define EED1_8_STATE_INPUT_BUFFER_HEIGHT (5 * NUM_PLANES) |
| 36 | 38 | |
| 37 | 39 | /* Each plane has width equal to half frame line */ |
| 38 | −#define EED1_8_STATE_INPUT_BUFFER_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 40 | +#define EED1_8_STATE_INPUT_BUFFER_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 39 | 41 | |
| 40 | 42 | /* 1 line state per color plane LD_H state */ |
| 41 | 43 | #define EED1_8_STATE_LD_H_HEIGHT (1 * NUM_PLANES) |
| 42 | −#define EED1_8_STATE_LD_H_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 44 | +#define EED1_8_STATE_LD_H_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 43 | 45 | |
| 44 | 46 | /* 1 line state per color plane LD_V state */ |
| 45 | 47 | #define EED1_8_STATE_LD_V_HEIGHT (1 * NUM_PLANES) |
| 46 | −#define EED1_8_STATE_LD_V_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 48 | +#define EED1_8_STATE_LD_V_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 47 | 49 | |
| 48 | 50 | /* 1 line (single plane) state for D_Hr state */ |
| 49 | 51 | #define EED1_8_STATE_D_HR_HEIGHT 1 |
| 50 | −#define EED1_8_STATE_D_HR_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 52 | +#define EED1_8_STATE_D_HR_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 51 | 53 | |
| 52 | 54 | /* 1 line (single plane) state for D_Hb state */ |
| 53 | 55 | #define EED1_8_STATE_D_HB_HEIGHT 1 |
| 54 | −#define EED1_8_STATE_D_HB_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 56 | +#define EED1_8_STATE_D_HB_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 55 | 57 | |
| 56 | 58 | /* 2 lines (single plane) state for D_Vr state */ |
| 57 | 59 | #define EED1_8_STATE_D_VR_HEIGHT 2 |
| 58 | −#define EED1_8_STATE_D_VR_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 60 | +#define EED1_8_STATE_D_VR_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 59 | 61 | |
| 60 | 62 | /* 2 line (single plane) state for D_Vb state */ |
| 61 | 63 | #define EED1_8_STATE_D_VB_HEIGHT 2 |
| 62 | −#define EED1_8_STATE_D_VB_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 64 | +#define EED1_8_STATE_D_VB_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 63 | 65 | |
| 64 | 66 | /* 2 lines state for R and B (= 2 planes) rb_zipped_state */ |
| 65 | 67 | #define EED1_8_STATE_RB_ZIPPED_HEIGHT (2 * 2) |
| 66 | −#define EED1_8_STATE_RB_ZIPPED_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 68 | +#define EED1_8_STATE_RB_ZIPPED_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 67 | 69 | |
| 68 | 70 | #if EED1_8_FC_ENABLE_MEDIAN |
| 69 | 71 | /* 1 full input line (GR-R color line) for Yc state */ |
| @@ -72,11 +74,11 @@ · 2 unmodified lines | ||
| 72 | 74 | |
| 73 | 75 | /* 1 line state per color plane Cg_state */ |
| 74 | 76 | #define EED1_8_STATE_CG_HEIGHT (1 * NUM_PLANES) |
| 75 | −#define EED1_8_STATE_CG_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 77 | +#define EED1_8_STATE_CG_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 76 | 78 | |
| 77 | 79 | /* 1 line state per color plane Co_state */ |
| 78 | 80 | #define EED1_8_STATE_CO_HEIGHT (1 * NUM_PLANES) |
| 79 | −#define EED1_8_STATE_CO_WIDTH CEIL_DIV(MAX_FRAME_SIMDWIDTH, 2) | |
| 81 | +#define EED1_8_STATE_CO_WIDTH DIV_ROUND_UP(MAX_FRAME_SIMDWIDTH, 2) | |
| 80 | 82 | |
| 81 | 83 | /* 1 full input line (GR-R color line) for AbsK state */ |
| 82 | 84 | #define EED1_8_STATE_ABSK_HEIGHT 1 |
| @@ -4,6 +4,8 @@ · 3 unmodified lines | ||
| 4 | 4 | * Copyright (c) 2015, Intel Corporation. |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | +#include <linux/math.h> | |
| 8 | + | |
| 7 | 9 | #include <assert_support.h> |
| 8 | 10 | #include <ia_css_frame_public.h> |
| 9 | 11 | #include <ia_css_frame.h> |
| @@ -71,9 +73,9 @@ int ia_css_fpn_configure(const struct ia_css_binary *binary, · 61 unmodified lines | ||
| 71 | 73 | &my_info |
| 72 | 74 | }; |
| 73 | 75 | |
| 74 | − my_info.res.width = CEIL_DIV(info->res.width, 2); /* Packed by 2x */ | |
| 76 | + my_info.res.width = DIV_ROUND_UP(info->res.width, 2); /* Packed by 2x */ | |
| 75 | 77 | my_info.res.height = info->res.height; |
| 76 | − my_info.padded_width = CEIL_DIV(info->padded_width, 2); /* Packed by 2x */ | |
| 78 | + my_info.padded_width = DIV_ROUND_UP(info->padded_width, 2); /* Packed by 2x */ | |
| 77 | 79 | my_info.format = info->format; |
| 78 | 80 | my_info.raw_bit_depth = FPN_BITS_PER_PIXEL; |
| 79 | 81 | my_info.raw_bayer_order = info->raw_bayer_order; |
| @@ -22,7 +22,7 @@ struct sh_css_isp_sc_params { · 21 unmodified lines | ||
| 22 | 22 | * vec_slice is used for 2 adjacent vectors of shading gains. |
| 23 | 23 | * The number of shift times by vec_slice is 8. |
| 24 | 24 | * Max grid cell bqs to support the shading table centerting: N = 32 |
| 25 | − * CEIL_DIV(N-1, ISP_SLICE_NELEMS) = CEIL_DIV(31, 4) = 8 | |
| 25 | + * DIV_ROUND_UP(N-1, ISP_SLICE_NELEMS) = DIV_ROUND_UP(31, 4) = 8 | |
| 26 | 26 | */ |
| 27 | 27 | #define SH_CSS_SC_INTERPED_GAIN_HOR_SLICE_TIMES 8 |
| 28 | 28 | |
| @@ -91,8 +91,7 @@ configure_kernel( · 90 unmodified lines | ||
| 91 | 91 | unsigned int vf_log_ds = 0; |
| 92 | 92 | |
| 93 | 93 | /* First compute value */ |
| 94 | − if (vf_info) | |
| 95 | − { | |
| 94 | + if (vf_info) { | |
| 96 | 95 | err = sh_css_vf_downscale_log2(out_info, vf_info, &vf_log_ds); |
| 97 | 96 | if (err) |
| 98 | 97 | return err; |
| @@ -8,9 +8,10 @@ Copyright (c) 2010 - 2015, Intel Corporation. · 7 unmodified lines | ||
| 8 | 8 | #ifndef _INPUT_BUF_ISP_H_ |
| 9 | 9 | #define _INPUT_BUF_ISP_H_ |
| 10 | 10 | |
| 11 | +#include <linux/math.h> | |
| 12 | + | |
| 11 | 13 | /* Temporary include, since IA_CSS_BINARY_MODE_COPY is still needed */ |
| 12 | 14 | #include "sh_css_defs.h" |
| 13 | −#include "isp_const.h" /* MAX_VECTORS_PER_INPUT_LINE */ | |
| 14 | 15 | |
| 15 | 16 | #define INPUT_BUF_HEIGHT 2 /* double buffer */ |
| 16 | 17 | #define INPUT_BUF_LINES 2 |
| @@ -22,7 +23,8 @@ Copyright (c) 2010 - 2015, Intel Corporation. · 5 unmodified lines | ||
| 22 | 23 | /* In continuous mode, the input buffer must be a fixed size for all binaries |
| 23 | 24 | * and at a fixed address since it will be used by the SP. */ |
| 24 | 25 | #define EXTRA_INPUT_VECTORS 2 /* For left padding */ |
| 25 | −#define MAX_VECTORS_PER_INPUT_LINE_CONT (CEIL_DIV(SH_CSS_MAX_SENSOR_WIDTH, ISP_NWAY) + EXTRA_INPUT_VECTORS) | |
| 26 | +#define MAX_VECTORS_PER_INPUT_LINE_CONT \ | |
| 27 | + (DIV_ROUND_UP(SH_CSS_MAX_SENSOR_WIDTH, ISP_NWAY) + EXTRA_INPUT_VECTORS) | |
| 26 | 28 | |
| 27 | 29 | /* The input buffer should be on a fixed address in vmem, for continuous capture */ |
| 28 | 30 | #define INPUT_BUF_ADDR 0x0 |
| @@ -1,157 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −/** | |
| 3 | −Support for Intel Camera Imaging ISP subsystem. | |
| 4 | −Copyright (c) 2010 - 2015, Intel Corporation. | |
| 5 | − | |
| 6 | −*/ | |
| 7 | − | |
| 8 | −#ifndef _COMMON_ISP_CONST_H_ | |
| 9 | −#define _COMMON_ISP_CONST_H_ | |
| 10 | − | |
| 11 | −/*#include "isp.h"*/ /* ISP_VEC_NELEMS */ | |
| 12 | − | |
| 13 | −/* Binary independent constants */ | |
| 14 | − | |
| 15 | −#ifndef NO_HOIST | |
| 16 | −# define NO_HOIST HIVE_ATTRIBUTE((no_hoist)) | |
| 17 | −#endif | |
| 18 | − | |
| 19 | −#define NO_HOIST_CSE HIVE_ATTRIBUTE((no_hoist, no_cse)) | |
| 20 | − | |
| 21 | −#define UNION struct /* Union constructors not allowed in C++ */ | |
| 22 | − | |
| 23 | −#define XMEM_WIDTH_BITS HIVE_ISP_DDR_WORD_BITS | |
| 24 | −#define XMEM_SHORTS_PER_WORD (HIVE_ISP_DDR_WORD_BITS / 16) | |
| 25 | −#define XMEM_INTS_PER_WORD (HIVE_ISP_DDR_WORD_BITS / 32) | |
| 26 | −#define XMEM_POW2_BYTES_PER_WORD HIVE_ISP_DDR_WORD_BYTES | |
| 27 | − | |
| 28 | −#define BITS8_ELEMENTS_PER_XMEM_ADDR CEIL_DIV(XMEM_WIDTH_BITS, 8) | |
| 29 | −#define BITS16_ELEMENTS_PER_XMEM_ADDR CEIL_DIV(XMEM_WIDTH_BITS, 16) | |
| 30 | − | |
| 31 | −#define ISP_NWAY_LOG2 6 | |
| 32 | − | |
| 33 | −/* ***************************** | |
| 34 | − * ISP input/output buffer sizes | |
| 35 | − * ****************************/ | |
| 36 | −/* input image */ | |
| 37 | −#define INPUT_BUF_DMA_HEIGHT 2 | |
| 38 | −#define INPUT_BUF_HEIGHT 2 /* double buffer */ | |
| 39 | −#define OUTPUT_BUF_DMA_HEIGHT 2 | |
| 40 | −#define OUTPUT_BUF_HEIGHT 2 /* double buffer */ | |
| 41 | −#define OUTPUT_NUM_TRANSFERS 4 | |
| 42 | − | |
| 43 | −/* GDC accelerator: Up/Down Scaling */ | |
| 44 | −/* These should be moved to the gdc_defs.h in the device */ | |
| 45 | −#define UDS_SCALING_N HRT_GDC_N | |
| 46 | −/* AB: This should cover the zooming up to 16MP */ | |
| 47 | −#define UDS_MAX_OXDIM 5000 | |
| 48 | −/* We support maximally 2 planes with different parameters | |
| 49 | − - luma and chroma (YUV420) */ | |
| 50 | −#define UDS_MAX_PLANES 2 | |
| 51 | −#define UDS_BLI_BLOCK_HEIGHT 2 | |
| 52 | −#define UDS_BCI_BLOCK_HEIGHT 4 | |
| 53 | −#define UDS_BLI_INTERP_ENVELOPE 1 | |
| 54 | −#define UDS_BCI_INTERP_ENVELOPE 3 | |
| 55 | −#define UDS_MAX_ZOOM_FAC 64 | |
| 56 | −/* Make it always one FPGA vector. | |
| 57 | − Four FPGA vectors are required and | |
| 58 | − four of them fit in one ASIC vector.*/ | |
| 59 | −#define UDS_MAX_CHUNKS 16 | |
| 60 | − | |
| 61 | −#define ISP_LEFT_PADDING _ISP_LEFT_CROP_EXTRA(ISP_LEFT_CROPPING) | |
| 62 | −#define ISP_LEFT_PADDING_VECS CEIL_DIV(ISP_LEFT_PADDING, ISP_VEC_NELEMS) | |
| 63 | −/* in case of continuous the croppong of the current binary doesn't matter for the buffer calculation, but the cropping of the sp copy should be used */ | |
| 64 | −#define ISP_LEFT_PADDING_CONT _ISP_LEFT_CROP_EXTRA(SH_CSS_MAX_LEFT_CROPPING) | |
| 65 | −#define ISP_LEFT_PADDING_VECS_CONT CEIL_DIV(ISP_LEFT_PADDING_CONT, ISP_VEC_NELEMS) | |
| 66 | − | |
| 67 | −#define CEIL_ROUND_DIV_STRIPE(width, stripe, padding) \ | |
| 68 | − CEIL_MUL(padding + CEIL_DIV(width - padding, stripe), ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2)) | |
| 69 | − | |
| 70 | −/* output (Y,U,V) image, 4:2:0 */ | |
| 71 | −#define MAX_VECTORS_PER_LINE \ | |
| 72 | − CEIL_ROUND_DIV_STRIPE(CEIL_DIV(ISP_MAX_INTERNAL_WIDTH, ISP_VEC_NELEMS), \ | |
| 73 | − ISP_NUM_STRIPES, \ | |
| 74 | − ISP_LEFT_PADDING_VECS) | |
| 75 | − | |
| 76 | −/* | |
| 77 | − * ITERATOR_VECTOR_INCREMENT' explanation: | |
| 78 | − * when striping an even number of iterations, one of the stripes is | |
| 79 | − * one iteration wider than the other to account for overlap | |
| 80 | − * so the calc for the output buffer vmem size is: | |
| 81 | − * ((width[vectors]/num_of_stripes) + 2[vectors]) | |
| 82 | − */ | |
| 83 | −#define MAX_VECTORS_PER_OUTPUT_LINE \ | |
| 84 | − CEIL_DIV(CEIL_DIV(ISP_MAX_OUTPUT_WIDTH, ISP_NUM_STRIPES) + ISP_LEFT_PADDING, ISP_VEC_NELEMS) | |
| 85 | − | |
| 86 | −/* Must be even due to interlaced bayer input */ | |
| 87 | −#define MAX_VECTORS_PER_INPUT_LINE CEIL_MUL((CEIL_DIV(ISP_MAX_INPUT_WIDTH, ISP_VEC_NELEMS) + ISP_LEFT_PADDING_VECS), 2) | |
| 88 | −#define MAX_VECTORS_PER_INPUT_STRIPE CEIL_ROUND_DIV_STRIPE(MAX_VECTORS_PER_INPUT_LINE, \ | |
| 89 | − ISP_NUM_STRIPES, \ | |
| 90 | − ISP_LEFT_PADDING_VECS) | |
| 91 | − | |
| 92 | −/* Add 2 for left croppping */ | |
| 93 | −#define MAX_SP_RAW_COPY_VECTORS_PER_INPUT_LINE (CEIL_DIV(ISP_MAX_INPUT_WIDTH, ISP_VEC_NELEMS) + 2) | |
| 94 | − | |
| 95 | −#define MAX_VECTORS_PER_BUF_LINE \ | |
| 96 | − (MAX_VECTORS_PER_LINE + DUMMY_BUF_VECTORS) | |
| 97 | −#define MAX_VECTORS_PER_BUF_INPUT_LINE \ | |
| 98 | − (MAX_VECTORS_PER_INPUT_STRIPE + DUMMY_BUF_VECTORS) | |
| 99 | −#define MAX_OUTPUT_Y_FRAME_WIDTH \ | |
| 100 | − (MAX_VECTORS_PER_LINE * ISP_VEC_NELEMS) | |
| 101 | −#define MAX_OUTPUT_Y_FRAME_SIMDWIDTH \ | |
| 102 | − MAX_VECTORS_PER_LINE | |
| 103 | −#define MAX_OUTPUT_C_FRAME_WIDTH \ | |
| 104 | − (MAX_OUTPUT_Y_FRAME_WIDTH / 2) | |
| 105 | −#define MAX_OUTPUT_C_FRAME_SIMDWIDTH \ | |
| 106 | − CEIL_DIV(MAX_OUTPUT_C_FRAME_WIDTH, ISP_VEC_NELEMS) | |
| 107 | − | |
| 108 | −/* should be even */ | |
| 109 | −#define NO_CHUNKING (OUTPUT_NUM_CHUNKS == 1) | |
| 110 | − | |
| 111 | −#define MAX_VECTORS_PER_CHUNK \ | |
| 112 | − (NO_CHUNKING ? MAX_VECTORS_PER_LINE \ | |
| 113 | − : 2 * CEIL_DIV(MAX_VECTORS_PER_LINE, \ | |
| 114 | − 2 * OUTPUT_NUM_CHUNKS)) | |
| 115 | − | |
| 116 | −#define MAX_C_VECTORS_PER_CHUNK \ | |
| 117 | − (MAX_VECTORS_PER_CHUNK / 2) | |
| 118 | − | |
| 119 | −/* should be even */ | |
| 120 | −#define MAX_VECTORS_PER_OUTPUT_CHUNK \ | |
| 121 | − (NO_CHUNKING ? MAX_VECTORS_PER_OUTPUT_LINE \ | |
| 122 | − : 2 * CEIL_DIV(MAX_VECTORS_PER_OUTPUT_LINE, \ | |
| 123 | − 2 * OUTPUT_NUM_CHUNKS)) | |
| 124 | − | |
| 125 | −#define MAX_C_VECTORS_PER_OUTPUT_CHUNK \ | |
| 126 | − (MAX_VECTORS_PER_OUTPUT_CHUNK / 2) | |
| 127 | − | |
| 128 | −/* should be even */ | |
| 129 | −#define MAX_VECTORS_PER_INPUT_CHUNK \ | |
| 130 | − (INPUT_NUM_CHUNKS == 1 ? MAX_VECTORS_PER_INPUT_STRIPE \ | |
| 131 | − : 2 * CEIL_DIV(MAX_VECTORS_PER_INPUT_STRIPE, \ | |
| 132 | − 2 * OUTPUT_NUM_CHUNKS)) | |
| 133 | − | |
| 134 | −#define DEFAULT_C_SUBSAMPLING 2 | |
| 135 | − | |
| 136 | −/****** DMA buffer properties */ | |
| 137 | − | |
| 138 | −#define RAW_BUF_LINES ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2) | |
| 139 | − | |
| 140 | −/* [isp vmem] table size[vectors] per line per color (GR,R,B,GB), | |
| 141 | − multiples of NWAY */ | |
| 142 | −#define ISP2400_SCTBL_VECTORS_PER_LINE_PER_COLOR \ | |
| 143 | − CEIL_DIV(SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR, ISP_VEC_NELEMS) | |
| 144 | −#define ISP2401_SCTBL_VECTORS_PER_LINE_PER_COLOR \ | |
| 145 | − CEIL_DIV(SH_CSS_MAX_SCTBL_WIDTH_PER_COLOR, ISP_VEC_NELEMS) | |
| 146 | −/* [isp vmem] table size[vectors] per line for 4colors (GR,R,B,GB), | |
| 147 | − multiples of NWAY */ | |
| 148 | −#define SCTBL_VECTORS_PER_LINE \ | |
| 149 | − (SCTBL_VECTORS_PER_LINE_PER_COLOR * IA_CSS_SC_NUM_COLORS) | |
| 150 | − | |
| 151 | −/*************/ | |
| 152 | − | |
| 153 | −/* Format for fixed primaries */ | |
| 154 | − | |
| 155 | −#define ISP_FIXED_PRIMARY_FORMAT IA_CSS_FRAME_FORMAT_NV12 | |
| 156 | − | |
| 157 | −#endif /* _COMMON_ISP_CONST_H_ */ | |
| @@ -51,7 +51,6 @@ · 50 unmodified lines | ||
| 51 | 51 | #include "sp.h" |
| 52 | 52 | #include "isp.h" |
| 53 | 53 | #include "type_support.h" |
| 54 | −#include "math_support.h" /* CEIL_DIV */ | |
| 55 | 54 | #include "input_system.h" /* input_formatter_reg_load */ |
| 56 | 55 | #include "ia_css_tagger_common.h" |
| 57 | 56 | |
| @@ -4,15 +4,16 @@ · 3 unmodified lines | ||
| 4 | 4 | * Copyright (c) 2015, Intel Corporation. |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | −#include "hmm.h" | |
| 7 | +#include <linux/bitops.h> | |
| 8 | +#include <linux/math.h> | |
| 8 | 9 | |
| 9 | −#include "ia_css_frame.h" | |
| 10 | −#include <math_support.h> | |
| 11 | 10 | #include "assert_support.h" |
| 11 | +#include "atomisp_internal.h" | |
| 12 | +#include "hmm.h" | |
| 12 | 13 | #include "ia_css_debug.h" |
| 14 | +#include "ia_css_frame.h" | |
| 13 | 15 | #include "isp.h" |
| 14 | 16 | #include "sh_css_internal.h" |
| 15 | −#include "atomisp_internal.h" | |
| 16 | 17 | |
| 17 | 18 | #define NV12_TILEY_TILE_WIDTH 128 |
| 18 | 19 | #define NV12_TILEY_TILE_HEIGHT 32 |
| @@ -459,15 +460,16 @@ static void frame_init_single_plane(struct ia_css_frame *frame, · 440 unmodified lines | ||
| 459 | 460 | unsigned int stride; |
| 460 | 461 | |
| 461 | 462 | stride = subpixels_per_line * bytes_per_pixel; |
| 462 | − /* Frame height needs to be even number - needed by hw ISYS2401 | |
| 463 | − In case of odd number, round up to even. | |
| 464 | − Images won't be impacted by this round up, | |
| 465 | − only needed by jpeg/embedded data. | |
| 466 | − As long as buffer allocation and release are using data_bytes, | |
| 467 | − there won't be memory leak. */ | |
| 468 | − frame->data_bytes = stride * CEIL_MUL2(height, 2); | |
| 463 | + /* | |
| 464 | + * Frame height needs to be even number - needed by hw ISYS2401. | |
| 465 | + * In case of odd number, round up to even. | |
| 466 | + * Images won't be impacted by this round up, | |
| 467 | + * only needed by jpeg/embedded data. | |
| 468 | + * As long as buffer allocation and release are using data_bytes, | |
| 469 | + * there won't be memory leak. | |
| 470 | + */ | |
| 471 | + frame->data_bytes = stride * round_up(height, 2); | |
| 469 | 472 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); |
| 470 | − return; | |
| 471 | 473 | } |
| 472 | 474 | |
| 473 | 475 | static void frame_init_raw_single_plane( |
| @@ -486,7 +488,6 @@ static void frame_init_raw_single_plane( · 12 unmodified lines | ||
| 486 | 488 | HIVE_ISP_DDR_WORD_BITS / bits_per_pixel); |
| 487 | 489 | frame->data_bytes = stride * height; |
| 488 | 490 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); |
| 489 | − return; | |
| 490 | 491 | } |
| 491 | 492 | |
| 492 | 493 | static void frame_init_nv_planes(struct ia_css_frame *frame, |
| @@ -690,7 +691,7 @@ ia_css_elems_bytes_from_info(const struct ia_css_frame_info *info) · 197 unmodified lines | ||
| 690 | 691 | if (info->format == IA_CSS_FRAME_FORMAT_RAW |
| 691 | 692 | || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) { |
| 692 | 693 | if (info->raw_bit_depth) |
| 693 | − return CEIL_DIV(info->raw_bit_depth, 8); | |
| 694 | + return BITS_TO_BYTES(info->raw_bit_depth); | |
| 694 | 695 | else |
| 695 | 696 | return 2; /* bytes per pixel */ |
| 696 | 697 | } |
| @@ -4,9 +4,9 @@ · 3 unmodified lines | ||
| 4 | 4 | * Copyright (c) 2010 - 2015, Intel Corporation. |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | −#include "system_global.h" | |
| 8 | −#include <linux/kernel.h> | |
| 7 | +#include <linux/math.h> | |
| 9 | 8 | |
| 9 | +#include "system_global.h" | |
| 10 | 10 | |
| 11 | 11 | #include "ia_css_ifmtr.h" |
| 12 | 12 | #include <math_support.h> |
| @@ -149,10 +149,9 @@ int ia_css_ifmtr_configure(struct ia_css_stream_config *config, · 136 unmodified lines | ||
| 149 | 149 | left_padding = 2 * ISP_VEC_NELEMS - config->left_padding; |
| 150 | 150 | |
| 151 | 151 | if (left_padding) { |
| 152 | − num_vectors = CEIL_DIV(cropped_width + left_padding, | |
| 153 | − ISP_VEC_NELEMS); | |
| 152 | + num_vectors = DIV_ROUND_UP(cropped_width + left_padding, ISP_VEC_NELEMS); | |
| 154 | 153 | } else { |
| 155 | − num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); | |
| 154 | + num_vectors = DIV_ROUND_UP(cropped_width, ISP_VEC_NELEMS); | |
| 156 | 155 | num_vectors *= buffer_height; |
| 157 | 156 | /* todo: in case of left padding, |
| 158 | 157 | num_vectors is vectors per line, |
| @@ -305,7 +304,7 @@ int ia_css_ifmtr_configure(struct ia_css_stream_config *config, · 146 unmodified lines | ||
| 305 | 304 | if ((!binary) || config->continuous) |
| 306 | 305 | /* !binary -> sp raw copy pipe */ |
| 307 | 306 | buffer_height *= 2; |
| 308 | − vectors_per_line = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); | |
| 307 | + vectors_per_line = DIV_ROUND_UP(cropped_width, ISP_VEC_NELEMS); | |
| 309 | 308 | vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); |
| 310 | 309 | break; |
| 311 | 310 | case ATOMISP_INPUT_FORMAT_RAW_14: |
| @@ -808,7 +808,7 @@ static bool calculate_isys2401_dma_port_cfg( · 807 unmodified lines | ||
| 808 | 808 | |
| 809 | 809 | cfg->elements = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; |
| 810 | 810 | cfg->cropping = 0; |
| 811 | − cfg->width = CEIL_DIV(cfg->stride, HIVE_ISP_DDR_WORD_BYTES); | |
| 811 | + cfg->width = DIV_ROUND_UP(cfg->stride, HIVE_ISP_DDR_WORD_BYTES); | |
| 812 | 812 | |
| 813 | 813 | return true; |
| 814 | 814 | } |
| @@ -34,7 +34,6 @@ struct ia_css_pipeline_stage { · 33 unmodified lines | ||
| 34 | 34 | struct ia_css_pipeline { |
| 35 | 35 | enum ia_css_pipe_id pipe_id; |
| 36 | 36 | u8 pipe_num; |
| 37 | − bool stop_requested; | |
| 38 | 37 | struct ia_css_pipeline_stage *stages; |
| 39 | 38 | struct ia_css_pipeline_stage *current_stage; |
| 40 | 39 | unsigned int num_stages; |
| @@ -198,7 +198,6 @@ int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline) · 197 unmodified lines | ||
| 198 | 198 | ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, |
| 199 | 199 | "ia_css_pipeline_request_stop() enter: pipeline=%p\n", |
| 200 | 200 | pipeline); |
| 201 | − pipeline->stop_requested = true; | |
| 202 | 201 | |
| 203 | 202 | /* Send stop event to the sp*/ |
| 204 | 203 | /* This needs improvement, stop on all the pipes available |
| @@ -663,7 +662,6 @@ static void pipeline_init_defaults( · 458 unmodified lines | ||
| 663 | 662 | |
| 664 | 663 | pipeline->pipe_id = pipe_id; |
| 665 | 664 | pipeline->stages = NULL; |
| 666 | − pipeline->stop_requested = false; | |
| 667 | 665 | pipeline->current_stage = NULL; |
| 668 | 666 | |
| 669 | 667 | memcpy(&pipeline->in_frame, &ia_css_default_frame, |
| @@ -2002,10 +2002,6 @@ ia_css_uninit(void) · 2001 unmodified lines | ||
| 2002 | 2002 | |
| 2003 | 2003 | sh_css_params_free_default_gdc_lut(); |
| 2004 | 2004 | |
| 2005 | − /* TODO: JB: implement decent check and handling of freeing mipi frames */ | |
| 2006 | − if (!mipi_is_free()) | |
| 2007 | − dev_warn(atomisp_dev, "mipi frames are not freed.\n"); | |
| 2008 | − | |
| 2009 | 2005 | /* cleanup generic data */ |
| 2010 | 2006 | sh_css_params_uninit(); |
| 2011 | 2007 | ia_css_refcount_uninit(); |
| @@ -3743,23 +3739,6 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, · 1731 unmodified lines | ||
| 3743 | 3739 | case IA_CSS_BUFFER_TYPE_INPUT_FRAME: |
| 3744 | 3740 | case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: |
| 3745 | 3741 | case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: |
| 3746 | − if (pipe && pipe->stop_requested) { | |
| 3747 | − if (!IS_ISP2401) { | |
| 3748 | − /* | |
| 3749 | − * free mipi frames only for old input | |
| 3750 | − * system for 2401 it is done in | |
| 3751 | − * ia_css_stream_destroy call | |
| 3752 | − */ | |
| 3753 | − return_err = free_mipi_frames(pipe); | |
| 3754 | − if (return_err) { | |
| 3755 | − IA_CSS_LOG("free_mipi_frames() failed"); | |
| 3756 | − IA_CSS_LEAVE_ERR(return_err); | |
| 3757 | − return return_err; | |
| 3758 | − } | |
| 3759 | − } | |
| 3760 | − pipe->stop_requested = false; | |
| 3761 | − } | |
| 3762 | − fallthrough; | |
| 3763 | 3742 | case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: |
| 3764 | 3743 | case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: |
| 3765 | 3744 | frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr); |
| @@ -4095,8 +4074,6 @@ sh_css_pipe_start(struct ia_css_stream *stream) · 329 unmodified lines | ||
| 4095 | 4074 | return err; |
| 4096 | 4075 | } |
| 4097 | 4076 | |
| 4098 | − pipe->stop_requested = false; | |
| 4099 | − | |
| 4100 | 4077 | switch (pipe_id) { |
| 4101 | 4078 | case IA_CSS_PIPE_ID_PREVIEW: |
| 4102 | 4079 | err = preview_start(pipe); |
| @@ -4120,19 +4097,15 @@ sh_css_pipe_start(struct ia_css_stream *stream) · 17 unmodified lines | ||
| 4120 | 4097 | for (i = 1; i < stream->num_pipes && 0 == err ; i++) { |
| 4121 | 4098 | switch (stream->pipes[i]->mode) { |
| 4122 | 4099 | case IA_CSS_PIPE_ID_PREVIEW: |
| 4123 | − stream->pipes[i]->stop_requested = false; | |
| 4124 | 4100 | err = preview_start(stream->pipes[i]); |
| 4125 | 4101 | break; |
| 4126 | 4102 | case IA_CSS_PIPE_ID_VIDEO: |
| 4127 | − stream->pipes[i]->stop_requested = false; | |
| 4128 | 4103 | err = video_start(stream->pipes[i]); |
| 4129 | 4104 | break; |
| 4130 | 4105 | case IA_CSS_PIPE_ID_CAPTURE: |
| 4131 | − stream->pipes[i]->stop_requested = false; | |
| 4132 | 4106 | err = capture_start(stream->pipes[i]); |
| 4133 | 4107 | break; |
| 4134 | 4108 | case IA_CSS_PIPE_ID_YUVPP: |
| 4135 | − stream->pipes[i]->stop_requested = false; | |
| 4136 | 4109 | err = yuvpp_start(stream->pipes[i]); |
| 4137 | 4110 | break; |
| 4138 | 4111 | default: |
| @@ -7,12 +7,12 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef _SH_CSS_DEFS_H_ |
| 8 | 8 | #define _SH_CSS_DEFS_H_ |
| 9 | 9 | |
| 10 | +#include <linux/math.h> | |
| 11 | + | |
| 10 | 12 | #include "isp.h" |
| 11 | 13 | |
| 12 | 14 | /*#include "vamem.h"*/ /* Cannot include for VAMEM properties this file is visible on ISP -> pipeline generator */ |
| 13 | 15 | |
| 14 | −#include "math_support.h" /* max(), min, etc etc */ | |
| 15 | − | |
| 16 | 16 | /* ID's for refcount */ |
| 17 | 17 | #define IA_CSS_REFCOUNT_PARAM_SET_POOL 0xCAFE0001 |
| 18 | 18 | #define IA_CSS_REFCOUNT_PARAM_BUFFER 0xCAFE0002 |
| @@ -182,7 +182,7 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] · 163 unmodified lines | ||
| 182 | 182 | The ISP firmware needs these rules to be applied at pre-processor time, |
| 183 | 183 | that's why these are macros, not functions. */ |
| 184 | 184 | #define _ISP_BQS(num) ((num) / 2) |
| 185 | −#define _ISP_VECS(width) CEIL_DIV(width, ISP_VEC_NELEMS) | |
| 185 | +#define _ISP_VECS(width) DIV_ROUND_UP(width, ISP_VEC_NELEMS) | |
| 186 | 186 | |
| 187 | 187 | #define ISP_BQ_GRID_WIDTH(elements_per_line, deci_factor_log2) \ |
| 188 | 188 | CEIL_SHIFT(elements_per_line / 2, deci_factor_log2) |
| @@ -194,9 +194,9 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] · 5 unmodified lines | ||
| 194 | 194 | /* The morphing table is similar to the shading table in the sense that we |
| 195 | 195 | have 1 more value than we have cells in the grid. */ |
| 196 | 196 | #define _ISP_MORPH_TABLE_WIDTH(int_width) \ |
| 197 | − (CEIL_DIV(int_width, SH_CSS_MORPH_TABLE_GRID) + 1) | |
| 197 | + (DIV_ROUND_UP(int_width, SH_CSS_MORPH_TABLE_GRID) + 1) | |
| 198 | 198 | #define _ISP_MORPH_TABLE_HEIGHT(int_height) \ |
| 199 | − (CEIL_DIV(int_height, SH_CSS_MORPH_TABLE_GRID) + 1) | |
| 199 | + (DIV_ROUND_UP(int_height, SH_CSS_MORPH_TABLE_GRID) + 1) | |
| 200 | 200 | #define _ISP_MORPH_TABLE_ALIGNED_WIDTH(width) \ |
| 201 | 201 | CEIL_MUL(_ISP_MORPH_TABLE_WIDTH(width), \ |
| 202 | 202 | SH_CSS_MORPH_TABLE_ELEMS_PER_DDR_WORD) |
| @@ -298,7 +298,7 @@ RGB[0,8191],coef[-8192,8191] -> RGB[0,8191] · 95 unmodified lines | ||
| 298 | 298 | c_subsampling, \ |
| 299 | 299 | num_chunks, \ |
| 300 | 300 | pipelining) \ |
| 301 | − CEIL_MUL2(CEIL_MUL2(MAX(__ISP_PADDED_OUTPUT_WIDTH(out_width, \ | |
| 301 | + round_up(round_up(MAX(__ISP_PADDED_OUTPUT_WIDTH(out_width, \ | |
| 302 | 302 | dvs_env_width, \ |
| 303 | 303 | left_crop), \ |
| 304 | 304 | __ISP_MIN_INTERNAL_WIDTH(num_chunks, \ |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #define _SH_CSS_INTERNAL_H_ |
| 9 | 9 | |
| 10 | 10 | #include <linux/build_bug.h> |
| 11 | +#include <linux/math.h> | |
| 11 | 12 | #include <linux/stdarg.h> |
| 12 | 13 | |
| 13 | 14 | #include <system_global.h> |
| @@ -95,7 +96,6 @@ · 81 unmodified lines | ||
| 95 | 96 | * the SIZE_OF_XXX macro of the corresponding struct. If they are not |
| 96 | 97 | * equal, functionality will break. |
| 97 | 98 | */ |
| 98 | −#define CALC_ALIGNMENT_MEMBER(x, y) (CEIL_MUL(x, y) - x) | |
| 99 | 99 | #define SIZE_OF_HRT_VADDRESS sizeof(hive_uint32) |
| 100 | 100 | |
| 101 | 101 | /* Number of SP's */ |
| @@ -704,13 +704,11 @@ struct sh_css_hmm_buffer { · 602 unmodified lines | ||
| 704 | 704 | |
| 705 | 705 | /* Do not use sizeof(uint64_t) since that does not exist of SP */ |
| 706 | 706 | #define SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT \ |
| 707 | − (SIZE_OF_PAYLOAD_UNION + \ | |
| 708 | − CALC_ALIGNMENT_MEMBER(SIZE_OF_PAYLOAD_UNION, 8) + \ | |
| 707 | + (round_up(SIZE_OF_PAYLOAD_UNION, 8) + \ | |
| 709 | 708 | 8 + \ |
| 710 | 709 | 8 + \ |
| 711 | 710 | SIZE_OF_IA_CSS_TIME_MEAS_STRUCT + \ |
| 712 | − SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT + \ | |
| 713 | − CALC_ALIGNMENT_MEMBER(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) | |
| 711 | + round_up(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) | |
| 714 | 712 | |
| 715 | 713 | static_assert(sizeof(struct sh_css_hmm_buffer) == SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT); |
| 716 | 714 | |
| @@ -185,17 +185,6 @@ mipi_init(void) · 184 unmodified lines | ||
| 185 | 185 | ref_count_mipi_allocation[i] = 0; |
| 186 | 186 | } |
| 187 | 187 | |
| 188 | −bool mipi_is_free(void) | |
| 189 | −{ | |
| 190 | − unsigned int i; | |
| 191 | − | |
| 192 | − for (i = 0; i < N_CSI_PORTS; i++) | |
| 193 | − if (ref_count_mipi_allocation[i]) | |
| 194 | − return false; | |
| 195 | − | |
| 196 | − return true; | |
| 197 | −} | |
| 198 | − | |
| 199 | 188 | /* |
| 200 | 189 | * @brief Calculate the required MIPI buffer sizes. |
| 201 | 190 | * Based on the stream configuration, calculate the |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | void |
| 15 | 15 | mipi_init(void); |
| 16 | 16 | |
| 17 | −bool mipi_is_free(void); | |
| 18 | − | |
| 19 | 17 | int |
| 20 | 18 | allocate_mipi_frames(struct ia_css_pipe *pipe, struct ia_css_stream_info *info); |
| 21 | 19 | |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef _SH_CSS_PARAMS_DVS_H_ |
| 8 | 8 | #define _SH_CSS_PARAMS_DVS_H_ |
| 9 | 9 | |
| 10 | +#include <linux/math.h> | |
| 11 | + | |
| 10 | 12 | #include <math_support.h> |
| 11 | 13 | #include <ia_css_types.h> |
| 12 | 14 | #include "gdc_global.h" /* gdc_warp_param_mem_t */ |
| @@ -20,22 +22,20 @@ · 7 unmodified lines | ||
| 20 | 22 | |
| 21 | 23 | /* ISP2400 */ |
| 22 | 24 | /* horizontal 64x64 blocks round up to DVS_BLOCKDIM_X, make even */ |
| 23 | −#define DVS_NUM_BLOCKS_X(X) (CEIL_MUL(CEIL_DIV((X), DVS_BLOCKDIM_X), 2)) | |
| 25 | +#define DVS_NUM_BLOCKS_X(X) round_up(DIV_ROUND_UP((X), DVS_BLOCKDIM_X), 2) | |
| 26 | +#define DVS_NUM_BLOCKS_X_CHROMA(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_X) | |
| 24 | 27 | |
| 25 | 28 | /* ISP2400 */ |
| 26 | 29 | /* vertical 64x64 blocks round up to DVS_BLOCKDIM_Y */ |
| 27 | −#define DVS_NUM_BLOCKS_Y(X) (CEIL_DIV((X), DVS_BLOCKDIM_Y_LUMA)) | |
| 28 | −#define DVS_NUM_BLOCKS_X_CHROMA(X) (CEIL_DIV((X), DVS_BLOCKDIM_X)) | |
| 29 | −#define DVS_NUM_BLOCKS_Y_CHROMA(X) (CEIL_DIV((X), DVS_BLOCKDIM_Y_CHROMA)) | |
| 30 | +#define DVS_NUM_BLOCKS_Y(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_LUMA) | |
| 31 | +#define DVS_NUM_BLOCKS_Y_CHROMA(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_CHROMA) | |
| 30 | 32 | |
| 31 | −#define DVS_TABLE_IN_BLOCKDIM_X_LUMA(X) (DVS_NUM_BLOCKS_X(X) + 1) /* N blocks have N + 1 set of coords */ | |
| 32 | −#define DVS_TABLE_IN_BLOCKDIM_X_CHROMA(X) (DVS_NUM_BLOCKS_X_CHROMA(X) + 1) | |
| 33 | +/* N blocks have N + 1 set of coords */ | |
| 34 | +#define DVS_TABLE_IN_BLOCKDIM_X_LUMA(X) (DVS_NUM_BLOCKS_X(X) + 1) | |
| 35 | +#define DVS_TABLE_IN_BLOCKDIM_X_CHROMA(X) (DVS_NUM_BLOCKS_X_CHROMA(X) + 1) | |
| 33 | 36 | #define DVS_TABLE_IN_BLOCKDIM_Y_LUMA(X) (DVS_NUM_BLOCKS_Y(X) + 1) |
| 34 | 37 | #define DVS_TABLE_IN_BLOCKDIM_Y_CHROMA(X) (DVS_NUM_BLOCKS_Y_CHROMA(X) + 1) |
| 35 | 38 | |
| 36 | −#define DVS_ENVELOPE_X(X) (((X) == 0) ? (DVS_ENV_MIN_X) : (X)) | |
| 37 | −#define DVS_ENVELOPE_Y(X) (((X) == 0) ? (DVS_ENV_MIN_Y) : (X)) | |
| 38 | − | |
| 39 | 39 | #define DVS_COORD_FRAC_BITS (10) |
| 40 | 40 | |
| 41 | 41 | /* ISP2400 */ |
| @@ -43,8 +43,8 @@ · 1 unmodified line | ||
| 43 | 43 | |
| 44 | 44 | #define XMEM_ALIGN_LOG2 (5) |
| 45 | 45 | |
| 46 | −#define DVS_6AXIS_COORDS_ELEMS CEIL_MUL(sizeof(gdc_warp_param_mem_t) \ | |
| 47 | − , HIVE_ISP_DDR_WORD_BYTES) | |
| 46 | +#define DVS_6AXIS_COORDS_ELEMS \ | |
| 47 | + round_up(sizeof(gdc_warp_param_mem_t), HIVE_ISP_DDR_WORD_BYTES) | |
| 48 | 48 | |
| 49 | 49 | /* currently we only support two output with the same resolution, output 0 is th default one. */ |
| 50 | 50 | #define DVS_6AXIS_BYTES(binary) \ |
| @@ -4,6 +4,8 @@ · 3 unmodified lines | ||
| 4 | 4 | * Copyright (c) 2015, Intel Corporation. |
| 5 | 5 | */ |
| 6 | 6 | |
| 7 | +#include <linux/math.h> | |
| 8 | + | |
| 7 | 9 | #include "gdc_device.h" /* gdc_lut_store(), ... */ |
| 8 | 10 | #include "isp.h" /* ISP_VEC_ELEMBITS */ |
| 9 | 11 | #include "vamem.h" |
| @@ -21,8 +23,6 @@ · 11 unmodified lines | ||
| 21 | 23 | |
| 22 | 24 | #include "platform_support.h" |
| 23 | 25 | #include "assert_support.h" |
| 24 | −#include "misc_support.h" /* NOT_USED */ | |
| 25 | −#include "math_support.h" /* max(), min() EVEN_FLOOR()*/ | |
| 26 | 26 | |
| 27 | 27 | #include "ia_css_stream.h" |
| 28 | 28 | #include "sh_css_params_internal.h" |
| @@ -4042,10 +4042,10 @@ sh_css_update_uds_and_crop_info( · 4013 unmodified lines | ||
| 4042 | 4042 | } |
| 4043 | 4043 | |
| 4044 | 4044 | /* Must enforce that the crop position is even */ |
| 4045 | − crop_x = EVEN_FLOOR(crop_x); | |
| 4046 | − crop_y = EVEN_FLOOR(crop_y); | |
| 4047 | − uds_xc = EVEN_FLOOR(uds_xc); | |
| 4048 | − uds_yc = EVEN_FLOOR(uds_yc); | |
| 4045 | + crop_x = round_down(crop_x, 2); | |
| 4046 | + crop_y = round_down(crop_y, 2); | |
| 4047 | + uds_xc = round_down(uds_xc, 2); | |
| 4048 | + uds_yc = round_down(uds_yc, 2); | |
| 4049 | 4049 | |
| 4050 | 4050 | uds->xc = (uint16_t)uds_xc; |
| 4051 | 4051 | uds->yc = (uint16_t)uds_yc; |
| @@ -912,7 +912,7 @@ imx_media_csc_scaler_device_init(struct imx_media_dev *md) · 911 unmodified lines | ||
| 912 | 912 | return &priv->vdev; |
| 913 | 913 | |
| 914 | 914 | err_m2m: |
| 915 | − video_set_drvdata(vfd, NULL); | |
| 915 | + video_device_release(vfd); | |
| 916 | 916 | err_vfd: |
| 917 | 917 | kfree(priv); |
| 918 | 918 | return ERR_PTR(ret); |
| @@ -0,0 +1,19 @@ | ||
| 1 | +config VIDEO_INTEL_IPU7 | |
| 2 | + tristate "Intel IPU7 driver" | |
| 3 | + depends on ACPI || COMPILE_TEST | |
| 4 | + depends on VIDEO_DEV | |
| 5 | + depends on X86 && HAS_DMA | |
| 6 | + depends on IPU_BRIDGE || !IPU_BRIDGE | |
| 7 | + depends on PCI | |
| 8 | + select AUXILIARY_BUS | |
| 9 | + select IOMMU_IOVA | |
| 10 | + select VIDEO_V4L2_SUBDEV_API | |
| 11 | + select MEDIA_CONTROLLER | |
| 12 | + select VIDEOBUF2_DMA_SG | |
| 13 | + select V4L2_FWNODE | |
| 14 | + help | |
| 15 | + This is the 7th Gen Intel Image Processing Unit, found in Intel SoCs | |
| 16 | + and used for capturing images and video from camera sensors. | |
| 17 | + | |
| 18 | + To compile this driver, say Y here! It contains 2 modules - | |
| 19 | + intel_ipu7 and intel_ipu7_isys. | |
| @@ -0,0 +1,23 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +# Copyright (c) 2017 - 2025 Intel Corporation. | |
| 3 | + | |
| 4 | +intel-ipu7-objs += ipu7.o \ | |
| 5 | + ipu7-bus.o \ | |
| 6 | + ipu7-dma.o \ | |
| 7 | + ipu7-mmu.o \ | |
| 8 | + ipu7-buttress.o \ | |
| 9 | + ipu7-cpd.o \ | |
| 10 | + ipu7-syscom.o \ | |
| 11 | + ipu7-boot.o | |
| 12 | + | |
| 13 | +obj-$(CONFIG_VIDEO_INTEL_IPU7) += intel-ipu7.o | |
| 14 | + | |
| 15 | +intel-ipu7-isys-objs += ipu7-isys.o \ | |
| 16 | + ipu7-isys-csi2.o \ | |
| 17 | + ipu7-isys-csi-phy.o \ | |
| 18 | + ipu7-fw-isys.o \ | |
| 19 | + ipu7-isys-video.o \ | |
| 20 | + ipu7-isys-queue.o \ | |
| 21 | + ipu7-isys-subdev.o | |
| 22 | + | |
| 23 | +obj-$(CONFIG_VIDEO_INTEL_IPU7) += intel-ipu7-isys.o | |
| @@ -0,0 +1,28 @@ | ||
| 1 | +This is a list of things that need to be done to get this driver out of the | |
| 2 | +staging directory. | |
| 3 | + | |
| 4 | +- ABI headers cleanup | |
| 5 | + Cleanup the firmware ABI headers | |
| 6 | + | |
| 7 | +- Add metadata capture support | |
| 8 | + The IPU7 hardware should support metadata capture, but it is not | |
| 9 | + fully verified with IPU7 firmware ABI so far, need to add the metadata | |
| 10 | + capture support. | |
| 11 | + | |
| 12 | +- Refine CSI2 PHY code | |
| 13 | + Refine the ipu7-isys-csi2-phy.c, move the hardware specific variant | |
| 14 | + into structure, clarify and explain the PHY registers to make it more | |
| 15 | + readable. | |
| 16 | + | |
| 17 | +- Work with the common IPU module | |
| 18 | + Sakari commented much of the driver code is the same than the IPU6 driver. | |
| 19 | + IPU7 driver is expected to work with the common IPU module in future. | |
| 20 | + | |
| 21 | +- Register definition cleanup | |
| 22 | + Cleanup the register definitions - remove some unnecessary definitions | |
| 23 | + remove 'U' suffix for hexadecimal and decimal values and add IPU7 prefix | |
| 24 | + for IPU7 specific registers. | |
| 25 | + Some ISYS IO sub-blocks register definitions are offset values from | |
| 26 | + specific sub-block base, but it is not clear and well suited for driver | |
| 27 | + to use, need to update the register definitions to make it more clear | |
| 28 | + and readable. | |
| @@ -0,0 +1,163 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2020 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_BOOT_ABI_H | |
| 7 | +#define IPU7_FW_BOOT_ABI_H | |
| 8 | + | |
| 9 | +#include "ipu7_fw_common_abi.h" | |
| 10 | +#include "ipu7_fw_syscom_abi.h" | |
| 11 | + | |
| 12 | +#define IA_GOFO_FWLOG_SEVERITY_CRIT (0U) | |
| 13 | +#define IA_GOFO_FWLOG_SEVERITY_ERROR (1U) | |
| 14 | +#define IA_GOFO_FWLOG_SEVERITY_WARNING (2U) | |
| 15 | +#define IA_GOFO_FWLOG_SEVERITY_INFO (3U) | |
| 16 | +#define IA_GOFO_FWLOG_SEVERITY_DEBUG (4U) | |
| 17 | +#define IA_GOFO_FWLOG_SEVERITY_VERBOSE (5U) | |
| 18 | +#define IA_GOFO_FWLOG_MAX_LOGGER_SOURCES (64U) | |
| 19 | + | |
| 20 | +#define LOGGER_CONFIG_CHANNEL_ENABLE_HWPRINTF_BITMASK BIT(0) | |
| 21 | +#define LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK BIT(1) | |
| 22 | +#define LOGGER_CONFIG_CHANNEL_ENABLE_ALL_BITMASK \ | |
| 23 | + (LOGGER_CONFIG_CHANNEL_ENABLE_HWPRINTF_BITMASK | \ | |
| 24 | + LOGGER_CONFIG_CHANNEL_ENABLE_SYSCOM_BITMASK) | |
| 25 | + | |
| 26 | +struct ia_gofo_logger_config { | |
| 27 | + u8 use_source_severity; | |
| 28 | + u8 source_severity[IA_GOFO_FWLOG_MAX_LOGGER_SOURCES]; | |
| 29 | + u8 use_channels_enable_bitmask; | |
| 30 | + u8 channels_enable_bitmask; | |
| 31 | + u8 padding[1]; | |
| 32 | + ia_gofo_addr_t hw_printf_buffer_base_addr; | |
| 33 | + u32 hw_printf_buffer_size_bytes; | |
| 34 | +}; | |
| 35 | + | |
| 36 | +#pragma pack(push, 1) | |
| 37 | + | |
| 38 | +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP \ | |
| 39 | + ((u32)IA_GOFO_FW_BOOT_ID_MAX) | |
| 40 | +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_IS_OFFSET (0U) | |
| 41 | +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_PS_OFFSET \ | |
| 42 | + ((IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_IS_OFFSET) + \ | |
| 43 | + (u32)(IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP)) | |
| 44 | +#define IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_PRIMARY_OFFSET (0U) | |
| 45 | +#define IA_GOFO_CCG_IPU_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET (0x3000U / 4U) | |
| 46 | +#define IA_GOFO_HKR_IPU_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET \ | |
| 47 | + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 2U) | |
| 48 | +#define IA_GOFO_HKR_HIF_BUTTRESS_FW_BOOT_PARAMS_SECONDARY_OFFSET \ | |
| 49 | + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP) | |
| 50 | +#define IA_GOFO_CCG_IPU_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX \ | |
| 51 | + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 4U) | |
| 52 | +#define IA_GOFO_HKR_IPU_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX \ | |
| 53 | + (IA_GOFO_BUTTRESS_FW_BOOT_PARAMS_MAX_REG_IDX_PER_APP * 4U) | |
| 54 | + | |
| 55 | +#define IA_GOFO_BOOT_RESERVED_SIZE (58U) | |
| 56 | +#define IA_GOFO_BOOT_SECONDARY_RESERVED_SIZE (IA_GOFO_BOOT_RESERVED_SIZE) | |
| 57 | +#define IA_GOFO_BOOT_SECONDARY_RESERVED_FIELDS \ | |
| 58 | + (sizeof(ia_gofo_addr_t) + sizeof(ia_gofo_addr_t) + sizeof(u32)) | |
| 59 | + | |
| 60 | +enum ia_gofo_buttress_reg_id { | |
| 61 | + IA_GOFO_FW_BOOT_CONFIG_ID = 0, | |
| 62 | + IA_GOFO_FW_BOOT_STATE_ID = 1, | |
| 63 | + IA_GOFO_FW_BOOT_RESERVED1_ID = IA_GOFO_FW_BOOT_STATE_ID, | |
| 64 | + IA_GOFO_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID = 2, | |
| 65 | + IA_GOFO_FW_BOOT_UNTRUSTED_ADDR_MIN_ID = 3, | |
| 66 | + IA_GOFO_FW_BOOT_RESERVED0_ID = IA_GOFO_FW_BOOT_UNTRUSTED_ADDR_MIN_ID, | |
| 67 | + IA_GOFO_FW_BOOT_MESSAGING_VERSION_ID = 4, | |
| 68 | + IA_GOFO_FW_BOOT_ID_MAX | |
| 69 | +}; | |
| 70 | + | |
| 71 | +enum ia_gofo_boot_uc_tile_frequency_units { | |
| 72 | + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_MHZ = 0, | |
| 73 | + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_HZ = 1, | |
| 74 | + IA_GOFO_FW_BOOT_UC_FREQUENCY_UNITS_N | |
| 75 | +}; | |
| 76 | + | |
| 77 | +#define IA_GOFO_FW_BOOT_STATE_IS_CRITICAL(boot_state) \ | |
| 78 | + (0xdead0000U == ((boot_state) & 0xffff0000U)) | |
| 79 | + | |
| 80 | +struct ia_gofo_boot_config { | |
| 81 | + u32 length; | |
| 82 | + struct ia_gofo_version_s config_version; | |
| 83 | + struct ia_gofo_msg_version_list client_version_support; | |
| 84 | + ia_gofo_addr_t pkg_dir; | |
| 85 | + ia_gofo_addr_t subsys_config; | |
| 86 | + u32 uc_tile_frequency; | |
| 87 | + u16 checksum; | |
| 88 | + u8 uc_tile_frequency_units; | |
| 89 | + u8 padding[1]; | |
| 90 | + u32 reserved[IA_GOFO_BOOT_RESERVED_SIZE]; | |
| 91 | + struct syscom_config_s syscom_context_config; | |
| 92 | +}; | |
| 93 | + | |
| 94 | +struct ia_gofo_secondary_boot_config { | |
| 95 | + u32 length; | |
| 96 | + struct ia_gofo_version_s config_version; | |
| 97 | + struct ia_gofo_msg_version_list client_version_support; | |
| 98 | + u8 reserved1[IA_GOFO_BOOT_SECONDARY_RESERVED_FIELDS]; | |
| 99 | + u16 checksum; | |
| 100 | + u8 padding[2]; | |
| 101 | + u32 reserved2[IA_GOFO_BOOT_SECONDARY_RESERVED_SIZE]; | |
| 102 | + struct syscom_config_s syscom_context_config; | |
| 103 | +}; | |
| 104 | + | |
| 105 | +#pragma pack(pop) | |
| 106 | + | |
| 107 | +#define IA_GOFO_WDT_TIMEOUT_ERR 0xdead0401U | |
| 108 | +#define IA_GOFO_MEM_FATAL_DME_ERR 0xdead0801U | |
| 109 | +#define IA_GOFO_MEM_UNCORRECTABLE_LOCAL_ERR 0xdead0802U | |
| 110 | +#define IA_GOFO_MEM_UNCORRECTABLE_DIRTY_ERR 0xdead0803U | |
| 111 | +#define IA_GOFO_MEM_UNCORRECTABLE_DTAG_ERR 0xdead0804U | |
| 112 | +#define IA_GOFO_MEM_UNCORRECTABLE_CACHE_ERR 0xdead0805U | |
| 113 | +#define IA_GOFO_DOUBLE_EXCEPTION_ERR 0xdead0806U | |
| 114 | +#define IA_GOFO_BIST_DMEM_FAULT_DETECTION_ERR 0xdead1000U | |
| 115 | +#define IA_GOFO_BIST_DATA_INTEGRITY_FAILURE 0xdead1010U | |
| 116 | + | |
| 117 | +enum ia_gofo_boot_state { | |
| 118 | + IA_GOFO_FW_BOOT_STATE_SECONDARY_BOOT_CONFIG_READY = 0x57a7b000U, | |
| 119 | + IA_GOFO_FW_BOOT_STATE_UNINIT = 0x57a7e000U, | |
| 120 | + IA_GOFO_FW_BOOT_STATE_STARTING_0 = 0x57a7d000U, | |
| 121 | + IA_GOFO_FW_BOOT_STATE_CACHE_INIT_DONE = 0x57a7d010U, | |
| 122 | + IA_GOFO_FW_BOOT_STATE_MEM_INIT_DONE = 0x57a7d020U, | |
| 123 | + IA_GOFO_FW_BOOT_STATE_STACK_INIT_DONE = 0x57a7d030U, | |
| 124 | + IA_GOFO_FW_BOOT_STATE_EARLY_BOOT_DONE = 0x57a7d100U, | |
| 125 | + IA_GOFO_FW_BOOT_STATE_BOOT_CONFIG_START = 0x57a7d200U, | |
| 126 | + IA_GOFO_FW_BOOT_STATE_QUEUE_INIT_DONE = 0x57a7d300U, | |
| 127 | + IA_GOFO_FW_BOOT_STATE_READY = 0x57a7e100U, | |
| 128 | + IA_GOFO_FW_BOOT_STATE_CRIT_UNSPECIFIED = 0xdead0001U, | |
| 129 | + IA_GOFO_FW_BOOT_STATE_CRIT_CFG_PTR = 0xdead0101U, | |
| 130 | + IA_GOFO_FW_BOOT_STATE_CRIT_CFG_VERSION = 0xdead0201U, | |
| 131 | + IA_GOFO_FW_BOOT_STATE_CRIT_MSG_VERSION = 0xdead0301U, | |
| 132 | + IA_GOFO_FW_BOOT_STATE_CRIT_WDT_TIMEOUT = IA_GOFO_WDT_TIMEOUT_ERR, | |
| 133 | + IA_GOFO_FW_BOOT_STATE_WRONG_DATA_SECTION_UNPACKING = 0xdead0501U, | |
| 134 | + IA_GOFO_FW_BOOT_STATE_WRONG_RO_DATA_SECTION_UNPACKING = 0xdead0601U, | |
| 135 | + IA_GOFO_FW_BOOT_STATE_INVALID_UNTRUSTED_ADDR_MIN = 0xdead0701U, | |
| 136 | + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_FATAL_DME = IA_GOFO_MEM_FATAL_DME_ERR, | |
| 137 | + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_LOCAL = | |
| 138 | + IA_GOFO_MEM_UNCORRECTABLE_LOCAL_ERR, | |
| 139 | + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_DIRTY = | |
| 140 | + IA_GOFO_MEM_UNCORRECTABLE_DIRTY_ERR, | |
| 141 | + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_DTAG = | |
| 142 | + IA_GOFO_MEM_UNCORRECTABLE_DTAG_ERR, | |
| 143 | + IA_GOFO_FW_BOOT_STATE_CRIT_MEM_UNCORRECTABLE_CACHE = | |
| 144 | + IA_GOFO_MEM_UNCORRECTABLE_CACHE_ERR, | |
| 145 | + IA_GOFO_FW_BOOT_STATE_CRIT_DOUBLE_EXCEPTION = | |
| 146 | + IA_GOFO_DOUBLE_EXCEPTION_ERR, | |
| 147 | + IA_GOFO_FW_BOOT_STATE_CRIT_BIST_DMEM_FAULT_DETECTION_ERR = | |
| 148 | + IA_GOFO_BIST_DMEM_FAULT_DETECTION_ERR, | |
| 149 | + IA_GOFO_FW_BOOT_STATE_CRIT_DATA_INTEGRITY_FAILURE = 0xdead1010U, | |
| 150 | + IA_GOFO_FW_BOOT_STATE_CRIT_STACK_CHK_FAILURE = 0xdead1011U, | |
| 151 | + IA_GOFO_FW_BOOT_STATE_CRIT_SYSCOM_CONTEXT_INTEGRITY_FAILURE = | |
| 152 | + 0xdead1012U, | |
| 153 | + IA_GOFO_FW_BOOT_STATE_CRIT_MPU_CONFIG_FAILURE = 0xdead1013U, | |
| 154 | + IA_GOFO_FW_BOOT_STATE_CRIT_SHARED_BUFFER_FAILURE = 0xdead1014U, | |
| 155 | + IA_GOFO_FW_BOOT_STATE_CRIT_CMEM_FAILURE = 0xdead1015U, | |
| 156 | + IA_GOFO_FW_BOOT_STATE_SHUTDOWN_CMD = 0x57a7f001U, | |
| 157 | + IA_GOFO_FW_BOOT_STATE_SHUTDOWN_START = 0x57a7e200U, | |
| 158 | + IA_GOFO_FW_BOOT_STATE_INACTIVE = 0x57a7e300U, | |
| 159 | + IA_GOFO_FW_BOOT_HW_CMD_ACK_TIMEOUT = 0x57a7e400U, | |
| 160 | + IA_GOFO_FW_BOOT_SYSTEM_CYCLES_ERROR = 0x57a7e500U | |
| 161 | +}; | |
| 162 | + | |
| 163 | +#endif | |
| @@ -0,0 +1,175 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2020 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_COMMOM_ABI_H | |
| 7 | +#define IPU7_FW_COMMOM_ABI_H | |
| 8 | + | |
| 9 | +#include <linux/types.h> | |
| 10 | + | |
| 11 | +#pragma pack(push, 1) | |
| 12 | +typedef u32 ia_gofo_addr_t; | |
| 13 | + | |
| 14 | +#define IA_GOFO_ADDR_NULL (0U) | |
| 15 | + | |
| 16 | +struct ia_gofo_version_s { | |
| 17 | + u8 patch; | |
| 18 | + u8 subminor; | |
| 19 | + u8 minor; | |
| 20 | + u8 major; | |
| 21 | +}; | |
| 22 | + | |
| 23 | +#define IA_GOFO_MSG_VERSION_INIT(major_val, minor_val, subminor_val, patch_val)\ | |
| 24 | + {.major = (major_val), .minor = (minor_val), .subminor = \ | |
| 25 | + (subminor_val), .patch = (patch_val)} | |
| 26 | + | |
| 27 | +#define IA_GOFO_MSG_VERSION_LIST_MAX_ENTRIES (3U) | |
| 28 | +#define IA_GOFO_MSG_RESERVED_SIZE (3U) | |
| 29 | + | |
| 30 | +struct ia_gofo_msg_version_list { | |
| 31 | + u8 num_versions; | |
| 32 | + u8 reserved[IA_GOFO_MSG_RESERVED_SIZE]; | |
| 33 | + struct ia_gofo_version_s versions[IA_GOFO_MSG_VERSION_LIST_MAX_ENTRIES]; | |
| 34 | +}; | |
| 35 | + | |
| 36 | +#pragma pack(pop) | |
| 37 | + | |
| 38 | +#define TLV_TYPE_PADDING (0U) | |
| 39 | + | |
| 40 | +#pragma pack(push, 1) | |
| 41 | + | |
| 42 | +#define IA_GOFO_ABI_BITS_PER_BYTE (8U) | |
| 43 | + | |
| 44 | +struct ia_gofo_tlv_header { | |
| 45 | + u16 tlv_type; | |
| 46 | + u16 tlv_len32; | |
| 47 | +}; | |
| 48 | + | |
| 49 | +struct ia_gofo_tlv_list { | |
| 50 | + u16 num_elems; | |
| 51 | + u16 head_offset; | |
| 52 | +}; | |
| 53 | + | |
| 54 | +#define TLV_ITEM_ALIGNMENT ((u32)sizeof(u32)) | |
| 55 | +#define TLV_MSG_ALIGNMENT ((u32)sizeof(u64)) | |
| 56 | +#define TLV_LIST_ALIGNMENT TLV_ITEM_ALIGNMENT | |
| 57 | +#pragma pack(pop) | |
| 58 | + | |
| 59 | +#define IA_GOFO_MODULO(dividend, divisor) ((dividend) % (divisor)) | |
| 60 | + | |
| 61 | +#define IA_GOFO_MSG_ERR_MAX_DETAILS (4U) | |
| 62 | +#define IA_GOFO_MSG_ERR_OK (0U) | |
| 63 | +#define IA_GOFO_MSG_ERR_UNSPECIFED (0xffffffffU) | |
| 64 | +#define IA_GOFO_MSG_ERR_GROUP_UNSPECIFIED (0U) | |
| 65 | +#define IA_GOFO_MSG_ERR_IS_OK(err) (IA_GOFO_MSG_ERR_OK == (err).err_code) | |
| 66 | + | |
| 67 | +#pragma pack(push, 1) | |
| 68 | +struct ia_gofo_msg_err { | |
| 69 | + u32 err_group; | |
| 70 | + u32 err_code; | |
| 71 | + u32 err_detail[IA_GOFO_MSG_ERR_MAX_DETAILS]; | |
| 72 | +}; | |
| 73 | + | |
| 74 | +#pragma pack(pop) | |
| 75 | + | |
| 76 | +#define IA_GOFO_MSG_ERR_GROUP_APP_EXT_START (16U) | |
| 77 | +#define IA_GOFO_MSG_ERR_GROUP_MAX (31U) | |
| 78 | +#define IA_GOFO_MSG_ERR_GROUP_INTERNAL_START (IA_GOFO_MSG_ERR_GROUP_MAX + 1U) | |
| 79 | +#define IA_GOFO_MSG_ERR_GROUP_RESERVED IA_GOFO_MSG_ERR_GROUP_UNSPECIFIED | |
| 80 | +#define IA_GOFO_MSG_ERR_GROUP_GENERAL 1 | |
| 81 | + | |
| 82 | +enum ia_gofo_msg_err_general { | |
| 83 | + IA_GOFO_MSG_ERR_GENERAL_OK = IA_GOFO_MSG_ERR_OK, | |
| 84 | + IA_GOFO_MSG_ERR_GENERAL_MSG_TOO_SMALL = 1, | |
| 85 | + IA_GOFO_MSG_ERR_GENERAL_MSG_TOO_LARGE = 2, | |
| 86 | + IA_GOFO_MSG_ERR_GENERAL_DEVICE_STATE = 3, | |
| 87 | + IA_GOFO_MSG_ERR_GENERAL_ALIGNMENT = 4, | |
| 88 | + IA_GOFO_MSG_ERR_GENERAL_INDIRECT_REF_PTR_INVALID = 5, | |
| 89 | + IA_GOFO_MSG_ERR_GENERAL_INVALID_MSG_TYPE = 6, | |
| 90 | + IA_GOFO_MSG_ERR_GENERAL_SYSCOM_FAIL = 7, | |
| 91 | + IA_GOFO_MSG_ERR_GENERAL_N | |
| 92 | +}; | |
| 93 | + | |
| 94 | +#pragma pack(push, 1) | |
| 95 | +#define IA_GOFO_MSG_TYPE_RESERVED 0 | |
| 96 | +#define IA_GOFO_MSG_TYPE_INDIRECT 1 | |
| 97 | +#define IA_GOFO_MSG_TYPE_LOG 2 | |
| 98 | +#define IA_GOFO_MSG_TYPE_GENERAL_ERR 3 | |
| 99 | + | |
| 100 | +struct ia_gofo_msg_header { | |
| 101 | + struct ia_gofo_tlv_header tlv_header; | |
| 102 | + struct ia_gofo_tlv_list msg_options; | |
| 103 | + u64 user_token; | |
| 104 | +}; | |
| 105 | + | |
| 106 | +struct ia_gofo_msg_header_ack { | |
| 107 | + struct ia_gofo_msg_header header; | |
| 108 | + struct ia_gofo_msg_err err; | |
| 109 | + | |
| 110 | +}; | |
| 111 | + | |
| 112 | +struct ia_gofo_msg_general_err { | |
| 113 | + struct ia_gofo_msg_header_ack header; | |
| 114 | +}; | |
| 115 | + | |
| 116 | +#pragma pack(pop) | |
| 117 | + | |
| 118 | +#pragma pack(push, 1) | |
| 119 | +enum ia_gofo_msg_link_streaming_mode { | |
| 120 | + IA_GOFO_MSG_LINK_STREAMING_MODE_SOFF = 0, | |
| 121 | + IA_GOFO_MSG_LINK_STREAMING_MODE_DOFF = 1, | |
| 122 | + IA_GOFO_MSG_LINK_STREAMING_MODE_BCLM = 2, | |
| 123 | + IA_GOFO_MSG_LINK_STREAMING_MODE_BCSM_FIX = 3, | |
| 124 | + IA_GOFO_MSG_LINK_STREAMING_MODE_N | |
| 125 | +}; | |
| 126 | + | |
| 127 | +enum ia_gofo_soc_pbk_instance_id { | |
| 128 | + IA_GOFO_SOC_PBK_ID0 = 0, | |
| 129 | + IA_GOFO_SOC_PBK_ID1 = 1, | |
| 130 | + IA_GOFO_SOC_PBK_ID_N | |
| 131 | +}; | |
| 132 | + | |
| 133 | +#define IA_GOFO_MSG_LINK_PBK_MAX_SLOTS (2U) | |
| 134 | + | |
| 135 | +struct ia_gofo_msg_indirect { | |
| 136 | + struct ia_gofo_msg_header header; | |
| 137 | + struct ia_gofo_tlv_header ref_header; | |
| 138 | + ia_gofo_addr_t ref_msg_ptr; | |
| 139 | +}; | |
| 140 | + | |
| 141 | +#pragma pack(pop) | |
| 142 | + | |
| 143 | +#pragma pack(push, 1) | |
| 144 | +#define IA_GOFO_MSG_LOG_MAX_PARAMS (4U) | |
| 145 | +#define IA_GOFO_MSG_LOG_DOC_FMT_ID_MIN (0U) | |
| 146 | + | |
| 147 | +#define IA_GOFO_MSG_LOG_DOC_FMT_ID_MAX (4095U) | |
| 148 | +#define IA_GOFO_MSG_LOG_FMT_ID_INVALID (0xfffffffU) | |
| 149 | + | |
| 150 | +struct ia_gofo_msg_log_info { | |
| 151 | + u16 log_counter; | |
| 152 | + u8 msg_parameter_types; | |
| 153 | + /* [0:0] is_out_of_order, [1:3] logger_channel, [4:7] reserved */ | |
| 154 | + u8 logger_opts; | |
| 155 | + u32 fmt_id; | |
| 156 | + u32 params[IA_GOFO_MSG_LOG_MAX_PARAMS]; | |
| 157 | +}; | |
| 158 | + | |
| 159 | +struct ia_gofo_msg_log_info_ts { | |
| 160 | + u64 msg_ts; | |
| 161 | + struct ia_gofo_msg_log_info log_info; | |
| 162 | +}; | |
| 163 | + | |
| 164 | +struct ia_gofo_msg_log { | |
| 165 | + struct ia_gofo_msg_header header; | |
| 166 | + struct ia_gofo_msg_log_info_ts log_info_ts; | |
| 167 | +}; | |
| 168 | + | |
| 169 | +#pragma pack(pop) | |
| 170 | + | |
| 171 | +#define IA_GOFO_MSG_ABI_OUT_ACK_QUEUE_ID (0U) | |
| 172 | +#define IA_GOFO_MSG_ABI_OUT_LOG_QUEUE_ID (1U) | |
| 173 | +#define IA_GOFO_MSG_ABI_IN_DEV_QUEUE_ID (2U) | |
| 174 | + | |
| 175 | +#endif | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2021 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_CONFIG_ABI_H | |
| 7 | +#define IPU7_FW_CONFIG_ABI_H | |
| 8 | + | |
| 9 | +#include <linux/types.h> | |
| 10 | + | |
| 11 | +#define IPU_CONFIG_ABI_WDT_TIMER_DISABLED 0U | |
| 12 | +#define IPU_CONFIG_ABI_CMD_TIMER_DISABLED 0U | |
| 13 | + | |
| 14 | +struct ipu7_wdt_abi { | |
| 15 | + u32 wdt_timer1_us; | |
| 16 | + u32 wdt_timer2_us; | |
| 17 | +}; | |
| 18 | + | |
| 19 | +#endif | |
| @@ -0,0 +1,19 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2021 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_INSYS_CONFIG_ABI_H | |
| 7 | +#define IPU7_FW_INSYS_CONFIG_ABI_H | |
| 8 | + | |
| 9 | +#include "ipu7_fw_boot_abi.h" | |
| 10 | +#include "ipu7_fw_config_abi.h" | |
| 11 | +#include "ipu7_fw_isys_abi.h" | |
| 12 | + | |
| 13 | +struct ipu7_insys_config { | |
| 14 | + u32 timeout_val_ms; | |
| 15 | + struct ia_gofo_logger_config logger_config; | |
| 16 | + struct ipu7_wdt_abi wdt_config; | |
| 17 | +}; | |
| 18 | + | |
| 19 | +#endif | |
| @@ -0,0 +1,412 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2020 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_ISYS_ABI_H | |
| 7 | +#define IPU7_FW_ISYS_ABI_H | |
| 8 | + | |
| 9 | +#include "ipu7_fw_common_abi.h" | |
| 10 | +#include "ipu7_fw_isys_abi.h" | |
| 11 | + | |
| 12 | +#define IPU_INSYS_MAX_OUTPUT_QUEUES (3U) | |
| 13 | +#define IPU_INSYS_STREAM_ID_MAX (16U) | |
| 14 | + | |
| 15 | +#define IPU_INSYS_MAX_INPUT_QUEUES (IPU_INSYS_STREAM_ID_MAX + 1U) | |
| 16 | +#define IPU_INSYS_OUTPUT_FIRST_QUEUE (0U) | |
| 17 | +#define IPU_INSYS_OUTPUT_LAST_QUEUE (IPU_INSYS_MAX_OUTPUT_QUEUES - 1U) | |
| 18 | +#define IPU_INSYS_OUTPUT_MSG_QUEUE (IPU_INSYS_OUTPUT_FIRST_QUEUE) | |
| 19 | +#define IPU_INSYS_OUTPUT_LOG_QUEUE (IPU_INSYS_OUTPUT_FIRST_QUEUE + 1U) | |
| 20 | +#define IPU_INSYS_OUTPUT_RESERVED_QUEUE (IPU_INSYS_OUTPUT_LAST_QUEUE) | |
| 21 | +#define IPU_INSYS_INPUT_FIRST_QUEUE (IPU_INSYS_MAX_OUTPUT_QUEUES) | |
| 22 | +#define IPU_INSYS_INPUT_LAST_QUEUE \ | |
| 23 | + (IPU_INSYS_INPUT_FIRST_QUEUE + IPU_INSYS_MAX_INPUT_QUEUES - 1U) | |
| 24 | +#define IPU_INSYS_INPUT_DEV_QUEUE (IPU_INSYS_INPUT_FIRST_QUEUE) | |
| 25 | +#define IPU_INSYS_INPUT_MSG_QUEUE (IPU_INSYS_INPUT_FIRST_QUEUE + 1U) | |
| 26 | +#define IPU_INSYS_INPUT_MSG_MAX_QUEUE (IPU_INSYS_MAX_INPUT_QUEUES - 1U) | |
| 27 | + | |
| 28 | +#define MAX_OPINS_FOR_SINGLE_IPINS (3U) | |
| 29 | +#define DEV_SEND_QUEUE_SIZE (IPU_INSYS_STREAM_ID_MAX) | |
| 30 | + | |
| 31 | +#define PIN_PLANES_MAX (4U) | |
| 32 | + | |
| 33 | +#define INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES_INPUT \ | |
| 34 | + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES | |
| 35 | + | |
| 36 | +typedef u64 ipu7_insys_return_token; | |
| 37 | + | |
| 38 | +enum ipu7_insys_resp_type { | |
| 39 | + IPU_INSYS_RESP_TYPE_STREAM_OPEN_DONE = 0, | |
| 40 | + IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK = 1, | |
| 41 | + IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK = 2, | |
| 42 | + IPU_INSYS_RESP_TYPE_STREAM_ABORT_ACK = 3, | |
| 43 | + IPU_INSYS_RESP_TYPE_STREAM_FLUSH_ACK = 4, | |
| 44 | + IPU_INSYS_RESP_TYPE_STREAM_CLOSE_ACK = 5, | |
| 45 | + IPU_INSYS_RESP_TYPE_PIN_DATA_READY = 6, | |
| 46 | + IPU_INSYS_RESP_TYPE_FRAME_SOF = 7, | |
| 47 | + IPU_INSYS_RESP_TYPE_FRAME_EOF = 8, | |
| 48 | + IPU_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE = 9, | |
| 49 | + IPU_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE = 10, | |
| 50 | + IPU_INSYS_RESP_TYPE_PWM_IRQ = 11, | |
| 51 | + N_IPU_INSYS_RESP_TYPE | |
| 52 | +}; | |
| 53 | + | |
| 54 | +enum ipu7_insys_send_type { | |
| 55 | + IPU_INSYS_SEND_TYPE_STREAM_OPEN = 0, | |
| 56 | + IPU_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE = 1, | |
| 57 | + IPU_INSYS_SEND_TYPE_STREAM_CAPTURE = 2, | |
| 58 | + IPU_INSYS_SEND_TYPE_STREAM_ABORT = 3, | |
| 59 | + IPU_INSYS_SEND_TYPE_STREAM_FLUSH = 4, | |
| 60 | + IPU_INSYS_SEND_TYPE_STREAM_CLOSE = 5, | |
| 61 | + N_IPU_INSYS_SEND_TYPE | |
| 62 | +}; | |
| 63 | + | |
| 64 | +enum ipu7_insys_mipi_vc { | |
| 65 | + IPU_INSYS_MIPI_VC_0 = 0, | |
| 66 | + IPU_INSYS_MIPI_VC_1 = 1, | |
| 67 | + IPU_INSYS_MIPI_VC_2 = 2, | |
| 68 | + IPU_INSYS_MIPI_VC_3 = 3, | |
| 69 | + IPU_INSYS_MIPI_VC_4 = 4, | |
| 70 | + IPU_INSYS_MIPI_VC_5 = 5, | |
| 71 | + IPU_INSYS_MIPI_VC_6 = 6, | |
| 72 | + IPU_INSYS_MIPI_VC_7 = 7, | |
| 73 | + IPU_INSYS_MIPI_VC_8 = 8, | |
| 74 | + IPU_INSYS_MIPI_VC_9 = 9, | |
| 75 | + IPU_INSYS_MIPI_VC_10 = 10, | |
| 76 | + IPU_INSYS_MIPI_VC_11 = 11, | |
| 77 | + IPU_INSYS_MIPI_VC_12 = 12, | |
| 78 | + IPU_INSYS_MIPI_VC_13 = 13, | |
| 79 | + IPU_INSYS_MIPI_VC_14 = 14, | |
| 80 | + IPU_INSYS_MIPI_VC_15 = 15, | |
| 81 | + N_IPU_INSYS_MIPI_VC | |
| 82 | +}; | |
| 83 | + | |
| 84 | +enum ipu7_insys_mipi_port { | |
| 85 | + IPU_INSYS_MIPI_PORT_0 = 0, | |
| 86 | + IPU_INSYS_MIPI_PORT_1 = 1, | |
| 87 | + IPU_INSYS_MIPI_PORT_2 = 2, | |
| 88 | + IPU_INSYS_MIPI_PORT_3 = 3, | |
| 89 | + IPU_INSYS_MIPI_PORT_4 = 4, | |
| 90 | + IPU_INSYS_MIPI_PORT_5 = 5, | |
| 91 | + NA_IPU_INSYS_MIPI_PORT | |
| 92 | +}; | |
| 93 | + | |
| 94 | +enum ipu7_insys_frame_format_type { | |
| 95 | + IPU_INSYS_FRAME_FORMAT_NV11 = 0, | |
| 96 | + IPU_INSYS_FRAME_FORMAT_NV12 = 1, | |
| 97 | + IPU_INSYS_FRAME_FORMAT_NV12_16 = 2, | |
| 98 | + IPU_INSYS_FRAME_FORMAT_NV12_TILEY = 3, | |
| 99 | + IPU_INSYS_FRAME_FORMAT_NV16 = 4, | |
| 100 | + IPU_INSYS_FRAME_FORMAT_NV21 = 5, | |
| 101 | + IPU_INSYS_FRAME_FORMAT_NV61 = 6, | |
| 102 | + IPU_INSYS_FRAME_FORMAT_YV12 = 7, | |
| 103 | + IPU_INSYS_FRAME_FORMAT_YV16 = 8, | |
| 104 | + IPU_INSYS_FRAME_FORMAT_YUV420 = 9, | |
| 105 | + IPU_INSYS_FRAME_FORMAT_YUV420_10 = 10, | |
| 106 | + IPU_INSYS_FRAME_FORMAT_YUV420_12 = 11, | |
| 107 | + IPU_INSYS_FRAME_FORMAT_YUV420_14 = 12, | |
| 108 | + IPU_INSYS_FRAME_FORMAT_YUV420_16 = 13, | |
| 109 | + IPU_INSYS_FRAME_FORMAT_YUV422 = 14, | |
| 110 | + IPU_INSYS_FRAME_FORMAT_YUV422_16 = 15, | |
| 111 | + IPU_INSYS_FRAME_FORMAT_UYVY = 16, | |
| 112 | + IPU_INSYS_FRAME_FORMAT_YUYV = 17, | |
| 113 | + IPU_INSYS_FRAME_FORMAT_YUV444 = 18, | |
| 114 | + IPU_INSYS_FRAME_FORMAT_YUV_LINE = 19, | |
| 115 | + IPU_INSYS_FRAME_FORMAT_RAW8 = 20, | |
| 116 | + IPU_INSYS_FRAME_FORMAT_RAW10 = 21, | |
| 117 | + IPU_INSYS_FRAME_FORMAT_RAW12 = 22, | |
| 118 | + IPU_INSYS_FRAME_FORMAT_RAW14 = 23, | |
| 119 | + IPU_INSYS_FRAME_FORMAT_RAW16 = 24, | |
| 120 | + IPU_INSYS_FRAME_FORMAT_RGB565 = 25, | |
| 121 | + IPU_INSYS_FRAME_FORMAT_PLANAR_RGB888 = 26, | |
| 122 | + IPU_INSYS_FRAME_FORMAT_RGBA888 = 27, | |
| 123 | + IPU_INSYS_FRAME_FORMAT_QPLANE6 = 28, | |
| 124 | + IPU_INSYS_FRAME_FORMAT_BINARY_8 = 29, | |
| 125 | + IPU_INSYS_FRAME_FORMAT_Y_8 = 30, | |
| 126 | + IPU_INSYS_FRAME_FORMAT_ARGB888 = 31, | |
| 127 | + IPU_INSYS_FRAME_FORMAT_BGRA888 = 32, | |
| 128 | + IPU_INSYS_FRAME_FORMAT_ABGR888 = 33, | |
| 129 | + N_IPU_INSYS_FRAME_FORMAT | |
| 130 | +}; | |
| 131 | + | |
| 132 | +#define IPU_INSYS_FRAME_FORMAT_RAW (IPU_INSYS_FRAME_FORMAT_RAW16) | |
| 133 | +#define N_IPU_INSYS_MIPI_DATA_TYPE 0x40 | |
| 134 | + | |
| 135 | +enum ipu7_insys_mipi_dt_rename_mode { | |
| 136 | + IPU_INSYS_MIPI_DT_NO_RENAME = 0, | |
| 137 | + IPU_INSYS_MIPI_DT_RENAMED_MODE = 1, | |
| 138 | + N_IPU_INSYS_MIPI_DT_MODE | |
| 139 | +}; | |
| 140 | + | |
| 141 | +#define IPU_INSYS_SEND_MSG_ENABLED 1U | |
| 142 | +#define IPU_INSYS_SEND_MSG_DISABLED 0U | |
| 143 | + | |
| 144 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF BIT(0) | |
| 145 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF BIT(1) | |
| 146 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF BIT(2) | |
| 147 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF BIT(3) | |
| 148 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED BIT(4) | |
| 149 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED BIT(5) | |
| 150 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED BIT(6) | |
| 151 | +#define IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED BIT(7) | |
| 152 | +#define IPU_INSYS_STREAM_SYNC_MSG_ENABLE_MSG_SEND_RESP ( \ | |
| 153 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF | \ | |
| 154 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF | \ | |
| 155 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED | \ | |
| 156 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED) | |
| 157 | +#define IPU_INSYS_STREAM_SYNC_MSG_ENABLE_MSG_SEND_IRQ ( \ | |
| 158 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF | \ | |
| 159 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF | \ | |
| 160 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED | \ | |
| 161 | + IPU_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED) | |
| 162 | + | |
| 163 | +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE BIT(0) | |
| 164 | +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE BIT(1) | |
| 165 | +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK BIT(2) | |
| 166 | +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK BIT(3) | |
| 167 | +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK BIT(4) | |
| 168 | +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK BIT(5) | |
| 169 | +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK BIT(6) | |
| 170 | +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK BIT(7) | |
| 171 | +#define IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK BIT(8) | |
| 172 | +#define IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK BIT(9) | |
| 173 | +#define IPU_INSYS_STREAM_ENABLE_MSG_SEND_RESP ( \ | |
| 174 | + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE | \ | |
| 175 | + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK | \ | |
| 176 | + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK | \ | |
| 177 | + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK | \ | |
| 178 | + IPU_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK) | |
| 179 | +#define IPU_INSYS_STREAM_ENABLE_MSG_SEND_IRQ ( \ | |
| 180 | + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE | \ | |
| 181 | + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK | \ | |
| 182 | + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK | \ | |
| 183 | + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK | \ | |
| 184 | + IPU_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK) | |
| 185 | + | |
| 186 | +#define IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK BIT(0) | |
| 187 | +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK BIT(1) | |
| 188 | +#define IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE BIT(2) | |
| 189 | +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE BIT(3) | |
| 190 | +#define IPU_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY BIT(4) | |
| 191 | +#define IPU_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY BIT(5) | |
| 192 | +#define IPU_INSYS_FRAME_ENABLE_MSG_SEND_RESP ( \ | |
| 193 | + IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK | \ | |
| 194 | + IPU_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE | \ | |
| 195 | + IPU_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY) | |
| 196 | +#define IPU_INSYS_FRAME_ENABLE_MSG_SEND_IRQ ( \ | |
| 197 | + IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK | \ | |
| 198 | + IPU_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE | \ | |
| 199 | + IPU_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY) | |
| 200 | + | |
| 201 | +enum ipu7_insys_output_link_dest { | |
| 202 | + IPU_INSYS_OUTPUT_LINK_DEST_MEM = 0, | |
| 203 | + IPU_INSYS_OUTPUT_LINK_DEST_PSYS = 1, | |
| 204 | + IPU_INSYS_OUTPUT_LINK_DEST_IPU_EXTERNAL = 2 | |
| 205 | +}; | |
| 206 | + | |
| 207 | +enum ipu7_insys_dpcm_type { | |
| 208 | + IPU_INSYS_DPCM_TYPE_DISABLED = 0, | |
| 209 | + IPU_INSYS_DPCM_TYPE_10_8_10 = 1, | |
| 210 | + IPU_INSYS_DPCM_TYPE_12_8_12 = 2, | |
| 211 | + IPU_INSYS_DPCM_TYPE_12_10_12 = 3, | |
| 212 | + N_IPU_INSYS_DPCM_TYPE | |
| 213 | +}; | |
| 214 | + | |
| 215 | +enum ipu7_insys_dpcm_predictor { | |
| 216 | + IPU_INSYS_DPCM_PREDICTOR_1 = 0, | |
| 217 | + IPU_INSYS_DPCM_PREDICTOR_2 = 1, | |
| 218 | + N_IPU_INSYS_DPCM_PREDICTOR | |
| 219 | +}; | |
| 220 | + | |
| 221 | +enum ipu7_insys_send_queue_token_flag { | |
| 222 | + IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE = 0, | |
| 223 | + IPU_INSYS_SEND_QUEUE_TOKEN_FLAG_FLUSH_FORCE = 1 | |
| 224 | +}; | |
| 225 | + | |
| 226 | +#pragma pack(push, 1) | |
| 227 | +struct ipu7_insys_resolution { | |
| 228 | + u32 width; | |
| 229 | + u32 height; | |
| 230 | +}; | |
| 231 | + | |
| 232 | +struct ipu7_insys_capture_output_pin_payload { | |
| 233 | + u64 user_token; | |
| 234 | + ia_gofo_addr_t addr; | |
| 235 | + u8 pad[4]; | |
| 236 | +}; | |
| 237 | + | |
| 238 | +struct ipu7_insys_output_link { | |
| 239 | + u32 buffer_lines; | |
| 240 | + u16 foreign_key; | |
| 241 | + u16 granularity_pointer_update; | |
| 242 | + u8 msg_link_streaming_mode; | |
| 243 | + u8 pbk_id; | |
| 244 | + u8 pbk_slot_id; | |
| 245 | + u8 dest; | |
| 246 | + u8 use_sw_managed; | |
| 247 | + u8 is_snoop; | |
| 248 | + u8 pad[2]; | |
| 249 | +}; | |
| 250 | + | |
| 251 | +struct ipu7_insys_output_cropping { | |
| 252 | + u16 line_top; | |
| 253 | + u16 line_bottom; | |
| 254 | +}; | |
| 255 | + | |
| 256 | +struct ipu7_insys_output_dpcm { | |
| 257 | + u8 enable; | |
| 258 | + u8 type; | |
| 259 | + u8 predictor; | |
| 260 | + u8 pad; | |
| 261 | +}; | |
| 262 | + | |
| 263 | +struct ipu7_insys_output_pin { | |
| 264 | + struct ipu7_insys_output_link link; | |
| 265 | + struct ipu7_insys_output_cropping crop; | |
| 266 | + struct ipu7_insys_output_dpcm dpcm; | |
| 267 | + u32 stride; | |
| 268 | + u16 ft; | |
| 269 | + u8 send_irq; | |
| 270 | + u8 input_pin_id; | |
| 271 | + u8 early_ack_en; | |
| 272 | + u8 pad[3]; | |
| 273 | +}; | |
| 274 | + | |
| 275 | +struct ipu7_insys_input_pin { | |
| 276 | + struct ipu7_insys_resolution input_res; | |
| 277 | + u16 sync_msg_map; | |
| 278 | + u8 dt; | |
| 279 | + u8 disable_mipi_unpacking; | |
| 280 | + u8 dt_rename_mode; | |
| 281 | + u8 mapped_dt; | |
| 282 | + u8 pad[2]; | |
| 283 | +}; | |
| 284 | + | |
| 285 | +struct ipu7_insys_stream_cfg { | |
| 286 | + struct ipu7_insys_input_pin input_pins[4]; | |
| 287 | + struct ipu7_insys_output_pin output_pins[4]; | |
| 288 | + u16 stream_msg_map; | |
| 289 | + u8 port_id; | |
| 290 | + u8 vc; | |
| 291 | + u8 nof_input_pins; | |
| 292 | + u8 nof_output_pins; | |
| 293 | + u8 pad[2]; | |
| 294 | +}; | |
| 295 | + | |
| 296 | +struct ipu7_insys_buffset { | |
| 297 | + struct ipu7_insys_capture_output_pin_payload output_pins[4]; | |
| 298 | + u8 capture_msg_map; | |
| 299 | + u8 frame_id; | |
| 300 | + u8 skip_frame; | |
| 301 | + u8 pad[5]; | |
| 302 | +}; | |
| 303 | + | |
| 304 | +struct ipu7_insys_resp { | |
| 305 | + u64 buf_id; | |
| 306 | + struct ipu7_insys_capture_output_pin_payload pin; | |
| 307 | + struct ia_gofo_msg_err error_info; | |
| 308 | + u32 timestamp[2]; | |
| 309 | + u8 type; | |
| 310 | + u8 msg_link_streaming_mode; | |
| 311 | + u8 stream_id; | |
| 312 | + u8 pin_id; | |
| 313 | + u8 frame_id; | |
| 314 | + u8 skip_frame; | |
| 315 | + u8 pad[2]; | |
| 316 | +}; | |
| 317 | + | |
| 318 | +struct ipu7_insys_resp_queue_token { | |
| 319 | + struct ipu7_insys_resp resp_info; | |
| 320 | +}; | |
| 321 | + | |
| 322 | +struct ipu7_insys_send_queue_token { | |
| 323 | + u64 buf_handle; | |
| 324 | + ia_gofo_addr_t addr; | |
| 325 | + u16 stream_id; | |
| 326 | + u8 send_type; | |
| 327 | + u8 flag; | |
| 328 | +}; | |
| 329 | + | |
| 330 | +#pragma pack(pop) | |
| 331 | + | |
| 332 | +enum insys_msg_err_stream { | |
| 333 | + INSYS_MSG_ERR_STREAM_OK = IA_GOFO_MSG_ERR_OK, | |
| 334 | + INSYS_MSG_ERR_STREAM_STREAM_ID = 1, | |
| 335 | + INSYS_MSG_ERR_STREAM_MAX_OPINS = 2, | |
| 336 | + INSYS_MSG_ERR_STREAM_MAX_IPINS = 3, | |
| 337 | + INSYS_MSG_ERR_STREAM_STREAM_MESSAGES_MAP = 4, | |
| 338 | + INSYS_MSG_ERR_STREAM_SYNC_MESSAGES_MAP = 5, | |
| 339 | + INSYS_MSG_ERR_STREAM_SENSOR_TYPE = 6, | |
| 340 | + INSYS_MSG_ERR_STREAM_FOREIGN_KEY = 7, | |
| 341 | + INSYS_MSG_ERR_STREAM_STREAMING_MODE = 8, | |
| 342 | + INSYS_MSG_ERR_STREAM_DPCM_EN = 9, | |
| 343 | + INSYS_MSG_ERR_STREAM_DPCM_TYPE = 10, | |
| 344 | + INSYS_MSG_ERR_STREAM_DPCM_PREDICTOR = 11, | |
| 345 | + INSYS_MSG_ERR_STREAM_GRANULARITY_POINTER_UPDATE = 12, | |
| 346 | + INSYS_MSG_ERR_STREAM_MPF_LUT_ENTRY_RESOURCES_BUSY = 13, | |
| 347 | + INSYS_MSG_ERR_STREAM_MPF_DEV_ID = 14, | |
| 348 | + INSYS_MSG_ERR_STREAM_BUFFER_LINES = 15, | |
| 349 | + INSYS_MSG_ERR_STREAM_IPIN_ID = 16, | |
| 350 | + INSYS_MSG_ERR_STREAM_DATA_TYPE = 17, | |
| 351 | + INSYS_MSG_ERR_STREAM_STREAMING_PROTOCOL_STATE = 18, | |
| 352 | + INSYS_MSG_ERR_STREAM_SYSCOM_FLUSH = 19, | |
| 353 | + INSYS_MSG_ERR_STREAM_MIPI_VC = 20, | |
| 354 | + INSYS_MSG_ERR_STREAM_STREAM_SRC = 21, | |
| 355 | + INSYS_MSG_ERR_STREAM_PBK_ID = 22, | |
| 356 | + INSYS_MSG_ERR_STREAM_CMD_QUEUE_DEALLOCATE = 23, | |
| 357 | + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES = 24, | |
| 358 | + INSYS_MSG_ERR_STREAM_IPIN_CONFIGURATION = 25, | |
| 359 | + INSYS_MSG_ERR_STREAM_INVALID_STATE = 26, | |
| 360 | + INSYS_MSG_ERR_STREAM_SW_MANAGED = 27, | |
| 361 | + INSYS_MSG_ERR_STREAM_PBK_SLOT_ID = 28, | |
| 362 | + INSYS_MSG_ERR_STREAM_FLUSH_TIMEOUT = 29, | |
| 363 | + INSYS_MSG_ERR_STREAM_IPIN_WIDTH = 30, | |
| 364 | + INSYS_MSG_ERR_STREAM_IPIN_HEIGHT = 31, | |
| 365 | + INSYS_MSG_ERR_STREAM_OUTPUT_PIN_EARLY_ACK_EN = 32, | |
| 366 | + INSYS_MSG_ERR_STREAM_INCONSISTENT_PARAMS = 33, | |
| 367 | + INSYS_MSG_ERR_STREAM_PLANE_COUNT = 34, | |
| 368 | + INSYS_MSG_ERR_STREAM_FRAME_FORMAT_TYPE = 35, | |
| 369 | + INSYS_MSG_ERR_STREAM_INSUFFICIENT_RESOURCES_OUTPUT = 36, | |
| 370 | + INSYS_MSG_ERR_STREAM_WIDTH_OUTPUT_SIZE = 37, | |
| 371 | + INSYS_MSG_ERR_STREAM_CLOSED = 38, | |
| 372 | + INSYS_MSG_ERR_STREAM_N | |
| 373 | +}; | |
| 374 | + | |
| 375 | +enum insys_msg_err_capture { | |
| 376 | + INSYS_MSG_ERR_CAPTURE_OK = IA_GOFO_MSG_ERR_OK, | |
| 377 | + INSYS_MSG_ERR_CAPTURE_STREAM_ID = 1, | |
| 378 | + INSYS_MSG_ERR_CAPTURE_PAYLOAD_PTR = 2, | |
| 379 | + INSYS_MSG_ERR_CAPTURE_MEM_SLOT = 3, | |
| 380 | + INSYS_MSG_ERR_CAPTURE_STREAMING_MODE = 4, | |
| 381 | + INSYS_MSG_ERR_CAPTURE_AVAILABLE_CMD_SLOT = 5, | |
| 382 | + INSYS_MSG_ERR_CAPTURE_CONSUMED_CMD_SLOT = 6, | |
| 383 | + INSYS_MSG_ERR_CAPTURE_CMD_SLOT_PAYLOAD_PTR = 7, | |
| 384 | + INSYS_MSG_ERR_CAPTURE_CMD_PREPARE = 8, | |
| 385 | + INSYS_MSG_ERR_CAPTURE_OUTPUT_PIN = 9, | |
| 386 | + INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP = 10, | |
| 387 | + INSYS_MSG_ERR_CAPTURE_FRAME_MESSAGES_MAP = 11, | |
| 388 | + INSYS_MSG_ERR_CAPTURE_TIMEOUT = 12, | |
| 389 | + INSYS_MSG_ERR_CAPTURE_INVALID_STREAM_STATE = 13, | |
| 390 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_MULTIBIT_PH_ERROR_DETECTED = 14, | |
| 391 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_PAYLOAD_CRC_ERROR = 15, | |
| 392 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_INPUT_DATA_LOSS_ELASTIC_FIFO_OVFL = 16, | |
| 393 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_PIXEL_BUFFER_OVERFLOW = 17, | |
| 394 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_BAD_FRAME_DIM = 18, | |
| 395 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_PHY_SYNC_ERR = 19, | |
| 396 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_SECURE_TOUCH = 20, | |
| 397 | + INSYS_MSG_ERR_CAPTURE_HW_ERR_MASTER_SLAVE_SYNC_ERR = 21, | |
| 398 | + INSYS_MSG_ERR_CAPTURE_FRAME_SKIP_ERR = 22, | |
| 399 | + INSYS_MSG_ERR_CAPTURE_FE_INPUT_FIFO_OVERFLOW_ERR = 23, | |
| 400 | + INSYS_MSG_ERR_CAPTURE_CMD_SUBMIT_TO_HW = 24, | |
| 401 | + INSYS_MSG_ERR_CAPTURE_N | |
| 402 | +}; | |
| 403 | + | |
| 404 | +enum insys_msg_err_groups { | |
| 405 | + INSYS_MSG_ERR_GROUP_RESERVED = IA_GOFO_MSG_ERR_GROUP_RESERVED, | |
| 406 | + INSYS_MSG_ERR_GROUP_GENERAL = IA_GOFO_MSG_ERR_GROUP_GENERAL, | |
| 407 | + INSYS_MSG_ERR_GROUP_STREAM = 2, | |
| 408 | + INSYS_MSG_ERR_GROUP_CAPTURE = 3, | |
| 409 | + INSYS_MSG_ERR_GROUP_N, | |
| 410 | +}; | |
| 411 | + | |
| 412 | +#endif | |
| @@ -0,0 +1,465 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2020 - 2025 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#ifndef IPU7_FW_MSG_ABI_H | |
| 7 | +#define IPU7_FW_MSG_ABI_H | |
| 8 | + | |
| 9 | +#include "ipu7_fw_common_abi.h" | |
| 10 | + | |
| 11 | +#pragma pack(push, 1) | |
| 12 | +enum ipu7_msg_type { | |
| 13 | + IPU_MSG_TYPE_RESERVED = IA_GOFO_MSG_TYPE_RESERVED, | |
| 14 | + IPU_MSG_TYPE_INDIRECT = IA_GOFO_MSG_TYPE_INDIRECT, | |
| 15 | + IPU_MSG_TYPE_DEV_LOG = IA_GOFO_MSG_TYPE_LOG, | |
| 16 | + IPU_MSG_TYPE_GENERAL_ERR = IA_GOFO_MSG_TYPE_GENERAL_ERR, | |
| 17 | + IPU_MSG_TYPE_DEV_OPEN = 4, | |
| 18 | + IPU_MSG_TYPE_DEV_OPEN_ACK = 5, | |
| 19 | + IPU_MSG_TYPE_GRAPH_OPEN = 6, | |
| 20 | + IPU_MSG_TYPE_GRAPH_OPEN_ACK = 7, | |
| 21 | + IPU_MSG_TYPE_TASK_REQ = 8, | |
| 22 | + IPU_MSG_TYPE_TASK_DONE = 9, | |
| 23 | + IPU_MSG_TYPE_GRAPH_CLOSE = 10, | |
| 24 | + IPU_MSG_TYPE_GRAPH_CLOSE_ACK = 11, | |
| 25 | + IPU_MSG_TYPE_DEV_CLOSE = 12, | |
| 26 | + IPU_MSG_TYPE_DEV_CLOSE_ACK = 13, | |
| 27 | + IPU_MSG_TYPE_TERM_EVENT = 14, | |
| 28 | + IPU_MSG_TYPE_N, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +#define IPU_MSG_MAX_NODE_TERMS (64U) | |
| 32 | +#define IPU_MSG_MAX_FRAGS (7U) | |
| 33 | + | |
| 34 | +enum ipu7_msg_node_type { | |
| 35 | + IPU_MSG_NODE_TYPE_PAD = 0, | |
| 36 | + IPU_MSG_NODE_TYPE_BASE, | |
| 37 | + IPU_MSG_NODE_TYPE_N | |
| 38 | +}; | |
| 39 | + | |
| 40 | +#define IPU_MSG_NODE_MAX_DEVICES (128U) | |
| 41 | +#define DEB_NUM_UINT32 (IPU_MSG_NODE_MAX_DEVICES / (sizeof(u32) * 8U)) | |
| 42 | + | |
| 43 | +typedef u32 ipu7_msg_teb_t[2]; | |
| 44 | +typedef u32 ipu7_msg_deb_t[DEB_NUM_UINT32]; | |
| 45 | + | |
| 46 | +#define IPU_MSG_NODE_MAX_ROUTE_ENABLES (128U) | |
| 47 | +#define RBM_NUM_UINT32 (IPU_MSG_NODE_MAX_ROUTE_ENABLES / (sizeof(u32) * 8U)) | |
| 48 | + | |
| 49 | +typedef u32 ipu7_msg_rbm_t[RBM_NUM_UINT32]; | |
| 50 | + | |
| 51 | +enum ipu7_msg_node_profile_type { | |
| 52 | + IPU_MSG_NODE_PROFILE_TYPE_PAD = 0, | |
| 53 | + IPU_MSG_NODE_PROFILE_TYPE_BASE, | |
| 54 | + IPU_MSG_NODE_PROFILE_TYPE_CB, | |
| 55 | + IPU_MSG_NODE_PROFILE_TYPE_N | |
| 56 | +}; | |
| 57 | + | |
| 58 | +struct ipu7_msg_node_profile { | |
| 59 | + struct ia_gofo_tlv_header tlv_header; | |
| 60 | + ipu7_msg_teb_t teb; | |
| 61 | +}; | |
| 62 | + | |
| 63 | +struct ipu7_msg_cb_profile { | |
| 64 | + struct ipu7_msg_node_profile profile_base; | |
| 65 | + ipu7_msg_deb_t deb; | |
| 66 | + ipu7_msg_rbm_t rbm; | |
| 67 | + ipu7_msg_rbm_t reb; | |
| 68 | +}; | |
| 69 | + | |
| 70 | +#define IPU_MSG_NODE_MAX_PROFILES (2U) | |
| 71 | +#define IPU_MSG_NODE_DEF_PROFILE_IDX (0U) | |
| 72 | +#define IPU_MSG_NODE_RSRC_ID_EXT_IP (0xffU) | |
| 73 | + | |
| 74 | +#define IPU_MSG_NODE_DONT_CARE_TEB_HI (0xffffffffU) | |
| 75 | +#define IPU_MSG_NODE_DONT_CARE_TEB_LO (0xffffffffU) | |
390 more lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 431 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 462 lines aren’t shown here.
This diff is large: its 1193 lines aren’t shown here.
This diff is large: its 78 lines aren’t shown here.
This diff is large: its 277 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 478 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 302 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 1035 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 1198 lines aren’t shown here.
This diff is large: its 544 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 830 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 349 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 1113 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 1167 lines aren’t shown here.
This diff is large: its 141 lines aren’t shown here.
This diff is large: its 854 lines aren’t shown here.
This diff is large: its 415 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 2784 lines aren’t shown here.
This diff is large: its 243 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.