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 | Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com> | 287 | Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com> |
| 288 | Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org> | 288 | Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org> |
| 289 | Hans de Goede <hansg@kernel.org> <hdegoede@redhat.com> | 289 | Hans de Goede <hansg@kernel.org> <hdegoede@redhat.com> |
| 290 | Hans Verkuil <hverkuil@xs4all.nl> <hansverk@cisco.com> | 290 | Hans Verkuil <hverkuil@kernel.org> <hverkuil@xs4all.nl> |
| 291 | Hans Verkuil <hverkuil@xs4all.nl> <hverkuil-cisco@xs4all.nl> | 291 | Hans Verkuil <hverkuil@kernel.org> <hverkuil-cisco@xs4all.nl> |
| 292 | Hans Verkuil <hverkuil@kernel.org> <hansverk@cisco.com> | ||
| 292 | Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com> | 293 | Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com> |
| 293 | Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com> | 294 | Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com> |
| 294 | Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com> | 295 | Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com> |
| @@ -24,6 +24,14 @@ properties: · 23 unmodified lines | |||
| 24 | reg: | 24 | reg: |
| 25 | maxItems: 1 | 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 | clocks: | 35 | clocks: |
| 28 | items: | 36 | items: |
| 29 | - description: CSI2Rx system clock | 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 | More detailed documentation can be found in | 23 | More detailed documentation can be found in |
| 24 | Documentation/devicetree/bindings/media/video-interfaces.txt . | 24 | Documentation/devicetree/bindings/media/video-interfaces.txt . |
| 25 | 25 | ||
| 26 | allOf: | ||
| 27 | - $ref: /schemas/media/video-interface-devices.yaml# | ||
| 28 | |||
| 26 | properties: | 29 | properties: |
| 27 | compatible: | 30 | compatible: |
| 28 | oneOf: | 31 | oneOf: |
| @@ -58,16 +61,10 @@ properties: · 29 unmodified lines | |||
| 58 | documentation. | 61 | documentation. |
| 59 | maxItems: 1 | 62 | maxItems: 1 |
| 60 | 63 | ||
| 61 | flash-leds: | 64 | flash-leds: true |
| 62 | description: Flash LED phandles. See ../video-interfaces.txt for details. | 65 | lens-focus: true |
| 63 | |||
| 64 | lens-focus: | ||
| 65 | description: Lens focus controller phandles. See ../video-interfaces.txt | ||
| 66 | for details. | ||
| 67 | 66 | ||
| 68 | rotation: | 67 | rotation: |
| 69 | description: Rotation of the sensor. See ../video-interfaces.txt for | ||
| 70 | details. | ||
| 71 | enum: [ 0, 180 ] | 68 | enum: [ 0, 180 ] |
| 72 | 69 | ||
| 73 | port: | 70 | port: |
| @@ -70,6 +70,15 @@ properties: · 69 unmodified lines | |||
| 70 | - bus-type | 70 | - bus-type |
| 71 | - link-frequencies | 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 | required: | 82 | required: |
| 74 | - compatible | 83 | - compatible |
| 75 | - reg | 84 | - reg |
| @@ -15,6 +15,8 @@ description: | · 14 unmodified lines | |||
| 15 | controlled through an I2C-compatible SCCB bus. The sensor transmits images | 15 | controlled through an I2C-compatible SCCB bus. The sensor transmits images |
| 16 | on a MIPI CSI-2 output interface with up to 4 data lanes. | 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 | properties: | 20 | properties: |
| 19 | compatible: | 21 | compatible: |
| 20 | const: ovti,ov8858 | 22 | const: ovti,ov8858 |
| @@ -69,7 +71,7 @@ required: · 48 unmodified lines | |||
| 69 | - clocks | 71 | - clocks |
| 70 | - port | 72 | - port |
| 71 | 73 | ||
| 72 | additionalProperties: false | 74 | unevaluatedProperties: false |
| 73 | 75 | ||
| 74 | examples: | 76 | examples: |
| 75 | - | | 77 | - | |
| @@ -33,20 +33,21 @@ properties: · 32 unmodified lines | |||
| 33 | 33 | ||
| 34 | clock-frequency: | 34 | clock-frequency: |
| 35 | description: Frequency of the xclk clock in Hz. | 35 | description: Frequency of the xclk clock in Hz. |
| 36 | deprecated: true | ||
| 36 | 37 | ||
| 37 | enable-gpios: | 38 | enable-gpios: |
| 38 | description: GPIO descriptor for the enable pin. | 39 | description: GPIO descriptor for the enable pin. |
| 39 | maxItems: 1 | 40 | maxItems: 1 |
| 40 | 41 | ||
| 41 | vdddo-supply: | ||
| 42 | description: Chip digital IO regulator (1.8V). | ||
| 43 | |||
| 44 | vdda-supply: | 42 | vdda-supply: |
| 45 | description: Chip analog regulator (2.7V). | 43 | description: Chip analog regulator (2.7V). |
| 46 | 44 | ||
| 47 | vddd-supply: | 45 | vddd-supply: |
| 48 | description: Chip digital core regulator (1.12V). | 46 | description: Chip digital core regulator (1.12V). |
| 49 | 47 | ||
| 48 | vdddo-supply: | ||
| 49 | description: Chip digital IO regulator (1.8V). | ||
| 50 | |||
| 50 | flash-leds: true | 51 | flash-leds: true |
| 51 | lens-focus: true | 52 | lens-focus: true |
| 52 | 53 | ||
| @@ -84,11 +85,10 @@ required: · 31 unmodified lines | |||
| 84 | - compatible | 85 | - compatible |
| 85 | - reg | 86 | - reg |
| 86 | - clocks | 87 | - clocks |
| 87 | - clock-frequency | ||
| 88 | - enable-gpios | 88 | - enable-gpios |
| 89 | - vdddo-supply | ||
| 90 | - vdda-supply | 89 | - vdda-supply |
| 91 | - vddd-supply | 90 | - vddd-supply |
| 91 | - vdddo-supply | ||
| 92 | - port | 92 | - port |
| 93 | 93 | ||
| 94 | unevaluatedProperties: false | 94 | unevaluatedProperties: false |
| @@ -104,22 +104,25 @@ examples: · 9 unmodified lines | |||
| 104 | camera-sensor@1a { | 104 | camera-sensor@1a { |
| 105 | compatible = "sony,imx214"; | 105 | compatible = "sony,imx214"; |
| 106 | reg = <0x1a>; | 106 | reg = <0x1a>; |
| 107 | vdddo-supply = <&pm8994_lvs1>; | 107 | |
| 108 | vddd-supply = <&camera_vddd_1v12>; | 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 | vdda-supply = <&pm8994_l17>; | 114 | vdda-supply = <&pm8994_l17>; |
| 115 | vddd-supply = <&camera_vddd_1v12>; | ||
| 116 | vdddo-supply = <&pm8994_lvs1>; | ||
| 117 | |||
| 110 | lens-focus = <&ad5820>; | 118 | lens-focus = <&ad5820>; |
| 111 | enable-gpios = <&msmgpio 25 GPIO_ACTIVE_HIGH>; | ||
| 112 | clocks = <&camera_clk>; | ||
| 113 | clock-frequency = <24000000>; | ||
| 114 | 119 | ||
| 115 | port { | 120 | port { |
| 116 | imx214_ep: endpoint { | 121 | imx214_ep: endpoint { |
| 117 | data-lanes = <1 2 3 4>; | 122 | data-lanes = <1 2 3 4>; |
| 118 | link-frequencies = /bits/ 64 <480000000>; | 123 | link-frequencies = /bits/ 64 <600000000>; |
| 119 | remote-endpoint = <&csiphy0_ep>; | 124 | remote-endpoint = <&csiphy0_ep>; |
| 120 | }; | 125 | }; |
| 121 | }; | 126 | }; |
| 122 | }; | 127 | }; |
| 123 | }; | 128 | }; |
| 124 | |||
| 125 | ... | ||
| @@ -18,6 +18,8 @@ description: |- · 17 unmodified lines | |||
| 18 | The camera module does not expose the model through registers, so the | 18 | The camera module does not expose the model through registers, so the |
| 19 | exact model needs to be specified. | 19 | exact model needs to be specified. |
| 20 | 20 | ||
| 21 | $ref: /schemas/media/video-interface-devices.yaml# | ||
| 22 | |||
| 21 | properties: | 23 | properties: |
| 22 | compatible: | 24 | compatible: |
| 23 | enum: | 25 | enum: |
| @@ -81,7 +83,7 @@ required: · 57 unmodified lines | |||
| 81 | - reg | 83 | - reg |
| 82 | - port | 84 | - port |
| 83 | 85 | ||
| 84 | additionalProperties: false | 86 | unevaluatedProperties: false |
| 85 | 87 | ||
| 86 | examples: | 88 | examples: |
| 87 | - | | 89 | - | |
| @@ -22,10 +22,14 @@ properties: · 21 unmodified lines | |||
| 22 | - nxp,imx8qxp-jpgdec | 22 | - nxp,imx8qxp-jpgdec |
| 23 | - nxp,imx8qxp-jpgenc | 23 | - nxp,imx8qxp-jpgenc |
| 24 | - items: | 24 | - items: |
| 25 | - const: nxp,imx8qm-jpgdec | 25 | - enum: |
| 26 | - nxp,imx8qm-jpgdec | ||
| 27 | - nxp,imx95-jpgdec | ||
| 26 | - const: nxp,imx8qxp-jpgdec | 28 | - const: nxp,imx8qxp-jpgdec |
| 27 | - items: | 29 | - items: |
| 28 | - const: nxp,imx8qm-jpgenc | 30 | - enum: |
| 31 | - nxp,imx8qm-jpgenc | ||
| 32 | - nxp,imx95-jpgenc | ||
| 29 | - const: nxp,imx8qxp-jpgenc | 33 | - const: nxp,imx8qxp-jpgenc |
| 30 | 34 | ||
| 31 | reg: | 35 | reg: |
| @@ -48,7 +52,7 @@ properties: · 16 unmodified lines | |||
| 48 | description: | 52 | description: |
| 49 | List of phandle and PM domain specifier as documented in | 53 | List of phandle and PM domain specifier as documented in |
| 50 | Documentation/devicetree/bindings/power/power_domain.txt | 54 | Documentation/devicetree/bindings/power/power_domain.txt |
| 51 | minItems: 2 # Wrapper and 1 slot | 55 | minItems: 1 # Wrapper and all slots |
| 52 | maxItems: 5 # Wrapper and 4 slots | 56 | maxItems: 5 # Wrapper and 4 slots |
| 53 | 57 | ||
| 54 | required: | 58 | required: |
| @@ -58,6 +62,24 @@ required: · 3 unmodified lines | |||
| 58 | - interrupts | 62 | - interrupts |
| 59 | - power-domains | 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 | additionalProperties: false | 83 | additionalProperties: false |
| 62 | 84 | ||
| 63 | examples: | 85 | examples: |
| @@ -16,11 +16,19 @@ description: |- · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | properties: | 17 | properties: |
| 18 | compatible: | 18 | compatible: |
| 19 | enum: | 19 | oneOf: |
| 20 | - fsl,imx8mq-mipi-csi2 | 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 | reg: | 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 | clocks: | 33 | clocks: |
| 26 | items: | 34 | items: |
| @@ -46,6 +54,7 @@ properties: · 19 unmodified lines | |||
| 46 | - description: CORE_RESET reset register bit definition | 54 | - description: CORE_RESET reset register bit definition |
| 47 | - description: PHY_REF_RESET reset register bit definition | 55 | - description: PHY_REF_RESET reset register bit definition |
| 48 | - description: ESC_RESET reset register bit definition | 56 | - description: ESC_RESET reset register bit definition |
| 57 | minItems: 1 | ||
| 49 | 58 | ||
| 50 | fsl,mipi-phy-gpr: | 59 | fsl,mipi-phy-gpr: |
| 51 | description: | | 60 | description: | |
| @@ -113,9 +122,30 @@ required: · 61 unmodified lines | |||
| 113 | - clock-names | 122 | - clock-names |
| 114 | - power-domains | 123 | - power-domains |
| 115 | - resets | 124 | - resets |
| 116 | - fsl,mipi-phy-gpr | ||
| 117 | - ports | 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 | additionalProperties: false | 149 | additionalProperties: false |
| 120 | 150 | ||
| 121 | examples: | 151 | examples: |
| @@ -133,7 +133,7 @@ properties: · 132 unmodified lines | |||
| 133 | CSI input ports. | 133 | CSI input ports. |
| 134 | 134 | ||
| 135 | patternProperties: | 135 | patternProperties: |
| 136 | "^port@[0-3]+$": | 136 | "^port@[0-3]$": |
| 137 | $ref: /schemas/graph.yaml#/$defs/port-base | 137 | $ref: /schemas/graph.yaml#/$defs/port-base |
| 138 | unevaluatedProperties: false | 138 | unevaluatedProperties: false |
| 139 | 139 | ||
| @@ -146,15 +146,16 @@ properties: · 6 unmodified lines | |||
| 146 | unevaluatedProperties: false | 146 | unevaluatedProperties: false |
| 147 | 147 | ||
| 148 | properties: | 148 | properties: |
| 149 | clock-lanes: | ||
| 150 | maxItems: 1 | ||
| 151 | |||
| 152 | data-lanes: | 149 | data-lanes: |
| 153 | minItems: 1 | 150 | minItems: 1 |
| 154 | maxItems: 4 | 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 | required: | 158 | required: |
| 157 | - clock-lanes | ||
| 158 | - data-lanes | 159 | - data-lanes |
| 159 | 160 | ||
| 160 | required: | 161 | required: |
| @@ -189,7 +190,7 @@ examples: · 28 unmodified lines | |||
| 189 | #address-cells = <2>; | 190 | #address-cells = <2>; |
| 190 | #size-cells = <2>; | 191 | #size-cells = <2>; |
| 191 | 192 | ||
| 192 | camss: isp@acb6000 { | 193 | camss: isp@acb7000 { |
| 193 | compatible = "qcom,x1e80100-camss"; | 194 | compatible = "qcom,x1e80100-camss"; |
| 194 | 195 | ||
| 195 | reg = <0 0x0acb7000 0 0x2000>, | 196 | reg = <0 0x0acb7000 0 0x2000>, |
| @@ -357,7 +358,6 @@ examples: · 161 unmodified lines | |||
| 357 | port@0 { | 358 | port@0 { |
| 358 | reg = <0>; | 359 | reg = <0>; |
| 359 | csiphy_ep0: endpoint { | 360 | csiphy_ep0: endpoint { |
| 360 | clock-lanes = <7>; | ||
| 361 | data-lanes = <0 1>; | 361 | data-lanes = <0 1>; |
| 362 | remote-endpoint = <&sensor_ep>; | 362 | remote-endpoint = <&sensor_ep>; |
| 363 | }; | 363 | }; |
| @@ -30,6 +30,7 @@ properties: · 29 unmodified lines | |||
| 30 | - renesas,r9a07g043u-fcpvd # RZ/G2UL | 30 | - renesas,r9a07g043u-fcpvd # RZ/G2UL |
| 31 | - renesas,r9a07g044-fcpvd # RZ/G2{L,LC} | 31 | - renesas,r9a07g044-fcpvd # RZ/G2{L,LC} |
| 32 | - renesas,r9a07g054-fcpvd # RZ/V2L | 32 | - renesas,r9a07g054-fcpvd # RZ/V2L |
| 33 | - renesas,r9a09g056-fcpvd # RZ/V2N | ||
| 33 | - renesas,r9a09g057-fcpvd # RZ/V2H(P) | 34 | - renesas,r9a09g057-fcpvd # RZ/V2H(P) |
| 34 | - const: renesas,fcpv # Generic FCP for VSP fallback | 35 | - const: renesas,fcpv # Generic FCP for VSP fallback |
| 35 | 36 | ||
| @@ -25,6 +25,7 @@ properties: · 24 unmodified lines | |||
| 25 | - enum: | 25 | - enum: |
| 26 | - renesas,r9a07g043u-vsp2 # RZ/G2UL | 26 | - renesas,r9a07g043u-vsp2 # RZ/G2UL |
| 27 | - renesas,r9a07g054-vsp2 # RZ/V2L | 27 | - renesas,r9a07g054-vsp2 # RZ/V2L |
| 28 | - renesas,r9a09g056-vsp2 # RZ/V2N | ||
| 28 | - renesas,r9a09g057-vsp2 # RZ/V2H(P) | 29 | - renesas,r9a09g057-vsp2 # RZ/V2H(P) |
| 29 | - const: renesas,r9a07g044-vsp2 # RZ/G2L fallback | 30 | - const: renesas,r9a07g044-vsp2 # RZ/G2L fallback |
| 30 | 31 | ||
| @@ -10,13 +10,15 @@ maintainers: · 9 unmodified lines | |||
| 10 | - Heiko Stuebner <heiko@sntech.de> | 10 | - Heiko Stuebner <heiko@sntech.de> |
| 11 | 11 | ||
| 12 | description: |- | 12 | description: |- |
| 13 | The Rockchip rk3399 has a stateless Video Decoder that can decodes H.264, | 13 | Rockchip SoCs have variants of the same stateless Video Decoder that can |
| 14 | HEVC an VP9 streams. | 14 | decodes H.264, HEVC, VP9 and AV1 streams, depending on the variant. |
| 15 | 15 | ||
| 16 | properties: | 16 | properties: |
| 17 | compatible: | 17 | compatible: |
| 18 | oneOf: | 18 | oneOf: |
| 19 | - const: rockchip,rk3399-vdec | 19 | - const: rockchip,rk3399-vdec |
| 20 | - const: rockchip,rk3576-vdec | ||
| 21 | - const: rockchip,rk3588-vdec | ||
| 20 | - items: | 22 | - items: |
| 21 | - enum: | 23 | - enum: |
| 22 | - rockchip,rk3228-vdec | 24 | - rockchip,rk3228-vdec |
| @@ -24,35 +26,72 @@ properties: · 1 unmodified line | |||
| 24 | - const: rockchip,rk3399-vdec | 26 | - const: rockchip,rk3399-vdec |
| 25 | 27 | ||
| 26 | reg: | 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 | interrupts: | 41 | interrupts: |
| 30 | maxItems: 1 | 42 | maxItems: 1 |
| 31 | 43 | ||
| 32 | clocks: | 44 | clocks: |
| 45 | minItems: 4 | ||
| 33 | items: | 46 | items: |
| 34 | - description: The Video Decoder AXI interface clock | 47 | - description: The Video Decoder AXI interface clock |
| 35 | - description: The Video Decoder AHB interface clock | 48 | - description: The Video Decoder AHB interface clock |
| 36 | - description: The Video Decoded CABAC clock | 49 | - description: The Video Decoded CABAC clock |
| 37 | - description: The Video Decoder core clock | 50 | - description: The Video Decoder core clock |
| 51 | - description: The Video decoder HEVC CABAC clock | ||
| 38 | 52 | ||
| 39 | clock-names: | 53 | clock-names: |
| 54 | minItems: 4 | ||
| 40 | items: | 55 | items: |
| 41 | - const: axi | 56 | - const: axi |
| 42 | - const: ahb | 57 | - const: ahb |
| 43 | - const: cabac | 58 | - const: cabac |
| 44 | - const: core | 59 | - const: core |
| 60 | - const: hevc_cabac | ||
| 45 | 61 | ||
| 46 | assigned-clocks: true | 62 | assigned-clocks: true |
| 47 | 63 | ||
| 48 | assigned-clock-rates: true | 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 | power-domains: | 82 | power-domains: |
| 51 | maxItems: 1 | 83 | maxItems: 1 |
| 52 | 84 | ||
| 53 | iommus: | 85 | iommus: |
| 54 | maxItems: 1 | 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 | required: | 95 | required: |
| 57 | - compatible | 96 | - compatible |
| 58 | - reg | 97 | - reg |
| @@ -61,6 +100,41 @@ required: · 2 unmodified lines | |||
| 61 | - clock-names | 100 | - clock-names |
| 62 | - power-domains | 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 | additionalProperties: false | 138 | additionalProperties: false |
| 65 | 139 | ||
| 66 | examples: | 140 | examples: |
| @@ -110,6 +110,7 @@ For sub-device drivers: · 109 unmodified lines | |||
| 110 | 110 | ||
| 111 | v4l2_ctrl_handler_free(&foo->ctrl_handler); | 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 | 2) Add controls: | 115 | 2) Add controls: |
| 115 | 116 | ||
| @@ -191,12 +192,8 @@ These functions are typically called right after the · 75 unmodified lines | |||
| 191 | V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, | 192 | V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0, |
| 192 | 0, test_pattern); | 193 | 0, test_pattern); |
| 193 | ... | 194 | ... |
| 194 | if (foo->ctrl_handler.error) { | 195 | if (foo->ctrl_handler.error) |
| 195 | int err = foo->ctrl_handler.error; | 196 | return v4l2_ctrl_handler_free(&foo->ctrl_handler); |
| 196 | |||
| 197 | v4l2_ctrl_handler_free(&foo->ctrl_handler); | ||
| 198 | return err; | ||
| 199 | } | ||
| 200 | 197 | ||
| 201 | The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to | 198 | The :c:func:`v4l2_ctrl_new_std` function returns the v4l2_ctrl pointer to |
| 202 | the new control, but if you do not need to access the pointer outside the | 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 | # <op> rx-clear clear all rx error injections for <op> | 41 | # <op> rx-clear clear all rx error injections for <op> |
| 42 | # <op> tx-clear clear all tx error injections for <op> | 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 | # RX error injection: | 47 | # RX error injection: |
| 45 | # <op>[,<mode>] rx-nack NACK the message instead of sending an ACK | 48 | # <op>[,<mode>] rx-nack NACK the message instead of sending an ACK |
| 46 | # <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position | 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 | # tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse | 56 | # tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse |
| 54 | # tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse | 57 | # tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse |
| 55 | # tx-custom-pulse transmit the custom pulse once the bus is idle | 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 | # TX error injection: | 64 | # TX error injection: |
| 58 | # <op>[,<mode>] tx-no-eom don't set the EOM bit | 65 | # <op>[,<mode>] tx-no-eom don't set the EOM bit |
| @@ -193,6 +200,14 @@ Receive Messages · 134 unmodified lines | |||
| 193 | This does not work if the remote CEC transmitter has logical address | 200 | This does not work if the remote CEC transmitter has logical address |
| 194 | 0 ('TV') since that will always win. | 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 | Transmit Messages | 211 | Transmit Messages |
| 197 | ----------------- | 212 | ----------------- |
| 198 | 213 | ||
| @@ -327,3 +342,30 @@ Custom Pulses · 128 unmodified lines | |||
| 327 | 342 | ||
| 328 | ``tx-custom-pulse`` | 343 | ``tx-custom-pulse`` |
| 329 | Transmit a single custom pulse as soon as the CEC bus is idle. | 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 | :author: International Telecommunication Union (http://www.itu.int) | 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 | The :ref:`video standard <standard>` ioctls provide information vital | 48 | The :ref:`video standard <standard>` ioctls provide information vital |
| 49 | to program a sliced VBI device, therefore must be supported. | 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 | Sliced VBI Format Negotiation | 53 | Sliced VBI Format Negotiation |
| 54 | ============================= | 54 | ============================= |
| @@ -377,7 +377,7 @@ Sliced VBI Data in MPEG Streams · 322 unmodified lines | |||
| 377 | 377 | ||
| 378 | If a device can produce an MPEG output stream, it may be capable of | 378 | If a device can produce an MPEG output stream, it may be capable of |
| 379 | providing | 379 | providing |
| 380 | :ref:`negotiated sliced VBI services <sliced-vbi-format-negotitation>` | 380 | :ref:`negotiated sliced VBI services <sliced-vbi-format-negotiation>` |
| 381 | as data embedded in the MPEG stream. Users or applications control this | 381 | as data embedded in the MPEG stream. Users or applications control this |
| 382 | sliced VBI data insertion with the | 382 | sliced VBI data insertion with the |
| 383 | :ref:`V4L2_CID_MPEG_STREAM_VBI_FMT <v4l2-mpeg-stream-vbi-fmt>` | 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 | broadcasts speech. If the transmitter doesn't make this distinction, | 64 | broadcasts speech. If the transmitter doesn't make this distinction, |
| 65 | then it will be set. | 65 | then it will be set. |
| 66 | 66 | ||
| 67 | ``V4L2_CID_TUNE_DEEMPHASIS`` | 67 | ``V4L2_CID_TUNE_DEEMPHASIS (enum)`` |
| 68 | (enum) | ||
| 69 | |||
| 70 | enum v4l2_deemphasis - | ||
| 71 | Configures the de-emphasis value for reception. A de-emphasis filter | 68 | Configures the de-emphasis value for reception. A de-emphasis filter |
| 72 | is applied to the broadcast to accentuate the high audio | 69 | is applied to the broadcast to accentuate the high audio |
| 73 | frequencies. Depending on the region, a time constant of either 50 | 70 | frequencies. Depending on the region, a time constant of either 50 |
| 74 | or 75 useconds is used. The enum v4l2_deemphasis defines possible | 71 | or 75 microseconds is used. The enum v4l2_deemphasis defines possible |
| 75 | values for de-emphasis. Here they are: | 72 | values for de-emphasis. They are: |
| 76 | |||
| 77 | |||
| 78 | 73 | ||
| 79 | .. flat-table:: | 74 | .. flat-table:: |
| 80 | :header-rows: 0 | 75 | :header-rows: 0 |
| @@ -104,7 +104,7 @@ FM_TX Control IDs · 103 unmodified lines | |||
| 104 | 104 | ||
| 105 | ``V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (integer)`` | 105 | ``V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (integer)`` |
| 106 | Sets the audio deviation limiter feature release time. Unit is in | 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 | ``V4L2_CID_AUDIO_LIMITER_DEVIATION (integer)`` | 109 | ``V4L2_CID_AUDIO_LIMITER_DEVIATION (integer)`` |
| 110 | Configures audio frequency deviation level in Hz. The range and step | 110 | Configures audio frequency deviation level in Hz. The range and step |
| @@ -121,16 +121,16 @@ FM_TX Control IDs · 10 unmodified lines | |||
| 121 | range and step are driver-specific. | 121 | range and step are driver-specific. |
| 122 | 122 | ||
| 123 | ``V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (integer)`` | 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 | value. The range and step are driver-specific. | 125 | value. The range and step are driver-specific. |
| 126 | 126 | ||
| 127 | ``V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (integer)`` | 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 | value. The range and step are driver-specific. | 129 | value. The range and step are driver-specific. |
| 130 | 130 | ||
| 131 | ``V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (integer)`` | 131 | ``V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (integer)`` |
| 132 | Sets the release time for audio compression feature. It is a | 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 | ``V4L2_CID_PILOT_TONE_ENABLED (boolean)`` | 135 | ``V4L2_CID_PILOT_TONE_ENABLED (boolean)`` |
| 136 | Enables or disables the pilot tone generation feature. | 136 | Enables or disables the pilot tone generation feature. |
| @@ -143,17 +143,12 @@ FM_TX Control IDs · 6 unmodified lines | |||
| 143 | Configures pilot tone frequency value. Unit is in Hz. The range and | 143 | Configures pilot tone frequency value. Unit is in Hz. The range and |
| 144 | step are driver-specific. | 144 | step are driver-specific. |
| 145 | 145 | ||
| 146 | ``V4L2_CID_TUNE_PREEMPHASIS`` | 146 | ``V4L2_CID_TUNE_PREEMPHASIS (enum)`` |
| 147 | (enum) | ||
| 148 | |||
| 149 | enum v4l2_preemphasis - | ||
| 150 | Configures the pre-emphasis value for broadcasting. A pre-emphasis | 147 | Configures the pre-emphasis value for broadcasting. A pre-emphasis |
| 151 | filter is applied to the broadcast to accentuate the high audio | 148 | filter is applied to the broadcast to accentuate the high audio |
| 152 | frequencies. Depending on the region, a time constant of either 50 | 149 | frequencies. Depending on the region, a time constant of either 50 |
| 153 | or 75 useconds is used. The enum v4l2_preemphasis defines possible | 150 | or 75 microseconds is used. The enum v4l2_preemphasis defines possible |
| 154 | values for pre-emphasis. Here they are: | 151 | values for pre-emphasis. They are: |
| 155 | |||
| 156 | |||
| 157 | 152 | ||
| 158 | .. flat-table:: | 153 | .. flat-table:: |
| 159 | :header-rows: 0 | 154 | :header-rows: 0 |
| @@ -166,8 +161,6 @@ enum v4l2_preemphasis - · 6 unmodified lines | |||
| 166 | * - ``V4L2_PREEMPHASIS_75_uS`` | 161 | * - ``V4L2_PREEMPHASIS_75_uS`` |
| 167 | - A pre-emphasis of 75 uS is used. | 162 | - A pre-emphasis of 75 uS is used. |
| 168 | 163 | ||
| 169 | |||
| 170 | |||
| 171 | ``V4L2_CID_TUNE_POWER_LEVEL (integer)`` | 164 | ``V4L2_CID_TUNE_POWER_LEVEL (integer)`` |
| 172 | Sets the output power level for signal transmission. Unit is in | 165 | Sets the output power level for signal transmission. Unit is in |
| 173 | dBuV. Range and step are driver-specific. | 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 | metafmt-pisp-fe | 20 | metafmt-pisp-fe |
| 21 | metafmt-rkisp1 | 21 | metafmt-rkisp1 |
| 22 | metafmt-uvc | 22 | metafmt-uvc |
| 23 | metafmt-uvc-msxu-1-5 | ||
| 23 | metafmt-vivid | 24 | metafmt-vivid |
| 24 | metafmt-vsp1-hgo | 25 | metafmt-vsp1-hgo |
| 25 | metafmt-vsp1-hgt | 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 | them | 44 | them |
| 45 | * - :cspan:`1` *The rest is an exact copy of the UVC payload header:* | 45 | * - :cspan:`1` *The rest is an exact copy of the UVC payload header:* |
| 46 | * - __u8 length; | 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 | * - __u8 flags; | 50 | * - __u8 flags; |
| 49 | - Flags, indicating presence of other standard UVC fields | 51 | - Flags, indicating presence of other standard UVC fields |
| 50 | * - __u8 buf[]; | 52 | * - __u8 buf[]; |
| @@ -19,6 +19,7 @@ orders. See also `the Wikipedia article on Bayer filter · 18 unmodified lines | |||
| 19 | .. toctree:: | 19 | .. toctree:: |
| 20 | :maxdepth: 1 | 20 | :maxdepth: 1 |
| 21 | 21 | ||
| 22 | pixfmt-rawnn-cru | ||
| 22 | pixfmt-srggb8 | 23 | pixfmt-srggb8 |
| 23 | pixfmt-srggb8-pisp-comp | 24 | pixfmt-srggb8-pisp-comp |
| 24 | pixfmt-srggb10 | 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 | .. _v4l2-pix-fmt-sgrbg12p: | 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 | These four pixel formats are packed raw sRGB / Bayer formats with 12 | 20 | These four pixel formats are packed raw sRGB / Bayer formats with 12 |
| 21 | bits per colour. Every two consecutive samples are packed into three | 21 | bits per colour. Every two consecutive samples are packed into three |
| 22 | bytes. Each of the first two bytes contain the 8 high order bits of | 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 | bits of each pixel, in the same order. | 24 | bits of each pixel, in the same order. |
| 25 | 25 | ||
| 26 | Each n-pixel row contains n/2 green samples and n/2 blue or red | 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 | bits per colour. Every four consecutive samples are packed into seven | 24 | bits per colour. Every four consecutive samples are packed into seven |
| 25 | bytes. Each of the first four bytes contain the eight high order bits | 25 | bytes. Each of the first four bytes contain the eight high order bits |
| 26 | of the pixels, and the three following bytes contains the six least | 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 | Each n-pixel row contains n/2 green samples and n/2 blue or red samples, | 29 | Each n-pixel row contains n/2 green samples and n/2 blue or red samples, |
| 30 | with alternating green-red and green-blue rows. They are conventionally | 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 | ALLIED VISION ALVIUM CAMERA DRIVER | 825 | ALLIED VISION ALVIUM CAMERA DRIVER |
| 826 | M: Tommaso Merciai <tomm.merciai@gmail.com> | 826 | M: Tommaso Merciai <tomm.merciai@gmail.com> |
| 827 | M: Martin Hecht <martin.hecht@avnet.eu> | 827 | M: Martin Hecht <mhecht73@gmail.com> |
| 828 | L: linux-media@vger.kernel.org | 828 | L: linux-media@vger.kernel.org |
| 829 | S: Maintained | 829 | S: Maintained |
| 830 | F: Documentation/devicetree/bindings/media/i2c/alliedvision,alvium-csi2.yaml | 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 | F: Documentation/admin-guide/media/ipu6-isys.rst | 12397 | F: Documentation/admin-guide/media/ipu6-isys.rst |
| 12398 | F: drivers/media/pci/intel/ipu6/ | 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 | INTEL ISHTP ECLITE DRIVER | 12409 | INTEL ISHTP ECLITE DRIVER |
| 12401 | M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> | 12410 | M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> |
| 12402 | L: platform-driver-x86@vger.kernel.org | 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 | T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/ | 12693 | T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/ |
| 12685 | F: drivers/net/wireless/intel/iwlwifi/ | 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 | INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER | 12706 | INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER |
| 12688 | S: Orphan | 12707 | S: Orphan |
| 12689 | W: https://slimbootloader.github.io/security/firmware-update.html | 12708 | W: https://slimbootloader.github.io/security/firmware-update.html |
| @@ -18134,6 +18153,7 @@ NXP i.MX 8M ISI DRIVER · 5444 unmodified lines | |||
| 18134 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 18153 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| 18135 | L: linux-media@vger.kernel.org | 18154 | L: linux-media@vger.kernel.org |
| 18136 | S: Maintained | 18155 | S: Maintained |
| 18156 | F: Documentation/devicetree/bindings/media/fsl,imx8*-isi.yaml | ||
| 18137 | F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml | 18157 | F: Documentation/devicetree/bindings/media/nxp,imx8-isi.yaml |
| 18138 | F: drivers/media/platform/nxp/imx8-isi/ | 18158 | F: drivers/media/platform/nxp/imx8-isi/ |
| 18139 | 18159 | ||
| @@ -20548,6 +20568,7 @@ QUALCOMM CAMERA SUBSYSTEM DRIVER · 2408 unmodified lines | |||
| 20548 | M: Robert Foss <rfoss@kernel.org> | 20568 | M: Robert Foss <rfoss@kernel.org> |
| 20549 | M: Todor Tomov <todor.too@gmail.com> | 20569 | M: Todor Tomov <todor.too@gmail.com> |
| 20550 | M: Bryan O'Donoghue <bryan.odonoghue@linaro.org> | 20570 | M: Bryan O'Donoghue <bryan.odonoghue@linaro.org> |
| 20571 | R: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org> | ||
| 20551 | L: linux-media@vger.kernel.org | 20572 | L: linux-media@vger.kernel.org |
| 20552 | S: Maintained | 20573 | S: Maintained |
| 20553 | F: Documentation/admin-guide/media/qcom_camss.rst | 20574 | F: Documentation/admin-guide/media/qcom_camss.rst |
| @@ -21693,6 +21714,14 @@ S: Maintained · 1139 unmodified lines | |||
| 21693 | F: Documentation/devicetree/bindings/media/rockchip-rga.yaml | 21714 | F: Documentation/devicetree/bindings/media/rockchip-rga.yaml |
| 21694 | F: drivers/media/platform/rockchip/rga/ | 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 | ROCKCHIP RK3308 INTERNAL AUDIO CODEC | 21725 | ROCKCHIP RK3308 INTERNAL AUDIO CODEC |
| 21697 | M: Luca Ceresoli <luca.ceresoli@bootlin.com> | 21726 | M: Luca Ceresoli <luca.ceresoli@bootlin.com> |
| 21698 | S: Maintained | 21727 | S: Maintained |
| @@ -26081,6 +26110,7 @@ S: Maintained · 4382 unmodified lines | |||
| 26081 | W: http://www.ideasonboard.org/uvc/ | 26110 | W: http://www.ideasonboard.org/uvc/ |
| 26082 | T: git git://linuxtv.org/media.git | 26111 | T: git git://linuxtv.org/media.git |
| 26083 | F: Documentation/userspace-api/media/drivers/uvcvideo.rst | 26112 | F: Documentation/userspace-api/media/drivers/uvcvideo.rst |
| 26113 | F: Documentation/userspace-api/media/v4l/metafmt-uvc-msxu-1-5.rst | ||
| 26084 | F: Documentation/userspace-api/media/v4l/metafmt-uvc.rst | 26114 | F: Documentation/userspace-api/media/v4l/metafmt-uvc.rst |
| 26085 | F: drivers/media/common/uvc.c | 26115 | F: drivers/media/common/uvc.c |
| 26086 | F: drivers/media/usb/uvc/ | 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 | if (!strcmp(token, "clear")) { | 91 | if (!strcmp(token, "clear")) { |
| 92 | memset(pin->error_inj, 0, sizeof(pin->error_inj)); | 92 | memset(pin->error_inj, 0, sizeof(pin->error_inj)); |
| 93 | pin->rx_toggle = pin->tx_toggle = false; | 93 | pin->rx_toggle = pin->tx_toggle = false; |
| 94 | pin->rx_no_low_drive = false; | ||
| 94 | pin->tx_ignore_nack_until_eom = false; | 95 | pin->tx_ignore_nack_until_eom = false; |
| 95 | pin->tx_custom_pulse = false; | 96 | pin->tx_custom_pulse = false; |
| 96 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; | 97 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 97 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; | 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 | return true; | 103 | return true; |
| 99 | } | 104 | } |
| 100 | if (!strcmp(token, "rx-clear")) { | 105 | if (!strcmp(token, "rx-clear")) { |
| 101 | for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) | 106 | for (i = 0; i <= CEC_ERROR_INJ_OP_ANY; i++) |
| 102 | pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; | 107 | pin->error_inj[i] &= ~CEC_ERROR_INJ_RX_MASK; |
| 103 | pin->rx_toggle = false; | 108 | pin->rx_toggle = false; |
| 109 | pin->rx_no_low_drive = false; | ||
| 104 | return true; | 110 | return true; |
| 105 | } | 111 | } |
| 106 | if (!strcmp(token, "tx-clear")) { | 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 | pin->tx_custom_pulse = false; | 117 | pin->tx_custom_pulse = false; |
| 112 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; | 118 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 113 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; | 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 | return true; | 128 | return true; |
| 115 | } | 129 | } |
| 116 | if (!strcmp(token, "tx-ignore-nack-until-eom")) { | 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 | cec_pin_start_timer(pin); | 136 | cec_pin_start_timer(pin); |
| 123 | return true; | 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 | if (!p) | 147 | if (!p) |
| 126 | return false; | 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 | if (kstrtou32(p, 0, &usecs) || usecs > 10000000) | 162 | if (kstrtou32(p, 0, &usecs) || usecs > 10000000) |
| 141 | return false; | 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 | return true; | 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 | seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n"); | 311 | seq_puts(sf, "# <op> rx-clear clear all rx error injections for <op>\n"); |
| 274 | seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n"); | 312 | seq_puts(sf, "# <op> tx-clear clear all tx error injections for <op>\n"); |
| 275 | seq_puts(sf, "#\n"); | 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 | seq_puts(sf, "# RX error injection:\n"); | 317 | seq_puts(sf, "# RX error injection:\n"); |
| 277 | seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n"); | 318 | seq_puts(sf, "# <op>[,<mode>] rx-nack NACK the message instead of sending an ACK\n"); |
| 278 | seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n"); | 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 | seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n"); | 326 | seq_puts(sf, "# tx-custom-low-usecs <usecs> define the 'low' time for the custom pulse\n"); |
| 286 | seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n"); | 327 | seq_puts(sf, "# tx-custom-high-usecs <usecs> define the 'high' time for the custom pulse\n"); |
| 287 | seq_puts(sf, "# tx-custom-pulse transmit the custom pulse once the bus is idle\n"); | 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 | seq_puts(sf, "#\n"); | 333 | seq_puts(sf, "#\n"); |
| 289 | seq_puts(sf, "# TX error injection:\n"); | 334 | seq_puts(sf, "# TX error injection:\n"); |
| 290 | seq_puts(sf, "# <op>[,<mode>] tx-no-eom don't set the EOM bit\n"); | 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 | if (pin->tx_ignore_nack_until_eom) | 382 | if (pin->tx_ignore_nack_until_eom) |
| 336 | seq_puts(sf, "tx-ignore-nack-until-eom\n"); | 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 | if (pin->tx_custom_pulse) | 388 | if (pin->tx_custom_pulse) |
| 338 | seq_puts(sf, "tx-custom-pulse\n"); | 389 | seq_puts(sf, "tx-custom-pulse\n"); |
| 339 | if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT) | 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 | if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) | 393 | if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT) |
| 343 | seq_printf(sf, "tx-custom-high-usecs %u\n", | 394 | seq_printf(sf, "tx-custom-high-usecs %u\n", |
| 344 | pin->tx_custom_high_usecs); | 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 | return 0; | 402 | return 0; |
| 346 | } | 403 | } |
| @@ -164,6 +164,9 @@ enum cec_pin_state { · 163 unmodified lines | |||
| 164 | /* The default for the low/high time of the custom pulse */ | 164 | /* The default for the low/high time of the custom pulse */ |
| 165 | #define CEC_TIM_CUSTOM_DEFAULT 1000 | 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 | #define CEC_NUM_PIN_EVENTS 128 | 170 | #define CEC_NUM_PIN_EVENTS 128 |
| 168 | #define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) | 171 | #define CEC_PIN_EVENT_FL_IS_HIGH (1 << 0) |
| 169 | #define CEC_PIN_EVENT_FL_DROPPED (1 << 1) | 172 | #define CEC_PIN_EVENT_FL_DROPPED (1 << 1) |
| @@ -225,12 +228,17 @@ struct cec_pin { · 55 unmodified lines | |||
| 225 | u32 timer_max_overrun; | 228 | u32 timer_max_overrun; |
| 226 | u32 timer_sum_overrun; | 229 | u32 timer_sum_overrun; |
| 227 | 230 | ||
| 231 | bool rx_no_low_drive; | ||
| 228 | u32 tx_custom_low_usecs; | 232 | u32 tx_custom_low_usecs; |
| 229 | u32 tx_custom_high_usecs; | 233 | u32 tx_custom_high_usecs; |
| 234 | u32 tx_glitch_low_usecs; | ||
| 235 | u32 tx_glitch_high_usecs; | ||
| 230 | bool tx_ignore_nack_until_eom; | 236 | bool tx_ignore_nack_until_eom; |
| 231 | bool tx_custom_pulse; | 237 | bool tx_custom_pulse; |
| 232 | bool tx_generated_poll; | 238 | bool tx_generated_poll; |
| 233 | bool tx_post_eom; | 239 | bool tx_post_eom; |
| 240 | bool tx_glitch_falling_edge; | ||
| 241 | bool tx_glitch_rising_edge; | ||
| 234 | u8 tx_extra_bytes; | 242 | u8 tx_extra_bytes; |
| 235 | u32 tx_low_drive_cnt; | 243 | u32 tx_low_drive_cnt; |
| 236 | #ifdef CONFIG_CEC_PIN_ERROR_INJ | 244 | #ifdef CONFIG_CEC_PIN_ERROR_INJ |
| @@ -142,15 +142,42 @@ static bool cec_pin_read(struct cec_pin *pin) · 141 unmodified lines | |||
| 142 | return v; | 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 | static void cec_pin_low(struct cec_pin *pin) | 168 | static void cec_pin_low(struct cec_pin *pin) |
| 146 | { | 169 | { |
| 147 | call_void_pin_op(pin, low); | 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 | cec_pin_update(pin, false, false); | 173 | cec_pin_update(pin, false, false); |
| 149 | } | 174 | } |
| 150 | 175 | ||
| 151 | static bool cec_pin_high(struct cec_pin *pin) | 176 | static bool cec_pin_high(struct cec_pin *pin) |
| 152 | { | 177 | { |
| 153 | call_void_pin_op(pin, high); | 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 | return cec_pin_read(pin); | 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 | * Go to low drive state when the total bit time is | 797 | * Go to low drive state when the total bit time is |
| 771 | * too short. | 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 | if (!pin->rx_data_bit_too_short_cnt++) { | 801 | if (!pin->rx_data_bit_too_short_cnt++) { |
| 775 | pin->rx_data_bit_too_short_ts = ktime_to_ns(pin->ts); | 802 | pin->rx_data_bit_too_short_ts = ktime_to_ns(pin->ts); |
| 776 | pin->rx_data_bit_too_short_delta = delta; | 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 | init_waitqueue_head(&pin->kthread_waitq); | 1377 | init_waitqueue_head(&pin->kthread_waitq); |
| 1351 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; | 1378 | pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; |
| 1352 | pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT; | 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 | adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, | 1383 | adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name, |
| 1355 | caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, | 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 | gpiod_set_value(cec->cec_gpio, 0); | 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 | struct cec_gpio *cec = priv; | 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 | return IRQ_HANDLED; | 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 | struct cec_gpio *cec = priv; | 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 | cec->v5_ts = ktime_get(); | 82 | cec->v5_ts = ktime_get(); |
| 81 | cec->v5_is_high = is_high; | ||
| 82 | return IRQ_WAKE_THREAD; | 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 | struct cec_gpio *cec = priv; | 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 | return IRQ_HANDLED; | 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 | struct cec_gpio *cec = priv; | 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 | cec->hpd_ts = ktime_get(); | 104 | cec->hpd_ts = ktime_get(); |
| 102 | cec->hpd_is_high = is_high; | ||
| 103 | return IRQ_WAKE_THREAD; | 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 | struct cec_gpio *cec = priv; | 110 | struct cec_gpio *cec = priv; |
| 109 | int val = gpiod_get_value(cec->cec_gpio); | 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 | return IRQ_HANDLED; | 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 | struct cec_gpio *cec = cec_get_drvdata(adap); | 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 | return true; | 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 | struct cec_gpio *cec = cec_get_drvdata(adap); | 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 | if (!cec->hpd_gpio) | 151 | if (!cec->hpd_gpio) |
| 150 | return -ENOTTY; | 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 | static int cec_gpio_read_5v(struct cec_adapter *adap) | 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 | if (!cec->v5_gpio) | 160 | if (!cec->v5_gpio) |
| 159 | return -ENOTTY; | 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 | static const struct cec_pin_ops cec_gpio_pin_ops = { | 165 | static const struct cec_pin_ops cec_gpio_pin_ops = { |
| 164 | .read = cec_gpio_read, | 166 | .read = cec_gpio_read, |
| 165 | .low = cec_gpio_low, | 167 | .low = cec_gpio_low, |
| 166 | .high = cec_gpio_high, | 168 | .high = cec_gpio_high, |
| 167 | .enable_irq = cec_gpio_enable_irq, | 169 | .enable_irq = cec_gpio_cec_enable_irq, |
| 168 | .disable_irq = cec_gpio_disable_irq, | 170 | .disable_irq = cec_gpio_cec_disable_irq, |
| 169 | .status = cec_gpio_status, | 171 | .status = cec_gpio_status, |
| 170 | .read_hpd = cec_gpio_read_hpd, | 172 | .read_hpd = cec_gpio_read_hpd, |
| 171 | .read_5v = cec_gpio_read_5v, | 173 | .read_5v = cec_gpio_read_5v, |
| @@ -209,7 +211,7 @@ static int cec_gpio_probe(struct platform_device *pdev) · 37 unmodified lines | |||
| 209 | if (IS_ERR(cec->adap)) | 211 | if (IS_ERR(cec->adap)) |
| 210 | return PTR_ERR(cec->adap); | 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 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, | 215 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, |
| 214 | cec->adap->name, cec); | 216 | cec->adap->name, cec); |
| 215 | if (ret) | 217 | if (ret) |
| @@ -218,8 +220,8 @@ static int cec_gpio_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 218 | if (cec->hpd_gpio) { | 220 | if (cec->hpd_gpio) { |
| 219 | cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); | 221 | cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); |
| 220 | ret = devm_request_threaded_irq(dev, cec->hpd_irq, | 222 | ret = devm_request_threaded_irq(dev, cec->hpd_irq, |
| 221 | cec_hpd_gpio_irq_handler, | 223 | cec_gpio_hpd_irq_handler, |
| 222 | cec_hpd_gpio_irq_handler_thread, | 224 | cec_gpio_hpd_irq_handler_thread, |
| 223 | IRQF_ONESHOT | | 225 | IRQF_ONESHOT | |
| 224 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 226 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
| 225 | "hpd-gpio", cec); | 227 | "hpd-gpio", cec); |
| @@ -230,8 +232,8 @@ static int cec_gpio_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 230 | if (cec->v5_gpio) { | 232 | if (cec->v5_gpio) { |
| 231 | cec->v5_irq = gpiod_to_irq(cec->v5_gpio); | 233 | cec->v5_irq = gpiod_to_irq(cec->v5_gpio); |
| 232 | ret = devm_request_threaded_irq(dev, cec->v5_irq, | 234 | ret = devm_request_threaded_irq(dev, cec->v5_irq, |
| 233 | cec_5v_gpio_irq_handler, | 235 | cec_gpio_5v_irq_handler, |
| 234 | cec_5v_gpio_irq_handler_thread, | 236 | cec_gpio_5v_irq_handler_thread, |
| 235 | IRQF_ONESHOT | | 237 | IRQF_ONESHOT | |
| 236 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 238 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
| 237 | "v5-gpio", cec); | 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 | struct rain *rain = serio_get_drvdata(serio); | 172 | struct rain *rain = serio_get_drvdata(serio); |
| 173 | 173 | ||
| 174 | spin_lock(&rain->buf_lock); | ||
| 174 | if (rain->buf_len == DATA_SIZE) { | 175 | if (rain->buf_len == DATA_SIZE) { |
| 176 | spin_unlock(&rain->buf_lock); | ||
| 175 | dev_warn_once(rain->dev, "buffer overflow\n"); | 177 | dev_warn_once(rain->dev, "buffer overflow\n"); |
| 176 | return IRQ_HANDLED; | 178 | return IRQ_HANDLED; |
| 177 | } | 179 | } |
| 178 | spin_lock(&rain->buf_lock); | ||
| 179 | rain->buf_len++; | 180 | rain->buf_len++; |
| 180 | rain->buf[rain->buf_wr_idx] = data; | 181 | rain->buf[rain->buf_wr_idx] = data; |
| 181 | rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff; | 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 | return I2C_FUNC_I2C; | 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 | .master_xfer = flexcop_master_xfer, | 213 | .master_xfer = flexcop_master_xfer, |
| 214 | .functionality = flexcop_i2c_func, | 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 | return cxd2820r_gpio(&priv->fe, gpio); | 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 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); | 438 | struct cxd2820r_priv *priv = gpiochip_get_data(chip); |
| 439 | struct i2c_client *client = priv->client[0]; | 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 | (void) cxd2820r_gpio(&priv->fe, gpio); | 447 | (void) cxd2820r_gpio(&priv->fe, gpio); |
| 448 | 448 | ||
| 449 | return; | 449 | return 0; |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | static int cxd2820r_gpio_get(struct gpio_chip *chip, unsigned nr) | 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 | priv->gpio_chip.parent = &client->dev; | 651 | priv->gpio_chip.parent = &client->dev; |
| 652 | priv->gpio_chip.owner = THIS_MODULE; | 652 | priv->gpio_chip.owner = THIS_MODULE; |
| 653 | priv->gpio_chip.direction_output = cxd2820r_gpio_direction_output; | 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 | priv->gpio_chip.get = cxd2820r_gpio_get; | 655 | priv->gpio_chip.get = cxd2820r_gpio_get; |
| 656 | priv->gpio_chip.base = -1; /* Dynamic allocation */ | 656 | priv->gpio_chip.base = -1; /* Dynamic allocation */ |
| 657 | priv->gpio_chip.ngpio = GPIO_COUNT; | 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 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); | 2193 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); |
| 2194 | u8 n_overflow = 1; | 2194 | u8 n_overflow = 1; |
| 2195 | u16 i = 1000; | 2195 | u16 i = 1000; |
| 2196 | if (msg[0].len < 3) | ||
| 2197 | return -EOPNOTSUPP; | ||
| 2196 | u16 serpar_num = msg[0].buf[0]; | 2198 | u16 serpar_num = msg[0].buf[0]; |
| 2197 | 2199 | ||
| 2198 | while (n_overflow == 1 && i) { | 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 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); | 2214 | struct dib7000p_state *state = i2c_get_adapdata(i2c_adap); |
| 2213 | u8 n_overflow = 1, n_empty = 1; | 2215 | u8 n_overflow = 1, n_empty = 1; |
| 2214 | u16 i = 1000; | 2216 | u16 i = 1000; |
| 2217 | if (msg[0].len < 1 || msg[1].len < 2) | ||
| 2218 | return -EOPNOTSUPP; | ||
| 2215 | u16 serpar_num = msg[0].buf[0]; | 2219 | u16 serpar_num = msg[0].buf[0]; |
| 2216 | u16 read_word; | 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 | u16 word; | 2260 | u16 word; |
| 2257 | 2261 | ||
| 2258 | if (num == 1) { /* write */ | 2262 | if (num == 1) { /* write */ |
| 2263 | if (msg[0].len < 3) | ||
| 2264 | return -EOPNOTSUPP; | ||
| 2259 | dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); | 2265 | dib7000p_write_word(state, apb_address, ((msg[0].buf[1] << 8) | (msg[0].buf[2]))); |
| 2260 | } else { | 2266 | } else { |
| 2267 | if (msg[1].len < 2) | ||
| 2268 | return -EOPNOTSUPP; | ||
| 2261 | word = dib7000p_read_word(state, apb_address); | 2269 | word = dib7000p_read_word(state, apb_address); |
| 2262 | msg[1].buf[0] = (word >> 8) & 0xff; | 2270 | msg[1].buf[0] = (word >> 8) & 0xff; |
| 2263 | msg[1].buf[1] = (word) & 0xff; | 2271 | msg[1].buf[1] = (word) & 0xff; |
| @@ -141,6 +141,7 @@ config VIDEO_IMX214 · 140 unmodified lines | |||
| 141 | depends on GPIOLIB | 141 | depends on GPIOLIB |
| 142 | select REGMAP_I2C | 142 | select REGMAP_I2C |
| 143 | select V4L2_CCI_I2C | 143 | select V4L2_CCI_I2C |
| 144 | select VIDEO_CCS_PLL | ||
| 144 | help | 145 | help |
| 145 | This is a Video4Linux2 sensor driver for the Sony | 146 | This is a Video4Linux2 sensor driver for the Sony |
| 146 | IMX214 camera. | 147 | IMX214 camera. |
| @@ -765,24 +766,25 @@ config VIDEO_THP7312 · 618 unmodified lines | |||
| 765 | 766 | ||
| 766 | endmenu | 767 | endmenu |
| 767 | 768 | ||
| 768 | menu "Lens drivers" | 769 | menuconfig VIDEO_CAMERA_LENS |
| 769 | visible if MEDIA_CAMERA_SUPPORT | 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 | config VIDEO_AD5820 | 779 | config VIDEO_AD5820 |
| 772 | tristate "AD5820 lens voice coil support" | 780 | tristate "AD5820 lens voice coil support" |
| 773 | depends on GPIOLIB && I2C && VIDEO_DEV | 781 | depends on GPIOLIB |
| 774 | select MEDIA_CONTROLLER | ||
| 775 | select V4L2_ASYNC | ||
| 776 | help | 782 | help |
| 777 | This is a driver for the AD5820 camera lens voice coil. | 783 | This is a driver for the AD5820 camera lens voice coil. |
| 778 | It is used for example in Nokia N900 (RX-51). | 784 | It is used for example in Nokia N900 (RX-51). |
| 779 | 785 | ||
| 780 | config VIDEO_AK7375 | 786 | config VIDEO_AK7375 |
| 781 | tristate "AK7375 lens voice coil support" | 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 | help | 788 | help |
| 787 | This is a driver for the AK7375 camera lens voice coil. | 789 | This is a driver for the AK7375 camera lens voice coil. |
| 788 | AK7375 is a 12 bit DAC with 120mA output current sink | 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 | config VIDEO_DW9714 | 794 | config VIDEO_DW9714 |
| 793 | tristate "DW9714 lens voice coil support" | 795 | tristate "DW9714 lens voice coil support" |
| 794 | depends on I2C && VIDEO_DEV | 796 | depends on GPIOLIB |
| 795 | select MEDIA_CONTROLLER | ||
| 796 | select VIDEO_V4L2_SUBDEV_API | ||
| 797 | select V4L2_ASYNC | ||
| 798 | help | 797 | help |
| 799 | This is a driver for the DW9714 camera lens voice coil. | 798 | This is a driver for the DW9714 camera lens voice coil. |
| 800 | DW9714 is a 10 bit DAC with 120mA output current sink | 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 | config VIDEO_DW9719 | 803 | config VIDEO_DW9719 |
| 805 | tristate "DW9719 lens voice coil support" | 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 | select V4L2_CCI_I2C | 805 | select V4L2_CCI_I2C |
| 811 | help | 806 | help |
| 812 | This is a driver for the DW9719 camera lens voice coil. | 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 | config VIDEO_DW9768 | 811 | config VIDEO_DW9768 |
| 817 | tristate "DW9768 lens voice coil support" | 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 | help | 813 | help |
| 823 | This is a driver for the DW9768 camera lens voice coil. | 814 | This is a driver for the DW9768 camera lens voice coil. |
| 824 | DW9768 is a 10 bit DAC with 100mA output current sink | 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 | config VIDEO_DW9807_VCM | 819 | config VIDEO_DW9807_VCM |
| 829 | tristate "DW9807 lens voice coil support" | 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 | help | 821 | help |
| 835 | This is a driver for the DW9807 camera lens voice coil. | 822 | This is a driver for the DW9807 camera lens voice coil. |
| 836 | DW9807 is a 10 bit DAC with 100mA output current sink | 823 | DW9807 is a 10 bit DAC with 100mA output current sink |
| 837 | capability. This is designed for linear control of | 824 | capability. This is designed for linear control of |
| 838 | voice coil motors, controlled via I2C serial interface. | 825 | voice coil motors, controlled via I2C serial interface. |
| 839 | 826 | ||
| 840 | endmenu | 827 | endif |
| 841 | 828 | ||
| 842 | menu "Flash devices" | 829 | menu "Flash devices" |
| 843 | visible if MEDIA_CAMERA_SUPPORT | 830 | visible if MEDIA_CAMERA_SUPPORT |
| @@ -1684,7 +1671,7 @@ config VIDEO_MAX96714 · 840 unmodified lines | |||
| 1684 | 1671 | ||
| 1685 | config VIDEO_MAX96717 | 1672 | config VIDEO_MAX96717 |
| 1686 | tristate "Maxim MAX96717 GMSL2 Serializer support" | 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 | select I2C_MUX | 1675 | select I2C_MUX |
| 1689 | select MEDIA_CONTROLLER | 1676 | select MEDIA_CONTROLLER |
| 1690 | select GPIOLIB | 1677 | select GPIOLIB |
| @@ -868,21 +868,6 @@ static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) · 867 unmodified lines | |||
| 868 | return 0; | 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 | static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) | 871 | static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) |
| 887 | { | 872 | { |
| 888 | *norm = V4L2_STD_ALL; | 873 | *norm = V4L2_STD_ALL; |
| @@ -929,7 +914,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { · 40 unmodified lines | |||
| 929 | .querystd = adv7180_querystd, | 914 | .querystd = adv7180_querystd, |
| 930 | .g_input_status = adv7180_g_input_status, | 915 | .g_input_status = adv7180_g_input_status, |
| 931 | .s_routing = adv7180_s_routing, | 916 | .s_routing = adv7180_s_routing, |
| 932 | .g_pixelaspect = adv7180_g_pixelaspect, | ||
| 933 | .g_tvnorms = adv7180_g_tvnorms, | 917 | .g_tvnorms = adv7180_g_tvnorms, |
| 934 | .s_stream = adv7180_s_stream, | 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 | return sdp_write(state, ADV748X_SDP_INSEL, input); | 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 | * v4l2_subdev_video_ops | 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 | .g_tvnorms = adv748x_afe_g_tvnorms, | 291 | .g_tvnorms = adv748x_afe_g_tvnorms, |
| 308 | .g_input_status = adv748x_afe_g_input_status, | 292 | .g_input_status = adv748x_afe_g_input_status, |
| 309 | .s_stream = adv748x_afe_s_stream, | 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 | return ret; | 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 | static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = { | 385 | static const struct v4l2_subdev_video_ops adv748x_video_ops_hdmi = { |
| 395 | .g_input_status = adv748x_hdmi_g_input_status, | 386 | .g_input_status = adv748x_hdmi_g_input_status, |
| 396 | .s_stream = adv748x_hdmi_s_stream, | 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 | cec_s_phys_addr(state->cec_adap, parent_pa, false); | 2449 | cec_s_phys_addr(state->cec_adap, parent_pa, false); |
| 2450 | 2450 | ||
| 2451 | /* enable hotplug after 100 ms */ | 2451 | /* enable hotplug after 143 ms */ |
| 2452 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); | 2452 | schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 7); |
| 2453 | return 0; | 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 | 0)); | 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 | static int ub913_gpio_of_xlate(struct gpio_chip *gc, | 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 | gc->ngpio = UB913_NUM_GPIOS; | 235 | gc->ngpio = UB913_NUM_GPIOS; |
| 236 | gc->get_direction = ub913_gpio_get_direction; | 236 | gc->get_direction = ub913_gpio_get_direction; |
| 237 | gc->direction_output = ub913_gpio_direction_out; | 237 | gc->direction_output = ub913_gpio_direction_out; |
| 238 | gc->set = ub913_gpio_set; | 238 | gc->set_rv = ub913_gpio_set; |
| 239 | gc->of_xlate = ub913_gpio_of_xlate; | 239 | gc->of_xlate = ub913_gpio_of_xlate; |
| 240 | gc->of_gpio_n_cells = 2; | 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 | unsigned int i; | 337 | unsigned int i; |
| 338 | int ret; | 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 | ret = v4l2_subdev_routing_validate(sd, routing, | 340 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 349 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); | 341 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 350 | if (ret) | 342 | if (ret) |
| @@ -317,14 +317,13 @@ static int ub953_gpio_get(struct gpio_chip *gc, unsigned int offset) · 316 unmodified lines | |||
| 317 | return !!(v & UB953_REG_GPIO_PIN_STS_GPIO_STS(offset)); | 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 | struct ub953_data *priv = gpiochip_get_data(gc); | 322 | struct ub953_data *priv = gpiochip_get_data(gc); |
| 323 | 323 | ||
| 324 | regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA, | 324 | return regmap_update_bits(priv->regmap, UB953_REG_LOCAL_GPIO_DATA, |
| 325 | UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset), | 325 | UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset), |
| 326 | value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : | 326 | value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : 0); |
| 327 | 0); | ||
| 328 | } | 327 | } |
| 329 | 328 | ||
| 330 | static int ub953_gpio_of_xlate(struct gpio_chip *gc, | 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 | gc->direction_input = ub953_gpio_direction_in; | 361 | gc->direction_input = ub953_gpio_direction_in; |
| 363 | gc->direction_output = ub953_gpio_direction_out; | 362 | gc->direction_output = ub953_gpio_direction_out; |
| 364 | gc->get = ub953_gpio_get; | 363 | gc->get = ub953_gpio_get; |
| 365 | gc->set = ub953_gpio_set; | 364 | gc->set_rv = ub953_gpio_set; |
| 366 | gc->of_xlate = ub953_gpio_of_xlate; | 365 | gc->of_xlate = ub953_gpio_of_xlate; |
| 367 | gc->of_gpio_n_cells = 2; | 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 | int ret; | 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 | ret = v4l2_subdev_routing_validate(sd, routing, | 402 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 412 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); | 403 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 413 | if (ret) | 404 | if (ret) |
| @@ -3861,14 +3861,6 @@ static int _ub960_set_routing(struct v4l2_subdev *sd, · 3860 unmodified lines | |||
| 3861 | }; | 3861 | }; |
| 3862 | int ret; | 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 | ret = v4l2_subdev_routing_validate(sd, routing, | 3864 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 3873 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | | 3865 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | |
| 3874 | V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX); | 3866 | V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX); |
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | // Copyright (c) 2015--2017 Intel Corporation. | 2 | // Copyright (c) 2015--2017 Intel Corporation. |
| 3 | 3 | ||
| 4 | #include <linux/delay.h> | 4 | #include <linux/delay.h> |
| 5 | #include <linux/gpio/consumer.h> | ||
| 5 | #include <linux/i2c.h> | 6 | #include <linux/i2c.h> |
| 6 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 7 | #include <linux/pm_runtime.h> | 8 | #include <linux/pm_runtime.h> |
| @@ -38,6 +39,7 @@ struct dw9714_device { · 30 unmodified lines | |||
| 38 | struct v4l2_subdev sd; | 39 | struct v4l2_subdev sd; |
| 39 | u16 current_val; | 40 | u16 current_val; |
| 40 | struct regulator *vcc; | 41 | struct regulator *vcc; |
| 42 | struct gpio_desc *powerdown_gpio; | ||
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 43 | static inline struct dw9714_device *to_dw9714_vcm(struct v4l2_ctrl *ctrl) | 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 | return hdl->error; | 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 | static int dw9714_probe(struct i2c_client *client) | 164 | static int dw9714_probe(struct i2c_client *client) |
| 141 | { | 165 | { |
| 142 | struct dw9714_device *dw9714_dev; | 166 | struct dw9714_device *dw9714_dev; |
| @@ -144,20 +168,25 @@ static int dw9714_probe(struct i2c_client *client) · 1 unmodified line | |||
| 144 | 168 | ||
| 145 | dw9714_dev = devm_kzalloc(&client->dev, sizeof(*dw9714_dev), | 169 | dw9714_dev = devm_kzalloc(&client->dev, sizeof(*dw9714_dev), |
| 146 | GFP_KERNEL); | 170 | GFP_KERNEL); |
| 147 | if (dw9714_dev == NULL) | 171 | if (!dw9714_dev) |
| 148 | return -ENOMEM; | 172 | return -ENOMEM; |
| 149 | 173 | ||
| 150 | dw9714_dev->vcc = devm_regulator_get(&client->dev, "vcc"); | 174 | dw9714_dev->vcc = devm_regulator_get(&client->dev, "vcc"); |
| 151 | if (IS_ERR(dw9714_dev->vcc)) | 175 | if (IS_ERR(dw9714_dev->vcc)) |
| 152 | return PTR_ERR(dw9714_dev->vcc); | 176 | return PTR_ERR(dw9714_dev->vcc); |
| 153 | 177 | ||
| 154 | rval = regulator_enable(dw9714_dev->vcc); | 178 | dw9714_dev->powerdown_gpio = devm_gpiod_get_optional(&client->dev, |
| 155 | if (rval < 0) { | 179 | "powerdown", |
| 156 | dev_err(&client->dev, "failed to enable vcc: %d\n", rval); | 180 | GPIOD_OUT_HIGH); |
| 157 | return rval; | 181 | if (IS_ERR(dw9714_dev->powerdown_gpio)) |
| 158 | } | 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 | v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); | 191 | v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); |
| 163 | dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | 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 | return 0; | 214 | return 0; |
| 186 | 215 | ||
| 187 | err_cleanup: | 216 | err_cleanup: |
| 188 | regulator_disable(dw9714_dev->vcc); | 217 | dw9714_power_down(dw9714_dev); |
| 189 | v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm); | 218 | v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm); |
| 190 | media_entity_cleanup(&dw9714_dev->sd.entity); | 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 | pm_runtime_disable(&client->dev); | 230 | pm_runtime_disable(&client->dev); |
| 202 | if (!pm_runtime_status_suspended(&client->dev)) { | 231 | if (!pm_runtime_status_suspended(&client->dev)) { |
| 203 | ret = regulator_disable(dw9714_dev->vcc); | 232 | ret = dw9714_power_down(dw9714_dev); |
| 204 | if (ret) { | 233 | if (ret) { |
| 205 | dev_err(&client->dev, | 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 | pm_runtime_set_suspended(&client->dev); | 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 | usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10); | 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 | if (ret) | 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 | return ret; | 270 | return ret; |
| 242 | } | 271 | } |
| @@ -247,7 +276,7 @@ static int __maybe_unused dw9714_vcm_suspend(struct device *dev) · 4 unmodified lines | |||
| 247 | * The lens position is gradually moved in units of DW9714_CTRL_STEPS, | 276 | * The lens position is gradually moved in units of DW9714_CTRL_STEPS, |
| 248 | * to make the movements smoothly. | 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 | struct i2c_client *client = to_i2c_client(dev); | 281 | struct i2c_client *client = to_i2c_client(dev); |
| 253 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 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 | if (pm_runtime_suspended(&client->dev)) | 286 | if (pm_runtime_suspended(&client->dev)) |
| 258 | return 0; | 287 | return 0; |
| 259 | 288 | ||
| 260 | ret = regulator_enable(dw9714_dev->vcc); | 289 | ret = dw9714_power_up(dw9714_dev); |
| 261 | if (ret) { | 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 | return ret; | 292 | return ret; |
| 264 | } | 293 | } |
| 265 | usleep_range(1000, 2000); | ||
| 266 | 294 | ||
| 267 | for (val = dw9714_dev->current_val % DW9714_CTRL_STEPS; | 295 | for (val = dw9714_dev->current_val % DW9714_CTRL_STEPS; |
| 268 | val < dw9714_dev->current_val + DW9714_CTRL_STEPS - 1; | 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 | DW9714_VAL(val, DW9714_DEFAULT_S)); | 299 | DW9714_VAL(val, DW9714_DEFAULT_S)); |
| 272 | if (ret) | 300 | if (ret) |
| 273 | dev_err_ratelimited(dev, "%s I2C failure: %d", | 301 | dev_err_ratelimited(dev, "%s I2C failure: %d", |
| 274 | __func__, ret); | 302 | __func__, ret); |
| 275 | usleep_range(DW9714_CTRL_DELAY_US, DW9714_CTRL_DELAY_US + 10); | 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 | struct hi556 { | 633 | struct hi556 { |
| 628 | struct v4l2_subdev sd; | 634 | struct v4l2_subdev sd; |
| 629 | struct media_pad pad; | 635 | struct media_pad pad; |
| @@ -639,7 +645,7 @@ struct hi556 { · 9 unmodified lines | |||
| 639 | /* GPIOs, clocks, etc. */ | 645 | /* GPIOs, clocks, etc. */ |
| 640 | struct gpio_desc *reset_gpio; | 646 | struct gpio_desc *reset_gpio; |
| 641 | struct clk *clk; | 647 | struct clk *clk; |
| 642 | struct regulator *avdd; | 648 | struct regulator_bulk_data supplies[ARRAY_SIZE(hi556_supply_names)]; |
| 643 | 649 | ||
| 644 | /* Current mode */ | 650 | /* Current mode */ |
| 645 | const struct hi556_mode *cur_mode; | 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 | int ret; | 762 | int ret; |
| 757 | u32 val; | 763 | u32 val; |
| 758 | 764 | ||
| 759 | if (pattern) { | 765 | ret = hi556_read_reg(hi556, HI556_REG_ISP, |
| 760 | ret = hi556_read_reg(hi556, HI556_REG_ISP, | 766 | HI556_REG_VALUE_08BIT, &val); |
| 761 | HI556_REG_VALUE_08BIT, &val); | 767 | if (ret) |
| 762 | if (ret) | 768 | return ret; |
| 763 | return ret; | ||
| 764 | 769 | ||
| 765 | ret = hi556_write_reg(hi556, HI556_REG_ISP, | 770 | val = pattern ? (val | HI556_REG_ISP_TPG_EN) : |
| 766 | HI556_REG_VALUE_08BIT, | 771 | (val & ~HI556_REG_ISP_TPG_EN); |
| 767 | val | HI556_REG_ISP_TPG_EN); | 772 | |
| 768 | if (ret) | 773 | ret = hi556_write_reg(hi556, HI556_REG_ISP, |
| 769 | return ret; | 774 | HI556_REG_VALUE_08BIT, val); |
| 770 | } | 775 | if (ret) |
| 776 | return ret; | ||
| 777 | |||
| 778 | val = pattern ? BIT(pattern - 1) : 0; | ||
| 771 | 779 | ||
| 772 | return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN, | 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 | static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) | 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 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | 1298 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
| 1291 | struct hi556 *hi556 = to_hi556(sd); | 1299 | struct hi556 *hi556 = to_hi556(sd); |
| 1292 | int ret; | ||
| 1293 | 1300 | ||
| 1294 | gpiod_set_value_cansleep(hi556->reset_gpio, 1); | 1301 | gpiod_set_value_cansleep(hi556->reset_gpio, 1); |
| 1295 | 1302 | regulator_bulk_disable(ARRAY_SIZE(hi556_supply_names), | |
| 1296 | ret = regulator_disable(hi556->avdd); | 1303 | hi556->supplies); |
| 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 | |||
| 1303 | clk_disable_unprepare(hi556->clk); | 1304 | clk_disable_unprepare(hi556->clk); |
| 1304 | return 0; | 1305 | return 0; |
| 1305 | } | 1306 | } |
| @@ -1314,14 +1315,20 @@ static int hi556_resume(struct device *dev) · 8 unmodified lines | |||
| 1314 | if (ret) | 1315 | if (ret) |
| 1315 | return ret; | 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 | if (ret) { | 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 | clk_disable_unprepare(hi556->clk); | 1322 | clk_disable_unprepare(hi556->clk); |
| 1321 | return ret; | 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 | usleep_range(5000, 5500); | 1332 | usleep_range(5000, 5500); |
| 1326 | return 0; | 1333 | return 0; |
| 1327 | } | 1334 | } |
| @@ -1330,7 +1337,7 @@ static int hi556_probe(struct i2c_client *client) · 2 unmodified lines | |||
| 1330 | { | 1337 | { |
| 1331 | struct hi556 *hi556; | 1338 | struct hi556 *hi556; |
| 1332 | bool full_power; | 1339 | bool full_power; |
| 1333 | int ret; | 1340 | int i, ret; |
| 1334 | 1341 | ||
| 1335 | ret = hi556_check_hwcfg(&client->dev); | 1342 | ret = hi556_check_hwcfg(&client->dev); |
| 1336 | if (ret) | 1343 | if (ret) |
| @@ -1353,11 +1360,15 @@ static int hi556_probe(struct i2c_client *client) · 16 unmodified lines | |||
| 1353 | return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), | 1360 | return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), |
| 1354 | "failed to get clock\n"); | 1361 | "failed to get clock\n"); |
| 1355 | 1362 | ||
| 1356 | /* The regulator core will provide a "dummy" regulator if necessary */ | 1363 | for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++) |
| 1357 | hi556->avdd = devm_regulator_get(&client->dev, "avdd"); | 1364 | hi556->supplies[i].supply = hi556_supply_names[i]; |
| 1358 | if (IS_ERR(hi556->avdd)) | 1365 | |
| 1359 | return dev_err_probe(&client->dev, PTR_ERR(hi556->avdd), | 1366 | ret = devm_regulator_bulk_get(&client->dev, |
| 1360 | "failed to get avdd regulator\n"); | 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 | full_power = acpi_dev_state_d0(&client->dev); | 1373 | full_power = acpi_dev_state_d0(&client->dev); |
| 1363 | if (full_power) { | 1374 | if (full_power) { |
| @@ -20,6 +20,8 @@ · 19 unmodified lines | |||
| 20 | #include <media/v4l2-fwnode.h> | 20 | #include <media/v4l2-fwnode.h> |
| 21 | #include <media/v4l2-subdev.h> | 21 | #include <media/v4l2-subdev.h> |
| 22 | 22 | ||
| 23 | #include "ccs-pll.h" | ||
| 24 | |||
| 23 | /* Chip ID */ | 25 | /* Chip ID */ |
| 24 | #define IMX214_REG_CHIP_ID CCI_REG16(0x0016) | 26 | #define IMX214_REG_CHIP_ID CCI_REG16(0x0016) |
| 25 | #define IMX214_CHIP_ID 0x0214 | 27 | #define IMX214_CHIP_ID 0x0214 |
| @@ -30,11 +32,9 @@ · 4 unmodified lines | |||
| 30 | 32 | ||
| 31 | #define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106) | 33 | #define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106) |
| 32 | 34 | ||
| 33 | #define IMX214_DEFAULT_CLK_FREQ 24000000 | ||
| 34 | #define IMX214_DEFAULT_LINK_FREQ 600000000 | 35 | #define IMX214_DEFAULT_LINK_FREQ 600000000 |
| 35 | /* Keep wrong link frequency for backward compatibility */ | 36 | /* Keep wrong link frequency for backward compatibility */ |
| 36 | #define IMX214_DEFAULT_LINK_FREQ_LEGACY 480000000 | 37 | #define IMX214_DEFAULT_LINK_FREQ_LEGACY 480000000 |
| 37 | #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10) | ||
| 38 | #define IMX214_FPS 30 | 38 | #define IMX214_FPS 30 |
| 39 | 39 | ||
| 40 | /* V-TIMING internal */ | 40 | /* V-TIMING internal */ |
| @@ -84,6 +84,7 @@ · 43 unmodified lines | |||
| 84 | #define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A | 84 | #define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A |
| 85 | #define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06 | 85 | #define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06 |
| 86 | #define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08 | 86 | #define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08 |
| 87 | #define IMX214_BITS_PER_PIXEL_MASK 0xFF | ||
| 87 | 88 | ||
| 88 | #define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114) | 89 | #define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114) |
| 89 | #define IMX214_CSI_2_LANE_MODE 1 | 90 | #define IMX214_CSI_2_LANE_MODE 1 |
| @@ -249,6 +250,10 @@ struct imx214 { · 159 unmodified lines | |||
| 249 | struct clk *xclk; | 250 | struct clk *xclk; |
| 250 | struct regmap *regmap; | 251 | struct regmap *regmap; |
| 251 | 252 | ||
| 253 | struct ccs_pll pll; | ||
| 254 | |||
| 255 | struct v4l2_fwnode_endpoint bus_cfg; | ||
| 256 | |||
| 252 | struct v4l2_subdev sd; | 257 | struct v4l2_subdev sd; |
| 253 | struct media_pad pad; | 258 | struct media_pad pad; |
| 254 | 259 | ||
| @@ -299,16 +304,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = { · 44 unmodified lines | |||
| 299 | { IMX214_REG_DIG_CROP_WIDTH, 4096 }, | 304 | { IMX214_REG_DIG_CROP_WIDTH, 4096 }, |
| 300 | { IMX214_REG_DIG_CROP_HEIGHT, 2304 }, | 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 | { CCI_REG8(0x3A03), 0x09 }, | 307 | { CCI_REG8(0x3A03), 0x09 }, |
| 313 | { CCI_REG8(0x3A04), 0x50 }, | 308 | { CCI_REG8(0x3A04), 0x50 }, |
| 314 | { CCI_REG8(0x3A05), 0x01 }, | 309 | { CCI_REG8(0x3A05), 0x01 }, |
| @@ -362,16 +357,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = { · 47 unmodified lines | |||
| 362 | { IMX214_REG_DIG_CROP_WIDTH, 1920 }, | 357 | { IMX214_REG_DIG_CROP_WIDTH, 1920 }, |
| 363 | { IMX214_REG_DIG_CROP_HEIGHT, 1080 }, | 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 | { CCI_REG8(0x3A03), 0x04 }, | 360 | { CCI_REG8(0x3A03), 0x04 }, |
| 376 | { CCI_REG8(0x3A04), 0xF8 }, | 361 | { CCI_REG8(0x3A04), 0xF8 }, |
| 377 | { CCI_REG8(0x3A05), 0x02 }, | 362 | { CCI_REG8(0x3A05), 0x02 }, |
| @@ -405,9 +390,6 @@ static const struct cci_reg_sequence mode_table_common[] = { · 27 unmodified lines | |||
| 405 | /* ATR setting */ | 390 | /* ATR setting */ |
| 406 | { IMX214_REG_ATR_FAST_MOVE, 2 }, | 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 | /* global setting */ | 393 | /* global setting */ |
| 412 | /* basic config */ | 394 | /* basic config */ |
| 413 | { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK }, | 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 | return 0; | 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 | static int imx214_update_digital_gain(struct imx214 *imx214, u32 val) | 786 | static int imx214_update_digital_gain(struct imx214 *imx214, u32 val) |
| 781 | { | 787 | { |
| 782 | int ret = 0; | 788 | int ret = 0; |
| @@ -877,9 +883,6 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = { · 94 unmodified lines | |||
| 877 | 883 | ||
| 878 | static int imx214_ctrls_init(struct imx214 *imx214) | 884 | static int imx214_ctrls_init(struct imx214 *imx214) |
| 879 | { | 885 | { |
| 880 | static const s64 link_freq[] = { | ||
| 881 | IMX214_DEFAULT_LINK_FREQ | ||
| 882 | }; | ||
| 883 | static const struct v4l2_area unit_size = { | 886 | static const struct v4l2_area unit_size = { |
| 884 | .width = 1120, | 887 | .width = 1120, |
| 885 | .height = 1120, | 888 | .height = 1120, |
| @@ -900,15 +903,14 @@ static int imx214_ctrls_init(struct imx214 *imx214) · 14 unmodified lines | |||
| 900 | if (ret) | 903 | if (ret) |
| 901 | return ret; | 904 | return ret; |
| 902 | 905 | ||
| 903 | imx214->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, NULL, | 906 | imx214->pixel_rate = |
| 904 | V4L2_CID_PIXEL_RATE, 0, | 907 | v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_PIXEL_RATE, 1, |
| 905 | IMX214_DEFAULT_PIXEL_RATE, 1, | 908 | INT_MAX, 1, 1); |
| 906 | IMX214_DEFAULT_PIXEL_RATE); | ||
| 907 | 909 | ||
| 908 | imx214->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, | 910 | imx214->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, |
| 909 | V4L2_CID_LINK_FREQ, | 911 | V4L2_CID_LINK_FREQ, |
| 910 | ARRAY_SIZE(link_freq) - 1, | 912 | imx214->bus_cfg.nr_of_link_frequencies - 1, |
| 911 | 0, link_freq); | 913 | 0, imx214->bus_cfg.link_frequencies); |
| 912 | if (imx214->link_freq) | 914 | if (imx214->link_freq) |
| 913 | imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 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 | const struct v4l2_mbus_framefmt *fmt; | 1013 | const struct v4l2_mbus_framefmt *fmt; |
| 1012 | struct v4l2_subdev_state *state; | 1014 | struct v4l2_subdev_state *state; |
| 1013 | const struct imx214_mode *mode; | 1015 | const struct imx214_mode *mode; |
| 1016 | int bit_rate_mbps; | ||
| 1014 | int ret; | 1017 | int ret; |
| 1015 | 1018 | ||
| 1016 | ret = cci_multi_reg_write(imx214->regmap, mode_table_common, | 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 | return ret; | 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 | ret = cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE, | 1041 | ret = cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE, |
| 1024 | IMX214_CSI_4_LANE_MODE, NULL); | 1042 | IMX214_CSI_4_LANE_MODE, NULL); |
| 1025 | if (ret) { | 1043 | if (ret) { |
| @@ -1097,6 +1115,109 @@ err_rpm_put: · 71 unmodified lines | |||
| 1097 | return ret; | 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 | static int imx214_get_frame_interval(struct v4l2_subdev *subdev, | 1221 | static int imx214_get_frame_interval(struct v4l2_subdev *subdev, |
| 1101 | struct v4l2_subdev_state *sd_state, | 1222 | struct v4l2_subdev_state *sd_state, |
| 1102 | struct v4l2_subdev_frame_interval *fival) | 1223 | struct v4l2_subdev_frame_interval *fival) |
| @@ -1203,12 +1324,10 @@ static int imx214_identify_module(struct imx214 *imx214) · 100 unmodified lines | |||
| 1203 | return 0; | 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 | struct fwnode_handle *endpoint; | 1330 | struct fwnode_handle *endpoint; |
| 1209 | struct v4l2_fwnode_endpoint bus_cfg = { | ||
| 1210 | .bus_type = V4L2_MBUS_CSI2_DPHY, | ||
| 1211 | }; | ||
| 1212 | unsigned int i; | 1331 | unsigned int i; |
| 1213 | int ret; | 1332 | int ret; |
| 1214 | 1333 | ||
| @@ -1216,42 +1335,52 @@ static int imx214_parse_fwnode(struct device *dev) · 1 unmodified line | |||
| 1216 | if (!endpoint) | 1335 | if (!endpoint) |
| 1217 | return dev_err_probe(dev, -EINVAL, "endpoint node not found\n"); | 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 | if (ret) { | 1341 | if (ret) { |
| 1221 | dev_err_probe(dev, ret, "parsing endpoint node failed\n"); | 1342 | dev_err_probe(dev, ret, "parsing endpoint node failed\n"); |
| 1222 | goto done; | 1343 | goto error; |
| 1223 | } | 1344 | } |
| 1224 | 1345 | ||
| 1225 | /* Check the number of MIPI CSI2 data lanes */ | 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 | ret = dev_err_probe(dev, -EINVAL, | 1348 | ret = dev_err_probe(dev, -EINVAL, |
| 1228 | "only 4 data lanes are currently supported\n"); | 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 | dev_warn(dev, "Only one link-frequency supported, please review your DT. Continuing anyway\n"); | 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++) { | 1356 | for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { |
| 1236 | if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ) | 1357 | u64 freq = bus_cfg->link_frequencies[i]; |
| 1358 | struct ccs_pll pll; | ||
| 1359 | |||
| 1360 | if (!imx214_pll_calculate(imx214, &pll, freq)) | ||
| 1237 | break; | 1361 | break; |
| 1238 | if (bus_cfg.link_frequencies[i] == | 1362 | if (freq == IMX214_DEFAULT_LINK_FREQ_LEGACY) { |
| 1239 | IMX214_DEFAULT_LINK_FREQ_LEGACY) { | ||
| 1240 | dev_warn(dev, | 1363 | dev_warn(dev, |
| 1241 | "link-frequencies %d not supported, please review your DT. Continuing anyway\n", | 1364 | "link-frequencies %d not supported, please review your DT. Continuing anyway\n", |
| 1242 | IMX214_DEFAULT_LINK_FREQ); | 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 | break; | 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 | ret = dev_err_probe(dev, -EINVAL, | 1375 | ret = dev_err_probe(dev, -EINVAL, |
| 1249 | "link-frequencies %d not supported, please review your DT\n", | 1376 | "link-frequencies %lld not supported, please review your DT\n", |
| 1250 | IMX214_DEFAULT_LINK_FREQ); | 1377 | bus_cfg->nr_of_link_frequencies ? |
| 1378 | bus_cfg->link_frequencies[0] : 0); | ||
| 1251 | 1379 | ||
| 1252 | done: | 1380 | return 0; |
| 1253 | v4l2_fwnode_endpoint_free(&bus_cfg); | 1381 | |
| 1254 | fwnode_handle_put(endpoint); | 1382 | error: |
| 1383 | v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | ||
| 1255 | return ret; | 1384 | return ret; |
| 1256 | } | 1385 | } |
| 1257 | 1386 | ||
| @@ -1261,10 +1390,6 @@ static int imx214_probe(struct i2c_client *client) · 3 unmodified lines | |||
| 1261 | struct imx214 *imx214; | 1390 | struct imx214 *imx214; |
| 1262 | int ret; | 1391 | int ret; |
| 1263 | 1392 | ||
| 1264 | ret = imx214_parse_fwnode(dev); | ||
| 1265 | if (ret) | ||
| 1266 | return ret; | ||
| 1267 | |||
| 1268 | imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL); | 1393 | imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL); |
| 1269 | if (!imx214) | 1394 | if (!imx214) |
| 1270 | return -ENOMEM; | 1395 | return -ENOMEM; |
| @@ -1276,11 +1401,6 @@ static int imx214_probe(struct i2c_client *client) · 5 unmodified lines | |||
| 1276 | return dev_err_probe(dev, PTR_ERR(imx214->xclk), | 1401 | return dev_err_probe(dev, PTR_ERR(imx214->xclk), |
| 1277 | "failed to get xclk\n"); | 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 | ret = imx214_get_regulators(dev, imx214); | 1404 | ret = imx214_get_regulators(dev, imx214); |
| 1285 | if (ret < 0) | 1405 | if (ret < 0) |
| 1286 | return dev_err_probe(dev, ret, "failed to get regulators\n"); | 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 | return dev_err_probe(dev, PTR_ERR(imx214->regmap), | 1415 | return dev_err_probe(dev, PTR_ERR(imx214->regmap), |
| 1296 | "failed to initialize CCI\n"); | 1416 | "failed to initialize CCI\n"); |
| 1297 | 1417 | ||
| 1418 | ret = imx214_parse_fwnode(dev, imx214); | ||
| 1419 | if (ret) | ||
| 1420 | return ret; | ||
| 1421 | |||
| 1298 | v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); | 1422 | v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); |
| 1299 | imx214->sd.internal_ops = &imx214_internal_ops; | 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 | * Enable power initially, to avoid warnings | 1426 | * Enable power initially, to avoid warnings |
| 1303 | * from clk_disable on power_off | 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 | ret = imx214_identify_module(imx214); | 1433 | ret = imx214_identify_module(imx214); |
| 1308 | if (ret) | 1434 | if (ret) |
| @@ -1333,6 +1459,12 @@ static int imx214_probe(struct i2c_client *client) · 24 unmodified lines | |||
| 1333 | pm_runtime_set_active(imx214->dev); | 1459 | pm_runtime_set_active(imx214->dev); |
| 1334 | pm_runtime_enable(imx214->dev); | 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 | ret = v4l2_async_register_subdev_sensor(&imx214->sd); | 1468 | ret = v4l2_async_register_subdev_sensor(&imx214->sd); |
| 1337 | if (ret < 0) { | 1469 | if (ret < 0) { |
| 1338 | dev_err_probe(dev, ret, | 1470 | dev_err_probe(dev, ret, |
| @@ -1358,6 +1490,9 @@ free_ctrl: · 19 unmodified lines | |||
| 1358 | error_power_off: | 1490 | error_power_off: |
| 1359 | imx214_power_off(imx214->dev); | 1491 | imx214_power_off(imx214->dev); |
| 1360 | 1492 | ||
| 1493 | error_fwnode: | ||
| 1494 | v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | ||
| 1495 | |||
| 1361 | return ret; | 1496 | return ret; |
| 1362 | } | 1497 | } |
| 1363 | 1498 | ||
| @@ -1370,6 +1505,8 @@ static void imx214_remove(struct i2c_client *client) · 6 unmodified lines | |||
| 1370 | v4l2_subdev_cleanup(sd); | 1505 | v4l2_subdev_cleanup(sd); |
| 1371 | media_entity_cleanup(&imx214->sd.entity); | 1506 | media_entity_cleanup(&imx214->sd.entity); |
| 1372 | v4l2_ctrl_handler_free(&imx214->ctrls); | 1507 | v4l2_ctrl_handler_free(&imx214->ctrls); |
| 1508 | v4l2_fwnode_endpoint_free(&imx214->bus_cfg); | ||
| 1509 | |||
| 1373 | pm_runtime_disable(&client->dev); | 1510 | pm_runtime_disable(&client->dev); |
| 1374 | if (!pm_runtime_status_suspended(&client->dev)) { | 1511 | if (!pm_runtime_status_suspended(&client->dev)) { |
| 1375 | imx214_power_off(imx214->dev); | 1512 | imx214_power_off(imx214->dev); |
| @@ -1294,7 +1294,6 @@ static int imx290_subdev_init(struct imx290 *imx290) · 1293 unmodified lines | |||
| 1294 | * will already be prevented even before the delay. | 1294 | * will already be prevented even before the delay. |
| 1295 | */ | 1295 | */ |
| 1296 | v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); | 1296 | v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); |
| 1297 | imx290->sd.dev = imx290->dev; | ||
| 1298 | pm_runtime_mark_last_busy(imx290->dev); | 1297 | pm_runtime_mark_last_busy(imx290->dev); |
| 1299 | pm_runtime_put_autosuspend(imx290->dev); | 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 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), | 1251 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), |
| 1252 | "failed to get reset GPIO\n"); | 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 | if (IS_ERR(sensor->clk)) | 1255 | if (IS_ERR(sensor->clk)) |
| 1256 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), | 1256 | return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), |
| 1257 | "failed to get clock\n"); | 1257 | "failed to get clock\n"); |
| @@ -600,7 +600,7 @@ static int lt6911uxe_probe(struct i2c_client *client) · 599 unmodified lines | |||
| 600 | 600 | ||
| 601 | v4l2_i2c_subdev_init(<6911uxe->sd, client, <6911uxe_subdev_ops); | 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 | if (IS_ERR(lt6911uxe->reset_gpio)) | 604 | if (IS_ERR(lt6911uxe->reset_gpio)) |
| 605 | return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio), | 605 | return dev_err_probe(dev, PTR_ERR(lt6911uxe->reset_gpio), |
| 606 | "failed to get reset gpio\n"); | 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 | MAX9286_0X0F_RESERVED | priv->gpio_state); | 1193 | MAX9286_0X0F_RESERVED | priv->gpio_state); |
| 1194 | } | 1194 | } |
| 1195 | 1195 | ||
| 1196 | static void max9286_gpiochip_set(struct gpio_chip *chip, | 1196 | static int max9286_gpiochip_set(struct gpio_chip *chip, |
| 1197 | unsigned int offset, int value) | 1197 | unsigned int offset, int value) |
| 1198 | { | 1198 | { |
| 1199 | struct max9286_priv *priv = gpiochip_get_data(chip); | 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 | static int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset) | 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 | gpio->owner = THIS_MODULE; | 1220 | gpio->owner = THIS_MODULE; |
| 1221 | gpio->ngpio = 2; | 1221 | gpio->ngpio = 2; |
| 1222 | gpio->base = -1; | 1222 | gpio->base = -1; |
| 1223 | gpio->set = max9286_gpiochip_set; | 1223 | gpio->set_rv = max9286_gpiochip_set; |
| 1224 | gpio->get = max9286_gpiochip_get; | 1224 | gpio->get = max9286_gpiochip_get; |
| 1225 | gpio->can_sleep = true; | 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 | int ret; | 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 | ret = v4l2_subdev_routing_validate(sd, routing, | 373 | ret = v4l2_subdev_routing_validate(sd, routing, |
| 381 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); | 374 | V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); |
| 382 | if (ret) | 375 | if (ret) |
| @@ -297,13 +297,13 @@ static int max96717_gpiochip_get(struct gpio_chip *gpiochip, · 296 unmodified lines | |||
| 297 | return !!(val & MAX96717_GPIO_OUT); | 297 | return !!(val & MAX96717_GPIO_OUT); |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static void max96717_gpiochip_set(struct gpio_chip *gpiochip, | 300 | static int max96717_gpiochip_set(struct gpio_chip *gpiochip, |
| 301 | unsigned int offset, int value) | 301 | unsigned int offset, int value) |
| 302 | { | 302 | { |
| 303 | struct max96717_priv *priv = gpiochip_get_data(gpiochip); | 303 | struct max96717_priv *priv = gpiochip_get_data(gpiochip); |
| 304 | 304 | ||
| 305 | cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | 305 | return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), |
| 306 | MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL); | 306 | MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL); |
| 307 | } | 307 | } |
| 308 | 308 | ||
| 309 | static int max96717_gpio_get_direction(struct gpio_chip *gpiochip, | 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 | gc->get_direction = max96717_gpio_get_direction; | 355 | gc->get_direction = max96717_gpio_get_direction; |
| 356 | gc->direction_input = max96717_gpio_direction_in; | 356 | gc->direction_input = max96717_gpio_direction_in; |
| 357 | gc->direction_output = max96717_gpio_direction_out; | 357 | gc->direction_output = max96717_gpio_direction_out; |
| 358 | gc->set = max96717_gpiochip_set; | 358 | gc->set_rv = max96717_gpiochip_set; |
| 359 | gc->get = max96717_gpiochip_get; | 359 | gc->get = max96717_gpiochip_get; |
| 360 | gc->of_gpio_n_cells = 2; | ||
| 361 | 360 | ||
| 362 | /* Disable GPIO forwarding */ | 361 | /* Disable GPIO forwarding */ |
| 363 | for (i = 0; i < gc->ngpio; i++) | 362 | for (i = 0; i < gc->ngpio; i++) |
| @@ -261,6 +261,7 @@ · 260 unmodified lines | |||
| 261 | #define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) | 261 | #define MT9M114_CAM_PGA_PGA_CONTROL CCI_REG16(0xc95e) |
| 262 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) | 262 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE CCI_REG8(0xc97e) |
| 263 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) | 263 | #define MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE BIT(0) |
| 264 | #define MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE 0x00 | ||
| 264 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) | 265 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N CCI_REG16(0xc980) |
| 265 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) | 266 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(m, n) (((n) << 8) | (m)) |
| 266 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) | 267 | #define MT9M114_CAM_SYSCTL_PLL_DIVIDER_P CCI_REG16(0xc982) |
| @@ -377,6 +378,7 @@ struct mt9m114 { · 110 unmodified lines | |||
| 377 | struct gpio_desc *reset; | 378 | struct gpio_desc *reset; |
| 378 | struct regulator_bulk_data supplies[3]; | 379 | struct regulator_bulk_data supplies[3]; |
| 379 | struct v4l2_fwnode_endpoint bus_cfg; | 380 | struct v4l2_fwnode_endpoint bus_cfg; |
| 381 | bool bypass_pll; | ||
| 380 | 382 | ||
| 381 | struct { | 383 | struct { |
| 382 | unsigned int m; | 384 | unsigned int m; |
| @@ -743,14 +745,21 @@ static int mt9m114_initialize(struct mt9m114 *sensor) · 360 unmodified lines | |||
| 743 | } | 745 | } |
| 744 | 746 | ||
| 745 | /* Configure the PLL. */ | 747 | /* Configure the PLL. */ |
| 746 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, | 748 | if (sensor->bypass_pll) { |
| 747 | MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); | 749 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, |
| 748 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, | 750 | MT9M114_CAM_SYSCTL_PLL_DISABLE_VALUE, &ret); |
| 749 | MT9M114_CAM_SYSCTL_PLL_DIVIDER_VALUE(sensor->pll.m, | 751 | } else { |
| 750 | sensor->pll.n), | 752 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_ENABLE, |
| 751 | &ret); | 753 | MT9M114_CAM_SYSCTL_PLL_ENABLE_VALUE, &ret); |
| 752 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_P, | 754 | cci_write(sensor->regmap, MT9M114_CAM_SYSCTL_PLL_DIVIDER_M_N, |
| 753 | MT9M114_CAM_SYSCTL_PLL_DIVIDER_P_VALUE(sensor->pll.p), &ret); | 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 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, | 763 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_PIXCLK, |
| 755 | sensor->pixrate, &ret); | 764 | sensor->pixrate, &ret); |
| 756 | 765 | ||
| @@ -781,41 +790,25 @@ static int mt9m114_initialize(struct mt9m114 *sensor) · 24 unmodified lines | |||
| 781 | return 0; | 790 | return 0; |
| 782 | } | 791 | } |
| 783 | 792 | ||
| 784 | static int mt9m114_configure(struct mt9m114 *sensor, | 793 | static int mt9m114_configure_pa(struct mt9m114 *sensor, |
| 785 | struct v4l2_subdev_state *pa_state, | 794 | struct v4l2_subdev_state *state) |
| 786 | struct v4l2_subdev_state *ifp_state) | ||
| 787 | { | 795 | { |
| 788 | const struct v4l2_mbus_framefmt *pa_format; | 796 | const struct v4l2_mbus_framefmt *format; |
| 789 | const struct v4l2_rect *pa_crop; | 797 | const struct v4l2_rect *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; | ||
| 794 | unsigned int hratio, vratio; | 798 | unsigned int hratio, vratio; |
| 795 | u64 output_format; | ||
| 796 | u64 read_mode; | 799 | u64 read_mode; |
| 797 | int ret = 0; | 800 | int ret; |
| 798 | |||
| 799 | pa_format = v4l2_subdev_state_get_format(pa_state, 0); | ||
| 800 | pa_crop = v4l2_subdev_state_get_crop(pa_state, 0); | ||
| 801 | 801 | ||
| 802 | ifp_format = v4l2_subdev_state_get_format(ifp_state, 1); | 802 | format = v4l2_subdev_state_get_format(state, 0); |
| 803 | ifp_info = mt9m114_format_info(sensor, 1, ifp_format->code); | 803 | crop = v4l2_subdev_state_get_crop(state, 0); |
| 804 | ifp_crop = v4l2_subdev_state_get_crop(ifp_state, 0); | ||
| 805 | ifp_compose = v4l2_subdev_state_get_compose(ifp_state, 0); | ||
| 806 | 804 | ||
| 807 | ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, | 805 | ret = cci_read(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
| 808 | &read_mode, NULL); | 806 | &read_mode, NULL); |
| 809 | if (ret < 0) | 807 | if (ret < 0) |
| 810 | return ret; | 808 | return ret; |
| 811 | 809 | ||
| 812 | ret = cci_read(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, | 810 | hratio = crop->width / format->width; |
| 813 | &output_format, NULL); | 811 | vratio = crop->height / format->height; |
| 814 | if (ret < 0) | ||
| 815 | return ret; | ||
| 816 | |||
| 817 | hratio = pa_crop->width / pa_format->width; | ||
| 818 | vratio = pa_crop->height / pa_format->height; | ||
| 819 | 812 | ||
| 820 | /* | 813 | /* |
| 821 | * Pixel array crop and binning. The CAM_SENSOR_CFG_CPIPE_LAST_ROW | 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 | * example sensor modes. | 817 | * example sensor modes. |
| 825 | */ | 818 | */ |
| 826 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, | 819 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_START, |
| 827 | pa_crop->left, &ret); | 820 | crop->left, &ret); |
| 828 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, | 821 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_START, |
| 829 | pa_crop->top, &ret); | 822 | crop->top, &ret); |
| 830 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_X_ADDR_END, | 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 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_Y_ADDR_END, | 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 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CFG_CPIPE_LAST_ROW, | 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 | read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | | 830 | read_mode &= ~(MT9M114_CAM_SENSOR_CONTROL_X_READ_OUT_MASK | |
| 838 | MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); | 831 | MT9M114_CAM_SENSOR_CONTROL_Y_READ_OUT_MASK); |
| @@ -845,6 +838,29 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 6 unmodified lines | |||
| 845 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, | 838 | cci_write(sensor->regmap, MT9M114_CAM_SENSOR_CONTROL_READ_MODE, |
| 846 | read_mode, &ret); | 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 | * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left | 865 | * Color pipeline (IFP) cropping and scaling. Subtract 4 from the left |
| 850 | * and top coordinates to compensate for the lines and columns removed | 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 | * not in the hardware. | 868 | * not in the hardware. |
| 853 | */ | 869 | */ |
| 854 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, | 870 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_XOFFSET, |
| 855 | ifp_crop->left - 4, &ret); | 871 | crop->left - 4, &ret); |
| 856 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, | 872 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_YOFFSET, |
| 857 | ifp_crop->top - 4, &ret); | 873 | crop->top - 4, &ret); |
| 858 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, | 874 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_WIDTH, |
| 859 | ifp_crop->width, &ret); | 875 | crop->width, &ret); |
| 860 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, | 876 | cci_write(sensor->regmap, MT9M114_CAM_CROP_WINDOW_HEIGHT, |
| 861 | ifp_crop->height, &ret); | 877 | crop->height, &ret); |
| 862 | 878 | ||
| 863 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, | 879 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_WIDTH, |
| 864 | ifp_compose->width, &ret); | 880 | compose->width, &ret); |
| 865 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, | 881 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_HEIGHT, |
| 866 | ifp_compose->height, &ret); | 882 | compose->height, &ret); |
| 867 | 883 | ||
| 868 | /* AWB and AE windows, use the full frame. */ | 884 | /* AWB and AE windows, use the full frame. */ |
| 869 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XSTART, | 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 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, | 887 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YSTART, |
| 872 | 0, &ret); | 888 | 0, &ret); |
| 873 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, | 889 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_XEND, |
| 874 | ifp_compose->width - 1, &ret); | 890 | compose->width - 1, &ret); |
| 875 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AWB_CLIP_WINDOW_YEND, | 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 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, | 894 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XSTART, |
| 879 | 0, &ret); | 895 | 0, &ret); |
| 880 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, | 896 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YSTART, |
| 881 | 0, &ret); | 897 | 0, &ret); |
| 882 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_XEND, | 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 | cci_write(sensor->regmap, MT9M114_CAM_STAT_AE_INITIAL_WINDOW_YEND, | 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 | cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE, | 903 | cci_write(sensor->regmap, MT9M114_CAM_CROP_CROPMODE, |
| 888 | MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | | 904 | MT9M114_CAM_CROP_MODE_AWB_AUTO_CROP_EN | |
| @@ -894,7 +910,7 @@ static int mt9m114_configure(struct mt9m114 *sensor, · 5 unmodified lines | |||
| 894 | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | | 910 | MT9M114_CAM_OUTPUT_FORMAT_FORMAT_MASK | |
| 895 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | | 911 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_BYTES | |
| 896 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); | 912 | MT9M114_CAM_OUTPUT_FORMAT_SWAP_RED_BLUE); |
| 897 | output_format |= ifp_info->output_format; | 913 | output_format |= info->output_format; |
| 898 | 914 | ||
| 899 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, | 915 | cci_write(sensor->regmap, MT9M114_CAM_OUTPUT_FORMAT, |
| 900 | output_format, &ret); | 916 | output_format, &ret); |
| @@ -925,7 +941,11 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor, · 24 unmodified lines | |||
| 925 | if (ret) | 941 | if (ret) |
| 926 | return ret; | 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 | if (ret) | 949 | if (ret) |
| 930 | goto error; | 950 | goto error; |
| 931 | 951 | ||
| @@ -1599,13 +1619,9 @@ static int mt9m114_ifp_get_frame_interval(struct v4l2_subdev *sd, · 667 unmodified lines | |||
| 1599 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | 1619 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
| 1600 | return -EINVAL; | 1620 | return -EINVAL; |
| 1601 | 1621 | ||
| 1602 | mutex_lock(sensor->ifp.hdl.lock); | ||
| 1603 | |||
| 1604 | ival->numerator = 1; | 1622 | ival->numerator = 1; |
| 1605 | ival->denominator = sensor->ifp.frame_rate; | 1623 | ival->denominator = sensor->ifp.frame_rate; |
| 1606 | 1624 | ||
| 1607 | mutex_unlock(sensor->ifp.hdl.lock); | ||
| 1608 | |||
| 1609 | return 0; | 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 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | 1640 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) |
| 1625 | return -EINVAL; | 1641 | return -EINVAL; |
| 1626 | 1642 | ||
| 1627 | mutex_lock(sensor->ifp.hdl.lock); | ||
| 1628 | |||
| 1629 | if (ival->numerator != 0 && ival->denominator != 0) | 1643 | if (ival->numerator != 0 && ival->denominator != 0) |
| 1630 | sensor->ifp.frame_rate = min_t(unsigned int, | 1644 | sensor->ifp.frame_rate = min_t(unsigned int, |
| 1631 | ival->denominator / ival->numerator, | 1645 | ival->denominator / ival->numerator, |
| @@ -1639,8 +1653,6 @@ static int mt9m114_ifp_set_frame_interval(struct v4l2_subdev *sd, · 7 unmodified lines | |||
| 1639 | if (sensor->streaming) | 1653 | if (sensor->streaming) |
| 1640 | ret = mt9m114_set_frame_rate(sensor); | 1654 | ret = mt9m114_set_frame_rate(sensor); |
| 1641 | 1655 | ||
| 1642 | mutex_unlock(sensor->ifp.hdl.lock); | ||
| 1643 | |||
| 1644 | return ret; | 1656 | return ret; |
| 1645 | } | 1657 | } |
| 1646 | 1658 | ||
| @@ -2235,9 +2247,22 @@ static const struct dev_pm_ops mt9m114_pm_ops = { · 588 unmodified lines | |||
| 2235 | * Probe & Remove | 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 | static int mt9m114_clk_init(struct mt9m114 *sensor) | 2263 | static int mt9m114_clk_init(struct mt9m114 *sensor) |
| 2239 | { | 2264 | { |
| 2240 | unsigned int link_freq; | 2265 | unsigned int pixrate; |
| 2241 | 2266 | ||
| 2242 | /* Hardcode the PLL multiplier and dividers to default settings. */ | 2267 | /* Hardcode the PLL multiplier and dividers to default settings. */ |
| 2243 | sensor->pll.m = 32; | 2268 | sensor->pll.m = 32; |
| @@ -2249,19 +2274,29 @@ static int mt9m114_clk_init(struct mt9m114 *sensor) · 5 unmodified lines | |||
| 2249 | * for 16-bit per pixel, transmitted in DDR over a single lane. For | 2274 | * for 16-bit per pixel, transmitted in DDR over a single lane. For |
| 2250 | * parallel mode, the sensor ouputs one pixel in two PIXCLK cycles. | 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 | 2278 | /* |
| 2256 | ? sensor->pixrate * 8 : sensor->pixrate * 2; | 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 || | 2289 | /* Check if the PLL configuration fits the configured link frequency. */ |
| 2259 | sensor->bus_cfg.link_frequencies[0] != link_freq) { | 2290 | pixrate = clk_get_rate(sensor->clk) * sensor->pll.m |
| 2260 | dev_err(&sensor->client->dev, "Unsupported DT link-frequencies\n"); | 2291 | / ((sensor->pll.n + 1) * (sensor->pll.p + 1)); |
| 2261 | return -EINVAL; | 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 | static int mt9m114_identify(struct mt9m114 *sensor) | 2302 | static int mt9m114_identify(struct mt9m114 *sensor) |
| @@ -1469,14 +1469,15 @@ static int ov2659_probe(struct i2c_client *client) · 1468 unmodified lines | |||
| 1469 | V4L2_CID_TEST_PATTERN, | 1469 | V4L2_CID_TEST_PATTERN, |
| 1470 | ARRAY_SIZE(ov2659_test_pattern_menu) - 1, | 1470 | ARRAY_SIZE(ov2659_test_pattern_menu) - 1, |
| 1471 | 0, 0, ov2659_test_pattern_menu); | 1471 | 0, 0, ov2659_test_pattern_menu); |
| 1472 | ov2659->sd.ctrl_handler = &ov2659->ctrls; | ||
| 1473 | 1472 | ||
| 1474 | if (ov2659->ctrls.error) { | 1473 | if (ov2659->ctrls.error) { |
| 1475 | dev_err(&client->dev, "%s: control initialization error %d\n", | 1474 | dev_err(&client->dev, "%s: control initialization error %d\n", |
| 1476 | __func__, ov2659->ctrls.error); | 1475 | __func__, ov2659->ctrls.error); |
| 1476 | v4l2_ctrl_handler_free(&ov2659->ctrls); | ||
| 1477 | return ov2659->ctrls.error; | 1477 | return ov2659->ctrls.error; |
| 1478 | } | 1478 | } |
| 1479 | 1479 | ||
| 1480 | ov2659->sd.ctrl_handler = &ov2659->ctrls; | ||
| 1480 | sd = &ov2659->sd; | 1481 | sd = &ov2659->sd; |
| 1481 | client->flags |= I2C_CLIENT_SCCB; | 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 | struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); | 767 | struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); |
| 768 | struct v4l2_ctrl_handler *ctrl_hdlr; | 768 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 769 | const struct ov2740_mode *cur_mode; | ||
| 770 | s64 exposure_max, h_blank, pixel_rate; | 769 | s64 exposure_max, h_blank, pixel_rate; |
| 771 | u32 vblank_min, vblank_max, vblank_default; | 770 | u32 vblank_min, vblank_max, vblank_default; |
| 772 | struct v4l2_fwnode_device_properties props; | 771 | struct v4l2_fwnode_device_properties props; |
| 773 | int size; | ||
| 774 | int ret; | 772 | int ret; |
| 775 | 773 | ||
| 776 | ctrl_hdlr = &ov2740->ctrl_handler; | 774 | ctrl_hdlr = &ov2740->ctrl_handler; |
| @@ -778,12 +776,10 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 1 unmodified line | |||
| 778 | if (ret) | 776 | if (ret) |
| 779 | return ret; | 777 | return ret; |
| 780 | 778 | ||
| 781 | cur_mode = ov2740->cur_mode; | ||
| 782 | size = ARRAY_SIZE(link_freq_menu_items); | ||
| 783 | |||
| 784 | ov2740->link_freq = | 779 | ov2740->link_freq = |
| 785 | v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2740_ctrl_ops, | 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 | ov2740->supported_modes->link_freq_index, | 783 | ov2740->supported_modes->link_freq_index, |
| 788 | link_freq_menu_items); | 784 | link_freq_menu_items); |
| 789 | if (ov2740->link_freq) | 785 | if (ov2740->link_freq) |
| @@ -794,14 +790,14 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 4 unmodified lines | |||
| 794 | V4L2_CID_PIXEL_RATE, 0, | 790 | V4L2_CID_PIXEL_RATE, 0, |
| 795 | pixel_rate, 1, pixel_rate); | 791 | pixel_rate, 1, pixel_rate); |
| 796 | 792 | ||
| 797 | vblank_min = cur_mode->vts_min - cur_mode->height; | 793 | vblank_min = ov2740->cur_mode->vts_min - ov2740->cur_mode->height; |
| 798 | vblank_max = cur_mode->vts_max - cur_mode->height; | 794 | vblank_max = ov2740->cur_mode->vts_max - ov2740->cur_mode->height; |
| 799 | vblank_default = cur_mode->vts_def - cur_mode->height; | 795 | vblank_default = ov2740->cur_mode->vts_def - ov2740->cur_mode->height; |
| 800 | ov2740->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, | 796 | ov2740->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 801 | V4L2_CID_VBLANK, vblank_min, | 797 | V4L2_CID_VBLANK, vblank_min, |
| 802 | vblank_max, 1, vblank_default); | 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 | ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, | 801 | ov2740->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 806 | V4L2_CID_HBLANK, h_blank, h_blank, 1, | 802 | V4L2_CID_HBLANK, h_blank, h_blank, 1, |
| 807 | h_blank); | 803 | h_blank); |
| @@ -814,7 +810,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740) · 6 unmodified lines | |||
| 814 | v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_DIGITAL_GAIN, | 810 | v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, V4L2_CID_DIGITAL_GAIN, |
| 815 | OV2740_DGTL_GAIN_MIN, OV2740_DGTL_GAIN_MAX, | 811 | OV2740_DGTL_GAIN_MIN, OV2740_DGTL_GAIN_MAX, |
| 816 | OV2740_DGTL_GAIN_STEP, OV2740_DGTL_GAIN_DEFAULT); | 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 | ov2740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, | 814 | ov2740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov2740_ctrl_ops, |
| 819 | V4L2_CID_EXPOSURE, | 815 | V4L2_CID_EXPOSURE, |
| 820 | OV2740_EXPOSURE_MIN, exposure_max, | 816 | OV2740_EXPOSURE_MIN, exposure_max, |
| @@ -2688,10 +2688,15 @@ static int ov5670_probe(struct i2c_client *client) · 2687 unmodified lines | |||
| 2688 | if (ret) | 2688 | if (ret) |
| 2689 | return dev_err_probe(&client->dev, ret, "GPIO probe failed\n"); | 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 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); | 2696 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); |
| 2693 | if (!handle) | 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 | ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; | 2701 | ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; |
| 2697 | ov5670->endpoint.bus.mipi_csi2.num_data_lanes = 2; | 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 | unsigned int i; | 1222 | unsigned int i; |
| 1223 | int ret; | 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 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); | 1229 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); |
| 1226 | if (!endpoint) | 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 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | 1234 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); |
| 1230 | fwnode_handle_put(endpoint); | 1235 | fwnode_handle_put(endpoint); |
| @@ -1486,9 +1486,14 @@ static int ov7251_check_hwcfg(struct ov7251 *ov7251) · 1485 unmodified lines | |||
| 1486 | unsigned int i, j; | 1486 | unsigned int i, j; |
| 1487 | int ret; | 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 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); | 1493 | endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); |
| 1490 | if (!endpoint) | 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 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | 1498 | ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); |
| 1494 | fwnode_handle_put(endpoint); | 1499 | fwnode_handle_put(endpoint); |
| @@ -2991,7 +2991,8 @@ static int ov8865_probe(struct i2c_client *client) · 2990 unmodified lines | |||
| 2991 | 2991 | ||
| 2992 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); | 2992 | handle = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); |
| 2993 | if (!handle) | 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 | sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; | 2997 | sensor->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; |
| 2997 | 2998 | ||
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | #include "saa711x_regs.h" | 26 | #include "saa711x_regs.h" |
| 27 | 27 | ||
| 28 | #include <linux/bitops.h> | ||
| 28 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 30 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| @@ -664,15 +665,6 @@ static const unsigned char saa7115_init_misc[] = { · 633 unmodified lines | |||
| 664 | 0x00, 0x00 | 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 | static int saa711x_decode_vps(u8 *dst, u8 *p) | 668 | static int saa711x_decode_vps(u8 *dst, u8 *p) |
| 677 | { | 669 | { |
| 678 | static const u8 biphase_tbl[] = { | 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 | vbi->type = V4L2_SLICED_TELETEXT_B; | 1219 | vbi->type = V4L2_SLICED_TELETEXT_B; |
| 1228 | break; | 1220 | break; |
| 1229 | case 4: | 1221 | case 4: |
| 1230 | if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1])) | 1222 | if (!parity8(p[0]) || !parity8(p[1])) |
| 1231 | return 0; | 1223 | return 0; |
| 1232 | vbi->type = V4L2_SLICED_CAPTION_525; | 1224 | vbi->type = V4L2_SLICED_CAPTION_525; |
| 1233 | break; | 1225 | break; |
| @@ -114,7 +114,7 @@ static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) · 113 unmodified lines | |||
| 114 | 114 | ||
| 115 | /* --------------- I2C --------------- */ | 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 | struct tc358743_state *state = to_state(sd); | 119 | struct tc358743_state *state = to_state(sd); |
| 120 | struct i2c_client *client = state->i2c_client; | 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 | v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n", | 140 | v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed: %d\n", |
| 141 | __func__, reg, client->addr, err); | 141 | __func__, reg, client->addr, err); |
| 142 | } | 142 | } |
| 143 | return err != ARRAY_SIZE(msgs); | ||
| 143 | } | 144 | } |
| 144 | 145 | ||
| 145 | static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | 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 | __le32 val = 0; | 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 | return le32_to_cpu(val); | 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 | static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) | 218 | static noinline void i2c_wrreg(struct v4l2_subdev *sd, u16 reg, u32 val, u32 n) |
| 209 | { | 219 | { |
| 210 | __le32 raw = cpu_to_le32(val); | 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 | return i2c_rdreg(sd, reg, 2); | 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 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) | 253 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) |
| 237 | { | 254 | { |
| 238 | i2c_wrreg(sd, reg, val, 2); | 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 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | 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 | * hotplug is enabled. See register DDC_CTL */ | 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 | tc358743_enable_interrupts(sd, true); | 444 | tc358743_enable_interrupts(sd, true); |
| 428 | tc358743_s_ctrl_detect_tx_5v(sd); | 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 | return 0; | 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 | static int tc358743_get_fmt(struct v4l2_subdev *sd, | 1723 | static int tc358743_get_fmt(struct v4l2_subdev *sd, |
| 1695 | struct v4l2_subdev_state *sd_state, | 1724 | struct v4l2_subdev_state *sd_state, |
| 1696 | struct v4l2_subdev_format *format) | 1725 | struct v4l2_subdev_format *format) |
| 1697 | { | 1726 | { |
| 1698 | struct tc358743_state *state = to_state(sd); | 1727 | struct tc358743_state *state = to_state(sd); |
| 1699 | u8 vi_rep = i2c_rd8(sd, VI_REP); | ||
| 1700 | 1728 | ||
| 1701 | if (format->pad != 0) | 1729 | if (format->pad != 0) |
| 1702 | return -EINVAL; | 1730 | return -EINVAL; |
| @@ -1706,23 +1734,7 @@ static int tc358743_get_fmt(struct v4l2_subdev *sd, · 3 unmodified lines | |||
| 1706 | format->format.height = state->timings.bt.height; | 1734 | format->format.height = state->timings.bt.height; |
| 1707 | format->format.field = V4L2_FIELD_NONE; | 1735 | format->format.field = V4L2_FIELD_NONE; |
| 1708 | 1736 | ||
| 1709 | switch (vi_rep & MASK_VOUT_COLOR_SEL) { | 1737 | format->format.colorspace = tc358743_g_colorspace(format->format.code); |
| 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 | } | ||
| 1726 | 1738 | ||
| 1727 | return 0; | 1739 | return 0; |
| 1728 | } | 1740 | } |
| @@ -1736,19 +1748,14 @@ static int tc358743_set_fmt(struct v4l2_subdev *sd, · 7 unmodified lines | |||
| 1736 | u32 code = format->format.code; /* is overwritten by get_fmt */ | 1748 | u32 code = format->format.code; /* is overwritten by get_fmt */ |
| 1737 | int ret = tc358743_get_fmt(sd, sd_state, format); | 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 | if (ret) | 1756 | if (ret) |
| 1742 | return ret; | 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 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | 1759 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) |
| 1753 | return 0; | 1760 | return 0; |
| 1754 | 1761 | ||
| @@ -1972,8 +1979,19 @@ static int tc358743_probe_of(struct tc358743_state *state) · 217 unmodified lines | |||
| 1972 | state->pdata.refclk_hz = clk_get_rate(refclk); | 1979 | state->pdata.refclk_hz = clk_get_rate(refclk); |
| 1973 | state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; | 1980 | state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; |
| 1974 | state->pdata.enable_hdcp = false; | 1981 | state->pdata.enable_hdcp = false; |
| 1975 | /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ | 1982 | /* |
| 1976 | state->pdata.fifo_level = 16; | 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 | * The PLL input clock is obtained by dividing refclk by pll_prd. | 1996 | * The PLL input clock is obtained by dividing refclk by pll_prd. |
| 1979 | * It must be between 6 MHz and 40 MHz, lower frequency is better. | 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 | * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. | 2012 | * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. |
| 1995 | * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. | 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 | bps_pr_lane = 2 * endpoint.link_frequencies[0]; | 2016 | bps_pr_lane = 2 * endpoint.link_frequencies[0]; |
| 1998 | if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { | 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 | state->pdata.refclk_hz * state->pdata.pll_prd; | 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 | 2028 | * FIXME: These timings are from REF_02 for 594 or 972 Mbps per lane |
| 2010 | * link frequency). In principle it should be possible to calculate | 2029 | * (297 MHz or 486 MHz link frequency). |
| 2030 | * In principle it should be possible to calculate | ||
| 2011 | * them based on link frequency and resolution. | 2031 | * them based on link frequency and resolution. |
| 2012 | */ | 2032 | */ |
| 2013 | if (bps_pr_lane != 594000000U) | 2033 | switch (bps_pr_lane) { |
| 2034 | default: | ||
| 2014 | dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); | 2035 | dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); |
| 2015 | state->pdata.lineinitcnt = 0xe80; | 2036 | fallthrough; |
| 2016 | state->pdata.lptxtimecnt = 0x003; | 2037 | case 594000000U: |
| 2017 | /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ | 2038 | state->pdata.lineinitcnt = 0xe80; |
| 2018 | state->pdata.tclk_headercnt = 0x1403; | 2039 | state->pdata.lptxtimecnt = 0x003; |
| 2019 | state->pdata.tclk_trailcnt = 0x00; | 2040 | /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ |
| 2020 | /* ths-preparecnt: 3, ths-zerocnt: 1 */ | 2041 | state->pdata.tclk_headercnt = 0x1403; |
| 2021 | state->pdata.ths_headercnt = 0x0103; | 2042 | state->pdata.tclk_trailcnt = 0x00; |
| 2022 | state->pdata.twakeup = 0x4882; | 2043 | /* ths-preparecnt: 3, ths-zerocnt: 1 */ |
| 2023 | state->pdata.tclk_postcnt = 0x008; | 2044 | state->pdata.ths_headercnt = 0x0103; |
| 2024 | state->pdata.ths_trailcnt = 0x2; | 2045 | state->pdata.twakeup = 0x4882; |
| 2025 | state->pdata.hstxvregcnt = 0; | 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 | state->reset_gpio = devm_gpiod_get_optional(dev, "reset", | 2065 | state->reset_gpio = devm_gpiod_get_optional(dev, "reset", |
| 2028 | GPIOD_OUT_LOW); | 2066 | GPIOD_OUT_LOW); |
| @@ -2061,6 +2099,7 @@ static int tc358743_probe(struct i2c_client *client) · 32 unmodified lines | |||
| 2061 | struct tc358743_platform_data *pdata = client->dev.platform_data; | 2099 | struct tc358743_platform_data *pdata = client->dev.platform_data; |
| 2062 | struct v4l2_subdev *sd; | 2100 | struct v4l2_subdev *sd; |
| 2063 | u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; | 2101 | u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; |
| 2102 | u16 chipid; | ||
| 2064 | int err; | 2103 | int err; |
| 2065 | 2104 | ||
| 2066 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 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 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | 2131 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; |
| 2093 | 2132 | ||
| 2094 | /* i2c access */ | 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 | v4l2_info(sd, "not a TC358743 on address 0x%x\n", | 2136 | v4l2_info(sd, "not a TC358743 on address 0x%x\n", |
| 2097 | client->addr << 1); | 2137 | client->addr << 1); |
| 2098 | return -ENODEV; | 2138 | return -ENODEV; |
| @@ -589,8 +589,8 @@ static void tda1997x_enable_edid(struct v4l2_subdev *sd) · 588 unmodified lines | |||
| 589 | 589 | ||
| 590 | v4l2_dbg(1, debug, sd, "%s\n", __func__); | 590 | v4l2_dbg(1, debug, sd, "%s\n", __func__); |
| 591 | 591 | ||
| 592 | /* Enable hotplug after 100ms */ | 592 | /* Enable hotplug after 143ms */ |
| 593 | schedule_delayed_work(&state->delayed_work_enable_hpd, HZ / 10); | 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 | #define VD55G1_WIDTH 804 | 112 | #define VD55G1_WIDTH 804 |
| 113 | #define VD55G1_HEIGHT 704 | 113 | #define VD55G1_HEIGHT 704 |
| 114 | #define VD55G1_DEFAULT_MODE 0 | 114 | #define VD55G1_MODE_DEF 0 |
| 115 | #define VD55G1_NB_GPIOS 4 | 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 | #define VD55G1_DGAIN_DEF 256 | 117 | #define VD55G1_DGAIN_DEF 256 |
| 118 | #define VD55G1_AGAIN_DEF 19 | 118 | #define VD55G1_AGAIN_DEF 19 |
| 119 | #define VD55G1_EXPO_MAX_TERM 64 | 119 | #define VD55G1_EXPO_MAX_TERM 64 |
| @@ -129,8 +129,8 @@ · 9 unmodified lines | |||
| 129 | #define VD55G1_FWPATCH_REVISION_MINOR 9 | 129 | #define VD55G1_FWPATCH_REVISION_MINOR 9 |
| 130 | #define VD55G1_XCLK_FREQ_MIN (6 * HZ_PER_MHZ) | 130 | #define VD55G1_XCLK_FREQ_MIN (6 * HZ_PER_MHZ) |
| 131 | #define VD55G1_XCLK_FREQ_MAX (27 * HZ_PER_MHZ) | 131 | #define VD55G1_XCLK_FREQ_MAX (27 * HZ_PER_MHZ) |
| 132 | #define VD55G1_MIPI_RATE_MIN (250 * HZ_PER_MHZ) | 132 | #define VD55G1_MIPI_RATE_MIN (250 * MEGA) |
| 133 | #define VD55G1_MIPI_RATE_MAX (1200 * HZ_PER_MHZ) | 133 | #define VD55G1_MIPI_RATE_MAX (1200 * MEGA) |
| 134 | 134 | ||
| 135 | static const u8 patch_array[] = { | 135 | static const u8 patch_array[] = { |
| 136 | 0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, | 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 | return ret; | 883 | return ret; |
| 884 | } | 884 | } |
| 885 | 885 | ||
| 886 | static void vd55g1_update_img_pad_format(struct vd55g1 *sensor, | 886 | static void vd55g1_update_pad_fmt(struct vd55g1 *sensor, |
| 887 | const struct vd55g1_mode *mode, | 887 | const struct vd55g1_mode *mode, u32 code, |
| 888 | u32 code, | 888 | struct v4l2_mbus_framefmt *fmt) |
| 889 | struct v4l2_mbus_framefmt *fmt) | ||
| 890 | { | 889 | { |
| 891 | fmt->code = code; | 890 | fmt->code = code; |
| 892 | fmt->width = mode->width; | 891 | fmt->width = mode->width; |
| @@ -1038,8 +1037,6 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd, · 145 unmodified lines | |||
| 1038 | if (ret < 0) | 1037 | if (ret < 0) |
| 1039 | return ret; | 1038 | return ret; |
| 1040 | 1039 | ||
| 1041 | vd55g1_write(sensor, VD55G1_REG_EXT_CLOCK, sensor->xclk_freq, &ret); | ||
| 1042 | |||
| 1043 | /* Configure output */ | 1040 | /* Configure output */ |
| 1044 | vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE, | 1041 | vd55g1_write(sensor, VD55G1_REG_MIPI_DATA_RATE, |
| 1045 | sensor->mipi_rate, &ret); | 1042 | sensor->mipi_rate, &ret); |
| @@ -1084,7 +1081,7 @@ static int vd55g1_enable_streams(struct v4l2_subdev *sd, · 38 unmodified lines | |||
| 1084 | 1081 | ||
| 1085 | err_rpm_put: | 1082 | err_rpm_put: |
| 1086 | pm_runtime_put(sensor->dev); | 1083 | pm_runtime_put(sensor->dev); |
| 1087 | return 0; | 1084 | return -EINVAL; |
| 1088 | } | 1085 | } |
| 1089 | 1086 | ||
| 1090 | static int vd55g1_disable_streams(struct v4l2_subdev *sd, | 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 | width, height, sd_fmt->format.width, | 1228 | width, height, sd_fmt->format.width, |
| 1232 | sd_fmt->format.height); | 1229 | sd_fmt->format.height); |
| 1233 | 1230 | ||
| 1234 | vd55g1_update_img_pad_format(sensor, new_mode, sd_fmt->format.code, | 1231 | vd55g1_update_pad_fmt(sensor, new_mode, sd_fmt->format.code, |
| 1235 | &sd_fmt->format); | 1232 | &sd_fmt->format); |
| 1236 | 1233 | ||
| 1237 | /* | 1234 | /* |
| 1238 | * Use binning to maximize the crop rectangle size, and centre it in the | 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 | static int vd55g1_init_state(struct v4l2_subdev *sd, | 1259 | static int vd55g1_init_state(struct v4l2_subdev *sd, |
| 1263 | struct v4l2_subdev_state *sd_state) | 1260 | struct v4l2_subdev_state *sd_state) |
| 1264 | { | 1261 | { |
| 1265 | unsigned int def_mode = VD55G1_DEFAULT_MODE; | ||
| 1266 | struct vd55g1 *sensor = to_vd55g1(sd); | 1262 | struct vd55g1 *sensor = to_vd55g1(sd); |
| 1267 | struct v4l2_subdev_format fmt = { 0 }; | 1263 | struct v4l2_subdev_format fmt = { 0 }; |
| 1268 | struct v4l2_subdev_route routes[] = { | 1264 | struct v4l2_subdev_route routes[] = { |
| @@ -1279,8 +1275,9 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, · 10 unmodified lines | |||
| 1279 | if (ret) | 1275 | if (ret) |
| 1280 | return ret; | 1276 | return ret; |
| 1281 | 1277 | ||
| 1282 | vd55g1_update_img_pad_format(sensor, &vd55g1_supported_modes[def_mode], | 1278 | vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF], |
| 1283 | VD55G1_MEDIA_BUS_FMT_DEF, &fmt.format); | 1279 | vd55g1_mbus_codes[VD55G1_MBUS_CODE_DEF].code, |
| 1280 | &fmt.format); | ||
| 1284 | 1281 | ||
| 1285 | return vd55g1_set_pad_fmt(sd, sd_state, &fmt); | 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 | goto disable_clock; | 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 | ret = vd55g1_patch(sensor); | 1616 | ret = vd55g1_patch(sensor); |
| 1617 | if (ret) { | 1617 | if (ret) { |
| 1618 | dev_err(dev, "Sensor patch failed %d\n", ret); | 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 | #include "cx18-driver.h" | 12 | #include "cx18-driver.h" |
| 12 | 13 | ||
| 13 | /* | 14 | /* |
| @@ -56,15 +57,6 @@ struct vbi_anc_data { · 42 unmodified lines | |||
| 56 | /* u8 fill[]; Variable number of fill bytes */ | 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 | static int decode_vps(u8 *dst, u8 *p) | 60 | static int decode_vps(u8 *dst, u8 *p) |
| 69 | { | 61 | { |
| 70 | static const u8 biphase_tbl[] = { | 62 | static const u8 biphase_tbl[] = { |
| @@ -278,7 +270,7 @@ int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, · 207 unmodified lines | |||
| 278 | break; | 270 | break; |
| 279 | case 6: | 271 | case 6: |
| 280 | sdid = V4L2_SLICED_CAPTION_525; | 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 | break; | 274 | break; |
| 283 | case 9: | 275 | case 9: |
| 284 | sdid = V4L2_SLICED_VPS; | 276 | sdid = V4L2_SLICED_VPS; |
| @@ -271,18 +271,6 @@ struct cx18_options { · 270 unmodified lines | |||
| 271 | #define CX18_SLICED_TYPE_WSS_625 (5) | 271 | #define CX18_SLICED_TYPE_WSS_625 (5) |
| 272 | #define CX18_SLICED_TYPE_VPS (7) | 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 | struct cx18_vb2_buffer { | 274 | struct cx18_vb2_buffer { |
| 287 | /* Common video buffer sub-system struct */ | 275 | /* Common video buffer sub-system struct */ |
| 288 | struct vb2_v4l2_buffer vb; | 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 | mdl->curr_buf = list_first_entry(&mdl->buf_list, | 371 | mdl->curr_buf = list_first_entry(&mdl->buf_list, |
| 372 | struct cx18_buffer, list); | 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 | * For some reason we've exhausted the buffers, but the MDL | 376 | * For some reason we've exhausted the buffers, but the MDL |
| 377 | * object still said some data was unread. | 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 | mdl->curr_buf = list_first_entry(&mdl->buf_list, | 764 | mdl->curr_buf = list_first_entry(&mdl->buf_list, |
| 765 | struct cx18_buffer, list); | 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 | * For some reason we've exhausted the buffers, but the MDL | 769 | * For some reason we've exhausted the buffers, but the MDL |
| 770 | * object still said some data was unread. | 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 | /* Himax HM2172 */ | 55 | /* Himax HM2172 */ |
| 56 | IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000), | 56 | IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000), |
| 57 | /* GalaxyCore GC0310 */ | 57 | /* GalaxyCore GC0310 */ |
| 58 | IPU_SENSOR_CONFIG("INT0310", 0), | 58 | IPU_SENSOR_CONFIG("INT0310", 1, 55692000), |
| 59 | /* Omnivision OV5693 */ | 59 | /* Omnivision OV5693 */ |
| 60 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), | 60 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), |
| 61 | /* Onsemi MT9M114 */ | ||
| 62 | IPU_SENSOR_CONFIG("INT33F0", 1, 384000000), | ||
| 61 | /* Omnivision OV2740 */ | 63 | /* Omnivision OV2740 */ |
| 62 | IPU_SENSOR_CONFIG("INT3474", 1, 180000000), | 64 | IPU_SENSOR_CONFIG("INT3474", 1, 180000000), |
| 65 | /* Omnivision OV5670 */ | ||
| 66 | IPU_SENSOR_CONFIG("INT3479", 1, 422400000), | ||
| 63 | /* Omnivision OV8865 */ | 67 | /* Omnivision OV8865 */ |
| 64 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), | 68 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), |
| 65 | /* Omnivision OV7251 */ | 69 | /* Omnivision OV7251 */ |
| @@ -78,7 +82,7 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { · 12 unmodified lines | |||
| 78 | /* Omnivision OV08A10 */ | 82 | /* Omnivision OV08A10 */ |
| 79 | IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000), | 83 | IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000), |
| 80 | /* Omnivision OV08x40 */ | 84 | /* Omnivision OV08x40 */ |
| 81 | IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000), | 85 | IPU_SENSOR_CONFIG("OVTI08F4", 3, 400000000, 749000000, 800000000), |
| 82 | /* Omnivision OV13B10 */ | 86 | /* Omnivision OV13B10 */ |
| 83 | IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000), | 87 | IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000), |
| 84 | IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), | 88 | IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), |
| @@ -86,6 +90,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { · 1 unmodified line | |||
| 86 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), | 90 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), |
| 87 | /* Omnivision OV8856 */ | 91 | /* Omnivision OV8856 */ |
| 88 | IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), | 92 | IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), |
| 93 | /* Toshiba T4KA3 */ | ||
| 94 | IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), | ||
| 89 | }; | 95 | }; |
| 90 | 96 | ||
| 91 | static const struct ipu_property_names prop_names = { | 97 | static const struct ipu_property_names prop_names = { |
| @@ -809,7 +815,8 @@ int ipu_bridge_init(struct device *dev, · 717 unmodified lines | |||
| 809 | return 0; | 815 | return 0; |
| 810 | 816 | ||
| 811 | if (!ipu_bridge_ivsc_is_ready()) | 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 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); | 821 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); |
| 815 | if (!bridge) | 822 | if (!bridge) |
| @@ -358,6 +358,8 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q) · 357 unmodified lines | |||
| 358 | static const int FBPT_WIDTH = DIV_ROUND_UP(CIO2_MAX_LOPS, | 358 | static const int FBPT_WIDTH = DIV_ROUND_UP(CIO2_MAX_LOPS, |
| 359 | CIO2_FBPT_SUBENTRY_UNIT); | 359 | CIO2_FBPT_SUBENTRY_UNIT); |
| 360 | const u32 num_buffers1 = CIO2_MAX_BUFFERS - 1; | 360 | const u32 num_buffers1 = CIO2_MAX_BUFFERS - 1; |
| 361 | struct v4l2_subdev_state *state; | ||
| 362 | const struct v4l2_mbus_framefmt *format; | ||
| 361 | const struct ipu3_cio2_fmt *fmt; | 363 | const struct ipu3_cio2_fmt *fmt; |
| 362 | void __iomem *const base = cio2->base; | 364 | void __iomem *const base = cio2->base; |
| 363 | u8 lanes, csi2bus = q->csi2.port; | 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 | struct cio2_csi2_timing timing = { 0 }; | 367 | struct cio2_csi2_timing timing = { 0 }; |
| 366 | int i, r; | 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 | if (!fmt) | 377 | if (!fmt) |
| 370 | return -EINVAL; | 378 | return -EINVAL; |
| 371 | 379 | ||
| @@ -1194,9 +1202,9 @@ static int cio2_subdev_subscribe_event(struct v4l2_subdev *sd, · 822 unmodified lines | |||
| 1194 | return v4l2_event_subscribe(fh, sub, 0, NULL); | 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 | const struct v4l2_mbus_framefmt fmt_default = { | 1208 | const struct v4l2_mbus_framefmt fmt_default = { |
| 1201 | .width = 1936, | 1209 | .width = 1936, |
| 1202 | .height = 1096, | 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 | .quantization = V4L2_QUANTIZATION_DEFAULT, | 1215 | .quantization = V4L2_QUANTIZATION_DEFAULT, |
| 1208 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, | 1216 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, |
| 1209 | }; | 1217 | }; |
| 1218 | struct v4l2_mbus_framefmt *format; | ||
| 1210 | 1219 | ||
| 1211 | /* Initialize try_fmt */ | 1220 | /* Initialize the format on the sink and source pads. */ |
| 1212 | format = v4l2_subdev_state_get_format(fh->state, CIO2_PAD_SINK); | 1221 | format = v4l2_subdev_state_get_format(state, CIO2_PAD_SINK); |
| 1213 | *format = fmt_default; | 1222 | *format = fmt_default; |
| 1214 | 1223 | ||
| 1215 | /* same as sink */ | 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 | *format = fmt_default; | 1226 | *format = fmt_default; |
| 1218 | 1227 | ||
| 1219 | return 0; | 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 | static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, | 1231 | static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, |
| 1242 | struct v4l2_subdev_state *sd_state, | 1232 | struct v4l2_subdev_state *sd_state, |
| 1243 | struct v4l2_subdev_format *fmt) | 1233 | struct v4l2_subdev_format *fmt) |
| 1244 | { | 1234 | { |
| 1245 | struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev); | ||
| 1246 | struct v4l2_mbus_framefmt *mbus; | 1235 | struct v4l2_mbus_framefmt *mbus; |
| 1247 | u32 mbus_code = fmt->format.code; | 1236 | u32 mbus_code = fmt->format.code; |
| 1248 | unsigned int i; | 1237 | unsigned int i; |
| @@ -1252,12 +1241,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd, · 3 unmodified lines | |||
| 1252 | * source always propagates from sink | 1241 | * source always propagates from sink |
| 1253 | */ | 1242 | */ |
| 1254 | if (fmt->pad == CIO2_PAD_SOURCE) | 1243 | if (fmt->pad == CIO2_PAD_SOURCE) |
| 1255 | return cio2_subdev_get_fmt(sd, sd_state, fmt); | 1244 | return v4l2_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; | ||
| 1261 | 1245 | ||
| 1262 | fmt->format.code = formats[0].mbus_code; | 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 | fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT); | 1256 | fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT); |
| 1273 | fmt->format.field = V4L2_FIELD_NONE; | 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 | *mbus = fmt->format; | 1264 | *mbus = fmt->format; |
| 1277 | mutex_unlock(&q->subdev_lock); | ||
| 1278 | 1265 | ||
| 1279 | return 0; | 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 | static const struct v4l2_subdev_internal_ops cio2_subdev_internal_ops = { | 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 | static const struct v4l2_subdev_pad_ops cio2_subdev_pad_ops = { | 1338 | static const struct v4l2_subdev_pad_ops cio2_subdev_pad_ops = { |
| 1352 | .link_validate = v4l2_subdev_link_validate_default, | 1339 | .link_validate = v4l2_subdev_link_validate_default, |
| 1353 | .get_fmt = cio2_subdev_get_fmt, | 1340 | .get_fmt = v4l2_subdev_get_fmt, |
| 1354 | .set_fmt = cio2_subdev_set_fmt, | 1341 | .set_fmt = cio2_subdev_set_fmt, |
| 1355 | .enum_mbus_code = cio2_subdev_enum_mbus_code, | 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 | static const u32 default_width = 1936; | 1490 | static const u32 default_width = 1936; |
| 1504 | static const u32 default_height = 1096; | 1491 | static const u32 default_height = 1096; |
| 1505 | const struct ipu3_cio2_fmt dflt_fmt = formats[0]; | ||
| 1506 | struct device *dev = &cio2->pci_dev->dev; | 1492 | struct device *dev = &cio2->pci_dev->dev; |
| 1507 | struct video_device *vdev = &q->vdev; | 1493 | struct video_device *vdev = &q->vdev; |
| 1508 | struct vb2_queue *vbq = &q->vbq; | 1494 | struct vb2_queue *vbq = &q->vbq; |
| 1509 | struct v4l2_subdev *subdev = &q->subdev; | 1495 | struct v4l2_subdev *subdev = &q->subdev; |
| 1510 | struct v4l2_mbus_framefmt *fmt; | ||
| 1511 | int r; | 1496 | int r; |
| 1512 | 1497 | ||
| 1513 | /* Initialize miscellaneous variables */ | 1498 | /* Initialize miscellaneous variables */ |
| 1514 | mutex_init(&q->lock); | 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 | q->format.width = default_width; | 1501 | q->format.width = default_width; |
| 1525 | q->format.height = default_height; | 1502 | q->format.height = default_height; |
| 1526 | q->format.pixelformat = dflt_fmt.fourcc; | 1503 | q->format.pixelformat = formats[0].fourcc; |
| 1527 | q->format.colorspace = V4L2_COLORSPACE_RAW; | 1504 | q->format.colorspace = V4L2_COLORSPACE_RAW; |
| 1528 | q->format.field = V4L2_FIELD_NONE; | 1505 | q->format.field = V4L2_FIELD_NONE; |
| 1529 | q->format.num_planes = 1; | 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 | CIO2_ENTITY_NAME " %td", q - cio2->queue); | 1544 | CIO2_ENTITY_NAME " %td", q - cio2->queue); |
| 1568 | subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | 1545 | subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; |
| 1569 | v4l2_set_subdevdata(subdev, cio2); | 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 | r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); | 1554 | r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); |
| 1571 | if (r) { | 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 | goto fail_subdev; | 1557 | goto fail_subdev; |
| 1574 | } | 1558 | } |
| 1575 | 1559 | ||
| @@ -1626,7 +1610,6 @@ fail_vdev_media_entity: · 50 unmodified lines | |||
| 1626 | fail_subdev_media_entity: | 1610 | fail_subdev_media_entity: |
| 1627 | cio2_fbpt_exit(q, dev); | 1611 | cio2_fbpt_exit(q, dev); |
| 1628 | fail_fbpt: | 1612 | fail_fbpt: |
| 1629 | mutex_destroy(&q->subdev_lock); | ||
| 1630 | mutex_destroy(&q->lock); | 1613 | mutex_destroy(&q->lock); |
| 1631 | 1614 | ||
| 1632 | return r; | 1615 | return r; |
| @@ -1639,7 +1622,6 @@ static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q) · 6 unmodified lines | |||
| 1639 | v4l2_device_unregister_subdev(&q->subdev); | 1622 | v4l2_device_unregister_subdev(&q->subdev); |
| 1640 | media_entity_cleanup(&q->subdev.entity); | 1623 | media_entity_cleanup(&q->subdev.entity); |
| 1641 | cio2_fbpt_exit(q, &cio2->pci_dev->dev); | 1624 | cio2_fbpt_exit(q, &cio2->pci_dev->dev); |
| 1642 | mutex_destroy(&q->subdev_lock); | ||
| 1643 | mutex_destroy(&q->lock); | 1625 | mutex_destroy(&q->lock); |
| 1644 | } | 1626 | } |
| 1645 | 1627 | ||
| @@ -351,9 +351,7 @@ struct cio2_queue { · 350 unmodified lines | |||
| 351 | 351 | ||
| 352 | /* Subdev, /dev/v4l-subdevX */ | 352 | /* Subdev, /dev/v4l-subdevX */ |
| 353 | struct v4l2_subdev subdev; | 353 | struct v4l2_subdev subdev; |
| 354 | struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */ | ||
| 355 | struct media_pad subdev_pads[CIO2_PADS]; | 354 | struct media_pad subdev_pads[CIO2_PADS]; |
| 356 | struct v4l2_mbus_framefmt subdev_fmt; | ||
| 357 | atomic_t frame_sequence; | 355 | atomic_t frame_sequence; |
| 358 | 356 | ||
| 359 | /* Video device, /dev/videoX */ | 357 | /* Video device, /dev/videoX */ |
| @@ -354,9 +354,9 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd, · 353 unmodified lines | |||
| 354 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); | 354 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); |
| 355 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | 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, | 357 | sink_streams = |
| 358 | CSI2_PAD_SINK, | 358 | v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK, |
| 359 | &streams_mask); | 359 | &streams_mask); |
| 360 | 360 | ||
| 361 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); | 361 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); |
| 362 | if (ret) | 362 | if (ret) |
| @@ -384,9 +384,9 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd, · 21 unmodified lines | |||
| 384 | struct media_pad *remote_pad; | 384 | struct media_pad *remote_pad; |
| 385 | u64 sink_streams; | 385 | u64 sink_streams; |
| 386 | 386 | ||
| 387 | sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC, | 387 | sink_streams = |
| 388 | CSI2_PAD_SINK, | 388 | v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK, |
| 389 | &streams_mask); | 389 | &streams_mask); |
| 390 | 390 | ||
| 391 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); | 391 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); |
| 392 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | 392 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); |
| @@ -40,7 +40,7 @@ struct ipu6_bus_device; · 39 unmodified lines | |||
| 40 | #define IPU6_ISYS_NUM_RECV_QUEUE 1 | 40 | #define IPU6_ISYS_NUM_RECV_QUEUE 1 |
| 41 | 41 | ||
| 42 | #define IPU6_ISYS_MIN_WIDTH 2U | 42 | #define IPU6_ISYS_MIN_WIDTH 2U |
| 43 | #define IPU6_ISYS_MIN_HEIGHT 2U | 43 | #define IPU6_ISYS_MIN_HEIGHT 1U |
| 44 | #define IPU6_ISYS_MAX_WIDTH 4672U | 44 | #define IPU6_ISYS_MAX_WIDTH 4672U |
| 45 | #define IPU6_ISYS_MAX_HEIGHT 3416U | 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 | ace_set_camera_owner(ace, ACE_CAMERA_IVSC); | 530 | ace_set_camera_owner(ace, ACE_CAMERA_IVSC); |
| 531 | 531 | ||
| 532 | mei_cldev_disable(cldev); | ||
| 533 | |||
| 532 | mutex_destroy(&ace->lock); | 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 | module_mei_cl_driver(mei_ace_driver); | 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 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); | 580 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); |
| 579 | MODULE_DESCRIPTION("Device driver for IVSC ACE"); | 581 | MODULE_DESCRIPTION("Device driver for IVSC ACE"); |
| 580 | MODULE_LICENSE("GPL"); | 582 | MODULE_LICENSE("GPL"); |
| @@ -760,6 +760,8 @@ static void mei_csi_remove(struct mei_cl_device *cldev) · 759 unmodified lines | |||
| 760 | 760 | ||
| 761 | pm_runtime_disable(&cldev->dev); | 761 | pm_runtime_disable(&cldev->dev); |
| 762 | 762 | ||
| 763 | mei_cldev_disable(cldev); | ||
| 764 | |||
| 763 | mutex_destroy(&csi->lock); | 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 | module_mei_cl_driver(mei_csi_driver); | 785 | module_mei_cl_driver(mei_csi_driver); |
| 784 | 786 | ||
| 785 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); | 787 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); |
| 786 | MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); | 788 | MODULE_AUTHOR("Wentong Wu"); |
| 787 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); | 789 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); |
| 788 | MODULE_DESCRIPTION("Device driver for IVSC CSI"); | 790 | MODULE_DESCRIPTION("Device driver for IVSC CSI"); |
| 789 | MODULE_LICENSE("GPL"); | 791 | MODULE_LICENSE("GPL"); |
| @@ -492,7 +492,14 @@ static int vidioc_s_dv_timings(struct file *file, void *fh, · 491 unmodified lines | |||
| 492 | static int vidioc_enum_dv_timings(struct file *file, void *fh, | 492 | static int vidioc_enum_dv_timings(struct file *file, void *fh, |
| 493 | struct v4l2_enum_dv_timings *timings) | 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 | static int vidioc_dv_timings_cap(struct file *file, void *fh, | 505 | static int vidioc_dv_timings_cap(struct file *file, void *fh, |
| @@ -52,26 +52,6 @@ · 51 unmodified lines | |||
| 52 | * | etc | 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 | /* Allocate a new buffer structure and associated PCI space in bytes. | 55 | /* Allocate a new buffer structure and associated PCI space in bytes. |
| 76 | * len must be a multiple of sizeof(u64) | 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 | return ret; | 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 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, | 298 | int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, |
| 327 | u16 controlselector, u16 size, void *buf) | 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 | int saa7164_cmd_send(struct saa7164_dev *dev, | 508 | int saa7164_cmd_send(struct saa7164_dev *dev, |
| 509 | u8 id, enum tmComResCmd command, u16 controlselector, | 509 | u8 id, enum tmComResCmd command, u16 controlselector, |
| 510 | u16 size, void *buf); | 510 | u16 size, void *buf); |
| 511 | void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno); | ||
| 512 | int saa7164_irq_dequeue(struct saa7164_dev *dev); | 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 | extern struct saa7164_buffer *saa7164_buffer_alloc( | 569 | extern struct saa7164_buffer *saa7164_buffer_alloc( |
| 571 | struct saa7164_port *port, u32 len); | 570 | struct saa7164_port *port, u32 len); |
| 572 | extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf); | 571 | extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf); |
| 573 | extern void saa7164_buffer_display(struct saa7164_buffer *buf); | ||
| 574 | extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i); | 572 | extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i); |
| 575 | extern int saa7164_buffer_cfg_port(struct saa7164_port *port); | 573 | extern int saa7164_buffer_cfg_port(struct saa7164_port *port); |
| 576 | extern struct saa7164_user_buffer *saa7164_buffer_alloc_user( | 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 | return -1; | 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 | static int solo_gpiochip_get(struct gpio_chip *chip, | 119 | static int solo_gpiochip_get(struct gpio_chip *chip, |
| 132 | unsigned int offset) | 120 | unsigned int offset) |
| 133 | { | 121 | { |
| @@ -139,8 +127,8 @@ static int solo_gpiochip_get(struct gpio_chip *chip, · 5 unmodified lines | |||
| 139 | return 1 & (ret >> (offset + 8)); | 127 | return 1 & (ret >> (offset + 8)); |
| 140 | } | 128 | } |
| 141 | 129 | ||
| 142 | static void solo_gpiochip_set(struct gpio_chip *chip, | 130 | static int solo_gpiochip_set(struct gpio_chip *chip, |
| 143 | unsigned int offset, int value) | 131 | unsigned int offset, int value) |
| 144 | { | 132 | { |
| 145 | struct solo_dev *solo_dev = gpiochip_get_data(chip); | 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 | solo_gpio_set(solo_dev, 1 << (offset + 8)); | 136 | solo_gpio_set(solo_dev, 1 << (offset + 8)); |
| 149 | else | 137 | else |
| 150 | solo_gpio_clear(solo_dev, 1 << (offset + 8)); | 138 | solo_gpio_clear(solo_dev, 1 << (offset + 8)); |
| 139 | |||
| 140 | return 0; | ||
| 151 | } | 141 | } |
| 152 | #endif | 142 | #endif |
| 153 | 143 | ||
| @@ -167,10 +157,8 @@ int solo_gpio_init(struct solo_dev *solo_dev) · 13 unmodified lines | |||
| 167 | solo_dev->gpio_dev.can_sleep = 0; | 157 | solo_dev->gpio_dev.can_sleep = 0; |
| 168 | 158 | ||
| 169 | solo_dev->gpio_dev.get_direction = solo_gpiochip_get_direction; | 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 | solo_dev->gpio_dev.get = solo_gpiochip_get; | 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 | ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); | 163 | ret = gpiochip_add_data(&solo_dev->gpio_dev, solo_dev); |
| 176 | 164 | ||
| @@ -26,6 +26,7 @@ · 25 unmodified lines | |||
| 26 | #include "vpu_cmds.h" | 26 | #include "vpu_cmds.h" |
| 27 | #include "vpu_rpc.h" | 27 | #include "vpu_rpc.h" |
| 28 | 28 | ||
| 29 | #define VDEC_SLOT_CNT_DFT 32 | ||
| 29 | #define VDEC_MIN_BUFFER_CAP 8 | 30 | #define VDEC_MIN_BUFFER_CAP 8 |
| 30 | #define VDEC_MIN_BUFFER_OUT 8 | 31 | #define VDEC_MIN_BUFFER_OUT 8 |
| 31 | 32 | ||
| @@ -41,6 +42,14 @@ struct vdec_fs_info { · 9 unmodified lines | |||
| 41 | u32 tag; | 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 | struct vdec_t { | 53 | struct vdec_t { |
| 45 | u32 seq_hdr_found; | 54 | u32 seq_hdr_found; |
| 46 | struct vpu_buffer udata; | 55 | struct vpu_buffer udata; |
| @@ -48,7 +57,8 @@ struct vdec_t { · 1 unmodified line | |||
| 48 | struct vpu_dec_codec_info codec_info; | 57 | struct vpu_dec_codec_info codec_info; |
| 49 | enum vpu_codec_state state; | 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 | u32 req_frame_count; | 62 | u32 req_frame_count; |
| 53 | struct vdec_fs_info mbi; | 63 | struct vdec_fs_info mbi; |
| 54 | struct vdec_fs_info dcp; | 64 | struct vdec_fs_info dcp; |
| @@ -232,6 +242,35 @@ static int vdec_ctrl_init(struct vpu_inst *inst) · 177 unmodified lines | |||
| 232 | V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, | 242 | V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, |
| 233 | 0, 1, 1, 0); | 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 | ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, | 274 | ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, |
| 236 | V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2); | 275 | V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 2); |
| 237 | if (ctrl) | 276 | if (ctrl) |
| @@ -258,6 +297,63 @@ static int vdec_ctrl_init(struct vpu_inst *inst) · 20 unmodified lines | |||
| 258 | return 0; | 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 | static void vdec_handle_resolution_change(struct vpu_inst *inst) | 357 | static void vdec_handle_resolution_change(struct vpu_inst *inst) |
| 262 | { | 358 | { |
| 263 | struct vdec_t *vdec = inst->priv; | 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 | struct vb2_v4l2_buffer *src_buf; | 810 | struct vb2_v4l2_buffer *src_buf; |
| 715 | int ret = 0; | 811 | int ret = 0; |
| 716 | 812 | ||
| 717 | if (!info || info->id >= ARRAY_SIZE(vdec->slots)) | 813 | if (!info || info->id >= vdec->slot_count) |
| 718 | return -EINVAL; | 814 | return -EINVAL; |
| 719 | 815 | ||
| 720 | vpu_inst_lock(inst); | 816 | vpu_inst_lock(inst); |
| 721 | vpu_buf = vdec->slots[info->id]; | 817 | vpu_buf = vdec->slots[info->id].curr; |
| 722 | if (!vpu_buf) { | 818 | if (!vpu_buf) { |
| 723 | dev_err(inst->dev, "[%d] decoded invalid frame[%d]\n", inst->id, info->id); | 819 | dev_err(inst->dev, "[%d] decoded invalid frame[%d]\n", inst->id, info->id); |
| 724 | ret = -EINVAL; | 820 | ret = -EINVAL; |
| @@ -739,11 +835,13 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) · 14 unmodified lines | |||
| 739 | if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) | 835 | if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) |
| 740 | dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); | 836 | dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); |
| 741 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); | 837 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); |
| 838 | vdec->slots[info->id].state = VPU_BUF_STATE_DECODED; | ||
| 742 | vdec->decoded_frame_count++; | 839 | vdec->decoded_frame_count++; |
| 743 | if (vdec->params.display_delay_enable) { | 840 | if (vdec->params.display_delay_enable) { |
| 744 | struct vpu_format *cur_fmt; | 841 | struct vpu_format *cur_fmt; |
| 745 | 842 | ||
| 746 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); | 843 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); |
| 844 | vdec->slots[info->id].state = VPU_BUF_STATE_READY; | ||
| 747 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); | 845 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); |
| 748 | for (int i = 0; i < vbuf->vb2_buf.num_planes; i++) | 846 | for (int i = 0; i < vbuf->vb2_buf.num_planes; i++) |
| 749 | vb2_set_plane_payload(&vbuf->vb2_buf, | 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 | struct vdec_t *vdec = inst->priv; | 864 | struct vdec_t *vdec = inst->priv; |
| 767 | int i; | 865 | int i; |
| 768 | 866 | ||
| 769 | for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { | 867 | for (i = 0; i < vdec->slot_count; i++) { |
| 770 | if (!vdec->slots[i]) | 868 | if (!vdec->slots[i].curr) |
| 771 | continue; | 869 | continue; |
| 772 | if (luma == vdec->slots[i]->luma) | 870 | if (luma == vdec->slots[i].addr) |
| 773 | return vdec->slots[i]; | 871 | return vdec->slots[i].curr; |
| 774 | } | 872 | } |
| 775 | 873 | ||
| 776 | return NULL; | 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 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); | 903 | cur_fmt = vpu_get_format(inst, inst->cap_format.type); |
| 806 | vbuf = &vpu_buf->m2m_buf.vb; | 904 | vbuf = &vpu_buf->m2m_buf.vb; |
| 807 | if (vbuf->vb2_buf.index != frame->id) | 905 | if (vpu_buf->fs_id != frame->id) |
| 808 | dev_err(inst->dev, "[%d] buffer id(%d, %d) mismatch\n", | 906 | dev_err(inst->dev, "[%d] buffer id(%d(%d), %d) mismatch\n", |
| 809 | inst->id, vbuf->vb2_buf.index, frame->id); | 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 | return; | 910 | return; |
| 813 | 911 | ||
| 814 | if (vpu_get_buffer_state(vbuf) != VPU_BUF_STATE_DECODED) | 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 | vbuf->sequence = vdec->sequence; | 919 | vbuf->sequence = vdec->sequence; |
| 822 | dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); | 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 | vpu_inst_lock(inst); | 922 | vpu_inst_lock(inst); |
| 923 | vdec->slots[vpu_buf->fs_id].state = VPU_BUF_STATE_READY; | ||
| 826 | vdec->display_frame_count++; | 924 | vdec->display_frame_count++; |
| 827 | vpu_inst_unlock(inst); | 925 | vpu_inst_unlock(inst); |
| 926 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); | ||
| 828 | dev_dbg(inst->dev, "[%d] decoded : %d, display : %d, sequence : %d\n", | 927 | dev_dbg(inst->dev, "[%d] decoded : %d, display : %d, sequence : %d\n", |
| 829 | inst->id, vdec->decoded_frame_count, vdec->display_frame_count, vdec->sequence); | 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 | if (!vbuf) | 1151 | if (!vbuf) |
| 1053 | return -EINVAL; | 1152 | return -EINVAL; |
| 1054 | 1153 | ||
| 1055 | if (vdec->slots[vbuf->vb2_buf.index]) { | 1154 | vpu_buf = to_vpu_vb2_buffer(vbuf); |
| 1056 | dev_err(inst->dev, "[%d] repeat alloc fs %d\n", | 1155 | if (vpu_buf->fs_id < 0 || vpu_buf->fs_id >= vdec->slot_count) { |
| 1057 | inst->id, vbuf->vb2_buf.index); | 1156 | dev_err(inst->dev, "invalid fs %d for v4l2 buffer %d\n", |
| 1157 | vpu_buf->fs_id, vbuf->vb2_buf.index); | ||
| 1058 | return -EINVAL; | 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 | dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n", | 1173 | dev_dbg(inst->dev, "[%d] state = %s, alloc fs %d, tag = 0x%x\n", |
| 1062 | inst->id, vpu_codec_state_name(inst->state), vbuf->vb2_buf.index, vdec->seq_tag); | 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 | memset(&info, 0, sizeof(info)); | 1176 | memset(&info, 0, sizeof(info)); |
| 1066 | info.id = vbuf->vb2_buf.index; | 1177 | info.id = vpu_buf->fs_id; |
| 1067 | info.type = MEM_RES_FRAME; | 1178 | info.type = MEM_RES_FRAME; |
| 1068 | info.tag = vdec->seq_tag; | 1179 | info.tag = vdec->seq_tag; |
| 1069 | info.luma_addr = vpu_get_vb_phy_addr(&vbuf->vb2_buf, 0); | 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 | if (ret) | 1189 | if (ret) |
| 1079 | return ret; | 1190 | return ret; |
| 1080 | 1191 | ||
| 1081 | vpu_buf->tag = info.tag; | ||
| 1082 | vpu_buf->luma = info.luma_addr; | 1192 | vpu_buf->luma = info.luma_addr; |
| 1083 | vpu_buf->chroma_u = info.chroma_addr; | 1193 | vpu_buf->chroma_u = info.chroma_addr; |
| 1084 | vpu_buf->chroma_v = 0; | 1194 | vpu_buf->chroma_v = 0; |
| 1085 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); | 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 | vdec->req_frame_count--; | 1199 | vdec->req_frame_count--; |
| 1088 | 1200 | ||
| 1089 | return 0; | 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 | v4l2_m2m_buf_queue(inst->fh.m2m_ctx, vbuf); | 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 | struct vdec_t *vdec = inst->priv; | 1261 | struct vdec_t *vdec = inst->priv; |
| 1150 | struct vpu_vb2_buffer *vpu_buf; | 1262 | struct vpu_vb2_buffer *vpu_buf; |
| 1151 | struct vb2_v4l2_buffer *vbuf; | 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 | int i; | 1292 | int i; |
| 1153 | 1293 | ||
| 1154 | for (i = 0; i < ARRAY_SIZE(vdec->slots); i++) { | 1294 | for (i = 0; i < vdec->slot_count; i++) { |
| 1155 | if (!vdec->slots[i]) | 1295 | if (!vdec->slots[i].curr) |
| 1156 | continue; | 1296 | continue; |
| 1157 | 1297 | ||
| 1158 | vpu_buf = vdec->slots[i]; | ||
| 1159 | vbuf = &vpu_buf->m2m_buf.vb; | ||
| 1160 | |||
| 1161 | vpu_trace(inst->dev, "clear slot %d\n", i); | 1298 | vpu_trace(inst->dev, "clear slot %d\n", i); |
| 1162 | vdec_response_fs_release(inst, i, vpu_buf->tag); | 1299 | vdec_release_curr_frame_store(inst, i); |
| 1163 | vdec_recycle_buffer(inst, vbuf); | 1300 | } |
| 1164 | vdec->slots[i]->state = VPU_BUF_STATE_IDLE; | 1301 | } |
| 1165 | vdec->slots[i] = NULL; | 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 | vdec_init_crop(inst); | 1352 | vdec_init_crop(inst); |
| 1190 | vdec_init_mbi(inst); | 1353 | vdec_init_mbi(inst); |
| 1191 | vdec_init_dcp(inst); | 1354 | vdec_init_dcp(inst); |
| 1355 | vdec_update_v4l2_profile_level(inst, hdr); | ||
| 1192 | if (!vdec->seq_hdr_found) { | 1356 | if (!vdec->seq_hdr_found) { |
| 1193 | vdec->seq_tag = vdec->codec_info.tag; | 1357 | vdec->seq_tag = vdec->codec_info.tag; |
| 1194 | if (vdec->is_source_changed) { | 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 | static void vdec_evnet_rel_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) | 1427 | static void vdec_evnet_rel_fs(struct vpu_inst *inst, struct vpu_fs_info *fs) |
| 1264 | { | 1428 | { |
| 1265 | struct vdec_t *vdec = inst->priv; | 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 | return; | 1432 | return; |
| 1271 | if (fs->type != MEM_RES_FRAME) | 1433 | if (fs->type != MEM_RES_FRAME) |
| 1272 | return; | 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 | dev_err(inst->dev, "[%d] invalid fs(%d) to release\n", inst->id, fs->id); | 1437 | dev_err(inst->dev, "[%d] invalid fs(%d) to release\n", inst->id, fs->id); |
| 1276 | return; | 1438 | return; |
| 1277 | } | 1439 | } |
| 1278 | 1440 | ||
| 1279 | vpu_inst_lock(inst); | 1441 | vpu_inst_lock(inst); |
| 1280 | vpu_buf = vdec->slots[fs->id]; | 1442 | if (!vdec->slots[fs->id].curr) { |
| 1281 | vdec->slots[fs->id] = NULL; | ||
| 1282 | |||
| 1283 | if (!vpu_buf) { | ||
| 1284 | dev_dbg(inst->dev, "[%d] fs[%d] has bee released\n", inst->id, fs->id); | 1443 | dev_dbg(inst->dev, "[%d] fs[%d] has bee released\n", inst->id, fs->id); |
| 1285 | goto exit; | 1444 | goto exit; |
| 1286 | } | 1445 | } |
| 1287 | 1446 | ||
| 1288 | vbuf = &vpu_buf->m2m_buf.vb; | 1447 | if (vdec->slots[fs->id].state == VPU_BUF_STATE_DECODED) { |
| 1289 | if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) { | ||
| 1290 | dev_dbg(inst->dev, "[%d] frame skip\n", inst->id); | 1448 | dev_dbg(inst->dev, "[%d] frame skip\n", inst->id); |
| 1291 | vdec->sequence++; | 1449 | vdec->sequence++; |
| 1292 | } | 1450 | } |
| 1293 | 1451 | ||
| 1294 | vdec_response_fs_release(inst, fs->id, vpu_buf->tag); | 1452 | vdec_release_curr_frame_store(inst, fs->id); |
| 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); | ||
| 1299 | vpu_process_capture_buffer(inst); | 1453 | vpu_process_capture_buffer(inst); |
| 1300 | 1454 | ||
| 1301 | exit: | 1455 | exit: |
| @@ -1485,6 +1639,11 @@ static void vdec_cleanup(struct vpu_inst *inst) · 183 unmodified lines | |||
| 1485 | return; | 1639 | return; |
| 1486 | 1640 | ||
| 1487 | vdec = inst->priv; | 1641 | vdec = inst->priv; |
| 1642 | if (vdec) { | ||
| 1643 | kfree(vdec->slots); | ||
| 1644 | vdec->slots = NULL; | ||
| 1645 | vdec->slot_count = 0; | ||
| 1646 | } | ||
| 1488 | vfree(vdec); | 1647 | vfree(vdec); |
| 1489 | inst->priv = NULL; | 1648 | inst->priv = NULL; |
| 1490 | vfree(inst); | 1649 | vfree(inst); |
| @@ -1606,11 +1765,43 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) · 115 unmodified lines | |||
| 1606 | return 0; | 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 | struct vdec_t *vdec = inst->priv; | 1770 | struct vdec_t *vdec = inst->priv; |
| 1771 | struct vpu_vb2_buffer *vpu_buf; | ||
| 1612 | int num = -1; | 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 | switch (i) { | 1805 | switch (i) { |
| 1615 | case 0: | 1806 | case 0: |
| 1616 | num = scnprintf(str, size, | 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 | vdec->codec_info.vui_present); | 1855 | vdec->codec_info.vui_present); |
| 1665 | break; | 1856 | break; |
| 1666 | default: | 1857 | default: |
| 1858 | num = vdec_get_slot_debug_info(inst, str, size, i - 10); | ||
| 1667 | break; | 1859 | break; |
| 1668 | } | 1860 | } |
| 1669 | 1861 | ||
| @@ -1687,6 +1879,8 @@ static struct vpu_inst_ops vdec_inst_ops = { · 17 unmodified lines | |||
| 1687 | .get_debug_info = vdec_get_debug_info, | 1879 | .get_debug_info = vdec_get_debug_info, |
| 1688 | .wait_prepare = vpu_inst_unlock, | 1880 | .wait_prepare = vpu_inst_unlock, |
| 1689 | .wait_finish = vpu_inst_lock, | 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 | static void vdec_init(struct file *file) | 1886 | static void vdec_init(struct file *file) |
| @@ -1727,6 +1921,16 @@ static int vdec_open(struct file *file) · 34 unmodified lines | |||
| 1727 | return -ENOMEM; | 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 | inst->ops = &vdec_inst_ops; | 1934 | inst->ops = &vdec_inst_ops; |
| 1731 | inst->formats = vdec_formats; | 1935 | inst->formats = vdec_formats; |
| 1732 | inst->type = VPU_CORE_TYPE_DEC; | 1936 | inst->type = VPU_CORE_TYPE_DEC; |
| @@ -222,6 +222,8 @@ struct vpu_inst_ops { · 221 unmodified lines | |||
| 222 | int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i); | 222 | int (*get_debug_info)(struct vpu_inst *inst, char *str, u32 size, u32 i); |
| 223 | void (*wait_prepare)(struct vpu_inst *inst); | 223 | void (*wait_prepare)(struct vpu_inst *inst); |
| 224 | void (*wait_finish)(struct vpu_inst *inst); | 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 | struct vpu_inst { | 229 | struct vpu_inst { |
| @@ -295,7 +297,8 @@ enum { · 67 unmodified lines | |||
| 295 | VPU_BUF_STATE_DECODED, | 297 | VPU_BUF_STATE_DECODED, |
| 296 | VPU_BUF_STATE_READY, | 298 | VPU_BUF_STATE_READY, |
| 297 | VPU_BUF_STATE_SKIP, | 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 | struct vpu_vb2_buffer { | 304 | struct vpu_vb2_buffer { |
| @@ -304,8 +307,8 @@ struct vpu_vb2_buffer { · 2 unmodified lines | |||
| 304 | dma_addr_t chroma_u; | 307 | dma_addr_t chroma_u; |
| 305 | dma_addr_t chroma_v; | 308 | dma_addr_t chroma_v; |
| 306 | unsigned int state; | 309 | unsigned int state; |
| 307 | u32 tag; | ||
| 308 | u32 average_qp; | 310 | u32 average_qp; |
| 311 | s32 fs_id; | ||
| 309 | }; | 312 | }; |
| 310 | 313 | ||
| 311 | void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val); | 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 | return V4L2_QUANTIZATION_LIM_RANGE; | 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 | [VPU_BUF_STATE_READY] = "ready", | 48 | [VPU_BUF_STATE_READY] = "ready", |
| 49 | [VPU_BUF_STATE_SKIP] = "skip", | 49 | [VPU_BUF_STATE_SKIP] = "skip", |
| 50 | [VPU_BUF_STATE_ERROR] = "error", | 50 | [VPU_BUF_STATE_ERROR] = "error", |
| 51 | [VPU_BUF_STATE_CHANGED] = "changed", | ||
| 51 | }; | 52 | }; |
| 52 | 53 | ||
| 53 | static inline const char *to_vpu_stat_name(int state) | 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 | for (i = 0; i < vb2_get_num_buffers(vq); i++) { | 165 | for (i = 0; i < vb2_get_num_buffers(vq); i++) { |
| 165 | struct vb2_buffer *vb; | 166 | struct vb2_buffer *vb; |
| 166 | struct vb2_v4l2_buffer *vbuf; | 167 | struct vb2_v4l2_buffer *vbuf; |
| 168 | struct vpu_vb2_buffer *vpu_buf; | ||
| 167 | 169 | ||
| 168 | vb = vb2_get_buffer(vq, i); | 170 | vb = vb2_get_buffer(vq, i); |
| 169 | if (!vb) | 171 | if (!vb) |
| @@ -173,13 +175,24 @@ static int vpu_dbg_instance(struct seq_file *s, void *data) · 3 unmodified lines | |||
| 173 | continue; | 175 | continue; |
| 174 | 176 | ||
| 175 | vbuf = to_vb2_v4l2_buffer(vb); | 177 | vbuf = to_vb2_v4l2_buffer(vb); |
| 178 | vpu_buf = to_vpu_vb2_buffer(vbuf); | ||
| 176 | 179 | ||
| 177 | num = scnprintf(str, sizeof(str), | 180 | num = scnprintf(str, sizeof(str), |
| 178 | "capture[%2d] state = %10s, %8s\n", | 181 | "capture[%2d] state = %10s, %8s", |
| 179 | i, vb2_stat_name[vb->state], | 182 | i, vb2_stat_name[vb->state], |
| 180 | to_vpu_stat_name(vpu_get_buffer_state(vbuf))); | 183 | to_vpu_stat_name(vpu_get_buffer_state(vbuf))); |
| 181 | if (seq_write(s, str, num)) | 184 | if (seq_write(s, str, num)) |
| 182 | return 0; | 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 | num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence); | 198 | num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence); |
| @@ -134,6 +134,7 @@ struct vpu_dec_codec_info { · 133 unmodified lines | |||
| 134 | u32 decoded_height; | 134 | u32 decoded_height; |
| 135 | struct v4l2_fract frame_rate; | 135 | struct v4l2_fract frame_rate; |
| 136 | u32 dsp_asp_ratio; | 136 | u32 dsp_asp_ratio; |
| 137 | u32 profile_idc; | ||
| 137 | u32 level_idc; | 138 | u32 level_idc; |
| 138 | u32 bit_depth_luma; | 139 | u32 bit_depth_luma; |
| 139 | u32 bit_depth_chroma; | 140 | u32 bit_depth_chroma; |
| @@ -147,6 +148,17 @@ struct vpu_dec_codec_info { · 7 unmodified lines | |||
| 147 | u32 mbi_size; | 148 | u32 mbi_size; |
| 148 | u32 dcp_size; | 149 | u32 dcp_size; |
| 149 | u32 stride; | 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 | struct vpu_dec_pic_info { | 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 | return "<unknown>"; | 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 | #ifndef _AMPHION_VPU_HELPERS_H | 6 | #ifndef _AMPHION_VPU_HELPERS_H |
| 7 | #define _AMPHION_VPU_HELPERS_H | 7 | #define _AMPHION_VPU_HELPERS_H |
| 8 | 8 | ||
| 9 | #include "vpu_defs.h" | ||
| 10 | |||
| 9 | struct vpu_pair { | 11 | struct vpu_pair { |
| 10 | u32 src; | 12 | u32 src; |
| 11 | u32 dst; | 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 | return pdata[pos % stream_buffer->length]; | 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 | u32 vpu_color_cvrt_primaries_v2i(u32 primaries); | 59 | u32 vpu_color_cvrt_primaries_v2i(u32 primaries); |
| 62 | u32 vpu_color_cvrt_primaries_i2v(u32 primaries); | 60 | u32 vpu_color_cvrt_primaries_i2v(u32 primaries); |
| 63 | u32 vpu_color_cvrt_transfers_v2i(u32 transfers); | 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 | u32 vpu_color_cvrt_matrix_i2v(u32 matrix); | 64 | u32 vpu_color_cvrt_matrix_i2v(u32 matrix); |
| 67 | u32 vpu_color_cvrt_full_range_v2i(u32 full_range); | 65 | u32 vpu_color_cvrt_full_range_v2i(u32 full_range); |
| 68 | u32 vpu_color_cvrt_full_range_i2v(u32 full_range); | 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 | int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src); | 68 | int vpu_find_dst_by_src(struct vpu_pair *pairs, u32 cnt, u32 src); |
| 72 | int vpu_find_src_by_dst(struct vpu_pair *pairs, u32 cnt, u32 dst); | 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 | #endif | 75 | #endif |
| @@ -908,7 +908,8 @@ static void vpu_malone_unpack_seq_hdr(struct vpu_rpc_event *pkt, · 907 unmodified lines | |||
| 908 | info->frame_rate.numerator = 1000; | 908 | info->frame_rate.numerator = 1000; |
| 909 | info->frame_rate.denominator = pkt->data[8]; | 909 | info->frame_rate.denominator = pkt->data[8]; |
| 910 | info->dsp_asp_ratio = pkt->data[9]; | 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 | info->bit_depth_luma = pkt->data[13]; | 913 | info->bit_depth_luma = pkt->data[13]; |
| 913 | info->bit_depth_chroma = pkt->data[14]; | 914 | info->bit_depth_chroma = pkt->data[14]; |
| 914 | info->chroma_fmt = pkt->data[15]; | 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 | info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128; | 926 | info->pixfmt = V4L2_PIX_FMT_NV12M_10BE_8L128; |
| 926 | else | 927 | else |
| 927 | info->pixfmt = V4L2_PIX_FMT_NV12M_8L128; | 928 | info->pixfmt = V4L2_PIX_FMT_NV12M_8L128; |
| 929 | if (pkt->hdr.num > 28) | ||
| 930 | info->constraint_set_flags = pkt->data[28]; | ||
| 928 | if (info->frame_rate.numerator && info->frame_rate.denominator) { | 931 | if (info->frame_rate.numerator && info->frame_rate.denominator) { |
| 929 | unsigned long n, d; | 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 | mbox_send_message(core->tx_data.ch, &data); | 109 | mbox_send_message(core->tx_data.ch, &data); |
| 110 | mbox_send_message(core->tx_type.ch, &type); | 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 | void vpu_mbox_free(struct vpu_core *core); | 11 | void vpu_mbox_free(struct vpu_core *core); |
| 12 | void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data); | 12 | void vpu_mbox_send_msg(struct vpu_core *core, u32 type, u32 data); |
| 13 | void vpu_mbox_send_type(struct vpu_core *core, u32 type); | 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 | #endif | 15 | #endif |
| @@ -501,14 +501,25 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, · 500 unmodified lines | |||
| 501 | call_void_vop(inst, release); | 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 | return 0; | 507 | return 0; |
| 505 | } | 508 | } |
| 506 | 509 | ||
| 507 | static int vpu_vb2_buf_init(struct vb2_buffer *vb) | 510 | static int vpu_vb2_buf_init(struct vb2_buffer *vb) |
| 508 | { | 511 | { |
| 509 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | 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 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); | 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 | return 0; | 523 | return 0; |
| 513 | } | 524 | } |
| 514 | 525 | ||
| @@ -57,6 +57,25 @@ · 56 unmodified lines | |||
| 57 | #define CSI2RX_LANES_MAX 4 | 57 | #define CSI2RX_LANES_MAX 4 |
| 58 | #define CSI2RX_STREAMS_MAX 4 | 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 | enum csi2rx_pads { | 79 | enum csi2rx_pads { |
| 61 | CSI2RX_PAD_SINK, | 80 | CSI2RX_PAD_SINK, |
| 62 | CSI2RX_PAD_SOURCE_STREAM0, | 81 | CSI2RX_PAD_SOURCE_STREAM0, |
| @@ -71,9 +90,32 @@ struct csi2rx_fmt { · 8 unmodified lines | |||
| 71 | u8 bpp; | 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 | struct csi2rx_priv { | 115 | struct csi2rx_priv { |
| 75 | struct device *dev; | 116 | struct device *dev; |
| 76 | unsigned int count; | 117 | unsigned int count; |
| 118 | int error_irq; | ||
| 77 | 119 | ||
| 78 | /* | 120 | /* |
| 79 | * Used to prevent race conditions between multiple, | 121 | * Used to prevent race conditions between multiple, |
| @@ -95,6 +137,7 @@ struct csi2rx_priv { · 15 unmodified lines | |||
| 95 | u8 max_lanes; | 137 | u8 max_lanes; |
| 96 | u8 max_streams; | 138 | u8 max_streams; |
| 97 | bool has_internal_dphy; | 139 | bool has_internal_dphy; |
| 140 | u32 events[CSI2RX_NUM_EVENTS]; | ||
| 98 | 141 | ||
| 99 | struct v4l2_subdev subdev; | 142 | struct v4l2_subdev subdev; |
| 100 | struct v4l2_async_notifier notifier; | 143 | struct v4l2_async_notifier notifier; |
| @@ -124,6 +167,54 @@ static const struct csi2rx_fmt formats[] = { · 23 unmodified lines | |||
| 124 | { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, | 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 | static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) | 218 | static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) |
| 128 | { | 219 | { |
| 129 | unsigned int i; | 220 | unsigned int i; |
| @@ -220,6 +311,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) · 90 unmodified lines | |||
| 220 | reset_control_deassert(csi2rx->p_rst); | 311 | reset_control_deassert(csi2rx->p_rst); |
| 221 | csi2rx_reset(csi2rx); | 312 | csi2rx_reset(csi2rx); |
| 222 | 313 | ||
| 314 | if (csi2rx->error_irq >= 0) | ||
| 315 | csi2rx_configure_error_irq_mask(csi2rx->base, csi2rx); | ||
| 316 | |||
| 223 | reg = csi2rx->num_lanes << 8; | 317 | reg = csi2rx->num_lanes << 8; |
| 224 | for (i = 0; i < csi2rx->num_lanes; i++) { | 318 | for (i = 0; i < csi2rx->num_lanes; i++) { |
| 225 | reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, csi2rx->lanes[i]); | 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 | reset_control_assert(csi2rx->sys_rst); | 426 | reset_control_assert(csi2rx->sys_rst); |
| 333 | clk_disable_unprepare(csi2rx->sys_clk); | 427 | clk_disable_unprepare(csi2rx->sys_clk); |
| 334 | 428 | ||
| 429 | writel(0, csi2rx->base + CSI2RX_ERROR_IRQS_MASK_REG); | ||
| 430 | |||
| 335 | for (i = 0; i < csi2rx->max_streams; i++) { | 431 | for (i = 0; i < csi2rx->max_streams; i++) { |
| 336 | writel(CSI2RX_STREAM_CTRL_STOP, | 432 | writel(CSI2RX_STREAM_CTRL_STOP, |
| 337 | csi2rx->base + CSI2RX_STREAM_CTRL_REG(i)); | 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 | static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) | 477 | static int csi2rx_s_stream(struct v4l2_subdev *subdev, int enable) |
| 367 | { | 478 | { |
| 368 | struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); | 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 | .s_stream = csi2rx_s_stream, | 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 | static const struct v4l2_subdev_ops csi2rx_subdev_ops = { | 586 | static const struct v4l2_subdev_ops csi2rx_subdev_ops = { |
| 587 | .core = &csi2rx_core_ops, | ||
| 472 | .video = &csi2rx_video_ops, | 588 | .video = &csi2rx_video_ops, |
| 473 | .pad = &csi2rx_pad_ops, | 589 | .pad = &csi2rx_pad_ops, |
| 474 | }; | 590 | }; |
| @@ -705,6 +821,21 @@ static int csi2rx_probe(struct platform_device *pdev) · 230 unmodified lines | |||
| 705 | if (ret) | 821 | if (ret) |
| 706 | goto err_cleanup; | 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 | ret = v4l2_subdev_init_finalize(&csi2rx->subdev); | 839 | ret = v4l2_subdev_init_finalize(&csi2rx->subdev); |
| 709 | if (ret) | 840 | if (ret) |
| 710 | goto err_cleanup; | 841 | goto err_cleanup; |
| @@ -598,6 +598,27 @@ static void _bswap16(u16 *a) · 597 unmodified lines | |||
| 598 | *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); | 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 | static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, | 622 | static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, |
| 602 | unsigned long len) | 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 | return; | 631 | return; |
| 611 | 632 | ||
| 612 | for (plane_no = 0; plane_no < buf->num_planes; plane_no++) { | 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 | if (len == 0) | 635 | if (len == 0) |
| 615 | len = payload; | 636 | len = payload; |
| 616 | dma_addr = vb2_dma_contig_plane_dma_addr(buf, plane_no); | 637 | dma_addr = mxc_jpeg_get_plane_dma_addr(buf, plane_no); |
| 617 | vaddr = vb2_plane_vaddr(buf, plane_no); | 638 | vaddr = mxc_jpeg_get_plane_vaddr(buf, plane_no); |
| 618 | v4l2_dbg(3, debug, &jpeg->v4l2_dev, | 639 | v4l2_dbg(3, debug, &jpeg->v4l2_dev, |
| 619 | "plane %d (vaddr=%p dma_addr=%x payload=%ld):", | 640 | "plane %d (vaddr=%p dma_addr=%x payload=%ld):", |
| 620 | plane_no, vaddr, dma_addr, payload); | 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 | struct mxc_jpeg_q_data *q_data; | 733 | struct mxc_jpeg_q_data *q_data; |
| 713 | 734 | ||
| 714 | q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type); | 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 | desc->buf_base1 = 0; | 737 | desc->buf_base1 = 0; |
| 717 | if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { | 738 | if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { |
| 718 | if (raw_buf->num_planes == 2) | 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 | else | 741 | else |
| 721 | desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0]; | 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) + | 744 | desc->stm_bufbase = mxc_jpeg_get_plane_dma_addr(jpeg_buf, 0) + offset; |
| 724 | offset; | ||
| 725 | } | 745 | } |
| 726 | 746 | ||
| 727 | static bool mxc_jpeg_is_extended_sequential(const struct mxc_jpeg_fmt *fmt) | 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 | vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); | 1049 | vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); |
| 1030 | } | 1050 | } |
| 1031 | dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", | 1051 | dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", |
| 1032 | vb2_get_plane_payload(&dst_buf->vb2_buf, 0), | 1052 | mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 0), |
| 1033 | vb2_get_plane_payload(&dst_buf->vb2_buf, 1)); | 1053 | mxc_jpeg_get_plane_payload(&dst_buf->vb2_buf, 1)); |
| 1034 | } | 1054 | } |
| 1035 | 1055 | ||
| 1036 | /* short preview of the results */ | 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 | struct mxc_jpeg_sof *psof = NULL; | 1909 | struct mxc_jpeg_sof *psof = NULL; |
| 1890 | struct mxc_jpeg_sos *psos = NULL; | 1910 | struct mxc_jpeg_sos *psos = NULL; |
| 1891 | struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); | 1911 | struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); |
| 1892 | u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0); | 1912 | u8 *src_addr = (u8 *)mxc_jpeg_get_plane_vaddr(vb, 0); |
| 1893 | u32 size = vb2_get_plane_payload(vb, 0); | 1913 | u32 size = mxc_jpeg_get_plane_payload(vb, 0); |
| 1894 | int ret; | 1914 | int ret; |
| 1895 | 1915 | ||
| 1896 | memset(&header, 0, sizeof(header)); | 1916 | memset(&header, 0, sizeof(header)); |
| @@ -2027,6 +2047,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) · 130 unmodified lines | |||
| 2027 | i, vb2_plane_size(vb, i), sizeimage); | 2047 | i, vb2_plane_size(vb, i), sizeimage); |
| 2028 | return -EINVAL; | 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 | if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { | 2056 | if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { |
| 2032 | vb2_set_plane_payload(vb, 0, 0); | 2057 | vb2_set_plane_payload(vb, 0, 0); |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | |||
| 30 | #define MXC_JPEG_MAX_PLANES 2 | 30 | #define MXC_JPEG_MAX_PLANES 2 |
| 31 | #define MXC_JPEG_PATTERN_WIDTH 128 | 31 | #define MXC_JPEG_PATTERN_WIDTH 128 |
| 32 | #define MXC_JPEG_PATTERN_HEIGHT 64 | 32 | #define MXC_JPEG_PATTERN_HEIGHT 64 |
| 33 | #define MXC_JPEG_ADDR_ALIGNMENT 16 | ||
| 33 | 34 | ||
| 34 | enum mxc_jpeg_enc_state { | 35 | enum mxc_jpeg_enc_state { |
| 35 | MXC_JPEG_ENCODING = 0, /* jpeg encode phase */ | 36 | MXC_JPEG_ENCODING = 0, /* jpeg encode phase */ |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | |||
| 28 | #include <linux/reset.h> | 28 | #include <linux/reset.h> |
| 29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
| 30 | 30 | ||
| 31 | #include <media/mipi-csi2.h> | ||
| 31 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
| 32 | #include <media/v4l2-device.h> | 33 | #include <media/v4l2-device.h> |
| 33 | #include <media/v4l2-event.h> | 34 | #include <media/v4l2-event.h> |
| @@ -229,25 +230,6 @@ · 195 unmodified lines | |||
| 229 | 230 | ||
| 230 | #define DEFAULT_SCLK_CSIS_FREQ 166000000UL | 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 | struct mipi_csis_event { | 233 | struct mipi_csis_event { |
| 252 | bool debug; | 234 | bool debug; |
| 253 | u32 mask; | 235 | u32 mask; |
| @@ -357,116 +339,116 @@ static const struct csis_pix_format mipi_csis_formats[] = { · 103 unmodified lines | |||
| 357 | { | 339 | { |
| 358 | .code = MEDIA_BUS_FMT_UYVY8_1X16, | 340 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
| 359 | .output = MEDIA_BUS_FMT_UYVY8_1X16, | 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 | .width = 16, | 343 | .width = 16, |
| 362 | }, | 344 | }, |
| 363 | /* RGB formats. */ | 345 | /* RGB formats. */ |
| 364 | { | 346 | { |
| 365 | .code = MEDIA_BUS_FMT_RGB565_1X16, | 347 | .code = MEDIA_BUS_FMT_RGB565_1X16, |
| 366 | .output = MEDIA_BUS_FMT_RGB565_1X16, | 348 | .output = MEDIA_BUS_FMT_RGB565_1X16, |
| 367 | .data_type = MIPI_CSI2_DATA_TYPE_RGB565, | 349 | .data_type = MIPI_CSI2_DT_RGB565, |
| 368 | .width = 16, | 350 | .width = 16, |
| 369 | }, { | 351 | }, { |
| 370 | .code = MEDIA_BUS_FMT_BGR888_1X24, | 352 | .code = MEDIA_BUS_FMT_BGR888_1X24, |
| 371 | .output = MEDIA_BUS_FMT_RGB888_1X24, | 353 | .output = MEDIA_BUS_FMT_RGB888_1X24, |
| 372 | .data_type = MIPI_CSI2_DATA_TYPE_RGB888, | 354 | .data_type = MIPI_CSI2_DT_RGB888, |
| 373 | .width = 24, | 355 | .width = 24, |
| 374 | }, | 356 | }, |
| 375 | /* RAW (Bayer and greyscale) formats. */ | 357 | /* RAW (Bayer and greyscale) formats. */ |
| 376 | { | 358 | { |
| 377 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | 359 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, |
| 378 | .output = MEDIA_BUS_FMT_SBGGR8_1X8, | 360 | .output = MEDIA_BUS_FMT_SBGGR8_1X8, |
| 379 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 361 | .data_type = MIPI_CSI2_DT_RAW8, |
| 380 | .width = 8, | 362 | .width = 8, |
| 381 | }, { | 363 | }, { |
| 382 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, | 364 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, |
| 383 | .output = MEDIA_BUS_FMT_SGBRG8_1X8, | 365 | .output = MEDIA_BUS_FMT_SGBRG8_1X8, |
| 384 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 366 | .data_type = MIPI_CSI2_DT_RAW8, |
| 385 | .width = 8, | 367 | .width = 8, |
| 386 | }, { | 368 | }, { |
| 387 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | 369 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, |
| 388 | .output = MEDIA_BUS_FMT_SGRBG8_1X8, | 370 | .output = MEDIA_BUS_FMT_SGRBG8_1X8, |
| 389 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 371 | .data_type = MIPI_CSI2_DT_RAW8, |
| 390 | .width = 8, | 372 | .width = 8, |
| 391 | }, { | 373 | }, { |
| 392 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, | 374 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, |
| 393 | .output = MEDIA_BUS_FMT_SRGGB8_1X8, | 375 | .output = MEDIA_BUS_FMT_SRGGB8_1X8, |
| 394 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 376 | .data_type = MIPI_CSI2_DT_RAW8, |
| 395 | .width = 8, | 377 | .width = 8, |
| 396 | }, { | 378 | }, { |
| 397 | .code = MEDIA_BUS_FMT_Y8_1X8, | 379 | .code = MEDIA_BUS_FMT_Y8_1X8, |
| 398 | .output = MEDIA_BUS_FMT_Y8_1X8, | 380 | .output = MEDIA_BUS_FMT_Y8_1X8, |
| 399 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 381 | .data_type = MIPI_CSI2_DT_RAW8, |
| 400 | .width = 8, | 382 | .width = 8, |
| 401 | }, { | 383 | }, { |
| 402 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, | 384 | .code = MEDIA_BUS_FMT_SBGGR10_1X10, |
| 403 | .output = MEDIA_BUS_FMT_SBGGR10_1X10, | 385 | .output = MEDIA_BUS_FMT_SBGGR10_1X10, |
| 404 | .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | 386 | .data_type = MIPI_CSI2_DT_RAW10, |
| 405 | .width = 10, | 387 | .width = 10, |
| 406 | }, { | 388 | }, { |
| 407 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, | 389 | .code = MEDIA_BUS_FMT_SGBRG10_1X10, |
| 408 | .output = MEDIA_BUS_FMT_SGBRG10_1X10, | 390 | .output = MEDIA_BUS_FMT_SGBRG10_1X10, |
| 409 | .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | 391 | .data_type = MIPI_CSI2_DT_RAW10, |
| 410 | .width = 10, | 392 | .width = 10, |
| 411 | }, { | 393 | }, { |
| 412 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, | 394 | .code = MEDIA_BUS_FMT_SGRBG10_1X10, |
| 413 | .output = MEDIA_BUS_FMT_SGRBG10_1X10, | 395 | .output = MEDIA_BUS_FMT_SGRBG10_1X10, |
| 414 | .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | 396 | .data_type = MIPI_CSI2_DT_RAW10, |
| 415 | .width = 10, | 397 | .width = 10, |
| 416 | }, { | 398 | }, { |
| 417 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, | 399 | .code = MEDIA_BUS_FMT_SRGGB10_1X10, |
| 418 | .output = MEDIA_BUS_FMT_SRGGB10_1X10, | 400 | .output = MEDIA_BUS_FMT_SRGGB10_1X10, |
| 419 | .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | 401 | .data_type = MIPI_CSI2_DT_RAW10, |
| 420 | .width = 10, | 402 | .width = 10, |
| 421 | }, { | 403 | }, { |
| 422 | .code = MEDIA_BUS_FMT_Y10_1X10, | 404 | .code = MEDIA_BUS_FMT_Y10_1X10, |
| 423 | .output = MEDIA_BUS_FMT_Y10_1X10, | 405 | .output = MEDIA_BUS_FMT_Y10_1X10, |
| 424 | .data_type = MIPI_CSI2_DATA_TYPE_RAW10, | 406 | .data_type = MIPI_CSI2_DT_RAW10, |
| 425 | .width = 10, | 407 | .width = 10, |
| 426 | }, { | 408 | }, { |
| 427 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, | 409 | .code = MEDIA_BUS_FMT_SBGGR12_1X12, |
| 428 | .output = MEDIA_BUS_FMT_SBGGR12_1X12, | 410 | .output = MEDIA_BUS_FMT_SBGGR12_1X12, |
| 429 | .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | 411 | .data_type = MIPI_CSI2_DT_RAW12, |
| 430 | .width = 12, | 412 | .width = 12, |
| 431 | }, { | 413 | }, { |
| 432 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, | 414 | .code = MEDIA_BUS_FMT_SGBRG12_1X12, |
| 433 | .output = MEDIA_BUS_FMT_SGBRG12_1X12, | 415 | .output = MEDIA_BUS_FMT_SGBRG12_1X12, |
| 434 | .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | 416 | .data_type = MIPI_CSI2_DT_RAW12, |
| 435 | .width = 12, | 417 | .width = 12, |
| 436 | }, { | 418 | }, { |
| 437 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, | 419 | .code = MEDIA_BUS_FMT_SGRBG12_1X12, |
| 438 | .output = MEDIA_BUS_FMT_SGRBG12_1X12, | 420 | .output = MEDIA_BUS_FMT_SGRBG12_1X12, |
| 439 | .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | 421 | .data_type = MIPI_CSI2_DT_RAW12, |
| 440 | .width = 12, | 422 | .width = 12, |
| 441 | }, { | 423 | }, { |
| 442 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, | 424 | .code = MEDIA_BUS_FMT_SRGGB12_1X12, |
| 443 | .output = MEDIA_BUS_FMT_SRGGB12_1X12, | 425 | .output = MEDIA_BUS_FMT_SRGGB12_1X12, |
| 444 | .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | 426 | .data_type = MIPI_CSI2_DT_RAW12, |
| 445 | .width = 12, | 427 | .width = 12, |
| 446 | }, { | 428 | }, { |
| 447 | .code = MEDIA_BUS_FMT_Y12_1X12, | 429 | .code = MEDIA_BUS_FMT_Y12_1X12, |
| 448 | .output = MEDIA_BUS_FMT_Y12_1X12, | 430 | .output = MEDIA_BUS_FMT_Y12_1X12, |
| 449 | .data_type = MIPI_CSI2_DATA_TYPE_RAW12, | 431 | .data_type = MIPI_CSI2_DT_RAW12, |
| 450 | .width = 12, | 432 | .width = 12, |
| 451 | }, { | 433 | }, { |
| 452 | .code = MEDIA_BUS_FMT_SBGGR14_1X14, | 434 | .code = MEDIA_BUS_FMT_SBGGR14_1X14, |
| 453 | .output = MEDIA_BUS_FMT_SBGGR14_1X14, | 435 | .output = MEDIA_BUS_FMT_SBGGR14_1X14, |
| 454 | .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | 436 | .data_type = MIPI_CSI2_DT_RAW14, |
| 455 | .width = 14, | 437 | .width = 14, |
| 456 | }, { | 438 | }, { |
| 457 | .code = MEDIA_BUS_FMT_SGBRG14_1X14, | 439 | .code = MEDIA_BUS_FMT_SGBRG14_1X14, |
| 458 | .output = MEDIA_BUS_FMT_SGBRG14_1X14, | 440 | .output = MEDIA_BUS_FMT_SGBRG14_1X14, |
| 459 | .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | 441 | .data_type = MIPI_CSI2_DT_RAW14, |
| 460 | .width = 14, | 442 | .width = 14, |
| 461 | }, { | 443 | }, { |
| 462 | .code = MEDIA_BUS_FMT_SGRBG14_1X14, | 444 | .code = MEDIA_BUS_FMT_SGRBG14_1X14, |
| 463 | .output = MEDIA_BUS_FMT_SGRBG14_1X14, | 445 | .output = MEDIA_BUS_FMT_SGRBG14_1X14, |
| 464 | .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | 446 | .data_type = MIPI_CSI2_DT_RAW14, |
| 465 | .width = 14, | 447 | .width = 14, |
| 466 | }, { | 448 | }, { |
| 467 | .code = MEDIA_BUS_FMT_SRGGB14_1X14, | 449 | .code = MEDIA_BUS_FMT_SRGGB14_1X14, |
| 468 | .output = MEDIA_BUS_FMT_SRGGB14_1X14, | 450 | .output = MEDIA_BUS_FMT_SRGGB14_1X14, |
| 469 | .data_type = MIPI_CSI2_DATA_TYPE_RAW14, | 451 | .data_type = MIPI_CSI2_DT_RAW14, |
| 470 | .width = 14, | 452 | .width = 14, |
| 471 | }, | 453 | }, |
| 472 | /* JPEG */ | 454 | /* JPEG */ |
| @@ -494,7 +476,7 @@ static const struct csis_pix_format mipi_csis_formats[] = { · 21 unmodified lines | |||
| 494 | * SoC that can support quad pixel mode, this will have to be | 476 | * SoC that can support quad pixel mode, this will have to be |
| 495 | * revisited. | 477 | * revisited. |
| 496 | */ | 478 | */ |
| 497 | .data_type = MIPI_CSI2_DATA_TYPE_RAW8, | 479 | .data_type = MIPI_CSI2_DT_RAW8, |
| 498 | .width = 8, | 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 | * TODO: Verify which other formats require DUAL (or QUAD) modes. | 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 | val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; | 569 | val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; |
| 588 | 570 | ||
| 589 | val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); | 571 | val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); |
| @@ -3,6 +3,7 @@ · 2 unmodified lines | |||
| 3 | * Copyright 2019-2020 NXP | 3 | * Copyright 2019-2020 NXP |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | #include <linux/bits.h> | ||
| 6 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
| 7 | #include <linux/device.h> | 8 | #include <linux/device.h> |
| 8 | #include <linux/errno.h> | 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 | /* Panic will assert when the buffers are 50% full */ | 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 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = { | 250 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v1 = { |
| 250 | .oflw_y_buf_en = { .offset = 19, .mask = 0x80000 }, | 251 | .oflw_y_buf_en = { .mask = BIT(19) }, |
| 251 | .oflw_u_buf_en = { .offset = 21, .mask = 0x200000 }, | 252 | .oflw_u_buf_en = { .mask = BIT(21) }, |
| 252 | .oflw_v_buf_en = { .offset = 23, .mask = 0x800000 }, | 253 | .oflw_v_buf_en = { .mask = BIT(23) }, |
| 253 | 254 | ||
| 254 | .panic_y_buf_en = {.offset = 20, .mask = 0x100000 }, | 255 | .panic_y_buf_en = { .mask = BIT(20) }, |
| 255 | .panic_u_buf_en = {.offset = 22, .mask = 0x400000 }, | 256 | .panic_u_buf_en = { .mask = BIT(22) }, |
| 256 | .panic_v_buf_en = {.offset = 24, .mask = 0x1000000 }, | 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 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = { | 261 | static const struct mxc_isi_ier_reg mxc_imx8_isi_ier_v2 = { |
| 261 | .oflw_y_buf_en = { .offset = 18, .mask = 0x40000 }, | 262 | .oflw_y_buf_en = { .mask = BIT(18) }, |
| 262 | .oflw_u_buf_en = { .offset = 20, .mask = 0x100000 }, | 263 | .oflw_u_buf_en = { .mask = BIT(20) }, |
| 263 | .oflw_v_buf_en = { .offset = 22, .mask = 0x400000 }, | 264 | .oflw_v_buf_en = { .mask = BIT(22) }, |
| 264 | 265 | ||
| 265 | .panic_y_buf_en = {.offset = 19, .mask = 0x80000 }, | 266 | .panic_y_buf_en = { .mask = BIT(19) }, |
| 266 | .panic_u_buf_en = {.offset = 21, .mask = 0x200000 }, | 267 | .panic_u_buf_en = { .mask = BIT(21) }, |
| 267 | .panic_v_buf_en = {.offset = 23, .mask = 0x800000 }, | 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 | /* Panic will assert when the buffers are 50% full */ | 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 | .panic_set_thd_v = { .mask = 0xf0000, .offset = 16, .threshold = 0x7 }, | 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 | static const struct mxc_isi_plat_data mxc_imx8mn_data = { | 293 | static const struct mxc_isi_plat_data mxc_imx8mn_data = { |
| 283 | .model = MXC_ISI_IMX8MN, | 294 | .model = MXC_ISI_IMX8MN, |
| 284 | .num_ports = 1, | 295 | .num_ports = 1, |
| @@ -286,8 +297,6 @@ static const struct mxc_isi_plat_data mxc_imx8mn_data = { · 1 unmodified line | |||
| 286 | .reg_offset = 0, | 297 | .reg_offset = 0, |
| 287 | .ier_reg = &mxc_imx8_isi_ier_v1, | 298 | .ier_reg = &mxc_imx8_isi_ier_v1, |
| 288 | .set_thd = &mxc_imx8_isi_thd_v1, | 299 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 289 | .clks = mxc_imx8mn_clks, | ||
| 290 | .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | ||
| 291 | .buf_active_reverse = false, | 300 | .buf_active_reverse = false, |
| 292 | .gasket_ops = &mxc_imx8_gasket_ops, | 301 | .gasket_ops = &mxc_imx8_gasket_ops, |
| 293 | .has_36bit_dma = false, | 302 | .has_36bit_dma = false, |
| @@ -300,8 +309,6 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = { · 6 unmodified lines | |||
| 300 | .reg_offset = 0x2000, | 309 | .reg_offset = 0x2000, |
| 301 | .ier_reg = &mxc_imx8_isi_ier_v2, | 310 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 302 | .set_thd = &mxc_imx8_isi_thd_v1, | 311 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 303 | .clks = mxc_imx8mn_clks, | ||
| 304 | .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | ||
| 305 | .buf_active_reverse = true, | 312 | .buf_active_reverse = true, |
| 306 | .gasket_ops = &mxc_imx8_gasket_ops, | 313 | .gasket_ops = &mxc_imx8_gasket_ops, |
| 307 | .has_36bit_dma = true, | 314 | .has_36bit_dma = true, |
| @@ -314,8 +321,6 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = { · 6 unmodified lines | |||
| 314 | .reg_offset = 0x0, | 321 | .reg_offset = 0x0, |
| 315 | .ier_reg = &mxc_imx8_isi_ier_v2, | 322 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 316 | .set_thd = &mxc_imx8_isi_thd_v1, | 323 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 317 | .clks = mxc_imx8mn_clks, | ||
| 318 | .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | ||
| 319 | .buf_active_reverse = true, | 324 | .buf_active_reverse = true, |
| 320 | .has_36bit_dma = false, | 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 | .reg_offset = 0, | 332 | .reg_offset = 0, |
| 328 | .ier_reg = &mxc_imx8_isi_ier_v2, | 333 | .ier_reg = &mxc_imx8_isi_ier_v2, |
| 329 | .set_thd = &mxc_imx8_isi_thd_v1, | 334 | .set_thd = &mxc_imx8_isi_thd_v1, |
| 330 | .clks = mxc_imx8mn_clks, | ||
| 331 | .num_clks = ARRAY_SIZE(mxc_imx8mn_clks), | ||
| 332 | .buf_active_reverse = true, | 335 | .buf_active_reverse = true, |
| 333 | .gasket_ops = &mxc_imx93_gasket_ops, | 336 | .gasket_ops = &mxc_imx93_gasket_ops, |
| 334 | .has_36bit_dma = false, | 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 | * Power management | 363 | * Power management |
| 339 | */ | 364 | */ |
| @@ -385,7 +410,7 @@ static int mxc_isi_runtime_suspend(struct device *dev) · 45 unmodified lines | |||
| 385 | { | 410 | { |
| 386 | struct mxc_isi_dev *isi = dev_get_drvdata(dev); | 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 | return 0; | 415 | return 0; |
| 391 | } | 416 | } |
| @@ -395,7 +420,7 @@ static int mxc_isi_runtime_resume(struct device *dev) · 3 unmodified lines | |||
| 395 | struct mxc_isi_dev *isi = dev_get_drvdata(dev); | 420 | struct mxc_isi_dev *isi = dev_get_drvdata(dev); |
| 396 | int ret; | 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 | if (ret) { | 424 | if (ret) { |
| 400 | dev_err(dev, "Failed to enable clocks (%d)\n", ret); | 425 | dev_err(dev, "Failed to enable clocks (%d)\n", ret); |
| 401 | return ret; | 426 | return ret; |
| @@ -413,27 +438,6 @@ static const struct dev_pm_ops mxc_isi_pm_ops = { · 11 unmodified lines | |||
| 413 | * Probe, remove & driver | 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 | static int mxc_isi_probe(struct platform_device *pdev) | 441 | static int mxc_isi_probe(struct platform_device *pdev) |
| 438 | { | 442 | { |
| 439 | struct device *dev = &pdev->dev; | 443 | struct device *dev = &pdev->dev; |
| @@ -456,34 +460,25 @@ static int mxc_isi_probe(struct platform_device *pdev) · 16 unmodified lines | |||
| 456 | if (!isi->pipes) | 460 | if (!isi->pipes) |
| 457 | return -ENOMEM; | 461 | return -ENOMEM; |
| 458 | 462 | ||
| 459 | ret = mxc_isi_clk_get(isi); | 463 | isi->num_clks = devm_clk_bulk_get_all(dev, &isi->clks); |
| 460 | if (ret < 0) { | 464 | if (isi->num_clks < 0) |
| 461 | dev_err(dev, "Failed to get clocks\n"); | 465 | return dev_err_probe(dev, isi->num_clks, "Failed to get clocks\n"); |
| 462 | return ret; | ||
| 463 | } | ||
| 464 | 466 | ||
| 465 | isi->regs = devm_platform_ioremap_resource(pdev, 0); | 467 | isi->regs = devm_platform_ioremap_resource(pdev, 0); |
| 466 | if (IS_ERR(isi->regs)) { | 468 | if (IS_ERR(isi->regs)) |
| 467 | dev_err(dev, "Failed to get ISI register map\n"); | 469 | return dev_err_probe(dev, PTR_ERR(isi->regs), |
| 468 | return PTR_ERR(isi->regs); | 470 | "Failed to get ISI register map\n"); |
| 469 | } | ||
| 470 | 471 | ||
| 471 | if (isi->pdata->gasket_ops) { | 472 | if (isi->pdata->gasket_ops) { |
| 472 | isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node, | 473 | isi->gasket = syscon_regmap_lookup_by_phandle(dev->of_node, |
| 473 | "fsl,blk-ctrl"); | 474 | "fsl,blk-ctrl"); |
| 474 | if (IS_ERR(isi->gasket)) { | 475 | if (IS_ERR(isi->gasket)) |
| 475 | ret = PTR_ERR(isi->gasket); | 476 | return dev_err_probe(dev, PTR_ERR(isi->gasket), |
| 476 | dev_err(dev, "failed to get gasket: %d\n", ret); | 477 | "failed to get gasket\n"); |
| 477 | return ret; | ||
| 478 | } | ||
| 479 | } | 478 | } |
| 480 | 479 | ||
| 481 | dma_size = isi->pdata->has_36bit_dma ? 36 : 32; | 480 | dma_size = isi->pdata->has_36bit_dma ? 36 : 32; |
| 482 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(dma_size)); | 481 | 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 | } | ||
| 487 | 482 | ||
| 488 | pm_runtime_enable(dev); | 483 | pm_runtime_enable(dev); |
| 489 | 484 | ||
| @@ -541,6 +536,8 @@ static void mxc_isi_remove(struct platform_device *pdev) · 51 unmodified lines | |||
| 541 | static const struct of_device_id mxc_isi_of_match[] = { | 536 | static const struct of_device_id mxc_isi_of_match[] = { |
| 542 | { .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data }, | 537 | { .compatible = "fsl,imx8mn-isi", .data = &mxc_imx8mn_data }, |
| 543 | { .compatible = "fsl,imx8mp-isi", .data = &mxc_imx8mp_data }, | 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 | { .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data }, | 541 | { .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data }, |
| 545 | { .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data }, | 542 | { .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data }, |
| 546 | { /* sentinel */ }, | 543 | { /* sentinel */ }, |
| @@ -114,7 +114,6 @@ struct mxc_isi_buffer { · 113 unmodified lines | |||
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | struct mxc_isi_reg { | 116 | struct mxc_isi_reg { |
| 117 | u32 offset; | ||
| 118 | u32 mask; | 117 | u32 mask; |
| 119 | }; | 118 | }; |
| 120 | 119 | ||
| @@ -158,6 +157,8 @@ struct mxc_gasket_ops { · 37 unmodified lines | |||
| 158 | enum model { | 157 | enum model { |
| 159 | MXC_ISI_IMX8MN, | 158 | MXC_ISI_IMX8MN, |
| 160 | MXC_ISI_IMX8MP, | 159 | MXC_ISI_IMX8MP, |
| 160 | MXC_ISI_IMX8QM, | ||
| 161 | MXC_ISI_IMX8QXP, | ||
| 161 | MXC_ISI_IMX8ULP, | 162 | MXC_ISI_IMX8ULP, |
| 162 | MXC_ISI_IMX93, | 163 | MXC_ISI_IMX93, |
| 163 | }; | 164 | }; |
| @@ -170,8 +171,6 @@ struct mxc_isi_plat_data { · 6 unmodified lines | |||
| 170 | const struct mxc_isi_ier_reg *ier_reg; | 171 | const struct mxc_isi_ier_reg *ier_reg; |
| 171 | const struct mxc_isi_set_thd *set_thd; | 172 | const struct mxc_isi_set_thd *set_thd; |
| 172 | const struct mxc_gasket_ops *gasket_ops; | 173 | const struct mxc_gasket_ops *gasket_ops; |
| 173 | const struct clk_bulk_data *clks; | ||
| 174 | unsigned int num_clks; | ||
| 175 | bool buf_active_reverse; | 174 | bool buf_active_reverse; |
| 176 | bool has_36bit_dma; | 175 | bool has_36bit_dma; |
| 177 | }; | 176 | }; |
| @@ -283,6 +282,7 @@ struct mxc_isi_dev { · 105 unmodified lines | |||
| 283 | 282 | ||
| 284 | void __iomem *regs; | 283 | void __iomem *regs; |
| 285 | struct clk_bulk_data *clks; | 284 | struct clk_bulk_data *clks; |
| 285 | int num_clks; | ||
| 286 | struct regmap *gasket; | 286 | struct regmap *gasket; |
| 287 | 287 | ||
| 288 | struct mxc_isi_crossbar crossbar; | 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 | * Create a 1:1 mapping between pixel link inputs and outputs to | 188 | * Create a 1:1 mapping between pixel link inputs and outputs to |
| 189 | * pipelines by default. | 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 | if (!routes) | 193 | if (!routes) |
| 193 | return -ENOMEM; | 194 | return -ENOMEM; |
| 194 | 195 | ||
| 195 | for (i = 0; i < xbar->num_sources; ++i) { | 196 | for (i = 0; i < routing.num_routes; ++i) { |
| 196 | struct v4l2_subdev_route *route = &routes[i]; | 197 | struct v4l2_subdev_route *route = &routes[i]; |
| 197 | 198 | ||
| 198 | route->sink_pad = i; | 199 | route->sink_pad = i; |
| @@ -200,7 +201,6 @@ static int mxc_isi_crossbar_init_state(struct v4l2_subdev *sd, · 1 unmodified line | |||
| 200 | route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; | 201 | route->flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE; |
| 201 | } | 202 | } |
| 202 | 203 | ||
| 203 | routing.num_routes = xbar->num_sources; | ||
| 204 | routing.routes = routes; | 204 | routing.routes = routes; |
| 205 | 205 | ||
| 206 | ret = __mxc_isi_crossbar_set_routing(sd, state, &routing); | 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 | sink_streams); | 352 | sink_streams); |
| 353 | if (ret) { | 353 | if (ret) { |
| 354 | dev_err(xbar->isi->dev, | 354 | dev_err(xbar->isi->dev, |
| 355 | "failed to %s streams 0x%llx on '%s':%u: %d\n", | 355 | "failed to enable streams 0x%llx on '%s':%u: %d\n", |
| 356 | "enable", sink_streams, remote_sd->name, | 356 | sink_streams, remote_sd->name, remote_pad, ret); |
| 357 | remote_pad, ret); | ||
| 358 | mxc_isi_crossbar_gasket_disable(xbar, sink_pad); | 357 | mxc_isi_crossbar_gasket_disable(xbar, sink_pad); |
| 359 | return ret; | 358 | return ret; |
| 360 | } | 359 | } |
| @@ -392,9 +391,8 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, · 31 unmodified lines | |||
| 392 | sink_streams); | 391 | sink_streams); |
| 393 | if (ret) | 392 | if (ret) |
| 394 | dev_err(xbar->isi->dev, | 393 | dev_err(xbar->isi->dev, |
| 395 | "failed to %s streams 0x%llx on '%s':%u: %d\n", | 394 | "failed to disable streams 0x%llx on '%s':%u: %d\n", |
| 396 | "disable", sink_streams, remote_sd->name, | 395 | sink_streams, remote_sd->name, remote_pad, ret); |
| 397 | remote_pad, ret); | ||
| 398 | 396 | ||
| 399 | mxc_isi_crossbar_gasket_disable(xbar, sink_pad); | 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 | * the memory input. | 451 | * the memory input. |
| 454 | */ | 452 | */ |
| 455 | xbar->num_sinks = isi->pdata->num_ports + 1; | 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 | num_pads = xbar->num_sinks + xbar->num_sources; | 455 | num_pads = xbar->num_sinks + xbar->num_sources; |
| 458 | 456 | ||
| 459 | xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL); | 457 | xbar->pads = kcalloc(num_pads, sizeof(*xbar->pads), GFP_KERNEL); |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright (C) 2021 Purism SPC | 5 | * Copyright (C) 2021 Purism SPC |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/bitfield.h> | ||
| 8 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
| 9 | #include <linux/clk-provider.h> | 10 | #include <linux/clk-provider.h> |
| 10 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| @@ -62,6 +63,8 @@ · 51 unmodified lines | |||
| 62 | #define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 | 63 | #define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 |
| 63 | #define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 | 64 | #define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 |
| 64 | 65 | ||
| 66 | struct csi_state; | ||
| 67 | |||
| 65 | enum { | 68 | enum { |
| 66 | ST_POWERED = 1, | 69 | ST_POWERED = 1, |
| 67 | ST_STREAMING = 2, | 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 | #define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) | 87 | #define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) |
| 85 | 88 | ||
| 86 | #define GPR_CSI2_1_RX_ENABLE BIT(13) | 89 | struct imx8mq_plat_data { |
| 87 | #define GPR_CSI2_1_VID_INTFC_ENB BIT(12) | 90 | int (*enable)(struct csi_state *state, u32 hs_settle); |
| 88 | #define GPR_CSI2_1_HSEL BIT(10) | 91 | void (*disable)(struct csi_state *state); |
| 89 | #define GPR_CSI2_1_CONT_CLK_MODE BIT(8) | 92 | bool use_reg_csr; |
| 90 | #define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) | 93 | }; |
| 91 | 94 | ||
| 92 | /* | 95 | /* |
| 93 | * The send level configures the number of entries that must accumulate in | 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 | struct csi_state { | 110 | struct csi_state { |
| 108 | struct device *dev; | 111 | struct device *dev; |
| 112 | const struct imx8mq_plat_data *pdata; | ||
| 109 | void __iomem *regs; | 113 | void __iomem *regs; |
| 110 | struct clk_bulk_data clks[CSI2_NUM_CLKS]; | 114 | struct clk_bulk_data clks[CSI2_NUM_CLKS]; |
| 111 | struct reset_control *rst; | 115 | struct reset_control *rst; |
| @@ -137,6 +141,123 @@ struct csi2_pix_format { · 25 unmodified lines | |||
| 137 | u8 width; | 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 | static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { | 261 | static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { |
| 141 | /* RAW (Bayer and greyscale) formats. */ | 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 | if (ret) | 492 | if (ret) |
| 372 | return ret; | 493 | return ret; |
| 373 | 494 | ||
| 374 | regmap_update_bits(state->phy_gpr, | 495 | ret = state->pdata->enable(state, hs_settle); |
| 375 | state->phy_gpr_reg, | 496 | if (ret) |
| 376 | 0x3fff, | 497 | return ret; |
| 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)); | ||
| 382 | 498 | ||
| 383 | return 0; | 499 | return 0; |
| 384 | } | 500 | } |
| @@ -386,6 +502,9 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state, · 1 unmodified line | |||
| 386 | static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) | 502 | static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) |
| 387 | { | 503 | { |
| 388 | imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, 0xf); | 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 | return PTR_ERR(state->rst); | 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 | ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, | 978 | ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, |
| 841 | ARRAY_SIZE(out_val)); | 979 | ARRAY_SIZE(out_val)); |
| 842 | if (ret) { | 980 | if (ret) { |
| @@ -876,6 +1014,8 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev) · 33 unmodified lines | |||
| 876 | 1014 | ||
| 877 | state->dev = dev; | 1015 | state->dev = dev; |
| 878 | 1016 | ||
| 1017 | state->pdata = of_device_get_match_data(dev); | ||
| 1018 | |||
| 879 | ret = imx8mq_mipi_csi_parse_dt(state); | 1019 | ret = imx8mq_mipi_csi_parse_dt(state); |
| 880 | if (ret < 0) { | 1020 | if (ret < 0) { |
| 881 | dev_err(dev, "Failed to parse device tree: %d\n", ret); | 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 | static const struct of_device_id imx8mq_mipi_csi_of_match[] = { | 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 | { /* sentinel */ }, | 1098 | { /* sentinel */ }, |
| 958 | }; | 1099 | }; |
| 959 | MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); | 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 | regs->offset = 0x1000; | 849 | regs->offset = 0x1000; |
| 850 | break; | 850 | break; |
| 851 | default: | 851 | default: |
| 852 | WARN(1, "unknown csiphy version\n"); | 852 | break; |
| 853 | return -ENODEV; | ||
| 854 | } | 853 | } |
| 855 | 854 | ||
| 856 | return 0; | 855 | return 0; |
| @@ -103,11 +103,6 @@ const struct csiphy_formats csiphy_formats_8x96 = { · 102 unmodified lines | |||
| 103 | .formats = formats_8x96 | 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 | const struct csiphy_formats csiphy_formats_sdm845 = { | 106 | const struct csiphy_formats csiphy_formats_sdm845 = { |
| 112 | .nformats = ARRAY_SIZE(formats_sdm845), | 107 | .nformats = ARRAY_SIZE(formats_sdm845), |
| 113 | .formats = formats_sdm845 | 108 | .formats = formats_sdm845 |
| @@ -126,7 +126,6 @@ void msm_csiphy_unregister_entity(struct csiphy_device *csiphy); · 125 unmodified lines | |||
| 126 | 126 | ||
| 127 | extern const struct csiphy_formats csiphy_formats_8x16; | 127 | extern const struct csiphy_formats csiphy_formats_8x16; |
| 128 | extern const struct csiphy_formats csiphy_formats_8x96; | 128 | extern const struct csiphy_formats csiphy_formats_8x96; |
| 129 | extern const struct csiphy_formats csiphy_formats_sc7280; | ||
| 130 | extern const struct csiphy_formats csiphy_formats_sdm845; | 129 | extern const struct csiphy_formats csiphy_formats_sdm845; |
| 131 | 130 | ||
| 132 | extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0; | 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 | return 0; | 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 | static int video_start_streaming(struct vb2_queue *q, unsigned int count) | 243 | static int video_start_streaming(struct vb2_queue *q, unsigned int count) |
| 229 | { | 244 | { |
| 230 | struct camss_video *video = vb2_get_drv_priv(q); | 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 | video->ops->flush_buffers(video, VB2_BUF_STATE_ERROR); | 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 | static const struct vb2_ops msm_video_vb2_q_ops = { | 334 | static const struct vb2_ops msm_video_vb2_q_ops = { |
| 312 | .queue_setup = video_queue_setup, | 335 | .queue_setup = video_queue_setup, |
| 313 | .buf_init = video_buf_init, | 336 | .buf_init = video_buf_init, |
| 314 | .buf_prepare = video_buf_prepare, | 337 | .buf_prepare = video_buf_prepare, |
| 315 | .buf_queue = video_buf_queue, | 338 | .buf_queue = video_buf_queue, |
| 339 | .prepare_streaming = video_prepare_streaming, | ||
| 316 | .start_streaming = video_start_streaming, | 340 | .start_streaming = video_start_streaming, |
| 317 | .stop_streaming = video_stop_streaming, | 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 | file->private_data = vfh; | 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 | mutex_unlock(&video->lock); | 627 | mutex_unlock(&video->lock); |
| 610 | 628 | ||
| 611 | return 0; | 629 | return 0; |
| 612 | 630 | ||
| 613 | error_pm_use: | ||
| 614 | v4l2_fh_release(file); | ||
| 615 | |||
| 616 | error_alloc: | 631 | error_alloc: |
| 617 | mutex_unlock(&video->lock); | 632 | mutex_unlock(&video->lock); |
| 618 | 633 | ||
| @@ -621,12 +636,8 @@ error_alloc: · 2 unmodified lines | |||
| 621 | 636 | ||
| 622 | static int video_release(struct file *file) | 637 | static int video_release(struct file *file) |
| 623 | { | 638 | { |
| 624 | struct video_device *vdev = video_devdata(file); | ||
| 625 | |||
| 626 | vb2_fop_release(file); | 639 | vb2_fop_release(file); |
| 627 | 640 | ||
| 628 | v4l2_pipeline_pm_put(&vdev->entity); | ||
| 629 | |||
| 630 | file->private_data = NULL; | 641 | file->private_data = NULL; |
| 631 | 642 | ||
| 632 | return 0; | 643 | return 0; |
| @@ -1481,7 +1481,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 1480 unmodified lines | |||
| 1481 | .csiphy = { | 1481 | .csiphy = { |
| 1482 | .id = 0, | 1482 | .id = 0, |
| 1483 | .hw_ops = &csiphy_ops_3ph_1_0, | 1483 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1484 | .formats = &csiphy_formats_sc7280 | 1484 | .formats = &csiphy_formats_sdm845, |
| 1485 | } | 1485 | } |
| 1486 | }, | 1486 | }, |
| 1487 | /* CSIPHY1 */ | 1487 | /* CSIPHY1 */ |
| @@ -1496,7 +1496,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | |||
| 1496 | .csiphy = { | 1496 | .csiphy = { |
| 1497 | .id = 1, | 1497 | .id = 1, |
| 1498 | .hw_ops = &csiphy_ops_3ph_1_0, | 1498 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1499 | .formats = &csiphy_formats_sc7280 | 1499 | .formats = &csiphy_formats_sdm845, |
| 1500 | } | 1500 | } |
| 1501 | }, | 1501 | }, |
| 1502 | /* CSIPHY2 */ | 1502 | /* CSIPHY2 */ |
| @@ -1511,7 +1511,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | |||
| 1511 | .csiphy = { | 1511 | .csiphy = { |
| 1512 | .id = 2, | 1512 | .id = 2, |
| 1513 | .hw_ops = &csiphy_ops_3ph_1_0, | 1513 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1514 | .formats = &csiphy_formats_sc7280 | 1514 | .formats = &csiphy_formats_sdm845, |
| 1515 | } | 1515 | } |
| 1516 | }, | 1516 | }, |
| 1517 | /* CSIPHY3 */ | 1517 | /* CSIPHY3 */ |
| @@ -1526,7 +1526,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | |||
| 1526 | .csiphy = { | 1526 | .csiphy = { |
| 1527 | .id = 3, | 1527 | .id = 3, |
| 1528 | .hw_ops = &csiphy_ops_3ph_1_0, | 1528 | .hw_ops = &csiphy_ops_3ph_1_0, |
| 1529 | .formats = &csiphy_formats_sc7280 | 1529 | .formats = &csiphy_formats_sdm845, |
| 1530 | } | 1530 | } |
| 1531 | }, | 1531 | }, |
| 1532 | /* CSIPHY4 */ | 1532 | /* CSIPHY4 */ |
| @@ -1541,7 +1541,7 @@ static const struct camss_subdev_resources csiphy_res_7280[] = { · 8 unmodified lines | |||
| 1541 | .csiphy = { | 1541 | .csiphy = { |
| 1542 | .id = 4, | 1542 | .id = 4, |
| 1543 | .hw_ops = &csiphy_ops_3ph_1_0, | 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 | static const struct camss_subdev_resources csiphy_res_x1e80100[] = { | 2486 | static const struct camss_subdev_resources csiphy_res_x1e80100[] = { |
| 2487 | /* CSIPHY0 */ | 2487 | /* CSIPHY0 */ |
| 2488 | { | 2488 | { |
| 2489 | .regulators = { "vdd-csiphy-0p8-supply", | 2489 | .regulators = { "vdd-csiphy-0p8", |
| 2490 | "vdd-csiphy-1p2-supply" }, | 2490 | "vdd-csiphy-1p2" }, |
| 2491 | .clock = { "csiphy0", "csiphy0_timer" }, | 2491 | .clock = { "csiphy0", "csiphy0_timer" }, |
| 2492 | .clock_rate = { { 300000000, 400000000, 480000000 }, | 2492 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2493 | { 266666667, 400000000 } }, | 2493 | { 266666667, 400000000 } }, |
| @@ -2501,8 +2501,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | |||
| 2501 | }, | 2501 | }, |
| 2502 | /* CSIPHY1 */ | 2502 | /* CSIPHY1 */ |
| 2503 | { | 2503 | { |
| 2504 | .regulators = { "vdd-csiphy-0p8-supply", | 2504 | .regulators = { "vdd-csiphy-0p8", |
| 2505 | "vdd-csiphy-1p2-supply" }, | 2505 | "vdd-csiphy-1p2" }, |
| 2506 | .clock = { "csiphy1", "csiphy1_timer" }, | 2506 | .clock = { "csiphy1", "csiphy1_timer" }, |
| 2507 | .clock_rate = { { 300000000, 400000000, 480000000 }, | 2507 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2508 | { 266666667, 400000000 } }, | 2508 | { 266666667, 400000000 } }, |
| @@ -2516,8 +2516,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | |||
| 2516 | }, | 2516 | }, |
| 2517 | /* CSIPHY2 */ | 2517 | /* CSIPHY2 */ |
| 2518 | { | 2518 | { |
| 2519 | .regulators = { "vdd-csiphy-0p8-supply", | 2519 | .regulators = { "vdd-csiphy-0p8", |
| 2520 | "vdd-csiphy-1p2-supply" }, | 2520 | "vdd-csiphy-1p2" }, |
| 2521 | .clock = { "csiphy2", "csiphy2_timer" }, | 2521 | .clock = { "csiphy2", "csiphy2_timer" }, |
| 2522 | .clock_rate = { { 300000000, 400000000, 480000000 }, | 2522 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2523 | { 266666667, 400000000 } }, | 2523 | { 266666667, 400000000 } }, |
| @@ -2531,8 +2531,8 @@ static const struct camss_subdev_resources csiphy_res_x1e80100[] = { · 7 unmodified lines | |||
| 2531 | }, | 2531 | }, |
| 2532 | /* CSIPHY4 */ | 2532 | /* CSIPHY4 */ |
| 2533 | { | 2533 | { |
| 2534 | .regulators = { "vdd-csiphy-0p8-supply", | 2534 | .regulators = { "vdd-csiphy-0p8", |
| 2535 | "vdd-csiphy-1p2-supply" }, | 2535 | "vdd-csiphy-1p2" }, |
| 2536 | .clock = { "csiphy4", "csiphy4_timer" }, | 2536 | .clock = { "csiphy4", "csiphy4_timer" }, |
| 2537 | .clock_rate = { { 300000000, 400000000, 480000000 }, | 2537 | .clock_rate = { { 300000000, 400000000, 480000000 }, |
| 2538 | { 266666667, 400000000 } }, | 2538 | { 266666667, 400000000 } }, |
| @@ -3386,43 +3386,39 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) · 847 unmodified lines | |||
| 3386 | struct camss *camss = container_of(async, struct camss, notifier); | 3386 | struct camss *camss = container_of(async, struct camss, notifier); |
| 3387 | struct v4l2_device *v4l2_dev = &camss->v4l2_dev; | 3387 | struct v4l2_device *v4l2_dev = &camss->v4l2_dev; |
| 3388 | struct v4l2_subdev *sd; | 3388 | struct v4l2_subdev *sd; |
| 3389 | int ret; | ||
| 3390 | 3389 | ||
| 3391 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { | 3390 | list_for_each_entry(sd, &v4l2_dev->subdevs, list) { |
| 3392 | if (sd->host_priv) { | 3391 | struct csiphy_device *csiphy = sd->host_priv; |
| 3393 | struct media_entity *sensor = &sd->entity; | 3392 | struct media_entity *input, *sensor; |
| 3394 | struct csiphy_device *csiphy = | 3393 | unsigned int i; |
| 3395 | (struct csiphy_device *) sd->host_priv; | 3394 | int ret; |
| 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 | } | ||
| 3408 | 3395 | ||
| 3409 | ret = media_create_pad_link(sensor, i, | 3396 | if (!csiphy) |
| 3410 | input, MSM_CSIPHY_PAD_SINK, | 3397 | continue; |
| 3411 | MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); | 3398 | |
| 3412 | if (ret < 0) { | 3399 | input = &csiphy->subdev.entity; |
| 3413 | camss_link_err(camss, sensor->name, | 3400 | sensor = &sd->entity; |
| 3414 | input->name, | 3401 | |
| 3415 | ret); | 3402 | for (i = 0; i < sensor->num_pads; i++) { |
| 3416 | return ret; | 3403 | if (sensor->pads[i].flags & MEDIA_PAD_FL_SOURCE) |
| 3417 | } | 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); | 3412 | ret = media_create_pad_link(sensor, i, input, |
| 3422 | if (ret < 0) | 3413 | MSM_CSIPHY_PAD_SINK, |
| 3423 | return ret; | 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 | static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { | 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 | ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); | 3621 | ret = v4l2_device_register(camss->dev, &camss->v4l2_dev); |
| 3626 | if (ret < 0) { | 3622 | if (ret < 0) { |
| 3627 | dev_err(dev, "Failed to register V4L2 device: %d\n", ret); | 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 | v4l2_async_nf_init(&camss->notifier, &camss->v4l2_dev); | 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 | if (ret < 0) | 3642 | if (ret < 0) |
| 3647 | goto err_register_subdevs; | 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 | if (num_subdevs) { | 3651 | if (num_subdevs) { |
| 3650 | camss->notifier.ops = &camss_subdev_notifier_ops; | 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 | dev_err(dev, | 3656 | dev_err(dev, |
| 3655 | "Failed to register async subdev nodes: %d\n", | 3657 | "Failed to register async subdev nodes: %d\n", |
| 3656 | ret); | 3658 | ret); |
| 3657 | goto err_register_subdevs; | 3659 | goto err_media_device_unregister; |
| 3658 | } | 3660 | } |
| 3659 | } else { | 3661 | } else { |
| 3660 | ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); | 3662 | ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); |
| 3661 | if (ret < 0) { | 3663 | if (ret < 0) { |
| 3662 | dev_err(dev, "Failed to register subdev nodes: %d\n", | 3664 | dev_err(dev, "Failed to register subdev nodes: %d\n", |
| 3663 | ret); | 3665 | ret); |
| 3664 | goto err_register_subdevs; | 3666 | goto err_media_device_unregister; |
| 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; | ||
| 3672 | } | 3667 | } |
| 3673 | } | 3668 | } |
| 3674 | 3669 | ||
| 3675 | return 0; | 3670 | return 0; |
| 3676 | 3671 | ||
| 3672 | err_media_device_unregister: | ||
| 3673 | media_device_unregister(&camss->media_dev); | ||
| 3677 | err_register_subdevs: | 3674 | err_register_subdevs: |
| 3678 | camss_unregister_entities(camss); | 3675 | camss_unregister_entities(camss); |
| 3679 | err_v4l2_device_unregister: | 3676 | err_v4l2_device_unregister: |
| 3680 | v4l2_device_unregister(&camss->v4l2_dev); | 3677 | v4l2_device_unregister(&camss->v4l2_dev); |
| 3681 | v4l2_async_nf_cleanup(&camss->notifier); | 3678 | v4l2_async_nf_cleanup(&camss->notifier); |
| 3682 | pm_runtime_disable(dev); | 3679 | pm_runtime_disable(dev); |
| 3680 | err_media_device_cleanup: | ||
| 3681 | media_device_cleanup(&camss->media_dev); | ||
| 3683 | err_genpd_cleanup: | 3682 | err_genpd_cleanup: |
| 3684 | camss_genpd_cleanup(camss); | 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 | if (num_mbs > NUM_MBS_4K) { | 205 | if (num_mbs > NUM_MBS_4K) { |
| 206 | div_factor = 4; | 206 | div_factor = 4; |
| 207 | base_res_mbs = caps->max_mbpf; | 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 | return 0; | 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 | const struct iris_platform_data *platform_data = inst->core->iris_platform_data; | 384 | const struct iris_platform_data *platform_data = inst->core->iris_platform_data; |
| 382 | struct iris_buffer *buf, *next; | 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 | for (i = 0; i < len; i++) { | 399 | for (i = 0; i < len; i++) { |
| 397 | buffers = &inst->buffers[internal_buf_type[i]]; | 400 | buffers = &inst->buffers[internal_buf_type[i]]; |
| 398 | list_for_each_entry_safe(buf, next, &buffers->list, list) { | 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 | ret = iris_destroy_internal_buffer(inst, buf); | 410 | ret = iris_destroy_internal_buffer(inst, buf); |
| 400 | if (ret) | 411 | if (ret) |
| 401 | return ret; | 412 | return ret; |
| @@ -405,6 +416,16 @@ int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane) · 3 unmodified lines | |||
| 405 | return 0; | 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 | static int iris_release_internal_buffers(struct iris_inst *inst, | 429 | static int iris_release_internal_buffers(struct iris_inst *inst, |
| 409 | enum iris_buffer_type buffer_type) | 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 | vb2 = &vbuf->vb2_buf; | 615 | vb2 = &vbuf->vb2_buf; |
| 595 | 616 | ||
| 596 | if (buf->flags & V4L2_BUF_FLAG_ERROR) | 617 | if (buf->flags & V4L2_BUF_FLAG_ERROR) { |
| 597 | state = VB2_BUF_STATE_ERROR; | 618 | state = VB2_BUF_STATE_ERROR; |
| 598 | else | 619 | vb2_set_plane_payload(vb2, 0, 0); |
| 599 | state = VB2_BUF_STATE_DONE; | 620 | vb2->timestamp = 0; |
| 621 | v4l2_m2m_buf_done(vbuf, state); | ||
| 622 | return 0; | ||
| 623 | } | ||
| 600 | 624 | ||
| 601 | vbuf->flags |= buf->flags; | 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 | v4l2_event_queue_fh(&inst->fh, &ev); | 639 | v4l2_event_queue_fh(&inst->fh, &ev); |
| 616 | v4l2_m2m_mark_stopped(m2m_ctx); | 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 | vb2->timestamp = buf->timestamp; | 646 | vb2->timestamp = buf->timestamp; |
| 620 | v4l2_m2m_buf_done(vbuf, state); | 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 | int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); | 106 | int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); |
| 107 | int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); | 107 | int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); |
| 108 | int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); | 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 | int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst); | 111 | int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst); |
| 111 | int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst); | 112 | int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst); |
| 112 | int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf); | 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 | static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) | 17 | static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) |
| 18 | { | 18 | { |
| 19 | switch (id) { | 19 | switch (id) { |
| 20 | case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: | ||
| 21 | return DEBLOCK; | ||
| 22 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: | 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 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: | 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 | default: | 34 | default: |
| 27 | return INST_FW_CAP_MAX; | 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 | return 0; | 42 | return 0; |
| 35 | 43 | ||
| 36 | switch (cap_id) { | 44 | switch (cap_id) { |
| 37 | case DEBLOCK: | 45 | case PROFILE_H264: |
| 38 | return V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER; | ||
| 39 | case PROFILE: | ||
| 40 | return V4L2_CID_MPEG_VIDEO_H264_PROFILE; | 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 | return V4L2_CID_MPEG_VIDEO_H264_LEVEL; | 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 | default: | 59 | default: |
| 44 | return 0; | 60 | return 0; |
| 45 | } | 61 | } |
| @@ -84,8 +100,6 @@ int iris_ctrls_init(struct iris_inst *inst) · 38 unmodified lines | |||
| 84 | if (iris_get_v4l2_id(cap[idx].cap_id)) | 100 | if (iris_get_v4l2_id(cap[idx].cap_id)) |
| 85 | num_ctrls++; | 101 | num_ctrls++; |
| 86 | } | 102 | } |
| 87 | if (!num_ctrls) | ||
| 88 | return -EINVAL; | ||
| 89 | 103 | ||
| 90 | /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ | 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 | core->inst_fw_caps[cap_id].value = caps[i].value; | 177 | core->inst_fw_caps[cap_id].value = caps[i].value; |
| 164 | core->inst_fw_caps[cap_id].flags = caps[i].flags; | 178 | core->inst_fw_caps[cap_id].flags = caps[i].flags; |
| 165 | core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; | 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 | u32 color_info; | 140 | u32 color_info; |
| 141 | u32 profile; | 141 | u32 profile; |
| 142 | u32 level; | 142 | u32 level; |
| 143 | u32 tier; | ||
| 143 | }; | 144 | }; |
| 144 | 145 | ||
| 145 | u32 iris_hfi_get_v4l2_color_primaries(u32 hfi_primaries); | 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 | static int iris_hfi_gen1_session_open(struct iris_inst *inst) | 88 | static int iris_hfi_gen1_session_open(struct iris_inst *inst) |
| 89 | { | 89 | { |
| 90 | struct hfi_session_open_pkt packet; | 90 | struct hfi_session_open_pkt packet; |
| 91 | u32 codec = 0; | ||
| 91 | int ret; | 92 | int ret; |
| 92 | 93 | ||
| 93 | if (inst->state != IRIS_INST_DEINIT) | 94 | if (inst->state != IRIS_INST_DEINIT) |
| 94 | return -EALREADY; | 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 | packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); | 109 | packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); |
| 97 | packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; | 110 | packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; |
| 98 | packet.shdr.session_id = inst->session_id; | 111 | packet.shdr.session_id = inst->session_id; |
| 99 | packet.session_domain = HFI_SESSION_TYPE_DEC; | 112 | packet.session_domain = HFI_SESSION_TYPE_DEC; |
| 100 | packet.session_codec = HFI_VIDEO_CODEC_H264; | 113 | packet.session_codec = codec; |
| 101 | 114 | ||
| 102 | reinit_completion(&inst->completion); | 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 | flush_pkt.flush_type = flush_type; | 221 | flush_pkt.flush_type = flush_type; |
| 209 | 222 | ||
| 210 | ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); | 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 | ret = iris_wait_for_session_response(inst, true); | 226 | ret = iris_wait_for_session_response(inst, true); |
| 227 | } | ||
| 213 | } | 228 | } |
| 214 | 229 | ||
| 215 | return ret; | 230 | return ret; |
| @@ -386,6 +401,8 @@ static int iris_hfi_gen1_session_drain(struct iris_inst *inst, u32 plane) · 170 unmodified lines | |||
| 386 | ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; | 401 | ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; |
| 387 | ip_pkt.shdr.session_id = inst->session_id; | 402 | ip_pkt.shdr.session_id = inst->session_id; |
| 388 | ip_pkt.flags = HFI_BUFFERFLAG_EOS; | 403 | ip_pkt.flags = HFI_BUFFERFLAG_EOS; |
| 404 | if (inst->codec == V4L2_PIX_FMT_VP9) | ||
| 405 | ip_pkt.packet_buffer = 0xdeadb000; | ||
| 389 | 406 | ||
| 390 | return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); | 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 | packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); | 507 | packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); |
| 491 | break; | 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 | default: | 510 | default: |
| 502 | return -EINVAL; | 511 | return -EINVAL; |
| 503 | } | 512 | } |
| @@ -546,14 +555,15 @@ static int iris_hfi_gen1_set_resolution(struct iris_inst *inst) · 42 unmodified lines | |||
| 546 | struct hfi_framesize fs; | 555 | struct hfi_framesize fs; |
| 547 | int ret; | 556 | int ret; |
| 548 | 557 | ||
| 549 | fs.buffer_type = HFI_BUFFER_INPUT; | 558 | if (!iris_drc_pending(inst)) { |
| 550 | fs.width = inst->fmt_src->fmt.pix_mp.width; | 559 | fs.buffer_type = HFI_BUFFER_INPUT; |
| 551 | fs.height = inst->fmt_src->fmt.pix_mp.height; | 560 | fs.width = inst->fmt_src->fmt.pix_mp.width; |
| 552 | 561 | fs.height = inst->fmt_src->fmt.pix_mp.height; | |
| 553 | ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); | ||
| 554 | if (ret) | ||
| 555 | return ret; | ||
| 556 | 562 | ||
| 563 | ret = hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); | ||
| 564 | if (ret) | ||
| 565 | return ret; | ||
| 566 | } | ||
| 557 | fs.buffer_type = HFI_BUFFER_OUTPUT2; | 567 | fs.buffer_type = HFI_BUFFER_OUTPUT2; |
| 558 | fs.width = inst->fmt_dst->fmt.pix_mp.width; | 568 | fs.width = inst->fmt_dst->fmt.pix_mp.width; |
| 559 | fs.height = inst->fmt_dst->fmt.pix_mp.height; | 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 | iris_hfi_gen1_set_bufsize}, | 778 | iris_hfi_gen1_set_bufsize}, |
| 769 | }; | 779 | }; |
| 770 | 780 | ||
| 771 | config_params = core->iris_platform_data->input_config_params; | 781 | config_params = core->iris_platform_data->input_config_params_default; |
| 772 | config_params_size = core->iris_platform_data->input_config_params_size; | 782 | config_params_size = core->iris_platform_data->input_config_params_default_size; |
| 773 | 783 | ||
| 774 | if (V4L2_TYPE_IS_OUTPUT(plane)) { | 784 | if (V4L2_TYPE_IS_OUTPUT(plane)) { |
| 775 | for (i = 0; i < config_params_size; i++) { | 785 | for (i = 0; i < config_params_size; i++) { |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | |||
| 13 | #define HFI_SESSION_TYPE_DEC 2 | 13 | #define HFI_SESSION_TYPE_DEC 2 |
| 14 | 14 | ||
| 15 | #define HFI_VIDEO_CODEC_H264 0x00000002 | 15 | #define HFI_VIDEO_CODEC_H264 0x00000002 |
| 16 | #define HFI_VIDEO_CODEC_HEVC 0x00002000 | ||
| 17 | #define HFI_VIDEO_CODEC_VP9 0x00004000 | ||
| 16 | 18 | ||
| 17 | #define HFI_ERR_NONE 0x0 | 19 | #define HFI_ERR_NONE 0x0 |
| 18 | 20 | ||
| @@ -65,7 +67,6 @@ · 46 unmodified lines | |||
| 65 | 67 | ||
| 66 | #define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 | 68 | #define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS 0x202001 |
| 67 | 69 | ||
| 68 | #define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER 0x1200001 | ||
| 69 | #define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e | 70 | #define HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS 0x120300e |
| 70 | #define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 | 71 | #define HFI_PROPERTY_CONFIG_VDEC_ENTROPY 0x1204004 |
| 71 | 72 | ||
| @@ -117,6 +118,8 @@ · 45 unmodified lines | |||
| 117 | #define HFI_FRAME_NOTCODED 0x7f002000 | 118 | #define HFI_FRAME_NOTCODED 0x7f002000 |
| 118 | #define HFI_FRAME_YUV 0x7f004000 | 119 | #define HFI_FRAME_YUV 0x7f004000 |
| 119 | #define HFI_UNUSED_PICT 0x10000000 | 120 | #define HFI_UNUSED_PICT 0x10000000 |
| 121 | #define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 | ||
| 122 | #define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 | ||
| 120 | 123 | ||
| 121 | struct hfi_pkt_hdr { | 124 | struct hfi_pkt_hdr { |
| 122 | u32 size; | 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 | iris_hfi_gen1_read_changed_params(inst, pkt); | 201 | iris_hfi_gen1_read_changed_params(inst, pkt); |
| 202 | 202 | ||
| 203 | if (inst->state != IRIS_INST_ERROR) { | 203 | if (inst->state != IRIS_INST_ERROR && !(inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { |
| 204 | reinit_completion(&inst->flush_completion); | ||
| 205 | 204 | ||
| 206 | flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); | 205 | flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); |
| 207 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; | 206 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; |
| 208 | flush_pkt.shdr.session_id = inst->session_id; | 207 | flush_pkt.shdr.session_id = inst->session_id; |
| 209 | flush_pkt.flush_type = HFI_FLUSH_OUTPUT; | 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 | iris_vdec_src_change(inst); | 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 | struct iris_buffer *buf = NULL; | 348 | struct iris_buffer *buf = NULL; |
| 349 | bool found = false; | 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 | v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { | 355 | v4l2_m2m_for_each_src_buf_safe(m2m_ctx, m2m_buffer, n) { |
| 352 | buf = to_iris_buffer(&m2m_buffer->vb); | 356 | buf = to_iris_buffer(&m2m_buffer->vb); |
| 353 | if (buf->index == pkt->input_tag) { | 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 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; | 412 | flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; |
| 409 | flush_pkt.shdr.session_id = inst->session_id; | 413 | flush_pkt.shdr.session_id = inst->session_id; |
| 410 | flush_pkt.flush_type = HFI_FLUSH_OUTPUT; | 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 | iris_inst_sub_state_change_drain_last(inst); | 418 | iris_inst_sub_state_change_drain_last(inst); |
| 413 | 419 | ||
| 414 | return; | 420 | return; |
| @@ -455,7 +461,12 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) · 40 unmodified lines | |||
| 455 | timestamp_us = timestamp_hi; | 461 | timestamp_us = timestamp_hi; |
| 456 | timestamp_us = (timestamp_us << 32) | timestamp_lo; | 462 | timestamp_us = (timestamp_us << 32) | timestamp_lo; |
| 457 | } else { | 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 | buf->timestamp = timestamp_us; | 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 | buf->attr |= BUF_ATTR_DEQUEUED; | 492 | buf->attr |= BUF_ATTR_DEQUEUED; |
| 482 | buf->attr |= BUF_ATTR_BUFFER_DONE; | 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 | buf->flags |= flags; | 501 | buf->flags |= flags; |
| 485 | 502 | ||
| 486 | iris_vb2_buffer_done(inst, buf); | 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 | const struct iris_hfi_gen1_response_pkt_info *pkt_info; | 575 | const struct iris_hfi_gen1_response_pkt_info *pkt_info; |
| 559 | struct device *dev = core->dev; | 576 | struct device *dev = core->dev; |
| 560 | struct hfi_session_pkt *pkt; | 577 | struct hfi_session_pkt *pkt; |
| 561 | struct completion *done; | ||
| 562 | struct iris_inst *inst; | 578 | struct iris_inst *inst; |
| 563 | bool found = false; | 579 | bool found = false; |
| 564 | u32 i; | 580 | u32 i; |
| @@ -619,9 +635,12 @@ static void iris_hfi_gen1_handle_response(struct iris_core *core, void *response · 54 unmodified lines | |||
| 619 | if (shdr->error_type != HFI_ERR_NONE) | 635 | if (shdr->error_type != HFI_ERR_NONE) |
| 620 | iris_inst_change_state(inst, IRIS_INST_ERROR); | 636 | iris_inst_change_state(inst, IRIS_INST_ERROR); |
| 621 | 637 | ||
| 622 | done = pkt_info->pkt == HFI_MSG_SESSION_FLUSH ? | 638 | if (pkt_info->pkt == HFI_MSG_SESSION_FLUSH) { |
| 623 | &inst->flush_completion : &inst->completion; | 639 | if (!(--inst->flush_responses_pending)) |
| 624 | complete(done); | 640 | complete(&inst->flush_completion); |
| 641 | } else { | ||
| 642 | complete(&inst->completion); | ||
| 643 | } | ||
| 625 | } | 644 | } |
| 626 | mutex_unlock(&inst->lock); | 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 | sizeof(u64)); | 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 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 183 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 184 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 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 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 296 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 297 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 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 | inst_hfi_gen2->src_subcr_params.profile = profile; | 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 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 325 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 314 | u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 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 | inst_hfi_gen2->src_subcr_params.level = level; | 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 | sizeof(u64)); | 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 | static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) | 411 | static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) |
| 371 | { | 412 | { |
| 372 | struct iris_core *core = inst->core; | 413 | struct iris_core *core = inst->core; |
| 373 | u32 config_params_size, i, j; | 414 | u32 config_params_size = 0, i, j; |
| 374 | const u32 *config_params; | 415 | const u32 *config_params = NULL; |
| 375 | int ret; | 416 | int ret; |
| 376 | 417 | ||
| 377 | static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = { | 418 | static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = { |
| 378 | {HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution }, | 419 | {HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution }, |
| 379 | {HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets }, | 420 | {HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets }, |
| 380 | {HFI_PROP_CODED_FRAMES, iris_hfi_gen2_set_coded_frames }, | 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 | {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, iris_hfi_gen2_set_min_output_count }, | 423 | {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, iris_hfi_gen2_set_min_output_count }, |
| 383 | {HFI_PROP_PIC_ORDER_CNT_TYPE, iris_hfi_gen2_set_picture_order_count }, | 424 | {HFI_PROP_PIC_ORDER_CNT_TYPE, iris_hfi_gen2_set_picture_order_count }, |
| 384 | {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, | 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 | {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, | 427 | {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, |
| 387 | {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, | 428 | {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, |
| 388 | {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, | 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 | if (V4L2_TYPE_IS_OUTPUT(plane)) { | 433 | if (V4L2_TYPE_IS_OUTPUT(plane)) { |
| 392 | config_params = core->iris_platform_data->input_config_params; | 434 | switch (inst->codec) { |
| 393 | config_params_size = core->iris_platform_data->input_config_params_size; | 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 | } else { | 451 | } else { |
| 395 | config_params = core->iris_platform_data->output_config_params; | 452 | config_params = core->iris_platform_data->output_config_params; |
| 396 | config_params_size = core->iris_platform_data->output_config_params_size; | 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 | static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) | 473 | static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) |
| 417 | { | 474 | { |
| 418 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 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 | iris_hfi_gen2_packet_session_property(inst, | 490 | iris_hfi_gen2_packet_session_property(inst, |
| 422 | HFI_PROP_CODEC, | 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 | struct hfi_subscription_params subsc_params; | 617 | struct hfi_subscription_params subsc_params; |
| 549 | u32 prop_type, payload_size, payload_type; | 618 | u32 prop_type, payload_size, payload_type; |
| 550 | struct iris_core *core = inst->core; | 619 | struct iris_core *core = inst->core; |
| 551 | const u32 *change_param; | 620 | const u32 *change_param = NULL; |
| 552 | u32 change_param_size; | 621 | u32 change_param_size = 0; |
| 553 | u32 payload[32] = {0}; | 622 | u32 payload[32] = {0}; |
| 554 | u32 hfi_port = 0, i; | 623 | u32 hfi_port = 0, i; |
| 555 | int ret; | 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 | return 0; | 629 | return 0; |
| 561 | } | 630 | } |
| 562 | 631 | ||
| 563 | change_param = core->iris_platform_data->input_config_params; | 632 | switch (inst->codec) { |
| 564 | change_param_size = core->iris_platform_data->input_config_params_size; | 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 | payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; | 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 | payload_size = sizeof(u32); | 692 | payload_size = sizeof(u32); |
| 609 | payload_type = HFI_PAYLOAD_U32; | 693 | payload_type = HFI_PAYLOAD_U32; |
| 610 | break; | 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 | case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: | 700 | case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: |
| 612 | payload[0] = subsc_params.fw_min_count; | 701 | payload[0] = subsc_params.fw_min_count; |
| 613 | payload_size = sizeof(u32); | 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 | payload_size = sizeof(u32); | 722 | payload_size = sizeof(u32); |
| 634 | payload_type = HFI_PAYLOAD_U32; | 723 | payload_type = HFI_PAYLOAD_U32; |
| 635 | break; | 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 | default: | 730 | default: |
| 637 | prop_type = 0; | 731 | prop_type = 0; |
| 638 | ret = -EINVAL; | 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 | static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) | 753 | static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) |
| 660 | { | 754 | { |
| 661 | struct iris_core *core = inst->core; | 755 | struct iris_core *core = inst->core; |
| 662 | u32 subscribe_prop_size, i; | 756 | u32 subscribe_prop_size = 0, i; |
| 663 | const u32 *subcribe_prop; | 757 | const u32 *subcribe_prop = NULL; |
| 664 | u32 payload[32] = {0}; | 758 | u32 payload[32] = {0}; |
| 665 | 759 | ||
| 666 | payload[0] = HFI_MODE_PROPERTY; | 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 | subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; | 763 | subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; |
| 670 | subcribe_prop = core->iris_platform_data->dec_input_prop; | 764 | subcribe_prop = core->iris_platform_data->dec_input_prop; |
| 671 | } else { | 765 | } else { |
| 672 | subscribe_prop_size = core->iris_platform_data->dec_output_prop_size; | 766 | switch (inst->codec) { |
| 673 | subcribe_prop = core->iris_platform_data->dec_output_prop; | 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 | for (i = 0; i < subscribe_prop_size; i++) | 785 | for (i = 0; i < subscribe_prop_size; i++) |
| @@ -46,6 +46,7 @@ · 45 unmodified lines | |||
| 46 | #define HFI_PROP_CROP_OFFSETS 0x03000105 | 46 | #define HFI_PROP_CROP_OFFSETS 0x03000105 |
| 47 | #define HFI_PROP_PROFILE 0x03000107 | 47 | #define HFI_PROP_PROFILE 0x03000107 |
| 48 | #define HFI_PROP_LEVEL 0x03000108 | 48 | #define HFI_PROP_LEVEL 0x03000108 |
| 49 | #define HFI_PROP_TIER 0x03000109 | ||
| 49 | #define HFI_PROP_STAGE 0x0300010a | 50 | #define HFI_PROP_STAGE 0x0300010a |
| 50 | #define HFI_PROP_PIPE 0x0300010b | 51 | #define HFI_PROP_PIPE 0x0300010b |
| 51 | #define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f | 52 | #define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f |
| @@ -104,6 +105,9 @@ enum hfi_color_format { · 52 unmodified lines | |||
| 104 | enum hfi_codec_type { | 105 | enum hfi_codec_type { |
| 105 | HFI_CODEC_DECODE_AVC = 1, | 106 | HFI_CODEC_DECODE_AVC = 1, |
| 106 | HFI_CODEC_ENCODE_AVC = 2, | 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 | enum hfi_picture_type { | 113 | enum hfi_picture_type { |
| @@ -113,6 +117,7 @@ enum hfi_picture_type { · 3 unmodified lines | |||
| 113 | HFI_PICTURE_I = 0x00000008, | 117 | HFI_PICTURE_I = 0x00000008, |
| 114 | HFI_PICTURE_CRA = 0x00000010, | 118 | HFI_PICTURE_CRA = 0x00000010, |
| 115 | HFI_PICTURE_BLA = 0x00000020, | 119 | HFI_PICTURE_BLA = 0x00000020, |
| 120 | HFI_PICTURE_NOSHOW = 0x00000040, | ||
| 116 | }; | 121 | }; |
| 117 | 122 | ||
| 118 | enum hfi_buffer_type { | 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 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 91 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); |
| 92 | u32 driver_flags = 0; | 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 | driver_flags |= V4L2_BUF_FLAG_KEYFRAME; | 97 | driver_flags |= V4L2_BUF_FLAG_KEYFRAME; |
| 96 | else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_P) | 98 | else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_P) |
| 97 | driver_flags |= V4L2_BUF_FLAG_PFRAME; | 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 | struct iris_inst *instance; | 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 | core->state = IRIS_CORE_ERROR; | 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 | buf->flags = iris_hfi_gen2_get_driver_buffer_flags(inst, hfi_buffer->flags); | 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 | return 0; | 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 | inst->crop.width = pixmp_ip->width - | 571 | inst->crop.width = pixmp_ip->width - |
| 564 | ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; | 572 | ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; |
| 565 | 573 | ||
| 566 | inst->fw_caps[PROFILE].value = subsc_params.profile; | 574 | switch (inst->codec) { |
| 567 | inst->fw_caps[LEVEL].value = subsc_params.level; | 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 | inst->fw_caps[POC].value = subsc_params.pic_order_cnt; | 589 | inst->fw_caps[POC].value = subsc_params.pic_order_cnt; |
| 590 | inst->fw_caps[TIER].value = subsc_params.tier; | ||
| 569 | 591 | ||
| 570 | if (subsc_params.bit_depth != BIT_DEPTH_8 || | 592 | if (subsc_params.bit_depth != BIT_DEPTH_8 || |
| 571 | !(subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG)) { | 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 | struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); | 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 | if (pkt->flags & HFI_FW_FLAGS_INFORMATION) | 661 | if (pkt->flags & HFI_FW_FLAGS_INFORMATION) |
| 643 | return 0; | 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 | inst_hfi_gen2->src_subcr_params.crop_offsets[0] = pkt->payload[0]; | 669 | inst_hfi_gen2->src_subcr_params.crop_offsets[0] = pkt->payload[0]; |
| 651 | inst_hfi_gen2->src_subcr_params.crop_offsets[1] = pkt->payload[1]; | 670 | inst_hfi_gen2->src_subcr_params.crop_offsets[1] = pkt->payload[1]; |
| 652 | break; | 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 | case HFI_PROP_CODED_FRAMES: | 675 | case HFI_PROP_CODED_FRAMES: |
| 654 | inst_hfi_gen2->src_subcr_params.coded_frames = pkt->payload[0]; | 676 | inst_hfi_gen2->src_subcr_params.coded_frames = pkt->payload[0]; |
| 655 | break; | 677 | break; |
| @@ -668,6 +690,9 @@ static int iris_hfi_gen2_handle_session_property(struct iris_inst *inst, · 12 unmodified lines | |||
| 668 | case HFI_PROP_LEVEL: | 690 | case HFI_PROP_LEVEL: |
| 669 | inst_hfi_gen2->src_subcr_params.level = pkt->payload[0]; | 691 | inst_hfi_gen2->src_subcr_params.level = pkt->payload[0]; |
| 670 | break; | 692 | break; |
| 693 | case HFI_PROP_TIER: | ||
| 694 | inst_hfi_gen2->src_subcr_params.tier = pkt->payload[0]; | ||
| 695 | break; | ||
| 671 | case HFI_PROP_PICTURE_TYPE: | 696 | case HFI_PROP_PICTURE_TYPE: |
| 672 | inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; | 697 | inst_hfi_gen2->hfi_frame_info.picture_type = pkt->payload[0]; |
| 673 | break; | 698 | break; |
| @@ -791,8 +816,21 @@ static void iris_hfi_gen2_init_src_change_param(struct iris_inst *inst) · 117 unmodified lines | |||
| 791 | full_range, video_format, | 816 | full_range, video_format, |
| 792 | video_signal_type_present_flag); | 817 | video_signal_type_present_flag); |
| 793 | 818 | ||
| 794 | subsc_params->profile = inst->fw_caps[PROFILE].value; | 819 | switch (inst->codec) { |
| 795 | subsc_params->level = inst->fw_caps[LEVEL].value; | 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 | subsc_params->pic_order_cnt = inst->fw_caps[POC].value; | 834 | subsc_params->pic_order_cnt = inst->fw_caps[POC].value; |
| 797 | subsc_params->bit_depth = inst->fw_caps[BIT_DEPTH].value; | 835 | subsc_params->bit_depth = inst->fw_caps[BIT_DEPTH].value; |
| 798 | if (inst->fw_caps[CODED_FRAMES].value == | 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 | struct iris_iface_q_info *q_info = &core->command_queue; | 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 | return -EINVAL; | 117 | return -EINVAL; |
| 118 | 118 | ||
| 119 | if (!iris_hfi_queue_write(q_info, pkt, pkt_size)) { | 119 | if (!iris_hfi_queue_write(q_info, pkt, pkt_size)) { |
| @@ -27,6 +27,7 @@ · 26 unmodified lines | |||
| 27 | * @crop: structure of crop info | 27 | * @crop: structure of crop info |
| 28 | * @completion: structure of signal completions | 28 | * @completion: structure of signal completions |
| 29 | * @flush_completion: structure of signal completions for flush cmd | 29 | * @flush_completion: structure of signal completions for flush cmd |
| 30 | * @flush_responses_pending: counter to track number of pending flush responses | ||
| 30 | * @fw_caps: array of supported instance firmware capabilities | 31 | * @fw_caps: array of supported instance firmware capabilities |
| 31 | * @buffers: array of different iris buffers | 32 | * @buffers: array of different iris buffers |
| 32 | * @fw_min_count: minimnum count of buffers needed by fw | 33 | * @fw_min_count: minimnum count of buffers needed by fw |
| @@ -42,6 +43,8 @@ · 9 unmodified lines | |||
| 42 | * @sequence_out: a sequence counter for output queue | 43 | * @sequence_out: a sequence counter for output queue |
| 43 | * @tss: timestamp metadata | 44 | * @tss: timestamp metadata |
| 44 | * @metadata_idx: index for metadata buffer | 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 | struct iris_inst { | 50 | struct iris_inst { |
| @@ -57,6 +60,7 @@ struct iris_inst { · 9 unmodified lines | |||
| 57 | struct iris_hfi_rect_desc crop; | 60 | struct iris_hfi_rect_desc crop; |
| 58 | struct completion completion; | 61 | struct completion completion; |
| 59 | struct completion flush_completion; | 62 | struct completion flush_completion; |
| 63 | u32 flush_responses_pending; | ||
| 60 | struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; | 64 | struct platform_inst_fw_cap fw_caps[INST_FW_CAP_MAX]; |
| 61 | struct iris_buffers buffers[BUF_TYPE_MAX]; | 65 | struct iris_buffers buffers[BUF_TYPE_MAX]; |
| 62 | u32 fw_min_count; | 66 | u32 fw_min_count; |
| @@ -72,6 +76,8 @@ struct iris_inst { · 9 unmodified lines | |||
| 72 | u32 sequence_out; | 76 | u32 sequence_out; |
| 73 | struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; | 77 | struct iris_ts_metadata tss[VIDEO_MAX_FRAME]; |
| 74 | u32 metadata_idx; | 78 | u32 metadata_idx; |
| 79 | u32 codec; | ||
| 80 | bool last_buffer_dequeued; | ||
| 75 | }; | 81 | }; |
| 76 | 82 | ||
| 77 | #endif | 83 | #endif |
| @@ -21,6 +21,7 @@ struct iris_inst; · 20 unmodified lines | |||
| 21 | #define DEFAULT_MAX_HOST_BUF_COUNT 64 | 21 | #define DEFAULT_MAX_HOST_BUF_COUNT 64 |
| 22 | #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 | 22 | #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 |
| 23 | #define DEFAULT_FPS 30 | 23 | #define DEFAULT_FPS 30 |
| 24 | #define NUM_MBS_8K ((8192 * 4352) / 256) | ||
| 24 | 25 | ||
| 25 | enum stage_type { | 26 | enum stage_type { |
| 26 | STAGE_1 = 1, | 27 | STAGE_1 = 1, |
| @@ -80,8 +81,12 @@ struct platform_inst_caps { · 53 unmodified lines | |||
| 80 | }; | 81 | }; |
| 81 | 82 | ||
| 82 | enum platform_inst_fw_cap_type { | 83 | enum platform_inst_fw_cap_type { |
| 83 | PROFILE = 1, | 84 | PROFILE_H264 = 1, |
| 84 | LEVEL, | 85 | PROFILE_HEVC, |
| 86 | PROFILE_VP9, | ||
| 87 | LEVEL_H264, | ||
| 88 | LEVEL_HEVC, | ||
| 89 | LEVEL_VP9, | ||
| 85 | INPUT_BUF_HOST_MAX_COUNT, | 90 | INPUT_BUF_HOST_MAX_COUNT, |
| 86 | STAGE, | 91 | STAGE, |
| 87 | PIPE, | 92 | PIPE, |
| @@ -89,7 +94,7 @@ enum platform_inst_fw_cap_type { · 1 unmodified line | |||
| 89 | CODED_FRAMES, | 94 | CODED_FRAMES, |
| 90 | BIT_DEPTH, | 95 | BIT_DEPTH, |
| 91 | RAP_FRAME, | 96 | RAP_FRAME, |
| 92 | DEBLOCK, | 97 | TIER, |
| 93 | INST_FW_CAP_MAX, | 98 | INST_FW_CAP_MAX, |
| 94 | }; | 99 | }; |
| 95 | 100 | ||
| @@ -172,15 +177,24 @@ struct iris_platform_data { · 76 unmodified lines | |||
| 172 | struct ubwc_config_data *ubwc_config; | 177 | struct ubwc_config_data *ubwc_config; |
| 173 | u32 num_vpp_pipe; | 178 | u32 num_vpp_pipe; |
| 174 | u32 max_session_count; | 179 | u32 max_session_count; |
| 180 | /* max number of macroblocks per frame supported */ | ||
| 175 | u32 max_core_mbpf; | 181 | u32 max_core_mbpf; |
| 176 | const u32 *input_config_params; | 182 | const u32 *input_config_params_default; |
| 177 | unsigned int input_config_params_size; | 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 | const u32 *output_config_params; | 188 | const u32 *output_config_params; |
| 179 | unsigned int output_config_params_size; | 189 | unsigned int output_config_params_size; |
| 180 | const u32 *dec_input_prop; | 190 | const u32 *dec_input_prop; |
| 181 | unsigned int dec_input_prop_size; | 191 | unsigned int dec_input_prop_size; |
| 182 | const u32 *dec_output_prop; | 192 | const u32 *dec_output_prop_avc; |
| 183 | unsigned int dec_output_prop_size; | 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 | const u32 *dec_ip_int_buf_tbl; | 198 | const u32 *dec_ip_int_buf_tbl; |
| 185 | unsigned int dec_ip_int_buf_tbl_size; | 199 | unsigned int dec_ip_int_buf_tbl_size; |
| 186 | const u32 *dec_op_int_buf_tbl; | 200 | const u32 *dec_op_int_buf_tbl; |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { | 18 | static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { |
| 19 | { | 19 | { |
| 20 | .cap_id = PROFILE, | 20 | .cap_id = PROFILE_H264, |
| 21 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, | 21 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, |
| 22 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, | 22 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, |
| 23 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | | 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 | .set = iris_set_u32_enum, | 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 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, | 57 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, |
| 36 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, | 58 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, |
| 37 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | | 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 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | 81 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 60 | .set = iris_set_u32_enum, | 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 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, | 139 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, |
| 64 | .min = DEFAULT_MAX_HOST_BUF_COUNT, | 140 | .min = DEFAULT_MAX_HOST_BUF_COUNT, |
| @@ -181,9 +257,10 @@ static struct tz_cp_config tz_cp_config_sm8550 = { · 116 unmodified lines | |||
| 181 | .cp_nonpixel_size = 0x24800000, | 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 | HFI_PROP_BITSTREAM_RESOLUTION, | 261 | HFI_PROP_BITSTREAM_RESOLUTION, |
| 186 | HFI_PROP_CROP_OFFSETS, | 262 | HFI_PROP_CROP_OFFSETS, |
| 263 | HFI_PROP_LUMA_CHROMA_BIT_DEPTH, | ||
| 187 | HFI_PROP_CODED_FRAMES, | 264 | HFI_PROP_CODED_FRAMES, |
| 188 | HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, | 265 | HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, |
| 189 | HFI_PROP_PIC_ORDER_CNT_TYPE, | 266 | HFI_PROP_PIC_ORDER_CNT_TYPE, |
| @@ -192,6 +269,26 @@ static const u32 sm8550_vdec_input_config_params[] = { · 2 unmodified lines | |||
| 192 | HFI_PROP_SIGNAL_COLOR_INFO, | 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 | static const u32 sm8550_vdec_output_config_params[] = { | 292 | static const u32 sm8550_vdec_output_config_params[] = { |
| 196 | HFI_PROP_COLOR_FORMAT, | 293 | HFI_PROP_COLOR_FORMAT, |
| 197 | HFI_PROP_LINEAR_STRIDE_SCANLINE, | 294 | HFI_PROP_LINEAR_STRIDE_SCANLINE, |
| @@ -201,11 +298,19 @@ static const u32 sm8550_vdec_subscribe_input_properties[] = { · 3 unmodified lines | |||
| 201 | HFI_PROP_NO_OUTPUT, | 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 | HFI_PROP_PICTURE_TYPE, | 302 | HFI_PROP_PICTURE_TYPE, |
| 206 | HFI_PROP_CABAC_SESSION, | 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 | static const u32 sm8550_dec_ip_int_buf_tbl[] = { | 314 | static const u32 sm8550_dec_ip_int_buf_tbl[] = { |
| 210 | BUF_BIN, | 315 | BUF_BIN, |
| 211 | BUF_COMV, | 316 | BUF_COMV, |
| @@ -248,19 +353,34 @@ struct iris_platform_data sm8550_data = { · 36 unmodified lines | |||
| 248 | .ubwc_config = &ubwc_config_sm8550, | 353 | .ubwc_config = &ubwc_config_sm8550, |
| 249 | .num_vpp_pipe = 4, | 354 | .num_vpp_pipe = 4, |
| 250 | .max_session_count = 16, | 355 | .max_session_count = 16, |
| 251 | .max_core_mbpf = ((8192 * 4352) / 256) * 2, | 356 | .max_core_mbpf = NUM_MBS_8K * 2, |
| 252 | .input_config_params = | 357 | .input_config_params_default = |
| 253 | sm8550_vdec_input_config_params, | 358 | sm8550_vdec_input_config_params_default, |
| 254 | .input_config_params_size = | 359 | .input_config_params_default_size = |
| 255 | ARRAY_SIZE(sm8550_vdec_input_config_params), | 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 | .output_config_params = | 369 | .output_config_params = |
| 257 | sm8550_vdec_output_config_params, | 370 | sm8550_vdec_output_config_params, |
| 258 | .output_config_params_size = | 371 | .output_config_params_size = |
| 259 | ARRAY_SIZE(sm8550_vdec_output_config_params), | 372 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 260 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, | 373 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 261 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), | 374 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 262 | .dec_output_prop = sm8550_vdec_subscribe_output_properties, | 375 | .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, |
| 263 | .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | 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 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, | 385 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 266 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), | 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 | .ubwc_config = &ubwc_config_sm8550, | 428 | .ubwc_config = &ubwc_config_sm8550, |
| 309 | .num_vpp_pipe = 4, | 429 | .num_vpp_pipe = 4, |
| 310 | .max_session_count = 16, | 430 | .max_session_count = 16, |
| 311 | .max_core_mbpf = ((8192 * 4352) / 256) * 2, | 431 | .max_core_mbpf = NUM_MBS_8K * 2, |
| 312 | .input_config_params = | 432 | .input_config_params_default = |
| 313 | sm8550_vdec_input_config_params, | 433 | sm8550_vdec_input_config_params_default, |
| 314 | .input_config_params_size = | 434 | .input_config_params_default_size = |
| 315 | ARRAY_SIZE(sm8550_vdec_input_config_params), | 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 | .output_config_params = | 444 | .output_config_params = |
| 317 | sm8550_vdec_output_config_params, | 445 | sm8550_vdec_output_config_params, |
| 318 | .output_config_params_size = | 446 | .output_config_params_size = |
| 319 | ARRAY_SIZE(sm8550_vdec_output_config_params), | 447 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 320 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, | 448 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 321 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), | 449 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 322 | .dec_output_prop = sm8550_vdec_subscribe_output_properties, | 450 | .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, |
| 323 | .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | 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 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, | 460 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 326 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), | 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 | .num_vpp_pipe = 2, | 500 | .num_vpp_pipe = 2, |
| 366 | .max_session_count = 16, | 501 | .max_session_count = 16, |
| 367 | .max_core_mbpf = ((4096 * 2176) / 256) * 4, | 502 | .max_core_mbpf = ((4096 * 2176) / 256) * 4, |
| 368 | .input_config_params = | 503 | .input_config_params_default = |
| 369 | sm8550_vdec_input_config_params, | 504 | sm8550_vdec_input_config_params_default, |
| 370 | .input_config_params_size = | 505 | .input_config_params_default_size = |
| 371 | ARRAY_SIZE(sm8550_vdec_input_config_params), | 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 | .output_config_params = | 515 | .output_config_params = |
| 373 | sm8550_vdec_output_config_params, | 516 | sm8550_vdec_output_config_params, |
| 374 | .output_config_params_size = | 517 | .output_config_params_size = |
| 375 | ARRAY_SIZE(sm8550_vdec_output_config_params), | 518 | ARRAY_SIZE(sm8550_vdec_output_config_params), |
| 376 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, | 519 | .dec_input_prop = sm8550_vdec_subscribe_input_properties, |
| 377 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), | 520 | .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), |
| 378 | .dec_output_prop = sm8550_vdec_subscribe_output_properties, | 521 | .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, |
| 379 | .dec_output_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_output_properties), | 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 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, | 531 | .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, |
| 382 | .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), | 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 | static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { | 6 | static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { |
| 7 | { | 7 | { |
| 8 | .cap_id = PROFILE, | 8 | .cap_id = PROFILE_H264, |
| 9 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, | 9 | .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, |
| 10 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, | 10 | .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, |
| 11 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | | 11 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | |
| 12 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | | 12 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | |
| 13 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | | 13 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | |
| 14 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | 14 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | |
| 15 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), | 15 | BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), |
| 16 | .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, | 16 | .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, |
| 17 | .hfi_id = HFI_PROP_PROFILE, | 17 | .hfi_id = HFI_PROP_PROFILE, |
| 18 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | 18 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 19 | .set = iris_set_u32_enum, | 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 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, | 45 | .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, |
| 24 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, | 46 | .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, |
| 25 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | | 47 | .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | |
| 26 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | | 48 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | |
| 27 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | | 49 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | |
| 28 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | | 50 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | |
| 29 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | | 51 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | |
| 30 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | | 52 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | |
| 31 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | | 53 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | |
| 32 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | | 54 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | |
| 33 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | | 55 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | |
| 34 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | | 56 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | |
| 35 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | | 57 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | |
| 36 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | | 58 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | |
| 37 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | | 59 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | |
| 38 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | | 60 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | |
| 39 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | | 61 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | |
| 40 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | | 62 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | |
| 41 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | | 63 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | |
| 42 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | | 64 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | |
| 43 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | | 65 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | |
| 44 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), | 66 | BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), |
| 45 | .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, | 67 | .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, |
| 46 | .hfi_id = HFI_PROP_LEVEL, | 68 | .hfi_id = HFI_PROP_LEVEL, |
| 47 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, | 69 | .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, |
| 48 | .set = iris_set_u32_enum, | 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 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, | 127 | .cap_id = INPUT_BUF_HOST_MAX_COUNT, |
| 52 | .min = DEFAULT_MAX_HOST_BUF_COUNT, | 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 | .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, | 30 | .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, |
| 31 | .set = iris_set_stage, | 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 | static struct platform_inst_caps platform_inst_cap_sm8250 = { | 35 | static struct platform_inst_caps platform_inst_cap_sm8250 = { |
| @@ -136,10 +127,10 @@ struct iris_platform_data sm8250_data = { · 91 unmodified lines | |||
| 136 | .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, | 127 | .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, |
| 137 | .num_vpp_pipe = 4, | 128 | .num_vpp_pipe = 4, |
| 138 | .max_session_count = 16, | 129 | .max_session_count = 16, |
| 139 | .max_core_mbpf = (8192 * 4352) / 256, | 130 | .max_core_mbpf = NUM_MBS_8K, |
| 140 | .input_config_params = | 131 | .input_config_params_default = |
| 141 | sm8250_vdec_input_config_param_default, | 132 | sm8250_vdec_input_config_param_default, |
| 142 | .input_config_params_size = | 133 | .input_config_params_default_size = |
| 143 | ARRAY_SIZE(sm8250_vdec_input_config_param_default), | 134 | ARRAY_SIZE(sm8250_vdec_input_config_param_default), |
| 144 | 135 | ||
| 145 | .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, | 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 | struct dev_pm_domain_attach_data iris_opp_pd_data = { | 53 | struct dev_pm_domain_attach_data iris_opp_pd_data = { |
| 54 | .pd_names = core->iris_platform_data->opp_pd_tbl, | 54 | .pd_names = core->iris_platform_data->opp_pd_tbl, |
| 55 | .num_pd_names = core->iris_platform_data->opp_pd_tbl_size, | 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 | ret = devm_pm_domain_attach_list(core->dev, &iris_pd_data, &core->pmdomain_tbl); | 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 | return iris_inst_change_sub_state(inst, 0, set_sub_state); | 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 | return inst->sub_state & IRIS_INST_SUB_DRC && | 250 | return inst->sub_state & IRIS_INST_SUB_DRC && |
| 251 | inst->sub_state & IRIS_INST_SUB_DRC_LAST; | 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 | int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); | 140 | int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); |
| 141 | int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane); | 141 | int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane); |
| 142 | bool iris_allow_cmd(struct iris_inst *inst, u32 cmd); | 142 | bool iris_allow_cmd(struct iris_inst *inst, u32 cmd); |
| 143 | bool iris_drc_pending(struct iris_inst *inst); | ||
| 143 | 144 | ||
| 144 | #endif | 145 | #endif |
| @@ -259,13 +259,14 @@ int iris_vb2_buf_prepare(struct vb2_buffer *vb) · 258 unmodified lines | |||
| 259 | return -EINVAL; | 259 | return -EINVAL; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | 262 | if (!(inst->sub_state & IRIS_INST_SUB_DRC)) { |
| 263 | vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) | 263 | if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && |
| 264 | return -EINVAL; | 264 | vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_OUTPUT)) |
| 265 | if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | 265 | return -EINVAL; |
| 266 | vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) | 266 | if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && |
| 267 | return -EINVAL; | 267 | vb2_plane_size(vb, 0) < iris_get_buffer_size(inst, BUF_INPUT)) |
| 268 | 268 | return -EINVAL; | |
| 269 | } | ||
| 269 | return 0; | 270 | return 0; |
| 270 | } | 271 | } |
| 271 | 272 | ||
| @@ -304,7 +305,7 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) · 32 unmodified lines | |||
| 304 | goto exit; | 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 | if ((inst->sub_state & IRIS_INST_SUB_DRC && | 309 | if ((inst->sub_state & IRIS_INST_SUB_DRC && |
| 309 | inst->sub_state & IRIS_INST_SUB_DRC_LAST) || | 310 | inst->sub_state & IRIS_INST_SUB_DRC_LAST) || |
| 310 | (inst->sub_state & IRIS_INST_SUB_DRAIN && | 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 | v4l2_event_queue_fh(&inst->fh, &eos); | 319 | v4l2_event_queue_fh(&inst->fh, &eos); |
| 319 | v4l2_m2m_mark_stopped(m2m_ctx); | 320 | v4l2_m2m_mark_stopped(m2m_ctx); |
| 320 | } | 321 | } |
| 322 | inst->last_buffer_dequeued = true; | ||
| 321 | goto exit; | 323 | goto exit; |
| 322 | } | 324 | } |
| 323 | } | 325 | } |
| @@ -32,6 +32,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) · 31 unmodified lines | |||
| 32 | f->fmt.pix_mp.width = DEFAULT_WIDTH; | 32 | f->fmt.pix_mp.width = DEFAULT_WIDTH; |
| 33 | f->fmt.pix_mp.height = DEFAULT_HEIGHT; | 33 | f->fmt.pix_mp.height = DEFAULT_HEIGHT; |
| 34 | f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; | 34 | f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; |
| 35 | inst->codec = f->fmt.pix_mp.pixelformat; | ||
| 35 | f->fmt.pix_mp.num_planes = 1; | 36 | f->fmt.pix_mp.num_planes = 1; |
| 36 | f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; | 37 | f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; |
| 37 | f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); | 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 | kfree(inst->fmt_src); | 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 | int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) | 116 | int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) |
| 71 | { | 117 | { |
| 118 | const struct iris_fmt *fmt; | ||
| 119 | |||
| 72 | switch (f->type) { | 120 | switch (f->type) { |
| 73 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 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 | f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; | 127 | f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; |
| 76 | break; | 128 | break; |
| 77 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | 129 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
| 130 | if (f->index) | ||
| 131 | return -EINVAL; | ||
| 78 | f->pixelformat = V4L2_PIX_FMT_NV12; | 132 | f->pixelformat = V4L2_PIX_FMT_NV12; |
| 79 | break; | 133 | break; |
| 80 | default: | 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 | struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; | 143 | struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; |
| 90 | struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; | 144 | struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; |
| 145 | const struct iris_fmt *fmt; | ||
| 91 | struct v4l2_format *f_inst; | 146 | struct v4l2_format *f_inst; |
| 92 | struct vb2_queue *src_q; | 147 | struct vb2_queue *src_q; |
| 93 | 148 | ||
| 94 | memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); | 149 | memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); |
| 150 | fmt = find_format(inst, pixmp->pixelformat, f->type); | ||
| 95 | switch (f->type) { | 151 | switch (f->type) { |
| 96 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 152 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: |
| 97 | if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) { | 153 | if (!fmt) { |
| 98 | f_inst = inst->fmt_src; | 154 | f_inst = inst->fmt_src; |
| 99 | f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; | 155 | f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; |
| 100 | f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; | 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 | break; | 159 | break; |
| 104 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | 160 | case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: |
| 105 | if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) { | 161 | if (!fmt) { |
| 106 | f_inst = inst->fmt_dst; | 162 | f_inst = inst->fmt_dst; |
| 107 | f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; | 163 | f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; |
| 108 | f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; | 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 | switch (f->type) { | 202 | switch (f->type) { |
| 147 | case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | 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 | return -EINVAL; | 205 | return -EINVAL; |
| 150 | 206 | ||
| 151 | fmt = inst->fmt_src; | 207 | fmt = inst->fmt_src; |
| 152 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | 208 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| 153 | 209 | fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; | |
| 154 | codec_align = DEFAULT_CODEC_ALIGNMENT; | 210 | inst->codec = fmt->fmt.pix_mp.pixelformat; |
| 211 | codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; | ||
| 155 | fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); | 212 | fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); |
| 156 | fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); | 213 | fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); |
| 157 | fmt->fmt.pix_mp.num_planes = 1; | 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 | output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; | 228 | output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; |
| 172 | output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; | 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 | inst->crop.left = 0; | 236 | inst->crop.left = 0; |
| 175 | inst->crop.top = 0; | 237 | inst->crop.top = 0; |
| 176 | inst->crop.width = f->fmt.pix_mp.width; | 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 | v4l2_event_queue_fh(&inst->fh, &event); | 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 | static void iris_vdec_flush_deferred_buffers(struct iris_inst *inst, | 305 | static void iris_vdec_flush_deferred_buffers(struct iris_inst *inst, |
| 273 | enum iris_buffer_type type) | 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 | const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; | 350 | const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; |
| 318 | enum iris_buffer_type buffer_type; | 351 | enum iris_buffer_type buffer_type; |
| 319 | u32 count; | ||
| 320 | int ret; | 352 | int ret; |
| 321 | 353 | ||
| 322 | switch (plane) { | 354 | switch (plane) { |
| @@ -334,12 +366,6 @@ int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) · 11 unmodified lines | |||
| 334 | if (ret) | 366 | if (ret) |
| 335 | goto error; | 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 | ret = iris_inst_state_change_streamoff(inst, plane); | 369 | ret = iris_inst_state_change_streamoff(inst, plane); |
| 344 | if (ret) | 370 | if (ret) |
| 345 | goto error; | 371 | goto error; |
| @@ -408,7 +434,7 @@ int iris_vdec_streamon_input(struct iris_inst *inst) · 62 unmodified lines | |||
| 408 | 434 | ||
| 409 | iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 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 | if (ret) | 438 | if (ret) |
| 413 | return ret; | 439 | return ret; |
| 414 | 440 | ||
| @@ -482,6 +508,8 @@ static int iris_vdec_process_streamon_output(struct iris_inst *inst) · 67 unmodified lines | |||
| 482 | if (ret) | 508 | if (ret) |
| 483 | return ret; | 509 | return ret; |
| 484 | 510 | ||
| 511 | inst->last_buffer_dequeued = false; | ||
| 512 | |||
| 485 | return iris_inst_change_sub_state(inst, clear_sub_state, 0); | 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 | iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | 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 | if (ret) | 528 | if (ret) |
| 501 | return ret; | 529 | return ret; |
| 502 | 530 | ||
| @@ -8,6 +8,17 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | struct iris_inst; | 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 | int iris_vdec_inst_init(struct iris_inst *inst); | 22 | int iris_vdec_inst_init(struct iris_inst *inst); |
| 12 | void iris_vdec_inst_deinit(struct iris_inst *inst); | 23 | void iris_vdec_inst_deinit(struct iris_inst *inst); |
| 13 | int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); | 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 | iris_wait_for_session_response(inst, false); | 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 | int iris_close(struct file *filp) | 251 | int iris_close(struct file *filp) |
| 225 | { | 252 | { |
| 226 | struct iris_inst *inst = iris_get_inst(filp, NULL); | 253 | struct iris_inst *inst = iris_get_inst(filp, NULL); |
| @@ -233,8 +260,10 @@ int iris_close(struct file *filp) · 6 unmodified lines | |||
| 233 | iris_session_close(inst); | 260 | iris_session_close(inst); |
| 234 | iris_inst_change_state(inst, IRIS_INST_DEINIT); | 261 | iris_inst_change_state(inst, IRIS_INST_DEINIT); |
| 235 | iris_v4l2_fh_deinit(inst); | 262 | iris_v4l2_fh_deinit(inst); |
| 236 | iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 263 | iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| 237 | iris_destroy_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_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 | iris_remove_session(inst); | 267 | iris_remove_session(inst); |
| 239 | mutex_unlock(&inst->lock); | 268 | mutex_unlock(&inst->lock); |
| 240 | mutex_destroy(&inst->ctx_q_lock); | 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 | struct iris_inst *inst = iris_get_inst(filp, NULL); | 279 | struct iris_inst *inst = iris_get_inst(filp, NULL); |
| 251 | 280 | ||
| 252 | if (f->index) | ||
| 253 | return -EINVAL; | ||
| 254 | |||
| 255 | return iris_vdec_enum_fmt(inst, f); | 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 | return size_h264d_hw_bin_buffer(n_aligned_w, n_aligned_h, num_vpp_pipes); | 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 | static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) | 70 | static u32 hfi_buffer_comv_h264d(u32 frame_width, u32 frame_height, u32 _comv_bufcount) |
| 35 | { | 71 | { |
| 36 | u32 frame_height_in_mbs = DIV_ROUND_UP(frame_height, 16); | 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 | return (size_colloc * (_comv_bufcount)) + 512; | 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 | static u32 size_h264d_bse_cmd_buf(u32 frame_height) | 105 | static u32 size_h264d_bse_cmd_buf(u32 frame_height) |
| 59 | { | 106 | { |
| 60 | u32 height = ALIGN(frame_height, 32); | 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 | SIZE_H264D_BSE_CMD_PER_BUF; | 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 | static u32 size_h264d_vpp_cmd_buf(u32 frame_height) | 151 | static u32 size_h264d_vpp_cmd_buf(u32 frame_height) |
| 67 | { | 152 | { |
| 68 | u32 size, height = ALIGN(frame_height, 32); | 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 | static u32 hfi_buffer_non_comv_h264d(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) | 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; | 171 | u32 size_bse = size_h264d_bse_cmd_buf(frame_height); |
| 87 | 172 | u32 size_vpp = size_h264d_vpp_cmd_buf(frame_height); | |
| 88 | size_bse = size_h264d_bse_cmd_buf(frame_height); | 173 | u32 size = ALIGN(size_bse, DMA_ALIGNMENT) + |
| 89 | size_vpp = size_h264d_vpp_cmd_buf(frame_height); | ||
| 90 | size = ALIGN(size_bse, DMA_ALIGNMENT) + | ||
| 91 | ALIGN(size_vpp, DMA_ALIGNMENT) + | 174 | ALIGN(size_vpp, DMA_ALIGNMENT) + |
| 92 | ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT); | 175 | ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), DMA_ALIGNMENT); |
| 93 | 176 | ||
| 94 | return ALIGN(size, DMA_ALIGNMENT); | 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 | static u32 size_vpss_lb(u32 frame_width, u32 frame_height) | 210 | static u32 size_vpss_lb(u32 frame_width, u32 frame_height) |
| 98 | { | 211 | { |
| 99 | u32 opb_lb_wr_llb_y_buffer_size, opb_lb_wr_llb_uv_buffer_size; | 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 | opb_lb_wr_llb_y_buffer_size; | 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 | static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height, | 432 | static u32 hfi_buffer_line_h264d(u32 frame_width, u32 frame_height, |
| 123 | bool is_opb, u32 num_vpp_pipes) | 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 | u32 height = f->fmt.pix_mp.height; | 458 | u32 height = f->fmt.pix_mp.height; |
| 149 | u32 width = f->fmt.pix_mp.width; | 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 | static u32 iris_vpu_dec_comv_size(struct iris_inst *inst) | 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 | u32 height = f->fmt.pix_mp.height; | 475 | u32 height = f->fmt.pix_mp.height; |
| 159 | u32 width = f->fmt.pix_mp.width; | 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 | static u32 iris_vpu_dec_persist_size(struct iris_inst *inst) | 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 | static u32 iris_vpu_dec_dpb_size(struct iris_inst *inst) | 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 | u32 height = f->fmt.pix_mp.height; | 510 | u32 height = f->fmt.pix_mp.height; |
| 182 | u32 width = f->fmt.pix_mp.width; | 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 | static u32 iris_vpu_dec_line_size(struct iris_inst *inst) | 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 | u32 height = f->fmt.pix_mp.height; | 525 | u32 height = f->fmt.pix_mp.height; |
| 192 | u32 width = f->fmt.pix_mp.width; | 526 | u32 width = f->fmt.pix_mp.width; |
| 193 | bool is_opb = false; | 527 | bool is_opb = false; |
| 528 | u32 out_min_count = inst->buffers[BUF_OUTPUT].min_count; | ||
| 194 | 529 | ||
| 195 | if (iris_split_mode_enabled(inst)) | 530 | if (iris_split_mode_enabled(inst)) |
| 196 | is_opb = true; | 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 | static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) | 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 | iris_vpu_dec_line_size(inst); | 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 | struct iris_vpu_buf_type_handle { | 569 | struct iris_vpu_buf_type_handle { |
| 209 | enum iris_buffer_type type; | 570 | enum iris_buffer_type type; |
| 210 | u32 (*handle)(struct iris_inst *inst); | 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 | return size; | 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 | static inline int iris_vpu_dpb_count(struct iris_inst *inst) | 615 | static inline int iris_vpu_dpb_count(struct iris_inst *inst) |
| 242 | { | 616 | { |
| 243 | if (iris_split_mode_enabled(inst)) { | 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 | case BUF_INPUT: | 628 | case BUF_INPUT: |
| 255 | return MIN_BUFFERS; | 629 | return MIN_BUFFERS; |
| 256 | case BUF_OUTPUT: | 630 | case BUF_OUTPUT: |
| 257 | return inst->fw_min_count; | 631 | return output_min_count(inst); |
| 258 | case BUF_BIN: | 632 | case BUF_BIN: |
| 259 | case BUF_COMV: | 633 | case BUF_COMV: |
| 260 | case BUF_NON_COMV: | 634 | case BUF_NON_COMV: |
| 261 | case BUF_LINE: | 635 | case BUF_LINE: |
| 262 | case BUF_PERSIST: | 636 | case BUF_PERSIST: |
| 637 | return internal_buffer_count(inst, buffer_type); | ||
| 263 | case BUF_SCRATCH_1: | 638 | case BUF_SCRATCH_1: |
| 264 | return 1; /* internal buffer count needed by firmware is 1 */ | 639 | return 1; /* internal buffer count needed by firmware is 1 */ |
| 265 | case BUF_DPB: | 640 | case BUF_DPB: |
| @@ -13,6 +13,10 @@ struct iris_inst; · 12 unmodified lines | |||
| 13 | #define DMA_ALIGNMENT 256 | 13 | #define DMA_ALIGNMENT 256 |
| 14 | 14 | ||
| 15 | #define NUM_HW_PIC_BUF 32 | 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 | #define SIZE_HW_PIC(size_per_buf) (NUM_HW_PIC_BUF * (size_per_buf)) | 20 | #define SIZE_HW_PIC(size_per_buf) (NUM_HW_PIC_BUF * (size_per_buf)) |
| 17 | 21 | ||
| 18 | #define MAX_TILE_COLUMNS 32 | 22 | #define MAX_TILE_COLUMNS 32 |
| @@ -28,11 +32,47 @@ struct iris_inst; · 9 unmodified lines | |||
| 28 | #define SIZE_SLIST_BUF_H264 512 | 32 | #define SIZE_SLIST_BUF_H264 512 |
| 29 | #define H264_DISPLAY_BUF_SIZE 3328 | 33 | #define H264_DISPLAY_BUF_SIZE 3328 |
| 30 | #define H264_NUM_FRM_INFO 66 | 34 | #define H264_NUM_FRM_INFO 66 |
| 31 | 35 | #define H265_NUM_TILE_COL 32 | |
| 32 | #define SIZE_SEI_USERDATA 4096 | 36 | #define H265_NUM_TILE_ROW 128 |
| 33 | 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 | #define H264_CABAC_HDR_RATIO_HD_TOT 1 | 61 | #define H264_CABAC_HDR_RATIO_HD_TOT 1 |
| 35 | #define H264_CABAC_RES_RATIO_HD_TOT 3 | 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 | #define SIZE_H264D_HW_PIC_T (BIT(11)) | 76 | #define SIZE_H264D_HW_PIC_T (BIT(11)) |
| 37 | 77 | ||
| 38 | #define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 | 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 | INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); | 424 | INIT_DELAYED_WORK(&core->work, venus_sys_error_handler); |
| 425 | init_waitqueue_head(&core->sys_err_done); | 425 | init_waitqueue_head(&core->sys_err_done); |
| 426 | 426 | ||
| 427 | ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread, | 427 | ret = hfi_create(core, &venus_core_ops); |
| 428 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, | ||
| 429 | "venus", core); | ||
| 430 | if (ret) | 428 | if (ret) |
| 431 | goto err_core_put; | 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 | if (ret) | 434 | if (ret) |
| 435 | goto err_core_put; | 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 | static const struct freq_tbl msm8998_freq_table[] = { | 711 | static const struct freq_tbl msm8998_freq_table[] = { |
| 712 | { 1944000, 465000000 }, /* 4k UHD @ 60 (decode only) */ | 712 | { 1728000, 533000000 }, /* 4k UHD @ 60 (decode only) */ |
| 713 | { 972000, 465000000 }, /* 4k UHD @ 30 */ | 713 | { 1036800, 444000000 }, /* 2k @ 120 */ |
| 714 | { 489600, 360000000 }, /* 1080p @ 60 */ | 714 | { 829440, 355200000 }, /* 4k @ 44 */ |
| 715 | { 244800, 186000000 }, /* 1080p @ 30 */ | 715 | { 489600, 269330000 },/* 4k @ 30 */ |
| 716 | { 108000, 100000000 }, /* 720p @ 30 */ | 716 | { 108000, 200000000 }, /* 1080p @ 60 */ |
| 717 | }; | 717 | }; |
| 718 | 718 | ||
| 719 | static const struct reg_val msm8998_reg_preset[] = { | 719 | static const struct reg_val msm8998_reg_preset[] = { |
| @@ -28,6 +28,8 @@ · 27 unmodified lines | |||
| 28 | #define VIDC_RESETS_NUM_MAX 2 | 28 | #define VIDC_RESETS_NUM_MAX 2 |
| 29 | #define VIDC_MAX_HIER_CODING_LAYER 6 | 29 | #define VIDC_MAX_HIER_CODING_LAYER 6 |
| 30 | 30 | ||
| 31 | #define VENUS_MAX_FPS 240 | ||
| 32 | |||
| 31 | extern int venus_fw_debug; | 33 | extern int venus_fw_debug; |
| 32 | 34 | ||
| 33 | struct freq_tbl { | 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 | struct hfi_buffer_requirements *bufreq; | 33 | struct hfi_buffer_requirements *bufreq; |
| 34 | struct hfi_extradata_input_crop *crop; | 34 | struct hfi_extradata_input_crop *crop; |
| 35 | struct hfi_dpb_counts *dpb_count; | 35 | struct hfi_dpb_counts *dpb_count; |
| 36 | u32 ptype, rem_bytes; | ||
| 37 | u32 size_read = 0; | ||
| 36 | u8 *data_ptr; | 38 | u8 *data_ptr; |
| 37 | u32 ptype; | ||
| 38 | 39 | ||
| 39 | inst->error = HFI_ERR_NONE; | 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 | break; | 45 | break; |
| 45 | default: | 46 | default: |
| 46 | inst->error = HFI_ERR_SESSION_INVALID_PARAMETER; | 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 | event.event_type = pkt->event_data1; | 52 | event.event_type = pkt->event_data1; |
| 51 | 53 | ||
| 52 | num_properties_changed = pkt->event_data2; | 54 | num_properties_changed = pkt->event_data2; |
| 53 | if (!num_properties_changed) { | 55 | if (!num_properties_changed) |
| 54 | inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES; | 56 | goto error; |
| 55 | goto done; | ||
| 56 | } | ||
| 57 | 57 | ||
| 58 | data_ptr = (u8 *)&pkt->ext_event_data[0]; | 58 | data_ptr = (u8 *)&pkt->ext_event_data[0]; |
| 59 | rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt); | ||
| 60 | |||
| 59 | do { | 61 | do { |
| 62 | if (rem_bytes < sizeof(u32)) | ||
| 63 | goto error; | ||
| 60 | ptype = *((u32 *)data_ptr); | 64 | ptype = *((u32 *)data_ptr); |
| 65 | |||
| 66 | data_ptr += sizeof(u32); | ||
| 67 | rem_bytes -= sizeof(u32); | ||
| 68 | |||
| 61 | switch (ptype) { | 69 | switch (ptype) { |
| 62 | case HFI_PROPERTY_PARAM_FRAME_SIZE: | 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 | frame_sz = (struct hfi_framesize *)data_ptr; | 74 | frame_sz = (struct hfi_framesize *)data_ptr; |
| 65 | event.width = frame_sz->width; | 75 | event.width = frame_sz->width; |
| 66 | event.height = frame_sz->height; | 76 | event.height = frame_sz->height; |
| 67 | data_ptr += sizeof(*frame_sz); | 77 | size_read = sizeof(struct hfi_framesize); |
| 68 | break; | 78 | break; |
| 69 | case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: | 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 | profile_level = (struct hfi_profile_level *)data_ptr; | 83 | profile_level = (struct hfi_profile_level *)data_ptr; |
| 72 | event.profile = profile_level->profile; | 84 | event.profile = profile_level->profile; |
| 73 | event.level = profile_level->level; | 85 | event.level = profile_level->level; |
| 74 | data_ptr += sizeof(*profile_level); | 86 | size_read = sizeof(struct hfi_profile_level); |
| 75 | break; | 87 | break; |
| 76 | case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH: | 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 | pixel_depth = (struct hfi_bit_depth *)data_ptr; | 92 | pixel_depth = (struct hfi_bit_depth *)data_ptr; |
| 79 | event.bit_depth = pixel_depth->bit_depth; | 93 | event.bit_depth = pixel_depth->bit_depth; |
| 80 | data_ptr += sizeof(*pixel_depth); | 94 | size_read = sizeof(struct hfi_bit_depth); |
| 81 | break; | 95 | break; |
| 82 | case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT: | 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 | pic_struct = (struct hfi_pic_struct *)data_ptr; | 100 | pic_struct = (struct hfi_pic_struct *)data_ptr; |
| 85 | event.pic_struct = pic_struct->progressive_only; | 101 | event.pic_struct = pic_struct->progressive_only; |
| 86 | data_ptr += sizeof(*pic_struct); | 102 | size_read = sizeof(struct hfi_pic_struct); |
| 87 | break; | 103 | break; |
| 88 | case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE: | 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 | colour_info = (struct hfi_colour_space *)data_ptr; | 108 | colour_info = (struct hfi_colour_space *)data_ptr; |
| 91 | event.colour_space = colour_info->colour_space; | 109 | event.colour_space = colour_info->colour_space; |
| 92 | data_ptr += sizeof(*colour_info); | 110 | size_read = sizeof(struct hfi_colour_space); |
| 93 | break; | 111 | break; |
| 94 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: | 112 | case HFI_PROPERTY_CONFIG_VDEC_ENTROPY: |
| 95 | data_ptr += sizeof(u32); | 113 | if (rem_bytes < sizeof(u32)) |
| 114 | goto error; | ||
| 115 | |||
| 96 | event.entropy_mode = *(u32 *)data_ptr; | 116 | event.entropy_mode = *(u32 *)data_ptr; |
| 97 | data_ptr += sizeof(u32); | 117 | size_read = sizeof(u32); |
| 98 | break; | 118 | break; |
| 99 | case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: | 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 | bufreq = (struct hfi_buffer_requirements *)data_ptr; | 123 | bufreq = (struct hfi_buffer_requirements *)data_ptr; |
| 102 | event.buf_count = hfi_bufreq_get_count_min(bufreq, ver); | 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 | break; | 126 | break; |
| 105 | case HFI_INDEX_EXTRADATA_INPUT_CROP: | 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 | crop = (struct hfi_extradata_input_crop *)data_ptr; | 131 | crop = (struct hfi_extradata_input_crop *)data_ptr; |
| 108 | event.input_crop.left = crop->left; | 132 | event.input_crop.left = crop->left; |
| 109 | event.input_crop.top = crop->top; | 133 | event.input_crop.top = crop->top; |
| 110 | event.input_crop.width = crop->width; | 134 | event.input_crop.width = crop->width; |
| 111 | event.input_crop.height = crop->height; | 135 | event.input_crop.height = crop->height; |
| 112 | data_ptr += sizeof(*crop); | 136 | size_read = sizeof(struct hfi_extradata_input_crop); |
| 113 | break; | 137 | break; |
| 114 | case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS: | 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 | dpb_count = (struct hfi_dpb_counts *)data_ptr; | 142 | dpb_count = (struct hfi_dpb_counts *)data_ptr; |
| 117 | event.buf_count = dpb_count->fw_min_cnt; | 143 | event.buf_count = dpb_count->fw_min_cnt; |
| 118 | data_ptr += sizeof(*dpb_count); | 144 | size_read = sizeof(struct hfi_dpb_counts); |
| 119 | break; | 145 | break; |
| 120 | default: | 146 | default: |
| 147 | size_read = 0; | ||
| 121 | break; | 148 | break; |
| 122 | } | 149 | } |
| 150 | data_ptr += size_read; | ||
| 151 | rem_bytes -= size_read; | ||
| 123 | num_properties_changed--; | 152 | num_properties_changed--; |
| 124 | } while (num_properties_changed > 0); | 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 | inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event); | 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 | static int venus_read_queue(struct venus_hfi_device *hdev, | 239 | static int venus_read_queue(struct venus_hfi_device *hdev, |
| 240 | struct iface_queue *queue, void *pkt, u32 *tx_req) | 240 | struct iface_queue *queue, void *pkt, u32 *tx_req) |
| 241 | { | 241 | { |
| 242 | struct hfi_pkt_hdr *pkt_hdr = NULL; | ||
| 242 | struct hfi_queue_header *qhdr; | 243 | struct hfi_queue_header *qhdr; |
| 243 | u32 dwords, new_rd_idx; | 244 | u32 dwords, new_rd_idx; |
| 244 | u32 rd_idx, wr_idx, type, qsize; | 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 | memcpy(pkt, rd_ptr, len); | 305 | memcpy(pkt, rd_ptr, len); |
| 305 | memcpy(pkt + len, queue->qmem.kva, new_rd_idx << 2); | 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 | } else { | 311 | } else { |
| 308 | /* bad packet received, dropping */ | 312 | /* bad packet received, dropping */ |
| 309 | new_rd_idx = qhdr->write_idx; | 313 | new_rd_idx = qhdr->write_idx; |
| @@ -1678,6 +1682,7 @@ void venus_hfi_destroy(struct venus_core *core) · 1368 unmodified lines | |||
| 1678 | venus_interface_queues_release(hdev); | 1682 | venus_interface_queues_release(hdev); |
| 1679 | mutex_destroy(&hdev->lock); | 1683 | mutex_destroy(&hdev->lock); |
| 1680 | kfree(hdev); | 1684 | kfree(hdev); |
| 1685 | disable_irq(core->irq); | ||
| 1681 | core->ops = NULL; | 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 | static int core_clks_enable(struct venus_core *core) | 41 | static int core_clks_enable(struct venus_core *core) |
| 42 | { | 42 | { |
| 43 | const struct venus_resources *res = core->res; | 43 | const struct venus_resources *res = core->res; |
| 44 | const struct freq_tbl *freq_tbl = core->res->freq_tbl; | 44 | struct device *dev = core->dev; |
| 45 | unsigned int freq_tbl_size = core->res->freq_tbl_size; | 45 | unsigned long freq = 0; |
| 46 | unsigned long freq; | 46 | struct dev_pm_opp *opp; |
| 47 | unsigned int i; | 47 | unsigned int i; |
| 48 | int ret; | 48 | int ret; |
| 49 | 49 | ||
| 50 | if (!freq_tbl) | 50 | opp = dev_pm_opp_find_freq_ceil(dev, &freq); |
| 51 | return -EINVAL; | 51 | dev_pm_opp_put(opp); |
| 52 | |||
| 53 | freq = freq_tbl[freq_tbl_size - 1].freq; | ||
| 54 | 52 | ||
| 55 | for (i = 0; i < res->clks_num; i++) { | 53 | for (i = 0; i < res->clks_num; i++) { |
| 56 | if (IS_V6(core)) { | 54 | if (IS_V6(core)) { |
| @@ -636,7 +634,9 @@ static int decide_core(struct venus_inst *inst) · 579 unmodified lines | |||
| 636 | u32 min_coreid, min_load, cur_inst_load; | 634 | u32 min_coreid, min_load, cur_inst_load; |
| 637 | u32 min_lp_coreid, min_lp_load, cur_inst_lp_load; | 635 | u32 min_lp_coreid, min_lp_load, cur_inst_lp_load; |
| 638 | struct hfi_videocores_usage_type cu; | 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 | int ret = 0; | 640 | int ret = 0; |
| 641 | 641 | ||
| 642 | if (legacy_binding) { | 642 | if (legacy_binding) { |
| @@ -659,7 +659,8 @@ static int decide_core(struct venus_inst *inst) · 16 unmodified lines | |||
| 659 | cur_inst_lp_load *= inst->clk_data.low_power_freq; | 659 | cur_inst_lp_load *= inst->clk_data.low_power_freq; |
| 660 | /*TODO : divide this inst->load by work_route */ | 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 | min_loaded_core(inst, &min_coreid, &min_load, false); | 665 | min_loaded_core(inst, &min_coreid, &min_load, false); |
| 665 | min_loaded_core(inst, &min_lp_coreid, &min_lp_load, true); | 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 | static int core_get_v4(struct venus_core *core) | 950 | static int core_get_v4(struct venus_core *core) |
| 950 | { | 951 | { |
| 951 | struct device *dev = core->dev; | 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 | const struct venus_resources *res = core->res; | 955 | const struct venus_resources *res = core->res; |
| 956 | unsigned int i; | ||
| 953 | int ret; | 957 | int ret; |
| 954 | 958 | ||
| 955 | ret = core_clks_get(core); | 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 | if (core->res->opp_pmdomain) { | 991 | if (core->res->opp_pmdomain) { |
| 988 | ret = devm_pm_opp_of_add_table(dev); | 992 | ret = devm_pm_opp_of_add_table(dev); |
| 989 | if (ret && ret != -ENODEV) { | 993 | if (ret) { |
| 990 | dev_err(dev, "invalid OPP table in device tree\n"); | 994 | if (ret == -ENODEV) { |
| 991 | return ret; | 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 | static int load_scale_v4(struct venus_inst *inst) | 1090 | static int load_scale_v4(struct venus_inst *inst) |
| 1079 | { | 1091 | { |
| 1080 | struct venus_core *core = inst->core; | 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 | struct device *dev = core->dev; | 1093 | struct device *dev = core->dev; |
| 1084 | unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; | 1094 | unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; |
| 1095 | unsigned long max_freq = ULONG_MAX; | ||
| 1085 | unsigned long filled_len = 0; | 1096 | unsigned long filled_len = 0; |
| 1097 | struct dev_pm_opp *opp; | ||
| 1086 | int i, ret = 0; | 1098 | int i, ret = 0; |
| 1087 | 1099 | ||
| 1088 | for (i = 0; i < inst->num_input_bufs; i++) | 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 | freq = max(freq_core1, freq_core2); | 1121 | freq = max(freq_core1, freq_core2); |
| 1110 | 1122 | ||
| 1111 | if (freq > table[0].freq) { | 1123 | opp = dev_pm_opp_find_freq_floor(dev, &max_freq); |
| 1112 | dev_dbg(dev, VDBGL "requested clock rate: %lu scaling clock rate : %lu\n", | 1124 | dev_pm_opp_put(opp); |
| 1113 | freq, table[0].freq); | ||
| 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 | goto set_freq; | 1130 | goto set_freq; |
| 1117 | } | 1131 | } |
| 1118 | 1132 | ||
| 1119 | for (i = num_rows - 1 ; i >= 0; i--) { | 1133 | opp = dev_pm_opp_find_freq_ceil(dev, &freq); |
| 1120 | if (freq <= table[i].freq) { | 1134 | dev_pm_opp_put(opp); |
| 1121 | freq = table[i].freq; | ||
| 1122 | break; | ||
| 1123 | } | ||
| 1124 | } | ||
| 1125 | 1135 | ||
| 1126 | set_freq: | 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 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; | 481 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; |
| 482 | do_div(us_per_frame, timeperframe->denominator); | 482 | do_div(us_per_frame, timeperframe->denominator); |
| 483 | 483 | ||
| 484 | if (!us_per_frame) | 484 | us_per_frame = clamp(us_per_frame, 1, USEC_PER_SEC); |
| 485 | return -EINVAL; | 485 | fps = USEC_PER_SEC / (u32)us_per_frame; |
| 486 | 486 | fps = min(VENUS_MAX_FPS, fps); | |
| 487 | fps = (u64)USEC_PER_SEC; | ||
| 488 | do_div(fps, us_per_frame); | ||
| 489 | 487 | ||
| 490 | inst->fps = fps; | 488 | inst->fps = fps; |
| 491 | inst->timeperframe = *timeperframe; | 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 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; | 411 | us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; |
| 412 | do_div(us_per_frame, timeperframe->denominator); | 412 | do_div(us_per_frame, timeperframe->denominator); |
| 413 | 413 | ||
| 414 | if (!us_per_frame) | 414 | us_per_frame = clamp(us_per_frame, 1, USEC_PER_SEC); |
| 415 | return -EINVAL; | 415 | fps = USEC_PER_SEC / (u32)us_per_frame; |
| 416 | 416 | fps = min(VENUS_MAX_FPS, fps); | |
| 417 | fps = (u64)USEC_PER_SEC; | ||
| 418 | do_div(fps, us_per_frame); | ||
| 419 | 417 | ||
| 420 | inst->timeperframe = *timeperframe; | 418 | inst->timeperframe = *timeperframe; |
| 421 | inst->fps = fps; | 419 | inst->fps = fps; |
| @@ -3,6 +3,7 @@ config VIDEO_RASPBERRYPI_PISP_BE · 2 unmodified lines | |||
| 3 | depends on V4L_PLATFORM_DRIVERS | 3 | depends on V4L_PLATFORM_DRIVERS |
| 4 | depends on VIDEO_DEV | 4 | depends on VIDEO_DEV |
| 5 | depends on ARCH_BCM2835 || COMPILE_TEST | 5 | depends on ARCH_BCM2835 || COMPILE_TEST |
| 6 | depends on PM | ||
| 6 | select VIDEO_V4L2_SUBDEV_API | 7 | select VIDEO_V4L2_SUBDEV_API |
| 7 | select MEDIA_CONTROLLER | 8 | select MEDIA_CONTROLLER |
| 8 | select VIDEOBUF2_DMA_CONTIG | 9 | select VIDEOBUF2_DMA_CONTIG |
| @@ -9,9 +9,11 @@ · 8 unmodified lines | |||
| 9 | #include <linux/io.h> | 9 | #include <linux/io.h> |
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/lockdep.h> | 11 | #include <linux/lockdep.h> |
| 12 | #include <linux/minmax.h> | ||
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 13 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 14 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
| 16 | #include <linux/slab.h> | ||
| 15 | #include <media/v4l2-device.h> | 17 | #include <media/v4l2-device.h> |
| 16 | #include <media/v4l2-ioctl.h> | 18 | #include <media/v4l2-ioctl.h> |
| 17 | #include <media/videobuf2-dma-contig.h> | 19 | #include <media/videobuf2-dma-contig.h> |
| @@ -161,8 +163,6 @@ struct pispbe_node { · 143 unmodified lines | |||
| 161 | struct mutex node_lock; | 163 | struct mutex node_lock; |
| 162 | /* vb2_queue lock */ | 164 | /* vb2_queue lock */ |
| 163 | struct mutex queue_lock; | 165 | struct mutex queue_lock; |
| 164 | /* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */ | ||
| 165 | spinlock_t ready_lock; | ||
| 166 | struct list_head ready_queue; | 166 | struct list_head ready_queue; |
| 167 | struct vb2_queue queue; | 167 | struct vb2_queue queue; |
| 168 | struct v4l2_format format; | 168 | struct v4l2_format format; |
| @@ -190,6 +190,8 @@ struct pispbe_hw_enables { · 21 unmodified lines | |||
| 190 | 190 | ||
| 191 | /* Records a job configuration and memory addresses. */ | 191 | /* Records a job configuration and memory addresses. */ |
| 192 | struct pispbe_job_descriptor { | 192 | struct pispbe_job_descriptor { |
| 193 | struct list_head queue; | ||
| 194 | struct pispbe_buffer *buffers[PISPBE_NUM_NODES]; | ||
| 193 | dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; | 195 | dma_addr_t hw_dma_addrs[N_HW_ADDRESSES]; |
| 194 | struct pisp_be_tiles_config *config; | 196 | struct pisp_be_tiles_config *config; |
| 195 | struct pispbe_hw_enables hw_enables; | 197 | struct pispbe_hw_enables hw_enables; |
| @@ -215,8 +217,10 @@ struct pispbe_dev { · 19 unmodified lines | |||
| 215 | unsigned int sequence; | 217 | unsigned int sequence; |
| 216 | u32 streaming_map; | 218 | u32 streaming_map; |
| 217 | struct pispbe_job queued_job, running_job; | 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 | bool hw_busy; /* non-zero if a job is queued or is being started */ | 222 | bool hw_busy; /* non-zero if a job is queued or is being started */ |
| 223 | struct list_head job_queue; | ||
| 220 | int irq; | 224 | int irq; |
| 221 | u32 hw_version; | 225 | u32 hw_version; |
| 222 | u8 done, started; | 226 | u8 done, started; |
| @@ -368,10 +372,7 @@ static void pispbe_xlate_addrs(struct pispbe_dev *pispbe, · 145 unmodified lines | |||
| 368 | ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE], | 372 | ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE], |
| 369 | &pispbe->node[MAIN_INPUT_NODE]); | 373 | &pispbe->node[MAIN_INPUT_NODE]); |
| 370 | if (ret <= 0) { | 374 | if (ret <= 0) { |
| 371 | /* | 375 | /* Shouldn't happen, we have validated an input is available. */ |
| 372 | * This shouldn't happen; pispbe_schedule_internal should insist | ||
| 373 | * on an input. | ||
| 374 | */ | ||
| 375 | dev_warn(pispbe->dev, "ISP-BE missing input\n"); | 376 | dev_warn(pispbe->dev, "ISP-BE missing input\n"); |
| 376 | hw_en->bayer_enables = 0; | 377 | hw_en->bayer_enables = 0; |
| 377 | hw_en->rgb_enables = 0; | 378 | hw_en->rgb_enables = 0; |
| @@ -443,42 +444,48 @@ static void pispbe_xlate_addrs(struct pispbe_dev *pispbe, · 65 unmodified lines | |||
| 443 | * For Output0, Output1, Tdn and Stitch, a buffer only needs to be | 444 | * For Output0, Output1, Tdn and Stitch, a buffer only needs to be |
| 444 | * available if the blocks are enabled in the config. | 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 | * Returns 0 if a job has been successfully prepared, < 0 otherwise. | 450 | * Returns 0 if a job has been successfully prepared, < 0 otherwise. |
| 449 | */ | 451 | */ |
| 450 | static int pispbe_prepare_job(struct pispbe_dev *pispbe, | 452 | static int pispbe_prepare_job(struct pispbe_dev *pispbe) |
| 451 | struct pispbe_job_descriptor *job) | ||
| 452 | { | 453 | { |
| 454 | struct pispbe_job_descriptor __free(kfree) *job = NULL; | ||
| 453 | struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {}; | 455 | struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {}; |
| 456 | unsigned int streaming_map; | ||
| 454 | unsigned int config_index; | 457 | unsigned int config_index; |
| 455 | struct pispbe_node *node; | 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)) & | 465 | if ((pispbe->streaming_map & mask) != mask) |
| 463 | pispbe->streaming_map) != | 466 | return -ENODEV; |
| 464 | (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE))) | 467 | |
| 465 | return -ENODEV; | 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 | node = &pispbe->node[CONFIG_NODE]; | 479 | node = &pispbe->node[CONFIG_NODE]; |
| 468 | spin_lock_irqsave(&node->ready_lock, flags); | ||
| 469 | buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue, | 480 | buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue, |
| 470 | struct pispbe_buffer, | 481 | struct pispbe_buffer, |
| 471 | ready_list); | 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 | if (!buf[CONFIG_NODE]) | 483 | if (!buf[CONFIG_NODE]) |
| 480 | return -ENODEV; | 484 | return -ENODEV; |
| 481 | 485 | ||
| 486 | list_del(&buf[CONFIG_NODE]->ready_list); | ||
| 487 | job->buffers[CONFIG_NODE] = buf[CONFIG_NODE]; | ||
| 488 | |||
| 482 | config_index = buf[CONFIG_NODE]->vb.vb2_buf.index; | 489 | config_index = buf[CONFIG_NODE]->vb.vb2_buf.index; |
| 483 | job->config = &pispbe->config[config_index]; | 490 | job->config = &pispbe->config[config_index]; |
| 484 | job->tiles = pispbe->config_dma_addr + | 491 | job->tiles = pispbe->config_dma_addr + |
| @@ -498,7 +505,7 @@ static int pispbe_prepare_job(struct pispbe_dev *pispbe, · 13 unmodified lines | |||
| 498 | continue; | 505 | continue; |
| 499 | 506 | ||
| 500 | buf[i] = NULL; | 507 | buf[i] = NULL; |
| 501 | if (!(pispbe->streaming_map & BIT(i))) | 508 | if (!(streaming_map & BIT(i))) |
| 502 | continue; | 509 | continue; |
| 503 | 510 | ||
| 504 | if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) && | 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 | node = &pispbe->node[i]; | 532 | node = &pispbe->node[i]; |
| 526 | 533 | ||
| 527 | /* Pull a buffer from each V4L2 queue to form the queued job */ | 534 | /* Pull a buffer from each V4L2 queue to form the queued job */ |
| 528 | spin_lock_irqsave(&node->ready_lock, flags); | ||
| 529 | buf[i] = list_first_entry_or_null(&node->ready_queue, | 535 | buf[i] = list_first_entry_or_null(&node->ready_queue, |
| 530 | struct pispbe_buffer, | 536 | struct pispbe_buffer, |
| 531 | ready_list); | 537 | ready_list); |
| 532 | if (buf[i]) { | 538 | if (buf[i]) { |
| 533 | list_del(&buf[i]->ready_list); | 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 | if (!buf[i] && !ignore_buffers) | 543 | if (!buf[i] && !ignore_buffers) |
| 539 | goto err_return_buffers; | 544 | goto err_return_buffers; |
| 540 | } | 545 | } |
| 541 | 546 | ||
| 542 | pispbe->queued_job.valid = true; | ||
| 543 | |||
| 544 | /* Convert buffers to DMA addresses for the hardware */ | 547 | /* Convert buffers to DMA addresses for the hardware */ |
| 545 | pispbe_xlate_addrs(pispbe, job, buf); | 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 | return 0; | 557 | return 0; |
| 548 | 558 | ||
| 549 | err_return_buffers: | 559 | err_return_buffers: |
| @@ -554,33 +564,37 @@ err_return_buffers: · 4 unmodified lines | |||
| 554 | continue; | 564 | continue; |
| 555 | 565 | ||
| 556 | /* Return the buffer to the ready_list queue */ | 566 | /* Return the buffer to the ready_list queue */ |
| 557 | spin_lock_irqsave(&n->ready_lock, flags); | ||
| 558 | list_add(&buf[i]->ready_list, &n->ready_queue); | 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 | return -ENODEV; | 570 | return -ENODEV; |
| 565 | } | 571 | } |
| 566 | 572 | ||
| 567 | static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy) | 573 | static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy) |
| 568 | { | 574 | { |
| 569 | struct pispbe_job_descriptor job; | 575 | struct pispbe_job_descriptor *job; |
| 570 | unsigned long flags; | ||
| 571 | int ret; | ||
| 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) | 581 | if (pispbe->hw_busy) |
| 576 | pispbe->hw_busy = false; | 582 | return; |
| 577 | 583 | ||
| 578 | if (pispbe->hw_busy) | 584 | job = list_first_entry_or_null(&pispbe->job_queue, |
| 579 | goto unlock_and_return; | 585 | struct pispbe_job_descriptor, |
| 586 | queue); | ||
| 587 | if (!job) | ||
| 588 | return; | ||
| 580 | 589 | ||
| 581 | ret = pispbe_prepare_job(pispbe, &job); | 590 | list_del(&job->queue); |
| 582 | if (ret) | 591 | |
| 583 | goto unlock_and_return; | 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 | * We can kick the job off without the hw_lock, as this can | 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 | * only when the following job has been queued and an interrupt | 602 | * only when the following job has been queued and an interrupt |
| 589 | * is rised. | 603 | * is rised. |
| 590 | */ | 604 | */ |
| 591 | pispbe->hw_busy = true; | 605 | pispbe_queue_job(pispbe, job); |
| 592 | spin_unlock_irqrestore(&pispbe->hw_lock, flags); | 606 | kfree(job); |
| 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); | ||
| 619 | } | 607 | } |
| 620 | 608 | ||
| 621 | static void pispbe_isr_jobdone(struct pispbe_dev *pispbe, | 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 | return -EIO; | 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 | /* Ensure output config strides and buffer sizes match the V4L2 formats. */ | 704 | /* Ensure output config strides and buffer sizes match the V4L2 formats. */ |
| 710 | fmt = &pispbe->node[TDN_OUTPUT_NODE].format; | 705 | fmt = &pispbe->node[TDN_OUTPUT_NODE].format; |
| 711 | if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) { | 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 | container_of(vbuf, struct pispbe_buffer, vb); | 855 | container_of(vbuf, struct pispbe_buffer, vb); |
| 861 | struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue); | 856 | struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue); |
| 862 | struct pispbe_dev *pispbe = node->pispbe; | 857 | struct pispbe_dev *pispbe = node->pispbe; |
| 863 | unsigned long flags; | ||
| 864 | 858 | ||
| 865 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); | 859 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); |
| 866 | spin_lock_irqsave(&node->ready_lock, flags); | ||
| 867 | list_add_tail(&buffer->ready_list, &node->ready_queue); | 860 | list_add_tail(&buffer->ready_list, &node->ready_queue); |
| 868 | spin_unlock_irqrestore(&node->ready_lock, flags); | ||
| 869 | 861 | ||
| 870 | /* | 862 | /* |
| 871 | * Every time we add a buffer, check if there's now some work for the hw | 863 | * Every time we add a buffer, check if there's now some work for the hw |
| 872 | * to do. | 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 | static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count) | 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 | struct pispbe_node *node = vb2_get_drv_priv(q); | 872 | struct pispbe_node *node = vb2_get_drv_priv(q); |
| 880 | struct pispbe_dev *pispbe = node->pispbe; | 873 | struct pispbe_dev *pispbe = node->pispbe; |
| 881 | struct pispbe_buffer *buf, *tmp; | 874 | struct pispbe_buffer *buf, *tmp; |
| 882 | unsigned long flags; | ||
| 883 | int ret; | 875 | int ret; |
| 884 | 876 | ||
| 885 | ret = pm_runtime_resume_and_get(pispbe->dev); | 877 | ret = pm_runtime_resume_and_get(pispbe->dev); |
| 886 | if (ret < 0) | 878 | if (ret < 0) |
| 887 | goto err_return_buffers; | 879 | goto err_return_buffers; |
| 888 | 880 | ||
| 889 | spin_lock_irqsave(&pispbe->hw_lock, flags); | 881 | scoped_guard(spinlock_irq, &pispbe->hw_lock) { |
| 890 | node->pispbe->streaming_map |= BIT(node->id); | 882 | node->pispbe->streaming_map |= BIT(node->id); |
| 891 | node->pispbe->sequence = 0; | 883 | node->pispbe->sequence = 0; |
| 892 | spin_unlock_irqrestore(&pispbe->hw_lock, flags); | 884 | } |
| 893 | 885 | ||
| 894 | dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n", | 886 | dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n", |
| 895 | __func__, NODE_NAME(node), count); | 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 | node->pispbe->streaming_map); | 889 | node->pispbe->streaming_map); |
| 898 | 890 | ||
| 899 | /* Maybe we're ready to run. */ | 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 | return 0; | 895 | return 0; |
| 903 | 896 | ||
| 904 | err_return_buffers: | 897 | err_return_buffers: |
| 905 | spin_lock_irqsave(&pispbe->hw_lock, flags); | ||
| 906 | list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) { | 898 | list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) { |
| 907 | list_del(&buf->ready_list); | 899 | list_del(&buf->ready_list); |
| 908 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); | 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 | return ret; | 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 | struct pispbe_node *node = vb2_get_drv_priv(q); | 908 | struct pispbe_node *node = vb2_get_drv_priv(q); |
| 918 | struct pispbe_dev *pispbe = node->pispbe; | 909 | struct pispbe_dev *pispbe = node->pispbe; |
| 910 | struct pispbe_job_descriptor *job, *temp; | ||
| 919 | struct pispbe_buffer *buf; | 911 | struct pispbe_buffer *buf; |
| 920 | unsigned long flags; | 912 | LIST_HEAD(tmp_list); |
| 921 | 913 | ||
| 922 | /* | 914 | /* |
| 923 | * Now this is a bit awkward. In a simple M2M device we could just wait | 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 | * This may return buffers out of order. | 921 | * This may return buffers out of order. |
| 930 | */ | 922 | */ |
| 931 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); | 923 | dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node)); |
| 932 | spin_lock_irqsave(&pispbe->hw_lock, flags); | ||
| 933 | do { | 924 | do { |
| 934 | unsigned long flags1; | ||
| 935 | |||
| 936 | spin_lock_irqsave(&node->ready_lock, flags1); | ||
| 937 | buf = list_first_entry_or_null(&node->ready_queue, | 925 | buf = list_first_entry_or_null(&node->ready_queue, |
| 938 | struct pispbe_buffer, | 926 | struct pispbe_buffer, |
| 939 | ready_list); | 927 | ready_list); |
| @@ -941,15 +929,26 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) · 1 unmodified line | |||
| 941 | list_del(&buf->ready_list); | 929 | list_del(&buf->ready_list); |
| 942 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | 930 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); |
| 943 | } | 931 | } |
| 944 | spin_unlock_irqrestore(&node->ready_lock, flags1); | ||
| 945 | } while (buf); | 932 | } while (buf); |
| 946 | spin_unlock_irqrestore(&pispbe->hw_lock, flags); | ||
| 947 | 933 | ||
| 948 | vb2_wait_for_all_buffers(&node->queue); | 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 | pispbe->streaming_map &= ~BIT(node->id); | 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 | pm_runtime_mark_last_busy(pispbe->dev); | 953 | pm_runtime_mark_last_busy(pispbe->dev); |
| 955 | pm_runtime_put_autosuspend(pispbe->dev); | 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 | f->fmt.pix_mp.pixelformat = fmt->fourcc; | 1113 | f->fmt.pix_mp.pixelformat = fmt->fourcc; |
| 1115 | f->fmt.pix_mp.num_planes = fmt->num_planes; | 1114 | f->fmt.pix_mp.num_planes = fmt->num_planes; |
| 1116 | f->fmt.pix_mp.field = V4L2_FIELD_NONE; | 1115 | f->fmt.pix_mp.field = V4L2_FIELD_NONE; |
| 1117 | f->fmt.pix_mp.width = max(min(f->fmt.pix_mp.width, 65536u), | 1116 | f->fmt.pix_mp.width = clamp(f->fmt.pix_mp.width, |
| 1118 | PISP_BACK_END_MIN_TILE_WIDTH); | 1117 | PISP_BACK_END_MIN_TILE_WIDTH, |
| 1119 | f->fmt.pix_mp.height = max(min(f->fmt.pix_mp.height, 65536u), | 1118 | PISP_BACK_END_MAX_TILE_WIDTH); |
| 1120 | PISP_BACK_END_MIN_TILE_HEIGHT); | 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 | * Fill in the actual colour space when the requested one was | 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 | mutex_init(&node->node_lock); | 1408 | mutex_init(&node->node_lock); |
| 1408 | mutex_init(&node->queue_lock); | 1409 | mutex_init(&node->queue_lock); |
| 1409 | INIT_LIST_HEAD(&node->ready_queue); | 1410 | INIT_LIST_HEAD(&node->ready_queue); |
| 1410 | spin_lock_init(&node->ready_lock); | ||
| 1411 | 1411 | ||
| 1412 | node->format.type = node->buf_type; | 1412 | node->format.type = node->buf_type; |
| 1413 | pispbe_node_def_fmt(node); | 1413 | pispbe_node_def_fmt(node); |
| @@ -1691,6 +1691,8 @@ static int pispbe_probe(struct platform_device *pdev) · 277 unmodified lines | |||
| 1691 | if (!pispbe) | 1691 | if (!pispbe) |
| 1692 | return -ENOMEM; | 1692 | return -ENOMEM; |
| 1693 | 1693 | ||
| 1694 | INIT_LIST_HEAD(&pispbe->job_queue); | ||
| 1695 | |||
| 1694 | dev_set_drvdata(&pdev->dev, pispbe); | 1696 | dev_set_drvdata(&pdev->dev, pispbe); |
| 1695 | pispbe->dev = &pdev->dev; | 1697 | pispbe->dev = &pdev->dev; |
| 1696 | platform_set_drvdata(pdev, pispbe); | 1698 | platform_set_drvdata(pdev, pispbe); |
| @@ -1726,7 +1728,7 @@ static int pispbe_probe(struct platform_device *pdev) · 29 unmodified lines | |||
| 1726 | pm_runtime_use_autosuspend(pispbe->dev); | 1728 | pm_runtime_use_autosuspend(pispbe->dev); |
| 1727 | pm_runtime_enable(pispbe->dev); | 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 | if (ret) | 1732 | if (ret) |
| 1731 | goto pm_runtime_disable_err; | 1733 | goto pm_runtime_disable_err; |
| 1732 | 1734 | ||
| @@ -1748,7 +1750,7 @@ static int pispbe_probe(struct platform_device *pdev) · 15 unmodified lines | |||
| 1748 | disable_devs_err: | 1750 | disable_devs_err: |
| 1749 | pispbe_destroy_devices(pispbe); | 1751 | pispbe_destroy_devices(pispbe); |
| 1750 | pm_runtime_suspend_err: | 1752 | pm_runtime_suspend_err: |
| 1751 | pispbe_runtime_suspend(pispbe->dev); | 1753 | pm_runtime_put(pispbe->dev); |
| 1752 | pm_runtime_disable_err: | 1754 | pm_runtime_disable_err: |
| 1753 | pm_runtime_dont_use_autosuspend(pispbe->dev); | 1755 | pm_runtime_dont_use_autosuspend(pispbe->dev); |
| 1754 | pm_runtime_disable(pispbe->dev); | 1756 | pm_runtime_disable(pispbe->dev); |
| @@ -1762,7 +1764,6 @@ static void pispbe_remove(struct platform_device *pdev) · 7 unmodified lines | |||
| 1762 | 1764 | ||
| 1763 | pispbe_destroy_devices(pispbe); | 1765 | pispbe_destroy_devices(pispbe); |
| 1764 | 1766 | ||
| 1765 | pispbe_runtime_suspend(pispbe->dev); | ||
| 1766 | pm_runtime_dont_use_autosuspend(pispbe->dev); | 1767 | pm_runtime_dont_use_autosuspend(pispbe->dev); |
| 1767 | pm_runtime_disable(pispbe->dev); | 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 | cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, | 1024 | cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name, |
| 1025 | node->buffer_queue.type); | 1025 | node->buffer_queue.type); |
| 1026 | 1026 | ||
| 1027 | if (vq->max_num_buffers + *nbuffers < 3) | ||
| 1028 | *nbuffers = 3 - vq->max_num_buffers; | ||
| 1029 | |||
| 1030 | if (*nplanes) { | 1027 | if (*nplanes) { |
| 1031 | if (sizes[0] < size) { | 1028 | if (sizes[0] < size) { |
| 1032 | cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size); | 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 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | 1995 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
| 1999 | q->lock = &node->lock; | 1996 | q->lock = &node->lock; |
| 2000 | q->min_queued_buffers = 1; | 1997 | q->min_queued_buffers = 1; |
| 1998 | q->min_reqbufs_allocation = 3; | ||
| 2001 | q->dev = &cfe->pdev->dev; | 1999 | q->dev = &cfe->pdev->dev; |
| 2002 | 2000 | ||
| 2003 | ret = vb2_queue_init(q); | 2001 | ret = vb2_queue_init(q); |
| @@ -172,20 +172,27 @@ struct rcar_csi2; · 171 unmodified lines | |||
| 172 | #define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a | 172 | #define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a |
| 173 | #define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c | 173 | #define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c |
| 174 | #define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG 0x21c10 | 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 | #define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c | 176 | #define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c |
| 176 | #define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 | 177 | #define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 |
| 177 | #define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 | 178 | #define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 |
| 178 | 179 | ||
| 179 | /* V4H CORE registers */ | 180 | /* V4H CORE registers */ |
| 180 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n) (0x22040 + ((n) * 2)) /* n = 0 - 15 */ | 181 | |
| 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_LANEl_CTRL_2_REG(l, n) (0x22040 + ((l) * 0x400) + ((n) * 2)) |
| 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_LANEl_CTRL_3_REG(l, n) (0x22060 + ((l) * 0x400) + ((n) * 2)) |
| 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_LANEl_CTRL_4_REG(l, n) (0x22080 + ((l) * 0x400) + ((n) * 2)) |
| 184 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n) (0x23040 + ((n) * 2)) /* n = 0 - 15 */ | 185 | |
| 185 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ | 186 | #define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ |
| 186 | #define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ | 187 | #define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ |
| 187 | #define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */ | 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 | /* V4H C-PHY */ | 197 | /* V4H C-PHY */ |
| 191 | #define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */ | 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 | #define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 | 204 | #define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 |
| 198 | #define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 | 205 | #define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 |
| 199 | #define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */ | 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 | #define V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG 0x2a800 | 208 | #define V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG 0x2a800 |
| 201 | #define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 | 209 | #define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 |
| 202 | #define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */ | 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 | static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, | 962 | static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, |
| 955 | unsigned int lanes) | 963 | unsigned int lanes) |
| 956 | { | 964 | { |
| 965 | struct media_pad *remote_pad; | ||
| 957 | struct v4l2_subdev *source; | 966 | struct v4l2_subdev *source; |
| 958 | s64 freq; | 967 | s64 freq; |
| 959 | u64 mbps; | 968 | u64 mbps; |
| @@ -962,8 +971,9 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, · 2 unmodified lines | |||
| 962 | return -ENODEV; | 971 | return -ENODEV; |
| 963 | 972 | ||
| 964 | source = priv->remote; | 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 | if (freq < 0) { | 977 | if (freq < 0) { |
| 968 | int ret = (int)freq; | 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 | mbps = div_u64(freq * 2, MEGA); | 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 | return mbps; | 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 | return -ETIMEDOUT; | 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 | const struct rcsi2_cphy_setting *conf; | 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 | for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { | 1221 | for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { |
| 1211 | if (conf->msps > msps) | 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 | if (!conf->msps) { | 1226 | if (!conf->msps) { |
| 1216 | dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps); | 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 | /* C-PHY specific */ | 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 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2); | 1257 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2); |
| 1247 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2); | 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); | 1260 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(0, 2), 0x0001); |
| 1250 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0); | 1261 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(1, 2), 0); |
| 1251 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001); | 1262 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(2, 2), 0x0001); |
| 1252 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001); | 1263 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(3, 2), 0x0001); |
| 1253 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0); | 1264 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANEl_CTRL_2_REG(4, 2), 0); |
| 1254 | 1265 | ||
| 1255 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0); | 1266 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0); |
| 1256 | rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0); | 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 | /* Configure data line order. */ | 1278 | /* Configure data line order. */ |
| 1268 | rsci2_set_line_order(priv, priv->line_orders[0], | 1279 | rsci2_set_line_order(priv, priv->line_orders[0], |
| 1269 | V4H_CORE_DIG_CLANE_0_RW_CFG_0_REG, | 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 | rsci2_set_line_order(priv, priv->line_orders[1], | 1282 | rsci2_set_line_order(priv, priv->line_orders[1], |
| 1272 | V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, | 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 | rsci2_set_line_order(priv, priv->line_orders[2], | 1285 | rsci2_set_line_order(priv, priv->line_orders[2], |
| 1275 | V4H_CORE_DIG_CLANE_2_RW_CFG_0_REG, | 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 | /* TODO: This registers is not documented. */ | 1289 | /* TODO: This registers is not documented. */ |
| 1279 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000); | 1290 | rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000); |
| 1280 | 1291 | ||
| 1281 | /* Leave Shutdown mode */ | 1292 | return conf; |
| 1282 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); | 1293 | } |
| 1283 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); | ||
| 1284 | 1294 | ||
| 1285 | /* Wait for calibration */ | 1295 | struct rcsi2_d_phy_setting_v4h_lut_value { |
| 1286 | if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { | 1296 | unsigned int mbps; |
| 1287 | dev_err(priv->dev, "PHY calibration failed\n"); | 1297 | unsigned char cfg_1; |
| 1288 | return -ETIMEDOUT; | 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*/ | 1450 | static const u16 deskew_fine[] = { |
| 1292 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29); | 1451 | 0x0404, 0x040c, 0x0414, 0x041c, 0x0423, 0x0429, 0x0430, 0x043a, |
| 1293 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27); | 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 | return 0; | 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 | static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, | 1477 | static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv, |
| 1299 | struct v4l2_subdev_state *state) | 1478 | struct v4l2_subdev_state *state) |
| 1300 | { | 1479 | { |
| 1480 | const struct rcsi2_cphy_setting *cphy = NULL; | ||
| 1301 | const struct rcar_csi2_format *format; | 1481 | const struct rcar_csi2_format *format; |
| 1302 | const struct v4l2_mbus_framefmt *fmt; | 1482 | const struct v4l2_mbus_framefmt *fmt; |
| 1303 | unsigned int lanes; | 1483 | unsigned int lanes; |
| 1304 | int msps; | 1484 | int mbps; |
| 1305 | int ret; | 1485 | int ret; |
| 1306 | 1486 | ||
| 1307 | /* Use the format on the sink pad to compute the receiver config. */ | 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 | if (ret) | 1494 | if (ret) |
| 1315 | return ret; | 1495 | return ret; |
| 1316 | 1496 | ||
| 1317 | msps = rcsi2_calc_mbps(priv, format->bpp, lanes); | 1497 | mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); |
| 1318 | if (msps < 0) | 1498 | if (mbps < 0) |
| 1319 | return msps; | 1499 | return mbps; |
| 1320 | 1500 | ||
| 1321 | /* Reset LINK and PHY*/ | 1501 | /* T0: Reset LINK and PHY*/ |
| 1322 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); | 1502 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); |
| 1323 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); | 1503 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); |
| 1324 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); | 1504 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); |
| 1325 | 1505 | ||
| 1326 | /* PHY static setting */ | 1506 | /* T1: PHY static setting */ |
| 1327 | rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK); | 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 | rcsi2_write(priv, V4H_FLDC_REG, 0); | 1510 | rcsi2_write(priv, V4H_FLDC_REG, 0); |
| 1329 | rcsi2_write(priv, V4H_FLDD_REG, 0); | 1511 | rcsi2_write(priv, V4H_FLDD_REG, 0); |
| 1330 | rcsi2_write(priv, V4H_IDIC_REG, 0); | 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 | rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); | 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 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); | 1525 | rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); |
| 1336 | 1526 | ||
| 1337 | /* Registers static setting through APB */ | 1527 | /* Registers static setting through APB */ |
| 1338 | /* Common setting */ | 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 | rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd); | 1531 | rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd); |
| 1340 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233); | 1532 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233); |
| 1341 | rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), 0x0027); | 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 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105); | 1542 | rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105); |
| 1351 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000); | 1543 | rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000); |
| 1352 | rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, 0x0003); | 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 */ | 1567 | /* T4: Leave Shutdown mode */ |
| 1355 | ret = rcsi2_c_phy_setting_v4h(priv, msps); | 1568 | rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); |
| 1356 | if (ret) | 1569 | rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); |
| 1357 | return ret; | 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 | rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | | 1598 | rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | |
| 1360 | V4H_ST_PHYST_ST_STOPSTATE_1 | | 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 | return 0; | 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 | unsigned int timeout; | 1611 | unsigned int timeout; |
| 1369 | int ret; | 1612 | int ret; |
| @@ -2213,6 +2456,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { · 843 unmodified lines | |||
| 2213 | .start_receiver = rcsi2_start_receiver_v4h, | 2456 | .start_receiver = rcsi2_start_receiver_v4h, |
| 2214 | .use_isp = true, | 2457 | .use_isp = true, |
| 2215 | .support_cphy = true, | 2458 | .support_cphy = true, |
| 2459 | .support_dphy = true, | ||
| 2216 | }; | 2460 | }; |
| 2217 | 2461 | ||
| 2218 | static const struct rcsi2_register_layout rcsi2_registers_v4m = { | 2462 | static const struct rcsi2_register_layout rcsi2_registers_v4m = { |
| @@ -9,6 +9,8 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/iopoll.h> | ||
| 12 | #include <linux/list.h> | 14 | #include <linux/list.h> |
| 13 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 14 | #include <linux/mod_devicetable.h> | 16 | #include <linux/mod_devicetable.h> |
| @@ -19,14 +21,25 @@ · 4 unmodified lines | |||
| 19 | 21 | ||
| 20 | #include <media/rcar-fcp.h> | 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 | struct rcar_fcp_device { | 29 | struct rcar_fcp_device { |
| 23 | struct list_head list; | 30 | struct list_head list; |
| 24 | struct device *dev; | 31 | struct device *dev; |
| 32 | void __iomem *base; | ||
| 25 | }; | 33 | }; |
| 26 | 34 | ||
| 27 | static LIST_HEAD(fcp_devices); | 35 | static LIST_HEAD(fcp_devices); |
| 28 | static DEFINE_MUTEX(fcp_lock); | 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 | * Public API | 44 | * Public API |
| 32 | */ | 45 | */ |
| @@ -117,6 +130,25 @@ void rcar_fcp_disable(struct rcar_fcp_device *fcp) · 84 unmodified lines | |||
| 117 | } | 130 | } |
| 118 | EXPORT_SYMBOL_GPL(rcar_fcp_disable); | 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 | * Platform Driver | 153 | * Platform Driver |
| 122 | */ | 154 | */ |
| @@ -131,6 +163,10 @@ static int rcar_fcp_probe(struct platform_device *pdev) · 8 unmodified lines | |||
| 131 | 163 | ||
| 132 | fcp->dev = &pdev->dev; | 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 | dma_set_max_seg_size(fcp->dev, UINT_MAX); | 170 | dma_set_max_seg_size(fcp->dev, UINT_MAX); |
| 135 | 171 | ||
| 136 | pm_runtime_enable(&pdev->dev); | 172 | pm_runtime_enable(&pdev->dev); |
| @@ -2,14 +2,14 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Driver for Renesas R-Car VIN | 3 | * Driver for Renesas R-Car VIN |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | ||
| 5 | * Copyright (C) 2016 Renesas Electronics Corp. | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | * Copyright (C) 2008 Magnus Damm | 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 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 15 | #include <linux/of_graph.h> | 15 | #include <linux/of_graph.h> |
| @@ -55,6 +55,7 @@ · 39 unmodified lines | |||
| 55 | * be only one group for all instances. | 55 | * be only one group for all instances. |
| 56 | */ | 56 | */ |
| 57 | 57 | ||
| 58 | static DEFINE_IDA(rvin_ida); | ||
| 58 | static DEFINE_MUTEX(rvin_group_lock); | 59 | static DEFINE_MUTEX(rvin_group_lock); |
| 59 | static struct rvin_group *rvin_group_data; | 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 | static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, | 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 | const struct media_device_ops *ops) | 70 | const struct media_device_ops *ops) |
| 70 | { | 71 | { |
| 71 | struct media_device *mdev = &group->mdev; | 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 | static int rvin_group_get(struct rvin_dev *vin, | 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 | const struct media_device_ops *ops) | 120 | const struct media_device_ops *ops) |
| 120 | { | 121 | { |
| 121 | struct rvin_group *group; | 122 | struct rvin_group *group; |
| 122 | u32 id; | ||
| 123 | int ret; | 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 | /* Join or create a VIN group */ | 125 | /* Join or create a VIN group */ |
| 140 | mutex_lock(&rvin_group_lock); | 126 | mutex_lock(&rvin_group_lock); |
| 141 | if (rvin_group_data) { | 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 | kref_init(&group->refcount); | 144 | kref_init(&group->refcount); |
| 145 | group->info = vin->info; | ||
| 159 | 146 | ||
| 160 | rvin_group_data = group; | 147 | rvin_group_data = group; |
| 161 | } | 148 | } |
| @@ -164,16 +151,15 @@ static int rvin_group_get(struct rvin_dev *vin, · 2 unmodified lines | |||
| 164 | /* Add VIN to group */ | 151 | /* Add VIN to group */ |
| 165 | mutex_lock(&group->lock); | 152 | mutex_lock(&group->lock); |
| 166 | 153 | ||
| 167 | if (group->vin[id]) { | 154 | if (group->vin[vin->id]) { |
| 168 | vin_err(vin, "Duplicate renesas,id property value %u\n", id); | 155 | vin_err(vin, "Duplicate renesas,id property value %u\n", vin->id); |
| 169 | mutex_unlock(&group->lock); | 156 | mutex_unlock(&group->lock); |
| 170 | kref_put(&group->refcount, rvin_group_release); | 157 | kref_put(&group->refcount, rvin_group_release); |
| 171 | return -EINVAL; | 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 | vin->group = group; | 163 | vin->group = group; |
| 178 | vin->v4l2_dev.mdev = &group->mdev; | 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 | sd = media_entity_to_v4l2_subdev(entity); | 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 | if (group->remotes[i].subdev == sd) | 203 | if (group->remotes[i].subdev == sd) |
| 218 | return i; | 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 | static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, | 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 | struct v4l2_async_connection *asc) | 240 | struct v4l2_async_connection *asc) |
| 255 | { | 241 | { |
| 256 | struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); | 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++) | 245 | for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { |
| 260 | if (vin->group->vin[i]) | 246 | if (group->vin[i]) |
| 261 | rvin_v4l2_unregister(vin->group->vin[i]); | 247 | rvin_v4l2_unregister(group->vin[i]); |
| 248 | } | ||
| 262 | 249 | ||
| 263 | mutex_lock(&vin->group->lock); | 250 | mutex_lock(&vin->group->lock); |
| 264 | 251 | ||
| 265 | for (i = 0; i < RVIN_CSI_MAX; i++) { | 252 | for (unsigned int i = 0; i < RCAR_VIN_NUM; i++) { |
| 266 | if (vin->group->remotes[i].asc != asc) | 253 | if (!group->vin[i] || group->vin[i]->parallel.asc != asc) |
| 267 | continue; | 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 | vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); | 268 | vin_dbg(vin, "Unbind %s from slot %u\n", subdev->name, i); |
| 270 | break; | ||
| 271 | } | 269 | } |
| 272 | 270 | ||
| 273 | mutex_unlock(&vin->group->lock); | 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 | struct v4l2_async_connection *asc) | 278 | struct v4l2_async_connection *asc) |
| 281 | { | 279 | { |
| 282 | struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); | 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 | if (vin->group->remotes[i].asc != asc) | 303 | if (vin->group->remotes[i].asc != asc) |
| 289 | continue; | 304 | continue; |
| 305 | |||
| 290 | vin->group->remotes[i].subdev = subdev; | 306 | vin->group->remotes[i].subdev = subdev; |
| 291 | vin_dbg(vin, "Bound %s to slot %u\n", subdev->name, i); | 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 | static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { | 315 | static const struct v4l2_async_notifier_operations rvin_group_notify_ops = { |
| @@ -343,12 +358,49 @@ out: · 42 unmodified lines | |||
| 343 | return ret; | 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) { | 363 | struct fwnode_handle *fwnode __free(fwnode_handle) = NULL; |
| 349 | v4l2_async_nf_unregister(&vin->group->notifier); | 364 | struct fwnode_handle *ep __free(fwnode_handle) = NULL; |
| 350 | v4l2_async_nf_cleanup(&vin->group->notifier); | 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 | static int rvin_group_notifier_init(struct rvin_dev *vin, unsigned int port, | 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 | if (!(vin_mask & BIT(i))) | 437 | if (!(vin_mask & BIT(i))) |
| 386 | continue; | 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 | for (id = 0; id < max_id; id++) { | 446 | for (id = 0; id < max_id; id++) { |
| 389 | if (vin->group->remotes[id].asc) | 447 | if (vin->group->remotes[id].asc) |
| 390 | continue; | 448 | continue; |
| @@ -437,11 +495,11 @@ static void rvin_free_controls(struct rvin_dev *vin) · 46 unmodified lines | |||
| 437 | vin->vdev.ctrl_handler = NULL; | 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 | int ret; | 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 | if (ret < 0) | 503 | if (ret < 0) |
| 446 | return ret; | 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 | return ret; | 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 | vin->vdev.ctrl_handler = &vin->ctrl_handler; | 516 | vin->vdev.ctrl_handler = &vin->ctrl_handler; |
| 469 | 517 | ||
| 470 | return 0; | 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 | * CSI-2 | 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 | return 0; | 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 | const struct rvin_group_route *route; | 734 | const struct rvin_group_route *route; |
| 915 | unsigned int id; | 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 | /* Create all media device links between VINs and CSI-2's. */ | 742 | /* Create all media device links between VINs and CSI-2's. */ |
| 919 | mutex_lock(&vin->group->lock); | 743 | mutex_lock(&group->lock); |
| 920 | for (route = vin->info->routes; route->chsel; route++) { | 744 | for (route = group->info->routes; route->chsel; route++) { |
| 921 | /* Check that VIN' master is part of the group. */ | 745 | /* Check that VIN' master is part of the group. */ |
| 922 | if (!vin->group->vin[route->master]) | 746 | if (!group->vin[route->master]) |
| 923 | continue; | 747 | continue; |
| 924 | 748 | ||
| 925 | /* Check that CSI-2 is part of the group. */ | 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 | continue; | 751 | continue; |
| 928 | 752 | ||
| 929 | for (id = route->master; id < route->master + 4; id++) { | 753 | for (id = route->master; id < route->master + 4; id++) { |
| 930 | /* Check that VIN is part of the group. */ | 754 | /* Check that VIN is part of the group. */ |
| 931 | if (!vin->group->vin[id]) | 755 | if (!group->vin[id]) |
| 932 | continue; | 756 | continue; |
| 933 | 757 | ||
| 934 | ret = rvin_csi2_create_link(vin->group, id, route); | 758 | ret = rvin_csi2_create_link(group, id, route); |
| 935 | if (ret) | 759 | if (ret) |
| 936 | goto out; | 760 | goto out; |
| 937 | } | 761 | } |
| 938 | } | 762 | } |
| 939 | out: | 763 | out: |
| 940 | mutex_unlock(&vin->group->lock); | 764 | mutex_unlock(&group->lock); |
| 941 | 765 | ||
| 942 | return ret; | 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 | static int rvin_csi2_init(struct rvin_dev *vin) | 769 | static int rvin_csi2_init(struct rvin_dev *vin) |
| 954 | { | 770 | { |
| 955 | int ret; | 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 | ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_csi2_media_ops); | 773 | ret = rvin_group_get(vin, rvin_csi2_setup_links, &rvin_csi2_media_ops); |
| 967 | if (ret) | 774 | if (ret) |
| 968 | goto err_controls; | 775 | return ret; |
| 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; | ||
| 974 | 776 | ||
| 975 | ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX); | 777 | ret = rvin_group_notifier_init(vin, 1, RVIN_CSI_MAX); |
| 976 | if (ret) | 778 | if (ret) |
| 977 | goto err_parallel; | 779 | rvin_group_put(vin); |
| 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); | ||
| 986 | 780 | ||
| 987 | return ret; | 781 | return ret; |
| 988 | } | 782 | } |
| @@ -991,30 +785,31 @@ err_controls: · 2 unmodified lines | |||
| 991 | * ISP | 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 | unsigned int i; | 790 | unsigned int i; |
| 997 | int ret = -EINVAL; | 791 | int ret = -EINVAL; |
| 998 | 792 | ||
| 999 | /* Create all media device links between VINs and ISP's. */ | 793 | /* Create all media device links between VINs and ISP's. */ |
| 1000 | mutex_lock(&vin->group->lock); | 794 | mutex_lock(&group->lock); |
| 1001 | for (i = 0; i < RCAR_VIN_NUM; i++) { | 795 | for (i = 0; i < RCAR_VIN_NUM; i++) { |
| 1002 | struct media_pad *source_pad, *sink_pad; | 796 | struct media_pad *source_pad, *sink_pad; |
| 1003 | struct media_entity *source, *sink; | 797 | struct media_entity *source, *sink; |
| 1004 | unsigned int source_slot = i / 8; | 798 | unsigned int source_slot = i / 8; |
| 1005 | unsigned int source_idx = i % 8 + 1; | 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 | continue; | 803 | continue; |
| 1009 | 804 | ||
| 1010 | /* Check that ISP is part of the group. */ | 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 | continue; | 807 | continue; |
| 1013 | 808 | ||
| 1014 | source = &vin->group->remotes[source_slot].subdev->entity; | 809 | source = &group->remotes[source_slot].subdev->entity; |
| 1015 | source_pad = &source->pads[source_idx]; | 810 | source_pad = &source->pads[source_idx]; |
| 1016 | 811 | ||
| 1017 | sink = &vin->group->vin[i]->vdev.entity; | 812 | sink = &vin->vdev.entity; |
| 1018 | sink_pad = &sink->pads[0]; | 813 | sink_pad = &sink->pads[0]; |
| 1019 | 814 | ||
| 1020 | /* Skip if link already exists. */ | 815 | /* Skip if link already exists. */ |
| @@ -1030,44 +825,22 @@ static int rvin_isp_setup_links(struct rvin_dev *vin) · 9 unmodified lines | |||
| 1030 | break; | 825 | break; |
| 1031 | } | 826 | } |
| 1032 | } | 827 | } |
| 1033 | mutex_unlock(&vin->group->lock); | 828 | mutex_unlock(&group->lock); |
| 1034 | 829 | ||
| 1035 | return ret; | 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 | static int rvin_isp_init(struct rvin_dev *vin) | 833 | static int rvin_isp_init(struct rvin_dev *vin) |
| 1046 | { | 834 | { |
| 1047 | int ret; | 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 | ret = rvin_group_get(vin, rvin_isp_setup_links, NULL); | 837 | ret = rvin_group_get(vin, rvin_isp_setup_links, NULL); |
| 1059 | if (ret) | 838 | if (ret) |
| 1060 | goto err_controls; | 839 | return ret; |
| 1061 | 840 | ||
| 1062 | ret = rvin_group_notifier_init(vin, 2, RVIN_ISP_MAX); | 841 | ret = rvin_group_notifier_init(vin, 2, RVIN_ISP_MAX); |
| 1063 | if (ret) | 842 | if (ret) |
| 1064 | goto err_group; | 843 | rvin_group_put(vin); |
| 1065 | |||
| 1066 | return 0; | ||
| 1067 | err_group: | ||
| 1068 | rvin_group_put(vin); | ||
| 1069 | err_controls: | ||
| 1070 | rvin_free_controls(vin); | ||
| 1071 | 844 | ||
| 1072 | return ret; | 845 | return ret; |
| 1073 | } | 846 | } |
| @@ -1102,7 +875,7 @@ static int __maybe_unused rvin_resume(struct device *dev) · 28 unmodified lines | |||
| 1102 | * as we don't know if and in which order the master VINs will | 875 | * as we don't know if and in which order the master VINs will |
| 1103 | * be resumed. | 876 | * be resumed. |
| 1104 | */ | 877 | */ |
| 1105 | if (vin->info->use_mc) { | 878 | if (vin->info->model == RCAR_GEN3) { |
| 1106 | unsigned int master_id = rvin_group_id_to_master(vin->id); | 879 | unsigned int master_id = rvin_group_id_to_master(vin->id); |
| 1107 | struct rvin_dev *master = vin->group->vin[master_id]; | 880 | struct rvin_dev *master = vin->group->vin[master_id]; |
| 1108 | int ret; | 881 | int ret; |
| @@ -1124,7 +897,6 @@ static int __maybe_unused rvin_resume(struct device *dev) · 15 unmodified lines | |||
| 1124 | 897 | ||
| 1125 | static const struct rvin_info rcar_info_h1 = { | 898 | static const struct rvin_info rcar_info_h1 = { |
| 1126 | .model = RCAR_H1, | 899 | .model = RCAR_H1, |
| 1127 | .use_mc = false, | ||
| 1128 | .max_width = 2048, | 900 | .max_width = 2048, |
| 1129 | .max_height = 2048, | 901 | .max_height = 2048, |
| 1130 | .scaler = rvin_scaler_gen2, | 902 | .scaler = rvin_scaler_gen2, |
| @@ -1132,7 +904,6 @@ static const struct rvin_info rcar_info_h1 = { · 1 unmodified line | |||
| 1132 | 904 | ||
| 1133 | static const struct rvin_info rcar_info_m1 = { | 905 | static const struct rvin_info rcar_info_m1 = { |
| 1134 | .model = RCAR_M1, | 906 | .model = RCAR_M1, |
| 1135 | .use_mc = false, | ||
| 1136 | .max_width = 2048, | 907 | .max_width = 2048, |
| 1137 | .max_height = 2048, | 908 | .max_height = 2048, |
| 1138 | .scaler = rvin_scaler_gen2, | 909 | .scaler = rvin_scaler_gen2, |
| @@ -1140,7 +911,6 @@ static const struct rvin_info rcar_info_m1 = { · 1 unmodified line | |||
| 1140 | 911 | ||
| 1141 | static const struct rvin_info rcar_info_gen2 = { | 912 | static const struct rvin_info rcar_info_gen2 = { |
| 1142 | .model = RCAR_GEN2, | 913 | .model = RCAR_GEN2, |
| 1143 | .use_mc = false, | ||
| 1144 | .max_width = 2048, | 914 | .max_width = 2048, |
| 1145 | .max_height = 2048, | 915 | .max_height = 2048, |
| 1146 | .scaler = rvin_scaler_gen2, | 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 | static const struct rvin_info rcar_info_r8a774e1 = { | 926 | static const struct rvin_info rcar_info_r8a774e1 = { |
| 1157 | .model = RCAR_GEN3, | 927 | .model = RCAR_GEN3, |
| 1158 | .use_mc = true, | ||
| 1159 | .max_width = 4096, | 928 | .max_width = 4096, |
| 1160 | .max_height = 4096, | 929 | .max_height = 4096, |
| 1161 | .routes = rcar_info_r8a774e1_routes, | 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 | static const struct rvin_info rcar_info_r8a7795 = { | 941 | static const struct rvin_info rcar_info_r8a7795 = { |
| 1173 | .model = RCAR_GEN3, | 942 | .model = RCAR_GEN3, |
| 1174 | .use_mc = true, | ||
| 1175 | .nv12 = true, | 943 | .nv12 = true, |
| 1176 | .max_width = 4096, | 944 | .max_width = 4096, |
| 1177 | .max_height = 4096, | 945 | .max_height = 4096, |
| @@ -1189,7 +957,6 @@ static const struct rvin_group_route rcar_info_r8a7796_routes[] = { · 11 unmodified lines | |||
| 1189 | 957 | ||
| 1190 | static const struct rvin_info rcar_info_r8a7796 = { | 958 | static const struct rvin_info rcar_info_r8a7796 = { |
| 1191 | .model = RCAR_GEN3, | 959 | .model = RCAR_GEN3, |
| 1192 | .use_mc = true, | ||
| 1193 | .nv12 = true, | 960 | .nv12 = true, |
| 1194 | .max_width = 4096, | 961 | .max_width = 4096, |
| 1195 | .max_height = 4096, | 962 | .max_height = 4096, |
| @@ -1207,7 +974,6 @@ static const struct rvin_group_route rcar_info_r8a77965_routes[] = { · 11 unmodified lines | |||
| 1207 | 974 | ||
| 1208 | static const struct rvin_info rcar_info_r8a77965 = { | 975 | static const struct rvin_info rcar_info_r8a77965 = { |
| 1209 | .model = RCAR_GEN3, | 976 | .model = RCAR_GEN3, |
| 1210 | .use_mc = true, | ||
| 1211 | .nv12 = true, | 977 | .nv12 = true, |
| 1212 | .max_width = 4096, | 978 | .max_width = 4096, |
| 1213 | .max_height = 4096, | 979 | .max_height = 4096, |
| @@ -1222,7 +988,6 @@ static const struct rvin_group_route rcar_info_r8a77970_routes[] = { · 8 unmodified lines | |||
| 1222 | 988 | ||
| 1223 | static const struct rvin_info rcar_info_r8a77970 = { | 989 | static const struct rvin_info rcar_info_r8a77970 = { |
| 1224 | .model = RCAR_GEN3, | 990 | .model = RCAR_GEN3, |
| 1225 | .use_mc = true, | ||
| 1226 | .max_width = 4096, | 991 | .max_width = 4096, |
| 1227 | .max_height = 4096, | 992 | .max_height = 4096, |
| 1228 | .routes = rcar_info_r8a77970_routes, | 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 | static const struct rvin_info rcar_info_r8a77980 = { | 1002 | static const struct rvin_info rcar_info_r8a77980 = { |
| 1238 | .model = RCAR_GEN3, | 1003 | .model = RCAR_GEN3, |
| 1239 | .use_mc = true, | ||
| 1240 | .nv12 = true, | 1004 | .nv12 = true, |
| 1241 | .max_width = 4096, | 1005 | .max_width = 4096, |
| 1242 | .max_height = 4096, | 1006 | .max_height = 4096, |
| @@ -1250,7 +1014,6 @@ static const struct rvin_group_route rcar_info_r8a77990_routes[] = { · 7 unmodified lines | |||
| 1250 | 1014 | ||
| 1251 | static const struct rvin_info rcar_info_r8a77990 = { | 1015 | static const struct rvin_info rcar_info_r8a77990 = { |
| 1252 | .model = RCAR_GEN3, | 1016 | .model = RCAR_GEN3, |
| 1253 | .use_mc = true, | ||
| 1254 | .nv12 = true, | 1017 | .nv12 = true, |
| 1255 | .max_width = 4096, | 1018 | .max_width = 4096, |
| 1256 | .max_height = 4096, | 1019 | .max_height = 4096, |
| @@ -1264,7 +1027,6 @@ static const struct rvin_group_route rcar_info_r8a77995_routes[] = { · 7 unmodified lines | |||
| 1264 | 1027 | ||
| 1265 | static const struct rvin_info rcar_info_r8a77995 = { | 1028 | static const struct rvin_info rcar_info_r8a77995 = { |
| 1266 | .model = RCAR_GEN3, | 1029 | .model = RCAR_GEN3, |
| 1267 | .use_mc = true, | ||
| 1268 | .nv12 = true, | 1030 | .nv12 = true, |
| 1269 | .max_width = 4096, | 1031 | .max_width = 4096, |
| 1270 | .max_height = 4096, | 1032 | .max_height = 4096, |
| @@ -1274,7 +1036,6 @@ static const struct rvin_info rcar_info_r8a77995 = { · 3 unmodified lines | |||
| 1274 | 1036 | ||
| 1275 | static const struct rvin_info rcar_info_gen4 = { | 1037 | static const struct rvin_info rcar_info_gen4 = { |
| 1276 | .model = RCAR_GEN4, | 1038 | .model = RCAR_GEN4, |
| 1277 | .use_mc = true, | ||
| 1278 | .use_isp = true, | 1039 | .use_isp = true, |
| 1279 | .nv12 = true, | 1040 | .nv12 = true, |
| 1280 | .raw10 = true, | 1041 | .raw10 = true, |
| @@ -1361,6 +1122,56 @@ static const struct of_device_id rvin_of_id_table[] = { · 80 unmodified lines | |||
| 1361 | }; | 1122 | }; |
| 1362 | MODULE_DEVICE_TABLE(of, rvin_of_id_table); | 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 | static int rcar_vin_probe(struct platform_device *pdev) | 1175 | static int rcar_vin_probe(struct platform_device *pdev) |
| 1365 | { | 1176 | { |
| 1366 | struct rvin_dev *vin; | 1177 | struct rvin_dev *vin; |
| @@ -1388,30 +1199,59 @@ static int rcar_vin_probe(struct platform_device *pdev) · 21 unmodified lines | |||
| 1388 | 1199 | ||
| 1389 | platform_set_drvdata(pdev, vin); | 1200 | platform_set_drvdata(pdev, vin); |
| 1390 | 1201 | ||
| 1391 | if (vin->info->use_isp) { | 1202 | if (rvin_id_get(vin)) { |
| 1392 | ret = rvin_isp_init(vin); | 1203 | ret = -EINVAL; |
| 1393 | } else if (vin->info->use_mc) { | 1204 | goto err_dma; |
| 1394 | ret = rvin_csi2_init(vin); | 1205 | } |
| 1395 | 1206 | ||
| 1396 | if (vin->info->scaler && | 1207 | vin->pad.flags = MEDIA_PAD_FL_SINK; |
| 1397 | rvin_group_id_to_master(vin->id) == vin->id) | 1208 | ret = media_entity_pads_init(&vin->vdev.entity, 1, &vin->pad); |
| 1398 | vin->scaler = vin->info->scaler; | 1209 | if (ret) |
| 1399 | } else { | 1210 | goto err_id; |
| 1400 | ret = rvin_parallel_init(vin); | 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 | if (vin->info->scaler) | 1234 | if (vin->info->scaler) |
| 1403 | vin->scaler = vin->info->scaler; | 1235 | vin->scaler = vin->info->scaler; |
| 1236 | break; | ||
| 1404 | } | 1237 | } |
| 1405 | 1238 | ||
| 1406 | if (ret) { | 1239 | if (ret) |
| 1407 | rvin_dma_unregister(vin); | 1240 | goto err_ctrl; |
| 1408 | return ret; | ||
| 1409 | } | ||
| 1410 | 1241 | ||
| 1411 | pm_suspend_ignore_children(&pdev->dev, true); | 1242 | pm_suspend_ignore_children(&pdev->dev, true); |
| 1412 | pm_runtime_enable(&pdev->dev); | 1243 | pm_runtime_enable(&pdev->dev); |
| 1413 | 1244 | ||
| 1414 | return 0; | 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 | static void rcar_vin_remove(struct platform_device *pdev) | 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 | rvin_v4l2_unregister(vin); | 1263 | rvin_v4l2_unregister(vin); |
| 1424 | 1264 | ||
| 1425 | if (vin->info->use_isp) | 1265 | if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) { |
| 1426 | rvin_isp_cleanup(vin); | 1266 | v4l2_async_nf_unregister(&vin->group->notifier); |
| 1427 | else if (vin->info->use_mc) | 1267 | v4l2_async_nf_cleanup(&vin->group->notifier); |
| 1428 | rvin_csi2_cleanup(vin); | 1268 | } |
| 1429 | else | 1269 | |
| 1430 | rvin_parallel_cleanup(vin); | 1270 | rvin_group_put(vin); |
| 1271 | |||
| 1272 | rvin_free_controls(vin); | ||
| 1273 | |||
| 1274 | rvin_id_put(vin); | ||
| 1431 | 1275 | ||
| 1432 | rvin_dma_unregister(vin); | 1276 | rvin_dma_unregister(vin); |
| 1433 | } | 1277 | } |
| @@ -2,18 +2,18 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Driver for Renesas R-Car VIN | 3 | * Driver for Renesas R-Car VIN |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | ||
| 5 | * Copyright (C) 2016 Renesas Electronics Corp. | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | * Copyright (C) 2008 Magnus Damm | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | * | ||
| 10 | * Based on the soc-camera rcar_vin driver | ||
| 11 | */ | 10 | */ |
| 12 | 11 | ||
| 13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
| 14 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 15 | #include <linux/pm_runtime.h> | 14 | #include <linux/pm_runtime.h> |
| 16 | 15 | ||
| 16 | #include <media/v4l2-event.h> | ||
| 17 | #include <media/videobuf2-dma-contig.h> | 17 | #include <media/videobuf2-dma-contig.h> |
| 18 | 18 | ||
| 19 | #include "rcar-vin.h" | 19 | #include "rcar-vin.h" |
| @@ -115,11 +115,16 @@ · 95 unmodified lines | |||
| 115 | #define VNFC_S_FRAME (1 << 0) | 115 | #define VNFC_S_FRAME (1 << 0) |
| 116 | 116 | ||
| 117 | /* Video n Interrupt Enable Register bits */ | 117 | /* Video n Interrupt Enable Register bits */ |
| 118 | #define VNIE_FIE (1 << 4) | 118 | #define VNIE_VFE BIT(17) |
| 119 | #define VNIE_EFE (1 << 1) | 119 | #define VNIE_VRE BIT(16) |
| 120 | #define VNIE_FIE BIT(4) | ||
| 121 | #define VNIE_EFE BIT(1) | ||
| 120 | 122 | ||
| 121 | /* Video n Interrupt Status Register bits */ | 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 | /* Video n Data Mode Register bits */ | 129 | /* Video n Data Mode Register bits */ |
| 125 | #define VNDMR_A8BIT(n) (((n) & 0xff) << 24) | 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 | void rvin_scaler_gen2(struct rvin_dev *vin) | 561 | void rvin_scaler_gen2(struct rvin_dev *vin) |
| 557 | { | 562 | { |
| 558 | unsigned int crop_height; | ||
| 559 | u32 xs, ys; | 563 | u32 xs, ys; |
| 560 | 564 | ||
| 561 | /* Set scaling coefficient */ | 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 | ys = 0; | 566 | ys = 0; |
| 567 | if (crop_height != vin->compose.height) | 567 | if (vin->crop.height != vin->compose.height) |
| 568 | ys = (4096 * crop_height) / vin->compose.height; | 568 | ys = (4096 * vin->crop.height) / vin->compose.height; |
| 569 | rvin_write(vin, ys, VNYS_REG); | 569 | rvin_write(vin, ys, VNYS_REG); |
| 570 | 570 | ||
| 571 | xs = 0; | 571 | xs = 0; |
| @@ -700,9 +700,6 @@ static int rvin_setup(struct rvin_dev *vin) · 128 unmodified lines | |||
| 700 | case V4L2_FIELD_INTERLACED: | 700 | case V4L2_FIELD_INTERLACED: |
| 701 | /* Default to TB */ | 701 | /* Default to TB */ |
| 702 | vnmc = VNMC_IM_FULL; | 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 | break; | 703 | break; |
| 707 | case V4L2_FIELD_INTERLACED_TB: | 704 | case V4L2_FIELD_INTERLACED_TB: |
| 708 | vnmc = VNMC_IM_FULL; | 705 | vnmc = VNMC_IM_FULL; |
| @@ -897,6 +894,8 @@ static int rvin_setup(struct rvin_dev *vin) · 188 unmodified lines | |||
| 897 | 894 | ||
| 898 | /* Progressive or interlaced mode */ | 895 | /* Progressive or interlaced mode */ |
| 899 | interrupts = progressive ? VNIE_FIE : VNIE_EFE; | 896 | interrupts = progressive ? VNIE_FIE : VNIE_EFE; |
| 897 | /* Enable VSYNC Rising Edge Detection. */ | ||
| 898 | interrupts |= VNIE_VRE; | ||
| 900 | 899 | ||
| 901 | /* Ack interrupts */ | 900 | /* Ack interrupts */ |
| 902 | rvin_write(vin, interrupts, VNINTS_REG); | 901 | rvin_write(vin, interrupts, VNINTS_REG); |
| @@ -912,21 +911,6 @@ static int rvin_setup(struct rvin_dev *vin) · 9 unmodified lines | |||
| 912 | return 0; | 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 | static bool rvin_capture_active(struct rvin_dev *vin) | 914 | static bool rvin_capture_active(struct rvin_dev *vin) |
| 931 | { | 915 | { |
| 932 | return rvin_read(vin, VNMS_REG) & VNMS_CA; | 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 | static irqreturn_t rvin_irq(int irq, void *data) | 1033 | static irqreturn_t rvin_irq(int irq, void *data) |
| 1050 | { | 1034 | { |
| 1051 | struct rvin_dev *vin = data; | 1035 | struct rvin_dev *vin = data; |
| 1052 | u32 int_status, vnms; | 1036 | u32 capture, status, vnms; |
| 1053 | int slot; | 1037 | int slot; |
| 1054 | unsigned int handled = 0; | 1038 | unsigned int handled = 0; |
| 1055 | unsigned long flags; | 1039 | unsigned long flags; |
| 1056 | 1040 | ||
| 1057 | spin_lock_irqsave(&vin->qlock, flags); | 1041 | spin_lock_irqsave(&vin->qlock, flags); |
| 1058 | 1042 | ||
| 1059 | int_status = rvin_get_interrupt_status(vin); | 1043 | status = rvin_read(vin, VNINTS_REG); |
| 1060 | if (!int_status) | 1044 | if (!status) |
| 1061 | goto done; | 1045 | goto done; |
| 1062 | 1046 | ||
| 1063 | rvin_ack_interrupt(vin); | 1047 | rvin_write(vin, status, VNINTS_REG); |
| 1064 | handled = 1; | 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 | /* Nothing to do if nothing was captured. */ | 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 | goto done; | 1065 | goto done; |
| 1069 | 1066 | ||
| 1070 | /* Nothing to do if not running. */ | 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 | struct media_pad *pad; | 1294 | struct media_pad *pad; |
| 1298 | int ret; | 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 | pad = media_pad_remote_pad_first(&vin->pad); | 1297 | pad = media_pad_remote_pad_first(&vin->pad); |
| 1309 | if (!pad) | 1298 | if (!pad) |
| 1310 | return -EPIPE; | 1299 | return -EPIPE; |
| @@ -1417,7 +1406,7 @@ void rvin_stop_streaming(struct rvin_dev *vin) · 106 unmodified lines | |||
| 1417 | rvin_set_stream(vin, 0); | 1406 | rvin_set_stream(vin, 0); |
| 1418 | 1407 | ||
| 1419 | /* disable interrupts */ | 1408 | /* disable interrupts */ |
| 1420 | rvin_disable_interrupts(vin); | 1409 | rvin_write(vin, 0, VNIE_REG); |
| 1421 | 1410 | ||
| 1422 | /* Return unprocessed buffers from hardware. */ | 1411 | /* Return unprocessed buffers from hardware. */ |
| 1423 | for (unsigned int i = 0; i < HW_BUFFER_NUM; i++) { | 1412 | for (unsigned int i = 0; i < HW_BUFFER_NUM; i++) { |
| @@ -2,12 +2,11 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Driver for Renesas R-Car VIN | 3 | * Driver for Renesas R-Car VIN |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | ||
| 5 | * Copyright (C) 2016 Renesas Electronics Corp. | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | * Copyright (C) 2008 Magnus Damm | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | * | ||
| 10 | * Based on the soc-camera rcar_vin driver | ||
| 11 | */ | 10 | */ |
| 12 | 11 | ||
| 13 | #include <linux/pm_runtime.h> | 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 | * V4L2 | 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 | static int rvin_querycap(struct file *file, void *priv, | 232 | static int rvin_querycap(struct file *file, void *priv, |
| 329 | struct v4l2_capability *cap) | 233 | struct v4l2_capability *cap) |
| 330 | { | 234 | { |
| @@ -333,42 +237,6 @@ static int rvin_querycap(struct file *file, void *priv, · 2 unmodified lines | |||
| 333 | return 0; | 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 | static int rvin_g_fmt_vid_cap(struct file *file, void *priv, | 240 | static int rvin_g_fmt_vid_cap(struct file *file, void *priv, |
| 373 | struct v4l2_format *f) | 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 | static int rvin_remote_rectangle(struct rvin_dev *vin, struct v4l2_rect *rect) | 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 | struct v4l2_subdev_format fmt = { | 337 | struct v4l2_subdev_format fmt = { |
| 469 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | 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 | unsigned int index; | 341 | unsigned int index; |
| 473 | int ret; | 342 | int ret; |
| 474 | 343 | ||
| 475 | if (vin->info->use_mc) { | 344 | if (!pad) |
| 476 | struct media_pad *pad = media_pad_remote_pad_first(&vin->pad); | 345 | return -EINVAL; |
| 477 | |||
| 478 | if (!pad) | ||
| 479 | return -EINVAL; | ||
| 480 | 346 | ||
| 481 | sd = media_entity_to_v4l2_subdev(pad->entity); | 347 | sd = media_entity_to_v4l2_subdev(pad->entity); |
| 482 | index = pad->index; | 348 | index = pad->index; |
| 483 | } else { | ||
| 484 | sd = vin_to_source(vin); | ||
| 485 | index = vin->parallel.source_pad; | ||
| 486 | } | ||
| 487 | 349 | ||
| 488 | fmt.pad = index; | 350 | fmt.pad = index; |
| 489 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); | 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 | return 0; | 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 | static int rvin_subscribe_event(struct v4l2_fh *fh, | 488 | static int rvin_subscribe_event(struct v4l2_fh *fh, |
| 734 | const struct v4l2_event_subscription *sub) | 489 | const struct v4l2_event_subscription *sub) |
| 735 | { | 490 | { |
| 736 | switch (sub->type) { | 491 | switch (sub->type) { |
| 492 | case V4L2_EVENT_FRAME_SYNC: | ||
| 493 | return v4l2_event_subscribe(fh, sub, 2, NULL); | ||
| 737 | case V4L2_EVENT_SOURCE_CHANGE: | 494 | case V4L2_EVENT_SOURCE_CHANGE: |
| 738 | return v4l2_event_subscribe(fh, sub, 4, NULL); | 495 | return v4l2_event_subscribe(fh, sub, 4, NULL); |
| 739 | } | 496 | } |
| 740 | return v4l2_ctrl_subscribe_event(fh, sub); | 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 | static void rvin_mc_try_format(struct rvin_dev *vin, | 500 | static void rvin_mc_try_format(struct rvin_dev *vin, |
| 905 | struct v4l2_pix_format *pix) | 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 | * File Operations | 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 | static int rvin_open(struct file *file) | 578 | static int rvin_open(struct file *file) |
| 996 | { | 579 | { |
| 997 | struct rvin_dev *vin = video_drvdata(file); | 580 | struct rvin_dev *vin = video_drvdata(file); |
| @@ -1011,11 +594,7 @@ static int rvin_open(struct file *file) · 13 unmodified lines | |||
| 1011 | if (ret) | 594 | if (ret) |
| 1012 | goto err_unlock; | 595 | goto err_unlock; |
| 1013 | 596 | ||
| 1014 | if (vin->info->use_mc) | 597 | ret = v4l2_pipeline_pm_get(&vin->vdev.entity); |
| 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 | |||
| 1019 | if (ret < 0) | 598 | if (ret < 0) |
| 1020 | goto err_open; | 599 | goto err_open; |
| 1021 | 600 | ||
| @@ -1027,10 +606,7 @@ static int rvin_open(struct file *file) · 5 unmodified lines | |||
| 1027 | 606 | ||
| 1028 | return 0; | 607 | return 0; |
| 1029 | err_power: | 608 | err_power: |
| 1030 | if (vin->info->use_mc) | 609 | v4l2_pipeline_pm_put(&vin->vdev.entity); |
| 1031 | v4l2_pipeline_pm_put(&vin->vdev.entity); | ||
| 1032 | else if (v4l2_fh_is_singular_file(file)) | ||
| 1033 | rvin_power_parallel(vin, false); | ||
| 1034 | err_open: | 610 | err_open: |
| 1035 | v4l2_fh_release(file); | 611 | v4l2_fh_release(file); |
| 1036 | err_unlock: | 612 | err_unlock: |
| @@ -1044,23 +620,14 @@ err_pm: · 7 unmodified lines | |||
| 1044 | static int rvin_release(struct file *file) | 620 | static int rvin_release(struct file *file) |
| 1045 | { | 621 | { |
| 1046 | struct rvin_dev *vin = video_drvdata(file); | 622 | struct rvin_dev *vin = video_drvdata(file); |
| 1047 | bool fh_singular; | ||
| 1048 | int ret; | 623 | int ret; |
| 1049 | 624 | ||
| 1050 | mutex_lock(&vin->lock); | 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 | /* the release helper will cleanup any on-going streaming */ | 627 | /* the release helper will cleanup any on-going streaming */ |
| 1056 | ret = _vb2_fop_release(file, NULL); | 628 | ret = _vb2_fop_release(file, NULL); |
| 1057 | 629 | ||
| 1058 | if (vin->info->use_mc) { | 630 | v4l2_pipeline_pm_put(&vin->vdev.entity); |
| 1059 | v4l2_pipeline_pm_put(&vin->vdev.entity); | ||
| 1060 | } else { | ||
| 1061 | if (fh_singular) | ||
| 1062 | rvin_power_parallel(vin, false); | ||
| 1063 | } | ||
| 1064 | 631 | ||
| 1065 | mutex_unlock(&vin->lock); | 632 | mutex_unlock(&vin->lock); |
| 1066 | 633 | ||
| @@ -1091,18 +658,6 @@ void rvin_v4l2_unregister(struct rvin_dev *vin) · 24 unmodified lines | |||
| 1091 | video_unregister_device(&vin->vdev); | 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 | static void rvin_notify(struct v4l2_subdev *sd, | 661 | static void rvin_notify(struct v4l2_subdev *sd, |
| 1107 | unsigned int notification, void *arg) | 662 | unsigned int notification, void *arg) |
| 1108 | { | 663 | { |
| @@ -1113,12 +668,6 @@ static void rvin_notify(struct v4l2_subdev *sd, · 4 unmodified lines | |||
| 1113 | container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); | 668 | container_of(sd->v4l2_dev, struct rvin_dev, v4l2_dev); |
| 1114 | unsigned int i; | 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 | group = vin->group; | 671 | group = vin->group; |
| 1123 | 672 | ||
| 1124 | for (i = 0; i < RCAR_VIN_NUM; i++) { | 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 | if (remote != sd) | 683 | if (remote != sd) |
| 1135 | continue; | 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 | vdev->lock = &vin->lock; | 708 | vdev->lock = &vin->lock; |
| 1154 | vdev->fops = &rvin_fops; | 709 | vdev->fops = &rvin_fops; |
| 1155 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | | 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 | /* Set a default format */ | 714 | /* Set a default format */ |
| 1159 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; | 715 | vin->format.pixelformat = RVIN_DEFAULT_FORMAT; |
| @@ -1162,14 +718,6 @@ int rvin_v4l2_register(struct rvin_dev *vin) · 2 unmodified lines | |||
| 1162 | vin->format.field = RVIN_DEFAULT_FIELD; | 718 | vin->format.field = RVIN_DEFAULT_FIELD; |
| 1163 | vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; | 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 | rvin_format_align(vin, &vin->format); | 721 | rvin_format_align(vin, &vin->format); |
| 1174 | 722 | ||
| 1175 | ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); | 723 | ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); |
| @@ -2,12 +2,11 @@ · 1 unmodified line | |||
| 2 | /* | 2 | /* |
| 3 | * Driver for Renesas R-Car VIN | 3 | * Driver for Renesas R-Car VIN |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2025 Niklas Söderlund <niklas.soderlund@ragnatech.se> | ||
| 5 | * Copyright (C) 2016 Renesas Electronics Corp. | 6 | * Copyright (C) 2016 Renesas Electronics Corp. |
| 6 | * Copyright (C) 2011-2013 Renesas Solutions Corp. | 7 | * Copyright (C) 2011-2013 Renesas Solutions Corp. |
| 7 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> | 8 | * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com> |
| 8 | * Copyright (C) 2008 Magnus Damm | 9 | * Copyright (C) 2008 Magnus Damm |
| 9 | * | ||
| 10 | * Based on the soc-camera rcar_vin driver | ||
| 11 | */ | 10 | */ |
| 12 | 11 | ||
| 13 | #ifndef __RCAR_VIN__ | 12 | #ifndef __RCAR_VIN__ |
| @@ -79,8 +78,6 @@ struct rvin_video_format { · 65 unmodified lines | |||
| 79 | * @mbus_type: media bus type | 78 | * @mbus_type: media bus type |
| 80 | * @bus: media bus parallel configuration | 79 | * @bus: media bus parallel configuration |
| 81 | * @source_pad: source pad of remote subdevice | 80 | * @source_pad: source pad of remote subdevice |
| 82 | * @sink_pad: sink pad of remote subdevice | ||
| 83 | * | ||
| 84 | */ | 81 | */ |
| 85 | struct rvin_parallel_entity { | 82 | struct rvin_parallel_entity { |
| 86 | struct v4l2_async_connection *asc; | 83 | struct v4l2_async_connection *asc; |
| @@ -90,7 +87,6 @@ struct rvin_parallel_entity { · 3 unmodified lines | |||
| 90 | struct v4l2_mbus_config_parallel bus; | 87 | struct v4l2_mbus_config_parallel bus; |
| 91 | 88 | ||
| 92 | unsigned int source_pad; | 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 | * struct rvin_info - Information about the particular VIN implementation | 114 | * struct rvin_info - Information about the particular VIN implementation |
| 119 | * @model: VIN model | 115 | * @model: VIN model |
| 120 | * @use_mc: use media controller instead of controlling subdevice | ||
| 121 | * @use_isp: the VIN is connected to the ISP and not to the CSI-2 | 116 | * @use_isp: the VIN is connected to the ISP and not to the CSI-2 |
| 122 | * @nv12: support outputting NV12 pixel format | 117 | * @nv12: support outputting NV12 pixel format |
| 123 | * @raw10: support outputting RAW10 pixel format | 118 | * @raw10: support outputting RAW10 pixel format |
| @@ -129,7 +124,6 @@ struct rvin_group_route { · 5 unmodified lines | |||
| 129 | */ | 124 | */ |
| 130 | struct rvin_info { | 125 | struct rvin_info { |
| 131 | enum model_id model; | 126 | enum model_id model; |
| 132 | bool use_mc; | ||
| 133 | bool use_isp; | 127 | bool use_isp; |
| 134 | bool nv12; | 128 | bool nv12; |
| 135 | bool raw10; | 129 | bool raw10; |
| @@ -149,7 +143,6 @@ struct rvin_info { · 13 unmodified lines | |||
| 149 | * @vdev: V4L2 video device associated with VIN | 143 | * @vdev: V4L2 video device associated with VIN |
| 150 | * @v4l2_dev: V4L2 device | 144 | * @v4l2_dev: V4L2 device |
| 151 | * @ctrl_handler: V4L2 control handler | 145 | * @ctrl_handler: V4L2 control handler |
| 152 | * @notifier: V4L2 asynchronous subdevs notifier | ||
| 153 | * | 146 | * |
| 154 | * @parallel: parallel input subdevice descriptor | 147 | * @parallel: parallel input subdevice descriptor |
| 155 | * | 148 | * |
| @@ -177,7 +170,6 @@ struct rvin_info { · 21 unmodified lines | |||
| 177 | * @crop: active cropping | 170 | * @crop: active cropping |
| 178 | * @compose: active composing | 171 | * @compose: active composing |
| 179 | * @scaler: Optional scaler | 172 | * @scaler: Optional scaler |
| 180 | * @std: active video standard of the video source | ||
| 181 | * | 173 | * |
| 182 | * @alpha: Alpha component to fill in for supported pixel formats | 174 | * @alpha: Alpha component to fill in for supported pixel formats |
| 183 | */ | 175 | */ |
| @@ -189,7 +181,6 @@ struct rvin_dev { · 5 unmodified lines | |||
| 189 | struct video_device vdev; | 181 | struct video_device vdev; |
| 190 | struct v4l2_device v4l2_dev; | 182 | struct v4l2_device v4l2_dev; |
| 191 | struct v4l2_ctrl_handler ctrl_handler; | 183 | struct v4l2_ctrl_handler ctrl_handler; |
| 192 | struct v4l2_async_notifier notifier; | ||
| 193 | 184 | ||
| 194 | struct rvin_parallel_entity parallel; | 185 | struct rvin_parallel_entity parallel; |
| 195 | 186 | ||
| @@ -220,7 +211,6 @@ struct rvin_dev { · 24 unmodified lines | |||
| 220 | struct v4l2_rect crop; | 211 | struct v4l2_rect crop; |
| 221 | struct v4l2_rect compose; | 212 | struct v4l2_rect compose; |
| 222 | void (*scaler)(struct rvin_dev *vin); | 213 | void (*scaler)(struct rvin_dev *vin); |
| 223 | v4l2_std_id std; | ||
| 224 | 214 | ||
| 225 | unsigned int alpha; | 215 | unsigned int alpha; |
| 226 | }; | 216 | }; |
| @@ -242,6 +232,7 @@ struct rvin_dev { · 15 unmodified lines | |||
| 242 | * @lock: protects the count, notifier, vin and csi members | 232 | * @lock: protects the count, notifier, vin and csi members |
| 243 | * @count: number of enabled VIN instances found in DT | 233 | * @count: number of enabled VIN instances found in DT |
| 244 | * @notifier: group notifier for CSI-2 async connections | 234 | * @notifier: group notifier for CSI-2 async connections |
| 235 | * @info: Platform dependent information about the VIN instances | ||
| 245 | * @vin: VIN instances which are part of the group | 236 | * @vin: VIN instances which are part of the group |
| 246 | * @link_setup: Callback to create all links for the media graph | 237 | * @link_setup: Callback to create all links for the media graph |
| 247 | * @remotes: array of pairs of async connection and subdev pointers | 238 | * @remotes: array of pairs of async connection and subdev pointers |
| @@ -255,9 +246,10 @@ struct rvin_group { · 7 unmodified lines | |||
| 255 | struct mutex lock; | 246 | struct mutex lock; |
| 256 | unsigned int count; | 247 | unsigned int count; |
| 257 | struct v4l2_async_notifier notifier; | 248 | struct v4l2_async_notifier notifier; |
| 249 | const struct rvin_info *info; | ||
| 258 | struct rvin_dev *vin[RCAR_VIN_NUM]; | 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 | struct { | 254 | struct { |
| 263 | struct v4l2_async_connection *asc; | 255 | struct v4l2_async_connection *asc; |
| @@ -366,7 +366,7 @@ static const struct rzg2l_cru_info rzg3e_cru_info = { · 365 unmodified lines | |||
| 366 | .irq_handler = rzg3e_cru_irq, | 366 | .irq_handler = rzg3e_cru_irq, |
| 367 | .enable_interrupts = rzg3e_cru_enable_interrupts, | 367 | .enable_interrupts = rzg3e_cru_enable_interrupts, |
| 368 | .disable_interrupts = rzg3e_cru_disable_interrupts, | 368 | .disable_interrupts = rzg3e_cru_disable_interrupts, |
| 369 | .fifo_empty = rz3e_fifo_empty, | 369 | .fifo_empty = rzg3e_fifo_empty, |
| 370 | .csi_setup = rzg3e_cru_csi2_setup, | 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 | [ICnDMR] = 0x26c, | 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 | .max_width = 2800, | 407 | .max_width = 2800, |
| 408 | .max_height = 4095, | 408 | .max_height = 4095, |
| 409 | .image_conv = ICnMC, | 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 | .compatible = "renesas,rzg2l-cru", | 424 | .compatible = "renesas,rzg2l-cru", |
| 425 | .data = &rzgl2_cru_info, | 425 | .data = &rzg2l_cru_info, |
| 426 | }, | 426 | }, |
| 427 | { /* sentinel */ } | 427 | { /* sentinel */ } |
| 428 | }; | 428 | }; |
| @@ -64,19 +64,21 @@ struct rzg2l_cru_ip { · 63 unmodified lines | |||
| 64 | 64 | ||
| 65 | /** | 65 | /** |
| 66 | * struct rzg2l_cru_ip_format - CRU IP format | 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 | * @datatype: MIPI CSI2 data type | 68 | * @datatype: MIPI CSI2 data type |
| 69 | * @format: 4CC format identifier (V4L2_PIX_FMT_*) | 69 | * @format: 4CC format identifier (V4L2_PIX_FMT_*) |
| 70 | * @icndmr: ICnDMR register value | 70 | * @icndmr: ICnDMR register value |
| 71 | * @bpp: bytes per pixel | ||
| 72 | * @yuv: Flag to indicate whether the format is YUV-based. | 71 | * @yuv: Flag to indicate whether the format is YUV-based. |
| 73 | */ | 72 | */ |
| 74 | struct rzg2l_cru_ip_format { | 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 | u32 datatype; | 79 | u32 datatype; |
| 77 | u32 format; | 80 | u32 format; |
| 78 | u32 icndmr; | 81 | u32 icndmr; |
| 79 | u8 bpp; | ||
| 80 | bool yuv; | 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 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code); | 194 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code); |
| 193 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format); | 195 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format); |
| 194 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index); | 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 | void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru); | 200 | void rzg2l_cru_enable_interrupts(struct rzg2l_cru_dev *cru); |
| 197 | void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru); | 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 | void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru); | 203 | void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru); |
| 200 | 204 | ||
| 201 | bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru); | 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 | void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, | 207 | void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, |
| 204 | const struct rzg2l_cru_ip_format *ip_fmt, | 208 | const struct rzg2l_cru_ip_format *ip_fmt, |
| 205 | u8 csi_vc); | 209 | u8 csi_vc); |
| @@ -232,6 +232,18 @@ static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = { · 231 unmodified lines | |||
| 232 | { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, | 232 | { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, |
| 233 | { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, | 233 | { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, |
| 234 | { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, | 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 | static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd) | 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 | const struct rzg2l_csi2_format *format; | 294 | const struct rzg2l_csi2_format *format; |
| 283 | const struct v4l2_mbus_framefmt *fmt; | 295 | const struct v4l2_mbus_framefmt *fmt; |
| 284 | struct v4l2_subdev_state *state; | 296 | struct v4l2_subdev_state *state; |
| 285 | struct v4l2_ctrl *ctrl; | 297 | struct media_pad *remote_pad; |
| 286 | u64 mbps; | 298 | u64 mbps; |
| 299 | s64 ret; | ||
| 287 | 300 | ||
| 288 | /* Read the pixel rate control from remote. */ | 301 | if (!csi2->remote_source) |
| 289 | ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); | 302 | return -ENODEV; |
| 290 | if (!ctrl) { | 303 | |
| 291 | dev_err(csi2->dev, "no pixel rate control in subdev %s\n", | 304 | remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]); |
| 292 | source->name); | 305 | if (IS_ERR(remote_pad)) { |
| 293 | return -EINVAL; | 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 | state = v4l2_subdev_lock_and_get_active_state(&csi2->subdev); | 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 | format = rzg2l_csi2_code_to_fmt(fmt->code); | 313 | format = rzg2l_csi2_code_to_fmt(fmt->code); |
| 299 | v4l2_subdev_unlock_state(state); | 314 | v4l2_subdev_unlock_state(state); |
| 300 | 315 | ||
| 301 | /* | 316 | /* Read the link frequency from remote subdevice. */ |
| 302 | * Calculate hsfreq in Mbps | 317 | ret = v4l2_get_link_freq(remote_pad, format->bpp, csi2->lanes * 2); |
| 303 | * hsfreq = (pixel_rate * bits_per_sample) / number_of_lanes | 318 | if (ret < 0) { |
| 304 | */ | 319 | dev_err(csi2->dev, "can't retrieve link freq from subdev %s\n", |
| 305 | mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * format->bpp; | 320 | source->name); |
| 306 | do_div(mbps, csi2->lanes * 1000000); | 321 | return -EINVAL; |
| 322 | } | ||
| 323 | |||
| 324 | mbps = ret * 2; | ||
| 325 | do_div(mbps, 1000000); | ||
| 307 | 326 | ||
| 308 | return mbps; | 327 | return mbps; |
| 309 | } | 328 | } |
| @@ -13,42 +13,83 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = { | 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 | .datatype = MIPI_CSI2_DT_YUV422_8B, | 19 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 18 | .format = V4L2_PIX_FMT_UYVY, | 20 | .format = V4L2_PIX_FMT_UYVY, |
| 19 | .bpp = 2, | ||
| 20 | .icndmr = ICnDMR_YCMODE_UYVY, | 21 | .icndmr = ICnDMR_YCMODE_UYVY, |
| 21 | .yuv = true, | 22 | .yuv = true, |
| 22 | }, | 23 | }, |
| 23 | { | 24 | { |
| 24 | .code = MEDIA_BUS_FMT_SBGGR8_1X8, | 25 | .codes = { |
| 26 | MEDIA_BUS_FMT_SBGGR8_1X8, | ||
| 27 | }, | ||
| 25 | .format = V4L2_PIX_FMT_SBGGR8, | 28 | .format = V4L2_PIX_FMT_SBGGR8, |
| 26 | .datatype = MIPI_CSI2_DT_RAW8, | 29 | .datatype = MIPI_CSI2_DT_RAW8, |
| 27 | .bpp = 1, | ||
| 28 | .icndmr = 0, | 30 | .icndmr = 0, |
| 29 | .yuv = false, | 31 | .yuv = false, |
| 30 | }, | 32 | }, |
| 31 | { | 33 | { |
| 32 | .code = MEDIA_BUS_FMT_SGBRG8_1X8, | 34 | .codes = { |
| 35 | MEDIA_BUS_FMT_SGBRG8_1X8, | ||
| 36 | }, | ||
| 33 | .format = V4L2_PIX_FMT_SGBRG8, | 37 | .format = V4L2_PIX_FMT_SGBRG8, |
| 34 | .datatype = MIPI_CSI2_DT_RAW8, | 38 | .datatype = MIPI_CSI2_DT_RAW8, |
| 35 | .bpp = 1, | ||
| 36 | .icndmr = 0, | 39 | .icndmr = 0, |
| 37 | .yuv = false, | 40 | .yuv = false, |
| 38 | }, | 41 | }, |
| 39 | { | 42 | { |
| 40 | .code = MEDIA_BUS_FMT_SGRBG8_1X8, | 43 | .codes = { |
| 44 | MEDIA_BUS_FMT_SGRBG8_1X8, | ||
| 45 | }, | ||
| 41 | .format = V4L2_PIX_FMT_SGRBG8, | 46 | .format = V4L2_PIX_FMT_SGRBG8, |
| 42 | .datatype = MIPI_CSI2_DT_RAW8, | 47 | .datatype = MIPI_CSI2_DT_RAW8, |
| 43 | .bpp = 1, | ||
| 44 | .icndmr = 0, | 48 | .icndmr = 0, |
| 45 | .yuv = false, | 49 | .yuv = false, |
| 46 | }, | 50 | }, |
| 47 | { | 51 | { |
| 48 | .code = MEDIA_BUS_FMT_SRGGB8_1X8, | 52 | .codes = { |
| 53 | MEDIA_BUS_FMT_SRGGB8_1X8, | ||
| 54 | }, | ||
| 49 | .format = V4L2_PIX_FMT_SRGGB8, | 55 | .format = V4L2_PIX_FMT_SRGGB8, |
| 50 | .datatype = MIPI_CSI2_DT_RAW8, | 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 | .icndmr = 0, | 93 | .icndmr = 0, |
| 53 | .yuv = false, | 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 | const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code) | 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++) | 102 | for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { |
| 62 | if (rzg2l_cru_ip_formats[i].code == code) | 103 | for (j = 0; j < ARRAY_SIZE(rzg2l_cru_ip_formats[i].codes); j++) { |
| 63 | return &rzg2l_cru_ip_formats[i]; | 104 | if (rzg2l_cru_ip_formats[i].codes[j] == code) |
| 105 | return &rzg2l_cru_ip_formats[i]; | ||
| 106 | } | ||
| 107 | } | ||
| 64 | 108 | ||
| 65 | return NULL; | 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 | return &rzg2l_cru_ip_formats[index]; | 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 | struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) | 143 | struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru) |
| 89 | { | 144 | { |
| 90 | struct v4l2_subdev_state *state; | 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 | sink_format = v4l2_subdev_state_get_format(state, fmt->pad); | 217 | sink_format = v4l2_subdev_state_get_format(state, fmt->pad); |
| 163 | 218 | ||
| 164 | if (!rzg2l_cru_ip_code_to_fmt(fmt->format.code)) | 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 | else | 221 | else |
| 167 | sink_format->code = fmt->format.code; | 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 | struct v4l2_subdev_state *state, | 243 | struct v4l2_subdev_state *state, |
| 189 | struct v4l2_subdev_mbus_code_enum *code) | 244 | struct v4l2_subdev_mbus_code_enum *code) |
| 190 | { | 245 | { |
| 191 | if (code->index >= ARRAY_SIZE(rzg2l_cru_ip_formats)) | 246 | unsigned int index = code->index; |
| 192 | return -EINVAL; | 247 | unsigned int i, j; |
| 193 | 248 | ||
| 194 | code->code = rzg2l_cru_ip_formats[code->index].code; | 249 | for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) { |
| 195 | return 0; | 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 | static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd, | 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 | return 0; | 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 | u32 amnfifopntr = rzg2l_cru_read(cru, AMnFIFOPNTR); | 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 | amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR; | 345 | amnfifopntr_w = amnfifopntr & AMnFIFOPNTR_FIFOWPNTR; |
| 346 | amnfifopntr_r_y = | 346 | amnfifopntr_r_y = |
| 347 | (amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16; | 347 | (amnfifopntr & AMnFIFOPNTR_FIFORPNTR_Y) >> 16; |
| 348 | if (amnfifopntr_w == amnfifopntr_r_y) | ||
| 349 | return true; | ||
| 350 | 348 | ||
| 351 | return amnfifopntr_w == amnfifopntr_r_y; | 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 | v4l_bound_align_image(&pix->width, 320, info->max_width, 1, | 939 | v4l_bound_align_image(&pix->width, 320, info->max_width, 1, |
| 942 | &pix->height, 240, info->max_height, 2, 0); | 940 | &pix->height, 240, info->max_height, 2, 0); |
| 943 | 941 | ||
| 944 | if (info->has_stride) { | 942 | v4l2_fill_pixfmt(pix, pix->pixelformat, pix->width, pix->height); |
| 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; | ||
| 953 | 943 | ||
| 954 | dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", | 944 | dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", |
| 955 | pix->width, pix->height, pix->bytesperline, pix->sizeimage); | 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 | return 0; | 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 | static const struct v4l2_ioctl_ops rzg2l_cru_ioctl_ops = { | 1049 | static const struct v4l2_ioctl_ops rzg2l_cru_ioctl_ops = { |
| 1035 | .vidioc_querycap = rzg2l_cru_querycap, | 1050 | .vidioc_querycap = rzg2l_cru_querycap, |
| 1036 | .vidioc_try_fmt_vid_cap = rzg2l_cru_try_fmt_vid_cap, | 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 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | 1062 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
| 1048 | .vidioc_streamon = vb2_ioctl_streamon, | 1063 | .vidioc_streamon = vb2_ioctl_streamon, |
| 1049 | .vidioc_streamoff = vb2_ioctl_streamoff, | 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 | if (fmt.format.width != cru->format.width || | 1145 | if (fmt.format.width != cru->format.width || |
| 1130 | fmt.format.height != cru->format.height || | 1146 | fmt.format.height != cru->format.height || |
| 1131 | fmt.format.field != cru->format.field || | 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 | return -EPIPE; | 1149 | return -EPIPE; |
| 1134 | 1150 | ||
| 1135 | return 0; | 1151 | return 0; |
| @@ -6,5 +6,6 @@ vsp1-y += vsp1_clu.o vsp1_hsit.o vsp1_lut.o · 5 unmodified lines | |||
| 6 | vsp1-y += vsp1_brx.o vsp1_sru.o vsp1_uds.o | 6 | vsp1-y += vsp1_brx.o vsp1_sru.o vsp1_uds.o |
| 7 | vsp1-y += vsp1_hgo.o vsp1_hgt.o vsp1_histo.o | 7 | vsp1-y += vsp1_hgo.o vsp1_hgt.o vsp1_histo.o |
| 8 | vsp1-y += vsp1_iif.o vsp1_lif.o vsp1_uif.o | 8 | vsp1-y += vsp1_iif.o vsp1_lif.o vsp1_uif.o |
| 9 | vsp1-y += vsp1_vspx.o | ||
| 9 | 10 | ||
| 10 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o | 11 | obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o |
| @@ -111,6 +111,7 @@ struct vsp1_device { · 110 unmodified lines | |||
| 111 | struct media_entity_operations media_ops; | 111 | struct media_entity_operations media_ops; |
| 112 | 112 | ||
| 113 | struct vsp1_drm *drm; | 113 | struct vsp1_drm *drm; |
| 114 | struct vsp1_vspx *vspx; | ||
| 114 | }; | 115 | }; |
| 115 | 116 | ||
| 116 | int vsp1_device_get(struct vsp1_device *vsp1); | 117 | int vsp1_device_get(struct vsp1_device *vsp1); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
| 12 | #include <linux/gfp.h> | 12 | #include <linux/gfp.h> |
| 13 | #include <linux/lockdep.h> | ||
| 13 | #include <linux/refcount.h> | 14 | #include <linux/refcount.h> |
| 14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 15 | #include <linux/workqueue.h> | 16 | #include <linux/workqueue.h> |
| @@ -176,6 +177,7 @@ struct vsp1_dl_cmd_pool { · 160 unmodified lines | |||
| 176 | * @bodies: list of extra display list bodies | 177 | * @bodies: list of extra display list bodies |
| 177 | * @pre_cmd: pre command to be issued through extended dl header | 178 | * @pre_cmd: pre command to be issued through extended dl header |
| 178 | * @post_cmd: post command to be issued through extended dl header | 179 | * @post_cmd: post command to be issued through extended dl header |
| 180 | * @allocated: flag to detect double list release | ||
| 179 | * @has_chain: if true, indicates that there's a partition chain | 181 | * @has_chain: if true, indicates that there's a partition chain |
| 180 | * @chain: entry in the display list partition chain | 182 | * @chain: entry in the display list partition chain |
| 181 | * @flags: display list flags, a combination of VSP1_DL_FRAME_END_* | 183 | * @flags: display list flags, a combination of VSP1_DL_FRAME_END_* |
| @@ -194,6 +196,8 @@ struct vsp1_dl_list { · 12 unmodified lines | |||
| 194 | struct vsp1_dl_ext_cmd *pre_cmd; | 196 | struct vsp1_dl_ext_cmd *pre_cmd; |
| 195 | struct vsp1_dl_ext_cmd *post_cmd; | 197 | struct vsp1_dl_ext_cmd *post_cmd; |
| 196 | 198 | ||
| 199 | bool allocated; | ||
| 200 | |||
| 197 | bool has_chain; | 201 | bool has_chain; |
| 198 | struct list_head chain; | 202 | struct list_head chain; |
| 199 | 203 | ||
| @@ -212,6 +216,7 @@ struct vsp1_dl_list { · 12 unmodified lines | |||
| 212 | * @pending: list waiting to be queued to the hardware | 216 | * @pending: list waiting to be queued to the hardware |
| 213 | * @pool: body pool for the display list bodies | 217 | * @pool: body pool for the display list bodies |
| 214 | * @cmdpool: commands pool for extended display list | 218 | * @cmdpool: commands pool for extended display list |
| 219 | * @list_count: number of allocated display lists | ||
| 215 | */ | 220 | */ |
| 216 | struct vsp1_dl_manager { | 221 | struct vsp1_dl_manager { |
| 217 | unsigned int index; | 222 | unsigned int index; |
| @@ -226,6 +231,8 @@ struct vsp1_dl_manager { · 8 unmodified lines | |||
| 226 | 231 | ||
| 227 | struct vsp1_dl_body_pool *pool; | 232 | struct vsp1_dl_body_pool *pool; |
| 228 | struct vsp1_dl_cmd_pool *cmdpool; | 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 | struct vsp1_dl_list *dl = NULL; | 613 | struct vsp1_dl_list *dl = NULL; |
| 607 | unsigned long flags; | 614 | unsigned long flags; |
| 608 | 615 | ||
| 616 | lockdep_assert_not_held(&dlm->lock); | ||
| 617 | |||
| 609 | spin_lock_irqsave(&dlm->lock, flags); | 618 | spin_lock_irqsave(&dlm->lock, flags); |
| 610 | 619 | ||
| 611 | if (!list_empty(&dlm->free)) { | 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 | * display list can assert list_empty() if it is not in a chain. | 626 | * display list can assert list_empty() if it is not in a chain. |
| 618 | */ | 627 | */ |
| 619 | INIT_LIST_HEAD(&dl->chain); | 628 | INIT_LIST_HEAD(&dl->chain); |
| 629 | dl->allocated = true; | ||
| 620 | } | 630 | } |
| 621 | 631 | ||
| 622 | spin_unlock_irqrestore(&dlm->lock, flags); | 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 | if (!dl) | 642 | if (!dl) |
| 633 | return; | 643 | return; |
| 634 | 644 | ||
| 645 | lockdep_assert_held(&dl->dlm->lock); | ||
| 646 | |||
| 635 | /* | 647 | /* |
| 636 | * Release any linked display-lists which were chained for a single | 648 | * Release any linked display-lists which were chained for a single |
| 637 | * hardware operation. | 649 | * hardware operation. |
| @@ -657,6 +669,13 @@ static void __vsp1_dl_list_put(struct vsp1_dl_list *dl) · 19 unmodified lines | |||
| 657 | */ | 669 | */ |
| 658 | dl->body0->num_entries = 0; | 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 | list_add_tail(&dl->list, &dl->dlm->free); | 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 | void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) | 1086 | void vsp1_dlm_reset(struct vsp1_dl_manager *dlm) |
| 1068 | { | 1087 | { |
| 1069 | unsigned long flags; | 1088 | unsigned long flags; |
| 1089 | size_t list_count; | ||
| 1070 | 1090 | ||
| 1071 | spin_lock_irqsave(&dlm->lock, flags); | 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 | __vsp1_dl_list_put(dlm->queued); | 1094 | __vsp1_dl_list_put(dlm->queued); |
| 1075 | __vsp1_dl_list_put(dlm->pending); | 1095 | __vsp1_dl_list_put(dlm->pending); |
| 1076 | 1096 | ||
| 1097 | list_count = list_count_nodes(&dlm->free); | ||
| 1077 | spin_unlock_irqrestore(&dlm->lock, flags); | 1098 | spin_unlock_irqrestore(&dlm->lock, flags); |
| 1078 | 1099 | ||
| 1100 | WARN_ON_ONCE(list_count != dlm->list_count); | ||
| 1101 | |||
| 1079 | dlm->active = NULL; | 1102 | dlm->active = NULL; |
| 1080 | dlm->queued = NULL; | 1103 | dlm->queued = NULL; |
| 1081 | dlm->pending = NULL; | 1104 | dlm->pending = NULL; |
| @@ -1145,6 +1168,8 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, · 63 unmodified lines | |||
| 1145 | list_add_tail(&dl->list, &dlm->free); | 1168 | list_add_tail(&dl->list, &dlm->free); |
| 1146 | } | 1169 | } |
| 1147 | 1170 | ||
| 1171 | dlm->list_count = prealloc; | ||
| 1172 | |||
| 1148 | if (vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) { | 1173 | if (vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) { |
| 1149 | dlm->cmdpool = vsp1_dl_cmd_pool_create(vsp1, | 1174 | dlm->cmdpool = vsp1_dl_cmd_pool_create(vsp1, |
| 1150 | VSP1_EXTCMD_AUTOFLD, prealloc); | 1175 | VSP1_EXTCMD_AUTOFLD, prealloc); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| 11 | #include <linux/dma-mapping.h> | 11 | #include <linux/dma-mapping.h> |
| 12 | #include <linux/export.h> | ||
| 12 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 13 | 14 | ||
| 14 | #include <media/media-entity.h> | 15 | #include <media/media-entity.h> |
| @@ -33,11 +33,13 @@ · 32 unmodified lines | |||
| 33 | #include "vsp1_lif.h" | 33 | #include "vsp1_lif.h" |
| 34 | #include "vsp1_lut.h" | 34 | #include "vsp1_lut.h" |
| 35 | #include "vsp1_pipe.h" | 35 | #include "vsp1_pipe.h" |
| 36 | #include "vsp1_regs.h" | ||
| 36 | #include "vsp1_rwpf.h" | 37 | #include "vsp1_rwpf.h" |
| 37 | #include "vsp1_sru.h" | 38 | #include "vsp1_sru.h" |
| 38 | #include "vsp1_uds.h" | 39 | #include "vsp1_uds.h" |
| 39 | #include "vsp1_uif.h" | 40 | #include "vsp1_uif.h" |
| 40 | #include "vsp1_video.h" | 41 | #include "vsp1_video.h" |
| 42 | #include "vsp1_vspx.h" | ||
| 41 | 43 | ||
| 42 | /* ----------------------------------------------------------------------------- | 44 | /* ----------------------------------------------------------------------------- |
| 43 | * Interrupt Handling | 45 | * Interrupt Handling |
| @@ -490,7 +492,10 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) · 446 unmodified lines | |||
| 490 | 492 | ||
| 491 | ret = media_device_register(mdev); | 493 | ret = media_device_register(mdev); |
| 492 | } else { | 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 | done: | 501 | done: |
| @@ -502,7 +507,9 @@ done: · 5 unmodified lines | |||
| 502 | 507 | ||
| 503 | int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) | 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 | unsigned int timeout; | 511 | unsigned int timeout; |
| 512 | int ret = 0; | ||
| 506 | u32 status; | 513 | u32 status; |
| 507 | 514 | ||
| 508 | status = vsp1_read(vsp1, VI6_STATUS); | 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 | return -ETIMEDOUT; | 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 | static int vsp1_device_init(struct vsp1_device *vsp1) | 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 | .uif_count = 2, | 862 | .uif_count = 2, |
| 852 | .wpf_count = 1, | 863 | .wpf_count = 1, |
| 853 | .num_bru_inputs = 5, | 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 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
| 11 | #include <linux/list.h> | 11 | #include <linux/list.h> |
| 12 | #include <linux/lockdep.h> | ||
| 12 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
| 13 | #include <linux/wait.h> | 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 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; | 475 | struct vsp1_device *vsp1 = pipe->output->entity.vsp1; |
| 475 | 476 | ||
| 477 | lockdep_assert_held(&pipe->irqlock); | ||
| 478 | |||
| 476 | if (pipe->state == VSP1_PIPELINE_STOPPED) { | 479 | if (pipe->state == VSP1_PIPELINE_STOPPED) { |
| 477 | vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index), | 480 | vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index), |
| 478 | VI6_CMD_STRCMD); | 481 | VI6_CMD_STRCMD); |
| @@ -799,6 +799,7 @@ · 798 unmodified lines | |||
| 799 | #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) | 799 | #define VI6_IP_VERSION_MODEL_VSPDL_GEN3 (0x19 << 8) |
| 800 | #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) | 800 | #define VI6_IP_VERSION_MODEL_VSPBS_GEN3 (0x1a << 8) |
| 801 | #define VI6_IP_VERSION_MODEL_VSPD_GEN4 (0x1c << 8) | 801 | #define VI6_IP_VERSION_MODEL_VSPD_GEN4 (0x1c << 8) |
| 802 | #define VI6_IP_VERSION_MODEL_VSPX_GEN4 (0x1d << 8) | ||
| 802 | /* RZ/G2L SoCs have no version register, So use 0x80 as the model version */ | 803 | /* RZ/G2L SoCs have no version register, So use 0x80 as the model version */ |
| 803 | #define VI6_IP_VERSION_MODEL_VSPD_RZG2L (0x80 << 8) | 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 | source "drivers/media/platform/rockchip/rga/Kconfig" | 5 | source "drivers/media/platform/rockchip/rga/Kconfig" |
| 6 | source "drivers/media/platform/rockchip/rkisp1/Kconfig" | 6 | source "drivers/media/platform/rockchip/rkisp1/Kconfig" |
| 7 | source "drivers/media/platform/rockchip/rkvdec/Kconfig" | ||
| @@ -1,3 +1,4 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | obj-y += rga/ | 2 | obj-y += rga/ |
| 3 | obj-y += rkisp1/ | 3 | obj-y += rkisp1/ |
| 4 | obj-y += rkvdec/ | ||
| @@ -415,6 +415,8 @@ struct rkisp1_params { · 414 unmodified lines | |||
| 415 | spinlock_t config_lock; /* locks the buffers list 'params' */ | 415 | spinlock_t config_lock; /* locks the buffers list 'params' */ |
| 416 | struct list_head params; | 416 | struct list_head params; |
| 417 | 417 | ||
| 418 | struct v4l2_ctrl_handler ctrls; | ||
| 419 | |||
| 418 | const struct v4l2_meta_format *metafmt; | 420 | const struct v4l2_meta_format *metafmt; |
| 419 | 421 | ||
| 420 | enum v4l2_quantization quantization; | 422 | enum v4l2_quantization quantization; |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright (C) 2017 Rockchip Electronics Co., Ltd. | 5 | * Copyright (C) 2017 Rockchip Electronics Co., Ltd. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/bitfield.h> | ||
| 8 | #include <linux/math.h> | 9 | #include <linux/math.h> |
| 9 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 10 | 11 | ||
| @@ -60,6 +61,7 @@ union rkisp1_ext_params_config { · 49 unmodified lines | |||
| 60 | struct rkisp1_ext_params_afc_config afc; | 61 | struct rkisp1_ext_params_afc_config afc; |
| 61 | struct rkisp1_ext_params_compand_bls_config compand_bls; | 62 | struct rkisp1_ext_params_compand_bls_config compand_bls; |
| 62 | struct rkisp1_ext_params_compand_curve_config compand_curve; | 63 | struct rkisp1_ext_params_compand_curve_config compand_curve; |
| 64 | struct rkisp1_ext_params_wdr_config wdr; | ||
| 63 | }; | 65 | }; |
| 64 | 66 | ||
| 65 | enum rkisp1_params_formats { | 67 | enum rkisp1_params_formats { |
| @@ -1348,6 +1350,73 @@ rkisp1_compand_compress_config(struct rkisp1_params *params, · 1282 unmodified lines | |||
| 1348 | arg->x); | 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 | static void | 1420 | static void |
| 1352 | rkisp1_isp_isr_other_config(struct rkisp1_params *params, | 1421 | rkisp1_isp_isr_other_config(struct rkisp1_params *params, |
| 1353 | const struct rkisp1_params_cfg *new_params) | 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 | RKISP1_CIF_ISP_COMPAND_CTRL_COMPRESS_ENABLE); | 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 | typedef void (*rkisp1_block_handler)(struct rkisp1_params *params, | 2096 | typedef void (*rkisp1_block_handler)(struct rkisp1_params *params, |
| 2009 | const union rkisp1_ext_params_config *config); | 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 | .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, | 2206 | .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, |
| 2119 | .features = RKISP1_FEATURE_COMPAND, | 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 | static void rkisp1_ext_params_config(struct rkisp1_params *params, | 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 | return vb2_queue_init(q); | 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 | int rkisp1_params_register(struct rkisp1_device *rkisp1) | 2870 | int rkisp1_params_register(struct rkisp1_device *rkisp1) |
| 2740 | { | 2871 | { |
| 2741 | struct rkisp1_params *params = &rkisp1->params; | 2872 | struct rkisp1_params *params = &rkisp1->params; |
| @@ -2763,7 +2894,9 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1) · 21 unmodified lines | |||
| 2763 | vdev->queue = &node->buf_queue; | 2894 | vdev->queue = &node->buf_queue; |
| 2764 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; | 2895 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_META_OUTPUT; |
| 2765 | vdev->vfl_dir = VFL_DIR_TX; | 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 | params->metafmt = &rkisp1_params_formats[RKISP1_PARAMS_FIXED]; | 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 | node->pad.flags = MEDIA_PAD_FL_SOURCE; | 2910 | node->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 2778 | ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); | 2911 | ret = media_entity_pads_init(&vdev->entity, 1, &node->pad); |
| 2779 | if (ret) | 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 | ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | 2921 | ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); |
| 2783 | if (ret) { | 2922 | if (ret) { |
| 2784 | dev_err(rkisp1->dev, | 2923 | dev_err(rkisp1->dev, |
| 2785 | "failed to register %s, ret=%d\n", vdev->name, ret); | 2924 | "failed to register %s, ret=%d\n", vdev->name, ret); |
| 2786 | goto error; | 2925 | goto err_ctrl; |
| 2787 | } | 2926 | } |
| 2788 | 2927 | ||
| 2789 | return 0; | 2928 | return 0; |
| 2790 | 2929 | ||
| 2791 | error: | 2930 | err_ctrl: |
| 2931 | v4l2_ctrl_handler_free(¶ms->ctrls); | ||
| 2932 | err_media: | ||
| 2792 | media_entity_cleanup(&vdev->entity); | 2933 | media_entity_cleanup(&vdev->entity); |
| 2793 | mutex_destroy(&node->vlock); | 2934 | mutex_destroy(&node->vlock); |
| 2794 | return ret; | 2935 | return ret; |
| @@ -2804,6 +2945,7 @@ void rkisp1_params_unregister(struct rkisp1_device *rkisp1) · 9 unmodified lines | |||
| 2804 | return; | 2945 | return; |
| 2805 | 2946 | ||
| 2806 | vb2_video_unregister_device(vdev); | 2947 | vb2_video_unregister_device(vdev); |
| 2948 | v4l2_ctrl_handler_free(¶ms->ctrls); | ||
| 2807 | media_entity_cleanup(&vdev->entity); | 2949 | media_entity_cleanup(&vdev->entity); |
| 2808 | mutex_destroy(&node->vlock); | 2950 | mutex_destroy(&node->vlock); |
| 2809 | } | 2951 | } |
| @@ -703,6 +703,27 @@ · 702 unmodified lines | |||
| 703 | #define RKISP1_CIF_ISP_COMPAND_CTRL_SOFT_RESET_FLAG BIT(2) | 703 | #define RKISP1_CIF_ISP_COMPAND_CTRL_SOFT_RESET_FLAG BIT(2) |
| 704 | #define RKISP1_CIF_ISP_COMPAND_CTRL_BLS_ENABLE BIT(3) | 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 | /* CIF Registers */ | 728 | /* CIF Registers */ |
| 708 | /* =================================================================== */ | 729 | /* =================================================================== */ |
| @@ -1295,82 +1316,12 @@ · 586 unmodified lines | |||
| 1295 | 1316 | ||
| 1296 | #define RKISP1_CIF_ISP_WDR_BASE 0x00002a00 | 1317 | #define RKISP1_CIF_ISP_WDR_BASE 0x00002a00 |
| 1297 | #define RKISP1_CIF_ISP_WDR_CTRL (RKISP1_CIF_ISP_WDR_BASE + 0x00000000) | 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) | 1319 | #define RKISP1_CIF_ISP_WDR_TONECURVE(n) (RKISP1_CIF_ISP_WDR_BASE + 0x00000004 + (n) * 4) |
| 1299 | #define RKISP1_CIF_ISP_WDR_TONECURVE_2 (RKISP1_CIF_ISP_WDR_BASE + 0x00000008) | 1320 | #define RKISP1_CIF_ISP_WDR_TONECURVE_YM(n) (RKISP1_CIF_ISP_WDR_BASE + 0x00000014 + (n) * 4) |
| 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) | ||
| 1335 | #define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) | 1321 | #define RKISP1_CIF_ISP_WDR_OFFSET (RKISP1_CIF_ISP_WDR_BASE + 0x00000098) |
| 1336 | #define RKISP1_CIF_ISP_WDR_DELTAMIN (RKISP1_CIF_ISP_WDR_BASE + 0x0000009c) | 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) | 1323 | #define RKISP1_CIF_ISP_WDR_TONECURVE_SHD(n) (RKISP1_CIF_ISP_WDR_BASE + 0x000000a0 + (n) * 4) |
| 1338 | #define RKISP1_CIF_ISP_WDR_TONECURVE_2_SHD (RKISP1_CIF_ISP_WDR_BASE + 0x000000a4) | 1324 | #define RKISP1_CIF_ISP_WDR_TONECURVE_YM_SHD(n) (RKISP1_CIF_ISP_WDR_BASE + 0x000000b0 + (n) * 4) |
| 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) | ||
| 1374 | 1325 | ||
| 1375 | #define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002c00 | 1326 | #define RKISP1_CIF_ISP_HIST_BASE_V12 0x00002c00 |
| 1376 | #define RKISP1_CIF_ISP_HIST_CTRL_V12 (RKISP1_CIF_ISP_HIST_BASE_V12 + 0x00000000) | 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 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/iommu.h> | ||
| 14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 15 | #include <linux/of.h> | 16 | #include <linux/of.h> |
| 16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| @@ -1055,24 +1056,42 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec) · 1038 unmodified lines | |||
| 1055 | v4l2_device_unregister(&rkvdec->v4l2_dev); | 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 | static irqreturn_t rkvdec_irq_handler(int irq, void *priv) | 1074 | static irqreturn_t rkvdec_irq_handler(int irq, void *priv) |
| 1059 | { | 1075 | { |
| 1060 | struct rkvdec_dev *rkvdec = priv; | 1076 | struct rkvdec_dev *rkvdec = priv; |
| 1077 | struct rkvdec_ctx *ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); | ||
| 1061 | enum vb2_buffer_state state; | 1078 | enum vb2_buffer_state state; |
| 1062 | u32 status; | 1079 | u32 status; |
| 1063 | 1080 | ||
| 1064 | status = readl(rkvdec->regs + RKVDEC_REG_INTERRUPT); | 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 | writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); | 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); | 1084 | if (status & RKVDEC_RDY_STA) { |
| 1073 | rkvdec_job_finish(ctx, state); | 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 | return IRQ_HANDLED; | 1095 | return IRQ_HANDLED; |
| 1077 | } | 1096 | } |
| 1078 | 1097 | ||
| @@ -1140,6 +1159,13 @@ static int rkvdec_probe(struct platform_device *pdev) · 61 unmodified lines | |||
| 1140 | return ret; | 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 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); | 1169 | vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); |
| 1144 | 1170 | ||
| 1145 | irq = platform_get_irq(pdev, 0); | 1171 | irq = platform_get_irq(pdev, 0); |
| @@ -1179,6 +1205,9 @@ static void rkvdec_remove(struct platform_device *pdev) · 33 unmodified lines | |||
| 1179 | rkvdec_v4l2_cleanup(rkvdec); | 1205 | rkvdec_v4l2_cleanup(rkvdec); |
| 1180 | pm_runtime_disable(&pdev->dev); | 1206 | pm_runtime_disable(&pdev->dev); |
| 1181 | pm_runtime_dont_use_autosuspend(&pdev->dev); | 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 | #ifdef CONFIG_PM | 1213 | #ifdef CONFIG_PM |
| @@ -110,6 +110,7 @@ struct rkvdec_dev { · 109 unmodified lines | |||
| 110 | void __iomem *regs; | 110 | void __iomem *regs; |
| 111 | struct mutex vdev_lock; /* serializes ioctls */ | 111 | struct mutex vdev_lock; /* serializes ioctls */ |
| 112 | struct delayed_work watchdog_work; | 112 | struct delayed_work watchdog_work; |
| 113 | struct iommu_domain *empty_domain; | ||
| 113 | }; | 114 | }; |
| 114 | 115 | ||
| 115 | struct rkvdec_ctx { | 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 | static const struct of_device_id fimc_is_i2c_of_match[] = { | 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 | * Sylwester Nawrocki <s.nawrocki@samsung.com> | 6 | * Sylwester Nawrocki <s.nawrocki@samsung.com> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp" | ||
| 10 | |||
| 11 | int fimc_is_register_i2c_driver(void); | 9 | int fimc_is_register_i2c_driver(void); |
| 12 | void fimc_is_unregister_i2c_driver(void); | 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 | if (ret < 0) | 207 | if (ret < 0) |
| 208 | return ret; | 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 | for_each_available_child_of_node(i2c_bus, child) { | 211 | for_each_available_child_of_node(i2c_bus, child) { |
| 212 | ret = fimc_is_parse_sensor_config(is, index, child); | 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 | static int fimc_md_parse_port_node(struct fimc_md *fmd, | 482 | static int fimc_md_parse_port_node(struct fimc_md *fmd, |
| 483 | struct device_node *port) | 483 | struct device_node *port) |
| 484 | { | 484 | { |
| 485 | struct device_node *ep; | ||
| 486 | int ret; | 485 | int ret; |
| 487 | 486 | ||
| 488 | for_each_child_of_node(port, ep) { | 487 | for_each_child_of_node_scoped(port, ep) { |
| 489 | ret = fimc_md_parse_one_endpoint(fmd, ep); | 488 | ret = fimc_md_parse_one_endpoint(fmd, ep); |
| 490 | if (ret < 0) { | 489 | if (ret < 0) |
| 491 | of_node_put(ep); | ||
| 492 | return ret; | 490 | return ret; |
| 493 | } | ||
| 494 | } | 491 | } |
| 495 | 492 | ||
| 496 | return 0; | 493 | return 0; |
| @@ -501,7 +498,6 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) · 4 unmodified lines | |||
| 501 | { | 498 | { |
| 502 | struct device_node *parent = fmd->pdev->dev.of_node; | 499 | struct device_node *parent = fmd->pdev->dev.of_node; |
| 503 | struct device_node *ports = NULL; | 500 | struct device_node *ports = NULL; |
| 504 | struct device_node *node; | ||
| 505 | int ret; | 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 | fmd->num_sensors = 0; | 514 | fmd->num_sensors = 0; |
| 519 | 515 | ||
| 520 | /* Attach sensors linked to MIPI CSI-2 receivers */ | 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 | struct device_node *port; | 518 | struct device_node *port; |
| 523 | 519 | ||
| 524 | if (!of_node_name_eq(node, "csis")) | 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 | ret = fimc_md_parse_port_node(fmd, port); | 527 | ret = fimc_md_parse_port_node(fmd, port); |
| 532 | of_node_put(port); | 528 | of_node_put(port); |
| 533 | if (ret < 0) { | 529 | if (ret < 0) |
| 534 | of_node_put(node); | ||
| 535 | goto cleanup; | 530 | goto cleanup; |
| 536 | } | ||
| 537 | } | 531 | } |
| 538 | 532 | ||
| 539 | /* Attach sensors listed in the parallel-ports node */ | 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 | if (!ports) | 535 | if (!ports) |
| 542 | goto rpm_put; | 536 | goto rpm_put; |
| 543 | 537 | ||
| 544 | for_each_child_of_node(ports, node) { | 538 | for_each_child_of_node_scoped(ports, node) { |
| 545 | ret = fimc_md_parse_port_node(fmd, node); | 539 | ret = fimc_md_parse_port_node(fmd, node); |
| 546 | if (ret < 0) { | 540 | if (ret < 0) |
| 547 | of_node_put(node); | ||
| 548 | goto cleanup; | 541 | goto cleanup; |
| 549 | } | ||
| 550 | } | 542 | } |
| 551 | of_node_put(ports); | 543 | of_node_put(ports); |
| 552 | 544 | ||
| @@ -736,10 +728,9 @@ dev_unlock: · 183 unmodified lines | |||
| 736 | static int fimc_md_register_platform_entities(struct fimc_md *fmd, | 728 | static int fimc_md_register_platform_entities(struct fimc_md *fmd, |
| 737 | struct device_node *parent) | 729 | struct device_node *parent) |
| 738 | { | 730 | { |
| 739 | struct device_node *node; | ||
| 740 | int ret = 0; | 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 | struct platform_device *pdev; | 734 | struct platform_device *pdev; |
| 744 | int plat_entity = -1; | 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 | ret = fimc_md_register_platform_entity(fmd, pdev, | 753 | ret = fimc_md_register_platform_entity(fmd, pdev, |
| 763 | plat_entity); | 754 | plat_entity); |
| 764 | put_device(&pdev->dev); | 755 | put_device(&pdev->dev); |
| 765 | if (ret < 0) { | 756 | if (ret < 0) |
| 766 | of_node_put(node); | ||
| 767 | break; | 757 | break; |
| 768 | } | ||
| 769 | } | 758 | } |
| 770 | 759 | ||
| 771 | return ret; | 760 | return ret; |
| @@ -658,7 +658,7 @@ static irqreturn_t c8sectpfe_error_irq_handler(int irq, void *priv) · 657 unmodified lines | |||
| 658 | static int c8sectpfe_probe(struct platform_device *pdev) | 658 | static int c8sectpfe_probe(struct platform_device *pdev) |
| 659 | { | 659 | { |
| 660 | struct device *dev = &pdev->dev; | 660 | struct device *dev = &pdev->dev; |
| 661 | struct device_node *child, *np = dev->of_node; | 661 | struct device_node *np = dev->of_node; |
| 662 | struct c8sectpfei *fei; | 662 | struct c8sectpfei *fei; |
| 663 | struct resource *res; | 663 | struct resource *res; |
| 664 | int ret, index = 0; | 664 | int ret, index = 0; |
| @@ -742,17 +742,15 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 77 unmodified lines | |||
| 742 | return PTR_ERR(fei->pinctrl); | 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 | struct device_node *i2c_bus; | 746 | struct device_node *i2c_bus; |
| 747 | 747 | ||
| 748 | fei->channel_data[index] = devm_kzalloc(dev, | 748 | fei->channel_data[index] = devm_kzalloc(dev, |
| 749 | sizeof(struct channel_info), | 749 | sizeof(struct channel_info), |
| 750 | GFP_KERNEL); | 750 | GFP_KERNEL); |
| 751 | 751 | ||
| 752 | if (!fei->channel_data[index]) { | 752 | if (!fei->channel_data[index]) |
| 753 | ret = -ENOMEM; | 753 | return -ENOMEM; |
| 754 | goto err_node_put; | ||
| 755 | } | ||
| 756 | 754 | ||
| 757 | tsin = fei->channel_data[index]; | 755 | tsin = fei->channel_data[index]; |
| 758 | 756 | ||
| @@ -761,7 +759,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 761 | ret = of_property_read_u32(child, "tsin-num", &tsin->tsin_id); | 759 | ret = of_property_read_u32(child, "tsin-num", &tsin->tsin_id); |
| 762 | if (ret) { | 760 | if (ret) { |
| 763 | dev_err(&pdev->dev, "No tsin_num found\n"); | 761 | dev_err(&pdev->dev, "No tsin_num found\n"); |
| 764 | goto err_node_put; | 762 | return ret; |
| 765 | } | 763 | } |
| 766 | 764 | ||
| 767 | /* sanity check value */ | 765 | /* sanity check value */ |
| @@ -769,8 +767,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 769 | dev_err(&pdev->dev, | 767 | dev_err(&pdev->dev, |
| 770 | "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", | 768 | "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", |
| 771 | tsin->tsin_id, fei->hw_stats.num_ib); | 769 | tsin->tsin_id, fei->hw_stats.num_ib); |
| 772 | ret = -EINVAL; | 770 | return -EINVAL; |
| 773 | goto err_node_put; | ||
| 774 | } | 771 | } |
| 775 | 772 | ||
| 776 | tsin->invert_ts_clk = of_property_read_bool(child, | 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 | &tsin->dvb_card); | 783 | &tsin->dvb_card); |
| 787 | if (ret) { | 784 | if (ret) { |
| 788 | dev_err(&pdev->dev, "No dvb-card found\n"); | 785 | dev_err(&pdev->dev, "No dvb-card found\n"); |
| 789 | goto err_node_put; | 786 | return ret; |
| 790 | } | 787 | } |
| 791 | 788 | ||
| 792 | i2c_bus = of_parse_phandle(child, "i2c-bus", 0); | 789 | i2c_bus = of_parse_phandle(child, "i2c-bus", 0); |
| 793 | if (!i2c_bus) { | 790 | if (!i2c_bus) { |
| 794 | dev_err(&pdev->dev, "No i2c-bus found\n"); | 791 | dev_err(&pdev->dev, "No i2c-bus found\n"); |
| 795 | ret = -ENODEV; | 792 | return -ENODEV; |
| 796 | goto err_node_put; | ||
| 797 | } | 793 | } |
| 798 | tsin->i2c_adapter = | 794 | tsin->i2c_adapter = |
| 799 | of_find_i2c_adapter_by_node(i2c_bus); | 795 | of_find_i2c_adapter_by_node(i2c_bus); |
| 800 | of_node_put(i2c_bus); | 796 | of_node_put(i2c_bus); |
| 801 | if (!tsin->i2c_adapter) { | 797 | if (!tsin->i2c_adapter) { |
| 802 | dev_err(&pdev->dev, "No i2c adapter found\n"); | 798 | dev_err(&pdev->dev, "No i2c adapter found\n"); |
| 803 | ret = -ENODEV; | 799 | return -ENODEV; |
| 804 | goto err_node_put; | ||
| 805 | } | 800 | } |
| 806 | 801 | ||
| 807 | /* Acquire reset GPIO and activate it */ | 802 | /* Acquire reset GPIO and activate it */ |
| @@ -813,7 +808,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 5 unmodified lines | |||
| 813 | if (ret && ret != -EBUSY) { | 808 | if (ret && ret != -EBUSY) { |
| 814 | dev_err(dev, "Can't request tsin%d reset gpio\n", | 809 | dev_err(dev, "Can't request tsin%d reset gpio\n", |
| 815 | fei->channel_data[index]->tsin_id); | 810 | fei->channel_data[index]->tsin_id); |
| 816 | goto err_node_put; | 811 | return ret; |
| 817 | } | 812 | } |
| 818 | 813 | ||
| 819 | if (!ret) { | 814 | if (!ret) { |
| @@ -855,10 +850,6 @@ static int c8sectpfe_probe(struct platform_device *pdev) · 35 unmodified lines | |||
| 855 | c8sectpfe_debugfs_init(fei); | 850 | c8sectpfe_debugfs_init(fei); |
| 856 | 851 | ||
| 857 | return 0; | 852 | return 0; |
| 858 | |||
| 859 | err_node_put: | ||
| 860 | of_node_put(child); | ||
| 861 | return ret; | ||
| 862 | } | 853 | } |
| 863 | 854 | ||
| 864 | static void c8sectpfe_remove(struct platform_device *pdev) | 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 | static int configure_channels(struct c8sectpfei *fei) | 888 | static int configure_channels(struct c8sectpfei *fei) |
| 898 | { | 889 | { |
| 899 | int index = 0, ret; | 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 | /* iterate round each tsin and configure memdma descriptor and IB hw */ | 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 | ret = configure_memdma_and_inputblock(fei, | 895 | ret = configure_memdma_and_inputblock(fei, |
| 905 | fei->channel_data[index]); | 896 | fei->channel_data[index]); |
| 906 | if (ret) { | 897 | if (ret) { |
| 907 | dev_err(fei->dev, | 898 | dev_err(fei->dev, |
| 908 | "configure_memdma_and_inputblock failed\n"); | 899 | "configure_memdma_and_inputblock failed\n"); |
| 909 | of_node_put(child); | ||
| 910 | goto err_unmap; | 900 | goto err_unmap; |
| 911 | } | 901 | } |
| 912 | index++; | 902 | index++; |
| @@ -619,6 +619,7 @@ static void ti_csi2rx_dma_callback(void *param) · 618 unmodified lines | |||
| 619 | 619 | ||
| 620 | if (ti_csi2rx_start_dma(csi, buf)) { | 620 | if (ti_csi2rx_start_dma(csi, buf)) { |
| 621 | dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); | 621 | dev_err(csi->dev, "Failed to queue the next buffer for DMA\n"); |
| 622 | list_del(&buf->list); | ||
| 622 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); | 623 | vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); |
| 623 | } else { | 624 | } else { |
| 624 | list_move_tail(&buf->list, &dma->submitted); | 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 | q->dev = dmaengine_get_dma_device(csi->dma.chan); | 896 | q->dev = dmaengine_get_dma_device(csi->dma.chan); |
| 896 | q->lock = &csi->mutex; | 897 | q->lock = &csi->mutex; |
| 897 | q->min_queued_buffers = 1; | 898 | q->min_queued_buffers = 1; |
| 899 | q->allow_cache_hints = 1; | ||
| 898 | 900 | ||
| 899 | ret = vb2_queue_init(q); | 901 | ret = vb2_queue_init(q); |
| 900 | if (ret) | 902 | if (ret) |
| @@ -552,38 +552,6 @@ EXPORT_SYMBOL(vpdma_submit_descs); · 551 unmodified lines | |||
| 552 | 552 | ||
| 553 | static void dump_dtd(struct vpdma_dtd *dtd); | 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 | void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, | 555 | void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, |
| 588 | u32 width, u32 height) | 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 | int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, | 222 | int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, |
| 223 | int list_num); | 223 | int list_num); |
| 224 | bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); | 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 | /* VPDMA hardware list funcs */ | 226 | /* VPDMA hardware list funcs */ |
| 230 | int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); | 227 | int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); |
| @@ -323,6 +323,8 @@ struct hantro_postproc_regs { · 322 unmodified lines | |||
| 323 | struct hantro_reg output_fmt; | 323 | struct hantro_reg output_fmt; |
| 324 | struct hantro_reg orig_width; | 324 | struct hantro_reg orig_width; |
| 325 | struct hantro_reg display_width; | 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 | struct hantro_vp9_decoded_buffer_info { | 330 | struct hantro_vp9_decoded_buffer_info { |
| @@ -350,7 +350,7 @@ · 349 unmodified lines | |||
| 350 | #define G1_REG_PP_CONTROL_OUT_WIDTH(v) (((v) << 4) & GENMASK(14, 4)) | 350 | #define G1_REG_PP_CONTROL_OUT_WIDTH(v) (((v) << 4) & GENMASK(14, 4)) |
| 351 | #define G1_REG_PP_MASK1_ORIG_WIDTH G1_SWREG(88) | 351 | #define G1_REG_PP_MASK1_ORIG_WIDTH G1_SWREG(88) |
| 352 | #define G1_REG_PP_ORIG_WIDTH(v) (((v) << 23) & GENMASK(31, 23)) | 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 | #define G1_REG_PP_FUSE G1_SWREG(99) | 354 | #define G1_REG_PP_FUSE G1_SWREG(99) |
| 355 | 355 | ||
| 356 | #endif /* HANTRO_G1_REGS_H_ */ | 356 | #endif /* HANTRO_G1_REGS_H_ */ |
| @@ -325,12 +325,12 @@ static void update_dpb(struct hantro_ctx *ctx) · 324 unmodified lines | |||
| 325 | continue; | 325 | continue; |
| 326 | 326 | ||
| 327 | *cdpb = *ndpb; | 327 | *cdpb = *ndpb; |
| 328 | set_bit(j, used); | 328 | __set_bit(j, used); |
| 329 | break; | 329 | break; |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | if (j == ARRAY_SIZE(ctx->h264_dec.dpb)) | 332 | if (j == ARRAY_SIZE(ctx->h264_dec.dpb)) |
| 333 | set_bit(i, new); | 333 | __set_bit(i, new); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | /* For entries that could not be matched, use remaining free slots. */ | 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 | cdpb = &ctx->h264_dec.dpb[j]; | 350 | cdpb = &ctx->h264_dec.dpb[j]; |
| 351 | *cdpb = *ndpb; | 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 | .input_fmt = {G1_REG_PP_CONTROL, 29, 0x7}, | 49 | .input_fmt = {G1_REG_PP_CONTROL, 29, 0x7}, |
| 50 | .output_fmt = {G1_REG_PP_CONTROL, 26, 0x7}, | 50 | .output_fmt = {G1_REG_PP_CONTROL, 26, 0x7}, |
| 51 | .orig_width = {G1_REG_PP_MASK1_ORIG_WIDTH, 23, 0x1ff}, | 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 | bool hantro_needs_postproc(const struct hantro_ctx *ctx, | 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 | HANTRO_PP_REG_WRITE(vpu, output_height, ctx->dst_fmt.height); | 105 | HANTRO_PP_REG_WRITE(vpu, output_height, ctx->dst_fmt.height); |
| 104 | HANTRO_PP_REG_WRITE(vpu, orig_width, MB_WIDTH(ctx->dst_fmt.width)); | 106 | HANTRO_PP_REG_WRITE(vpu, orig_width, MB_WIDTH(ctx->dst_fmt.width)); |
| 105 | HANTRO_PP_REG_WRITE(vpu, display_width, ctx->dst_fmt.width); | 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 | static int down_scale_factor(struct hantro_ctx *ctx) | 112 | static int down_scale_factor(struct hantro_ctx *ctx) |
| @@ -17,7 +17,6 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | #define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000) | 18 | #define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000) |
| 19 | #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) | 19 | #define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) |
| 20 | #define RK3588_ACLK_MAX_FREQ (300 * 1000 * 1000) | ||
| 21 | 20 | ||
| 22 | #define ROCKCHIP_VPU981_MIN_SIZE 64 | 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 | return 0; | 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 | static int rockchip_vpu_hw_init(struct hantro_dev *vpu) | 456 | static int rockchip_vpu_hw_init(struct hantro_dev *vpu) |
| 465 | { | 457 | { |
| 466 | /* Bump ACLK to max. possible freq. to improve performance. */ | 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 | .codec_ops = rk3588_vpu981_codec_ops, | 813 | .codec_ops = rk3588_vpu981_codec_ops, |
| 822 | .irqs = rk3588_vpu981_irqs, | 814 | .irqs = rk3588_vpu981_irqs, |
| 823 | .num_irqs = ARRAY_SIZE(rk3588_vpu981_irqs), | 815 | .num_irqs = ARRAY_SIZE(rk3588_vpu981_irqs), |
| 824 | .init = rk3588_vpu981_hw_init, | ||
| 825 | .clk_names = rk3588_vpu981_vpu_clk_names, | 816 | .clk_names = rk3588_vpu981_vpu_clk_names, |
| 826 | .num_clocks = ARRAY_SIZE(rk3588_vpu981_vpu_clk_names) | 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 | static int xvip_graph_dma_init(struct xvip_composite_device *xdev) | 450 | static int xvip_graph_dma_init(struct xvip_composite_device *xdev) |
| 451 | { | 451 | { |
| 452 | struct device_node *ports; | 452 | struct device_node *ports; |
| 453 | struct device_node *port; | ||
| 454 | int ret = 0; | 453 | int ret = 0; |
| 455 | 454 | ||
| 456 | ports = of_get_child_by_name(xdev->dev->of_node, "ports"); | 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 | return -EINVAL; | 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 | ret = xvip_graph_dma_init_one(xdev, port); | 462 | ret = xvip_graph_dma_init_one(xdev, port); |
| 464 | if (ret) { | 463 | if (ret) |
| 465 | of_node_put(port); | ||
| 466 | break; | 464 | break; |
| 467 | } | ||
| 468 | } | 465 | } |
| 469 | 466 | ||
| 470 | of_node_put(ports); | 467 | of_node_put(ports); |
| @@ -21,13 +21,12 @@ · 20 unmodified lines | |||
| 21 | #define IR_SPI_DRIVER_NAME "ir-spi" | 21 | #define IR_SPI_DRIVER_NAME "ir-spi" |
| 22 | 22 | ||
| 23 | #define IR_SPI_DEFAULT_FREQUENCY 38000 | 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 | struct ir_spi_data { | 26 | struct ir_spi_data { |
| 27 | u32 freq; | 27 | u32 freq; |
| 28 | bool negated; | 28 | bool negated; |
| 29 | 29 | ||
| 30 | u16 tx_buf[IR_SPI_MAX_BUFSIZE]; | ||
| 31 | u16 pulse; | 30 | u16 pulse; |
| 32 | u16 space; | 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 | unsigned int len = 0; | 42 | unsigned int len = 0; |
| 44 | struct ir_spi_data *idata = dev->priv; | 43 | struct ir_spi_data *idata = dev->priv; |
| 45 | struct spi_transfer xfer; | 44 | struct spi_transfer xfer; |
| 45 | u16 *tx_buf; | ||
| 46 | 46 | ||
| 47 | /* convert the pulse/space signal to raw binary signal */ | 47 | /* convert the pulse/space signal to raw binary signal */ |
| 48 | for (i = 0; i < count; i++) { | 48 | for (i = 0; i < count; i++) { |
| 49 | unsigned int periods; | 49 | buffer[i] = DIV_ROUND_CLOSEST_ULL((u64)buffer[i] * idata->freq, |
| 50 | int j; | 50 | 1000000); |
| 51 | u16 val; | 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) | 58 | len = 0; |
| 56 | return -EINVAL; | 59 | for (i = 0; i < count; i++) { |
| 60 | int j; | ||
| 61 | u16 val; | ||
| 57 | 62 | ||
| 58 | /* | 63 | /* |
| 59 | * The first value in buffer is a pulse, so that 0, 2, 4, ... | 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 | * contain a space duration. | 66 | * contain a space duration. |
| 62 | */ | 67 | */ |
| 63 | val = (i % 2) ? idata->space : idata->pulse; | 68 | val = (i % 2) ? idata->space : idata->pulse; |
| 64 | for (j = 0; j < periods; j++) | 69 | for (j = 0; j < buffer[i]; j++) |
| 65 | idata->tx_buf[len++] = val; | 70 | tx_buf[len++] = val; |
| 66 | } | 71 | } |
| 67 | 72 | ||
| 68 | memset(&xfer, 0, sizeof(xfer)); | 73 | memset(&xfer, 0, sizeof(xfer)); |
| 69 | 74 | ||
| 70 | xfer.speed_hz = idata->freq * 16; | 75 | xfer.speed_hz = idata->freq * IR_SPI_BITS_PER_PULSE; |
| 71 | xfer.len = len * sizeof(*idata->tx_buf); | 76 | xfer.len = len * sizeof(*tx_buf); |
| 72 | xfer.tx_buf = idata->tx_buf; | 77 | xfer.tx_buf = tx_buf; |
| 73 | 78 | ||
| 74 | ret = regulator_enable(idata->regulator); | 79 | ret = regulator_enable(idata->regulator); |
| 75 | if (ret) | 80 | if (ret) |
| 76 | return ret; | 81 | goto err_free_tx_buf; |
| 77 | 82 | ||
| 78 | ret = spi_sync_transfer(idata->spi, &xfer, 1); | 83 | ret = spi_sync_transfer(idata->spi, &xfer, 1); |
| 79 | if (ret) | 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 | regulator_disable(idata->regulator); | 87 | regulator_disable(idata->regulator); |
| 83 | 88 | ||
| 89 | err_free_tx_buf: | ||
| 90 | |||
| 91 | kfree(tx_buf); | ||
| 92 | |||
| 84 | return ret ? ret : count; | 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 | if (!carrier) | 100 | if (!carrier) |
| 92 | return -EINVAL; | 101 | return -EINVAL; |
| 93 | 102 | ||
| 103 | if (carrier > idata->spi->max_speed_hz / IR_SPI_BITS_PER_PULSE) | ||
| 104 | return -EINVAL; | ||
| 105 | |||
| 94 | idata->freq = carrier; | 106 | idata->freq = carrier; |
| 95 | 107 | ||
| 96 | return 0; | 108 | return 0; |
| @@ -244,7 +244,8 @@ static const struct v4l2_ctrl_config vivid_ctrl_u8_pixel_array = { · 243 unmodified lines | |||
| 244 | .min = 0x00, | 244 | .min = 0x00, |
| 245 | .max = 0xff, | 245 | .max = 0xff, |
| 246 | .step = 1, | 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 | static const struct v4l2_ctrl_config vivid_ctrl_s32_array = { | 251 | static const struct v4l2_ctrl_config vivid_ctrl_s32_array = { |
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. | 5 | * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/bitops.h> | ||
| 8 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/ktime.h> | 11 | #include <linux/ktime.h> |
| @@ -165,12 +166,7 @@ static const u8 vivid_cc_sequence2[30] = { · 154 unmodified lines | |||
| 165 | 166 | ||
| 166 | static u8 calc_parity(u8 val) | 167 | static u8 calc_parity(u8 val) |
| 167 | { | 168 | { |
| 168 | unsigned i; | 169 | return val | (parity8(val) ? 0 : 0x80); |
| 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); | ||
| 174 | } | 170 | } |
| 175 | 171 | ||
| 176 | static void vivid_vbi_gen_set_time_of_day(u8 *packet) | 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 | if (keep_controls) | 454 | if (keep_controls) |
| 455 | return; | 455 | return; |
| 456 | 456 | ||
| 457 | dims[0] = roundup(dev->src_rect.width, PIXEL_ARRAY_DIV); | 457 | dims[0] = DIV_ROUND_UP(dev->src_rect.height, PIXEL_ARRAY_DIV); |
| 458 | dims[1] = roundup(dev->src_rect.height, PIXEL_ARRAY_DIV); | 458 | dims[1] = DIV_ROUND_UP(dev->src_rect.width, PIXEL_ARRAY_DIV); |
| 459 | v4l2_ctrl_modify_dimensions(dev->pixel_array, dims); | 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 | const struct ihex_binrec *rec; | 227 | const struct ihex_binrec *rec; |
| 228 | const struct firmware *fw; | 228 | const struct firmware *fw; |
| 229 | u8 *firmware_buf; | 229 | u8 *firmware_buf; |
| 230 | int len; | ||
| 230 | 231 | ||
| 231 | ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, | 232 | ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, |
| 232 | &gspca_dev->dev->dev); | 233 | &gspca_dev->dev->dev); |
| @@ -241,9 +242,14 @@ static int sd_init(struct gspca_dev *gspca_dev) · 8 unmodified lines | |||
| 241 | goto exit; | 242 | goto exit; |
| 242 | } | 243 | } |
| 243 | for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) { | 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 | ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, | 251 | ret = vicam_control_msg(gspca_dev, 0xff, 0, 0, firmware_buf, |
| 246 | be16_to_cpu(rec->len)); | 252 | len); |
| 247 | if (ret < 0) | 253 | if (ret < 0) |
| 248 | break; | 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 | else | 124 | else |
| 125 | retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, | 125 | retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, |
| 126 | msgs[0].len); | 126 | msgs[0].len); |
| 127 | } else if (num == 2) { | 127 | } else { |
| 128 | if (msgs[0].addr != msgs[1].addr) { | 128 | /* do write-then-read */ |
| 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 | */ | ||
| 146 | retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, | 129 | retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, |
| 147 | msgs[1].buf, msgs[1].len); | 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 | mutex_unlock(&dev->i2c_mutex); | 133 | mutex_unlock(&dev->i2c_mutex); |
| 154 | 134 | ||
| 155 | return retval ? retval : num; | 135 | return retval ? retval : num; |
| @@ -165,10 +145,16 @@ static const struct i2c_algorithm hdpvr_algo = { · 9 unmodified lines | |||
| 165 | .functionality = hdpvr_functionality, | 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 | static const struct i2c_adapter hdpvr_i2c_adapter_template = { | 153 | static const struct i2c_adapter hdpvr_i2c_adapter_template = { |
| 169 | .name = "Hauppauge HD PVR I2C", | 154 | .name = "Hauppauge HD PVR I2C", |
| 170 | .owner = THIS_MODULE, | 155 | .owner = THIS_MODULE, |
| 171 | .algo = &hdpvr_algo, | 156 | .algo = &hdpvr_algo, |
| 157 | .quirks = &hdpvr_quirks, | ||
| 172 | }; | 158 | }; |
| 173 | 159 | ||
| 174 | static int hdpvr_activate_ir(struct hdpvr_device *dev) | 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 | if (params) { | 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 | usbtv->width = params->cap_width; | 80 | usbtv->width = params->cap_width; |
| 77 | usbtv->height = params->cap_height; | 81 | usbtv->height = params->cap_height; |
| 78 | usbtv->n_chunks = usbtv->width * usbtv->height | 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 | return ~0; | 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 | static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain, | 1492 | static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain, |
| 1487 | struct uvc_control *ctrl, | 1493 | struct uvc_control *ctrl, |
| 1488 | struct uvc_control_mapping *mapping, | 1494 | struct uvc_control_mapping *mapping, |
| 1489 | struct v4l2_query_ext_ctrl *v4l2_ctrl) | 1495 | struct v4l2_query_ext_ctrl *v4l2_ctrl) |
| 1490 | { | 1496 | { |
| 1491 | if (!ctrl->cached) { | 1497 | if (!ctrl->cached) { |
| 1492 | int ret = uvc_ctrl_populate_cache(chain, ctrl); | 1498 | unsigned int retries; |
| 1493 | if (ret < 0) | 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 | return ret; | 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 | struct uvc_control_mapping *master_map = NULL; | 1582 | struct uvc_control_mapping *master_map = NULL; |
| 1569 | struct uvc_control *master_ctrl = NULL; | 1583 | struct uvc_control *master_ctrl = NULL; |
| 1584 | int ret; | ||
| 1570 | 1585 | ||
| 1571 | memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); | 1586 | memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl)); |
| 1572 | v4l2_ctrl->id = mapping->id; | 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 | __uvc_find_control(ctrl->entity, mapping->master_id, | 1602 | __uvc_find_control(ctrl->entity, mapping->master_id, |
| 1588 | &master_map, &master_ctrl, 0, 0); | 1603 | &master_map, &master_ctrl, 0, 0); |
| 1589 | if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { | 1604 | if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) { |
| 1605 | unsigned int retries; | ||
| 1590 | s32 val; | 1606 | s32 val; |
| 1591 | int ret; | 1607 | int ret; |
| 1592 | 1608 | ||
| 1593 | if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) | 1609 | if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map))) |
| 1594 | return -EIO; | 1610 | return -EIO; |
| 1595 | 1611 | ||
| 1596 | ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val); | 1612 | for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) { |
| 1597 | if (ret < 0) | 1613 | ret = __uvc_ctrl_get(chain, master_ctrl, master_map, |
| 1598 | return ret; | 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) | 1621 | if (ret == -EIO) { |
| 1601 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; | 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 | v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping); | 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 | return 0; | 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 | int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | 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 | uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes); | 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, | 1854 | static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) |
| 1816 | struct uvc_fh *new_handle) | ||
| 1817 | { | 1855 | { |
| 1818 | lockdep_assert_held(&handle->chain->ctrl_mutex); | 1856 | int ret; |
| 1819 | |||
| 1820 | if (new_handle) { | ||
| 1821 | int ret; | ||
| 1822 | 1857 | ||
| 1823 | if (ctrl->handle) | 1858 | lockdep_assert_held(&handle->chain->ctrl_mutex); |
| 1824 | dev_warn_ratelimited(&handle->stream->dev->udev->dev, | ||
| 1825 | "UVC non compliance: Setting an async control with a pending operation."); | ||
| 1826 | 1859 | ||
| 1827 | if (new_handle == ctrl->handle) | 1860 | if (ctrl->handle) { |
| 1828 | return 0; | 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) { | 1864 | if (ctrl->handle == 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++; | ||
| 1836 | return 0; | 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; | 1867 | WARN_ON(!ctrl->handle->pending_async_ctrls); |
| 1844 | 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 | return 0; | 1872 | return 0; |
| 1846 | } | 1873 | } |
| 1847 | 1874 | ||
| 1848 | /* Cannot clear the handle for a control not owned by us.*/ | 1875 | ret = uvc_pm_get(handle->chain->dev); |
| 1849 | if (WARN_ON(ctrl->handle != handle)) | 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 | return -EINVAL; | 1890 | return -EINVAL; |
| 1891 | } | ||
| 1851 | 1892 | ||
| 1893 | ctrl->handle->pending_async_ctrls--; | ||
| 1894 | uvc_pm_put(ctrl->handle->chain->dev); | ||
| 1852 | ctrl->handle = NULL; | 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 | return 0; | 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 | handle = ctrl->handle; | 1911 | handle = ctrl->handle; |
| 1873 | if (handle) | 1912 | if (handle) |
| 1874 | uvc_ctrl_set_handle(handle, ctrl, NULL); | 1913 | uvc_ctrl_clear_handle(ctrl); |
| 1875 | 1914 | ||
| 1876 | list_for_each_entry(mapping, &ctrl->info.mappings, list) { | 1915 | list_for_each_entry(mapping, &ctrl->info.mappings, list) { |
| 1877 | s32 value; | 1916 | s32 value; |
| @@ -2033,18 +2072,24 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) · 155 unmodified lines | |||
| 2033 | goto done; | 2072 | goto done; |
| 2034 | } | 2073 | } |
| 2035 | 2074 | ||
| 2036 | list_add_tail(&sev->node, &mapping->ev_subs); | ||
| 2037 | if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { | 2075 | if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) { |
| 2038 | struct v4l2_event ev; | 2076 | struct v4l2_event ev; |
| 2039 | u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; | 2077 | u32 changes = V4L2_EVENT_CTRL_CH_FLAGS; |
| 2040 | s32 val = 0; | 2078 | s32 val = 0; |
| 2041 | 2079 | ||
| 2080 | ret = uvc_pm_get(handle->chain->dev); | ||
| 2081 | if (ret) | ||
| 2082 | goto done; | ||
| 2083 | |||
| 2042 | if (uvc_ctrl_mapping_is_compound(mapping) || | 2084 | if (uvc_ctrl_mapping_is_compound(mapping) || |
| 2043 | __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) | 2085 | __uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0) |
| 2044 | changes |= V4L2_EVENT_CTRL_CH_VALUE; | 2086 | changes |= V4L2_EVENT_CTRL_CH_VALUE; |
| 2045 | 2087 | ||
| 2046 | uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, | 2088 | uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val, |
| 2047 | changes); | 2089 | changes); |
| 2090 | |||
| 2091 | uvc_pm_put(handle->chain->dev); | ||
| 2092 | |||
| 2048 | /* | 2093 | /* |
| 2049 | * Mark the queue as active, allowing this initial event to be | 2094 | * Mark the queue as active, allowing this initial event to be |
| 2050 | * accepted. | 2095 | * accepted. |
| @@ -2053,6 +2098,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) · 2 unmodified lines | |||
| 2053 | v4l2_event_queue_fh(sev->fh, &ev); | 2098 | v4l2_event_queue_fh(sev->fh, &ev); |
| 2054 | } | 2099 | } |
| 2055 | 2100 | ||
| 2101 | list_add_tail(&sev->node, &mapping->ev_subs); | ||
| 2102 | |||
| 2056 | done: | 2103 | done: |
| 2057 | mutex_unlock(&handle->chain->ctrl_mutex); | 2104 | mutex_unlock(&handle->chain->ctrl_mutex); |
| 2058 | return ret; | 2105 | return ret; |
| @@ -2161,7 +2208,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, · 102 unmodified lines | |||
| 2161 | 2208 | ||
| 2162 | if (!rollback && handle && !ret && | 2209 | if (!rollback && handle && !ret && |
| 2163 | ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS) | 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 | if (ret < 0 && !rollback) { | 2213 | if (ret < 0 && !rollback) { |
| 2167 | if (err_ctrl) | 2214 | if (err_ctrl) |
| @@ -3271,7 +3318,7 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) · 1103 unmodified lines | |||
| 3271 | for (unsigned int i = 0; i < entity->ncontrols; ++i) { | 3318 | for (unsigned int i = 0; i < entity->ncontrols; ++i) { |
| 3272 | if (entity->controls[i].handle != handle) | 3319 | if (entity->controls[i].handle != handle) |
| 3273 | continue; | 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 | u8 ftype; | 344 | u8 ftype; |
| 345 | int ret; | 345 | int ret; |
| 346 | 346 | ||
| 347 | if (buflen < 4) | ||
| 348 | return -EINVAL; | ||
| 349 | |||
| 347 | format->type = buffer[2]; | 350 | format->type = buffer[2]; |
| 348 | format->index = buffer[3]; | 351 | format->index = buffer[3]; |
| 349 | format->frames = frames; | 352 | format->frames = frames; |
| @@ -1866,7 +1869,7 @@ static int uvc_scan_device(struct uvc_device *dev) · 1516 unmodified lines | |||
| 1866 | 1869 | ||
| 1867 | if (list_empty(&dev->chains)) { | 1870 | if (list_empty(&dev->chains)) { |
| 1868 | dev_info(&dev->udev->dev, "No valid video chain found.\n"); | 1871 | dev_info(&dev->udev->dev, "No valid video chain found.\n"); |
| 1869 | return -1; | 1872 | return -ENODEV; |
| 1870 | } | 1873 | } |
| 1871 | 1874 | ||
| 1872 | /* Add GPIO entity to the first chain. */ | 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 | if (!video_is_registered(&stream->vdev)) | 1961 | if (!video_is_registered(&stream->vdev)) |
| 1959 | continue; | 1962 | continue; |
| 1960 | 1963 | ||
| 1961 | /* | 1964 | vb2_video_unregister_device(&stream->vdev); |
| 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 | */ | ||
| 1986 | vb2_video_unregister_device(&stream->meta.vdev); | 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 | vdev->ioctl_ops = ioctl_ops; | 2009 | vdev->ioctl_ops = ioctl_ops; |
| 2031 | vdev->release = uvc_release; | 2010 | vdev->release = uvc_release; |
| 2032 | vdev->prio = &stream->chain->prio; | 2011 | vdev->prio = &stream->chain->prio; |
| 2012 | vdev->queue = &queue->queue; | ||
| 2013 | vdev->lock = &queue->mutex; | ||
| 2033 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | 2014 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) |
| 2034 | vdev->vfl_dir = VFL_DIR_TX; | 2015 | vdev->vfl_dir = VFL_DIR_TX; |
| 2035 | else | 2016 | else |
| @@ -2239,7 +2220,6 @@ static int uvc_probe(struct usb_interface *intf, · 203 unmodified lines | |||
| 2239 | /* Parse the Video Class control descriptor. */ | 2220 | /* Parse the Video Class control descriptor. */ |
| 2240 | ret = uvc_parse_control(dev); | 2221 | ret = uvc_parse_control(dev); |
| 2241 | if (ret < 0) { | 2222 | if (ret < 0) { |
| 2242 | ret = -ENODEV; | ||
| 2243 | uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); | 2223 | uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); |
| 2244 | goto error; | 2224 | goto error; |
| 2245 | } | 2225 | } |
| @@ -2275,22 +2255,19 @@ static int uvc_probe(struct usb_interface *intf, · 29 unmodified lines | |||
| 2275 | goto error; | 2255 | goto error; |
| 2276 | 2256 | ||
| 2277 | /* Scan the device for video chains. */ | 2257 | /* Scan the device for video chains. */ |
| 2278 | if (uvc_scan_device(dev) < 0) { | 2258 | ret = uvc_scan_device(dev); |
| 2279 | ret = -ENODEV; | 2259 | if (ret < 0) |
| 2280 | goto error; | 2260 | goto error; |
| 2281 | } | ||
| 2282 | 2261 | ||
| 2283 | /* Initialize controls. */ | 2262 | /* Initialize controls. */ |
| 2284 | if (uvc_ctrl_init_device(dev) < 0) { | 2263 | ret = uvc_ctrl_init_device(dev); |
| 2285 | ret = -ENODEV; | 2264 | if (ret < 0) |
| 2286 | goto error; | 2265 | goto error; |
| 2287 | } | ||
| 2288 | 2266 | ||
| 2289 | /* Register video device nodes. */ | 2267 | /* Register video device nodes. */ |
| 2290 | if (uvc_register_chains(dev) < 0) { | 2268 | ret = uvc_register_chains(dev); |
| 2291 | ret = -ENODEV; | 2269 | if (ret < 0) |
| 2292 | goto error; | 2270 | goto error; |
| 2293 | } | ||
| 2294 | 2271 | ||
| 2295 | #ifdef CONFIG_MEDIA_CONTROLLER | 2272 | #ifdef CONFIG_MEDIA_CONTROLLER |
| 2296 | /* Register the media device node */ | 2273 | /* Register the media device node */ |
| @@ -2316,6 +2293,13 @@ static int uvc_probe(struct usb_interface *intf, · 19 unmodified lines | |||
| 2316 | goto error; | 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 | if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) | 2303 | if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME) |
| 2320 | udev->quirks &= ~USB_QUIRK_RESET_RESUME; | 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 | list_for_each_entry(stream, &dev->streams, list) { | 2382 | list_for_each_entry(stream, &dev->streams, list) { |
| 2399 | if (stream->intf == intf) { | 2383 | if (stream->intf == intf) { |
| 2400 | ret = uvc_video_resume(stream, reset); | 2384 | ret = uvc_video_resume(stream, reset); |
| 2401 | if (ret < 0) | 2385 | if (ret < 0) { |
| 2402 | uvc_queue_streamoff(&stream->queue, | 2386 | mutex_lock(&stream->queue.mutex); |
| 2403 | stream->queue.queue.type); | 2387 | vb2_streamoff(&stream->queue.queue, |
| 2388 | stream->queue.queue.type); | ||
| 2389 | mutex_unlock(&stream->queue.mutex); | ||
| 2390 | } | ||
| 2404 | return ret; | 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 | * Sort these by vendor/product ID. | 2501 | * Sort these by vendor/product ID. |
| 2515 | */ | 2502 | */ |
| 2516 | static const struct usb_device_id uvc_ids[] = { | 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 | /* Quanta ACER HD User Facing */ | 2513 | /* Quanta ACER HD User Facing */ |
| 2518 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 2514 | { .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
| 2519 | | USB_DEVICE_ID_MATCH_INT_INFO, | 2515 | | USB_DEVICE_ID_MATCH_INT_INFO, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
| 11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 12 | #include <linux/usb.h> | 12 | #include <linux/usb.h> |
| 13 | #include <linux/usb/uvc.h> | ||
| 13 | #include <linux/videodev2.h> | 14 | #include <linux/videodev2.h> |
| 14 | 15 | ||
| 15 | #include <media/v4l2-ioctl.h> | 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 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); | 64 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); |
| 64 | struct uvc_device *dev = stream->dev; | 65 | struct uvc_device *dev = stream->dev; |
| 65 | struct v4l2_meta_format *fmt = &format->fmt.meta; | 66 | struct v4l2_meta_format *fmt = &format->fmt.meta; |
| 66 | u32 fmeta = fmt->dataformat; | 67 | u32 fmeta = V4L2_META_FMT_UVC; |
| 67 | 68 | ||
| 68 | if (format->type != vfh->vdev->queue->type) | 69 | if (format->type != vfh->vdev->queue->type) |
| 69 | return -EINVAL; | 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 | memset(fmt, 0, sizeof(*fmt)); | 78 | memset(fmt, 0, sizeof(*fmt)); |
| 72 | 79 | ||
| 73 | fmt->dataformat = fmeta == dev->info->meta_format | 80 | fmt->dataformat = fmeta; |
| 74 | ? fmeta : V4L2_META_FMT_UVC; | ||
| 75 | fmt->buffersize = UVC_METADATA_BUF_SIZE; | 81 | fmt->buffersize = UVC_METADATA_BUF_SIZE; |
| 76 | 82 | ||
| 77 | return 0; | 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 | mutex_lock(&stream->mutex); | 103 | mutex_lock(&stream->mutex); |
| 98 | 104 | ||
| 99 | if (uvc_queue_allocated(&stream->queue)) | 105 | if (vb2_is_busy(&stream->meta.queue.queue)) |
| 100 | ret = -EBUSY; | 106 | ret = -EBUSY; |
| 101 | else | 107 | else |
| 102 | stream->meta.format = fmt->dataformat; | 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 | struct v4l2_fh *vfh = file->private_data; | 118 | struct v4l2_fh *vfh = file->private_data; |
| 113 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); | 119 | struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); |
| 114 | struct uvc_device *dev = stream->dev; | 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 || | 126 | if (i >= dev->nmeta_formats) |
| 118 | index > 1U || (index && !dev->info->meta_format)) | ||
| 119 | return -EINVAL; | 127 | return -EINVAL; |
| 120 | 128 | ||
| 121 | memset(fdesc, 0, sizeof(*fdesc)); | 129 | memset(fdesc, 0, sizeof(*fdesc)); |
| 122 | 130 | ||
| 123 | fdesc->type = vfh->vdev->queue->type; | 131 | fdesc->type = vfh->vdev->queue->type; |
| 124 | fdesc->index = index; | 132 | fdesc->index = i; |
| 125 | fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC; | 133 | fdesc->pixelformat = dev->meta_formats[i]; |
| 126 | 134 | ||
| 127 | return 0; | 135 | return 0; |
| 128 | } | 136 | } |
| @@ -156,6 +164,71 @@ static const struct v4l2_file_operations uvc_meta_fops = { · 27 unmodified lines | |||
| 156 | .mmap = vb2_fop_mmap, | 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 | int uvc_meta_register(struct uvc_streaming *stream) | 232 | int uvc_meta_register(struct uvc_streaming *stream) |
| 160 | { | 233 | { |
| 161 | struct uvc_device *dev = stream->dev; | 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 | stream->meta.format = V4L2_META_FMT_UVC; | 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 | return uvc_register_video_device(dev, stream, vdev, queue, | 240 | return uvc_register_video_device(dev, stream, vdev, queue, |
| 174 | V4L2_BUF_TYPE_META_CAPTURE, | 241 | V4L2_BUF_TYPE_META_CAPTURE, |
| 175 | &uvc_meta_fops, &uvc_meta_ioctl_ops); | 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 | * This function must be called with the queue spinlock held. | 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, | 45 | static void __uvc_queue_return_buffers(struct uvc_video_queue *queue, |
| 46 | enum uvc_buffer_state state) | 46 | enum uvc_buffer_state state) |
| 47 | { | 47 | { |
| 48 | enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR | 48 | enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR |
| 49 | ? VB2_BUF_STATE_ERROR | 49 | ? VB2_BUF_STATE_ERROR |
| 50 | : VB2_BUF_STATE_QUEUED; | 50 | : VB2_BUF_STATE_QUEUED; |
| 51 | 51 | ||
| 52 | lockdep_assert_held(&queue->irqlock); | ||
| 53 | |||
| 52 | while (!list_empty(&queue->irqqueue)) { | 54 | while (!list_empty(&queue->irqqueue)) { |
| 53 | struct uvc_buffer *buf = list_first_entry(&queue->irqqueue, | 55 | struct uvc_buffer *buf = list_first_entry(&queue->irqqueue, |
| 54 | struct uvc_buffer, | 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 | * videobuf2 queue operations | 73 | * videobuf2 queue operations |
| 64 | */ | 74 | */ |
| @@ -157,7 +167,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb) · 92 unmodified lines | |||
| 157 | uvc_video_clock_update(stream, vbuf, buf); | 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 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); | 172 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); |
| 163 | struct uvc_streaming *stream = uvc_queue_to_stream(queue); | 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 | lockdep_assert_irqs_enabled(); | 176 | lockdep_assert_irqs_enabled(); |
| 167 | 177 | ||
| 178 | ret = uvc_pm_get(stream->dev); | ||
| 179 | if (ret) | ||
| 180 | return ret; | ||
| 181 | |||
| 168 | queue->buf_used = 0; | 182 | queue->buf_used = 0; |
| 169 | 183 | ||
| 170 | ret = uvc_video_start_streaming(stream); | 184 | ret = uvc_video_start_streaming(stream); |
| 171 | if (ret == 0) | 185 | if (ret == 0) |
| 172 | return 0; | 186 | return 0; |
| 173 | 187 | ||
| 174 | spin_lock_irq(&queue->irqlock); | 188 | uvc_pm_put(stream->dev); |
| 189 | |||
| 175 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); | 190 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); |
| 176 | spin_unlock_irq(&queue->irqlock); | ||
| 177 | 191 | ||
| 178 | return ret; | 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 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); | 197 | struct uvc_video_queue *queue = vb2_get_drv_priv(vq); |
| 198 | struct uvc_streaming *stream = uvc_queue_to_stream(queue); | ||
| 184 | 199 | ||
| 185 | lockdep_assert_irqs_enabled(); | 200 | lockdep_assert_irqs_enabled(); |
| 186 | 201 | ||
| 187 | if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) | 202 | uvc_video_stop_streaming(uvc_queue_to_stream(queue)); |
| 188 | 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 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); | 215 | uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); |
| 192 | spin_unlock_irq(&queue->irqlock); | ||
| 193 | } | 216 | } |
| 194 | 217 | ||
| 195 | static const struct vb2_ops uvc_queue_qops = { | 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 | .buf_prepare = uvc_buffer_prepare, | 220 | .buf_prepare = uvc_buffer_prepare, |
| 198 | .buf_queue = uvc_buffer_queue, | 221 | .buf_queue = uvc_buffer_queue, |
| 199 | .buf_finish = uvc_buffer_finish, | 222 | .buf_finish = uvc_buffer_finish, |
| 200 | .start_streaming = uvc_start_streaming, | 223 | .start_streaming = uvc_start_streaming_video, |
| 201 | .stop_streaming = uvc_stop_streaming, | 224 | .stop_streaming = uvc_stop_streaming_video, |
| 202 | }; | 225 | }; |
| 203 | 226 | ||
| 204 | static const struct vb2_ops uvc_meta_queue_qops = { | 227 | static const struct vb2_ops uvc_meta_queue_qops = { |
| 205 | .queue_setup = uvc_queue_setup, | 228 | .queue_setup = uvc_queue_setup, |
| 206 | .buf_prepare = uvc_buffer_prepare, | 229 | .buf_prepare = uvc_buffer_prepare, |
| 207 | .buf_queue = uvc_buffer_queue, | 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 | int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) | 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 | return 0; | 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 | * Cancel the video buffers queue. | 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 | unsigned long flags; | 291 | unsigned long flags; |
| 407 | 292 | ||
| 408 | spin_lock_irqsave(&queue->irqlock, flags); | 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 | * This must be protected by the irqlock spinlock to avoid race | 296 | * This must be protected by the irqlock spinlock to avoid race |
| 412 | * conditions between uvc_buffer_queue and the disconnection event that | 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 | usb_autopm_put_interface(dev->intf); | 47 | usb_autopm_put_interface(dev->intf); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | static int uvc_acquire_privileges(struct uvc_fh *handle); | ||
| 51 | |||
| 52 | static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, | 50 | static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain, |
| 53 | struct uvc_control_mapping *map, | 51 | struct uvc_control_mapping *map, |
| 54 | const struct uvc_xu_control_mapping *xmap) | 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 | const struct uvc_frame *frame; | 434 | const struct uvc_frame *frame; |
| 437 | int ret; | 435 | int ret; |
| 438 | 436 | ||
| 439 | ret = uvc_acquire_privileges(handle); | ||
| 440 | if (ret < 0) | ||
| 441 | return ret; | ||
| 442 | |||
| 443 | if (fmt->type != stream->type) | 437 | if (fmt->type != stream->type) |
| 444 | return -EINVAL; | 438 | return -EINVAL; |
| 445 | 439 | ||
| @@ -448,8 +442,7 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, · 2 unmodified lines | |||
| 448 | return ret; | 442 | return ret; |
| 449 | 443 | ||
| 450 | mutex_lock(&stream->mutex); | 444 | mutex_lock(&stream->mutex); |
| 451 | 445 | if (vb2_is_busy(&stream->queue.queue)) { | |
| 452 | if (uvc_queue_allocated(&stream->queue)) { | ||
| 453 | ret = -EBUSY; | 446 | ret = -EBUSY; |
| 454 | goto done; | 447 | goto done; |
| 455 | } | 448 | } |
| @@ -513,10 +506,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, · 57 unmodified lines | |||
| 513 | unsigned int i; | 506 | unsigned int i; |
| 514 | int ret; | 507 | int ret; |
| 515 | 508 | ||
| 516 | ret = uvc_acquire_privileges(handle); | ||
| 517 | if (ret < 0) | ||
| 518 | return ret; | ||
| 519 | |||
| 520 | if (parm->type != stream->type) | 509 | if (parm->type != stream->type) |
| 521 | return -EINVAL; | 510 | return -EINVAL; |
| 522 | 511 | ||
| @@ -593,63 +582,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, · 70 unmodified lines | |||
| 593 | return 0; | 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 | * V4L2 file operations | 586 | * V4L2 file operations |
| 655 | */ | 587 | */ |
| @@ -671,7 +603,6 @@ static int uvc_v4l2_open(struct file *file) · 15 unmodified lines | |||
| 671 | v4l2_fh_add(&handle->vfh); | 603 | v4l2_fh_add(&handle->vfh); |
| 672 | handle->chain = stream->chain; | 604 | handle->chain = stream->chain; |
| 673 | handle->stream = stream; | 605 | handle->stream = stream; |
| 674 | handle->state = UVC_HANDLE_PASSIVE; | ||
| 675 | file->private_data = handle; | 606 | file->private_data = handle; |
| 676 | 607 | ||
| 677 | return 0; | 608 | return 0; |
| @@ -686,19 +617,8 @@ static int uvc_v4l2_release(struct file *file) · 8 unmodified lines | |||
| 686 | 617 | ||
| 687 | uvc_ctrl_cleanup_fh(handle); | 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 | /* Release the file handle. */ | 620 | /* Release the file handle. */ |
| 697 | uvc_dismiss_privileges(handle); | 621 | vb2_fop_release(file); |
| 698 | v4l2_fh_del(&handle->vfh); | ||
| 699 | v4l2_fh_exit(&handle->vfh); | ||
| 700 | kfree(handle); | ||
| 701 | file->private_data = NULL; | ||
| 702 | 622 | ||
| 703 | return 0; | 623 | return 0; |
| 704 | } | 624 | } |
| @@ -753,140 +673,6 @@ static int uvc_ioctl_try_fmt(struct file *file, void *fh, · 48 unmodified lines | |||
| 753 | return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); | 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 | static int uvc_ioctl_enum_input(struct file *file, void *fh, | 676 | static int uvc_ioctl_enum_input(struct file *file, void *fh, |
| 891 | struct v4l2_input *input) | 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 | static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) | 747 | static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) |
| 962 | { | 748 | { |
| 963 | struct uvc_fh *handle = fh; | 749 | struct uvc_fh *handle = fh; |
| 750 | struct uvc_streaming *stream = handle->stream; | ||
| 964 | struct uvc_video_chain *chain = handle->chain; | 751 | struct uvc_video_chain *chain = handle->chain; |
| 965 | u8 *buf; | 752 | u8 *buf; |
| 966 | int ret; | 753 | int ret; |
| 967 | 754 | ||
| 968 | ret = uvc_acquire_privileges(handle); | 755 | if (vb2_is_busy(&stream->queue.queue)) |
| 969 | if (ret < 0) | 756 | return -EBUSY; |
| 970 | return ret; | ||
| 971 | 757 | ||
| 972 | if (chain->selector == NULL || | 758 | if (chain->selector == NULL || |
| 973 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { | 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 | #define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) | 1167 | #define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32) |
| 1382 | #define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32) | 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 | static long uvc_v4l2_compat_ioctl32(struct file *file, | 1170 | static long uvc_v4l2_compat_ioctl32(struct file *file, |
| 1386 | unsigned int cmd, unsigned long arg) | 1171 | unsigned int cmd, unsigned long arg) |
| 1387 | { | 1172 | { |
| 1388 | struct uvc_device *uvc_device __free(uvc_pm_put) = NULL; | ||
| 1389 | struct uvc_fh *handle = file->private_data; | 1173 | struct uvc_fh *handle = file->private_data; |
| 1390 | union { | 1174 | union { |
| 1391 | struct uvc_xu_control_mapping xmap; | 1175 | struct uvc_xu_control_mapping xmap; |
| @@ -1398,38 +1182,38 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, · 6 unmodified lines | |||
| 1398 | if (ret) | 1182 | if (ret) |
| 1399 | return ret; | 1183 | return ret; |
| 1400 | 1184 | ||
| 1401 | uvc_device = handle->stream->dev; | ||
| 1402 | |||
| 1403 | switch (cmd) { | 1185 | switch (cmd) { |
| 1404 | case UVCIOC_CTRL_MAP32: | 1186 | case UVCIOC_CTRL_MAP32: |
| 1405 | ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); | 1187 | ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up); |
| 1406 | if (ret) | 1188 | if (ret) |
| 1407 | return ret; | 1189 | break; |
| 1408 | ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); | 1190 | ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap); |
| 1409 | if (ret) | 1191 | if (ret) |
| 1410 | return ret; | 1192 | break; |
| 1411 | ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); | 1193 | ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up); |
| 1412 | if (ret) | 1194 | if (ret) |
| 1413 | return ret; | 1195 | break; |
| 1414 | |||
| 1415 | break; | 1196 | break; |
| 1416 | 1197 | ||
| 1417 | case UVCIOC_CTRL_QUERY32: | 1198 | case UVCIOC_CTRL_QUERY32: |
| 1418 | ret = uvc_v4l2_get_xu_query(&karg.xqry, up); | 1199 | ret = uvc_v4l2_get_xu_query(&karg.xqry, up); |
| 1419 | if (ret) | 1200 | if (ret) |
| 1420 | return ret; | 1201 | break; |
| 1421 | ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); | 1202 | ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry); |
| 1422 | if (ret) | 1203 | if (ret) |
| 1423 | return ret; | 1204 | break; |
| 1424 | ret = uvc_v4l2_put_xu_query(&karg.xqry, up); | 1205 | ret = uvc_v4l2_put_xu_query(&karg.xqry, up); |
| 1425 | if (ret) | 1206 | if (ret) |
| 1426 | return ret; | 1207 | break; |
| 1427 | break; | 1208 | break; |
| 1428 | 1209 | ||
| 1429 | default: | 1210 | default: |
| 1430 | return -ENOIOCTLCMD; | 1211 | ret = -ENOIOCTLCMD; |
| 1212 | break; | ||
| 1431 | } | 1213 | } |
| 1432 | 1214 | ||
| 1215 | uvc_pm_put(handle->stream->dev); | ||
| 1216 | |||
| 1433 | return ret; | 1217 | return ret; |
| 1434 | } | 1218 | } |
| 1435 | #endif | 1219 | #endif |
| @@ -1438,81 +1222,37 @@ static long uvc_v4l2_unlocked_ioctl(struct file *file, · 2 unmodified lines | |||
| 1438 | unsigned int cmd, unsigned long arg) | 1222 | unsigned int cmd, unsigned long arg) |
| 1439 | { | 1223 | { |
| 1440 | struct uvc_fh *handle = file->private_data; | 1224 | struct uvc_fh *handle = file->private_data; |
| 1225 | unsigned int converted_cmd = v4l2_translate_cmd(cmd); | ||
| 1441 | int ret; | 1226 | int ret; |
| 1442 | 1227 | ||
| 1443 | /* The following IOCTLs do not need to turn on the camera. */ | 1228 | /* The following IOCTLs need to turn on the camera. */ |
| 1444 | switch (cmd) { | 1229 | switch (converted_cmd) { |
| 1445 | case VIDIOC_CREATE_BUFS: | 1230 | case UVCIOC_CTRL_MAP: |
| 1446 | case VIDIOC_DQBUF: | 1231 | case UVCIOC_CTRL_QUERY: |
| 1447 | case VIDIOC_ENUM_FMT: | 1232 | case VIDIOC_G_CTRL: |
| 1448 | case VIDIOC_ENUM_FRAMEINTERVALS: | 1233 | case VIDIOC_G_EXT_CTRLS: |
| 1449 | case VIDIOC_ENUM_FRAMESIZES: | 1234 | case VIDIOC_G_INPUT: |
| 1450 | case VIDIOC_ENUMINPUT: | 1235 | case VIDIOC_QUERYCTRL: |
| 1451 | case VIDIOC_EXPBUF: | 1236 | case VIDIOC_QUERYMENU: |
| 1452 | case VIDIOC_G_FMT: | 1237 | case VIDIOC_QUERY_EXT_CTRL: |
| 1453 | case VIDIOC_G_PARM: | 1238 | case VIDIOC_S_CTRL: |
| 1454 | case VIDIOC_G_SELECTION: | 1239 | case VIDIOC_S_EXT_CTRLS: |
| 1455 | case VIDIOC_QBUF: | 1240 | case VIDIOC_S_FMT: |
| 1456 | case VIDIOC_QUERYCAP: | 1241 | case VIDIOC_S_INPUT: |
| 1457 | case VIDIOC_REQBUFS: | 1242 | case VIDIOC_S_PARM: |
| 1458 | case VIDIOC_SUBSCRIBE_EVENT: | 1243 | case VIDIOC_TRY_EXT_CTRLS: |
| 1459 | case VIDIOC_UNSUBSCRIBE_EVENT: | 1244 | case VIDIOC_TRY_FMT: |
| 1460 | return video_ioctl2(file, cmd, arg); | 1245 | ret = uvc_pm_get(handle->stream->dev); |
| 1461 | } | 1246 | if (ret) |
| 1462 | 1247 | return ret; | |
| 1463 | ret = uvc_pm_get(handle->stream->dev); | 1248 | ret = video_ioctl2(file, cmd, arg); |
| 1464 | if (ret) | 1249 | uvc_pm_put(handle->stream->dev); |
| 1465 | return ret; | 1250 | return ret; |
| 1251 | } | ||
| 1466 | 1252 | ||
| 1467 | ret = video_ioctl2(file, cmd, arg); | 1253 | /* The other IOCTLs can run with the camera off. */ |
| 1468 | 1254 | return video_ioctl2(file, cmd, arg); | |
| 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); | ||
| 1514 | } | 1255 | } |
| 1515 | #endif | ||
| 1516 | 1256 | ||
| 1517 | const struct v4l2_ioctl_ops uvc_ioctl_ops = { | 1257 | const struct v4l2_ioctl_ops uvc_ioctl_ops = { |
| 1518 | .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt, | 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 | .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt, | 1266 | .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt, |
| 1527 | .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt, | 1267 | .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt, |
| 1528 | .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt, | 1268 | .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt, |
| 1529 | .vidioc_reqbufs = uvc_ioctl_reqbufs, | 1269 | .vidioc_reqbufs = vb2_ioctl_reqbufs, |
| 1530 | .vidioc_querybuf = uvc_ioctl_querybuf, | 1270 | .vidioc_querybuf = vb2_ioctl_querybuf, |
| 1531 | .vidioc_qbuf = uvc_ioctl_qbuf, | 1271 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, |
| 1532 | .vidioc_expbuf = uvc_ioctl_expbuf, | 1272 | .vidioc_qbuf = vb2_ioctl_qbuf, |
| 1533 | .vidioc_dqbuf = uvc_ioctl_dqbuf, | 1273 | .vidioc_expbuf = vb2_ioctl_expbuf, |
| 1534 | .vidioc_create_bufs = uvc_ioctl_create_bufs, | 1274 | .vidioc_dqbuf = vb2_ioctl_dqbuf, |
| 1535 | .vidioc_streamon = uvc_ioctl_streamon, | 1275 | .vidioc_create_bufs = vb2_ioctl_create_bufs, |
| 1536 | .vidioc_streamoff = uvc_ioctl_streamoff, | 1276 | .vidioc_streamon = vb2_ioctl_streamon, |
| 1277 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
| 1537 | .vidioc_enum_input = uvc_ioctl_enum_input, | 1278 | .vidioc_enum_input = uvc_ioctl_enum_input, |
| 1538 | .vidioc_g_input = uvc_ioctl_g_input, | 1279 | .vidioc_g_input = uvc_ioctl_g_input, |
| 1539 | .vidioc_s_input = uvc_ioctl_s_input, | 1280 | .vidioc_s_input = uvc_ioctl_s_input, |
| @@ -1558,11 +1299,10 @@ const struct v4l2_file_operations uvc_fops = { · 18 unmodified lines | |||
| 1558 | #ifdef CONFIG_COMPAT | 1299 | #ifdef CONFIG_COMPAT |
| 1559 | .compat_ioctl32 = uvc_v4l2_compat_ioctl32, | 1300 | .compat_ioctl32 = uvc_v4l2_compat_ioctl32, |
| 1560 | #endif | 1301 | #endif |
| 1561 | .read = uvc_v4l2_read, | 1302 | .mmap = vb2_fop_mmap, |
| 1562 | .mmap = uvc_v4l2_mmap, | 1303 | .poll = vb2_fop_poll, |
| 1563 | .poll = uvc_v4l2_poll, | ||
| 1564 | #ifndef CONFIG_MMU | 1304 | #ifndef CONFIG_MMU |
| 1565 | .get_unmapped_area = uvc_v4l2_get_unmapped_area, | 1305 | .get_unmapped_area = vb2_fop_get_unmapped_area, |
| 1566 | #endif | 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 | ctrl->dwMaxPayloadTransferSize = bandwidth; | 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 | static size_t uvc_video_ctrl_size(struct uvc_streaming *stream) | 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 | if (!meta_buf || length == 2) | 1428 | if (!meta_buf || length == 2) |
| 1420 | return; | 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 | has_pts = mem[1] & UVC_STREAM_PTS; | 1431 | has_pts = mem[1] & UVC_STREAM_PTS; |
| 1429 | has_scr = mem[1] & UVC_STREAM_SCR; | 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 | !memcmp(scr, stream->clock.last_scr, 6))) | 1448 | !memcmp(scr, stream->clock.last_scr, 6))) |
| 1446 | return; | 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 | meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused); | 1457 | meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused); |
| 1449 | local_irq_save(flags); | 1458 | local_irq_save(flags); |
| 1450 | time = uvc_video_get_time(); | 1459 | time = uvc_video_get_time(); |
| @@ -77,6 +77,7 @@ · 76 unmodified lines | |||
| 77 | #define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 | 77 | #define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000 |
| 78 | #define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 | 78 | #define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000 |
| 79 | #define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 | 79 | #define UVC_QUIRK_MJPEG_NO_EOF 0x00020000 |
| 80 | #define UVC_QUIRK_MSXU_META 0x00040000 | ||
| 80 | 81 | ||
| 81 | /* Format flags */ | 82 | /* Format flags */ |
| 82 | #define UVC_FMT_FLAG_COMPRESSED 0x00000001 | 83 | #define UVC_FMT_FLAG_COMPRESSED 0x00000001 |
| @@ -134,6 +135,8 @@ struct uvc_control_mapping { · 51 unmodified lines | |||
| 134 | s32 master_manual; | 135 | s32 master_manual; |
| 135 | u32 slave_ids[2]; | 136 | u32 slave_ids[2]; |
| 136 | 137 | ||
| 138 | bool disabled; | ||
| 139 | |||
| 137 | const struct uvc_control_mapping *(*filter_mapping) | 140 | const struct uvc_control_mapping *(*filter_mapping) |
| 138 | (struct uvc_video_chain *chain, | 141 | (struct uvc_video_chain *chain, |
| 139 | struct uvc_control *ctrl); | 142 | struct uvc_control *ctrl); |
| @@ -326,7 +329,10 @@ struct uvc_buffer { · 186 unmodified lines | |||
| 326 | 329 | ||
| 327 | struct uvc_video_queue { | 330 | struct uvc_video_queue { |
| 328 | struct vb2_queue queue; | 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 | unsigned int flags; | 337 | unsigned int flags; |
| 332 | unsigned int buf_used; | 338 | unsigned int buf_used; |
| @@ -570,6 +576,8 @@ struct uvc_status { · 237 unmodified lines | |||
| 570 | }; | 576 | }; |
| 571 | } __packed; | 577 | } __packed; |
| 572 | 578 | ||
| 579 | #define UVC_MAX_META_DATA_FORMATS 3 | ||
| 580 | |||
| 573 | struct uvc_device { | 581 | struct uvc_device { |
| 574 | struct usb_device *udev; | 582 | struct usb_device *udev; |
| 575 | struct usb_interface *intf; | 583 | struct usb_interface *intf; |
| @@ -580,6 +588,9 @@ struct uvc_device { · 4 unmodified lines | |||
| 580 | 588 | ||
| 581 | const struct uvc_device_info *info; | 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 | atomic_t nmappings; | 594 | atomic_t nmappings; |
| 584 | 595 | ||
| 585 | /* Video control interface */ | 596 | /* Video control interface */ |
| @@ -619,18 +630,11 @@ struct uvc_device { · 33 unmodified lines | |||
| 619 | struct uvc_entity *gpio_unit; | 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 | struct uvc_fh { | 633 | struct uvc_fh { |
| 628 | struct v4l2_fh vfh; | 634 | struct v4l2_fh vfh; |
| 629 | struct uvc_video_chain *chain; | 635 | struct uvc_video_chain *chain; |
| 630 | struct uvc_streaming *stream; | 636 | struct uvc_streaming *stream; |
| 631 | enum uvc_handle_state state; | ||
| 632 | unsigned int pending_async_ctrls; | 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 | /* Video buffers queue management. */ | 692 | /* Video buffers queue management. */ |
| 689 | int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type); | 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 | void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); | 694 | void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); |
| 707 | struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, | 695 | struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, |
| 708 | struct uvc_buffer *buf); | 696 | struct uvc_buffer *buf); |
| 709 | struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); | 697 | struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); |
| 710 | void uvc_queue_buffer_release(struct uvc_buffer *buf); | 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 | static inline int uvc_queue_streaming(struct uvc_video_queue *queue) | 699 | static inline int uvc_queue_streaming(struct uvc_video_queue *queue) |
| 721 | { | 700 | { |
| 722 | return vb2_is_streaming(&queue->queue); | 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 | void uvc_video_clock_update(struct uvc_streaming *stream, | 728 | void uvc_video_clock_update(struct uvc_streaming *stream, |
| 750 | struct vb2_v4l2_buffer *vbuf, | 729 | struct vb2_v4l2_buffer *vbuf, |
| 751 | struct uvc_buffer *buf); | 730 | struct uvc_buffer *buf); |
| 731 | int uvc_meta_init(struct uvc_device *dev); | ||
| 752 | int uvc_meta_register(struct uvc_streaming *stream); | 732 | int uvc_meta_register(struct uvc_streaming *stream); |
| 753 | 733 | ||
| 754 | int uvc_register_video_device(struct uvc_device *dev, | 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 | { .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 }, | 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 | { .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 }, | 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 | /* Bayer RGB formats */ | 332 | /* Bayer RGB formats */ |
| 327 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | { .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 }, | 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 | unsigned int i; | 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 | freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div); | 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", | 540 | pr_warn_once("%s: Link frequency estimated using pixel rate: result might be inaccurate\n", |
| 509 | __func__); | 541 | __func__); |
| 510 | pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", | 542 | pr_warn_once("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", |
| 511 | __func__); | 543 | __func__); |
| 512 | } | 544 | } |
| 513 | 545 | ||
| 514 | return freq > 0 ? freq : -EINVAL; | 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 | p_h264_sps->flags &= | 969 | p_h264_sps->flags &= |
| 970 | ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS; | 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 | if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) | 977 | if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) |
| 978 | p_h264_sps->flags &= | 978 | p_h264_sps->flags &= |
| 979 | ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD; | 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 | EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); | 1631 | EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); |
| 1632 | 1632 | ||
| 1633 | /* Free all controls and control refs */ | 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 | struct v4l2_ctrl_ref *ref, *next_ref; | 1636 | struct v4l2_ctrl_ref *ref, *next_ref; |
| 1637 | struct v4l2_ctrl *ctrl, *next_ctrl; | 1637 | struct v4l2_ctrl *ctrl, *next_ctrl; |
| 1638 | struct v4l2_subscribed_event *sev, *next_sev; | 1638 | struct v4l2_subscribed_event *sev, *next_sev; |
| 1639 | 1639 | ||
| 1640 | if (hdl == NULL || hdl->buckets == NULL) | 1640 | if (!hdl) |
| 1641 | return; | 1641 | return 0; |
| 1642 | |||
| 1643 | if (!hdl->buckets) | ||
| 1644 | return hdl->error; | ||
| 1642 | 1645 | ||
| 1643 | v4l2_ctrl_handler_free_request(hdl); | 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 | kvfree(hdl->buckets); | 1664 | kvfree(hdl->buckets); |
| 1662 | hdl->buckets = NULL; | 1665 | hdl->buckets = NULL; |
| 1663 | hdl->cached = NULL; | 1666 | hdl->cached = NULL; |
| 1664 | hdl->error = 0; | ||
| 1665 | mutex_unlock(hdl->lock); | 1667 | mutex_unlock(hdl->lock); |
| 1666 | mutex_destroy(&hdl->_lock); | 1668 | mutex_destroy(&hdl->_lock); |
| 1669 | |||
| 1670 | return hdl->error; | ||
| 1667 | } | 1671 | } |
| 1668 | EXPORT_SYMBOL(v4l2_ctrl_handler_free); | 1672 | EXPORT_SYMBOL(v4l2_ctrl_handler_free); |
| 1669 | 1673 | ||
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | #include <linux/i2c.h> | 6 | #include <linux/i2c.h> |
| 7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 8 | #include <linux/property.h> | ||
| 8 | #include <media/v4l2-common.h> | 9 | #include <media/v4l2-common.h> |
| 9 | #include <media/v4l2-device.h> | 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 | * registered by us, and would not be | 25 | * registered by us, and would not be |
| 25 | * re-created by just probing the V4L2 driver. | 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 | i2c_unregister_device(client); | 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 | case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; | 1413 | case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; |
| 1414 | case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; | 1414 | case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; |
| 1415 | case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break; | 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 | case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; | 1417 | case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break; |
| 1417 | case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; | 1418 | case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break; |
| 1418 | case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break; | 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 | case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; | 1422 | case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; |
| 1422 | case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; | 1423 | case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; |
| 1423 | case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break; | 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 | case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break; | 1426 | case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break; |
| 1425 | case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break; | 1427 | case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break; |
| 1426 | case V4L2_PIX_FMT_SGRBG14: descr = "14-bit Bayer GRGR/BGBG"; break; | 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 | case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break; | 1431 | case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break; |
| 1430 | case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break; | 1432 | case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break; |
| 1431 | case V4L2_PIX_FMT_SRGGB14P: descr = "14-bit Bayer RGRG/GBGB Packed"; break; | 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 | case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break; | 1435 | case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break; |
| 1433 | case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; | 1436 | case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; |
| 1434 | case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; | 1437 | case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; |
| 1435 | case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break; | 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 | case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; | 1440 | case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; |
| 1437 | case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; | 1441 | case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; |
| 1438 | case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; | 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 | case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; | 1463 | case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break; |
| 1460 | case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; | 1464 | case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; |
| 1461 | case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; | 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 | case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; | 1467 | case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; |
| 1463 | case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; | 1468 | case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; |
| 1464 | case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break; | 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 | return ret; | 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 | #if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME) | 3255 | #if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME) |
| 3251 | switch (cmd) { | 3256 | switch (cmd) { |
| @@ -3266,6 +3271,7 @@ static unsigned int video_translate_cmd(unsigned int cmd) · 14 unmodified lines | |||
| 3266 | 3271 | ||
| 3267 | return cmd; | 3272 | return cmd; |
| 3268 | } | 3273 | } |
| 3274 | EXPORT_SYMBOL_GPL(v4l2_translate_cmd); | ||
| 3269 | 3275 | ||
| 3270 | static int video_get_user(void __user *arg, void *parg, | 3276 | static int video_get_user(void __user *arg, void *parg, |
| 3271 | unsigned int real_cmd, unsigned int cmd, | 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 | size_t array_size = 0; | 3432 | size_t array_size = 0; |
| 3427 | void __user *user_ptr = NULL; | 3433 | void __user *user_ptr = NULL; |
| 3428 | void **kernel_ptr = NULL; | 3434 | void **kernel_ptr = NULL; |
| 3429 | unsigned int cmd = video_translate_cmd(orig_cmd); | 3435 | unsigned int cmd = v4l2_translate_cmd(orig_cmd); |
| 3430 | const size_t ioc_size = _IOC_SIZE(cmd); | 3436 | const size_t ioc_size = _IOC_SIZE(cmd); |
| 3431 | 3437 | ||
| 3432 | /* Copy arguments into temp kernel buffer */ | 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 | return marker; | 711 | return marker; |
| 712 | } | 712 | } |
| 713 | EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_header); | 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 | struct v4l2_subdev_route *routes = | 1004 | struct v4l2_subdev_route *routes = |
| 1005 | (struct v4l2_subdev_route *)(uintptr_t)routing->routes; | 1005 | (struct v4l2_subdev_route *)(uintptr_t)routing->routes; |
| 1006 | struct v4l2_subdev_krouting krouting = {}; | 1006 | struct v4l2_subdev_krouting krouting = {}; |
| 1007 | unsigned int num_active_routes = 0; | ||
| 1007 | unsigned int i; | 1008 | unsigned int i; |
| 1008 | 1009 | ||
| 1009 | if (!v4l2_subdev_enable_streams_api) | 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 | if (!(pads[route->source_pad].flags & | 1042 | if (!(pads[route->source_pad].flags & |
| 1042 | MEDIA_PAD_FL_SOURCE)) | 1043 | MEDIA_PAD_FL_SOURCE)) |
| 1043 | return -EINVAL; | 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 | * If the driver doesn't support setting routing, just return | 1061 | * If the driver doesn't support setting routing, just return |
| 1048 | * the routing table. | 1062 | * the routing table. |
| @@ -2219,6 +2233,9 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd, · 1170 unmodified lines | |||
| 2219 | *found_streams = BIT_ULL(0); | 2233 | *found_streams = BIT_ULL(0); |
| 2220 | *enabled_streams = | 2234 | *enabled_streams = |
| 2221 | (sd->enabled_pads & BIT_ULL(pad)) ? BIT_ULL(0) : 0; | 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 | return; | 2239 | return; |
| 2223 | } | 2240 | } |
| 2224 | 2241 | ||
| @@ -2236,6 +2253,10 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd, · 11 unmodified lines | |||
| 2236 | if (cfg->enabled) | 2253 | if (cfg->enabled) |
| 2237 | *enabled_streams |= BIT_ULL(cfg->stream); | 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 | static void v4l2_subdev_set_streams_enabled(struct v4l2_subdev *sd, | 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 | bool use_s_stream; | 2292 | bool use_s_stream; |
| 2272 | int ret; | 2293 | int ret; |
| 2273 | 2294 | ||
| 2295 | dev_dbg(dev, "enable streams \"%s\":%u/%#llx\n", sd->entity.name, pad, | ||
| 2296 | streams_mask); | ||
| 2297 | |||
| 2274 | /* A few basic sanity checks first. */ | 2298 | /* A few basic sanity checks first. */ |
| 2275 | if (pad >= sd->entity.num_pads) | 2299 | if (pad >= sd->entity.num_pads) |
| 2276 | return -EINVAL; | 2300 | return -EINVAL; |
| @@ -2318,8 +2342,6 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad, · 41 unmodified lines | |||
| 2318 | goto done; | 2342 | goto done; |
| 2319 | } | 2343 | } |
| 2320 | 2344 | ||
| 2321 | dev_dbg(dev, "enable streams %u:%#llx\n", pad, streams_mask); | ||
| 2322 | |||
| 2323 | already_streaming = v4l2_subdev_is_streaming(sd); | 2345 | already_streaming = v4l2_subdev_is_streaming(sd); |
| 2324 | 2346 | ||
| 2325 | if (!use_s_stream) { | 2347 | if (!use_s_stream) { |
| @@ -2371,6 +2393,9 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, · 45 unmodified lines | |||
| 2371 | bool use_s_stream; | 2393 | bool use_s_stream; |
| 2372 | int ret; | 2394 | int ret; |
| 2373 | 2395 | ||
| 2396 | dev_dbg(dev, "disable streams \"%s\":%u/%#llx\n", sd->entity.name, pad, | ||
| 2397 | streams_mask); | ||
| 2398 | |||
| 2374 | /* A few basic sanity checks first. */ | 2399 | /* A few basic sanity checks first. */ |
| 2375 | if (pad >= sd->entity.num_pads) | 2400 | if (pad >= sd->entity.num_pads) |
| 2376 | return -EINVAL; | 2401 | return -EINVAL; |
| @@ -2418,8 +2443,6 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad, · 41 unmodified lines | |||
| 2418 | goto done; | 2443 | goto done; |
| 2419 | } | 2444 | } |
| 2420 | 2445 | ||
| 2421 | dev_dbg(dev, "disable streams %u:%#llx\n", pad, streams_mask); | ||
| 2422 | |||
| 2423 | if (!use_s_stream) { | 2446 | if (!use_s_stream) { |
| 2424 | /* Call the .disable_streams() operation. */ | 2447 | /* Call the .disable_streams() operation. */ |
| 2425 | ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad, | 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 | static struct gpiod_lookup_table surface_go_int347a_gpios = { | 235 | static struct gpiod_lookup_table surface_go_int347a_gpios = { |
| 133 | .dev_id = "i2c-INT347A:00", | 236 | .dev_id = "i2c-INT347A:00", |
| 134 | .table = { | 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 | static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = { | 261 | static const struct int3472_tps68470_board_data surface_go_tps68470_board_data = { |
| 150 | .dev_name = "i2c-INT3472:05", | 262 | .dev_name = "i2c-INT3472:05", |
| 151 | .tps68470_regulator_pdata = &surface_go_tps68470_pdata, | 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 | static const struct dmi_system_id int3472_tps68470_board_data_table[] = { | 290 | static const struct dmi_system_id int3472_tps68470_board_data_table[] = { |
| 170 | { | 291 | { |
| 171 | .matches = { | 292 | .matches = { |
| @@ -188,6 +309,13 @@ static const struct dmi_system_id int3472_tps68470_board_data_table[] = { · 16 unmodified lines | |||
| 188 | }, | 309 | }, |
| 189 | .driver_data = (void *)&surface_go3_tps68470_board_data, | 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 | source "drivers/staging/media/ipu3/Kconfig" | 29 | source "drivers/staging/media/ipu3/Kconfig" |
| 30 | 30 | ||
| 31 | source "drivers/staging/media/ipu7/Kconfig" | ||
| 32 | |||
| 31 | source "drivers/staging/media/max96712/Kconfig" | 33 | source "drivers/staging/media/max96712/Kconfig" |
| 32 | 34 | ||
| 33 | source "drivers/staging/media/meson/vdec/Kconfig" | 35 | source "drivers/staging/media/meson/vdec/Kconfig" |
| 34 | 36 | ||
| 35 | source "drivers/staging/media/rkvdec/Kconfig" | ||
| 36 | |||
| 37 | source "drivers/staging/media/starfive/Kconfig" | 37 | source "drivers/staging/media/starfive/Kconfig" |
| 38 | 38 | ||
| 39 | source "drivers/staging/media/sunxi/Kconfig" | 39 | source "drivers/staging/media/sunxi/Kconfig" |
| @@ -4,9 +4,9 @@ obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ · 3 unmodified lines | |||
| 4 | obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ | 4 | obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ |
| 5 | obj-$(CONFIG_VIDEO_MAX96712) += max96712/ | 5 | obj-$(CONFIG_VIDEO_MAX96712) += max96712/ |
| 6 | obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ | 6 | obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/ |
| 7 | obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ | ||
| 8 | obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ | 7 | obj-$(CONFIG_VIDEO_STARFIVE_CAMSS) += starfive/ |
| 9 | obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ | 8 | obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ |
| 10 | obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ | 9 | obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ |
| 11 | obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ | 10 | obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ |
| 11 | obj-$(CONFIG_VIDEO_INTEL_IPU7) += ipu7/ | ||
| 12 | obj-$(CONFIG_DVB_AV7110) += av7110/ | 12 | obj-$(CONFIG_DVB_AV7110) += av7110/ |
| @@ -12,6 +12,7 @@ menuconfig INTEL_ATOMISP · 11 unmodified lines | |||
| 12 | config VIDEO_ATOMISP | 12 | config VIDEO_ATOMISP |
| 13 | tristate "Intel Atom Image Signal Processor Driver" | 13 | tristate "Intel Atom Image Signal Processor Driver" |
| 14 | depends on VIDEO_DEV && INTEL_ATOMISP | 14 | depends on VIDEO_DEV && INTEL_ATOMISP |
| 15 | depends on INTEL_SKL_INT3472 | ||
| 15 | depends on IPU_BRIDGE | 16 | depends on IPU_BRIDGE |
| 16 | depends on MEDIA_PCI_SUPPORT | 17 | depends on MEDIA_PCI_SUPPORT |
| 17 | depends on PMIC_OPREGION | 18 | depends on PMIC_OPREGION |
| @@ -17,7 +17,6 @@ atomisp-objs += \ · 16 unmodified lines | |||
| 17 | pci/atomisp_compat_css20.o \ | 17 | pci/atomisp_compat_css20.o \ |
| 18 | pci/atomisp_csi2.o \ | 18 | pci/atomisp_csi2.o \ |
| 19 | pci/atomisp_csi2_bridge.o \ | 19 | pci/atomisp_csi2_bridge.o \ |
| 20 | pci/atomisp_drvfs.o \ | ||
| 21 | pci/atomisp_fops.o \ | 20 | pci/atomisp_fops.o \ |
| 22 | pci/atomisp_ioctl.o \ | 21 | pci/atomisp_ioctl.o \ |
| 23 | pci/atomisp_subdev.o \ | 22 | pci/atomisp_subdev.o \ |
| @@ -7,8 +7,6 @@ TODO · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | * Remove/disable custom v4l2-ctrls | 8 | * Remove/disable custom v4l2-ctrls |
| 9 | 9 | ||
| 10 | * Remove custom sysfs files created by atomisp_drvfs.c | ||
| 11 | |||
| 12 | * Remove unnecessary/unwanted module parameters | 10 | * Remove unnecessary/unwanted module parameters |
| 13 | 11 | ||
| 14 | * Remove abuse of priv field in various v4l2 userspace API structs | 12 | * Remove abuse of priv field in various v4l2 userspace API structs |
| @@ -31,6 +31,7 @@ config VIDEO_ATOMISP_GC0310 · 30 unmodified lines | |||
| 31 | tristate "GC0310 sensor support" | 31 | tristate "GC0310 sensor support" |
| 32 | depends on ACPI | 32 | depends on ACPI |
| 33 | depends on I2C && VIDEO_DEV | 33 | depends on I2C && VIDEO_DEV |
| 34 | select V4L2_CCI_I2C | ||
| 34 | help | 35 | help |
| 35 | This is a Video4Linux2 sensor-level driver for the Galaxycore | 36 | This is a Video4Linux2 sensor-level driver for the Galaxycore |
| 36 | GC0310 0.3MP sensor. | 37 | GC0310 0.3MP sensor. |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | |||
| 3 | * Support for GalaxyCore GC0310 VGA camera sensor. | 3 | * Support for GalaxyCore GC0310 VGA camera sensor. |
| 4 | * | 4 | * |
| 5 | * Copyright (c) 2013 Intel Corporation. All Rights Reserved. | 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 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| @@ -13,77 +13,92 @@ · 3 unmodified lines | |||
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
| 16 | #include <linux/regmap.h> | ||
| 16 | #include <linux/string.h> | 17 | #include <linux/string.h> |
| 17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 18 | 19 | ||
| 20 | #include <media/v4l2-cci.h> | ||
| 19 | #include <media/v4l2-ctrls.h> | 21 | #include <media/v4l2-ctrls.h> |
| 20 | #include <media/v4l2-device.h> | 22 | #include <media/v4l2-device.h> |
| 23 | #include <media/v4l2-fwnode.h> | ||
| 21 | 24 | ||
| 22 | #define GC0310_NATIVE_WIDTH 656 | 25 | #define GC0310_NATIVE_WIDTH 656 |
| 23 | #define GC0310_NATIVE_HEIGHT 496 | 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 | #define GC0310_FPS 30 | 40 | #define GC0310_FPS 30 |
| 26 | #define GC0310_SKIP_FRAMES 3 | 41 | #define GC0310_SKIP_FRAMES 3 |
| 27 | 42 | ||
| 28 | #define GC0310_FOCAL_LENGTH_NUM 278 /* 2.78mm */ | ||
| 29 | |||
| 30 | #define GC0310_ID 0xa310 | 43 | #define GC0310_ID 0xa310 |
| 31 | 44 | ||
| 32 | #define GC0310_RESET_RELATED 0xFE | 45 | #define GC0310_RESET_RELATED_REG CCI_REG8(0xfe) |
| 33 | #define GC0310_REGISTER_PAGE_0 0x0 | 46 | #define GC0310_REGISTER_PAGE_0 0x0 |
| 34 | #define GC0310_REGISTER_PAGE_3 0x3 | 47 | #define GC0310_REGISTER_PAGE_3 0x3 |
| 35 | 48 | ||
| 36 | /* | 49 | /* |
| 37 | * GC0310 System control registers | 50 | * GC0310 System control registers |
| 38 | */ | 51 | */ |
| 39 | #define GC0310_SW_STREAM 0x10 | 52 | #define GC0310_SW_STREAM_REG CCI_REG8(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 | ||
| 63 | 53 | ||
| 64 | #define GC0310_START_STREAMING 0x94 /* 8-bit enable */ | 54 | #define GC0310_START_STREAMING 0x94 /* 8-bit enable */ |
| 65 | #define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */ | 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 | #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) | 84 | #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) |
| 68 | 85 | ||
| 69 | struct gc0310_device { | 86 | struct gc0310_device { |
| 70 | struct v4l2_subdev sd; | 87 | struct v4l2_subdev sd; |
| 71 | struct media_pad pad; | 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 | struct gpio_desc *reset; | 91 | struct gpio_desc *reset; |
| 77 | struct gpio_desc *powerdown; | 92 | struct gpio_desc *powerdown; |
| 78 | 93 | ||
| 79 | struct gc0310_mode { | ||
| 80 | struct v4l2_mbus_framefmt fmt; | ||
| 81 | } mode; | ||
| 82 | |||
| 83 | struct gc0310_ctrls { | 94 | struct gc0310_ctrls { |
| 84 | struct v4l2_ctrl_handler handler; | 95 | struct v4l2_ctrl_handler handler; |
| 85 | struct v4l2_ctrl *exposure; | 96 | struct v4l2_ctrl *exposure; |
| 86 | struct v4l2_ctrl *gain; | 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 | } ctrls; | 102 | } ctrls; |
| 88 | }; | 103 | }; |
| 89 | 104 | ||
| @@ -92,7 +107,7 @@ struct gc0310_reg { · 2 unmodified lines | |||
| 92 | u8 val; | 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 | /* System registers */ | 111 | /* System registers */ |
| 97 | { 0xfe, 0xf0 }, | 112 | { 0xfe, 0xf0 }, |
| 98 | { 0xfe, 0xf0 }, | 113 | { 0xfe, 0xf0 }, |
| @@ -142,8 +157,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { · 43 unmodified lines | |||
| 142 | { 0x04, 0xc0 }, /* 0xe8 //58 */ | 157 | { 0x04, 0xc0 }, /* 0xe8 //58 */ |
| 143 | { 0x05, 0x00 }, | 158 | { 0x05, 0x00 }, |
| 144 | { 0x06, 0xb2 }, /* 0x0a //HB */ | 159 | { 0x06, 0xb2 }, /* 0x0a //HB */ |
| 145 | { 0x07, 0x00 }, | 160 | /* Vblank (reg 0x07 + 0x08) gets set by the vblank ctrl */ |
| 146 | { 0x08, 0x0c }, /* 0x89 //VB */ | ||
| 147 | { 0x09, 0x00 }, /* row start */ | 161 | { 0x09, 0x00 }, /* row start */ |
| 148 | { 0x0a, 0x00 }, | 162 | { 0x0a, 0x00 }, |
| 149 | { 0x0b, 0x00 }, /* col start */ | 163 | { 0x0b, 0x00 }, /* col start */ |
| @@ -235,7 +249,7 @@ static const struct gc0310_reg gc0310_reset_register[] = { · 85 unmodified lines | |||
| 235 | { 0xfe, 0x00 }, | 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 | { 0xfe, 0x00 }, | 253 | { 0xfe, 0x00 }, |
| 240 | { 0x0d, 0x01 }, /* height */ | 254 | { 0x0d, 0x01 }, /* height */ |
| 241 | { 0x0e, 0xf2 }, /* 0xf7 //height */ | 255 | { 0x0e, 0xf2 }, /* 0xf7 //height */ |
| @@ -259,41 +273,14 @@ static const struct gc0310_reg gc0310_VGA_30fps[] = { · 17 unmodified lines | |||
| 259 | { 0xfe, 0x00 }, | 273 | { 0xfe, 0x00 }, |
| 260 | }; | 274 | }; |
| 261 | 275 | ||
| 262 | /* | 276 | static const s64 link_freq_menu_items[] = { |
| 263 | * gc0310_write_reg_array - Initializes a list of GC0310 registers | 277 | GC0310_LINK_FREQ, |
| 264 | * @client: i2c driver client structure | 278 | }; |
| 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 | } | ||
| 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 | u8 again, dgain; | 282 | u8 again, dgain; |
| 296 | int ret; | 283 | int ret = 0; |
| 297 | 284 | ||
| 298 | /* Taken from original driver, this never sets dgain lower then 32? */ | 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 | dgain = gain / 2; | 295 | dgain = gain / 2; |
| 309 | } | 296 | } |
| 310 | 297 | ||
| 311 | ret = i2c_smbus_write_byte_data(client, GC0310_AGC_ADJ, again); | 298 | cci_write(sensor->regmap, GC0310_AGC_ADJ_REG, again, &ret); |
| 312 | if (ret) | 299 | cci_write(sensor->regmap, GC0310_DGC_ADJ_REG, dgain, &ret); |
| 313 | return 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 | static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) | 311 | static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) |
| 319 | { | 312 | { |
| 320 | struct gc0310_device *dev = | 313 | struct gc0310_device *sensor = |
| 321 | container_of(ctrl->handler, struct gc0310_device, ctrls.handler); | 314 | container_of(ctrl->handler, struct gc0310_device, ctrls.handler); |
| 322 | int ret; | 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 | /* Only apply changes to the controls if the device is powered up */ | 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 | return 0; | 326 | return 0; |
| 327 | 327 | ||
| 328 | switch (ctrl->id) { | 328 | switch (ctrl->id) { |
| 329 | case V4L2_CID_EXPOSURE: | 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 | break; | 332 | break; |
| 332 | case V4L2_CID_GAIN: | 333 | case V4L2_CID_ANALOGUE_GAIN: |
| 333 | ret = gc0310_gain_set(dev, ctrl->val); | 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 | break; | 340 | break; |
| 335 | default: | 341 | default: |
| 336 | ret = -EINVAL; | 342 | ret = -EINVAL; |
| 337 | break; | 343 | break; |
| 338 | } | 344 | } |
| 339 | 345 | ||
| 340 | pm_runtime_put(dev->sd.dev); | 346 | pm_runtime_put(sensor->sd.dev); |
| 341 | return ret; | 347 | return ret; |
| 342 | } | 348 | } |
| 343 | 349 | ||
| @@ -345,17 +351,6 @@ static const struct v4l2_ctrl_ops ctrl_ops = { · 1 unmodified line | |||
| 345 | .s_ctrl = gc0310_s_ctrl, | 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 | /* The GC0310 currently only supports 1 fixed fmt */ | 354 | /* The GC0310 currently only supports 1 fixed fmt */ |
| 360 | static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) | 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 | fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; | 361 | fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; |
| 367 | } | 362 | } |
| 368 | 363 | ||
| 369 | static int gc0310_set_fmt(struct v4l2_subdev *sd, | 364 | static int gc0310_get_selection(struct v4l2_subdev *sd, |
| 370 | struct v4l2_subdev_state *sd_state, | 365 | struct v4l2_subdev_state *state, |
| 371 | struct v4l2_subdev_format *format) | 366 | struct v4l2_subdev_selection *sel) |
| 372 | { | 367 | { |
| 373 | struct gc0310_device *dev = to_gc0310_sensor(sd); | 368 | /* Only the single fixed 656x496 mode is supported, without croping */ |
| 374 | struct v4l2_mbus_framefmt *fmt; | 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); | 386 | static int gc0310_power_off(struct device *dev) |
| 377 | gc0310_fill_format(fmt); | 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 | return 0; | 393 | return 0; |
| 381 | } | 394 | } |
| 382 | 395 | ||
| 383 | static int gc0310_get_fmt(struct v4l2_subdev *sd, | 396 | static int gc0310_power_on(struct device *dev) |
| 384 | struct v4l2_subdev_state *sd_state, | ||
| 385 | struct v4l2_subdev_format *format) | ||
| 386 | { | 397 | { |
| 387 | struct gc0310_device *dev = to_gc0310_sensor(sd); | 398 | struct v4l2_subdev *sd = dev_get_drvdata(dev); |
| 388 | struct v4l2_mbus_framefmt *fmt; | 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 | return 0; | 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 | int ret; | 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 | return -ENODEV; | 417 | return -ENODEV; |
| 402 | 418 | ||
| 403 | ret = pm_runtime_get_sync(&client->dev); | 419 | ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL); |
| 404 | if (ret >= 0) | ||
| 405 | ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H); | ||
| 406 | pm_runtime_put(&client->dev); | ||
| 407 | if (ret < 0) { | 420 | if (ret < 0) { |
| 408 | dev_err(&client->dev, "read sensor_id failed: %d\n", ret); | 421 | dev_err(&client->dev, "read sensor_id failed: %d\n", ret); |
| 409 | return -ENODEV; | 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) { | 427 | if (val != GC0310_ID) { |
| 415 | dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", | 428 | dev_err(&client->dev, "sensor ID error, read id = 0x%llx, target id = 0x%x\n", |
| 416 | ret, GC0310_ID); | 429 | val, GC0310_ID); |
| 417 | return -ENODEV; | 430 | return -ENODEV; |
| 418 | } | 431 | } |
| 419 | 432 | ||
| @@ -422,85 +435,67 @@ static int gc0310_detect(struct i2c_client *client) · 2 unmodified lines | |||
| 422 | return 0; | 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 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 443 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 429 | int ret = 0; | 444 | int ret; |
| 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 | } | ||
| 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 | if (ret) | 447 | if (ret) |
| 464 | goto error_power_down; | 448 | return ret; |
| 465 | 449 | ||
| 466 | ret = i2c_smbus_write_byte_data(client, GC0310_SW_STREAM, | 450 | ret = regmap_multi_reg_write(sensor->regmap, |
| 467 | enable ? GC0310_START_STREAMING : GC0310_STOP_STREAMING); | 451 | gc0310_reset_register, |
| 452 | ARRAY_SIZE(gc0310_reset_register)); | ||
| 468 | if (ret) | 453 | if (ret) |
| 469 | goto error_power_down; | 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 | if (ret) | 459 | if (ret) |
| 473 | goto error_power_down; | 460 | goto error_power_down; |
| 474 | 461 | ||
| 475 | if (!enable) | 462 | /* restore value of all ctrls */ |
| 476 | pm_runtime_put(&client->dev); | 463 | ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); |
| 477 | 464 | ||
| 478 | dev->is_streaming = enable; | 465 | /* enable per frame MIPI and sensor ctrl reset */ |
| 479 | mutex_unlock(&dev->input_lock); | 466 | cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, 0x30, &ret); |
| 480 | return 0; | 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 | error_power_down: | 475 | error_power_down: |
| 483 | pm_runtime_put(&client->dev); | 476 | if (ret) |
| 484 | dev->is_streaming = false; | 477 | pm_runtime_put(&client->dev); |
| 485 | mutex_unlock(&dev->input_lock); | 478 | |
| 486 | return ret; | 479 | return ret; |
| 487 | } | 480 | } |
| 488 | 481 | ||
| 489 | static int gc0310_get_frame_interval(struct v4l2_subdev *sd, | 482 | static int gc0310_disable_streams(struct v4l2_subdev *sd, |
| 490 | struct v4l2_subdev_state *sd_state, | 483 | struct v4l2_subdev_state *state, |
| 491 | struct v4l2_subdev_frame_interval *interval) | 484 | u32 pad, u64 streams_mask) |
| 492 | { | 485 | { |
| 493 | /* | 486 | struct gc0310_device *sensor = to_gc0310_sensor(sd); |
| 494 | * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 | 487 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 495 | * subdev active state API. | 488 | int ret = 0; |
| 496 | */ | ||
| 497 | if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | ||
| 498 | return -EINVAL; | ||
| 499 | 489 | ||
| 500 | interval->interval.numerator = 1; | 490 | cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, |
| 501 | interval->interval.denominator = GC0310_FPS; | 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 | static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, | 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 | return 0; | 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 | static const struct v4l2_subdev_video_ops gc0310_video_ops = { | 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 | static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { | 533 | static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { |
| 549 | .enum_mbus_code = gc0310_enum_mbus_code, | 534 | .enum_mbus_code = gc0310_enum_mbus_code, |
| 550 | .enum_frame_size = gc0310_enum_frame_size, | 535 | .enum_frame_size = gc0310_enum_frame_size, |
| 551 | .get_fmt = gc0310_get_fmt, | 536 | .get_fmt = v4l2_subdev_get_fmt, |
| 552 | .set_fmt = gc0310_set_fmt, | 537 | .set_fmt = v4l2_subdev_get_fmt, /* Only 1 fixed mode supported */ |
| 553 | .get_frame_interval = gc0310_get_frame_interval, | 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 | static const struct v4l2_subdev_ops gc0310_ops = { | 544 | static const struct v4l2_subdev_ops gc0310_ops = { |
| 557 | .video = &gc0310_video_ops, | 545 | .video = &gc0310_video_ops, |
| 558 | .pad = &gc0310_pad_ops, | 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 | /* Use the same lock for controls as for everything else */ | 569 | /* Use the same lock for controls as for everything else */ |
| 569 | hdl->lock = &dev->input_lock; | 570 | sensor->sd.ctrl_handler = hdl; |
| 570 | dev->sd.ctrl_handler = hdl; | ||
| 571 | 571 | ||
| 572 | dev->ctrls.exposure = | 572 | exp_max = GC0310_NATIVE_HEIGHT + GC0310_V_BLANK_DEFAULT; |
| 573 | v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, 4095, 1, 1023); | 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 | /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ | 577 | /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ |
| 576 | dev->ctrls.gain = | 578 | sensor->ctrls.gain = |
| 577 | v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_GAIN, 0, 95, 1, 31); | 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 | static void gc0310_remove(struct i2c_client *client) | 615 | static void gc0310_remove(struct i2c_client *client) |
| 583 | { | 616 | { |
| 584 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 617 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 585 | struct gc0310_device *dev = to_gc0310_sensor(sd); | 618 | struct gc0310_device *sensor = to_gc0310_sensor(sd); |
| 586 | |||
| 587 | dev_dbg(&client->dev, "gc0310_remove...\n"); | ||
| 588 | 619 | ||
| 589 | v4l2_async_unregister_subdev(sd); | 620 | v4l2_async_unregister_subdev(sd); |
| 590 | media_entity_cleanup(&dev->sd.entity); | 621 | v4l2_subdev_cleanup(sd); |
| 591 | v4l2_ctrl_handler_free(&dev->ctrls.handler); | 622 | media_entity_cleanup(&sensor->sd.entity); |
| 592 | mutex_destroy(&dev->input_lock); | 623 | v4l2_ctrl_handler_free(&sensor->ctrls.handler); |
| 593 | pm_runtime_disable(&client->dev); | 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 | struct fwnode_handle *ep_fwnode; | 636 | struct fwnode_handle *ep_fwnode; |
| 599 | struct gc0310_device *dev; | 637 | unsigned long link_freq_bitmap; |
| 638 | u32 mclk; | ||
| 600 | int ret; | 639 | int ret; |
| 601 | 640 | ||
| 602 | /* | 641 | /* |
| 603 | * Sometimes the fwnode graph is initialized by the bridge driver. | 642 | * Sometimes the fwnode graph is initialized by the bridge driver. |
| 604 | * Bridge drivers doing this may also add GPIO mappings, wait for this. | 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 | if (!ep_fwnode) | 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 | fwnode_handle_put(ep_fwnode); | 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); | 690 | ret = gc0310_check_hwcfg(&client->dev); |
| 613 | if (!dev) | 691 | if (ret) |
| 692 | return ret; | ||
| 693 | |||
| 694 | sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); | ||
| 695 | if (!sensor) | ||
| 614 | return -ENOMEM; | 696 | return -ENOMEM; |
| 615 | 697 | ||
| 616 | dev->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); | 698 | sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); |
| 617 | if (IS_ERR(dev->reset)) { | 699 | if (IS_ERR(sensor->reset)) { |
| 618 | return dev_err_probe(&client->dev, PTR_ERR(dev->reset), | 700 | return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), |
| 619 | "getting reset GPIO\n"); | 701 | "getting reset GPIO\n"); |
| 620 | } | 702 | } |
| 621 | 703 | ||
| 622 | dev->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); | 704 | sensor->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); |
| 623 | if (IS_ERR(dev->powerdown)) { | 705 | if (IS_ERR(sensor->powerdown)) { |
| 624 | return dev_err_probe(&client->dev, PTR_ERR(dev->powerdown), | 706 | return dev_err_probe(&client->dev, PTR_ERR(sensor->powerdown), |
| 625 | "getting powerdown GPIO\n"); | 707 | "getting powerdown GPIO\n"); |
| 626 | } | 708 | } |
| 627 | 709 | ||
| 628 | mutex_init(&dev->input_lock); | 710 | v4l2_i2c_subdev_init(&sensor->sd, client, &gc0310_ops); |
| 629 | v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops); | ||
| 630 | gc0310_fill_format(&dev->mode.fmt); | ||
| 631 | 711 | ||
| 632 | pm_runtime_set_suspended(&client->dev); | 712 | sensor->regmap = devm_cci_regmap_init_i2c(client, 8); |
| 633 | pm_runtime_enable(&client->dev); | 713 | if (IS_ERR(sensor->regmap)) |
| 634 | pm_runtime_set_autosuspend_delay(&client->dev, 1000); | 714 | return PTR_ERR(sensor->regmap); |
| 635 | pm_runtime_use_autosuspend(&client->dev); | ||
| 636 | 715 | ||
| 637 | ret = gc0310_detect(client); | 716 | gc0310_power_on(&client->dev); |
| 638 | if (ret) { | ||
| 639 | gc0310_remove(client); | ||
| 640 | return ret; | ||
| 641 | } | ||
| 642 | 717 | ||
| 643 | dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 718 | pm_runtime_set_active(&client->dev); |
| 644 | dev->pad.flags = MEDIA_PAD_FL_SOURCE; | 719 | pm_runtime_get_noresume(&client->dev); |
| 645 | dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | 720 | pm_runtime_enable(&client->dev); |
| 646 | |||
| 647 | ret = gc0310_init_controls(dev); | ||
| 648 | if (ret) { | ||
| 649 | gc0310_remove(client); | ||
| 650 | return ret; | ||
| 651 | } | ||
| 652 | 721 | ||
| 653 | ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); | 722 | ret = gc0310_detect(sensor); |
| 654 | if (ret) { | 723 | if (ret) |
| 655 | gc0310_remove(client); | 724 | goto err_power_down; |
| 656 | return ret; | ||
| 657 | } | ||
| 658 | 725 | ||
| 659 | ret = v4l2_async_register_subdev_sensor(&dev->sd); | 726 | sensor->sd.internal_ops = &gc0310_internal_ops; |
| 660 | if (ret) { | 727 | sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
| 661 | gc0310_remove(client); | 728 | sensor->pad.flags = MEDIA_PAD_FL_SOURCE; |
| 662 | return ret; | 729 | sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; |
| 663 | } | ||
| 664 | 730 | ||
| 665 | return 0; | 731 | ret = gc0310_init_controls(sensor); |
| 666 | } | 732 | if (ret) |
| 733 | goto err_power_down; | ||
| 667 | 734 | ||
| 668 | static int gc0310_suspend(struct device *dev) | 735 | ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); |
| 669 | { | 736 | if (ret) |
| 670 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | 737 | goto err_power_down; |
| 671 | struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); | ||
| 672 | 738 | ||
| 673 | gpiod_set_value_cansleep(gc0310_dev->powerdown, 1); | 739 | sensor->sd.state_lock = sensor->ctrls.handler.lock; |
| 674 | gpiod_set_value_cansleep(gc0310_dev->reset, 1); | 740 | ret = v4l2_subdev_init_finalize(&sensor->sd); |
| 675 | return 0; | 741 | if (ret) |
| 676 | } | 742 | goto err_power_down; |
| 677 | 743 | ||
| 678 | static int gc0310_resume(struct device *dev) | 744 | ret = v4l2_async_register_subdev_sensor(&sensor->sd); |
| 679 | { | 745 | if (ret) |
| 680 | struct v4l2_subdev *sd = dev_get_drvdata(dev); | 746 | goto err_power_down; |
| 681 | struct gc0310_device *gc0310_dev = to_gc0310_sensor(sd); | ||
| 682 | 747 | ||
| 683 | usleep_range(10000, 15000); | 748 | pm_runtime_set_autosuspend_delay(&client->dev, 1000); |
| 684 | gpiod_set_value_cansleep(gc0310_dev->reset, 0); | 749 | pm_runtime_use_autosuspend(&client->dev); |
| 685 | usleep_range(10000, 15000); | 750 | pm_runtime_put_autosuspend(&client->dev); |
| 686 | gpiod_set_value_cansleep(gc0310_dev->powerdown, 0); | ||
| 687 | 751 | ||
| 688 | return 0; | 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 | static const struct acpi_device_id gc0310_acpi_match[] = { | 763 | static const struct acpi_device_id gc0310_acpi_match[] = { |
| 694 | {"INT0310"}, | 764 | {"INT0310"}, |
| @@ -708,5 +778,6 @@ static struct i2c_driver gc0310_driver = { · 13 unmodified lines | |||
| 708 | module_i2c_driver(gc0310_driver); | 778 | module_i2c_driver(gc0310_driver); |
| 709 | 779 | ||
| 710 | MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); | 780 | MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); |
| 781 | MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); | ||
| 711 | MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); | 782 | MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); |
| 712 | MODULE_LICENSE("GPL"); | 783 | MODULE_LICENSE("GPL"); |
| @@ -779,8 +779,6 @@ static void gc2235_remove(struct i2c_client *client) · 778 unmodified lines | |||
| 779 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 779 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
| 780 | struct gc2235_device *dev = to_gc2235_sensor(sd); | 780 | struct gc2235_device *dev = to_gc2235_sensor(sd); |
| 781 | 781 | ||
| 782 | dev_dbg(&client->dev, "gc2235_remove...\n"); | ||
| 783 | |||
| 784 | dev->platform_data->csi_cfg(sd, 0); | 782 | dev->platform_data->csi_cfg(sd, 0); |
| 785 | 783 | ||
| 786 | v4l2_device_unregister_subdev(sd); | 784 | v4l2_device_unregister_subdev(sd); |
| @@ -179,21 +179,21 @@ struct gc2235_write_ctrl { · 178 unmodified lines | |||
| 179 | struct gc2235_write_buffer buffer; | 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 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ | 183 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ |
| 184 | { GC2235_8BIT, 0x10, 0x91}, /* start mipi */ | 184 | { GC2235_8BIT, 0x10, 0x91}, /* start mipi */ |
| 185 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ | 185 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ |
| 186 | { GC2235_TOK_TERM, 0, 0 } | 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 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ | 190 | { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ |
| 191 | { GC2235_8BIT, 0x10, 0x01}, /* stop mipi */ | 191 | { GC2235_8BIT, 0x10, 0x01}, /* stop mipi */ |
| 192 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ | 192 | { GC2235_8BIT, 0xfe, 0x00}, /* switch to P0 */ |
| 193 | { GC2235_TOK_TERM, 0, 0 } | 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 | /* System */ | 197 | /* System */ |
| 198 | { GC2235_8BIT, 0xfe, 0x80 }, | 198 | { GC2235_8BIT, 0xfe, 0x80 }, |
| 199 | { GC2235_8BIT, 0xfe, 0x80 }, | 199 | { GC2235_8BIT, 0xfe, 0x80 }, |
| @@ -268,7 +268,7 @@ static struct gc2235_reg const gc2235_init_settings[] = { · 68 unmodified lines | |||
| 268 | * Register settings for various resolution | 268 | * Register settings for various resolution |
| 269 | */ | 269 | */ |
| 270 | #if ENABLE_NON_PREVIEW | 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 | { GC2235_8BIT, 0x8b, 0xa0 }, | 272 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 273 | { GC2235_8BIT, 0x8c, 0x02 }, | 273 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 274 | 274 | ||
| @@ -321,7 +321,7 @@ static struct gc2235_reg const gc2235_1296_736_30fps[] = { · 46 unmodified lines | |||
| 321 | { GC2235_TOK_TERM, 0, 0 } | 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 | { GC2235_8BIT, 0x8b, 0xa0 }, | 325 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 326 | { GC2235_8BIT, 0x8c, 0x02 }, | 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 | #endif | 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 | { GC2235_8BIT, 0x8b, 0xa0 }, | 377 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 378 | { GC2235_8BIT, 0x8c, 0x02 }, | 378 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 379 | 379 | ||
| @@ -418,7 +418,7 @@ static struct gc2235_reg const gc2235_1600_900_30fps[] = { · 38 unmodified lines | |||
| 418 | { GC2235_TOK_TERM, 0, 0 } | 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 | { GC2235_8BIT, 0x8b, 0xa0 }, | 422 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 423 | { GC2235_8BIT, 0x8c, 0x02 }, | 423 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 424 | 424 | ||
| @@ -463,7 +463,7 @@ static struct gc2235_reg const gc2235_1616_1082_30fps[] = { · 38 unmodified lines | |||
| 463 | { GC2235_TOK_TERM, 0, 0 } | 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 | { GC2235_8BIT, 0x8b, 0xa0 }, | 467 | { GC2235_8BIT, 0x8b, 0xa0 }, |
| 468 | { GC2235_8BIT, 0x8c, 0x02 }, | 468 | { GC2235_8BIT, 0x8c, 0x02 }, |
| 469 | 469 | ||
| @@ -236,7 +236,7 @@ struct ov2722_write_ctrl { · 235 unmodified lines | |||
| 236 | * Register settings for various resolution | 236 | * Register settings for various resolution |
| 237 | */ | 237 | */ |
| 238 | #if 0 | 238 | #if 0 |
| 239 | static struct ov2722_reg const ov2722_QVGA_30fps[] = { | 239 | static const struct ov2722_reg ov2722_QVGA_30fps[] = { |
| 240 | {OV2722_8BIT, 0x3718, 0x10}, | 240 | {OV2722_8BIT, 0x3718, 0x10}, |
| 241 | {OV2722_8BIT, 0x3702, 0x0c}, | 241 | {OV2722_8BIT, 0x3702, 0x0c}, |
| 242 | {OV2722_8BIT, 0x373a, 0x1c}, | 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 | {OV2722_8BIT, 0x3718, 0x10}, | 350 | {OV2722_8BIT, 0x3718, 0x10}, |
| 351 | {OV2722_8BIT, 0x3702, 0x18}, | 351 | {OV2722_8BIT, 0x3702, 0x18}, |
| 352 | {OV2722_8BIT, 0x373a, 0x3c}, | 352 | {OV2722_8BIT, 0x373a, 0x3c}, |
| @@ -455,7 +455,7 @@ static struct ov2722_reg const ov2722_480P_30fps[] = { · 102 unmodified lines | |||
| 455 | {OV2722_TOK_TERM, 0, 0}, | 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 | {OV2722_8BIT, 0x3718, 0x10}, | 459 | {OV2722_8BIT, 0x3718, 0x10}, |
| 460 | {OV2722_8BIT, 0x3702, 0x18}, | 460 | {OV2722_8BIT, 0x3702, 0x18}, |
| 461 | {OV2722_8BIT, 0x373a, 0x3c}, | 461 | {OV2722_8BIT, 0x373a, 0x3c}, |
| @@ -565,7 +565,7 @@ static struct ov2722_reg const ov2722_VGA_30fps[] = { · 103 unmodified lines | |||
| 565 | }; | 565 | }; |
| 566 | #endif | 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 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for | 569 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for |
| 570 | a whole frame complete.(vblank) */ | 570 | a whole frame complete.(vblank) */ |
| 571 | {OV2722_8BIT, 0x3718, 0x10}, | 571 | {OV2722_8BIT, 0x3718, 0x10}, |
| @@ -667,7 +667,7 @@ static struct ov2722_reg const ov2722_1632_1092_30fps[] = { · 95 unmodified lines | |||
| 667 | {OV2722_TOK_TERM, 0, 0} | 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 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for | 671 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for |
| 672 | a whole frame complete.(vblank) */ | 672 | a whole frame complete.(vblank) */ |
| 673 | {OV2722_8BIT, 0x3718, 0x10}, | 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 | #if 0 | 771 | #if 0 |
| 772 | static struct ov2722_reg const ov2722_1M3_30fps[] = { | 772 | static const struct ov2722_reg ov2722_1M3_30fps[] = { |
| 773 | {OV2722_8BIT, 0x3718, 0x10}, | 773 | {OV2722_8BIT, 0x3718, 0x10}, |
| 774 | {OV2722_8BIT, 0x3702, 0x24}, | 774 | {OV2722_8BIT, 0x3702, 0x24}, |
| 775 | {OV2722_8BIT, 0x373a, 0x60}, | 775 | {OV2722_8BIT, 0x373a, 0x60}, |
| @@ -877,7 +877,7 @@ static struct ov2722_reg const ov2722_1M3_30fps[] = { · 101 unmodified lines | |||
| 877 | }; | 877 | }; |
| 878 | #endif | 878 | #endif |
| 879 | 879 | ||
| 880 | static struct ov2722_reg const ov2722_1080p_30fps[] = { | 880 | static const struct ov2722_reg ov2722_1080p_30fps[] = { |
| 881 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole | 881 | {OV2722_8BIT, 0x3021, 0x03}, /* For stand wait for a whole |
| 882 | frame complete.(vblank) */ | 882 | frame complete.(vblank) */ |
| 883 | {OV2722_8BIT, 0x3718, 0x10}, | 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 | #if 0 /* Currently unused */ | 985 | #if 0 /* Currently unused */ |
| 986 | static struct ov2722_reg const ov2722_720p_30fps[] = { | 986 | static const struct ov2722_reg ov2722_720p_30fps[] = { |
| 987 | {OV2722_8BIT, 0x3021, 0x03}, | 987 | {OV2722_8BIT, 0x3021, 0x03}, |
| 988 | {OV2722_8BIT, 0x3718, 0x10}, | 988 | {OV2722_8BIT, 0x3718, 0x10}, |
| 989 | {OV2722_8BIT, 0x3702, 0x24}, | 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 | if (stream_env->stream_state == CSS_STREAM_STARTED) { | 389 | if (stream_env->stream_state == CSS_STREAM_STARTED) { |
| 390 | timeout = jiffies + msecs_to_jiffies(40); | 390 | timeout = jiffies + msecs_to_jiffies(200); |
| 391 | while (1) { | 391 | while (1) { |
| 392 | if (ia_css_stream_has_stopped(stream_env->stream)) | 392 | if (ia_css_stream_has_stopped(stream_env->stream)) |
| 393 | break; | 393 | break; |
| @@ -19,28 +19,11 @@ · 18 unmodified lines | |||
| 19 | #define CSI2_PAD_SOURCE 1 | 19 | #define CSI2_PAD_SOURCE 1 |
| 20 | #define CSI2_PADS_NUM 2 | 20 | #define CSI2_PADS_NUM 2 |
| 21 | 21 | ||
| 22 | #define CSI2_MAX_ACPI_GPIOS 2u | ||
| 23 | |||
| 24 | struct acpi_device; | ||
| 25 | struct v4l2_device; | 22 | struct v4l2_device; |
| 26 | 23 | ||
| 27 | struct atomisp_device; | 24 | struct atomisp_device; |
| 28 | struct atomisp_sub_device; | 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 | struct atomisp_mipi_csi2_device { | 27 | struct atomisp_mipi_csi2_device { |
| 45 | struct v4l2_subdev subdev; | 28 | struct v4l2_subdev subdev; |
| 46 | struct media_pad pads[CSI2_PADS_NUM]; | 29 | struct media_pad pads[CSI2_PADS_NUM]; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/dmi.h> | 15 | #include <linux/dmi.h> |
| 16 | #include <linux/platform_data/x86/int3472.h> | ||
| 16 | #include <linux/property.h> | 17 | #include <linux/property.h> |
| 17 | 18 | ||
| 18 | #include <media/ipu-bridge.h> | 19 | #include <media/ipu-bridge.h> |
| @@ -24,39 +25,6 @@ · 5 unmodified lines | |||
| 24 | 25 | ||
| 25 | #define PMC_CLK_RATE_19_2MHZ 19200000 | 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 | * dc2f6c4f-045b-4f1d-97b9-882a6860a4be | 29 | * dc2f6c4f-045b-4f1d-97b9-882a6860a4be |
| 62 | * This _DSM GUID returns a package with n*2 strings, with each set of 2 strings | 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 | return gmin_cfg_get_int(adev, "CsiPort", port); | 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 | 295 | * Alloc and fill an int3472_discrete_device struct so that we can re-use |
| 401 | * powerdown signals on Intel Bay Trail (BYT) and Cherry Trail (CHT) devices, | 296 | * the INT3472 sensor GPIO mapping code. |
| 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(). | ||
| 413 | * | 297 | * |
| 414 | * Note this code uses the same DSM GUID as the int3472_gpio_guid in | 298 | * This gets called from ipu_bridge_init() which runs only once per boot, |
| 415 | * the INT3472 discrete.c code and there is some overlap, but there are | 299 | * the created faux int3472 device is leaked on purpose to keep the created |
| 416 | * enough differences that it is difficult to share the code. | 300 | * GPIO mappings around permanently. |
| 417 | */ | 301 | */ |
| 418 | static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev) | 302 | static int atomisp_csi2_add_gpio_mappings(struct acpi_device *adev) |
| 419 | { | 303 | { |
| 420 | struct atomisp_csi2_acpi_gpio_parsing_data data = { }; | 304 | struct int3472_discrete_device *int3472; |
| 421 | LIST_HEAD(resource_list); | ||
| 422 | union acpi_object *obj; | ||
| 423 | unsigned int i, j; | ||
| 424 | int ret; | 305 | int ret; |
| 425 | 306 | ||
| 426 | obj = acpi_evaluate_dsm_typed(adev->handle, &intel_sensor_module_guid, | 307 | /* Max num GPIOs we've seen plus a terminator */ |
| 427 | 0x00, 1, NULL, ACPI_TYPE_STRING); | 308 | int3472 = kzalloc(struct_size(int3472, gpios.table, INT3472_MAX_SENSOR_GPIOS + 1), |
| 428 | if (obj) { | 309 | GFP_KERNEL); |
| 429 | acpi_handle_info(adev->handle, "%s: Sensor module id: '%s'\n", | 310 | if (!int3472) |
| 430 | dev_name(&adev->dev), obj->string.pointer); | 311 | return -ENOMEM; |
| 431 | ACPI_FREE(obj); | ||
| 432 | } | ||
| 433 | 312 | ||
| 434 | /* | 313 | /* |
| 435 | * First get the GPIO-settings count and then get count GPIO-settings | 314 | * On atomisp the _DSM to get the GPIO type must be made on the sensor |
| 436 | * values. Note the order of these may differ from the order in which | 315 | * adev, rather than on a separate INT3472 adev. |
| 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. | ||
| 439 | */ | 316 | */ |
| 440 | obj = acpi_evaluate_dsm_typed(adev->handle, | 317 | int3472->adev = adev; |
| 441 | &intel_sensor_gpio_info_guid, 0x00, 1, | 318 | int3472->dev = &adev->dev; |
| 442 | NULL, ACPI_TYPE_INTEGER); | 319 | int3472->sensor = adev; |
| 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); | ||
| 451 | 320 | ||
| 452 | if (data.settings_count > CSI2_MAX_ACPI_GPIOS) { | 321 | int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev)); |
| 453 | acpi_handle_err(adev->handle, "%s: Too many GPIOs %u > %u\n", | 322 | if (!int3472->sensor_name) { |
| 454 | dev_name(&adev->dev), data.settings_count, | 323 | kfree(int3472); |
| 455 | CSI2_MAX_ACPI_GPIOS); | 324 | return -ENOMEM; |
| 456 | return -EOVERFLOW; | ||
| 457 | } | 325 | } |
| 458 | 326 | ||
| 459 | for (i = 0; i < data.settings_count; i++) { | 327 | ret = int3472_discrete_parse_crs(int3472); |
| 460 | /* | 328 | if (ret) { |
| 461 | * i + 2 because the index of this _DSM function is 1-based | 329 | int3472_discrete_cleanup(int3472); |
| 462 | * and the first function is just a count. | 330 | kfree(int3472); |
| 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); | ||
| 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 | return ret; | 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 | if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM)) | 234 | if (WARN_ON(css_pipe_id >= IA_CSS_PIPE_ID_NUM)) |
| 235 | return -EINVAL; | 235 | return -EINVAL; |
| 236 | 236 | ||
| 237 | if (pipe->stopping) | ||
| 238 | return -EINVAL; | ||
| 239 | |||
| 240 | space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); | 237 | space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); |
| 241 | while (space--) { | 238 | while (space--) { |
| 242 | struct ia_css_frame *frame; | 239 | struct ia_css_frame *frame; |
| @@ -367,7 +364,7 @@ static void atomisp_buf_queue(struct vb2_buffer *vb) · 124 unmodified lines | |||
| 367 | mutex_lock(&asd->isp->mutex); | 364 | mutex_lock(&asd->isp->mutex); |
| 368 | 365 | ||
| 369 | ret = atomisp_pipe_check(pipe, false); | 366 | ret = atomisp_pipe_check(pipe, false); |
| 370 | if (ret || pipe->stopping) { | 367 | if (ret) { |
| 371 | spin_lock_irqsave(&pipe->irq_lock, irqflags); | 368 | spin_lock_irqsave(&pipe->irq_lock, irqflags); |
| 372 | atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); | 369 | atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); |
| 373 | spin_unlock_irqrestore(&pipe->irq_lock, irqflags); | 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 | atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00); | 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 | int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) | 915 | int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) |
| 860 | { | 916 | { |
| 861 | struct atomisp_video_pipe *pipe = vq_to_pipe(vq); | 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 | ret = atomisp_css_start(asd); | 966 | ret = atomisp_css_start(asd); |
| 911 | if (ret) { | 967 | if (ret) { |
| 912 | atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); | 968 | atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); |
| 969 | media_pipeline_stop(&asd->video_out.vdev.entity.pads[0]); | ||
| 913 | goto out_unlock; | 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 | video, s_stream, 1); | 1006 | video, s_stream, 1); |
| 950 | if (ret) { | 1007 | if (ret) { |
| 951 | dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret); | 1008 | dev_err(isp->dev, "Starting sensor stream failed: %d\n", ret); |
| 952 | spin_lock_irqsave(&isp->lock, irqflags); | 1009 | atomisp_stop_stream(pipe, false, VB2_BUF_STATE_QUEUED); |
| 953 | asd->streaming = false; | ||
| 954 | spin_unlock_irqrestore(&isp->lock, irqflags); | ||
| 955 | ret = -EINVAL; | ||
| 956 | goto out_unlock; | ||
| 957 | } | 1010 | } |
| 958 | 1011 | ||
| 959 | out_unlock: | 1012 | out_unlock: |
| @@ -964,74 +1017,12 @@ out_unlock: · 4 unmodified lines | |||
| 964 | void atomisp_stop_streaming(struct vb2_queue *vq) | 1017 | void atomisp_stop_streaming(struct vb2_queue *vq) |
| 965 | { | 1018 | { |
| 966 | struct atomisp_video_pipe *pipe = vq_to_pipe(vq); | 1019 | struct atomisp_video_pipe *pipe = vq_to_pipe(vq); |
| 967 | struct atomisp_sub_device *asd = pipe->asd; | 1020 | struct atomisp_device *isp = pipe->asd->isp; |
| 968 | struct atomisp_device *isp = asd->isp; | ||
| 969 | struct pci_dev *pdev = to_pci_dev(isp->dev); | ||
| 970 | unsigned long flags; | ||
| 971 | int ret; | ||
| 972 | 1021 | ||
| 973 | dev_dbg(isp->dev, "Stop stream\n"); | 1022 | dev_dbg(isp->dev, "Stop stream\n"); |
| 974 | 1023 | ||
| 975 | mutex_lock(&isp->mutex); | 1024 | mutex_lock(&isp->mutex); |
| 976 | /* | 1025 | atomisp_stop_stream(pipe, true, VB2_BUF_STATE_ERROR); |
| 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]); | ||
| 1035 | mutex_unlock(&isp->mutex); | 1026 | mutex_unlock(&isp->mutex); |
| 1036 | } | 1027 | } |
| 1037 | 1028 | ||
| @@ -57,9 +57,6 @@ struct atomisp_video_pipe { · 56 unmodified lines | |||
| 57 | /* Filled through atomisp_get_css_frame_info() on queue setup */ | 57 | /* Filled through atomisp_get_css_frame_info() on queue setup */ |
| 58 | struct ia_css_frame_info frame_info; | 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 | * irq_lock is used to protect video buffer state change operations and | 61 | * irq_lock is used to protect video buffer state change operations and |
| 65 | * also to make activeq and capq operations atomic. | 62 | * also to make activeq and capq operations atomic. |
| @@ -29,7 +29,6 @@ · 28 unmodified lines | |||
| 29 | #include "atomisp_internal.h" | 29 | #include "atomisp_internal.h" |
| 30 | #include "atomisp-regs.h" | 30 | #include "atomisp-regs.h" |
| 31 | #include "atomisp_dfs_tables.h" | 31 | #include "atomisp_dfs_tables.h" |
| 32 | #include "atomisp_drvfs.h" | ||
| 33 | #include "hmm/hmm.h" | 32 | #include "hmm/hmm.h" |
| 34 | #include "atomisp_trace_event.h" | 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 | MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); | 1496 | MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); |
| 1498 | 1497 | ||
| 1499 | static struct pci_driver atomisp_pci_driver = { | 1498 | static struct pci_driver atomisp_pci_driver = { |
| 1500 | .driver = { | ||
| 1501 | .dev_groups = dbg_attr_groups, | ||
| 1502 | }, | ||
| 1503 | .name = "atomisp-isp2", | 1499 | .name = "atomisp-isp2", |
| 1504 | .id_table = atomisp_pci_tbl, | 1500 | .id_table = atomisp_pci_tbl, |
| 1505 | .probe = atomisp_pci_probe, | 1501 | .probe = atomisp_pci_probe, |
| @@ -1513,3 +1509,4 @@ MODULE_AUTHOR("Xiaolin Zhang <xiaolin.zhang@intel.com>"); · 7 unmodified lines | |||
| 1513 | MODULE_LICENSE("GPL"); | 1509 | MODULE_LICENSE("GPL"); |
| 1514 | MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); | 1510 | MODULE_DESCRIPTION("Intel ATOM Platform ISP Driver"); |
| 1515 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); | 1511 | MODULE_IMPORT_NS("INTEL_IPU_BRIDGE"); |
| 1512 | MODULE_IMPORT_NS("INTEL_INT3472_DISCRETE"); | ||
| @@ -10,14 +10,9 @@ · 9 unmodified lines | |||
| 10 | /* Override the definition of max/min from Linux kernel */ | 10 | /* Override the definition of max/min from Linux kernel */ |
| 11 | #include <linux/minmax.h> | 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 | #define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0) | 13 | #define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0) |
| 17 | #define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) | 14 | #define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b)) |
| 18 | #define CEIL_MUL2(a, b) (((a) + (b) - 1) & ~((b) - 1)) | ||
| 19 | #define CEIL_SHIFT(a, b) (((a) + (1 << (b)) - 1) >> (b)) | 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 | * For SP and ISP, SDK provides the definition of OP_std_modadd. | 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 | static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; | 28 | static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; |
| 29 | static bool hmm_initialized; | 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 | int hmm_init(void) | 31 | int hmm_init(void) |
| 114 | { | 32 | { |
| 115 | int ret; | 33 | int ret; |
| @@ -130,14 +48,6 @@ int hmm_init(void) · 14 unmodified lines | |||
| 130 | */ | 48 | */ |
| 131 | dummy_ptr = hmm_alloc(1); | 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 | return ret; | 51 | return ret; |
| 142 | } | 52 | } |
| 143 | 53 | ||
| @@ -145,7 +55,6 @@ void hmm_cleanup(void) · 1 unmodified line | |||
| 145 | { | 55 | { |
| 146 | if (dummy_ptr == mmgr_EXCEPTION) | 56 | if (dummy_ptr == mmgr_EXCEPTION) |
| 147 | return; | 57 | return; |
| 148 | sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); | ||
| 149 | 58 | ||
| 150 | /* free dummy memory first */ | 59 | /* free dummy memory first */ |
| 151 | hmm_free(dummy_ptr); | 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 | unsigned int pgnr) | 37 | unsigned int pgnr) |
| 38 | { | 38 | { |
| 39 | check_bodev_null_return(bdev, -EINVAL); | 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 | /* prevent zero size buffer object */ | 40 | /* prevent zero size buffer object */ |
| 43 | if (pgnr == 0) { | 41 | if (pgnr == 0) { |
| 44 | dev_err(atomisp_dev, "0 size buffer is not allowed.\n"); | 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 | spin_lock_init(&bdev->list_lock); | 339 | spin_lock_init(&bdev->list_lock); |
| 342 | mutex_init(&bdev->rbtree_mutex); | 340 | mutex_init(&bdev->rbtree_mutex); |
| 343 | 341 | ||
| 344 | bdev->flag = HMM_BO_DEVICE_INITED; | ||
| 345 | 342 | ||
| 346 | INIT_LIST_HEAD(&bdev->entire_bo_list); | 343 | INIT_LIST_HEAD(&bdev->entire_bo_list); |
| 347 | bdev->allocated_rbtree = RB_ROOT; | 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 | __bo_insert_to_free_rbtree(&bdev->free_rbtree, bo); | 374 | __bo_insert_to_free_rbtree(&bdev->free_rbtree, bo); |
| 378 | 375 | ||
| 376 | bdev->flag = HMM_BO_DEVICE_INITED; | ||
| 377 | |||
| 379 | return 0; | 378 | return 0; |
| 380 | } | 379 | } |
| 381 | 380 | ||
| @@ -102,8 +102,6 @@ struct ia_css_yuvpp_settings { · 101 unmodified lines | |||
| 102 | struct osys_object; | 102 | struct osys_object; |
| 103 | 103 | ||
| 104 | struct ia_css_pipe { | 104 | struct ia_css_pipe { |
| 105 | /* TODO: Remove stop_requested and use stop_requested in the pipeline */ | ||
| 106 | bool stop_requested; | ||
| 107 | struct ia_css_pipe_config config; | 105 | struct ia_css_pipe_config config; |
| 108 | struct ia_css_pipe_extra_config extra_config; | 106 | struct ia_css_pipe_extra_config extra_config; |
| 109 | struct ia_css_pipe_info info; | 107 | struct ia_css_pipe_info info; |
| @@ -11,9 +11,11 @@ · 10 unmodified lines | |||
| 11 | * CSS-API header file for Advanced Noise Reduction kernel v1 | 11 | * CSS-API header file for Advanced Noise Reduction kernel v1 |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/math.h> | ||
| 15 | |||
| 14 | /* Application specific DMA settings */ | 16 | /* Application specific DMA settings */ |
| 15 | #define ANR_BPP 10 | 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 | /* Advanced Noise Reduction configuration. | 20 | /* Advanced Noise Reduction configuration. |
| 19 | * This is also known as Low-Light. | 21 | * This is also known as Low-Light. |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | #ifndef __IA_CSS_DPC2_PARAM_H | 7 | #ifndef __IA_CSS_DPC2_PARAM_H |
| 8 | #define __IA_CSS_DPC2_PARAM_H | 8 | #define __IA_CSS_DPC2_PARAM_H |
| 9 | 9 | ||
| 10 | #include <linux/math.h> | ||
| 11 | |||
| 10 | #include "type_support.h" | 12 | #include "type_support.h" |
| 11 | #include "vmem.h" /* for VMEM_ARRAY*/ | 13 | #include "vmem.h" /* for VMEM_ARRAY*/ |
| 12 | 14 | ||
| @@ -19,12 +21,12 @@ · 6 unmodified lines | |||
| 19 | /* 3 lines state per color plane input_line_state */ | 21 | /* 3 lines state per color plane input_line_state */ |
| 20 | #define DPC2_STATE_INPUT_BUFFER_HEIGHT (3 * NUM_PLANES) | 22 | #define DPC2_STATE_INPUT_BUFFER_HEIGHT (3 * NUM_PLANES) |
| 21 | /* Each plane has width equal to half frame line */ | 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 | /* 1 line state per color plane for local deviation state*/ | 26 | /* 1 line state per color plane for local deviation state*/ |
| 25 | #define DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT (1 * NUM_PLANES) | 27 | #define DPC2_STATE_LOCAL_DEVIATION_BUFFER_HEIGHT (1 * NUM_PLANES) |
| 26 | /* Each plane has width equal to half frame line */ | 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 | /* MINMAX state buffer stores 1 full input line (GR-R color line) */ | 31 | /* MINMAX state buffer stores 1 full input line (GR-R color line) */ |
| 30 | #define DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT 1 | 32 | #define DPC2_STATE_SECOND_MINMAX_BUFFER_HEIGHT 1 |
| @@ -141,10 +141,10 @@ convert_coords_to_ispparams( · 140 unmodified lines | |||
| 141 | 141 | ||
| 142 | /* similar to topleft_y calculation, but round up if ymax | 142 | /* similar to topleft_y calculation, but round up if ymax |
| 143 | * has any fraction bits */ | 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 | s.in_block_height = bottom_y - topleft_y + dvs_interp_envelope; | 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 | s.in_block_width = bottom_x - topleft_x + dvs_interp_envelope; | 148 | s.in_block_width = bottom_x - topleft_x + dvs_interp_envelope; |
| 149 | 149 | ||
| 150 | topleft_x_frac = topleft_x << (DVS_COORD_FRAC_BITS); | 150 | topleft_x_frac = topleft_x << (DVS_COORD_FRAC_BITS); |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | |||
| 7 | #ifndef __IA_CSS_EED1_8_PARAM_H | 7 | #ifndef __IA_CSS_EED1_8_PARAM_H |
| 8 | #define __IA_CSS_EED1_8_PARAM_H | 8 | #define __IA_CSS_EED1_8_PARAM_H |
| 9 | 9 | ||
| 10 | #include <linux/math.h> | ||
| 11 | |||
| 10 | #include "type_support.h" | 12 | #include "type_support.h" |
| 11 | #include "vmem.h" /* needed for VMEM_ARRAY */ | 13 | #include "vmem.h" /* needed for VMEM_ARRAY */ |
| 12 | 14 | ||
| @@ -35,35 +37,35 @@ · 22 unmodified lines | |||
| 35 | #define EED1_8_STATE_INPUT_BUFFER_HEIGHT (5 * NUM_PLANES) | 37 | #define EED1_8_STATE_INPUT_BUFFER_HEIGHT (5 * NUM_PLANES) |
| 36 | 38 | ||
| 37 | /* Each plane has width equal to half frame line */ | 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 | /* 1 line state per color plane LD_H state */ | 42 | /* 1 line state per color plane LD_H state */ |
| 41 | #define EED1_8_STATE_LD_H_HEIGHT (1 * NUM_PLANES) | 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 | /* 1 line state per color plane LD_V state */ | 46 | /* 1 line state per color plane LD_V state */ |
| 45 | #define EED1_8_STATE_LD_V_HEIGHT (1 * NUM_PLANES) | 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 | /* 1 line (single plane) state for D_Hr state */ | 50 | /* 1 line (single plane) state for D_Hr state */ |
| 49 | #define EED1_8_STATE_D_HR_HEIGHT 1 | 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 | /* 1 line (single plane) state for D_Hb state */ | 54 | /* 1 line (single plane) state for D_Hb state */ |
| 53 | #define EED1_8_STATE_D_HB_HEIGHT 1 | 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 | /* 2 lines (single plane) state for D_Vr state */ | 58 | /* 2 lines (single plane) state for D_Vr state */ |
| 57 | #define EED1_8_STATE_D_VR_HEIGHT 2 | 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 | /* 2 line (single plane) state for D_Vb state */ | 62 | /* 2 line (single plane) state for D_Vb state */ |
| 61 | #define EED1_8_STATE_D_VB_HEIGHT 2 | 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 | /* 2 lines state for R and B (= 2 planes) rb_zipped_state */ | 66 | /* 2 lines state for R and B (= 2 planes) rb_zipped_state */ |
| 65 | #define EED1_8_STATE_RB_ZIPPED_HEIGHT (2 * 2) | 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 | #if EED1_8_FC_ENABLE_MEDIAN | 70 | #if EED1_8_FC_ENABLE_MEDIAN |
| 69 | /* 1 full input line (GR-R color line) for Yc state */ | 71 | /* 1 full input line (GR-R color line) for Yc state */ |
| @@ -72,11 +74,11 @@ · 2 unmodified lines | |||
| 72 | 74 | ||
| 73 | /* 1 line state per color plane Cg_state */ | 75 | /* 1 line state per color plane Cg_state */ |
| 74 | #define EED1_8_STATE_CG_HEIGHT (1 * NUM_PLANES) | 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 | /* 1 line state per color plane Co_state */ | 79 | /* 1 line state per color plane Co_state */ |
| 78 | #define EED1_8_STATE_CO_HEIGHT (1 * NUM_PLANES) | 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 | /* 1 full input line (GR-R color line) for AbsK state */ | 83 | /* 1 full input line (GR-R color line) for AbsK state */ |
| 82 | #define EED1_8_STATE_ABSK_HEIGHT 1 | 84 | #define EED1_8_STATE_ABSK_HEIGHT 1 |
| @@ -4,6 +4,8 @@ · 3 unmodified lines | |||
| 4 | * Copyright (c) 2015, Intel Corporation. | 4 | * Copyright (c) 2015, Intel Corporation. |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <linux/math.h> | ||
| 8 | |||
| 7 | #include <assert_support.h> | 9 | #include <assert_support.h> |
| 8 | #include <ia_css_frame_public.h> | 10 | #include <ia_css_frame_public.h> |
| 9 | #include <ia_css_frame.h> | 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 | &my_info | 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 | my_info.res.height = info->res.height; | 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 | my_info.format = info->format; | 79 | my_info.format = info->format; |
| 78 | my_info.raw_bit_depth = FPN_BITS_PER_PIXEL; | 80 | my_info.raw_bit_depth = FPN_BITS_PER_PIXEL; |
| 79 | my_info.raw_bayer_order = info->raw_bayer_order; | 81 | my_info.raw_bayer_order = info->raw_bayer_order; |
| @@ -22,7 +22,7 @@ struct sh_css_isp_sc_params { · 21 unmodified lines | |||
| 22 | * vec_slice is used for 2 adjacent vectors of shading gains. | 22 | * vec_slice is used for 2 adjacent vectors of shading gains. |
| 23 | * The number of shift times by vec_slice is 8. | 23 | * The number of shift times by vec_slice is 8. |
| 24 | * Max grid cell bqs to support the shading table centerting: N = 32 | 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 | #define SH_CSS_SC_INTERPED_GAIN_HOR_SLICE_TIMES 8 | 27 | #define SH_CSS_SC_INTERPED_GAIN_HOR_SLICE_TIMES 8 |
| 28 | 28 | ||
| @@ -91,8 +91,7 @@ configure_kernel( · 90 unmodified lines | |||
| 91 | unsigned int vf_log_ds = 0; | 91 | unsigned int vf_log_ds = 0; |
| 92 | 92 | ||
| 93 | /* First compute value */ | 93 | /* First compute value */ |
| 94 | if (vf_info) | 94 | if (vf_info) { |
| 95 | { | ||
| 96 | err = sh_css_vf_downscale_log2(out_info, vf_info, &vf_log_ds); | 95 | err = sh_css_vf_downscale_log2(out_info, vf_info, &vf_log_ds); |
| 97 | if (err) | 96 | if (err) |
| 98 | return err; | 97 | return err; |
| @@ -8,9 +8,10 @@ Copyright (c) 2010 - 2015, Intel Corporation. · 7 unmodified lines | |||
| 8 | #ifndef _INPUT_BUF_ISP_H_ | 8 | #ifndef _INPUT_BUF_ISP_H_ |
| 9 | #define _INPUT_BUF_ISP_H_ | 9 | #define _INPUT_BUF_ISP_H_ |
| 10 | 10 | ||
| 11 | #include <linux/math.h> | ||
| 12 | |||
| 11 | /* Temporary include, since IA_CSS_BINARY_MODE_COPY is still needed */ | 13 | /* Temporary include, since IA_CSS_BINARY_MODE_COPY is still needed */ |
| 12 | #include "sh_css_defs.h" | 14 | #include "sh_css_defs.h" |
| 13 | #include "isp_const.h" /* MAX_VECTORS_PER_INPUT_LINE */ | ||
| 14 | 15 | ||
| 15 | #define INPUT_BUF_HEIGHT 2 /* double buffer */ | 16 | #define INPUT_BUF_HEIGHT 2 /* double buffer */ |
| 16 | #define INPUT_BUF_LINES 2 | 17 | #define INPUT_BUF_LINES 2 |
| @@ -22,7 +23,8 @@ Copyright (c) 2010 - 2015, Intel Corporation. · 5 unmodified lines | |||
| 22 | /* In continuous mode, the input buffer must be a fixed size for all binaries | 23 | /* In continuous mode, the input buffer must be a fixed size for all binaries |
| 23 | * and at a fixed address since it will be used by the SP. */ | 24 | * and at a fixed address since it will be used by the SP. */ |
| 24 | #define EXTRA_INPUT_VECTORS 2 /* For left padding */ | 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 | /* The input buffer should be on a fixed address in vmem, for continuous capture */ | 29 | /* The input buffer should be on a fixed address in vmem, for continuous capture */ |
| 28 | #define INPUT_BUF_ADDR 0x0 | 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 | #include "sp.h" | 51 | #include "sp.h" |
| 52 | #include "isp.h" | 52 | #include "isp.h" |
| 53 | #include "type_support.h" | 53 | #include "type_support.h" |
| 54 | #include "math_support.h" /* CEIL_DIV */ | ||
| 55 | #include "input_system.h" /* input_formatter_reg_load */ | 54 | #include "input_system.h" /* input_formatter_reg_load */ |
| 56 | #include "ia_css_tagger_common.h" | 55 | #include "ia_css_tagger_common.h" |
| 57 | 56 | ||
| @@ -4,15 +4,16 @@ · 3 unmodified lines | |||
| 4 | * Copyright (c) 2015, Intel Corporation. | 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 | #include "assert_support.h" | 10 | #include "assert_support.h" |
| 11 | #include "atomisp_internal.h" | ||
| 12 | #include "hmm.h" | ||
| 12 | #include "ia_css_debug.h" | 13 | #include "ia_css_debug.h" |
| 14 | #include "ia_css_frame.h" | ||
| 13 | #include "isp.h" | 15 | #include "isp.h" |
| 14 | #include "sh_css_internal.h" | 16 | #include "sh_css_internal.h" |
| 15 | #include "atomisp_internal.h" | ||
| 16 | 17 | ||
| 17 | #define NV12_TILEY_TILE_WIDTH 128 | 18 | #define NV12_TILEY_TILE_WIDTH 128 |
| 18 | #define NV12_TILEY_TILE_HEIGHT 32 | 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 | unsigned int stride; | 460 | unsigned int stride; |
| 460 | 461 | ||
| 461 | stride = subpixels_per_line * bytes_per_pixel; | 462 | stride = subpixels_per_line * bytes_per_pixel; |
| 462 | /* Frame height needs to be even number - needed by hw ISYS2401 | 463 | /* |
| 463 | In case of odd number, round up to even. | 464 | * Frame height needs to be even number - needed by hw ISYS2401. |
| 464 | Images won't be impacted by this round up, | 465 | * In case of odd number, round up to even. |
| 465 | only needed by jpeg/embedded data. | 466 | * Images won't be impacted by this round up, |
| 466 | As long as buffer allocation and release are using data_bytes, | 467 | * only needed by jpeg/embedded data. |
| 467 | there won't be memory leak. */ | 468 | * As long as buffer allocation and release are using data_bytes, |
| 468 | frame->data_bytes = stride * CEIL_MUL2(height, 2); | 469 | * there won't be memory leak. |
| 470 | */ | ||
| 471 | frame->data_bytes = stride * round_up(height, 2); | ||
| 469 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); | 472 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); |
| 470 | return; | ||
| 471 | } | 473 | } |
| 472 | 474 | ||
| 473 | static void frame_init_raw_single_plane( | 475 | static void frame_init_raw_single_plane( |
| @@ -486,7 +488,6 @@ static void frame_init_raw_single_plane( · 12 unmodified lines | |||
| 486 | HIVE_ISP_DDR_WORD_BITS / bits_per_pixel); | 488 | HIVE_ISP_DDR_WORD_BITS / bits_per_pixel); |
| 487 | frame->data_bytes = stride * height; | 489 | frame->data_bytes = stride * height; |
| 488 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); | 490 | frame_init_plane(plane, subpixels_per_line, stride, height, 0); |
| 489 | return; | ||
| 490 | } | 491 | } |
| 491 | 492 | ||
| 492 | static void frame_init_nv_planes(struct ia_css_frame *frame, | 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 | if (info->format == IA_CSS_FRAME_FORMAT_RAW | 691 | if (info->format == IA_CSS_FRAME_FORMAT_RAW |
| 691 | || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) { | 692 | || (info->format == IA_CSS_FRAME_FORMAT_RAW_PACKED)) { |
| 692 | if (info->raw_bit_depth) | 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 | else | 695 | else |
| 695 | return 2; /* bytes per pixel */ | 696 | return 2; /* bytes per pixel */ |
| 696 | } | 697 | } |
| @@ -4,9 +4,9 @@ · 3 unmodified lines | |||
| 4 | * Copyright (c) 2010 - 2015, Intel Corporation. | 4 | * Copyright (c) 2010 - 2015, Intel Corporation. |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include "system_global.h" | 7 | #include <linux/math.h> |
| 8 | #include <linux/kernel.h> | ||
| 9 | 8 | ||
| 9 | #include "system_global.h" | ||
| 10 | 10 | ||
| 11 | #include "ia_css_ifmtr.h" | 11 | #include "ia_css_ifmtr.h" |
| 12 | #include <math_support.h> | 12 | #include <math_support.h> |
| @@ -149,10 +149,9 @@ int ia_css_ifmtr_configure(struct ia_css_stream_config *config, · 136 unmodified lines | |||
| 149 | left_padding = 2 * ISP_VEC_NELEMS - config->left_padding; | 149 | left_padding = 2 * ISP_VEC_NELEMS - config->left_padding; |
| 150 | 150 | ||
| 151 | if (left_padding) { | 151 | if (left_padding) { |
| 152 | num_vectors = CEIL_DIV(cropped_width + left_padding, | 152 | num_vectors = DIV_ROUND_UP(cropped_width + left_padding, ISP_VEC_NELEMS); |
| 153 | ISP_VEC_NELEMS); | ||
| 154 | } else { | 153 | } else { |
| 155 | num_vectors = CEIL_DIV(cropped_width, ISP_VEC_NELEMS); | 154 | num_vectors = DIV_ROUND_UP(cropped_width, ISP_VEC_NELEMS); |
| 156 | num_vectors *= buffer_height; | 155 | num_vectors *= buffer_height; |
| 157 | /* todo: in case of left padding, | 156 | /* todo: in case of left padding, |
| 158 | num_vectors is vectors per line, | 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 | if ((!binary) || config->continuous) | 304 | if ((!binary) || config->continuous) |
| 306 | /* !binary -> sp raw copy pipe */ | 305 | /* !binary -> sp raw copy pipe */ |
| 307 | buffer_height *= 2; | 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 | vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); | 308 | vectors_per_line = CEIL_MUL(vectors_per_line, deinterleaving); |
| 310 | break; | 309 | break; |
| 311 | case ATOMISP_INPUT_FORMAT_RAW_14: | 310 | case ATOMISP_INPUT_FORMAT_RAW_14: |
| @@ -808,7 +808,7 @@ static bool calculate_isys2401_dma_port_cfg( · 807 unmodified lines | |||
| 808 | 808 | ||
| 809 | cfg->elements = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; | 809 | cfg->elements = HIVE_ISP_DDR_WORD_BITS / bits_per_pixel; |
| 810 | cfg->cropping = 0; | 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 | return true; | 813 | return true; |
| 814 | } | 814 | } |
| @@ -34,7 +34,6 @@ struct ia_css_pipeline_stage { · 33 unmodified lines | |||
| 34 | struct ia_css_pipeline { | 34 | struct ia_css_pipeline { |
| 35 | enum ia_css_pipe_id pipe_id; | 35 | enum ia_css_pipe_id pipe_id; |
| 36 | u8 pipe_num; | 36 | u8 pipe_num; |
| 37 | bool stop_requested; | ||
| 38 | struct ia_css_pipeline_stage *stages; | 37 | struct ia_css_pipeline_stage *stages; |
| 39 | struct ia_css_pipeline_stage *current_stage; | 38 | struct ia_css_pipeline_stage *current_stage; |
| 40 | unsigned int num_stages; | 39 | unsigned int num_stages; |
| @@ -198,7 +198,6 @@ int ia_css_pipeline_request_stop(struct ia_css_pipeline *pipeline) · 197 unmodified lines | |||
| 198 | ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, | 198 | ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, |
| 199 | "ia_css_pipeline_request_stop() enter: pipeline=%p\n", | 199 | "ia_css_pipeline_request_stop() enter: pipeline=%p\n", |
| 200 | pipeline); | 200 | pipeline); |
| 201 | pipeline->stop_requested = true; | ||
| 202 | 201 | ||
| 203 | /* Send stop event to the sp*/ | 202 | /* Send stop event to the sp*/ |
| 204 | /* This needs improvement, stop on all the pipes available | 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 | pipeline->pipe_id = pipe_id; | 663 | pipeline->pipe_id = pipe_id; |
| 665 | pipeline->stages = NULL; | 664 | pipeline->stages = NULL; |
| 666 | pipeline->stop_requested = false; | ||
| 667 | pipeline->current_stage = NULL; | 665 | pipeline->current_stage = NULL; |
| 668 | 666 | ||
| 669 | memcpy(&pipeline->in_frame, &ia_css_default_frame, | 667 | memcpy(&pipeline->in_frame, &ia_css_default_frame, |
| @@ -2002,10 +2002,6 @@ ia_css_uninit(void) · 2001 unmodified lines | |||
| 2002 | 2002 | ||
| 2003 | sh_css_params_free_default_gdc_lut(); | 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 | /* cleanup generic data */ | 2005 | /* cleanup generic data */ |
| 2010 | sh_css_params_uninit(); | 2006 | sh_css_params_uninit(); |
| 2011 | ia_css_refcount_uninit(); | 2007 | ia_css_refcount_uninit(); |
| @@ -3743,23 +3739,6 @@ ia_css_pipe_dequeue_buffer(struct ia_css_pipe *pipe, · 1731 unmodified lines | |||
| 3743 | case IA_CSS_BUFFER_TYPE_INPUT_FRAME: | 3739 | case IA_CSS_BUFFER_TYPE_INPUT_FRAME: |
| 3744 | case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: | 3740 | case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME: |
| 3745 | case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME: | 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 | case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: | 3742 | case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME: |
| 3764 | case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: | 3743 | case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME: |
| 3765 | frame = (struct ia_css_frame *)HOST_ADDRESS(ddr_buffer.kernel_ptr); | 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 | return err; | 4074 | return err; |
| 4096 | } | 4075 | } |
| 4097 | 4076 | ||
| 4098 | pipe->stop_requested = false; | ||
| 4099 | |||
| 4100 | switch (pipe_id) { | 4077 | switch (pipe_id) { |
| 4101 | case IA_CSS_PIPE_ID_PREVIEW: | 4078 | case IA_CSS_PIPE_ID_PREVIEW: |
| 4102 | err = preview_start(pipe); | 4079 | err = preview_start(pipe); |
| @@ -4120,19 +4097,15 @@ sh_css_pipe_start(struct ia_css_stream *stream) · 17 unmodified lines | |||
| 4120 | for (i = 1; i < stream->num_pipes && 0 == err ; i++) { | 4097 | for (i = 1; i < stream->num_pipes && 0 == err ; i++) { |
| 4121 | switch (stream->pipes[i]->mode) { | 4098 | switch (stream->pipes[i]->mode) { |
| 4122 | case IA_CSS_PIPE_ID_PREVIEW: | 4099 | case IA_CSS_PIPE_ID_PREVIEW: |
| 4123 | stream->pipes[i]->stop_requested = false; | ||
| 4124 | err = preview_start(stream->pipes[i]); | 4100 | err = preview_start(stream->pipes[i]); |
| 4125 | break; | 4101 | break; |
| 4126 | case IA_CSS_PIPE_ID_VIDEO: | 4102 | case IA_CSS_PIPE_ID_VIDEO: |
| 4127 | stream->pipes[i]->stop_requested = false; | ||
| 4128 | err = video_start(stream->pipes[i]); | 4103 | err = video_start(stream->pipes[i]); |
| 4129 | break; | 4104 | break; |
| 4130 | case IA_CSS_PIPE_ID_CAPTURE: | 4105 | case IA_CSS_PIPE_ID_CAPTURE: |
| 4131 | stream->pipes[i]->stop_requested = false; | ||
| 4132 | err = capture_start(stream->pipes[i]); | 4106 | err = capture_start(stream->pipes[i]); |
| 4133 | break; | 4107 | break; |
| 4134 | case IA_CSS_PIPE_ID_YUVPP: | 4108 | case IA_CSS_PIPE_ID_YUVPP: |
| 4135 | stream->pipes[i]->stop_requested = false; | ||
| 4136 | err = yuvpp_start(stream->pipes[i]); | 4109 | err = yuvpp_start(stream->pipes[i]); |
| 4137 | break; | 4110 | break; |
| 4138 | default: | 4111 | default: |
| @@ -7,12 +7,12 @@ · 6 unmodified lines | |||
| 7 | #ifndef _SH_CSS_DEFS_H_ | 7 | #ifndef _SH_CSS_DEFS_H_ |
| 8 | #define _SH_CSS_DEFS_H_ | 8 | #define _SH_CSS_DEFS_H_ |
| 9 | 9 | ||
| 10 | #include <linux/math.h> | ||
| 11 | |||
| 10 | #include "isp.h" | 12 | #include "isp.h" |
| 11 | 13 | ||
| 12 | /*#include "vamem.h"*/ /* Cannot include for VAMEM properties this file is visible on ISP -> pipeline generator */ | 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 | /* ID's for refcount */ | 16 | /* ID's for refcount */ |
| 17 | #define IA_CSS_REFCOUNT_PARAM_SET_POOL 0xCAFE0001 | 17 | #define IA_CSS_REFCOUNT_PARAM_SET_POOL 0xCAFE0001 |
| 18 | #define IA_CSS_REFCOUNT_PARAM_BUFFER 0xCAFE0002 | 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 | The ISP firmware needs these rules to be applied at pre-processor time, | 182 | The ISP firmware needs these rules to be applied at pre-processor time, |
| 183 | that's why these are macros, not functions. */ | 183 | that's why these are macros, not functions. */ |
| 184 | #define _ISP_BQS(num) ((num) / 2) | 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 | #define ISP_BQ_GRID_WIDTH(elements_per_line, deci_factor_log2) \ | 187 | #define ISP_BQ_GRID_WIDTH(elements_per_line, deci_factor_log2) \ |
| 188 | CEIL_SHIFT(elements_per_line / 2, deci_factor_log2) | 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 | /* The morphing table is similar to the shading table in the sense that we | 194 | /* The morphing table is similar to the shading table in the sense that we |
| 195 | have 1 more value than we have cells in the grid. */ | 195 | have 1 more value than we have cells in the grid. */ |
| 196 | #define _ISP_MORPH_TABLE_WIDTH(int_width) \ | 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 | #define _ISP_MORPH_TABLE_HEIGHT(int_height) \ | 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 | #define _ISP_MORPH_TABLE_ALIGNED_WIDTH(width) \ | 200 | #define _ISP_MORPH_TABLE_ALIGNED_WIDTH(width) \ |
| 201 | CEIL_MUL(_ISP_MORPH_TABLE_WIDTH(width), \ | 201 | CEIL_MUL(_ISP_MORPH_TABLE_WIDTH(width), \ |
| 202 | SH_CSS_MORPH_TABLE_ELEMS_PER_DDR_WORD) | 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 | c_subsampling, \ | 298 | c_subsampling, \ |
| 299 | num_chunks, \ | 299 | num_chunks, \ |
| 300 | pipelining) \ | 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 | dvs_env_width, \ | 302 | dvs_env_width, \ |
| 303 | left_crop), \ | 303 | left_crop), \ |
| 304 | __ISP_MIN_INTERNAL_WIDTH(num_chunks, \ | 304 | __ISP_MIN_INTERNAL_WIDTH(num_chunks, \ |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | #define _SH_CSS_INTERNAL_H_ | 8 | #define _SH_CSS_INTERNAL_H_ |
| 9 | 9 | ||
| 10 | #include <linux/build_bug.h> | 10 | #include <linux/build_bug.h> |
| 11 | #include <linux/math.h> | ||
| 11 | #include <linux/stdarg.h> | 12 | #include <linux/stdarg.h> |
| 12 | 13 | ||
| 13 | #include <system_global.h> | 14 | #include <system_global.h> |
| @@ -95,7 +96,6 @@ · 81 unmodified lines | |||
| 95 | * the SIZE_OF_XXX macro of the corresponding struct. If they are not | 96 | * the SIZE_OF_XXX macro of the corresponding struct. If they are not |
| 96 | * equal, functionality will break. | 97 | * equal, functionality will break. |
| 97 | */ | 98 | */ |
| 98 | #define CALC_ALIGNMENT_MEMBER(x, y) (CEIL_MUL(x, y) - x) | ||
| 99 | #define SIZE_OF_HRT_VADDRESS sizeof(hive_uint32) | 99 | #define SIZE_OF_HRT_VADDRESS sizeof(hive_uint32) |
| 100 | 100 | ||
| 101 | /* Number of SP's */ | 101 | /* Number of SP's */ |
| @@ -704,13 +704,11 @@ struct sh_css_hmm_buffer { · 602 unmodified lines | |||
| 704 | 704 | ||
| 705 | /* Do not use sizeof(uint64_t) since that does not exist of SP */ | 705 | /* Do not use sizeof(uint64_t) since that does not exist of SP */ |
| 706 | #define SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT \ | 706 | #define SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT \ |
| 707 | (SIZE_OF_PAYLOAD_UNION + \ | 707 | (round_up(SIZE_OF_PAYLOAD_UNION, 8) + \ |
| 708 | CALC_ALIGNMENT_MEMBER(SIZE_OF_PAYLOAD_UNION, 8) + \ | ||
| 709 | 8 + \ | 708 | 8 + \ |
| 710 | 8 + \ | 709 | 8 + \ |
| 711 | SIZE_OF_IA_CSS_TIME_MEAS_STRUCT + \ | 710 | SIZE_OF_IA_CSS_TIME_MEAS_STRUCT + \ |
| 712 | SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT + \ | 711 | round_up(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) |
| 713 | CALC_ALIGNMENT_MEMBER(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8)) | ||
| 714 | 712 | ||
| 715 | static_assert(sizeof(struct sh_css_hmm_buffer) == SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT); | 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 | ref_count_mipi_allocation[i] = 0; | 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 | * @brief Calculate the required MIPI buffer sizes. | 189 | * @brief Calculate the required MIPI buffer sizes. |
| 201 | * Based on the stream configuration, calculate the | 190 | * Based on the stream configuration, calculate the |
| @@ -14,8 +14,6 @@ · 13 unmodified lines | |||
| 14 | void | 14 | void |
| 15 | mipi_init(void); | 15 | mipi_init(void); |
| 16 | 16 | ||
| 17 | bool mipi_is_free(void); | ||
| 18 | |||
| 19 | int | 17 | int |
| 20 | allocate_mipi_frames(struct ia_css_pipe *pipe, struct ia_css_stream_info *info); | 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 | #ifndef _SH_CSS_PARAMS_DVS_H_ | 7 | #ifndef _SH_CSS_PARAMS_DVS_H_ |
| 8 | #define _SH_CSS_PARAMS_DVS_H_ | 8 | #define _SH_CSS_PARAMS_DVS_H_ |
| 9 | 9 | ||
| 10 | #include <linux/math.h> | ||
| 11 | |||
| 10 | #include <math_support.h> | 12 | #include <math_support.h> |
| 11 | #include <ia_css_types.h> | 13 | #include <ia_css_types.h> |
| 12 | #include "gdc_global.h" /* gdc_warp_param_mem_t */ | 14 | #include "gdc_global.h" /* gdc_warp_param_mem_t */ |
| @@ -20,22 +22,20 @@ · 7 unmodified lines | |||
| 20 | 22 | ||
| 21 | /* ISP2400 */ | 23 | /* ISP2400 */ |
| 22 | /* horizontal 64x64 blocks round up to DVS_BLOCKDIM_X, make even */ | 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 | /* ISP2400 */ | 28 | /* ISP2400 */ |
| 26 | /* vertical 64x64 blocks round up to DVS_BLOCKDIM_Y */ | 29 | /* vertical 64x64 blocks round up to DVS_BLOCKDIM_Y */ |
| 27 | #define DVS_NUM_BLOCKS_Y(X) (CEIL_DIV((X), DVS_BLOCKDIM_Y_LUMA)) | 30 | #define DVS_NUM_BLOCKS_Y(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_LUMA) |
| 28 | #define DVS_NUM_BLOCKS_X_CHROMA(X) (CEIL_DIV((X), DVS_BLOCKDIM_X)) | 31 | #define DVS_NUM_BLOCKS_Y_CHROMA(X) DIV_ROUND_UP((X), DVS_BLOCKDIM_Y_CHROMA) |
| 29 | #define DVS_NUM_BLOCKS_Y_CHROMA(X) (CEIL_DIV((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 */ | 33 | /* N blocks have N + 1 set of coords */ |
| 32 | #define DVS_TABLE_IN_BLOCKDIM_X_CHROMA(X) (DVS_NUM_BLOCKS_X_CHROMA(X) + 1) | 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 | #define DVS_TABLE_IN_BLOCKDIM_Y_LUMA(X) (DVS_NUM_BLOCKS_Y(X) + 1) | 36 | #define DVS_TABLE_IN_BLOCKDIM_Y_LUMA(X) (DVS_NUM_BLOCKS_Y(X) + 1) |
| 34 | #define DVS_TABLE_IN_BLOCKDIM_Y_CHROMA(X) (DVS_NUM_BLOCKS_Y_CHROMA(X) + 1) | 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 | #define DVS_COORD_FRAC_BITS (10) | 39 | #define DVS_COORD_FRAC_BITS (10) |
| 40 | 40 | ||
| 41 | /* ISP2400 */ | 41 | /* ISP2400 */ |
| @@ -43,8 +43,8 @@ · 1 unmodified line | |||
| 43 | 43 | ||
| 44 | #define XMEM_ALIGN_LOG2 (5) | 44 | #define XMEM_ALIGN_LOG2 (5) |
| 45 | 45 | ||
| 46 | #define DVS_6AXIS_COORDS_ELEMS CEIL_MUL(sizeof(gdc_warp_param_mem_t) \ | 46 | #define DVS_6AXIS_COORDS_ELEMS \ |
| 47 | , HIVE_ISP_DDR_WORD_BYTES) | 47 | round_up(sizeof(gdc_warp_param_mem_t), HIVE_ISP_DDR_WORD_BYTES) |
| 48 | 48 | ||
| 49 | /* currently we only support two output with the same resolution, output 0 is th default one. */ | 49 | /* currently we only support two output with the same resolution, output 0 is th default one. */ |
| 50 | #define DVS_6AXIS_BYTES(binary) \ | 50 | #define DVS_6AXIS_BYTES(binary) \ |
| @@ -4,6 +4,8 @@ · 3 unmodified lines | |||
| 4 | * Copyright (c) 2015, Intel Corporation. | 4 | * Copyright (c) 2015, Intel Corporation. |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <linux/math.h> | ||
| 8 | |||
| 7 | #include "gdc_device.h" /* gdc_lut_store(), ... */ | 9 | #include "gdc_device.h" /* gdc_lut_store(), ... */ |
| 8 | #include "isp.h" /* ISP_VEC_ELEMBITS */ | 10 | #include "isp.h" /* ISP_VEC_ELEMBITS */ |
| 9 | #include "vamem.h" | 11 | #include "vamem.h" |
| @@ -21,8 +23,6 @@ · 11 unmodified lines | |||
| 21 | 23 | ||
| 22 | #include "platform_support.h" | 24 | #include "platform_support.h" |
| 23 | #include "assert_support.h" | 25 | #include "assert_support.h" |
| 24 | #include "misc_support.h" /* NOT_USED */ | ||
| 25 | #include "math_support.h" /* max(), min() EVEN_FLOOR()*/ | ||
| 26 | 26 | ||
| 27 | #include "ia_css_stream.h" | 27 | #include "ia_css_stream.h" |
| 28 | #include "sh_css_params_internal.h" | 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 | /* Must enforce that the crop position is even */ | 4044 | /* Must enforce that the crop position is even */ |
| 4045 | crop_x = EVEN_FLOOR(crop_x); | 4045 | crop_x = round_down(crop_x, 2); |
| 4046 | crop_y = EVEN_FLOOR(crop_y); | 4046 | crop_y = round_down(crop_y, 2); |
| 4047 | uds_xc = EVEN_FLOOR(uds_xc); | 4047 | uds_xc = round_down(uds_xc, 2); |
| 4048 | uds_yc = EVEN_FLOOR(uds_yc); | 4048 | uds_yc = round_down(uds_yc, 2); |
| 4049 | 4049 | ||
| 4050 | uds->xc = (uint16_t)uds_xc; | 4050 | uds->xc = (uint16_t)uds_xc; |
| 4051 | uds->yc = (uint16_t)uds_yc; | 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 | return &priv->vdev; | 912 | return &priv->vdev; |
| 913 | 913 | ||
| 914 | err_m2m: | 914 | err_m2m: |
| 915 | video_set_drvdata(vfd, NULL); | 915 | video_device_release(vfd); |
| 916 | err_vfd: | 916 | err_vfd: |
| 917 | kfree(priv); | 917 | kfree(priv); |
| 918 | return ERR_PTR(ret); | 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.