Pull media updates from Mauro Carvalho Chehab: - New sensor driver: imx219 - Support for some new pixelformats - Support for Sun8i SoC - Added more codecs to meson vdec driver - Prepare for removing the legacy usbvision driver by moving it to staging. This driver has issues and use legacy core APIs. If nobody steps up to address those, it is time for its retirement. - Several cleanups and improvements on drivers, with the addition of new supported boards * tag 'media/v5.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (236 commits) media: venus: firmware: Ignore secure call error on first resume media: mtk-vpu: load vpu firmware from the new location media: i2c: video-i2c: fix build errors due to 'imply hwmon' media: MAINTAINERS: add myself to co-maintain Hantro G1/G2 for i.MX8MQ media: hantro: add initial i.MX8MQ support media: dt-bindings: Document i.MX8MQ VPU bindings media: vivid: fix incorrect PA assignment to HDMI outputs media: hantro: Add linux-rockchip mailing list to MAINTAINERS media: cedrus: h264: Fix 4K decoding on H6 media: siano: Use scnprintf() for avoiding potential buffer overflow media: rc: Use scnprintf() for avoiding potential buffer overflow media: allegro: create new struct for channel parameters media: allegro: move mail definitions to separate file media: allegro: pass buffers through firmware media: allegro: verify source and destination buffer in VCU response media: allegro: handle dependency of bitrate and bitrate_peak media: allegro: read bitrate mode directly from control media: allegro: make QP configurable media: allegro: make frame rate configurable media: allegro: skip filler data if possible ...
Unified · Split
| @@ -244,6 +244,7 @@ Santosh Shilimkar <ssantosh@kernel.org> · 243 unmodified lines | ||
| 244 | 244 | Santosh Shilimkar <santosh.shilimkar@oracle.org> |
| 245 | 245 | Sascha Hauer <s.hauer@pengutronix.de> |
| 246 | 246 | S.Çağlar Onur <caglar@pardus.org.tr> |
| 247 | +Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi> | |
| 247 | 248 | Sean Nyekjaer <sean@geanix.com> <sean.nyekjaer@prevas.dk> |
| 248 | 249 | Sebastian Reichel <sre@kernel.org> <sre@debian.org> |
| 249 | 250 | Sebastian Reichel <sre@kernel.org> <sebastian.reichel@collabora.co.uk> |
| @@ -6,16 +6,22 @@ Required properties: · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | Optional properties: |
| 8 | 8 | - label: a symbolic name for the connector |
| 9 | +- sdtv-standards: limit the supported TV standards on a connector to the given | |
| 10 | + ones. If not specified all TV standards are allowed. | |
| 11 | + Possible TV standards are defined in | |
| 12 | + include/dt-bindings/display/sdtv-standards.h. | |
| 9 | 13 | |
| 10 | 14 | Required nodes: |
| 11 | 15 | - Video port for TV input |
| 12 | 16 | |
| 13 | 17 | Example |
| 14 | 18 | ------- |
| 19 | +#include <dt-bindings/display/sdtv-standards.h> | |
| 15 | 20 | |
| 16 | 21 | tv: connector { |
| 17 | 22 | compatible = "composite-video-connector"; |
| 18 | 23 | label = "tv"; |
| 24 | + sdtv-standards = <(SDTV_STD_PAL | SDTV_STD_NTSC)>; | |
| 19 | 25 | |
| 20 | 26 | port { |
| 21 | 27 | tv_connector_in: endpoint { |
| @@ -0,0 +1,70 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-de2-rotate.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Allwinner A83T DE2 Rotate Device Tree Bindings | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Jernej Skrabec <jernej.skrabec@siol.net> | |
| 11 | + - Chen-Yu Tsai <wens@csie.org> | |
| 12 | + - Maxime Ripard <mripard@kernel.org> | |
| 13 | + | |
| 14 | +description: |- | |
| 15 | + The Allwinner A83T and A64 have a rotation core used for | |
| 16 | + rotating and flipping images. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + oneOf: | |
| 21 | + - const: allwinner,sun8i-a83t-de2-rotate | |
| 22 | + - items: | |
| 23 | + - const: allwinner,sun50i-a64-de2-rotate | |
| 24 | + - const: allwinner,sun8i-a83t-de2-rotate | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + maxItems: 1 | |
| 28 | + | |
| 29 | + interrupts: | |
| 30 | + maxItems: 1 | |
| 31 | + | |
| 32 | + clocks: | |
| 33 | + items: | |
| 34 | + - description: Rotate interface clock | |
| 35 | + - description: Rotate module clock | |
| 36 | + | |
| 37 | + clock-names: | |
| 38 | + items: | |
| 39 | + - const: bus | |
| 40 | + - const: mod | |
| 41 | + | |
| 42 | + resets: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | +required: | |
| 46 | + - compatible | |
| 47 | + - reg | |
| 48 | + - interrupts | |
| 49 | + - clocks | |
| 50 | + | |
| 51 | +additionalProperties: false | |
| 52 | + | |
| 53 | +examples: | |
| 54 | + - | | |
| 55 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 56 | + #include <dt-bindings/clock/sun8i-de2.h> | |
| 57 | + #include <dt-bindings/reset/sun8i-de2.h> | |
| 58 | + | |
| 59 | + rotate: rotate@1020000 { | |
| 60 | + compatible = "allwinner,sun8i-a83t-de2-rotate"; | |
| 61 | + reg = <0x1020000 0x10000>; | |
| 62 | + interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>; | |
| 63 | + clocks = <&display_clocks CLK_BUS_ROT>, | |
| 64 | + <&display_clocks CLK_ROT>; | |
| 65 | + clock-names = "bus", | |
| 66 | + "mod"; | |
| 67 | + resets = <&display_clocks RST_ROT>; | |
| 68 | + }; | |
| 69 | + | |
| 70 | +... | |
| @@ -17,7 +17,11 @@ description: |- · 16 unmodified lines | ||
| 17 | 17 | |
| 18 | 18 | properties: |
| 19 | 19 | compatible: |
| 20 | − const: allwinner,sun8i-h3-deinterlace | |
| 20 | + oneOf: | |
| 21 | + - const: allwinner,sun8i-h3-deinterlace | |
| 22 | + - items: | |
| 23 | + - const: allwinner,sun50i-a64-deinterlace | |
| 24 | + - const: allwinner,sun8i-h3-deinterlace | |
| 21 | 25 | |
| 22 | 26 | reg: |
| 23 | 27 | maxItems: 1 |
| @@ -1,11 +1,12 @@ | ||
| 1 | 1 | * Device tree bindings for Aspeed Video Engine |
| 2 | 2 | |
| 3 | −The Video Engine (VE) embedded in the Aspeed AST2400 and AST2500 SOCs can | |
| 3 | +The Video Engine (VE) embedded in the Aspeed AST2400/2500/2600 SOCs can | |
| 4 | 4 | capture and compress video data from digital or analog sources. |
| 5 | 5 | |
| 6 | 6 | Required properties: |
| 7 | 7 | - compatible: "aspeed,ast2400-video-engine" or |
| 8 | − "aspeed,ast2500-video-engine" | |
| 8 | + "aspeed,ast2500-video-engine" or | |
| 9 | + "aspeed,ast2600-video-engine" | |
| 9 | 10 | - reg: contains the offset and length of the VE memory region |
| 10 | 11 | - clocks: clock specifiers for the syscon clocks associated with |
| 11 | 12 | the VE (ordering must match the clock-names property) |
| @@ -0,0 +1,114 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/imx219.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Sony 1/4.0-Inch 8Mpixel CMOS Digital Image Sensor | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Dave Stevenson <dave.stevenson@raspberrypi.com> | |
| 11 | + | |
| 12 | +description: |- | |
| 13 | + The Sony imx219 is a 1/4.0-inch CMOS active pixel digital image sensor | |
| 14 | + with an active array size of 3280H x 2464V. It is programmable through | |
| 15 | + I2C interface. The I2C address is fixed to 0x10 as per sensor data sheet. | |
| 16 | + Image data is sent through MIPI CSI-2, which is configured as either 2 or | |
| 17 | + 4 data lanes. | |
| 18 | + | |
| 19 | +properties: | |
| 20 | + compatible: | |
| 21 | + const: sony,imx219 | |
| 22 | + | |
| 23 | + reg: | |
| 24 | + description: I2C device address | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + VDIG-supply: | |
| 31 | + description: | |
| 32 | + Digital I/O voltage supply, 1.8 volts | |
| 33 | + | |
| 34 | + VANA-supply: | |
| 35 | + description: | |
| 36 | + Analog voltage supply, 2.8 volts | |
| 37 | + | |
| 38 | + VDDL-supply: | |
| 39 | + description: | |
| 40 | + Digital core voltage supply, 1.2 volts | |
| 41 | + | |
| 42 | + reset-gpios: | |
| 43 | + description: |- | |
| 44 | + Reference to the GPIO connected to the xclr pin, if any. | |
| 45 | + Must be released (set high) after all supplies are applied. | |
| 46 | + | |
| 47 | + # See ../video-interfaces.txt for more details | |
| 48 | + port: | |
| 49 | + type: object | |
| 50 | + properties: | |
| 51 | + endpoint: | |
| 52 | + type: object | |
| 53 | + properties: | |
| 54 | + data-lanes: | |
| 55 | + description: |- | |
| 56 | + The sensor supports either two-lane, or four-lane operation. | |
| 57 | + If this property is omitted four-lane operation is assumed. | |
| 58 | + For two-lane operation the property must be set to <1 2>. | |
| 59 | + items: | |
| 60 | + - const: 1 | |
| 61 | + - const: 2 | |
| 62 | + | |
| 63 | + clock-noncontinuous: | |
| 64 | + type: boolean | |
| 65 | + description: |- | |
| 66 | + MIPI CSI-2 clock is non-continuous if this property is present, | |
| 67 | + otherwise it's continuous. | |
| 68 | + | |
| 69 | + link-frequencies: | |
| 70 | + allOf: | |
| 71 | + - $ref: /schemas/types.yaml#/definitions/uint64-array | |
| 72 | + description: | |
| 73 | + Allowed data bus frequencies. | |
| 74 | + | |
| 75 | + required: | |
| 76 | + - link-frequencies | |
| 77 | + | |
| 78 | +required: | |
| 79 | + - compatible | |
| 80 | + - reg | |
| 81 | + - clocks | |
| 82 | + - VANA-supply | |
| 83 | + - VDIG-supply | |
| 84 | + - VDDL-supply | |
| 85 | + - port | |
| 86 | + | |
| 87 | +additionalProperties: false | |
| 88 | + | |
| 89 | +examples: | |
| 90 | + - | | |
| 91 | + i2c0 { | |
| 92 | + #address-cells = <1>; | |
| 93 | + #size-cells = <0>; | |
| 94 | + | |
| 95 | + imx219: sensor@10 { | |
| 96 | + compatible = "sony,imx219"; | |
| 97 | + reg = <0x10>; | |
| 98 | + clocks = <&imx219_clk>; | |
| 99 | + VANA-supply = <&imx219_vana>; /* 2.8v */ | |
| 100 | + VDIG-supply = <&imx219_vdig>; /* 1.8v */ | |
| 101 | + VDDL-supply = <&imx219_vddl>; /* 1.2v */ | |
| 102 | + | |
| 103 | + port { | |
| 104 | + imx219_0: endpoint { | |
| 105 | + remote-endpoint = <&csi1_ep>; | |
| 106 | + data-lanes = <1 2>; | |
| 107 | + clock-noncontinuous; | |
| 108 | + link-frequencies = /bits/ 64 <456000000>; | |
| 109 | + }; | |
| 110 | + }; | |
| 111 | + }; | |
| 112 | + }; | |
| 113 | + | |
| 114 | +... | |
| @@ -5,38 +5,150 @@ The TVP5150 and TVP5151 are video decoders that convert baseband NTSC and PAL · 4 unmodified lines | ||
| 5 | 5 | with discrete syncs or 8-bit ITU-R BT.656 with embedded syncs output formats. |
| 6 | 6 | |
| 7 | 7 | Required Properties: |
| 8 | −- compatible: value must be "ti,tvp5150" | |
| 9 | −- reg: I2C slave address | |
| 8 | +==================== | |
| 9 | +- compatible: Value must be "ti,tvp5150". | |
| 10 | +- reg: I2C slave address. | |
| 10 | 11 | |
| 11 | 12 | Optional Properties: |
| 12 | −- pdn-gpios: phandle for the GPIO connected to the PDN pin, if any. | |
| 13 | −- reset-gpios: phandle for the GPIO connected to the RESETB pin, if any. | |
| 13 | +==================== | |
| 14 | +- pdn-gpios: Phandle for the GPIO connected to the PDN pin, if any. | |
| 15 | +- reset-gpios: Phandle for the GPIO connected to the RESETB pin, if any. | |
| 14 | 16 | |
| 15 | −The device node must contain one 'port' child node for its digital output | |
| 16 | −video port, in accordance with the video interface bindings defined in | |
| 17 | −Documentation/devicetree/bindings/media/video-interfaces.txt. | |
| 17 | +The device node must contain one 'port' child node per device physical input | |
| 18 | +and output port, in accordance with the video interface bindings defined in | |
| 19 | +Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes | |
| 20 | +are numbered as follows | |
| 18 | 21 | |
| 19 | −Required Endpoint Properties for parallel synchronization: | |
| 22 | + Name Type Port | |
| 23 | + -------------------------------------- | |
| 24 | + AIP1A sink 0 | |
| 25 | + AIP1B sink 1 | |
| 26 | + Y-OUT src 2 | |
| 20 | 27 | |
| 21 | −- hsync-active: active state of the HSYNC signal. Must be <1> (HIGH). | |
| 22 | −- vsync-active: active state of the VSYNC signal. Must be <1> (HIGH). | |
| 23 | −- field-even-active: field signal level during the even field data | |
| 24 | − transmission. Must be <0>. | |
| 28 | +The device node must contain at least one sink port and the src port. Each input | |
| 29 | +port must be linked to an endpoint defined in [1]. The port/connector layout is | |
| 30 | +as follows | |
| 25 | 31 | |
| 26 | −If none of hsync-active, vsync-active and field-even-active is specified, | |
| 27 | −the endpoint is assumed to use embedded BT.656 synchronization. | |
| 32 | +tvp-5150 port@0 (AIP1A) | |
| 33 | + endpoint@0 -----------> Comp0-Con port | |
| 34 | + endpoint@1 ------+----> Svideo-Con port | |
| 35 | +tvp-5150 port@1 (AIP1B) | | |
| 36 | + endpoint@1 ------+ | |
| 37 | + endpoint@0 -----------> Comp1-Con port | |
| 38 | +tvp-5150 port@2 | |
| 39 | + endpoint (video bitstream output at YOUT[0-7] parallel bus) | |
| 28 | 40 | |
| 29 | −Example: | |
| 41 | +Required Endpoint Properties for parallel synchronization on output port: | |
| 42 | +========================================================================= | |
| 43 | + | |
| 44 | +- hsync-active: Active state of the HSYNC signal. Must be <1> (HIGH). | |
| 45 | +- vsync-active: Active state of the VSYNC signal. Must be <1> (HIGH). | |
| 46 | +- field-even-active: Field signal level during the even field data | |
| 47 | + transmission. Must be <0>. | |
| 48 | + | |
| 49 | +Note: Do not specify any of these properties if you want to use the embedded | |
| 50 | + BT.656 synchronization. | |
| 51 | + | |
| 52 | +Optional Connector Properties: | |
| 53 | +============================== | |
| 54 | + | |
| 55 | +- sdtv-standards: Set the possible signals to which the hardware tries to lock | |
| 56 | + instead of using the autodetection mechnism. Please look at | |
| 57 | + [1] for more information. | |
| 58 | + | |
| 59 | +[1] Documentation/devicetree/bindings/display/connector/analog-tv-connector.txt. | |
| 60 | + | |
| 61 | +Example - three input sources: | |
| 62 | +#include <dt-bindings/display/sdtv-standards.h> | |
| 63 | + | |
| 64 | +comp_connector_0 { | |
| 65 | + compatible = "composite-video-connector"; | |
| 66 | + label = "Composite0"; | |
| 67 | + sdtv-standards = <SDTV_STD_PAL_M>; /* limit to pal-m signals */ | |
| 68 | + | |
| 69 | + port { | |
| 70 | + composite0_to_tvp5150: endpoint { | |
| 71 | + remote-endpoint = <&tvp5150_to_composite0>; | |
| 72 | + }; | |
| 73 | + }; | |
| 74 | +}; | |
| 75 | + | |
| 76 | +comp_connector_1 { | |
| 77 | + compatible = "composite-video-connector"; | |
| 78 | + label = "Composite1"; | |
| 79 | + sdtv-standards = <SDTV_STD_NTSC_M>; /* limit to ntsc-m signals */ | |
| 80 | + | |
| 81 | + port { | |
| 82 | + composite1_to_tvp5150: endpoint { | |
| 83 | + remote-endpoint = <&tvp5150_to_composite1>; | |
| 84 | + }; | |
| 85 | + }; | |
| 86 | +}; | |
| 87 | + | |
| 88 | +svideo_connector { | |
| 89 | + compatible = "svideo-connector"; | |
| 90 | + label = "S-Video"; | |
| 91 | + | |
| 92 | + port { | |
| 93 | + #address-cells = <1>; | |
| 94 | + #size-cells = <0>; | |
| 95 | + | |
| 96 | + svideo_luma_to_tvp5150: endpoint@0 { | |
| 97 | + reg = <0>; | |
| 98 | + remote-endpoint = <&tvp5150_to_svideo_luma>; | |
| 99 | + }; | |
| 100 | + | |
| 101 | + svideo_chroma_to_tvp5150: endpoint@1 { | |
| 102 | + reg = <1>; | |
| 103 | + remote-endpoint = <&tvp5150_to_svideo_chroma>; | |
| 104 | + }; | |
| 105 | + }; | |
| 106 | +}; | |
| 30 | 107 | |
| 31 | 108 | &i2c2 { |
| 32 | − ... | |
| 33 | 109 | tvp5150@5c { |
| 34 | 110 | compatible = "ti,tvp5150"; |
| 35 | 111 | reg = <0x5c>; |
| 36 | 112 | pdn-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>; |
| 37 | 113 | reset-gpios = <&gpio6 7 GPIO_ACTIVE_LOW>; |
| 114 | + #address-cells = <1>; | |
| 115 | + #size-cells = <0>; | |
| 116 | + | |
| 117 | + port@0 { | |
| 118 | + #address-cells = <1>; | |
| 119 | + #size-cells = <0>; | |
| 120 | + reg = <0>; | |
| 121 | + | |
| 122 | + tvp5150_to_composite0: endpoint@0 { | |
| 123 | + reg = <0>; | |
| 124 | + remote-endpoint = <&composite0_to_tvp5150>; | |
| 125 | + }; | |
| 126 | + | |
| 127 | + tvp5150_to_svideo_luma: endpoint@1 { | |
| 128 | + reg = <1>; | |
| 129 | + remote-endpoint = <&svideo_luma_to_tvp5150>; | |
| 130 | + }; | |
| 131 | + }; | |
| 132 | + | |
| 133 | + port@1 { | |
| 134 | + #address-cells = <1>; | |
| 135 | + #size-cells = <0>; | |
| 136 | + reg = <1>; | |
| 137 | + | |
| 138 | + tvp5150_to_composite1: endpoint@0 { | |
| 139 | + reg = <0>; | |
| 140 | + remote-endpoint = <&composite1_to_tvp5150>; | |
| 141 | + }; | |
| 142 | + | |
| 143 | + tvp5150_to_svideo_chroma: endpoint@1 { | |
| 144 | + reg = <1>; | |
| 145 | + remote-endpoint = <&svideo_chroma_to_tvp5150>; | |
| 146 | + }; | |
| 147 | + }; | |
| 148 | + | |
| 149 | + port@2 { | |
| 150 | + reg = <2>; | |
| 38 | 151 | |
| 39 | − port { | |
| 40 | 152 | tvp5150_1: endpoint { |
| 41 | 153 | remote-endpoint = <&ccdc_ep>; |
| 42 | 154 | }; |
| @@ -0,0 +1,77 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/nxp,imx8mq-vpu.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Hantro G1/G2 VPU codecs implemented on i.MX8MQ SoCs | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Philipp Zabel <p.zabel@pengutronix.de> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + Hantro G1/G2 video decode accelerators present on i.MX8MQ SoCs. | |
| 15 | + | |
| 16 | +properties: | |
| 17 | + compatible: | |
| 18 | + const: nxp,imx8mq-vpu | |
| 19 | + | |
| 20 | + reg: | |
| 21 | + maxItems: 3 | |
| 22 | + | |
| 23 | + reg-names: | |
| 24 | + items: | |
| 25 | + - const: g1 | |
| 26 | + - const: g2 | |
| 27 | + - const: ctrl | |
| 28 | + | |
| 29 | + interrupts: | |
| 30 | + maxItems: 2 | |
| 31 | + | |
| 32 | + interrupt-names: | |
| 33 | + items: | |
| 34 | + - const: g1 | |
| 35 | + - const: g2 | |
| 36 | + | |
| 37 | + clocks: | |
| 38 | + maxItems: 3 | |
| 39 | + | |
| 40 | + clock-names: | |
| 41 | + items: | |
| 42 | + - const: g1 | |
| 43 | + - const: g2 | |
| 44 | + - const: bus | |
| 45 | + | |
| 46 | + power-domains: | |
| 47 | + maxItems: 1 | |
| 48 | + | |
| 49 | +required: | |
| 50 | + - compatible | |
| 51 | + - reg | |
| 52 | + - reg-names | |
| 53 | + - interrupts | |
| 54 | + - interrupt-names | |
| 55 | + - clocks | |
| 56 | + - clock-names | |
| 57 | + | |
| 58 | +examples: | |
| 59 | + - | | |
| 60 | + #include <dt-bindings/clock/imx8mq-clock.h> | |
| 61 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 62 | + | |
| 63 | + vpu: video-codec@38300000 { | |
| 64 | + compatible = "nxp,imx8mq-vpu"; | |
| 65 | + reg = <0x38300000 0x10000>, | |
| 66 | + <0x38310000 0x10000>, | |
| 67 | + <0x38320000 0x10000>; | |
| 68 | + reg-names = "g1", "g2", "ctrl"; | |
| 69 | + interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>, | |
| 70 | + <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; | |
| 71 | + interrupt-names = "g1", "g2"; | |
| 72 | + clocks = <&clk IMX8MQ_CLK_VPU_G1_ROOT>, | |
| 73 | + <&clk IMX8MQ_CLK_VPU_G2_ROOT>, | |
| 74 | + <&clk IMX8MQ_CLK_VPU_DEC_ROOT>; | |
| 75 | + clock-names = "g1", "g2", "bus"; | |
| 76 | + power-domains = <&pgc_vpu>; | |
| 77 | + }; | |
| @@ -0,0 +1,119 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/qcom,msm8916-venus.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Qualcomm Venus video encode and decode accelerators | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: qcom,msm8916-venus | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + power-domains: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + clocks: | |
| 31 | + maxItems: 3 | |
| 32 | + | |
| 33 | + clock-names: | |
| 34 | + items: | |
| 35 | + - const: core | |
| 36 | + - const: iface | |
| 37 | + - const: bus | |
| 38 | + | |
| 39 | + iommus: | |
| 40 | + maxItems: 1 | |
| 41 | + | |
| 42 | + memory-region: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | + video-decoder: | |
| 46 | + type: object | |
| 47 | + | |
| 48 | + properties: | |
| 49 | + compatible: | |
| 50 | + const: "venus-decoder" | |
| 51 | + | |
| 52 | + required: | |
| 53 | + - compatible | |
| 54 | + | |
| 55 | + additionalProperties: false | |
| 56 | + | |
| 57 | + video-encoder: | |
| 58 | + type: object | |
| 59 | + | |
| 60 | + properties: | |
| 61 | + compatible: | |
| 62 | + const: "venus-encoder" | |
| 63 | + | |
| 64 | + required: | |
| 65 | + - compatible | |
| 66 | + | |
| 67 | + additionalProperties: false | |
| 68 | + | |
| 69 | + video-firmware: | |
| 70 | + type: object | |
| 71 | + | |
| 72 | + description: | | |
| 73 | + Firmware subnode is needed when the platform does not | |
| 74 | + have TrustZone. | |
| 75 | + | |
| 76 | + properties: | |
| 77 | + iommus: | |
| 78 | + maxItems: 1 | |
| 79 | + | |
| 80 | + required: | |
| 81 | + - iommus | |
| 82 | + | |
| 83 | +required: | |
| 84 | + - compatible | |
| 85 | + - reg | |
| 86 | + - interrupts | |
| 87 | + - power-domains | |
| 88 | + - clocks | |
| 89 | + - clock-names | |
| 90 | + - iommus | |
| 91 | + - memory-region | |
| 92 | + - video-decoder | |
| 93 | + - video-encoder | |
| 94 | + | |
| 95 | +examples: | |
| 96 | + - | | |
| 97 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 98 | + #include <dt-bindings/clock/qcom,gcc-msm8916.h> | |
| 99 | + | |
| 100 | + video-codec@1d00000 { | |
| 101 | + compatible = "qcom,msm8916-venus"; | |
| 102 | + reg = <0x01d00000 0xff000>; | |
| 103 | + interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 104 | + clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, | |
| 105 | + <&gcc GCC_VENUS0_AHB_CLK>, | |
| 106 | + <&gcc GCC_VENUS0_AXI_CLK>; | |
| 107 | + clock-names = "core", "iface", "bus"; | |
| 108 | + power-domains = <&gcc VENUS_GDSC>; | |
| 109 | + iommus = <&apps_iommu 5>; | |
| 110 | + memory-region = <&venus_mem>; | |
| 111 | + | |
| 112 | + video-decoder { | |
| 113 | + compatible = "venus-decoder"; | |
| 114 | + }; | |
| 115 | + | |
| 116 | + video-encoder { | |
| 117 | + compatible = "venus-encoder"; | |
| 118 | + }; | |
| 119 | + }; | |
| @@ -0,0 +1,172 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/qcom,msm8996-venus.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Qualcomm Venus video encode and decode accelerators | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: qcom,msm8996-venus | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + power-domains: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + clocks: | |
| 31 | + maxItems: 4 | |
| 32 | + | |
| 33 | + clock-names: | |
| 34 | + items: | |
| 35 | + - const: core | |
| 36 | + - const: iface | |
| 37 | + - const: bus | |
| 38 | + - const: mbus | |
| 39 | + | |
| 40 | + iommus: | |
| 41 | + maxItems: 20 | |
| 42 | + | |
| 43 | + memory-region: | |
| 44 | + maxItems: 1 | |
| 45 | + | |
| 46 | + video-decoder: | |
| 47 | + type: object | |
| 48 | + | |
| 49 | + properties: | |
| 50 | + compatible: | |
| 51 | + const: venus-decoder | |
| 52 | + | |
| 53 | + clocks: | |
| 54 | + maxItems: 1 | |
| 55 | + | |
| 56 | + clock-names: | |
| 57 | + items: | |
| 58 | + - const: core | |
| 59 | + | |
| 60 | + power-domains: | |
| 61 | + maxItems: 1 | |
| 62 | + | |
| 63 | + required: | |
| 64 | + - compatible | |
| 65 | + - clocks | |
| 66 | + - clock-names | |
| 67 | + - power-domains | |
| 68 | + | |
| 69 | + additionalProperties: false | |
| 70 | + | |
| 71 | + video-encoder: | |
| 72 | + type: object | |
| 73 | + | |
| 74 | + properties: | |
| 75 | + compatible: | |
| 76 | + const: venus-encoder | |
| 77 | + | |
| 78 | + clocks: | |
| 79 | + maxItems: 1 | |
| 80 | + | |
| 81 | + clock-names: | |
| 82 | + items: | |
| 83 | + - const: core | |
| 84 | + | |
| 85 | + power-domains: | |
| 86 | + maxItems: 1 | |
| 87 | + | |
| 88 | + required: | |
| 89 | + - compatible | |
| 90 | + - clocks | |
| 91 | + - clock-names | |
| 92 | + - power-domains | |
| 93 | + | |
| 94 | + additionalProperties: false | |
| 95 | + | |
| 96 | + video-firmware: | |
| 97 | + type: object | |
| 98 | + | |
| 99 | + description: | | |
| 100 | + Firmware subnode is needed when the platform does not | |
| 101 | + have TrustZone. | |
| 102 | + | |
| 103 | + properties: | |
| 104 | + iommus: | |
| 105 | + maxItems: 1 | |
| 106 | + | |
| 107 | + required: | |
| 108 | + - iommus | |
| 109 | + | |
| 110 | +required: | |
| 111 | + - compatible | |
| 112 | + - reg | |
| 113 | + - interrupts | |
| 114 | + - power-domains | |
| 115 | + - clocks | |
| 116 | + - clock-names | |
| 117 | + - iommus | |
| 118 | + - memory-region | |
| 119 | + - video-decoder | |
| 120 | + - video-encoder | |
| 121 | + | |
| 122 | +examples: | |
| 123 | + - | | |
| 124 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 125 | + #include <dt-bindings/clock/qcom,mmcc-msm8996.h> | |
| 126 | + | |
| 127 | + video-codec@c00000 { | |
| 128 | + compatible = "qcom,msm8996-venus"; | |
| 129 | + reg = <0x00c00000 0xff000>; | |
| 130 | + interrupts = <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>; | |
| 131 | + clocks = <&mmcc VIDEO_CORE_CLK>, | |
| 132 | + <&mmcc VIDEO_AHB_CLK>, | |
| 133 | + <&mmcc VIDEO_AXI_CLK>, | |
| 134 | + <&mmcc VIDEO_MAXI_CLK>; | |
| 135 | + clock-names = "core", "iface", "bus", "mbus"; | |
| 136 | + power-domains = <&mmcc VENUS_GDSC>; | |
| 137 | + iommus = <&venus_smmu 0x00>, | |
| 138 | + <&venus_smmu 0x01>, | |
| 139 | + <&venus_smmu 0x0a>, | |
| 140 | + <&venus_smmu 0x07>, | |
| 141 | + <&venus_smmu 0x0e>, | |
| 142 | + <&venus_smmu 0x0f>, | |
| 143 | + <&venus_smmu 0x08>, | |
| 144 | + <&venus_smmu 0x09>, | |
| 145 | + <&venus_smmu 0x0b>, | |
| 146 | + <&venus_smmu 0x0c>, | |
| 147 | + <&venus_smmu 0x0d>, | |
| 148 | + <&venus_smmu 0x10>, | |
| 149 | + <&venus_smmu 0x11>, | |
| 150 | + <&venus_smmu 0x21>, | |
| 151 | + <&venus_smmu 0x28>, | |
| 152 | + <&venus_smmu 0x29>, | |
| 153 | + <&venus_smmu 0x2b>, | |
| 154 | + <&venus_smmu 0x2c>, | |
| 155 | + <&venus_smmu 0x2d>, | |
| 156 | + <&venus_smmu 0x31>; | |
| 157 | + memory-region = <&venus_mem>; | |
| 158 | + | |
| 159 | + video-decoder { | |
| 160 | + compatible = "venus-decoder"; | |
| 161 | + clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 162 | + clock-names = "core"; | |
| 163 | + power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 164 | + }; | |
| 165 | + | |
| 166 | + video-encoder { | |
| 167 | + compatible = "venus-encoder"; | |
| 168 | + clocks = <&mmcc VIDEO_SUBCORE1_CLK>; | |
| 169 | + clock-names = "core"; | |
| 170 | + power-domains = <&mmcc VENUS_CORE1_GDSC>; | |
| 171 | + }; | |
| 172 | + }; | |
| @@ -0,0 +1,140 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/qcom,sc7180-venus.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Qualcomm Venus video encode and decode accelerators | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: qcom,sc7180-venus | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + power-domains: | |
| 28 | + maxItems: 2 | |
| 29 | + | |
| 30 | + power-domain-names: | |
| 31 | + items: | |
| 32 | + - const: venus | |
| 33 | + - const: vcodec0 | |
| 34 | + | |
| 35 | + clocks: | |
| 36 | + maxItems: 5 | |
| 37 | + | |
| 38 | + clock-names: | |
| 39 | + items: | |
| 40 | + - const: core | |
| 41 | + - const: iface | |
| 42 | + - const: bus | |
| 43 | + - const: vcodec0_core | |
| 44 | + - const: vcodec0_bus | |
| 45 | + | |
| 46 | + iommus: | |
| 47 | + maxItems: 1 | |
| 48 | + | |
| 49 | + memory-region: | |
| 50 | + maxItems: 1 | |
| 51 | + | |
| 52 | + interconnects: | |
| 53 | + maxItems: 2 | |
| 54 | + | |
| 55 | + interconnect-names: | |
| 56 | + items: | |
| 57 | + - const: video-mem | |
| 58 | + - const: cpu-cfg | |
| 59 | + | |
| 60 | + video-decoder: | |
| 61 | + type: object | |
| 62 | + | |
| 63 | + properties: | |
| 64 | + compatible: | |
| 65 | + const: venus-decoder | |
| 66 | + | |
| 67 | + required: | |
| 68 | + - compatible | |
| 69 | + | |
| 70 | + additionalProperties: false | |
| 71 | + | |
| 72 | + video-encoder: | |
| 73 | + type: object | |
| 74 | + | |
| 75 | + properties: | |
| 76 | + compatible: | |
| 77 | + const: venus-encoder | |
| 78 | + | |
| 79 | + required: | |
| 80 | + - compatible | |
| 81 | + | |
| 82 | + additionalProperties: false | |
| 83 | + | |
| 84 | + video-firmware: | |
| 85 | + type: object | |
| 86 | + | |
| 87 | + description: | | |
| 88 | + Firmware subnode is needed when the platform does not | |
| 89 | + have TrustZone. | |
| 90 | + | |
| 91 | + properties: | |
| 92 | + iommus: | |
| 93 | + maxItems: 1 | |
| 94 | + | |
| 95 | + required: | |
| 96 | + - iommus | |
| 97 | + | |
| 98 | +required: | |
| 99 | + - compatible | |
| 100 | + - reg | |
| 101 | + - interrupts | |
| 102 | + - power-domains | |
| 103 | + - power-domain-names | |
| 104 | + - clocks | |
| 105 | + - clock-names | |
| 106 | + - iommus | |
| 107 | + - memory-region | |
| 108 | + - video-decoder | |
| 109 | + - video-encoder | |
| 110 | + | |
| 111 | +examples: | |
| 112 | + - | | |
| 113 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 114 | + #include <dt-bindings/clock/qcom,videocc-sc7180.h> | |
| 115 | + | |
| 116 | + venus: video-codec@aa00000 { | |
| 117 | + compatible = "qcom,sc7180-venus"; | |
| 118 | + reg = <0 0x0aa00000 0 0xff000>; | |
| 119 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 120 | + power-domains = <&videocc VENUS_GDSC>, | |
| 121 | + <&videocc VCODEC0_GDSC>; | |
| 122 | + power-domain-names = "venus", "vcodec0"; | |
| 123 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 124 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 125 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 126 | + <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 127 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 128 | + clock-names = "core", "iface", "bus", | |
| 129 | + "vcodec0_core", "vcodec0_bus"; | |
| 130 | + iommus = <&apps_smmu 0x0c00 0x60>; | |
| 131 | + memory-region = <&venus_mem>; | |
| 132 | + | |
| 133 | + video-decoder { | |
| 134 | + compatible = "venus-decoder"; | |
| 135 | + }; | |
| 136 | + | |
| 137 | + video-encoder { | |
| 138 | + compatible = "venus-encoder"; | |
| 139 | + }; | |
| 140 | + }; | |
| @@ -0,0 +1,140 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus-v2.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Qualcomm Venus video encode and decode accelerators | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: qcom,sdm845-venus-v2 | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + power-domains: | |
| 28 | + maxItems: 3 | |
| 29 | + | |
| 30 | + power-domain-names: | |
| 31 | + items: | |
| 32 | + - const: venus | |
| 33 | + - const: vcodec0 | |
| 34 | + - const: vcodec1 | |
| 35 | + | |
| 36 | + clocks: | |
| 37 | + maxItems: 7 | |
| 38 | + | |
| 39 | + clock-names: | |
| 40 | + items: | |
| 41 | + - const: core | |
| 42 | + - const: iface | |
| 43 | + - const: bus | |
| 44 | + - const: vcodec0_core | |
| 45 | + - const: vcodec0_bus | |
| 46 | + - const: vcodec1_core | |
| 47 | + - const: vcodec1_bus | |
| 48 | + | |
| 49 | + iommus: | |
| 50 | + maxItems: 2 | |
| 51 | + | |
| 52 | + memory-region: | |
| 53 | + maxItems: 1 | |
| 54 | + | |
| 55 | + video-core0: | |
| 56 | + type: object | |
| 57 | + | |
| 58 | + properties: | |
| 59 | + compatible: | |
| 60 | + const: venus-decoder | |
| 61 | + | |
| 62 | + required: | |
| 63 | + - compatible | |
| 64 | + | |
| 65 | + additionalProperties: false | |
| 66 | + | |
| 67 | + video-core1: | |
| 68 | + type: object | |
| 69 | + | |
| 70 | + properties: | |
| 71 | + compatible: | |
| 72 | + const: venus-encoder | |
| 73 | + | |
| 74 | + required: | |
| 75 | + - compatible | |
| 76 | + | |
| 77 | + additionalProperties: false | |
| 78 | + | |
| 79 | + video-firmware: | |
| 80 | + type: object | |
| 81 | + | |
| 82 | + description: | | |
| 83 | + Firmware subnode is needed when the platform does not | |
| 84 | + have TrustZone. | |
| 85 | + | |
| 86 | + properties: | |
| 87 | + iommus: | |
| 88 | + maxItems: 1 | |
| 89 | + | |
| 90 | + required: | |
| 91 | + - iommus | |
| 92 | + | |
| 93 | +required: | |
| 94 | + - compatible | |
| 95 | + - reg | |
| 96 | + - interrupts | |
| 97 | + - power-domains | |
| 98 | + - power-domain-names | |
| 99 | + - clocks | |
| 100 | + - clock-names | |
| 101 | + - iommus | |
| 102 | + - memory-region | |
| 103 | + - video-core0 | |
| 104 | + - video-core1 | |
| 105 | + | |
| 106 | +examples: | |
| 107 | + - | | |
| 108 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 109 | + #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 110 | + | |
| 111 | + video-codec@aa00000 { | |
| 112 | + compatible = "qcom,sdm845-venus-v2"; | |
| 113 | + reg = <0 0x0aa00000 0 0xff000>; | |
| 114 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 115 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 116 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 117 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, | |
| 118 | + <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 119 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>, | |
| 120 | + <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 121 | + <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 122 | + clock-names = "core", "iface", "bus", | |
| 123 | + "vcodec0_core", "vcodec0_bus", | |
| 124 | + "vcodec1_core", "vcodec1_bus"; | |
| 125 | + power-domains = <&videocc VENUS_GDSC>, | |
| 126 | + <&videocc VCODEC0_GDSC>, | |
| 127 | + <&videocc VCODEC1_GDSC>; | |
| 128 | + power-domain-names = "venus", "vcodec0", "vcodec1"; | |
| 129 | + iommus = <&apps_smmu 0x10a0 0x8>, | |
| 130 | + <&apps_smmu 0x10b0 0x0>; | |
| 131 | + memory-region = <&venus_mem>; | |
| 132 | + | |
| 133 | + video-core0 { | |
| 134 | + compatible = "venus-decoder"; | |
| 135 | + }; | |
| 136 | + | |
| 137 | + video-core1 { | |
| 138 | + compatible = "venus-encoder"; | |
| 139 | + }; | |
| 140 | + }; | |
| @@ -0,0 +1,156 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | + | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: "http://devicetree.org/schemas/media/qcom,sdm845-venus.yaml#" | |
| 6 | +$schema: "http://devicetree.org/meta-schemas/core.yaml#" | |
| 7 | + | |
| 8 | +title: Qualcomm Venus video encode and decode accelerators | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Venus IP is a video encode and decode accelerator present | |
| 15 | + on Qualcomm platforms | |
| 16 | + | |
| 17 | +properties: | |
| 18 | + compatible: | |
| 19 | + const: qcom,sdm845-venus | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + power-domains: | |
| 28 | + maxItems: 1 | |
| 29 | + | |
| 30 | + clocks: | |
| 31 | + maxItems: 3 | |
| 32 | + | |
| 33 | + clock-names: | |
| 34 | + items: | |
| 35 | + - const: core | |
| 36 | + - const: iface | |
| 37 | + - const: bus | |
| 38 | + | |
| 39 | + iommus: | |
| 40 | + maxItems: 2 | |
| 41 | + | |
| 42 | + memory-region: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | + video-core0: | |
| 46 | + type: object | |
| 47 | + | |
| 48 | + properties: | |
| 49 | + compatible: | |
| 50 | + const: venus-decoder | |
| 51 | + | |
| 52 | + clocks: | |
| 53 | + maxItems: 2 | |
| 54 | + | |
| 55 | + clock-names: | |
| 56 | + items: | |
| 57 | + - const: core | |
| 58 | + - const: bus | |
| 59 | + | |
| 60 | + power-domains: | |
| 61 | + maxItems: 1 | |
| 62 | + | |
| 63 | + required: | |
| 64 | + - compatible | |
| 65 | + - clocks | |
| 66 | + - clock-names | |
| 67 | + - power-domains | |
| 68 | + | |
| 69 | + additionalProperties: false | |
| 70 | + | |
| 71 | + video-core1: | |
| 72 | + type: object | |
| 73 | + | |
| 74 | + properties: | |
| 75 | + compatible: | |
| 76 | + const: venus-encoder | |
| 77 | + | |
| 78 | + clocks: | |
| 79 | + maxItems: 2 | |
| 80 | + | |
| 81 | + clock-names: | |
| 82 | + items: | |
| 83 | + - const: core | |
| 84 | + - const: bus | |
| 85 | + | |
| 86 | + power-domains: | |
| 87 | + maxItems: 1 | |
| 88 | + | |
| 89 | + required: | |
| 90 | + - compatible | |
| 91 | + - clocks | |
| 92 | + - clock-names | |
| 93 | + - power-domains | |
| 94 | + | |
| 95 | + additionalProperties: false | |
| 96 | + | |
| 97 | + video-firmware: | |
| 98 | + type: object | |
| 99 | + | |
| 100 | + description: | | |
| 101 | + Firmware subnode is needed when the platform does not | |
| 102 | + have TrustZone. | |
| 103 | + | |
| 104 | + properties: | |
| 105 | + iommus: | |
| 106 | + maxItems: 1 | |
| 107 | + | |
| 108 | + required: | |
| 109 | + - iommus | |
| 110 | + | |
| 111 | +required: | |
| 112 | + - compatible | |
| 113 | + - reg | |
| 114 | + - interrupts | |
| 115 | + - power-domains | |
| 116 | + - clocks | |
| 117 | + - clock-names | |
| 118 | + - iommus | |
| 119 | + - memory-region | |
| 120 | + - video-core0 | |
| 121 | + - video-core1 | |
| 122 | + | |
| 123 | +examples: | |
| 124 | + - | | |
| 125 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 126 | + #include <dt-bindings/clock/qcom,videocc-sdm845.h> | |
| 127 | + | |
| 128 | + video-codec@aa00000 { | |
| 129 | + compatible = "qcom,sdm845-venus"; | |
| 130 | + reg = <0 0x0aa00000 0 0xff000>; | |
| 131 | + interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>; | |
| 132 | + clocks = <&videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, | |
| 133 | + <&videocc VIDEO_CC_VENUS_AHB_CLK>, | |
| 134 | + <&videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; | |
| 135 | + clock-names = "core", "iface", "bus"; | |
| 136 | + power-domains = <&videocc VENUS_GDSC>; | |
| 137 | + iommus = <&apps_smmu 0x10a0 0x8>, | |
| 138 | + <&apps_smmu 0x10b0 0x0>; | |
| 139 | + memory-region = <&venus_mem>; | |
| 140 | + | |
| 141 | + video-core0 { | |
| 142 | + compatible = "venus-decoder"; | |
| 143 | + clocks = <&videocc VIDEO_CC_VCODEC0_CORE_CLK>, | |
| 144 | + <&videocc VIDEO_CC_VCODEC0_AXI_CLK>; | |
| 145 | + clock-names = "core", "bus"; | |
| 146 | + power-domains = <&videocc VCODEC0_GDSC>; | |
| 147 | + }; | |
| 148 | + | |
| 149 | + video-core1 { | |
| 150 | + compatible = "venus-encoder"; | |
| 151 | + clocks = <&videocc VIDEO_CC_VCODEC1_CORE_CLK>, | |
| 152 | + <&videocc VIDEO_CC_VCODEC1_AXI_CLK>; | |
| 153 | + clock-names = "core", "bus"; | |
| 154 | + power-domains = <&videocc VCODEC1_GDSC>; | |
| 155 | + }; | |
| 156 | + }; | |
| @@ -1,120 +0,0 @@ | ||
| 1 | −* Qualcomm Venus video encoder/decoder accelerators | |
| 2 | − | |
| 3 | −- compatible: | |
| 4 | − Usage: required | |
| 5 | − Value type: <stringlist> | |
| 6 | − Definition: Value should contain one of: | |
| 7 | − - "qcom,msm8916-venus" | |
| 8 | − - "qcom,msm8996-venus" | |
| 9 | − - "qcom,sdm845-venus" | |
| 10 | −- reg: | |
| 11 | − Usage: required | |
| 12 | − Value type: <prop-encoded-array> | |
| 13 | − Definition: Register base address and length of the register map. | |
| 14 | −- interrupts: | |
| 15 | − Usage: required | |
| 16 | − Value type: <prop-encoded-array> | |
| 17 | − Definition: Should contain interrupt line number. | |
| 18 | −- clocks: | |
| 19 | − Usage: required | |
| 20 | − Value type: <prop-encoded-array> | |
| 21 | − Definition: A List of phandle and clock specifier pairs as listed | |
| 22 | − in clock-names property. | |
| 23 | −- clock-names: | |
| 24 | − Usage: required for msm8916 | |
| 25 | − Value type: <stringlist> | |
| 26 | − Definition: Should contain the following entries: | |
| 27 | − - "core" Core video accelerator clock | |
| 28 | − - "iface" Video accelerator AHB clock | |
| 29 | − - "bus" Video accelerator AXI clock | |
| 30 | −- clock-names: | |
| 31 | − Usage: required for msm8996 | |
| 32 | − Value type: <stringlist> | |
| 33 | − Definition: Should contain the following entries: | |
| 34 | − - "core" Core video accelerator clock | |
| 35 | − - "iface" Video accelerator AHB clock | |
| 36 | − - "bus" Video accelerator AXI clock | |
| 37 | − - "mbus" Video MAXI clock | |
| 38 | −- power-domains: | |
| 39 | − Usage: required | |
| 40 | − Value type: <prop-encoded-array> | |
| 41 | − Definition: A phandle and power domain specifier pairs to the | |
| 42 | − power domain which is responsible for collapsing | |
| 43 | − and restoring power to the peripheral. | |
| 44 | −- iommus: | |
| 45 | − Usage: required | |
| 46 | − Value type: <prop-encoded-array> | |
| 47 | − Definition: A list of phandle and IOMMU specifier pairs. | |
| 48 | −- memory-region: | |
| 49 | − Usage: required | |
| 50 | − Value type: <phandle> | |
| 51 | − Definition: reference to the reserved-memory for the firmware | |
| 52 | − memory region. | |
| 53 | − | |
| 54 | −* Subnodes | |
| 55 | −The Venus video-codec node must contain two subnodes representing | |
| 56 | −video-decoder and video-encoder, and one optional firmware subnode. | |
| 57 | −Firmware subnode is needed when the platform does not have TrustZone. | |
| 58 | − | |
| 59 | −Every of video-encoder or video-decoder subnode should have: | |
| 60 | − | |
| 61 | −- compatible: | |
| 62 | − Usage: required | |
| 63 | − Value type: <stringlist> | |
| 64 | − Definition: Value should contain "venus-decoder" or "venus-encoder" | |
| 65 | −- clocks: | |
| 66 | − Usage: required for msm8996 | |
| 67 | − Value type: <prop-encoded-array> | |
| 68 | − Definition: A List of phandle and clock specifier pairs as listed | |
| 69 | − in clock-names property. | |
| 70 | −- clock-names: | |
| 71 | − Usage: required for msm8996 | |
| 72 | − Value type: <stringlist> | |
| 73 | − Definition: Should contain the following entries: | |
| 74 | − - "core" Subcore video accelerator clock | |
| 75 | − | |
| 76 | −- power-domains: | |
| 77 | − Usage: required for msm8996 | |
| 78 | − Value type: <prop-encoded-array> | |
| 79 | − Definition: A phandle and power domain specifier pairs to the | |
| 80 | − power domain which is responsible for collapsing | |
| 81 | − and restoring power to the subcore. | |
| 82 | − | |
| 83 | −The firmware subnode must have: | |
| 84 | − | |
| 85 | −- iommus: | |
| 86 | − Usage: required | |
| 87 | − Value type: <prop-encoded-array> | |
| 88 | − Definition: A list of phandle and IOMMU specifier pairs. | |
| 89 | − | |
| 90 | −* An Example | |
| 91 | − video-codec@1d00000 { | |
| 92 | − compatible = "qcom,msm8916-venus"; | |
| 93 | − reg = <0x01d00000 0xff000>; | |
| 94 | − interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>; | |
| 95 | − clocks = <&gcc GCC_VENUS0_VCODEC0_CLK>, | |
| 96 | − <&gcc GCC_VENUS0_AHB_CLK>, | |
| 97 | − <&gcc GCC_VENUS0_AXI_CLK>; | |
| 98 | − clock-names = "core", "iface", "bus"; | |
| 99 | − power-domains = <&gcc VENUS_GDSC>; | |
| 100 | − iommus = <&apps_iommu 5>; | |
| 101 | − memory-region = <&venus_mem>; | |
| 102 | − | |
| 103 | − video-decoder { | |
| 104 | − compatible = "venus-decoder"; | |
| 105 | − clocks = <&mmcc VIDEO_SUBCORE0_CLK>; | |
| 106 | − clock-names = "core"; | |
| 107 | − power-domains = <&mmcc VENUS_CORE0_GDSC>; | |
| 108 | − }; | |
| 109 | − | |
| 110 | − video-encoder { | |
| 111 | − compatible = "venus-encoder"; | |
| 112 | − clocks = <&mmcc VIDEO_SUBCORE1_CLK>; | |
| 113 | − clock-names = "core"; | |
| 114 | − power-domains = <&mmcc VENUS_CORE1_GDSC>; | |
| 115 | − }; | |
| 116 | − | |
| 117 | − video-firmware { | |
| 118 | − iommus = <&apps_iommu 0x10b2 0x0>; | |
| 119 | − }; | |
| 120 | − }; | |
| @@ -143,6 +143,7 @@ properties: · 142 unmodified lines | ||
| 143 | 143 | - rc-videomate-k100 |
| 144 | 144 | - rc-videomate-s350 |
| 145 | 145 | - rc-videomate-tv-pvr |
| 146 | + - rc-videostrong-kii-pro | |
| 146 | 147 | - rc-wetek-hub |
| 147 | 148 | - rc-wetek-play2 |
| 148 | 149 | - rc-winfast |
| @@ -6,8 +6,9 @@ BitBLT, alpha blending and image blur/sharpness. · 5 unmodified lines | ||
| 6 | 6 | |
| 7 | 7 | Required properties: |
| 8 | 8 | - compatible: value should be one of the following |
| 9 | − "rockchip,rk3288-rga"; | |
| 10 | − "rockchip,rk3399-rga"; | |
| 9 | + "rockchip,rk3228-rga", "rockchip,rk3288-rga": for Rockchip RK3228 | |
| 10 | + "rockchip,rk3288-rga": for Rockchip RK3288 | |
| 11 | + "rockchip,rk3399-rga": for Rockchip RK3399 | |
| 11 | 12 | |
| 12 | 13 | - interrupts: RGA interrupt specifier. |
| 13 | 14 | |
| @@ -74,7 +74,7 @@ Before the receiver driver may enable the CSI-2 transmitter by using · 73 unmodified lines | ||
| 74 | 74 | the :c:type:`v4l2_subdev_video_ops`->s_stream(), it must have powered |
| 75 | 75 | the transmitter up by using the |
| 76 | 76 | :c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take |
| 77 | −place either indirectly by using :c:func:`v4l2_pipeline_pm_use` or | |
| 77 | +place either indirectly by using :c:func:`v4l2_pipeline_pm_get` or | |
| 78 | 78 | directly. |
| 79 | 79 | |
| 80 | 80 | Formats |
| @@ -185,7 +185,7 @@ This will create the character device for you. · 184 unmodified lines | ||
| 185 | 185 | |
| 186 | 186 | .. code-block:: c |
| 187 | 187 | |
| 188 | − err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 188 | + err = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 189 | 189 | if (err) { |
| 190 | 190 | video_device_release(vdev); /* or kfree(my_vdev); */ |
| 191 | 191 | return err; |
| @@ -201,7 +201,7 @@ types exist: · 9 unmodified lines | ||
| 201 | 201 | ========================== ==================== ============================== |
| 202 | 202 | :c:type:`vfl_devnode_type` Device name Usage |
| 203 | 203 | ========================== ==================== ============================== |
| 204 | −``VFL_TYPE_GRABBER`` ``/dev/videoX`` for video input/output devices | |
| 204 | +``VFL_TYPE_VIDEO`` ``/dev/videoX`` for video input/output devices | |
| 205 | 205 | ``VFL_TYPE_VBI`` ``/dev/vbiX`` for vertical blank data (i.e. |
| 206 | 206 | closed captions, teletext) |
| 207 | 207 | ``VFL_TYPE_RADIO`` ``/dev/radioX`` for radio tuners |
| @@ -44,18 +44,18 @@ is only available if the ``CEC_CAP_CONNECTOR_INFO`` capability is set. · 43 unmodified lines | ||
| 44 | 44 | .. flat-table:: struct cec_connector_info |
| 45 | 45 | :header-rows: 0 |
| 46 | 46 | :stub-columns: 0 |
| 47 | − :widths: 1 1 1 8 | |
| 47 | + :widths: 1 1 8 | |
| 48 | 48 | |
| 49 | 49 | * - __u32 |
| 50 | 50 | - ``type`` |
| 51 | 51 | - The type of connector this adapter is associated with. |
| 52 | − * - union | |
| 52 | + * - union { | |
| 53 | 53 | - ``(anonymous)`` |
| 54 | − - | |
| 55 | − * - | |
| 56 | − - ``struct cec_drm_connector_info`` | |
| 54 | + * - ``struct cec_drm_connector_info`` | |
| 57 | 55 | - drm |
| 58 | 56 | - :ref:`cec-drm-connector-info` |
| 57 | + * - } | |
| 58 | + - | |
| 59 | 59 | |
| 60 | 60 | |
| 61 | 61 | .. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| |
| @@ -109,35 +109,33 @@ it is guaranteed that the state did change in between the two events. · 108 unmodified lines | ||
| 109 | 109 | .. flat-table:: struct cec_event |
| 110 | 110 | :header-rows: 0 |
| 111 | 111 | :stub-columns: 0 |
| 112 | − :widths: 1 1 1 8 | |
| 112 | + :widths: 1 1 8 | |
| 113 | 113 | |
| 114 | 114 | * - __u64 |
| 115 | 115 | - ``ts`` |
| 116 | − - :cspan:`1`\ Timestamp of the event in ns. | |
| 116 | + - Timestamp of the event in ns. | |
| 117 | 117 | |
| 118 | 118 | The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. |
| 119 | 119 | |
| 120 | 120 | To access the same clock from userspace use :c:func:`clock_gettime`. |
| 121 | 121 | * - __u32 |
| 122 | 122 | - ``event`` |
| 123 | − - :cspan:`1` The CEC event type, see :ref:`cec-events`. | |
| 123 | + - The CEC event type, see :ref:`cec-events`. | |
| 124 | 124 | * - __u32 |
| 125 | 125 | - ``flags`` |
| 126 | − - :cspan:`1` Event flags, see :ref:`cec-event-flags`. | |
| 127 | − * - union | |
| 126 | + - Event flags, see :ref:`cec-event-flags`. | |
| 127 | + * - union { | |
| 128 | 128 | - (anonymous) |
| 129 | − - | |
| 130 | − - | |
| 131 | − * - | |
| 132 | − - struct cec_event_state_change | |
| 129 | + * - struct cec_event_state_change | |
| 133 | 130 | - ``state_change`` |
| 134 | 131 | - The new adapter state as sent by the :ref:`CEC_EVENT_STATE_CHANGE <CEC-EVENT-STATE-CHANGE>` |
| 135 | 132 | event. |
| 136 | − * - | |
| 137 | − - struct cec_event_lost_msgs | |
| 133 | + * - struct cec_event_lost_msgs | |
| 138 | 134 | - ``lost_msgs`` |
| 139 | 135 | - The number of lost messages as sent by the :ref:`CEC_EVENT_LOST_MSGS <CEC-EVENT-LOST-MSGS>` |
| 140 | 136 | event. |
| 137 | + * - } | |
| 138 | + - | |
| 141 | 139 | |
| 142 | 140 | |
| 143 | 141 | .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| |
| @@ -64,12 +64,11 @@ id's until they get an error. · 63 unmodified lines | ||
| 64 | 64 | .. flat-table:: struct media_entity_desc |
| 65 | 65 | :header-rows: 0 |
| 66 | 66 | :stub-columns: 0 |
| 67 | − :widths: 1 1 1 1 8 | |
| 67 | + :widths: 2 2 1 8 | |
| 68 | 68 | |
| 69 | 69 | * - __u32 |
| 70 | 70 | - ``id`` |
| 71 | 71 | - |
| 72 | − - | |
| 73 | 72 | - Entity ID, set by the application. When the ID is or'ed with |
| 74 | 73 | ``MEDIA_ENT_ID_FLAG_NEXT``, the driver clears the flag and returns |
| 75 | 74 | the first entity with a larger ID. Do not expect that the ID will |
| @@ -79,79 +78,70 @@ id's until they get an error. · 3 unmodified lines | ||
| 79 | 78 | * - char |
| 80 | 79 | - ``name``\ [32] |
| 81 | 80 | - |
| 82 | − - | |
| 83 | 81 | - Entity name as an UTF-8 NULL-terminated string. This name must be unique |
| 84 | 82 | within the media topology. |
| 85 | 83 | |
| 86 | 84 | * - __u32 |
| 87 | 85 | - ``type`` |
| 88 | 86 | - |
| 89 | − - | |
| 90 | 87 | - Entity type, see :ref:`media-entity-functions` for details. |
| 91 | 88 | |
| 92 | 89 | * - __u32 |
| 93 | 90 | - ``revision`` |
| 94 | 91 | - |
| 95 | − - | |
| 96 | 92 | - Entity revision. Always zero (obsolete) |
| 97 | 93 | |
| 98 | 94 | * - __u32 |
| 99 | 95 | - ``flags`` |
| 100 | 96 | - |
| 101 | − - | |
| 102 | 97 | - Entity flags, see :ref:`media-entity-flag` for details. |
| 103 | 98 | |
| 104 | 99 | * - __u32 |
| 105 | 100 | - ``group_id`` |
| 106 | 101 | - |
| 107 | − - | |
| 108 | 102 | - Entity group ID. Always zero (obsolete) |
| 109 | 103 | |
| 110 | 104 | * - __u16 |
| 111 | 105 | - ``pads`` |
| 112 | 106 | - |
| 113 | − - | |
| 114 | 107 | - Number of pads |
| 115 | 108 | |
| 116 | 109 | * - __u16 |
| 117 | 110 | - ``links`` |
| 118 | 111 | - |
| 119 | − - | |
| 120 | 112 | - Total number of outbound links. Inbound links are not counted in |
| 121 | 113 | this field. |
| 122 | 114 | |
| 123 | 115 | * - __u32 |
| 124 | 116 | - ``reserved[4]`` |
| 125 | 117 | - |
| 126 | − - | |
| 127 | 118 | - Reserved for future extensions. Drivers and applications must set |
| 128 | 119 | the array to zero. |
| 129 | 120 | |
| 130 | − * - union | |
| 121 | + * - union { | |
| 122 | + - (anonymous) | |
| 131 | 123 | |
| 132 | − * - | |
| 133 | − - struct | |
| 124 | + * - struct | |
| 134 | 125 | - ``dev`` |
| 135 | 126 | - |
| 136 | 127 | - Valid for (sub-)devices that create a single device node. |
| 137 | 128 | |
| 138 | 129 | * - |
| 139 | − - | |
| 140 | 130 | - __u32 |
| 141 | 131 | - ``major`` |
| 142 | 132 | - Device node major number. |
| 143 | 133 | |
| 144 | 134 | * - |
| 145 | − - | |
| 146 | 135 | - __u32 |
| 147 | 136 | - ``minor`` |
| 148 | 137 | - Device node minor number. |
| 149 | 138 | |
| 150 | − * - | |
| 151 | − - __u8 | |
| 139 | + * - __u8 | |
| 152 | 140 | - ``raw``\ [184] |
| 153 | 141 | - |
| 154 | 142 | - |
| 143 | + * - } | |
| 144 | + - | |
| 155 | 145 | |
| 156 | 146 | |
| 157 | 147 | Return Value |
| @@ -172,11 +172,10 @@ struct v4l2_buffer · 171 unmodified lines | ||
| 172 | 172 | .. flat-table:: struct v4l2_buffer |
| 173 | 173 | :header-rows: 0 |
| 174 | 174 | :stub-columns: 0 |
| 175 | − :widths: 1 2 1 10 | |
| 175 | + :widths: 1 2 10 | |
| 176 | 176 | |
| 177 | 177 | * - __u32 |
| 178 | 178 | - ``index`` |
| 179 | − - | |
| 180 | 179 | - Number of the buffer, set by the application except when calling |
| 181 | 180 | :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`, then it is set by the |
| 182 | 181 | driver. This field can range from zero to the number of buffers |
| @@ -186,14 +185,12 @@ struct v4l2_buffer · 3 unmodified lines | ||
| 186 | 185 | :ref:`VIDIOC_CREATE_BUFS` minus one. |
| 187 | 186 | * - __u32 |
| 188 | 187 | - ``type`` |
| 189 | − - | |
| 190 | 188 | - Type of the buffer, same as struct |
| 191 | 189 | :c:type:`v4l2_format` ``type`` or struct |
| 192 | 190 | :c:type:`v4l2_requestbuffers` ``type``, set |
| 193 | 191 | by the application. See :c:type:`v4l2_buf_type` |
| 194 | 192 | * - __u32 |
| 195 | 193 | - ``bytesused`` |
| 196 | − - | |
| 197 | 194 | - The number of bytes occupied by the data in the buffer. It depends |
| 198 | 195 | on the negotiated data format and may change with each buffer for |
| 199 | 196 | compressed variable size data like JPEG images. Drivers must set |
| @@ -205,18 +202,15 @@ struct v4l2_buffer · 5 unmodified lines | ||
| 205 | 202 | ``planes`` pointer is used instead. |
| 206 | 203 | * - __u32 |
| 207 | 204 | - ``flags`` |
| 208 | − - | |
| 209 | 205 | - Flags set by the application or driver, see :ref:`buffer-flags`. |
| 210 | 206 | * - __u32 |
| 211 | 207 | - ``field`` |
| 212 | − - | |
| 213 | 208 | - Indicates the field order of the image in the buffer, see |
| 214 | 209 | :c:type:`v4l2_field`. This field is not used when the buffer |
| 215 | 210 | contains VBI data. Drivers must set it when ``type`` refers to a |
| 216 | 211 | capture stream, applications when it refers to an output stream. |
| 217 | 212 | * - struct timeval |
| 218 | 213 | - ``timestamp`` |
| 219 | − - | |
| 220 | 214 | - For capture streams this is time when the first data byte was |
| 221 | 215 | captured, as returned by the :c:func:`clock_gettime()` function |
| 222 | 216 | for the relevant clock id; see ``V4L2_BUF_FLAG_TIMESTAMP_*`` in |
| @@ -229,7 +223,6 @@ struct v4l2_buffer · 6 unmodified lines | ||
| 229 | 223 | stream. |
| 230 | 224 | * - struct :c:type:`v4l2_timecode` |
| 231 | 225 | - ``timecode`` |
| 232 | − - | |
| 233 | 226 | - When the ``V4L2_BUF_FLAG_TIMECODE`` flag is set in ``flags``, this |
| 234 | 227 | structure contains a frame timecode. In |
| 235 | 228 | :c:type:`V4L2_FIELD_ALTERNATE <v4l2_field>` mode the top and |
| @@ -239,10 +232,9 @@ struct v4l2_buffer · 3 unmodified lines | ||
| 239 | 232 | independent of the ``timestamp`` and ``sequence`` fields. |
| 240 | 233 | * - __u32 |
| 241 | 234 | - ``sequence`` |
| 242 | − - | |
| 243 | 235 | - Set by the driver, counting the frames (not fields!) in sequence. |
| 244 | 236 | This field is set for both input and output devices. |
| 245 | − * - :cspan:`3` | |
| 237 | + * - :cspan:`2` | |
| 246 | 238 | |
| 247 | 239 | In :c:type:`V4L2_FIELD_ALTERNATE <v4l2_field>` mode the top and |
| 248 | 240 | bottom field have the same sequence number. The count starts at |
| @@ -262,13 +254,11 @@ struct v4l2_buffer · 13 unmodified lines | ||
| 262 | 254 | |
| 263 | 255 | * - __u32 |
| 264 | 256 | - ``memory`` |
| 265 | − - | |
| 266 | 257 | - This field must be set by applications and/or drivers in |
| 267 | 258 | accordance with the selected I/O method. See :c:type:`v4l2_memory` |
| 268 | − * - union | |
| 259 | + * - union { | |
| 269 | 260 | - ``m`` |
| 270 | − * - | |
| 271 | − - __u32 | |
| 261 | + * - __u32 | |
| 272 | 262 | - ``offset`` |
| 273 | 263 | - For the single-planar API and when ``memory`` is |
| 274 | 264 | ``V4L2_MEMORY_MMAP`` this is the offset of the buffer from the |
| @@ -276,29 +266,27 @@ struct v4l2_buffer · 1 unmodified line | ||
| 276 | 266 | and apart of serving as parameter to the |
| 277 | 267 | :ref:`mmap() <func-mmap>` function not useful for applications. |
| 278 | 268 | See :ref:`mmap` for details |
| 279 | − * - | |
| 280 | − - unsigned long | |
| 269 | + * - unsigned long | |
| 281 | 270 | - ``userptr`` |
| 282 | 271 | - For the single-planar API and when ``memory`` is |
| 283 | 272 | ``V4L2_MEMORY_USERPTR`` this is a pointer to the buffer (casted to |
| 284 | 273 | unsigned long type) in virtual memory, set by the application. See |
| 285 | 274 | :ref:`userp` for details. |
| 286 | − * - | |
| 287 | − - struct v4l2_plane | |
| 275 | + * - struct v4l2_plane | |
| 288 | 276 | - ``*planes`` |
| 289 | 277 | - When using the multi-planar API, contains a userspace pointer to |
| 290 | 278 | an array of struct :c:type:`v4l2_plane`. The size of |
| 291 | 279 | the array should be put in the ``length`` field of this |
| 292 | 280 | struct :c:type:`v4l2_buffer` structure. |
| 293 | − * - | |
| 294 | − - int | |
| 281 | + * - int | |
| 295 | 282 | - ``fd`` |
| 296 | 283 | - For the single-plane API and when ``memory`` is |
| 297 | 284 | ``V4L2_MEMORY_DMABUF`` this is the file descriptor associated with |
| 298 | 285 | a DMABUF buffer. |
| 286 | + * - } | |
| 287 | + - | |
| 299 | 288 | * - __u32 |
| 300 | 289 | - ``length`` |
| 301 | − - | |
| 302 | 290 | - Size of the buffer (not the payload) in bytes for the |
| 303 | 291 | single-planar API. This is set by the driver based on the calls to |
| 304 | 292 | :ref:`VIDIOC_REQBUFS` and/or |
| @@ -308,12 +296,10 @@ struct v4l2_buffer · 3 unmodified lines | ||
| 308 | 296 | actual number of valid elements in that array. |
| 309 | 297 | * - __u32 |
| 310 | 298 | - ``reserved2`` |
| 311 | − - | |
| 312 | 299 | - A place holder for future extensions. Drivers and applications |
| 313 | 300 | must set this to 0. |
| 314 | 301 | * - __u32 |
| 315 | 302 | - ``request_fd`` |
| 316 | − - | |
| 317 | 303 | - The file descriptor of the request to queue the buffer to. If the flag |
| 318 | 304 | ``V4L2_BUF_FLAG_REQUEST_FD`` is set, then the buffer will be |
| 319 | 305 | queued to this request. If the flag is not set, then this field will |
| @@ -344,11 +330,10 @@ struct v4l2_plane · 24 unmodified lines | ||
| 344 | 330 | .. flat-table:: |
| 345 | 331 | :header-rows: 0 |
| 346 | 332 | :stub-columns: 0 |
| 347 | − :widths: 1 1 1 2 | |
| 333 | + :widths: 1 1 2 | |
| 348 | 334 | |
| 349 | 335 | * - __u32 |
| 350 | 336 | - ``bytesused`` |
| 351 | − - | |
| 352 | 337 | - The number of bytes occupied by data in the plane (its payload). |
| 353 | 338 | Drivers must set this field when ``type`` refers to a capture |
| 354 | 339 | stream, applications when it refers to an output stream. If the |
| @@ -362,40 +347,35 @@ struct v4l2_plane · 7 unmodified lines | ||
| 362 | 347 | which may not be 0. |
| 363 | 348 | * - __u32 |
| 364 | 349 | - ``length`` |
| 365 | − - | |
| 366 | 350 | - Size in bytes of the plane (not its payload). This is set by the |
| 367 | 351 | driver based on the calls to |
| 368 | 352 | :ref:`VIDIOC_REQBUFS` and/or |
| 369 | 353 | :ref:`VIDIOC_CREATE_BUFS`. |
| 370 | − * - union | |
| 354 | + * - union { | |
| 371 | 355 | - ``m`` |
| 372 | − - | |
| 373 | − - | |
| 374 | − * - | |
| 375 | − - __u32 | |
| 356 | + * - __u32 | |
| 376 | 357 | - ``mem_offset`` |
| 377 | 358 | - When the memory type in the containing struct |
| 378 | 359 | :c:type:`v4l2_buffer` is ``V4L2_MEMORY_MMAP``, this |
| 379 | 360 | is the value that should be passed to :ref:`mmap() <func-mmap>`, |
| 380 | 361 | similar to the ``offset`` field in struct |
| 381 | 362 | :c:type:`v4l2_buffer`. |
| 382 | − * - | |
| 383 | − - unsigned long | |
| 363 | + * - unsigned long | |
| 384 | 364 | - ``userptr`` |
| 385 | 365 | - When the memory type in the containing struct |
| 386 | 366 | :c:type:`v4l2_buffer` is ``V4L2_MEMORY_USERPTR``, |
| 387 | 367 | this is a userspace pointer to the memory allocated for this plane |
| 388 | 368 | by an application. |
| 389 | − * - | |
| 390 | − - int | |
| 369 | + * - int | |
| 391 | 370 | - ``fd`` |
| 392 | 371 | - When the memory type in the containing struct |
| 393 | 372 | :c:type:`v4l2_buffer` is ``V4L2_MEMORY_DMABUF``, |
| 394 | 373 | this is a file descriptor associated with a DMABUF buffer, similar |
| 395 | 374 | to the ``fd`` field in struct :c:type:`v4l2_buffer`. |
| 375 | + * - } | |
| 376 | + - | |
| 396 | 377 | * - __u32 |
| 397 | 378 | - ``data_offset`` |
| 398 | − - | |
| 399 | 379 | - Offset in bytes to video data in the plane. Drivers must set this |
| 400 | 380 | field when ``type`` refers to a capture stream, applications when |
| 401 | 381 | it refers to an output stream. |
| @@ -407,7 +387,6 @@ struct v4l2_plane · 5 unmodified lines | ||
| 407 | 387 | at offset ``data_offset`` from the start of the plane. |
| 408 | 388 | * - __u32 |
| 409 | 389 | - ``reserved[11]`` |
| 410 | − - | |
| 411 | 390 | - Reserved for future use. Should be zeroed by drivers and |
| 412 | 391 | applications. |
| 413 | 392 | |
| @@ -478,33 +478,30 @@ struct v4l2_mpeg_vbi_fmt_ivtv · 477 unmodified lines | ||
| 478 | 478 | .. flat-table:: |
| 479 | 479 | :header-rows: 0 |
| 480 | 480 | :stub-columns: 0 |
| 481 | − :widths: 1 1 1 2 | |
| 481 | + :widths: 1 1 2 | |
| 482 | 482 | |
| 483 | 483 | * - __u8 |
| 484 | 484 | - ``magic``\ [4] |
| 485 | − - | |
| 486 | 485 | - A "magic" constant from :ref:`v4l2-mpeg-vbi-fmt-ivtv-magic` that |
| 487 | 486 | indicates this is a valid sliced VBI data payload and also |
| 488 | 487 | indicates which member of the anonymous union, ``itv0`` or |
| 489 | 488 | ``ITV0``, to use for the payload data. |
| 490 | − * - union | |
| 489 | + * - union { | |
| 491 | 490 | - (anonymous) |
| 492 | − * - | |
| 493 | − - struct :c:type:`v4l2_mpeg_vbi_itv0` | |
| 491 | + * - struct :c:type:`v4l2_mpeg_vbi_itv0` | |
| 494 | 492 | - ``itv0`` |
| 495 | 493 | - The primary form of the sliced VBI data payload that contains |
| 496 | 494 | anywhere from 1 to 35 lines of sliced VBI data. Line masks are |
| 497 | 495 | provided in this form of the payload indicating which VBI lines |
| 498 | 496 | are provided. |
| 499 | − * - | |
| 500 | − - struct :ref:`v4l2_mpeg_vbi_ITV0 <v4l2-mpeg-vbi-itv0-1>` | |
| 497 | + * - struct :ref:`v4l2_mpeg_vbi_ITV0 <v4l2-mpeg-vbi-itv0-1>` | |
| 501 | 498 | - ``ITV0`` |
| 502 | 499 | - An alternate form of the sliced VBI data payload used when 36 |
| 503 | 500 | lines of sliced VBI data are present. No line masks are provided |
| 504 | 501 | in this form of the payload; all valid line mask bits are |
| 505 | 502 | implcitly set. |
| 506 | − | |
| 507 | − | |
| 503 | + * - } | |
| 504 | + - | |
| 508 | 505 | |
| 509 | 506 | .. _v4l2-mpeg-vbi-fmt-ivtv-magic: |
| 510 | 507 | |
| @@ -2028,6 +2028,22 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - · 2027 unmodified lines | ||
| 2028 | 2028 | * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` |
| 2029 | 2029 | - 0x00000004 |
| 2030 | 2030 | - The DPB entry is a long term reference frame |
| 2031 | + * - ``V4L2_H264_DPB_ENTRY_FLAG_FIELD`` | |
| 2032 | + - 0x00000008 | |
| 2033 | + - The DPB entry is a field reference, which means only one of the field | |
| 2034 | + will be used when decoding the new frame/field. When not set the DPB | |
| 2035 | + entry is a frame reference (both fields will be used). Note that this | |
| 2036 | + flag does not say anything about the number of fields contained in the | |
| 2037 | + reference frame, it just describes the one used to decode the new | |
| 2038 | + field/frame | |
| 2039 | + * - ``V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD`` | |
| 2040 | + - 0x00000010 | |
| 2041 | + - The DPB entry is a bottom field reference (only the bottom field of the | |
| 2042 | + reference frame is needed to decode the new frame/field). Only valid if | |
| 2043 | + V4L2_H264_DPB_ENTRY_FLAG_FIELD is set. When | |
| 2044 | + V4L2_H264_DPB_ENTRY_FLAG_FIELD is set but | |
| 2045 | + V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD is not, that means the | |
| 2046 | + DPB entry is a top field reference | |
| 2031 | 2047 | |
| 2032 | 2048 | ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE (enum)`` |
| 2033 | 2049 | Specifies the decoding mode to use. Currently exposes slice-based and |
| @@ -34,5 +34,6 @@ orders. See also `the Wikipedia article on Bayer filter · 33 unmodified lines | ||
| 34 | 34 | pixfmt-srggb10-ipu3 |
| 35 | 35 | pixfmt-srggb12 |
| 36 | 36 | pixfmt-srggb12p |
| 37 | + pixfmt-srggb14 | |
| 37 | 38 | pixfmt-srggb14p |
| 38 | 39 | pixfmt-srggb16 |
| @@ -0,0 +1,82 @@ | ||
| 1 | +.. Permission is granted to copy, distribute and/or modify this | |
| 2 | +.. document under the terms of the GNU Free Documentation License, | |
| 3 | +.. Version 1.1 or any later version published by the Free Software | |
| 4 | +.. Foundation, with no Invariant Sections, no Front-Cover Texts | |
| 5 | +.. and no Back-Cover Texts. A copy of the license is included at | |
| 6 | +.. Documentation/media/uapi/fdl-appendix.rst. | |
| 7 | +.. | |
| 8 | +.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections | |
| 9 | + | |
| 10 | +.. _V4L2-PIX-FMT-SRGGB14: | |
| 11 | +.. _v4l2-pix-fmt-sbggr14: | |
| 12 | +.. _v4l2-pix-fmt-sgbrg14: | |
| 13 | +.. _v4l2-pix-fmt-sgrbg14: | |
| 14 | + | |
| 15 | + | |
| 16 | +*************************************************************************************************************************** | |
| 17 | +V4L2_PIX_FMT_SRGGB14 ('RG14'), V4L2_PIX_FMT_SGRBG14 ('GR14'), V4L2_PIX_FMT_SGBRG14 ('GB14'), V4L2_PIX_FMT_SBGGR14 ('BG14'), | |
| 18 | +*************************************************************************************************************************** | |
| 19 | + | |
| 20 | + | |
| 21 | +14-bit Bayer formats expanded to 16 bits | |
| 22 | + | |
| 23 | + | |
| 24 | +Description | |
| 25 | +=========== | |
| 26 | + | |
| 27 | +These four pixel formats are raw sRGB / Bayer formats with 14 bits per | |
| 28 | +colour. Each sample is stored in a 16-bit word, with two unused high | |
| 29 | +bits filled with zeros. Each n-pixel row contains n/2 green samples | |
| 30 | +and n/2 blue or red samples, with alternating red and blue rows. Bytes | |
| 31 | +are stored in memory in little endian order. They are conventionally | |
| 32 | +described as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an | |
| 33 | +example of a small V4L2_PIX_FMT_SBGGR14 image: | |
| 34 | + | |
| 35 | +**Byte Order.** | |
| 36 | +Each cell is one byte, the two most significant bits in the high bytes are | |
| 37 | +zero. | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | +.. flat-table:: | |
| 42 | + :header-rows: 0 | |
| 43 | + :stub-columns: 0 | |
| 44 | + :widths: 2 1 1 1 1 1 1 1 1 | |
| 45 | + | |
| 46 | + | |
| 47 | + * - start + 0: | |
| 48 | + - B\ :sub:`00low` | |
| 49 | + - B\ :sub:`00high` | |
| 50 | + - G\ :sub:`01low` | |
| 51 | + - G\ :sub:`01high` | |
| 52 | + - B\ :sub:`02low` | |
| 53 | + - B\ :sub:`02high` | |
| 54 | + - G\ :sub:`03low` | |
| 55 | + - G\ :sub:`03high` | |
| 56 | + * - start + 8: | |
| 57 | + - G\ :sub:`10low` | |
| 58 | + - G\ :sub:`10high` | |
| 59 | + - R\ :sub:`11low` | |
| 60 | + - R\ :sub:`11high` | |
| 61 | + - G\ :sub:`12low` | |
| 62 | + - G\ :sub:`12high` | |
| 63 | + - R\ :sub:`13low` | |
| 64 | + - R\ :sub:`13high` | |
| 65 | + * - start + 16: | |
| 66 | + - B\ :sub:`20low` | |
| 67 | + - B\ :sub:`20high` | |
| 68 | + - G\ :sub:`21low` | |
| 69 | + - G\ :sub:`21high` | |
| 70 | + - B\ :sub:`22low` | |
| 71 | + - B\ :sub:`22high` | |
| 72 | + - G\ :sub:`23low` | |
| 73 | + - G\ :sub:`23high` | |
| 74 | + * - start + 24: | |
| 75 | + - G\ :sub:`30low` | |
| 76 | + - G\ :sub:`30high` | |
| 77 | + - R\ :sub:`31low` | |
| 78 | + - R\ :sub:`31high` | |
| 79 | + - G\ :sub:`32low` | |
| 80 | + - G\ :sub:`32high` | |
| 81 | + - R\ :sub:`33low` | |
| 82 | + - R\ :sub:`33high` | |
| @@ -100,7 +100,8 @@ describing all planes of that format. · 99 unmodified lines | ||
| 100 | 100 | * - __u8 |
| 101 | 101 | - ``flags`` |
| 102 | 102 | - Flags set by the application or driver, see :ref:`format-flags`. |
| 103 | − * - :cspan:`2` union { (anonymous) | |
| 103 | + * - union { | |
| 104 | + - (anonymous) | |
| 104 | 105 | * - __u8 |
| 105 | 106 | - ``ycbcr_enc`` |
| 106 | 107 | - Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. |
| @@ -113,7 +114,8 @@ describing all planes of that format. · 6 unmodified lines | ||
| 113 | 114 | This information supplements the ``colorspace`` and must be set by |
| 114 | 115 | the driver for capture streams and by the application for output |
| 115 | 116 | streams, see :ref:`colorspaces`. |
| 116 | − * - :cspan:`2` } | |
| 117 | + * - } | |
| 118 | + - | |
| 117 | 119 | * - __u8 |
| 118 | 120 | - ``quantization`` |
| 119 | 121 | - Quantization range, from enum :c:type:`v4l2_quantization`. |
| @@ -143,7 +143,6 @@ Single-planar format structure · 142 unmodified lines | ||
| 143 | 143 | - Flags set by the application or driver, see :ref:`format-flags`. |
| 144 | 144 | * - union { |
| 145 | 145 | - (anonymous) |
| 146 | − - | |
| 147 | 146 | * - __u32 |
| 148 | 147 | - ``ycbcr_enc`` |
| 149 | 148 | - Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. |
| @@ -158,7 +157,6 @@ Single-planar format structure · 8 unmodified lines | ||
| 158 | 157 | streams, see :ref:`colorspaces`. |
| 159 | 158 | * - } |
| 160 | 159 | - |
| 161 | − - | |
| 162 | 160 | * - __u32 |
| 163 | 161 | - ``quantization`` |
| 164 | 162 | - Quantization range, from enum :c:type:`v4l2_quantization`. |
| @@ -0,0 +1,72 @@ | ||
| 1 | +.. Permission is granted to copy, distribute and/or modify this | |
| 2 | +.. document under the terms of the GNU Free Documentation License, | |
| 3 | +.. Version 1.1 or any later version published by the Free Software | |
| 4 | +.. Foundation, with no Invariant Sections, no Front-Cover Texts | |
| 5 | +.. and no Back-Cover Texts. A copy of the license is included at | |
| 6 | +.. Documentation/media/uapi/fdl-appendix.rst. | |
| 7 | +.. | |
| 8 | +.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections | |
| 9 | + | |
| 10 | +.. _V4L2-PIX-FMT-Y14: | |
| 11 | + | |
| 12 | +************************* | |
| 13 | +V4L2_PIX_FMT_Y14 ('Y14 ') | |
| 14 | +************************* | |
| 15 | + | |
| 16 | + | |
| 17 | +Grey-scale image | |
| 18 | + | |
| 19 | + | |
| 20 | +Description | |
| 21 | +=========== | |
| 22 | + | |
| 23 | +This is a grey-scale image with a depth of 14 bits per pixel. Pixels are | |
| 24 | +stored in 16-bit words with unused high bits padded with 0. The least | |
| 25 | +significant byte is stored at lower memory addresses (little-endian). | |
| 26 | + | |
| 27 | +**Byte Order.** | |
| 28 | +Each cell is one byte. | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | +.. flat-table:: | |
| 34 | + :header-rows: 0 | |
| 35 | + :stub-columns: 0 | |
| 36 | + | |
| 37 | + * - start + 0: | |
| 38 | + - Y'\ :sub:`00low` | |
| 39 | + - Y'\ :sub:`00high` | |
| 40 | + - Y'\ :sub:`01low` | |
| 41 | + - Y'\ :sub:`01high` | |
| 42 | + - Y'\ :sub:`02low` | |
| 43 | + - Y'\ :sub:`02high` | |
| 44 | + - Y'\ :sub:`03low` | |
| 45 | + - Y'\ :sub:`03high` | |
| 46 | + * - start + 8: | |
| 47 | + - Y'\ :sub:`10low` | |
| 48 | + - Y'\ :sub:`10high` | |
| 49 | + - Y'\ :sub:`11low` | |
| 50 | + - Y'\ :sub:`11high` | |
| 51 | + - Y'\ :sub:`12low` | |
| 52 | + - Y'\ :sub:`12high` | |
| 53 | + - Y'\ :sub:`13low` | |
| 54 | + - Y'\ :sub:`13high` | |
| 55 | + * - start + 16: | |
| 56 | + - Y'\ :sub:`20low` | |
| 57 | + - Y'\ :sub:`20high` | |
| 58 | + - Y'\ :sub:`21low` | |
| 59 | + - Y'\ :sub:`21high` | |
| 60 | + - Y'\ :sub:`22low` | |
| 61 | + - Y'\ :sub:`22high` | |
| 62 | + - Y'\ :sub:`23low` | |
| 63 | + - Y'\ :sub:`23high` | |
| 64 | + * - start + 24: | |
| 65 | + - Y'\ :sub:`30low` | |
| 66 | + - Y'\ :sub:`30high` | |
| 67 | + - Y'\ :sub:`31low` | |
| 68 | + - Y'\ :sub:`31high` | |
| 69 | + - Y'\ :sub:`32low` | |
| 70 | + - Y'\ :sub:`32high` | |
| 71 | + - Y'\ :sub:`33low` | |
| 72 | + - Y'\ :sub:`33high` | |
| @@ -5792,6 +5792,43 @@ the following codes. · 5791 unmodified lines | ||
| 5792 | 5792 | - u\ :sub:`2` |
| 5793 | 5793 | - u\ :sub:`1` |
| 5794 | 5794 | - u\ :sub:`0` |
| 5795 | + * .. _MEDIA-BUS-FMT-Y14-1X14: | |
| 5796 | + | |
| 5797 | + - MEDIA_BUS_FMT_Y14_1X14 | |
| 5798 | + - 0x202d | |
| 5799 | + - | |
| 5800 | + - | |
| 5801 | + - | |
| 5802 | + - | |
| 5803 | + - | |
| 5804 | + - | |
| 5805 | + - | |
| 5806 | + - | |
| 5807 | + - | |
| 5808 | + - | |
| 5809 | + - | |
| 5810 | + - | |
| 5811 | + - | |
| 5812 | + - | |
| 5813 | + - | |
| 5814 | + - | |
| 5815 | + - | |
| 5816 | + - | |
| 5817 | + - | |
| 5818 | + - y\ :sub:`13` | |
| 5819 | + - y\ :sub:`12` | |
| 5820 | + - y\ :sub:`11` | |
| 5821 | + - y\ :sub:`10` | |
| 5822 | + - y\ :sub:`9` | |
| 5823 | + - y\ :sub:`8` | |
| 5824 | + - y\ :sub:`7` | |
| 5825 | + - y\ :sub:`6` | |
| 5826 | + - y\ :sub:`5` | |
| 5827 | + - y\ :sub:`4` | |
| 5828 | + - y\ :sub:`3` | |
| 5829 | + - y\ :sub:`2` | |
| 5830 | + - y\ :sub:`1` | |
| 5831 | + - y\ :sub:`0` | |
| 5795 | 5832 | * .. _MEDIA-BUS-FMT-UYVY8-1X16: |
| 5796 | 5833 | |
| 5797 | 5834 | - MEDIA_BUS_FMT_UYVY8_1X16 |
| @@ -91,23 +91,23 @@ instructions. · 90 unmodified lines | ||
| 91 | 91 | .. flat-table:: struct v4l2_dbg_match |
| 92 | 92 | :header-rows: 0 |
| 93 | 93 | :stub-columns: 0 |
| 94 | − :widths: 1 1 1 2 | |
| 94 | + :widths: 1 1 2 | |
| 95 | 95 | |
| 96 | 96 | * - __u32 |
| 97 | 97 | - ``type`` |
| 98 | 98 | - See :ref:`name-chip-match-types` for a list of possible types. |
| 99 | − * - union | |
| 99 | + * - union { | |
| 100 | 100 | - (anonymous) |
| 101 | − * - | |
| 102 | − - __u32 | |
| 101 | + * - __u32 | |
| 103 | 102 | - ``addr`` |
| 104 | 103 | - Match a chip by this number, interpreted according to the ``type`` |
| 105 | 104 | field. |
| 106 | − * - | |
| 107 | − - char | |
| 105 | + * - char | |
| 108 | 106 | - ``name[32]`` |
| 109 | 107 | - Match a chip by this name, interpreted according to the ``type`` |
| 110 | 108 | field. Currently unused. |
| 109 | + * - } | |
| 110 | + - | |
| 111 | 111 | |
| 112 | 112 | |
| 113 | 113 | |
| @@ -100,23 +100,23 @@ instructions. · 99 unmodified lines | ||
| 100 | 100 | .. flat-table:: struct v4l2_dbg_match |
| 101 | 101 | :header-rows: 0 |
| 102 | 102 | :stub-columns: 0 |
| 103 | − :widths: 1 1 1 2 | |
| 103 | + :widths: 1 1 2 | |
| 104 | 104 | |
| 105 | 105 | * - __u32 |
| 106 | 106 | - ``type`` |
| 107 | 107 | - See :ref:`chip-match-types` for a list of possible types. |
| 108 | − * - union | |
| 108 | + * - union { | |
| 109 | 109 | - (anonymous) |
| 110 | − * - | |
| 111 | − - __u32 | |
| 110 | + * - __u32 | |
| 112 | 111 | - ``addr`` |
| 113 | 112 | - Match a chip by this number, interpreted according to the ``type`` |
| 114 | 113 | field. |
| 115 | − * - | |
| 116 | − - char | |
| 114 | + * - char | |
| 117 | 115 | - ``name[32]`` |
| 118 | 116 | - Match a chip by this name, interpreted according to the ``type`` |
| 119 | 117 | field. Currently unused. |
| 118 | + * - } | |
| 119 | + - | |
| 120 | 120 | |
| 121 | 121 | |
| 122 | 122 | |
| @@ -77,32 +77,25 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod · 76 unmodified lines | ||
| 77 | 77 | .. flat-table:: struct v4l2_decoder_cmd |
| 78 | 78 | :header-rows: 0 |
| 79 | 79 | :stub-columns: 0 |
| 80 | − :widths: 11 24 12 16 106 | |
| 80 | + :widths: 1 1 1 3 | |
| 81 | 81 | |
| 82 | 82 | * - __u32 |
| 83 | 83 | - ``cmd`` |
| 84 | 84 | - |
| 85 | − - | |
| 86 | 85 | - The decoder command, see :ref:`decoder-cmds`. |
| 87 | 86 | * - __u32 |
| 88 | 87 | - ``flags`` |
| 89 | 88 | - |
| 90 | − - | |
| 91 | 89 | - Flags to go with the command. If no flags are defined for this |
| 92 | 90 | command, drivers and applications must set this field to zero. |
| 93 | − * - union | |
| 91 | + * - union { | |
| 94 | 92 | - (anonymous) |
| 95 | − - | |
| 96 | − - | |
| 97 | − - | |
| 98 | − * - | |
| 99 | − - struct | |
| 93 | + * - struct | |
| 100 | 94 | - ``start`` |
| 101 | 95 | - |
| 102 | 96 | - Structure containing additional data for the |
| 103 | 97 | ``V4L2_DEC_CMD_START`` command. |
| 104 | 98 | * - |
| 105 | − - | |
| 106 | 99 | - __s32 |
| 107 | 100 | - ``speed`` |
| 108 | 101 | - Playback speed and direction. The playback speed is defined as |
| @@ -113,7 +106,6 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod · 4 unmodified lines | ||
| 113 | 106 | of 1 steps just one frame forward, a speed of -1 steps just one |
| 114 | 107 | frame back. |
| 115 | 108 | * - |
| 116 | − - | |
| 117 | 109 | - __u32 |
| 118 | 110 | - ``format`` |
| 119 | 111 | - Format restrictions. This field is set by the driver, not the |
| @@ -124,30 +116,26 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod · 4 unmodified lines | ||
| 124 | 116 | GOPs, which it can then play in reverse order. So to implement |
| 125 | 117 | reverse playback the application must feed the decoder the last |
| 126 | 118 | GOP in the video file, then the GOP before that, etc. etc. |
| 127 | − * - | |
| 128 | − - struct | |
| 119 | + * - struct | |
| 129 | 120 | - ``stop`` |
| 130 | 121 | - |
| 131 | 122 | - Structure containing additional data for the ``V4L2_DEC_CMD_STOP`` |
| 132 | 123 | command. |
| 133 | 124 | * - |
| 134 | − - | |
| 135 | 125 | - __u64 |
| 136 | 126 | - ``pts`` |
| 137 | 127 | - Stop playback at this ``pts`` or immediately if the playback is |
| 138 | 128 | already past that timestamp. Leave to 0 if you want to stop after |
| 139 | 129 | the last frame was decoded. |
| 140 | − * - | |
| 141 | − - struct | |
| 130 | + * - struct | |
| 142 | 131 | - ``raw`` |
| 143 | − - | |
| 144 | − - | |
| 145 | 132 | * - |
| 146 | − - | |
| 147 | 133 | - __u32 |
| 148 | 134 | - ``data``\ [16] |
| 149 | 135 | - Reserved for future extensions. Drivers and applications must set |
| 150 | 136 | the array to zero. |
| 137 | + * - } | |
| 138 | + - | |
| 151 | 139 | |
| 152 | 140 | |
| 153 | 141 | |
| @@ -55,66 +55,54 @@ call. · 54 unmodified lines | ||
| 55 | 55 | .. flat-table:: struct v4l2_event |
| 56 | 56 | :header-rows: 0 |
| 57 | 57 | :stub-columns: 0 |
| 58 | − :widths: 1 1 2 1 | |
| 58 | + :widths: 1 1 2 | |
| 59 | 59 | |
| 60 | 60 | * - __u32 |
| 61 | 61 | - ``type`` |
| 62 | − - | |
| 63 | 62 | - Type of the event, see :ref:`event-type`. |
| 64 | − * - union | |
| 63 | + * - union { | |
| 65 | 64 | - ``u`` |
| 66 | − - | |
| 67 | − - | |
| 68 | − * - | |
| 69 | − - struct :c:type:`v4l2_event_vsync` | |
| 65 | + * - struct :c:type:`v4l2_event_vsync` | |
| 70 | 66 | - ``vsync`` |
| 71 | 67 | - Event data for event ``V4L2_EVENT_VSYNC``. |
| 72 | − * - | |
| 73 | − - struct :c:type:`v4l2_event_ctrl` | |
| 68 | + * - struct :c:type:`v4l2_event_ctrl` | |
| 74 | 69 | - ``ctrl`` |
| 75 | 70 | - Event data for event ``V4L2_EVENT_CTRL``. |
| 76 | − * - | |
| 77 | − - struct :c:type:`v4l2_event_frame_sync` | |
| 71 | + * - struct :c:type:`v4l2_event_frame_sync` | |
| 78 | 72 | - ``frame_sync`` |
| 79 | 73 | - Event data for event ``V4L2_EVENT_FRAME_SYNC``. |
| 80 | − * - | |
| 81 | − - struct :c:type:`v4l2_event_motion_det` | |
| 74 | + * - struct :c:type:`v4l2_event_motion_det` | |
| 82 | 75 | - ``motion_det`` |
| 83 | 76 | - Event data for event V4L2_EVENT_MOTION_DET. |
| 84 | − * - | |
| 85 | − - struct :c:type:`v4l2_event_src_change` | |
| 77 | + * - struct :c:type:`v4l2_event_src_change` | |
| 86 | 78 | - ``src_change`` |
| 87 | 79 | - Event data for event V4L2_EVENT_SOURCE_CHANGE. |
| 88 | − * - | |
| 89 | − - __u8 | |
| 80 | + * - __u8 | |
| 90 | 81 | - ``data``\ [64] |
| 91 | 82 | - Event data. Defined by the event type. The union should be used to |
| 92 | 83 | define easily accessible type for events. |
| 84 | + * - } | |
| 85 | + - | |
| 93 | 86 | * - __u32 |
| 94 | 87 | - ``pending`` |
| 95 | − - | |
| 96 | 88 | - Number of pending events excluding this one. |
| 97 | 89 | * - __u32 |
| 98 | 90 | - ``sequence`` |
| 99 | − - | |
| 100 | 91 | - Event sequence number. The sequence number is incremented for |
| 101 | 92 | every subscribed event that takes place. If sequence numbers are |
| 102 | 93 | not contiguous it means that events have been lost. |
| 103 | 94 | * - struct timespec |
| 104 | 95 | - ``timestamp`` |
| 105 | − - | |
| 106 | 96 | - Event timestamp. The timestamp has been taken from the |
| 107 | 97 | ``CLOCK_MONOTONIC`` clock. To access the same clock outside V4L2, |
| 108 | 98 | use :c:func:`clock_gettime`. |
| 109 | 99 | * - u32 |
| 110 | 100 | - ``id`` |
| 111 | − - | |
| 112 | 101 | - The ID associated with the event source. If the event does not |
| 113 | 102 | have an associated ID (this depends on the event type), then this |
| 114 | 103 | is 0. |
| 115 | 104 | * - __u32 |
| 116 | 105 | - ``reserved``\ [8] |
| 117 | − - | |
| 118 | 106 | - Reserved for future extensions. Drivers must set the array to |
| 119 | 107 | zero. |
| 120 | 108 | |
| @@ -233,54 +221,45 @@ call. · 112 unmodified lines | ||
| 233 | 221 | .. flat-table:: struct v4l2_event_ctrl |
| 234 | 222 | :header-rows: 0 |
| 235 | 223 | :stub-columns: 0 |
| 236 | − :widths: 1 1 2 1 | |
| 224 | + :widths: 1 1 2 | |
| 237 | 225 | |
| 238 | 226 | * - __u32 |
| 239 | 227 | - ``changes`` |
| 240 | − - | |
| 241 | 228 | - A bitmask that tells what has changed. See |
| 242 | 229 | :ref:`ctrl-changes-flags`. |
| 243 | 230 | * - __u32 |
| 244 | 231 | - ``type`` |
| 245 | − - | |
| 246 | 232 | - The type of the control. See enum |
| 247 | 233 | :c:type:`v4l2_ctrl_type`. |
| 248 | − * - union (anonymous) | |
| 249 | − - | |
| 250 | − - | |
| 251 | − - | |
| 252 | − * - | |
| 253 | − - __s32 | |
| 234 | + * - union { | |
| 235 | + - (anonymous) | |
| 236 | + * - __s32 | |
| 254 | 237 | - ``value`` |
| 255 | 238 | - The 32-bit value of the control for 32-bit control types. This is |
| 256 | 239 | 0 for string controls since the value of a string cannot be passed |
| 257 | 240 | using :ref:`VIDIOC_DQEVENT`. |
| 258 | − * - | |
| 259 | − - __s64 | |
| 241 | + * - __s64 | |
| 260 | 242 | - ``value64`` |
| 261 | 243 | - The 64-bit value of the control for 64-bit control types. |
| 244 | + * - } | |
| 245 | + - | |
| 262 | 246 | * - __u32 |
| 263 | 247 | - ``flags`` |
| 264 | − - | |
| 265 | 248 | - The control flags. See :ref:`control-flags`. |
| 266 | 249 | * - __s32 |
| 267 | 250 | - ``minimum`` |
| 268 | − - | |
| 269 | 251 | - The minimum value of the control. See struct |
| 270 | 252 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 271 | 253 | * - __s32 |
| 272 | 254 | - ``maximum`` |
| 273 | − - | |
| 274 | 255 | - The maximum value of the control. See struct |
| 275 | 256 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 276 | 257 | * - __s32 |
| 277 | 258 | - ``step`` |
| 278 | − - | |
| 279 | 259 | - The step value of the control. See struct |
| 280 | 260 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 281 | 261 | * - __s32 |
| 282 | 262 | - ``default_value`` |
| 283 | − - | |
| 284 | 263 | - The default value value of the control. See struct |
| 285 | 264 | :ref:`v4l2_queryctrl <v4l2-queryctrl>`. |
| 286 | 265 | |
| @@ -112,7 +112,7 @@ that doesn't support them will return an ``EINVAL`` error code. · 111 unmodified lines | ||
| 112 | 112 | .. flat-table:: struct v4l2_dv_timings_cap |
| 113 | 113 | :header-rows: 0 |
| 114 | 114 | :stub-columns: 0 |
| 115 | − :widths: 1 1 2 1 | |
| 115 | + :widths: 1 1 2 | |
| 116 | 116 | |
| 117 | 117 | * - __u32 |
| 118 | 118 | - ``type`` |
| @@ -127,16 +127,14 @@ that doesn't support them will return an ``EINVAL`` error code. · 8 unmodified lines | ||
| 127 | 127 | - Reserved for future extensions. |
| 128 | 128 | |
| 129 | 129 | Drivers and applications must set the array to zero. |
| 130 | − * - union | |
| 131 | − - | |
| 132 | − - | |
| 133 | − * - | |
| 134 | − - struct :c:type:`v4l2_bt_timings_cap` | |
| 130 | + * - union { | |
| 131 | + - (anonymous) | |
| 132 | + * - struct :c:type:`v4l2_bt_timings_cap` | |
| 135 | 133 | - ``bt`` |
| 136 | 134 | - BT.656/1120 timings capabilities of the hardware. |
| 137 | − * - | |
| 138 | − - __u32 | |
| 135 | + * - __u32 | |
| 139 | 136 | - ``raw_data``\ [32] |
| 137 | + * - } | |
| 140 | 138 | - |
| 141 | 139 | |
| 142 | 140 | .. tabularcolumns:: |p{7.0cm}|p{10.5cm}| |
| @@ -138,36 +138,31 @@ application should zero out all members except for the *IN* fields. · 137 unmodified lines | ||
| 138 | 138 | |
| 139 | 139 | * - __u32 |
| 140 | 140 | - ``index`` |
| 141 | − - | |
| 142 | 141 | - IN: Index of the given frame interval in the enumeration. |
| 143 | 142 | * - __u32 |
| 144 | 143 | - ``pixel_format`` |
| 145 | − - | |
| 146 | 144 | - IN: Pixel format for which the frame intervals are enumerated. |
| 147 | 145 | * - __u32 |
| 148 | 146 | - ``width`` |
| 149 | − - | |
| 150 | 147 | - IN: Frame width for which the frame intervals are enumerated. |
| 151 | 148 | * - __u32 |
| 152 | 149 | - ``height`` |
| 153 | − - | |
| 154 | 150 | - IN: Frame height for which the frame intervals are enumerated. |
| 155 | 151 | * - __u32 |
| 156 | 152 | - ``type`` |
| 157 | − - | |
| 158 | 153 | - OUT: Frame interval type the device supports. |
| 159 | − * - union | |
| 160 | − - | |
| 161 | − - | |
| 154 | + * - union { | |
| 155 | + - (anonymous) | |
| 162 | 156 | - OUT: Frame interval with the given index. |
| 163 | − * - | |
| 164 | − - struct :c:type:`v4l2_fract` | |
| 157 | + * - struct :c:type:`v4l2_fract` | |
| 165 | 158 | - ``discrete`` |
| 166 | 159 | - Frame interval [s]. |
| 167 | − * - | |
| 168 | − - struct :c:type:`v4l2_frmival_stepwise` | |
| 160 | + * - struct :c:type:`v4l2_frmival_stepwise` | |
| 169 | 161 | - ``stepwise`` |
| 170 | 162 | - |
| 163 | + * - } | |
| 164 | + - | |
| 165 | + - | |
| 171 | 166 | * - __u32 |
| 172 | 167 | - ``reserved[2]`` |
| 173 | 168 | - |
| @@ -155,31 +155,27 @@ application should zero out all members except for the *IN* fields. · 154 unmodified lines | ||
| 155 | 155 | |
| 156 | 156 | * - __u32 |
| 157 | 157 | - ``index`` |
| 158 | − - | |
| 159 | 158 | - IN: Index of the given frame size in the enumeration. |
| 160 | 159 | * - __u32 |
| 161 | 160 | - ``pixel_format`` |
| 162 | − - | |
| 163 | 161 | - IN: Pixel format for which the frame sizes are enumerated. |
| 164 | 162 | * - __u32 |
| 165 | 163 | - ``type`` |
| 166 | − - | |
| 167 | 164 | - OUT: Frame size type the device supports. |
| 168 | − * - union | |
| 169 | − - | |
| 170 | − - | |
| 165 | + * - union { | |
| 166 | + - (anonymous) | |
| 171 | 167 | - OUT: Frame size with the given index. |
| 172 | − * - | |
| 173 | − - struct :c:type:`v4l2_frmsize_discrete` | |
| 168 | + * - struct :c:type:`v4l2_frmsize_discrete` | |
| 174 | 169 | - ``discrete`` |
| 175 | 170 | - |
| 176 | − * - | |
| 177 | − - struct :c:type:`v4l2_frmsize_stepwise` | |
| 171 | + * - struct :c:type:`v4l2_frmsize_stepwise` | |
| 178 | 172 | - ``stepwise`` |
| 179 | 173 | - |
| 174 | + * - } | |
| 175 | + - | |
| 176 | + - | |
| 180 | 177 | * - __u32 |
| 181 | 178 | - ``reserved[2]`` |
| 182 | − - | |
| 183 | 179 | - Reserved space for future use. Must be zeroed by drivers and |
| 184 | 180 | applications. |
| 185 | 181 | |
| @@ -179,23 +179,21 @@ EBUSY · 178 unmodified lines | ||
| 179 | 179 | .. flat-table:: struct v4l2_dv_timings |
| 180 | 180 | :header-rows: 0 |
| 181 | 181 | :stub-columns: 0 |
| 182 | − :widths: 1 1 2 1 | |
| 182 | + :widths: 1 1 2 | |
| 183 | 183 | |
| 184 | 184 | * - __u32 |
| 185 | 185 | - ``type`` |
| 186 | − - | |
| 187 | 186 | - Type of DV timings as listed in :ref:`dv-timing-types`. |
| 188 | − * - union | |
| 189 | − - | |
| 190 | − - | |
| 191 | − * - | |
| 192 | − - struct :c:type:`v4l2_bt_timings` | |
| 187 | + * - union { | |
| 188 | + - (anonymous) | |
| 189 | + * - struct :c:type:`v4l2_bt_timings` | |
| 193 | 190 | - ``bt`` |
| 194 | 191 | - Timings defined by BT.656/1120 specifications |
| 195 | − * - | |
| 196 | − - __u32 | |
| 192 | + * - __u32 | |
| 197 | 193 | - ``reserved``\ [32] |
| 198 | 194 | - |
| 195 | + * - } | |
| 196 | + - | |
| 199 | 197 | |
| 200 | 198 | .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| |
| 201 | 199 | |
| @@ -136,15 +136,13 @@ still cause this situation. · 135 unmodified lines | ||
| 136 | 136 | .. flat-table:: struct v4l2_ext_control |
| 137 | 137 | :header-rows: 0 |
| 138 | 138 | :stub-columns: 0 |
| 139 | − :widths: 1 1 1 2 | |
| 139 | + :widths: 1 1 2 | |
| 140 | 140 | |
| 141 | 141 | * - __u32 |
| 142 | 142 | - ``id`` |
| 143 | − - | |
| 144 | 143 | - Identifies the control, set by the application. |
| 145 | 144 | * - __u32 |
| 146 | 145 | - ``size`` |
| 147 | − - | |
| 148 | 146 | - The total size in bytes of the payload of this control. This is |
| 149 | 147 | normally 0, but for pointer controls this should be set to the |
| 150 | 148 | size of the memory containing the payload, or that will receive |
| @@ -161,55 +159,48 @@ still cause this situation. · 10 unmodified lines | ||
| 161 | 159 | *length* of the string may well be much smaller. |
| 162 | 160 | * - __u32 |
| 163 | 161 | - ``reserved2``\ [1] |
| 164 | − - | |
| 165 | 162 | - Reserved for future extensions. Drivers and applications must set |
| 166 | 163 | the array to zero. |
| 167 | − * - union | |
| 164 | + * - union { | |
| 168 | 165 | - (anonymous) |
| 169 | − * - | |
| 170 | − - __s32 | |
| 166 | + * - __s32 | |
| 171 | 167 | - ``value`` |
| 172 | 168 | - New value or current value. Valid if this control is not of type |
| 173 | 169 | ``V4L2_CTRL_TYPE_INTEGER64`` and ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is |
| 174 | 170 | not set. |
| 175 | − * - | |
| 176 | − - __s64 | |
| 171 | + * - __s64 | |
| 177 | 172 | - ``value64`` |
| 178 | 173 | - New value or current value. Valid if this control is of type |
| 179 | 174 | ``V4L2_CTRL_TYPE_INTEGER64`` and ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is |
| 180 | 175 | not set. |
| 181 | − * - | |
| 182 | − - char * | |
| 176 | + * - char * | |
| 183 | 177 | - ``string`` |
| 184 | 178 | - A pointer to a string. Valid if this control is of type |
| 185 | 179 | ``V4L2_CTRL_TYPE_STRING``. |
| 186 | − * - | |
| 187 | − - __u8 * | |
| 180 | + * - __u8 * | |
| 188 | 181 | - ``p_u8`` |
| 189 | 182 | - A pointer to a matrix control of unsigned 8-bit values. Valid if |
| 190 | 183 | this control is of type ``V4L2_CTRL_TYPE_U8``. |
| 191 | − * - | |
| 192 | − - __u16 * | |
| 184 | + * - __u16 * | |
| 193 | 185 | - ``p_u16`` |
| 194 | 186 | - A pointer to a matrix control of unsigned 16-bit values. Valid if |
| 195 | 187 | this control is of type ``V4L2_CTRL_TYPE_U16``. |
| 196 | − * - | |
| 197 | − - __u32 * | |
| 188 | + * - __u32 * | |
| 198 | 189 | - ``p_u32`` |
| 199 | 190 | - A pointer to a matrix control of unsigned 32-bit values. Valid if |
| 200 | 191 | this control is of type ``V4L2_CTRL_TYPE_U32``. |
| 201 | − * - | |
| 202 | − - :c:type:`v4l2_area` * | |
| 192 | + * - :c:type:`v4l2_area` * | |
| 203 | 193 | - ``p_area`` |
| 204 | 194 | - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is |
| 205 | 195 | of type ``V4L2_CTRL_TYPE_AREA``. |
| 206 | − * - | |
| 207 | − - void * | |
| 196 | + * - void * | |
| 208 | 197 | - ``ptr`` |
| 209 | 198 | - A pointer to a compound type which can be an N-dimensional array |
| 210 | 199 | and/or a compound type (the control's type is >= |
| 211 | 200 | ``V4L2_CTRL_COMPOUND_TYPES``). Valid if |
| 212 | 201 | ``V4L2_CTRL_FLAG_HAS_PAYLOAD`` is set for this control. |
| 202 | + * - } | |
| 203 | + - | |
| 213 | 204 | |
| 214 | 205 | |
| 215 | 206 | .. tabularcolumns:: |p{4.0cm}|p{2.2cm}|p{2.1cm}|p{8.2cm}| |
| @@ -221,12 +212,11 @@ still cause this situation. · 5 unmodified lines | ||
| 221 | 212 | .. flat-table:: struct v4l2_ext_controls |
| 222 | 213 | :header-rows: 0 |
| 223 | 214 | :stub-columns: 0 |
| 224 | − :widths: 1 1 2 1 | |
| 215 | + :widths: 1 1 2 | |
| 225 | 216 | |
| 226 | − * - union | |
| 217 | + * - union { | |
| 227 | 218 | - (anonymous) |
| 228 | − * - | |
| 229 | − - __u32 | |
| 219 | + * - __u32 | |
| 230 | 220 | - ``ctrl_class`` |
| 231 | 221 | - The control class to which all controls belong, see |
| 232 | 222 | :ref:`ctrl-class`. Drivers that use a kernel framework for |
| @@ -235,8 +225,7 @@ still cause this situation. · 2 unmodified lines | ||
| 235 | 225 | support this can be tested by setting ``ctrl_class`` to 0 and |
| 236 | 226 | calling :ref:`VIDIOC_TRY_EXT_CTRLS <VIDIOC_G_EXT_CTRLS>` with a ``count`` of 0. If that |
| 237 | 227 | succeeds, then the driver supports this feature. |
| 238 | − * - | |
| 239 | − - __u32 | |
| 228 | + * - __u32 | |
| 240 | 229 | - ``which`` |
| 241 | 230 | - Which value of the control to get/set/try. |
| 242 | 231 | ``V4L2_CTRL_WHICH_CUR_VAL`` will return the current value of the |
| @@ -261,6 +250,8 @@ still cause this situation. · 18 unmodified lines | ||
| 261 | 250 | by setting ctrl_class to ``V4L2_CTRL_WHICH_CUR_VAL`` and calling |
| 262 | 251 | VIDIOC_TRY_EXT_CTRLS with a count of 0. If that fails, then the |
| 263 | 252 | driver does not support ``V4L2_CTRL_WHICH_CUR_VAL``. |
| 253 | + * - } | |
| 254 | + - | |
| 264 | 255 | * - __u32 |
| 265 | 256 | - ``count`` |
| 266 | 257 | - The number of controls in the controls array. May also be zero. |
| @@ -103,51 +103,44 @@ The format as returned by :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>` must be identical · 102 unmodified lines | ||
| 103 | 103 | |
| 104 | 104 | * - __u32 |
| 105 | 105 | - ``type`` |
| 106 | − - | |
| 107 | 106 | - Type of the data stream, see :c:type:`v4l2_buf_type`. |
| 108 | − * - union | |
| 107 | + * - union { | |
| 109 | 108 | - ``fmt`` |
| 110 | − * - | |
| 111 | − - struct :c:type:`v4l2_pix_format` | |
| 109 | + * - struct :c:type:`v4l2_pix_format` | |
| 112 | 110 | - ``pix`` |
| 113 | 111 | - Definition of an image format, see :ref:`pixfmt`, used by video |
| 114 | 112 | capture and output devices. |
| 115 | − * - | |
| 116 | − - struct :c:type:`v4l2_pix_format_mplane` | |
| 113 | + * - struct :c:type:`v4l2_pix_format_mplane` | |
| 117 | 114 | - ``pix_mp`` |
| 118 | 115 | - Definition of an image format, see :ref:`pixfmt`, used by video |
| 119 | 116 | capture and output devices that support the |
| 120 | 117 | :ref:`multi-planar version of the API <planar-apis>`. |
| 121 | − * - | |
| 122 | − - struct :c:type:`v4l2_window` | |
| 118 | + * - struct :c:type:`v4l2_window` | |
| 123 | 119 | - ``win`` |
| 124 | 120 | - Definition of an overlaid image, see :ref:`overlay`, used by |
| 125 | 121 | video overlay devices. |
| 126 | − * - | |
| 127 | − - struct :c:type:`v4l2_vbi_format` | |
| 122 | + * - struct :c:type:`v4l2_vbi_format` | |
| 128 | 123 | - ``vbi`` |
| 129 | 124 | - Raw VBI capture or output parameters. This is discussed in more |
| 130 | 125 | detail in :ref:`raw-vbi`. Used by raw VBI capture and output |
| 131 | 126 | devices. |
| 132 | − * - | |
| 133 | − - struct :c:type:`v4l2_sliced_vbi_format` | |
| 127 | + * - struct :c:type:`v4l2_sliced_vbi_format` | |
| 134 | 128 | - ``sliced`` |
| 135 | 129 | - Sliced VBI capture or output parameters. See :ref:`sliced` for |
| 136 | 130 | details. Used by sliced VBI capture and output devices. |
| 137 | − * - | |
| 138 | − - struct :c:type:`v4l2_sdr_format` | |
| 131 | + * - struct :c:type:`v4l2_sdr_format` | |
| 139 | 132 | - ``sdr`` |
| 140 | 133 | - Definition of a data format, see :ref:`pixfmt`, used by SDR |
| 141 | 134 | capture and output devices. |
| 142 | − * - | |
| 143 | − - struct :c:type:`v4l2_meta_format` | |
| 135 | + * - struct :c:type:`v4l2_meta_format` | |
| 144 | 136 | - ``meta`` |
| 145 | 137 | - Definition of a metadata format, see :ref:`meta-formats`, used by |
| 146 | 138 | metadata capture devices. |
| 147 | − * - | |
| 148 | − - __u8 | |
| 139 | + * - __u8 | |
| 149 | 140 | - ``raw_data``\ [200] |
| 150 | 141 | - Place holder for future extensions. |
| 142 | + * - } | |
| 143 | + - | |
| 151 | 144 | |
| 152 | 145 | |
| 153 | 146 | Return Value |
| @@ -69,33 +69,29 @@ union holding separate parameters for input and output devices. · 68 unmodified lines | ||
| 69 | 69 | .. flat-table:: struct v4l2_streamparm |
| 70 | 70 | :header-rows: 0 |
| 71 | 71 | :stub-columns: 0 |
| 72 | − :widths: 1 1 1 2 | |
| 72 | + :widths: 1 1 2 | |
| 73 | 73 | |
| 74 | 74 | * - __u32 |
| 75 | 75 | - ``type`` |
| 76 | − - | |
| 77 | 76 | - The buffer (stream) type, same as struct |
| 78 | 77 | :c:type:`v4l2_format` ``type``, set by the |
| 79 | 78 | application. See :c:type:`v4l2_buf_type`. |
| 80 | − * - union | |
| 79 | + * - union { | |
| 81 | 80 | - ``parm`` |
| 82 | − - | |
| 83 | − - | |
| 84 | − * - | |
| 85 | − - struct :c:type:`v4l2_captureparm` | |
| 81 | + * - struct :c:type:`v4l2_captureparm` | |
| 86 | 82 | - ``capture`` |
| 87 | 83 | - Parameters for capture devices, used when ``type`` is |
| 88 | 84 | ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` or |
| 89 | 85 | ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE``. |
| 90 | − * - | |
| 91 | − - struct :c:type:`v4l2_outputparm` | |
| 86 | + * - struct :c:type:`v4l2_outputparm` | |
| 92 | 87 | - ``output`` |
| 93 | 88 | - Parameters for output devices, used when ``type`` is |
| 94 | 89 | ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` or ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE``. |
| 95 | − * - | |
| 96 | − - __u8 | |
| 90 | + * - __u8 | |
| 97 | 91 | - ``raw_data``\ [200] |
| 98 | 92 | - A place holder for future extensions. |
| 93 | + * - } | |
| 94 | + - | |
| 99 | 95 | |
| 100 | 96 | |
| 101 | 97 | |
| @@ -290,34 +290,29 @@ See also the examples in :ref:`control`. · 289 unmodified lines | ||
| 290 | 290 | .. flat-table:: struct v4l2_querymenu |
| 291 | 291 | :header-rows: 0 |
| 292 | 292 | :stub-columns: 0 |
| 293 | − :widths: 1 1 2 1 | |
| 293 | + :widths: 1 1 2 | |
| 294 | 294 | |
| 295 | 295 | * - __u32 |
| 296 | − - | |
| 297 | 296 | - ``id`` |
| 298 | 297 | - Identifies the control, set by the application from the respective |
| 299 | 298 | struct :ref:`v4l2_queryctrl <v4l2-queryctrl>` ``id``. |
| 300 | 299 | * - __u32 |
| 301 | − - | |
| 302 | 300 | - ``index`` |
| 303 | 301 | - Index of the menu item, starting at zero, set by the application. |
| 304 | − * - union | |
| 305 | − - | |
| 306 | − - | |
| 307 | − - | |
| 308 | − * - | |
| 309 | − - __u8 | |
| 302 | + * - union { | |
| 303 | + - (anonymous) | |
| 304 | + * - __u8 | |
| 310 | 305 | - ``name``\ [32] |
| 311 | 306 | - Name of the menu item, a NUL-terminated ASCII string. This |
| 312 | 307 | information is intended for the user. This field is valid for |
| 313 | 308 | ``V4L2_CTRL_TYPE_MENU`` type controls. |
| 314 | − * - | |
| 315 | − - __s64 | |
| 309 | + * - __s64 | |
| 316 | 310 | - ``value`` |
| 317 | 311 | - Value of the integer menu item. This field is valid for |
| 318 | 312 | ``V4L2_CTRL_TYPE_INTEGER_MENU`` type controls. |
| 319 | − * - __u32 | |
| 313 | + * - } | |
| 320 | 314 | - |
| 315 | + * - __u32 | |
| 321 | 316 | - ``reserved`` |
| 322 | 317 | - Reserved for future extensions. Drivers must set the array to |
| 323 | 318 | zero. |
| @@ -378,7 +373,7 @@ See also the examples in :ref:`control`. · 54 unmodified lines | ||
| 378 | 373 | - 0 |
| 379 | 374 | - 0 |
| 380 | 375 | - A control which performs an action when set. Drivers must ignore |
| 381 | − the value passed with ``VIDIOC_S_CTRL`` and return an ``EINVAL`` error | |
| 376 | + the value passed with ``VIDIOC_S_CTRL`` and return an ``EACCES`` error | |
| 382 | 377 | code on a ``VIDIOC_G_CTRL`` attempt. |
| 383 | 378 | * - ``V4L2_CTRL_TYPE_INTEGER64`` |
| 384 | 379 | - any |
| @@ -35,6 +35,7 @@ to brightness information. · 34 unmodified lines | ||
| 35 | 35 | pixfmt-grey |
| 36 | 36 | pixfmt-y10 |
| 37 | 37 | pixfmt-y12 |
| 38 | + pixfmt-y14 | |
| 38 | 39 | pixfmt-y10b |
| 39 | 40 | pixfmt-y10p |
| 40 | 41 | pixfmt-y16 |
| @@ -311,10 +311,13 @@ Down Scaler and GDC blocks should be configured with the supported resolutions · 310 unmodified lines | ||
| 311 | 311 | as each hardware block has its own alignment requirement. |
| 312 | 312 | |
| 313 | 313 | You must configure the output resolution of the hardware blocks smartly to meet |
| 314 | −the hardware requirement along with keeping the maximum field of view. | |
| 315 | −The intermediate resolutions can be generated by specific tool and this | |
| 316 | −information can be obtained by looking at the following IPU3 ImgU configuration | |
| 317 | −table. | |
| 314 | +the hardware requirement along with keeping the maximum field of view. The | |
| 315 | +intermediate resolutions can be generated by specific tool - | |
| 316 | + | |
| 317 | +https://github.com/intel/intel-ipu3-pipecfg | |
| 318 | + | |
| 319 | +This tool can be used to generate intermediate resolutions. More information can | |
| 320 | +be obtained by looking at the following IPU3 ImgU configuration table. | |
| 318 | 321 | |
| 319 | 322 | https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master |
| 320 | 323 | |
| @@ -4,9 +4,9 @@ The Virtual Video Test Driver (vivid) · 3 unmodified lines | ||
| 4 | 4 | ===================================== |
| 5 | 5 | |
| 6 | 6 | This driver emulates video4linux hardware of various types: video capture, video |
| 7 | −output, vbi capture and output, radio receivers and transmitters and a software | |
| 8 | −defined radio receiver. In addition a simple framebuffer device is available for | |
| 9 | −testing capture and output overlays. | |
| 7 | +output, vbi capture and output, metadata capture and output, radio receivers and | |
| 8 | +transmitters, touch capture and a software defined radio receiver. In addition a | |
| 9 | +simple framebuffer device is available for testing capture and output overlays. | |
| 10 | 10 | |
| 11 | 11 | Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs. |
| 12 | 12 | |
| @@ -36,6 +36,8 @@ This document describes the features implemented by this driver: · 23 unmodified lines | ||
| 36 | 36 | - Radio receiver and transmitter support, including RDS support |
| 37 | 37 | - Software defined radio (SDR) support |
| 38 | 38 | - Capture and output overlay support |
| 39 | +- Metadata capture and output support | |
| 40 | +- Touch capture support | |
| 39 | 41 | |
| 40 | 42 | These features will be described in more detail below. |
| 41 | 43 | |
| @@ -69,6 +71,9 @@ all configurable using the following module options: · 27 unmodified lines | ||
| 69 | 71 | - bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both |
| 70 | 72 | - bit 12: Radio Transmitter node |
| 71 | 73 | - bit 16: Framebuffer for testing overlays |
| 74 | + - bit 17: Metadata Capture node | |
| 75 | + - bit 18: Metadata Output node | |
| 76 | + - bit 19: Touch Capture node | |
| 72 | 77 | |
| 73 | 78 | So to create four instances, the first two with just one video capture |
| 74 | 79 | device, the second two with just one video output device you would pass |
| @@ -175,6 +180,21 @@ all configurable using the following module options: · 100 unmodified lines | ||
| 175 | 180 | give the desired swradioX start number for each SDR capture device. |
| 176 | 181 | The default is -1 which will just take the first free number. |
| 177 | 182 | |
| 183 | +- meta_cap_nr: | |
| 184 | + | |
| 185 | + give the desired videoX start number for each metadata capture device. | |
| 186 | + The default is -1 which will just take the first free number. | |
| 187 | + | |
| 188 | +- meta_out_nr: | |
| 189 | + | |
| 190 | + give the desired videoX start number for each metadata output device. | |
| 191 | + The default is -1 which will just take the first free number. | |
| 192 | + | |
| 193 | +- touch_cap_nr: | |
| 194 | + | |
| 195 | + give the desired v4l-touchX start number for each touch capture device. | |
| 196 | + The default is -1 which will just take the first free number. | |
| 197 | + | |
| 178 | 198 | - ccs_cap_mode: |
| 179 | 199 | |
| 180 | 200 | specify the allowed video capture crop/compose/scaling combination |
| @@ -547,6 +567,33 @@ The generated data contains the In-phase and Quadrature components of a · 366 unmodified lines | ||
| 547 | 567 | 1 kHz tone that has an amplitude of sqrt(2). |
| 548 | 568 | |
| 549 | 569 | |
| 570 | +Metadata Capture | |
| 571 | +---------------- | |
| 572 | + | |
| 573 | +The Metadata capture generates UVC format metadata. The PTS and SCR are | |
| 574 | +transmitted based on the values set in vivid contols. | |
| 575 | + | |
| 576 | +The Metadata device will only work for the Webcam input, it will give | |
| 577 | +back an error for all other inputs. | |
| 578 | + | |
| 579 | + | |
| 580 | +Metadata Output | |
| 581 | +--------------- | |
| 582 | + | |
| 583 | +The Metadata output can be used to set brightness, contrast, saturation and hue. | |
| 584 | + | |
| 585 | +The Metadata device will only work for the Webcam output, it will give | |
| 586 | +back an error for all other outputs. | |
| 587 | + | |
| 588 | + | |
| 589 | +Touch Capture | |
| 590 | +------------- | |
| 591 | + | |
| 592 | +The Touch capture generates touch patterns simulating single tap, double tap, | |
| 593 | +triple tap, move from left to right, zoom in, zoom out, palm press (simulating | |
| 594 | +a large area being pressed on a touchpad), and simulating 16 simultaneous | |
| 595 | +touch points. | |
| 596 | + | |
| 550 | 597 | Controls |
| 551 | 598 | -------- |
| 552 | 599 | |
| @@ -1049,6 +1096,16 @@ FM Radio Modulator Controls · 496 unmodified lines | ||
| 1049 | 1096 | to pass the RDS blocks to the driver, or "Controls" where the RDS data |
| 1050 | 1097 | is Provided by the RDS controls mentioned above. |
| 1051 | 1098 | |
| 1099 | +Metadata Capture Controls | |
| 1100 | +~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 1101 | + | |
| 1102 | +- Generate PTS | |
| 1103 | + | |
| 1104 | + if set, then the generated metadata stream contains Presentation timestamp. | |
| 1105 | + | |
| 1106 | +- Generate SCR | |
| 1107 | + | |
| 1108 | + if set, then the generated metadata stream contains Source Clock information. | |
| 1052 | 1109 | |
| 1053 | 1110 | Video, VBI and RDS Looping |
| 1054 | 1111 | -------------------------- |
| @@ -649,7 +649,7 @@ video_device注册 · 648 unmodified lines | ||
| 649 | 649 | |
| 650 | 650 | 接下来你需要注册视频设备:这会为你创建一个字符设备。 |
| 651 | 651 | |
| 652 | − err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 652 | + err = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 653 | 653 | if (err) { |
| 654 | 654 | video_device_release(vdev); /* or kfree(my_vdev); */ |
| 655 | 655 | return err; |
| @@ -660,7 +660,7 @@ video_device注册 · 4 unmodified lines | ||
| 660 | 660 | |
| 661 | 661 | 注册哪种设备是根据类型(type)参数。存在以下类型: |
| 662 | 662 | |
| 663 | −VFL_TYPE_GRABBER: 用于视频输入/输出设备的 videoX | |
| 663 | +VFL_TYPE_VIDEO: 用于视频输入/输出设备的 videoX | |
| 664 | 664 | VFL_TYPE_VBI: 用于垂直消隐数据的 vbiX (例如,隐藏式字幕,图文电视) |
| 665 | 665 | VFL_TYPE_RADIO: 用于广播调谐器的 radioX |
| 666 | 666 | |
| @@ -10963,6 +10963,7 @@ F: drivers/media/platform/atmel/atmel-isc.h · 10962 unmodified lines | ||
| 10963 | 10963 | F: drivers/media/platform/atmel/atmel-isc-base.c |
| 10964 | 10964 | F: drivers/media/platform/atmel/atmel-isc-regs.h |
| 10965 | 10965 | F: Documentation/devicetree/bindings/media/atmel-isc.txt |
| 10966 | +F: include/linux/atmel-isc-media.h | |
| 10966 | 10967 | |
| 10967 | 10968 | MICROCHIP ISI DRIVER |
| 10968 | 10969 | M: Eugen Hristev <eugen.hristev@microchip.com> |
| @@ -13914,6 +13915,7 @@ L: linux-arm-msm@vger.kernel.org · 2945 unmodified lines | ||
| 13914 | 13915 | T: git git://linuxtv.org/media_tree.git |
| 13915 | 13916 | S: Maintained |
| 13916 | 13917 | F: drivers/media/platform/qcom/venus/ |
| 13918 | +F: Documentation/devicetree/bindings/media/*venus* | |
| 13917 | 13919 | |
| 13918 | 13920 | QUALCOMM WCN36XX WIRELESS DRIVER |
| 13919 | 13921 | M: Kalle Valo <kvalo@codeaurora.org> |
| @@ -14328,9 +14330,12 @@ F: Documentation/devicetree/bindings/media/rockchip-rga.txt · 408 unmodified lines | ||
| 14328 | 14330 | |
| 14329 | 14331 | HANTRO VPU CODEC DRIVER |
| 14330 | 14332 | M: Ezequiel Garcia <ezequiel@collabora.com> |
| 14333 | +M: Philipp Zabel <p.zabel@pengutronix.de> | |
| 14331 | 14334 | L: linux-media@vger.kernel.org |
| 14335 | +L: linux-rockchip@lists.infradead.org | |
| 14332 | 14336 | S: Maintained |
| 14333 | 14337 | F: drivers/staging/media/hantro/ |
| 14338 | +F: Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml | |
| 14334 | 14339 | F: Documentation/devicetree/bindings/media/rockchip-vpu.txt |
| 14335 | 14340 | |
| 14336 | 14341 | ROCKER DRIVER |
| @@ -14377,6 +14382,14 @@ F: include/net/rose.h · 40 unmodified lines | ||
| 14377 | 14382 | F: include/uapi/linux/rose.h |
| 14378 | 14383 | F: net/rose/ |
| 14379 | 14384 | |
| 14385 | +ROTATION DRIVER FOR ALLWINNER A83T | |
| 14386 | +M: Jernej Skrabec <jernej.skrabec@siol.net> | |
| 14387 | +L: linux-media@vger.kernel.org | |
| 14388 | +T: git git://linuxtv.org/media_tree.git | |
| 14389 | +S: Maintained | |
| 14390 | +F: drivers/media/platform/sunxi/sun8i-rotate/ | |
| 14391 | +F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml | |
| 14392 | + | |
| 14380 | 14393 | RTL2830 MEDIA DRIVER |
| 14381 | 14394 | M: Antti Palosaari <crope@iki.fi> |
| 14382 | 14395 | L: linux-media@vger.kernel.org |
| @@ -15347,11 +15360,10 @@ S: Odd Fixes · 964 unmodified lines | ||
| 15347 | 15360 | F: drivers/net/ethernet/smsc/smc91x.* |
| 15348 | 15361 | |
| 15349 | 15362 | SMIA AND SMIA++ IMAGE SENSOR DRIVER |
| 15350 | −M: Sakari Ailus <sakari.ailus@iki.fi> | |
| 15363 | +M: Sakari Ailus <sakari.ailus@linux.intel.com> | |
| 15351 | 15364 | L: linux-media@vger.kernel.org |
| 15352 | 15365 | S: Maintained |
| 15353 | 15366 | F: drivers/media/i2c/smiapp/ |
| 15354 | −F: include/media/i2c/smiapp.h | |
| 15355 | 15367 | F: drivers/media/i2c/smiapp-pll.c |
| 15356 | 15368 | F: drivers/media/i2c/smiapp-pll.h |
| 15357 | 15369 | F: include/uapi/linux/smiapp.h |
| @@ -15530,6 +15542,14 @@ S: Maintained · 172 unmodified lines | ||
| 15530 | 15542 | F: drivers/media/i2c/imx214.c |
| 15531 | 15543 | F: Documentation/devicetree/bindings/media/i2c/sony,imx214.txt |
| 15532 | 15544 | |
| 15545 | +SONY IMX219 SENSOR DRIVER | |
| 15546 | +M: Dave Stevenson <dave.stevenson@raspberrypi.com> | |
| 15547 | +L: linux-media@vger.kernel.org | |
| 15548 | +T: git git://linuxtv.org/media_tree.git | |
| 15549 | +S: Maintained | |
| 15550 | +F: drivers/media/i2c/imx219.c | |
| 15551 | +F: Documentation/devicetree/bindings/media/i2c/imx219.yaml | |
| 15552 | + | |
| 15533 | 15553 | SONY IMX258 SENSOR DRIVER |
| 15534 | 15554 | M: Sakari Ailus <sakari.ailus@linux.intel.com> |
| 15535 | 15555 | L: linux-media@vger.kernel.org |
| @@ -16763,12 +16783,12 @@ F: sound/soc/codecs/twl4030* · 1227 unmodified lines | ||
| 16763 | 16783 | TI VPE/CAL DRIVERS |
| 16764 | 16784 | M: Benoit Parrot <bparrot@ti.com> |
| 16765 | 16785 | L: linux-media@vger.kernel.org |
| 16786 | +S: Maintained | |
| 16766 | 16787 | W: http://linuxtv.org/ |
| 16767 | 16788 | Q: http://patchwork.linuxtv.org/project/linux-media/list/ |
| 16768 | −S: Maintained | |
| 16769 | −F: drivers/media/platform/ti-vpe/ | |
| 16770 | −F: Documentation/devicetree/bindings/media/ti,vpe.yaml | |
| 16771 | 16789 | F: Documentation/devicetree/bindings/media/ti,cal.yaml |
| 16790 | +F: Documentation/devicetree/bindings/media/ti,vpe.yaml | |
| 16791 | +F: drivers/media/platform/ti-vpe/ | |
| 16772 | 16792 | |
| 16773 | 16793 | TI WILINK WIRELESS DRIVERS |
| 16774 | 16794 | L: linux-wireless@vger.kernel.org |
| @@ -17460,7 +17480,7 @@ L: linux-media@vger.kernel.org · 685 unmodified lines | ||
| 17460 | 17480 | T: git git://linuxtv.org/media_tree.git |
| 17461 | 17481 | W: https://linuxtv.org |
| 17462 | 17482 | S: Odd Fixes |
| 17463 | −F: drivers/media/usb/usbvision/ | |
| 17483 | +F: drivers/staging/media/usbvision/ | |
| 17464 | 17484 | |
| 17465 | 17485 | USB WEBCAM GADGET |
| 17466 | 17486 | M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> |
| @@ -76,3 +76,7 @@ · 75 unmodified lines | ||
| 76 | 76 | }; |
| 77 | 77 | }; |
| 78 | 78 | }; |
| 79 | + | |
| 80 | +&ir { | |
| 81 | + linux,rc-map-name = "rc-videostrong-kii-pro"; | |
| 82 | +}; | |
| @@ -566,6 +566,7 @@ const char *fwnode_get_name(const struct fwnode_handle *fwnode) · 565 unmodified lines | ||
| 566 | 566 | { |
| 567 | 567 | return fwnode_call_ptr_op(fwnode, get_name); |
| 568 | 568 | } |
| 569 | +EXPORT_SYMBOL_GPL(fwnode_get_name); | |
| 569 | 570 | |
| 570 | 571 | /** |
| 571 | 572 | * fwnode_get_name_prefix - Return the prefix of node for printing purposes |
| @@ -208,9 +208,9 @@ config MEDIA_SUBDRV_AUTOSELECT · 207 unmodified lines | ||
| 208 | 208 | If unsure say Y. |
| 209 | 209 | |
| 210 | 210 | config MEDIA_HIDE_ANCILLARY_SUBDRV |
| 211 | − bool | |
| 212 | − depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT | |
| 213 | − default y | |
| 211 | + bool | |
| 212 | + depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT | |
| 213 | + default y | |
| 214 | 214 | |
| 215 | 215 | config MEDIA_ATTACH |
| 216 | 216 | bool |
| @@ -23,7 +23,7 @@ struct cec_notifier { · 22 unmodified lines | ||
| 23 | 23 | struct kref kref; |
| 24 | 24 | struct device *hdmi_dev; |
| 25 | 25 | struct cec_connector_info conn_info; |
| 26 | − const char *conn_name; | |
| 26 | + const char *port_name; | |
| 27 | 27 | struct cec_adapter *cec_adap; |
| 28 | 28 | |
| 29 | 29 | u16 phys_addr; |
| @@ -32,16 +32,30 @@ struct cec_notifier { · 2 unmodified lines | ||
| 32 | 32 | static LIST_HEAD(cec_notifiers); |
| 33 | 33 | static DEFINE_MUTEX(cec_notifiers_lock); |
| 34 | 34 | |
| 35 | −struct cec_notifier * | |
| 36 | −cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name) | |
| 35 | +/** | |
| 36 | + * cec_notifier_get_conn - find or create a new cec_notifier for the given | |
| 37 | + * device and connector tuple. | |
| 38 | + * @hdmi_dev: device that sends the events. | |
| 39 | + * @port_name: the connector name from which the event occurs | |
| 40 | + * | |
| 41 | + * If a notifier for device @dev already exists, then increase the refcount | |
| 42 | + * and return that notifier. | |
| 43 | + * | |
| 44 | + * If it doesn't exist, then allocate a new notifier struct and return a | |
| 45 | + * pointer to that new struct. | |
| 46 | + * | |
| 47 | + * Return NULL if the memory could not be allocated. | |
| 48 | + */ | |
| 49 | +static struct cec_notifier * | |
| 50 | +cec_notifier_get_conn(struct device *hdmi_dev, const char *port_name) | |
| 37 | 51 | { |
| 38 | 52 | struct cec_notifier *n; |
| 39 | 53 | |
| 40 | 54 | mutex_lock(&cec_notifiers_lock); |
| 41 | 55 | list_for_each_entry(n, &cec_notifiers, head) { |
| 42 | 56 | if (n->hdmi_dev == hdmi_dev && |
| 43 | − (!conn_name || | |
| 44 | − (n->conn_name && !strcmp(n->conn_name, conn_name)))) { | |
| 57 | + (!port_name || | |
| 58 | + (n->port_name && !strcmp(n->port_name, port_name)))) { | |
| 45 | 59 | kref_get(&n->kref); |
| 46 | 60 | mutex_unlock(&cec_notifiers_lock); |
| 47 | 61 | return n; |
| @@ -51,9 +65,9 @@ cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name) · 3 unmodified lines | ||
| 51 | 65 | if (!n) |
| 52 | 66 | goto unlock; |
| 53 | 67 | n->hdmi_dev = hdmi_dev; |
| 54 | − if (conn_name) { | |
| 55 | − n->conn_name = kstrdup(conn_name, GFP_KERNEL); | |
| 56 | − if (!n->conn_name) { | |
| 68 | + if (port_name) { | |
| 69 | + n->port_name = kstrdup(port_name, GFP_KERNEL); | |
| 70 | + if (!n->port_name) { | |
| 57 | 71 | kfree(n); |
| 58 | 72 | n = NULL; |
| 59 | 73 | goto unlock; |
| @@ -68,7 +82,6 @@ unlock: · 8 unmodified lines | ||
| 68 | 82 | mutex_unlock(&cec_notifiers_lock); |
| 69 | 83 | return n; |
| 70 | 84 | } |
| 71 | −EXPORT_SYMBOL_GPL(cec_notifier_get_conn); | |
| 72 | 85 | |
| 73 | 86 | static void cec_notifier_release(struct kref *kref) |
| 74 | 87 | { |
| @@ -76,7 +89,7 @@ static void cec_notifier_release(struct kref *kref) · 1 unmodified line | ||
| 76 | 89 | container_of(kref, struct cec_notifier, kref); |
| 77 | 90 | |
| 78 | 91 | list_del(&n->head); |
| 79 | − kfree(n->conn_name); | |
| 92 | + kfree(n->port_name); | |
| 80 | 93 | kfree(n); |
| 81 | 94 | } |
| 82 | 95 | |
| @@ -88,10 +101,10 @@ static void cec_notifier_put(struct cec_notifier *n) · 5 unmodified lines | ||
| 88 | 101 | } |
| 89 | 102 | |
| 90 | 103 | struct cec_notifier * |
| 91 | −cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, | |
| 104 | +cec_notifier_conn_register(struct device *hdmi_dev, const char *port_name, | |
| 92 | 105 | const struct cec_connector_info *conn_info) |
| 93 | 106 | { |
| 94 | − struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name); | |
| 107 | + struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, port_name); | |
| 95 | 108 | |
| 96 | 109 | if (!n) |
| 97 | 110 | return n; |
| @@ -129,7 +142,7 @@ void cec_notifier_conn_unregister(struct cec_notifier *n) · 31 unmodified lines | ||
| 129 | 142 | EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister); |
| 130 | 143 | |
| 131 | 144 | struct cec_notifier * |
| 132 | −cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, | |
| 145 | +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *port_name, | |
| 133 | 146 | struct cec_adapter *adap) |
| 134 | 147 | { |
| 135 | 148 | struct cec_notifier *n; |
| @@ -137,7 +150,7 @@ cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, · 1 unmodified line | ||
| 137 | 150 | if (WARN_ON(!adap)) |
| 138 | 151 | return NULL; |
| 139 | 152 | |
| 140 | − n = cec_notifier_get_conn(hdmi_dev, conn_name); | |
| 153 | + n = cec_notifier_get_conn(hdmi_dev, port_name); | |
| 141 | 154 | if (!n) |
| 142 | 155 | return n; |
| 143 | 156 | |
| @@ -97,8 +97,6 @@ void saa7146_buffer_finish(struct saa7146_dev *dev, · 96 unmodified lines | ||
| 97 | 97 | DEB_EE("dev:%p, dmaq:%p, state:%d\n", dev, q, state); |
| 98 | 98 | DEB_EE("q->curr:%p\n", q->curr); |
| 99 | 99 | |
| 100 | − BUG_ON(!q->curr); | |
| 101 | − | |
| 102 | 100 | /* finish current buffer */ |
| 103 | 101 | if (NULL == q->curr) { |
| 104 | 102 | DEB_D("aiii. no current buffer\n"); |
| @@ -296,7 +294,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma) · 191 unmodified lines | ||
| 296 | 294 | int res; |
| 297 | 295 | |
| 298 | 296 | switch (vdev->vfl_type) { |
| 299 | − case VFL_TYPE_GRABBER: { | |
| 297 | + case VFL_TYPE_VIDEO: { | |
| 300 | 298 | DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n", |
| 301 | 299 | file, vma); |
| 302 | 300 | q = &fh->video_q; |
| @@ -378,7 +376,7 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof · 75 unmodified lines | ||
| 378 | 376 | int ret; |
| 379 | 377 | |
| 380 | 378 | switch (vdev->vfl_type) { |
| 381 | − case VFL_TYPE_GRABBER: | |
| 379 | + case VFL_TYPE_VIDEO: | |
| 382 | 380 | /* |
| 383 | 381 | DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun", |
| 384 | 382 | file, data, (unsigned long)count); |
| @@ -409,7 +407,7 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou · 24 unmodified lines | ||
| 409 | 407 | int ret; |
| 410 | 408 | |
| 411 | 409 | switch (vdev->vfl_type) { |
| 412 | − case VFL_TYPE_GRABBER: | |
| 410 | + case VFL_TYPE_VIDEO: | |
| 413 | 411 | return -EINVAL; |
| 414 | 412 | case VFL_TYPE_VBI: |
| 415 | 413 | if (fh->dev->ext_vv_data->vbi_fops.write) { |
| @@ -597,7 +595,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, · 181 unmodified lines | ||
| 597 | 595 | DEB_EE("dev:%p, name:'%s', type:%d\n", dev, name, type); |
| 598 | 596 | |
| 599 | 597 | vfd->fops = &video_fops; |
| 600 | − if (type == VFL_TYPE_GRABBER) | |
| 598 | + if (type == VFL_TYPE_VIDEO) | |
| 601 | 599 | vfd->ioctl_ops = &dev->ext_vv_data->vid_ops; |
| 602 | 600 | else |
| 603 | 601 | vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops; |
| @@ -611,7 +609,7 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, · 7 unmodified lines | ||
| 611 | 609 | vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | |
| 612 | 610 | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; |
| 613 | 611 | vfd->device_caps |= dev->ext_vv_data->capabilities; |
| 614 | − if (type == VFL_TYPE_GRABBER) | |
| 612 | + if (type == VFL_TYPE_VIDEO) | |
| 615 | 613 | vfd->device_caps &= |
| 616 | 614 | ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); |
| 617 | 615 | else |
| @@ -45,88 +45,88 @@ static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, · 44 unmodified lines | ||
| 45 | 45 | |
| 46 | 46 | buf = debug_data->stats_data; |
| 47 | 47 | |
| 48 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 48 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 49 | 49 | "is_rf_locked = %d\n", p->is_rf_locked); |
| 50 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 50 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 51 | 51 | "is_demod_locked = %d\n", p->is_demod_locked); |
| 52 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 52 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 53 | 53 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
| 54 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 54 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 55 | 55 | "SNR = %d\n", p->SNR); |
| 56 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 56 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 57 | 57 | "ber = %d\n", p->ber); |
| 58 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 58 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 59 | 59 | "FIB_CRC = %d\n", p->FIB_CRC); |
| 60 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 60 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 61 | 61 | "ts_per = %d\n", p->ts_per); |
| 62 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 62 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 63 | 63 | "MFER = %d\n", p->MFER); |
| 64 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 64 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 65 | 65 | "RSSI = %d\n", p->RSSI); |
| 66 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 66 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 67 | 67 | "in_band_pwr = %d\n", p->in_band_pwr); |
| 68 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 68 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 69 | 69 | "carrier_offset = %d\n", p->carrier_offset); |
| 70 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 70 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 71 | 71 | "modem_state = %d\n", p->modem_state); |
| 72 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 72 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 73 | 73 | "frequency = %d\n", p->frequency); |
| 74 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 74 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 75 | 75 | "bandwidth = %d\n", p->bandwidth); |
| 76 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 76 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 77 | 77 | "transmission_mode = %d\n", p->transmission_mode); |
| 78 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 78 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 79 | 79 | "modem_state = %d\n", p->modem_state); |
| 80 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 80 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 81 | 81 | "guard_interval = %d\n", p->guard_interval); |
| 82 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 82 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 83 | 83 | "code_rate = %d\n", p->code_rate); |
| 84 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 84 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 85 | 85 | "lp_code_rate = %d\n", p->lp_code_rate); |
| 86 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 86 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 87 | 87 | "hierarchy = %d\n", p->hierarchy); |
| 88 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 88 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 89 | 89 | "constellation = %d\n", p->constellation); |
| 90 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 90 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 91 | 91 | "burst_size = %d\n", p->burst_size); |
| 92 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 92 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 93 | 93 | "burst_duration = %d\n", p->burst_duration); |
| 94 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 94 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 95 | 95 | "burst_cycle_time = %d\n", p->burst_cycle_time); |
| 96 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 96 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 97 | 97 | "calc_burst_cycle_time = %d\n", |
| 98 | 98 | p->calc_burst_cycle_time); |
| 99 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 99 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 100 | 100 | "num_of_rows = %d\n", p->num_of_rows); |
| 101 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 101 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 102 | 102 | "num_of_padd_cols = %d\n", p->num_of_padd_cols); |
| 103 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 103 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 104 | 104 | "num_of_punct_cols = %d\n", p->num_of_punct_cols); |
| 105 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 105 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 106 | 106 | "error_ts_packets = %d\n", p->error_ts_packets); |
| 107 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 107 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 108 | 108 | "total_ts_packets = %d\n", p->total_ts_packets); |
| 109 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 109 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 110 | 110 | "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs); |
| 111 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 111 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 112 | 112 | "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs); |
| 113 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 113 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 114 | 114 | "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs); |
| 115 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 115 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 116 | 116 | "ber_error_count = %d\n", p->ber_error_count); |
| 117 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 117 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 118 | 118 | "ber_bit_count = %d\n", p->ber_bit_count); |
| 119 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 119 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 120 | 120 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
| 121 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 121 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 122 | 122 | "pre_ber = %d\n", p->pre_ber); |
| 123 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 123 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 124 | 124 | "cell_id = %d\n", p->cell_id); |
| 125 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 125 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 126 | 126 | "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp); |
| 127 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 127 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 128 | 128 | "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp); |
| 129 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 129 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 130 | 130 | "num_mpe_received = %d\n", p->num_mpe_received); |
| 131 | 131 | |
| 132 | 132 | debug_data->stats_count = n; |
| @@ -148,42 +148,42 @@ static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, · 15 unmodified lines | ||
| 148 | 148 | |
| 149 | 149 | buf = debug_data->stats_data; |
| 150 | 150 | |
| 151 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 151 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 152 | 152 | "statistics_type = %d\t", p->statistics_type); |
| 153 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 153 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 154 | 154 | "full_size = %d\n", p->full_size); |
| 155 | 155 | |
| 156 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 156 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 157 | 157 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
| 158 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 158 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 159 | 159 | "is_demod_locked = %d\t", p->is_demod_locked); |
| 160 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 160 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 161 | 161 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
| 162 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 162 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 163 | 163 | "SNR = %d dB\t\t", p->SNR); |
| 164 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 164 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 165 | 165 | "RSSI = %d dBm\t\t", p->RSSI); |
| 166 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 166 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 167 | 167 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
| 168 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 168 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 169 | 169 | "carrier_offset = %d\t", p->carrier_offset); |
| 170 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 170 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 171 | 171 | "bandwidth = %d\t\t", p->bandwidth); |
| 172 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 172 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 173 | 173 | "frequency = %d Hz\n", p->frequency); |
| 174 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 174 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 175 | 175 | "transmission_mode = %d\t", p->transmission_mode); |
| 176 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 176 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 177 | 177 | "modem_state = %d\t\t", p->modem_state); |
| 178 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 178 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 179 | 179 | "guard_interval = %d\n", p->guard_interval); |
| 180 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 180 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 181 | 181 | "system_type = %d\t\t", p->system_type); |
| 182 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 182 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 183 | 183 | "partial_reception = %d\t", p->partial_reception); |
| 184 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 184 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 185 | 185 | "num_of_layers = %d\n", p->num_of_layers); |
| 186 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 186 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 187 | 187 | "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); |
| 188 | 188 | |
| 189 | 189 | for (i = 0; i < 3; i++) { |
| @@ -191,31 +191,34 @@ static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, · 1 unmodified line | ||
| 191 | 191 | p->layer_info[i].number_of_segments > 13) |
| 192 | 192 | continue; |
| 193 | 193 | |
| 194 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
| 195 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", | |
| 194 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
| 195 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", | |
| 196 | 196 | p->layer_info[i].code_rate); |
| 197 | − n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", | |
| 197 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", | |
| 198 | 198 | p->layer_info[i].constellation); |
| 199 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
| 199 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
| 200 | 200 | p->layer_info[i].ber); |
| 201 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", | |
| 201 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 202 | + "\tber_error_count = %-5d\t", | |
| 202 | 203 | p->layer_info[i].ber_error_count); |
| 203 | − n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", | |
| 204 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", | |
| 204 | 205 | p->layer_info[i].ber_bit_count); |
| 205 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", | |
| 206 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", | |
| 206 | 207 | p->layer_info[i].pre_ber); |
| 207 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
| 208 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
| 208 | 209 | p->layer_info[i].ts_per); |
| 209 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", | |
| 210 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 211 | + "\terror_ts_packets = %-5d\t", | |
| 210 | 212 | p->layer_info[i].error_ts_packets); |
| 211 | − n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", | |
| 213 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 214 | + "total_ts_packets = %-5d\t", | |
| 212 | 215 | p->layer_info[i].total_ts_packets); |
| 213 | − n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", | |
| 216 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", | |
| 214 | 217 | p->layer_info[i].ti_ldepth_i); |
| 215 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 218 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 216 | 219 | "\tnumber_of_segments = %d\t", |
| 217 | 220 | p->layer_info[i].number_of_segments); |
| 218 | − n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", | |
| 221 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", | |
| 219 | 222 | p->layer_info[i].tmcc_errors); |
| 220 | 223 | } |
| 221 | 224 | |
| @@ -238,44 +241,44 @@ static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, · 16 unmodified lines | ||
| 238 | 241 | |
| 239 | 242 | buf = debug_data->stats_data; |
| 240 | 243 | |
| 241 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 244 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 242 | 245 | "statistics_type = %d\t", p->statistics_type); |
| 243 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 246 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 244 | 247 | "full_size = %d\n", p->full_size); |
| 245 | 248 | |
| 246 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 249 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 247 | 250 | "is_rf_locked = %d\t\t", p->is_rf_locked); |
| 248 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 251 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 249 | 252 | "is_demod_locked = %d\t", p->is_demod_locked); |
| 250 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 253 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 251 | 254 | "is_external_lna_on = %d\n", p->is_external_lna_on); |
| 252 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 255 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 253 | 256 | "SNR = %d dB\t\t", p->SNR); |
| 254 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 257 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 255 | 258 | "RSSI = %d dBm\t\t", p->RSSI); |
| 256 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 259 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 257 | 260 | "in_band_pwr = %d dBm\n", p->in_band_pwr); |
| 258 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 261 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 259 | 262 | "carrier_offset = %d\t", p->carrier_offset); |
| 260 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 263 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 261 | 264 | "bandwidth = %d\t\t", p->bandwidth); |
| 262 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 265 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 263 | 266 | "frequency = %d Hz\n", p->frequency); |
| 264 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 267 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 265 | 268 | "transmission_mode = %d\t", p->transmission_mode); |
| 266 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 269 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 267 | 270 | "modem_state = %d\t\t", p->modem_state); |
| 268 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 271 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 269 | 272 | "guard_interval = %d\n", p->guard_interval); |
| 270 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 273 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 271 | 274 | "system_type = %d\t\t", p->system_type); |
| 272 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 275 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 273 | 276 | "partial_reception = %d\t", p->partial_reception); |
| 274 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 277 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 275 | 278 | "num_of_layers = %d\n", p->num_of_layers); |
| 276 | − n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", | |
| 279 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", | |
| 277 | 280 | p->segment_number); |
| 278 | − n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", | |
| 281 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", | |
| 279 | 282 | p->tune_bw); |
| 280 | 283 | |
| 281 | 284 | for (i = 0; i < 3; i++) { |
| @@ -283,31 +286,34 @@ static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, · 1 unmodified line | ||
| 283 | 286 | p->layer_info[i].number_of_segments > 13) |
| 284 | 287 | continue; |
| 285 | 288 | |
| 286 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
| 287 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", | |
| 289 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); | |
| 290 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", | |
| 288 | 291 | p->layer_info[i].code_rate); |
| 289 | − n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", | |
| 292 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", | |
| 290 | 293 | p->layer_info[i].constellation); |
| 291 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
| 294 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", | |
| 292 | 295 | p->layer_info[i].ber); |
| 293 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", | |
| 296 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 297 | + "\tber_error_count = %-5d\t", | |
| 294 | 298 | p->layer_info[i].ber_error_count); |
| 295 | − n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", | |
| 299 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", | |
| 296 | 300 | p->layer_info[i].ber_bit_count); |
| 297 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", | |
| 301 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", | |
| 298 | 302 | p->layer_info[i].pre_ber); |
| 299 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
| 303 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", | |
| 300 | 304 | p->layer_info[i].ts_per); |
| 301 | − n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", | |
| 305 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 306 | + "\terror_ts_packets = %-5d\t", | |
| 302 | 307 | p->layer_info[i].error_ts_packets); |
| 303 | − n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", | |
| 308 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 309 | + "total_ts_packets = %-5d\t", | |
| 304 | 310 | p->layer_info[i].total_ts_packets); |
| 305 | − n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", | |
| 311 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", | |
| 306 | 312 | p->layer_info[i].ti_ldepth_i); |
| 307 | − n += snprintf(&buf[n], PAGE_SIZE - n, | |
| 313 | + n += scnprintf(&buf[n], PAGE_SIZE - n, | |
| 308 | 314 | "\tnumber_of_segments = %d\t", |
| 309 | 315 | p->layer_info[i].number_of_segments); |
| 310 | − n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", | |
| 316 | + n += scnprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", | |
| 311 | 317 | p->layer_info[i].tmcc_errors); |
| 312 | 318 | } |
| 313 | 319 | |
| @@ -393,8 +393,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, · 392 unmodified lines | ||
| 393 | 393 | } |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | − dprintk(1, "allocated %d buffers, %d plane(s) each\n", | |
| 397 | − buffer, num_planes); | |
| 396 | + dprintk(3, "allocated %d buffers, %d plane(s) each\n", | |
| 397 | + buffer, num_planes); | |
| 398 | 398 | |
| 399 | 399 | return buffer; |
| 400 | 400 | } |
| @@ -593,8 +593,8 @@ static int vb2_dc_map_dmabuf(void *mem_priv) · 592 unmodified lines | ||
| 593 | 593 | /* checking if dmabuf is big enough to store contiguous chunk */ |
| 594 | 594 | contig_size = vb2_dc_get_contiguous_size(sgt); |
| 595 | 595 | if (contig_size < buf->size) { |
| 596 | − pr_err("contiguous chunk is too small %lu/%lu b\n", | |
| 597 | − contig_size, buf->size); | |
| 596 | + pr_err("contiguous chunk is too small %lu/%lu\n", | |
| 597 | + contig_size, buf->size); | |
| 598 | 598 | dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); |
| 599 | 599 | return -EFAULT; |
| 600 | 600 | } |
| @@ -2182,7 +2182,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr, · 2181 unmodified lines | ||
| 2182 | 2182 | u32 *data, u32 flags) |
| 2183 | 2183 | { |
| 2184 | 2184 | u8 buf[sizeof(*data)] = { 0 }; |
| 2185 | − int rc = -EIO; | |
| 2185 | + int rc; | |
| 2186 | 2186 | u32 word = 0; |
| 2187 | 2187 | |
| 2188 | 2188 | if (!data) |
| @@ -4229,7 +4229,7 @@ int drxj_dap_scu_atomic_write_reg16(struct i2c_device_addr *dev_addr, · 2040 unmodified lines | ||
| 4229 | 4229 | u16 data, u32 flags) |
| 4230 | 4230 | { |
| 4231 | 4231 | u8 buf[2]; |
| 4232 | − int rc = -EIO; | |
| 4232 | + int rc; | |
| 4233 | 4233 | |
| 4234 | 4234 | buf[0] = (u8) (data & 0xff); |
| 4235 | 4235 | buf[1] = (u8) ((data >> 8) & 0xff); |
| @@ -64,6 +64,92 @@ err: · 63 unmodified lines | ||
| 64 | 64 | return ret; |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | +/* | |
| 68 | + * m88ds3103b demod has an internal device related to clocking. First the i2c | |
| 69 | + * gate must be opened, for one transaction, then writes will be allowed. | |
| 70 | + */ | |
| 71 | +static int m88ds3103b_dt_write(struct m88ds3103_dev *dev, int reg, int data) | |
| 72 | +{ | |
| 73 | + struct i2c_client *client = dev->client; | |
| 74 | + u8 buf[] = {reg, data}; | |
| 75 | + u8 val; | |
| 76 | + int ret; | |
| 77 | + struct i2c_msg msg = { | |
| 78 | + .addr = dev->dt_addr, .flags = 0, .buf = buf, .len = 2 | |
| 79 | + }; | |
| 80 | + | |
| 81 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); | |
| 82 | + | |
| 83 | + val = 0x11; | |
| 84 | + ret = regmap_write(dev->regmap, 0x03, val); | |
| 85 | + if (ret) | |
| 86 | + dev_dbg(&client->dev, "fail=%d\n", ret); | |
| 87 | + | |
| 88 | + ret = i2c_transfer(dev->dt_client->adapter, &msg, 1); | |
| 89 | + if (ret != 1) { | |
| 90 | + dev_err(&client->dev, "0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n", | |
| 91 | + dev->dt_addr, ret, reg, data); | |
| 92 | + | |
| 93 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); | |
| 94 | + return -EREMOTEIO; | |
| 95 | + } | |
| 96 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); | |
| 97 | + | |
| 98 | + dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", | |
| 99 | + dev->dt_addr, reg, data); | |
| 100 | + | |
| 101 | + return 0; | |
| 102 | +} | |
| 103 | + | |
| 104 | +/* | |
| 105 | + * m88ds3103b demod has an internal device related to clocking. First the i2c | |
| 106 | + * gate must be opened, for two transactions, then reads will be allowed. | |
| 107 | + */ | |
| 108 | +static int m88ds3103b_dt_read(struct m88ds3103_dev *dev, u8 reg) | |
| 109 | +{ | |
| 110 | + struct i2c_client *client = dev->client; | |
| 111 | + int ret; | |
| 112 | + u8 val; | |
| 113 | + u8 b0[] = { reg }; | |
| 114 | + u8 b1[] = { 0 }; | |
| 115 | + struct i2c_msg msg[] = { | |
| 116 | + { | |
| 117 | + .addr = dev->dt_addr, | |
| 118 | + .flags = 0, | |
| 119 | + .buf = b0, | |
| 120 | + .len = 1 | |
| 121 | + }, | |
| 122 | + { | |
| 123 | + .addr = dev->dt_addr, | |
| 124 | + .flags = I2C_M_RD, | |
| 125 | + .buf = b1, | |
| 126 | + .len = 1 | |
| 127 | + } | |
| 128 | + }; | |
| 129 | + | |
| 130 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x00); | |
| 131 | + | |
| 132 | + val = 0x12; | |
| 133 | + ret = regmap_write(dev->regmap, 0x03, val); | |
| 134 | + if (ret) | |
| 135 | + dev_dbg(&client->dev, "fail=%d\n", ret); | |
| 136 | + | |
| 137 | + ret = i2c_transfer(dev->dt_client->adapter, msg, 2); | |
| 138 | + if (ret != 2) { | |
| 139 | + dev_err(&client->dev, "0x%02x (ret=%d, reg=0x%02x)\n", | |
| 140 | + dev->dt_addr, ret, reg); | |
| 141 | + | |
| 142 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); | |
| 143 | + return -EREMOTEIO; | |
| 144 | + } | |
| 145 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); | |
| 146 | + | |
| 147 | + dev_dbg(&client->dev, "0x%02x reg 0x%02x, value 0x%02x\n", | |
| 148 | + dev->dt_addr, reg, b1[0]); | |
| 149 | + | |
| 150 | + return b1[0]; | |
| 151 | +} | |
| 152 | + | |
| 67 | 153 | /* |
| 68 | 154 | * Get the demodulator AGC PWM voltage setting supplied to the tuner. |
| 69 | 155 | */ |
| @@ -288,6 +374,251 @@ err: · 218 unmodified lines | ||
| 288 | 374 | return ret; |
| 289 | 375 | } |
| 290 | 376 | |
| 377 | +static int m88ds3103b_select_mclk(struct m88ds3103_dev *dev) | |
| 378 | +{ | |
| 379 | + struct i2c_client *client = dev->client; | |
| 380 | + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; | |
| 381 | + u32 adc_Freq_MHz[3] = {96, 93, 99}; | |
| 382 | + u8 reg16_list[3] = {96, 92, 100}, reg16, reg15; | |
| 383 | + u32 offset_MHz[3]; | |
| 384 | + u32 max_offset = 0; | |
| 385 | + u32 old_setting = dev->mclk; | |
| 386 | + u32 tuner_freq_MHz = c->frequency / 1000; | |
| 387 | + u8 i; | |
| 388 | + char big_symbol = 0; | |
| 389 | + | |
| 390 | + big_symbol = (c->symbol_rate > 45010000) ? 1 : 0; | |
| 391 | + | |
| 392 | + if (big_symbol) { | |
| 393 | + reg16 = 115; | |
| 394 | + } else { | |
| 395 | + reg16 = 96; | |
| 396 | + | |
| 397 | + /* TODO: IS THIS NECESSARY ? */ | |
| 398 | + for (i = 0; i < 3; i++) { | |
| 399 | + offset_MHz[i] = tuner_freq_MHz % adc_Freq_MHz[i]; | |
| 400 | + | |
| 401 | + if (offset_MHz[i] > (adc_Freq_MHz[i] / 2)) | |
| 402 | + offset_MHz[i] = adc_Freq_MHz[i] - offset_MHz[i]; | |
| 403 | + | |
| 404 | + if (offset_MHz[i] > max_offset) { | |
| 405 | + max_offset = offset_MHz[i]; | |
| 406 | + reg16 = reg16_list[i]; | |
| 407 | + dev->mclk = adc_Freq_MHz[i] * 1000 * 1000; | |
| 408 | + | |
| 409 | + if (big_symbol) | |
| 410 | + dev->mclk /= 2; | |
| 411 | + | |
| 412 | + dev_dbg(&client->dev, "modifying mclk %u -> %u\n", | |
| 413 | + old_setting, dev->mclk); | |
| 414 | + } | |
| 415 | + } | |
| 416 | + } | |
| 417 | + | |
| 418 | + if (dev->mclk == 93000000) | |
| 419 | + regmap_write(dev->regmap, 0xA0, 0x42); | |
| 420 | + else if (dev->mclk == 96000000) | |
| 421 | + regmap_write(dev->regmap, 0xA0, 0x44); | |
| 422 | + else if (dev->mclk == 99000000) | |
| 423 | + regmap_write(dev->regmap, 0xA0, 0x46); | |
| 424 | + else if (dev->mclk == 110250000) | |
| 425 | + regmap_write(dev->regmap, 0xA0, 0x4E); | |
| 426 | + else | |
| 427 | + regmap_write(dev->regmap, 0xA0, 0x44); | |
| 428 | + | |
| 429 | + reg15 = m88ds3103b_dt_read(dev, 0x15); | |
| 430 | + | |
| 431 | + m88ds3103b_dt_write(dev, 0x05, 0x40); | |
| 432 | + m88ds3103b_dt_write(dev, 0x11, 0x08); | |
| 433 | + | |
| 434 | + if (big_symbol) | |
| 435 | + reg15 |= 0x02; | |
| 436 | + else | |
| 437 | + reg15 &= ~0x02; | |
| 438 | + | |
| 439 | + m88ds3103b_dt_write(dev, 0x15, reg15); | |
| 440 | + m88ds3103b_dt_write(dev, 0x16, reg16); | |
| 441 | + | |
| 442 | + usleep_range(5000, 5500); | |
| 443 | + | |
| 444 | + m88ds3103b_dt_write(dev, 0x05, 0x00); | |
| 445 | + m88ds3103b_dt_write(dev, 0x11, (u8)(big_symbol ? 0x0E : 0x0A)); | |
| 446 | + | |
| 447 | + usleep_range(5000, 5500); | |
| 448 | + | |
| 449 | + return 0; | |
| 450 | +} | |
| 451 | + | |
| 452 | +static int m88ds3103b_set_mclk(struct m88ds3103_dev *dev, u32 mclk_khz) | |
| 453 | +{ | |
| 454 | + u8 reg11 = 0x0A, reg15, reg16, reg1D, reg1E, reg1F, tmp; | |
| 455 | + u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0; | |
| 456 | + u16 pll_div_fb, N; | |
| 457 | + u32 div; | |
| 458 | + | |
| 459 | + reg15 = m88ds3103b_dt_read(dev, 0x15); | |
| 460 | + reg16 = m88ds3103b_dt_read(dev, 0x16); | |
| 461 | + reg1D = m88ds3103b_dt_read(dev, 0x1D); | |
| 462 | + | |
| 463 | + if (dev->cfg->ts_mode != M88DS3103_TS_SERIAL) { | |
| 464 | + if (reg16 == 92) | |
| 465 | + tmp = 93; | |
| 466 | + else if (reg16 == 100) | |
| 467 | + tmp = 99; | |
| 468 | + else | |
| 469 | + tmp = 96; | |
| 470 | + | |
| 471 | + mclk_khz *= tmp; | |
| 472 | + mclk_khz /= 96; | |
| 473 | + } | |
| 474 | + | |
| 475 | + pll_div_fb = (reg15 & 0x01) << 8; | |
| 476 | + pll_div_fb += reg16; | |
| 477 | + pll_div_fb += 32; | |
| 478 | + | |
| 479 | + div = 9000 * pll_div_fb * 4; | |
| 480 | + div /= mclk_khz; | |
| 481 | + | |
| 482 | + if (dev->cfg->ts_mode == M88DS3103_TS_SERIAL) { | |
| 483 | + reg11 |= 0x02; | |
| 484 | + | |
| 485 | + if (div <= 32) { | |
| 486 | + N = 2; | |
| 487 | + | |
| 488 | + f0 = 0; | |
| 489 | + f1 = div / N; | |
| 490 | + f2 = div - f1; | |
| 491 | + f3 = 0; | |
| 492 | + } else if (div <= 34) { | |
| 493 | + N = 3; | |
| 494 | + | |
| 495 | + f0 = div / N; | |
| 496 | + f1 = (div - f0) / (N - 1); | |
| 497 | + f2 = div - f0 - f1; | |
| 498 | + f3 = 0; | |
| 499 | + } else if (div <= 64) { | |
| 500 | + N = 4; | |
| 501 | + | |
| 502 | + f0 = div / N; | |
| 503 | + f1 = (div - f0) / (N - 1); | |
| 504 | + f2 = (div - f0 - f1) / (N - 2); | |
| 505 | + f3 = div - f0 - f1 - f2; | |
| 506 | + } else { | |
| 507 | + N = 4; | |
| 508 | + | |
| 509 | + f0 = 16; | |
| 510 | + f1 = 16; | |
| 511 | + f2 = 16; | |
| 512 | + f3 = 16; | |
| 513 | + } | |
| 514 | + | |
| 515 | + if (f0 == 16) | |
| 516 | + f0 = 0; | |
| 517 | + else if ((f0 < 8) && (f0 != 0)) | |
| 518 | + f0 = 8; | |
| 519 | + | |
| 520 | + if (f1 == 16) | |
| 521 | + f1 = 0; | |
| 522 | + else if ((f1 < 8) && (f1 != 0)) | |
| 523 | + f1 = 8; | |
| 524 | + | |
| 525 | + if (f2 == 16) | |
| 526 | + f2 = 0; | |
| 527 | + else if ((f2 < 8) && (f2 != 0)) | |
| 528 | + f2 = 8; | |
| 529 | + | |
| 530 | + if (f3 == 16) | |
| 531 | + f3 = 0; | |
| 532 | + else if ((f3 < 8) && (f3 != 0)) | |
| 533 | + f3 = 8; | |
| 534 | + } else { | |
| 535 | + reg11 &= ~0x02; | |
| 536 | + | |
| 537 | + if (div <= 32) { | |
| 538 | + N = 2; | |
| 539 | + | |
| 540 | + f0 = 0; | |
| 541 | + f1 = div / N; | |
| 542 | + f2 = div - f1; | |
| 543 | + f3 = 0; | |
| 544 | + } else if (div <= 48) { | |
| 545 | + N = 3; | |
| 546 | + | |
| 547 | + f0 = div / N; | |
| 548 | + f1 = (div - f0) / (N - 1); | |
| 549 | + f2 = div - f0 - f1; | |
| 550 | + f3 = 0; | |
| 551 | + } else if (div <= 64) { | |
| 552 | + N = 4; | |
| 553 | + | |
| 554 | + f0 = div / N; | |
| 555 | + f1 = (div - f0) / (N - 1); | |
| 556 | + f2 = (div - f0 - f1) / (N - 2); | |
| 557 | + f3 = div - f0 - f1 - f2; | |
| 558 | + } else { | |
| 559 | + N = 4; | |
| 560 | + | |
| 561 | + f0 = 16; | |
| 562 | + f1 = 16; | |
| 563 | + f2 = 16; | |
| 564 | + f3 = 16; | |
| 565 | + } | |
| 566 | + | |
| 567 | + if (f0 == 16) | |
| 568 | + f0 = 0; | |
| 569 | + else if ((f0 < 9) && (f0 != 0)) | |
| 570 | + f0 = 9; | |
| 571 | + | |
| 572 | + if (f1 == 16) | |
| 573 | + f1 = 0; | |
| 574 | + else if ((f1 < 9) && (f1 != 0)) | |
| 575 | + f1 = 9; | |
| 576 | + | |
| 577 | + if (f2 == 16) | |
| 578 | + f2 = 0; | |
| 579 | + else if ((f2 < 9) && (f2 != 0)) | |
| 580 | + f2 = 9; | |
| 581 | + | |
| 582 | + if (f3 == 16) | |
| 583 | + f3 = 0; | |
| 584 | + else if ((f3 < 9) && (f3 != 0)) | |
| 585 | + f3 = 9; | |
| 586 | + } | |
| 587 | + | |
| 588 | + sm = N - 1; | |
| 589 | + | |
| 590 | + /* Write to registers */ | |
| 591 | + //reg15 &= 0x01; | |
| 592 | + //reg15 |= (pll_div_fb >> 8) & 0x01; | |
| 593 | + | |
| 594 | + //reg16 = pll_div_fb & 0xFF; | |
| 595 | + | |
| 596 | + reg1D &= ~0x03; | |
| 597 | + reg1D |= sm; | |
| 598 | + reg1D |= 0x80; | |
| 599 | + | |
| 600 | + reg1E = ((f3 << 4) + f2) & 0xFF; | |
| 601 | + reg1F = ((f1 << 4) + f0) & 0xFF; | |
| 602 | + | |
| 603 | + m88ds3103b_dt_write(dev, 0x05, 0x40); | |
| 604 | + m88ds3103b_dt_write(dev, 0x11, 0x08); | |
| 605 | + m88ds3103b_dt_write(dev, 0x1D, reg1D); | |
| 606 | + m88ds3103b_dt_write(dev, 0x1E, reg1E); | |
| 607 | + m88ds3103b_dt_write(dev, 0x1F, reg1F); | |
| 608 | + | |
| 609 | + m88ds3103b_dt_write(dev, 0x17, 0xc1); | |
| 610 | + m88ds3103b_dt_write(dev, 0x17, 0x81); | |
| 611 | + | |
| 612 | + usleep_range(5000, 5500); | |
| 613 | + | |
| 614 | + m88ds3103b_dt_write(dev, 0x05, 0x00); | |
| 615 | + m88ds3103b_dt_write(dev, 0x11, 0x0A); | |
| 616 | + | |
| 617 | + usleep_range(5000, 5500); | |
| 618 | + | |
| 619 | + return 0; | |
| 620 | +} | |
| 621 | + | |
| 291 | 622 | static int m88ds3103_set_frontend(struct dvb_frontend *fe) |
| 292 | 623 | { |
| 293 | 624 | struct m88ds3103_dev *dev = fe->demodulator_priv; |
| @@ -298,7 +629,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 298 | 629 | u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */ |
| 299 | 630 | u8 buf[3]; |
| 300 | 631 | u16 u16tmp; |
| 301 | − u32 tuner_frequency_khz, target_mclk; | |
| 632 | + u32 tuner_frequency_khz, target_mclk, u32tmp; | |
| 302 | 633 | s32 s32tmp; |
| 303 | 634 | static const struct reg_sequence reset_buf[] = { |
| 304 | 635 | {0x07, 0x80}, {0x07, 0x00} |
| @@ -321,6 +652,20 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 16 unmodified lines | ||
| 321 | 652 | |
| 322 | 653 | /* Disable demod clock path */ |
| 323 | 654 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 655 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 656 | + ret = regmap_read(dev->regmap, 0xb2, &u32tmp); | |
| 657 | + if (ret) | |
| 658 | + goto err; | |
| 659 | + if (u32tmp == 0x01) { | |
| 660 | + ret = regmap_write(dev->regmap, 0x00, 0x00); | |
| 661 | + if (ret) | |
| 662 | + goto err; | |
| 663 | + ret = regmap_write(dev->regmap, 0xb2, 0x00); | |
| 664 | + if (ret) | |
| 665 | + goto err; | |
| 666 | + } | |
| 667 | + } | |
| 668 | + | |
| 324 | 669 | ret = regmap_write(dev->regmap, 0x06, 0xe0); |
| 325 | 670 | if (ret) |
| 326 | 671 | goto err; |
| @@ -346,7 +691,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 19 unmodified lines | ||
| 346 | 691 | tuner_frequency_khz = c->frequency; |
| 347 | 692 | } |
| 348 | 693 | |
| 349 | − /* select M88RS6000 demod main mclk and ts mclk from tuner die. */ | |
| 694 | + /* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */ | |
| 350 | 695 | if (dev->chip_id == M88RS6000_CHIP_ID) { |
| 351 | 696 | if (c->symbol_rate > 45010000) |
| 352 | 697 | dev->mclk = 110250000; |
| @@ -358,6 +703,11 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 5 unmodified lines | ||
| 358 | 703 | else |
| 359 | 704 | target_mclk = 144000000; |
| 360 | 705 | |
| 706 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 707 | + m88ds3103b_select_mclk(dev); | |
| 708 | + m88ds3103b_set_mclk(dev, target_mclk / 1000); | |
| 709 | + } | |
| 710 | + | |
| 361 | 711 | /* Enable demod clock path */ |
| 362 | 712 | ret = regmap_write(dev->regmap, 0x06, 0x00); |
| 363 | 713 | if (ret) |
| @@ -469,12 +819,42 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 105 unmodified lines | ||
| 469 | 819 | ret = m88ds3103_update_bits(dev, 0x9d, 0x08, 0x08); |
| 470 | 820 | if (ret) |
| 471 | 821 | goto err; |
| 822 | + | |
| 823 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 824 | + buf[0] = m88ds3103b_dt_read(dev, 0x15); | |
| 825 | + buf[1] = m88ds3103b_dt_read(dev, 0x16); | |
| 826 | + | |
| 827 | + if (c->symbol_rate > 45010000) { | |
| 828 | + buf[0] &= ~0x03; | |
| 829 | + buf[0] |= 0x02; | |
| 830 | + buf[0] |= ((147 - 32) >> 8) & 0x01; | |
| 831 | + buf[1] = (147 - 32) & 0xFF; | |
| 832 | + | |
| 833 | + dev->mclk = 110250 * 1000; | |
| 834 | + } else { | |
| 835 | + buf[0] &= ~0x03; | |
| 836 | + buf[0] |= ((128 - 32) >> 8) & 0x01; | |
| 837 | + buf[1] = (128 - 32) & 0xFF; | |
| 838 | + | |
| 839 | + dev->mclk = 96000 * 1000; | |
| 840 | + } | |
| 841 | + m88ds3103b_dt_write(dev, 0x15, buf[0]); | |
| 842 | + m88ds3103b_dt_write(dev, 0x16, buf[1]); | |
| 843 | + | |
| 844 | + regmap_read(dev->regmap, 0x30, &u32tmp); | |
| 845 | + u32tmp &= ~0x80; | |
| 846 | + regmap_write(dev->regmap, 0x30, u32tmp & 0xff); | |
| 847 | + } | |
| 848 | + | |
| 472 | 849 | ret = regmap_write(dev->regmap, 0xf1, 0x01); |
| 473 | 850 | if (ret) |
| 474 | 851 | goto err; |
| 475 | − ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); | |
| 476 | − if (ret) | |
| 477 | − goto err; | |
| 852 | + | |
| 853 | + if (dev->chiptype != M88DS3103_CHIPTYPE_3103B) { | |
| 854 | + ret = m88ds3103_update_bits(dev, 0x30, 0x80, 0x80); | |
| 855 | + if (ret) | |
| 856 | + goto err; | |
| 857 | + } | |
| 478 | 858 | } |
| 479 | 859 | |
| 480 | 860 | switch (dev->cfg->ts_mode) { |
| @@ -488,6 +868,10 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 7 unmodified lines | ||
| 488 | 868 | break; |
| 489 | 869 | case M88DS3103_TS_PARALLEL: |
| 490 | 870 | u8tmp = 0x02; |
| 871 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 872 | + u8tmp = 0x01; | |
| 873 | + u8tmp1 = 0x01; | |
| 874 | + } | |
| 491 | 875 | break; |
| 492 | 876 | case M88DS3103_TS_CI: |
| 493 | 877 | u8tmp = 0x03; |
| @@ -516,6 +900,13 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 22 unmodified lines | ||
| 516 | 900 | u8tmp1 = 0x3f; |
| 517 | 901 | u8tmp2 = 0x3f; |
| 518 | 902 | break; |
| 903 | + case M88DS3103_TS_PARALLEL: | |
| 904 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 905 | + ret = m88ds3103_update_bits(dev, 0x29, 0x01, u8tmp1); | |
| 906 | + if (ret) | |
| 907 | + goto err; | |
| 908 | + } | |
| 909 | + /* fall through */ | |
| 519 | 910 | default: |
| 520 | 911 | u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk); |
| 521 | 912 | u8tmp1 = u16tmp / 2 - 1; |
| @@ -543,6 +934,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 21 unmodified lines | ||
| 543 | 934 | else |
| 544 | 935 | u8tmp = 0x06; |
| 545 | 936 | |
| 937 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) | |
| 938 | + m88ds3103b_set_mclk(dev, target_mclk / 1000); | |
| 939 | + | |
| 546 | 940 | ret = regmap_write(dev->regmap, 0xc3, 0x08); |
| 547 | 941 | if (ret) |
| 548 | 942 | goto err; |
| @@ -578,6 +972,16 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) · 29 unmodified lines | ||
| 578 | 972 | if (ret) |
| 579 | 973 | goto err; |
| 580 | 974 | |
| 975 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 976 | + /* enable/disable 192M LDPC clock */ | |
| 977 | + ret = m88ds3103_update_bits(dev, 0x29, 0x10, | |
| 978 | + (c->delivery_system == SYS_DVBS) ? 0x10 : 0x0); | |
| 979 | + if (ret) | |
| 980 | + goto err; | |
| 981 | + | |
| 982 | + ret = m88ds3103_update_bits(dev, 0xc9, 0x08, 0x08); | |
| 983 | + } | |
| 984 | + | |
| 581 | 985 | dev_dbg(&client->dev, "carrier offset=%d\n", |
| 582 | 986 | (tuner_frequency_khz - c->frequency)); |
| 583 | 987 | |
| @@ -642,7 +1046,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 58 unmodified lines | ||
| 642 | 1046 | if (utmp) |
| 643 | 1047 | goto warm; |
| 644 | 1048 | |
| 645 | − /* global reset, global diseqc reset, golbal fec reset */ | |
| 1049 | + /* global reset, global diseqc reset, global fec reset */ | |
| 646 | 1050 | ret = regmap_write(dev->regmap, 0x07, 0xe0); |
| 647 | 1051 | if (ret) |
| 648 | 1052 | goto err; |
| @@ -652,12 +1056,15 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 3 unmodified lines | ||
| 652 | 1056 | |
| 653 | 1057 | /* cold state - try to download firmware */ |
| 654 | 1058 | dev_info(&client->dev, "found a '%s' in cold state\n", |
| 655 | − m88ds3103_ops.info.name); | |
| 1059 | + dev->fe.ops.info.name); | |
| 656 | 1060 | |
| 657 | − if (dev->chip_id == M88RS6000_CHIP_ID) | |
| 1061 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) | |
| 1062 | + name = M88DS3103B_FIRMWARE; | |
| 1063 | + else if (dev->chip_id == M88RS6000_CHIP_ID) | |
| 658 | 1064 | name = M88RS6000_FIRMWARE; |
| 659 | 1065 | else |
| 660 | 1066 | name = M88DS3103_FIRMWARE; |
| 1067 | + | |
| 661 | 1068 | /* request the firmware, this will block and timeout */ |
| 662 | 1069 | ret = request_firmware(&firmware, name, &client->dev); |
| 663 | 1070 | if (ret) { |
| @@ -700,10 +1107,16 @@ static int m88ds3103_init(struct dvb_frontend *fe) · 36 unmodified lines | ||
| 700 | 1107 | } |
| 701 | 1108 | |
| 702 | 1109 | dev_info(&client->dev, "found a '%s' in warm state\n", |
| 703 | − m88ds3103_ops.info.name); | |
| 1110 | + dev->fe.ops.info.name); | |
| 704 | 1111 | dev_info(&client->dev, "firmware version: %X.%X\n", |
| 705 | 1112 | (utmp >> 4) & 0xf, (utmp >> 0 & 0xf)); |
| 706 | 1113 | |
| 1114 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 1115 | + m88ds3103b_dt_write(dev, 0x21, 0x92); | |
| 1116 | + m88ds3103b_dt_write(dev, 0x15, 0x6C); | |
| 1117 | + m88ds3103b_dt_write(dev, 0x17, 0xC1); | |
| 1118 | + m88ds3103b_dt_write(dev, 0x17, 0x81); | |
| 1119 | + } | |
| 707 | 1120 | warm: |
| 708 | 1121 | /* warm state */ |
| 709 | 1122 | dev->warm = true; |
| @@ -1393,6 +1806,8 @@ static int m88ds3103_probe(struct i2c_client *client, · 683 unmodified lines | ||
| 1393 | 1806 | goto err_kfree; |
| 1394 | 1807 | |
| 1395 | 1808 | dev->chip_id = utmp >> 1; |
| 1809 | + dev->chiptype = (u8)id->driver_data; | |
| 1810 | + | |
| 1396 | 1811 | dev_dbg(&client->dev, "chip_id=%02x\n", dev->chip_id); |
| 1397 | 1812 | |
| 1398 | 1813 | switch (dev->chip_id) { |
| @@ -1459,7 +1874,10 @@ static int m88ds3103_probe(struct i2c_client *client, · 60 unmodified lines | ||
| 1459 | 1874 | |
| 1460 | 1875 | /* create dvb_frontend */ |
| 1461 | 1876 | memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); |
| 1462 | − if (dev->chip_id == M88RS6000_CHIP_ID) | |
| 1877 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) | |
| 1878 | + strscpy(dev->fe.ops.info.name, "Montage Technology M88DS3103B", | |
| 1879 | + sizeof(dev->fe.ops.info.name)); | |
| 1880 | + else if (dev->chip_id == M88RS6000_CHIP_ID) | |
| 1463 | 1881 | strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", |
| 1464 | 1882 | sizeof(dev->fe.ops.info.name)); |
| 1465 | 1883 | if (!pdata->attach_in_use) |
| @@ -1470,6 +1888,26 @@ static int m88ds3103_probe(struct i2c_client *client, · 4 unmodified lines | ||
| 1470 | 1888 | /* setup callbacks */ |
| 1471 | 1889 | pdata->get_dvb_frontend = m88ds3103_get_dvb_frontend; |
| 1472 | 1890 | pdata->get_i2c_adapter = m88ds3103_get_i2c_adapter; |
| 1891 | + | |
| 1892 | + if (dev->chiptype == M88DS3103_CHIPTYPE_3103B) { | |
| 1893 | + /* enable i2c repeater for tuner */ | |
| 1894 | + m88ds3103_update_bits(dev, 0x11, 0x01, 0x01); | |
| 1895 | + | |
| 1896 | + /* get frontend address */ | |
| 1897 | + ret = regmap_read(dev->regmap, 0x29, &utmp); | |
| 1898 | + if (ret) | |
| 1899 | + goto err_kfree; | |
| 1900 | + dev->dt_addr = ((utmp & 0x80) == 0) ? 0x42 >> 1 : 0x40 >> 1; | |
| 1901 | + dev_err(&client->dev, "dt addr is 0x%02x", dev->dt_addr); | |
| 1902 | + | |
| 1903 | + dev->dt_client = i2c_new_dummy_device(client->adapter, | |
| 1904 | + dev->dt_addr); | |
| 1905 | + if (!dev->dt_client) { | |
| 1906 | + ret = -ENODEV; | |
| 1907 | + goto err_kfree; | |
| 1908 | + } | |
| 1909 | + } | |
| 1910 | + | |
| 1473 | 1911 | return 0; |
| 1474 | 1912 | err_kfree: |
| 1475 | 1913 | kfree(dev); |
| @@ -1484,6 +1922,9 @@ static int m88ds3103_remove(struct i2c_client *client) · 8 unmodified lines | ||
| 1484 | 1922 | |
| 1485 | 1923 | dev_dbg(&client->dev, "\n"); |
| 1486 | 1924 | |
| 1925 | + if (dev->dt_client) | |
| 1926 | + i2c_unregister_device(dev->dt_client); | |
| 1927 | + | |
| 1487 | 1928 | i2c_mux_del_adapters(dev->muxc); |
| 1488 | 1929 | |
| 1489 | 1930 | kfree(dev); |
| @@ -1491,7 +1932,9 @@ static int m88ds3103_remove(struct i2c_client *client) · 1 unmodified line | ||
| 1491 | 1932 | } |
| 1492 | 1933 | |
| 1493 | 1934 | static const struct i2c_device_id m88ds3103_id_table[] = { |
| 1494 | − {"m88ds3103", 0}, | |
| 1935 | + {"m88ds3103", M88DS3103_CHIPTYPE_3103}, | |
| 1936 | + {"m88rs6000", M88DS3103_CHIPTYPE_RS6000}, | |
| 1937 | + {"m88ds3103b", M88DS3103_CHIPTYPE_3103B}, | |
| 1495 | 1938 | {} |
| 1496 | 1939 | }; |
| 1497 | 1940 | MODULE_DEVICE_TABLE(i2c, m88ds3103_id_table); |
| @@ -1513,3 +1956,4 @@ MODULE_DESCRIPTION("Montage Technology M88DS3103 DVB-S/S2 demodulator driver"); · 15 unmodified lines | ||
| 1513 | 1956 | MODULE_LICENSE("GPL"); |
| 1514 | 1957 | MODULE_FIRMWARE(M88DS3103_FIRMWARE); |
| 1515 | 1958 | MODULE_FIRMWARE(M88RS6000_FIRMWARE); |
| 1959 | +MODULE_FIRMWARE(M88DS3103B_FIRMWARE); | |
| @@ -16,13 +16,20 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <linux/regmap.h> |
| 17 | 17 | #include <linux/math64.h> |
| 18 | 18 | |
| 19 | −#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" | |
| 20 | −#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" | |
| 19 | +#define M88DS3103B_FIRMWARE "dvb-demod-m88ds3103b.fw" | |
| 20 | +#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw" | |
| 21 | +#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw" | |
| 22 | + | |
| 21 | 23 | #define M88RS6000_CHIP_ID 0x74 |
| 22 | 24 | #define M88DS3103_CHIP_ID 0x70 |
| 23 | 25 | |
| 26 | +#define M88DS3103_CHIPTYPE_3103 0 | |
| 27 | +#define M88DS3103_CHIPTYPE_RS6000 1 | |
| 28 | +#define M88DS3103_CHIPTYPE_3103B 2 | |
| 29 | + | |
| 24 | 30 | struct m88ds3103_dev { |
| 25 | 31 | struct i2c_client *client; |
| 32 | + struct i2c_client *dt_client; | |
| 26 | 33 | struct regmap_config regmap_config; |
| 27 | 34 | struct regmap *regmap; |
| 28 | 35 | struct m88ds3103_config config; |
| @@ -35,10 +42,13 @@ struct m88ds3103_dev { · 6 unmodified lines | ||
| 35 | 42 | struct i2c_mux_core *muxc; |
| 36 | 43 | /* auto detect chip id to do different config */ |
| 37 | 44 | u8 chip_id; |
| 45 | + /* chip type to differentiate m88rs6000 from m88ds3103b */ | |
| 46 | + u8 chiptype; | |
| 38 | 47 | /* main mclk is calculated for M88RS6000 dynamically */ |
| 39 | 48 | s32 mclk; |
| 40 | 49 | u64 post_bit_error; |
| 41 | 50 | u64 post_bit_count; |
| 51 | + u8 dt_addr; | |
| 42 | 52 | }; |
| 43 | 53 | |
| 44 | 54 | struct m88ds3103_reg_val { |
| @@ -470,10 +470,11 @@ static int tda10071_read_status(struct dvb_frontend *fe, enum fe_status *status) · 469 unmodified lines | ||
| 470 | 470 | goto error; |
| 471 | 471 | |
| 472 | 472 | if (dev->delivery_system == SYS_DVBS) { |
| 473 | − dev->dvbv3_ber = buf[0] << 24 | buf[1] << 16 | | |
| 474 | − buf[2] << 8 | buf[3] << 0; | |
| 475 | − dev->post_bit_error += buf[0] << 24 | buf[1] << 16 | | |
| 476 | − buf[2] << 8 | buf[3] << 0; | |
| 473 | + u32 bit_error = buf[0] << 24 | buf[1] << 16 | | |
| 474 | + buf[2] << 8 | buf[3] << 0; | |
| 475 | + | |
| 476 | + dev->dvbv3_ber = bit_error; | |
| 477 | + dev->post_bit_error += bit_error; | |
| 477 | 478 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
| 478 | 479 | c->post_bit_error.stat[0].uvalue = dev->post_bit_error; |
| 479 | 480 | dev->block_error += buf[4] << 8 | buf[5] << 0; |
| @@ -238,6 +238,7 @@ config VIDEO_ADV7604 · 237 unmodified lines | ||
| 238 | 238 | tristate "Analog Devices ADV7604 decoder" |
| 239 | 239 | depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API |
| 240 | 240 | depends on GPIOLIB || COMPILE_TEST |
| 241 | + select REGMAP_I2C | |
| 241 | 242 | select HDMI |
| 242 | 243 | select V4L2_FWNODE |
| 243 | 244 | help |
| @@ -379,6 +380,7 @@ config VIDEO_TVP5150 · 135 unmodified lines | ||
| 379 | 380 | tristate "Texas Instruments TVP5150 video decoder" |
| 380 | 381 | depends on VIDEO_V4L2 && I2C |
| 381 | 382 | select V4L2_FWNODE |
| 383 | + select REGMAP_I2C | |
| 382 | 384 | help |
| 383 | 385 | Support for the Texas Instruments TVP5150 video decoder. |
| 384 | 386 | |
| @@ -584,6 +586,7 @@ config VIDEO_IMX214 · 199 unmodified lines | ||
| 584 | 586 | tristate "Sony IMX214 sensor support" |
| 585 | 587 | depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
| 586 | 588 | depends on V4L2_FWNODE |
| 589 | + select REGMAP_I2C | |
| 587 | 590 | help |
| 588 | 591 | This is a Video4Linux2 sensor driver for the Sony |
| 589 | 592 | IMX214 camera. |
| @@ -591,6 +594,17 @@ config VIDEO_IMX214 · 1 unmodified line | ||
| 591 | 594 | To compile this driver as a module, choose M here: the |
| 592 | 595 | module will be called imx214. |
| 593 | 596 | |
| 597 | +config VIDEO_IMX219 | |
| 598 | + tristate "Sony IMX219 sensor support" | |
| 599 | + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | |
| 600 | + select V4L2_FWNODE | |
| 601 | + help | |
| 602 | + This is a Video4Linux2 sensor driver for the Sony | |
| 603 | + IMX219 camera. | |
| 604 | + | |
| 605 | + To compile this driver as a module, choose M here: the | |
| 606 | + module will be called imx219. | |
| 607 | + | |
| 594 | 608 | config VIDEO_IMX258 |
| 595 | 609 | tristate "Sony IMX258 sensor support" |
| 596 | 610 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
| @@ -612,6 +626,7 @@ config VIDEO_IMX274 · 15 unmodified lines | ||
| 612 | 626 | config VIDEO_IMX290 |
| 613 | 627 | tristate "Sony IMX290 sensor support" |
| 614 | 628 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API |
| 629 | + select REGMAP_I2C | |
| 615 | 630 | select V4L2_FWNODE |
| 616 | 631 | help |
| 617 | 632 | This is a Video4Linux2 sensor driver for the Sony |
| @@ -804,6 +819,7 @@ config VIDEO_OV7670 · 186 unmodified lines | ||
| 804 | 819 | config VIDEO_OV7740 |
| 805 | 820 | tristate "OmniVision OV7740 sensor support" |
| 806 | 821 | depends on I2C && VIDEO_V4L2 |
| 822 | + select REGMAP_I2C | |
| 807 | 823 | help |
| 808 | 824 | This is a Video4Linux2 sensor driver for the OmniVision |
| 809 | 825 | OV7740 VGA camera sensor. |
| @@ -111,6 +111,7 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o · 110 unmodified lines | ||
| 111 | 111 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o |
| 112 | 112 | obj-$(CONFIG_VIDEO_HI556) += hi556.o |
| 113 | 113 | obj-$(CONFIG_VIDEO_IMX214) += imx214.o |
| 114 | +obj-$(CONFIG_VIDEO_IMX219) += imx219.o | |
| 114 | 115 | obj-$(CONFIG_VIDEO_IMX258) += imx258.o |
| 115 | 116 | obj-$(CONFIG_VIDEO_IMX274) += imx274.o |
| 116 | 117 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o |
| @@ -749,6 +749,17 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, · 748 unmodified lines | ||
| 749 | 749 | return ret; |
| 750 | 750 | } |
| 751 | 751 | |
| 752 | +static int adv7180_init_cfg(struct v4l2_subdev *sd, | |
| 753 | + struct v4l2_subdev_pad_config *cfg) | |
| 754 | +{ | |
| 755 | + struct v4l2_subdev_format fmt = { | |
| 756 | + .which = cfg ? V4L2_SUBDEV_FORMAT_TRY | |
| 757 | + : V4L2_SUBDEV_FORMAT_ACTIVE, | |
| 758 | + }; | |
| 759 | + | |
| 760 | + return adv7180_set_pad_format(sd, cfg, &fmt); | |
| 761 | +} | |
| 762 | + | |
| 752 | 763 | static int adv7180_g_mbus_config(struct v4l2_subdev *sd, |
| 753 | 764 | struct v4l2_mbus_config *cfg) |
| 754 | 765 | { |
| @@ -854,6 +865,7 @@ static const struct v4l2_subdev_core_ops adv7180_core_ops = { · 99 unmodified lines | ||
| 854 | 865 | }; |
| 855 | 866 | |
| 856 | 867 | static const struct v4l2_subdev_pad_ops adv7180_pad_ops = { |
| 868 | + .init_cfg = adv7180_init_cfg, | |
| 857 | 869 | .enum_mbus_code = adv7180_enum_mbus_code, |
| 858 | 870 | .set_fmt = adv7180_set_pad_format, |
| 859 | 871 | .get_fmt = adv7180_get_pad_format, |
| @@ -803,7 +803,6 @@ err_rpm_put: · 802 unmodified lines | ||
| 803 | 803 | static int imx214_g_frame_interval(struct v4l2_subdev *subdev, |
| 804 | 804 | struct v4l2_subdev_frame_interval *fival) |
| 805 | 805 | { |
| 806 | − fival->pad = 0; | |
| 807 | 806 | fival->interval.numerator = 1; |
| 808 | 807 | fival->interval.denominator = IMX214_FPS; |
| 809 | 808 | |
| @@ -0,0 +1,1481 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * A V4L2 driver for Sony IMX219 cameras. | |
| 4 | + * Copyright (C) 2019, Raspberry Pi (Trading) Ltd | |
| 5 | + * | |
| 6 | + * Based on Sony imx258 camera driver | |
| 7 | + * Copyright (C) 2018 Intel Corporation | |
| 8 | + * | |
| 9 | + * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver | |
| 10 | + * Copyright 2018 Qtechnology A/S | |
| 11 | + * | |
| 12 | + * Flip handling taken from the Sony IMX319 driver. | |
| 13 | + * Copyright (C) 2018 Intel Corporation | |
| 14 | + * | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/clk.h> | |
| 18 | +#include <linux/clk-provider.h> | |
| 19 | +#include <linux/clkdev.h> | |
| 20 | +#include <linux/delay.h> | |
| 21 | +#include <linux/gpio/consumer.h> | |
| 22 | +#include <linux/i2c.h> | |
| 23 | +#include <linux/module.h> | |
| 24 | +#include <linux/pm_runtime.h> | |
| 25 | +#include <linux/regulator/consumer.h> | |
| 26 | +#include <media/v4l2-ctrls.h> | |
| 27 | +#include <media/v4l2-device.h> | |
| 28 | +#include <media/v4l2-event.h> | |
| 29 | +#include <media/v4l2-fwnode.h> | |
| 30 | +#include <media/v4l2-mediabus.h> | |
| 31 | +#include <asm/unaligned.h> | |
| 32 | + | |
| 33 | +#define IMX219_REG_VALUE_08BIT 1 | |
| 34 | +#define IMX219_REG_VALUE_16BIT 2 | |
| 35 | + | |
| 36 | +#define IMX219_REG_MODE_SELECT 0x0100 | |
| 37 | +#define IMX219_MODE_STANDBY 0x00 | |
| 38 | +#define IMX219_MODE_STREAMING 0x01 | |
| 39 | + | |
| 40 | +/* Chip ID */ | |
| 41 | +#define IMX219_REG_CHIP_ID 0x0000 | |
| 42 | +#define IMX219_CHIP_ID 0x0219 | |
| 43 | + | |
| 44 | +/* External clock frequency is 24.0M */ | |
| 45 | +#define IMX219_XCLK_FREQ 24000000 | |
| 46 | + | |
| 47 | +/* Pixel rate is fixed at 182.4M for all the modes */ | |
| 48 | +#define IMX219_PIXEL_RATE 182400000 | |
| 49 | + | |
| 50 | +#define IMX219_DEFAULT_LINK_FREQ 456000000 | |
| 51 | + | |
| 52 | +/* V_TIMING internal */ | |
| 53 | +#define IMX219_REG_VTS 0x0160 | |
| 54 | +#define IMX219_VTS_15FPS 0x0dc6 | |
| 55 | +#define IMX219_VTS_30FPS_1080P 0x06e3 | |
| 56 | +#define IMX219_VTS_30FPS_BINNED 0x06e3 | |
| 57 | +#define IMX219_VTS_30FPS_640x480 0x06e3 | |
| 58 | +#define IMX219_VTS_MAX 0xffff | |
| 59 | + | |
| 60 | +#define IMX219_VBLANK_MIN 4 | |
| 61 | + | |
| 62 | +/*Frame Length Line*/ | |
| 63 | +#define IMX219_FLL_MIN 0x08a6 | |
| 64 | +#define IMX219_FLL_MAX 0xffff | |
| 65 | +#define IMX219_FLL_STEP 1 | |
| 66 | +#define IMX219_FLL_DEFAULT 0x0c98 | |
| 67 | + | |
| 68 | +/* HBLANK control - read only */ | |
| 69 | +#define IMX219_PPL_DEFAULT 3448 | |
| 70 | + | |
| 71 | +/* Exposure control */ | |
| 72 | +#define IMX219_REG_EXPOSURE 0x015a | |
| 73 | +#define IMX219_EXPOSURE_MIN 4 | |
| 74 | +#define IMX219_EXPOSURE_STEP 1 | |
| 75 | +#define IMX219_EXPOSURE_DEFAULT 0x640 | |
| 76 | +#define IMX219_EXPOSURE_MAX 65535 | |
| 77 | + | |
| 78 | +/* Analog gain control */ | |
| 79 | +#define IMX219_REG_ANALOG_GAIN 0x0157 | |
| 80 | +#define IMX219_ANA_GAIN_MIN 0 | |
| 81 | +#define IMX219_ANA_GAIN_MAX 232 | |
| 82 | +#define IMX219_ANA_GAIN_STEP 1 | |
| 83 | +#define IMX219_ANA_GAIN_DEFAULT 0x0 | |
| 84 | + | |
| 85 | +/* Digital gain control */ | |
| 86 | +#define IMX219_REG_DIGITAL_GAIN 0x0158 | |
| 87 | +#define IMX219_DGTL_GAIN_MIN 0x0100 | |
| 88 | +#define IMX219_DGTL_GAIN_MAX 0x0fff | |
| 89 | +#define IMX219_DGTL_GAIN_DEFAULT 0x0100 | |
| 90 | +#define IMX219_DGTL_GAIN_STEP 1 | |
| 91 | + | |
| 92 | +#define IMX219_REG_ORIENTATION 0x0172 | |
| 93 | + | |
| 94 | +/* Test Pattern Control */ | |
| 95 | +#define IMX219_REG_TEST_PATTERN 0x0600 | |
| 96 | +#define IMX219_TEST_PATTERN_DISABLE 0 | |
| 97 | +#define IMX219_TEST_PATTERN_SOLID_COLOR 1 | |
| 98 | +#define IMX219_TEST_PATTERN_COLOR_BARS 2 | |
| 99 | +#define IMX219_TEST_PATTERN_GREY_COLOR 3 | |
| 100 | +#define IMX219_TEST_PATTERN_PN9 4 | |
| 101 | + | |
| 102 | +/* Test pattern colour components */ | |
| 103 | +#define IMX219_REG_TESTP_RED 0x0602 | |
| 104 | +#define IMX219_REG_TESTP_GREENR 0x0604 | |
| 105 | +#define IMX219_REG_TESTP_BLUE 0x0606 | |
| 106 | +#define IMX219_REG_TESTP_GREENB 0x0608 | |
| 107 | +#define IMX219_TESTP_COLOUR_MIN 0 | |
| 108 | +#define IMX219_TESTP_COLOUR_MAX 0x03ff | |
| 109 | +#define IMX219_TESTP_COLOUR_STEP 1 | |
| 110 | +#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX | |
| 111 | +#define IMX219_TESTP_GREENR_DEFAULT 0 | |
| 112 | +#define IMX219_TESTP_BLUE_DEFAULT 0 | |
| 113 | +#define IMX219_TESTP_GREENB_DEFAULT 0 | |
| 114 | + | |
| 115 | +struct imx219_reg { | |
| 116 | + u16 address; | |
| 117 | + u8 val; | |
| 118 | +}; | |
| 119 | + | |
| 120 | +struct imx219_reg_list { | |
| 121 | + unsigned int num_of_regs; | |
| 122 | + const struct imx219_reg *regs; | |
| 123 | +}; | |
| 124 | + | |
| 125 | +/* Mode : resolution and related config&values */ | |
| 126 | +struct imx219_mode { | |
| 127 | + /* Frame width */ | |
| 128 | + unsigned int width; | |
| 129 | + /* Frame height */ | |
| 130 | + unsigned int height; | |
| 131 | + | |
| 132 | + /* V-timing */ | |
| 133 | + unsigned int vts_def; | |
| 134 | + | |
| 135 | + /* Default register values */ | |
| 136 | + struct imx219_reg_list reg_list; | |
| 137 | +}; | |
| 138 | + | |
| 139 | +/* | |
| 140 | + * Register sets lifted off the i2C interface from the Raspberry Pi firmware | |
| 141 | + * driver. | |
| 142 | + * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. | |
| 143 | + */ | |
| 144 | +static const struct imx219_reg mode_3280x2464_regs[] = { | |
| 145 | + {0x0100, 0x00}, | |
| 146 | + {0x30eb, 0x0c}, | |
| 147 | + {0x30eb, 0x05}, | |
| 148 | + {0x300a, 0xff}, | |
| 149 | + {0x300b, 0xff}, | |
| 150 | + {0x30eb, 0x05}, | |
| 151 | + {0x30eb, 0x09}, | |
| 152 | + {0x0114, 0x01}, | |
| 153 | + {0x0128, 0x00}, | |
| 154 | + {0x012a, 0x18}, | |
| 155 | + {0x012b, 0x00}, | |
| 156 | + {0x0164, 0x00}, | |
| 157 | + {0x0165, 0x00}, | |
| 158 | + {0x0166, 0x0c}, | |
| 159 | + {0x0167, 0xcf}, | |
| 160 | + {0x0168, 0x00}, | |
| 161 | + {0x0169, 0x00}, | |
| 162 | + {0x016a, 0x09}, | |
| 163 | + {0x016b, 0x9f}, | |
| 164 | + {0x016c, 0x0c}, | |
| 165 | + {0x016d, 0xd0}, | |
| 166 | + {0x016e, 0x09}, | |
| 167 | + {0x016f, 0xa0}, | |
| 168 | + {0x0170, 0x01}, | |
| 169 | + {0x0171, 0x01}, | |
| 170 | + {0x0174, 0x00}, | |
| 171 | + {0x0175, 0x00}, | |
| 172 | + {0x0301, 0x05}, | |
| 173 | + {0x0303, 0x01}, | |
| 174 | + {0x0304, 0x03}, | |
| 175 | + {0x0305, 0x03}, | |
| 176 | + {0x0306, 0x00}, | |
| 177 | + {0x0307, 0x39}, | |
| 178 | + {0x030b, 0x01}, | |
| 179 | + {0x030c, 0x00}, | |
| 180 | + {0x030d, 0x72}, | |
| 181 | + {0x0624, 0x0c}, | |
| 182 | + {0x0625, 0xd0}, | |
| 183 | + {0x0626, 0x09}, | |
| 184 | + {0x0627, 0xa0}, | |
| 185 | + {0x455e, 0x00}, | |
| 186 | + {0x471e, 0x4b}, | |
| 187 | + {0x4767, 0x0f}, | |
| 188 | + {0x4750, 0x14}, | |
| 189 | + {0x4540, 0x00}, | |
| 190 | + {0x47b4, 0x14}, | |
| 191 | + {0x4713, 0x30}, | |
| 192 | + {0x478b, 0x10}, | |
| 193 | + {0x478f, 0x10}, | |
| 194 | + {0x4793, 0x10}, | |
| 195 | + {0x4797, 0x0e}, | |
| 196 | + {0x479b, 0x0e}, | |
| 197 | + {0x0162, 0x0d}, | |
| 198 | + {0x0163, 0x78}, | |
| 199 | +}; | |
| 200 | + | |
| 201 | +static const struct imx219_reg mode_1920_1080_regs[] = { | |
| 202 | + {0x0100, 0x00}, | |
| 203 | + {0x30eb, 0x05}, | |
| 204 | + {0x30eb, 0x0c}, | |
| 205 | + {0x300a, 0xff}, | |
| 206 | + {0x300b, 0xff}, | |
| 207 | + {0x30eb, 0x05}, | |
| 208 | + {0x30eb, 0x09}, | |
| 209 | + {0x0114, 0x01}, | |
| 210 | + {0x0128, 0x00}, | |
| 211 | + {0x012a, 0x18}, | |
| 212 | + {0x012b, 0x00}, | |
| 213 | + {0x0162, 0x0d}, | |
| 214 | + {0x0163, 0x78}, | |
| 215 | + {0x0164, 0x02}, | |
| 216 | + {0x0165, 0xa8}, | |
| 217 | + {0x0166, 0x0a}, | |
| 218 | + {0x0167, 0x27}, | |
| 219 | + {0x0168, 0x02}, | |
| 220 | + {0x0169, 0xb4}, | |
| 221 | + {0x016a, 0x06}, | |
| 222 | + {0x016b, 0xeb}, | |
| 223 | + {0x016c, 0x07}, | |
| 224 | + {0x016d, 0x80}, | |
| 225 | + {0x016e, 0x04}, | |
| 226 | + {0x016f, 0x38}, | |
| 227 | + {0x0170, 0x01}, | |
| 228 | + {0x0171, 0x01}, | |
| 229 | + {0x0174, 0x00}, | |
| 230 | + {0x0175, 0x00}, | |
| 231 | + {0x0301, 0x05}, | |
| 232 | + {0x0303, 0x01}, | |
| 233 | + {0x0304, 0x03}, | |
| 234 | + {0x0305, 0x03}, | |
| 235 | + {0x0306, 0x00}, | |
| 236 | + {0x0307, 0x39}, | |
| 237 | + {0x030b, 0x01}, | |
| 238 | + {0x030c, 0x00}, | |
| 239 | + {0x030d, 0x72}, | |
| 240 | + {0x0624, 0x07}, | |
| 241 | + {0x0625, 0x80}, | |
| 242 | + {0x0626, 0x04}, | |
| 243 | + {0x0627, 0x38}, | |
| 244 | + {0x455e, 0x00}, | |
| 245 | + {0x471e, 0x4b}, | |
| 246 | + {0x4767, 0x0f}, | |
| 247 | + {0x4750, 0x14}, | |
| 248 | + {0x4540, 0x00}, | |
| 249 | + {0x47b4, 0x14}, | |
| 250 | + {0x4713, 0x30}, | |
| 251 | + {0x478b, 0x10}, | |
| 252 | + {0x478f, 0x10}, | |
| 253 | + {0x4793, 0x10}, | |
| 254 | + {0x4797, 0x0e}, | |
| 255 | + {0x479b, 0x0e}, | |
| 256 | + {0x0162, 0x0d}, | |
| 257 | + {0x0163, 0x78}, | |
| 258 | +}; | |
| 259 | + | |
| 260 | +static const struct imx219_reg mode_1640_1232_regs[] = { | |
| 261 | + {0x0100, 0x00}, | |
| 262 | + {0x30eb, 0x0c}, | |
| 263 | + {0x30eb, 0x05}, | |
| 264 | + {0x300a, 0xff}, | |
| 265 | + {0x300b, 0xff}, | |
| 266 | + {0x30eb, 0x05}, | |
| 267 | + {0x30eb, 0x09}, | |
| 268 | + {0x0114, 0x01}, | |
| 269 | + {0x0128, 0x00}, | |
| 270 | + {0x012a, 0x18}, | |
| 271 | + {0x012b, 0x00}, | |
| 272 | + {0x0164, 0x00}, | |
| 273 | + {0x0165, 0x00}, | |
| 274 | + {0x0166, 0x0c}, | |
| 275 | + {0x0167, 0xcf}, | |
| 276 | + {0x0168, 0x00}, | |
| 277 | + {0x0169, 0x00}, | |
| 278 | + {0x016a, 0x09}, | |
| 279 | + {0x016b, 0x9f}, | |
| 280 | + {0x016c, 0x06}, | |
| 281 | + {0x016d, 0x68}, | |
| 282 | + {0x016e, 0x04}, | |
| 283 | + {0x016f, 0xd0}, | |
| 284 | + {0x0170, 0x01}, | |
| 285 | + {0x0171, 0x01}, | |
| 286 | + {0x0174, 0x01}, | |
| 287 | + {0x0175, 0x01}, | |
| 288 | + {0x0301, 0x05}, | |
| 289 | + {0x0303, 0x01}, | |
| 290 | + {0x0304, 0x03}, | |
| 291 | + {0x0305, 0x03}, | |
| 292 | + {0x0306, 0x00}, | |
| 293 | + {0x0307, 0x39}, | |
| 294 | + {0x030b, 0x01}, | |
| 295 | + {0x030c, 0x00}, | |
| 296 | + {0x030d, 0x72}, | |
| 297 | + {0x0624, 0x06}, | |
| 298 | + {0x0625, 0x68}, | |
| 299 | + {0x0626, 0x04}, | |
| 300 | + {0x0627, 0xd0}, | |
| 301 | + {0x455e, 0x00}, | |
| 302 | + {0x471e, 0x4b}, | |
| 303 | + {0x4767, 0x0f}, | |
| 304 | + {0x4750, 0x14}, | |
| 305 | + {0x4540, 0x00}, | |
| 306 | + {0x47b4, 0x14}, | |
| 307 | + {0x4713, 0x30}, | |
| 308 | + {0x478b, 0x10}, | |
| 309 | + {0x478f, 0x10}, | |
| 310 | + {0x4793, 0x10}, | |
| 311 | + {0x4797, 0x0e}, | |
| 312 | + {0x479b, 0x0e}, | |
| 313 | + {0x0162, 0x0d}, | |
| 314 | + {0x0163, 0x78}, | |
| 315 | +}; | |
| 316 | + | |
| 317 | +static const struct imx219_reg mode_640_480_regs[] = { | |
| 318 | + {0x0100, 0x00}, | |
| 319 | + {0x30eb, 0x05}, | |
| 320 | + {0x30eb, 0x0c}, | |
| 321 | + {0x300a, 0xff}, | |
| 322 | + {0x300b, 0xff}, | |
| 323 | + {0x30eb, 0x05}, | |
| 324 | + {0x30eb, 0x09}, | |
| 325 | + {0x0114, 0x01}, | |
| 326 | + {0x0128, 0x00}, | |
| 327 | + {0x012a, 0x18}, | |
| 328 | + {0x012b, 0x00}, | |
| 329 | + {0x0162, 0x0d}, | |
| 330 | + {0x0163, 0x78}, | |
| 331 | + {0x0164, 0x03}, | |
| 332 | + {0x0165, 0xe8}, | |
| 333 | + {0x0166, 0x08}, | |
| 334 | + {0x0167, 0xe7}, | |
| 335 | + {0x0168, 0x02}, | |
| 336 | + {0x0169, 0xf0}, | |
| 337 | + {0x016a, 0x06}, | |
| 338 | + {0x016b, 0xaf}, | |
| 339 | + {0x016c, 0x02}, | |
| 340 | + {0x016d, 0x80}, | |
| 341 | + {0x016e, 0x01}, | |
| 342 | + {0x016f, 0xe0}, | |
| 343 | + {0x0170, 0x01}, | |
| 344 | + {0x0171, 0x01}, | |
| 345 | + {0x0174, 0x03}, | |
| 346 | + {0x0175, 0x03}, | |
| 347 | + {0x0301, 0x05}, | |
| 348 | + {0x0303, 0x01}, | |
| 349 | + {0x0304, 0x03}, | |
| 350 | + {0x0305, 0x03}, | |
| 351 | + {0x0306, 0x00}, | |
| 352 | + {0x0307, 0x39}, | |
| 353 | + {0x030b, 0x01}, | |
| 354 | + {0x030c, 0x00}, | |
| 355 | + {0x030d, 0x72}, | |
| 356 | + {0x0624, 0x06}, | |
| 357 | + {0x0625, 0x68}, | |
| 358 | + {0x0626, 0x04}, | |
| 359 | + {0x0627, 0xd0}, | |
| 360 | + {0x455e, 0x00}, | |
| 361 | + {0x471e, 0x4b}, | |
| 362 | + {0x4767, 0x0f}, | |
| 363 | + {0x4750, 0x14}, | |
| 364 | + {0x4540, 0x00}, | |
| 365 | + {0x47b4, 0x14}, | |
| 366 | + {0x4713, 0x30}, | |
| 367 | + {0x478b, 0x10}, | |
| 368 | + {0x478f, 0x10}, | |
| 369 | + {0x4793, 0x10}, | |
| 370 | + {0x4797, 0x0e}, | |
| 371 | + {0x479b, 0x0e}, | |
| 372 | +}; | |
| 373 | + | |
| 374 | +static const struct imx219_reg raw8_framefmt_regs[] = { | |
| 375 | + {0x018c, 0x08}, | |
| 376 | + {0x018d, 0x08}, | |
| 377 | + {0x0309, 0x08}, | |
| 378 | +}; | |
| 379 | + | |
| 380 | +static const struct imx219_reg raw10_framefmt_regs[] = { | |
| 381 | + {0x018c, 0x0a}, | |
| 382 | + {0x018d, 0x0a}, | |
| 383 | + {0x0309, 0x0a}, | |
| 384 | +}; | |
| 385 | + | |
| 386 | +static const char * const imx219_test_pattern_menu[] = { | |
| 387 | + "Disabled", | |
| 388 | + "Color Bars", | |
| 389 | + "Solid Color", | |
| 390 | + "Grey Color Bars", | |
| 391 | + "PN9" | |
| 392 | +}; | |
| 393 | + | |
| 394 | +static const int imx219_test_pattern_val[] = { | |
| 395 | + IMX219_TEST_PATTERN_DISABLE, | |
| 396 | + IMX219_TEST_PATTERN_COLOR_BARS, | |
| 397 | + IMX219_TEST_PATTERN_SOLID_COLOR, | |
| 398 | + IMX219_TEST_PATTERN_GREY_COLOR, | |
| 399 | + IMX219_TEST_PATTERN_PN9, | |
| 400 | +}; | |
| 401 | + | |
| 402 | +/* regulator supplies */ | |
| 403 | +static const char * const imx219_supply_name[] = { | |
| 404 | + /* Supplies can be enabled in any order */ | |
| 405 | + "VANA", /* Analog (2.8V) supply */ | |
| 406 | + "VDIG", /* Digital Core (1.8V) supply */ | |
| 407 | + "VDDL", /* IF (1.2V) supply */ | |
| 408 | +}; | |
| 409 | + | |
| 410 | +#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name) | |
| 411 | + | |
| 412 | +/* | |
| 413 | + * The supported formats. | |
| 414 | + * This table MUST contain 4 entries per format, to cover the various flip | |
| 415 | + * combinations in the order | |
| 416 | + * - no flip | |
| 417 | + * - h flip | |
| 418 | + * - v flip | |
| 419 | + * - h&v flips | |
| 420 | + */ | |
| 421 | +static const u32 codes[] = { | |
| 422 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 423 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 424 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 425 | + MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 426 | + | |
| 427 | + MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 428 | + MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 429 | + MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 430 | + MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 431 | +}; | |
| 432 | + | |
| 433 | +/* | |
| 434 | + * Initialisation delay between XCLR low->high and the moment when the sensor | |
| 435 | + * can start capture (i.e. can leave software stanby) must be not less than: | |
| 436 | + * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>) | |
| 437 | + * where | |
| 438 | + * t4 is fixed, and is max 200uS, | |
| 439 | + * t5 is fixed, and is 6000uS, | |
| 440 | + * t6 depends on the sensor external clock, and is max 32000 clock periods. | |
| 441 | + * As per sensor datasheet, the external clock must be from 6MHz to 27MHz. | |
| 442 | + * So for any acceptable external clock t6 is always within the range of | |
| 443 | + * 1185 to 5333 uS, and is always less than t5. | |
| 444 | + * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then | |
| 445 | + * initialize the sensor over I2C, and then exit the software standby. | |
| 446 | + * | |
| 447 | + * This start-up time can be optimized a bit more, if we start the writes | |
| 448 | + * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor | |
| 449 | + * initialization over I2C may complete before (t4+t5) expires, and we must | |
| 450 | + * ensure that capture is not started before (t4+t5). | |
| 451 | + * | |
| 452 | + * This delay doesn't account for the power supply startup time. If needed, | |
| 453 | + * this should be taken care of via the regulator framework. E.g. in the | |
| 454 | + * case of DT for regulator-fixed one should define the startup-delay-us | |
| 455 | + * property. | |
| 456 | + */ | |
| 457 | +#define IMX219_XCLR_MIN_DELAY_US 6200 | |
| 458 | +#define IMX219_XCLR_DELAY_RANGE_US 1000 | |
| 459 | + | |
| 460 | +/* Mode configs */ | |
| 461 | +static const struct imx219_mode supported_modes[] = { | |
| 462 | + { | |
| 463 | + /* 8MPix 15fps mode */ | |
| 464 | + .width = 3280, | |
| 465 | + .height = 2464, | |
| 466 | + .vts_def = IMX219_VTS_15FPS, | |
| 467 | + .reg_list = { | |
| 468 | + .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), | |
| 469 | + .regs = mode_3280x2464_regs, | |
| 470 | + }, | |
| 471 | + }, | |
| 472 | + { | |
| 473 | + /* 1080P 30fps cropped */ | |
| 474 | + .width = 1920, | |
| 475 | + .height = 1080, | |
| 476 | + .vts_def = IMX219_VTS_30FPS_1080P, | |
| 477 | + .reg_list = { | |
| 478 | + .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), | |
| 479 | + .regs = mode_1920_1080_regs, | |
| 480 | + }, | |
| 481 | + }, | |
| 482 | + { | |
| 483 | + /* 2x2 binned 30fps mode */ | |
| 484 | + .width = 1640, | |
| 485 | + .height = 1232, | |
| 486 | + .vts_def = IMX219_VTS_30FPS_BINNED, | |
| 487 | + .reg_list = { | |
| 488 | + .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), | |
| 489 | + .regs = mode_1640_1232_regs, | |
| 490 | + }, | |
| 491 | + }, | |
| 492 | + { | |
| 493 | + /* 640x480 30fps mode */ | |
| 494 | + .width = 640, | |
| 495 | + .height = 480, | |
| 496 | + .vts_def = IMX219_VTS_30FPS_640x480, | |
| 497 | + .reg_list = { | |
| 498 | + .num_of_regs = ARRAY_SIZE(mode_640_480_regs), | |
| 499 | + .regs = mode_640_480_regs, | |
| 500 | + }, | |
| 501 | + }, | |
| 502 | +}; | |
| 503 | + | |
| 504 | +struct imx219 { | |
| 505 | + struct v4l2_subdev sd; | |
| 506 | + struct media_pad pad; | |
| 507 | + | |
| 508 | + struct v4l2_mbus_framefmt fmt; | |
| 509 | + | |
| 510 | + struct clk *xclk; /* system clock to IMX219 */ | |
| 511 | + u32 xclk_freq; | |
| 512 | + | |
| 513 | + struct gpio_desc *reset_gpio; | |
| 514 | + struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES]; | |
| 515 | + | |
| 516 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 517 | + /* V4L2 Controls */ | |
| 518 | + struct v4l2_ctrl *pixel_rate; | |
| 519 | + struct v4l2_ctrl *exposure; | |
| 520 | + struct v4l2_ctrl *vflip; | |
| 521 | + struct v4l2_ctrl *hflip; | |
| 522 | + struct v4l2_ctrl *vblank; | |
| 523 | + struct v4l2_ctrl *hblank; | |
| 524 | + | |
| 525 | + /* Current mode */ | |
| 526 | + const struct imx219_mode *mode; | |
| 527 | + | |
| 528 | + /* | |
| 529 | + * Mutex for serialized access: | |
| 530 | + * Protect sensor module set pad format and start/stop streaming safely. | |
| 531 | + */ | |
| 532 | + struct mutex mutex; | |
| 533 | + | |
| 534 | + /* Streaming on/off */ | |
| 535 | + bool streaming; | |
| 536 | +}; | |
| 537 | + | |
| 538 | +static inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) | |
| 539 | +{ | |
| 540 | + return container_of(_sd, struct imx219, sd); | |
| 541 | +} | |
| 542 | + | |
| 543 | +/* Read registers up to 2 at a time */ | |
| 544 | +static int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val) | |
| 545 | +{ | |
| 546 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 547 | + struct i2c_msg msgs[2]; | |
| 548 | + u8 addr_buf[2] = { reg >> 8, reg & 0xff }; | |
| 549 | + u8 data_buf[4] = { 0, }; | |
| 550 | + int ret; | |
| 551 | + | |
| 552 | + if (len > 4) | |
| 553 | + return -EINVAL; | |
| 554 | + | |
| 555 | + /* Write register address */ | |
| 556 | + msgs[0].addr = client->addr; | |
| 557 | + msgs[0].flags = 0; | |
| 558 | + msgs[0].len = ARRAY_SIZE(addr_buf); | |
| 559 | + msgs[0].buf = addr_buf; | |
| 560 | + | |
| 561 | + /* Read data from register */ | |
| 562 | + msgs[1].addr = client->addr; | |
| 563 | + msgs[1].flags = I2C_M_RD; | |
| 564 | + msgs[1].len = len; | |
| 565 | + msgs[1].buf = &data_buf[4 - len]; | |
| 566 | + | |
| 567 | + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | |
| 568 | + if (ret != ARRAY_SIZE(msgs)) | |
| 569 | + return -EIO; | |
| 570 | + | |
| 571 | + *val = get_unaligned_be32(data_buf); | |
| 572 | + | |
| 573 | + return 0; | |
| 574 | +} | |
| 575 | + | |
| 576 | +/* Write registers up to 2 at a time */ | |
| 577 | +static int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val) | |
| 578 | +{ | |
| 579 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 580 | + u8 buf[6]; | |
| 581 | + | |
| 582 | + if (len > 4) | |
| 583 | + return -EINVAL; | |
| 584 | + | |
| 585 | + put_unaligned_be16(reg, buf); | |
| 586 | + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); | |
| 587 | + if (i2c_master_send(client, buf, len + 2) != len + 2) | |
| 588 | + return -EIO; | |
| 589 | + | |
| 590 | + return 0; | |
| 591 | +} | |
| 592 | + | |
| 593 | +/* Write a list of registers */ | |
| 594 | +static int imx219_write_regs(struct imx219 *imx219, | |
| 595 | + const struct imx219_reg *regs, u32 len) | |
| 596 | +{ | |
| 597 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 598 | + unsigned int i; | |
| 599 | + int ret; | |
| 600 | + | |
| 601 | + for (i = 0; i < len; i++) { | |
| 602 | + ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val); | |
| 603 | + if (ret) { | |
| 604 | + dev_err_ratelimited(&client->dev, | |
| 605 | + "Failed to write reg 0x%4.4x. error = %d\n", | |
| 606 | + regs[i].address, ret); | |
| 607 | + | |
| 608 | + return ret; | |
| 609 | + } | |
| 610 | + } | |
| 611 | + | |
| 612 | + return 0; | |
| 613 | +} | |
| 614 | + | |
| 615 | +/* Get bayer order based on flip setting. */ | |
| 616 | +static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) | |
| 617 | +{ | |
| 618 | + unsigned int i; | |
| 619 | + | |
| 620 | + lockdep_assert_held(&imx219->mutex); | |
| 621 | + | |
| 622 | + for (i = 0; i < ARRAY_SIZE(codes); i++) | |
| 623 | + if (codes[i] == code) | |
| 624 | + break; | |
| 625 | + | |
| 626 | + if (i >= ARRAY_SIZE(codes)) | |
| 627 | + i = 0; | |
| 628 | + | |
| 629 | + i = (i & ~3) | (imx219->vflip->val ? 2 : 0) | | |
| 630 | + (imx219->hflip->val ? 1 : 0); | |
| 631 | + | |
| 632 | + return codes[i]; | |
| 633 | +} | |
| 634 | + | |
| 635 | +static void imx219_set_default_format(struct imx219 *imx219) | |
| 636 | +{ | |
| 637 | + struct v4l2_mbus_framefmt *fmt; | |
| 638 | + | |
| 639 | + fmt = &imx219->fmt; | |
| 640 | + fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; | |
| 641 | + fmt->colorspace = V4L2_COLORSPACE_SRGB; | |
| 642 | + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); | |
| 643 | + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, | |
| 644 | + fmt->colorspace, | |
| 645 | + fmt->ycbcr_enc); | |
| 646 | + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); | |
| 647 | + fmt->width = supported_modes[0].width; | |
| 648 | + fmt->height = supported_modes[0].height; | |
| 649 | + fmt->field = V4L2_FIELD_NONE; | |
| 650 | +} | |
| 651 | + | |
| 652 | +static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 653 | +{ | |
| 654 | + struct imx219 *imx219 = to_imx219(sd); | |
| 655 | + struct v4l2_mbus_framefmt *try_fmt = | |
| 656 | + v4l2_subdev_get_try_format(sd, fh->pad, 0); | |
| 657 | + | |
| 658 | + mutex_lock(&imx219->mutex); | |
| 659 | + | |
| 660 | + /* Initialize try_fmt */ | |
| 661 | + try_fmt->width = supported_modes[0].width; | |
| 662 | + try_fmt->height = supported_modes[0].height; | |
| 663 | + try_fmt->code = imx219_get_format_code(imx219, | |
| 664 | + MEDIA_BUS_FMT_SRGGB10_1X10); | |
| 665 | + try_fmt->field = V4L2_FIELD_NONE; | |
| 666 | + | |
| 667 | + mutex_unlock(&imx219->mutex); | |
| 668 | + | |
| 669 | + return 0; | |
| 670 | +} | |
| 671 | + | |
| 672 | +static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 673 | +{ | |
| 674 | + struct imx219 *imx219 = | |
| 675 | + container_of(ctrl->handler, struct imx219, ctrl_handler); | |
| 676 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 677 | + int ret; | |
| 678 | + | |
| 679 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 680 | + int exposure_max, exposure_def; | |
| 681 | + | |
| 682 | + /* Update max exposure while meeting expected vblanking */ | |
| 683 | + exposure_max = imx219->mode->height + ctrl->val - 4; | |
| 684 | + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? | |
| 685 | + exposure_max : IMX219_EXPOSURE_DEFAULT; | |
| 686 | + __v4l2_ctrl_modify_range(imx219->exposure, | |
| 687 | + imx219->exposure->minimum, | |
| 688 | + exposure_max, imx219->exposure->step, | |
| 689 | + exposure_def); | |
| 690 | + } | |
| 691 | + | |
| 692 | + /* | |
| 693 | + * Applying V4L2 control value only happens | |
| 694 | + * when power is up for streaming | |
| 695 | + */ | |
| 696 | + if (pm_runtime_get_if_in_use(&client->dev) == 0) | |
| 697 | + return 0; | |
| 698 | + | |
| 699 | + switch (ctrl->id) { | |
| 700 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 701 | + ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN, | |
| 702 | + IMX219_REG_VALUE_08BIT, ctrl->val); | |
| 703 | + break; | |
| 704 | + case V4L2_CID_EXPOSURE: | |
| 705 | + ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE, | |
| 706 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 707 | + break; | |
| 708 | + case V4L2_CID_DIGITAL_GAIN: | |
| 709 | + ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN, | |
| 710 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 711 | + break; | |
| 712 | + case V4L2_CID_TEST_PATTERN: | |
| 713 | + ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN, | |
| 714 | + IMX219_REG_VALUE_16BIT, | |
| 715 | + imx219_test_pattern_val[ctrl->val]); | |
| 716 | + break; | |
| 717 | + case V4L2_CID_HFLIP: | |
| 718 | + case V4L2_CID_VFLIP: | |
| 719 | + ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1, | |
| 720 | + imx219->hflip->val | | |
| 721 | + imx219->vflip->val << 1); | |
| 722 | + break; | |
| 723 | + case V4L2_CID_VBLANK: | |
| 724 | + ret = imx219_write_reg(imx219, IMX219_REG_VTS, | |
| 725 | + IMX219_REG_VALUE_16BIT, | |
| 726 | + imx219->mode->height + ctrl->val); | |
| 727 | + break; | |
| 728 | + case V4L2_CID_TEST_PATTERN_RED: | |
| 729 | + ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED, | |
| 730 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 731 | + break; | |
| 732 | + case V4L2_CID_TEST_PATTERN_GREENR: | |
| 733 | + ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR, | |
| 734 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 735 | + break; | |
| 736 | + case V4L2_CID_TEST_PATTERN_BLUE: | |
| 737 | + ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE, | |
| 738 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 739 | + break; | |
| 740 | + case V4L2_CID_TEST_PATTERN_GREENB: | |
| 741 | + ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB, | |
| 742 | + IMX219_REG_VALUE_16BIT, ctrl->val); | |
| 743 | + break; | |
| 744 | + default: | |
| 745 | + dev_info(&client->dev, | |
| 746 | + "ctrl(id:0x%x,val:0x%x) is not handled\n", | |
| 747 | + ctrl->id, ctrl->val); | |
| 748 | + ret = -EINVAL; | |
| 749 | + break; | |
| 750 | + } | |
| 751 | + | |
| 752 | + pm_runtime_put(&client->dev); | |
| 753 | + | |
| 754 | + return ret; | |
| 755 | +} | |
| 756 | + | |
| 757 | +static const struct v4l2_ctrl_ops imx219_ctrl_ops = { | |
| 758 | + .s_ctrl = imx219_set_ctrl, | |
| 759 | +}; | |
| 760 | + | |
| 761 | +static int imx219_enum_mbus_code(struct v4l2_subdev *sd, | |
| 762 | + struct v4l2_subdev_pad_config *cfg, | |
| 763 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 764 | +{ | |
| 765 | + struct imx219 *imx219 = to_imx219(sd); | |
| 766 | + | |
| 767 | + if (code->index >= (ARRAY_SIZE(codes) / 4)) | |
| 768 | + return -EINVAL; | |
| 769 | + | |
| 770 | + code->code = imx219_get_format_code(imx219, codes[code->index * 4]); | |
| 771 | + | |
| 772 | + return 0; | |
| 773 | +} | |
| 774 | + | |
| 775 | +static int imx219_enum_frame_size(struct v4l2_subdev *sd, | |
| 776 | + struct v4l2_subdev_pad_config *cfg, | |
| 777 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 778 | +{ | |
| 779 | + struct imx219 *imx219 = to_imx219(sd); | |
| 780 | + | |
| 781 | + if (fse->index >= ARRAY_SIZE(supported_modes)) | |
| 782 | + return -EINVAL; | |
| 783 | + | |
| 784 | + if (fse->code != imx219_get_format_code(imx219, imx219->fmt.code)) | |
| 785 | + return -EINVAL; | |
| 786 | + | |
| 787 | + fse->min_width = supported_modes[fse->index].width; | |
| 788 | + fse->max_width = fse->min_width; | |
| 789 | + fse->min_height = supported_modes[fse->index].height; | |
| 790 | + fse->max_height = fse->min_height; | |
| 791 | + | |
| 792 | + return 0; | |
| 793 | +} | |
| 794 | + | |
| 795 | +static void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt) | |
| 796 | +{ | |
| 797 | + fmt->colorspace = V4L2_COLORSPACE_SRGB; | |
| 798 | + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); | |
| 799 | + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, | |
| 800 | + fmt->colorspace, | |
| 801 | + fmt->ycbcr_enc); | |
| 802 | + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); | |
| 803 | +} | |
| 804 | + | |
| 805 | +static void imx219_update_pad_format(struct imx219 *imx219, | |
| 806 | + const struct imx219_mode *mode, | |
| 807 | + struct v4l2_subdev_format *fmt) | |
| 808 | +{ | |
| 809 | + fmt->format.width = mode->width; | |
| 810 | + fmt->format.height = mode->height; | |
| 811 | + fmt->format.field = V4L2_FIELD_NONE; | |
| 812 | + imx219_reset_colorspace(&fmt->format); | |
| 813 | +} | |
| 814 | + | |
| 815 | +static int __imx219_get_pad_format(struct imx219 *imx219, | |
| 816 | + struct v4l2_subdev_pad_config *cfg, | |
| 817 | + struct v4l2_subdev_format *fmt) | |
| 818 | +{ | |
| 819 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 820 | + struct v4l2_mbus_framefmt *try_fmt = | |
| 821 | + v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad); | |
| 822 | + /* update the code which could change due to vflip or hflip: */ | |
| 823 | + try_fmt->code = imx219_get_format_code(imx219, try_fmt->code); | |
| 824 | + fmt->format = *try_fmt; | |
| 825 | + } else { | |
| 826 | + imx219_update_pad_format(imx219, imx219->mode, fmt); | |
| 827 | + fmt->format.code = imx219_get_format_code(imx219, | |
| 828 | + imx219->fmt.code); | |
| 829 | + } | |
| 830 | + | |
| 831 | + return 0; | |
| 832 | +} | |
| 833 | + | |
| 834 | +static int imx219_get_pad_format(struct v4l2_subdev *sd, | |
| 835 | + struct v4l2_subdev_pad_config *cfg, | |
| 836 | + struct v4l2_subdev_format *fmt) | |
| 837 | +{ | |
| 838 | + struct imx219 *imx219 = to_imx219(sd); | |
| 839 | + int ret; | |
| 840 | + | |
| 841 | + mutex_lock(&imx219->mutex); | |
| 842 | + ret = __imx219_get_pad_format(imx219, cfg, fmt); | |
| 843 | + mutex_unlock(&imx219->mutex); | |
| 844 | + | |
| 845 | + return ret; | |
| 846 | +} | |
| 847 | + | |
| 848 | +static int imx219_set_pad_format(struct v4l2_subdev *sd, | |
| 849 | + struct v4l2_subdev_pad_config *cfg, | |
| 850 | + struct v4l2_subdev_format *fmt) | |
| 851 | +{ | |
| 852 | + struct imx219 *imx219 = to_imx219(sd); | |
| 853 | + const struct imx219_mode *mode; | |
| 854 | + struct v4l2_mbus_framefmt *framefmt; | |
| 855 | + int exposure_max, exposure_def, hblank; | |
| 856 | + unsigned int i; | |
| 857 | + | |
| 858 | + mutex_lock(&imx219->mutex); | |
| 859 | + | |
| 860 | + for (i = 0; i < ARRAY_SIZE(codes); i++) | |
| 861 | + if (codes[i] == fmt->format.code) | |
| 862 | + break; | |
| 863 | + if (i >= ARRAY_SIZE(codes)) | |
| 864 | + i = 0; | |
| 865 | + | |
| 866 | + /* Bayer order varies with flips */ | |
| 867 | + fmt->format.code = imx219_get_format_code(imx219, codes[i]); | |
| 868 | + | |
| 869 | + mode = v4l2_find_nearest_size(supported_modes, | |
| 870 | + ARRAY_SIZE(supported_modes), | |
| 871 | + width, height, | |
| 872 | + fmt->format.width, fmt->format.height); | |
| 873 | + imx219_update_pad_format(imx219, mode, fmt); | |
| 874 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | |
| 875 | + framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); | |
| 876 | + *framefmt = fmt->format; | |
| 877 | + } else if (imx219->mode != mode || | |
| 878 | + imx219->fmt.code != fmt->format.code) { | |
| 879 | + imx219->fmt = fmt->format; | |
| 880 | + imx219->mode = mode; | |
| 881 | + /* Update limits and set FPS to default */ | |
| 882 | + __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, | |
| 883 | + IMX219_VTS_MAX - mode->height, 1, | |
| 884 | + mode->vts_def - mode->height); | |
| 885 | + __v4l2_ctrl_s_ctrl(imx219->vblank, | |
| 886 | + mode->vts_def - mode->height); | |
| 887 | + /* Update max exposure while meeting expected vblanking */ | |
| 888 | + exposure_max = mode->vts_def - 4; | |
| 889 | + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? | |
| 890 | + exposure_max : IMX219_EXPOSURE_DEFAULT; | |
| 891 | + __v4l2_ctrl_modify_range(imx219->exposure, | |
| 892 | + imx219->exposure->minimum, | |
| 893 | + exposure_max, imx219->exposure->step, | |
| 894 | + exposure_def); | |
| 895 | + /* | |
| 896 | + * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank | |
| 897 | + * depends on mode->width only, and is not changeble in any | |
| 898 | + * way other than changing the mode. | |
| 899 | + */ | |
| 900 | + hblank = IMX219_PPL_DEFAULT - mode->width; | |
| 901 | + __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, | |
| 902 | + hblank); | |
| 903 | + } | |
| 904 | + | |
| 905 | + mutex_unlock(&imx219->mutex); | |
| 906 | + | |
| 907 | + return 0; | |
| 908 | +} | |
| 909 | + | |
| 910 | +static int imx219_set_framefmt(struct imx219 *imx219) | |
| 911 | +{ | |
| 912 | + switch (imx219->fmt.code) { | |
| 913 | + case MEDIA_BUS_FMT_SRGGB8_1X8: | |
| 914 | + case MEDIA_BUS_FMT_SGRBG8_1X8: | |
| 915 | + case MEDIA_BUS_FMT_SGBRG8_1X8: | |
| 916 | + case MEDIA_BUS_FMT_SBGGR8_1X8: | |
| 917 | + return imx219_write_regs(imx219, raw8_framefmt_regs, | |
| 918 | + ARRAY_SIZE(raw8_framefmt_regs)); | |
| 919 | + | |
| 920 | + case MEDIA_BUS_FMT_SRGGB10_1X10: | |
| 921 | + case MEDIA_BUS_FMT_SGRBG10_1X10: | |
| 922 | + case MEDIA_BUS_FMT_SGBRG10_1X10: | |
| 923 | + case MEDIA_BUS_FMT_SBGGR10_1X10: | |
| 924 | + return imx219_write_regs(imx219, raw10_framefmt_regs, | |
| 925 | + ARRAY_SIZE(raw10_framefmt_regs)); | |
| 926 | + } | |
| 927 | + | |
| 928 | + return -EINVAL; | |
| 929 | +} | |
| 930 | + | |
| 931 | +static int imx219_start_streaming(struct imx219 *imx219) | |
| 932 | +{ | |
| 933 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 934 | + const struct imx219_reg_list *reg_list; | |
| 935 | + int ret; | |
| 936 | + | |
| 937 | + /* Apply default values of current mode */ | |
| 938 | + reg_list = &imx219->mode->reg_list; | |
| 939 | + ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); | |
| 940 | + if (ret) { | |
| 941 | + dev_err(&client->dev, "%s failed to set mode\n", __func__); | |
| 942 | + return ret; | |
| 943 | + } | |
| 944 | + | |
| 945 | + ret = imx219_set_framefmt(imx219); | |
| 946 | + if (ret) { | |
| 947 | + dev_err(&client->dev, "%s failed to set frame format: %d\n", | |
| 948 | + __func__, ret); | |
| 949 | + return ret; | |
| 950 | + } | |
| 951 | + | |
| 952 | + /* Apply customized values from user */ | |
| 953 | + ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); | |
| 954 | + if (ret) | |
| 955 | + return ret; | |
| 956 | + | |
| 957 | + /* set stream on register */ | |
| 958 | + return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, | |
| 959 | + IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); | |
| 960 | +} | |
| 961 | + | |
| 962 | +static void imx219_stop_streaming(struct imx219 *imx219) | |
| 963 | +{ | |
| 964 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 965 | + int ret; | |
| 966 | + | |
| 967 | + /* set stream off register */ | |
| 968 | + ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, | |
| 969 | + IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); | |
| 970 | + if (ret) | |
| 971 | + dev_err(&client->dev, "%s failed to set stream\n", __func__); | |
| 972 | +} | |
| 973 | + | |
| 974 | +static int imx219_set_stream(struct v4l2_subdev *sd, int enable) | |
| 975 | +{ | |
| 976 | + struct imx219 *imx219 = to_imx219(sd); | |
| 977 | + struct i2c_client *client = v4l2_get_subdevdata(sd); | |
| 978 | + int ret = 0; | |
| 979 | + | |
| 980 | + mutex_lock(&imx219->mutex); | |
| 981 | + if (imx219->streaming == enable) { | |
| 982 | + mutex_unlock(&imx219->mutex); | |
| 983 | + return 0; | |
| 984 | + } | |
| 985 | + | |
| 986 | + if (enable) { | |
| 987 | + ret = pm_runtime_get_sync(&client->dev); | |
| 988 | + if (ret < 0) { | |
| 989 | + pm_runtime_put_noidle(&client->dev); | |
| 990 | + goto err_unlock; | |
| 991 | + } | |
| 992 | + | |
| 993 | + /* | |
| 994 | + * Apply default & customized values | |
| 995 | + * and then start streaming. | |
| 996 | + */ | |
| 997 | + ret = imx219_start_streaming(imx219); | |
| 998 | + if (ret) | |
| 999 | + goto err_rpm_put; | |
| 1000 | + } else { | |
| 1001 | + imx219_stop_streaming(imx219); | |
| 1002 | + pm_runtime_put(&client->dev); | |
| 1003 | + } | |
| 1004 | + | |
| 1005 | + imx219->streaming = enable; | |
| 1006 | + | |
| 1007 | + /* vflip and hflip cannot change during streaming */ | |
| 1008 | + __v4l2_ctrl_grab(imx219->vflip, enable); | |
| 1009 | + __v4l2_ctrl_grab(imx219->hflip, enable); | |
| 1010 | + | |
| 1011 | + mutex_unlock(&imx219->mutex); | |
| 1012 | + | |
| 1013 | + return ret; | |
| 1014 | + | |
| 1015 | +err_rpm_put: | |
| 1016 | + pm_runtime_put(&client->dev); | |
| 1017 | +err_unlock: | |
| 1018 | + mutex_unlock(&imx219->mutex); | |
| 1019 | + | |
| 1020 | + return ret; | |
| 1021 | +} | |
| 1022 | + | |
| 1023 | +/* Power/clock management functions */ | |
| 1024 | +static int imx219_power_on(struct device *dev) | |
| 1025 | +{ | |
| 1026 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1027 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1028 | + struct imx219 *imx219 = to_imx219(sd); | |
| 1029 | + int ret; | |
| 1030 | + | |
| 1031 | + ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, | |
| 1032 | + imx219->supplies); | |
| 1033 | + if (ret) { | |
| 1034 | + dev_err(&client->dev, "%s: failed to enable regulators\n", | |
| 1035 | + __func__); | |
| 1036 | + return ret; | |
| 1037 | + } | |
| 1038 | + | |
| 1039 | + ret = clk_prepare_enable(imx219->xclk); | |
| 1040 | + if (ret) { | |
| 1041 | + dev_err(&client->dev, "%s: failed to enable clock\n", | |
| 1042 | + __func__); | |
| 1043 | + goto reg_off; | |
| 1044 | + } | |
| 1045 | + | |
| 1046 | + gpiod_set_value_cansleep(imx219->reset_gpio, 1); | |
| 1047 | + usleep_range(IMX219_XCLR_MIN_DELAY_US, | |
| 1048 | + IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); | |
| 1049 | + | |
| 1050 | + return 0; | |
| 1051 | + | |
| 1052 | +reg_off: | |
| 1053 | + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); | |
| 1054 | + | |
| 1055 | + return ret; | |
| 1056 | +} | |
| 1057 | + | |
| 1058 | +static int imx219_power_off(struct device *dev) | |
| 1059 | +{ | |
| 1060 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1061 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1062 | + struct imx219 *imx219 = to_imx219(sd); | |
| 1063 | + | |
| 1064 | + gpiod_set_value_cansleep(imx219->reset_gpio, 0); | |
| 1065 | + regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); | |
| 1066 | + clk_disable_unprepare(imx219->xclk); | |
| 1067 | + | |
| 1068 | + return 0; | |
| 1069 | +} | |
| 1070 | + | |
| 1071 | +static int __maybe_unused imx219_suspend(struct device *dev) | |
| 1072 | +{ | |
| 1073 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1074 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1075 | + struct imx219 *imx219 = to_imx219(sd); | |
| 1076 | + | |
| 1077 | + if (imx219->streaming) | |
| 1078 | + imx219_stop_streaming(imx219); | |
| 1079 | + | |
| 1080 | + return 0; | |
| 1081 | +} | |
| 1082 | + | |
| 1083 | +static int __maybe_unused imx219_resume(struct device *dev) | |
| 1084 | +{ | |
| 1085 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1086 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1087 | + struct imx219 *imx219 = to_imx219(sd); | |
| 1088 | + int ret; | |
| 1089 | + | |
| 1090 | + if (imx219->streaming) { | |
| 1091 | + ret = imx219_start_streaming(imx219); | |
| 1092 | + if (ret) | |
| 1093 | + goto error; | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + return 0; | |
| 1097 | + | |
| 1098 | +error: | |
| 1099 | + imx219_stop_streaming(imx219); | |
| 1100 | + imx219->streaming = 0; | |
| 1101 | + | |
| 1102 | + return ret; | |
| 1103 | +} | |
| 1104 | + | |
| 1105 | +static int imx219_get_regulators(struct imx219 *imx219) | |
| 1106 | +{ | |
| 1107 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 1108 | + unsigned int i; | |
| 1109 | + | |
| 1110 | + for (i = 0; i < IMX219_NUM_SUPPLIES; i++) | |
| 1111 | + imx219->supplies[i].supply = imx219_supply_name[i]; | |
| 1112 | + | |
| 1113 | + return devm_regulator_bulk_get(&client->dev, | |
| 1114 | + IMX219_NUM_SUPPLIES, | |
| 1115 | + imx219->supplies); | |
| 1116 | +} | |
| 1117 | + | |
| 1118 | +/* Verify chip ID */ | |
| 1119 | +static int imx219_identify_module(struct imx219 *imx219) | |
| 1120 | +{ | |
| 1121 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 1122 | + int ret; | |
| 1123 | + u32 val; | |
| 1124 | + | |
| 1125 | + ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID, | |
| 1126 | + IMX219_REG_VALUE_16BIT, &val); | |
| 1127 | + if (ret) { | |
| 1128 | + dev_err(&client->dev, "failed to read chip id %x\n", | |
| 1129 | + IMX219_CHIP_ID); | |
| 1130 | + return ret; | |
| 1131 | + } | |
| 1132 | + | |
| 1133 | + if (val != IMX219_CHIP_ID) { | |
| 1134 | + dev_err(&client->dev, "chip id mismatch: %x!=%x\n", | |
| 1135 | + IMX219_CHIP_ID, val); | |
| 1136 | + return -EIO; | |
| 1137 | + } | |
| 1138 | + | |
| 1139 | + return 0; | |
| 1140 | +} | |
| 1141 | + | |
| 1142 | +static const struct v4l2_subdev_core_ops imx219_core_ops = { | |
| 1143 | + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
| 1144 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1145 | +}; | |
| 1146 | + | |
| 1147 | +static const struct v4l2_subdev_video_ops imx219_video_ops = { | |
| 1148 | + .s_stream = imx219_set_stream, | |
| 1149 | +}; | |
| 1150 | + | |
| 1151 | +static const struct v4l2_subdev_pad_ops imx219_pad_ops = { | |
| 1152 | + .enum_mbus_code = imx219_enum_mbus_code, | |
| 1153 | + .get_fmt = imx219_get_pad_format, | |
| 1154 | + .set_fmt = imx219_set_pad_format, | |
| 1155 | + .enum_frame_size = imx219_enum_frame_size, | |
| 1156 | +}; | |
| 1157 | + | |
| 1158 | +static const struct v4l2_subdev_ops imx219_subdev_ops = { | |
| 1159 | + .core = &imx219_core_ops, | |
| 1160 | + .video = &imx219_video_ops, | |
| 1161 | + .pad = &imx219_pad_ops, | |
| 1162 | +}; | |
| 1163 | + | |
| 1164 | +static const struct v4l2_subdev_internal_ops imx219_internal_ops = { | |
| 1165 | + .open = imx219_open, | |
| 1166 | +}; | |
| 1167 | + | |
| 1168 | +/* Initialize control handlers */ | |
| 1169 | +static int imx219_init_controls(struct imx219 *imx219) | |
| 1170 | +{ | |
| 1171 | + struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); | |
| 1172 | + struct v4l2_ctrl_handler *ctrl_hdlr; | |
| 1173 | + unsigned int height = imx219->mode->height; | |
| 1174 | + int exposure_max, exposure_def, hblank; | |
| 1175 | + int i, ret; | |
| 1176 | + | |
| 1177 | + ctrl_hdlr = &imx219->ctrl_handler; | |
| 1178 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); | |
| 1179 | + if (ret) | |
| 1180 | + return ret; | |
| 1181 | + | |
| 1182 | + mutex_init(&imx219->mutex); | |
| 1183 | + ctrl_hdlr->lock = &imx219->mutex; | |
| 1184 | + | |
| 1185 | + /* By default, PIXEL_RATE is read only */ | |
| 1186 | + imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1187 | + V4L2_CID_PIXEL_RATE, | |
| 1188 | + IMX219_PIXEL_RATE, | |
| 1189 | + IMX219_PIXEL_RATE, 1, | |
| 1190 | + IMX219_PIXEL_RATE); | |
| 1191 | + | |
| 1192 | + /* Initial vblank/hblank/exposure parameters based on current mode */ | |
| 1193 | + imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1194 | + V4L2_CID_VBLANK, IMX219_VBLANK_MIN, | |
| 1195 | + IMX219_VTS_MAX - height, 1, | |
| 1196 | + imx219->mode->vts_def - height); | |
| 1197 | + hblank = IMX219_PPL_DEFAULT - imx219->mode->width; | |
| 1198 | + imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1199 | + V4L2_CID_HBLANK, hblank, hblank, | |
| 1200 | + 1, hblank); | |
| 1201 | + if (imx219->hblank) | |
| 1202 | + imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1203 | + exposure_max = imx219->mode->vts_def - 4; | |
| 1204 | + exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? | |
| 1205 | + exposure_max : IMX219_EXPOSURE_DEFAULT; | |
| 1206 | + imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1207 | + V4L2_CID_EXPOSURE, | |
| 1208 | + IMX219_EXPOSURE_MIN, exposure_max, | |
| 1209 | + IMX219_EXPOSURE_STEP, | |
| 1210 | + exposure_def); | |
| 1211 | + | |
| 1212 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, | |
| 1213 | + IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, | |
| 1214 | + IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); | |
| 1215 | + | |
| 1216 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, | |
| 1217 | + IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, | |
| 1218 | + IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); | |
| 1219 | + | |
| 1220 | + imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1221 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 1222 | + if (imx219->hflip) | |
| 1223 | + imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | |
| 1224 | + | |
| 1225 | + imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1226 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 1227 | + if (imx219->vflip) | |
| 1228 | + imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | |
| 1229 | + | |
| 1230 | + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1231 | + V4L2_CID_TEST_PATTERN, | |
| 1232 | + ARRAY_SIZE(imx219_test_pattern_menu) - 1, | |
| 1233 | + 0, 0, imx219_test_pattern_menu); | |
| 1234 | + for (i = 0; i < 4; i++) { | |
| 1235 | + /* | |
| 1236 | + * The assumption is that | |
| 1237 | + * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 | |
| 1238 | + * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 | |
| 1239 | + * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 | |
| 1240 | + */ | |
| 1241 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, | |
| 1242 | + V4L2_CID_TEST_PATTERN_RED + i, | |
| 1243 | + IMX219_TESTP_COLOUR_MIN, | |
| 1244 | + IMX219_TESTP_COLOUR_MAX, | |
| 1245 | + IMX219_TESTP_COLOUR_STEP, | |
| 1246 | + IMX219_TESTP_COLOUR_MAX); | |
| 1247 | + /* The "Solid color" pattern is white by default */ | |
| 1248 | + } | |
| 1249 | + | |
| 1250 | + if (ctrl_hdlr->error) { | |
| 1251 | + ret = ctrl_hdlr->error; | |
| 1252 | + dev_err(&client->dev, "%s control init failed (%d)\n", | |
| 1253 | + __func__, ret); | |
| 1254 | + goto error; | |
| 1255 | + } | |
| 1256 | + | |
| 1257 | + imx219->sd.ctrl_handler = ctrl_hdlr; | |
| 1258 | + | |
| 1259 | + return 0; | |
| 1260 | + | |
| 1261 | +error: | |
| 1262 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1263 | + mutex_destroy(&imx219->mutex); | |
| 1264 | + | |
| 1265 | + return ret; | |
| 1266 | +} | |
| 1267 | + | |
| 1268 | +static void imx219_free_controls(struct imx219 *imx219) | |
| 1269 | +{ | |
| 1270 | + v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); | |
| 1271 | + mutex_destroy(&imx219->mutex); | |
| 1272 | +} | |
| 1273 | + | |
| 1274 | +static int imx219_check_hwcfg(struct device *dev) | |
| 1275 | +{ | |
| 1276 | + struct fwnode_handle *endpoint; | |
| 1277 | + struct v4l2_fwnode_endpoint ep_cfg = { | |
| 1278 | + .bus_type = V4L2_MBUS_CSI2_DPHY | |
| 1279 | + }; | |
| 1280 | + int ret = -EINVAL; | |
| 1281 | + | |
| 1282 | + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); | |
| 1283 | + if (!endpoint) { | |
| 1284 | + dev_err(dev, "endpoint node not found\n"); | |
| 1285 | + return -EINVAL; | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { | |
| 1289 | + dev_err(dev, "could not parse endpoint\n"); | |
| 1290 | + goto error_out; | |
| 1291 | + } | |
| 1292 | + | |
| 1293 | + /* Check the number of MIPI CSI2 data lanes */ | |
| 1294 | + if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { | |
| 1295 | + dev_err(dev, "only 2 data lanes are currently supported\n"); | |
| 1296 | + goto error_out; | |
| 1297 | + } | |
| 1298 | + | |
| 1299 | + /* Check the link frequency set in device tree */ | |
| 1300 | + if (!ep_cfg.nr_of_link_frequencies) { | |
| 1301 | + dev_err(dev, "link-frequency property not found in DT\n"); | |
| 1302 | + goto error_out; | |
| 1303 | + } | |
| 1304 | + | |
| 1305 | + if (ep_cfg.nr_of_link_frequencies != 1 || | |
| 1306 | + ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) { | |
| 1307 | + dev_err(dev, "Link frequency not supported: %lld\n", | |
| 1308 | + ep_cfg.link_frequencies[0]); | |
| 1309 | + goto error_out; | |
| 1310 | + } | |
| 1311 | + | |
| 1312 | + ret = 0; | |
| 1313 | + | |
| 1314 | +error_out: | |
| 1315 | + v4l2_fwnode_endpoint_free(&ep_cfg); | |
| 1316 | + fwnode_handle_put(endpoint); | |
| 1317 | + | |
| 1318 | + return ret; | |
| 1319 | +} | |
| 1320 | + | |
| 1321 | +static int imx219_probe(struct i2c_client *client) | |
| 1322 | +{ | |
| 1323 | + struct device *dev = &client->dev; | |
| 1324 | + struct imx219 *imx219; | |
| 1325 | + int ret; | |
| 1326 | + | |
| 1327 | + imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); | |
| 1328 | + if (!imx219) | |
| 1329 | + return -ENOMEM; | |
| 1330 | + | |
| 1331 | + v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); | |
| 1332 | + | |
| 1333 | + /* Check the hardware configuration in device tree */ | |
| 1334 | + if (imx219_check_hwcfg(dev)) | |
| 1335 | + return -EINVAL; | |
| 1336 | + | |
| 1337 | + /* Get system clock (xclk) */ | |
| 1338 | + imx219->xclk = devm_clk_get(dev, NULL); | |
| 1339 | + if (IS_ERR(imx219->xclk)) { | |
| 1340 | + dev_err(dev, "failed to get xclk\n"); | |
| 1341 | + return PTR_ERR(imx219->xclk); | |
| 1342 | + } | |
| 1343 | + | |
| 1344 | + imx219->xclk_freq = clk_get_rate(imx219->xclk); | |
| 1345 | + if (imx219->xclk_freq != IMX219_XCLK_FREQ) { | |
| 1346 | + dev_err(dev, "xclk frequency not supported: %d Hz\n", | |
| 1347 | + imx219->xclk_freq); | |
| 1348 | + return -EINVAL; | |
| 1349 | + } | |
| 1350 | + | |
| 1351 | + ret = imx219_get_regulators(imx219); | |
| 1352 | + if (ret) { | |
| 1353 | + dev_err(dev, "failed to get regulators\n"); | |
| 1354 | + return ret; | |
| 1355 | + } | |
| 1356 | + | |
| 1357 | + /* Request optional enable pin */ | |
| 1358 | + imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", | |
| 1359 | + GPIOD_OUT_HIGH); | |
| 1360 | + | |
| 1361 | + /* | |
| 1362 | + * The sensor must be powered for imx219_identify_module() | |
| 1363 | + * to be able to read the CHIP_ID register | |
| 1364 | + */ | |
| 1365 | + ret = imx219_power_on(dev); | |
| 1366 | + if (ret) | |
| 1367 | + return ret; | |
| 1368 | + | |
| 1369 | + ret = imx219_identify_module(imx219); | |
| 1370 | + if (ret) | |
| 1371 | + goto error_power_off; | |
| 1372 | + | |
| 1373 | + /* Set default mode to max resolution */ | |
| 1374 | + imx219->mode = &supported_modes[0]; | |
| 1375 | + | |
| 1376 | + /* sensor doesn't enter LP-11 state upon power up until and unless | |
| 1377 | + * streaming is started, so upon power up switch the modes to: | |
| 1378 | + * streaming -> standby | |
| 1379 | + */ | |
| 1380 | + ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, | |
| 1381 | + IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); | |
| 1382 | + if (ret < 0) | |
| 1383 | + goto error_power_off; | |
| 1384 | + usleep_range(100, 110); | |
| 1385 | + | |
| 1386 | + /* put sensor back to standby mode */ | |
| 1387 | + ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, | |
| 1388 | + IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); | |
| 1389 | + if (ret < 0) | |
| 1390 | + goto error_power_off; | |
| 1391 | + usleep_range(100, 110); | |
| 1392 | + | |
| 1393 | + ret = imx219_init_controls(imx219); | |
| 1394 | + if (ret) | |
| 1395 | + goto error_power_off; | |
| 1396 | + | |
| 1397 | + /* Initialize subdev */ | |
| 1398 | + imx219->sd.internal_ops = &imx219_internal_ops; | |
| 1399 | + imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1400 | + imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1401 | + | |
| 1402 | + /* Initialize source pad */ | |
| 1403 | + imx219->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1404 | + | |
| 1405 | + /* Initialize default format */ | |
| 1406 | + imx219_set_default_format(imx219); | |
| 1407 | + | |
| 1408 | + ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); | |
| 1409 | + if (ret) { | |
| 1410 | + dev_err(dev, "failed to init entity pads: %d\n", ret); | |
| 1411 | + goto error_handler_free; | |
| 1412 | + } | |
| 1413 | + | |
| 1414 | + ret = v4l2_async_register_subdev_sensor_common(&imx219->sd); | |
| 1415 | + if (ret < 0) { | |
| 1416 | + dev_err(dev, "failed to register sensor sub-device: %d\n", ret); | |
| 1417 | + goto error_media_entity; | |
| 1418 | + } | |
| 1419 | + | |
| 1420 | + /* Enable runtime PM and turn off the device */ | |
| 1421 | + pm_runtime_set_active(dev); | |
| 1422 | + pm_runtime_enable(dev); | |
| 1423 | + pm_runtime_idle(dev); | |
| 1424 | + | |
| 1425 | + return 0; | |
| 1426 | + | |
| 1427 | +error_media_entity: | |
| 1428 | + media_entity_cleanup(&imx219->sd.entity); | |
| 1429 | + | |
| 1430 | +error_handler_free: | |
| 1431 | + imx219_free_controls(imx219); | |
| 1432 | + | |
| 1433 | +error_power_off: | |
| 1434 | + imx219_power_off(dev); | |
| 1435 | + | |
| 1436 | + return ret; | |
| 1437 | +} | |
| 1438 | + | |
| 1439 | +static int imx219_remove(struct i2c_client *client) | |
| 1440 | +{ | |
| 1441 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1442 | + struct imx219 *imx219 = to_imx219(sd); | |
| 1443 | + | |
| 1444 | + v4l2_async_unregister_subdev(sd); | |
| 1445 | + media_entity_cleanup(&sd->entity); | |
| 1446 | + imx219_free_controls(imx219); | |
| 1447 | + | |
| 1448 | + pm_runtime_disable(&client->dev); | |
| 1449 | + if (!pm_runtime_status_suspended(&client->dev)) | |
| 1450 | + imx219_power_off(&client->dev); | |
| 1451 | + pm_runtime_set_suspended(&client->dev); | |
| 1452 | + | |
| 1453 | + return 0; | |
| 1454 | +} | |
| 1455 | + | |
| 1456 | +static const struct of_device_id imx219_dt_ids[] = { | |
| 1457 | + { .compatible = "sony,imx219" }, | |
| 1458 | + { /* sentinel */ } | |
| 1459 | +}; | |
| 1460 | +MODULE_DEVICE_TABLE(of, imx219_dt_ids); | |
| 1461 | + | |
| 1462 | +static const struct dev_pm_ops imx219_pm_ops = { | |
| 1463 | + SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume) | |
| 1464 | + SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL) | |
| 1465 | +}; | |
| 1466 | + | |
| 1467 | +static struct i2c_driver imx219_i2c_driver = { | |
| 1468 | + .driver = { | |
| 1469 | + .name = "imx219", | |
| 1470 | + .of_match_table = imx219_dt_ids, | |
| 1471 | + .pm = &imx219_pm_ops, | |
| 1472 | + }, | |
| 1473 | + .probe_new = imx219_probe, | |
| 1474 | + .remove = imx219_remove, | |
| 1475 | +}; | |
| 1476 | + | |
| 1477 | +module_i2c_driver(imx219_i2c_driver); | |
| 1478 | + | |
| 1479 | +MODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com"); | |
| 1480 | +MODULE_DESCRIPTION("Sony IMX219 sensor driver"); | |
| 1481 | +MODULE_LICENSE("GPL v2"); | |
| @@ -63,6 +63,10 @@ · 62 unmodified lines | ||
| 63 | 63 | #define OV5675_TEST_PATTERN_ENABLE BIT(7) |
| 64 | 64 | #define OV5675_TEST_PATTERN_BAR_SHIFT 2 |
| 65 | 65 | |
| 66 | +/* Flip Mirror Controls from sensor */ | |
| 67 | +#define OV5675_REG_FORMAT1 0x3820 | |
| 68 | +#define OV5675_REG_FORMAT2 0x373d | |
| 69 | + | |
| 66 | 70 | #define to_ov5675(_sd) container_of(_sd, struct ov5675, sd) |
| 67 | 71 | |
| 68 | 72 | enum { |
| @@ -314,21 +318,21 @@ static const struct ov5675_reg mode_1296x972_regs[] = { · 245 unmodified lines | ||
| 314 | 318 | {0x3800, 0x00}, |
| 315 | 319 | {0x3801, 0x00}, |
| 316 | 320 | {0x3802, 0x00}, |
| 317 | − {0x3803, 0xf4}, | |
| 321 | + {0x3803, 0x00}, | |
| 318 | 322 | {0x3804, 0x0a}, |
| 319 | 323 | {0x3805, 0x3f}, |
| 320 | − {0x3806, 0x06}, | |
| 321 | − {0x3807, 0xb3}, | |
| 324 | + {0x3806, 0x07}, | |
| 325 | + {0x3807, 0xb7}, | |
| 322 | 326 | {0x3808, 0x05}, |
| 323 | − {0x3809, 0x00}, | |
| 324 | − {0x380a, 0x02}, | |
| 325 | − {0x380b, 0xd0}, | |
| 327 | + {0x3809, 0x10}, | |
| 328 | + {0x380a, 0x03}, | |
| 329 | + {0x380b, 0xcc}, | |
| 326 | 330 | {0x380c, 0x02}, |
| 327 | 331 | {0x380d, 0xee}, |
| 328 | 332 | {0x380e, 0x07}, |
| 329 | − {0x380f, 0xe4}, | |
| 330 | − {0x3811, 0x10}, | |
| 331 | − {0x3813, 0x09}, | |
| 333 | + {0x380f, 0xd0}, | |
| 334 | + {0x3811, 0x08}, | |
| 335 | + {0x3813, 0x0d}, | |
| 332 | 336 | {0x3814, 0x03}, |
| 333 | 337 | {0x3815, 0x01}, |
| 334 | 338 | {0x3816, 0x03}, |
| @@ -604,6 +608,53 @@ static int ov5675_test_pattern(struct ov5675 *ov5675, u32 pattern) · 269 unmodified lines | ||
| 604 | 608 | OV5675_REG_VALUE_08BIT, pattern); |
| 605 | 609 | } |
| 606 | 610 | |
| 611 | +/* | |
| 612 | + * OV5675 supports keeping the pixel order by mirror and flip function | |
| 613 | + * The Bayer order isn't affected by the flip controls | |
| 614 | + */ | |
| 615 | +static int ov5675_set_ctrl_hflip(struct ov5675 *ov5675, u32 ctrl_val) | |
| 616 | +{ | |
| 617 | + int ret; | |
| 618 | + u32 val; | |
| 619 | + | |
| 620 | + ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1, | |
| 621 | + OV5675_REG_VALUE_08BIT, &val); | |
| 622 | + if (ret) | |
| 623 | + return ret; | |
| 624 | + | |
| 625 | + return ov5675_write_reg(ov5675, OV5675_REG_FORMAT1, | |
| 626 | + OV5675_REG_VALUE_08BIT, | |
| 627 | + ctrl_val ? val & ~BIT(3) : val); | |
| 628 | +} | |
| 629 | + | |
| 630 | +static int ov5675_set_ctrl_vflip(struct ov5675 *ov5675, u8 ctrl_val) | |
| 631 | +{ | |
| 632 | + int ret; | |
| 633 | + u32 val; | |
| 634 | + | |
| 635 | + ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT1, | |
| 636 | + OV5675_REG_VALUE_08BIT, &val); | |
| 637 | + if (ret) | |
| 638 | + return ret; | |
| 639 | + | |
| 640 | + ret = ov5675_write_reg(ov5675, OV5675_REG_FORMAT1, | |
| 641 | + OV5675_REG_VALUE_08BIT, | |
| 642 | + ctrl_val ? val | BIT(4) | BIT(5) : val); | |
| 643 | + | |
| 644 | + if (ret) | |
| 645 | + return ret; | |
| 646 | + | |
| 647 | + ret = ov5675_read_reg(ov5675, OV5675_REG_FORMAT2, | |
| 648 | + OV5675_REG_VALUE_08BIT, &val); | |
| 649 | + | |
| 650 | + if (ret) | |
| 651 | + return ret; | |
| 652 | + | |
| 653 | + return ov5675_write_reg(ov5675, OV5675_REG_FORMAT2, | |
| 654 | + OV5675_REG_VALUE_08BIT, | |
| 655 | + ctrl_val ? val | BIT(1) : val); | |
| 656 | +} | |
| 657 | + | |
| 607 | 658 | static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) |
| 608 | 659 | { |
| 609 | 660 | struct ov5675 *ov5675 = container_of(ctrl->handler, |
| @@ -654,6 +705,14 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) · 44 unmodified lines | ||
| 654 | 705 | ret = ov5675_test_pattern(ov5675, ctrl->val); |
| 655 | 706 | break; |
| 656 | 707 | |
| 708 | + case V4L2_CID_HFLIP: | |
| 709 | + ov5675_set_ctrl_hflip(ov5675, ctrl->val); | |
| 710 | + break; | |
| 711 | + | |
| 712 | + case V4L2_CID_VFLIP: | |
| 713 | + ov5675_set_ctrl_vflip(ov5675, ctrl->val); | |
| 714 | + break; | |
| 715 | + | |
| 657 | 716 | default: |
| 658 | 717 | ret = -EINVAL; |
| 659 | 718 | break; |
| @@ -722,6 +781,11 @@ static int ov5675_init_controls(struct ov5675 *ov5675) · 62 unmodified lines | ||
| 722 | 781 | V4L2_CID_TEST_PATTERN, |
| 723 | 782 | ARRAY_SIZE(ov5675_test_pattern_menu) - 1, |
| 724 | 783 | 0, 0, ov5675_test_pattern_menu); |
| 784 | + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, | |
| 785 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 786 | + v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, | |
| 787 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 788 | + | |
| 725 | 789 | if (ctrl_hdlr->error) |
| 726 | 790 | return ctrl_hdlr->error; |
| 727 | 791 | |
| @@ -971,16 +971,9 @@ unlock_and_return: · 970 unmodified lines | ||
| 971 | 971 | return ret; |
| 972 | 972 | } |
| 973 | 973 | |
| 974 | −/* Calculate the delay in us by clock rate and clock cycles */ | |
| 975 | −static inline u32 ov5695_cal_delay(u32 cycles) | |
| 976 | −{ | |
| 977 | − return DIV_ROUND_UP(cycles, OV5695_XVCLK_FREQ / 1000 / 1000); | |
| 978 | −} | |
| 979 | − | |
| 980 | 974 | static int __ov5695_power_on(struct ov5695 *ov5695) |
| 981 | 975 | { |
| 982 | − int ret; | |
| 983 | − u32 delay_us; | |
| 976 | + int i, ret; | |
| 984 | 977 | struct device *dev = &ov5695->client->dev; |
| 985 | 978 | |
| 986 | 979 | ret = clk_prepare_enable(ov5695->xvclk); |
| @@ -991,21 +984,28 @@ static int __ov5695_power_on(struct ov5695 *ov5695) · 4 unmodified lines | ||
| 991 | 984 | |
| 992 | 985 | gpiod_set_value_cansleep(ov5695->reset_gpio, 1); |
| 993 | 986 | |
| 994 | − ret = regulator_bulk_enable(OV5695_NUM_SUPPLIES, ov5695->supplies); | |
| 995 | − if (ret < 0) { | |
| 996 | − dev_err(dev, "Failed to enable regulators\n"); | |
| 997 | − goto disable_clk; | |
| 987 | + /* | |
| 988 | + * The hardware requires the regulators to be powered on in order, | |
| 989 | + * so enable them one by one. | |
| 990 | + */ | |
| 991 | + for (i = 0; i < OV5695_NUM_SUPPLIES; i++) { | |
| 992 | + ret = regulator_enable(ov5695->supplies[i].consumer); | |
| 993 | + if (ret) { | |
| 994 | + dev_err(dev, "Failed to enable %s: %d\n", | |
| 995 | + ov5695->supplies[i].supply, ret); | |
| 996 | + goto disable_reg_clk; | |
| 997 | + } | |
| 998 | 998 | } |
| 999 | 999 | |
| 1000 | 1000 | gpiod_set_value_cansleep(ov5695->reset_gpio, 0); |
| 1001 | 1001 | |
| 1002 | − /* 8192 cycles prior to first SCCB transaction */ | |
| 1003 | − delay_us = ov5695_cal_delay(8192); | |
| 1004 | − usleep_range(delay_us, delay_us * 2); | |
| 1002 | + usleep_range(1000, 1200); | |
| 1005 | 1003 | |
| 1006 | 1004 | return 0; |
| 1007 | 1005 | |
| 1008 | −disable_clk: | |
| 1006 | +disable_reg_clk: | |
| 1007 | + for (--i; i >= 0; i--) | |
| 1008 | + regulator_disable(ov5695->supplies[i].consumer); | |
| 1009 | 1009 | clk_disable_unprepare(ov5695->xvclk); |
| 1010 | 1010 | |
| 1011 | 1011 | return ret; |
| @@ -1013,9 +1013,22 @@ disable_clk: · 1 unmodified line | ||
| 1013 | 1013 | |
| 1014 | 1014 | static void __ov5695_power_off(struct ov5695 *ov5695) |
| 1015 | 1015 | { |
| 1016 | + struct device *dev = &ov5695->client->dev; | |
| 1017 | + int i, ret; | |
| 1018 | + | |
| 1016 | 1019 | clk_disable_unprepare(ov5695->xvclk); |
| 1017 | 1020 | gpiod_set_value_cansleep(ov5695->reset_gpio, 1); |
| 1018 | − regulator_bulk_disable(OV5695_NUM_SUPPLIES, ov5695->supplies); | |
| 1021 | + | |
| 1022 | + /* | |
| 1023 | + * The hardware requires the regulators to be powered off in order, | |
| 1024 | + * so disable them one by one. | |
| 1025 | + */ | |
| 1026 | + for (i = OV5695_NUM_SUPPLIES - 1; i >= 0; i--) { | |
| 1027 | + ret = regulator_disable(ov5695->supplies[i].consumer); | |
| 1028 | + if (ret) | |
| 1029 | + dev_err(dev, "Failed to disable %s: %d\n", | |
| 1030 | + ov5695->supplies[i].supply, ret); | |
| 1031 | + } | |
| 1019 | 1032 | } |
| 1020 | 1033 | |
| 1021 | 1034 | static int __maybe_unused ov5695_runtime_resume(struct device *dev) |
| @@ -1285,7 +1298,7 @@ static int ov5695_probe(struct i2c_client *client, · 263 unmodified lines | ||
| 1285 | 1298 | if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ) |
| 1286 | 1299 | dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); |
| 1287 | 1300 | |
| 1288 | − ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 1301 | + ov5695->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | |
| 1289 | 1302 | if (IS_ERR(ov5695->reset_gpio)) { |
| 1290 | 1303 | dev_err(dev, "Failed to get reset-gpios\n"); |
| 1291 | 1304 | return -EINVAL; |
| @@ -547,7 +547,7 @@ int s5c73m3_init_controls(struct s5c73m3 *state) · 546 unmodified lines | ||
| 547 | 547 | V4L2_CTRL_FLAG_UPDATE; |
| 548 | 548 | v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, 0, false); |
| 549 | 549 | ctrls->af_status->flags |= V4L2_CTRL_FLAG_VOLATILE; |
| 550 | − v4l2_ctrl_cluster(6, &ctrls->focus_auto); | |
| 550 | + v4l2_ctrl_cluster(5, &ctrls->focus_auto); | |
| 551 | 551 | |
| 552 | 552 | state->sensor_sd.ctrl_handler = hdl; |
| 553 | 553 | |
| @@ -57,6 +57,45 @@ static const struct smiapp_module_ident smiapp_module_idents[] = { · 56 unmodified lines | ||
| 57 | 57 | * |
| 58 | 58 | */ |
| 59 | 59 | |
| 60 | +static u32 smiapp_get_limit(struct smiapp_sensor *sensor, | |
| 61 | + unsigned int limit) | |
| 62 | +{ | |
| 63 | + if (WARN_ON(limit >= SMIAPP_LIMIT_LAST)) | |
| 64 | + return 1; | |
| 65 | + | |
| 66 | + return sensor->limits[limit]; | |
| 67 | +} | |
| 68 | + | |
| 69 | +#define SMIA_LIM(sensor, limit) \ | |
| 70 | + smiapp_get_limit(sensor, SMIAPP_LIMIT_##limit) | |
| 71 | + | |
| 72 | +static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor) | |
| 73 | +{ | |
| 74 | + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | |
| 75 | + unsigned int i; | |
| 76 | + int rval; | |
| 77 | + | |
| 78 | + for (i = 0; i < SMIAPP_LIMIT_LAST; i++) { | |
| 79 | + u32 val; | |
| 80 | + | |
| 81 | + rval = smiapp_read( | |
| 82 | + sensor, smiapp_reg_limits[i].addr, &val); | |
| 83 | + if (rval) | |
| 84 | + return rval; | |
| 85 | + | |
| 86 | + sensor->limits[i] = val; | |
| 87 | + | |
| 88 | + dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", | |
| 89 | + smiapp_reg_limits[i].addr, | |
| 90 | + smiapp_reg_limits[i].what, val, val); | |
| 91 | + } | |
| 92 | + | |
| 93 | + if (SMIA_LIM(sensor, SCALER_N_MIN) == 0) | |
| 94 | + smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16); | |
| 95 | + | |
| 96 | + return 0; | |
| 97 | +} | |
| 98 | + | |
| 60 | 99 | static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) |
| 61 | 100 | { |
| 62 | 101 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
| @@ -240,35 +279,35 @@ static int smiapp_pll_try(struct smiapp_sensor *sensor, · 177 unmodified lines | ||
| 240 | 279 | { |
| 241 | 280 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
| 242 | 281 | struct smiapp_pll_limits lim = { |
| 243 | − .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV], | |
| 244 | − .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV], | |
| 245 | − .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ], | |
| 246 | − .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ], | |
| 247 | − .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER], | |
| 248 | − .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER], | |
| 249 | − .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ], | |
| 250 | − .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ], | |
| 251 | − | |
| 252 | − .op.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], | |
| 253 | − .op.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], | |
| 254 | − .op.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], | |
| 255 | − .op.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], | |
| 256 | − .op.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], | |
| 257 | − .op.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], | |
| 258 | − .op.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], | |
| 259 | − .op.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], | |
| 260 | − | |
| 261 | − .vt.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], | |
| 262 | − .vt.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], | |
| 263 | − .vt.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], | |
| 264 | − .vt.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], | |
| 265 | − .vt.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], | |
| 266 | − .vt.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], | |
| 267 | − .vt.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], | |
| 268 | − .vt.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], | |
| 269 | − | |
| 270 | − .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN], | |
| 271 | − .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK], | |
| 282 | + .min_pre_pll_clk_div = SMIA_LIM(sensor, MIN_PRE_PLL_CLK_DIV), | |
| 283 | + .max_pre_pll_clk_div = SMIA_LIM(sensor, MAX_PRE_PLL_CLK_DIV), | |
| 284 | + .min_pll_ip_freq_hz = SMIA_LIM(sensor, MIN_PLL_IP_FREQ_HZ), | |
| 285 | + .max_pll_ip_freq_hz = SMIA_LIM(sensor, MAX_PLL_IP_FREQ_HZ), | |
| 286 | + .min_pll_multiplier = SMIA_LIM(sensor, MIN_PLL_MULTIPLIER), | |
| 287 | + .max_pll_multiplier = SMIA_LIM(sensor, MAX_PLL_MULTIPLIER), | |
| 288 | + .min_pll_op_freq_hz = SMIA_LIM(sensor, MIN_PLL_OP_FREQ_HZ), | |
| 289 | + .max_pll_op_freq_hz = SMIA_LIM(sensor, MAX_PLL_OP_FREQ_HZ), | |
| 290 | + | |
| 291 | + .op.min_sys_clk_div = SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV), | |
| 292 | + .op.max_sys_clk_div = SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV), | |
| 293 | + .op.min_pix_clk_div = SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV), | |
| 294 | + .op.max_pix_clk_div = SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV), | |
| 295 | + .op.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_SYS_CLK_FREQ_HZ), | |
| 296 | + .op.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_SYS_CLK_FREQ_HZ), | |
| 297 | + .op.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_OP_PIX_CLK_FREQ_HZ), | |
| 298 | + .op.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_OP_PIX_CLK_FREQ_HZ), | |
| 299 | + | |
| 300 | + .vt.min_sys_clk_div = SMIA_LIM(sensor, MIN_VT_SYS_CLK_DIV), | |
| 301 | + .vt.max_sys_clk_div = SMIA_LIM(sensor, MAX_VT_SYS_CLK_DIV), | |
| 302 | + .vt.min_pix_clk_div = SMIA_LIM(sensor, MIN_VT_PIX_CLK_DIV), | |
| 303 | + .vt.max_pix_clk_div = SMIA_LIM(sensor, MAX_VT_PIX_CLK_DIV), | |
| 304 | + .vt.min_sys_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_SYS_CLK_FREQ_HZ), | |
| 305 | + .vt.max_sys_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_SYS_CLK_FREQ_HZ), | |
| 306 | + .vt.min_pix_clk_freq_hz = SMIA_LIM(sensor, MIN_VT_PIX_CLK_FREQ_HZ), | |
| 307 | + .vt.max_pix_clk_freq_hz = SMIA_LIM(sensor, MAX_VT_PIX_CLK_FREQ_HZ), | |
| 308 | + | |
| 309 | + .min_line_length_pck_bin = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN), | |
| 310 | + .min_line_length_pck = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK), | |
| 272 | 311 | }; |
| 273 | 312 | |
| 274 | 313 | return smiapp_pll_calculate(&client->dev, &lim, pll); |
| @@ -311,7 +350,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) · 36 unmodified lines | ||
| 311 | 350 | |
| 312 | 351 | max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height |
| 313 | 352 | + sensor->vblank->val |
| 314 | − - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN]; | |
| 353 | + - SMIA_LIM(sensor, COARSE_INTEGRATION_TIME_MAX_MARGIN); | |
| 315 | 354 | |
| 316 | 355 | __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); |
| 317 | 356 | } |
| @@ -568,10 +607,10 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) · 250 unmodified lines | ||
| 568 | 607 | sensor->analog_gain = v4l2_ctrl_new_std( |
| 569 | 608 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, |
| 570 | 609 | V4L2_CID_ANALOGUE_GAIN, |
| 571 | − sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN], | |
| 572 | − sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX], | |
| 573 | − max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U), | |
| 574 | − sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]); | |
| 610 | + SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN), | |
| 611 | + SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MAX), | |
| 612 | + max(SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_STEP), 1U), | |
| 613 | + SMIA_LIM(sensor, ANALOGUE_GAIN_CODE_MIN)); | |
| 575 | 614 | |
| 576 | 615 | /* Exposure limits will be updated soon, use just something here. */ |
| 577 | 616 | sensor->exposure = v4l2_ctrl_new_std( |
| @@ -677,45 +716,6 @@ static void smiapp_free_controls(struct smiapp_sensor *sensor) · 99 unmodified lines | ||
| 677 | 716 | v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); |
| 678 | 717 | } |
| 679 | 718 | |
| 680 | −static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit, | |
| 681 | − unsigned int n) | |
| 682 | −{ | |
| 683 | − struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | |
| 684 | − unsigned int i; | |
| 685 | − u32 val; | |
| 686 | − int rval; | |
| 687 | − | |
| 688 | − for (i = 0; i < n; i++) { | |
| 689 | − rval = smiapp_read( | |
| 690 | − sensor, smiapp_reg_limits[limit[i]].addr, &val); | |
| 691 | − if (rval) | |
| 692 | − return rval; | |
| 693 | − sensor->limits[limit[i]] = val; | |
| 694 | − dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n", | |
| 695 | − smiapp_reg_limits[limit[i]].addr, | |
| 696 | − smiapp_reg_limits[limit[i]].what, val, val); | |
| 697 | − } | |
| 698 | − | |
| 699 | − return 0; | |
| 700 | −} | |
| 701 | − | |
| 702 | −static int smiapp_get_all_limits(struct smiapp_sensor *sensor) | |
| 703 | −{ | |
| 704 | − unsigned int i; | |
| 705 | − int rval; | |
| 706 | − | |
| 707 | − for (i = 0; i < SMIAPP_LIMIT_LAST; i++) { | |
| 708 | − rval = smiapp_get_limits(sensor, &i, 1); | |
| 709 | − if (rval < 0) | |
| 710 | − return rval; | |
| 711 | − } | |
| 712 | − | |
| 713 | − if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0) | |
| 714 | − smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16); | |
| 715 | − | |
| 716 | − return 0; | |
| 717 | −} | |
| 718 | − | |
| 719 | 719 | static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) |
| 720 | 720 | { |
| 721 | 721 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
| @@ -869,21 +869,21 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) · 147 unmodified lines | ||
| 869 | 869 | int min, max; |
| 870 | 870 | |
| 871 | 871 | if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { |
| 872 | − min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]; | |
| 873 | − max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN]; | |
| 874 | − min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]; | |
| 875 | − max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN]; | |
| 876 | − min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]; | |
| 872 | + min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES_BIN); | |
| 873 | + max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES_BIN); | |
| 874 | + min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK_BIN); | |
| 875 | + max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK_BIN); | |
| 876 | + min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK_BIN); | |
| 877 | 877 | } else { |
| 878 | − min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES]; | |
| 879 | − max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES]; | |
| 880 | − min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK]; | |
| 881 | − max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK]; | |
| 882 | − min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK]; | |
| 878 | + min_fll = SMIA_LIM(sensor, MIN_FRAME_LENGTH_LINES); | |
| 879 | + max_fll = SMIA_LIM(sensor, MAX_FRAME_LENGTH_LINES); | |
| 880 | + min_llp = SMIA_LIM(sensor, MIN_LINE_LENGTH_PCK); | |
| 881 | + max_llp = SMIA_LIM(sensor, MAX_LINE_LENGTH_PCK); | |
| 882 | + min_lbp = SMIA_LIM(sensor, MIN_LINE_BLANKING_PCK); | |
| 883 | 883 | } |
| 884 | 884 | |
| 885 | 885 | min = max_t(int, |
| 886 | − sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], | |
| 886 | + SMIA_LIM(sensor, MIN_FRAME_BLANKING_LINES), | |
| 887 | 887 | min_fll - |
| 888 | 888 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); |
| 889 | 889 | max = max_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; |
| @@ -961,7 +961,7 @@ static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, · 71 unmodified lines | ||
| 961 | 961 | return -ENODATA; |
| 962 | 962 | } |
| 963 | 963 | |
| 964 | − if (sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] & | |
| 964 | + if (SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & | |
| 965 | 965 | SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL) { |
| 966 | 966 | for (i = 1000; i > 0; i--) { |
| 967 | 967 | if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) |
| @@ -1416,7 +1416,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) · 448 unmodified lines | ||
| 1416 | 1416 | */ |
| 1417 | 1417 | |
| 1418 | 1418 | /* Digital crop */ |
| 1419 | − if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | |
| 1419 | + if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) | |
| 1420 | 1420 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { |
| 1421 | 1421 | rval = smiapp_write( |
| 1422 | 1422 | sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET, |
| @@ -1444,7 +1444,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) · 21 unmodified lines | ||
| 1444 | 1444 | } |
| 1445 | 1445 | |
| 1446 | 1446 | /* Scaling */ |
| 1447 | − if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | |
| 1447 | + if (SMIA_LIM(sensor, SCALING_CAPABILITY) | |
| 1448 | 1448 | != SMIAPP_SCALING_CAPABILITY_NONE) { |
| 1449 | 1449 | rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE, |
| 1450 | 1450 | sensor->scaling_mode); |
| @@ -1467,7 +1467,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) · 16 unmodified lines | ||
| 1467 | 1467 | if (rval < 0) |
| 1468 | 1468 | goto out; |
| 1469 | 1469 | |
| 1470 | − if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] & | |
| 1470 | + if ((SMIA_LIM(sensor, FLASH_MODE_CAPABILITY) & | |
| 1471 | 1471 | (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | |
| 1472 | 1472 | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && |
| 1473 | 1473 | sensor->hwcfg->strobe_setup != NULL && |
| @@ -1715,8 +1715,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, · 241 unmodified lines | ||
| 1715 | 1715 | if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
| 1716 | 1716 | if (ssd == sensor->scaler) { |
| 1717 | 1717 | sensor->scale_m = |
| 1718 | − sensor->limits[ | |
| 1719 | − SMIAPP_LIMIT_SCALER_N_MIN]; | |
| 1718 | + SMIA_LIM(sensor, SCALER_N_MIN); | |
| 1720 | 1719 | sensor->scaling_mode = |
| 1721 | 1720 | SMIAPP_SCALING_MODE_NONE; |
| 1722 | 1721 | } else if (ssd == sensor->binner) { |
| @@ -1828,12 +1827,12 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, · 105 unmodified lines | ||
| 1828 | 1827 | |
| 1829 | 1828 | fmt->format.width = |
| 1830 | 1829 | clamp(fmt->format.width, |
| 1831 | − sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], | |
| 1832 | − sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]); | |
| 1830 | + SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE), | |
| 1831 | + SMIA_LIM(sensor, MAX_X_OUTPUT_SIZE)); | |
| 1833 | 1832 | fmt->format.height = |
| 1834 | 1833 | clamp(fmt->format.height, |
| 1835 | − sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], | |
| 1836 | − sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]); | |
| 1834 | + SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE), | |
| 1835 | + SMIA_LIM(sensor, MAX_Y_OUTPUT_SIZE)); | |
| 1837 | 1836 | |
| 1838 | 1837 | smiapp_get_crop_compose(subdev, cfg, crops, NULL, fmt->which); |
| 1839 | 1838 | |
| @@ -1886,7 +1885,7 @@ static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, · 46 unmodified lines | ||
| 1886 | 1885 | val -= abs(w - ask_w); |
| 1887 | 1886 | val -= abs(h - ask_h); |
| 1888 | 1887 | |
| 1889 | − if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE]) | |
| 1888 | + if (w < SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE)) | |
| 1890 | 1889 | val -= SCALING_GOODNESS_EXTREME; |
| 1891 | 1890 | |
| 1892 | 1891 | dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", |
| @@ -1952,7 +1951,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, · 59 unmodified lines | ||
| 1952 | 1951 | struct i2c_client *client = v4l2_get_subdevdata(subdev); |
| 1953 | 1952 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); |
| 1954 | 1953 | u32 min, max, a, b, max_m; |
| 1955 | − u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | |
| 1954 | + u32 scale_m = SMIA_LIM(sensor, SCALER_N_MIN); | |
| 1956 | 1955 | int mode = SMIAPP_SCALING_MODE_HORIZONTAL; |
| 1957 | 1956 | u32 try[4]; |
| 1958 | 1957 | u32 ntry = 0; |
| @@ -1965,19 +1964,19 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, · 6 unmodified lines | ||
| 1965 | 1964 | crops[SMIAPP_PAD_SINK]->height); |
| 1966 | 1965 | |
| 1967 | 1966 | a = crops[SMIAPP_PAD_SINK]->width |
| 1968 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width; | |
| 1967 | + * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.width; | |
| 1969 | 1968 | b = crops[SMIAPP_PAD_SINK]->height |
| 1970 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height; | |
| 1969 | + * SMIA_LIM(sensor, SCALER_N_MIN) / sel->r.height; | |
| 1971 | 1970 | max_m = crops[SMIAPP_PAD_SINK]->width |
| 1972 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] | |
| 1973 | − / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE]; | |
| 1971 | + * SMIA_LIM(sensor, SCALER_N_MIN) | |
| 1972 | + / SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE); | |
| 1974 | 1973 | |
| 1975 | − a = clamp(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN], | |
| 1976 | − sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]); | |
| 1977 | − b = clamp(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN], | |
| 1978 | − sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]); | |
| 1979 | − max_m = clamp(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN], | |
| 1980 | − sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX]); | |
| 1974 | + a = clamp(a, SMIA_LIM(sensor, SCALER_M_MIN), | |
| 1975 | + SMIA_LIM(sensor, SCALER_M_MAX)); | |
| 1976 | + b = clamp(b, SMIA_LIM(sensor, SCALER_M_MIN), | |
| 1977 | + SMIA_LIM(sensor, SCALER_M_MAX)); | |
| 1978 | + max_m = clamp(max_m, SMIA_LIM(sensor, SCALER_M_MIN), | |
| 1979 | + SMIA_LIM(sensor, SCALER_M_MAX)); | |
| 1981 | 1980 | |
| 1982 | 1981 | dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); |
| 1983 | 1982 | |
| @@ -2004,7 +2003,7 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, · 20 unmodified lines | ||
| 2004 | 2003 | subdev, |
| 2005 | 2004 | crops[SMIAPP_PAD_SINK]->width |
| 2006 | 2005 | / try[i] |
| 2007 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | |
| 2006 | + * SMIA_LIM(sensor, SCALER_N_MIN), | |
| 2008 | 2007 | sel->r.width, |
| 2009 | 2008 | crops[SMIAPP_PAD_SINK]->height, |
| 2010 | 2009 | sel->r.height, |
| @@ -2018,18 +2017,18 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, · 7 unmodified lines | ||
| 2018 | 2017 | best = this; |
| 2019 | 2018 | } |
| 2020 | 2019 | |
| 2021 | − if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | |
| 2020 | + if (SMIA_LIM(sensor, SCALING_CAPABILITY) | |
| 2022 | 2021 | == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) |
| 2023 | 2022 | continue; |
| 2024 | 2023 | |
| 2025 | 2024 | this = scaling_goodness( |
| 2026 | 2025 | subdev, crops[SMIAPP_PAD_SINK]->width |
| 2027 | 2026 | / try[i] |
| 2028 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | |
| 2027 | + * SMIA_LIM(sensor, SCALER_N_MIN), | |
| 2029 | 2028 | sel->r.width, |
| 2030 | 2029 | crops[SMIAPP_PAD_SINK]->height |
| 2031 | 2030 | / try[i] |
| 2032 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | |
| 2031 | + * SMIA_LIM(sensor, SCALER_N_MIN), | |
| 2033 | 2032 | sel->r.height, |
| 2034 | 2033 | sel->flags); |
| 2035 | 2034 | |
| @@ -2043,12 +2042,12 @@ static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, · 7 unmodified lines | ||
| 2043 | 2042 | sel->r.width = |
| 2044 | 2043 | (crops[SMIAPP_PAD_SINK]->width |
| 2045 | 2044 | / scale_m |
| 2046 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1; | |
| 2045 | + * SMIA_LIM(sensor, SCALER_N_MIN)) & ~1; | |
| 2047 | 2046 | if (mode == SMIAPP_SCALING_MODE_BOTH) |
| 2048 | 2047 | sel->r.height = |
| 2049 | 2048 | (crops[SMIAPP_PAD_SINK]->height |
| 2050 | 2049 | / scale_m |
| 2051 | − * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) | |
| 2050 | + * SMIA_LIM(sensor, SCALER_N_MIN)) | |
| 2052 | 2051 | & ~1; |
| 2053 | 2052 | else |
| 2054 | 2053 | sel->r.height = crops[SMIAPP_PAD_SINK]->height; |
| @@ -2104,7 +2103,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, · 49 unmodified lines | ||
| 2104 | 2103 | return 0; |
| 2105 | 2104 | if (ssd == sensor->scaler |
| 2106 | 2105 | && sel->pad == SMIAPP_PAD_SINK |
| 2107 | − && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | |
| 2106 | + && SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) | |
| 2108 | 2107 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) |
| 2109 | 2108 | return 0; |
| 2110 | 2109 | return -EINVAL; |
| @@ -2120,7 +2119,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev, · 9 unmodified lines | ||
| 2120 | 2119 | if (ssd == sensor->binner) |
| 2121 | 2120 | return 0; |
| 2122 | 2121 | if (ssd == sensor->scaler |
| 2123 | − && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | |
| 2122 | + && SMIA_LIM(sensor, SCALING_CAPABILITY) | |
| 2124 | 2123 | != SMIAPP_SCALING_CAPABILITY_NONE) |
| 2125 | 2124 | return 0; |
| 2126 | 2125 | /* Fall through */ |
| @@ -2185,8 +2184,8 @@ static void smiapp_get_native_size(struct smiapp_subdev *ssd, · 58 unmodified lines | ||
| 2185 | 2184 | { |
| 2186 | 2185 | r->top = 0; |
| 2187 | 2186 | r->left = 0; |
| 2188 | − r->width = ssd->sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; | |
| 2189 | − r->height = ssd->sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; | |
| 2187 | + r->width = SMIA_LIM(ssd->sensor, X_ADDR_MAX) + 1; | |
| 2188 | + r->height = SMIA_LIM(ssd->sensor, Y_ADDR_MAX) + 1; | |
| 2190 | 2189 | } |
| 2191 | 2190 | |
| 2192 | 2191 | static int __smiapp_get_selection(struct v4l2_subdev *subdev, |
| @@ -2271,10 +2270,10 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, · 78 unmodified lines | ||
| 2271 | 2270 | sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags); |
| 2272 | 2271 | |
| 2273 | 2272 | sel->r.width = max_t(unsigned int, |
| 2274 | − sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], | |
| 2273 | + SMIA_LIM(sensor, MIN_X_OUTPUT_SIZE), | |
| 2275 | 2274 | sel->r.width); |
| 2276 | 2275 | sel->r.height = max_t(unsigned int, |
| 2277 | − sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], | |
| 2276 | + SMIA_LIM(sensor, MIN_Y_OUTPUT_SIZE), | |
| 2278 | 2277 | sel->r.height); |
| 2279 | 2278 | |
| 2280 | 2279 | switch (sel->target) { |
| @@ -2927,7 +2926,7 @@ static int smiapp_probe(struct i2c_client *client) · 646 unmodified lines | ||
| 2927 | 2926 | goto out_power_off; |
| 2928 | 2927 | } |
| 2929 | 2928 | |
| 2930 | − rval = smiapp_get_all_limits(sensor); | |
| 2929 | + rval = smiapp_read_all_smia_limits(sensor); | |
| 2931 | 2930 | if (rval) { |
| 2932 | 2931 | rval = -ENODEV; |
| 2933 | 2932 | goto out_power_off; |
| @@ -2963,7 +2962,7 @@ static int smiapp_probe(struct i2c_client *client) · 29 unmodified lines | ||
| 2963 | 2962 | goto out_power_off; |
| 2964 | 2963 | } |
| 2965 | 2964 | |
| 2966 | − if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) { | |
| 2965 | + if (SMIA_LIM(sensor, BINNING_CAPABILITY)) { | |
| 2967 | 2966 | u32 val; |
| 2968 | 2967 | |
| 2969 | 2968 | rval = smiapp_read(sensor, |
| @@ -3000,7 +2999,7 @@ static int smiapp_probe(struct i2c_client *client) · 30 unmodified lines | ||
| 3000 | 2999 | } |
| 3001 | 3000 | |
| 3002 | 3001 | if (sensor->minfo.smiapp_version && |
| 3003 | − sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] & | |
| 3002 | + SMIA_LIM(sensor, DATA_TRANSFER_IF_CAPABILITY) & | |
| 3004 | 3003 | SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { |
| 3005 | 3004 | if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { |
| 3006 | 3005 | dev_err(&client->dev, "sysfs nvm entry failed\n"); |
| @@ -3010,21 +3009,21 @@ static int smiapp_probe(struct i2c_client *client) · 3 unmodified lines | ||
| 3010 | 3009 | } |
| 3011 | 3010 | |
| 3012 | 3011 | /* We consider this as profile 0 sensor if any of these are zero. */ |
| 3013 | − if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] || | |
| 3014 | − !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] || | |
| 3015 | − !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] || | |
| 3016 | − !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) { | |
| 3012 | + if (!SMIA_LIM(sensor, MIN_OP_SYS_CLK_DIV) || | |
| 3013 | + !SMIA_LIM(sensor, MAX_OP_SYS_CLK_DIV) || | |
| 3014 | + !SMIA_LIM(sensor, MIN_OP_PIX_CLK_DIV) || | |
| 3015 | + !SMIA_LIM(sensor, MAX_OP_PIX_CLK_DIV)) { | |
| 3017 | 3016 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; |
| 3018 | − } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | |
| 3017 | + } else if (SMIA_LIM(sensor, SCALING_CAPABILITY) | |
| 3019 | 3018 | != SMIAPP_SCALING_CAPABILITY_NONE) { |
| 3020 | − if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | |
| 3019 | + if (SMIA_LIM(sensor, SCALING_CAPABILITY) | |
| 3021 | 3020 | == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) |
| 3022 | 3021 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; |
| 3023 | 3022 | else |
| 3024 | 3023 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; |
| 3025 | 3024 | sensor->scaler = &sensor->ssds[sensor->ssds_used]; |
| 3026 | 3025 | sensor->ssds_used++; |
| 3027 | − } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | |
| 3026 | + } else if (SMIA_LIM(sensor, DIGITAL_CROP_CAPABILITY) | |
| 3028 | 3027 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { |
| 3029 | 3028 | sensor->scaler = &sensor->ssds[sensor->ssds_used]; |
| 3030 | 3029 | sensor->ssds_used++; |
| @@ -3034,13 +3033,13 @@ static int smiapp_probe(struct i2c_client *client) · 3 unmodified lines | ||
| 3034 | 3033 | sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; |
| 3035 | 3034 | sensor->ssds_used++; |
| 3036 | 3035 | |
| 3037 | − sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | |
| 3036 | + sensor->scale_m = SMIA_LIM(sensor, SCALER_N_MIN); | |
| 3038 | 3037 | |
| 3039 | 3038 | /* prepare PLL configuration input values */ |
| 3040 | 3039 | sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; |
| 3041 | 3040 | sensor->pll.csi2.lanes = sensor->hwcfg->lanes; |
| 3042 | 3041 | sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; |
| 3043 | − sensor->pll.scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | |
| 3042 | + sensor->pll.scale_n = SMIA_LIM(sensor, SCALER_N_MIN); | |
| 3044 | 3043 | /* Profile 0 sensors have no separate OP clock branch. */ |
| 3045 | 3044 | if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) |
| 3046 | 3045 | sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; |
| @@ -35,6 +35,10 @@ · 34 unmodified lines | ||
| 35 | 35 | #define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) |
| 36 | 36 | #define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) |
| 37 | 37 | |
| 38 | +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0 | |
| 39 | +#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1 | |
| 40 | +#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2 | |
| 41 | + | |
| 38 | 42 | #define SMIAPP_DPHY_CTRL_AUTOMATIC 0 |
| 39 | 43 | /* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ |
| 40 | 44 | #define SMIAPP_DPHY_CTRL_UI 1 |
| @@ -8,6 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | * Contact: Sakari Ailus <sakari.ailus@iki.fi> |
| 9 | 9 | */ |
| 10 | 10 | |
| 11 | +#include <asm/unaligned.h> | |
| 12 | + | |
| 11 | 13 | #include <linux/delay.h> |
| 12 | 14 | #include <linux/i2c.h> |
| 13 | 15 | |
| @@ -69,18 +71,19 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg, · 55 unmodified lines | ||
| 69 | 71 | { |
| 70 | 72 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); |
| 71 | 73 | struct i2c_msg msg; |
| 72 | − unsigned char data[4]; | |
| 73 | − u16 offset = reg; | |
| 74 | + unsigned char data_buf[sizeof(u32)] = { 0 }; | |
| 75 | + unsigned char offset_buf[sizeof(u16)]; | |
| 74 | 76 | int r; |
| 75 | 77 | |
| 78 | + if (len > sizeof(data_buf)) | |
| 79 | + return -EINVAL; | |
| 80 | + | |
| 76 | 81 | msg.addr = client->addr; |
| 77 | 82 | msg.flags = 0; |
| 78 | − msg.len = 2; | |
| 79 | − msg.buf = data; | |
| 83 | + msg.len = sizeof(offset_buf); | |
| 84 | + msg.buf = offset_buf; | |
| 85 | + put_unaligned_be16(reg, offset_buf); | |
| 80 | 86 | |
| 81 | − /* high byte goes out first */ | |
| 82 | − data[0] = (u8) (offset >> 8); | |
| 83 | − data[1] = (u8) offset; | |
| 84 | 87 | r = i2c_transfer(client->adapter, &msg, 1); |
| 85 | 88 | if (r != 1) { |
| 86 | 89 | if (r >= 0) |
| @@ -90,6 +93,8 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg, · 3 unmodified lines | ||
| 90 | 93 | |
| 91 | 94 | msg.len = len; |
| 92 | 95 | msg.flags = I2C_M_RD; |
| 96 | + msg.buf = &data_buf[sizeof(data_buf) - len]; | |
| 97 | + | |
| 93 | 98 | r = i2c_transfer(client->adapter, &msg, 1); |
| 94 | 99 | if (r != 1) { |
| 95 | 100 | if (r >= 0) |
| @@ -97,27 +102,12 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg, · 1 unmodified line | ||
| 97 | 102 | goto err; |
| 98 | 103 | } |
| 99 | 104 | |
| 100 | − *val = 0; | |
| 101 | − /* high byte comes first */ | |
| 102 | − switch (len) { | |
| 103 | − case SMIAPP_REG_32BIT: | |
| 104 | − *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + | |
| 105 | − data[3]; | |
| 106 | − break; | |
| 107 | − case SMIAPP_REG_16BIT: | |
| 108 | − *val = (data[0] << 8) + data[1]; | |
| 109 | − break; | |
| 110 | − case SMIAPP_REG_8BIT: | |
| 111 | − *val = data[0]; | |
| 112 | − break; | |
| 113 | − default: | |
| 114 | − BUG(); | |
| 115 | − } | |
| 105 | + *val = get_unaligned_be32(data_buf); | |
| 116 | 106 | |
| 117 | 107 | return 0; |
| 118 | 108 | |
| 119 | 109 | err: |
| 120 | − dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r); | |
| 110 | + dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r); | |
| 121 | 111 | |
| 122 | 112 | return r; |
| 123 | 113 | } |
| @@ -158,7 +148,7 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, · 34 unmodified lines | ||
| 158 | 148 | && len != SMIAPP_REG_32BIT) |
| 159 | 149 | return -EINVAL; |
| 160 | 150 | |
| 161 | − if (len == SMIAPP_REG_8BIT || !only8) | |
| 151 | + if (!only8) | |
| 162 | 152 | rval = ____smiapp_read(sensor, SMIAPP_REG_ADDR(reg), len, val); |
| 163 | 153 | else |
| 164 | 154 | rval = ____smiapp_read_8only(sensor, SMIAPP_REG_ADDR(reg), len, |
| @@ -214,13 +204,10 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) · 49 unmodified lines | ||
| 214 | 204 | struct i2c_msg msg; |
| 215 | 205 | unsigned char data[6]; |
| 216 | 206 | unsigned int retries; |
| 217 | − u8 flags = SMIAPP_REG_FLAGS(reg); | |
| 218 | 207 | u8 len = SMIAPP_REG_WIDTH(reg); |
| 219 | − u16 offset = SMIAPP_REG_ADDR(reg); | |
| 220 | 208 | int r; |
| 221 | 209 | |
| 222 | − if ((len != SMIAPP_REG_8BIT && len != SMIAPP_REG_16BIT && | |
| 223 | − len != SMIAPP_REG_32BIT) || flags) | |
| 210 | + if (len > sizeof(data) - 2) | |
| 224 | 211 | return -EINVAL; |
| 225 | 212 | |
| 226 | 213 | msg.addr = client->addr; |
| @@ -228,27 +215,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) · 1 unmodified line | ||
| 228 | 215 | msg.len = 2 + len; |
| 229 | 216 | msg.buf = data; |
| 230 | 217 | |
| 231 | − /* high byte goes out first */ | |
| 232 | − data[0] = (u8) (reg >> 8); | |
| 233 | − data[1] = (u8) (reg & 0xff); | |
| 234 | − | |
| 235 | − switch (len) { | |
| 236 | − case SMIAPP_REG_8BIT: | |
| 237 | − data[2] = val; | |
| 238 | − break; | |
| 239 | − case SMIAPP_REG_16BIT: | |
| 240 | − data[2] = val >> 8; | |
| 241 | − data[3] = val; | |
| 242 | − break; | |
| 243 | − case SMIAPP_REG_32BIT: | |
| 244 | − data[2] = val >> 24; | |
| 245 | − data[3] = val >> 16; | |
| 246 | − data[4] = val >> 8; | |
| 247 | − data[5] = val; | |
| 248 | − break; | |
| 249 | − default: | |
| 250 | − BUG(); | |
| 251 | − } | |
| 218 | + put_unaligned_be16(SMIAPP_REG_ADDR(reg), data); | |
| 219 | + put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2); | |
| 252 | 220 | |
| 253 | 221 | for (retries = 0; retries < 5; retries++) { |
| 254 | 222 | /* |
| @@ -269,7 +237,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) · 14 unmodified lines | ||
| 269 | 237 | } |
| 270 | 238 | |
| 271 | 239 | dev_err(&client->dev, |
| 272 | − "wrote 0x%x to offset 0x%x error %d\n", val, offset, r); | |
| 240 | + "wrote 0x%x to offset 0x%x error %d\n", val, | |
| 241 | + SMIAPP_REG_ADDR(reg), r); | |
| 273 | 242 | |
| 274 | 243 | return r; |
| 275 | 244 | } |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/mutex.h> |
| 15 | 15 | #include <media/v4l2-ctrls.h> |
| 16 | 16 | #include <media/v4l2-subdev.h> |
| 17 | −#include <media/i2c/smiapp.h> | |
| 18 | 17 | |
| 19 | 18 | #include "smiapp-pll.h" |
| 20 | 19 | #include "smiapp-reg.h" |
| @@ -42,6 +41,49 @@ · 21 unmodified lines | ||
| 42 | 41 | |
| 43 | 42 | #define SMIAPP_COLOUR_COMPONENTS 4 |
| 44 | 43 | |
| 44 | +#define SMIAPP_NAME "smiapp" | |
| 45 | + | |
| 46 | +#define SMIAPP_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */ | |
| 47 | +#define SMIAPP_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */ | |
| 48 | + | |
| 49 | +/* | |
| 50 | + * Sometimes due to board layout considerations the camera module can be | |
| 51 | + * mounted rotated. The typical rotation used is 180 degrees which can be | |
| 52 | + * corrected by giving a default H-FLIP and V-FLIP in the sensor readout. | |
| 53 | + * FIXME: rotation also changes the bayer pattern. | |
| 54 | + */ | |
| 55 | +enum smiapp_module_board_orient { | |
| 56 | + SMIAPP_MODULE_BOARD_ORIENT_0 = 0, | |
| 57 | + SMIAPP_MODULE_BOARD_ORIENT_180, | |
| 58 | +}; | |
| 59 | + | |
| 60 | +struct smiapp_flash_strobe_parms { | |
| 61 | + u8 mode; | |
| 62 | + u32 strobe_width_high_us; | |
| 63 | + u16 strobe_delay; | |
| 64 | + u16 stobe_start_point; | |
| 65 | + u8 trigger; | |
| 66 | +}; | |
| 67 | + | |
| 68 | +struct smiapp_hwconfig { | |
| 69 | + /* | |
| 70 | + * Change the cci address if i2c_addr_alt is set. | |
| 71 | + * Both default and alternate cci addr need to be present | |
| 72 | + */ | |
| 73 | + unsigned short i2c_addr_dfl; /* Default i2c addr */ | |
| 74 | + unsigned short i2c_addr_alt; /* Alternate i2c addr */ | |
| 75 | + | |
| 76 | + uint32_t ext_clk; /* sensor external clk */ | |
| 77 | + | |
| 78 | + unsigned int lanes; /* Number of CSI-2 lanes */ | |
| 79 | + uint32_t csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */ | |
| 80 | + uint64_t *op_sys_clock; | |
| 81 | + | |
| 82 | + enum smiapp_module_board_orient module_board_orient; | |
| 83 | + | |
| 84 | + struct smiapp_flash_strobe_parms *strobe_setup; | |
| 85 | +}; | |
| 86 | + | |
| 45 | 87 | #include "smiapp-limits.h" |
| 46 | 88 | |
| 47 | 89 | struct smiapp_quirk; |
| @@ -13,12 +13,15 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/interrupt.h> |
| 14 | 14 | #include <linux/module.h> |
| 15 | 15 | #include <linux/of_graph.h> |
| 16 | +#include <linux/pm_runtime.h> | |
| 16 | 17 | #include <linux/regmap.h> |
| 17 | 18 | #include <media/v4l2-async.h> |
| 18 | 19 | #include <media/v4l2-device.h> |
| 20 | +#include <media/v4l2-event.h> | |
| 19 | 21 | #include <media/v4l2-ctrls.h> |
| 20 | 22 | #include <media/v4l2-fwnode.h> |
| 21 | 23 | #include <media/v4l2-mc.h> |
| 24 | +#include <media/v4l2-rect.h> | |
| 22 | 25 | |
| 23 | 26 | #include "tvp5150_reg.h" |
| 24 | 27 | |
| @@ -31,6 +34,15 @@ · 6 unmodified lines | ||
| 31 | 34 | #define TVP5150_MBUS_FMT MEDIA_BUS_FMT_UYVY8_2X8 |
| 32 | 35 | #define TVP5150_FIELD V4L2_FIELD_ALTERNATE |
| 33 | 36 | #define TVP5150_COLORSPACE V4L2_COLORSPACE_SMPTE170M |
| 37 | +#define TVP5150_STD_MASK (V4L2_STD_NTSC | \ | |
| 38 | + V4L2_STD_NTSC_443 | \ | |
| 39 | + V4L2_STD_PAL | \ | |
| 40 | + V4L2_STD_PAL_M | \ | |
| 41 | + V4L2_STD_PAL_N | \ | |
| 42 | + V4L2_STD_PAL_Nc | \ | |
| 43 | + V4L2_STD_SECAM) | |
| 44 | + | |
| 45 | +#define TVP5150_MAX_CONNECTORS 3 /* Check dt-bindings for more information */ | |
| 34 | 46 | |
| 35 | 47 | MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver"); |
| 36 | 48 | MODULE_AUTHOR("Mauro Carvalho Chehab"); |
| @@ -44,18 +56,26 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)"); · 7 unmodified lines | ||
| 44 | 56 | #define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg) |
| 45 | 57 | |
| 46 | 58 | enum tvp5150_pads { |
| 47 | − TVP5150_PAD_IF_INPUT, | |
| 59 | + TVP5150_PAD_AIP1A, | |
| 60 | + TVP5150_PAD_AIP1B, | |
| 48 | 61 | TVP5150_PAD_VID_OUT, |
| 49 | 62 | TVP5150_NUM_PADS |
| 50 | 63 | }; |
| 51 | 64 | |
| 65 | +struct tvp5150_connector { | |
| 66 | + struct v4l2_fwnode_connector base; | |
| 67 | + struct media_entity ent; | |
| 68 | + struct media_pad pad; | |
| 69 | +}; | |
| 70 | + | |
| 52 | 71 | struct tvp5150 { |
| 53 | 72 | struct v4l2_subdev sd; |
| 54 | −#ifdef CONFIG_MEDIA_CONTROLLER | |
| 73 | + | |
| 55 | 74 | struct media_pad pads[TVP5150_NUM_PADS]; |
| 56 | − struct media_entity input_ent[TVP5150_INPUT_NUM]; | |
| 57 | − struct media_pad input_pad[TVP5150_INPUT_NUM]; | |
| 58 | −#endif | |
| 75 | + struct tvp5150_connector connectors[TVP5150_MAX_CONNECTORS]; | |
| 76 | + struct tvp5150_connector *cur_connector; | |
| 77 | + unsigned int connectors_num; | |
| 78 | + | |
| 59 | 79 | struct v4l2_ctrl_handler hdl; |
| 60 | 80 | struct v4l2_rect rect; |
| 61 | 81 | struct regmap *regmap; |
| @@ -282,9 +302,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd) · 220 unmodified lines | ||
| 282 | 302 | break; |
| 283 | 303 | } |
| 284 | 304 | |
| 285 | − dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n", | |
| 286 | − decoder->input, decoder->output, | |
| 287 | − input, opmode); | |
| 305 | + dev_dbg_lvl(sd->dev, 1, debug, | |
| 306 | + "Selecting video route: route input=%s, output=%s => tvp5150 input=0x%02x, opmode=0x%02x\n", | |
| 307 | + decoder->input == 0 ? "aip1a" : | |
| 308 | + decoder->input == 2 ? "aip1b" : "svideo", | |
| 309 | + decoder->output == 0 ? "normal" : "black-frame-gen", | |
| 310 | + input, opmode); | |
| 288 | 311 | |
| 289 | 312 | regmap_write(decoder->regmap, TVP5150_OP_MODE_CTL, opmode); |
| 290 | 313 | regmap_write(decoder->regmap, TVP5150_VD_IN_SRC_SEL_1, input); |
| @@ -773,17 +796,33 @@ static int tvp5150_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) · 482 unmodified lines | ||
| 773 | 796 | static int tvp5150_s_std(struct v4l2_subdev *sd, v4l2_std_id std) |
| 774 | 797 | { |
| 775 | 798 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 799 | + struct tvp5150_connector *cur_con = decoder->cur_connector; | |
| 800 | + v4l2_std_id supported_stds; | |
| 776 | 801 | |
| 777 | 802 | if (decoder->norm == std) |
| 778 | 803 | return 0; |
| 779 | 804 | |
| 805 | + /* In case of no of-connectors are available no limitations are made */ | |
| 806 | + if (!decoder->connectors_num) | |
| 807 | + supported_stds = V4L2_STD_ALL; | |
| 808 | + else | |
| 809 | + supported_stds = cur_con->base.connector.analog.sdtv_stds; | |
| 810 | + | |
| 811 | + /* | |
| 812 | + * Check if requested std or group of std's is/are supported by the | |
| 813 | + * connector. | |
| 814 | + */ | |
| 815 | + if ((supported_stds & std) == 0) | |
| 816 | + return -EINVAL; | |
| 817 | + | |
| 780 | 818 | /* Change cropping height limits */ |
| 781 | 819 | if (std & V4L2_STD_525_60) |
| 782 | 820 | decoder->rect.height = TVP5150_V_MAX_525_60; |
| 783 | 821 | else |
| 784 | 822 | decoder->rect.height = TVP5150_V_MAX_OTHERS; |
| 785 | 823 | |
| 786 | − decoder->norm = std; | |
| 824 | + /* Set only the specific supported std in case of group of std's. */ | |
| 825 | + decoder->norm = supported_stds & std; | |
| 787 | 826 | |
| 788 | 827 | return tvp5150_set_std(sd, std); |
| 789 | 828 | } |
| @@ -986,6 +1025,25 @@ static void tvp5150_set_default(v4l2_std_id std, struct v4l2_rect *crop) · 196 unmodified lines | ||
| 986 | 1025 | crop->height = TVP5150_V_MAX_OTHERS; |
| 987 | 1026 | } |
| 988 | 1027 | |
| 1028 | +static struct v4l2_rect * | |
| 1029 | +tvp5150_get_pad_crop(struct tvp5150 *decoder, | |
| 1030 | + struct v4l2_subdev_pad_config *cfg, unsigned int pad, | |
| 1031 | + enum v4l2_subdev_format_whence which) | |
| 1032 | +{ | |
| 1033 | + switch (which) { | |
| 1034 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 1035 | + return &decoder->rect; | |
| 1036 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 1037 | +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) | |
| 1038 | + return v4l2_subdev_get_try_crop(&decoder->sd, cfg, pad); | |
| 1039 | +#else | |
| 1040 | + return ERR_PTR(-EINVAL); | |
| 1041 | +#endif | |
| 1042 | + default: | |
| 1043 | + return ERR_PTR(-EINVAL); | |
| 1044 | + } | |
| 1045 | +} | |
| 1046 | + | |
| 989 | 1047 | static int tvp5150_fill_fmt(struct v4l2_subdev *sd, |
| 990 | 1048 | struct v4l2_subdev_pad_config *cfg, |
| 991 | 1049 | struct v4l2_subdev_format *format) |
| @@ -1010,25 +1068,10 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, · 18 unmodified lines | ||
| 1010 | 1068 | return 0; |
| 1011 | 1069 | } |
| 1012 | 1070 | |
| 1013 | −static int tvp5150_set_selection(struct v4l2_subdev *sd, | |
| 1014 | − struct v4l2_subdev_pad_config *cfg, | |
| 1015 | − struct v4l2_subdev_selection *sel) | |
| 1071 | +static unsigned int tvp5150_get_hmax(struct v4l2_subdev *sd) | |
| 1016 | 1072 | { |
| 1017 | 1073 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 1018 | − struct v4l2_rect rect = sel->r; | |
| 1019 | 1074 | v4l2_std_id std; |
| 1020 | − int hmax; | |
| 1021 | − | |
| 1022 | − if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || | |
| 1023 | − sel->target != V4L2_SEL_TGT_CROP) | |
| 1024 | − return -EINVAL; | |
| 1025 | − | |
| 1026 | − dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", | |
| 1027 | − __func__, rect.left, rect.top, rect.width, rect.height); | |
| 1028 | − | |
| 1029 | − /* tvp5150 has some special limits */ | |
| 1030 | − rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT); | |
| 1031 | − rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP); | |
| 1032 | 1075 | |
| 1033 | 1076 | /* Calculate height based on current standard */ |
| 1034 | 1077 | if (decoder->norm == V4L2_STD_ALL) |
| @@ -1036,36 +1079,78 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd, · 1 unmodified line | ||
| 1036 | 1079 | else |
| 1037 | 1080 | std = decoder->norm; |
| 1038 | 1081 | |
| 1039 | − if (std & V4L2_STD_525_60) | |
| 1040 | − hmax = TVP5150_V_MAX_525_60; | |
| 1041 | − else | |
| 1042 | − hmax = TVP5150_V_MAX_OTHERS; | |
| 1082 | + return (std & V4L2_STD_525_60) ? | |
| 1083 | + TVP5150_V_MAX_525_60 : TVP5150_V_MAX_OTHERS; | |
| 1084 | +} | |
| 1043 | 1085 | |
| 1044 | − /* | |
| 1045 | − * alignments: | |
| 1046 | − * - width = 2 due to UYVY colorspace | |
| 1047 | − * - height, image = no special alignment | |
| 1048 | − */ | |
| 1049 | − v4l_bound_align_image(&rect.width, | |
| 1050 | − TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left, | |
| 1051 | − TVP5150_H_MAX - rect.left, 1, &rect.height, | |
| 1052 | − hmax - TVP5150_MAX_CROP_TOP - rect.top, | |
| 1053 | − hmax - rect.top, 0, 0); | |
| 1086 | +static void tvp5150_set_hw_selection(struct v4l2_subdev *sd, | |
| 1087 | + struct v4l2_rect *rect) | |
| 1088 | +{ | |
| 1089 | + struct tvp5150 *decoder = to_tvp5150(sd); | |
| 1090 | + unsigned int hmax = tvp5150_get_hmax(sd); | |
| 1054 | 1091 | |
| 1055 | − regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect.top); | |
| 1092 | + regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_START, rect->top); | |
| 1056 | 1093 | regmap_write(decoder->regmap, TVP5150_VERT_BLANKING_STOP, |
| 1057 | − rect.top + rect.height - hmax); | |
| 1094 | + rect->top + rect->height - hmax); | |
| 1058 | 1095 | regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_MSB, |
| 1059 | − rect.left >> TVP5150_CROP_SHIFT); | |
| 1096 | + rect->left >> TVP5150_CROP_SHIFT); | |
| 1060 | 1097 | regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_ST_LSB, |
| 1061 | − rect.left | (1 << TVP5150_CROP_SHIFT)); | |
| 1098 | + rect->left | (1 << TVP5150_CROP_SHIFT)); | |
| 1062 | 1099 | regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_MSB, |
| 1063 | − (rect.left + rect.width - TVP5150_MAX_CROP_LEFT) >> | |
| 1100 | + (rect->left + rect->width - TVP5150_MAX_CROP_LEFT) >> | |
| 1064 | 1101 | TVP5150_CROP_SHIFT); |
| 1065 | 1102 | regmap_write(decoder->regmap, TVP5150_ACT_VD_CROP_STP_LSB, |
| 1066 | − rect.left + rect.width - TVP5150_MAX_CROP_LEFT); | |
| 1103 | + rect->left + rect->width - TVP5150_MAX_CROP_LEFT); | |
| 1104 | +} | |
| 1105 | + | |
| 1106 | +static int tvp5150_set_selection(struct v4l2_subdev *sd, | |
| 1107 | + struct v4l2_subdev_pad_config *cfg, | |
| 1108 | + struct v4l2_subdev_selection *sel) | |
| 1109 | +{ | |
| 1110 | + struct tvp5150 *decoder = to_tvp5150(sd); | |
| 1111 | + struct v4l2_rect *rect = &sel->r; | |
| 1112 | + struct v4l2_rect *crop; | |
| 1113 | + unsigned int hmax; | |
| 1114 | + | |
| 1115 | + if (sel->target != V4L2_SEL_TGT_CROP) | |
| 1116 | + return -EINVAL; | |
| 1117 | + | |
| 1118 | + dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", | |
| 1119 | + __func__, rect->left, rect->top, rect->width, rect->height); | |
| 1120 | + | |
| 1121 | + /* tvp5150 has some special limits */ | |
| 1122 | + rect->left = clamp(rect->left, 0, TVP5150_MAX_CROP_LEFT); | |
| 1123 | + rect->top = clamp(rect->top, 0, TVP5150_MAX_CROP_TOP); | |
| 1124 | + hmax = tvp5150_get_hmax(sd); | |
| 1125 | + | |
| 1126 | + /* | |
| 1127 | + * alignments: | |
| 1128 | + * - width = 2 due to UYVY colorspace | |
| 1129 | + * - height, image = no special alignment | |
| 1130 | + */ | |
| 1131 | + v4l_bound_align_image(&rect->width, | |
| 1132 | + TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect->left, | |
| 1133 | + TVP5150_H_MAX - rect->left, 1, &rect->height, | |
| 1134 | + hmax - TVP5150_MAX_CROP_TOP - rect->top, | |
| 1135 | + hmax - rect->top, 0, 0); | |
| 1136 | + | |
| 1137 | + if (!IS_ENABLED(CONFIG_VIDEO_V4L2_SUBDEV_API) && | |
| 1138 | + sel->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 1139 | + return 0; | |
| 1140 | + | |
| 1141 | + crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, sel->which); | |
| 1142 | + if (IS_ERR(crop)) | |
| 1143 | + return PTR_ERR(crop); | |
| 1144 | + | |
| 1145 | + /* | |
| 1146 | + * Update output image size if the selection (crop) rectangle size or | |
| 1147 | + * position has been modified. | |
| 1148 | + */ | |
| 1149 | + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && | |
| 1150 | + !v4l2_rect_equal(rect, crop)) | |
| 1151 | + tvp5150_set_hw_selection(sd, rect); | |
| 1067 | 1152 | |
| 1068 | − decoder->rect = rect; | |
| 1153 | + *crop = *rect; | |
| 1069 | 1154 | |
| 1070 | 1155 | return 0; |
| 1071 | 1156 | } |
| @@ -1075,11 +1160,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd, · 3 unmodified lines | ||
| 1075 | 1160 | struct v4l2_subdev_selection *sel) |
| 1076 | 1161 | { |
| 1077 | 1162 | struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd); |
| 1163 | + struct v4l2_rect *crop; | |
| 1078 | 1164 | v4l2_std_id std; |
| 1079 | 1165 | |
| 1080 | − if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 1081 | − return -EINVAL; | |
| 1082 | − | |
| 1083 | 1166 | switch (sel->target) { |
| 1084 | 1167 | case V4L2_SEL_TGT_CROP_BOUNDS: |
| 1085 | 1168 | sel->r.left = 0; |
| @@ -1097,7 +1180,11 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd, · 11 unmodified lines | ||
| 1097 | 1180 | sel->r.height = TVP5150_V_MAX_OTHERS; |
| 1098 | 1181 | return 0; |
| 1099 | 1182 | case V4L2_SEL_TGT_CROP: |
| 1100 | − sel->r = decoder->rect; | |
| 1183 | + crop = tvp5150_get_pad_crop(decoder, cfg, sel->pad, | |
| 1184 | + sel->which); | |
| 1185 | + if (IS_ERR(crop)) | |
| 1186 | + return PTR_ERR(crop); | |
| 1187 | + sel->r = *crop; | |
| 1101 | 1188 | return 0; |
| 1102 | 1189 | default: |
| 1103 | 1190 | return -EINVAL; |
| @@ -1170,30 +1257,148 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, · 66 unmodified lines | ||
| 1170 | 1257 | } |
| 1171 | 1258 | |
| 1172 | 1259 | /**************************************************************************** |
| 1173 | − Media entity ops | |
| 1260 | + * Media entity ops | |
| 1174 | 1261 | ****************************************************************************/ |
| 1262 | +#if defined(CONFIG_MEDIA_CONTROLLER) | |
| 1263 | +static int tvp5150_set_link(struct media_pad *connector_pad, | |
| 1264 | + struct media_pad *tvp5150_pad, u32 flags) | |
| 1265 | +{ | |
| 1266 | + struct media_link *link; | |
| 1267 | + | |
| 1268 | + link = media_entity_find_link(connector_pad, tvp5150_pad); | |
| 1269 | + if (!link) | |
| 1270 | + return -EINVAL; | |
| 1271 | + | |
| 1272 | + link->flags = flags; | |
| 1273 | + link->reverse->flags = link->flags; | |
| 1274 | + | |
| 1275 | + return 0; | |
| 1276 | +} | |
| 1277 | + | |
| 1278 | +static int tvp5150_disable_all_input_links(struct tvp5150 *decoder) | |
| 1279 | +{ | |
| 1280 | + struct media_pad *connector_pad; | |
| 1281 | + unsigned int i; | |
| 1282 | + int err; | |
| 1283 | + | |
| 1284 | + for (i = 0; i < TVP5150_NUM_PADS - 1; i++) { | |
| 1285 | + connector_pad = media_entity_remote_pad(&decoder->pads[i]); | |
| 1286 | + if (!connector_pad) | |
| 1287 | + continue; | |
| 1288 | + | |
| 1289 | + err = tvp5150_set_link(connector_pad, &decoder->pads[i], 0); | |
| 1290 | + if (err) | |
| 1291 | + return err; | |
| 1292 | + } | |
| 1293 | + | |
| 1294 | + return 0; | |
| 1295 | +} | |
| 1296 | + | |
| 1297 | +static int tvp5150_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, | |
| 1298 | + u32 config); | |
| 1175 | 1299 | |
| 1176 | −#ifdef CONFIG_MEDIA_CONTROLLER | |
| 1177 | 1300 | static int tvp5150_link_setup(struct media_entity *entity, |
| 1178 | − const struct media_pad *local, | |
| 1301 | + const struct media_pad *tvp5150_pad, | |
| 1179 | 1302 | const struct media_pad *remote, u32 flags) |
| 1180 | 1303 | { |
| 1181 | 1304 | struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); |
| 1182 | 1305 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 1183 | − int i; | |
| 1306 | + struct media_pad *other_tvp5150_pad = | |
| 1307 | + &decoder->pads[tvp5150_pad->index ^ 1]; | |
| 1308 | + struct v4l2_fwnode_connector *v4l2c; | |
| 1309 | + bool is_svideo = false; | |
| 1310 | + unsigned int i; | |
| 1311 | + int err; | |
| 1312 | + | |
| 1313 | + /* | |
| 1314 | + * The TVP5150 state is determined by the enabled sink pad link(s). | |
| 1315 | + * Enabling or disabling the source pad link has no effect. | |
| 1316 | + */ | |
| 1317 | + if (tvp5150_pad->flags & MEDIA_PAD_FL_SOURCE) | |
| 1318 | + return 0; | |
| 1184 | 1319 | |
| 1185 | − for (i = 0; i < TVP5150_INPUT_NUM; i++) { | |
| 1186 | − if (remote->entity == &decoder->input_ent[i]) | |
| 1320 | + /* Check if the svideo connector should be enabled */ | |
| 1321 | + for (i = 0; i < decoder->connectors_num; i++) { | |
| 1322 | + if (remote->entity == &decoder->connectors[i].ent) { | |
| 1323 | + v4l2c = &decoder->connectors[i].base; | |
| 1324 | + is_svideo = v4l2c->type == V4L2_CONN_SVIDEO; | |
| 1187 | 1325 | break; |
| 1326 | + } | |
| 1188 | 1327 | } |
| 1189 | 1328 | |
| 1190 | − /* Do nothing for entities that are not input connectors */ | |
| 1191 | − if (i == TVP5150_INPUT_NUM) | |
| 1192 | − return 0; | |
| 1329 | + dev_dbg_lvl(sd->dev, 1, debug, "link setup '%s':%d->'%s':%d[%d]", | |
| 1330 | + remote->entity->name, remote->index, | |
| 1331 | + tvp5150_pad->entity->name, tvp5150_pad->index, | |
| 1332 | + flags & MEDIA_LNK_FL_ENABLED); | |
| 1333 | + if (is_svideo) | |
| 1334 | + dev_dbg_lvl(sd->dev, 1, debug, | |
| 1335 | + "link setup '%s':%d->'%s':%d[%d]", | |
| 1336 | + remote->entity->name, remote->index, | |
| 1337 | + other_tvp5150_pad->entity->name, | |
| 1338 | + other_tvp5150_pad->index, | |
| 1339 | + flags & MEDIA_LNK_FL_ENABLED); | |
| 1193 | 1340 | |
| 1194 | − decoder->input = i; | |
| 1341 | + /* | |
| 1342 | + * The TVP5150 has an internal mux which allows the following setup: | |
| 1343 | + * | |
| 1344 | + * comp-connector1 --\ | |
| 1345 | + * |---> AIP1A | |
| 1346 | + * / | |
| 1347 | + * svideo-connector -| | |
| 1348 | + * \ | |
| 1349 | + * |---> AIP1B | |
| 1350 | + * comp-connector2 --/ | |
| 1351 | + * | |
| 1352 | + * We can't rely on user space that the current connector gets disabled | |
| 1353 | + * first before enabling the new connector. Disable all active | |
| 1354 | + * connector links to be on the safe side. | |
| 1355 | + */ | |
| 1356 | + err = tvp5150_disable_all_input_links(decoder); | |
| 1357 | + if (err) | |
| 1358 | + return err; | |
| 1359 | + | |
| 1360 | + tvp5150_s_routing(sd, is_svideo ? TVP5150_SVIDEO : tvp5150_pad->index, | |
| 1361 | + flags & MEDIA_LNK_FL_ENABLED ? TVP5150_NORMAL : | |
| 1362 | + TVP5150_BLACK_SCREEN, 0); | |
| 1363 | + | |
| 1364 | + if (flags & MEDIA_LNK_FL_ENABLED) { | |
| 1365 | + struct v4l2_fwnode_connector_analog *v4l2ca; | |
| 1366 | + u32 new_norm; | |
| 1367 | + | |
| 1368 | + /* | |
| 1369 | + * S-Video connector is conneted to both ports AIP1A and AIP1B. | |
| 1370 | + * Both links must be enabled in one-shot regardless which link | |
| 1371 | + * the user requests. | |
| 1372 | + */ | |
| 1373 | + if (is_svideo) { | |
| 1374 | + err = tvp5150_set_link((struct media_pad *)remote, | |
| 1375 | + other_tvp5150_pad, flags); | |
| 1376 | + if (err) | |
| 1377 | + return err; | |
| 1378 | + } | |
| 1195 | 1379 | |
| 1196 | − tvp5150_selmux(sd); | |
| 1380 | + if (!decoder->connectors_num) | |
| 1381 | + return 0; | |
| 1382 | + | |
| 1383 | + /* Update the current connector */ | |
| 1384 | + decoder->cur_connector = | |
| 1385 | + container_of(remote, struct tvp5150_connector, pad); | |
| 1386 | + | |
| 1387 | + /* | |
| 1388 | + * Do nothing if the new connector supports the same tv-norms as | |
| 1389 | + * the old one. | |
| 1390 | + */ | |
| 1391 | + v4l2ca = &decoder->cur_connector->base.connector.analog; | |
| 1392 | + new_norm = decoder->norm & v4l2ca->sdtv_stds; | |
| 1393 | + if (decoder->norm == new_norm) | |
| 1394 | + return 0; | |
| 1395 | + | |
| 1396 | + /* | |
| 1397 | + * Fallback to the new connector tv-norms if we can't find any | |
| 1398 | + * common between the current tv-norm and the new one. | |
| 1399 | + */ | |
| 1400 | + tvp5150_s_std(sd, new_norm ? new_norm : v4l2ca->sdtv_stds); | |
| 1401 | + } | |
| 1197 | 1402 | |
| 1198 | 1403 | return 0; |
| 1199 | 1404 | } |
| @@ -1202,20 +1407,54 @@ static const struct media_entity_operations tvp5150_sd_media_ops = { · 2 unmodified lines | ||
| 1202 | 1407 | .link_setup = tvp5150_link_setup, |
| 1203 | 1408 | }; |
| 1204 | 1409 | #endif |
| 1205 | − | |
| 1206 | 1410 | /**************************************************************************** |
| 1207 | 1411 | I2C Command |
| 1208 | 1412 | ****************************************************************************/ |
| 1413 | +static int __maybe_unused tvp5150_runtime_suspend(struct device *dev) | |
| 1414 | +{ | |
| 1415 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1416 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1417 | + struct tvp5150 *decoder = to_tvp5150(sd); | |
| 1418 | + | |
| 1419 | + if (decoder->irq) | |
| 1420 | + /* Disable lock interrupt */ | |
| 1421 | + return regmap_update_bits(decoder->regmap, | |
| 1422 | + TVP5150_INT_ENABLE_REG_A, | |
| 1423 | + TVP5150_INT_A_LOCK, 0); | |
| 1424 | + return 0; | |
| 1425 | +} | |
| 1426 | + | |
| 1427 | +static int __maybe_unused tvp5150_runtime_resume(struct device *dev) | |
| 1428 | +{ | |
| 1429 | + struct i2c_client *client = to_i2c_client(dev); | |
| 1430 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1431 | + struct tvp5150 *decoder = to_tvp5150(sd); | |
| 1432 | + | |
| 1433 | + if (decoder->irq) | |
| 1434 | + /* Enable lock interrupt */ | |
| 1435 | + return regmap_update_bits(decoder->regmap, | |
| 1436 | + TVP5150_INT_ENABLE_REG_A, | |
| 1437 | + TVP5150_INT_A_LOCK, | |
| 1438 | + TVP5150_INT_A_LOCK); | |
| 1439 | + return 0; | |
| 1440 | +} | |
| 1209 | 1441 | |
| 1210 | 1442 | static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) |
| 1211 | 1443 | { |
| 1212 | 1444 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 1213 | − unsigned int mask, val = 0, int_val = 0; | |
| 1445 | + unsigned int mask, val = 0; | |
| 1446 | + int ret; | |
| 1214 | 1447 | |
| 1215 | 1448 | mask = TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | |
| 1216 | 1449 | TVP5150_MISC_CTL_CLOCK_OE; |
| 1217 | 1450 | |
| 1218 | 1451 | if (enable) { |
| 1452 | + ret = pm_runtime_get_sync(sd->dev); | |
| 1453 | + if (ret < 0) { | |
| 1454 | + pm_runtime_put_noidle(sd->dev); | |
| 1455 | + return ret; | |
| 1456 | + } | |
| 1457 | + | |
| 1219 | 1458 | tvp5150_enable(sd); |
| 1220 | 1459 | |
| 1221 | 1460 | /* Enable outputs if decoder is locked */ |
| @@ -1223,15 +1462,13 @@ static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) · 1 unmodified line | ||
| 1223 | 1462 | val = decoder->lock ? decoder->oe : 0; |
| 1224 | 1463 | else |
| 1225 | 1464 | val = decoder->oe; |
| 1226 | − int_val = TVP5150_INT_A_LOCK; | |
| 1465 | + | |
| 1227 | 1466 | v4l2_subdev_notify_event(&decoder->sd, &tvp5150_ev_fmt); |
| 1467 | + } else { | |
| 1468 | + pm_runtime_put(sd->dev); | |
| 1228 | 1469 | } |
| 1229 | 1470 | |
| 1230 | 1471 | regmap_update_bits(decoder->regmap, TVP5150_MISC_CTL, mask, val); |
| 1231 | − if (decoder->irq) | |
| 1232 | − /* Enable / Disable lock interrupt */ | |
| 1233 | − regmap_update_bits(decoder->regmap, TVP5150_INT_ENABLE_REG_A, | |
| 1234 | − TVP5150_INT_A_LOCK, int_val); | |
| 1235 | 1472 | |
| 1236 | 1473 | return 0; |
| 1237 | 1474 | } |
| @@ -1342,6 +1579,19 @@ static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi · 104 unmodified lines | ||
| 1342 | 1579 | } |
| 1343 | 1580 | #endif |
| 1344 | 1581 | |
| 1582 | +static int tvp5150_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, | |
| 1583 | + struct v4l2_event_subscription *sub) | |
| 1584 | +{ | |
| 1585 | + switch (sub->type) { | |
| 1586 | + case V4L2_EVENT_SOURCE_CHANGE: | |
| 1587 | + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); | |
| 1588 | + case V4L2_EVENT_CTRL: | |
| 1589 | + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); | |
| 1590 | + default: | |
| 1591 | + return -EINVAL; | |
| 1592 | + } | |
| 1593 | +} | |
| 1594 | + | |
| 1345 | 1595 | static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) |
| 1346 | 1596 | { |
| 1347 | 1597 | int status = tvp5150_read(sd, 0x88); |
| @@ -1352,40 +1602,96 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) · 4 unmodified lines | ||
| 1352 | 1602 | |
| 1353 | 1603 | static int tvp5150_registered(struct v4l2_subdev *sd) |
| 1354 | 1604 | { |
| 1355 | −#ifdef CONFIG_MEDIA_CONTROLLER | |
| 1605 | +#if defined(CONFIG_MEDIA_CONTROLLER) | |
| 1356 | 1606 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 1357 | − int ret = 0; | |
| 1358 | − int i; | |
| 1359 | − | |
| 1360 | − for (i = 0; i < TVP5150_INPUT_NUM; i++) { | |
| 1361 | − struct media_entity *input = &decoder->input_ent[i]; | |
| 1362 | − struct media_pad *pad = &decoder->input_pad[i]; | |
| 1363 | − | |
| 1364 | − if (!input->name) | |
| 1365 | − continue; | |
| 1607 | + unsigned int i; | |
| 1608 | + int ret; | |
| 1366 | 1609 | |
| 1367 | − decoder->input_pad[i].flags = MEDIA_PAD_FL_SOURCE; | |
| 1610 | + /* | |
| 1611 | + * Setup connector pads and links. Enable the link to the first | |
| 1612 | + * available connector per default. | |
| 1613 | + */ | |
| 1614 | + for (i = 0; i < decoder->connectors_num; i++) { | |
| 1615 | + struct media_entity *con = &decoder->connectors[i].ent; | |
| 1616 | + struct media_pad *pad = &decoder->connectors[i].pad; | |
| 1617 | + struct v4l2_fwnode_connector *v4l2c = | |
| 1618 | + &decoder->connectors[i].base; | |
| 1619 | + struct v4l2_connector_link *link = | |
| 1620 | + v4l2_connector_first_link(v4l2c); | |
| 1621 | + unsigned int port = link->fwnode_link.remote_port; | |
| 1622 | + unsigned int flags = i ? 0 : MEDIA_LNK_FL_ENABLED; | |
| 1623 | + bool is_svideo = v4l2c->type == V4L2_CONN_SVIDEO; | |
| 1624 | + | |
| 1625 | + pad->flags = MEDIA_PAD_FL_SOURCE; | |
| 1626 | + ret = media_entity_pads_init(con, 1, pad); | |
| 1627 | + if (ret < 0) | |
| 1628 | + goto err; | |
| 1368 | 1629 | |
| 1369 | − ret = media_entity_pads_init(input, 1, pad); | |
| 1630 | + ret = media_device_register_entity(sd->v4l2_dev->mdev, con); | |
| 1370 | 1631 | if (ret < 0) |
| 1371 | − return ret; | |
| 1632 | + goto err; | |
| 1372 | 1633 | |
| 1373 | − ret = media_device_register_entity(sd->v4l2_dev->mdev, input); | |
| 1634 | + ret = media_create_pad_link(con, 0, &sd->entity, port, flags); | |
| 1374 | 1635 | if (ret < 0) |
| 1375 | − return ret; | |
| 1636 | + goto err; | |
| 1376 | 1637 | |
| 1377 | − ret = media_create_pad_link(input, 0, &sd->entity, | |
| 1378 | − TVP5150_PAD_IF_INPUT, 0); | |
| 1379 | − if (ret < 0) { | |
| 1380 | − media_device_unregister_entity(input); | |
| 1381 | − return ret; | |
| 1638 | + if (is_svideo) { | |
| 1639 | + /* | |
| 1640 | + * Check tvp5150_link_setup() comments for more | |
| 1641 | + * information. | |
| 1642 | + */ | |
| 1643 | + link = v4l2_connector_last_link(v4l2c); | |
| 1644 | + port = link->fwnode_link.remote_port; | |
| 1645 | + ret = media_create_pad_link(con, 0, &sd->entity, port, | |
| 1646 | + flags); | |
| 1647 | + if (ret < 0) | |
| 1648 | + goto err; | |
| 1649 | + } | |
| 1650 | + | |
| 1651 | + /* Enable default input. */ | |
| 1652 | + if (flags == MEDIA_LNK_FL_ENABLED) { | |
| 1653 | + decoder->input = | |
| 1654 | + is_svideo ? TVP5150_SVIDEO : | |
| 1655 | + port == 0 ? TVP5150_COMPOSITE0 : | |
| 1656 | + TVP5150_COMPOSITE1; | |
| 1657 | + | |
| 1658 | + tvp5150_selmux(sd); | |
| 1659 | + decoder->cur_connector = &decoder->connectors[i]; | |
| 1660 | + tvp5150_s_std(sd, v4l2c->connector.analog.sdtv_stds); | |
| 1382 | 1661 | } |
| 1383 | 1662 | } |
| 1663 | + | |
| 1664 | + return 0; | |
| 1665 | + | |
| 1666 | +err: | |
| 1667 | + for (i = 0; i < decoder->connectors_num; i++) | |
| 1668 | + media_device_unregister_entity(&decoder->connectors[i].ent); | |
| 1669 | + return ret; | |
| 1384 | 1670 | #endif |
| 1385 | 1671 | |
| 1386 | 1672 | return 0; |
| 1387 | 1673 | } |
| 1388 | 1674 | |
| 1675 | +static int tvp5150_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 1676 | +{ | |
| 1677 | + int ret; | |
| 1678 | + | |
| 1679 | + ret = pm_runtime_get_sync(sd->dev); | |
| 1680 | + if (ret < 0) { | |
| 1681 | + pm_runtime_put_noidle(sd->dev); | |
| 1682 | + return ret; | |
| 1683 | + } | |
| 1684 | + | |
| 1685 | + return 0; | |
| 1686 | +} | |
| 1687 | + | |
| 1688 | +static int tvp5150_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | |
| 1689 | +{ | |
| 1690 | + pm_runtime_put(sd->dev); | |
| 1691 | + | |
| 1692 | + return 0; | |
| 1693 | +} | |
| 1694 | + | |
| 1389 | 1695 | /* ----------------------------------------------------------------------- */ |
| 1390 | 1696 | |
| 1391 | 1697 | static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = { |
| @@ -1399,6 +1705,8 @@ static const struct v4l2_subdev_core_ops tvp5150_core_ops = { · 7 unmodified lines | ||
| 1399 | 1705 | .g_register = tvp5150_g_register, |
| 1400 | 1706 | .s_register = tvp5150_s_register, |
| 1401 | 1707 | #endif |
| 1708 | + .subscribe_event = tvp5150_subscribe_event, | |
| 1709 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1402 | 1710 | }; |
| 1403 | 1711 | |
| 1404 | 1712 | static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { |
| @@ -1441,6 +1749,8 @@ static const struct v4l2_subdev_ops tvp5150_ops = { · 36 unmodified lines | ||
| 1441 | 1749 | |
| 1442 | 1750 | static const struct v4l2_subdev_internal_ops tvp5150_internal_ops = { |
| 1443 | 1751 | .registered = tvp5150_registered, |
| 1752 | + .open = tvp5150_open, | |
| 1753 | + .close = tvp5150_close, | |
| 1444 | 1754 | }; |
| 1445 | 1755 | |
| 1446 | 1756 | /**************************************************************************** |
| @@ -1591,102 +1901,211 @@ static int tvp5150_init(struct i2c_client *c) · 144 unmodified lines | ||
| 1591 | 1901 | return 0; |
| 1592 | 1902 | } |
| 1593 | 1903 | |
| 1594 | −static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) | |
| 1904 | +#if defined(CONFIG_MEDIA_CONTROLLER) | |
| 1905 | +static int tvp5150_mc_init(struct tvp5150 *decoder) | |
| 1595 | 1906 | { |
| 1596 | − struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 }; | |
| 1597 | − struct device_node *ep; | |
| 1598 | −#ifdef CONFIG_MEDIA_CONTROLLER | |
| 1599 | − struct device_node *connectors, *child; | |
| 1600 | − struct media_entity *input; | |
| 1601 | − const char *name; | |
| 1602 | − u32 input_type; | |
| 1603 | −#endif | |
| 1604 | − unsigned int flags; | |
| 1605 | − int ret = 0; | |
| 1907 | + struct v4l2_subdev *sd = &decoder->sd; | |
| 1908 | + unsigned int i; | |
| 1606 | 1909 | |
| 1607 | − ep = of_graph_get_next_endpoint(np, NULL); | |
| 1608 | − if (!ep) | |
| 1609 | − return -EINVAL; | |
| 1910 | + sd->entity.ops = &tvp5150_sd_media_ops; | |
| 1911 | + sd->entity.function = MEDIA_ENT_F_ATV_DECODER; | |
| 1610 | 1912 | |
| 1611 | − ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); | |
| 1612 | − if (ret) | |
| 1613 | − goto err; | |
| 1913 | + for (i = 0; i < TVP5150_NUM_PADS - 1; i++) { | |
| 1914 | + decoder->pads[i].flags = MEDIA_PAD_FL_SINK; | |
| 1915 | + decoder->pads[i].sig_type = PAD_SIGNAL_ANALOG; | |
| 1916 | + } | |
| 1614 | 1917 | |
| 1615 | − flags = bus_cfg.bus.parallel.flags; | |
| 1918 | + decoder->pads[i].flags = MEDIA_PAD_FL_SOURCE; | |
| 1919 | + decoder->pads[i].sig_type = PAD_SIGNAL_DV; | |
| 1616 | 1920 | |
| 1617 | − if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && | |
| 1618 | − !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && | |
| 1619 | − flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && | |
| 1620 | − flags & V4L2_MBUS_FIELD_EVEN_LOW)) { | |
| 1621 | − ret = -EINVAL; | |
| 1622 | − goto err; | |
| 1623 | − } | |
| 1921 | + return media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, | |
| 1922 | + decoder->pads); | |
| 1923 | +} | |
| 1624 | 1924 | |
| 1625 | − decoder->mbus_type = bus_cfg.bus_type; | |
| 1925 | +#else /* !defined(CONFIG_MEDIA_CONTROLLER) */ | |
| 1626 | 1926 | |
| 1627 | −#ifdef CONFIG_MEDIA_CONTROLLER | |
| 1628 | − connectors = of_get_child_by_name(np, "connectors"); | |
| 1927 | +static inline int tvp5150_mc_init(struct tvp5150 *decoder) | |
| 1928 | +{ | |
| 1929 | + return 0; | |
| 1930 | +} | |
| 1931 | +#endif /* defined(CONFIG_MEDIA_CONTROLLER) */ | |
| 1629 | 1932 | |
| 1630 | − if (!connectors) | |
| 1631 | − goto err; | |
| 1933 | +static int tvp5150_validate_connectors(struct tvp5150 *decoder) | |
| 1934 | +{ | |
| 1935 | + struct device *dev = decoder->sd.dev; | |
| 1936 | + struct tvp5150_connector *tvpc; | |
| 1937 | + struct v4l2_fwnode_connector *v4l2c; | |
| 1938 | + unsigned int i; | |
| 1939 | + | |
| 1940 | + if (!decoder->connectors_num) { | |
| 1941 | + dev_err(dev, "No valid connector found\n"); | |
| 1942 | + return -ENODEV; | |
| 1943 | + } | |
| 1632 | 1944 | |
| 1633 | − for_each_available_child_of_node(connectors, child) { | |
| 1634 | − ret = of_property_read_u32(child, "input", &input_type); | |
| 1635 | − if (ret) { | |
| 1636 | − dev_err(decoder->sd.dev, | |
| 1637 | − "missing type property in node %pOFn\n", | |
| 1638 | − child); | |
| 1639 | − of_node_put(child); | |
| 1640 | − goto err_connector; | |
| 1945 | + for (i = 0; i < decoder->connectors_num; i++) { | |
| 1946 | + struct v4l2_connector_link *link0 = NULL; | |
| 1947 | + struct v4l2_connector_link *link1; | |
| 1948 | + | |
| 1949 | + tvpc = &decoder->connectors[i]; | |
| 1950 | + v4l2c = &tvpc->base; | |
| 1951 | + | |
| 1952 | + if (v4l2c->type == V4L2_CONN_COMPOSITE) { | |
| 1953 | + if (v4l2c->nr_of_links != 1) { | |
| 1954 | + dev_err(dev, "Composite: connector needs 1 link\n"); | |
| 1955 | + return -EINVAL; | |
| 1956 | + } | |
| 1957 | + link0 = v4l2_connector_first_link(v4l2c); | |
| 1958 | + if (!link0) { | |
| 1959 | + dev_err(dev, "Composite: invalid first link\n"); | |
| 1960 | + return -EINVAL; | |
| 1961 | + } | |
| 1962 | + if (link0->fwnode_link.remote_id == 1) { | |
| 1963 | + dev_err(dev, "Composite: invalid endpoint id\n"); | |
| 1964 | + return -EINVAL; | |
| 1965 | + } | |
| 1641 | 1966 | } |
| 1642 | 1967 | |
| 1643 | − if (input_type >= TVP5150_INPUT_NUM) { | |
| 1644 | − ret = -EINVAL; | |
| 1645 | − of_node_put(child); | |
| 1646 | − goto err_connector; | |
| 1968 | + if (v4l2c->type == V4L2_CONN_SVIDEO) { | |
| 1969 | + if (v4l2c->nr_of_links != 2) { | |
| 1970 | + dev_err(dev, "SVideo: connector needs 2 links\n"); | |
| 1971 | + return -EINVAL; | |
| 1972 | + } | |
| 1973 | + link0 = v4l2_connector_first_link(v4l2c); | |
| 1974 | + if (!link0) { | |
| 1975 | + dev_err(dev, "SVideo: invalid first link\n"); | |
| 1976 | + return -EINVAL; | |
| 1977 | + } | |
| 1978 | + link1 = v4l2_connector_last_link(v4l2c); | |
| 1979 | + if (link0->fwnode_link.remote_port == | |
| 1980 | + link1->fwnode_link.remote_port) { | |
| 1981 | + dev_err(dev, "SVideo: invalid link setup\n"); | |
| 1982 | + return -EINVAL; | |
| 1983 | + } | |
| 1647 | 1984 | } |
| 1648 | 1985 | |
| 1649 | − input = &decoder->input_ent[input_type]; | |
| 1986 | + if (!(v4l2c->connector.analog.sdtv_stds & TVP5150_STD_MASK)) { | |
| 1987 | + dev_err(dev, "Unsupported tv-norm on connector %s\n", | |
| 1988 | + v4l2c->name); | |
| 1989 | + return -EINVAL; | |
| 1990 | + } | |
| 1991 | + } | |
| 1992 | + | |
| 1993 | + return 0; | |
| 1994 | +} | |
| 1995 | + | |
| 1996 | +static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) | |
| 1997 | +{ | |
| 1998 | + struct device *dev = decoder->sd.dev; | |
| 1999 | + struct v4l2_fwnode_endpoint bus_cfg = { | |
| 2000 | + .bus_type = V4L2_MBUS_UNKNOWN | |
| 2001 | + }; | |
| 2002 | + struct device_node *ep_np; | |
| 2003 | + struct tvp5150_connector *tvpc; | |
| 2004 | + struct v4l2_fwnode_connector *v4l2c; | |
| 2005 | + unsigned int flags, ep_num; | |
| 2006 | + unsigned int i; | |
| 2007 | + int ret; | |
| 2008 | + | |
| 2009 | + /* At least 1 output and 1 input */ | |
| 2010 | + ep_num = of_graph_get_endpoint_count(np); | |
| 2011 | + if (ep_num < 2 || ep_num > 5) { | |
| 2012 | + dev_err(dev, "At least 1 input and 1 output must be connected to the device.\n"); | |
| 2013 | + return -EINVAL; | |
| 2014 | + } | |
| 1650 | 2015 | |
| 1651 | − /* Each input connector can only be defined once */ | |
| 1652 | − if (input->name) { | |
| 1653 | − dev_err(decoder->sd.dev, | |
| 1654 | − "input %s with same type already exists\n", | |
| 1655 | − input->name); | |
| 1656 | − of_node_put(child); | |
| 1657 | − ret = -EINVAL; | |
| 1658 | − goto err_connector; | |
| 2016 | + /* Layout if all connectors are used: | |
| 2017 | + * | |
| 2018 | + * tvp-5150 port@0 (AIP1A) | |
| 2019 | + * endpoint@0 -----------> Comp0-Con port | |
| 2020 | + * endpoint@1 --------+--> Svideo-Con port | |
| 2021 | + * tvp-5150 port@1 (AIP1B) | | |
| 2022 | + * endpoint@1 --------+ | |
| 2023 | + * endpoint@0 -----------> Comp1-Con port | |
| 2024 | + * tvp-5150 port@2 | |
| 2025 | + * endpoint (video bitstream output at YOUT[0-7] parallel bus) | |
| 2026 | + */ | |
| 2027 | + for_each_endpoint_of_node(np, ep_np) { | |
| 2028 | + struct fwnode_handle *ep_fwnode = of_fwnode_handle(ep_np); | |
| 2029 | + unsigned int next_connector = decoder->connectors_num; | |
| 2030 | + struct of_endpoint ep; | |
| 2031 | + | |
| 2032 | + of_graph_parse_endpoint(ep_np, &ep); | |
| 2033 | + if (ep.port > 1 || ep.id > 1) { | |
| 2034 | + dev_dbg(dev, "Ignore connector on port@%u/ep@%u\n", | |
| 2035 | + ep.port, ep.id); | |
| 2036 | + continue; | |
| 1659 | 2037 | } |
| 1660 | 2038 | |
| 1661 | − switch (input_type) { | |
| 1662 | − case TVP5150_COMPOSITE0: | |
| 1663 | − case TVP5150_COMPOSITE1: | |
| 1664 | − input->function = MEDIA_ENT_F_CONN_COMPOSITE; | |
| 1665 | − break; | |
| 1666 | − case TVP5150_SVIDEO: | |
| 1667 | − input->function = MEDIA_ENT_F_CONN_SVIDEO; | |
| 1668 | − break; | |
| 2039 | + tvpc = &decoder->connectors[next_connector]; | |
| 2040 | + v4l2c = &tvpc->base; | |
| 2041 | + | |
| 2042 | + if (ep.port == 0 || (ep.port == 1 && ep.id == 0)) { | |
| 2043 | + ret = v4l2_fwnode_connector_parse(ep_fwnode, v4l2c); | |
| 2044 | + if (ret) | |
| 2045 | + goto err_put; | |
| 2046 | + ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c); | |
| 2047 | + if (ret) | |
| 2048 | + goto err_put; | |
| 2049 | + decoder->connectors_num++; | |
| 2050 | + } else { | |
| 2051 | + /* Adding the 2nd svideo link */ | |
| 2052 | + for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) { | |
| 2053 | + tvpc = &decoder->connectors[i]; | |
| 2054 | + v4l2c = &tvpc->base; | |
| 2055 | + if (v4l2c->type == V4L2_CONN_SVIDEO) | |
| 2056 | + break; | |
| 2057 | + } | |
| 2058 | + | |
| 2059 | + ret = v4l2_fwnode_connector_add_link(ep_fwnode, v4l2c); | |
| 2060 | + if (ret) | |
| 2061 | + goto err_put; | |
| 1669 | 2062 | } |
| 2063 | + } | |
| 1670 | 2064 | |
| 1671 | − input->flags = MEDIA_ENT_FL_CONNECTOR; | |
| 2065 | + ret = tvp5150_validate_connectors(decoder); | |
| 2066 | + if (ret) | |
| 2067 | + goto err_free; | |
| 2068 | + | |
| 2069 | + for (i = 0; i < decoder->connectors_num; i++) { | |
| 2070 | + tvpc = &decoder->connectors[i]; | |
| 2071 | + v4l2c = &tvpc->base; | |
| 2072 | + tvpc->ent.flags = MEDIA_ENT_FL_CONNECTOR; | |
| 2073 | + tvpc->ent.function = v4l2c->type == V4L2_CONN_SVIDEO ? | |
| 2074 | + MEDIA_ENT_F_CONN_SVIDEO : MEDIA_ENT_F_CONN_COMPOSITE; | |
| 2075 | + tvpc->ent.name = devm_kasprintf(dev, GFP_KERNEL, "%s %s", | |
| 2076 | + v4l2c->name, v4l2c->label ? | |
| 2077 | + v4l2c->label : ""); | |
| 2078 | + } | |
| 1672 | 2079 | |
| 1673 | − ret = of_property_read_string(child, "label", &name); | |
| 1674 | − if (ret < 0) { | |
| 1675 | − dev_err(decoder->sd.dev, | |
| 1676 | − "missing label property in node %pOFn\n", | |
| 1677 | − child); | |
| 1678 | − of_node_put(child); | |
| 1679 | − goto err_connector; | |
| 1680 | − } | |
| 2080 | + ep_np = of_graph_get_endpoint_by_regs(np, TVP5150_PAD_VID_OUT, 0); | |
| 2081 | + if (!ep_np) { | |
| 2082 | + dev_err(dev, "Error no output endpoint available\n"); | |
| 2083 | + goto err_free; | |
| 2084 | + } | |
| 2085 | + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_np), &bus_cfg); | |
| 2086 | + of_node_put(ep_np); | |
| 2087 | + if (ret) | |
| 2088 | + goto err_free; | |
| 1681 | 2089 | |
| 1682 | − input->name = name; | |
| 2090 | + flags = bus_cfg.bus.parallel.flags; | |
| 2091 | + if (bus_cfg.bus_type == V4L2_MBUS_PARALLEL && | |
| 2092 | + !(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH && | |
| 2093 | + flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH && | |
| 2094 | + flags & V4L2_MBUS_FIELD_EVEN_LOW)) { | |
| 2095 | + ret = -EINVAL; | |
| 2096 | + goto err_free; | |
| 1683 | 2097 | } |
| 1684 | 2098 | |
| 1685 | −err_connector: | |
| 1686 | − of_node_put(connectors); | |
| 1687 | −#endif | |
| 1688 | −err: | |
| 1689 | − of_node_put(ep); | |
| 2099 | + decoder->mbus_type = bus_cfg.bus_type; | |
| 2100 | + | |
| 2101 | + return 0; | |
| 2102 | + | |
| 2103 | +err_put: | |
| 2104 | + of_node_put(ep_np); | |
| 2105 | +err_free: | |
| 2106 | + for (i = 0; i < TVP5150_MAX_CONNECTORS; i++) | |
| 2107 | + v4l2_fwnode_connector_free(&decoder->connectors[i].base); | |
| 2108 | + | |
| 1690 | 2109 | return ret; |
| 1691 | 2110 | } |
| 1692 | 2111 | |
| @@ -1701,6 +2120,7 @@ static int tvp5150_probe(struct i2c_client *c) · 8 unmodified lines | ||
| 1701 | 2120 | struct v4l2_subdev *sd; |
| 1702 | 2121 | struct device_node *np = c->dev.of_node; |
| 1703 | 2122 | struct regmap *map; |
| 2123 | + unsigned int i; | |
| 1704 | 2124 | int res; |
| 1705 | 2125 | |
| 1706 | 2126 | /* Check if the adapter supports the needed features */ |
| @@ -1722,6 +2142,9 @@ static int tvp5150_probe(struct i2c_client *c) · 15 unmodified lines | ||
| 1722 | 2142 | |
| 1723 | 2143 | core->regmap = map; |
| 1724 | 2144 | sd = &core->sd; |
| 2145 | + v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); | |
| 2146 | + sd->internal_ops = &tvp5150_internal_ops; | |
| 2147 | + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1725 | 2148 | |
| 1726 | 2149 | if (IS_ENABLED(CONFIG_OF) && np) { |
| 1727 | 2150 | res = tvp5150_parse_dt(core, np); |
| @@ -1734,30 +2157,29 @@ static int tvp5150_probe(struct i2c_client *c) · 6 unmodified lines | ||
| 1734 | 2157 | core->mbus_type = V4L2_MBUS_BT656; |
| 1735 | 2158 | } |
| 1736 | 2159 | |
| 1737 | − v4l2_i2c_subdev_init(sd, c, &tvp5150_ops); | |
| 1738 | − sd->internal_ops = &tvp5150_internal_ops; | |
| 1739 | − sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | |
| 1740 | − | |
| 1741 | −#if defined(CONFIG_MEDIA_CONTROLLER) | |
| 1742 | − core->pads[TVP5150_PAD_IF_INPUT].flags = MEDIA_PAD_FL_SINK; | |
| 1743 | − core->pads[TVP5150_PAD_IF_INPUT].sig_type = PAD_SIGNAL_ANALOG; | |
| 1744 | − core->pads[TVP5150_PAD_VID_OUT].flags = MEDIA_PAD_FL_SOURCE; | |
| 1745 | − core->pads[TVP5150_PAD_VID_OUT].sig_type = PAD_SIGNAL_DV; | |
| 1746 | − | |
| 1747 | − sd->entity.function = MEDIA_ENT_F_ATV_DECODER; | |
| 1748 | − | |
| 1749 | − res = media_entity_pads_init(&sd->entity, TVP5150_NUM_PADS, core->pads); | |
| 1750 | − if (res < 0) | |
| 2160 | + res = tvp5150_mc_init(core); | |
| 2161 | + if (res) | |
| 1751 | 2162 | return res; |
| 1752 | 2163 | |
| 1753 | − sd->entity.ops = &tvp5150_sd_media_ops; | |
| 1754 | −#endif | |
| 1755 | − | |
| 1756 | 2164 | res = tvp5150_detect_version(core); |
| 1757 | 2165 | if (res < 0) |
| 1758 | 2166 | return res; |
| 1759 | 2167 | |
| 1760 | − core->norm = V4L2_STD_ALL; /* Default is autodetect */ | |
| 2168 | + /* | |
| 2169 | + * Iterate over all available connectors in case they are supported and | |
| 2170 | + * successfully parsed. Fallback to default autodetect in case they | |
| 2171 | + * aren't supported. | |
| 2172 | + */ | |
| 2173 | + for (i = 0; i < core->connectors_num; i++) { | |
| 2174 | + struct v4l2_fwnode_connector *v4l2c; | |
| 2175 | + | |
| 2176 | + v4l2c = &core->connectors[i].base; | |
| 2177 | + core->norm |= v4l2c->connector.analog.sdtv_stds; | |
| 2178 | + } | |
| 2179 | + | |
| 2180 | + if (!core->connectors_num) | |
| 2181 | + core->norm = V4L2_STD_ALL; | |
| 2182 | + | |
| 1761 | 2183 | core->detected_norm = V4L2_STD_UNKNOWN; |
| 1762 | 2184 | core->input = TVP5150_COMPOSITE1; |
| 1763 | 2185 | core->enable = true; |
| @@ -1802,6 +2224,11 @@ static int tvp5150_probe(struct i2c_client *c) · 38 unmodified lines | ||
| 1802 | 2224 | |
| 1803 | 2225 | if (debug > 1) |
| 1804 | 2226 | tvp5150_log_status(sd); |
| 2227 | + | |
| 2228 | + pm_runtime_set_active(&c->dev); | |
| 2229 | + pm_runtime_enable(&c->dev); | |
| 2230 | + pm_runtime_idle(&c->dev); | |
| 2231 | + | |
| 1805 | 2232 | return 0; |
| 1806 | 2233 | |
| 1807 | 2234 | err: |
| @@ -1813,18 +2240,32 @@ static int tvp5150_remove(struct i2c_client *c) · 5 unmodified lines | ||
| 1813 | 2240 | { |
| 1814 | 2241 | struct v4l2_subdev *sd = i2c_get_clientdata(c); |
| 1815 | 2242 | struct tvp5150 *decoder = to_tvp5150(sd); |
| 2243 | + unsigned int i; | |
| 1816 | 2244 | |
| 1817 | 2245 | dev_dbg_lvl(sd->dev, 1, debug, |
| 1818 | 2246 | "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", |
| 1819 | 2247 | c->addr << 1); |
| 1820 | 2248 | |
| 2249 | + for (i = 0; i < decoder->connectors_num; i++) | |
| 2250 | + v4l2_fwnode_connector_free(&decoder->connectors[i].base); | |
| 2251 | + for (i = 0; i < decoder->connectors_num; i++) | |
| 2252 | + media_device_unregister_entity(&decoder->connectors[i].ent); | |
| 1821 | 2253 | v4l2_async_unregister_subdev(sd); |
| 1822 | 2254 | v4l2_ctrl_handler_free(&decoder->hdl); |
| 2255 | + pm_runtime_disable(&c->dev); | |
| 2256 | + pm_runtime_set_suspended(&c->dev); | |
| 2257 | + | |
| 1823 | 2258 | return 0; |
| 1824 | 2259 | } |
| 1825 | 2260 | |
| 1826 | 2261 | /* ----------------------------------------------------------------------- */ |
| 1827 | 2262 | |
| 2263 | +static const struct dev_pm_ops tvp5150_pm_ops = { | |
| 2264 | + SET_RUNTIME_PM_OPS(tvp5150_runtime_suspend, | |
| 2265 | + tvp5150_runtime_resume, | |
| 2266 | + NULL) | |
| 2267 | +}; | |
| 2268 | + | |
| 1828 | 2269 | static const struct i2c_device_id tvp5150_id[] = { |
| 1829 | 2270 | { "tvp5150", 0 }, |
| 1830 | 2271 | { } |
| @@ -1843,6 +2284,7 @@ static struct i2c_driver tvp5150_driver = { · 12 unmodified lines | ||
| 1843 | 2284 | .driver = { |
| 1844 | 2285 | .of_match_table = of_match_ptr(tvp5150_of_match), |
| 1845 | 2286 | .name = "tvp5150", |
| 2287 | + .pm = &tvp5150_pm_ops, | |
| 1846 | 2288 | }, |
| 1847 | 2289 | .probe_new = tvp5150_probe, |
| 1848 | 2290 | .remove = tvp5150_remove, |
| @@ -255,7 +255,7 @@ static int amg88xx_set_power(struct video_i2c_data *data, bool on) · 254 unmodified lines | ||
| 255 | 255 | return amg88xx_set_power_off(data); |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | −#if IS_ENABLED(CONFIG_HWMON) | |
| 258 | +#if IS_REACHABLE(CONFIG_HWMON) | |
| 259 | 259 | |
| 260 | 260 | static const u32 amg88xx_temp_config[] = { |
| 261 | 261 | HWMON_T_INPUT, |
| @@ -858,7 +858,7 @@ static int video_i2c_probe(struct i2c_client *client, · 596 unmodified lines | ||
| 858 | 858 | } |
| 859 | 859 | } |
| 860 | 860 | |
| 861 | − ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1); | |
| 861 | + ret = video_register_device(&data->vdev, VFL_TYPE_VIDEO, -1); | |
| 862 | 862 | if (ret < 0) |
| 863 | 863 | goto error_pm_disable; |
| 864 | 864 | |
| @@ -662,9 +662,14 @@ media_create_pad_link(struct media_entity *source, u16 source_pad, · 661 unmodified lines | ||
| 662 | 662 | struct media_link *link; |
| 663 | 663 | struct media_link *backlink; |
| 664 | 664 | |
| 665 | − BUG_ON(source == NULL || sink == NULL); | |
| 666 | − BUG_ON(source_pad >= source->num_pads); | |
| 667 | − BUG_ON(sink_pad >= sink->num_pads); | |
| 665 | + if (WARN_ON(!source || !sink) || | |
| 666 | + WARN_ON(source_pad >= source->num_pads) || | |
| 667 | + WARN_ON(sink_pad >= sink->num_pads)) | |
| 668 | + return -EINVAL; | |
| 669 | + if (WARN_ON(!(source->pads[source_pad].flags & MEDIA_PAD_FL_SOURCE))) | |
| 670 | + return -EINVAL; | |
| 671 | + if (WARN_ON(!(sink->pads[sink_pad].flags & MEDIA_PAD_FL_SINK))) | |
| 672 | + return -EINVAL; | |
| 668 | 673 | |
| 669 | 674 | link = media_add_link(&source->links); |
| 670 | 675 | if (link == NULL) |
| @@ -2964,7 +2964,7 @@ static int bttv_open(struct file *file) · 2963 unmodified lines | ||
| 2964 | 2964 | |
| 2965 | 2965 | dprintk("open dev=%s\n", video_device_node_name(vdev)); |
| 2966 | 2966 | |
| 2967 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) { | |
| 2967 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) { | |
| 2968 | 2968 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 2969 | 2969 | } else if (vdev->vfl_type == VFL_TYPE_VBI) { |
| 2970 | 2970 | type = V4L2_BUF_TYPE_VBI_CAPTURE; |
| @@ -3905,7 +3905,7 @@ static int bttv_register_video(struct bttv *btv) · 934 unmodified lines | ||
| 3905 | 3905 | if (no_overlay <= 0) |
| 3906 | 3906 | btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY; |
| 3907 | 3907 | |
| 3908 | − if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER, | |
| 3908 | + if (video_register_device(&btv->video_dev, VFL_TYPE_VIDEO, | |
| 3909 | 3909 | video_nr[btv->c.nr]) < 0) |
| 3910 | 3910 | goto err; |
| 3911 | 3911 | pr_info("%d: registered device %s\n", |
| @@ -1272,7 +1272,7 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) · 1271 unmodified lines | ||
| 1272 | 1272 | video_set_drvdata(vdev, s); |
| 1273 | 1273 | ret = vb2_queue_init(q); |
| 1274 | 1274 | if (!s->is_audio && ret == 0) |
| 1275 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1275 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1276 | 1276 | else if (!s->is_dummy) |
| 1277 | 1277 | ret = cobalt_alsa_init(s); |
| 1278 | 1278 | |
| @@ -48,19 +48,19 @@ static struct { · 47 unmodified lines | ||
| 48 | 48 | } cx18_stream_info[] = { |
| 49 | 49 | { /* CX18_ENC_STREAM_TYPE_MPG */ |
| 50 | 50 | "encoder MPEG", |
| 51 | − VFL_TYPE_GRABBER, 0, | |
| 51 | + VFL_TYPE_VIDEO, 0, | |
| 52 | 52 | PCI_DMA_FROMDEVICE, |
| 53 | 53 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
| 54 | 54 | V4L2_CAP_AUDIO | V4L2_CAP_TUNER |
| 55 | 55 | }, |
| 56 | 56 | { /* CX18_ENC_STREAM_TYPE_TS */ |
| 57 | 57 | "TS", |
| 58 | − VFL_TYPE_GRABBER, -1, | |
| 58 | + VFL_TYPE_VIDEO, -1, | |
| 59 | 59 | PCI_DMA_FROMDEVICE, |
| 60 | 60 | }, |
| 61 | 61 | { /* CX18_ENC_STREAM_TYPE_YUV */ |
| 62 | 62 | "encoder YUV", |
| 63 | − VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, | |
| 63 | + VFL_TYPE_VIDEO, CX18_V4L2_ENC_YUV_OFFSET, | |
| 64 | 64 | PCI_DMA_FROMDEVICE, |
| 65 | 65 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
| 66 | 66 | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER |
| @@ -74,13 +74,13 @@ static struct { · 7 unmodified lines | ||
| 74 | 74 | }, |
| 75 | 75 | { /* CX18_ENC_STREAM_TYPE_PCM */ |
| 76 | 76 | "encoder PCM audio", |
| 77 | − VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, | |
| 77 | + VFL_TYPE_VIDEO, CX18_V4L2_ENC_PCM_OFFSET, | |
| 78 | 78 | PCI_DMA_FROMDEVICE, |
| 79 | 79 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| 80 | 80 | }, |
| 81 | 81 | { /* CX18_ENC_STREAM_TYPE_IDX */ |
| 82 | 82 | "encoder IDX", |
| 83 | − VFL_TYPE_GRABBER, -1, | |
| 83 | + VFL_TYPE_VIDEO, -1, | |
| 84 | 84 | PCI_DMA_FROMDEVICE, |
| 85 | 85 | }, |
| 86 | 86 | { /* CX18_ENC_STREAM_TYPE_RAD */ |
| @@ -434,7 +434,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) · 347 unmodified lines | ||
| 434 | 434 | name = video_device_node_name(&s->video_dev); |
| 435 | 435 | |
| 436 | 436 | switch (vfl_type) { |
| 437 | − case VFL_TYPE_GRABBER: | |
| 437 | + case VFL_TYPE_VIDEO: | |
| 438 | 438 | CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", |
| 439 | 439 | name, s->name, cx->stream_buffers[type], |
| 440 | 440 | cx->stream_buf_size[type] / 1024, |
| @@ -1545,7 +1545,7 @@ int cx23885_417_register(struct cx23885_dev *dev) · 1544 unmodified lines | ||
| 1545 | 1545 | if (dev->tuner_type != TUNER_ABSENT) |
| 1546 | 1546 | dev->v4l_device->device_caps |= V4L2_CAP_TUNER; |
| 1547 | 1547 | err = video_register_device(dev->v4l_device, |
| 1548 | − VFL_TYPE_GRABBER, -1); | |
| 1548 | + VFL_TYPE_VIDEO, -1); | |
| 1549 | 1549 | if (err < 0) { |
| 1550 | 1550 | pr_info("%s: can't register mpeg device\n", dev->name); |
| 1551 | 1551 | return err; |
| @@ -1304,7 +1304,7 @@ int cx23885_video_register(struct cx23885_dev *dev) · 1303 unmodified lines | ||
| 1304 | 1304 | V4L2_CAP_AUDIO | V4L2_CAP_VIDEO_CAPTURE; |
| 1305 | 1305 | if (dev->tuner_type != TUNER_ABSENT) |
| 1306 | 1306 | dev->video_dev->device_caps |= V4L2_CAP_TUNER; |
| 1307 | − err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, | |
| 1307 | + err = video_register_device(dev->video_dev, VFL_TYPE_VIDEO, | |
| 1308 | 1308 | video_nr[dev->nr]); |
| 1309 | 1309 | if (err < 0) { |
| 1310 | 1310 | pr_info("%s: can't register video device\n", |
| @@ -757,7 +757,7 @@ int cx25821_video_register(struct cx25821_dev *dev) · 756 unmodified lines | ||
| 757 | 757 | snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); |
| 758 | 758 | video_set_drvdata(vdev, chan); |
| 759 | 759 | |
| 760 | − err = video_register_device(vdev, VFL_TYPE_GRABBER, | |
| 760 | + err = video_register_device(vdev, VFL_TYPE_VIDEO, | |
| 761 | 761 | video_nr[dev->nr]); |
| 762 | 762 | |
| 763 | 763 | if (err < 0) |
| @@ -1138,7 +1138,7 @@ static int blackbird_register_video(struct cx8802_dev *dev) · 1137 unmodified lines | ||
| 1138 | 1138 | V4L2_CAP_VIDEO_CAPTURE; |
| 1139 | 1139 | if (dev->core->board.tuner_type != UNSET) |
| 1140 | 1140 | dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER; |
| 1141 | − err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1); | |
| 1141 | + err = video_register_device(&dev->mpeg_dev, VFL_TYPE_VIDEO, -1); | |
| 1142 | 1142 | if (err < 0) { |
| 1143 | 1143 | pr_info("can't register mpeg device\n"); |
| 1144 | 1144 | return err; |
| @@ -1451,7 +1451,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, · 1450 unmodified lines | ||
| 1451 | 1451 | V4L2_CAP_VIDEO_CAPTURE; |
| 1452 | 1452 | if (core->board.tuner_type != UNSET) |
| 1453 | 1453 | dev->video_dev.device_caps |= V4L2_CAP_TUNER; |
| 1454 | − err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, | |
| 1454 | + err = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, | |
| 1455 | 1455 | video_nr[core->nr]); |
| 1456 | 1456 | if (err < 0) { |
| 1457 | 1457 | pr_err("can't register video device\n"); |
| @@ -550,7 +550,7 @@ static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) · 549 unmodified lines | ||
| 550 | 550 | IRQF_SHARED, DT3155_NAME, pd); |
| 551 | 551 | if (err) |
| 552 | 552 | goto err_iounmap; |
| 553 | − err = video_register_device(&pd->vdev, VFL_TYPE_GRABBER, -1); | |
| 553 | + err = video_register_device(&pd->vdev, VFL_TYPE_VIDEO, -1); | |
| 554 | 554 | if (err) |
| 555 | 555 | goto err_free_irq; |
| 556 | 556 | dev_info(&pdev->dev, "/dev/video%i is ready\n", pd->vdev.minor); |
| @@ -1647,7 +1647,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) · 1646 unmodified lines | ||
| 1647 | 1647 | vdev->queue = &q->vbq; |
| 1648 | 1648 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; |
| 1649 | 1649 | video_set_drvdata(vdev, cio2); |
| 1650 | − r = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1650 | + r = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1651 | 1651 | if (r) { |
| 1652 | 1652 | dev_err(&cio2->pci_dev->dev, |
| 1653 | 1653 | "failed to register video device (%d)\n", r); |
| @@ -99,7 +99,7 @@ static struct { · 98 unmodified lines | ||
| 99 | 99 | } ivtv_stream_info[] = { |
| 100 | 100 | { /* IVTV_ENC_STREAM_TYPE_MPG */ |
| 101 | 101 | "encoder MPG", |
| 102 | − VFL_TYPE_GRABBER, 0, | |
| 102 | + VFL_TYPE_VIDEO, 0, | |
| 103 | 103 | PCI_DMA_FROMDEVICE, 0, |
| 104 | 104 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | |
| 105 | 105 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| @@ -107,7 +107,7 @@ static struct { · 1 unmodified line | ||
| 107 | 107 | }, |
| 108 | 108 | { /* IVTV_ENC_STREAM_TYPE_YUV */ |
| 109 | 109 | "encoder YUV", |
| 110 | − VFL_TYPE_GRABBER, IVTV_V4L2_ENC_YUV_OFFSET, | |
| 110 | + VFL_TYPE_VIDEO, IVTV_V4L2_ENC_YUV_OFFSET, | |
| 111 | 111 | PCI_DMA_FROMDEVICE, 0, |
| 112 | 112 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | |
| 113 | 113 | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| @@ -123,7 +123,7 @@ static struct { · 9 unmodified lines | ||
| 123 | 123 | }, |
| 124 | 124 | { /* IVTV_ENC_STREAM_TYPE_PCM */ |
| 125 | 125 | "encoder PCM", |
| 126 | − VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET, | |
| 126 | + VFL_TYPE_VIDEO, IVTV_V4L2_ENC_PCM_OFFSET, | |
| 127 | 127 | PCI_DMA_FROMDEVICE, 0, |
| 128 | 128 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| 129 | 129 | &ivtv_v4l2_enc_fops |
| @@ -137,7 +137,7 @@ static struct { · 7 unmodified lines | ||
| 137 | 137 | }, |
| 138 | 138 | { /* IVTV_DEC_STREAM_TYPE_MPG */ |
| 139 | 139 | "decoder MPG", |
| 140 | − VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, | |
| 140 | + VFL_TYPE_VIDEO, IVTV_V4L2_DEC_MPG_OFFSET, | |
| 141 | 141 | PCI_DMA_TODEVICE, 0, |
| 142 | 142 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| 143 | 143 | &ivtv_v4l2_dec_fops |
| @@ -158,7 +158,7 @@ static struct { · 14 unmodified lines | ||
| 158 | 158 | }, |
| 159 | 159 | { /* IVTV_DEC_STREAM_TYPE_YUV */ |
| 160 | 160 | "decoder YUV", |
| 161 | − VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, | |
| 161 | + VFL_TYPE_VIDEO, IVTV_V4L2_DEC_YUV_OFFSET, | |
| 162 | 162 | PCI_DMA_TODEVICE, 0, |
| 163 | 163 | V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, |
| 164 | 164 | &ivtv_v4l2_dec_fops |
| @@ -318,7 +318,7 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) · 153 unmodified lines | ||
| 318 | 318 | name = video_device_node_name(&s->vdev); |
| 319 | 319 | |
| 320 | 320 | switch (vfl_type) { |
| 321 | − case VFL_TYPE_GRABBER: | |
| 321 | + case VFL_TYPE_VIDEO: | |
| 322 | 322 | IVTV_INFO("Registered device %s for %s (%d kB)\n", |
| 323 | 323 | name, s->name, itv->options.kilobytes[type]); |
| 324 | 324 | break; |
| @@ -1711,7 +1711,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) · 1710 unmodified lines | ||
| 1711 | 1711 | v4l2_ctrl_handler_setup(&meye.hdl); |
| 1712 | 1712 | meye.vdev.ctrl_handler = &meye.hdl; |
| 1713 | 1713 | |
| 1714 | − if (video_register_device(&meye.vdev, VFL_TYPE_GRABBER, | |
| 1714 | + if (video_register_device(&meye.vdev, VFL_TYPE_VIDEO, | |
| 1715 | 1715 | video_nr) < 0) { |
| 1716 | 1716 | v4l2_err(v4l2_dev, "video_register_device failed\n"); |
| 1717 | 1717 | goto outvideoreg; |
| @@ -1214,7 +1214,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, · 1213 unmodified lines | ||
| 1214 | 1214 | if (saa7134_no_overlay <= 0) |
| 1215 | 1215 | dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY; |
| 1216 | 1216 | |
| 1217 | − err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | |
| 1217 | + err = video_register_device(dev->video_dev,VFL_TYPE_VIDEO, | |
| 1218 | 1218 | video_nr[dev->nr]); |
| 1219 | 1219 | if (err < 0) { |
| 1220 | 1220 | pr_info("%s: can't register video device\n", |
| @@ -291,7 +291,7 @@ static int empress_init(struct saa7134_dev *dev) · 290 unmodified lines | ||
| 291 | 291 | dev->empress_dev->device_caps |= V4L2_CAP_TUNER; |
| 292 | 292 | |
| 293 | 293 | video_set_drvdata(dev->empress_dev, dev); |
| 294 | − err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, | |
| 294 | + err = video_register_device(dev->empress_dev,VFL_TYPE_VIDEO, | |
| 295 | 295 | empress_nr[dev->nr]); |
| 296 | 296 | if (err < 0) { |
| 297 | 297 | pr_info("%s: can't register video device\n", |
| @@ -289,7 +289,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d · 288 unmodified lines | ||
| 289 | 289 | vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; |
| 290 | 290 | vv_data.vid_ops.vidioc_g_input = vidioc_g_input; |
| 291 | 291 | vv_data.vid_ops.vidioc_s_input = vidioc_s_input; |
| 292 | − ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER); | |
| 292 | + ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_VIDEO); | |
| 293 | 293 | if (ret < 0) { |
| 294 | 294 | pr_err("cannot register capture v4l2 device. skipping.\n"); |
| 295 | 295 | saa7146_vv_release(dev); |
| @@ -362,7 +362,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d · 361 unmodified lines | ||
| 362 | 362 | vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input; |
| 363 | 363 | vv_data.vid_ops.vidioc_g_input = vidioc_g_input; |
| 364 | 364 | vv_data.vid_ops.vidioc_s_input = vidioc_s_input; |
| 365 | − if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { | |
| 365 | + if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_VIDEO)) { | |
| 366 | 366 | pr_err("cannot register capture v4l2 device. skipping.\n"); |
| 367 | 367 | return -1; |
| 368 | 368 | } |
| @@ -707,7 +707,7 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data · 706 unmodified lines | ||
| 707 | 707 | vv_data.vid_ops.vidioc_g_register = vidioc_g_register; |
| 708 | 708 | vv_data.vid_ops.vidioc_s_register = vidioc_s_register; |
| 709 | 709 | #endif |
| 710 | − if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { | |
| 710 | + if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_VIDEO)) { | |
| 711 | 711 | ERR("cannot register capture v4l2 device. skipping.\n"); |
| 712 | 712 | saa7146_vv_release(dev); |
| 713 | 713 | return -1; |
| @@ -1087,7 +1087,7 @@ int saa7164_encoder_register(struct saa7164_port *port) · 1086 unmodified lines | ||
| 1087 | 1087 | v4l2_ctrl_handler_setup(hdl); |
| 1088 | 1088 | video_set_drvdata(port->v4l_device, port); |
| 1089 | 1089 | result = video_register_device(port->v4l_device, |
| 1090 | − VFL_TYPE_GRABBER, -1); | |
| 1090 | + VFL_TYPE_VIDEO, -1); | |
| 1091 | 1091 | if (result < 0) { |
| 1092 | 1092 | printk(KERN_INFO "%s: can't register mpeg device\n", |
| 1093 | 1093 | dev->name); |
| @@ -1304,7 +1304,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, · 1303 unmodified lines | ||
| 1304 | 1304 | solo_enc->vfd->queue = &solo_enc->vidq; |
| 1305 | 1305 | solo_enc->vfd->lock = &solo_enc->lock; |
| 1306 | 1306 | video_set_drvdata(solo_enc->vfd, solo_enc); |
| 1307 | − ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); | |
| 1307 | + ret = video_register_device(solo_enc->vfd, VFL_TYPE_VIDEO, nr); | |
| 1308 | 1308 | if (ret < 0) |
| 1309 | 1309 | goto vdev_release; |
| 1310 | 1310 | |
| @@ -692,7 +692,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) · 691 unmodified lines | ||
| 692 | 692 | while (erase_off(solo_dev)) |
| 693 | 693 | /* Do nothing */; |
| 694 | 694 | |
| 695 | − ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); | |
| 695 | + ret = video_register_device(solo_dev->vfd, VFL_TYPE_VIDEO, nr); | |
| 696 | 696 | if (ret < 0) |
| 697 | 697 | goto fail; |
| 698 | 698 | |
| @@ -1069,7 +1069,7 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev, · 1068 unmodified lines | ||
| 1069 | 1069 | vip->video_dev.lock = &vip->v4l_lock; |
| 1070 | 1070 | video_set_drvdata(&vip->video_dev, vip); |
| 1071 | 1071 | |
| 1072 | − ret = video_register_device(&vip->video_dev, VFL_TYPE_GRABBER, -1); | |
| 1072 | + ret = video_register_device(&vip->video_dev, VFL_TYPE_VIDEO, -1); | |
| 1073 | 1073 | if (ret) |
| 1074 | 1074 | goto vrelease; |
| 1075 | 1075 | |
| @@ -831,7 +831,7 @@ int av7110_init_v4l(struct av7110 *av7110) · 830 unmodified lines | ||
| 831 | 831 | if (FW_VERSION(av7110->arm_app) < 0x2623) |
| 832 | 832 | vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT; |
| 833 | 833 | |
| 834 | − if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { | |
| 834 | + if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_VIDEO)) { | |
| 835 | 835 | ERR("cannot register capture device. skipping\n"); |
| 836 | 836 | saa7146_vv_release(dev); |
| 837 | 837 | return -ENODEV; |
| @@ -1470,7 +1470,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio · 1469 unmodified lines | ||
| 1470 | 1470 | vv_data.vid_ops.vidioc_g_input = vidioc_g_input; |
| 1471 | 1471 | vv_data.vid_ops.vidioc_s_input = vidioc_s_input; |
| 1472 | 1472 | |
| 1473 | − if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { | |
| 1473 | + if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_VIDEO))) { | |
| 1474 | 1474 | /* fixme: proper cleanup here */ |
| 1475 | 1475 | ERR("cannot register capture v4l2 device\n"); |
| 1476 | 1476 | saa7146_vv_release(dev); |
| @@ -1156,7 +1156,7 @@ static int tw5864_video_input_init(struct tw5864_input *input, int video_nr) · 1155 unmodified lines | ||
| 1156 | 1156 | input->gop = GOP_SIZE; |
| 1157 | 1157 | input->frame_interval = 1; |
| 1158 | 1158 | |
| 1159 | − ret = video_register_device(&input->vdev, VFL_TYPE_GRABBER, video_nr); | |
| 1159 | + ret = video_register_device(&input->vdev, VFL_TYPE_VIDEO, video_nr); | |
| 1160 | 1160 | if (ret) |
| 1161 | 1161 | goto free_v4l2_hdl; |
| 1162 | 1162 | |
| @@ -962,7 +962,7 @@ int tw68_video_init2(struct tw68_dev *dev, int video_nr) · 961 unmodified lines | ||
| 962 | 962 | dev->vdev.lock = &dev->lock; |
| 963 | 963 | dev->vdev.queue = &dev->vidq; |
| 964 | 964 | video_set_drvdata(&dev->vdev, dev); |
| 965 | − return video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr); | |
| 965 | + return video_register_device(&dev->vdev, VFL_TYPE_VIDEO, video_nr); | |
| 966 | 966 | } |
| 967 | 967 | |
| 968 | 968 | /* |
| @@ -1282,7 +1282,7 @@ int tw686x_video_init(struct tw686x_dev *dev) · 1281 unmodified lines | ||
| 1282 | 1282 | vc->device = vdev; |
| 1283 | 1283 | video_set_drvdata(vdev, vc); |
| 1284 | 1284 | |
| 1285 | − err = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1285 | + err = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1286 | 1286 | if (err < 0) |
| 1287 | 1287 | goto error; |
| 1288 | 1288 | vc->num = vdev->num; |
| @@ -507,6 +507,18 @@ config VIDEO_SUN8I_DEINTERLACE · 506 unmodified lines | ||
| 507 | 507 | capability found on some SoCs, like H3. |
| 508 | 508 | To compile this driver as a module choose m here. |
| 509 | 509 | |
| 510 | +config VIDEO_SUN8I_ROTATE | |
| 511 | + tristate "Allwinner DE2 rotation driver" | |
| 512 | + depends on VIDEO_DEV && VIDEO_V4L2 | |
| 513 | + depends on ARCH_SUNXI || COMPILE_TEST | |
| 514 | + depends on COMMON_CLK && OF | |
| 515 | + depends on PM | |
| 516 | + select VIDEOBUF2_DMA_CONTIG | |
| 517 | + select V4L2_MEM2MEM_DEV | |
| 518 | + help | |
| 519 | + Support for the Allwinner DE2 rotation unit. | |
| 520 | + To compile this driver as a module choose m here. | |
| 521 | + | |
| 510 | 522 | endif # V4L_MEM2MEM_DRIVERS |
| 511 | 523 | |
| 512 | 524 | # TI VIDEO PORT Helper Modules |
| @@ -610,49 +622,49 @@ config CEC_GPIO · 97 unmodified lines | ||
| 610 | 622 | between compatible devices. |
| 611 | 623 | |
| 612 | 624 | config VIDEO_SAMSUNG_S5P_CEC |
| 613 | − tristate "Samsung S5P CEC driver" | |
| 614 | − depends on ARCH_EXYNOS || COMPILE_TEST | |
| 615 | − select CEC_CORE | |
| 616 | − select CEC_NOTIFIER | |
| 617 | − help | |
| 618 | − This is a driver for Samsung S5P HDMI CEC interface. It uses the | |
| 619 | − generic CEC framework interface. | |
| 620 | − CEC bus is present in the HDMI connector and enables communication | |
| 621 | − between compatible devices. | |
| 625 | + tristate "Samsung S5P CEC driver" | |
| 626 | + depends on ARCH_EXYNOS || COMPILE_TEST | |
| 627 | + select CEC_CORE | |
| 628 | + select CEC_NOTIFIER | |
| 629 | + help | |
| 630 | + This is a driver for Samsung S5P HDMI CEC interface. It uses the | |
| 631 | + generic CEC framework interface. | |
| 632 | + CEC bus is present in the HDMI connector and enables communication | |
| 633 | + between compatible devices. | |
| 622 | 634 | |
| 623 | 635 | config VIDEO_STI_HDMI_CEC |
| 624 | − tristate "STMicroelectronics STiH4xx HDMI CEC driver" | |
| 625 | − depends on ARCH_STI || COMPILE_TEST | |
| 626 | − select CEC_CORE | |
| 627 | − select CEC_NOTIFIER | |
| 628 | − help | |
| 629 | − This is a driver for STIH4xx HDMI CEC interface. It uses the | |
| 630 | − generic CEC framework interface. | |
| 631 | − CEC bus is present in the HDMI connector and enables communication | |
| 632 | − between compatible devices. | |
| 636 | + tristate "STMicroelectronics STiH4xx HDMI CEC driver" | |
| 637 | + depends on ARCH_STI || COMPILE_TEST | |
| 638 | + select CEC_CORE | |
| 639 | + select CEC_NOTIFIER | |
| 640 | + help | |
| 641 | + This is a driver for STIH4xx HDMI CEC interface. It uses the | |
| 642 | + generic CEC framework interface. | |
| 643 | + CEC bus is present in the HDMI connector and enables communication | |
| 644 | + between compatible devices. | |
| 633 | 645 | |
| 634 | 646 | config VIDEO_STM32_HDMI_CEC |
| 635 | − tristate "STMicroelectronics STM32 HDMI CEC driver" | |
| 636 | − depends on ARCH_STM32 || COMPILE_TEST | |
| 637 | − select REGMAP | |
| 638 | − select REGMAP_MMIO | |
| 639 | − select CEC_CORE | |
| 640 | − help | |
| 641 | − This is a driver for STM32 interface. It uses the | |
| 642 | − generic CEC framework interface. | |
| 643 | − CEC bus is present in the HDMI connector and enables communication | |
| 644 | − between compatible devices. | |
| 647 | + tristate "STMicroelectronics STM32 HDMI CEC driver" | |
| 648 | + depends on ARCH_STM32 || COMPILE_TEST | |
| 649 | + select REGMAP | |
| 650 | + select REGMAP_MMIO | |
| 651 | + select CEC_CORE | |
| 652 | + help | |
| 653 | + This is a driver for STM32 interface. It uses the | |
| 654 | + generic CEC framework interface. | |
| 655 | + CEC bus is present in the HDMI connector and enables communication | |
| 656 | + between compatible devices. | |
| 645 | 657 | |
| 646 | 658 | config VIDEO_TEGRA_HDMI_CEC |
| 647 | − tristate "Tegra HDMI CEC driver" | |
| 648 | − depends on ARCH_TEGRA || COMPILE_TEST | |
| 649 | − select CEC_CORE | |
| 650 | − select CEC_NOTIFIER | |
| 651 | − help | |
| 652 | − This is a driver for the Tegra HDMI CEC interface. It uses the | |
| 653 | − generic CEC framework interface. | |
| 654 | − The CEC bus is present in the HDMI connector and enables communication | |
| 655 | − between compatible devices. | |
| 659 | + tristate "Tegra HDMI CEC driver" | |
| 660 | + depends on ARCH_TEGRA || COMPILE_TEST | |
| 661 | + select CEC_CORE | |
| 662 | + select CEC_NOTIFIER | |
| 663 | + help | |
| 664 | + This is a driver for the Tegra HDMI CEC interface. It uses the | |
| 665 | + generic CEC framework interface. | |
| 666 | + The CEC bus is present in the HDMI connector and enables communication | |
| 667 | + between compatible devices. | |
| 656 | 668 | |
| 657 | 669 | config VIDEO_SECO_CEC |
| 658 | 670 | tristate "SECO Boards HDMI CEC driver" |
| @@ -285,6 +285,7 @@ vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc, · 284 unmodified lines | ||
| 285 | 285 | max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); |
| 286 | 286 | |
| 287 | 287 | if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || |
| 288 | + ccdcparam->data_sz > VPFE_CCDC_DATA_8BITS || | |
| 288 | 289 | max_gamma > max_data) { |
| 289 | 290 | vpfe_dbg(1, vpfe, "Invalid data line select\n"); |
| 290 | 291 | return -EINVAL; |
| @@ -324,7 +325,7 @@ static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc) · 33 unmodified lines | ||
| 324 | 325 | |
| 325 | 326 | static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) |
| 326 | 327 | { |
| 327 | − struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); | |
| 328 | + struct vpfe_device *vpfe = to_vpfe(ccdc); | |
| 328 | 329 | u32 dma_cntl, pcr; |
| 329 | 330 | |
| 330 | 331 | pcr = vpfe_reg_read(ccdc, VPFE_PCR); |
| @@ -348,7 +349,7 @@ static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) · 17 unmodified lines | ||
| 348 | 349 | |
| 349 | 350 | static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) |
| 350 | 351 | { |
| 351 | − struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); | |
| 352 | + struct vpfe_device *vpfe = to_vpfe(ccdc); | |
| 352 | 353 | struct vpfe_ccdc_config_params_raw raw_params; |
| 353 | 354 | int x; |
| 354 | 355 | |
| @@ -504,7 +505,7 @@ vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc, · 149 unmodified lines | ||
| 504 | 505 | */ |
| 505 | 506 | static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) |
| 506 | 507 | { |
| 507 | − struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); | |
| 508 | + struct vpfe_device *vpfe = to_vpfe(ccdc); | |
| 508 | 509 | struct vpfe_ccdc_config_params_raw *config_params = |
| 509 | 510 | &ccdc->ccdc_cfg.bayer.config_params; |
| 510 | 511 | struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer; |
| @@ -609,7 +610,7 @@ static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc) · 98 unmodified lines | ||
| 609 | 610 | |
| 610 | 611 | static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) |
| 611 | 612 | { |
| 612 | − struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); | |
| 613 | + struct vpfe_device *vpfe = to_vpfe(ccdc); | |
| 613 | 614 | |
| 614 | 615 | vpfe_dbg(1, vpfe, "%s: if_type: %d, pixfmt:%s\n", |
| 615 | 616 | __func__, ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); |
| @@ -741,7 +742,7 @@ static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr) · 125 unmodified lines | ||
| 741 | 742 | static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc, |
| 742 | 743 | struct vpfe_hw_if_param *params) |
| 743 | 744 | { |
| 744 | − struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); | |
| 745 | + struct vpfe_device *vpfe = to_vpfe(ccdc); | |
| 745 | 746 | |
| 746 | 747 | ccdc->ccdc_cfg.if_type = params->if_type; |
| 747 | 748 | |
| @@ -2267,7 +2268,7 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe) · 1519 unmodified lines | ||
| 2267 | 2268 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
| 2268 | 2269 | V4L2_CAP_READWRITE; |
| 2269 | 2270 | video_set_drvdata(vdev, vpfe); |
| 2270 | − err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1); | |
| 2271 | + err = video_register_device(&vpfe->video_dev, VFL_TYPE_VIDEO, -1); | |
| 2271 | 2272 | if (err) { |
| 2272 | 2273 | vpfe_err(vpfe, |
| 2273 | 2274 | "Unable to register video device.\n"); |
| @@ -1,4 +1,6 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0+ | |
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | +// Copyright 2020 IBM Corp. | |
| 3 | +// Copyright (c) 2019-2020 Intel Corporation | |
| 2 | 4 | |
| 3 | 5 | #include <linux/atomic.h> |
| 4 | 6 | #include <linux/bitfield.h> |
| @@ -72,11 +74,8 @@ · 67 unmodified lines | ||
| 72 | 74 | #define VE_SEQ_CTRL_CAP_BUSY BIT(16) |
| 73 | 75 | #define VE_SEQ_CTRL_COMP_BUSY BIT(18) |
| 74 | 76 | |
| 75 | −#ifdef CONFIG_MACH_ASPEED_G5 | |
| 76 | −#define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500 */ | |
| 77 | −#else | |
| 78 | −#define VE_SEQ_CTRL_JPEG_MODE BIT(8) /* AST2400 */ | |
| 79 | −#endif /* CONFIG_MACH_ASPEED_G5 */ | |
| 77 | +#define AST2500_VE_SEQ_CTRL_JPEG_MODE BIT(13) | |
| 78 | +#define AST2400_VE_SEQ_CTRL_JPEG_MODE BIT(8) | |
| 80 | 79 | |
| 81 | 80 | #define VE_CTRL 0x008 |
| 82 | 81 | #define VE_CTRL_HSYNC_POL BIT(0) |
| @@ -133,7 +132,8 @@ · 50 unmodified lines | ||
| 133 | 132 | #define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22) |
| 134 | 133 | #define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27) |
| 135 | 134 | |
| 136 | −#define VE_OFFSET_COMP_STREAM 0x078 | |
| 135 | +#define AST2400_VE_COMP_SIZE_READ_BACK 0x078 | |
| 136 | +#define AST2600_VE_COMP_SIZE_READ_BACK 0x084 | |
| 137 | 137 | |
| 138 | 138 | #define VE_SRC_LR_EDGE_DET 0x090 |
| 139 | 139 | #define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0) |
| @@ -220,6 +220,9 @@ struct aspeed_video { · 80 unmodified lines | ||
| 220 | 220 | struct video_device vdev; |
| 221 | 221 | struct mutex video_lock; /* v4l2 and videobuf2 lock */ |
| 222 | 222 | |
| 223 | + u32 jpeg_mode; | |
| 224 | + u32 comp_size_read; | |
| 225 | + | |
| 223 | 226 | wait_queue_head_t wait; |
| 224 | 227 | spinlock_t lock; /* buffer list lock */ |
| 225 | 228 | struct delayed_work res_work; |
| @@ -243,6 +246,26 @@ struct aspeed_video { · 17 unmodified lines | ||
| 243 | 246 | |
| 244 | 247 | #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) |
| 245 | 248 | |
| 249 | +struct aspeed_video_config { | |
| 250 | + u32 jpeg_mode; | |
| 251 | + u32 comp_size_read; | |
| 252 | +}; | |
| 253 | + | |
| 254 | +static const struct aspeed_video_config ast2400_config = { | |
| 255 | + .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, | |
| 256 | + .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, | |
| 257 | +}; | |
| 258 | + | |
| 259 | +static const struct aspeed_video_config ast2500_config = { | |
| 260 | + .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, | |
| 261 | + .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, | |
| 262 | +}; | |
| 263 | + | |
| 264 | +static const struct aspeed_video_config ast2600_config = { | |
| 265 | + .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, | |
| 266 | + .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, | |
| 267 | +}; | |
| 268 | + | |
| 246 | 269 | static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = { |
| 247 | 270 | 0xe0ffd8ff, 0x464a1000, 0x01004649, 0x60000101, 0x00006000, 0x0f00feff, |
| 248 | 271 | 0x00002d05, 0x00000000, 0x00000000, 0x00dbff00 |
| @@ -572,7 +595,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) · 323 unmodified lines | ||
| 572 | 595 | if (sts & VE_INTERRUPT_COMP_COMPLETE) { |
| 573 | 596 | struct aspeed_video_buffer *buf; |
| 574 | 597 | u32 frame_size = aspeed_video_read(video, |
| 575 | − VE_OFFSET_COMP_STREAM); | |
| 598 | + video->comp_size_read); | |
| 576 | 599 | |
| 577 | 600 | spin_lock(&video->lock); |
| 578 | 601 | clear_bit(VIDEO_FRAME_INPRG, &video->flags); |
| @@ -907,7 +930,7 @@ static void aspeed_video_init_regs(struct aspeed_video *video) · 328 unmodified lines | ||
| 907 | 930 | FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | |
| 908 | 931 | FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); |
| 909 | 932 | u32 ctrl = VE_CTRL_AUTO_OR_CURSOR; |
| 910 | − u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE; | |
| 933 | + u32 seq_ctrl = video->jpeg_mode; | |
| 911 | 934 | |
| 912 | 935 | if (video->frame_rate) |
| 913 | 936 | ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); |
| @@ -1565,14 +1588,14 @@ static int aspeed_video_setup_video(struct aspeed_video *video) · 651 unmodified lines | ||
| 1565 | 1588 | V4L2_CAP_STREAMING; |
| 1566 | 1589 | vdev->v4l2_dev = v4l2_dev; |
| 1567 | 1590 | strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name)); |
| 1568 | − vdev->vfl_type = VFL_TYPE_GRABBER; | |
| 1591 | + vdev->vfl_type = VFL_TYPE_VIDEO; | |
| 1569 | 1592 | vdev->vfl_dir = VFL_DIR_RX; |
| 1570 | 1593 | vdev->release = video_device_release_empty; |
| 1571 | 1594 | vdev->ioctl_ops = &aspeed_video_ioctl_ops; |
| 1572 | 1595 | vdev->lock = &video->video_lock; |
| 1573 | 1596 | |
| 1574 | 1597 | video_set_drvdata(vdev, video); |
| 1575 | − rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0); | |
| 1598 | + rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0); | |
| 1576 | 1599 | if (rc) { |
| 1577 | 1600 | vb2_queue_release(vbq); |
| 1578 | 1601 | v4l2_ctrl_handler_free(&video->ctrl_handler); |
| @@ -1653,16 +1676,37 @@ err_unprepare_eclk: · 74 unmodified lines | ||
| 1653 | 1676 | return rc; |
| 1654 | 1677 | } |
| 1655 | 1678 | |
| 1679 | +static const struct of_device_id aspeed_video_of_match[] = { | |
| 1680 | + { .compatible = "aspeed,ast2400-video-engine", .data = &ast2400_config }, | |
| 1681 | + { .compatible = "aspeed,ast2500-video-engine", .data = &ast2500_config }, | |
| 1682 | + { .compatible = "aspeed,ast2600-video-engine", .data = &ast2600_config }, | |
| 1683 | + {} | |
| 1684 | +}; | |
| 1685 | +MODULE_DEVICE_TABLE(of, aspeed_video_of_match); | |
| 1686 | + | |
| 1656 | 1687 | static int aspeed_video_probe(struct platform_device *pdev) |
| 1657 | 1688 | { |
| 1689 | + const struct aspeed_video_config *config; | |
| 1690 | + const struct of_device_id *match; | |
| 1691 | + struct aspeed_video *video; | |
| 1658 | 1692 | int rc; |
| 1659 | − struct resource *res; | |
| 1660 | − struct aspeed_video *video = | |
| 1661 | − devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); | |
| 1662 | 1693 | |
| 1694 | + video = devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); | |
| 1663 | 1695 | if (!video) |
| 1664 | 1696 | return -ENOMEM; |
| 1665 | 1697 | |
| 1698 | + video->base = devm_platform_ioremap_resource(pdev, 0); | |
| 1699 | + if (IS_ERR(video->base)) | |
| 1700 | + return PTR_ERR(video->base); | |
| 1701 | + | |
| 1702 | + match = of_match_node(aspeed_video_of_match, pdev->dev.of_node); | |
| 1703 | + if (!match) | |
| 1704 | + return -EINVAL; | |
| 1705 | + | |
| 1706 | + config = match->data; | |
| 1707 | + video->jpeg_mode = config->jpeg_mode; | |
| 1708 | + video->comp_size_read = config->comp_size_read; | |
| 1709 | + | |
| 1666 | 1710 | video->frame_rate = 30; |
| 1667 | 1711 | video->dev = &pdev->dev; |
| 1668 | 1712 | spin_lock_init(&video->lock); |
| @@ -1671,13 +1715,6 @@ static int aspeed_video_probe(struct platform_device *pdev) · 2 unmodified lines | ||
| 1671 | 1715 | INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); |
| 1672 | 1716 | INIT_LIST_HEAD(&video->buffers); |
| 1673 | 1717 | |
| 1674 | − res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
| 1675 | − | |
| 1676 | − video->base = devm_ioremap_resource(video->dev, res); | |
| 1677 | − | |
| 1678 | − if (IS_ERR(video->base)) | |
| 1679 | − return PTR_ERR(video->base); | |
| 1680 | − | |
| 1681 | 1718 | rc = aspeed_video_init(video); |
| 1682 | 1719 | if (rc) |
| 1683 | 1720 | return rc; |
| @@ -1716,13 +1753,6 @@ static int aspeed_video_remove(struct platform_device *pdev) · 32 unmodified lines | ||
| 1716 | 1753 | return 0; |
| 1717 | 1754 | } |
| 1718 | 1755 | |
| 1719 | −static const struct of_device_id aspeed_video_of_match[] = { | |
| 1720 | − { .compatible = "aspeed,ast2400-video-engine" }, | |
| 1721 | − { .compatible = "aspeed,ast2500-video-engine" }, | |
| 1722 | − {} | |
| 1723 | −}; | |
| 1724 | −MODULE_DEVICE_TABLE(of, aspeed_video_of_match); | |
| 1725 | − | |
| 1726 | 1756 | static struct platform_driver aspeed_video_driver = { |
| 1727 | 1757 | .driver = { |
| 1728 | 1758 | .name = DEVICE_NAME, |
| @@ -22,6 +22,7 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <linux/pm_runtime.h> |
| 23 | 23 | #include <linux/regmap.h> |
| 24 | 24 | #include <linux/videodev2.h> |
| 25 | +#include <linux/atmel-isc-media.h> | |
| 25 | 26 | |
| 26 | 27 | #include <media/v4l2-ctrls.h> |
| 27 | 28 | #include <media/v4l2-device.h> |
| @@ -224,10 +225,35 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { · 196 unmodified lines | ||
| 224 | 225 | (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \ |
| 225 | 226 | (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8))) |
| 226 | 227 | |
| 228 | +#define ISC_CTRL_ISC_TO_V4L2(x) ((x) == ISC_WB_O_ZERO_VAL ? 0 : (x)) | |
| 229 | +#define ISC_CTRL_V4L2_TO_ISC(x) ((x) ? (x) : ISC_WB_O_ZERO_VAL) | |
| 230 | + | |
| 231 | +static inline void isc_update_v4l2_ctrls(struct isc_device *isc) | |
| 232 | +{ | |
| 233 | + struct isc_ctrls *ctrls = &isc->ctrls; | |
| 234 | + | |
| 235 | + /* In here we set the v4l2 controls w.r.t. our pipeline config */ | |
| 236 | + v4l2_ctrl_s_ctrl(isc->r_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_R]); | |
| 237 | + v4l2_ctrl_s_ctrl(isc->b_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_B]); | |
| 238 | + v4l2_ctrl_s_ctrl(isc->gr_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GR]); | |
| 239 | + v4l2_ctrl_s_ctrl(isc->gb_gain_ctrl, ctrls->gain[ISC_HIS_CFG_MODE_GB]); | |
| 240 | + | |
| 241 | + v4l2_ctrl_s_ctrl(isc->r_off_ctrl, | |
| 242 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R])); | |
| 243 | + v4l2_ctrl_s_ctrl(isc->b_off_ctrl, | |
| 244 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B])); | |
| 245 | + v4l2_ctrl_s_ctrl(isc->gr_off_ctrl, | |
| 246 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR])); | |
| 247 | + v4l2_ctrl_s_ctrl(isc->gb_off_ctrl, | |
| 248 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB])); | |
| 249 | +} | |
| 250 | + | |
| 227 | 251 | static inline void isc_update_awb_ctrls(struct isc_device *isc) |
| 228 | 252 | { |
| 229 | 253 | struct isc_ctrls *ctrls = &isc->ctrls; |
| 230 | 254 | |
| 255 | + /* In here we set our actual hw pipeline config */ | |
| 256 | + | |
| 231 | 257 | regmap_write(isc->regmap, ISC_WB_O_RGR, |
| 232 | 258 | (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | |
| 233 | 259 | ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); |
| @@ -662,11 +688,9 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) · 428 unmodified lines | ||
| 662 | 688 | |
| 663 | 689 | bay_cfg = isc->config.sd_format->cfa_baycfg; |
| 664 | 690 | |
| 665 | − if (ctrls->awb == ISC_WB_NONE) | |
| 666 | − isc_reset_awb_ctrls(isc); | |
| 667 | − | |
| 668 | 691 | regmap_write(regmap, ISC_WB_CFG, bay_cfg); |
| 669 | 692 | isc_update_awb_ctrls(isc); |
| 693 | + isc_update_v4l2_ctrls(isc); | |
| 670 | 694 | |
| 671 | 695 | regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); |
| 672 | 696 | |
| @@ -1396,6 +1420,7 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) · 723 unmodified lines | ||
| 1396 | 1420 | isc->try_config.sd_format != isc->config.sd_format) { |
| 1397 | 1421 | isc->ctrls.hist_stat = HIST_INIT; |
| 1398 | 1422 | isc_reset_awb_ctrls(isc); |
| 1423 | + isc_update_v4l2_ctrls(isc); | |
| 1399 | 1424 | } |
| 1400 | 1425 | /* make the try configuration active */ |
| 1401 | 1426 | isc->config = isc->try_config; |
| @@ -1814,10 +1839,6 @@ static void isc_awb_work(struct work_struct *w) · 412 unmodified lines | ||
| 1814 | 1839 | ctrls->hist_id = hist_id; |
| 1815 | 1840 | baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; |
| 1816 | 1841 | |
| 1817 | − /* if no more auto white balance, reset controls. */ | |
| 1818 | − if (ctrls->awb == ISC_WB_NONE) | |
| 1819 | − isc_reset_awb_ctrls(isc); | |
| 1820 | − | |
| 1821 | 1842 | pm_runtime_get_sync(isc->dev); |
| 1822 | 1843 | |
| 1823 | 1844 | /* |
| @@ -1842,6 +1863,8 @@ static void isc_awb_work(struct work_struct *w) · 18 unmodified lines | ||
| 1842 | 1863 | if (ctrls->awb == ISC_WB_ONETIME) { |
| 1843 | 1864 | v4l2_info(&isc->v4l2_dev, |
| 1844 | 1865 | "Completed one time white-balance adjustment.\n"); |
| 1866 | + /* update the v4l2 controls values */ | |
| 1867 | + isc_update_v4l2_ctrls(isc); | |
| 1845 | 1868 | ctrls->awb = ISC_WB_NONE; |
| 1846 | 1869 | } |
| 1847 | 1870 | } |
| @@ -1873,6 +1896,27 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) · 25 unmodified lines | ||
| 1873 | 1896 | case V4L2_CID_GAMMA: |
| 1874 | 1897 | ctrls->gamma_index = ctrl->val; |
| 1875 | 1898 | break; |
| 1899 | + default: | |
| 1900 | + return -EINVAL; | |
| 1901 | + } | |
| 1902 | + | |
| 1903 | + return 0; | |
| 1904 | +} | |
| 1905 | + | |
| 1906 | +static const struct v4l2_ctrl_ops isc_ctrl_ops = { | |
| 1907 | + .s_ctrl = isc_s_ctrl, | |
| 1908 | +}; | |
| 1909 | + | |
| 1910 | +static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) | |
| 1911 | +{ | |
| 1912 | + struct isc_device *isc = container_of(ctrl->handler, | |
| 1913 | + struct isc_device, ctrls.handler); | |
| 1914 | + struct isc_ctrls *ctrls = &isc->ctrls; | |
| 1915 | + | |
| 1916 | + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) | |
| 1917 | + return 0; | |
| 1918 | + | |
| 1919 | + switch (ctrl->id) { | |
| 1876 | 1920 | case V4L2_CID_AUTO_WHITE_BALANCE: |
| 1877 | 1921 | if (ctrl->val == 1) |
| 1878 | 1922 | ctrls->awb = ISC_WB_AUTO; |
| @@ -1883,36 +1927,142 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) · 4 unmodified lines | ||
| 1883 | 1927 | if (!isc->config.sd_format) |
| 1884 | 1928 | break; |
| 1885 | 1929 | |
| 1886 | − if (ctrls->hist_stat != HIST_ENABLED) | |
| 1887 | − isc_reset_awb_ctrls(isc); | |
| 1930 | + /* configure the controls with new values from v4l2 */ | |
| 1931 | + if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new) | |
| 1932 | + ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val; | |
| 1933 | + if (ctrl->cluster[ISC_CTRL_B_GAIN]->is_new) | |
| 1934 | + ctrls->gain[ISC_HIS_CFG_MODE_B] = isc->b_gain_ctrl->val; | |
| 1935 | + if (ctrl->cluster[ISC_CTRL_GR_GAIN]->is_new) | |
| 1936 | + ctrls->gain[ISC_HIS_CFG_MODE_GR] = isc->gr_gain_ctrl->val; | |
| 1937 | + if (ctrl->cluster[ISC_CTRL_GB_GAIN]->is_new) | |
| 1938 | + ctrls->gain[ISC_HIS_CFG_MODE_GB] = isc->gb_gain_ctrl->val; | |
| 1939 | + | |
| 1940 | + if (ctrl->cluster[ISC_CTRL_R_OFF]->is_new) | |
| 1941 | + ctrls->offset[ISC_HIS_CFG_MODE_R] = | |
| 1942 | + ISC_CTRL_V4L2_TO_ISC(isc->r_off_ctrl->val); | |
| 1943 | + if (ctrl->cluster[ISC_CTRL_B_OFF]->is_new) | |
| 1944 | + ctrls->offset[ISC_HIS_CFG_MODE_B] = | |
| 1945 | + ISC_CTRL_V4L2_TO_ISC(isc->b_off_ctrl->val); | |
| 1946 | + if (ctrl->cluster[ISC_CTRL_GR_OFF]->is_new) | |
| 1947 | + ctrls->offset[ISC_HIS_CFG_MODE_GR] = | |
| 1948 | + ISC_CTRL_V4L2_TO_ISC(isc->gr_off_ctrl->val); | |
| 1949 | + if (ctrl->cluster[ISC_CTRL_GB_OFF]->is_new) | |
| 1950 | + ctrls->offset[ISC_HIS_CFG_MODE_GB] = | |
| 1951 | + ISC_CTRL_V4L2_TO_ISC(isc->gb_off_ctrl->val); | |
| 1888 | 1952 | |
| 1889 | − if (isc->ctrls.awb == ISC_WB_AUTO && | |
| 1953 | + isc_update_awb_ctrls(isc); | |
| 1954 | + | |
| 1955 | + if (vb2_is_streaming(&isc->vb2_vidq)) { | |
| 1956 | + /* | |
| 1957 | + * If we are streaming, we can update profile to | |
| 1958 | + * have the new settings in place. | |
| 1959 | + */ | |
| 1960 | + isc_update_profile(isc); | |
| 1961 | + } else { | |
| 1962 | + /* | |
| 1963 | + * The auto cluster will activate automatically this | |
| 1964 | + * control. This has to be deactivated when not | |
| 1965 | + * streaming. | |
| 1966 | + */ | |
| 1967 | + v4l2_ctrl_activate(isc->do_wb_ctrl, false); | |
| 1968 | + } | |
| 1969 | + | |
| 1970 | + /* if we have autowhitebalance on, start histogram procedure */ | |
| 1971 | + if (ctrls->awb == ISC_WB_AUTO && | |
| 1890 | 1972 | vb2_is_streaming(&isc->vb2_vidq) && |
| 1891 | 1973 | ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) |
| 1892 | 1974 | isc_set_histogram(isc, true); |
| 1893 | 1975 | |
| 1894 | − break; | |
| 1895 | − case V4L2_CID_DO_WHITE_BALANCE: | |
| 1896 | − /* if AWB is enabled, do nothing */ | |
| 1897 | − if (ctrls->awb == ISC_WB_AUTO) | |
| 1898 | − return 0; | |
| 1976 | + /* | |
| 1977 | + * for one time whitebalance adjustment, check the button, | |
| 1978 | + * if it's pressed, perform the one time operation. | |
| 1979 | + */ | |
| 1980 | + if (ctrls->awb == ISC_WB_NONE && | |
| 1981 | + ctrl->cluster[ISC_CTRL_DO_WB]->is_new && | |
| 1982 | + !(ctrl->cluster[ISC_CTRL_DO_WB]->flags & | |
| 1983 | + V4L2_CTRL_FLAG_INACTIVE)) { | |
| 1984 | + ctrls->awb = ISC_WB_ONETIME; | |
| 1985 | + isc_set_histogram(isc, true); | |
| 1986 | + v4l2_dbg(1, debug, &isc->v4l2_dev, | |
| 1987 | + "One time white-balance started.\n"); | |
| 1988 | + } | |
| 1989 | + return 0; | |
| 1990 | + } | |
| 1991 | + return 0; | |
| 1992 | +} | |
| 1899 | 1993 | |
| 1900 | − ctrls->awb = ISC_WB_ONETIME; | |
| 1901 | − isc_set_histogram(isc, true); | |
| 1902 | − v4l2_dbg(1, debug, &isc->v4l2_dev, | |
| 1903 | − "One time white-balance started.\n"); | |
| 1994 | +static int isc_g_volatile_awb_ctrl(struct v4l2_ctrl *ctrl) | |
| 1995 | +{ | |
| 1996 | + struct isc_device *isc = container_of(ctrl->handler, | |
| 1997 | + struct isc_device, ctrls.handler); | |
| 1998 | + struct isc_ctrls *ctrls = &isc->ctrls; | |
| 1999 | + | |
| 2000 | + switch (ctrl->id) { | |
| 2001 | + /* being a cluster, this id will be called for every control */ | |
| 2002 | + case V4L2_CID_AUTO_WHITE_BALANCE: | |
| 2003 | + ctrl->cluster[ISC_CTRL_R_GAIN]->val = | |
| 2004 | + ctrls->gain[ISC_HIS_CFG_MODE_R]; | |
| 2005 | + ctrl->cluster[ISC_CTRL_B_GAIN]->val = | |
| 2006 | + ctrls->gain[ISC_HIS_CFG_MODE_B]; | |
| 2007 | + ctrl->cluster[ISC_CTRL_GR_GAIN]->val = | |
| 2008 | + ctrls->gain[ISC_HIS_CFG_MODE_GR]; | |
| 2009 | + ctrl->cluster[ISC_CTRL_GB_GAIN]->val = | |
| 2010 | + ctrls->gain[ISC_HIS_CFG_MODE_GB]; | |
| 2011 | + | |
| 2012 | + ctrl->cluster[ISC_CTRL_R_OFF]->val = | |
| 2013 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_R]); | |
| 2014 | + ctrl->cluster[ISC_CTRL_B_OFF]->val = | |
| 2015 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_B]); | |
| 2016 | + ctrl->cluster[ISC_CTRL_GR_OFF]->val = | |
| 2017 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GR]); | |
| 2018 | + ctrl->cluster[ISC_CTRL_GB_OFF]->val = | |
| 2019 | + ISC_CTRL_ISC_TO_V4L2(ctrls->offset[ISC_HIS_CFG_MODE_GB]); | |
| 1904 | 2020 | break; |
| 1905 | − default: | |
| 1906 | − return -EINVAL; | |
| 1907 | 2021 | } |
| 1908 | − | |
| 1909 | 2022 | return 0; |
| 1910 | 2023 | } |
| 1911 | 2024 | |
| 1912 | −static const struct v4l2_ctrl_ops isc_ctrl_ops = { | |
| 1913 | − .s_ctrl = isc_s_ctrl, | |
| 2025 | +static const struct v4l2_ctrl_ops isc_awb_ops = { | |
| 2026 | + .s_ctrl = isc_s_awb_ctrl, | |
| 2027 | + .g_volatile_ctrl = isc_g_volatile_awb_ctrl, | |
| 1914 | 2028 | }; |
| 1915 | 2029 | |
| 2030 | +#define ISC_CTRL_OFF(_name, _id, _name_str) \ | |
| 2031 | + static const struct v4l2_ctrl_config _name = { \ | |
| 2032 | + .ops = &isc_awb_ops, \ | |
| 2033 | + .id = _id, \ | |
| 2034 | + .name = _name_str, \ | |
| 2035 | + .type = V4L2_CTRL_TYPE_INTEGER, \ | |
| 2036 | + .flags = V4L2_CTRL_FLAG_SLIDER, \ | |
| 2037 | + .min = -4095, \ | |
| 2038 | + .max = 4095, \ | |
| 2039 | + .step = 1, \ | |
| 2040 | + .def = 0, \ | |
| 2041 | + } | |
| 2042 | + | |
| 2043 | +ISC_CTRL_OFF(isc_r_off_ctrl, ISC_CID_R_OFFSET, "Red Component Offset"); | |
| 2044 | +ISC_CTRL_OFF(isc_b_off_ctrl, ISC_CID_B_OFFSET, "Blue Component Offset"); | |
| 2045 | +ISC_CTRL_OFF(isc_gr_off_ctrl, ISC_CID_GR_OFFSET, "Green Red Component Offset"); | |
| 2046 | +ISC_CTRL_OFF(isc_gb_off_ctrl, ISC_CID_GB_OFFSET, "Green Blue Component Offset"); | |
| 2047 | + | |
| 2048 | +#define ISC_CTRL_GAIN(_name, _id, _name_str) \ | |
| 2049 | + static const struct v4l2_ctrl_config _name = { \ | |
| 2050 | + .ops = &isc_awb_ops, \ | |
| 2051 | + .id = _id, \ | |
| 2052 | + .name = _name_str, \ | |
| 2053 | + .type = V4L2_CTRL_TYPE_INTEGER, \ | |
| 2054 | + .flags = V4L2_CTRL_FLAG_SLIDER, \ | |
| 2055 | + .min = 0, \ | |
| 2056 | + .max = 8191, \ | |
| 2057 | + .step = 1, \ | |
| 2058 | + .def = 512, \ | |
| 2059 | + } | |
| 2060 | + | |
| 2061 | +ISC_CTRL_GAIN(isc_r_gain_ctrl, ISC_CID_R_GAIN, "Red Component Gain"); | |
| 2062 | +ISC_CTRL_GAIN(isc_b_gain_ctrl, ISC_CID_B_GAIN, "Blue Component Gain"); | |
| 2063 | +ISC_CTRL_GAIN(isc_gr_gain_ctrl, ISC_CID_GR_GAIN, "Green Red Component Gain"); | |
| 2064 | +ISC_CTRL_GAIN(isc_gb_gain_ctrl, ISC_CID_GB_GAIN, "Green Blue Component Gain"); | |
| 2065 | + | |
| 1916 | 2066 | static int isc_ctrl_init(struct isc_device *isc) |
| 1917 | 2067 | { |
| 1918 | 2068 | const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; |
| @@ -1923,7 +2073,7 @@ static int isc_ctrl_init(struct isc_device *isc) · 4 unmodified lines | ||
| 1923 | 2073 | ctrls->hist_stat = HIST_INIT; |
| 1924 | 2074 | isc_reset_awb_ctrls(isc); |
| 1925 | 2075 | |
| 1926 | − ret = v4l2_ctrl_handler_init(hdl, 5); | |
| 2076 | + ret = v4l2_ctrl_handler_init(hdl, 13); | |
| 1927 | 2077 | if (ret < 0) |
| 1928 | 2078 | return ret; |
| 1929 | 2079 | |
| @@ -1933,10 +2083,13 @@ static int isc_ctrl_init(struct isc_device *isc) · 3 unmodified lines | ||
| 1933 | 2083 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); |
| 1934 | 2084 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); |
| 1935 | 2085 | v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); |
| 1936 | − v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | |
| 2086 | + isc->awb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops, | |
| 2087 | + V4L2_CID_AUTO_WHITE_BALANCE, | |
| 2088 | + 0, 1, 1, 1); | |
| 1937 | 2089 | |
| 1938 | 2090 | /* do_white_balance is a button, so min,max,step,default are ignored */ |
| 1939 | − isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, | |
| 2091 | + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, &isc_awb_ops, | |
| 2092 | + V4L2_CID_DO_WHITE_BALANCE, | |
| 1940 | 2093 | 0, 0, 0, 0); |
| 1941 | 2094 | |
| 1942 | 2095 | if (!isc->do_wb_ctrl) { |
| @@ -1947,6 +2100,21 @@ static int isc_ctrl_init(struct isc_device *isc) · 4 unmodified lines | ||
| 1947 | 2100 | |
| 1948 | 2101 | v4l2_ctrl_activate(isc->do_wb_ctrl, false); |
| 1949 | 2102 | |
| 2103 | + isc->r_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_gain_ctrl, NULL); | |
| 2104 | + isc->b_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_gain_ctrl, NULL); | |
| 2105 | + isc->gr_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_gain_ctrl, NULL); | |
| 2106 | + isc->gb_gain_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_gain_ctrl, NULL); | |
| 2107 | + isc->r_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_r_off_ctrl, NULL); | |
| 2108 | + isc->b_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_b_off_ctrl, NULL); | |
| 2109 | + isc->gr_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gr_off_ctrl, NULL); | |
| 2110 | + isc->gb_off_ctrl = v4l2_ctrl_new_custom(hdl, &isc_gb_off_ctrl, NULL); | |
| 2111 | + | |
| 2112 | + /* | |
| 2113 | + * The cluster is in auto mode with autowhitebalance enabled | |
| 2114 | + * and manual mode otherwise. | |
| 2115 | + */ | |
| 2116 | + v4l2_ctrl_auto_cluster(10, &isc->awb_ctrl, 0, true); | |
| 2117 | + | |
| 1950 | 2118 | v4l2_ctrl_handler_setup(hdl); |
| 1951 | 2119 | |
| 1952 | 2120 | return 0; |
| @@ -2143,7 +2311,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) · 190 unmodified lines | ||
| 2143 | 2311 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; |
| 2144 | 2312 | video_set_drvdata(vdev, isc); |
| 2145 | 2313 | |
| 2146 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 2314 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 2147 | 2315 | if (ret < 0) { |
| 2148 | 2316 | v4l2_err(&isc->v4l2_dev, |
| 2149 | 2317 | "video_register_device failed: %d\n", ret); |
| @@ -213,7 +213,6 @@ struct isc_device { · 212 unmodified lines | ||
| 213 | 213 | struct fmt_config try_config; |
| 214 | 214 | |
| 215 | 215 | struct isc_ctrls ctrls; |
| 216 | − struct v4l2_ctrl *do_wb_ctrl; | |
| 217 | 216 | struct work_struct awb_work; |
| 218 | 217 | |
| 219 | 218 | struct mutex lock; /* serialize access to file operations */ |
| @@ -223,6 +222,28 @@ struct isc_device { · 3 unmodified lines | ||
| 223 | 222 | |
| 224 | 223 | struct isc_subdev_entity *current_subdev; |
| 225 | 224 | struct list_head subdev_entities; |
| 225 | + | |
| 226 | + struct { | |
| 227 | +#define ISC_CTRL_DO_WB 1 | |
| 228 | +#define ISC_CTRL_R_GAIN 2 | |
| 229 | +#define ISC_CTRL_B_GAIN 3 | |
| 230 | +#define ISC_CTRL_GR_GAIN 4 | |
| 231 | +#define ISC_CTRL_GB_GAIN 5 | |
| 232 | +#define ISC_CTRL_R_OFF 6 | |
| 233 | +#define ISC_CTRL_B_OFF 7 | |
| 234 | +#define ISC_CTRL_GR_OFF 8 | |
| 235 | +#define ISC_CTRL_GB_OFF 9 | |
| 236 | + struct v4l2_ctrl *awb_ctrl; | |
| 237 | + struct v4l2_ctrl *do_wb_ctrl; | |
| 238 | + struct v4l2_ctrl *r_gain_ctrl; | |
| 239 | + struct v4l2_ctrl *b_gain_ctrl; | |
| 240 | + struct v4l2_ctrl *gr_gain_ctrl; | |
| 241 | + struct v4l2_ctrl *gb_gain_ctrl; | |
| 242 | + struct v4l2_ctrl *r_off_ctrl; | |
| 243 | + struct v4l2_ctrl *b_off_ctrl; | |
| 244 | + struct v4l2_ctrl *gr_off_ctrl; | |
| 245 | + struct v4l2_ctrl *gb_off_ctrl; | |
| 246 | + }; | |
| 226 | 247 | }; |
| 227 | 248 | |
| 228 | 249 | #define GAMMA_MAX 2 |
| @@ -1094,7 +1094,7 @@ static int isi_graph_notify_complete(struct v4l2_async_notifier *notifier) · 1093 unmodified lines | ||
| 1094 | 1094 | return ret; |
| 1095 | 1095 | } |
| 1096 | 1096 | |
| 1097 | − ret = video_register_device(isi->vdev, VFL_TYPE_GRABBER, -1); | |
| 1097 | + ret = video_register_device(isi->vdev, VFL_TYPE_VIDEO, -1); | |
| 1098 | 1098 | if (ret) { |
| 1099 | 1099 | dev_err(isi->dev, "Failed to register video device\n"); |
| 1100 | 1100 | return ret; |
| @@ -2726,7 +2726,7 @@ static int coda_register_device(struct coda_dev *dev, int i) · 2725 unmodified lines | ||
| 2726 | 2726 | v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); |
| 2727 | 2727 | v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); |
| 2728 | 2728 | |
| 2729 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 2729 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 2730 | 2730 | if (!ret) |
| 2731 | 2731 | v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", |
| 2732 | 2732 | type == CODA_INST_ENCODER ? "encoder" : "decoder", |
| @@ -29,7 +29,7 @@ · 28 unmodified lines | ||
| 29 | 29 | #include "ccdc_hw_device.h" |
| 30 | 30 | |
| 31 | 31 | /* Defaults for module configuration parameters */ |
| 32 | −static struct isif_config_params_raw isif_config_defaults = { | |
| 32 | +static const struct isif_config_params_raw isif_config_defaults = { | |
| 33 | 33 | .linearize = { |
| 34 | 34 | .en = 0, |
| 35 | 35 | .corr_shft = ISIF_NO_SHIFT, |
| @@ -1339,7 +1339,7 @@ static int register_device(struct vpbe_layer *vpbe_display_layer, · 1338 unmodified lines | ||
| 1339 | 1339 | |
| 1340 | 1340 | vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue; |
| 1341 | 1341 | err = video_register_device(&vpbe_display_layer->video_dev, |
| 1342 | − VFL_TYPE_GRABBER, | |
| 1342 | + VFL_TYPE_VIDEO, | |
| 1343 | 1343 | -1); |
| 1344 | 1344 | if (err) |
| 1345 | 1345 | return -ENODEV; |
| @@ -880,7 +880,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, · 879 unmodified lines | ||
| 880 | 880 | /* Fill in the information about format */ |
| 881 | 881 | pix_fmt = vpfe_lookup_pix_format(pix); |
| 882 | 882 | if (pix_fmt) { |
| 883 | − fmt->pixelformat = fmt->pixelformat; | |
| 883 | + fmt->pixelformat = pix_fmt->pixelformat; | |
| 884 | 884 | return 0; |
| 885 | 885 | } |
| 886 | 886 | return -EINVAL; |
| @@ -1780,7 +1780,7 @@ static int vpfe_probe(struct platform_device *pdev) · 893 unmodified lines | ||
| 1780 | 1780 | "video_dev=%p\n", &vpfe_dev->video_dev); |
| 1781 | 1781 | vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 1782 | 1782 | ret = video_register_device(&vpfe_dev->video_dev, |
| 1783 | − VFL_TYPE_GRABBER, -1); | |
| 1783 | + VFL_TYPE_VIDEO, -1); | |
| 1784 | 1784 | |
| 1785 | 1785 | if (ret) { |
| 1786 | 1786 | v4l2_err(pdev->dev.driver, |
| @@ -1466,7 +1466,7 @@ static int vpif_probe_complete(void) · 1465 unmodified lines | ||
| 1466 | 1466 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
| 1467 | 1467 | video_set_drvdata(&ch->video_dev, ch); |
| 1468 | 1468 | err = video_register_device(vdev, |
| 1469 | − VFL_TYPE_GRABBER, (j ? 1 : 0)); | |
| 1469 | + VFL_TYPE_VIDEO, (j ? 1 : 0)); | |
| 1470 | 1470 | if (err) |
| 1471 | 1471 | goto probe_out; |
| 1472 | 1472 | } |
| @@ -1214,7 +1214,7 @@ static int vpif_probe_complete(void) · 1213 unmodified lines | ||
| 1214 | 1214 | vdev->lock = &common->lock; |
| 1215 | 1215 | vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; |
| 1216 | 1216 | video_set_drvdata(&ch->video_dev, ch); |
| 1217 | − err = video_register_device(vdev, VFL_TYPE_GRABBER, | |
| 1217 | + err = video_register_device(vdev, VFL_TYPE_VIDEO, | |
| 1218 | 1218 | (j ? 3 : 2)); |
| 1219 | 1219 | if (err < 0) |
| 1220 | 1220 | goto probe_out; |
| @@ -771,7 +771,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc) · 770 unmodified lines | ||
| 771 | 771 | return PTR_ERR(gsc->m2m.m2m_dev); |
| 772 | 772 | } |
| 773 | 773 | |
| 774 | − ret = video_register_device(&gsc->vdev, VFL_TYPE_GRABBER, -1); | |
| 774 | + ret = video_register_device(&gsc->vdev, VFL_TYPE_VIDEO, -1); | |
| 775 | 775 | if (ret) { |
| 776 | 776 | dev_err(&pdev->dev, |
| 777 | 777 | "%s(): failed to register video device\n", __func__); |
| @@ -13,7 +13,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS · 12 unmodified lines | ||
| 13 | 13 | if VIDEO_SAMSUNG_EXYNOS4_IS |
| 14 | 14 | |
| 15 | 15 | config VIDEO_EXYNOS4_IS_COMMON |
| 16 | − tristate | |
| 16 | + tristate | |
| 17 | 17 | |
| 18 | 18 | config VIDEO_S5P_FIMC |
| 19 | 19 | tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" |
| @@ -1808,7 +1808,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, · 1807 unmodified lines | ||
| 1808 | 1808 | if (ret) |
| 1809 | 1809 | goto err_me_cleanup; |
| 1810 | 1810 | |
| 1811 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 1811 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 1812 | 1812 | if (ret) |
| 1813 | 1813 | goto err_ctrl_free; |
| 1814 | 1814 | |
| @@ -619,7 +619,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, · 618 unmodified lines | ||
| 619 | 619 | |
| 620 | 620 | video_set_drvdata(vdev, isp); |
| 621 | 621 | |
| 622 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 622 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 623 | 623 | if (ret < 0) { |
| 624 | 624 | media_entity_cleanup(&vdev->entity); |
| 625 | 625 | return ret; |
| @@ -1297,7 +1297,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) · 1296 unmodified lines | ||
| 1297 | 1297 | video_set_drvdata(vfd, fimc); |
| 1298 | 1298 | fimc->ve.pipe = v4l2_get_subdev_hostdata(sd); |
| 1299 | 1299 | |
| 1300 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 1300 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 1301 | 1301 | if (ret < 0) { |
| 1302 | 1302 | media_entity_cleanup(&vfd->entity); |
| 1303 | 1303 | fimc->ve.pipe = NULL; |
| @@ -1614,6 +1614,9 @@ static int fimc_lite_remove(struct platform_device *pdev) · 310 unmodified lines | ||
| 1614 | 1614 | struct fimc_lite *fimc = platform_get_drvdata(pdev); |
| 1615 | 1615 | struct device *dev = &pdev->dev; |
| 1616 | 1616 | |
| 1617 | + if (!pm_runtime_enabled(dev)) | |
| 1618 | + clk_disable_unprepare(fimc->clock); | |
| 1619 | + | |
| 1617 | 1620 | pm_runtime_disable(dev); |
| 1618 | 1621 | pm_runtime_set_suspended(dev); |
| 1619 | 1622 | fimc_lite_unregister_capture_subdev(fimc); |
| @@ -746,7 +746,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc, · 745 unmodified lines | ||
| 746 | 746 | if (ret) |
| 747 | 747 | goto err_me; |
| 748 | 748 | |
| 749 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 749 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 750 | 750 | if (ret) |
| 751 | 751 | goto err_vd; |
| 752 | 752 | |
| @@ -1486,7 +1486,7 @@ static int viu_of_probe(struct platform_device *op) · 1485 unmodified lines | ||
| 1486 | 1486 | |
| 1487 | 1487 | mutex_lock(&viu_dev->lock); |
| 1488 | 1488 | |
| 1489 | − ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1); | |
| 1489 | + ret = video_register_device(viu_dev->vdev, VFL_TYPE_VIDEO, -1); | |
| 1490 | 1490 | if (ret < 0) { |
| 1491 | 1491 | video_device_release(viu_dev->vdev); |
| 1492 | 1492 | goto err_unlock; |
| @@ -1709,7 +1709,7 @@ static int pxp_probe(struct platform_device *pdev) · 1708 unmodified lines | ||
| 1709 | 1709 | goto err_v4l2; |
| 1710 | 1710 | } |
| 1711 | 1711 | |
| 1712 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 1712 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 1713 | 1713 | if (ret) { |
| 1714 | 1714 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 1715 | 1715 | goto err_m2m; |
| @@ -953,7 +953,7 @@ static int deinterlace_probe(struct platform_device *pdev) · 952 unmodified lines | ||
| 953 | 953 | vfd->lock = &pcdev->dev_mutex; |
| 954 | 954 | vfd->v4l2_dev = &pcdev->v4l2_dev; |
| 955 | 955 | |
| 956 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 956 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 957 | 957 | if (ret) { |
| 958 | 958 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); |
| 959 | 959 | goto unreg_dev; |
| @@ -1802,7 +1802,7 @@ static int mccic_notify_bound(struct v4l2_async_notifier *notifier, · 1801 unmodified lines | ||
| 1802 | 1802 | cam->vdev.lock = &cam->s_mutex; |
| 1803 | 1803 | cam->vdev.queue = &cam->vb_queue; |
| 1804 | 1804 | video_set_drvdata(&cam->vdev, cam); |
| 1805 | − ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); | |
| 1805 | + ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); | |
| 1806 | 1806 | if (ret) { |
| 1807 | 1807 | cam->sensor = NULL; |
| 1808 | 1808 | goto out; |
| @@ -1150,7 +1150,7 @@ static int mtk_jpeg_probe(struct platform_device *pdev) · 1149 unmodified lines | ||
| 1150 | 1150 | jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | |
| 1151 | 1151 | V4L2_CAP_VIDEO_M2M_MPLANE; |
| 1152 | 1152 | |
| 1153 | − ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3); | |
| 1153 | + ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_VIDEO, 3); | |
| 1154 | 1154 | if (ret) { |
| 1155 | 1155 | v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); |
| 1156 | 1156 | goto err_dec_vdev_register; |
| @@ -110,6 +110,12 @@ int mtk_mdp_comp_init(struct device *dev, struct device_node *node, · 109 unmodified lines | ||
| 110 | 110 | |
| 111 | 111 | for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { |
| 112 | 112 | comp->clk[i] = of_clk_get(node, i); |
| 113 | + if (IS_ERR(comp->clk[i])) { | |
| 114 | + if (PTR_ERR(comp->clk[i]) != -EPROBE_DEFER) | |
| 115 | + dev_err(dev, "Failed to get clock\n"); | |
| 116 | + | |
| 117 | + return PTR_ERR(comp->clk[i]); | |
| 118 | + } | |
| 113 | 119 | |
| 114 | 120 | /* Only RDMA needs two clocks */ |
| 115 | 121 | if (comp->type != MTK_MDP_RDMA) |
| @@ -1229,7 +1229,7 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp) · 1228 unmodified lines | ||
| 1229 | 1229 | goto err_m2m_init; |
| 1230 | 1230 | } |
| 1231 | 1231 | |
| 1232 | − ret = video_register_device(mdp->vdev, VFL_TYPE_GRABBER, 2); | |
| 1232 | + ret = video_register_device(mdp->vdev, VFL_TYPE_VIDEO, 2); | |
| 1233 | 1233 | if (ret) { |
| 1234 | 1234 | dev_err(dev, "failed to register video device\n"); |
| 1235 | 1235 | goto err_vdev_register; |
| @@ -15,7 +15,7 @@ static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu) · 14 unmodified lines | ||
| 15 | 15 | return container_of(vpu, struct mtk_mdp_ctx, vpu); |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | −static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg) | |
| 18 | +static void mtk_mdp_vpu_handle_init_ack(const struct mdp_ipi_comm_ack *msg) | |
| 19 | 19 | { |
| 20 | 20 | struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *) |
| 21 | 21 | (unsigned long)msg->ap_inst; |
| @@ -26,10 +26,11 @@ static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg) · 4 unmodified lines | ||
| 26 | 26 | vpu->inst_addr = msg->vpu_inst_addr; |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | −static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv) | |
| 29 | +static void mtk_mdp_vpu_ipi_handler(const void *data, unsigned int len, | |
| 30 | + void *priv) | |
| 30 | 31 | { |
| 31 | − unsigned int msg_id = *(unsigned int *)data; | |
| 32 | − struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data; | |
| 32 | + const struct mdp_ipi_comm_ack *msg = data; | |
| 33 | + unsigned int msg_id = msg->msg_id; | |
| 33 | 34 | struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *) |
| 34 | 35 | (unsigned long)msg->ap_inst; |
| 35 | 36 | struct mtk_mdp_ctx *ctx; |
| @@ -331,7 +331,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) · 330 unmodified lines | ||
| 331 | 331 | goto err_event_workq; |
| 332 | 332 | } |
| 333 | 333 | |
| 334 | − ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0); | |
| 334 | + ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, 0); | |
| 335 | 335 | if (ret) { |
| 336 | 336 | mtk_v4l2_err("Failed to register video device"); |
| 337 | 337 | goto err_dec_reg; |
| @@ -356,7 +356,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) · 355 unmodified lines | ||
| 356 | 356 | goto err_event_workq; |
| 357 | 357 | } |
| 358 | 358 | |
| 359 | − ret = video_register_device(vfd_enc, VFL_TYPE_GRABBER, 1); | |
| 359 | + ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, 1); | |
| 360 | 360 | if (ret) { |
| 361 | 361 | mtk_v4l2_err("Failed to register video device"); |
| 362 | 362 | goto err_enc_reg; |
| @@ -110,7 +110,11 @@ struct vp9_sf_ref_fb { · 109 unmodified lines | ||
| 110 | 110 | * @buf_len_sz_c : size used to store cbcr plane ufo info (AP-R, VPU-W) |
| 111 | 111 | |
| 112 | 112 | * @profile : profile sparsed from vpu (AP-R, VPU-W) |
| 113 | − * @show_frame : display this frame or not (AP-R, VPU-W) | |
| 113 | + * @show_frame : [BIT(0)] display this frame or not (AP-R, VPU-W) | |
| 114 | + * [BIT(1)] reset segment data or not (AP-R, VPU-W) | |
| 115 | + * [BIT(2)] trig decoder hardware or not (AP-R, VPU-W) | |
| 116 | + * [BIT(3)] ask VPU to set bits(0~4) accordingly (AP-W, VPU-R) | |
| 117 | + * [BIT(4)] do not reset segment data before every frame (AP-R, VPU-W) | |
| 114 | 118 | * @show_existing_frame : inform this frame is show existing frame |
| 115 | 119 | * (AP-R, VPU-W) |
| 116 | 120 | * @frm_to_show_idx : index to show frame (AP-R, VPU-W) |
| @@ -494,12 +498,12 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst) · 377 unmodified lines | ||
| 494 | 498 | frm_to_show->fb->base_y.size); |
| 495 | 499 | } |
| 496 | 500 | if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) { |
| 497 | − if (vsi->show_frame) | |
| 501 | + if (vsi->show_frame & BIT(0)) | |
| 498 | 502 | vp9_add_to_fb_disp_list(inst, inst->cur_fb); |
| 499 | 503 | } |
| 500 | 504 | } else { |
| 501 | 505 | if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) { |
| 502 | − if (vsi->show_frame) | |
| 506 | + if (vsi->show_frame & BIT(0)) | |
| 503 | 507 | vp9_add_to_fb_disp_list(inst, frm_to_show->fb); |
| 504 | 508 | } |
| 505 | 509 | } |
| @@ -800,6 +804,9 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx) · 294 unmodified lines | ||
| 800 | 804 | } |
| 801 | 805 | |
| 802 | 806 | inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi; |
| 807 | + | |
| 808 | + inst->vsi->show_frame |= BIT(3); | |
| 809 | + | |
| 803 | 810 | init_all_fb_lists(inst); |
| 804 | 811 | |
| 805 | 812 | ctx->drv_handle = inst; |
| @@ -870,13 +877,27 @@ static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs, · 64 unmodified lines | ||
| 870 | 877 | vsi->sf_frm_sz[idx]); |
| 871 | 878 | } |
| 872 | 879 | } |
| 873 | − memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size); | |
| 880 | + | |
| 881 | + if (!(vsi->show_frame & BIT(4))) | |
| 882 | + memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size); | |
| 883 | + | |
| 874 | 884 | ret = vpu_dec_start(&inst->vpu, data, 3); |
| 875 | 885 | if (ret) { |
| 876 | 886 | mtk_vcodec_err(inst, "vpu_dec_start failed"); |
| 877 | 887 | goto DECODE_ERROR; |
| 878 | 888 | } |
| 879 | 889 | |
| 890 | + if (vsi->show_frame & BIT(1)) { | |
| 891 | + memset(inst->seg_id_buf.va, 0, inst->seg_id_buf.size); | |
| 892 | + | |
| 893 | + if (vsi->show_frame & BIT(2)) { | |
| 894 | + if (vpu_dec_start(&inst->vpu, NULL, 0)) { | |
| 895 | + mtk_vcodec_err(inst, "vpu trig decoder failed"); | |
| 896 | + goto DECODE_ERROR; | |
| 897 | + } | |
| 898 | + } | |
| 899 | + } | |
| 900 | + | |
| 880 | 901 | ret = validate_vsi_array_indexes(inst, vsi); |
| 881 | 902 | if (ret) { |
| 882 | 903 | mtk_vcodec_err(inst, "Invalid values from VPU."); |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "vdec_ipi_msg.h" |
| 10 | 10 | #include "vdec_vpu_if.h" |
| 11 | 11 | |
| 12 | −static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg) | |
| 12 | +static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) | |
| 13 | 13 | { |
| 14 | 14 | struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) |
| 15 | 15 | (unsigned long)msg->ap_inst_addr; |
| @@ -34,9 +34,9 @@ static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg) · 18 unmodified lines | ||
| 34 | 34 | * This function runs in interrupt context and it means there's an IPI MSG |
| 35 | 35 | * from VPU. |
| 36 | 36 | */ |
| 37 | −static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) | |
| 37 | +static void vpu_dec_ipi_handler(const void *data, unsigned int len, void *priv) | |
| 38 | 38 | { |
| 39 | − struct vdec_vpu_ipi_ack *msg = data; | |
| 39 | + const struct vdec_vpu_ipi_ack *msg = data; | |
| 40 | 40 | struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) |
| 41 | 41 | (unsigned long)msg->ap_inst_addr; |
| 42 | 42 | |
| @@ -8,26 +8,26 @@ · 7 unmodified lines | ||
| 8 | 8 | #include "venc_ipi_msg.h" |
| 9 | 9 | #include "venc_vpu_if.h" |
| 10 | 10 | |
| 11 | −static void handle_enc_init_msg(struct venc_vpu_inst *vpu, void *data) | |
| 11 | +static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data) | |
| 12 | 12 | { |
| 13 | − struct venc_vpu_ipi_msg_init *msg = data; | |
| 13 | + const struct venc_vpu_ipi_msg_init *msg = data; | |
| 14 | 14 | |
| 15 | 15 | vpu->inst_addr = msg->vpu_inst_addr; |
| 16 | 16 | vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr); |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | −static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, void *data) | |
| 19 | +static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data) | |
| 20 | 20 | { |
| 21 | − struct venc_vpu_ipi_msg_enc *msg = data; | |
| 21 | + const struct venc_vpu_ipi_msg_enc *msg = data; | |
| 22 | 22 | |
| 23 | 23 | vpu->state = msg->state; |
| 24 | 24 | vpu->bs_size = msg->bs_size; |
| 25 | 25 | vpu->is_key_frm = msg->is_key_frm; |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | −static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv) | |
| 28 | +static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv) | |
| 29 | 29 | { |
| 30 | − struct venc_vpu_ipi_msg_common *msg = data; | |
| 30 | + const struct venc_vpu_ipi_msg_common *msg = data; | |
| 31 | 31 | struct venc_vpu_inst *vpu = |
| 32 | 32 | (struct venc_vpu_inst *)(unsigned long)msg->venc_inst; |
| 33 | 33 | |
| @@ -46,6 +46,8 @@ · 45 unmodified lines | ||
| 46 | 46 | /* binary firmware name */ |
| 47 | 47 | #define VPU_P_FW "vpu_p.bin" |
| 48 | 48 | #define VPU_D_FW "vpu_d.bin" |
| 49 | +#define VPU_P_FW_NEW "mediatek/mt8173/vpu_p.bin" | |
| 50 | +#define VPU_D_FW_NEW "mediatek/mt8173/vpu_d.bin" | |
| 49 | 51 | |
| 50 | 52 | #define VPU_RESET 0x0 |
| 51 | 53 | #define VPU_TCM_CFG 0x0008 |
| @@ -203,8 +205,8 @@ struct mtk_vpu { · 151 unmodified lines | ||
| 203 | 205 | struct vpu_run run; |
| 204 | 206 | struct vpu_wdt wdt; |
| 205 | 207 | struct vpu_ipi_desc ipi_desc[IPI_MAX]; |
| 206 | − struct share_obj *recv_buf; | |
| 207 | − struct share_obj *send_buf; | |
| 208 | + struct share_obj __iomem *recv_buf; | |
| 209 | + struct share_obj __iomem *send_buf; | |
| 208 | 210 | struct device *dev; |
| 209 | 211 | struct clk *clk; |
| 210 | 212 | bool fw_loaded; |
| @@ -292,7 +294,7 @@ int vpu_ipi_send(struct platform_device *pdev, · 81 unmodified lines | ||
| 292 | 294 | unsigned int len) |
| 293 | 295 | { |
| 294 | 296 | struct mtk_vpu *vpu = platform_get_drvdata(pdev); |
| 295 | − struct share_obj *send_obj = vpu->send_buf; | |
| 297 | + struct share_obj __iomem *send_obj = vpu->send_buf; | |
| 296 | 298 | unsigned long timeout; |
| 297 | 299 | int ret = 0; |
| 298 | 300 | |
| @@ -325,9 +327,9 @@ int vpu_ipi_send(struct platform_device *pdev, · 26 unmodified lines | ||
| 325 | 327 | } |
| 326 | 328 | } while (vpu_cfg_readl(vpu, HOST_TO_VPU)); |
| 327 | 329 | |
| 328 | − memcpy((void *)send_obj->share_buf, buf, len); | |
| 329 | − send_obj->len = len; | |
| 330 | − send_obj->id = id; | |
| 330 | + memcpy_toio(send_obj->share_buf, buf, len); | |
| 331 | + writel(len, &send_obj->len); | |
| 332 | + writel(id, &send_obj->id); | |
| 331 | 333 | |
| 332 | 334 | vpu->ipi_id_ack[id] = false; |
| 333 | 335 | /* send the command to VPU */ |
| @@ -477,16 +479,24 @@ static int load_requested_vpu(struct mtk_vpu *vpu, · 143 unmodified lines | ||
| 477 | 479 | size_t tcm_size = fw_type ? VPU_DTCM_SIZE : VPU_PTCM_SIZE; |
| 478 | 480 | size_t fw_size = fw_type ? VPU_D_FW_SIZE : VPU_P_FW_SIZE; |
| 479 | 481 | char *fw_name = fw_type ? VPU_D_FW : VPU_P_FW; |
| 482 | + char *fw_new_name = fw_type ? VPU_D_FW_NEW : VPU_P_FW_NEW; | |
| 480 | 483 | const struct firmware *vpu_fw; |
| 481 | 484 | size_t dl_size = 0; |
| 482 | 485 | size_t extra_fw_size = 0; |
| 483 | 486 | void *dest; |
| 484 | 487 | int ret; |
| 485 | 488 | |
| 486 | − ret = request_firmware(&vpu_fw, fw_name, vpu->dev); | |
| 489 | + ret = request_firmware(&vpu_fw, fw_new_name, vpu->dev); | |
| 487 | 490 | if (ret < 0) { |
| 488 | − dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name, ret); | |
| 489 | − return ret; | |
| 491 | + dev_info(vpu->dev, "Failed to load %s, %d, retry\n", | |
| 492 | + fw_new_name, ret); | |
| 493 | + | |
| 494 | + ret = request_firmware(&vpu_fw, fw_name, vpu->dev); | |
| 495 | + if (ret < 0) { | |
| 496 | + dev_err(vpu->dev, "Failed to load %s, %d\n", fw_name, | |
| 497 | + ret); | |
| 498 | + return ret; | |
| 499 | + } | |
| 490 | 500 | } |
| 491 | 501 | dl_size = vpu_fw->size; |
| 492 | 502 | if (dl_size > fw_size) { |
| @@ -600,10 +610,10 @@ OUT_LOAD_FW: · 107 unmodified lines | ||
| 600 | 610 | } |
| 601 | 611 | EXPORT_SYMBOL_GPL(vpu_load_firmware); |
| 602 | 612 | |
| 603 | −static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) | |
| 613 | +static void vpu_init_ipi_handler(const void *data, unsigned int len, void *priv) | |
| 604 | 614 | { |
| 605 | − struct mtk_vpu *vpu = (struct mtk_vpu *)priv; | |
| 606 | − struct vpu_run *run = (struct vpu_run *)data; | |
| 615 | + struct mtk_vpu *vpu = priv; | |
| 616 | + const struct vpu_run *run = data; | |
| 607 | 617 | |
| 608 | 618 | vpu->run.signaled = run->signaled; |
| 609 | 619 | strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver)); |
| @@ -700,19 +710,21 @@ static int vpu_alloc_ext_mem(struct mtk_vpu *vpu, u32 fw_type) · 90 unmodified lines | ||
| 700 | 710 | |
| 701 | 711 | static void vpu_ipi_handler(struct mtk_vpu *vpu) |
| 702 | 712 | { |
| 703 | − struct share_obj *rcv_obj = vpu->recv_buf; | |
| 713 | + struct share_obj __iomem *rcv_obj = vpu->recv_buf; | |
| 704 | 714 | struct vpu_ipi_desc *ipi_desc = vpu->ipi_desc; |
| 705 | − | |
| 706 | − if (rcv_obj->id < IPI_MAX && ipi_desc[rcv_obj->id].handler) { | |
| 707 | − ipi_desc[rcv_obj->id].handler(rcv_obj->share_buf, | |
| 708 | − rcv_obj->len, | |
| 709 | − ipi_desc[rcv_obj->id].priv); | |
| 710 | − if (rcv_obj->id > IPI_VPU_INIT) { | |
| 711 | − vpu->ipi_id_ack[rcv_obj->id] = true; | |
| 715 | + unsigned char data[SHARE_BUF_SIZE]; | |
| 716 | + s32 id = readl(&rcv_obj->id); | |
| 717 | + | |
| 718 | + memcpy_fromio(data, rcv_obj->share_buf, sizeof(data)); | |
| 719 | + if (id < IPI_MAX && ipi_desc[id].handler) { | |
| 720 | + ipi_desc[id].handler(data, readl(&rcv_obj->len), | |
| 721 | + ipi_desc[id].priv); | |
| 722 | + if (id > IPI_VPU_INIT) { | |
| 723 | + vpu->ipi_id_ack[id] = true; | |
| 712 | 724 | wake_up(&vpu->ack_wq); |
| 713 | 725 | } |
| 714 | 726 | } else { |
| 715 | − dev_err(vpu->dev, "No such ipi id = %d\n", rcv_obj->id); | |
| 727 | + dev_err(vpu->dev, "No such ipi id = %d\n", id); | |
| 716 | 728 | } |
| 717 | 729 | } |
| 718 | 730 | |
| @@ -722,11 +734,10 @@ static int vpu_ipi_init(struct mtk_vpu *vpu) · 3 unmodified lines | ||
| 722 | 734 | vpu_cfg_writel(vpu, 0x0, VPU_TO_HOST); |
| 723 | 735 | |
| 724 | 736 | /* shared buffer initialization */ |
| 725 | − vpu->recv_buf = (__force struct share_obj *)(vpu->reg.tcm + | |
| 726 | − VPU_DTCM_OFFSET); | |
| 737 | + vpu->recv_buf = vpu->reg.tcm + VPU_DTCM_OFFSET; | |
| 727 | 738 | vpu->send_buf = vpu->recv_buf + 1; |
| 728 | − memset(vpu->recv_buf, 0, sizeof(struct share_obj)); | |
| 729 | − memset(vpu->send_buf, 0, sizeof(struct share_obj)); | |
| 739 | + memset_io(vpu->recv_buf, 0, sizeof(struct share_obj)); | |
| 740 | + memset_io(vpu->send_buf, 0, sizeof(struct share_obj)); | |
| 730 | 741 | |
| 731 | 742 | return 0; |
| 732 | 743 | } |
| @@ -15,7 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | * VPU interfaces with other blocks by share memory and interrupt. |
| 16 | 16 | **/ |
| 17 | 17 | |
| 18 | −typedef void (*ipi_handler_t) (void *data, | |
| 18 | +typedef void (*ipi_handler_t) (const void *data, | |
| 19 | 19 | unsigned int len, |
| 20 | 20 | void *priv); |
| 21 | 21 | |
| @@ -866,7 +866,7 @@ static int emmaprp_probe(struct platform_device *pdev) · 865 unmodified lines | ||
| 866 | 866 | goto rel_vdev; |
| 867 | 867 | } |
| 868 | 868 | |
| 869 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 869 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 870 | 870 | if (ret) { |
| 871 | 871 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); |
| 872 | 872 | goto rel_m2m; |
| @@ -1500,7 +1500,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) · 1499 unmodified lines | ||
| 1500 | 1500 | /* Register the Video device with V4L2 |
| 1501 | 1501 | */ |
| 1502 | 1502 | vfd = vout->vfd; |
| 1503 | − if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) { | |
| 1503 | + if (video_register_device(vfd, VFL_TYPE_VIDEO, -1) < 0) { | |
| 1504 | 1504 | dev_err(&pdev->dev, |
| 1505 | 1505 | ": Could not register Video for Linux device\n"); |
| 1506 | 1506 | vfd->minor = -1; |
| @@ -1312,6 +1312,10 @@ static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable) · 1311 unmodified lines | ||
| 1312 | 1312 | { |
| 1313 | 1313 | struct isp_device *isp = to_isp_device(ccdc); |
| 1314 | 1314 | |
| 1315 | + /* Avoid restarting the CCDC when streaming is stopping. */ | |
| 1316 | + if (enable && ccdc->stopping & CCDC_STOP_REQUEST) | |
| 1317 | + return; | |
| 1318 | + | |
| 1315 | 1319 | isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, |
| 1316 | 1320 | ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0); |
| 1317 | 1321 | |
| @@ -1311,7 +1311,7 @@ static int isp_video_open(struct file *file) · 1310 unmodified lines | ||
| 1311 | 1311 | goto done; |
| 1312 | 1312 | } |
| 1313 | 1313 | |
| 1314 | − ret = v4l2_pipeline_pm_use(&video->video.entity, 1); | |
| 1314 | + ret = v4l2_pipeline_pm_get(&video->video.entity); | |
| 1315 | 1315 | if (ret < 0) { |
| 1316 | 1316 | omap3isp_put(video->isp); |
| 1317 | 1317 | goto done; |
| @@ -1363,7 +1363,7 @@ static int isp_video_release(struct file *file) · 45 unmodified lines | ||
| 1363 | 1363 | vb2_queue_release(&handle->queue); |
| 1364 | 1364 | mutex_unlock(&video->queue_lock); |
| 1365 | 1365 | |
| 1366 | − v4l2_pipeline_pm_use(&video->video.entity, 0); | |
| 1366 | + v4l2_pipeline_pm_put(&video->video.entity); | |
| 1367 | 1367 | |
| 1368 | 1368 | /* Release the file handle. */ |
| 1369 | 1369 | v4l2_fh_del(vfh); |
| @@ -1453,7 +1453,7 @@ int omap3isp_video_init(struct isp_video *video, const char *name) · 83 unmodified lines | ||
| 1453 | 1453 | video->video.fops = &isp_video_fops; |
| 1454 | 1454 | snprintf(video->video.name, sizeof(video->video.name), |
| 1455 | 1455 | "OMAP3 ISP %s %s", name, direction); |
| 1456 | − video->video.vfl_type = VFL_TYPE_GRABBER; | |
| 1456 | + video->video.vfl_type = VFL_TYPE_VIDEO; | |
| 1457 | 1457 | video->video.release = video_device_release_empty; |
| 1458 | 1458 | video->video.ioctl_ops = &isp_video_ioctl_ops; |
| 1459 | 1459 | if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
| @@ -1484,7 +1484,7 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) · 24 unmodified lines | ||
| 1484 | 1484 | |
| 1485 | 1485 | video->video.v4l2_dev = vdev; |
| 1486 | 1486 | |
| 1487 | − ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); | |
| 1487 | + ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1); | |
| 1488 | 1488 | if (ret < 0) |
| 1489 | 1489 | dev_err(video->isp->dev, |
| 1490 | 1490 | "%s: could not register video device (%d)\n", |
| @@ -2191,7 +2191,7 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, · 2190 unmodified lines | ||
| 2191 | 2191 | if (err) |
| 2192 | 2192 | goto out_sensor_poweroff; |
| 2193 | 2193 | |
| 2194 | − err = video_register_device(&pcdev->vdev, VFL_TYPE_GRABBER, -1); | |
| 2194 | + err = video_register_device(&pcdev->vdev, VFL_TYPE_VIDEO, -1); | |
| 2195 | 2195 | if (err) { |
| 2196 | 2196 | v4l2_err(v4l2_dev, "register video device failed: %d\n", err); |
| 2197 | 2197 | pcdev->sensor = NULL; |
| @@ -2440,23 +2440,23 @@ static int pxa_camera_probe(struct platform_device *pdev) · 242 unmodified lines | ||
| 2440 | 2440 | pcdev->base = base; |
| 2441 | 2441 | |
| 2442 | 2442 | /* request dma */ |
| 2443 | − pcdev->dma_chans[0] = dma_request_slave_channel(&pdev->dev, "CI_Y"); | |
| 2444 | − if (!pcdev->dma_chans[0]) { | |
| 2443 | + pcdev->dma_chans[0] = dma_request_chan(&pdev->dev, "CI_Y"); | |
| 2444 | + if (IS_ERR(pcdev->dma_chans[0])) { | |
| 2445 | 2445 | dev_err(&pdev->dev, "Can't request DMA for Y\n"); |
| 2446 | − return -ENODEV; | |
| 2446 | + return PTR_ERR(pcdev->dma_chans[0]); | |
| 2447 | 2447 | } |
| 2448 | 2448 | |
| 2449 | − pcdev->dma_chans[1] = dma_request_slave_channel(&pdev->dev, "CI_U"); | |
| 2450 | − if (!pcdev->dma_chans[1]) { | |
| 2451 | − dev_err(&pdev->dev, "Can't request DMA for Y\n"); | |
| 2452 | − err = -ENODEV; | |
| 2449 | + pcdev->dma_chans[1] = dma_request_chan(&pdev->dev, "CI_U"); | |
| 2450 | + if (IS_ERR(pcdev->dma_chans[1])) { | |
| 2451 | + dev_err(&pdev->dev, "Can't request DMA for U\n"); | |
| 2452 | + err = PTR_ERR(pcdev->dma_chans[1]); | |
| 2453 | 2453 | goto exit_free_dma_y; |
| 2454 | 2454 | } |
| 2455 | 2455 | |
| 2456 | − pcdev->dma_chans[2] = dma_request_slave_channel(&pdev->dev, "CI_V"); | |
| 2457 | − if (!pcdev->dma_chans[2]) { | |
| 2456 | + pcdev->dma_chans[2] = dma_request_chan(&pdev->dev, "CI_V"); | |
| 2457 | + if (IS_ERR(pcdev->dma_chans[2])) { | |
| 2458 | 2458 | dev_err(&pdev->dev, "Can't request DMA for V\n"); |
| 2459 | − err = -ENODEV; | |
| 2459 | + err = PTR_ERR(pcdev->dma_chans[2]); | |
| 2460 | 2460 | goto exit_free_dma_u; |
| 2461 | 2461 | } |
| 2462 | 2462 | |
| @@ -745,7 +745,7 @@ static int video_open(struct file *file) · 744 unmodified lines | ||
| 745 | 745 | |
| 746 | 746 | file->private_data = vfh; |
| 747 | 747 | |
| 748 | − ret = v4l2_pipeline_pm_use(&vdev->entity, 1); | |
| 748 | + ret = v4l2_pipeline_pm_get(&vdev->entity); | |
| 749 | 749 | if (ret < 0) { |
| 750 | 750 | dev_err(video->camss->dev, "Failed to power up pipeline: %d\n", |
| 751 | 751 | ret); |
| @@ -771,7 +771,7 @@ static int video_release(struct file *file) · 19 unmodified lines | ||
| 771 | 771 | |
| 772 | 772 | vb2_fop_release(file); |
| 773 | 773 | |
| 774 | − v4l2_pipeline_pm_use(&vdev->entity, 0); | |
| 774 | + v4l2_pipeline_pm_put(&vdev->entity); | |
| 775 | 775 | |
| 776 | 776 | file->private_data = NULL; |
| 777 | 777 | |
| @@ -921,7 +921,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, · 143 unmodified lines | ||
| 921 | 921 | vdev->lock = &video->lock; |
| 922 | 922 | strscpy(vdev->name, name, sizeof(vdev->name)); |
| 923 | 923 | |
| 924 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 924 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 925 | 925 | if (ret < 0) { |
| 926 | 926 | dev_err(v4l2_dev->dev, "Failed to register video device: %d\n", |
| 927 | 927 | ret); |
| @@ -3,7 +3,7 @@ · 2 unmodified lines | ||
| 3 | 3 | |
| 4 | 4 | venus-core-objs += core.o helpers.o firmware.o \ |
| 5 | 5 | hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \ |
| 6 | − hfi_parser.o | |
| 6 | + hfi_parser.o pm_helpers.o | |
| 7 | 7 | |
| 8 | 8 | venus-dec-objs += vdec.o vdec_ctrls.o |
| 9 | 9 | venus-enc-objs += venc.o venc_ctrls.o |
| @@ -3,7 +3,6 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. |
| 4 | 4 | * Copyright (C) 2017 Linaro Ltd. |
| 5 | 5 | */ |
| 6 | −#include <linux/clk.h> | |
| 7 | 6 | #include <linux/init.h> |
| 8 | 7 | #include <linux/interconnect.h> |
| 9 | 8 | #include <linux/ioctl.h> |
| @@ -19,9 +18,8 @@ · 9 unmodified lines | ||
| 19 | 18 | #include <media/v4l2-ioctl.h> |
| 20 | 19 | |
| 21 | 20 | #include "core.h" |
| 22 | −#include "vdec.h" | |
| 23 | −#include "venc.h" | |
| 24 | 21 | #include "firmware.h" |
| 22 | +#include "pm_helpers.h" | |
| 25 | 23 | |
| 26 | 24 | static void venus_event_notify(struct venus_core *core, u32 event) |
| 27 | 25 | { |
| @@ -100,50 +98,6 @@ static void venus_sys_error_handler(struct work_struct *work) · 72 unmodified lines | ||
| 100 | 98 | mutex_unlock(&core->lock); |
| 101 | 99 | } |
| 102 | 100 | |
| 103 | −static int venus_clks_get(struct venus_core *core) | |
| 104 | −{ | |
| 105 | − const struct venus_resources *res = core->res; | |
| 106 | − struct device *dev = core->dev; | |
| 107 | − unsigned int i; | |
| 108 | − | |
| 109 | − for (i = 0; i < res->clks_num; i++) { | |
| 110 | − core->clks[i] = devm_clk_get(dev, res->clks[i]); | |
| 111 | − if (IS_ERR(core->clks[i])) | |
| 112 | − return PTR_ERR(core->clks[i]); | |
| 113 | − } | |
| 114 | − | |
| 115 | − return 0; | |
| 116 | −} | |
| 117 | − | |
| 118 | −static int venus_clks_enable(struct venus_core *core) | |
| 119 | −{ | |
| 120 | − const struct venus_resources *res = core->res; | |
| 121 | − unsigned int i; | |
| 122 | − int ret; | |
| 123 | − | |
| 124 | − for (i = 0; i < res->clks_num; i++) { | |
| 125 | − ret = clk_prepare_enable(core->clks[i]); | |
| 126 | − if (ret) | |
| 127 | − goto err; | |
| 128 | − } | |
| 129 | − | |
| 130 | − return 0; | |
| 131 | −err: | |
| 132 | − while (i--) | |
| 133 | − clk_disable_unprepare(core->clks[i]); | |
| 134 | − | |
| 135 | − return ret; | |
| 136 | −} | |
| 137 | − | |
| 138 | −static void venus_clks_disable(struct venus_core *core) | |
| 139 | −{ | |
| 140 | − const struct venus_resources *res = core->res; | |
| 141 | − unsigned int i = res->clks_num; | |
| 142 | − | |
| 143 | − while (i--) | |
| 144 | − clk_disable_unprepare(core->clks[i]); | |
| 145 | −} | |
| 146 | − | |
| 147 | 101 | static u32 to_v4l2_codec_type(u32 codec) |
| 148 | 102 | { |
| 149 | 103 | switch (codec) { |
| @@ -256,9 +210,15 @@ static int venus_probe(struct platform_device *pdev) · 106 unmodified lines | ||
| 256 | 210 | if (!core->res) |
| 257 | 211 | return -ENODEV; |
| 258 | 212 | |
| 259 | − ret = venus_clks_get(core); | |
| 260 | − if (ret) | |
| 261 | − return ret; | |
| 213 | + core->pm_ops = venus_pm_get(core->res->hfi_version); | |
| 214 | + if (!core->pm_ops) | |
| 215 | + return -ENODEV; | |
| 216 | + | |
| 217 | + if (core->pm_ops->core_get) { | |
| 218 | + ret = core->pm_ops->core_get(dev); | |
| 219 | + if (ret) | |
| 220 | + return ret; | |
| 221 | + } | |
| 262 | 222 | |
| 263 | 223 | ret = dma_set_mask_and_coherent(dev, core->res->dma_mask); |
| 264 | 224 | if (ret) |
| @@ -350,6 +310,7 @@ err_runtime_disable: · 85 unmodified lines | ||
| 350 | 310 | static int venus_remove(struct platform_device *pdev) |
| 351 | 311 | { |
| 352 | 312 | struct venus_core *core = platform_get_drvdata(pdev); |
| 313 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 353 | 314 | struct device *dev = core->dev; |
| 354 | 315 | int ret; |
| 355 | 316 | |
| @@ -368,6 +329,9 @@ static int venus_remove(struct platform_device *pdev) · 12 unmodified lines | ||
| 368 | 329 | pm_runtime_put_sync(dev); |
| 369 | 330 | pm_runtime_disable(dev); |
| 370 | 331 | |
| 332 | + if (pm_ops->core_put) | |
| 333 | + pm_ops->core_put(dev); | |
| 334 | + | |
| 371 | 335 | icc_put(core->video_path); |
| 372 | 336 | icc_put(core->cpucfg_path); |
| 373 | 337 | |
| @@ -379,11 +343,15 @@ static int venus_remove(struct platform_device *pdev) · 5 unmodified lines | ||
| 379 | 343 | static __maybe_unused int venus_runtime_suspend(struct device *dev) |
| 380 | 344 | { |
| 381 | 345 | struct venus_core *core = dev_get_drvdata(dev); |
| 346 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 382 | 347 | int ret; |
| 383 | 348 | |
| 384 | 349 | ret = hfi_core_suspend(core); |
| 350 | + if (ret) | |
| 351 | + return ret; | |
| 385 | 352 | |
| 386 | − venus_clks_disable(core); | |
| 353 | + if (pm_ops->core_power) | |
| 354 | + ret = pm_ops->core_power(dev, POWER_OFF); | |
| 387 | 355 | |
| 388 | 356 | return ret; |
| 389 | 357 | } |
| @@ -391,21 +359,16 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) · 1 unmodified line | ||
| 391 | 359 | static __maybe_unused int venus_runtime_resume(struct device *dev) |
| 392 | 360 | { |
| 393 | 361 | struct venus_core *core = dev_get_drvdata(dev); |
| 362 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 394 | 363 | int ret; |
| 395 | 364 | |
| 396 | − ret = venus_clks_enable(core); | |
| 397 | − if (ret) | |
| 398 | − return ret; | |
| 399 | − | |
| 400 | − ret = hfi_core_resume(core, false); | |
| 401 | − if (ret) | |
| 402 | − goto err_clks_disable; | |
| 403 | − | |
| 404 | − return 0; | |
| 365 | + if (pm_ops->core_power) { | |
| 366 | + ret = pm_ops->core_power(dev, POWER_ON); | |
| 367 | + if (ret) | |
| 368 | + return ret; | |
| 369 | + } | |
| 405 | 370 | |
| 406 | −err_clks_disable: | |
| 407 | − venus_clks_disable(core); | |
| 408 | − return ret; | |
| 371 | + return hfi_core_resume(core, false); | |
| 409 | 372 | } |
| 410 | 373 | |
| 411 | 374 | static const struct dev_pm_ops venus_pm_ops = { |
| @@ -463,6 +426,9 @@ static const struct venus_resources msm8996_res = { · 51 unmodified lines | ||
| 463 | 426 | .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), |
| 464 | 427 | .clks = {"core", "iface", "bus", "mbus" }, |
| 465 | 428 | .clks_num = 4, |
| 429 | + .vcodec0_clks = { "core" }, | |
| 430 | + .vcodec1_clks = { "core" }, | |
| 431 | + .vcodec_clks_num = 1, | |
| 466 | 432 | .max_load = 2563200, |
| 467 | 433 | .hfi_version = HFI_VERSION_3XX, |
| 468 | 434 | .vmem_id = VIDC_RESOURCE_NONE, |
| @@ -517,6 +483,35 @@ static const struct venus_resources sdm845_res = { · 48 unmodified lines | ||
| 517 | 483 | .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data), |
| 518 | 484 | .clks = {"core", "iface", "bus" }, |
| 519 | 485 | .clks_num = 3, |
| 486 | + .vcodec0_clks = { "core", "bus" }, | |
| 487 | + .vcodec1_clks = { "core", "bus" }, | |
| 488 | + .vcodec_clks_num = 2, | |
| 489 | + .max_load = 3110400, /* 4096x2160@90 */ | |
| 490 | + .hfi_version = HFI_VERSION_4XX, | |
| 491 | + .vmem_id = VIDC_RESOURCE_NONE, | |
| 492 | + .vmem_size = 0, | |
| 493 | + .vmem_addr = 0, | |
| 494 | + .dma_mask = 0xe0000000 - 1, | |
| 495 | + .fwname = "qcom/venus-5.2/venus.mdt", | |
| 496 | +}; | |
| 497 | + | |
| 498 | +static const struct venus_resources sdm845_res_v2 = { | |
| 499 | + .freq_tbl = sdm845_freq_table, | |
| 500 | + .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), | |
| 501 | + .bw_tbl_enc = sdm845_bw_table_enc, | |
| 502 | + .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), | |
| 503 | + .bw_tbl_dec = sdm845_bw_table_dec, | |
| 504 | + .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), | |
| 505 | + .codec_freq_data = sdm845_codec_freq_data, | |
| 506 | + .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data), | |
| 507 | + .clks = {"core", "iface", "bus" }, | |
| 508 | + .clks_num = 3, | |
| 509 | + .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, | |
| 510 | + .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, | |
| 511 | + .vcodec_clks_num = 2, | |
| 512 | + .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, | |
| 513 | + .vcodec_pmdomains_num = 3, | |
| 514 | + .vcodec_num = 2, | |
| 520 | 515 | .max_load = 3110400, /* 4096x2160@90 */ |
| 521 | 516 | .hfi_version = HFI_VERSION_4XX, |
| 522 | 517 | .vmem_id = VIDC_RESOURCE_NONE, |
| @@ -526,10 +521,56 @@ static const struct venus_resources sdm845_res = { · 3 unmodified lines | ||
| 526 | 521 | .fwname = "qcom/venus-5.2/venus.mdt", |
| 527 | 522 | }; |
| 528 | 523 | |
| 524 | +static const struct freq_tbl sc7180_freq_table[] = { | |
| 525 | + { 0, 500000000 }, | |
| 526 | + { 0, 434000000 }, | |
| 527 | + { 0, 340000000 }, | |
| 528 | + { 0, 270000000 }, | |
| 529 | + { 0, 150000000 }, | |
| 530 | +}; | |
| 531 | + | |
| 532 | +static const struct bw_tbl sc7180_bw_table_enc[] = { | |
| 533 | + { 972000, 750000, 0, 0, 0 }, /* 3840x2160@30 */ | |
| 534 | + { 489600, 451000, 0, 0, 0 }, /* 1920x1080@60 */ | |
| 535 | + { 244800, 234000, 0, 0, 0 }, /* 1920x1080@30 */ | |
| 536 | +}; | |
| 537 | + | |
| 538 | +static const struct bw_tbl sc7180_bw_table_dec[] = { | |
| 539 | + { 1036800, 1386000, 0, 1875000, 0 }, /* 4096x2160@30 */ | |
| 540 | + { 489600, 865000, 0, 1146000, 0 }, /* 1920x1080@60 */ | |
| 541 | + { 244800, 530000, 0, 583000, 0 }, /* 1920x1080@30 */ | |
| 542 | +}; | |
| 543 | + | |
| 544 | +static const struct venus_resources sc7180_res = { | |
| 545 | + .freq_tbl = sc7180_freq_table, | |
| 546 | + .freq_tbl_size = ARRAY_SIZE(sc7180_freq_table), | |
| 547 | + .bw_tbl_enc = sc7180_bw_table_enc, | |
| 548 | + .bw_tbl_enc_size = ARRAY_SIZE(sc7180_bw_table_enc), | |
| 549 | + .bw_tbl_dec = sc7180_bw_table_dec, | |
| 550 | + .bw_tbl_dec_size = ARRAY_SIZE(sc7180_bw_table_dec), | |
| 551 | + .codec_freq_data = sdm845_codec_freq_data, | |
| 552 | + .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data), | |
| 553 | + .clks = {"core", "iface", "bus" }, | |
| 554 | + .clks_num = 3, | |
| 555 | + .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, | |
| 556 | + .vcodec_clks_num = 2, | |
| 557 | + .vcodec_pmdomains = { "venus", "vcodec0" }, | |
| 558 | + .vcodec_pmdomains_num = 2, | |
| 559 | + .vcodec_num = 1, | |
| 560 | + .hfi_version = HFI_VERSION_4XX, | |
| 561 | + .vmem_id = VIDC_RESOURCE_NONE, | |
| 562 | + .vmem_size = 0, | |
| 563 | + .vmem_addr = 0, | |
| 564 | + .dma_mask = 0xe0000000 - 1, | |
| 565 | + .fwname = "qcom/venus-5.4/venus.mdt", | |
| 566 | +}; | |
| 567 | + | |
| 529 | 568 | static const struct of_device_id venus_dt_match[] = { |
| 530 | 569 | { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, |
| 531 | 570 | { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, |
| 532 | 571 | { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, |
| 572 | + { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, | |
| 573 | + { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, | |
| 533 | 574 | { } |
| 534 | 575 | }; |
| 535 | 576 | MODULE_DEVICE_TABLE(of, venus_dt_match); |
| @@ -14,7 +14,9 @@ · 13 unmodified lines | ||
| 14 | 14 | |
| 15 | 15 | #include "hfi.h" |
| 16 | 16 | |
| 17 | −#define VIDC_CLKS_NUM_MAX 4 | |
| 17 | +#define VIDC_CLKS_NUM_MAX 4 | |
| 18 | +#define VIDC_VCODEC_CLKS_NUM_MAX 2 | |
| 19 | +#define VIDC_PMDOMAINS_NUM_MAX 3 | |
| 18 | 20 | |
| 19 | 21 | struct freq_tbl { |
| 20 | 22 | unsigned int load; |
| @@ -55,6 +57,12 @@ struct venus_resources { · 34 unmodified lines | ||
| 55 | 57 | unsigned int codec_freq_data_size; |
| 56 | 58 | const char * const clks[VIDC_CLKS_NUM_MAX]; |
| 57 | 59 | unsigned int clks_num; |
| 60 | + const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; | |
| 61 | + const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; | |
| 62 | + unsigned int vcodec_clks_num; | |
| 63 | + const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; | |
| 64 | + unsigned int vcodec_pmdomains_num; | |
| 65 | + unsigned int vcodec_num; | |
| 58 | 66 | enum hfi_version hfi_version; |
| 59 | 67 | u32 max_load; |
| 60 | 68 | unsigned int vmem_id; |
| @@ -100,10 +108,10 @@ struct venus_caps { · 39 unmodified lines | ||
| 100 | 108 | * @base: IO memory base address |
| 101 | 109 | * @irq: Venus irq |
| 102 | 110 | * @clks: an array of struct clk pointers |
| 103 | − * @core0_clk: a struct clk pointer for core0 | |
| 104 | − * @core1_clk: a struct clk pointer for core1 | |
| 105 | − * @core0_bus_clk: a struct clk pointer for core0 bus clock | |
| 106 | − * @core1_bus_clk: a struct clk pointer for core1 bus clock | |
| 111 | + * @vcodec0_clks: an array of vcodec0 struct clk pointers | |
| 112 | + * @vcodec1_clks: an array of vcodec1 struct clk pointers | |
| 113 | + * @pd_dl_venus: pmdomain device-link for venus domain | |
| 114 | + * @pmdomains: an array of pmdomains struct device pointers | |
| 107 | 115 | * @vdev_dec: a reference to video device structure for decoder instances |
| 108 | 116 | * @vdev_enc: a reference to video device structure for encoder instances |
| 109 | 117 | * @v4l2_dev: a holder for v4l2 device structure |
| @@ -132,12 +140,12 @@ struct venus_core { · 22 unmodified lines | ||
| 132 | 140 | void __iomem *base; |
| 133 | 141 | int irq; |
| 134 | 142 | struct clk *clks[VIDC_CLKS_NUM_MAX]; |
| 135 | − struct clk *core0_clk; | |
| 136 | − struct clk *core1_clk; | |
| 137 | − struct clk *core0_bus_clk; | |
| 138 | − struct clk *core1_bus_clk; | |
| 143 | + struct clk *vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; | |
| 144 | + struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; | |
| 139 | 145 | struct icc_path *video_path; |
| 140 | 146 | struct icc_path *cpucfg_path; |
| 147 | + struct device_link *pd_dl_venus; | |
| 148 | + struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; | |
| 141 | 149 | struct video_device *vdev_dec; |
| 142 | 150 | struct video_device *vdev_enc; |
| 143 | 151 | struct v4l2_device v4l2_dev; |
| @@ -159,6 +167,7 @@ struct venus_core { · 15 unmodified lines | ||
| 159 | 167 | unsigned int error; |
| 160 | 168 | bool sys_error; |
| 161 | 169 | const struct hfi_core_ops *core_ops; |
| 170 | + const struct venus_pm_ops *pm_ops; | |
| 162 | 171 | unsigned long enc_codecs; |
| 163 | 172 | unsigned long dec_codecs; |
| 164 | 173 | unsigned int max_sessions_supported; |
| @@ -172,6 +181,8 @@ struct venus_core { · 7 unmodified lines | ||
| 172 | 181 | struct delayed_work work; |
| 173 | 182 | struct venus_caps caps[MAX_CODEC_NUM]; |
| 174 | 183 | unsigned int codecs_count; |
| 184 | + unsigned int core0_usage_count; | |
| 185 | + unsigned int core1_usage_count; | |
| 175 | 186 | }; |
| 176 | 187 | |
| 177 | 188 | struct vdec_controls { |
| @@ -187,6 +198,7 @@ struct venc_controls { · 9 unmodified lines | ||
| 187 | 198 | u32 bitrate_mode; |
| 188 | 199 | u32 bitrate; |
| 189 | 200 | u32 bitrate_peak; |
| 201 | + u32 rc_enable; | |
| 190 | 202 | |
| 191 | 203 | u32 h264_i_period; |
| 192 | 204 | u32 h264_entropy_mode; |
| @@ -344,6 +356,7 @@ struct venus_inst { · 151 unmodified lines | ||
| 344 | 356 | unsigned int subscriptions; |
| 345 | 357 | int buf_count; |
| 346 | 358 | struct venus_ts_metadata tss[VIDEO_MAX_FRAME]; |
| 359 | + unsigned long payloads[VIDEO_MAX_FRAME]; | |
| 347 | 360 | u64 fps; |
| 348 | 361 | struct v4l2_fract timeperframe; |
| 349 | 362 | const struct venus_format *fmt_out; |
| @@ -370,6 +383,8 @@ struct venus_inst { · 20 unmodified lines | ||
| 370 | 383 | const struct hfi_inst_ops *ops; |
| 371 | 384 | u32 session_type; |
| 372 | 385 | union hfi_get_property hprop; |
| 386 | + unsigned int core_acquired: 1; | |
| 387 | + unsigned int bit_depth; | |
| 373 | 388 | }; |
| 374 | 389 | |
| 375 | 390 | #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) |
| @@ -44,8 +44,14 @@ static void venus_reset_cpu(struct venus_core *core) · 43 unmodified lines | ||
| 44 | 44 | |
| 45 | 45 | int venus_set_hw_state(struct venus_core *core, bool resume) |
| 46 | 46 | { |
| 47 | − if (core->use_tz) | |
| 48 | − return qcom_scm_set_remote_state(resume, 0); | |
| 47 | + int ret; | |
| 48 | + | |
| 49 | + if (core->use_tz) { | |
| 50 | + ret = qcom_scm_set_remote_state(resume, 0); | |
| 51 | + if (resume && ret == -EINVAL) | |
| 52 | + ret = 0; | |
| 53 | + return ret; | |
| 54 | + } | |
| 49 | 55 | |
| 50 | 56 | if (resume) |
| 51 | 57 | venus_reset_cpu(core); |
| @@ -100,8 +106,7 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, · 48 unmodified lines | ||
| 100 | 106 | |
| 101 | 107 | mem_va = memremap(r.start, *mem_size, MEMREMAP_WC); |
| 102 | 108 | if (!mem_va) { |
| 103 | − dev_err(dev, "unable to map memory region: %pa+%zx\n", | |
| 104 | − &r.start, *mem_size); | |
| 109 | + dev_err(dev, "unable to map memory region: %pR\n", &r); | |
| 105 | 110 | ret = -ENOMEM; |
| 106 | 111 | goto err_release_fw; |
| 107 | 112 | } |
| @@ -3,12 +3,8 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. |
| 4 | 4 | * Copyright (C) 2017 Linaro Ltd. |
| 5 | 5 | */ |
| 6 | −#include <linux/clk.h> | |
| 7 | −#include <linux/iopoll.h> | |
| 8 | −#include <linux/interconnect.h> | |
| 9 | 6 | #include <linux/list.h> |
| 10 | 7 | #include <linux/mutex.h> |
| 11 | −#include <linux/pm_runtime.h> | |
| 12 | 8 | #include <linux/slab.h> |
| 13 | 9 | #include <media/videobuf2-dma-sg.h> |
| 14 | 10 | #include <media/v4l2-mem2mem.h> |
| @@ -17,7 +13,7 @@ · 2 unmodified lines | ||
| 17 | 13 | #include "core.h" |
| 18 | 14 | #include "helpers.h" |
| 19 | 15 | #include "hfi_helper.h" |
| 20 | −#include "hfi_venus_io.h" | |
| 16 | +#include "pm_helpers.h" | |
| 21 | 17 | |
| 22 | 18 | struct intbuf { |
| 23 | 19 | struct list_head list; |
| @@ -360,266 +356,6 @@ err: · 336 unmodified lines | ||
| 360 | 356 | } |
| 361 | 357 | EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc); |
| 362 | 358 | |
| 363 | −static u32 load_per_instance(struct venus_inst *inst) | |
| 364 | −{ | |
| 365 | − u32 mbs; | |
| 366 | − | |
| 367 | − if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP)) | |
| 368 | − return 0; | |
| 369 | − | |
| 370 | − mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16); | |
| 371 | − | |
| 372 | − return mbs * inst->fps; | |
| 373 | −} | |
| 374 | − | |
| 375 | −static u32 load_per_type(struct venus_core *core, u32 session_type) | |
| 376 | −{ | |
| 377 | − struct venus_inst *inst = NULL; | |
| 378 | − u32 mbs_per_sec = 0; | |
| 379 | − | |
| 380 | − mutex_lock(&core->lock); | |
| 381 | − list_for_each_entry(inst, &core->instances, list) { | |
| 382 | − if (inst->session_type != session_type) | |
| 383 | − continue; | |
| 384 | − | |
| 385 | − mbs_per_sec += load_per_instance(inst); | |
| 386 | − } | |
| 387 | − mutex_unlock(&core->lock); | |
| 388 | − | |
| 389 | − return mbs_per_sec; | |
| 390 | −} | |
| 391 | − | |
| 392 | −static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak) | |
| 393 | −{ | |
| 394 | − const struct venus_resources *res = inst->core->res; | |
| 395 | − const struct bw_tbl *bw_tbl; | |
| 396 | − unsigned int num_rows, i; | |
| 397 | − | |
| 398 | − *avg = 0; | |
| 399 | − *peak = 0; | |
| 400 | − | |
| 401 | − if (mbs == 0) | |
| 402 | − return; | |
| 403 | − | |
| 404 | − if (inst->session_type == VIDC_SESSION_TYPE_ENC) { | |
| 405 | − num_rows = res->bw_tbl_enc_size; | |
| 406 | − bw_tbl = res->bw_tbl_enc; | |
| 407 | − } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) { | |
| 408 | − num_rows = res->bw_tbl_dec_size; | |
| 409 | − bw_tbl = res->bw_tbl_dec; | |
| 410 | − } else { | |
| 411 | − return; | |
| 412 | − } | |
| 413 | − | |
| 414 | − if (!bw_tbl || num_rows == 0) | |
| 415 | − return; | |
| 416 | − | |
| 417 | − for (i = 0; i < num_rows; i++) { | |
| 418 | − if (mbs > bw_tbl[i].mbs_per_sec) | |
| 419 | − break; | |
| 420 | − | |
| 421 | − if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) { | |
| 422 | − *avg = bw_tbl[i].avg_10bit; | |
| 423 | − *peak = bw_tbl[i].peak_10bit; | |
| 424 | − } else { | |
| 425 | − *avg = bw_tbl[i].avg; | |
| 426 | − *peak = bw_tbl[i].peak; | |
| 427 | − } | |
| 428 | − } | |
| 429 | −} | |
| 430 | − | |
| 431 | −static int load_scale_bw(struct venus_core *core) | |
| 432 | −{ | |
| 433 | − struct venus_inst *inst = NULL; | |
| 434 | − u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0; | |
| 435 | − | |
| 436 | − mutex_lock(&core->lock); | |
| 437 | − list_for_each_entry(inst, &core->instances, list) { | |
| 438 | − mbs_per_sec = load_per_instance(inst); | |
| 439 | − mbs_to_bw(inst, mbs_per_sec, &avg, &peak); | |
| 440 | − total_avg += avg; | |
| 441 | − total_peak += peak; | |
| 442 | − } | |
| 443 | − mutex_unlock(&core->lock); | |
| 444 | − | |
| 445 | − dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n", | |
| 446 | − total_avg, total_peak); | |
| 447 | − | |
| 448 | − return icc_set_bw(core->video_path, total_avg, total_peak); | |
| 449 | −} | |
| 450 | − | |
| 451 | −static int set_clk_freq(struct venus_core *core, unsigned long freq) | |
| 452 | −{ | |
| 453 | − struct clk *clk = core->clks[0]; | |
| 454 | − int ret; | |
| 455 | − | |
| 456 | − ret = clk_set_rate(clk, freq); | |
| 457 | − if (ret) | |
| 458 | − return ret; | |
| 459 | − | |
| 460 | − ret = clk_set_rate(core->core0_clk, freq); | |
| 461 | − if (ret) | |
| 462 | − return ret; | |
| 463 | − | |
| 464 | − ret = clk_set_rate(core->core1_clk, freq); | |
| 465 | − if (ret) | |
| 466 | − return ret; | |
| 467 | − | |
| 468 | − return 0; | |
| 469 | −} | |
| 470 | − | |
| 471 | −static int scale_clocks(struct venus_inst *inst) | |
| 472 | −{ | |
| 473 | − struct venus_core *core = inst->core; | |
| 474 | − const struct freq_tbl *table = core->res->freq_tbl; | |
| 475 | − unsigned int num_rows = core->res->freq_tbl_size; | |
| 476 | − unsigned long freq = table[0].freq; | |
| 477 | − struct device *dev = core->dev; | |
| 478 | − u32 mbs_per_sec; | |
| 479 | − unsigned int i; | |
| 480 | − int ret; | |
| 481 | − | |
| 482 | − mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) + | |
| 483 | − load_per_type(core, VIDC_SESSION_TYPE_DEC); | |
| 484 | − | |
| 485 | − if (mbs_per_sec > core->res->max_load) | |
| 486 | − dev_warn(dev, "HW is overloaded, needed: %d max: %d\n", | |
| 487 | − mbs_per_sec, core->res->max_load); | |
| 488 | − | |
| 489 | − if (!mbs_per_sec && num_rows > 1) { | |
| 490 | − freq = table[num_rows - 1].freq; | |
| 491 | − goto set_freq; | |
| 492 | − } | |
| 493 | − | |
| 494 | − for (i = 0; i < num_rows; i++) { | |
| 495 | − if (mbs_per_sec > table[i].load) | |
| 496 | − break; | |
| 497 | − freq = table[i].freq; | |
| 498 | − } | |
| 499 | − | |
| 500 | −set_freq: | |
| 501 | − | |
| 502 | − ret = set_clk_freq(core, freq); | |
| 503 | − if (ret) { | |
| 504 | − dev_err(dev, "failed to set clock rate %lu (%d)\n", | |
| 505 | − freq, ret); | |
| 506 | − return ret; | |
| 507 | − } | |
| 508 | − | |
| 509 | − ret = load_scale_bw(core); | |
| 510 | − if (ret) { | |
| 511 | − dev_err(dev, "failed to set bandwidth (%d)\n", | |
| 512 | − ret); | |
| 513 | − return ret; | |
| 514 | − } | |
| 515 | − | |
| 516 | − return 0; | |
| 517 | −} | |
| 518 | − | |
| 519 | −static unsigned long calculate_inst_freq(struct venus_inst *inst, | |
| 520 | − unsigned long filled_len) | |
| 521 | −{ | |
| 522 | − unsigned long vpp_freq = 0, vsp_freq = 0; | |
| 523 | − u32 fps = (u32)inst->fps; | |
| 524 | − u32 mbs_per_sec; | |
| 525 | − | |
| 526 | − mbs_per_sec = load_per_instance(inst) / fps; | |
| 527 | − | |
| 528 | − vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq; | |
| 529 | − /* 21 / 20 is overhead factor */ | |
| 530 | − vpp_freq += vpp_freq / 20; | |
| 531 | − vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq; | |
| 532 | − | |
| 533 | − /* 10 / 7 is overhead factor */ | |
| 534 | − if (inst->session_type == VIDC_SESSION_TYPE_ENC) | |
| 535 | − vsp_freq += (inst->controls.enc.bitrate * 10) / 7; | |
| 536 | − else | |
| 537 | − vsp_freq += ((fps * filled_len * 8) * 10) / 7; | |
| 538 | − | |
| 539 | − return max(vpp_freq, vsp_freq); | |
| 540 | −} | |
| 541 | − | |
| 542 | −static int scale_clocks_v4(struct venus_inst *inst) | |
| 543 | −{ | |
| 544 | − struct venus_core *core = inst->core; | |
| 545 | − const struct freq_tbl *table = core->res->freq_tbl; | |
| 546 | − unsigned int num_rows = core->res->freq_tbl_size; | |
| 547 | − struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; | |
| 548 | − struct device *dev = core->dev; | |
| 549 | − unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; | |
| 550 | − unsigned long filled_len = 0; | |
| 551 | − struct venus_buffer *buf, *n; | |
| 552 | − struct vb2_buffer *vb; | |
| 553 | − int i, ret; | |
| 554 | − | |
| 555 | − v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { | |
| 556 | − vb = &buf->vb.vb2_buf; | |
| 557 | − filled_len = max(filled_len, vb2_get_plane_payload(vb, 0)); | |
| 558 | − } | |
| 559 | − | |
| 560 | − if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len) | |
| 561 | − return 0; | |
| 562 | − | |
| 563 | − freq = calculate_inst_freq(inst, filled_len); | |
| 564 | − inst->clk_data.freq = freq; | |
| 565 | − | |
| 566 | − mutex_lock(&core->lock); | |
| 567 | − list_for_each_entry(inst, &core->instances, list) { | |
| 568 | − if (inst->clk_data.core_id == VIDC_CORE_ID_1) { | |
| 569 | − freq_core1 += inst->clk_data.freq; | |
| 570 | − } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) { | |
| 571 | − freq_core2 += inst->clk_data.freq; | |
| 572 | − } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) { | |
| 573 | − freq_core1 += inst->clk_data.freq; | |
| 574 | − freq_core2 += inst->clk_data.freq; | |
| 575 | − } | |
| 576 | − } | |
| 577 | − mutex_unlock(&core->lock); | |
| 578 | − | |
| 579 | − freq = max(freq_core1, freq_core2); | |
| 580 | − | |
| 581 | − if (freq >= table[0].freq) { | |
| 582 | − freq = table[0].freq; | |
| 583 | − dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", | |
| 584 | − freq, table[0].freq); | |
| 585 | − goto set_freq; | |
| 586 | − } | |
| 587 | − | |
| 588 | − for (i = num_rows - 1 ; i >= 0; i--) { | |
| 589 | − if (freq <= table[i].freq) { | |
| 590 | − freq = table[i].freq; | |
| 591 | − break; | |
| 592 | − } | |
| 593 | − } | |
| 594 | − | |
| 595 | −set_freq: | |
| 596 | − | |
| 597 | − ret = set_clk_freq(core, freq); | |
| 598 | − if (ret) { | |
| 599 | − dev_err(dev, "failed to set clock rate %lu (%d)\n", | |
| 600 | − freq, ret); | |
| 601 | − return ret; | |
| 602 | − } | |
| 603 | − | |
| 604 | − ret = load_scale_bw(core); | |
| 605 | − if (ret) { | |
| 606 | − dev_err(dev, "failed to set bandwidth (%d)\n", | |
| 607 | − ret); | |
| 608 | − return ret; | |
| 609 | − } | |
| 610 | − | |
| 611 | − return 0; | |
| 612 | −} | |
| 613 | − | |
| 614 | −int venus_helper_load_scale_clocks(struct venus_inst *inst) | |
| 615 | −{ | |
| 616 | − if (IS_V4(inst->core)) | |
| 617 | − return scale_clocks_v4(inst); | |
| 618 | − | |
| 619 | − return scale_clocks(inst); | |
| 620 | −} | |
| 621 | −EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks); | |
| 622 | − | |
| 623 | 359 | static void fill_buffer_desc(const struct venus_buffer *buf, |
| 624 | 360 | struct hfi_buffer_desc *bd, bool response) |
| 625 | 361 | { |
| @@ -723,7 +459,7 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) · 97 unmodified lines | ||
| 723 | 459 | if (inst->session_type == VIDC_SESSION_TYPE_DEC) |
| 724 | 460 | put_ts_metadata(inst, vbuf); |
| 725 | 461 | |
| 726 | − venus_helper_load_scale_clocks(inst); | |
| 462 | + venus_pm_load_scale(inst); | |
| 727 | 463 | } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
| 728 | 464 | if (inst->session_type == VIDC_SESSION_TYPE_ENC) |
| 729 | 465 | fdata.buffer_type = HFI_BUFFER_OUTPUT; |
| @@ -890,6 +626,78 @@ static u32 get_framesize_raw_nv12_ubwc(u32 width, u32 height) · 160 unmodified lines | ||
| 890 | 626 | max(extradata, y_stride * 48), SZ_4K); |
| 891 | 627 | } |
| 892 | 628 | |
| 629 | +static u32 get_framesize_raw_p010(u32 width, u32 height) | |
| 630 | +{ | |
| 631 | + u32 y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines; | |
| 632 | + | |
| 633 | + y_stride = ALIGN(width * 2, 256); | |
| 634 | + uv_stride = ALIGN(width * 2, 256); | |
| 635 | + y_sclines = ALIGN(height, 32); | |
| 636 | + uv_sclines = ALIGN((height + 1) >> 1, 16); | |
| 637 | + y_plane = y_stride * y_sclines; | |
| 638 | + uv_plane = uv_stride * uv_sclines; | |
| 639 | + | |
| 640 | + return ALIGN((y_plane + uv_plane), SZ_4K); | |
| 641 | +} | |
| 642 | + | |
| 643 | +static u32 get_framesize_raw_p010_ubwc(u32 width, u32 height) | |
| 644 | +{ | |
| 645 | + u32 y_stride, uv_stride, y_sclines, uv_sclines; | |
| 646 | + u32 y_ubwc_plane, uv_ubwc_plane; | |
| 647 | + u32 y_meta_stride, y_meta_scanlines; | |
| 648 | + u32 uv_meta_stride, uv_meta_scanlines; | |
| 649 | + u32 y_meta_plane, uv_meta_plane; | |
| 650 | + u32 size; | |
| 651 | + | |
| 652 | + y_stride = ALIGN(width * 2, 256); | |
| 653 | + uv_stride = ALIGN(width * 2, 256); | |
| 654 | + y_sclines = ALIGN(height, 16); | |
| 655 | + uv_sclines = ALIGN((height + 1) >> 1, 16); | |
| 656 | + | |
| 657 | + y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K); | |
| 658 | + uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K); | |
| 659 | + y_meta_stride = ALIGN(DIV_ROUND_UP(width, 32), 64); | |
| 660 | + y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16); | |
| 661 | + y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K); | |
| 662 | + uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 16), 64); | |
| 663 | + uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16); | |
| 664 | + uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K); | |
| 665 | + | |
| 666 | + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane; | |
| 667 | + | |
| 668 | + return ALIGN(size, SZ_4K); | |
| 669 | +} | |
| 670 | + | |
| 671 | +static u32 get_framesize_raw_yuv420_tp10_ubwc(u32 width, u32 height) | |
| 672 | +{ | |
| 673 | + u32 y_stride, uv_stride, y_sclines, uv_sclines; | |
| 674 | + u32 y_ubwc_plane, uv_ubwc_plane; | |
| 675 | + u32 y_meta_stride, y_meta_scanlines; | |
| 676 | + u32 uv_meta_stride, uv_meta_scanlines; | |
| 677 | + u32 y_meta_plane, uv_meta_plane; | |
| 678 | + u32 extradata = SZ_16K; | |
| 679 | + u32 size; | |
| 680 | + | |
| 681 | + y_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256); | |
| 682 | + uv_stride = ALIGN(ALIGN(width, 192) * 4 / 3, 256); | |
| 683 | + y_sclines = ALIGN(height, 16); | |
| 684 | + uv_sclines = ALIGN((height + 1) >> 1, 16); | |
| 685 | + | |
| 686 | + y_ubwc_plane = ALIGN(y_stride * y_sclines, SZ_4K); | |
| 687 | + uv_ubwc_plane = ALIGN(uv_stride * uv_sclines, SZ_4K); | |
| 688 | + y_meta_stride = ALIGN(DIV_ROUND_UP(width, 48), 64); | |
| 689 | + y_meta_scanlines = ALIGN(DIV_ROUND_UP(height, 4), 16); | |
| 690 | + y_meta_plane = ALIGN(y_meta_stride * y_meta_scanlines, SZ_4K); | |
| 691 | + uv_meta_stride = ALIGN(DIV_ROUND_UP((width + 1) >> 1, 24), 64); | |
| 692 | + uv_meta_scanlines = ALIGN(DIV_ROUND_UP((height + 1) >> 1, 4), 16); | |
| 693 | + uv_meta_plane = ALIGN(uv_meta_stride * uv_meta_scanlines, SZ_4K); | |
| 694 | + | |
| 695 | + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane; | |
| 696 | + size += max(extradata + SZ_8K, y_stride * 48); | |
| 697 | + | |
| 698 | + return ALIGN(size, SZ_4K); | |
| 699 | +} | |
| 700 | + | |
| 893 | 701 | u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height) |
| 894 | 702 | { |
| 895 | 703 | switch (hfi_fmt) { |
| @@ -898,6 +706,12 @@ u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height) · 2 unmodified lines | ||
| 898 | 706 | return get_framesize_raw_nv12(width, height); |
| 899 | 707 | case HFI_COLOR_FORMAT_NV12_UBWC: |
| 900 | 708 | return get_framesize_raw_nv12_ubwc(width, height); |
| 709 | + case HFI_COLOR_FORMAT_P010: | |
| 710 | + return get_framesize_raw_p010(width, height); | |
| 711 | + case HFI_COLOR_FORMAT_P010_UBWC: | |
| 712 | + return get_framesize_raw_p010_ubwc(width, height); | |
| 713 | + case HFI_COLOR_FORMAT_YUV420_TP10_UBWC: | |
| 714 | + return get_framesize_raw_yuv420_tp10_ubwc(width, height); | |
| 901 | 715 | default: |
| 902 | 716 | return 0; |
| 903 | 717 | } |
| @@ -987,21 +801,6 @@ int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode) · 83 unmodified lines | ||
| 987 | 801 | } |
| 988 | 802 | EXPORT_SYMBOL_GPL(venus_helper_set_work_mode); |
| 989 | 803 | |
| 990 | −int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage) | |
| 991 | −{ | |
| 992 | − const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; | |
| 993 | − struct hfi_videocores_usage_type cu; | |
| 994 | − | |
| 995 | − inst->clk_data.core_id = usage; | |
| 996 | − if (!IS_V4(inst->core)) | |
| 997 | − return 0; | |
| 998 | − | |
| 999 | − cu.video_core_enable_mask = usage; | |
| 1000 | − | |
| 1001 | − return hfi_session_set_property(inst, ptype, &cu); | |
| 1002 | −} | |
| 1003 | −EXPORT_SYMBOL_GPL(venus_helper_set_core_usage); | |
| 1004 | − | |
| 1005 | 804 | int venus_helper_init_codec_freq_data(struct venus_inst *inst) |
| 1006 | 805 | { |
| 1007 | 806 | const struct codec_freq_data *data; |
| @@ -1289,6 +1088,15 @@ int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb) · 281 unmodified lines | ||
| 1289 | 1088 | } |
| 1290 | 1089 | EXPORT_SYMBOL_GPL(venus_helper_vb2_buf_prepare); |
| 1291 | 1090 | |
| 1091 | +static void cache_payload(struct venus_inst *inst, struct vb2_buffer *vb) | |
| 1092 | +{ | |
| 1093 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 1094 | + unsigned int idx = vbuf->vb2_buf.index; | |
| 1095 | + | |
| 1096 | + if (vbuf->vb2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | |
| 1097 | + inst->payloads[idx] = vb2_get_plane_payload(vb, 0); | |
| 1098 | +} | |
| 1099 | + | |
| 1292 | 1100 | void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) |
| 1293 | 1101 | { |
| 1294 | 1102 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
| @@ -1300,6 +1108,8 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) · 5 unmodified lines | ||
| 1300 | 1108 | |
| 1301 | 1109 | v4l2_m2m_buf_queue(m2m_ctx, vbuf); |
| 1302 | 1110 | |
| 1111 | + cache_payload(inst, vb); | |
| 1112 | + | |
| 1303 | 1113 | if (inst->session_type == VIDC_SESSION_TYPE_ENC && |
| 1304 | 1114 | !(inst->streamon_out && inst->streamon_cap)) |
| 1305 | 1115 | goto unlock; |
| @@ -1354,7 +1164,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) · 48 unmodified lines | ||
| 1354 | 1164 | |
| 1355 | 1165 | venus_helper_free_dpb_bufs(inst); |
| 1356 | 1166 | |
| 1357 | − venus_helper_load_scale_clocks(inst); | |
| 1167 | + venus_pm_load_scale(inst); | |
| 1358 | 1168 | INIT_LIST_HEAD(&inst->registeredbufs); |
| 1359 | 1169 | } |
| 1360 | 1170 | |
| @@ -1365,6 +1175,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) · 4 unmodified lines | ||
| 1365 | 1175 | else |
| 1366 | 1176 | inst->streamon_cap = 0; |
| 1367 | 1177 | |
| 1178 | + venus_pm_release_core(inst); | |
| 1179 | + | |
| 1368 | 1180 | mutex_unlock(&inst->lock); |
| 1369 | 1181 | } |
| 1370 | 1182 | EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); |
| @@ -1417,7 +1229,7 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst) · 46 unmodified lines | ||
| 1417 | 1229 | if (ret) |
| 1418 | 1230 | goto err_bufs_free; |
| 1419 | 1231 | |
| 1420 | − venus_helper_load_scale_clocks(inst); | |
| 1232 | + venus_pm_load_scale(inst); | |
| 1421 | 1233 | |
| 1422 | 1234 | ret = hfi_session_load_res(inst); |
| 1423 | 1235 | if (ret) |
| @@ -1512,6 +1324,27 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, · 88 unmodified lines | ||
| 1512 | 1324 | if (!caps) |
| 1513 | 1325 | return -EINVAL; |
| 1514 | 1326 | |
| 1327 | + if (inst->bit_depth == VIDC_BITDEPTH_10 && | |
| 1328 | + inst->session_type == VIDC_SESSION_TYPE_DEC) { | |
| 1329 | + found_ubwc = | |
| 1330 | + find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, | |
| 1331 | + HFI_COLOR_FORMAT_YUV420_TP10_UBWC); | |
| 1332 | + found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, | |
| 1333 | + HFI_COLOR_FORMAT_NV12); | |
| 1334 | + if (found_ubwc && found) { | |
| 1335 | + /* | |
| 1336 | + * Hard-code DPB buffers to be 10bit UBWC and decoder | |
| 1337 | + * output buffers in 8bit NV12 until V4L2 is able to | |
| 1338 | + * expose compressed/tiled formats to applications. | |
| 1339 | + */ | |
| 1340 | + *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC; | |
| 1341 | + *out2_fmt = HFI_COLOR_FORMAT_NV12; | |
| 1342 | + return 0; | |
| 1343 | + } | |
| 1344 | + | |
| 1345 | + return -EINVAL; | |
| 1346 | + } | |
| 1347 | + | |
| 1515 | 1348 | if (ubwc) { |
| 1516 | 1349 | ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE; |
| 1517 | 1350 | found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, |
| @@ -1542,52 +1375,3 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, · 24 unmodified lines | ||
| 1542 | 1375 | return -EINVAL; |
| 1543 | 1376 | } |
| 1544 | 1377 | EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts); |
| 1545 | − | |
| 1546 | −int venus_helper_power_enable(struct venus_core *core, u32 session_type, | |
| 1547 | − bool enable) | |
| 1548 | −{ | |
| 1549 | − void __iomem *ctrl, *stat; | |
| 1550 | − u32 val; | |
| 1551 | − int ret; | |
| 1552 | − | |
| 1553 | − if (!IS_V3(core) && !IS_V4(core)) | |
| 1554 | − return 0; | |
| 1555 | − | |
| 1556 | − if (IS_V3(core)) { | |
| 1557 | − if (session_type == VIDC_SESSION_TYPE_DEC) | |
| 1558 | − ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL; | |
| 1559 | − else | |
| 1560 | − ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL; | |
| 1561 | − if (enable) | |
| 1562 | − writel(0, ctrl); | |
| 1563 | − else | |
| 1564 | − writel(1, ctrl); | |
| 1565 | − | |
| 1566 | − return 0; | |
| 1567 | − } | |
| 1568 | − | |
| 1569 | − if (session_type == VIDC_SESSION_TYPE_DEC) { | |
| 1570 | − ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; | |
| 1571 | − stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; | |
| 1572 | − } else { | |
| 1573 | − ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL; | |
| 1574 | − stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS; | |
| 1575 | − } | |
| 1576 | − | |
| 1577 | − if (enable) { | |
| 1578 | − writel(0, ctrl); | |
| 1579 | − | |
| 1580 | − ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100); | |
| 1581 | − if (ret) | |
| 1582 | − return ret; | |
| 1583 | − } else { | |
| 1584 | − writel(1, ctrl); | |
| 1585 | − | |
| 1586 | − ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100); | |
| 1587 | − if (ret) | |
| 1588 | − return ret; | |
| 1589 | − } | |
| 1590 | − | |
| 1591 | − return 0; | |
| 1592 | −} | |
| 1593 | −EXPORT_SYMBOL_GPL(venus_helper_power_enable); | |
| @@ -34,7 +34,6 @@ int venus_helper_set_output_resolution(struct venus_inst *inst, · 33 unmodified lines | ||
| 34 | 34 | u32 buftype); |
| 35 | 35 | int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode); |
| 36 | 36 | int venus_helper_init_codec_freq_data(struct venus_inst *inst); |
| 37 | −int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage); | |
| 38 | 37 | int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, |
| 39 | 38 | unsigned int output_bufs, |
| 40 | 39 | unsigned int output2_bufs); |
| @@ -53,14 +52,11 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt, · 12 unmodified lines | ||
| 53 | 52 | u32 *out2_fmt, bool ubwc); |
| 54 | 53 | int venus_helper_alloc_dpb_bufs(struct venus_inst *inst); |
| 55 | 54 | int venus_helper_free_dpb_bufs(struct venus_inst *inst); |
| 56 | −int venus_helper_power_enable(struct venus_core *core, u32 session_type, | |
| 57 | − bool enable); | |
| 58 | 55 | int venus_helper_intbufs_alloc(struct venus_inst *inst); |
| 59 | 56 | int venus_helper_intbufs_free(struct venus_inst *inst); |
| 60 | 57 | int venus_helper_intbufs_realloc(struct venus_inst *inst); |
| 61 | 58 | int venus_helper_queue_dpb_bufs(struct venus_inst *inst); |
| 62 | 59 | int venus_helper_unregister_bufs(struct venus_inst *inst); |
| 63 | −int venus_helper_load_scale_clocks(struct venus_inst *inst); | |
| 64 | 60 | int venus_helper_process_initial_cap_bufs(struct venus_inst *inst); |
| 65 | 61 | int venus_helper_process_initial_out_bufs(struct venus_inst *inst); |
| 66 | 62 | void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us, |
| @@ -1207,6 +1207,8 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, · 1206 unmodified lines | ||
| 1207 | 1207 | case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: |
| 1208 | 1208 | case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: |
| 1209 | 1209 | case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: |
| 1210 | + case HFI_PROPERTY_PARAM_VENC_SESSION_QP: | |
| 1211 | + case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE: | |
| 1210 | 1212 | /* not implemented on Venus 4xx */ |
| 1211 | 1213 | return -ENOTSUPP; |
| 1212 | 1214 | default: |
| @@ -550,6 +550,7 @@ struct hfi_bitrate { · 549 unmodified lines | ||
| 550 | 550 | #define HFI_CAPABILITY_LCU_SIZE 0x14 |
| 551 | 551 | #define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS 0x15 |
| 552 | 552 | #define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE 0x16 |
| 553 | +#define HFI_CAPABILITY_MAX_VIDEOCORES 0x2b | |
| 553 | 554 | |
| 554 | 555 | struct hfi_capability { |
| 555 | 556 | u32 capability_type; |
| @@ -792,6 +793,9 @@ struct hfi_h264_vui_timing_info { · 236 unmodified lines | ||
| 792 | 793 | u32 time_scale; |
| 793 | 794 | }; |
| 794 | 795 | |
| 796 | +#define VIDC_BITDEPTH_8 0x00000 | |
| 797 | +#define VIDC_BITDEPTH_10 0x20002 | |
| 798 | + | |
| 795 | 799 | struct hfi_bit_depth { |
| 796 | 800 | u32 buffer_type; |
| 797 | 801 | u32 bit_depth; |
| @@ -840,8 +844,10 @@ struct hfi_extradata_input_crop { · 42 unmodified lines | ||
| 840 | 844 | #define HFI_COLOR_FORMAT_10_BIT_BASE 0x4000 |
| 841 | 845 | |
| 842 | 846 | #define HFI_COLOR_FORMAT_YUV420_TP10 0x4002 |
| 847 | +#define HFI_COLOR_FORMAT_P010 0x4003 | |
| 843 | 848 | #define HFI_COLOR_FORMAT_NV12_UBWC 0x8002 |
| 844 | 849 | #define HFI_COLOR_FORMAT_YUV420_TP10_UBWC 0xc002 |
| 850 | +#define HFI_COLOR_FORMAT_P010_UBWC 0xc003 | |
| 845 | 851 | #define HFI_COLOR_FORMAT_RGBA8888_UBWC 0x8010 |
| 846 | 852 | |
| 847 | 853 | struct hfi_uncompressed_format_select { |
| @@ -181,6 +181,7 @@ static void parse_codecs(struct venus_core *core, void *data) · 180 unmodified lines | ||
| 181 | 181 | if (IS_V1(core)) { |
| 182 | 182 | core->dec_codecs &= ~HFI_VIDEO_CODEC_HEVC; |
| 183 | 183 | core->dec_codecs &= ~HFI_VIDEO_CODEC_SPARK; |
| 184 | + core->enc_codecs &= ~HFI_VIDEO_CODEC_HEVC; | |
| 184 | 185 | } |
| 185 | 186 | } |
| 186 | 187 | |
| @@ -107,4 +107,9 @@ static inline u32 frate_step(struct venus_inst *inst) · 106 unmodified lines | ||
| 107 | 107 | return cap_step(inst, HFI_CAPABILITY_FRAMERATE); |
| 108 | 108 | } |
| 109 | 109 | |
| 110 | +static inline u32 core_num_max(struct venus_inst *inst) | |
| 111 | +{ | |
| 112 | + return cap_max(inst, HFI_CAPABILITY_MAX_VIDEOCORES); | |
| 113 | +} | |
| 114 | + | |
| 110 | 115 | #endif |
| @@ -0,0 +1,959 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2019 Linaro Ltd. | |
| 4 | + * | |
| 5 | + * Author: Stanimir Varbanov <stanimir.varbanov@linaro.org> | |
| 6 | + */ | |
| 7 | +#include <linux/clk.h> | |
| 8 | +#include <linux/interconnect.h> | |
| 9 | +#include <linux/iopoll.h> | |
| 10 | +#include <linux/kernel.h> | |
| 11 | +#include <linux/pm_domain.h> | |
| 12 | +#include <linux/pm_runtime.h> | |
| 13 | +#include <linux/types.h> | |
| 14 | +#include <media/v4l2-mem2mem.h> | |
| 15 | + | |
| 16 | +#include "core.h" | |
| 17 | +#include "hfi_parser.h" | |
| 18 | +#include "hfi_venus_io.h" | |
| 19 | +#include "pm_helpers.h" | |
| 20 | + | |
| 21 | +static bool legacy_binding; | |
| 22 | + | |
| 23 | +static int core_clks_get(struct venus_core *core) | |
| 24 | +{ | |
| 25 | + const struct venus_resources *res = core->res; | |
| 26 | + struct device *dev = core->dev; | |
| 27 | + unsigned int i; | |
| 28 | + | |
| 29 | + for (i = 0; i < res->clks_num; i++) { | |
| 30 | + core->clks[i] = devm_clk_get(dev, res->clks[i]); | |
| 31 | + if (IS_ERR(core->clks[i])) | |
| 32 | + return PTR_ERR(core->clks[i]); | |
| 33 | + } | |
| 34 | + | |
| 35 | + return 0; | |
| 36 | +} | |
| 37 | + | |
| 38 | +static int core_clks_enable(struct venus_core *core) | |
| 39 | +{ | |
| 40 | + const struct venus_resources *res = core->res; | |
| 41 | + unsigned int i; | |
| 42 | + int ret; | |
| 43 | + | |
| 44 | + for (i = 0; i < res->clks_num; i++) { | |
| 45 | + ret = clk_prepare_enable(core->clks[i]); | |
| 46 | + if (ret) | |
| 47 | + goto err; | |
| 48 | + } | |
| 49 | + | |
| 50 | + return 0; | |
| 51 | +err: | |
| 52 | + while (i--) | |
| 53 | + clk_disable_unprepare(core->clks[i]); | |
| 54 | + | |
| 55 | + return ret; | |
| 56 | +} | |
| 57 | + | |
| 58 | +static void core_clks_disable(struct venus_core *core) | |
| 59 | +{ | |
| 60 | + const struct venus_resources *res = core->res; | |
| 61 | + unsigned int i = res->clks_num; | |
| 62 | + | |
| 63 | + while (i--) | |
| 64 | + clk_disable_unprepare(core->clks[i]); | |
| 65 | +} | |
| 66 | + | |
| 67 | +static int core_clks_set_rate(struct venus_core *core, unsigned long freq) | |
| 68 | +{ | |
| 69 | + struct clk *clk = core->clks[0]; | |
| 70 | + int ret; | |
| 71 | + | |
| 72 | + ret = clk_set_rate(clk, freq); | |
| 73 | + if (ret) | |
| 74 | + return ret; | |
| 75 | + | |
| 76 | + ret = clk_set_rate(core->vcodec0_clks[0], freq); | |
| 77 | + if (ret) | |
| 78 | + return ret; | |
| 79 | + | |
| 80 | + ret = clk_set_rate(core->vcodec1_clks[0], freq); | |
| 81 | + if (ret) | |
| 82 | + return ret; | |
| 83 | + | |
| 84 | + return 0; | |
| 85 | +} | |
| 86 | + | |
| 87 | +static int vcodec_clks_get(struct venus_core *core, struct device *dev, | |
| 88 | + struct clk **clks, const char * const *id) | |
| 89 | +{ | |
| 90 | + const struct venus_resources *res = core->res; | |
| 91 | + unsigned int i; | |
| 92 | + | |
| 93 | + for (i = 0; i < res->vcodec_clks_num; i++) { | |
| 94 | + if (!id[i]) | |
| 95 | + continue; | |
| 96 | + clks[i] = devm_clk_get(dev, id[i]); | |
| 97 | + if (IS_ERR(clks[i])) | |
| 98 | + return PTR_ERR(clks[i]); | |
| 99 | + } | |
| 100 | + | |
| 101 | + return 0; | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int vcodec_clks_enable(struct venus_core *core, struct clk **clks) | |
| 105 | +{ | |
| 106 | + const struct venus_resources *res = core->res; | |
| 107 | + unsigned int i; | |
| 108 | + int ret; | |
| 109 | + | |
| 110 | + for (i = 0; i < res->vcodec_clks_num; i++) { | |
| 111 | + ret = clk_prepare_enable(clks[i]); | |
| 112 | + if (ret) | |
| 113 | + goto err; | |
| 114 | + } | |
| 115 | + | |
| 116 | + return 0; | |
| 117 | +err: | |
| 118 | + while (i--) | |
| 119 | + clk_disable_unprepare(clks[i]); | |
| 120 | + | |
| 121 | + return ret; | |
| 122 | +} | |
| 123 | + | |
| 124 | +static void vcodec_clks_disable(struct venus_core *core, struct clk **clks) | |
| 125 | +{ | |
| 126 | + const struct venus_resources *res = core->res; | |
| 127 | + unsigned int i = res->vcodec_clks_num; | |
| 128 | + | |
| 129 | + while (i--) | |
| 130 | + clk_disable_unprepare(clks[i]); | |
| 131 | +} | |
| 132 | + | |
| 133 | +static u32 load_per_instance(struct venus_inst *inst) | |
| 134 | +{ | |
| 135 | + u32 mbs; | |
| 136 | + | |
| 137 | + if (!inst || !(inst->state >= INST_INIT && inst->state < INST_STOP)) | |
| 138 | + return 0; | |
| 139 | + | |
| 140 | + mbs = (ALIGN(inst->width, 16) / 16) * (ALIGN(inst->height, 16) / 16); | |
| 141 | + | |
| 142 | + return mbs * inst->fps; | |
| 143 | +} | |
| 144 | + | |
| 145 | +static u32 load_per_type(struct venus_core *core, u32 session_type) | |
| 146 | +{ | |
| 147 | + struct venus_inst *inst = NULL; | |
| 148 | + u32 mbs_per_sec = 0; | |
| 149 | + | |
| 150 | + mutex_lock(&core->lock); | |
| 151 | + list_for_each_entry(inst, &core->instances, list) { | |
| 152 | + if (inst->session_type != session_type) | |
| 153 | + continue; | |
| 154 | + | |
| 155 | + mbs_per_sec += load_per_instance(inst); | |
| 156 | + } | |
| 157 | + mutex_unlock(&core->lock); | |
| 158 | + | |
| 159 | + return mbs_per_sec; | |
| 160 | +} | |
| 161 | + | |
| 162 | +static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak) | |
| 163 | +{ | |
| 164 | + const struct venus_resources *res = inst->core->res; | |
| 165 | + const struct bw_tbl *bw_tbl; | |
| 166 | + unsigned int num_rows, i; | |
| 167 | + | |
| 168 | + *avg = 0; | |
| 169 | + *peak = 0; | |
| 170 | + | |
| 171 | + if (mbs == 0) | |
| 172 | + return; | |
| 173 | + | |
| 174 | + if (inst->session_type == VIDC_SESSION_TYPE_ENC) { | |
| 175 | + num_rows = res->bw_tbl_enc_size; | |
| 176 | + bw_tbl = res->bw_tbl_enc; | |
| 177 | + } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) { | |
| 178 | + num_rows = res->bw_tbl_dec_size; | |
| 179 | + bw_tbl = res->bw_tbl_dec; | |
| 180 | + } else { | |
| 181 | + return; | |
| 182 | + } | |
| 183 | + | |
| 184 | + if (!bw_tbl || num_rows == 0) | |
| 185 | + return; | |
| 186 | + | |
| 187 | + for (i = 0; i < num_rows; i++) { | |
| 188 | + if (mbs > bw_tbl[i].mbs_per_sec) | |
| 189 | + break; | |
| 190 | + | |
| 191 | + if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) { | |
| 192 | + *avg = bw_tbl[i].avg_10bit; | |
| 193 | + *peak = bw_tbl[i].peak_10bit; | |
| 194 | + } else { | |
| 195 | + *avg = bw_tbl[i].avg; | |
| 196 | + *peak = bw_tbl[i].peak; | |
| 197 | + } | |
| 198 | + } | |
| 199 | +} | |
| 200 | + | |
| 201 | +static int load_scale_bw(struct venus_core *core) | |
| 202 | +{ | |
| 203 | + struct venus_inst *inst = NULL; | |
| 204 | + u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0; | |
| 205 | + | |
| 206 | + mutex_lock(&core->lock); | |
| 207 | + list_for_each_entry(inst, &core->instances, list) { | |
| 208 | + mbs_per_sec = load_per_instance(inst); | |
| 209 | + mbs_to_bw(inst, mbs_per_sec, &avg, &peak); | |
| 210 | + total_avg += avg; | |
| 211 | + total_peak += peak; | |
| 212 | + } | |
| 213 | + mutex_unlock(&core->lock); | |
| 214 | + | |
| 215 | + dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n", | |
| 216 | + total_avg, total_peak); | |
| 217 | + | |
| 218 | + return icc_set_bw(core->video_path, total_avg, total_peak); | |
| 219 | +} | |
| 220 | + | |
| 221 | +static int load_scale_v1(struct venus_inst *inst) | |
| 222 | +{ | |
| 223 | + struct venus_core *core = inst->core; | |
| 224 | + const struct freq_tbl *table = core->res->freq_tbl; | |
| 225 | + unsigned int num_rows = core->res->freq_tbl_size; | |
| 226 | + unsigned long freq = table[0].freq; | |
| 227 | + struct device *dev = core->dev; | |
| 228 | + u32 mbs_per_sec; | |
| 229 | + unsigned int i; | |
| 230 | + int ret; | |
| 231 | + | |
| 232 | + mbs_per_sec = load_per_type(core, VIDC_SESSION_TYPE_ENC) + | |
| 233 | + load_per_type(core, VIDC_SESSION_TYPE_DEC); | |
| 234 | + | |
| 235 | + if (mbs_per_sec > core->res->max_load) | |
| 236 | + dev_warn(dev, "HW is overloaded, needed: %d max: %d\n", | |
| 237 | + mbs_per_sec, core->res->max_load); | |
| 238 | + | |
| 239 | + if (!mbs_per_sec && num_rows > 1) { | |
| 240 | + freq = table[num_rows - 1].freq; | |
| 241 | + goto set_freq; | |
| 242 | + } | |
| 243 | + | |
| 244 | + for (i = 0; i < num_rows; i++) { | |
| 245 | + if (mbs_per_sec > table[i].load) | |
| 246 | + break; | |
| 247 | + freq = table[i].freq; | |
| 248 | + } | |
| 249 | + | |
| 250 | +set_freq: | |
| 251 | + | |
| 252 | + ret = core_clks_set_rate(core, freq); | |
| 253 | + if (ret) { | |
| 254 | + dev_err(dev, "failed to set clock rate %lu (%d)\n", | |
| 255 | + freq, ret); | |
| 256 | + return ret; | |
| 257 | + } | |
| 258 | + | |
| 259 | + ret = load_scale_bw(core); | |
| 260 | + if (ret) { | |
| 261 | + dev_err(dev, "failed to set bandwidth (%d)\n", | |
| 262 | + ret); | |
| 263 | + return ret; | |
| 264 | + } | |
| 265 | + | |
| 266 | + return 0; | |
| 267 | +} | |
| 268 | + | |
| 269 | +static int core_get_v1(struct device *dev) | |
| 270 | +{ | |
| 271 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 272 | + | |
| 273 | + return core_clks_get(core); | |
| 274 | +} | |
| 275 | + | |
| 276 | +static int core_power_v1(struct device *dev, int on) | |
| 277 | +{ | |
| 278 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 279 | + int ret = 0; | |
| 280 | + | |
| 281 | + if (on == POWER_ON) | |
| 282 | + ret = core_clks_enable(core); | |
| 283 | + else | |
| 284 | + core_clks_disable(core); | |
| 285 | + | |
| 286 | + return ret; | |
| 287 | +} | |
| 288 | + | |
| 289 | +static const struct venus_pm_ops pm_ops_v1 = { | |
| 290 | + .core_get = core_get_v1, | |
| 291 | + .core_power = core_power_v1, | |
| 292 | + .load_scale = load_scale_v1, | |
| 293 | +}; | |
| 294 | + | |
| 295 | +static void | |
| 296 | +vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable) | |
| 297 | +{ | |
| 298 | + void __iomem *ctrl; | |
| 299 | + | |
| 300 | + if (session_type == VIDC_SESSION_TYPE_DEC) | |
| 301 | + ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL; | |
| 302 | + else | |
| 303 | + ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL; | |
| 304 | + | |
| 305 | + if (enable) | |
| 306 | + writel(0, ctrl); | |
| 307 | + else | |
| 308 | + writel(1, ctrl); | |
| 309 | +} | |
| 310 | + | |
| 311 | +static int vdec_get_v3(struct device *dev) | |
| 312 | +{ | |
| 313 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 314 | + | |
| 315 | + return vcodec_clks_get(core, dev, core->vcodec0_clks, | |
| 316 | + core->res->vcodec0_clks); | |
| 317 | +} | |
| 318 | + | |
| 319 | +static int vdec_power_v3(struct device *dev, int on) | |
| 320 | +{ | |
| 321 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 322 | + int ret = 0; | |
| 323 | + | |
| 324 | + vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, true); | |
| 325 | + | |
| 326 | + if (on == POWER_ON) | |
| 327 | + ret = vcodec_clks_enable(core, core->vcodec0_clks); | |
| 328 | + else | |
| 329 | + vcodec_clks_disable(core, core->vcodec0_clks); | |
| 330 | + | |
| 331 | + vcodec_control_v3(core, VIDC_SESSION_TYPE_DEC, false); | |
| 332 | + | |
| 333 | + return ret; | |
| 334 | +} | |
| 335 | + | |
| 336 | +static int venc_get_v3(struct device *dev) | |
| 337 | +{ | |
| 338 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 339 | + | |
| 340 | + return vcodec_clks_get(core, dev, core->vcodec1_clks, | |
| 341 | + core->res->vcodec1_clks); | |
| 342 | +} | |
| 343 | + | |
| 344 | +static int venc_power_v3(struct device *dev, int on) | |
| 345 | +{ | |
| 346 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 347 | + int ret = 0; | |
| 348 | + | |
| 349 | + vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, true); | |
| 350 | + | |
| 351 | + if (on == POWER_ON) | |
| 352 | + ret = vcodec_clks_enable(core, core->vcodec1_clks); | |
| 353 | + else | |
| 354 | + vcodec_clks_disable(core, core->vcodec1_clks); | |
| 355 | + | |
| 356 | + vcodec_control_v3(core, VIDC_SESSION_TYPE_ENC, false); | |
| 357 | + | |
| 358 | + return ret; | |
| 359 | +} | |
| 360 | + | |
| 361 | +static const struct venus_pm_ops pm_ops_v3 = { | |
| 362 | + .core_get = core_get_v1, | |
| 363 | + .core_power = core_power_v1, | |
| 364 | + .vdec_get = vdec_get_v3, | |
| 365 | + .vdec_power = vdec_power_v3, | |
| 366 | + .venc_get = venc_get_v3, | |
| 367 | + .venc_power = venc_power_v3, | |
| 368 | + .load_scale = load_scale_v1, | |
| 369 | +}; | |
| 370 | + | |
| 371 | +static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable) | |
| 372 | +{ | |
| 373 | + void __iomem *ctrl, *stat; | |
| 374 | + u32 val; | |
| 375 | + int ret; | |
| 376 | + | |
| 377 | + if (coreid == VIDC_CORE_ID_1) { | |
| 378 | + ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; | |
| 379 | + stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; | |
| 380 | + } else { | |
| 381 | + ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL; | |
| 382 | + stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS; | |
| 383 | + } | |
| 384 | + | |
| 385 | + if (enable) { | |
| 386 | + writel(0, ctrl); | |
| 387 | + | |
| 388 | + ret = readl_poll_timeout(stat, val, val & BIT(1), 1, 100); | |
| 389 | + if (ret) | |
| 390 | + return ret; | |
| 391 | + } else { | |
| 392 | + writel(1, ctrl); | |
| 393 | + | |
| 394 | + ret = readl_poll_timeout(stat, val, !(val & BIT(1)), 1, 100); | |
| 395 | + if (ret) | |
| 396 | + return ret; | |
| 397 | + } | |
| 398 | + | |
| 399 | + return 0; | |
| 400 | +} | |
| 401 | + | |
| 402 | +static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) | |
| 403 | +{ | |
| 404 | + int ret; | |
| 405 | + | |
| 406 | + if (coreid_mask & VIDC_CORE_ID_1) { | |
| 407 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); | |
| 408 | + if (ret) | |
| 409 | + return ret; | |
| 410 | + | |
| 411 | + vcodec_clks_disable(core, core->vcodec0_clks); | |
| 412 | + | |
| 413 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); | |
| 414 | + if (ret) | |
| 415 | + return ret; | |
| 416 | + | |
| 417 | + ret = pm_runtime_put_sync(core->pmdomains[1]); | |
| 418 | + if (ret < 0) | |
| 419 | + return ret; | |
| 420 | + } | |
| 421 | + | |
| 422 | + if (coreid_mask & VIDC_CORE_ID_2) { | |
| 423 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); | |
| 424 | + if (ret) | |
| 425 | + return ret; | |
| 426 | + | |
| 427 | + vcodec_clks_disable(core, core->vcodec1_clks); | |
| 428 | + | |
| 429 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); | |
| 430 | + if (ret) | |
| 431 | + return ret; | |
| 432 | + | |
| 433 | + ret = pm_runtime_put_sync(core->pmdomains[2]); | |
| 434 | + if (ret < 0) | |
| 435 | + return ret; | |
| 436 | + } | |
| 437 | + | |
| 438 | + return 0; | |
| 439 | +} | |
| 440 | + | |
| 441 | +static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) | |
| 442 | +{ | |
| 443 | + int ret; | |
| 444 | + | |
| 445 | + if (coreid_mask & VIDC_CORE_ID_1) { | |
| 446 | + ret = pm_runtime_get_sync(core->pmdomains[1]); | |
| 447 | + if (ret < 0) | |
| 448 | + return ret; | |
| 449 | + | |
| 450 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); | |
| 451 | + if (ret) | |
| 452 | + return ret; | |
| 453 | + | |
| 454 | + ret = vcodec_clks_enable(core, core->vcodec0_clks); | |
| 455 | + if (ret) | |
| 456 | + return ret; | |
| 457 | + | |
| 458 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, false); | |
| 459 | + if (ret < 0) | |
| 460 | + return ret; | |
| 461 | + } | |
| 462 | + | |
| 463 | + if (coreid_mask & VIDC_CORE_ID_2) { | |
| 464 | + ret = pm_runtime_get_sync(core->pmdomains[2]); | |
| 465 | + if (ret < 0) | |
| 466 | + return ret; | |
| 467 | + | |
| 468 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); | |
| 469 | + if (ret) | |
| 470 | + return ret; | |
| 471 | + | |
| 472 | + ret = vcodec_clks_enable(core, core->vcodec1_clks); | |
| 473 | + if (ret) | |
| 474 | + return ret; | |
| 475 | + | |
| 476 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, false); | |
| 477 | + if (ret < 0) | |
| 478 | + return ret; | |
| 479 | + } | |
| 480 | + | |
| 481 | + return 0; | |
| 482 | +} | |
| 483 | + | |
| 484 | +static void | |
| 485 | +min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load) | |
| 486 | +{ | |
| 487 | + u32 mbs_per_sec, load, core1_load = 0, core2_load = 0; | |
| 488 | + u32 cores_max = core_num_max(inst); | |
| 489 | + struct venus_core *core = inst->core; | |
| 490 | + struct venus_inst *inst_pos; | |
| 491 | + unsigned long vpp_freq; | |
| 492 | + u32 coreid; | |
| 493 | + | |
| 494 | + mutex_lock(&core->lock); | |
| 495 | + | |
| 496 | + list_for_each_entry(inst_pos, &core->instances, list) { | |
| 497 | + if (inst_pos == inst) | |
| 498 | + continue; | |
| 499 | + vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq; | |
| 500 | + coreid = inst_pos->clk_data.core_id; | |
| 501 | + | |
| 502 | + mbs_per_sec = load_per_instance(inst_pos); | |
| 503 | + load = mbs_per_sec * vpp_freq; | |
| 504 | + | |
| 505 | + if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) { | |
| 506 | + core1_load += load / 2; | |
| 507 | + core2_load += load / 2; | |
| 508 | + } else if (coreid & VIDC_CORE_ID_1) { | |
| 509 | + core1_load += load; | |
| 510 | + } else if (coreid & VIDC_CORE_ID_2) { | |
| 511 | + core2_load += load; | |
| 512 | + } | |
| 513 | + } | |
| 514 | + | |
| 515 | + *min_coreid = core1_load <= core2_load ? | |
| 516 | + VIDC_CORE_ID_1 : VIDC_CORE_ID_2; | |
| 517 | + *min_load = min(core1_load, core2_load); | |
| 518 | + | |
| 519 | + if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) { | |
| 520 | + *min_coreid = VIDC_CORE_ID_1; | |
| 521 | + *min_load = core1_load; | |
| 522 | + } | |
| 523 | + | |
| 524 | + mutex_unlock(&core->lock); | |
| 525 | +} | |
| 526 | + | |
| 527 | +static int decide_core(struct venus_inst *inst) | |
| 528 | +{ | |
| 529 | + const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; | |
| 530 | + struct venus_core *core = inst->core; | |
| 531 | + u32 min_coreid, min_load, inst_load; | |
| 532 | + struct hfi_videocores_usage_type cu; | |
| 533 | + unsigned long max_freq; | |
| 534 | + | |
| 535 | + if (legacy_binding) { | |
| 536 | + if (inst->session_type == VIDC_SESSION_TYPE_DEC) | |
| 537 | + cu.video_core_enable_mask = VIDC_CORE_ID_1; | |
| 538 | + else | |
| 539 | + cu.video_core_enable_mask = VIDC_CORE_ID_2; | |
| 540 | + | |
| 541 | + goto done; | |
| 542 | + } | |
| 543 | + | |
| 544 | + if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT) | |
| 545 | + return 0; | |
| 546 | + | |
| 547 | + inst_load = load_per_instance(inst); | |
| 548 | + inst_load *= inst->clk_data.codec_freq_data->vpp_freq; | |
| 549 | + max_freq = core->res->freq_tbl[0].freq; | |
| 550 | + | |
| 551 | + min_loaded_core(inst, &min_coreid, &min_load); | |
| 552 | + | |
| 553 | + if ((inst_load + min_load) > max_freq) { | |
| 554 | + dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n", | |
| 555 | + inst_load, max_freq); | |
| 556 | + return -EINVAL; | |
| 557 | + } | |
| 558 | + | |
| 559 | + inst->clk_data.core_id = min_coreid; | |
| 560 | + cu.video_core_enable_mask = min_coreid; | |
| 561 | + | |
| 562 | +done: | |
| 563 | + return hfi_session_set_property(inst, ptype, &cu); | |
| 564 | +} | |
| 565 | + | |
| 566 | +static int acquire_core(struct venus_inst *inst) | |
| 567 | +{ | |
| 568 | + struct venus_core *core = inst->core; | |
| 569 | + unsigned int coreid_mask = 0; | |
| 570 | + | |
| 571 | + if (inst->core_acquired) | |
| 572 | + return 0; | |
| 573 | + | |
| 574 | + inst->core_acquired = true; | |
| 575 | + | |
| 576 | + if (inst->clk_data.core_id & VIDC_CORE_ID_1) { | |
| 577 | + if (core->core0_usage_count++) | |
| 578 | + return 0; | |
| 579 | + | |
| 580 | + coreid_mask = VIDC_CORE_ID_1; | |
| 581 | + } | |
| 582 | + | |
| 583 | + if (inst->clk_data.core_id & VIDC_CORE_ID_2) { | |
| 584 | + if (core->core1_usage_count++) | |
| 585 | + return 0; | |
| 586 | + | |
| 587 | + coreid_mask |= VIDC_CORE_ID_2; | |
| 588 | + } | |
| 589 | + | |
| 590 | + return poweron_coreid(core, coreid_mask); | |
| 591 | +} | |
| 592 | + | |
| 593 | +static int release_core(struct venus_inst *inst) | |
| 594 | +{ | |
| 595 | + struct venus_core *core = inst->core; | |
| 596 | + unsigned int coreid_mask = 0; | |
| 597 | + int ret; | |
| 598 | + | |
| 599 | + if (!inst->core_acquired) | |
| 600 | + return 0; | |
| 601 | + | |
| 602 | + if (inst->clk_data.core_id & VIDC_CORE_ID_1) { | |
| 603 | + if (--core->core0_usage_count) | |
| 604 | + goto done; | |
| 605 | + | |
| 606 | + coreid_mask = VIDC_CORE_ID_1; | |
| 607 | + } | |
| 608 | + | |
| 609 | + if (inst->clk_data.core_id & VIDC_CORE_ID_2) { | |
| 610 | + if (--core->core1_usage_count) | |
| 611 | + goto done; | |
| 612 | + | |
| 613 | + coreid_mask |= VIDC_CORE_ID_2; | |
| 614 | + } | |
| 615 | + | |
| 616 | + ret = poweroff_coreid(core, coreid_mask); | |
| 617 | + if (ret) | |
| 618 | + return ret; | |
| 619 | + | |
| 620 | +done: | |
| 621 | + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; | |
| 622 | + inst->core_acquired = false; | |
| 623 | + return 0; | |
| 624 | +} | |
| 625 | + | |
| 626 | +static int coreid_power_v4(struct venus_inst *inst, int on) | |
| 627 | +{ | |
| 628 | + struct venus_core *core = inst->core; | |
| 629 | + int ret; | |
| 630 | + | |
| 631 | + if (legacy_binding) | |
| 632 | + return 0; | |
| 633 | + | |
| 634 | + if (on == POWER_ON) { | |
| 635 | + ret = decide_core(inst); | |
| 636 | + if (ret) | |
| 637 | + return ret; | |
| 638 | + | |
| 639 | + mutex_lock(&core->lock); | |
| 640 | + ret = acquire_core(inst); | |
| 641 | + mutex_unlock(&core->lock); | |
| 642 | + } else { | |
| 643 | + mutex_lock(&core->lock); | |
| 644 | + ret = release_core(inst); | |
| 645 | + mutex_unlock(&core->lock); | |
| 646 | + } | |
| 647 | + | |
| 648 | + return ret; | |
| 649 | +} | |
| 650 | + | |
| 651 | +static int vdec_get_v4(struct device *dev) | |
| 652 | +{ | |
| 653 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 654 | + | |
| 655 | + if (!legacy_binding) | |
| 656 | + return 0; | |
| 657 | + | |
| 658 | + return vcodec_clks_get(core, dev, core->vcodec0_clks, | |
| 659 | + core->res->vcodec0_clks); | |
| 660 | +} | |
| 661 | + | |
| 662 | +static void vdec_put_v4(struct device *dev) | |
| 663 | +{ | |
| 664 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 665 | + unsigned int i; | |
| 666 | + | |
| 667 | + if (!legacy_binding) | |
| 668 | + return; | |
| 669 | + | |
| 670 | + for (i = 0; i < core->res->vcodec_clks_num; i++) | |
| 671 | + core->vcodec0_clks[i] = NULL; | |
| 672 | +} | |
| 673 | + | |
| 674 | +static int vdec_power_v4(struct device *dev, int on) | |
| 675 | +{ | |
| 676 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 677 | + int ret; | |
| 678 | + | |
| 679 | + if (!legacy_binding) | |
| 680 | + return 0; | |
| 681 | + | |
| 682 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_1, true); | |
| 683 | + if (ret) | |
| 684 | + return ret; | |
| 685 | + | |
| 686 | + if (on == POWER_ON) | |
| 687 | + ret = vcodec_clks_enable(core, core->vcodec0_clks); | |
| 688 | + else | |
| 689 | + vcodec_clks_disable(core, core->vcodec0_clks); | |
| 690 | + | |
| 691 | + vcodec_control_v4(core, VIDC_CORE_ID_1, false); | |
| 692 | + | |
| 693 | + return ret; | |
| 694 | +} | |
| 695 | + | |
| 696 | +static int venc_get_v4(struct device *dev) | |
| 697 | +{ | |
| 698 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 699 | + | |
| 700 | + if (!legacy_binding) | |
| 701 | + return 0; | |
| 702 | + | |
| 703 | + return vcodec_clks_get(core, dev, core->vcodec1_clks, | |
| 704 | + core->res->vcodec1_clks); | |
| 705 | +} | |
| 706 | + | |
| 707 | +static void venc_put_v4(struct device *dev) | |
| 708 | +{ | |
| 709 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 710 | + unsigned int i; | |
| 711 | + | |
| 712 | + if (!legacy_binding) | |
| 713 | + return; | |
| 714 | + | |
| 715 | + for (i = 0; i < core->res->vcodec_clks_num; i++) | |
| 716 | + core->vcodec1_clks[i] = NULL; | |
| 717 | +} | |
| 718 | + | |
| 719 | +static int venc_power_v4(struct device *dev, int on) | |
| 720 | +{ | |
| 721 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 722 | + int ret; | |
| 723 | + | |
| 724 | + if (!legacy_binding) | |
| 725 | + return 0; | |
| 726 | + | |
| 727 | + ret = vcodec_control_v4(core, VIDC_CORE_ID_2, true); | |
| 728 | + if (ret) | |
| 729 | + return ret; | |
| 730 | + | |
| 731 | + if (on == POWER_ON) | |
| 732 | + ret = vcodec_clks_enable(core, core->vcodec1_clks); | |
| 733 | + else | |
| 734 | + vcodec_clks_disable(core, core->vcodec1_clks); | |
| 735 | + | |
| 736 | + vcodec_control_v4(core, VIDC_CORE_ID_2, false); | |
| 737 | + | |
| 738 | + return ret; | |
| 739 | +} | |
| 740 | + | |
| 741 | +static int vcodec_domains_get(struct device *dev) | |
| 742 | +{ | |
| 743 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 744 | + const struct venus_resources *res = core->res; | |
| 745 | + struct device *pd; | |
| 746 | + unsigned int i; | |
| 747 | + | |
| 748 | + if (!res->vcodec_pmdomains_num) | |
| 749 | + return -ENODEV; | |
| 750 | + | |
| 751 | + for (i = 0; i < res->vcodec_pmdomains_num; i++) { | |
| 752 | + pd = dev_pm_domain_attach_by_name(dev, | |
| 753 | + res->vcodec_pmdomains[i]); | |
| 754 | + if (IS_ERR(pd)) | |
| 755 | + return PTR_ERR(pd); | |
| 756 | + core->pmdomains[i] = pd; | |
| 757 | + } | |
| 758 | + | |
| 759 | + core->pd_dl_venus = device_link_add(dev, core->pmdomains[0], | |
| 760 | + DL_FLAG_PM_RUNTIME | | |
| 761 | + DL_FLAG_STATELESS | | |
| 762 | + DL_FLAG_RPM_ACTIVE); | |
| 763 | + if (!core->pd_dl_venus) | |
| 764 | + return -ENODEV; | |
| 765 | + | |
| 766 | + return 0; | |
| 767 | +} | |
| 768 | + | |
| 769 | +static void vcodec_domains_put(struct device *dev) | |
| 770 | +{ | |
| 771 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 772 | + const struct venus_resources *res = core->res; | |
| 773 | + unsigned int i; | |
| 774 | + | |
| 775 | + if (!res->vcodec_pmdomains_num) | |
| 776 | + return; | |
| 777 | + | |
| 778 | + if (core->pd_dl_venus) | |
| 779 | + device_link_del(core->pd_dl_venus); | |
| 780 | + | |
| 781 | + for (i = 0; i < res->vcodec_pmdomains_num; i++) { | |
| 782 | + if (IS_ERR_OR_NULL(core->pmdomains[i])) | |
| 783 | + continue; | |
| 784 | + dev_pm_domain_detach(core->pmdomains[i], true); | |
| 785 | + } | |
| 786 | +} | |
| 787 | + | |
| 788 | +static int core_get_v4(struct device *dev) | |
| 789 | +{ | |
| 790 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 791 | + const struct venus_resources *res = core->res; | |
| 792 | + int ret; | |
| 793 | + | |
| 794 | + ret = core_clks_get(core); | |
| 795 | + if (ret) | |
| 796 | + return ret; | |
| 797 | + | |
| 798 | + if (!res->vcodec_pmdomains_num) | |
| 799 | + legacy_binding = true; | |
| 800 | + | |
| 801 | + dev_info(dev, "%s legacy binding\n", legacy_binding ? "" : "non"); | |
| 802 | + | |
| 803 | + ret = vcodec_clks_get(core, dev, core->vcodec0_clks, res->vcodec0_clks); | |
| 804 | + if (ret) | |
| 805 | + return ret; | |
| 806 | + | |
| 807 | + ret = vcodec_clks_get(core, dev, core->vcodec1_clks, res->vcodec1_clks); | |
| 808 | + if (ret) | |
| 809 | + return ret; | |
| 810 | + | |
| 811 | + if (legacy_binding) | |
| 812 | + return 0; | |
| 813 | + | |
| 814 | + ret = vcodec_domains_get(dev); | |
| 815 | + if (ret) | |
| 816 | + return ret; | |
| 817 | + | |
| 818 | + return 0; | |
| 819 | +} | |
| 820 | + | |
| 821 | +static void core_put_v4(struct device *dev) | |
| 822 | +{ | |
| 823 | + if (legacy_binding) | |
| 824 | + return; | |
| 825 | + | |
| 826 | + vcodec_domains_put(dev); | |
| 827 | +} | |
| 828 | + | |
| 829 | +static int core_power_v4(struct device *dev, int on) | |
| 830 | +{ | |
| 831 | + struct venus_core *core = dev_get_drvdata(dev); | |
| 832 | + int ret = 0; | |
| 833 | + | |
| 834 | + if (on == POWER_ON) | |
| 835 | + ret = core_clks_enable(core); | |
| 836 | + else | |
| 837 | + core_clks_disable(core); | |
| 838 | + | |
| 839 | + return ret; | |
| 840 | +} | |
| 841 | + | |
| 842 | +static unsigned long calculate_inst_freq(struct venus_inst *inst, | |
| 843 | + unsigned long filled_len) | |
| 844 | +{ | |
| 845 | + unsigned long vpp_freq = 0, vsp_freq = 0; | |
| 846 | + u32 fps = (u32)inst->fps; | |
| 847 | + u32 mbs_per_sec; | |
| 848 | + | |
| 849 | + mbs_per_sec = load_per_instance(inst) / fps; | |
| 850 | + | |
| 851 | + vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq; | |
| 852 | + /* 21 / 20 is overhead factor */ | |
| 853 | + vpp_freq += vpp_freq / 20; | |
| 854 | + vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq; | |
| 855 | + | |
| 856 | + /* 10 / 7 is overhead factor */ | |
| 857 | + if (inst->session_type == VIDC_SESSION_TYPE_ENC) | |
| 858 | + vsp_freq += (inst->controls.enc.bitrate * 10) / 7; | |
| 859 | + else | |
| 860 | + vsp_freq += ((fps * filled_len * 8) * 10) / 7; | |
| 861 | + | |
| 862 | + return max(vpp_freq, vsp_freq); | |
| 863 | +} | |
| 864 | + | |
| 865 | +static int load_scale_v4(struct venus_inst *inst) | |
| 866 | +{ | |
| 867 | + struct venus_core *core = inst->core; | |
| 868 | + const struct freq_tbl *table = core->res->freq_tbl; | |
| 869 | + unsigned int num_rows = core->res->freq_tbl_size; | |
| 870 | + struct device *dev = core->dev; | |
| 871 | + unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; | |
| 872 | + unsigned long filled_len = 0; | |
| 873 | + int i, ret; | |
| 874 | + | |
| 875 | + for (i = 0; i < inst->num_input_bufs; i++) | |
| 876 | + filled_len = max(filled_len, inst->payloads[i]); | |
| 877 | + | |
| 878 | + if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len) | |
| 879 | + return 0; | |
| 880 | + | |
| 881 | + freq = calculate_inst_freq(inst, filled_len); | |
| 882 | + inst->clk_data.freq = freq; | |
| 883 | + | |
| 884 | + mutex_lock(&core->lock); | |
| 885 | + list_for_each_entry(inst, &core->instances, list) { | |
| 886 | + if (inst->clk_data.core_id == VIDC_CORE_ID_1) { | |
| 887 | + freq_core1 += inst->clk_data.freq; | |
| 888 | + } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) { | |
| 889 | + freq_core2 += inst->clk_data.freq; | |
| 890 | + } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) { | |
| 891 | + freq_core1 += inst->clk_data.freq; | |
| 892 | + freq_core2 += inst->clk_data.freq; | |
| 893 | + } | |
| 894 | + } | |
| 895 | + mutex_unlock(&core->lock); | |
| 896 | + | |
| 897 | + freq = max(freq_core1, freq_core2); | |
| 898 | + | |
| 899 | + if (freq >= table[0].freq) { | |
| 900 | + freq = table[0].freq; | |
| 901 | + dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", | |
| 902 | + freq, table[0].freq); | |
| 903 | + goto set_freq; | |
| 904 | + } | |
| 905 | + | |
| 906 | + for (i = num_rows - 1 ; i >= 0; i--) { | |
| 907 | + if (freq <= table[i].freq) { | |
| 908 | + freq = table[i].freq; | |
| 909 | + break; | |
| 910 | + } | |
| 911 | + } | |
| 912 | + | |
| 913 | +set_freq: | |
| 914 | + | |
| 915 | + ret = core_clks_set_rate(core, freq); | |
| 916 | + if (ret) { | |
| 917 | + dev_err(dev, "failed to set clock rate %lu (%d)\n", | |
| 918 | + freq, ret); | |
| 919 | + return ret; | |
| 920 | + } | |
| 921 | + | |
| 922 | + ret = load_scale_bw(core); | |
| 923 | + if (ret) { | |
| 924 | + dev_err(dev, "failed to set bandwidth (%d)\n", | |
| 925 | + ret); | |
| 926 | + return ret; | |
| 927 | + } | |
| 928 | + | |
| 929 | + return 0; | |
| 930 | +} | |
| 931 | + | |
| 932 | +static const struct venus_pm_ops pm_ops_v4 = { | |
| 933 | + .core_get = core_get_v4, | |
| 934 | + .core_put = core_put_v4, | |
| 935 | + .core_power = core_power_v4, | |
| 936 | + .vdec_get = vdec_get_v4, | |
| 937 | + .vdec_put = vdec_put_v4, | |
| 938 | + .vdec_power = vdec_power_v4, | |
| 939 | + .venc_get = venc_get_v4, | |
| 940 | + .venc_put = venc_put_v4, | |
| 941 | + .venc_power = venc_power_v4, | |
| 942 | + .coreid_power = coreid_power_v4, | |
| 943 | + .load_scale = load_scale_v4, | |
| 944 | +}; | |
| 945 | + | |
| 946 | +const struct venus_pm_ops *venus_pm_get(enum hfi_version version) | |
| 947 | +{ | |
| 948 | + switch (version) { | |
| 949 | + case HFI_VERSION_1XX: | |
| 950 | + default: | |
| 951 | + return &pm_ops_v1; | |
| 952 | + case HFI_VERSION_3XX: | |
| 953 | + return &pm_ops_v3; | |
| 954 | + case HFI_VERSION_4XX: | |
| 955 | + return &pm_ops_v4; | |
| 956 | + } | |
| 957 | + | |
| 958 | + return NULL; | |
| 959 | +} | |
| @@ -0,0 +1,65 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* Copyright (C) 2019 Linaro Ltd. */ | |
| 3 | +#ifndef __VENUS_PM_HELPERS_H__ | |
| 4 | +#define __VENUS_PM_HELPERS_H__ | |
| 5 | + | |
| 6 | +struct device; | |
| 7 | + | |
| 8 | +#define POWER_ON 1 | |
| 9 | +#define POWER_OFF 0 | |
| 10 | + | |
| 11 | +struct venus_pm_ops { | |
| 12 | + int (*core_get)(struct device *dev); | |
| 13 | + void (*core_put)(struct device *dev); | |
| 14 | + int (*core_power)(struct device *dev, int on); | |
| 15 | + | |
| 16 | + int (*vdec_get)(struct device *dev); | |
| 17 | + void (*vdec_put)(struct device *dev); | |
| 18 | + int (*vdec_power)(struct device *dev, int on); | |
| 19 | + | |
| 20 | + int (*venc_get)(struct device *dev); | |
| 21 | + void (*venc_put)(struct device *dev); | |
| 22 | + int (*venc_power)(struct device *dev, int on); | |
| 23 | + | |
| 24 | + int (*coreid_power)(struct venus_inst *inst, int on); | |
| 25 | + | |
| 26 | + int (*load_scale)(struct venus_inst *inst); | |
| 27 | +}; | |
| 28 | + | |
| 29 | +const struct venus_pm_ops *venus_pm_get(enum hfi_version version); | |
| 30 | + | |
| 31 | +static inline int venus_pm_load_scale(struct venus_inst *inst) | |
| 32 | +{ | |
| 33 | + struct venus_core *core = inst->core; | |
| 34 | + | |
| 35 | + if (!core->pm_ops || !core->pm_ops->load_scale) | |
| 36 | + return 0; | |
| 37 | + | |
| 38 | + return core->pm_ops->load_scale(inst); | |
| 39 | +} | |
| 40 | + | |
| 41 | +static inline int venus_pm_acquire_core(struct venus_inst *inst) | |
| 42 | +{ | |
| 43 | + struct venus_core *core = inst->core; | |
| 44 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 45 | + int ret = 0; | |
| 46 | + | |
| 47 | + if (pm_ops && pm_ops->coreid_power) | |
| 48 | + ret = pm_ops->coreid_power(inst, POWER_ON); | |
| 49 | + | |
| 50 | + return ret; | |
| 51 | +} | |
| 52 | + | |
| 53 | +static inline int venus_pm_release_core(struct venus_inst *inst) | |
| 54 | +{ | |
| 55 | + struct venus_core *core = inst->core; | |
| 56 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 57 | + int ret = 0; | |
| 58 | + | |
| 59 | + if (pm_ops && pm_ops->coreid_power) | |
| 60 | + ret = pm_ops->coreid_power(inst, POWER_OFF); | |
| 61 | + | |
| 62 | + return ret; | |
| 63 | +} | |
| 64 | + | |
| 65 | +#endif | |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "core.h" |
| 21 | 21 | #include "helpers.h" |
| 22 | 22 | #include "vdec.h" |
| 23 | +#include "pm_helpers.h" | |
| 23 | 24 | |
| 24 | 25 | /* |
| 25 | 26 | * Three resons to keep MPLANE formats (despite that the number of planes |
| @@ -578,10 +579,6 @@ static int vdec_output_conf(struct venus_inst *inst) · 552 unmodified lines | ||
| 578 | 579 | if (ret) |
| 579 | 580 | return ret; |
| 580 | 581 | |
| 581 | − ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_1); | |
| 582 | − if (ret) | |
| 583 | − return ret; | |
| 584 | − | |
| 585 | 582 | if (core->res->hfi_version == HFI_VERSION_1XX) { |
| 586 | 583 | ptype = HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER; |
| 587 | 584 | ret = hfi_session_set_property(inst, ptype, &en); |
| @@ -868,7 +865,7 @@ reconfigure: · 280 unmodified lines | ||
| 868 | 865 | if (ret) |
| 869 | 866 | goto free_dpb_bufs; |
| 870 | 867 | |
| 871 | − venus_helper_load_scale_clocks(inst); | |
| 868 | + venus_pm_load_scale(inst); | |
| 872 | 869 | |
| 873 | 870 | ret = hfi_session_continue(inst); |
| 874 | 871 | if (ret) |
| @@ -950,6 +947,10 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) · 75 unmodified lines | ||
| 950 | 947 | |
| 951 | 948 | mutex_lock(&inst->lock); |
| 952 | 949 | |
| 950 | + ret = venus_pm_acquire_core(inst); | |
| 951 | + if (ret) | |
| 952 | + goto error; | |
| 953 | + | |
| 953 | 954 | if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) |
| 954 | 955 | ret = vdec_start_capture(inst); |
| 955 | 956 | else |
| @@ -1076,7 +1077,8 @@ static void vdec_session_release(struct venus_inst *inst) · 120 unmodified lines | ||
| 1076 | 1077 | hfi_session_abort(inst); |
| 1077 | 1078 | |
| 1078 | 1079 | venus_helper_free_dpb_bufs(inst); |
| 1079 | − venus_helper_load_scale_clocks(inst); | |
| 1080 | + venus_pm_load_scale(inst); | |
| 1081 | + venus_pm_release_core(inst); | |
| 1080 | 1082 | INIT_LIST_HEAD(&inst->registeredbufs); |
| 1081 | 1083 | |
| 1082 | 1084 | mutex_unlock(&inst->lock); |
| @@ -1191,6 +1193,9 @@ static void vdec_event_change(struct venus_inst *inst, · 108 unmodified lines | ||
| 1191 | 1193 | inst->out_width = ev_data->width; |
| 1192 | 1194 | inst->out_height = ev_data->height; |
| 1193 | 1195 | |
| 1196 | + if (inst->bit_depth != ev_data->bit_depth) | |
| 1197 | + inst->bit_depth = ev_data->bit_depth; | |
| 1198 | + | |
| 1194 | 1199 | dev_dbg(dev, "event %s sufficient resources (%ux%u)\n", |
| 1195 | 1200 | sufficient ? "" : "not", ev_data->width, ev_data->height); |
| 1196 | 1201 | |
| @@ -1336,6 +1341,9 @@ static int vdec_open(struct file *file) · 139 unmodified lines | ||
| 1336 | 1341 | inst->num_output_bufs = 1; |
| 1337 | 1342 | inst->codec_state = VENUS_DEC_STATE_DEINIT; |
| 1338 | 1343 | inst->buf_count = 0; |
| 1344 | + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; | |
| 1345 | + inst->core_acquired = false; | |
| 1346 | + inst->bit_depth = VIDC_BITDEPTH_8; | |
| 1339 | 1347 | init_waitqueue_head(&inst->reconf_wait); |
| 1340 | 1348 | venus_helper_init_instance(inst); |
| 1341 | 1349 | |
| @@ -1432,20 +1440,14 @@ static int vdec_probe(struct platform_device *pdev) · 90 unmodified lines | ||
| 1432 | 1440 | if (!core) |
| 1433 | 1441 | return -EPROBE_DEFER; |
| 1434 | 1442 | |
| 1435 | − if (IS_V3(core) || IS_V4(core)) { | |
| 1436 | − core->core0_clk = devm_clk_get(dev, "core"); | |
| 1437 | − if (IS_ERR(core->core0_clk)) | |
| 1438 | − return PTR_ERR(core->core0_clk); | |
| 1439 | − } | |
| 1443 | + platform_set_drvdata(pdev, core); | |
| 1440 | 1444 | |
| 1441 | − if (IS_V4(core)) { | |
| 1442 | − core->core0_bus_clk = devm_clk_get(dev, "bus"); | |
| 1443 | − if (IS_ERR(core->core0_bus_clk)) | |
| 1444 | − return PTR_ERR(core->core0_bus_clk); | |
| 1445 | + if (core->pm_ops->vdec_get) { | |
| 1446 | + ret = core->pm_ops->vdec_get(dev); | |
| 1447 | + if (ret) | |
| 1448 | + return ret; | |
| 1445 | 1449 | } |
| 1446 | 1450 | |
| 1447 | − platform_set_drvdata(pdev, core); | |
| 1448 | − | |
| 1449 | 1451 | vdev = video_device_alloc(); |
| 1450 | 1452 | if (!vdev) |
| 1451 | 1453 | return -ENOMEM; |
| @@ -1458,7 +1460,7 @@ static int vdec_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 1458 | 1460 | vdev->v4l2_dev = &core->v4l2_dev; |
| 1459 | 1461 | vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 1460 | 1462 | |
| 1461 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1463 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1462 | 1464 | if (ret) |
| 1463 | 1465 | goto err_vdev_release; |
| 1464 | 1466 | |
| @@ -1482,57 +1484,33 @@ static int vdec_remove(struct platform_device *pdev) · 17 unmodified lines | ||
| 1482 | 1484 | video_unregister_device(core->vdev_dec); |
| 1483 | 1485 | pm_runtime_disable(core->dev_dec); |
| 1484 | 1486 | |
| 1487 | + if (core->pm_ops->vdec_put) | |
| 1488 | + core->pm_ops->vdec_put(core->dev_dec); | |
| 1489 | + | |
| 1485 | 1490 | return 0; |
| 1486 | 1491 | } |
| 1487 | 1492 | |
| 1488 | 1493 | static __maybe_unused int vdec_runtime_suspend(struct device *dev) |
| 1489 | 1494 | { |
| 1490 | 1495 | struct venus_core *core = dev_get_drvdata(dev); |
| 1491 | − int ret; | |
| 1492 | − | |
| 1493 | − if (IS_V1(core)) | |
| 1494 | − return 0; | |
| 1495 | − | |
| 1496 | − ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, true); | |
| 1497 | − if (ret) | |
| 1498 | − return ret; | |
| 1499 | − | |
| 1500 | − if (IS_V4(core)) | |
| 1501 | − clk_disable_unprepare(core->core0_bus_clk); | |
| 1496 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 1497 | + int ret = 0; | |
| 1502 | 1498 | |
| 1503 | − clk_disable_unprepare(core->core0_clk); | |
| 1499 | + if (pm_ops->vdec_power) | |
| 1500 | + ret = pm_ops->vdec_power(dev, POWER_OFF); | |
| 1504 | 1501 | |
| 1505 | − return venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false); | |
| 1502 | + return ret; | |
| 1506 | 1503 | } |
| 1507 | 1504 | |
| 1508 | 1505 | static __maybe_unused int vdec_runtime_resume(struct device *dev) |
| 1509 | 1506 | { |
| 1510 | 1507 | struct venus_core *core = dev_get_drvdata(dev); |
| 1511 | − int ret; | |
| 1512 | − | |
| 1513 | − if (IS_V1(core)) | |
| 1514 | − return 0; | |
| 1515 | − | |
| 1516 | − ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, true); | |
| 1517 | − if (ret) | |
| 1518 | − return ret; | |
| 1519 | − | |
| 1520 | − ret = clk_prepare_enable(core->core0_clk); | |
| 1521 | − if (ret) | |
| 1522 | − goto err_power_disable; | |
| 1523 | − | |
| 1524 | − if (IS_V4(core)) | |
| 1525 | − ret = clk_prepare_enable(core->core0_bus_clk); | |
| 1526 | − | |
| 1527 | − if (ret) | |
| 1528 | − goto err_unprepare_core0; | |
| 1508 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 1509 | + int ret = 0; | |
| 1529 | 1510 | |
| 1530 | − return venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false); | |
| 1511 | + if (pm_ops->vdec_power) | |
| 1512 | + ret = pm_ops->vdec_power(dev, POWER_ON); | |
| 1531 | 1513 | |
| 1532 | −err_unprepare_core0: | |
| 1533 | − clk_disable_unprepare(core->core0_clk); | |
| 1534 | −err_power_disable: | |
| 1535 | − venus_helper_power_enable(core, VIDC_SESSION_TYPE_DEC, false); | |
| 1536 | 1514 | return ret; |
| 1537 | 1515 | } |
| 1538 | 1516 | |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "core.h" |
| 21 | 21 | #include "helpers.h" |
| 22 | 22 | #include "venc.h" |
| 23 | +#include "pm_helpers.h" | |
| 23 | 24 | |
| 24 | 25 | #define NUM_B_FRAMES_MAX 4 |
| 25 | 26 | |
| @@ -655,10 +656,6 @@ static int venc_set_properties(struct venus_inst *inst) · 629 unmodified lines | ||
| 655 | 656 | if (ret) |
| 656 | 657 | return ret; |
| 657 | 658 | |
| 658 | − ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_2); | |
| 659 | − if (ret) | |
| 660 | − return ret; | |
| 661 | − | |
| 662 | 659 | ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; |
| 663 | 660 | frate.buffer_type = HFI_BUFFER_OUTPUT; |
| 664 | 661 | frate.framerate = inst->fps * (1 << 16); |
| @@ -731,7 +728,9 @@ static int venc_set_properties(struct venus_inst *inst) · 66 unmodified lines | ||
| 731 | 728 | if (ret) |
| 732 | 729 | return ret; |
| 733 | 730 | |
| 734 | − if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | |
| 731 | + if (!ctr->rc_enable) | |
| 732 | + rate_control = HFI_RATE_CONTROL_OFF; | |
| 733 | + else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | |
| 735 | 734 | rate_control = HFI_RATE_CONTROL_VBR_CFR; |
| 736 | 735 | else |
| 737 | 736 | rate_control = HFI_RATE_CONTROL_CBR_CFR; |
| @@ -991,6 +990,10 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) · 253 unmodified lines | ||
| 991 | 990 | if (ret) |
| 992 | 991 | goto bufs_done; |
| 993 | 992 | |
| 993 | + ret = venus_pm_acquire_core(inst); | |
| 994 | + if (ret) | |
| 995 | + goto deinit_sess; | |
| 996 | + | |
| 994 | 997 | ret = venc_set_properties(inst); |
| 995 | 998 | if (ret) |
| 996 | 999 | goto deinit_sess; |
| @@ -1159,6 +1162,8 @@ static int venc_open(struct file *file) · 162 unmodified lines | ||
| 1159 | 1162 | |
| 1160 | 1163 | inst->core = core; |
| 1161 | 1164 | inst->session_type = VIDC_SESSION_TYPE_ENC; |
| 1165 | + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; | |
| 1166 | + inst->core_acquired = false; | |
| 1162 | 1167 | |
| 1163 | 1168 | venus_helper_init_instance(inst); |
| 1164 | 1169 | |
| @@ -1255,20 +1260,14 @@ static int venc_probe(struct platform_device *pdev) · 90 unmodified lines | ||
| 1255 | 1260 | if (!core) |
| 1256 | 1261 | return -EPROBE_DEFER; |
| 1257 | 1262 | |
| 1258 | − if (IS_V3(core) || IS_V4(core)) { | |
| 1259 | − core->core1_clk = devm_clk_get(dev, "core"); | |
| 1260 | − if (IS_ERR(core->core1_clk)) | |
| 1261 | − return PTR_ERR(core->core1_clk); | |
| 1262 | − } | |
| 1263 | + platform_set_drvdata(pdev, core); | |
| 1263 | 1264 | |
| 1264 | − if (IS_V4(core)) { | |
| 1265 | − core->core1_bus_clk = devm_clk_get(dev, "bus"); | |
| 1266 | − if (IS_ERR(core->core1_bus_clk)) | |
| 1267 | − return PTR_ERR(core->core1_bus_clk); | |
| 1265 | + if (core->pm_ops->venc_get) { | |
| 1266 | + ret = core->pm_ops->venc_get(dev); | |
| 1267 | + if (ret) | |
| 1268 | + return ret; | |
| 1268 | 1269 | } |
| 1269 | 1270 | |
| 1270 | − platform_set_drvdata(pdev, core); | |
| 1271 | − | |
| 1272 | 1271 | vdev = video_device_alloc(); |
| 1273 | 1272 | if (!vdev) |
| 1274 | 1273 | return -ENOMEM; |
| @@ -1281,7 +1280,7 @@ static int venc_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 1281 | 1280 | vdev->v4l2_dev = &core->v4l2_dev; |
| 1282 | 1281 | vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; |
| 1283 | 1282 | |
| 1284 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1283 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1285 | 1284 | if (ret) |
| 1286 | 1285 | goto err_vdev_release; |
| 1287 | 1286 | |
| @@ -1305,57 +1304,33 @@ static int venc_remove(struct platform_device *pdev) · 17 unmodified lines | ||
| 1305 | 1304 | video_unregister_device(core->vdev_enc); |
| 1306 | 1305 | pm_runtime_disable(core->dev_enc); |
| 1307 | 1306 | |
| 1307 | + if (core->pm_ops->venc_put) | |
| 1308 | + core->pm_ops->venc_put(core->dev_enc); | |
| 1309 | + | |
| 1308 | 1310 | return 0; |
| 1309 | 1311 | } |
| 1310 | 1312 | |
| 1311 | 1313 | static __maybe_unused int venc_runtime_suspend(struct device *dev) |
| 1312 | 1314 | { |
| 1313 | 1315 | struct venus_core *core = dev_get_drvdata(dev); |
| 1314 | − int ret; | |
| 1315 | − | |
| 1316 | − if (IS_V1(core)) | |
| 1317 | − return 0; | |
| 1318 | − | |
| 1319 | − ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true); | |
| 1320 | − if (ret) | |
| 1321 | − return ret; | |
| 1322 | − | |
| 1323 | − if (IS_V4(core)) | |
| 1324 | − clk_disable_unprepare(core->core1_bus_clk); | |
| 1316 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 1317 | + int ret = 0; | |
| 1325 | 1318 | |
| 1326 | − clk_disable_unprepare(core->core1_clk); | |
| 1319 | + if (pm_ops->venc_power) | |
| 1320 | + ret = pm_ops->venc_power(dev, POWER_OFF); | |
| 1327 | 1321 | |
| 1328 | − return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false); | |
| 1322 | + return ret; | |
| 1329 | 1323 | } |
| 1330 | 1324 | |
| 1331 | 1325 | static __maybe_unused int venc_runtime_resume(struct device *dev) |
| 1332 | 1326 | { |
| 1333 | 1327 | struct venus_core *core = dev_get_drvdata(dev); |
| 1334 | − int ret; | |
| 1335 | − | |
| 1336 | − if (IS_V1(core)) | |
| 1337 | − return 0; | |
| 1338 | − | |
| 1339 | − ret = venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, true); | |
| 1340 | − if (ret) | |
| 1341 | − return ret; | |
| 1342 | − | |
| 1343 | − ret = clk_prepare_enable(core->core1_clk); | |
| 1344 | − if (ret) | |
| 1345 | − goto err_power_disable; | |
| 1346 | − | |
| 1347 | − if (IS_V4(core)) | |
| 1348 | − ret = clk_prepare_enable(core->core1_bus_clk); | |
| 1349 | − | |
| 1350 | − if (ret) | |
| 1351 | − goto err_unprepare_core1; | |
| 1328 | + const struct venus_pm_ops *pm_ops = core->pm_ops; | |
| 1329 | + int ret = 0; | |
| 1352 | 1330 | |
| 1353 | − return venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false); | |
| 1331 | + if (pm_ops->venc_power) | |
| 1332 | + ret = pm_ops->venc_power(dev, POWER_ON); | |
| 1354 | 1333 | |
| 1355 | −err_unprepare_core1: | |
| 1356 | − clk_disable_unprepare(core->core1_clk); | |
| 1357 | −err_power_disable: | |
| 1358 | − venus_helper_power_enable(core, VIDC_SESSION_TYPE_ENC, false); | |
| 1359 | 1334 | return ret; |
| 1360 | 1335 | } |
| 1361 | 1336 | |
| @@ -199,6 +199,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) · 198 unmodified lines | ||
| 199 | 199 | } |
| 200 | 200 | mutex_unlock(&inst->lock); |
| 201 | 201 | break; |
| 202 | + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: | |
| 203 | + ctr->rc_enable = ctrl->val; | |
| 204 | + break; | |
| 202 | 205 | default: |
| 203 | 206 | return -EINVAL; |
| 204 | 207 | } |
| @@ -214,7 +217,7 @@ int venc_ctrl_init(struct venus_inst *inst) · 9 unmodified lines | ||
| 214 | 217 | { |
| 215 | 218 | int ret; |
| 216 | 219 | |
| 217 | − ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 30); | |
| 220 | + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 31); | |
| 218 | 221 | if (ret) |
| 219 | 222 | return ret; |
| 220 | 223 | |
| @@ -351,6 +354,9 @@ int venc_ctrl_init(struct venus_inst *inst) · 130 unmodified lines | ||
| 351 | 354 | v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, |
| 352 | 355 | V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0); |
| 353 | 356 | |
| 357 | + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, | |
| 358 | + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1); | |
| 359 | + | |
| 354 | 360 | ret = inst->ctrl_handler.error; |
| 355 | 361 | if (ret) |
| 356 | 362 | goto err; |
| @@ -535,7 +535,7 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) · 534 unmodified lines | ||
| 535 | 535 | |
| 536 | 536 | /* Set scaling coefficient */ |
| 537 | 537 | crop_height = vin->crop.height; |
| 538 | − if (V4L2_FIELD_IS_INTERLACED(vin->format.field)) | |
| 538 | + if (V4L2_FIELD_HAS_BOTH(vin->format.field)) | |
| 539 | 539 | crop_height *= 2; |
| 540 | 540 | |
| 541 | 541 | ys = 0; |
| @@ -564,7 +564,7 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) · 22 unmodified lines | ||
| 564 | 564 | rvin_write(vin, 0, VNSLPOC_REG); |
| 565 | 565 | rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); |
| 566 | 566 | |
| 567 | − if (V4L2_FIELD_IS_INTERLACED(vin->format.field)) | |
| 567 | + if (V4L2_FIELD_HAS_BOTH(vin->format.field)) | |
| 568 | 568 | rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); |
| 569 | 569 | else |
| 570 | 570 | rvin_write(vin, vin->format.height - 1, VNELPOC_REG); |
| @@ -626,6 +626,8 @@ static int rvin_setup(struct rvin_dev *vin) · 55 unmodified lines | ||
| 626 | 626 | case V4L2_FIELD_INTERLACED_BT: |
| 627 | 627 | vnmc = VNMC_IM_FULL | VNMC_FOC; |
| 628 | 628 | break; |
| 629 | + case V4L2_FIELD_SEQ_TB: | |
| 630 | + case V4L2_FIELD_SEQ_BT: | |
| 629 | 631 | case V4L2_FIELD_NONE: |
| 630 | 632 | vnmc = VNMC_IM_ODD_EVEN; |
| 631 | 633 | progressive = true; |
| @@ -842,27 +844,52 @@ static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) · 210 unmodified lines | ||
| 842 | 844 | struct rvin_buffer *buf; |
| 843 | 845 | struct vb2_v4l2_buffer *vbuf; |
| 844 | 846 | dma_addr_t phys_addr; |
| 847 | + int prev; | |
| 845 | 848 | |
| 846 | 849 | /* A already populated slot shall never be overwritten. */ |
| 847 | − if (WARN_ON(vin->queue_buf[slot] != NULL)) | |
| 850 | + if (WARN_ON(vin->buf_hw[slot].buffer)) | |
| 848 | 851 | return; |
| 849 | 852 | |
| 850 | − vin_dbg(vin, "Filling HW slot: %d\n", slot); | |
| 851 | − | |
| 852 | − if (list_empty(&vin->buf_list)) { | |
| 853 | − vin->queue_buf[slot] = NULL; | |
| 853 | + prev = (slot == 0 ? HW_BUFFER_NUM : slot) - 1; | |
| 854 | + | |
| 855 | + if (vin->buf_hw[prev].type == HALF_TOP) { | |
| 856 | + vbuf = vin->buf_hw[prev].buffer; | |
| 857 | + vin->buf_hw[slot].buffer = vbuf; | |
| 858 | + vin->buf_hw[slot].type = HALF_BOTTOM; | |
| 859 | + switch (vin->format.pixelformat) { | |
| 860 | + case V4L2_PIX_FMT_NV12: | |
| 861 | + case V4L2_PIX_FMT_NV16: | |
| 862 | + phys_addr = vin->buf_hw[prev].phys + | |
| 863 | + vin->format.sizeimage / 4; | |
| 864 | + break; | |
| 865 | + default: | |
| 866 | + phys_addr = vin->buf_hw[prev].phys + | |
| 867 | + vin->format.sizeimage / 2; | |
| 868 | + break; | |
| 869 | + } | |
| 870 | + } else if (list_empty(&vin->buf_list)) { | |
| 871 | + vin->buf_hw[slot].buffer = NULL; | |
| 872 | + vin->buf_hw[slot].type = FULL; | |
| 854 | 873 | phys_addr = vin->scratch_phys; |
| 855 | 874 | } else { |
| 856 | 875 | /* Keep track of buffer we give to HW */ |
| 857 | 876 | buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); |
| 858 | 877 | vbuf = &buf->vb; |
| 859 | 878 | list_del_init(to_buf_list(vbuf)); |
| 860 | − vin->queue_buf[slot] = vbuf; | |
| 879 | + vin->buf_hw[slot].buffer = vbuf; | |
| 880 | + | |
| 881 | + vin->buf_hw[slot].type = | |
| 882 | + V4L2_FIELD_IS_SEQUENTIAL(vin->format.field) ? | |
| 883 | + HALF_TOP : FULL; | |
| 861 | 884 | |
| 862 | 885 | /* Setup DMA */ |
| 863 | 886 | phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); |
| 864 | 887 | } |
| 865 | 888 | |
| 889 | + vin_dbg(vin, "Filling HW slot: %d type: %d buffer: %p\n", | |
| 890 | + slot, vin->buf_hw[slot].type, vin->buf_hw[slot].buffer); | |
| 891 | + | |
| 892 | + vin->buf_hw[slot].phys = phys_addr; | |
| 866 | 893 | rvin_set_slot_addr(vin, slot, phys_addr); |
| 867 | 894 | } |
| 868 | 895 | |
| @@ -870,6 +897,11 @@ static int rvin_capture_start(struct rvin_dev *vin) · 1 unmodified line | ||
| 870 | 897 | { |
| 871 | 898 | int slot, ret; |
| 872 | 899 | |
| 900 | + for (slot = 0; slot < HW_BUFFER_NUM; slot++) { | |
| 901 | + vin->buf_hw[slot].buffer = NULL; | |
| 902 | + vin->buf_hw[slot].type = FULL; | |
| 903 | + } | |
| 904 | + | |
| 873 | 905 | for (slot = 0; slot < HW_BUFFER_NUM; slot++) |
| 874 | 906 | rvin_fill_hw_slot(vin, slot); |
| 875 | 907 | |
| @@ -953,13 +985,24 @@ static irqreturn_t rvin_irq(int irq, void *data) · 77 unmodified lines | ||
| 953 | 985 | } |
| 954 | 986 | |
| 955 | 987 | /* Capture frame */ |
| 956 | − if (vin->queue_buf[slot]) { | |
| 957 | − vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); | |
| 958 | − vin->queue_buf[slot]->sequence = vin->sequence; | |
| 959 | − vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); | |
| 960 | − vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, | |
| 988 | + if (vin->buf_hw[slot].buffer) { | |
| 989 | + /* | |
| 990 | + * Nothing to do but refill the hardware slot if | |
| 991 | + * capture only filled first half of vb2 buffer. | |
| 992 | + */ | |
| 993 | + if (vin->buf_hw[slot].type == HALF_TOP) { | |
| 994 | + vin->buf_hw[slot].buffer = NULL; | |
| 995 | + rvin_fill_hw_slot(vin, slot); | |
| 996 | + goto done; | |
| 997 | + } | |
| 998 | + | |
| 999 | + vin->buf_hw[slot].buffer->field = | |
| 1000 | + rvin_get_active_field(vin, vnms); | |
| 1001 | + vin->buf_hw[slot].buffer->sequence = vin->sequence; | |
| 1002 | + vin->buf_hw[slot].buffer->vb2_buf.timestamp = ktime_get_ns(); | |
| 1003 | + vb2_buffer_done(&vin->buf_hw[slot].buffer->vb2_buf, | |
| 961 | 1004 | VB2_BUF_STATE_DONE); |
| 962 | − vin->queue_buf[slot] = NULL; | |
| 1005 | + vin->buf_hw[slot].buffer = NULL; | |
| 963 | 1006 | } else { |
| 964 | 1007 | /* Scratch buffer was used, dropping frame. */ |
| 965 | 1008 | vin_dbg(vin, "Dropping frame %u\n", vin->sequence); |
| @@ -980,14 +1023,22 @@ static void return_all_buffers(struct rvin_dev *vin, · 14 unmodified lines | ||
| 980 | 1023 | enum vb2_buffer_state state) |
| 981 | 1024 | { |
| 982 | 1025 | struct rvin_buffer *buf, *node; |
| 983 | − int i; | |
| 1026 | + struct vb2_v4l2_buffer *freed[HW_BUFFER_NUM]; | |
| 1027 | + unsigned int i, n; | |
| 984 | 1028 | |
| 985 | 1029 | for (i = 0; i < HW_BUFFER_NUM; i++) { |
| 986 | − if (vin->queue_buf[i]) { | |
| 987 | − vb2_buffer_done(&vin->queue_buf[i]->vb2_buf, | |
| 988 | − state); | |
| 989 | − vin->queue_buf[i] = NULL; | |
| 1030 | + freed[i] = vin->buf_hw[i].buffer; | |
| 1031 | + vin->buf_hw[i].buffer = NULL; | |
| 1032 | + | |
| 1033 | + for (n = 0; n < i; n++) { | |
| 1034 | + if (freed[i] == freed[n]) { | |
| 1035 | + freed[i] = NULL; | |
| 1036 | + break; | |
| 1037 | + } | |
| 990 | 1038 | } |
| 1039 | + | |
| 1040 | + if (freed[i]) | |
| 1041 | + vb2_buffer_done(&freed[i]->vb2_buf, state); | |
| 991 | 1042 | } |
| 992 | 1043 | |
| 993 | 1044 | list_for_each_entry_safe(buf, node, &vin->buf_list, list) { |
| @@ -1291,7 +1342,7 @@ int rvin_dma_register(struct rvin_dev *vin, int irq) · 297 unmodified lines | ||
| 1291 | 1342 | vin->state = STOPPED; |
| 1292 | 1343 | |
| 1293 | 1344 | for (i = 0; i < HW_BUFFER_NUM; i++) |
| 1294 | − vin->queue_buf[i] = NULL; | |
| 1345 | + vin->buf_hw[i].buffer = NULL; | |
| 1295 | 1346 | |
| 1296 | 1347 | /* buffer queue */ |
| 1297 | 1348 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| @@ -73,11 +73,22 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, · 72 unmodified lines | ||
| 73 | 73 | { |
| 74 | 74 | int i; |
| 75 | 75 | |
| 76 | − if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32) | |
| 77 | − return NULL; | |
| 78 | − | |
| 79 | − if (pixelformat == V4L2_PIX_FMT_NV12 && !vin->info->nv12) | |
| 80 | − return NULL; | |
| 76 | + switch (pixelformat) { | |
| 77 | + case V4L2_PIX_FMT_XBGR32: | |
| 78 | + if (vin->info->model == RCAR_M1) | |
| 79 | + return NULL; | |
| 80 | + break; | |
| 81 | + case V4L2_PIX_FMT_NV12: | |
| 82 | + /* | |
| 83 | + * If NV12 is supported it's only supported on channels 0, 1, 4, | |
| 84 | + * 5, 8, 9, 12 and 13. | |
| 85 | + */ | |
| 86 | + if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333)) | |
| 87 | + return NULL; | |
| 88 | + break; | |
| 89 | + default: | |
| 90 | + break; | |
| 91 | + } | |
| 81 | 92 | |
| 82 | 93 | for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) |
| 83 | 94 | if (rvin_formats[i].fourcc == pixelformat) |
| @@ -107,6 +118,9 @@ static u32 rvin_format_bytesperline(struct rvin_dev *vin, · 23 unmodified lines | ||
| 107 | 118 | break; |
| 108 | 119 | } |
| 109 | 120 | |
| 121 | + if (V4L2_FIELD_IS_SEQUENTIAL(pix->field)) | |
| 122 | + align = 0x80; | |
| 123 | + | |
| 110 | 124 | return ALIGN(pix->width, align) * fmt->bpp; |
| 111 | 125 | } |
| 112 | 126 | |
| @@ -137,6 +151,8 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) · 24 unmodified lines | ||
| 137 | 151 | case V4L2_FIELD_INTERLACED_BT: |
| 138 | 152 | case V4L2_FIELD_INTERLACED: |
| 139 | 153 | case V4L2_FIELD_ALTERNATE: |
| 154 | + case V4L2_FIELD_SEQ_TB: | |
| 155 | + case V4L2_FIELD_SEQ_BT: | |
| 140 | 156 | break; |
| 141 | 157 | default: |
| 142 | 158 | pix->field = RVIN_DEFAULT_FIELD; |
| @@ -826,7 +842,7 @@ static int rvin_open(struct file *file) · 683 unmodified lines | ||
| 826 | 842 | goto err_unlock; |
| 827 | 843 | |
| 828 | 844 | if (vin->info->use_mc) |
| 829 | − ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); | |
| 845 | + ret = v4l2_pipeline_pm_get(&vin->vdev.entity); | |
| 830 | 846 | else if (v4l2_fh_is_singular_file(file)) |
| 831 | 847 | ret = rvin_power_parallel(vin, true); |
| 832 | 848 | |
| @@ -842,7 +858,7 @@ static int rvin_open(struct file *file) · 9 unmodified lines | ||
| 842 | 858 | return 0; |
| 843 | 859 | err_power: |
| 844 | 860 | if (vin->info->use_mc) |
| 845 | − v4l2_pipeline_pm_use(&vin->vdev.entity, 0); | |
| 861 | + v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 846 | 862 | else if (v4l2_fh_is_singular_file(file)) |
| 847 | 863 | rvin_power_parallel(vin, false); |
| 848 | 864 | err_open: |
| @@ -870,7 +886,7 @@ static int rvin_release(struct file *file) · 21 unmodified lines | ||
| 870 | 886 | ret = _vb2_fop_release(file, NULL); |
| 871 | 887 | |
| 872 | 888 | if (vin->info->use_mc) { |
| 873 | − v4l2_pipeline_pm_use(&vin->vdev.entity, 0); | |
| 889 | + v4l2_pipeline_pm_put(&vin->vdev.entity); | |
| 874 | 890 | } else { |
| 875 | 891 | if (fh_singular) |
| 876 | 892 | rvin_power_parallel(vin, false); |
| @@ -953,7 +969,7 @@ int rvin_v4l2_register(struct rvin_dev *vin) · 76 unmodified lines | ||
| 953 | 969 | |
| 954 | 970 | rvin_format_align(vin, &vin->format); |
| 955 | 971 | |
| 956 | − ret = video_register_device(&vin->vdev, VFL_TYPE_GRABBER, -1); | |
| 972 | + ret = video_register_device(&vin->vdev, VFL_TYPE_VIDEO, -1); | |
| 957 | 973 | if (ret) { |
| 958 | 974 | vin_err(vin, "Failed to register video device\n"); |
| 959 | 975 | return ret; |
| @@ -60,6 +60,23 @@ enum rvin_dma_state { · 59 unmodified lines | ||
| 60 | 60 | STOPPING, |
| 61 | 61 | }; |
| 62 | 62 | |
| 63 | +/** | |
| 64 | + * enum rvin_buffer_type | |
| 65 | + * | |
| 66 | + * Describes how a buffer is given to the hardware. To be able | |
| 67 | + * to capture SEQ_TB/BT it's needed to capture to the same vb2 | |
| 68 | + * buffer twice so the type of buffer needs to be kept. | |
| 69 | + * | |
| 70 | + * FULL - One capture fills the whole vb2 buffer | |
| 71 | + * HALF_TOP - One capture fills the top half of the vb2 buffer | |
| 72 | + * HALF_BOTTOM - One capture fills the bottom half of the vb2 buffer | |
| 73 | + */ | |
| 74 | +enum rvin_buffer_type { | |
| 75 | + FULL, | |
| 76 | + HALF_TOP, | |
| 77 | + HALF_BOTTOM, | |
| 78 | +}; | |
| 79 | + | |
| 63 | 80 | /** |
| 64 | 81 | * struct rvin_video_format - Data format stored in memory |
| 65 | 82 | * @fourcc: Pixelformat |
| @@ -164,9 +181,8 @@ struct rvin_info { · 98 unmodified lines | ||
| 164 | 181 | * @scratch: cpu address for scratch buffer |
| 165 | 182 | * @scratch_phys: physical address of the scratch buffer |
| 166 | 183 | * |
| 167 | − * @qlock: protects @queue_buf, @buf_list, @sequence | |
| 168 | − * @state | |
| 169 | − * @queue_buf: Keeps track of buffers given to HW slot | |
| 184 | + * @qlock: protects @buf_hw, @buf_list, @sequence and @state | |
| 185 | + * @buf_hw: Keeps track of buffers given to HW slot | |
| 170 | 186 | * @buf_list: list of queued buffers |
| 171 | 187 | * @sequence: V4L2 buffers sequence number |
| 172 | 188 | * @state: keeps track of operation state |
| @@ -205,7 +221,11 @@ struct rvin_dev { · 32 unmodified lines | ||
| 205 | 221 | dma_addr_t scratch_phys; |
| 206 | 222 | |
| 207 | 223 | spinlock_t qlock; |
| 208 | − struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; | |
| 224 | + struct { | |
| 225 | + struct vb2_v4l2_buffer *buffer; | |
| 226 | + enum rvin_buffer_type type; | |
| 227 | + dma_addr_t phys; | |
| 228 | + } buf_hw[HW_BUFFER_NUM]; | |
| 209 | 229 | struct list_head buf_list; |
| 210 | 230 | unsigned int sequence; |
| 211 | 231 | enum rvin_dma_state state; |
| @@ -275,10 +275,14 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) · 274 unmodified lines | ||
| 275 | 275 | for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { |
| 276 | 276 | struct rcar_drif *ch = sdr->ch[i]; |
| 277 | 277 | |
| 278 | − ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx"); | |
| 279 | − if (!ch->dmach) { | |
| 280 | − rdrif_err(sdr, "ch%u: dma channel req failed\n", i); | |
| 281 | − ret = -ENODEV; | |
| 278 | + ch->dmach = dma_request_chan(&ch->pdev->dev, "rx"); | |
| 279 | + if (IS_ERR(ch->dmach)) { | |
| 280 | + ret = PTR_ERR(ch->dmach); | |
| 281 | + if (ret != -EPROBE_DEFER) | |
| 282 | + rdrif_err(sdr, | |
| 283 | + "ch%u: dma channel req failed: %pe\n", | |
| 284 | + i, ch->dmach); | |
| 285 | + ch->dmach = NULL; | |
| 282 | 286 | goto dmach_error; |
| 283 | 287 | } |
| 284 | 288 | |
| @@ -2344,7 +2344,7 @@ static int fdp1_probe(struct platform_device *pdev) · 2343 unmodified lines | ||
| 2344 | 2344 | video_set_drvdata(vfd, fdp1); |
| 2345 | 2345 | strscpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name)); |
| 2346 | 2346 | |
| 2347 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 2347 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 2348 | 2348 | if (ret) { |
| 2349 | 2349 | v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n"); |
| 2350 | 2350 | goto release_m2m; |
| @@ -1663,7 +1663,7 @@ static int jpu_probe(struct platform_device *pdev) · 1662 unmodified lines | ||
| 1663 | 1663 | jpu->vfd_encoder.device_caps = V4L2_CAP_STREAMING | |
| 1664 | 1664 | V4L2_CAP_VIDEO_M2M_MPLANE; |
| 1665 | 1665 | |
| 1666 | − ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_GRABBER, -1); | |
| 1666 | + ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_VIDEO, -1); | |
| 1667 | 1667 | if (ret) { |
| 1668 | 1668 | v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n"); |
| 1669 | 1669 | goto m2m_init_rollback; |
| @@ -1682,7 +1682,7 @@ static int jpu_probe(struct platform_device *pdev) · 12 unmodified lines | ||
| 1682 | 1682 | jpu->vfd_decoder.device_caps = V4L2_CAP_STREAMING | |
| 1683 | 1683 | V4L2_CAP_VIDEO_M2M_MPLANE; |
| 1684 | 1684 | |
| 1685 | − ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_GRABBER, -1); | |
| 1685 | + ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_VIDEO, -1); | |
| 1686 | 1686 | if (ret) { |
| 1687 | 1687 | v4l2_err(&jpu->v4l2_dev, "Failed to register video device\n"); |
| 1688 | 1688 | goto enc_vdev_register_rollback; |
| @@ -1450,7 +1450,7 @@ static int ceu_notify_complete(struct v4l2_async_notifier *notifier) · 1449 unmodified lines | ||
| 1450 | 1450 | V4L2_CAP_STREAMING; |
| 1451 | 1451 | video_set_drvdata(vdev, ceudev); |
| 1452 | 1452 | |
| 1453 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1453 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1454 | 1454 | if (ret < 0) { |
| 1455 | 1455 | v4l2_err(vdev->v4l2_dev, |
| 1456 | 1456 | "video_register_device failed: %d\n", ret); |
| @@ -889,7 +889,7 @@ static int rga_probe(struct platform_device *pdev) · 888 unmodified lines | ||
| 889 | 889 | def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; |
| 890 | 890 | def_frame.size = def_frame.stride * def_frame.height; |
| 891 | 891 | |
| 892 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 892 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 893 | 893 | if (ret) { |
| 894 | 894 | v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); |
| 895 | 895 | goto rel_vdev; |
| @@ -1158,7 +1158,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) · 1157 unmodified lines | ||
| 1158 | 1158 | vfd->ctrl_handler = &vp->ctrl_handler; |
| 1159 | 1159 | vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; |
| 1160 | 1160 | |
| 1161 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 1161 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 1162 | 1162 | if (ret) |
| 1163 | 1163 | goto err_ctrlh_free; |
| 1164 | 1164 | |
| @@ -695,7 +695,7 @@ static int g2d_probe(struct platform_device *pdev) · 694 unmodified lines | ||
| 695 | 695 | vfd->lock = &dev->mutex; |
| 696 | 696 | vfd->v4l2_dev = &dev->v4l2_dev; |
| 697 | 697 | vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; |
| 698 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 698 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 699 | 699 | if (ret) { |
| 700 | 700 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 701 | 701 | goto rel_vdev; |
| @@ -2946,7 +2946,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) · 2945 unmodified lines | ||
| 2946 | 2946 | jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M; |
| 2947 | 2947 | jpeg->vfd_encoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; |
| 2948 | 2948 | |
| 2949 | − ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1); | |
| 2949 | + ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_VIDEO, -1); | |
| 2950 | 2950 | if (ret) { |
| 2951 | 2951 | v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); |
| 2952 | 2952 | video_device_release(jpeg->vfd_encoder); |
| @@ -2976,7 +2976,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev) · 23 unmodified lines | ||
| 2976 | 2976 | jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M; |
| 2977 | 2977 | jpeg->vfd_decoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M; |
| 2978 | 2978 | |
| 2979 | − ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1); | |
| 2979 | + ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_VIDEO, -1); | |
| 2980 | 2980 | if (ret) { |
| 2981 | 2981 | v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n"); |
| 2982 | 2982 | video_device_release(jpeg->vfd_decoder); |
| @@ -1376,7 +1376,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) · 1375 unmodified lines | ||
| 1376 | 1376 | s5p_mfc_init_regs(dev); |
| 1377 | 1377 | |
| 1378 | 1378 | /* Register decoder and encoder */ |
| 1379 | − ret = video_register_device(dev->vfd_dec, VFL_TYPE_GRABBER, 0); | |
| 1379 | + ret = video_register_device(dev->vfd_dec, VFL_TYPE_VIDEO, 0); | |
| 1380 | 1380 | if (ret) { |
| 1381 | 1381 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 1382 | 1382 | goto err_dec_reg; |
| @@ -1384,7 +1384,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) · 1 unmodified line | ||
| 1384 | 1384 | v4l2_info(&dev->v4l2_dev, |
| 1385 | 1385 | "decoder registered as /dev/video%d\n", dev->vfd_dec->num); |
| 1386 | 1386 | |
| 1387 | − ret = video_register_device(dev->vfd_enc, VFL_TYPE_GRABBER, 0); | |
| 1387 | + ret = video_register_device(dev->vfd_enc, VFL_TYPE_VIDEO, 0); | |
| 1388 | 1388 | if (ret) { |
| 1389 | 1389 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 1390 | 1390 | goto err_enc_reg; |
| @@ -1160,7 +1160,7 @@ static int sh_veu_probe(struct platform_device *pdev) · 1159 unmodified lines | ||
| 1160 | 1160 | pm_runtime_enable(&pdev->dev); |
| 1161 | 1161 | pm_runtime_resume(&pdev->dev); |
| 1162 | 1162 | |
| 1163 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1163 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1164 | 1164 | pm_runtime_suspend(&pdev->dev); |
| 1165 | 1165 | if (ret < 0) |
| 1166 | 1166 | goto evidreg; |
| @@ -1323,7 +1323,7 @@ static int sh_vou_probe(struct platform_device *pdev) · 1322 unmodified lines | ||
| 1323 | 1323 | goto ei2cnd; |
| 1324 | 1324 | } |
| 1325 | 1325 | |
| 1326 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1326 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1327 | 1327 | if (ret < 0) |
| 1328 | 1328 | goto evregdev; |
| 1329 | 1329 | |
| @@ -1066,7 +1066,7 @@ static int bdisp_register_device(struct bdisp_dev *bdisp) · 1065 unmodified lines | ||
| 1066 | 1066 | return PTR_ERR(bdisp->m2m.m2m_dev); |
| 1067 | 1067 | } |
| 1068 | 1068 | |
| 1069 | − ret = video_register_device(&bdisp->vdev, VFL_TYPE_GRABBER, -1); | |
| 1069 | + ret = video_register_device(&bdisp->vdev, VFL_TYPE_VIDEO, -1); | |
| 1070 | 1070 | if (ret) { |
| 1071 | 1071 | dev_err(bdisp->dev, |
| 1072 | 1072 | "%s(): failed to register video device\n", __func__); |
| @@ -1781,7 +1781,7 @@ static int delta_register_device(struct delta_dev *delta) · 1780 unmodified lines | ||
| 1781 | 1781 | snprintf(vdev->name, sizeof(vdev->name), "%s-%s", |
| 1782 | 1782 | DELTA_NAME, DELTA_FW_VERSION); |
| 1783 | 1783 | |
| 1784 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1784 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1785 | 1785 | if (ret) { |
| 1786 | 1786 | dev_err(delta->dev, "%s failed to register video device\n", |
| 1787 | 1787 | DELTA_PREFIX); |
| @@ -1316,7 +1316,7 @@ static int hva_register_device(struct hva_dev *hva) · 1315 unmodified lines | ||
| 1316 | 1316 | snprintf(vdev->name, sizeof(vdev->name), "%s%lx", HVA_NAME, |
| 1317 | 1317 | hva->ip_version); |
| 1318 | 1318 | |
| 1319 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1319 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1320 | 1320 | if (ret) { |
| 1321 | 1321 | dev_err(dev, "%s failed to register video device\n", |
| 1322 | 1322 | HVA_PREFIX); |
| @@ -291,7 +291,9 @@ static int stm32_cec_probe(struct platform_device *pdev) · 290 unmodified lines | ||
| 291 | 291 | |
| 292 | 292 | cec->clk_cec = devm_clk_get(&pdev->dev, "cec"); |
| 293 | 293 | if (IS_ERR(cec->clk_cec)) { |
| 294 | − dev_err(&pdev->dev, "Cannot get cec clock\n"); | |
| 294 | + if (PTR_ERR(cec->clk_cec) != -EPROBE_DEFER) | |
| 295 | + dev_err(&pdev->dev, "Cannot get cec clock\n"); | |
| 296 | + | |
| 295 | 297 | return PTR_ERR(cec->clk_cec); |
| 296 | 298 | } |
| 297 | 299 | |
| @@ -302,10 +304,14 @@ static int stm32_cec_probe(struct platform_device *pdev) · 4 unmodified lines | ||
| 302 | 304 | } |
| 303 | 305 | |
| 304 | 306 | cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec"); |
| 307 | + if (IS_ERR(cec->clk_hdmi_cec) && | |
| 308 | + PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) | |
| 309 | + return -EPROBE_DEFER; | |
| 310 | + | |
| 305 | 311 | if (!IS_ERR(cec->clk_hdmi_cec)) { |
| 306 | 312 | ret = clk_prepare(cec->clk_hdmi_cec); |
| 307 | 313 | if (ret) { |
| 308 | − dev_err(&pdev->dev, "Unable to prepare hdmi-cec clock\n"); | |
| 314 | + dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n"); | |
| 309 | 315 | return ret; |
| 310 | 316 | } |
| 311 | 317 | } |
| @@ -1910,10 +1910,13 @@ static int dcmi_probe(struct platform_device *pdev) · 1909 unmodified lines | ||
| 1910 | 1910 | return PTR_ERR(mclk); |
| 1911 | 1911 | } |
| 1912 | 1912 | |
| 1913 | − chan = dma_request_slave_channel(&pdev->dev, "tx"); | |
| 1914 | − if (!chan) { | |
| 1915 | − dev_info(&pdev->dev, "Unable to request DMA channel, defer probing\n"); | |
| 1916 | − return -EPROBE_DEFER; | |
| 1913 | + chan = dma_request_chan(&pdev->dev, "tx"); | |
| 1914 | + if (IS_ERR(chan)) { | |
| 1915 | + ret = PTR_ERR(chan); | |
| 1916 | + if (ret != -EPROBE_DEFER) | |
| 1917 | + dev_err(&pdev->dev, | |
| 1918 | + "Failed to request DMA channel: %d\n", ret); | |
| 1919 | + return ret; | |
| 1917 | 1920 | } |
| 1918 | 1921 | |
| 1919 | 1922 | spin_lock_init(&dcmi->irqlock); |
| @@ -1971,7 +1974,7 @@ static int dcmi_probe(struct platform_device *pdev) · 51 unmodified lines | ||
| 1971 | 1974 | } |
| 1972 | 1975 | dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; |
| 1973 | 1976 | |
| 1974 | − ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); | |
| 1977 | + ret = video_register_device(dcmi->vdev, VFL_TYPE_VIDEO, -1); | |
| 1975 | 1978 | if (ret) { |
| 1976 | 1979 | dev_err(dcmi->dev, "Failed to register video device\n"); |
| 1977 | 1980 | goto err_media_entity_cleanup; |
| @@ -1,3 +1,4 @@ | ||
| 1 | 1 | obj-y += sun4i-csi/ |
| 2 | 2 | obj-y += sun6i-csi/ |
| 3 | 3 | obj-y += sun8i-di/ |
| 4 | +obj-y += sun8i-rotate/ | |
| @@ -214,7 +214,7 @@ static int sun4i_csi_open(struct file *file) · 213 unmodified lines | ||
| 214 | 214 | if (ret < 0) |
| 215 | 215 | goto err_pm_put; |
| 216 | 216 | |
| 217 | − ret = v4l2_pipeline_pm_use(&csi->vdev.entity, 1); | |
| 217 | + ret = v4l2_pipeline_pm_get(&csi->vdev.entity); | |
| 218 | 218 | if (ret) |
| 219 | 219 | goto err_pm_put; |
| 220 | 220 | |
| @@ -227,7 +227,7 @@ static int sun4i_csi_open(struct file *file) · 6 unmodified lines | ||
| 227 | 227 | return 0; |
| 228 | 228 | |
| 229 | 229 | err_pipeline_pm_put: |
| 230 | − v4l2_pipeline_pm_use(&csi->vdev.entity, 0); | |
| 230 | + v4l2_pipeline_pm_put(&csi->vdev.entity); | |
| 231 | 231 | |
| 232 | 232 | err_pm_put: |
| 233 | 233 | pm_runtime_put(csi->dev); |
| @@ -243,7 +243,7 @@ static int sun4i_csi_release(struct file *file) · 9 unmodified lines | ||
| 243 | 243 | mutex_lock(&csi->lock); |
| 244 | 244 | |
| 245 | 245 | v4l2_fh_release(file); |
| 246 | − v4l2_pipeline_pm_use(&csi->vdev.entity, 0); | |
| 246 | + v4l2_pipeline_pm_put(&csi->vdev.entity); | |
| 247 | 247 | pm_runtime_put(csi->dev); |
| 248 | 248 | |
| 249 | 249 | mutex_unlock(&csi->lock); |
| @@ -374,7 +374,7 @@ int sun4i_csi_v4l2_register(struct sun4i_csi *csi) · 124 unmodified lines | ||
| 374 | 374 | vdev->ioctl_ops = &sun4i_csi_ioctl_ops; |
| 375 | 375 | video_set_drvdata(vdev, csi); |
| 376 | 376 | |
| 377 | − ret = video_register_device(&csi->vdev, VFL_TYPE_GRABBER, -1); | |
| 377 | + ret = video_register_device(&csi->vdev, VFL_TYPE_VIDEO, -1); | |
| 378 | 378 | if (ret) |
| 379 | 379 | return ret; |
| 380 | 380 | |
| @@ -474,7 +474,7 @@ static int sun6i_video_open(struct file *file) · 473 unmodified lines | ||
| 474 | 474 | if (ret < 0) |
| 475 | 475 | goto unlock; |
| 476 | 476 | |
| 477 | − ret = v4l2_pipeline_pm_use(&video->vdev.entity, 1); | |
| 477 | + ret = v4l2_pipeline_pm_get(&video->vdev.entity); | |
| 478 | 478 | if (ret < 0) |
| 479 | 479 | goto fh_release; |
| 480 | 480 | |
| @@ -507,7 +507,7 @@ static int sun6i_video_close(struct file *file) · 26 unmodified lines | ||
| 507 | 507 | |
| 508 | 508 | _vb2_fop_release(file, NULL); |
| 509 | 509 | |
| 510 | − v4l2_pipeline_pm_use(&video->vdev.entity, 0); | |
| 510 | + v4l2_pipeline_pm_put(&video->vdev.entity); | |
| 511 | 511 | |
| 512 | 512 | if (last_fh) |
| 513 | 513 | sun6i_csi_set_power(video->csi, false); |
| @@ -648,7 +648,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, · 134 unmodified lines | ||
| 648 | 648 | vdev->release = video_device_release_empty; |
| 649 | 649 | vdev->fops = &sun6i_video_fops; |
| 650 | 650 | vdev->ioctl_ops = &sun6i_video_ioctl_ops; |
| 651 | − vdev->vfl_type = VFL_TYPE_GRABBER; | |
| 651 | + vdev->vfl_type = VFL_TYPE_VIDEO; | |
| 652 | 652 | vdev->vfl_dir = VFL_DIR_RX; |
| 653 | 653 | vdev->v4l2_dev = &csi->v4l2_dev; |
| 654 | 654 | vdev->queue = vidq; |
| @@ -656,7 +656,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, · 1 unmodified line | ||
| 656 | 656 | vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; |
| 657 | 657 | video_set_drvdata(vdev, video); |
| 658 | 658 | |
| 659 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 659 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 660 | 660 | if (ret < 0) { |
| 661 | 661 | v4l2_err(&csi->v4l2_dev, |
| 662 | 662 | "video_register_device failed: %d\n", ret); |
| @@ -814,11 +814,8 @@ static int deinterlace_probe(struct platform_device *pdev) · 813 unmodified lines | ||
| 814 | 814 | dev->dev = &pdev->dev; |
| 815 | 815 | |
| 816 | 816 | irq = platform_get_irq(pdev, 0); |
| 817 | − if (irq <= 0) { | |
| 818 | − dev_err(dev->dev, "Failed to get IRQ\n"); | |
| 819 | − | |
| 817 | + if (irq <= 0) | |
| 820 | 818 | return irq; |
| 821 | − } | |
| 822 | 819 | |
| 823 | 820 | ret = devm_request_irq(dev->dev, irq, deinterlace_irq, |
| 824 | 821 | 0, dev_name(dev->dev), dev); |
| @@ -882,7 +879,7 @@ static int deinterlace_probe(struct platform_device *pdev) · 57 unmodified lines | ||
| 882 | 879 | deinterlace_video_device.name); |
| 883 | 880 | video_set_drvdata(vfd, dev); |
| 884 | 881 | |
| 885 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 882 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 886 | 883 | if (ret) { |
| 887 | 884 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 888 | 885 | |
| @@ -0,0 +1,5 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +sun8i-rotate-y += sun8i_rotate.o | |
| 3 | +sun8i-rotate-y += sun8i_formats.o | |
| 4 | + | |
| 5 | +obj-$(CONFIG_VIDEO_SUN8I_ROTATE) += sun8i-rotate.o | |
| @@ -0,0 +1,25 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */ | |
| 3 | + | |
| 4 | +#ifndef _SUN8I_FORMATS_H_ | |
| 5 | +#define _SUN8I_FORMATS_H_ | |
| 6 | + | |
| 7 | +#include <linux/videodev2.h> | |
| 8 | + | |
| 9 | +#define ROTATE_FLAG_YUV BIT(0) | |
| 10 | +#define ROTATE_FLAG_OUTPUT BIT(1) | |
| 11 | + | |
| 12 | +struct rotate_format { | |
| 13 | + u32 fourcc; | |
| 14 | + u32 hw_format; | |
| 15 | + int planes; | |
| 16 | + int bpp[3]; | |
| 17 | + int hsub; | |
| 18 | + int vsub; | |
| 19 | + unsigned int flags; | |
| 20 | +}; | |
| 21 | + | |
| 22 | +const struct rotate_format *rotate_find_format(u32 pixelformat); | |
| 23 | +int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst); | |
| 24 | + | |
| 25 | +#endif | |
| @@ -0,0 +1,135 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Allwinner DE2 rotation driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#ifndef _SUN8I_ROTATE_H_ | |
| 9 | +#define _SUN8I_ROTATE_H_ | |
| 10 | + | |
| 11 | +#include <media/v4l2-ctrls.h> | |
| 12 | +#include <media/v4l2-device.h> | |
| 13 | +#include <media/v4l2-mem2mem.h> | |
| 14 | +#include <media/videobuf2-v4l2.h> | |
| 15 | +#include <media/videobuf2-dma-contig.h> | |
| 16 | + | |
| 17 | +#include <linux/platform_device.h> | |
| 18 | + | |
| 19 | +#define ROTATE_NAME "sun8i-rotate" | |
| 20 | + | |
| 21 | +#define ROTATE_GLB_CTL 0x00 | |
| 22 | +#define ROTATE_GLB_CTL_START BIT(31) | |
| 23 | +#define ROTATE_GLB_CTL_RESET BIT(30) | |
| 24 | +#define ROTATE_GLB_CTL_BURST_LEN(x) ((x) << 16) | |
| 25 | +#define ROTATE_GLB_CTL_HFLIP BIT(7) | |
| 26 | +#define ROTATE_GLB_CTL_VFLIP BIT(6) | |
| 27 | +#define ROTATE_GLB_CTL_ROTATION(x) ((x) << 4) | |
| 28 | +#define ROTATE_GLB_CTL_MODE(x) ((x) << 0) | |
| 29 | + | |
| 30 | +#define ROTATE_INT 0x04 | |
| 31 | +#define ROTATE_INT_FINISH_IRQ_EN BIT(16) | |
| 32 | +#define ROTATE_INT_FINISH_IRQ BIT(0) | |
| 33 | + | |
| 34 | +#define ROTATE_IN_FMT 0x20 | |
| 35 | +#define ROTATE_IN_FMT_FORMAT(x) ((x) << 0) | |
| 36 | + | |
| 37 | +#define ROTATE_IN_SIZE 0x24 | |
| 38 | +#define ROTATE_IN_PITCH0 0x30 | |
| 39 | +#define ROTATE_IN_PITCH1 0x34 | |
| 40 | +#define ROTATE_IN_PITCH2 0x38 | |
| 41 | +#define ROTATE_IN_ADDRL0 0x40 | |
| 42 | +#define ROTATE_IN_ADDRH0 0x44 | |
| 43 | +#define ROTATE_IN_ADDRL1 0x48 | |
| 44 | +#define ROTATE_IN_ADDRH1 0x4c | |
| 45 | +#define ROTATE_IN_ADDRL2 0x50 | |
| 46 | +#define ROTATE_IN_ADDRH2 0x54 | |
| 47 | +#define ROTATE_OUT_SIZE 0x84 | |
| 48 | +#define ROTATE_OUT_PITCH0 0x90 | |
| 49 | +#define ROTATE_OUT_PITCH1 0x94 | |
| 50 | +#define ROTATE_OUT_PITCH2 0x98 | |
| 51 | +#define ROTATE_OUT_ADDRL0 0xA0 | |
| 52 | +#define ROTATE_OUT_ADDRH0 0xA4 | |
| 53 | +#define ROTATE_OUT_ADDRL1 0xA8 | |
| 54 | +#define ROTATE_OUT_ADDRH1 0xAC | |
| 55 | +#define ROTATE_OUT_ADDRL2 0xB0 | |
| 56 | +#define ROTATE_OUT_ADDRH2 0xB4 | |
| 57 | + | |
| 58 | +#define ROTATE_BURST_8 0x07 | |
| 59 | +#define ROTATE_BURST_16 0x0f | |
| 60 | +#define ROTATE_BURST_32 0x1f | |
| 61 | +#define ROTATE_BURST_64 0x3f | |
| 62 | + | |
| 63 | +#define ROTATE_MODE_COPY_ROTATE 0x01 | |
| 64 | + | |
| 65 | +#define ROTATE_FORMAT_ARGB32 0x00 | |
| 66 | +#define ROTATE_FORMAT_ABGR32 0x01 | |
| 67 | +#define ROTATE_FORMAT_RGBA32 0x02 | |
| 68 | +#define ROTATE_FORMAT_BGRA32 0x03 | |
| 69 | +#define ROTATE_FORMAT_XRGB32 0x04 | |
| 70 | +#define ROTATE_FORMAT_XBGR32 0x05 | |
| 71 | +#define ROTATE_FORMAT_RGBX32 0x06 | |
| 72 | +#define ROTATE_FORMAT_BGRX32 0x07 | |
| 73 | +#define ROTATE_FORMAT_RGB24 0x08 | |
| 74 | +#define ROTATE_FORMAT_BGR24 0x09 | |
| 75 | +#define ROTATE_FORMAT_RGB565 0x0a | |
| 76 | +#define ROTATE_FORMAT_BGR565 0x0b | |
| 77 | +#define ROTATE_FORMAT_ARGB4444 0x0c | |
| 78 | +#define ROTATE_FORMAT_ABGR4444 0x0d | |
| 79 | +#define ROTATE_FORMAT_RGBA4444 0x0e | |
| 80 | +#define ROTATE_FORMAT_BGRA4444 0x0f | |
| 81 | +#define ROTATE_FORMAT_ARGB1555 0x10 | |
| 82 | +#define ROTATE_FORMAT_ABGR1555 0x11 | |
| 83 | +#define ROTATE_FORMAT_RGBA5551 0x12 | |
| 84 | +#define ROTATE_FORMAT_BGRA5551 0x13 | |
| 85 | + | |
| 86 | +#define ROTATE_FORMAT_YUYV 0x20 | |
| 87 | +#define ROTATE_FORMAT_UYVY 0x21 | |
| 88 | +#define ROTATE_FORMAT_YVYU 0x22 | |
| 89 | +#define ROTATE_FORMAT_VYUV 0x23 | |
| 90 | +#define ROTATE_FORMAT_NV61 0x24 | |
| 91 | +#define ROTATE_FORMAT_NV16 0x25 | |
| 92 | +#define ROTATE_FORMAT_YUV422P 0x26 | |
| 93 | +#define ROTATE_FORMAT_NV21 0x28 | |
| 94 | +#define ROTATE_FORMAT_NV12 0x29 | |
| 95 | +#define ROTATE_FORMAT_YUV420P 0x2A | |
| 96 | + | |
| 97 | +#define ROTATE_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) | |
| 98 | + | |
| 99 | +#define ROTATE_MIN_WIDTH 8U | |
| 100 | +#define ROTATE_MIN_HEIGHT 8U | |
| 101 | +#define ROTATE_MAX_WIDTH 4096U | |
| 102 | +#define ROTATE_MAX_HEIGHT 4096U | |
| 103 | + | |
| 104 | +struct rotate_ctx { | |
| 105 | + struct v4l2_fh fh; | |
| 106 | + struct rotate_dev *dev; | |
| 107 | + | |
| 108 | + struct v4l2_pix_format src_fmt; | |
| 109 | + struct v4l2_pix_format dst_fmt; | |
| 110 | + | |
| 111 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 112 | + | |
| 113 | + u32 hflip; | |
| 114 | + u32 vflip; | |
| 115 | + u32 rotate; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +struct rotate_dev { | |
| 119 | + struct v4l2_device v4l2_dev; | |
| 120 | + struct video_device vfd; | |
| 121 | + struct device *dev; | |
| 122 | + struct v4l2_m2m_dev *m2m_dev; | |
| 123 | + | |
| 124 | + /* Device file mutex */ | |
| 125 | + struct mutex dev_mutex; | |
| 126 | + | |
| 127 | + void __iomem *base; | |
| 128 | + | |
| 129 | + struct clk *bus_clk; | |
| 130 | + struct clk *mod_clk; | |
| 131 | + | |
| 132 | + struct reset_control *rstc; | |
| 133 | +}; | |
| 134 | + | |
| 135 | +#endif | |
| @@ -0,0 +1,273 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */ | |
| 3 | + | |
| 4 | +#include "sun8i-formats.h" | |
| 5 | +#include "sun8i-rotate.h" | |
| 6 | + | |
| 7 | +/* | |
| 8 | + * Formats not included in array: | |
| 9 | + * ROTATE_FORMAT_BGR565 | |
| 10 | + * ROTATE_FORMAT_VYUV | |
| 11 | + */ | |
| 12 | + | |
| 13 | +static const struct rotate_format rotate_formats[] = { | |
| 14 | + { | |
| 15 | + .fourcc = V4L2_PIX_FMT_ARGB32, | |
| 16 | + .hw_format = ROTATE_FORMAT_ARGB32, | |
| 17 | + .planes = 1, | |
| 18 | + .bpp = { 4, 0, 0 }, | |
| 19 | + .hsub = 1, | |
| 20 | + .vsub = 1, | |
| 21 | + .flags = ROTATE_FLAG_OUTPUT | |
| 22 | + }, { | |
| 23 | + .fourcc = V4L2_PIX_FMT_ABGR32, | |
| 24 | + .hw_format = ROTATE_FORMAT_ABGR32, | |
| 25 | + .planes = 1, | |
| 26 | + .bpp = { 4, 0, 0 }, | |
| 27 | + .hsub = 1, | |
| 28 | + .vsub = 1, | |
| 29 | + .flags = ROTATE_FLAG_OUTPUT | |
| 30 | + }, { | |
| 31 | + .fourcc = V4L2_PIX_FMT_RGBA32, | |
| 32 | + .hw_format = ROTATE_FORMAT_RGBA32, | |
| 33 | + .planes = 1, | |
| 34 | + .bpp = { 4, 0, 0 }, | |
| 35 | + .hsub = 1, | |
| 36 | + .vsub = 1, | |
| 37 | + .flags = ROTATE_FLAG_OUTPUT | |
| 38 | + }, { | |
| 39 | + .fourcc = V4L2_PIX_FMT_BGRA32, | |
| 40 | + .hw_format = ROTATE_FORMAT_BGRA32, | |
| 41 | + .planes = 1, | |
| 42 | + .bpp = { 4, 0, 0 }, | |
| 43 | + .hsub = 1, | |
| 44 | + .vsub = 1, | |
| 45 | + .flags = ROTATE_FLAG_OUTPUT | |
| 46 | + }, { | |
| 47 | + .fourcc = V4L2_PIX_FMT_XRGB32, | |
| 48 | + .hw_format = ROTATE_FORMAT_XRGB32, | |
| 49 | + .planes = 1, | |
| 50 | + .bpp = { 4, 0, 0 }, | |
| 51 | + .hsub = 1, | |
| 52 | + .vsub = 1, | |
| 53 | + .flags = ROTATE_FLAG_OUTPUT | |
| 54 | + }, { | |
| 55 | + .fourcc = V4L2_PIX_FMT_XBGR32, | |
| 56 | + .hw_format = ROTATE_FORMAT_XBGR32, | |
| 57 | + .planes = 1, | |
| 58 | + .bpp = { 4, 0, 0 }, | |
| 59 | + .hsub = 1, | |
| 60 | + .vsub = 1, | |
| 61 | + .flags = ROTATE_FLAG_OUTPUT | |
| 62 | + }, { | |
| 63 | + .fourcc = V4L2_PIX_FMT_RGB32, | |
| 64 | + .hw_format = ROTATE_FORMAT_RGBX32, | |
| 65 | + .planes = 1, | |
| 66 | + .bpp = { 4, 0, 0 }, | |
| 67 | + .hsub = 1, | |
| 68 | + .vsub = 1, | |
| 69 | + .flags = ROTATE_FLAG_OUTPUT | |
| 70 | + }, { | |
| 71 | + .fourcc = V4L2_PIX_FMT_BGR32, | |
| 72 | + .hw_format = ROTATE_FORMAT_BGRX32, | |
| 73 | + .planes = 1, | |
| 74 | + .bpp = { 4, 0, 0 }, | |
| 75 | + .hsub = 1, | |
| 76 | + .vsub = 1, | |
| 77 | + .flags = ROTATE_FLAG_OUTPUT | |
| 78 | + }, { | |
| 79 | + .fourcc = V4L2_PIX_FMT_RGB24, | |
| 80 | + .hw_format = ROTATE_FORMAT_RGB24, | |
| 81 | + .planes = 1, | |
| 82 | + .bpp = { 3, 0, 0 }, | |
| 83 | + .hsub = 1, | |
| 84 | + .vsub = 1, | |
| 85 | + .flags = ROTATE_FLAG_OUTPUT | |
| 86 | + }, { | |
| 87 | + .fourcc = V4L2_PIX_FMT_BGR24, | |
| 88 | + .hw_format = ROTATE_FORMAT_BGR24, | |
| 89 | + .planes = 1, | |
| 90 | + .bpp = { 3, 0, 0 }, | |
| 91 | + .hsub = 1, | |
| 92 | + .vsub = 1, | |
| 93 | + .flags = ROTATE_FLAG_OUTPUT | |
| 94 | + }, { | |
| 95 | + .fourcc = V4L2_PIX_FMT_RGB565, | |
| 96 | + .hw_format = ROTATE_FORMAT_RGB565, | |
| 97 | + .planes = 1, | |
| 98 | + .bpp = { 2, 0, 0 }, | |
| 99 | + .hsub = 1, | |
| 100 | + .vsub = 1, | |
| 101 | + .flags = ROTATE_FLAG_OUTPUT | |
| 102 | + }, { | |
| 103 | + .fourcc = V4L2_PIX_FMT_ARGB444, | |
| 104 | + .hw_format = ROTATE_FORMAT_ARGB4444, | |
| 105 | + .planes = 1, | |
| 106 | + .bpp = { 2, 0, 0 }, | |
| 107 | + .hsub = 1, | |
| 108 | + .vsub = 1, | |
| 109 | + .flags = ROTATE_FLAG_OUTPUT | |
| 110 | + }, { | |
| 111 | + .fourcc = V4L2_PIX_FMT_ABGR444, | |
| 112 | + .hw_format = ROTATE_FORMAT_ABGR4444, | |
| 113 | + .planes = 1, | |
| 114 | + .bpp = { 2, 0, 0 }, | |
| 115 | + .hsub = 1, | |
| 116 | + .vsub = 1, | |
| 117 | + .flags = ROTATE_FLAG_OUTPUT | |
| 118 | + }, { | |
| 119 | + .fourcc = V4L2_PIX_FMT_RGBA444, | |
| 120 | + .hw_format = ROTATE_FORMAT_RGBA4444, | |
| 121 | + .planes = 1, | |
| 122 | + .bpp = { 2, 0, 0 }, | |
| 123 | + .hsub = 1, | |
| 124 | + .vsub = 1, | |
| 125 | + .flags = ROTATE_FLAG_OUTPUT | |
| 126 | + }, { | |
| 127 | + .fourcc = V4L2_PIX_FMT_BGRA444, | |
| 128 | + .hw_format = ROTATE_FORMAT_BGRA4444, | |
| 129 | + .planes = 1, | |
| 130 | + .bpp = { 2, 0, 0 }, | |
| 131 | + .hsub = 1, | |
| 132 | + .vsub = 1, | |
| 133 | + .flags = ROTATE_FLAG_OUTPUT | |
| 134 | + }, { | |
| 135 | + .fourcc = V4L2_PIX_FMT_ARGB555, | |
| 136 | + .hw_format = ROTATE_FORMAT_ARGB1555, | |
| 137 | + .planes = 1, | |
| 138 | + .bpp = { 2, 0, 0 }, | |
| 139 | + .hsub = 1, | |
| 140 | + .vsub = 1, | |
| 141 | + .flags = ROTATE_FLAG_OUTPUT | |
| 142 | + }, { | |
| 143 | + .fourcc = V4L2_PIX_FMT_ABGR555, | |
| 144 | + .hw_format = ROTATE_FORMAT_ABGR1555, | |
| 145 | + .planes = 1, | |
| 146 | + .bpp = { 2, 0, 0 }, | |
| 147 | + .hsub = 1, | |
| 148 | + .vsub = 1, | |
| 149 | + .flags = ROTATE_FLAG_OUTPUT | |
| 150 | + }, { | |
| 151 | + .fourcc = V4L2_PIX_FMT_RGBA555, | |
| 152 | + .hw_format = ROTATE_FORMAT_RGBA5551, | |
| 153 | + .planes = 1, | |
| 154 | + .bpp = { 2, 0, 0 }, | |
| 155 | + .hsub = 1, | |
| 156 | + .vsub = 1, | |
| 157 | + .flags = ROTATE_FLAG_OUTPUT | |
| 158 | + }, { | |
| 159 | + .fourcc = V4L2_PIX_FMT_BGRA555, | |
| 160 | + .hw_format = ROTATE_FORMAT_BGRA5551, | |
| 161 | + .planes = 1, | |
| 162 | + .bpp = { 2, 0, 0 }, | |
| 163 | + .hsub = 1, | |
| 164 | + .vsub = 1, | |
| 165 | + .flags = ROTATE_FLAG_OUTPUT | |
| 166 | + }, { | |
| 167 | + .fourcc = V4L2_PIX_FMT_YVYU, | |
| 168 | + .hw_format = ROTATE_FORMAT_YVYU, | |
| 169 | + .planes = 1, | |
| 170 | + .bpp = { 2, 0, 0 }, | |
| 171 | + .hsub = 2, | |
| 172 | + .vsub = 1, | |
| 173 | + .flags = ROTATE_FLAG_YUV | |
| 174 | + }, { | |
| 175 | + .fourcc = V4L2_PIX_FMT_UYVY, | |
| 176 | + .hw_format = ROTATE_FORMAT_UYVY, | |
| 177 | + .planes = 1, | |
| 178 | + .bpp = { 2, 0, 0 }, | |
| 179 | + .hsub = 2, | |
| 180 | + .vsub = 1, | |
| 181 | + .flags = ROTATE_FLAG_YUV | |
| 182 | + }, { | |
| 183 | + .fourcc = V4L2_PIX_FMT_YUYV, | |
| 184 | + .hw_format = ROTATE_FORMAT_YUYV, | |
| 185 | + .planes = 1, | |
| 186 | + .bpp = { 2, 0, 0 }, | |
| 187 | + .hsub = 2, | |
| 188 | + .vsub = 1, | |
| 189 | + .flags = ROTATE_FLAG_YUV | |
| 190 | + }, { | |
| 191 | + .fourcc = V4L2_PIX_FMT_NV61, | |
| 192 | + .hw_format = ROTATE_FORMAT_NV61, | |
| 193 | + .planes = 2, | |
| 194 | + .bpp = { 1, 2, 0 }, | |
| 195 | + .hsub = 2, | |
| 196 | + .vsub = 1, | |
| 197 | + .flags = ROTATE_FLAG_YUV | |
| 198 | + }, { | |
| 199 | + .fourcc = V4L2_PIX_FMT_NV16, | |
| 200 | + .hw_format = ROTATE_FORMAT_NV16, | |
| 201 | + .planes = 2, | |
| 202 | + .bpp = { 1, 2, 0 }, | |
| 203 | + .hsub = 2, | |
| 204 | + .vsub = 1, | |
| 205 | + .flags = ROTATE_FLAG_YUV | |
| 206 | + }, { | |
| 207 | + .fourcc = V4L2_PIX_FMT_YUV422P, | |
| 208 | + .hw_format = ROTATE_FORMAT_YUV422P, | |
| 209 | + .planes = 3, | |
| 210 | + .bpp = { 1, 1, 1 }, | |
| 211 | + .hsub = 2, | |
| 212 | + .vsub = 1, | |
| 213 | + .flags = ROTATE_FLAG_YUV | |
| 214 | + }, { | |
| 215 | + .fourcc = V4L2_PIX_FMT_NV21, | |
| 216 | + .hw_format = ROTATE_FORMAT_NV21, | |
| 217 | + .planes = 2, | |
| 218 | + .bpp = { 1, 2, 0 }, | |
| 219 | + .hsub = 2, | |
| 220 | + .vsub = 2, | |
| 221 | + .flags = ROTATE_FLAG_YUV | |
| 222 | + }, { | |
| 223 | + .fourcc = V4L2_PIX_FMT_NV12, | |
| 224 | + .hw_format = ROTATE_FORMAT_NV12, | |
| 225 | + .planes = 2, | |
| 226 | + .bpp = { 1, 2, 0 }, | |
| 227 | + .hsub = 2, | |
| 228 | + .vsub = 2, | |
| 229 | + .flags = ROTATE_FLAG_YUV | |
| 230 | + }, { | |
| 231 | + .fourcc = V4L2_PIX_FMT_YUV420, | |
| 232 | + .hw_format = ROTATE_FORMAT_YUV420P, | |
| 233 | + .planes = 3, | |
| 234 | + .bpp = { 1, 1, 1 }, | |
| 235 | + .hsub = 2, | |
| 236 | + .vsub = 2, | |
| 237 | + .flags = ROTATE_FLAG_YUV | ROTATE_FLAG_OUTPUT | |
| 238 | + }, | |
| 239 | +}; | |
| 240 | + | |
| 241 | +const struct rotate_format *rotate_find_format(u32 pixelformat) | |
| 242 | +{ | |
| 243 | + unsigned int i; | |
| 244 | + | |
| 245 | + for (i = 0; i < ARRAY_SIZE(rotate_formats); i++) | |
| 246 | + if (rotate_formats[i].fourcc == pixelformat) | |
| 247 | + return &rotate_formats[i]; | |
| 248 | + | |
| 249 | + return NULL; | |
| 250 | +} | |
| 251 | + | |
| 252 | +int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst) | |
| 253 | +{ | |
| 254 | + int i, index; | |
| 255 | + | |
| 256 | + index = 0; | |
| 257 | + | |
| 258 | + for (i = 0; i < ARRAY_SIZE(rotate_formats); i++) { | |
| 259 | + /* not all formats can be used for capture buffers */ | |
| 260 | + if (dst && !(rotate_formats[i].flags & ROTATE_FLAG_OUTPUT)) | |
| 261 | + continue; | |
| 262 | + | |
| 263 | + if (index == f->index) { | |
| 264 | + f->pixelformat = rotate_formats[i].fourcc; | |
| 265 | + | |
| 266 | + return 0; | |
| 267 | + } | |
| 268 | + | |
| 269 | + index++; | |
| 270 | + } | |
| 271 | + | |
| 272 | + return -EINVAL; | |
| 273 | +} | |
| @@ -0,0 +1,924 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Allwinner sun8i DE2 rotation driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/interrupt.h> | |
| 10 | +#include <linux/io.h> | |
| 11 | +#include <linux/iopoll.h> | |
| 12 | +#include <linux/module.h> | |
| 13 | +#include <linux/of.h> | |
| 14 | +#include <linux/of_device.h> | |
| 15 | +#include <linux/pm_runtime.h> | |
| 16 | +#include <linux/reset.h> | |
| 17 | + | |
| 18 | +#include <media/v4l2-device.h> | |
| 19 | +#include <media/v4l2-event.h> | |
| 20 | +#include <media/v4l2-ioctl.h> | |
| 21 | +#include <media/v4l2-mem2mem.h> | |
| 22 | + | |
| 23 | +#include "sun8i-formats.h" | |
| 24 | +#include "sun8i-rotate.h" | |
| 25 | + | |
| 26 | +static inline u32 rotate_read(struct rotate_dev *dev, u32 reg) | |
| 27 | +{ | |
| 28 | + return readl(dev->base + reg); | |
| 29 | +} | |
| 30 | + | |
| 31 | +static inline void rotate_write(struct rotate_dev *dev, u32 reg, u32 value) | |
| 32 | +{ | |
| 33 | + writel(value, dev->base + reg); | |
| 34 | +} | |
| 35 | + | |
| 36 | +static inline void rotate_set_bits(struct rotate_dev *dev, u32 reg, u32 bits) | |
| 37 | +{ | |
| 38 | + writel(readl(dev->base + reg) | bits, dev->base + reg); | |
| 39 | +} | |
| 40 | + | |
| 41 | +static void rotate_calc_addr_pitch(dma_addr_t buffer, | |
| 42 | + u32 bytesperline, u32 height, | |
| 43 | + const struct rotate_format *fmt, | |
| 44 | + dma_addr_t *addr, u32 *pitch) | |
| 45 | +{ | |
| 46 | + u32 size; | |
| 47 | + int i; | |
| 48 | + | |
| 49 | + for (i = 0; i < fmt->planes; i++) { | |
| 50 | + pitch[i] = bytesperline; | |
| 51 | + addr[i] = buffer; | |
| 52 | + if (i > 0) | |
| 53 | + pitch[i] /= fmt->hsub / fmt->bpp[i]; | |
| 54 | + size = pitch[i] * height; | |
| 55 | + if (i > 0) | |
| 56 | + size /= fmt->vsub; | |
| 57 | + buffer += size; | |
| 58 | + } | |
| 59 | +} | |
| 60 | + | |
| 61 | +static void rotate_device_run(void *priv) | |
| 62 | +{ | |
| 63 | + struct rotate_ctx *ctx = priv; | |
| 64 | + struct rotate_dev *dev = ctx->dev; | |
| 65 | + struct vb2_v4l2_buffer *src, *dst; | |
| 66 | + const struct rotate_format *fmt; | |
| 67 | + dma_addr_t addr[3]; | |
| 68 | + u32 val, pitch[3]; | |
| 69 | + | |
| 70 | + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | |
| 71 | + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | |
| 72 | + | |
| 73 | + v4l2_m2m_buf_copy_metadata(src, dst, true); | |
| 74 | + | |
| 75 | + val = ROTATE_GLB_CTL_MODE(ROTATE_MODE_COPY_ROTATE); | |
| 76 | + if (ctx->hflip) | |
| 77 | + val |= ROTATE_GLB_CTL_HFLIP; | |
| 78 | + if (ctx->vflip) | |
| 79 | + val |= ROTATE_GLB_CTL_VFLIP; | |
| 80 | + val |= ROTATE_GLB_CTL_ROTATION(ctx->rotate / 90); | |
| 81 | + if (ctx->rotate != 90 && ctx->rotate != 270) | |
| 82 | + val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_64); | |
| 83 | + else | |
| 84 | + val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_8); | |
| 85 | + rotate_write(dev, ROTATE_GLB_CTL, val); | |
| 86 | + | |
| 87 | + fmt = rotate_find_format(ctx->src_fmt.pixelformat); | |
| 88 | + if (!fmt) | |
| 89 | + return; | |
| 90 | + | |
| 91 | + rotate_write(dev, ROTATE_IN_FMT, ROTATE_IN_FMT_FORMAT(fmt->hw_format)); | |
| 92 | + | |
| 93 | + rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0), | |
| 94 | + ctx->src_fmt.bytesperline, ctx->src_fmt.height, | |
| 95 | + fmt, addr, pitch); | |
| 96 | + | |
| 97 | + rotate_write(dev, ROTATE_IN_SIZE, | |
| 98 | + ROTATE_SIZE(ctx->src_fmt.width, ctx->src_fmt.height)); | |
| 99 | + | |
| 100 | + rotate_write(dev, ROTATE_IN_PITCH0, pitch[0]); | |
| 101 | + rotate_write(dev, ROTATE_IN_PITCH1, pitch[1]); | |
| 102 | + rotate_write(dev, ROTATE_IN_PITCH2, pitch[2]); | |
| 103 | + | |
| 104 | + rotate_write(dev, ROTATE_IN_ADDRL0, addr[0]); | |
| 105 | + rotate_write(dev, ROTATE_IN_ADDRL1, addr[1]); | |
| 106 | + rotate_write(dev, ROTATE_IN_ADDRL2, addr[2]); | |
| 107 | + | |
| 108 | + rotate_write(dev, ROTATE_IN_ADDRH0, 0); | |
| 109 | + rotate_write(dev, ROTATE_IN_ADDRH1, 0); | |
| 110 | + rotate_write(dev, ROTATE_IN_ADDRH2, 0); | |
| 111 | + | |
| 112 | + fmt = rotate_find_format(ctx->dst_fmt.pixelformat); | |
| 113 | + if (!fmt) | |
| 114 | + return; | |
| 115 | + | |
| 116 | + rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0), | |
| 117 | + ctx->dst_fmt.bytesperline, ctx->dst_fmt.height, | |
| 118 | + fmt, addr, pitch); | |
| 119 | + | |
| 120 | + rotate_write(dev, ROTATE_OUT_SIZE, | |
| 121 | + ROTATE_SIZE(ctx->dst_fmt.width, ctx->dst_fmt.height)); | |
| 122 | + | |
| 123 | + rotate_write(dev, ROTATE_OUT_PITCH0, pitch[0]); | |
| 124 | + rotate_write(dev, ROTATE_OUT_PITCH1, pitch[1]); | |
| 125 | + rotate_write(dev, ROTATE_OUT_PITCH2, pitch[2]); | |
| 126 | + | |
| 127 | + rotate_write(dev, ROTATE_OUT_ADDRL0, addr[0]); | |
| 128 | + rotate_write(dev, ROTATE_OUT_ADDRL1, addr[1]); | |
| 129 | + rotate_write(dev, ROTATE_OUT_ADDRL2, addr[2]); | |
| 130 | + | |
| 131 | + rotate_write(dev, ROTATE_OUT_ADDRH0, 0); | |
| 132 | + rotate_write(dev, ROTATE_OUT_ADDRH1, 0); | |
| 133 | + rotate_write(dev, ROTATE_OUT_ADDRH2, 0); | |
| 134 | + | |
| 135 | + rotate_set_bits(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ_EN); | |
| 136 | + rotate_set_bits(dev, ROTATE_GLB_CTL, ROTATE_GLB_CTL_START); | |
| 137 | +} | |
| 138 | + | |
| 139 | +static irqreturn_t rotate_irq(int irq, void *data) | |
| 140 | +{ | |
| 141 | + struct vb2_v4l2_buffer *buffer; | |
| 142 | + struct rotate_dev *dev = data; | |
| 143 | + struct rotate_ctx *ctx; | |
| 144 | + unsigned int val; | |
| 145 | + | |
| 146 | + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); | |
| 147 | + if (!ctx) { | |
| 148 | + v4l2_err(&dev->v4l2_dev, | |
| 149 | + "Instance released before the end of transaction\n"); | |
| 150 | + return IRQ_NONE; | |
| 151 | + } | |
| 152 | + | |
| 153 | + val = rotate_read(dev, ROTATE_INT); | |
| 154 | + if (!(val & ROTATE_INT_FINISH_IRQ)) | |
| 155 | + return IRQ_NONE; | |
| 156 | + | |
| 157 | + /* clear flag and disable irq */ | |
| 158 | + rotate_write(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ); | |
| 159 | + | |
| 160 | + buffer = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
| 161 | + v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE); | |
| 162 | + | |
| 163 | + buffer = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | |
| 164 | + v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE); | |
| 165 | + | |
| 166 | + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); | |
| 167 | + | |
| 168 | + return IRQ_HANDLED; | |
| 169 | +} | |
| 170 | + | |
| 171 | +static inline struct rotate_ctx *rotate_file2ctx(struct file *file) | |
| 172 | +{ | |
| 173 | + return container_of(file->private_data, struct rotate_ctx, fh); | |
| 174 | +} | |
| 175 | + | |
| 176 | +static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt) | |
| 177 | +{ | |
| 178 | + unsigned int height, width, alignment, sizeimage, size, bpl; | |
| 179 | + const struct rotate_format *fmt; | |
| 180 | + int i; | |
| 181 | + | |
| 182 | + fmt = rotate_find_format(pix_fmt->pixelformat); | |
| 183 | + if (!fmt) | |
| 184 | + return; | |
| 185 | + | |
| 186 | + width = ALIGN(pix_fmt->width, fmt->hsub); | |
| 187 | + height = ALIGN(pix_fmt->height, fmt->vsub); | |
| 188 | + | |
| 189 | + /* all pitches have to be 16 byte aligned */ | |
| 190 | + alignment = 16; | |
| 191 | + if (fmt->planes > 1) | |
| 192 | + alignment *= fmt->hsub / fmt->bpp[1]; | |
| 193 | + bpl = ALIGN(width * fmt->bpp[0], alignment); | |
| 194 | + | |
| 195 | + sizeimage = 0; | |
| 196 | + for (i = 0; i < fmt->planes; i++) { | |
| 197 | + size = bpl * height; | |
| 198 | + if (i > 0) { | |
| 199 | + size *= fmt->bpp[i]; | |
| 200 | + size /= fmt->hsub; | |
| 201 | + size /= fmt->vsub; | |
| 202 | + } | |
| 203 | + sizeimage += size; | |
| 204 | + } | |
| 205 | + | |
| 206 | + pix_fmt->width = width; | |
| 207 | + pix_fmt->height = height; | |
| 208 | + pix_fmt->bytesperline = bpl; | |
| 209 | + pix_fmt->sizeimage = sizeimage; | |
| 210 | +} | |
| 211 | + | |
| 212 | +static int rotate_querycap(struct file *file, void *priv, | |
| 213 | + struct v4l2_capability *cap) | |
| 214 | +{ | |
| 215 | + strscpy(cap->driver, ROTATE_NAME, sizeof(cap->driver)); | |
| 216 | + strscpy(cap->card, ROTATE_NAME, sizeof(cap->card)); | |
| 217 | + snprintf(cap->bus_info, sizeof(cap->bus_info), | |
| 218 | + "platform:%s", ROTATE_NAME); | |
| 219 | + | |
| 220 | + return 0; | |
| 221 | +} | |
| 222 | + | |
| 223 | +static int rotate_enum_fmt_vid_cap(struct file *file, void *priv, | |
| 224 | + struct v4l2_fmtdesc *f) | |
| 225 | +{ | |
| 226 | + return rotate_enum_fmt(f, true); | |
| 227 | +} | |
| 228 | + | |
| 229 | +static int rotate_enum_fmt_vid_out(struct file *file, void *priv, | |
| 230 | + struct v4l2_fmtdesc *f) | |
| 231 | +{ | |
| 232 | + return rotate_enum_fmt(f, false); | |
| 233 | +} | |
| 234 | + | |
| 235 | +static int rotate_enum_framesizes(struct file *file, void *priv, | |
| 236 | + struct v4l2_frmsizeenum *fsize) | |
| 237 | +{ | |
| 238 | + const struct rotate_format *fmt; | |
| 239 | + | |
| 240 | + if (fsize->index != 0) | |
| 241 | + return -EINVAL; | |
| 242 | + | |
| 243 | + fmt = rotate_find_format(fsize->pixel_format); | |
| 244 | + if (!fmt) | |
| 245 | + return -EINVAL; | |
| 246 | + | |
| 247 | + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; | |
| 248 | + fsize->stepwise.min_width = ROTATE_MIN_WIDTH; | |
| 249 | + fsize->stepwise.min_height = ROTATE_MIN_HEIGHT; | |
| 250 | + fsize->stepwise.max_width = ROTATE_MAX_WIDTH; | |
| 251 | + fsize->stepwise.max_height = ROTATE_MAX_HEIGHT; | |
| 252 | + fsize->stepwise.step_width = fmt->hsub; | |
| 253 | + fsize->stepwise.step_height = fmt->vsub; | |
| 254 | + | |
| 255 | + return 0; | |
| 256 | +} | |
| 257 | + | |
| 258 | +static int rotate_set_cap_format(struct rotate_ctx *ctx, | |
| 259 | + struct v4l2_pix_format *f, | |
| 260 | + u32 rotate) | |
| 261 | +{ | |
| 262 | + const struct rotate_format *fmt; | |
| 263 | + | |
| 264 | + fmt = rotate_find_format(ctx->src_fmt.pixelformat); | |
| 265 | + if (!fmt) | |
| 266 | + return -EINVAL; | |
| 267 | + | |
| 268 | + if (fmt->flags & ROTATE_FLAG_YUV) | |
| 269 | + f->pixelformat = V4L2_PIX_FMT_YUV420; | |
| 270 | + else | |
| 271 | + f->pixelformat = ctx->src_fmt.pixelformat; | |
| 272 | + | |
| 273 | + f->field = V4L2_FIELD_NONE; | |
| 274 | + | |
| 275 | + if (rotate == 90 || rotate == 270) { | |
| 276 | + f->width = ctx->src_fmt.height; | |
| 277 | + f->height = ctx->src_fmt.width; | |
| 278 | + } else { | |
| 279 | + f->width = ctx->src_fmt.width; | |
| 280 | + f->height = ctx->src_fmt.height; | |
| 281 | + } | |
| 282 | + | |
| 283 | + rotate_prepare_format(f); | |
| 284 | + | |
| 285 | + return 0; | |
| 286 | +} | |
| 287 | + | |
| 288 | +static int rotate_g_fmt_vid_cap(struct file *file, void *priv, | |
| 289 | + struct v4l2_format *f) | |
| 290 | +{ | |
| 291 | + struct rotate_ctx *ctx = rotate_file2ctx(file); | |
| 292 | + | |
| 293 | + f->fmt.pix = ctx->dst_fmt; | |
| 294 | + | |
| 295 | + return 0; | |
| 296 | +} | |
| 297 | + | |
| 298 | +static int rotate_g_fmt_vid_out(struct file *file, void *priv, | |
| 299 | + struct v4l2_format *f) | |
| 300 | +{ | |
| 301 | + struct rotate_ctx *ctx = rotate_file2ctx(file); | |
| 302 | + | |
| 303 | + f->fmt.pix = ctx->src_fmt; | |
| 304 | + | |
| 305 | + return 0; | |
| 306 | +} | |
| 307 | + | |
| 308 | +static int rotate_try_fmt_vid_cap(struct file *file, void *priv, | |
| 309 | + struct v4l2_format *f) | |
| 310 | +{ | |
| 311 | + struct rotate_ctx *ctx = rotate_file2ctx(file); | |
| 312 | + | |
| 313 | + return rotate_set_cap_format(ctx, &f->fmt.pix, ctx->rotate); | |
| 314 | +} | |
| 315 | + | |
| 316 | +static int rotate_try_fmt_vid_out(struct file *file, void *priv, | |
| 317 | + struct v4l2_format *f) | |
| 318 | +{ | |
| 319 | + if (!rotate_find_format(f->fmt.pix.pixelformat)) | |
| 320 | + f->fmt.pix.pixelformat = V4L2_PIX_FMT_ARGB32; | |
| 321 | + | |
| 322 | + if (f->fmt.pix.width < ROTATE_MIN_WIDTH) | |
| 323 | + f->fmt.pix.width = ROTATE_MIN_WIDTH; | |
| 324 | + if (f->fmt.pix.height < ROTATE_MIN_HEIGHT) | |
| 325 | + f->fmt.pix.height = ROTATE_MIN_HEIGHT; | |
| 326 | + | |
| 327 | + if (f->fmt.pix.width > ROTATE_MAX_WIDTH) | |
| 328 | + f->fmt.pix.width = ROTATE_MAX_WIDTH; | |
| 329 | + if (f->fmt.pix.height > ROTATE_MAX_HEIGHT) | |
| 330 | + f->fmt.pix.height = ROTATE_MAX_HEIGHT; | |
| 331 | + | |
| 332 | + f->fmt.pix.field = V4L2_FIELD_NONE; | |
| 333 | + | |
| 334 | + rotate_prepare_format(&f->fmt.pix); | |
| 335 | + | |
| 336 | + return 0; | |
| 337 | +} | |
| 338 | + | |
| 339 | +static int rotate_s_fmt_vid_cap(struct file *file, void *priv, | |
| 340 | + struct v4l2_format *f) | |
| 341 | +{ | |
| 342 | + struct rotate_ctx *ctx = rotate_file2ctx(file); | |
| 343 | + struct vb2_queue *vq; | |
| 344 | + int ret; | |
| 345 | + | |
| 346 | + ret = rotate_try_fmt_vid_cap(file, priv, f); | |
| 347 | + if (ret) | |
| 348 | + return ret; | |
| 349 | + | |
| 350 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | |
| 351 | + if (vb2_is_busy(vq)) | |
| 352 | + return -EBUSY; | |
| 353 | + | |
| 354 | + ctx->dst_fmt = f->fmt.pix; | |
| 355 | + | |
| 356 | + return 0; | |
| 357 | +} | |
| 358 | + | |
| 359 | +static int rotate_s_fmt_vid_out(struct file *file, void *priv, | |
| 360 | + struct v4l2_format *f) | |
| 361 | +{ | |
| 362 | + struct rotate_ctx *ctx = rotate_file2ctx(file); | |
| 363 | + struct vb2_queue *vq; | |
| 364 | + int ret; | |
| 365 | + | |
| 366 | + ret = rotate_try_fmt_vid_out(file, priv, f); | |
| 367 | + if (ret) | |
| 368 | + return ret; | |
| 369 | + | |
| 370 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | |
| 371 | + if (vb2_is_busy(vq)) | |
| 372 | + return -EBUSY; | |
| 373 | + | |
| 374 | + /* | |
| 375 | + * Capture queue has to be also checked, because format and size | |
| 376 | + * depends on output format and size. | |
| 377 | + */ | |
| 378 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); | |
| 379 | + if (vb2_is_busy(vq)) | |
| 380 | + return -EBUSY; | |
| 381 | + | |
| 382 | + ctx->src_fmt = f->fmt.pix; | |
| 383 | + | |
| 384 | + /* Propagate colorspace information to capture. */ | |
| 385 | + ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; | |
| 386 | + ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; | |
| 387 | + ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; | |
| 388 | + ctx->dst_fmt.quantization = f->fmt.pix.quantization; | |
| 389 | + | |
| 390 | + return rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); | |
| 391 | +} | |
| 392 | + | |
| 393 | +static const struct v4l2_ioctl_ops rotate_ioctl_ops = { | |
| 394 | + .vidioc_querycap = rotate_querycap, | |
| 395 | + | |
| 396 | + .vidioc_enum_framesizes = rotate_enum_framesizes, | |
| 397 | + | |
| 398 | + .vidioc_enum_fmt_vid_cap = rotate_enum_fmt_vid_cap, | |
| 399 | + .vidioc_g_fmt_vid_cap = rotate_g_fmt_vid_cap, | |
| 400 | + .vidioc_try_fmt_vid_cap = rotate_try_fmt_vid_cap, | |
| 401 | + .vidioc_s_fmt_vid_cap = rotate_s_fmt_vid_cap, | |
| 402 | + | |
| 403 | + .vidioc_enum_fmt_vid_out = rotate_enum_fmt_vid_out, | |
| 404 | + .vidioc_g_fmt_vid_out = rotate_g_fmt_vid_out, | |
| 405 | + .vidioc_try_fmt_vid_out = rotate_try_fmt_vid_out, | |
| 406 | + .vidioc_s_fmt_vid_out = rotate_s_fmt_vid_out, | |
| 407 | + | |
| 408 | + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | |
| 409 | + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | |
| 410 | + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | |
| 411 | + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | |
| 412 | + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, | |
| 413 | + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | |
| 414 | + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | |
| 415 | + | |
| 416 | + .vidioc_streamon = v4l2_m2m_ioctl_streamon, | |
| 417 | + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | |
| 418 | + | |
| 419 | + .vidioc_log_status = v4l2_ctrl_log_status, | |
| 420 | + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, | |
| 421 | + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
| 422 | +}; | |
| 423 | + | |
| 424 | +static int rotate_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | |
| 425 | + unsigned int *nplanes, unsigned int sizes[], | |
| 426 | + struct device *alloc_devs[]) | |
| 427 | +{ | |
| 428 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vq); | |
| 429 | + struct v4l2_pix_format *pix_fmt; | |
| 430 | + | |
| 431 | + if (V4L2_TYPE_IS_OUTPUT(vq->type)) | |
| 432 | + pix_fmt = &ctx->src_fmt; | |
| 433 | + else | |
| 434 | + pix_fmt = &ctx->dst_fmt; | |
| 435 | + | |
| 436 | + if (*nplanes) { | |
| 437 | + if (sizes[0] < pix_fmt->sizeimage) | |
| 438 | + return -EINVAL; | |
| 439 | + } else { | |
| 440 | + sizes[0] = pix_fmt->sizeimage; | |
| 441 | + *nplanes = 1; | |
| 442 | + } | |
| 443 | + | |
| 444 | + return 0; | |
| 445 | +} | |
| 446 | + | |
| 447 | +static int rotate_buf_prepare(struct vb2_buffer *vb) | |
| 448 | +{ | |
| 449 | + struct vb2_queue *vq = vb->vb2_queue; | |
| 450 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vq); | |
| 451 | + struct v4l2_pix_format *pix_fmt; | |
| 452 | + | |
| 453 | + if (V4L2_TYPE_IS_OUTPUT(vq->type)) | |
| 454 | + pix_fmt = &ctx->src_fmt; | |
| 455 | + else | |
| 456 | + pix_fmt = &ctx->dst_fmt; | |
| 457 | + | |
| 458 | + if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage) | |
| 459 | + return -EINVAL; | |
| 460 | + | |
| 461 | + vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); | |
| 462 | + | |
| 463 | + return 0; | |
| 464 | +} | |
| 465 | + | |
| 466 | +static void rotate_buf_queue(struct vb2_buffer *vb) | |
| 467 | +{ | |
| 468 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 469 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 470 | + | |
| 471 | + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | |
| 472 | +} | |
| 473 | + | |
| 474 | +static void rotate_queue_cleanup(struct vb2_queue *vq, u32 state) | |
| 475 | +{ | |
| 476 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vq); | |
| 477 | + struct vb2_v4l2_buffer *vbuf; | |
| 478 | + | |
| 479 | + do { | |
| 480 | + if (V4L2_TYPE_IS_OUTPUT(vq->type)) | |
| 481 | + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | |
| 482 | + else | |
| 483 | + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
| 484 | + | |
| 485 | + if (vbuf) | |
| 486 | + v4l2_m2m_buf_done(vbuf, state); | |
| 487 | + } while (vbuf); | |
| 488 | +} | |
| 489 | + | |
| 490 | +static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count) | |
| 491 | +{ | |
| 492 | + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { | |
| 493 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vq); | |
| 494 | + struct device *dev = ctx->dev->dev; | |
| 495 | + int ret; | |
| 496 | + | |
| 497 | + ret = pm_runtime_get_sync(dev); | |
| 498 | + if (ret < 0) { | |
| 499 | + dev_err(dev, "Failed to enable module\n"); | |
| 500 | + | |
| 501 | + return ret; | |
| 502 | + } | |
| 503 | + } | |
| 504 | + | |
| 505 | + return 0; | |
| 506 | +} | |
| 507 | + | |
| 508 | +static void rotate_stop_streaming(struct vb2_queue *vq) | |
| 509 | +{ | |
| 510 | + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { | |
| 511 | + struct rotate_ctx *ctx = vb2_get_drv_priv(vq); | |
| 512 | + | |
| 513 | + pm_runtime_put(ctx->dev->dev); | |
| 514 | + } | |
| 515 | + | |
| 516 | + rotate_queue_cleanup(vq, VB2_BUF_STATE_ERROR); | |
| 517 | +} | |
| 518 | + | |
| 519 | +static const struct vb2_ops rotate_qops = { | |
| 520 | + .queue_setup = rotate_queue_setup, | |
| 521 | + .buf_prepare = rotate_buf_prepare, | |
| 522 | + .buf_queue = rotate_buf_queue, | |
| 523 | + .start_streaming = rotate_start_streaming, | |
| 524 | + .stop_streaming = rotate_stop_streaming, | |
| 525 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 526 | + .wait_finish = vb2_ops_wait_finish, | |
| 527 | +}; | |
| 528 | + | |
| 529 | +static int rotate_queue_init(void *priv, struct vb2_queue *src_vq, | |
| 530 | + struct vb2_queue *dst_vq) | |
| 531 | +{ | |
| 532 | + struct rotate_ctx *ctx = priv; | |
| 533 | + int ret; | |
| 534 | + | |
| 535 | + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | |
| 536 | + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; | |
| 537 | + src_vq->drv_priv = ctx; | |
| 538 | + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | |
| 539 | + src_vq->min_buffers_needed = 1; | |
| 540 | + src_vq->ops = &rotate_qops; | |
| 541 | + src_vq->mem_ops = &vb2_dma_contig_memops; | |
| 542 | + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 543 | + src_vq->lock = &ctx->dev->dev_mutex; | |
| 544 | + src_vq->dev = ctx->dev->dev; | |
| 545 | + | |
| 546 | + ret = vb2_queue_init(src_vq); | |
| 547 | + if (ret) | |
| 548 | + return ret; | |
| 549 | + | |
| 550 | + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
| 551 | + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; | |
| 552 | + dst_vq->drv_priv = ctx; | |
| 553 | + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | |
| 554 | + dst_vq->min_buffers_needed = 2; | |
| 555 | + dst_vq->ops = &rotate_qops; | |
| 556 | + dst_vq->mem_ops = &vb2_dma_contig_memops; | |
| 557 | + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 558 | + dst_vq->lock = &ctx->dev->dev_mutex; | |
| 559 | + dst_vq->dev = ctx->dev->dev; | |
| 560 | + | |
| 561 | + ret = vb2_queue_init(dst_vq); | |
| 562 | + if (ret) | |
| 563 | + return ret; | |
| 564 | + | |
| 565 | + return 0; | |
| 566 | +} | |
| 567 | + | |
| 568 | +static int rotate_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 569 | +{ | |
| 570 | + struct rotate_ctx *ctx = container_of(ctrl->handler, | |
| 571 | + struct rotate_ctx, | |
| 572 | + ctrl_handler); | |
| 573 | + struct v4l2_pix_format fmt; | |
| 574 | + | |
| 575 | + switch (ctrl->id) { | |
| 576 | + case V4L2_CID_HFLIP: | |
| 577 | + ctx->hflip = ctrl->val; | |
| 578 | + break; | |
| 579 | + case V4L2_CID_VFLIP: | |
| 580 | + ctx->vflip = ctrl->val; | |
| 581 | + break; | |
| 582 | + case V4L2_CID_ROTATE: | |
| 583 | + rotate_set_cap_format(ctx, &fmt, ctrl->val); | |
| 584 | + | |
| 585 | + /* Check if capture format needs to be changed */ | |
| 586 | + if (fmt.width != ctx->dst_fmt.width || | |
| 587 | + fmt.height != ctx->dst_fmt.height || | |
| 588 | + fmt.bytesperline != ctx->dst_fmt.bytesperline || | |
| 589 | + fmt.sizeimage != ctx->dst_fmt.sizeimage) { | |
| 590 | + struct vb2_queue *vq; | |
| 591 | + | |
| 592 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, | |
| 593 | + V4L2_BUF_TYPE_VIDEO_CAPTURE); | |
| 594 | + if (vb2_is_busy(vq)) | |
| 595 | + return -EBUSY; | |
| 596 | + | |
| 597 | + rotate_set_cap_format(ctx, &ctx->dst_fmt, ctrl->val); | |
| 598 | + } | |
| 599 | + | |
| 600 | + ctx->rotate = ctrl->val; | |
| 601 | + break; | |
| 602 | + default: | |
| 603 | + return -EINVAL; | |
| 604 | + } | |
| 605 | + | |
| 606 | + return 0; | |
| 607 | +} | |
| 608 | + | |
| 609 | +static const struct v4l2_ctrl_ops rotate_ctrl_ops = { | |
| 610 | + .s_ctrl = rotate_s_ctrl, | |
| 611 | +}; | |
| 612 | + | |
| 613 | +static int rotate_setup_ctrls(struct rotate_ctx *ctx) | |
| 614 | +{ | |
| 615 | + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3); | |
| 616 | + | |
| 617 | + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, | |
| 618 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 619 | + | |
| 620 | + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, | |
| 621 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 622 | + | |
| 623 | + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops, | |
| 624 | + V4L2_CID_ROTATE, 0, 270, 90, 0); | |
| 625 | + | |
| 626 | + if (ctx->ctrl_handler.error) { | |
| 627 | + int err = ctx->ctrl_handler.error; | |
| 628 | + | |
| 629 | + v4l2_err(&ctx->dev->v4l2_dev, "control setup failed!\n"); | |
| 630 | + v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
| 631 | + | |
| 632 | + return err; | |
| 633 | + } | |
| 634 | + | |
| 635 | + return v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | |
| 636 | +} | |
| 637 | + | |
| 638 | +static int rotate_open(struct file *file) | |
| 639 | +{ | |
| 640 | + struct rotate_dev *dev = video_drvdata(file); | |
| 641 | + struct rotate_ctx *ctx = NULL; | |
| 642 | + int ret; | |
| 643 | + | |
| 644 | + if (mutex_lock_interruptible(&dev->dev_mutex)) | |
| 645 | + return -ERESTARTSYS; | |
| 646 | + | |
| 647 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 648 | + if (!ctx) { | |
| 649 | + mutex_unlock(&dev->dev_mutex); | |
| 650 | + return -ENOMEM; | |
| 651 | + } | |
| 652 | + | |
| 653 | + /* default output format */ | |
| 654 | + ctx->src_fmt.pixelformat = V4L2_PIX_FMT_ARGB32; | |
| 655 | + ctx->src_fmt.field = V4L2_FIELD_NONE; | |
| 656 | + ctx->src_fmt.width = 640; | |
| 657 | + ctx->src_fmt.height = 480; | |
| 658 | + rotate_prepare_format(&ctx->src_fmt); | |
| 659 | + | |
| 660 | + /* default capture format */ | |
| 661 | + rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); | |
| 662 | + | |
| 663 | + v4l2_fh_init(&ctx->fh, video_devdata(file)); | |
| 664 | + file->private_data = &ctx->fh; | |
| 665 | + ctx->dev = dev; | |
| 666 | + | |
| 667 | + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, | |
| 668 | + &rotate_queue_init); | |
| 669 | + if (IS_ERR(ctx->fh.m2m_ctx)) { | |
| 670 | + ret = PTR_ERR(ctx->fh.m2m_ctx); | |
| 671 | + goto err_free; | |
| 672 | + } | |
| 673 | + | |
| 674 | + v4l2_fh_add(&ctx->fh); | |
| 675 | + | |
| 676 | + ret = rotate_setup_ctrls(ctx); | |
| 677 | + if (ret) | |
| 678 | + goto err_free; | |
| 679 | + | |
| 680 | + ctx->fh.ctrl_handler = &ctx->ctrl_handler; | |
| 681 | + | |
| 682 | + mutex_unlock(&dev->dev_mutex); | |
| 683 | + | |
| 684 | + return 0; | |
| 685 | + | |
| 686 | +err_free: | |
| 687 | + kfree(ctx); | |
| 688 | + mutex_unlock(&dev->dev_mutex); | |
| 689 | + | |
| 690 | + return ret; | |
| 691 | +} | |
| 692 | + | |
| 693 | +static int rotate_release(struct file *file) | |
| 694 | +{ | |
| 695 | + struct rotate_dev *dev = video_drvdata(file); | |
| 696 | + struct rotate_ctx *ctx = container_of(file->private_data, | |
| 697 | + struct rotate_ctx, fh); | |
| 698 | + | |
| 699 | + mutex_lock(&dev->dev_mutex); | |
| 700 | + | |
| 701 | + v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
| 702 | + v4l2_fh_del(&ctx->fh); | |
| 703 | + v4l2_fh_exit(&ctx->fh); | |
| 704 | + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | |
| 705 | + | |
| 706 | + kfree(ctx); | |
| 707 | + | |
| 708 | + mutex_unlock(&dev->dev_mutex); | |
| 709 | + | |
| 710 | + return 0; | |
| 711 | +} | |
| 712 | + | |
| 713 | +static const struct v4l2_file_operations rotate_fops = { | |
| 714 | + .owner = THIS_MODULE, | |
| 715 | + .open = rotate_open, | |
| 716 | + .release = rotate_release, | |
| 717 | + .poll = v4l2_m2m_fop_poll, | |
| 718 | + .unlocked_ioctl = video_ioctl2, | |
| 719 | + .mmap = v4l2_m2m_fop_mmap, | |
| 720 | +}; | |
| 721 | + | |
| 722 | +static const struct video_device rotate_video_device = { | |
| 723 | + .name = ROTATE_NAME, | |
| 724 | + .vfl_dir = VFL_DIR_M2M, | |
| 725 | + .fops = &rotate_fops, | |
| 726 | + .ioctl_ops = &rotate_ioctl_ops, | |
| 727 | + .minor = -1, | |
| 728 | + .release = video_device_release_empty, | |
| 729 | + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, | |
| 730 | +}; | |
| 731 | + | |
| 732 | +static const struct v4l2_m2m_ops rotate_m2m_ops = { | |
| 733 | + .device_run = rotate_device_run, | |
| 734 | +}; | |
| 735 | + | |
| 736 | +static int rotate_probe(struct platform_device *pdev) | |
| 737 | +{ | |
| 738 | + struct rotate_dev *dev; | |
| 739 | + struct video_device *vfd; | |
| 740 | + int irq, ret; | |
| 741 | + | |
| 742 | + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | |
| 743 | + if (!dev) | |
| 744 | + return -ENOMEM; | |
| 745 | + | |
| 746 | + dev->vfd = rotate_video_device; | |
| 747 | + dev->dev = &pdev->dev; | |
| 748 | + | |
| 749 | + irq = platform_get_irq(pdev, 0); | |
| 750 | + if (irq <= 0) { | |
| 751 | + dev_err(dev->dev, "Failed to get IRQ\n"); | |
| 752 | + | |
| 753 | + return irq; | |
| 754 | + } | |
| 755 | + | |
| 756 | + ret = devm_request_irq(dev->dev, irq, rotate_irq, | |
| 757 | + 0, dev_name(dev->dev), dev); | |
| 758 | + if (ret) { | |
| 759 | + dev_err(dev->dev, "Failed to request IRQ\n"); | |
| 760 | + | |
| 761 | + return ret; | |
| 762 | + } | |
| 763 | + | |
| 764 | + dev->base = devm_platform_ioremap_resource(pdev, 0); | |
| 765 | + if (IS_ERR(dev->base)) | |
| 766 | + return PTR_ERR(dev->base); | |
| 767 | + | |
| 768 | + dev->bus_clk = devm_clk_get(dev->dev, "bus"); | |
| 769 | + if (IS_ERR(dev->bus_clk)) { | |
| 770 | + dev_err(dev->dev, "Failed to get bus clock\n"); | |
| 771 | + | |
| 772 | + return PTR_ERR(dev->bus_clk); | |
| 773 | + } | |
| 774 | + | |
| 775 | + dev->mod_clk = devm_clk_get(dev->dev, "mod"); | |
| 776 | + if (IS_ERR(dev->mod_clk)) { | |
| 777 | + dev_err(dev->dev, "Failed to get mod clock\n"); | |
| 778 | + | |
| 779 | + return PTR_ERR(dev->mod_clk); | |
| 780 | + } | |
| 781 | + | |
| 782 | + dev->rstc = devm_reset_control_get(dev->dev, NULL); | |
| 783 | + if (IS_ERR(dev->rstc)) { | |
| 784 | + dev_err(dev->dev, "Failed to get reset control\n"); | |
| 785 | + | |
| 786 | + return PTR_ERR(dev->rstc); | |
| 787 | + } | |
| 788 | + | |
| 789 | + mutex_init(&dev->dev_mutex); | |
| 790 | + | |
| 791 | + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); | |
| 792 | + if (ret) { | |
| 793 | + dev_err(dev->dev, "Failed to register V4L2 device\n"); | |
| 794 | + | |
| 795 | + return ret; | |
| 796 | + } | |
| 797 | + | |
| 798 | + vfd = &dev->vfd; | |
| 799 | + vfd->lock = &dev->dev_mutex; | |
| 800 | + vfd->v4l2_dev = &dev->v4l2_dev; | |
| 801 | + | |
| 802 | + snprintf(vfd->name, sizeof(vfd->name), "%s", | |
| 803 | + rotate_video_device.name); | |
| 804 | + video_set_drvdata(vfd, dev); | |
| 805 | + | |
| 806 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 807 | + if (ret) { | |
| 808 | + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | |
| 809 | + | |
| 810 | + goto err_v4l2; | |
| 811 | + } | |
| 812 | + | |
| 813 | + v4l2_info(&dev->v4l2_dev, | |
| 814 | + "Device registered as /dev/video%d\n", vfd->num); | |
| 815 | + | |
| 816 | + dev->m2m_dev = v4l2_m2m_init(&rotate_m2m_ops); | |
| 817 | + if (IS_ERR(dev->m2m_dev)) { | |
| 818 | + v4l2_err(&dev->v4l2_dev, | |
| 819 | + "Failed to initialize V4L2 M2M device\n"); | |
| 820 | + ret = PTR_ERR(dev->m2m_dev); | |
| 821 | + | |
| 822 | + goto err_video; | |
| 823 | + } | |
| 824 | + | |
| 825 | + platform_set_drvdata(pdev, dev); | |
| 826 | + | |
| 827 | + pm_runtime_enable(dev->dev); | |
| 828 | + | |
| 829 | + return 0; | |
| 830 | + | |
| 831 | +err_video: | |
| 832 | + video_unregister_device(&dev->vfd); | |
| 833 | +err_v4l2: | |
| 834 | + v4l2_device_unregister(&dev->v4l2_dev); | |
| 835 | + | |
| 836 | + return ret; | |
| 837 | +} | |
| 838 | + | |
| 839 | +static int rotate_remove(struct platform_device *pdev) | |
| 840 | +{ | |
| 841 | + struct rotate_dev *dev = platform_get_drvdata(pdev); | |
| 842 | + | |
| 843 | + v4l2_m2m_release(dev->m2m_dev); | |
| 844 | + video_unregister_device(&dev->vfd); | |
| 845 | + v4l2_device_unregister(&dev->v4l2_dev); | |
| 846 | + | |
| 847 | + pm_runtime_force_suspend(&pdev->dev); | |
| 848 | + | |
| 849 | + return 0; | |
| 850 | +} | |
| 851 | + | |
| 852 | +static int rotate_runtime_resume(struct device *device) | |
| 853 | +{ | |
| 854 | + struct rotate_dev *dev = dev_get_drvdata(device); | |
| 855 | + int ret; | |
| 856 | + | |
| 857 | + ret = clk_prepare_enable(dev->bus_clk); | |
| 858 | + if (ret) { | |
| 859 | + dev_err(dev->dev, "Failed to enable bus clock\n"); | |
| 860 | + | |
| 861 | + return ret; | |
| 862 | + } | |
| 863 | + | |
| 864 | + ret = clk_prepare_enable(dev->mod_clk); | |
| 865 | + if (ret) { | |
| 866 | + dev_err(dev->dev, "Failed to enable mod clock\n"); | |
| 867 | + | |
| 868 | + goto err_bus_clk; | |
| 869 | + } | |
| 870 | + | |
| 871 | + ret = reset_control_deassert(dev->rstc); | |
| 872 | + if (ret) { | |
| 873 | + dev_err(dev->dev, "Failed to apply reset\n"); | |
| 874 | + | |
| 875 | + goto err_mod_clk; | |
| 876 | + } | |
| 877 | + | |
| 878 | + return 0; | |
| 879 | + | |
| 880 | +err_mod_clk: | |
| 881 | + clk_disable_unprepare(dev->mod_clk); | |
| 882 | +err_bus_clk: | |
| 883 | + clk_disable_unprepare(dev->bus_clk); | |
| 884 | + | |
| 885 | + return ret; | |
| 886 | +} | |
| 887 | + | |
| 888 | +static int rotate_runtime_suspend(struct device *device) | |
| 889 | +{ | |
| 890 | + struct rotate_dev *dev = dev_get_drvdata(device); | |
| 891 | + | |
| 892 | + reset_control_assert(dev->rstc); | |
| 893 | + | |
| 894 | + clk_disable_unprepare(dev->mod_clk); | |
| 895 | + clk_disable_unprepare(dev->bus_clk); | |
| 896 | + | |
| 897 | + return 0; | |
| 898 | +} | |
| 899 | + | |
| 900 | +static const struct of_device_id rotate_dt_match[] = { | |
| 901 | + { .compatible = "allwinner,sun8i-a83t-de2-rotate" }, | |
| 902 | + { /* sentinel */ } | |
| 903 | +}; | |
| 904 | +MODULE_DEVICE_TABLE(of, rotate_dt_match); | |
| 905 | + | |
| 906 | +static const struct dev_pm_ops rotate_pm_ops = { | |
| 907 | + .runtime_resume = rotate_runtime_resume, | |
| 908 | + .runtime_suspend = rotate_runtime_suspend, | |
| 909 | +}; | |
| 910 | + | |
| 911 | +static struct platform_driver rotate_driver = { | |
| 912 | + .probe = rotate_probe, | |
| 913 | + .remove = rotate_remove, | |
| 914 | + .driver = { | |
| 915 | + .name = ROTATE_NAME, | |
| 916 | + .of_match_table = rotate_dt_match, | |
| 917 | + .pm = &rotate_pm_ops, | |
| 918 | + }, | |
| 919 | +}; | |
| 920 | +module_platform_driver(rotate_driver); | |
| 921 | + | |
| 922 | +MODULE_LICENSE("GPL v2"); | |
| 923 | +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); | |
| 924 | +MODULE_DESCRIPTION("Allwinner DE2 rotate driver"); | |
| @@ -372,8 +372,6 @@ struct cal_ctx { · 371 unmodified lines | ||
| 372 | 372 | struct v4l2_subdev *sensor; |
| 373 | 373 | struct v4l2_fwnode_endpoint endpoint; |
| 374 | 374 | |
| 375 | − struct v4l2_async_subdev asd; | |
| 376 | − | |
| 377 | 375 | struct v4l2_fh fh; |
| 378 | 376 | struct cal_dev *dev; |
| 379 | 377 | struct cc_data *cc; |
| @@ -722,16 +720,16 @@ static void enable_irqs(struct cal_ctx *ctx) · 342 unmodified lines | ||
| 722 | 720 | |
| 723 | 721 | static void disable_irqs(struct cal_ctx *ctx) |
| 724 | 722 | { |
| 723 | + u32 val; | |
| 724 | + | |
| 725 | 725 | /* Disable IRQ_WDMA_END 0/1 */ |
| 726 | − reg_write_field(ctx->dev, | |
| 727 | − CAL_HL_IRQENABLE_CLR(2), | |
| 728 | − CAL_HL_IRQ_CLEAR, | |
| 729 | − CAL_HL_IRQ_MASK(ctx->csi2_port)); | |
| 726 | + val = 0; | |
| 727 | + set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port)); | |
| 728 | + reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(2), val); | |
| 730 | 729 | /* Disable IRQ_WDMA_START 0/1 */ |
| 731 | − reg_write_field(ctx->dev, | |
| 732 | − CAL_HL_IRQENABLE_CLR(3), | |
| 733 | − CAL_HL_IRQ_CLEAR, | |
| 734 | − CAL_HL_IRQ_MASK(ctx->csi2_port)); | |
| 730 | + val = 0; | |
| 731 | + set_field(&val, CAL_HL_IRQ_CLEAR, CAL_HL_IRQ_MASK(ctx->csi2_port)); | |
| 732 | + reg_write(ctx->dev, CAL_HL_IRQENABLE_CLR(3), val); | |
| 735 | 733 | /* Todo: Add VC_IRQ and CSI2_COMPLEXIO_IRQ handling */ |
| 736 | 734 | reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0); |
| 737 | 735 | } |
| @@ -1948,7 +1946,7 @@ static int cal_complete_ctx(struct cal_ctx *ctx) · 1210 unmodified lines | ||
| 1948 | 1946 | vfd->lock = &ctx->mutex; |
| 1949 | 1947 | video_set_drvdata(vfd, ctx); |
| 1950 | 1948 | |
| 1951 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); | |
| 1949 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, video_nr); | |
| 1952 | 1950 | if (ret < 0) |
| 1953 | 1951 | return ret; |
| 1954 | 1952 | |
| @@ -2032,7 +2030,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) · 77 unmodified lines | ||
| 2032 | 2030 | |
| 2033 | 2031 | parent = pdev->dev.of_node; |
| 2034 | 2032 | |
| 2035 | − asd = &ctx->asd; | |
| 2036 | 2033 | endpoint = &ctx->endpoint; |
| 2037 | 2034 | |
| 2038 | 2035 | ep_node = NULL; |
| @@ -2079,8 +2076,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) · 40 unmodified lines | ||
| 2079 | 2076 | ctx_dbg(3, ctx, "can't get remote parent\n"); |
| 2080 | 2077 | goto cleanup_exit; |
| 2081 | 2078 | } |
| 2082 | − asd->match_type = V4L2_ASYNC_MATCH_FWNODE; | |
| 2083 | − asd->match.fwnode = of_fwnode_handle(sensor_node); | |
| 2084 | 2079 | |
| 2085 | 2080 | v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); |
| 2086 | 2081 | |
| @@ -2110,9 +2105,17 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) · 23 unmodified lines | ||
| 2110 | 2105 | |
| 2111 | 2106 | v4l2_async_notifier_init(&ctx->notifier); |
| 2112 | 2107 | |
| 2108 | + asd = kzalloc(sizeof(*asd), GFP_KERNEL); | |
| 2109 | + if (!asd) | |
| 2110 | + goto cleanup_exit; | |
| 2111 | + | |
| 2112 | + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; | |
| 2113 | + asd->match.fwnode = of_fwnode_handle(sensor_node); | |
| 2114 | + | |
| 2113 | 2115 | ret = v4l2_async_notifier_add_subdev(&ctx->notifier, asd); |
| 2114 | 2116 | if (ret) { |
| 2115 | 2117 | ctx_err(ctx, "Error adding asd\n"); |
| 2118 | + kfree(asd); | |
| 2116 | 2119 | goto cleanup_exit; |
| 2117 | 2120 | } |
| 2118 | 2121 | |
| @@ -2500,7 +2500,7 @@ static void vpe_fw_cb(struct platform_device *pdev) · 2499 unmodified lines | ||
| 2500 | 2500 | vfd->lock = &dev->dev_mutex; |
| 2501 | 2501 | vfd->v4l2_dev = &dev->v4l2_dev; |
| 2502 | 2502 | |
| 2503 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 2503 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 2504 | 2504 | if (ret) { |
| 2505 | 2505 | vpe_err(dev, "Failed to register video device\n"); |
| 2506 | 2506 | |
| @@ -1262,7 +1262,7 @@ static int viacam_probe(struct platform_device *pdev) · 1261 unmodified lines | ||
| 1262 | 1262 | cam->vdev.lock = &cam->lock; |
| 1263 | 1263 | cam->vdev.queue = vq; |
| 1264 | 1264 | video_set_drvdata(&cam->vdev, cam); |
| 1265 | − ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); | |
| 1265 | + ret = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); | |
| 1266 | 1266 | if (ret) |
| 1267 | 1267 | goto out_irq; |
| 1268 | 1268 | |
| @@ -117,15 +117,10 @@ struct vicodec_ctx { · 116 unmodified lines | ||
| 117 | 117 | struct vicodec_dev *dev; |
| 118 | 118 | bool is_enc; |
| 119 | 119 | bool is_stateless; |
| 120 | − bool is_draining; | |
| 121 | − bool next_is_last; | |
| 122 | − bool has_stopped; | |
| 123 | 120 | spinlock_t *lock; |
| 124 | 121 | |
| 125 | 122 | struct v4l2_ctrl_handler hdl; |
| 126 | 123 | |
| 127 | − struct vb2_v4l2_buffer *last_src_buf; | |
| 128 | − | |
| 129 | 124 | /* Source and destination queue data */ |
| 130 | 125 | struct vicodec_q_data q_data[2]; |
| 131 | 126 | struct v4l2_fwht_state state; |
| @@ -431,11 +426,11 @@ static void device_run(void *priv) · 299 unmodified lines | ||
| 431 | 426 | v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); |
| 432 | 427 | |
| 433 | 428 | spin_lock(ctx->lock); |
| 434 | − if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) { | |
| 429 | + if (!ctx->comp_has_next_frame && | |
| 430 | + v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { | |
| 435 | 431 | dst_buf->flags |= V4L2_BUF_FLAG_LAST; |
| 436 | 432 | v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); |
| 437 | − ctx->is_draining = false; | |
| 438 | − ctx->has_stopped = true; | |
| 433 | + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); | |
| 439 | 434 | } |
| 440 | 435 | if (ctx->is_enc || ctx->is_stateless) { |
| 441 | 436 | src_buf->sequence = q_src->sequence++; |
| @@ -586,8 +581,6 @@ static int job_ready(void *priv) · 144 unmodified lines | ||
| 586 | 581 | unsigned int max_to_copy; |
| 587 | 582 | unsigned int comp_frame_size; |
| 588 | 583 | |
| 589 | − if (ctx->has_stopped) | |
| 590 | − return 0; | |
| 591 | 584 | if (ctx->source_changed) |
| 592 | 585 | return 0; |
| 593 | 586 | if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) |
| @@ -607,7 +600,8 @@ restart: · 13 unmodified lines | ||
| 607 | 600 | if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { |
| 608 | 601 | state = get_next_header(ctx, &p, p_src + sz - p); |
| 609 | 602 | if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { |
| 610 | − if (ctx->is_draining && src_buf == ctx->last_src_buf) | |
| 603 | + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, | |
| 604 | + src_buf)) | |
| 611 | 605 | return 1; |
| 612 | 606 | job_remove_src_buf(ctx, state); |
| 613 | 607 | goto restart; |
| @@ -636,7 +630,8 @@ restart: · 22 unmodified lines | ||
| 636 | 630 | p += copy; |
| 637 | 631 | ctx->comp_size += copy; |
| 638 | 632 | if (ctx->comp_size < max_to_copy) { |
| 639 | − if (ctx->is_draining && src_buf == ctx->last_src_buf) | |
| 633 | + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, | |
| 634 | + src_buf)) | |
| 640 | 635 | return 1; |
| 641 | 636 | job_remove_src_buf(ctx, state); |
| 642 | 637 | goto restart; |
| @@ -1219,41 +1214,6 @@ static int vidioc_s_selection(struct file *file, void *priv, · 576 unmodified lines | ||
| 1219 | 1214 | return 0; |
| 1220 | 1215 | } |
| 1221 | 1216 | |
| 1222 | −static int vicodec_mark_last_buf(struct vicodec_ctx *ctx) | |
| 1223 | −{ | |
| 1224 | − struct vb2_v4l2_buffer *next_dst_buf; | |
| 1225 | − int ret = 0; | |
| 1226 | − | |
| 1227 | − spin_lock(ctx->lock); | |
| 1228 | − if (ctx->is_draining) { | |
| 1229 | − ret = -EBUSY; | |
| 1230 | − goto unlock; | |
| 1231 | − } | |
| 1232 | − if (ctx->has_stopped) | |
| 1233 | − goto unlock; | |
| 1234 | − | |
| 1235 | − ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); | |
| 1236 | − ctx->is_draining = true; | |
| 1237 | − if (ctx->last_src_buf) | |
| 1238 | − goto unlock; | |
| 1239 | − | |
| 1240 | − next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
| 1241 | − if (!next_dst_buf) { | |
| 1242 | − ctx->next_is_last = true; | |
| 1243 | − goto unlock; | |
| 1244 | − } | |
| 1245 | − | |
| 1246 | − next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; | |
| 1247 | − vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); | |
| 1248 | − ctx->is_draining = false; | |
| 1249 | − ctx->has_stopped = true; | |
| 1250 | − v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1251 | − | |
| 1252 | −unlock: | |
| 1253 | − spin_unlock(ctx->lock); | |
| 1254 | − return ret; | |
| 1255 | −} | |
| 1256 | − | |
| 1257 | 1217 | static int vicodec_encoder_cmd(struct file *file, void *fh, |
| 1258 | 1218 | struct v4l2_encoder_cmd *ec) |
| 1259 | 1219 | { |
| @@ -1268,18 +1228,19 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, · 8 unmodified lines | ||
| 1268 | 1228 | !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) |
| 1269 | 1229 | return 0; |
| 1270 | 1230 | |
| 1271 | − if (ec->cmd == V4L2_ENC_CMD_STOP) | |
| 1272 | − return vicodec_mark_last_buf(ctx); | |
| 1273 | − ret = 0; | |
| 1274 | − spin_lock(ctx->lock); | |
| 1275 | − if (ctx->is_draining) { | |
| 1276 | − ret = -EBUSY; | |
| 1277 | − } else if (ctx->has_stopped) { | |
| 1278 | − ctx->has_stopped = false; | |
| 1231 | + ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); | |
| 1232 | + if (ret < 0) | |
| 1233 | + return ret; | |
| 1234 | + | |
| 1235 | + if (ec->cmd == V4L2_ENC_CMD_STOP && | |
| 1236 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1237 | + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1238 | + | |
| 1239 | + if (ec->cmd == V4L2_ENC_CMD_START && | |
| 1240 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1279 | 1241 | vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); |
| 1280 | − } | |
| 1281 | − spin_unlock(ctx->lock); | |
| 1282 | − return ret; | |
| 1242 | + | |
| 1243 | + return 0; | |
| 1283 | 1244 | } |
| 1284 | 1245 | |
| 1285 | 1246 | static int vicodec_decoder_cmd(struct file *file, void *fh, |
| @@ -1296,18 +1257,19 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, · 10 unmodified lines | ||
| 1296 | 1257 | !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) |
| 1297 | 1258 | return 0; |
| 1298 | 1259 | |
| 1299 | − if (dc->cmd == V4L2_DEC_CMD_STOP) | |
| 1300 | − return vicodec_mark_last_buf(ctx); | |
| 1301 | − ret = 0; | |
| 1302 | − spin_lock(ctx->lock); | |
| 1303 | − if (ctx->is_draining) { | |
| 1304 | − ret = -EBUSY; | |
| 1305 | − } else if (ctx->has_stopped) { | |
| 1306 | − ctx->has_stopped = false; | |
| 1260 | + ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); | |
| 1261 | + if (ret < 0) | |
| 1262 | + return ret; | |
| 1263 | + | |
| 1264 | + if (dc->cmd == V4L2_DEC_CMD_STOP && | |
| 1265 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1266 | + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1267 | + | |
| 1268 | + if (dc->cmd == V4L2_DEC_CMD_START && | |
| 1269 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1307 | 1270 | vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); |
| 1308 | − } | |
| 1309 | − spin_unlock(ctx->lock); | |
| 1310 | − return ret; | |
| 1271 | + | |
| 1272 | + return 0; | |
| 1311 | 1273 | } |
| 1312 | 1274 | |
| 1313 | 1275 | static int vicodec_enum_framesizes(struct file *file, void *fh, |
| @@ -1480,23 +1442,21 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) · 166 unmodified lines | ||
| 1480 | 1442 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, |
| 1481 | 1443 | }; |
| 1482 | 1444 | |
| 1483 | − if (vb2_is_streaming(vq_cap)) { | |
| 1484 | − if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && | |
| 1485 | − ctx->next_is_last) { | |
| 1486 | − unsigned int i; | |
| 1445 | + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && | |
| 1446 | + vb2_is_streaming(vb->vb2_queue) && | |
| 1447 | + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { | |
| 1448 | + unsigned int i; | |
| 1487 | 1449 | |
| 1488 | − for (i = 0; i < vb->num_planes; i++) | |
| 1489 | − vb->planes[i].bytesused = 0; | |
| 1490 | − vbuf->flags = V4L2_BUF_FLAG_LAST; | |
| 1491 | − vbuf->field = V4L2_FIELD_NONE; | |
| 1492 | − vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++; | |
| 1493 | − vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | |
| 1494 | − ctx->is_draining = false; | |
| 1495 | − ctx->has_stopped = true; | |
| 1496 | − ctx->next_is_last = false; | |
| 1497 | − v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1498 | − return; | |
| 1499 | − } | |
| 1450 | + for (i = 0; i < vb->num_planes; i++) | |
| 1451 | + vb->planes[i].bytesused = 0; | |
| 1452 | + | |
| 1453 | + vbuf->field = V4L2_FIELD_NONE; | |
| 1454 | + vbuf->sequence = | |
| 1455 | + get_q_data(ctx, vb->vb2_queue->type)->sequence++; | |
| 1456 | + | |
| 1457 | + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); | |
| 1458 | + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1459 | + return; | |
| 1500 | 1460 | } |
| 1501 | 1461 | |
| 1502 | 1462 | /* buf_queue handles only the first source change event */ |
| @@ -1609,8 +1569,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, · 106 unmodified lines | ||
| 1609 | 1569 | chroma_div = info->width_div * info->height_div; |
| 1610 | 1570 | q_data->sequence = 0; |
| 1611 | 1571 | |
| 1612 | − if (V4L2_TYPE_IS_OUTPUT(q->type)) | |
| 1613 | − ctx->last_src_buf = NULL; | |
| 1572 | + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); | |
| 1614 | 1573 | |
| 1615 | 1574 | state->gop_cnt = 0; |
| 1616 | 1575 | |
| @@ -1689,29 +1648,12 @@ static void vicodec_stop_streaming(struct vb2_queue *q) · 72 unmodified lines | ||
| 1689 | 1648 | |
| 1690 | 1649 | vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); |
| 1691 | 1650 | |
| 1692 | − if (V4L2_TYPE_IS_OUTPUT(q->type)) { | |
| 1693 | − if (ctx->is_draining) { | |
| 1694 | − struct vb2_v4l2_buffer *next_dst_buf; | |
| 1695 | − | |
| 1696 | − spin_lock(ctx->lock); | |
| 1697 | − ctx->last_src_buf = NULL; | |
| 1698 | − next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
| 1699 | − if (!next_dst_buf) { | |
| 1700 | − ctx->next_is_last = true; | |
| 1701 | − } else { | |
| 1702 | − next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; | |
| 1703 | − vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); | |
| 1704 | − ctx->is_draining = false; | |
| 1705 | − ctx->has_stopped = true; | |
| 1706 | − v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1707 | − } | |
| 1708 | − spin_unlock(ctx->lock); | |
| 1709 | − } | |
| 1710 | − } else { | |
| 1711 | − ctx->is_draining = false; | |
| 1712 | − ctx->has_stopped = false; | |
| 1713 | − ctx->next_is_last = false; | |
| 1714 | − } | |
| 1651 | + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); | |
| 1652 | + | |
| 1653 | + if (V4L2_TYPE_IS_OUTPUT(q->type) && | |
| 1654 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1655 | + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); | |
| 1656 | + | |
| 1715 | 1657 | if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) |
| 1716 | 1658 | ctx->first_source_change_sent = false; |
| 1717 | 1659 | |
| @@ -2120,7 +2062,7 @@ static int register_instance(struct vicodec_dev *dev, · 402 unmodified lines | ||
| 2120 | 2062 | } |
| 2121 | 2063 | video_set_drvdata(vfd, dev); |
| 2122 | 2064 | |
| 2123 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 2065 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 2124 | 2066 | if (ret) { |
| 2125 | 2067 | v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name); |
| 2126 | 2068 | v4l2_m2m_release(dev_instance->m2m_dev); |
| @@ -1333,7 +1333,7 @@ static int vim2m_probe(struct platform_device *pdev) · 1332 unmodified lines | ||
| 1333 | 1333 | vfd->lock = &dev->dev_mutex; |
| 1334 | 1334 | vfd->v4l2_dev = &dev->v4l2_dev; |
| 1335 | 1335 | |
| 1336 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | |
| 1336 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); | |
| 1337 | 1337 | if (ret) { |
| 1338 | 1338 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); |
| 1339 | 1339 | goto error_v4l2; |
| @@ -325,20 +325,20 @@ static const struct media_entity_operations vimc_cap_mops = { · 324 unmodified lines | ||
| 325 | 325 | .link_validate = vimc_vdev_link_validate, |
| 326 | 326 | }; |
| 327 | 327 | |
| 328 | −static void vimc_cap_release(struct video_device *vdev) | |
| 328 | +void vimc_cap_release(struct vimc_ent_device *ved) | |
| 329 | 329 | { |
| 330 | 330 | struct vimc_cap_device *vcap = |
| 331 | − container_of(vdev, struct vimc_cap_device, vdev); | |
| 331 | + container_of(ved, struct vimc_cap_device, ved); | |
| 332 | 332 | |
| 333 | 333 | media_entity_cleanup(vcap->ved.ent); |
| 334 | 334 | kfree(vcap); |
| 335 | 335 | } |
| 336 | 336 | |
| 337 | −void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) | |
| 337 | +void vimc_cap_unregister(struct vimc_ent_device *ved) | |
| 338 | 338 | { |
| 339 | − struct vimc_cap_device *vcap; | |
| 339 | + struct vimc_cap_device *vcap = | |
| 340 | + container_of(ved, struct vimc_cap_device, ved); | |
| 340 | 341 | |
| 341 | − vcap = container_of(ved, struct vimc_cap_device, ved); | |
| 342 | 342 | vb2_queue_release(&vcap->queue); |
| 343 | 343 | video_unregister_device(&vcap->vdev); |
| 344 | 344 | } |
| @@ -423,7 +423,7 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, · 78 unmodified lines | ||
| 423 | 423 | |
| 424 | 424 | ret = vb2_queue_init(q); |
| 425 | 425 | if (ret) { |
| 426 | − dev_err(&vimc->pdev.dev, "%s: vb2 queue init failed (err=%d)\n", | |
| 426 | + dev_err(vimc->mdev.dev, "%s: vb2 queue init failed (err=%d)\n", | |
| 427 | 427 | vcfg_name, ret); |
| 428 | 428 | goto err_clean_m_ent; |
| 429 | 429 | } |
| @@ -443,13 +443,13 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, · 13 unmodified lines | ||
| 443 | 443 | vcap->ved.ent = &vcap->vdev.entity; |
| 444 | 444 | vcap->ved.process_frame = vimc_cap_process_frame; |
| 445 | 445 | vcap->ved.vdev_get_format = vimc_cap_get_format; |
| 446 | − vcap->ved.dev = &vimc->pdev.dev; | |
| 446 | + vcap->ved.dev = vimc->mdev.dev; | |
| 447 | 447 | |
| 448 | 448 | /* Initialize the video_device struct */ |
| 449 | 449 | vdev = &vcap->vdev; |
| 450 | 450 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
| 451 | 451 | vdev->entity.ops = &vimc_cap_mops; |
| 452 | − vdev->release = vimc_cap_release; | |
| 452 | + vdev->release = video_device_release_empty; | |
| 453 | 453 | vdev->fops = &vimc_cap_fops; |
| 454 | 454 | vdev->ioctl_ops = &vimc_cap_ioctl_ops; |
| 455 | 455 | vdev->lock = &vcap->lock; |
| @@ -460,9 +460,9 @@ struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, · 4 unmodified lines | ||
| 460 | 460 | video_set_drvdata(vdev, &vcap->ved); |
| 461 | 461 | |
| 462 | 462 | /* Register the video_device with the v4l2 and the media framework */ |
| 463 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 463 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 464 | 464 | if (ret) { |
| 465 | − dev_err(&vimc->pdev.dev, "%s: video register failed (err=%d)\n", | |
| 465 | + dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n", | |
| 466 | 466 | vcap->vdev.name, ret); |
| 467 | 467 | goto err_release_queue; |
| 468 | 468 | } |
| @@ -327,7 +327,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, · 326 unmodified lines | ||
| 327 | 327 | u32 function, |
| 328 | 328 | u16 num_pads, |
| 329 | 329 | struct media_pad *pads, |
| 330 | − const struct v4l2_subdev_internal_ops *sd_int_ops, | |
| 331 | 330 | const struct v4l2_subdev_ops *sd_ops) |
| 332 | 331 | { |
| 333 | 332 | int ret; |
| @@ -337,7 +336,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, · 3 unmodified lines | ||
| 337 | 336 | |
| 338 | 337 | /* Initialize the subdev */ |
| 339 | 338 | v4l2_subdev_init(sd, sd_ops); |
| 340 | − sd->internal_ops = sd_int_ops; | |
| 341 | 339 | sd->entity.function = function; |
| 342 | 340 | sd->entity.ops = &vimc_ent_sd_mops; |
| 343 | 341 | sd->owner = THIS_MODULE; |
| @@ -106,14 +106,12 @@ struct vimc_ent_device { · 105 unmodified lines | ||
| 106 | 106 | /** |
| 107 | 107 | * struct vimc_device - main device for vimc driver |
| 108 | 108 | * |
| 109 | − * @pdev pointer to the platform device | |
| 110 | 109 | * @pipe_cfg pointer to the vimc pipeline configuration structure |
| 111 | 110 | * @ent_devs array of vimc_ent_device pointers |
| 112 | 111 | * @mdev the associated media_device parent |
| 113 | 112 | * @v4l2_dev Internal v4l2 parent device |
| 114 | 113 | */ |
| 115 | 114 | struct vimc_device { |
| 116 | − struct platform_device pdev; | |
| 117 | 115 | const struct vimc_pipeline_config *pipe_cfg; |
| 118 | 116 | struct vimc_ent_device **ent_devs; |
| 119 | 117 | struct media_device mdev; |
| @@ -127,16 +125,18 @@ struct vimc_device { · 7 unmodified lines | ||
| 127 | 125 | * @name entity name |
| 128 | 126 | * @ved pointer to vimc_ent_device (a node in the |
| 129 | 127 | * topology) |
| 130 | − * @add subdev add hook - initializes and registers | |
| 131 | − * subdev called from vimc-core | |
| 132 | − * @rm subdev rm hook - unregisters and frees | |
| 133 | − * subdev called from vimc-core | |
| 128 | + * @add initializes and registers | |
| 129 | + * vim entity - called from vimc-core | |
| 130 | + * @unregister unregisters vimc entity - called from vimc-core | |
| 131 | + * @release releases vimc entity - called from the v4l2_dev | |
| 132 | + * release callback | |
| 134 | 133 | */ |
| 135 | 134 | struct vimc_ent_config { |
| 136 | 135 | const char *name; |
| 137 | 136 | struct vimc_ent_device *(*add)(struct vimc_device *vimc, |
| 138 | 137 | const char *vcfg_name); |
| 139 | − void (*rm)(struct vimc_device *vimc, struct vimc_ent_device *ved); | |
| 138 | + void (*unregister)(struct vimc_ent_device *ved); | |
| 139 | + void (*release)(struct vimc_ent_device *ved); | |
| 140 | 140 | }; |
| 141 | 141 | |
| 142 | 142 | /** |
| @@ -147,22 +147,23 @@ struct vimc_ent_config { · 4 unmodified lines | ||
| 147 | 147 | */ |
| 148 | 148 | bool vimc_is_source(struct media_entity *ent); |
| 149 | 149 | |
| 150 | −/* prototypes for vimc_ent_config add and rm hooks */ | |
| 150 | +/* prototypes for vimc_ent_config hooks */ | |
| 151 | 151 | struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, |
| 152 | 152 | const char *vcfg_name); |
| 153 | −void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); | |
| 153 | +void vimc_cap_unregister(struct vimc_ent_device *ved); | |
| 154 | +void vimc_cap_release(struct vimc_ent_device *ved); | |
| 154 | 155 | |
| 155 | 156 | struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, |
| 156 | 157 | const char *vcfg_name); |
| 157 | −void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); | |
| 158 | +void vimc_deb_release(struct vimc_ent_device *ved); | |
| 158 | 159 | |
| 159 | 160 | struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, |
| 160 | 161 | const char *vcfg_name); |
| 161 | −void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); | |
| 162 | +void vimc_sca_release(struct vimc_ent_device *ved); | |
| 162 | 163 | |
| 163 | 164 | struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, |
| 164 | 165 | const char *vcfg_name); |
| 165 | −void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); | |
| 166 | +void vimc_sen_release(struct vimc_ent_device *ved); | |
| 166 | 167 | |
| 167 | 168 | /** |
| 168 | 169 | * vimc_pix_map_by_index - get vimc_pix_map struct by its index |
| @@ -197,7 +198,6 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); · 28 unmodified lines | ||
| 197 | 198 | * @num_pads: number of pads to initialize |
| 198 | 199 | * @pads: the array of pads of the entity, the caller should set the |
| 199 | 200 | flags of the pads |
| 200 | − * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops | |
| 201 | 201 | * @sd_ops: pointer to &struct v4l2_subdev_ops. |
| 202 | 202 | * |
| 203 | 203 | * Helper function initialize and register the struct vimc_ent_device and struct |
| @@ -210,7 +210,6 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, · 6 unmodified lines | ||
| 210 | 210 | u32 function, |
| 211 | 211 | u16 num_pads, |
| 212 | 212 | struct media_pad *pads, |
| 213 | − const struct v4l2_subdev_internal_ops *sd_int_ops, | |
| 214 | 213 | const struct v4l2_subdev_ops *sd_ops); |
| 215 | 214 | |
| 216 | 215 | /** |
| @@ -48,48 +48,51 @@ static struct vimc_ent_config ent_config[] = { · 47 unmodified lines | ||
| 48 | 48 | { |
| 49 | 49 | .name = "Sensor A", |
| 50 | 50 | .add = vimc_sen_add, |
| 51 | − .rm = vimc_sen_rm, | |
| 51 | + .release = vimc_sen_release, | |
| 52 | 52 | }, |
| 53 | 53 | { |
| 54 | 54 | .name = "Sensor B", |
| 55 | 55 | .add = vimc_sen_add, |
| 56 | − .rm = vimc_sen_rm, | |
| 56 | + .release = vimc_sen_release, | |
| 57 | 57 | }, |
| 58 | 58 | { |
| 59 | 59 | .name = "Debayer A", |
| 60 | 60 | .add = vimc_deb_add, |
| 61 | − .rm = vimc_deb_rm, | |
| 61 | + .release = vimc_deb_release, | |
| 62 | 62 | }, |
| 63 | 63 | { |
| 64 | 64 | .name = "Debayer B", |
| 65 | 65 | .add = vimc_deb_add, |
| 66 | − .rm = vimc_deb_rm, | |
| 66 | + .release = vimc_deb_release, | |
| 67 | 67 | }, |
| 68 | 68 | { |
| 69 | 69 | .name = "Raw Capture 0", |
| 70 | 70 | .add = vimc_cap_add, |
| 71 | − .rm = vimc_cap_rm, | |
| 71 | + .unregister = vimc_cap_unregister, | |
| 72 | + .release = vimc_cap_release, | |
| 72 | 73 | }, |
| 73 | 74 | { |
| 74 | 75 | .name = "Raw Capture 1", |
| 75 | 76 | .add = vimc_cap_add, |
| 76 | − .rm = vimc_cap_rm, | |
| 77 | + .unregister = vimc_cap_unregister, | |
| 78 | + .release = vimc_cap_release, | |
| 77 | 79 | }, |
| 78 | 80 | { |
| 79 | 81 | /* TODO: change this to vimc-input when it is implemented */ |
| 80 | 82 | .name = "RGB/YUV Input", |
| 81 | 83 | .add = vimc_sen_add, |
| 82 | − .rm = vimc_sen_rm, | |
| 84 | + .release = vimc_sen_release, | |
| 83 | 85 | }, |
| 84 | 86 | { |
| 85 | 87 | .name = "Scaler", |
| 86 | 88 | .add = vimc_sca_add, |
| 87 | − .rm = vimc_sca_rm, | |
| 89 | + .release = vimc_sca_release, | |
| 88 | 90 | }, |
| 89 | 91 | { |
| 90 | 92 | .name = "RGB/YUV Capture", |
| 91 | 93 | .add = vimc_cap_add, |
| 92 | − .rm = vimc_cap_rm, | |
| 94 | + .unregister = vimc_cap_unregister, | |
| 95 | + .release = vimc_cap_release, | |
| 93 | 96 | }, |
| 94 | 97 | }; |
| 95 | 98 | |
| @@ -162,12 +165,12 @@ static int vimc_add_subdevs(struct vimc_device *vimc) · 66 unmodified lines | ||
| 162 | 165 | unsigned int i; |
| 163 | 166 | |
| 164 | 167 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { |
| 165 | − dev_dbg(&vimc->pdev.dev, "new entity for %s\n", | |
| 168 | + dev_dbg(vimc->mdev.dev, "new entity for %s\n", | |
| 166 | 169 | vimc->pipe_cfg->ents[i].name); |
| 167 | 170 | vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc, |
| 168 | 171 | vimc->pipe_cfg->ents[i].name); |
| 169 | 172 | if (!vimc->ent_devs[i]) { |
| 170 | − dev_err(&vimc->pdev.dev, "add new entity for %s\n", | |
| 173 | + dev_err(vimc->mdev.dev, "add new entity for %s\n", | |
| 171 | 174 | vimc->pipe_cfg->ents[i].name); |
| 172 | 175 | return -EINVAL; |
| 173 | 176 | } |
| @@ -175,13 +178,33 @@ static int vimc_add_subdevs(struct vimc_device *vimc) · 1 unmodified line | ||
| 175 | 178 | return 0; |
| 176 | 179 | } |
| 177 | 180 | |
| 178 | −static void vimc_rm_subdevs(struct vimc_device *vimc) | |
| 181 | +static void vimc_release_subdevs(struct vimc_device *vimc) | |
| 179 | 182 | { |
| 180 | 183 | unsigned int i; |
| 181 | 184 | |
| 182 | 185 | for (i = 0; i < vimc->pipe_cfg->num_ents; i++) |
| 183 | 186 | if (vimc->ent_devs[i]) |
| 184 | − vimc->pipe_cfg->ents[i].rm(vimc, vimc->ent_devs[i]); | |
| 187 | + vimc->pipe_cfg->ents[i].release(vimc->ent_devs[i]); | |
| 188 | +} | |
| 189 | + | |
| 190 | +static void vimc_unregister_subdevs(struct vimc_device *vimc) | |
| 191 | +{ | |
| 192 | + unsigned int i; | |
| 193 | + | |
| 194 | + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) | |
| 195 | + if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].unregister) | |
| 196 | + vimc->pipe_cfg->ents[i].unregister(vimc->ent_devs[i]); | |
| 197 | +} | |
| 198 | + | |
| 199 | +static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev) | |
| 200 | +{ | |
| 201 | + struct vimc_device *vimc = | |
| 202 | + container_of(v4l2_dev, struct vimc_device, v4l2_dev); | |
| 203 | + | |
| 204 | + vimc_release_subdevs(vimc); | |
| 205 | + media_device_cleanup(&vimc->mdev); | |
| 206 | + kfree(vimc->ent_devs); | |
| 207 | + kfree(vimc); | |
| 185 | 208 | } |
| 186 | 209 | |
| 187 | 210 | static int vimc_register_devices(struct vimc_device *vimc) |
| @@ -195,7 +218,6 @@ static int vimc_register_devices(struct vimc_device *vimc) · 7 unmodified lines | ||
| 195 | 218 | "v4l2 device register failed (err=%d)\n", ret); |
| 196 | 219 | return ret; |
| 197 | 220 | } |
| 198 | − | |
| 199 | 221 | /* allocate ent_devs */ |
| 200 | 222 | vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, |
| 201 | 223 | sizeof(*vimc->ent_devs), GFP_KERNEL); |
| @@ -236,9 +258,9 @@ static int vimc_register_devices(struct vimc_device *vimc) · 34 unmodified lines | ||
| 236 | 258 | |
| 237 | 259 | err_mdev_unregister: |
| 238 | 260 | media_device_unregister(&vimc->mdev); |
| 239 | − media_device_cleanup(&vimc->mdev); | |
| 240 | 261 | err_rm_subdevs: |
| 241 | − vimc_rm_subdevs(vimc); | |
| 262 | + vimc_unregister_subdevs(vimc); | |
| 263 | + vimc_release_subdevs(vimc); | |
| 242 | 264 | kfree(vimc->ent_devs); |
| 243 | 265 | err_v4l2_unregister: |
| 244 | 266 | v4l2_device_unregister(&vimc->v4l2_dev); |
| @@ -248,20 +270,23 @@ err_v4l2_unregister: · 3 unmodified lines | ||
| 248 | 270 | |
| 249 | 271 | static void vimc_unregister(struct vimc_device *vimc) |
| 250 | 272 | { |
| 273 | + vimc_unregister_subdevs(vimc); | |
| 251 | 274 | media_device_unregister(&vimc->mdev); |
| 252 | − media_device_cleanup(&vimc->mdev); | |
| 253 | 275 | v4l2_device_unregister(&vimc->v4l2_dev); |
| 254 | − kfree(vimc->ent_devs); | |
| 255 | 276 | } |
| 256 | 277 | |
| 257 | 278 | static int vimc_probe(struct platform_device *pdev) |
| 258 | 279 | { |
| 259 | − struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); | |
| 280 | + struct vimc_device *vimc; | |
| 260 | 281 | int ret; |
| 261 | 282 | |
| 262 | 283 | dev_dbg(&pdev->dev, "probe"); |
| 263 | 284 | |
| 264 | − memset(&vimc->mdev, 0, sizeof(vimc->mdev)); | |
| 285 | + vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); | |
| 286 | + if (!vimc) | |
| 287 | + return -ENOMEM; | |
| 288 | + | |
| 289 | + vimc->pipe_cfg = &pipe_cfg; | |
| 265 | 290 | |
| 266 | 291 | /* Link the media device within the v4l2_device */ |
| 267 | 292 | vimc->v4l2_dev.mdev = &vimc->mdev; |
| @@ -277,20 +302,27 @@ static int vimc_probe(struct platform_device *pdev) · 9 unmodified lines | ||
| 277 | 302 | ret = vimc_register_devices(vimc); |
| 278 | 303 | if (ret) { |
| 279 | 304 | media_device_cleanup(&vimc->mdev); |
| 305 | + kfree(vimc); | |
| 280 | 306 | return ret; |
| 281 | 307 | } |
| 308 | + /* | |
| 309 | + * the release cb is set only after successful registration. | |
| 310 | + * if the registration fails, we release directly from probe | |
| 311 | + */ | |
| 282 | 312 | |
| 313 | + vimc->v4l2_dev.release = vimc_v4l2_dev_release; | |
| 314 | + platform_set_drvdata(pdev, vimc); | |
| 283 | 315 | return 0; |
| 284 | 316 | } |
| 285 | 317 | |
| 286 | 318 | static int vimc_remove(struct platform_device *pdev) |
| 287 | 319 | { |
| 288 | − struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); | |
| 320 | + struct vimc_device *vimc = platform_get_drvdata(pdev); | |
| 289 | 321 | |
| 290 | 322 | dev_dbg(&pdev->dev, "remove"); |
| 291 | 323 | |
| 292 | − vimc_rm_subdevs(vimc); | |
| 293 | 324 | vimc_unregister(vimc); |
| 325 | + v4l2_device_put(&vimc->v4l2_dev); | |
| 294 | 326 | |
| 295 | 327 | return 0; |
| 296 | 328 | } |
| @@ -299,12 +331,9 @@ static void vimc_dev_release(struct device *dev) · 2 unmodified lines | ||
| 299 | 331 | { |
| 300 | 332 | } |
| 301 | 333 | |
| 302 | −static struct vimc_device vimc_dev = { | |
| 303 | − .pipe_cfg = &pipe_cfg, | |
| 304 | − .pdev = { | |
| 305 | − .name = VIMC_PDEV_NAME, | |
| 306 | − .dev.release = vimc_dev_release, | |
| 307 | − } | |
| 334 | +static struct platform_device vimc_pdev = { | |
| 335 | + .name = VIMC_PDEV_NAME, | |
| 336 | + .dev.release = vimc_dev_release, | |
| 308 | 337 | }; |
| 309 | 338 | |
| 310 | 339 | static struct platform_driver vimc_pdrv = { |
| @@ -319,16 +348,16 @@ static int __init vimc_init(void) · 8 unmodified lines | ||
| 319 | 348 | { |
| 320 | 349 | int ret; |
| 321 | 350 | |
| 322 | − ret = platform_device_register(&vimc_dev.pdev); | |
| 351 | + ret = platform_device_register(&vimc_pdev); | |
| 323 | 352 | if (ret) { |
| 324 | − dev_err(&vimc_dev.pdev.dev, | |
| 353 | + dev_err(&vimc_pdev.dev, | |
| 325 | 354 | "platform device registration failed (err=%d)\n", ret); |
| 326 | 355 | return ret; |
| 327 | 356 | } |
| 328 | 357 | |
| 329 | 358 | ret = platform_driver_register(&vimc_pdrv); |
| 330 | 359 | if (ret) { |
| 331 | − dev_err(&vimc_dev.pdev.dev, | |
| 360 | + dev_err(&vimc_pdev.dev, | |
| 332 | 361 | "platform driver registration failed (err=%d)\n", ret); |
| 333 | 362 | platform_driver_unregister(&vimc_pdrv); |
| 334 | 363 | return ret; |
| @@ -341,7 +370,7 @@ static void __exit vimc_exit(void) · 6 unmodified lines | ||
| 341 | 370 | { |
| 342 | 371 | platform_driver_unregister(&vimc_pdrv); |
| 343 | 372 | |
| 344 | − platform_device_unregister(&vimc_dev.pdev); | |
| 373 | + platform_device_unregister(&vimc_pdev); | |
| 345 | 374 | } |
| 346 | 375 | |
| 347 | 376 | module_init(vimc_init); |
| @@ -494,28 +494,16 @@ static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { · 493 unmodified lines | ||
| 494 | 494 | .s_ctrl = vimc_deb_s_ctrl, |
| 495 | 495 | }; |
| 496 | 496 | |
| 497 | −static void vimc_deb_release(struct v4l2_subdev *sd) | |
| 497 | +void vimc_deb_release(struct vimc_ent_device *ved) | |
| 498 | 498 | { |
| 499 | 499 | struct vimc_deb_device *vdeb = |
| 500 | − container_of(sd, struct vimc_deb_device, sd); | |
| 500 | + container_of(ved, struct vimc_deb_device, ved); | |
| 501 | 501 | |
| 502 | 502 | v4l2_ctrl_handler_free(&vdeb->hdl); |
| 503 | 503 | media_entity_cleanup(vdeb->ved.ent); |
| 504 | 504 | kfree(vdeb); |
| 505 | 505 | } |
| 506 | 506 | |
| 507 | −static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = { | |
| 508 | − .release = vimc_deb_release, | |
| 509 | −}; | |
| 510 | − | |
| 511 | −void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) | |
| 512 | −{ | |
| 513 | − struct vimc_deb_device *vdeb; | |
| 514 | − | |
| 515 | − vdeb = container_of(ved, struct vimc_deb_device, ved); | |
| 516 | − v4l2_device_unregister_subdev(&vdeb->sd); | |
| 517 | −} | |
| 518 | − | |
| 519 | 507 | static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { |
| 520 | 508 | .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, |
| 521 | 509 | .id = VIMC_CID_VIMC_CLASS, |
| @@ -563,13 +551,12 @@ struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, · 41 unmodified lines | ||
| 563 | 551 | ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, |
| 564 | 552 | vcfg_name, |
| 565 | 553 | MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, |
| 566 | − vdeb->pads, | |
| 567 | − &vimc_deb_int_ops, &vimc_deb_ops); | |
| 554 | + vdeb->pads, &vimc_deb_ops); | |
| 568 | 555 | if (ret) |
| 569 | 556 | goto err_free_hdl; |
| 570 | 557 | |
| 571 | 558 | vdeb->ved.process_frame = vimc_deb_process_frame; |
| 572 | − vdeb->ved.dev = &vimc->pdev.dev; | |
| 559 | + vdeb->ved.dev = vimc->mdev.dev; | |
| 573 | 560 | vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; |
| 574 | 561 | |
| 575 | 562 | /* Initialize the frame format */ |
| @@ -464,27 +464,15 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, · 463 unmodified lines | ||
| 464 | 464 | return vsca->src_frame; |
| 465 | 465 | }; |
| 466 | 466 | |
| 467 | −static void vimc_sca_release(struct v4l2_subdev *sd) | |
| 467 | +void vimc_sca_release(struct vimc_ent_device *ved) | |
| 468 | 468 | { |
| 469 | 469 | struct vimc_sca_device *vsca = |
| 470 | − container_of(sd, struct vimc_sca_device, sd); | |
| 470 | + container_of(ved, struct vimc_sca_device, ved); | |
| 471 | 471 | |
| 472 | 472 | media_entity_cleanup(vsca->ved.ent); |
| 473 | 473 | kfree(vsca); |
| 474 | 474 | } |
| 475 | 475 | |
| 476 | −static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = { | |
| 477 | − .release = vimc_sca_release, | |
| 478 | −}; | |
| 479 | − | |
| 480 | −void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) | |
| 481 | −{ | |
| 482 | − struct vimc_sca_device *vsca; | |
| 483 | − | |
| 484 | − vsca = container_of(ved, struct vimc_sca_device, ved); | |
| 485 | − v4l2_device_unregister_subdev(&vsca->sd); | |
| 486 | −} | |
| 487 | − | |
| 488 | 476 | struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, |
| 489 | 477 | const char *vcfg_name) |
| 490 | 478 | { |
| @@ -504,15 +492,14 @@ struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, · 13 unmodified lines | ||
| 504 | 492 | ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, |
| 505 | 493 | vcfg_name, |
| 506 | 494 | MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, |
| 507 | − vsca->pads, | |
| 508 | − &vimc_sca_int_ops, &vimc_sca_ops); | |
| 495 | + vsca->pads, &vimc_sca_ops); | |
| 509 | 496 | if (ret) { |
| 510 | 497 | kfree(vsca); |
| 511 | 498 | return NULL; |
| 512 | 499 | } |
| 513 | 500 | |
| 514 | 501 | vsca->ved.process_frame = vimc_sca_process_frame; |
| 515 | − vsca->ved.dev = &vimc->pdev.dev; | |
| 502 | + vsca->ved.dev = vimc->mdev.dev; | |
| 516 | 503 | |
| 517 | 504 | /* Initialize the frame format */ |
| 518 | 505 | vsca->sink_fmt = sink_fmt_default; |
| @@ -279,10 +279,10 @@ static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { · 278 unmodified lines | ||
| 279 | 279 | .s_ctrl = vimc_sen_s_ctrl, |
| 280 | 280 | }; |
| 281 | 281 | |
| 282 | −static void vimc_sen_release(struct v4l2_subdev *sd) | |
| 282 | +void vimc_sen_release(struct vimc_ent_device *ved) | |
| 283 | 283 | { |
| 284 | 284 | struct vimc_sen_device *vsen = |
| 285 | − container_of(sd, struct vimc_sen_device, sd); | |
| 285 | + container_of(ved, struct vimc_sen_device, ved); | |
| 286 | 286 | |
| 287 | 287 | v4l2_ctrl_handler_free(&vsen->hdl); |
| 288 | 288 | tpg_free(&vsen->tpg); |
| @@ -290,18 +290,6 @@ static void vimc_sen_release(struct v4l2_subdev *sd) · 1 unmodified line | ||
| 290 | 290 | kfree(vsen); |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | −static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = { | |
| 294 | − .release = vimc_sen_release, | |
| 295 | −}; | |
| 296 | − | |
| 297 | −void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) | |
| 298 | −{ | |
| 299 | − struct vimc_sen_device *vsen; | |
| 300 | − | |
| 301 | − vsen = container_of(ved, struct vimc_sen_device, ved); | |
| 302 | − v4l2_device_unregister_subdev(&vsen->sd); | |
| 303 | −} | |
| 304 | − | |
| 305 | 293 | /* Image Processing Controls */ |
| 306 | 294 | static const struct v4l2_ctrl_config vimc_sen_ctrl_class = { |
| 307 | 295 | .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, |
| @@ -365,12 +353,12 @@ struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, · 57 unmodified lines | ||
| 365 | 353 | ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, |
| 366 | 354 | vcfg_name, |
| 367 | 355 | MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, |
| 368 | − &vimc_sen_int_ops, &vimc_sen_ops); | |
| 356 | + &vimc_sen_ops); | |
| 369 | 357 | if (ret) |
| 370 | 358 | goto err_free_tpg; |
| 371 | 359 | |
| 372 | 360 | vsen->ved.process_frame = vimc_sen_process_frame; |
| 373 | − vsen->ved.dev = &vimc->pdev.dev; | |
| 361 | + vsen->ved.dev = vimc->mdev.dev; | |
| 374 | 362 | |
| 375 | 363 | /* Initialize the frame format */ |
| 376 | 364 | vsen->mbus_format = fmt_default; |
| @@ -207,16 +207,27 @@ int vimc_streamer_s_stream(struct vimc_stream *stream, · 206 unmodified lines | ||
| 207 | 207 | stream->kthread = kthread_run(vimc_streamer_thread, stream, |
| 208 | 208 | "vimc-streamer thread"); |
| 209 | 209 | |
| 210 | − if (IS_ERR(stream->kthread)) | |
| 211 | − return PTR_ERR(stream->kthread); | |
| 210 | + if (IS_ERR(stream->kthread)) { | |
| 211 | + ret = PTR_ERR(stream->kthread); | |
| 212 | + dev_err(ved->dev, "kthread_run failed with %d\n", ret); | |
| 213 | + vimc_streamer_pipeline_terminate(stream); | |
| 214 | + stream->kthread = NULL; | |
| 215 | + return ret; | |
| 216 | + } | |
| 212 | 217 | |
| 213 | 218 | } else { |
| 214 | 219 | if (!stream->kthread) |
| 215 | 220 | return 0; |
| 216 | 221 | |
| 217 | 222 | ret = kthread_stop(stream->kthread); |
| 223 | + /* | |
| 224 | + * kthread_stop returns -EINTR in cases when streamon was | |
| 225 | + * immediately followed by streamoff, and the thread didn't had | |
| 226 | + * a chance to run. Ignore errors to stop the stream in the | |
| 227 | + * pipeline. | |
| 228 | + */ | |
| 218 | 229 | if (ret) |
| 219 | − return ret; | |
| 230 | + dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret); | |
| 220 | 231 | |
| 221 | 232 | stream->kthread = NULL; |
| 222 | 233 | |
| @@ -407,7 +407,7 @@ static int vidioc_log_status(struct file *file, void *fh) · 406 unmodified lines | ||
| 407 | 407 | struct video_device *vdev = video_devdata(file); |
| 408 | 408 | |
| 409 | 409 | v4l2_ctrl_log_status(file, fh); |
| 410 | − if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 410 | + if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 411 | 411 | tpg_log_status(&dev->tpg); |
| 412 | 412 | return 0; |
| 413 | 413 | } |
| @@ -1525,7 +1525,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 1111 unmodified lines | ||
| 1525 | 1525 | } |
| 1526 | 1526 | #endif |
| 1527 | 1527 | |
| 1528 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]); | |
| 1528 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]); | |
| 1529 | 1529 | if (ret < 0) |
| 1530 | 1530 | goto unreg_dev; |
| 1531 | 1531 | v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", |
| @@ -1571,14 +1571,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 39 unmodified lines | ||
| 1571 | 1571 | } |
| 1572 | 1572 | v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", |
| 1573 | 1573 | dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); |
| 1574 | − if (i <= out_type_counter[HDMI]) | |
| 1575 | − cec_s_phys_addr(dev->cec_tx_adap[i], i << 12, false); | |
| 1574 | + if (i < out_type_counter[HDMI]) | |
| 1575 | + cec_s_phys_addr(dev->cec_tx_adap[i], (i + 1) << 12, false); | |
| 1576 | 1576 | else |
| 1577 | 1577 | cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false); |
| 1578 | 1578 | } |
| 1579 | 1579 | #endif |
| 1580 | 1580 | |
| 1581 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]); | |
| 1581 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]); | |
| 1582 | 1582 | if (ret < 0) |
| 1583 | 1583 | goto unreg_dev; |
| 1584 | 1584 | v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n", |
| @@ -1734,7 +1734,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 149 unmodified lines | ||
| 1734 | 1734 | if (ret) |
| 1735 | 1735 | goto unreg_dev; |
| 1736 | 1736 | #endif |
| 1737 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, | |
| 1737 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, | |
| 1738 | 1738 | meta_cap_nr[inst]); |
| 1739 | 1739 | if (ret < 0) |
| 1740 | 1740 | goto unreg_dev; |
| @@ -1764,7 +1764,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) · 23 unmodified lines | ||
| 1764 | 1764 | if (ret) |
| 1765 | 1765 | goto unreg_dev; |
| 1766 | 1766 | #endif |
| 1767 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, | |
| 1767 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, | |
| 1768 | 1768 | meta_out_nr[inst]); |
| 1769 | 1769 | if (ret < 0) |
| 1770 | 1770 | goto unreg_dev; |
| @@ -551,7 +551,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo, · 550 unmodified lines | ||
| 551 | 551 | histo->video.fops = &histo_v4l2_fops; |
| 552 | 552 | snprintf(histo->video.name, sizeof(histo->video.name), |
| 553 | 553 | "%s histo", histo->entity.subdev.name); |
| 554 | − histo->video.vfl_type = VFL_TYPE_GRABBER; | |
| 554 | + histo->video.vfl_type = VFL_TYPE_VIDEO; | |
| 555 | 555 | histo->video.release = video_device_release_empty; |
| 556 | 556 | histo->video.ioctl_ops = &histo_v4l2_ioctl_ops; |
| 557 | 557 | histo->video.device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; |
| @@ -576,7 +576,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo, · 18 unmodified lines | ||
| 576 | 576 | |
| 577 | 577 | /* ... and register the video device. */ |
| 578 | 578 | histo->video.queue = &histo->queue; |
| 579 | − ret = video_register_device(&histo->video, VFL_TYPE_GRABBER, -1); | |
| 579 | + ret = video_register_device(&histo->video, VFL_TYPE_VIDEO, -1); | |
| 580 | 580 | if (ret < 0) { |
| 581 | 581 | dev_err(vsp1->dev, "failed to register video device\n"); |
| 582 | 582 | goto error; |
| @@ -706,7 +706,7 @@ · 705 unmodified lines | ||
| 706 | 706 | #define VI6_HGT_HUE_AREA_LOWER_SHIFT 16 |
| 707 | 707 | #define VI6_HGT_HUE_AREA_UPPER_SHIFT 0 |
| 708 | 708 | #define VI6_HGT_LB_TH 0x3424 |
| 709 | −#define VI6_HGT_LBn_H(n) (0x3438 + (n) * 8) | |
| 709 | +#define VI6_HGT_LBn_H(n) (0x3428 + (n) * 8) | |
| 710 | 710 | #define VI6_HGT_LBn_V(n) (0x342c + (n) * 8) |
| 711 | 711 | #define VI6_HGT_HISTO(m, n) (0x3450 + (m) * 128 + (n) * 4) |
| 712 | 712 | #define VI6_HGT_MAXMIN 0x3750 |
| @@ -1293,7 +1293,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, · 1292 unmodified lines | ||
| 1293 | 1293 | video->video.fops = &vsp1_video_fops; |
| 1294 | 1294 | snprintf(video->video.name, sizeof(video->video.name), "%s %s", |
| 1295 | 1295 | rwpf->entity.subdev.name, direction); |
| 1296 | − video->video.vfl_type = VFL_TYPE_GRABBER; | |
| 1296 | + video->video.vfl_type = VFL_TYPE_VIDEO; | |
| 1297 | 1297 | video->video.release = video_device_release_empty; |
| 1298 | 1298 | video->video.ioctl_ops = &vsp1_video_ioctl_ops; |
| 1299 | 1299 | |
| @@ -1316,7 +1316,7 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1, · 16 unmodified lines | ||
| 1316 | 1316 | |
| 1317 | 1317 | /* ... and register the video device. */ |
| 1318 | 1318 | video->video.queue = &video->queue; |
| 1319 | − ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); | |
| 1319 | + ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1); | |
| 1320 | 1320 | if (ret < 0) { |
| 1321 | 1321 | dev_err(video->vsp1->dev, "failed to register video device\n"); |
| 1322 | 1322 | goto error; |
| @@ -685,7 +685,7 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, · 684 unmodified lines | ||
| 685 | 685 | xdev->dev->of_node, |
| 686 | 686 | type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? "output" : "input", |
| 687 | 687 | port); |
| 688 | − dma->video.vfl_type = VFL_TYPE_GRABBER; | |
| 688 | + dma->video.vfl_type = VFL_TYPE_VIDEO; | |
| 689 | 689 | dma->video.vfl_dir = type == V4L2_BUF_TYPE_VIDEO_CAPTURE |
| 690 | 690 | ? VFL_DIR_RX : VFL_DIR_TX; |
| 691 | 691 | dma->video.release = video_device_release_empty; |
| @@ -725,16 +725,17 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, · 33 unmodified lines | ||
| 725 | 725 | |
| 726 | 726 | /* ... and the DMA channel. */ |
| 727 | 727 | snprintf(name, sizeof(name), "port%u", port); |
| 728 | − dma->dma = dma_request_slave_channel(dma->xdev->dev, name); | |
| 729 | − if (dma->dma == NULL) { | |
| 730 | − dev_err(dma->xdev->dev, "no VDMA channel found\n"); | |
| 731 | − ret = -ENODEV; | |
| 728 | + dma->dma = dma_request_chan(dma->xdev->dev, name); | |
| 729 | + if (IS_ERR(dma->dma)) { | |
| 730 | + ret = PTR_ERR(dma->dma); | |
| 731 | + if (ret != -EPROBE_DEFER) | |
| 732 | + dev_err(dma->xdev->dev, "no VDMA channel found\n"); | |
| 732 | 733 | goto error; |
| 733 | 734 | } |
| 734 | 735 | |
| 735 | 736 | dma->align = 1 << dma->dma->device->copy_align; |
| 736 | 737 | |
| 737 | − ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1); | |
| 738 | + ret = video_register_device(&dma->video, VFL_TYPE_VIDEO, -1); | |
| 738 | 739 | if (ret < 0) { |
| 739 | 740 | dev_err(dma->xdev->dev, "failed to register video device\n"); |
| 740 | 741 | goto error; |
| @@ -752,7 +753,7 @@ void xvip_dma_cleanup(struct xvip_dma *dma) · 11 unmodified lines | ||
| 752 | 753 | if (video_is_registered(&dma->video)) |
| 753 | 754 | video_unregister_device(&dma->video); |
| 754 | 755 | |
| 755 | − if (dma->dma) | |
| 756 | + if (!IS_ERR_OR_NULL(dma->dma)) | |
| 756 | 757 | dma_release_channel(dma->dma); |
| 757 | 758 | |
| 758 | 759 | media_entity_cleanup(&dma->video.entity); |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | 2 | config RADIO_SI470X |
| 3 | − tristate "Silicon Labs Si470x FM Radio Receiver support" | |
| 4 | − depends on VIDEO_V4L2 | |
| 3 | + tristate "Silicon Labs Si470x FM Radio Receiver support" | |
| 4 | + depends on VIDEO_V4L2 | |
| 5 | 5 | help |
| 6 | 6 | This is a driver for devices with the Silicon Labs SI470x |
| 7 | 7 | chip (either via USB or I2C buses). |
| @@ -35,11 +35,6 @@ static const struct bpf_func_proto rc_repeat_proto = { · 34 unmodified lines | ||
| 35 | 35 | .arg1_type = ARG_PTR_TO_CTX, |
| 36 | 36 | }; |
| 37 | 37 | |
| 38 | −/* | |
| 39 | − * Currently rc-core does not support 64-bit scancodes, but there are many | |
| 40 | − * known protocols with more than 32 bits. So, define the interface as u64 | |
| 41 | − * as a future-proof. | |
| 42 | − */ | |
| 43 | 38 | BPF_CALL_4(bpf_rc_keydown, u32*, sample, u32, protocol, u64, scancode, |
| 44 | 39 | u32, toggle) |
| 45 | 40 | { |
| @@ -76,7 +76,7 @@ struct send_packet { · 75 unmodified lines | ||
| 76 | 76 | uint8_t channels; |
| 77 | 77 | uint8_t busy7; |
| 78 | 78 | uint8_t busy4; |
| 79 | − uint8_t payload[0]; | |
| 79 | + uint8_t payload[]; | |
| 80 | 80 | }; |
| 81 | 81 | |
| 82 | 82 | static void process_ir_data(struct iguanair *ir, unsigned len) |
| @@ -166,7 +166,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev) · 165 unmodified lines | ||
| 166 | 166 | } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) { |
| 167 | 167 | /* store nibble raw data, decode after trailer */ |
| 168 | 168 | if (data->count == 16) { |
| 169 | − dev_dbg(&dev->dev, "to many pulses (%d) ignoring: %u\n", | |
| 169 | + dev_dbg(&dev->dev, "too many pulses (%d) ignoring: %u\n", | |
| 170 | 170 | data->count, ev.duration); |
| 171 | 171 | data->state = STATE_INACTIVE; |
| 172 | 172 | return -EINVAL; |
| @@ -119,6 +119,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ · 118 unmodified lines | ||
| 119 | 119 | rc-videomate-m1f.o \ |
| 120 | 120 | rc-videomate-s350.o \ |
| 121 | 121 | rc-videomate-tv-pvr.o \ |
| 122 | + rc-videostrong-kii-pro.o \ | |
| 122 | 123 | rc-wetek-hub.o \ |
| 123 | 124 | rc-wetek-play2.o \ |
| 124 | 125 | rc-winfast.o \ |
| @@ -0,0 +1,83 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +// | |
| 3 | +// Copyright (C) 2019 Mohammad Rasim <mohammad.rasim96@gmail.com> | |
| 4 | + | |
| 5 | +#include <media/rc-map.h> | |
| 6 | +#include <linux/module.h> | |
| 7 | + | |
| 8 | +// | |
| 9 | +// Keytable for the Videostrong KII Pro STB remote control | |
| 10 | +// | |
| 11 | + | |
| 12 | +static struct rc_map_table kii_pro[] = { | |
| 13 | + { 0x59, KEY_POWER }, | |
| 14 | + { 0x19, KEY_MUTE }, | |
| 15 | + { 0x42, KEY_RED }, | |
| 16 | + { 0x40, KEY_GREEN }, | |
| 17 | + { 0x00, KEY_YELLOW }, | |
| 18 | + { 0x03, KEY_BLUE }, | |
| 19 | + { 0x4a, KEY_BACK }, | |
| 20 | + { 0x48, KEY_FORWARD }, | |
| 21 | + { 0x08, KEY_PREVIOUSSONG}, | |
| 22 | + { 0x0b, KEY_NEXTSONG}, | |
| 23 | + { 0x46, KEY_PLAYPAUSE }, | |
| 24 | + { 0x44, KEY_STOP }, | |
| 25 | + { 0x1f, KEY_FAVORITES}, //KEY_F5? | |
| 26 | + { 0x04, KEY_PVR }, | |
| 27 | + { 0x4d, KEY_EPG }, | |
| 28 | + { 0x02, KEY_INFO }, | |
| 29 | + { 0x09, KEY_SUBTITLE }, | |
| 30 | + { 0x01, KEY_AUDIO }, | |
| 31 | + { 0x0d, KEY_HOMEPAGE }, | |
| 32 | + { 0x11, KEY_TV }, // DTV ? | |
| 33 | + { 0x06, KEY_UP }, | |
| 34 | + { 0x5a, KEY_LEFT }, | |
| 35 | + { 0x1a, KEY_ENTER }, // KEY_OK ? | |
| 36 | + { 0x1b, KEY_RIGHT }, | |
| 37 | + { 0x16, KEY_DOWN }, | |
| 38 | + { 0x45, KEY_MENU }, | |
| 39 | + { 0x05, KEY_ESC }, | |
| 40 | + { 0x13, KEY_VOLUMEUP }, | |
| 41 | + { 0x17, KEY_VOLUMEDOWN }, | |
| 42 | + { 0x58, KEY_APPSELECT }, | |
| 43 | + { 0x12, KEY_VENDOR }, // mouse | |
| 44 | + { 0x55, KEY_PAGEUP }, // KEY_CHANNELUP ? | |
| 45 | + { 0x15, KEY_PAGEDOWN }, // KEY_CHANNELDOWN ? | |
| 46 | + { 0x52, KEY_1 }, | |
| 47 | + { 0x50, KEY_2 }, | |
| 48 | + { 0x10, KEY_3 }, | |
| 49 | + { 0x56, KEY_4 }, | |
| 50 | + { 0x54, KEY_5 }, | |
| 51 | + { 0x14, KEY_6 }, | |
| 52 | + { 0x4e, KEY_7 }, | |
| 53 | + { 0x4c, KEY_8 }, | |
| 54 | + { 0x0c, KEY_9 }, | |
| 55 | + { 0x18, KEY_WWW }, // KEY_F7 | |
| 56 | + { 0x0f, KEY_0 }, | |
| 57 | + { 0x51, KEY_BACKSPACE }, | |
| 58 | +}; | |
| 59 | + | |
| 60 | +static struct rc_map_list kii_pro_map = { | |
| 61 | + .map = { | |
| 62 | + .scan = kii_pro, | |
| 63 | + .size = ARRAY_SIZE(kii_pro), | |
| 64 | + .rc_proto = RC_PROTO_NEC, | |
| 65 | + .name = RC_MAP_KII_PRO, | |
| 66 | + } | |
| 67 | +}; | |
| 68 | + | |
| 69 | +static int __init init_rc_map_kii_pro(void) | |
| 70 | +{ | |
| 71 | + return rc_map_register(&kii_pro_map); | |
| 72 | +} | |
| 73 | + | |
| 74 | +static void __exit exit_rc_map_kii_pro(void) | |
| 75 | +{ | |
| 76 | + rc_map_unregister(&kii_pro_map); | |
| 77 | +} | |
| 78 | + | |
| 79 | +module_init(init_rc_map_kii_pro) | |
| 80 | +module_exit(exit_rc_map_kii_pro) | |
| 81 | + | |
| 82 | +MODULE_LICENSE("GPL"); | |
| 83 | +MODULE_AUTHOR("Mohammad Rasim <mohammad.rasim96@gmail.com>"); | |
| @@ -269,12 +269,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf, · 268 unmodified lines | ||
| 269 | 269 | goto out_unlock; |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | − /* | |
| 273 | − * The scancode field in lirc_scancode is 64-bit simply | |
| 274 | − * to future-proof it, since there are IR protocols encode | |
| 275 | − * use more than 32 bits. For now only 32-bit protocols | |
| 276 | − * are supported. | |
| 277 | − */ | |
| 272 | + /* We only have encoders for 32-bit protocols. */ | |
| 278 | 273 | if (scan.scancode > U32_MAX || |
| 279 | 274 | !rc_validate_scancode(scan.rc_proto, scan.scancode)) { |
| 280 | 275 | ret = -EINVAL; |
| @@ -230,10 +230,10 @@ static ssize_t wakeup_data_show(struct device *dev, · 229 unmodified lines | ||
| 230 | 230 | for (i = 0; i < fifo_len; i++) { |
| 231 | 231 | duration = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY); |
| 232 | 232 | duration = (duration & BUF_LEN_MASK) * SAMPLE_PERIOD; |
| 233 | − buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, | |
| 233 | + buf_len += scnprintf(buf + buf_len, PAGE_SIZE - buf_len, | |
| 234 | 234 | "%d ", duration); |
| 235 | 235 | } |
| 236 | − buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); | |
| 236 | + buf_len += scnprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); | |
| 237 | 237 | |
| 238 | 238 | spin_unlock_irqrestore(&nvt->lock, flags); |
| 239 | 239 | |
| @@ -163,6 +163,41 @@ static struct rc_map_list empty_map = { · 162 unmodified lines | ||
| 163 | 163 | } |
| 164 | 164 | }; |
| 165 | 165 | |
| 166 | +/** | |
| 167 | + * scancode_to_u64() - converts scancode in &struct input_keymap_entry | |
| 168 | + * @ke: keymap entry containing scancode to be converted. | |
| 169 | + * @scancode: pointer to the location where converted scancode should | |
| 170 | + * be stored. | |
| 171 | + * | |
| 172 | + * This function is a version of input_scancode_to_scalar specialized for | |
| 173 | + * rc-core. | |
| 174 | + */ | |
| 175 | +static int scancode_to_u64(const struct input_keymap_entry *ke, u64 *scancode) | |
| 176 | +{ | |
| 177 | + switch (ke->len) { | |
| 178 | + case 1: | |
| 179 | + *scancode = *((u8 *)ke->scancode); | |
| 180 | + break; | |
| 181 | + | |
| 182 | + case 2: | |
| 183 | + *scancode = *((u16 *)ke->scancode); | |
| 184 | + break; | |
| 185 | + | |
| 186 | + case 4: | |
| 187 | + *scancode = *((u32 *)ke->scancode); | |
| 188 | + break; | |
| 189 | + | |
| 190 | + case 8: | |
| 191 | + *scancode = *((u64 *)ke->scancode); | |
| 192 | + break; | |
| 193 | + | |
| 194 | + default: | |
| 195 | + return -EINVAL; | |
| 196 | + } | |
| 197 | + | |
| 198 | + return 0; | |
| 199 | +} | |
| 200 | + | |
| 166 | 201 | /** |
| 167 | 202 | * ir_create_table() - initializes a scancode table |
| 168 | 203 | * @dev: the rc_dev device |
| @@ -285,13 +320,13 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, · 116 unmodified lines | ||
| 285 | 320 | |
| 286 | 321 | /* Did the user wish to remove the mapping? */ |
| 287 | 322 | if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) { |
| 288 | − dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04x\n", | |
| 323 | + dev_dbg(&dev->dev, "#%d: Deleting scan 0x%04llx\n", | |
| 289 | 324 | index, rc_map->scan[index].scancode); |
| 290 | 325 | rc_map->len--; |
| 291 | 326 | memmove(&rc_map->scan[index], &rc_map->scan[index+ 1], |
| 292 | 327 | (rc_map->len - index) * sizeof(struct rc_map_table)); |
| 293 | 328 | } else { |
| 294 | − dev_dbg(&dev->dev, "#%d: %s scan 0x%04x with key 0x%04x\n", | |
| 329 | + dev_dbg(&dev->dev, "#%d: %s scan 0x%04llx with key 0x%04x\n", | |
| 295 | 330 | index, |
| 296 | 331 | old_keycode == KEY_RESERVED ? "New" : "Replacing", |
| 297 | 332 | rc_map->scan[index].scancode, new_keycode); |
| @@ -334,8 +369,7 @@ static unsigned int ir_update_mapping(struct rc_dev *dev, · 36 unmodified lines | ||
| 334 | 369 | */ |
| 335 | 370 | static unsigned int ir_establish_scancode(struct rc_dev *dev, |
| 336 | 371 | struct rc_map *rc_map, |
| 337 | − unsigned int scancode, | |
| 338 | − bool resize) | |
| 372 | + u64 scancode, bool resize) | |
| 339 | 373 | { |
| 340 | 374 | unsigned int i; |
| 341 | 375 | |
| @@ -394,7 +428,7 @@ static int ir_setkeycode(struct input_dev *idev, · 52 unmodified lines | ||
| 394 | 428 | struct rc_dev *rdev = input_get_drvdata(idev); |
| 395 | 429 | struct rc_map *rc_map = &rdev->rc_map; |
| 396 | 430 | unsigned int index; |
| 397 | − unsigned int scancode; | |
| 431 | + u64 scancode; | |
| 398 | 432 | int retval = 0; |
| 399 | 433 | unsigned long flags; |
| 400 | 434 | |
| @@ -407,7 +441,7 @@ static int ir_setkeycode(struct input_dev *idev, · 6 unmodified lines | ||
| 407 | 441 | goto out; |
| 408 | 442 | } |
| 409 | 443 | } else { |
| 410 | − retval = input_scancode_to_scalar(ke, &scancode); | |
| 444 | + retval = scancode_to_u64(ke, &scancode); | |
| 411 | 445 | if (retval) |
| 412 | 446 | goto out; |
| 413 | 447 | |
| @@ -434,8 +468,7 @@ out: · 20 unmodified lines | ||
| 434 | 468 | * |
| 435 | 469 | * return: -ENOMEM if all keycodes could not be inserted, otherwise zero. |
| 436 | 470 | */ |
| 437 | −static int ir_setkeytable(struct rc_dev *dev, | |
| 438 | − const struct rc_map *from) | |
| 471 | +static int ir_setkeytable(struct rc_dev *dev, const struct rc_map *from) | |
| 439 | 472 | { |
| 440 | 473 | struct rc_map *rc_map = &dev->rc_map; |
| 441 | 474 | unsigned int i, index; |
| @@ -466,7 +499,7 @@ static int ir_setkeytable(struct rc_dev *dev, · 24 unmodified lines | ||
| 466 | 499 | |
| 467 | 500 | static int rc_map_cmp(const void *key, const void *elt) |
| 468 | 501 | { |
| 469 | − const unsigned int *scancode = key; | |
| 502 | + const u64 *scancode = key; | |
| 470 | 503 | const struct rc_map_table *e = elt; |
| 471 | 504 | |
| 472 | 505 | if (*scancode < e->scancode) |
| @@ -487,7 +520,7 @@ static int rc_map_cmp(const void *key, const void *elt) · 14 unmodified lines | ||
| 487 | 520 | * return: index in the table, -1U if not found |
| 488 | 521 | */ |
| 489 | 522 | static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, |
| 490 | − unsigned int scancode) | |
| 523 | + u64 scancode) | |
| 491 | 524 | { |
| 492 | 525 | struct rc_map_table *res; |
| 493 | 526 | |
| @@ -516,7 +549,7 @@ static int ir_getkeycode(struct input_dev *idev, · 22 unmodified lines | ||
| 516 | 549 | struct rc_map_table *entry; |
| 517 | 550 | unsigned long flags; |
| 518 | 551 | unsigned int index; |
| 519 | − unsigned int scancode; | |
| 552 | + u64 scancode; | |
| 520 | 553 | int retval; |
| 521 | 554 | |
| 522 | 555 | spin_lock_irqsave(&rc_map->lock, flags); |
| @@ -524,7 +557,7 @@ static int ir_getkeycode(struct input_dev *idev, · 1 unmodified line | ||
| 524 | 557 | if (ke->flags & INPUT_KEYMAP_BY_INDEX) { |
| 525 | 558 | index = ke->index; |
| 526 | 559 | } else { |
| 527 | − retval = input_scancode_to_scalar(ke, &scancode); | |
| 560 | + retval = scancode_to_u64(ke, &scancode); | |
| 528 | 561 | if (retval) |
| 529 | 562 | goto out; |
| 530 | 563 | |
| @@ -538,7 +571,6 @@ static int ir_getkeycode(struct input_dev *idev, · 7 unmodified lines | ||
| 538 | 571 | ke->keycode = entry->keycode; |
| 539 | 572 | ke->len = sizeof(entry->scancode); |
| 540 | 573 | memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode)); |
| 541 | − | |
| 542 | 574 | } else if (!(ke->flags & INPUT_KEYMAP_BY_INDEX)) { |
| 543 | 575 | /* |
| 544 | 576 | * We do not really know the valid range of scancodes |
| @@ -570,7 +602,7 @@ out: · 25 unmodified lines | ||
| 570 | 602 | * |
| 571 | 603 | * return: the corresponding keycode, or KEY_RESERVED |
| 572 | 604 | */ |
| 573 | −u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) | |
| 605 | +u32 rc_g_keycode_from_table(struct rc_dev *dev, u64 scancode) | |
| 574 | 606 | { |
| 575 | 607 | struct rc_map *rc_map = &dev->rc_map; |
| 576 | 608 | unsigned int keycode; |
| @@ -586,7 +618,7 @@ u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode) · 9 unmodified lines | ||
| 586 | 618 | spin_unlock_irqrestore(&rc_map->lock, flags); |
| 587 | 619 | |
| 588 | 620 | if (keycode != KEY_RESERVED) |
| 589 | − dev_dbg(&dev->dev, "%s: scancode 0x%04x keycode 0x%02x\n", | |
| 621 | + dev_dbg(&dev->dev, "%s: scancode 0x%04llx keycode 0x%02x\n", | |
| 590 | 622 | dev->device_name, scancode, keycode); |
| 591 | 623 | |
| 592 | 624 | return keycode; |
| @@ -719,8 +751,11 @@ void rc_repeat(struct rc_dev *dev) · 126 unmodified lines | ||
| 719 | 751 | |
| 720 | 752 | spin_lock_irqsave(&dev->keylock, flags); |
| 721 | 753 | |
| 722 | − input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode); | |
| 723 | − input_sync(dev->input_dev); | |
| 754 | + if (dev->last_scancode <= U32_MAX) { | |
| 755 | + input_event(dev->input_dev, EV_MSC, MSC_SCAN, | |
| 756 | + dev->last_scancode); | |
| 757 | + input_sync(dev->input_dev); | |
| 758 | + } | |
| 724 | 759 | |
| 725 | 760 | if (dev->keypressed) { |
| 726 | 761 | dev->keyup_jiffies = jiffies + timeout; |
| @@ -743,7 +778,7 @@ EXPORT_SYMBOL_GPL(rc_repeat); · 16 unmodified lines | ||
| 743 | 778 | * called with keylock held. |
| 744 | 779 | */ |
| 745 | 780 | static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, |
| 746 | − u32 scancode, u32 keycode, u8 toggle) | |
| 781 | + u64 scancode, u32 keycode, u8 toggle) | |
| 747 | 782 | { |
| 748 | 783 | bool new_event = (!dev->keypressed || |
| 749 | 784 | dev->last_protocol != protocol || |
| @@ -761,7 +796,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, · 11 unmodified lines | ||
| 761 | 796 | if (new_event && dev->keypressed) |
| 762 | 797 | ir_do_keyup(dev, false); |
| 763 | 798 | |
| 764 | − input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); | |
| 799 | + if (scancode <= U32_MAX) | |
| 800 | + input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode); | |
| 765 | 801 | |
| 766 | 802 | dev->last_protocol = protocol; |
| 767 | 803 | dev->last_scancode = scancode; |
| @@ -772,7 +808,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, · 4 unmodified lines | ||
| 772 | 808 | /* Register a keypress */ |
| 773 | 809 | dev->keypressed = true; |
| 774 | 810 | |
| 775 | − dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", | |
| 811 | + dev_dbg(&dev->dev, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08llx\n", | |
| 776 | 812 | dev->device_name, keycode, protocol, scancode); |
| 777 | 813 | input_report_key(dev->input_dev, keycode, 1); |
| 778 | 814 | |
| @@ -809,7 +845,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol, · 30 unmodified lines | ||
| 809 | 845 | * This routine is used to signal that a key has been pressed on the |
| 810 | 846 | * remote control. |
| 811 | 847 | */ |
| 812 | −void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode, | |
| 848 | +void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u64 scancode, | |
| 813 | 849 | u8 toggle) |
| 814 | 850 | { |
| 815 | 851 | unsigned long flags; |
| @@ -840,7 +876,7 @@ EXPORT_SYMBOL_GPL(rc_keydown); · 24 unmodified lines | ||
| 840 | 876 | * remote control. The driver must manually call rc_keyup() at a later stage. |
| 841 | 877 | */ |
| 842 | 878 | void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol, |
| 843 | − u32 scancode, u8 toggle) | |
| 879 | + u64 scancode, u8 toggle) | |
| 844 | 880 | { |
| 845 | 881 | unsigned long flags; |
| 846 | 882 | u32 keycode = rc_g_keycode_from_table(dev, scancode); |
| @@ -147,11 +147,17 @@ static int gs_read_register(struct spi_device *spi, u16 addr, u16 *value) · 146 unmodified lines | ||
| 147 | 147 | { |
| 148 | 148 | .tx_buf = &buf_addr, |
| 149 | 149 | .len = 2, |
| 150 | − .delay_usecs = 1, | |
| 150 | + .delay = { | |
| 151 | + .value = 1, | |
| 152 | + .unit = SPI_DELAY_UNIT_USECS | |
| 153 | + }, | |
| 151 | 154 | }, { |
| 152 | 155 | .rx_buf = &buf_value, |
| 153 | 156 | .len = 2, |
| 154 | − .delay_usecs = 1, | |
| 157 | + .delay = { | |
| 158 | + .value = 1, | |
| 159 | + .unit = SPI_DELAY_UNIT_USECS | |
| 160 | + }, | |
| 155 | 161 | }, |
| 156 | 162 | }; |
| 157 | 163 | |
| @@ -175,11 +181,17 @@ static int gs_write_register(struct spi_device *spi, u16 addr, u16 value) · 17 unmodified lines | ||
| 175 | 181 | { |
| 176 | 182 | .tx_buf = &buf_addr, |
| 177 | 183 | .len = 2, |
| 178 | − .delay_usecs = 1, | |
| 184 | + .delay = { | |
| 185 | + .value = 1, | |
| 186 | + .unit = SPI_DELAY_UNIT_USECS | |
| 187 | + }, | |
| 179 | 188 | }, { |
| 180 | 189 | .tx_buf = &buf_value, |
| 181 | 190 | .len = 2, |
| 182 | − .delay_usecs = 1, | |
| 191 | + .delay = { | |
| 192 | + .value = 1, | |
| 193 | + .unit = SPI_DELAY_UNIT_USECS | |
| 194 | + }, | |
| 183 | 195 | }, |
| 184 | 196 | }; |
| 185 | 197 | |
| @@ -25,7 +25,6 @@ if MEDIA_ANALOG_TV_SUPPORT · 24 unmodified lines | ||
| 25 | 25 | comment "Analog TV USB devices" |
| 26 | 26 | source "drivers/media/usb/pvrusb2/Kconfig" |
| 27 | 27 | source "drivers/media/usb/hdpvr/Kconfig" |
| 28 | −source "drivers/media/usb/usbvision/Kconfig" | |
| 29 | 28 | source "drivers/media/usb/stk1160/Kconfig" |
| 30 | 29 | source "drivers/media/usb/go7007/Kconfig" |
| 31 | 30 | endif |
| @@ -17,7 +17,6 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ · 16 unmodified lines | ||
| 17 | 17 | obj-$(CONFIG_VIDEO_AU0828) += au0828/ |
| 18 | 18 | obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ |
| 19 | 19 | obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ |
| 20 | −obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | |
| 21 | 20 | obj-$(CONFIG_VIDEO_STK1160) += stk1160/ |
| 22 | 21 | obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ |
| 23 | 22 | obj-$(CONFIG_VIDEO_TM6000) += tm6000/ |
| @@ -1042,7 +1042,7 @@ static int au0828_v4l2_close(struct file *filp) · 1041 unmodified lines | ||
| 1042 | 1042 | dev->streaming_users, dev->users); |
| 1043 | 1043 | |
| 1044 | 1044 | mutex_lock(&dev->lock); |
| 1045 | − if (vdev->vfl_type == VFL_TYPE_GRABBER && dev->vid_timeout_running) { | |
| 1045 | + if (vdev->vfl_type == VFL_TYPE_VIDEO && dev->vid_timeout_running) { | |
| 1046 | 1046 | /* Cancel timeout thread in case they didn't call streamoff */ |
| 1047 | 1047 | dev->vid_timeout_running = 0; |
| 1048 | 1048 | del_timer_sync(&dev->vid_timeout); |
| @@ -2007,7 +2007,7 @@ int au0828_analog_register(struct au0828_dev *dev, · 958 unmodified lines | ||
| 2007 | 2007 | |
| 2008 | 2008 | /* Register the v4l2 device */ |
| 2009 | 2009 | video_set_drvdata(&dev->vdev, dev); |
| 2010 | − retval = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); | |
| 2010 | + retval = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1); | |
| 2011 | 2011 | if (retval != 0) { |
| 2012 | 2012 | dprintk(1, "unable to register video device (error = %d).\n", |
| 2013 | 2013 | retval); |
| @@ -511,6 +511,9 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb) · 510 unmodified lines | ||
| 511 | 511 | return ret; |
| 512 | 512 | } |
| 513 | 513 | |
| 514 | + if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1) | |
| 515 | + return -ENODEV; | |
| 516 | + | |
| 514 | 517 | switch (fc_usb->udev->speed) { |
| 515 | 518 | case USB_SPEED_LOW: |
| 516 | 519 | err("cannot handle USB speed because it is too slow."); |
| @@ -544,9 +547,6 @@ static int flexcop_usb_probe(struct usb_interface *intf, · 27 unmodified lines | ||
| 544 | 547 | struct flexcop_device *fc = NULL; |
| 545 | 548 | int ret; |
| 546 | 549 | |
| 547 | − if (intf->cur_altsetting->desc.bNumEndpoints < 1) | |
| 548 | − return -ENODEV; | |
| 549 | − | |
| 550 | 550 | if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { |
| 551 | 551 | err("out of memory\n"); |
| 552 | 552 | return -ENOMEM; |
| @@ -1134,7 +1134,7 @@ int cpia2_register_camera(struct camera_data *cam) · 1133 unmodified lines | ||
| 1134 | 1134 | reset_camera_struct_v4l(cam); |
| 1135 | 1135 | |
| 1136 | 1136 | /* register v4l device */ |
| 1137 | − if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { | |
| 1137 | + if (video_register_device(&cam->vdev, VFL_TYPE_VIDEO, video_nr) < 0) { | |
| 1138 | 1138 | ERR("video_register_device failed\n"); |
| 1139 | 1139 | return -ENODEV; |
| 1140 | 1140 | } |
| @@ -1790,7 +1790,7 @@ int cx231xx_417_register(struct cx231xx *dev) · 1789 unmodified lines | ||
| 1790 | 1790 | dev->v4l_device.queue = q; |
| 1791 | 1791 | |
| 1792 | 1792 | err = video_register_device(&dev->v4l_device, |
| 1793 | − VFL_TYPE_GRABBER, -1); | |
| 1793 | + VFL_TYPE_VIDEO, -1); | |
| 1794 | 1794 | if (err < 0) { |
| 1795 | 1795 | dprintk(3, "%s: can't register mpeg device\n", dev->name); |
| 1796 | 1796 | v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl); |
| @@ -147,7 +147,7 @@ static struct tda18271_config pv_tda18271_config = { · 146 unmodified lines | ||
| 147 | 147 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, |
| 148 | 148 | }; |
| 149 | 149 | |
| 150 | −static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { | |
| 150 | +static const struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { | |
| 151 | 151 | .qam_if_khz = 4000, |
| 152 | 152 | .vsb_if_khz = 3250, |
| 153 | 153 | .spectral_inversion = 1, |
| @@ -1785,7 +1785,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) · 1784 unmodified lines | ||
| 1785 | 1785 | dev->vdev.device_caps |= V4L2_CAP_TUNER; |
| 1786 | 1786 | |
| 1787 | 1787 | /* register v4l2 video video_device */ |
| 1788 | − ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, | |
| 1788 | + ret = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, | |
| 1789 | 1789 | video_nr[dev->devno]); |
| 1790 | 1790 | if (ret) { |
| 1791 | 1791 | dev_err(dev->dev, |
| @@ -318,14 +318,14 @@ static struct tda10023_config anysee_tda10023_tda18212_config = { · 317 unmodified lines | ||
| 318 | 318 | .deltaf = 0xba02, |
| 319 | 319 | }; |
| 320 | 320 | |
| 321 | −static struct tda18212_config anysee_tda18212_config = { | |
| 321 | +static const struct tda18212_config anysee_tda18212_config = { | |
| 322 | 322 | .if_dvbt_6 = 4150, |
| 323 | 323 | .if_dvbt_7 = 4150, |
| 324 | 324 | .if_dvbt_8 = 4150, |
| 325 | 325 | .if_dvbc = 5000, |
| 326 | 326 | }; |
| 327 | 327 | |
| 328 | −static struct tda18212_config anysee_tda18212_config2 = { | |
| 328 | +static const struct tda18212_config anysee_tda18212_config2 = { | |
| 329 | 329 | .if_dvbt_6 = 3550, |
| 330 | 330 | .if_dvbt_7 = 3700, |
| 331 | 331 | .if_dvbt_8 = 4150, |
| @@ -486,13 +486,10 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], · 485 unmodified lines | ||
| 486 | 486 | static u8 obuf[64], ibuf[64]; |
| 487 | 487 | int i, read, read_o; |
| 488 | 488 | u16 len; |
| 489 | − u8 gate = st->i2c_gate; | |
| 489 | + u8 gate; | |
| 490 | 490 | |
| 491 | 491 | mutex_lock(&d->i2c_mutex); |
| 492 | 492 | |
| 493 | − if (gate == 0) | |
| 494 | − gate = 5; | |
| 495 | − | |
| 496 | 493 | for (i = 0; i < num; i++) { |
| 497 | 494 | read_o = msg[i].flags & I2C_M_RD; |
| 498 | 495 | read = i + 1 < num && msg[i + 1].flags & I2C_M_RD; |
| @@ -552,6 +552,9 @@ tuner_found: · 551 unmodified lines | ||
| 552 | 552 | if (ret) |
| 553 | 553 | goto err; |
| 554 | 554 | |
| 555 | + /* slave demod needs some time to wake up */ | |
| 556 | + msleep(20); | |
| 557 | + | |
| 555 | 558 | /* check slave answers */ |
| 556 | 559 | ret = rtl28xxu_ctrl_msg(d, &req_mn88472); |
| 557 | 560 | if (ret == 0 && buf[0] == 0x02) { |
| @@ -1223,7 +1223,7 @@ static int cxusb_medion_g_tuner(struct file *file, void *fh, · 1222 unmodified lines | ||
| 1223 | 1223 | if (tuner->index != 0) |
| 1224 | 1224 | return -EINVAL; |
| 1225 | 1225 | |
| 1226 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 1226 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 1227 | 1227 | tuner->type = V4L2_TUNER_ANALOG_TV; |
| 1228 | 1228 | else |
| 1229 | 1229 | tuner->type = V4L2_TUNER_RADIO; |
| @@ -1259,7 +1259,7 @@ static int cxusb_medion_g_tuner(struct file *file, void *fh, · 29 unmodified lines | ||
| 1259 | 1259 | if (ret != 0) |
| 1260 | 1260 | return ret; |
| 1261 | 1261 | |
| 1262 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 1262 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 1263 | 1263 | strscpy(tuner->name, "TV tuner", sizeof(tuner->name)); |
| 1264 | 1264 | else |
| 1265 | 1265 | strscpy(tuner->name, "Radio tuner", sizeof(tuner->name)); |
| @@ -1292,7 +1292,7 @@ static int cxusb_medion_s_tuner(struct file *file, void *fh, · 26 unmodified lines | ||
| 1292 | 1292 | * make sure that cx25840 is in a correct TV / radio mode, |
| 1293 | 1293 | * since calls above may have changed it for tuner / IF demod |
| 1294 | 1294 | */ |
| 1295 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 1295 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 1296 | 1296 | v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); |
| 1297 | 1297 | else |
| 1298 | 1298 | v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); |
| @@ -1335,7 +1335,7 @@ static int cxusb_medion_s_frequency(struct file *file, void *fh, · 36 unmodified lines | ||
| 1335 | 1335 | * make sure that cx25840 is in a correct TV / radio mode, |
| 1336 | 1336 | * since calls above may have changed it for tuner / IF demod |
| 1337 | 1337 | */ |
| 1338 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 1338 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 1339 | 1339 | v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); |
| 1340 | 1340 | else |
| 1341 | 1341 | v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); |
| @@ -1564,7 +1564,7 @@ static int cxusb_videoradio_release(struct file *f) · 222 unmodified lines | ||
| 1564 | 1564 | |
| 1565 | 1565 | cxusb_vprintk(dvbdev, OPS, "got release\n"); |
| 1566 | 1566 | |
| 1567 | − if (vdev->vfl_type == VFL_TYPE_GRABBER) | |
| 1567 | + if (vdev->vfl_type == VFL_TYPE_VIDEO) | |
| 1568 | 1568 | ret = vb2_fop_release(f); |
| 1569 | 1569 | else |
| 1570 | 1570 | ret = v4l2_fh_release(f); |
| @@ -1663,7 +1663,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) · 92 unmodified lines | ||
| 1663 | 1663 | cxdev->videodev->lock = &cxdev->dev_lock; |
| 1664 | 1664 | video_set_drvdata(cxdev->videodev, dvbdev); |
| 1665 | 1665 | |
| 1666 | − ret = video_register_device(cxdev->videodev, VFL_TYPE_GRABBER, -1); | |
| 1666 | + ret = video_register_device(cxdev->videodev, VFL_TYPE_VIDEO, -1); | |
| 1667 | 1667 | if (ret) { |
| 1668 | 1668 | dev_err(&dvbdev->udev->dev, |
| 1669 | 1669 | "video device register failed, ret = %d\n", ret); |
| @@ -818,7 +818,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) · 817 unmodified lines | ||
| 818 | 818 | |
| 819 | 819 | /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ |
| 820 | 820 | |
| 821 | − if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1) | |
| 821 | + if (intf->cur_altsetting->desc.bNumEndpoints < rc_ep + 1) | |
| 822 | 822 | return -ENODEV; |
| 823 | 823 | |
| 824 | 824 | purb = usb_alloc_urb(0, GFP_KERNEL); |
| @@ -838,7 +838,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf) · 13 unmodified lines | ||
| 838 | 838 | * Some devices like the Hauppauge NovaTD model 52009 use an interrupt |
| 839 | 839 | * endpoint, while others use a bulk one. |
| 840 | 840 | */ |
| 841 | − e = &intf->altsetting[0].endpoint[rc_ep].desc; | |
| 841 | + e = &intf->cur_altsetting->endpoint[rc_ep].desc; | |
| 842 | 842 | if (usb_endpoint_dir_in(e)) { |
| 843 | 843 | if (usb_endpoint_xfer_bulk(e)) { |
| 844 | 844 | pipe = usb_rcvbulkpipe(d->udev, rc_ep); |
| @@ -1524,6 +1524,29 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap) · 1523 unmodified lines | ||
| 1524 | 1524 | return -EIO; |
| 1525 | 1525 | } |
| 1526 | 1526 | |
| 1527 | +static int tt_s2_4600_frontend_attach_probe_demod(struct dvb_usb_device *d, | |
| 1528 | + const int probe_addr) | |
| 1529 | +{ | |
| 1530 | + struct dw2102_state *state = d->priv; | |
| 1531 | + | |
| 1532 | + state->data[0] = 0x9; | |
| 1533 | + state->data[1] = 0x1; | |
| 1534 | + state->data[2] = 0x1; | |
| 1535 | + state->data[3] = probe_addr; | |
| 1536 | + state->data[4] = 0x0; | |
| 1537 | + | |
| 1538 | + if (dvb_usb_generic_rw(d, state->data, 5, state->data, 2, 0) < 0) { | |
| 1539 | + err("i2c probe for address 0x%x failed.", probe_addr); | |
| 1540 | + return 0; | |
| 1541 | + } | |
| 1542 | + | |
| 1543 | + if (state->data[0] != 8) /* fail(7) or error, no device at address */ | |
| 1544 | + return 0; | |
| 1545 | + | |
| 1546 | + /* probing successful */ | |
| 1547 | + return 1; | |
| 1548 | +} | |
| 1549 | + | |
| 1527 | 1550 | static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) |
| 1528 | 1551 | { |
| 1529 | 1552 | struct dvb_usb_device *d = adap->dev; |
| @@ -1533,6 +1556,7 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) · 3 unmodified lines | ||
| 1533 | 1556 | struct i2c_board_info board_info; |
| 1534 | 1557 | struct m88ds3103_platform_data m88ds3103_pdata = {}; |
| 1535 | 1558 | struct ts2020_config ts2020_config = {}; |
| 1559 | + int demod_addr; | |
| 1536 | 1560 | |
| 1537 | 1561 | mutex_lock(&d->data_mutex); |
| 1538 | 1562 | |
| @@ -1570,8 +1594,22 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) · 31 unmodified lines | ||
| 1570 | 1594 | if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0) |
| 1571 | 1595 | err("command 0x51 transfer failed."); |
| 1572 | 1596 | |
| 1597 | + /* probe for demodulator i2c address */ | |
| 1598 | + demod_addr = -1; | |
| 1599 | + if (tt_s2_4600_frontend_attach_probe_demod(d, 0x68)) | |
| 1600 | + demod_addr = 0x68; | |
| 1601 | + else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x69)) | |
| 1602 | + demod_addr = 0x69; | |
| 1603 | + else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x6a)) | |
| 1604 | + demod_addr = 0x6a; | |
| 1605 | + | |
| 1573 | 1606 | mutex_unlock(&d->data_mutex); |
| 1574 | 1607 | |
| 1608 | + if (demod_addr < 0) { | |
| 1609 | + err("probing for demodulator failed. Is the external power switched on?"); | |
| 1610 | + return -ENODEV; | |
| 1611 | + } | |
| 1612 | + | |
| 1575 | 1613 | /* attach demod */ |
| 1576 | 1614 | m88ds3103_pdata.clk = 27000000; |
| 1577 | 1615 | m88ds3103_pdata.i2c_wr_max = 33; |
| @@ -1586,8 +1624,11 @@ static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap) · 8 unmodified lines | ||
| 1586 | 1624 | m88ds3103_pdata.lnb_hv_pol = 1; |
| 1587 | 1625 | m88ds3103_pdata.lnb_en_pol = 0; |
| 1588 | 1626 | memset(&board_info, 0, sizeof(board_info)); |
| 1589 | − strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); | |
| 1590 | − board_info.addr = 0x68; | |
| 1627 | + if (demod_addr == 0x6a) | |
| 1628 | + strscpy(board_info.type, "m88ds3103b", I2C_NAME_SIZE); | |
| 1629 | + else | |
| 1630 | + strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); | |
| 1631 | + board_info.addr = demod_addr; | |
| 1591 | 1632 | board_info.platform_data = &m88ds3103_pdata; |
| 1592 | 1633 | request_module("m88ds3103"); |
| 1593 | 1634 | client = i2c_new_client_device(&d->i2c_adap, &board_info); |
| @@ -2397,6 +2397,20 @@ const struct em28xx_board em28xx_boards[] = { · 2396 unmodified lines | ||
| 2397 | 2397 | .has_dvb = 1, |
| 2398 | 2398 | .ir_codes = RC_MAP_PINNACLE_PCTV_HD, |
| 2399 | 2399 | }, |
| 2400 | + /* | |
| 2401 | + * 2013:0259 PCTV DVB-S2 Stick (461e_v2) | |
| 2402 | + * Empia EM28178, Montage M88DS3103b, Montage M88TS2022, Allegro A8293 | |
| 2403 | + */ | |
| 2404 | + [EM28178_BOARD_PCTV_461E_V2] = { | |
| 2405 | + .def_i2c_bus = 1, | |
| 2406 | + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | | |
| 2407 | + EM28XX_I2C_FREQ_400_KHZ, | |
| 2408 | + .name = "PCTV DVB-S2 Stick (461e v2)", | |
| 2409 | + .tuner_type = TUNER_ABSENT, | |
| 2410 | + .tuner_gpio = pctv_461e, | |
| 2411 | + .has_dvb = 1, | |
| 2412 | + .ir_codes = RC_MAP_PINNACLE_PCTV_HD, | |
| 2413 | + }, | |
| 2400 | 2414 | /* |
| 2401 | 2415 | * 2013:025f PCTV tripleStick (292e). |
| 2402 | 2416 | * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 |
| @@ -2696,6 +2710,10 @@ struct usb_device_id em28xx_id_table[] = { · 293 unmodified lines | ||
| 2696 | 2710 | .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, |
| 2697 | 2711 | { USB_DEVICE(0x2013, 0x0258), |
| 2698 | 2712 | .driver_info = EM28178_BOARD_PCTV_461E }, |
| 2713 | + { USB_DEVICE(0x2013, 0x0461), | |
| 2714 | + .driver_info = EM28178_BOARD_PCTV_461E_V2 }, | |
| 2715 | + { USB_DEVICE(0x2013, 0x0259), | |
| 2716 | + .driver_info = EM28178_BOARD_PCTV_461E_V2 }, | |
| 2699 | 2717 | { USB_DEVICE(0x2013, 0x025f), |
| 2700 | 2718 | .driver_info = EM28178_BOARD_PCTV_292E }, |
| 2701 | 2719 | { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */ |
| @@ -1219,6 +1219,61 @@ static int em28178_dvb_init_pctv_461e(struct em28xx *dev) · 1218 unmodified lines | ||
| 1219 | 1219 | return 0; |
| 1220 | 1220 | } |
| 1221 | 1221 | |
| 1222 | +static int em28178_dvb_init_pctv_461e_v2(struct em28xx *dev) | |
| 1223 | +{ | |
| 1224 | + struct em28xx_dvb *dvb = dev->dvb; | |
| 1225 | + struct i2c_adapter *i2c_adapter; | |
| 1226 | + struct m88ds3103_platform_data m88ds3103_pdata = {}; | |
| 1227 | + struct ts2020_config ts2020_config = {}; | |
| 1228 | + struct a8293_platform_data a8293_pdata = {}; | |
| 1229 | + | |
| 1230 | + /* attach demod */ | |
| 1231 | + m88ds3103_pdata.clk = 27000000; | |
| 1232 | + m88ds3103_pdata.i2c_wr_max = 33; | |
| 1233 | + m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; | |
| 1234 | + m88ds3103_pdata.ts_clk = 16000; | |
| 1235 | + m88ds3103_pdata.ts_clk_pol = 0; | |
| 1236 | + m88ds3103_pdata.agc = 0x99; | |
| 1237 | + m88ds3103_pdata.agc_inv = 0; | |
| 1238 | + m88ds3103_pdata.spec_inv = 0; | |
| 1239 | + dvb->i2c_client_demod = dvb_module_probe("m88ds3103", "m88ds3103b", | |
| 1240 | + &dev->i2c_adap[dev->def_i2c_bus], | |
| 1241 | + 0x6a, &m88ds3103_pdata); | |
| 1242 | + | |
| 1243 | + if (!dvb->i2c_client_demod) | |
| 1244 | + return -ENODEV; | |
| 1245 | + | |
| 1246 | + dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod); | |
| 1247 | + i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod); | |
| 1248 | + | |
| 1249 | + /* attach tuner */ | |
| 1250 | + ts2020_config.fe = dvb->fe[0]; | |
| 1251 | + dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022", | |
| 1252 | + i2c_adapter, | |
| 1253 | + 0x60, &ts2020_config); | |
| 1254 | + if (!dvb->i2c_client_tuner) { | |
| 1255 | + dvb_module_release(dvb->i2c_client_demod); | |
| 1256 | + return -ENODEV; | |
| 1257 | + } | |
| 1258 | + | |
| 1259 | + /* delegate signal strength measurement to tuner */ | |
| 1260 | + dvb->fe[0]->ops.read_signal_strength = | |
| 1261 | + dvb->fe[0]->ops.tuner_ops.get_rf_strength; | |
| 1262 | + | |
| 1263 | + /* attach SEC */ | |
| 1264 | + a8293_pdata.dvb_frontend = dvb->fe[0]; | |
| 1265 | + dvb->i2c_client_sec = dvb_module_probe("a8293", NULL, | |
| 1266 | + &dev->i2c_adap[dev->def_i2c_bus], | |
| 1267 | + 0x08, &a8293_pdata); | |
| 1268 | + if (!dvb->i2c_client_sec) { | |
| 1269 | + dvb_module_release(dvb->i2c_client_tuner); | |
| 1270 | + dvb_module_release(dvb->i2c_client_demod); | |
| 1271 | + return -ENODEV; | |
| 1272 | + } | |
| 1273 | + | |
| 1274 | + return 0; | |
| 1275 | +} | |
| 1276 | + | |
| 1222 | 1277 | static int em28178_dvb_init_pctv_292e(struct em28xx *dev) |
| 1223 | 1278 | { |
| 1224 | 1279 | struct em28xx_dvb *dvb = dev->dvb; |
| @@ -1860,6 +1915,11 @@ static int em28xx_dvb_init(struct em28xx *dev) · 635 unmodified lines | ||
| 1860 | 1915 | if (result) |
| 1861 | 1916 | goto out_free; |
| 1862 | 1917 | break; |
| 1918 | + case EM28178_BOARD_PCTV_461E_V2: | |
| 1919 | + result = em28178_dvb_init_pctv_461e_v2(dev); | |
| 1920 | + if (result) | |
| 1921 | + goto out_free; | |
| 1922 | + break; | |
| 1863 | 1923 | case EM28178_BOARD_PCTV_292E: |
| 1864 | 1924 | result = em28178_dvb_init_pctv_292e(dev); |
| 1865 | 1925 | if (result) |
| @@ -2141,7 +2141,7 @@ static int em28xx_v4l2_open(struct file *filp) · 2140 unmodified lines | ||
| 2141 | 2141 | int ret; |
| 2142 | 2142 | |
| 2143 | 2143 | switch (vdev->vfl_type) { |
| 2144 | − case VFL_TYPE_GRABBER: | |
| 2144 | + case VFL_TYPE_VIDEO: | |
| 2145 | 2145 | fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 2146 | 2146 | break; |
| 2147 | 2147 | case VFL_TYPE_VBI: |
| @@ -2789,7 +2789,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) · 641 unmodified lines | ||
| 2789 | 2789 | } |
| 2790 | 2790 | |
| 2791 | 2791 | /* register v4l2 video video_device */ |
| 2792 | − ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, | |
| 2792 | + ret = video_register_device(&v4l2->vdev, VFL_TYPE_VIDEO, | |
| 2793 | 2793 | video_nr[dev->devno]); |
| 2794 | 2794 | if (ret) { |
| 2795 | 2795 | dev_err(&dev->intf->dev, |
| @@ -150,6 +150,7 @@ · 149 unmodified lines | ||
| 150 | 150 | #define EM2884_BOARD_TERRATEC_H6 101 |
| 151 | 151 | #define EM2882_BOARD_ZOLID_HYBRID_TV_STICK 102 |
| 152 | 152 | #define EM2861_BOARD_MAGIX_VIDEOWANDLER2 103 |
| 153 | +#define EM28178_BOARD_PCTV_461E_V2 104 | |
| 153 | 154 | |
| 154 | 155 | /* Limits minimum and default number of buffers */ |
| 155 | 156 | #define EM28XX_MIN_BUF 4 |
| @@ -1044,6 +1044,7 @@ static int go7007_usb_probe(struct usb_interface *intf, · 1043 unmodified lines | ||
| 1044 | 1044 | struct go7007_usb *usb; |
| 1045 | 1045 | const struct go7007_usb_board *board; |
| 1046 | 1046 | struct usb_device *usbdev = interface_to_usbdev(intf); |
| 1047 | + struct usb_host_endpoint *ep; | |
| 1047 | 1048 | unsigned num_i2c_devs; |
| 1048 | 1049 | char *name; |
| 1049 | 1050 | int video_pipe, i, v_urb_len; |
| @@ -1140,7 +1141,8 @@ static int go7007_usb_probe(struct usb_interface *intf, · 90 unmodified lines | ||
| 1140 | 1141 | if (usb->intr_urb->transfer_buffer == NULL) |
| 1141 | 1142 | goto allocfail; |
| 1142 | 1143 | |
| 1143 | − if (go->board_id == GO7007_BOARDID_SENSORAY_2250) | |
| 1144 | + ep = usb->usbdev->ep_in[4]; | |
| 1145 | + if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK) | |
| 1144 | 1146 | usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, |
| 1145 | 1147 | usb_rcvbulkpipe(usb->usbdev, 4), |
| 1146 | 1148 | usb->intr_urb->transfer_buffer, 2*sizeof(u16), |
| @@ -1138,7 +1138,7 @@ int go7007_v4l2_init(struct go7007 *go) · 1137 unmodified lines | ||
| 1138 | 1138 | go7007_s_input(go); |
| 1139 | 1139 | if (go->board_info->sensor_flags & GO7007_SENSOR_TV) |
| 1140 | 1140 | go7007_s_std(go); |
| 1141 | − rv = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1141 | + rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1142 | 1142 | if (rv < 0) |
| 1143 | 1143 | return rv; |
| 1144 | 1144 | dev_info(go->dev, "registered device %s [v4l2]\n", |
| @@ -1555,7 +1555,7 @@ int gspca_dev_probe2(struct usb_interface *intf, · 1554 unmodified lines | ||
| 1555 | 1555 | |
| 1556 | 1556 | /* init video stuff */ |
| 1557 | 1557 | ret = video_register_device(&gspca_dev->vdev, |
| 1558 | − VFL_TYPE_GRABBER, | |
| 1558 | + VFL_TYPE_VIDEO, | |
| 1559 | 1559 | -1); |
| 1560 | 1560 | if (ret < 0) { |
| 1561 | 1561 | pr_err("video_register_device err %d\n", ret); |
| @@ -3477,6 +3477,11 @@ static void ov511_mode_init_regs(struct sd *sd) · 3476 unmodified lines | ||
| 3477 | 3477 | return; |
| 3478 | 3478 | } |
| 3479 | 3479 | |
| 3480 | + if (alt->desc.bNumEndpoints < 1) { | |
| 3481 | + sd->gspca_dev.usb_err = -ENODEV; | |
| 3482 | + return; | |
| 3483 | + } | |
| 3484 | + | |
| 3480 | 3485 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 3481 | 3486 | reg_w(sd, R51x_FIFO_PSIZE, packet_size >> 5); |
| 3482 | 3487 | |
| @@ -3603,6 +3608,11 @@ static void ov518_mode_init_regs(struct sd *sd) · 120 unmodified lines | ||
| 3603 | 3608 | return; |
| 3604 | 3609 | } |
| 3605 | 3610 | |
| 3611 | + if (alt->desc.bNumEndpoints < 1) { | |
| 3612 | + sd->gspca_dev.usb_err = -ENODEV; | |
| 3613 | + return; | |
| 3614 | + } | |
| 3615 | + | |
| 3606 | 3616 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 3607 | 3617 | ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2); |
| 3608 | 3618 | |
| @@ -282,6 +282,9 @@ static int stv06xx_start(struct gspca_dev *gspca_dev) · 281 unmodified lines | ||
| 282 | 282 | return -EIO; |
| 283 | 283 | } |
| 284 | 284 | |
| 285 | + if (alt->desc.bNumEndpoints < 1) | |
| 286 | + return -ENODEV; | |
| 287 | + | |
| 285 | 288 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 286 | 289 | err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size); |
| 287 | 290 | if (err < 0) |
| @@ -306,11 +309,21 @@ out: · 18 unmodified lines | ||
| 306 | 309 | |
| 307 | 310 | static int stv06xx_isoc_init(struct gspca_dev *gspca_dev) |
| 308 | 311 | { |
| 312 | + struct usb_interface_cache *intfc; | |
| 309 | 313 | struct usb_host_interface *alt; |
| 310 | 314 | struct sd *sd = (struct sd *) gspca_dev; |
| 311 | 315 | |
| 316 | + intfc = gspca_dev->dev->actconfig->intf_cache[0]; | |
| 317 | + | |
| 318 | + if (intfc->num_altsetting < 2) | |
| 319 | + return -ENODEV; | |
| 320 | + | |
| 321 | + alt = &intfc->altsetting[1]; | |
| 322 | + | |
| 323 | + if (alt->desc.bNumEndpoints < 1) | |
| 324 | + return -ENODEV; | |
| 325 | + | |
| 312 | 326 | /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ |
| 313 | − alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; | |
| 314 | 327 | alt->endpoint[0].desc.wMaxPacketSize = |
| 315 | 328 | cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]); |
| 316 | 329 | |
| @@ -323,6 +336,10 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) · 6 unmodified lines | ||
| 323 | 336 | struct usb_host_interface *alt; |
| 324 | 337 | struct sd *sd = (struct sd *) gspca_dev; |
| 325 | 338 | |
| 339 | + /* | |
| 340 | + * Existence of altsetting and endpoint was verified in | |
| 341 | + * stv06xx_isoc_init() | |
| 342 | + */ | |
| 326 | 343 | alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; |
| 327 | 344 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 328 | 345 | min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode]; |
| @@ -185,6 +185,10 @@ static int pb0100_start(struct sd *sd) · 184 unmodified lines | ||
| 185 | 185 | alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); |
| 186 | 186 | if (!alt) |
| 187 | 187 | return -ENODEV; |
| 188 | + | |
| 189 | + if (alt->desc.bNumEndpoints < 1) | |
| 190 | + return -ENODEV; | |
| 191 | + | |
| 188 | 192 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 189 | 193 | |
| 190 | 194 | /* If we don't have enough bandwidth use a lower framerate */ |
| @@ -1442,6 +1442,9 @@ static int cit_get_packet_size(struct gspca_dev *gspca_dev) · 1441 unmodified lines | ||
| 1442 | 1442 | return -EIO; |
| 1443 | 1443 | } |
| 1444 | 1444 | |
| 1445 | + if (alt->desc.bNumEndpoints < 1) | |
| 1446 | + return -ENODEV; | |
| 1447 | + | |
| 1445 | 1448 | return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 1446 | 1449 | } |
| 1447 | 1450 | |
| @@ -2626,6 +2629,7 @@ static int sd_start(struct gspca_dev *gspca_dev) · 1178 unmodified lines | ||
| 2626 | 2629 | |
| 2627 | 2630 | static int sd_isoc_init(struct gspca_dev *gspca_dev) |
| 2628 | 2631 | { |
| 2632 | + struct usb_interface_cache *intfc; | |
| 2629 | 2633 | struct usb_host_interface *alt; |
| 2630 | 2634 | int max_packet_size; |
| 2631 | 2635 | |
| @@ -2641,8 +2645,17 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) · 9 unmodified lines | ||
| 2641 | 2645 | break; |
| 2642 | 2646 | } |
| 2643 | 2647 | |
| 2648 | + intfc = gspca_dev->dev->actconfig->intf_cache[0]; | |
| 2649 | + | |
| 2650 | + if (intfc->num_altsetting < 2) | |
| 2651 | + return -ENODEV; | |
| 2652 | + | |
| 2653 | + alt = &intfc->altsetting[1]; | |
| 2654 | + | |
| 2655 | + if (alt->desc.bNumEndpoints < 1) | |
| 2656 | + return -ENODEV; | |
| 2657 | + | |
| 2644 | 2658 | /* Start isoc bandwidth "negotiation" at max isoc bandwidth */ |
| 2645 | − alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; | |
| 2646 | 2659 | alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size); |
| 2647 | 2660 | |
| 2648 | 2661 | return 0; |
| @@ -2665,6 +2678,9 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev) · 16 unmodified lines | ||
| 2665 | 2678 | break; |
| 2666 | 2679 | } |
| 2667 | 2680 | |
| 2681 | + /* | |
| 2682 | + * Existence of altsetting and endpoint was verified in sd_isoc_init() | |
| 2683 | + */ | |
| 2668 | 2684 | alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1]; |
| 2669 | 2685 | packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize); |
| 2670 | 2686 | if (packet_size <= min_packet_size) |
| @@ -1238,7 +1238,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, · 1237 unmodified lines | ||
| 1238 | 1238 | dev->video_dev.v4l2_dev = &dev->v4l2_dev; |
| 1239 | 1239 | video_set_drvdata(&dev->video_dev, dev); |
| 1240 | 1240 | |
| 1241 | − res = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, devnum); | |
| 1241 | + res = video_register_device(&dev->video_dev, VFL_TYPE_VIDEO, devnum); | |
| 1242 | 1242 | if (res < 0) { |
| 1243 | 1243 | v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); |
| 1244 | 1244 | goto error; |
| @@ -1196,7 +1196,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, · 1195 unmodified lines | ||
| 1196 | 1196 | hdw = vp->channel.mc_head->hdw; |
| 1197 | 1197 | dip->v4l_type = v4l_type; |
| 1198 | 1198 | switch (v4l_type) { |
| 1199 | − case VFL_TYPE_GRABBER: | |
| 1199 | + case VFL_TYPE_VIDEO: | |
| 1200 | 1200 | dip->stream = &vp->channel.mc_head->video_stream; |
| 1201 | 1201 | dip->config = pvr2_config_mpeg; |
| 1202 | 1202 | dip->minor_type = pvr2_v4l_type_video; |
| @@ -1276,7 +1276,7 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) · 73 unmodified lines | ||
| 1276 | 1276 | /* register streams */ |
| 1277 | 1277 | vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL); |
| 1278 | 1278 | if (!vp->dev_video) goto fail; |
| 1279 | − pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER); | |
| 1279 | + pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_VIDEO); | |
| 1280 | 1280 | if (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) & |
| 1281 | 1281 | (1 << PVR2_CVAL_INPUT_RADIO)) { |
| 1282 | 1282 | vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL); |
| @@ -1116,7 +1116,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id · 1115 unmodified lines | ||
| 1116 | 1116 | pdev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | |
| 1117 | 1117 | V4L2_CAP_READWRITE; |
| 1118 | 1118 | |
| 1119 | − rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); | |
| 1119 | + rc = video_register_device(&pdev->vdev, VFL_TYPE_VIDEO, -1); | |
| 1120 | 1120 | if (rc < 0) { |
| 1121 | 1121 | PWC_ERROR("Failed to register as video device (%d).\n", rc); |
| 1122 | 1122 | goto err_unregister_v4l2_dev; |
| @@ -1649,11 +1649,11 @@ static int s2255_probe_v4l(struct s2255_dev *dev) · 1648 unmodified lines | ||
| 1649 | 1649 | video_set_drvdata(&vc->vdev, vc); |
| 1650 | 1650 | if (video_nr == -1) |
| 1651 | 1651 | ret = video_register_device(&vc->vdev, |
| 1652 | − VFL_TYPE_GRABBER, | |
| 1652 | + VFL_TYPE_VIDEO, | |
| 1653 | 1653 | video_nr); |
| 1654 | 1654 | else |
| 1655 | 1655 | ret = video_register_device(&vc->vdev, |
| 1656 | − VFL_TYPE_GRABBER, | |
| 1656 | + VFL_TYPE_VIDEO, | |
| 1657 | 1657 | cur_nr + i); |
| 1658 | 1658 | |
| 1659 | 1659 | if (ret) { |
| @@ -830,7 +830,7 @@ int stk1160_video_register(struct stk1160 *dev) · 829 unmodified lines | ||
| 830 | 830 | dev->norm); |
| 831 | 831 | |
| 832 | 832 | video_set_drvdata(&dev->vdev, dev); |
| 833 | − rc = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); | |
| 833 | + rc = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1); | |
| 834 | 834 | if (rc < 0) { |
| 835 | 835 | stk1160_err("video_register_device failed (%d)\n", rc); |
| 836 | 836 | return rc; |
| @@ -1254,7 +1254,7 @@ static int stk_register_video_device(struct stk_camera *dev) · 1253 unmodified lines | ||
| 1254 | 1254 | dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
| 1255 | 1255 | V4L2_CAP_STREAMING; |
| 1256 | 1256 | video_set_drvdata(&dev->vdev, dev); |
| 1257 | − err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); | |
| 1257 | + err = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1); | |
| 1258 | 1258 | if (err) |
| 1259 | 1259 | pr_err("v4l registration failed\n"); |
| 1260 | 1260 | else |
| @@ -1300,7 +1300,7 @@ static int __tm6000_open(struct file *file) · 1299 unmodified lines | ||
| 1300 | 1300 | video_device_node_name(vdev)); |
| 1301 | 1301 | |
| 1302 | 1302 | switch (vdev->vfl_type) { |
| 1303 | − case VFL_TYPE_GRABBER: | |
| 1303 | + case VFL_TYPE_VIDEO: | |
| 1304 | 1304 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| 1305 | 1305 | break; |
| 1306 | 1306 | case VFL_TYPE_VBI: |
| @@ -1639,7 +1639,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev) · 332 unmodified lines | ||
| 1639 | 1639 | INIT_LIST_HEAD(&dev->vidq.active); |
| 1640 | 1640 | INIT_LIST_HEAD(&dev->vidq.queued); |
| 1641 | 1641 | |
| 1642 | − ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, video_nr); | |
| 1642 | + ret = video_register_device(&dev->vfd, VFL_TYPE_VIDEO, video_nr); | |
| 1643 | 1643 | |
| 1644 | 1644 | if (ret < 0) { |
| 1645 | 1645 | printk(KERN_INFO "%s: can't register video device\n", |
| @@ -56,7 +56,7 @@ int usbtv_set_regs(struct usbtv *usbtv, const u16 regs[][2], int size) · 55 unmodified lines | ||
| 56 | 56 | |
| 57 | 57 | ret = usb_control_msg(usbtv->udev, pipe, USBTV_REQUEST_REG, |
| 58 | 58 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 59 | − value, index, NULL, 0, 0); | |
| 59 | + value, index, NULL, 0, USB_CTRL_GET_TIMEOUT); | |
| 60 | 60 | if (ret < 0) |
| 61 | 61 | return ret; |
| 62 | 62 | } |
| @@ -800,7 +800,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) · 799 unmodified lines | ||
| 800 | 800 | ret = usb_control_msg(usbtv->udev, |
| 801 | 801 | usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, |
| 802 | 802 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 803 | − 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); | |
| 803 | + 0, USBTV_BASE + 0x0244, (void *)data, 3, | |
| 804 | + USB_CTRL_GET_TIMEOUT); | |
| 804 | 805 | if (ret < 0) |
| 805 | 806 | goto error; |
| 806 | 807 | } |
| @@ -851,7 +852,7 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) · 44 unmodified lines | ||
| 851 | 852 | ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0), |
| 852 | 853 | USBTV_CONTROL_REG, |
| 853 | 854 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
| 854 | − 0, index, (void *)data, size, 0); | |
| 855 | + 0, index, (void *)data, size, USB_CTRL_SET_TIMEOUT); | |
| 855 | 856 | |
| 856 | 857 | error: |
| 857 | 858 | if (ret < 0) |
| @@ -940,7 +941,7 @@ int usbtv_video_init(struct usbtv *usbtv) · 82 unmodified lines | ||
| 940 | 941 | usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | |
| 941 | 942 | V4L2_CAP_STREAMING; |
| 942 | 943 | video_set_drvdata(&usbtv->vdev, usbtv); |
| 943 | − ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); | |
| 944 | + ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1); | |
| 944 | 945 | if (ret < 0) { |
| 945 | 946 | dev_warn(usbtv->dev, "Could not register video device\n"); |
| 946 | 947 | goto vdev_fail; |
| @@ -2014,7 +2014,7 @@ int uvc_register_video_device(struct uvc_device *dev, · 2013 unmodified lines | ||
| 2014 | 2014 | */ |
| 2015 | 2015 | video_set_drvdata(vdev, stream); |
| 2016 | 2016 | |
| 2017 | − ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 2017 | + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 2018 | 2018 | if (ret < 0) { |
| 2019 | 2019 | uvc_printk(KERN_ERR, "Failed to register %s device (%d).\n", |
| 2020 | 2020 | v4l2_type_names[type], ret); |
| @@ -1516,7 +1516,7 @@ static int zr364xx_probe(struct usb_interface *intf, · 1515 unmodified lines | ||
| 1516 | 1516 | V4L2_FIELD_NONE, |
| 1517 | 1517 | sizeof(struct zr364xx_buffer), cam, &cam->lock); |
| 1518 | 1518 | |
| 1519 | − err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); | |
| 1519 | + err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); | |
| 1520 | 1520 | if (err) { |
| 1521 | 1521 | dev_err(&udev->dev, "video_register_device failed\n"); |
| 1522 | 1522 | goto fail; |
| @@ -4296,10 +4296,17 @@ void v4l2_ctrl_request_complete(struct media_request *req, · 4295 unmodified lines | ||
| 4296 | 4296 | continue; |
| 4297 | 4297 | |
| 4298 | 4298 | v4l2_ctrl_lock(ctrl); |
| 4299 | − if (ref->req) | |
| 4299 | + if (ref->req) { | |
| 4300 | 4300 | ptr_to_ptr(ctrl, ref->req->p_req, ref->p_req); |
| 4301 | − else | |
| 4301 | + } else { | |
| 4302 | 4302 | ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req); |
| 4303 | + /* | |
| 4304 | + * Set ref->req to ensure that when userspace wants to | |
| 4305 | + * obtain the controls of this request it will take | |
| 4306 | + * this value and not the current value of the control. | |
| 4307 | + */ | |
| 4308 | + ref->req = ref; | |
| 4309 | + } | |
| 4303 | 4310 | v4l2_ctrl_unlock(ctrl); |
| 4304 | 4311 | } |
| 4305 | 4312 | |
| @@ -542,13 +542,13 @@ static void determine_valid_ioctls(struct video_device *vdev) · 541 unmodified lines | ||
| 542 | 542 | V4L2_CAP_META_OUTPUT; |
| 543 | 543 | DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); |
| 544 | 544 | const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; |
| 545 | − bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER && | |
| 545 | + bool is_vid = vdev->vfl_type == VFL_TYPE_VIDEO && | |
| 546 | 546 | (vdev->device_caps & vid_caps); |
| 547 | 547 | bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; |
| 548 | 548 | bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; |
| 549 | 549 | bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; |
| 550 | 550 | bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH; |
| 551 | − bool is_meta = vdev->vfl_type == VFL_TYPE_GRABBER && | |
| 551 | + bool is_meta = vdev->vfl_type == VFL_TYPE_VIDEO && | |
| 552 | 552 | (vdev->device_caps & meta_caps); |
| 553 | 553 | bool is_rx = vdev->vfl_dir != VFL_DIR_TX; |
| 554 | 554 | bool is_tx = vdev->vfl_dir != VFL_DIR_RX; |
| @@ -783,7 +783,7 @@ static int video_register_media_controller(struct video_device *vdev) · 228 unmodified lines | ||
| 783 | 783 | vdev->entity.function = MEDIA_ENT_F_UNKNOWN; |
| 784 | 784 | |
| 785 | 785 | switch (vdev->vfl_type) { |
| 786 | − case VFL_TYPE_GRABBER: | |
| 786 | + case VFL_TYPE_VIDEO: | |
| 787 | 787 | intf_type = MEDIA_INTF_T_V4L_VIDEO; |
| 788 | 788 | vdev->entity.function = MEDIA_ENT_F_IO_V4L; |
| 789 | 789 | break; |
| @@ -891,7 +891,7 @@ int __video_register_device(struct video_device *vdev, · 101 unmodified lines | ||
| 891 | 891 | |
| 892 | 892 | /* Part 1: check device type */ |
| 893 | 893 | switch (type) { |
| 894 | − case VFL_TYPE_GRABBER: | |
| 894 | + case VFL_TYPE_VIDEO: | |
| 895 | 895 | name_base = "video"; |
| 896 | 896 | break; |
| 897 | 897 | case VFL_TYPE_VBI: |
| @@ -935,7 +935,7 @@ int __video_register_device(struct video_device *vdev, · 37 unmodified lines | ||
| 935 | 935 | * of 128-191 and just pick the first free minor there |
| 936 | 936 | * (new style). */ |
| 937 | 937 | switch (type) { |
| 938 | − case VFL_TYPE_GRABBER: | |
| 938 | + case VFL_TYPE_VIDEO: | |
| 939 | 939 | minor_offset = 0; |
| 940 | 940 | minor_cnt = 64; |
| 941 | 941 | break; |
| @@ -111,9 +111,6 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister); · 110 unmodified lines | ||
| 111 | 111 | int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, |
| 112 | 112 | struct v4l2_subdev *sd) |
| 113 | 113 | { |
| 114 | −#if defined(CONFIG_MEDIA_CONTROLLER) | |
| 115 | − struct media_entity *entity = &sd->entity; | |
| 116 | −#endif | |
| 117 | 114 | int err; |
| 118 | 115 | |
| 119 | 116 | /* Check for valid input */ |
| @@ -143,7 +140,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, · 23 unmodified lines | ||
| 143 | 140 | #if defined(CONFIG_MEDIA_CONTROLLER) |
| 144 | 141 | /* Register the entity. */ |
| 145 | 142 | if (v4l2_dev->mdev) { |
| 146 | − err = media_device_register_entity(v4l2_dev->mdev, entity); | |
| 143 | + err = media_device_register_entity(v4l2_dev->mdev, &sd->entity); | |
| 147 | 144 | if (err < 0) |
| 148 | 145 | goto error_module; |
| 149 | 146 | } |
| @@ -163,7 +160,7 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, · 13 unmodified lines | ||
| 163 | 160 | |
| 164 | 161 | error_unregister: |
| 165 | 162 | #if defined(CONFIG_MEDIA_CONTROLLER) |
| 166 | − media_device_unregister_entity(entity); | |
| 163 | + media_device_unregister_entity(&sd->entity); | |
| 167 | 164 | #endif |
| 168 | 165 | error_module: |
| 169 | 166 | if (!sd->owner_v4l2_dev) |
| @@ -179,6 +176,7 @@ static void v4l2_subdev_release(struct v4l2_subdev *sd) · 9 unmodified lines | ||
| 179 | 176 | |
| 180 | 177 | if (sd->internal_ops && sd->internal_ops->release) |
| 181 | 178 | sd->internal_ops->release(sd); |
| 179 | + sd->devnode = NULL; | |
| 182 | 180 | module_put(owner); |
| 183 | 181 | } |
| 184 | 182 | |
| @@ -557,33 +557,28 @@ int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode, · 556 unmodified lines | ||
| 557 | 557 | } |
| 558 | 558 | EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse); |
| 559 | 559 | |
| 560 | −int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode, | |
| 560 | +int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, | |
| 561 | 561 | struct v4l2_fwnode_link *link) |
| 562 | 562 | { |
| 563 | − const char *port_prop = is_of_node(__fwnode) ? "reg" : "port"; | |
| 564 | − struct fwnode_handle *fwnode; | |
| 563 | + struct fwnode_endpoint fwep; | |
| 565 | 564 | |
| 566 | 565 | memset(link, 0, sizeof(*link)); |
| 567 | 566 | |
| 568 | − fwnode = fwnode_get_parent(__fwnode); | |
| 569 | − fwnode_property_read_u32(fwnode, port_prop, &link->local_port); | |
| 570 | − fwnode = fwnode_get_next_parent(fwnode); | |
| 571 | − if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports")) | |
| 572 | − fwnode = fwnode_get_next_parent(fwnode); | |
| 573 | − link->local_node = fwnode; | |
| 567 | + fwnode_graph_parse_endpoint(fwnode, &fwep); | |
| 568 | + link->local_id = fwep.id; | |
| 569 | + link->local_port = fwep.port; | |
| 570 | + link->local_node = fwnode_graph_get_port_parent(fwnode); | |
| 574 | 571 | |
| 575 | − fwnode = fwnode_graph_get_remote_endpoint(__fwnode); | |
| 572 | + fwnode = fwnode_graph_get_remote_endpoint(fwnode); | |
| 576 | 573 | if (!fwnode) { |
| 577 | 574 | fwnode_handle_put(fwnode); |
| 578 | 575 | return -ENOLINK; |
| 579 | 576 | } |
| 580 | 577 | |
| 581 | − fwnode = fwnode_get_parent(fwnode); | |
| 582 | − fwnode_property_read_u32(fwnode, port_prop, &link->remote_port); | |
| 583 | − fwnode = fwnode_get_next_parent(fwnode); | |
| 584 | − if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports")) | |
| 585 | − fwnode = fwnode_get_next_parent(fwnode); | |
| 586 | − link->remote_node = fwnode; | |
| 578 | + fwnode_graph_parse_endpoint(fwnode, &fwep); | |
| 579 | + link->remote_id = fwep.id; | |
| 580 | + link->remote_port = fwep.port; | |
| 581 | + link->remote_node = fwnode_graph_get_port_parent(fwnode); | |
| 587 | 582 | |
| 588 | 583 | return 0; |
| 589 | 584 | } |
| @@ -596,6 +591,171 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) · 6 unmodified lines | ||
| 596 | 591 | } |
| 597 | 592 | EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link); |
| 598 | 593 | |
| 594 | +static const struct v4l2_fwnode_connector_conv { | |
| 595 | + enum v4l2_connector_type type; | |
| 596 | + const char *compatible; | |
| 597 | +} connectors[] = { | |
| 598 | + { | |
| 599 | + .type = V4L2_CONN_COMPOSITE, | |
| 600 | + .compatible = "composite-video-connector", | |
| 601 | + }, { | |
| 602 | + .type = V4L2_CONN_SVIDEO, | |
| 603 | + .compatible = "svideo-connector", | |
| 604 | + }, | |
| 605 | +}; | |
| 606 | + | |
| 607 | +static enum v4l2_connector_type | |
| 608 | +v4l2_fwnode_string_to_connector_type(const char *con_str) | |
| 609 | +{ | |
| 610 | + unsigned int i; | |
| 611 | + | |
| 612 | + for (i = 0; i < ARRAY_SIZE(connectors); i++) | |
| 613 | + if (!strcmp(con_str, connectors[i].compatible)) | |
| 614 | + return connectors[i].type; | |
| 615 | + | |
| 616 | + return V4L2_CONN_UNKNOWN; | |
| 617 | +} | |
| 618 | + | |
| 619 | +static void | |
| 620 | +v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode, | |
| 621 | + struct v4l2_fwnode_connector *vc) | |
| 622 | +{ | |
| 623 | + u32 stds; | |
| 624 | + int ret; | |
| 625 | + | |
| 626 | + ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds); | |
| 627 | + | |
| 628 | + /* The property is optional. */ | |
| 629 | + vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds; | |
| 630 | +} | |
| 631 | + | |
| 632 | +void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector) | |
| 633 | +{ | |
| 634 | + struct v4l2_connector_link *link, *tmp; | |
| 635 | + | |
| 636 | + if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN) | |
| 637 | + return; | |
| 638 | + | |
| 639 | + list_for_each_entry_safe(link, tmp, &connector->links, head) { | |
| 640 | + v4l2_fwnode_put_link(&link->fwnode_link); | |
| 641 | + list_del(&link->head); | |
| 642 | + kfree(link); | |
| 643 | + } | |
| 644 | + | |
| 645 | + kfree(connector->label); | |
| 646 | + connector->label = NULL; | |
| 647 | + connector->type = V4L2_CONN_UNKNOWN; | |
| 648 | +} | |
| 649 | +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free); | |
| 650 | + | |
| 651 | +static enum v4l2_connector_type | |
| 652 | +v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode) | |
| 653 | +{ | |
| 654 | + const char *type_name; | |
| 655 | + int err; | |
| 656 | + | |
| 657 | + if (!fwnode) | |
| 658 | + return V4L2_CONN_UNKNOWN; | |
| 659 | + | |
| 660 | + /* The connector-type is stored within the compatible string. */ | |
| 661 | + err = fwnode_property_read_string(fwnode, "compatible", &type_name); | |
| 662 | + if (err) | |
| 663 | + return V4L2_CONN_UNKNOWN; | |
| 664 | + | |
| 665 | + return v4l2_fwnode_string_to_connector_type(type_name); | |
| 666 | +} | |
| 667 | + | |
| 668 | +int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode, | |
| 669 | + struct v4l2_fwnode_connector *connector) | |
| 670 | +{ | |
| 671 | + struct fwnode_handle *connector_node; | |
| 672 | + enum v4l2_connector_type connector_type; | |
| 673 | + const char *label; | |
| 674 | + int err; | |
| 675 | + | |
| 676 | + if (!fwnode) | |
| 677 | + return -EINVAL; | |
| 678 | + | |
| 679 | + memset(connector, 0, sizeof(*connector)); | |
| 680 | + | |
| 681 | + INIT_LIST_HEAD(&connector->links); | |
| 682 | + | |
| 683 | + connector_node = fwnode_graph_get_port_parent(fwnode); | |
| 684 | + connector_type = v4l2_fwnode_get_connector_type(connector_node); | |
| 685 | + if (connector_type == V4L2_CONN_UNKNOWN) { | |
| 686 | + fwnode_handle_put(connector_node); | |
| 687 | + connector_node = fwnode_graph_get_remote_port_parent(fwnode); | |
| 688 | + connector_type = v4l2_fwnode_get_connector_type(connector_node); | |
| 689 | + } | |
| 690 | + | |
| 691 | + if (connector_type == V4L2_CONN_UNKNOWN) { | |
| 692 | + pr_err("Unknown connector type\n"); | |
| 693 | + err = -ENOTCONN; | |
| 694 | + goto out; | |
| 695 | + } | |
| 696 | + | |
| 697 | + connector->type = connector_type; | |
| 698 | + connector->name = fwnode_get_name(connector_node); | |
| 699 | + err = fwnode_property_read_string(connector_node, "label", &label); | |
| 700 | + connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL); | |
| 701 | + | |
| 702 | + /* Parse the connector specific properties. */ | |
| 703 | + switch (connector->type) { | |
| 704 | + case V4L2_CONN_COMPOSITE: | |
| 705 | + case V4L2_CONN_SVIDEO: | |
| 706 | + v4l2_fwnode_connector_parse_analog(connector_node, connector); | |
| 707 | + break; | |
| 708 | + /* Avoid compiler warnings */ | |
| 709 | + case V4L2_CONN_UNKNOWN: | |
| 710 | + break; | |
| 711 | + } | |
| 712 | + | |
| 713 | +out: | |
| 714 | + fwnode_handle_put(connector_node); | |
| 715 | + | |
| 716 | + return err; | |
| 717 | +} | |
| 718 | +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse); | |
| 719 | + | |
| 720 | +int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode, | |
| 721 | + struct v4l2_fwnode_connector *connector) | |
| 722 | +{ | |
| 723 | + struct fwnode_handle *connector_ep; | |
| 724 | + struct v4l2_connector_link *link; | |
| 725 | + int err; | |
| 726 | + | |
| 727 | + if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN) | |
| 728 | + return -EINVAL; | |
| 729 | + | |
| 730 | + connector_ep = fwnode_graph_get_remote_endpoint(fwnode); | |
| 731 | + if (!connector_ep) | |
| 732 | + return -ENOTCONN; | |
| 733 | + | |
| 734 | + link = kzalloc(sizeof(*link), GFP_KERNEL); | |
| 735 | + if (!link) { | |
| 736 | + err = -ENOMEM; | |
| 737 | + goto err; | |
| 738 | + } | |
| 739 | + | |
| 740 | + err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link); | |
| 741 | + if (err) | |
| 742 | + goto err; | |
| 743 | + | |
| 744 | + fwnode_handle_put(connector_ep); | |
| 745 | + | |
| 746 | + list_add(&link->head, &connector->links); | |
| 747 | + connector->nr_of_links++; | |
| 748 | + | |
| 749 | + return 0; | |
| 750 | + | |
| 751 | +err: | |
| 752 | + kfree(link); | |
| 753 | + fwnode_handle_put(connector_ep); | |
| 754 | + | |
| 755 | + return err; | |
| 756 | +} | |
| 757 | +EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link); | |
| 758 | + | |
| 599 | 759 | static int |
| 600 | 760 | v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, |
| 601 | 761 | struct v4l2_async_notifier *notifier, |
| @@ -74,10 +74,10 @@ struct v4l2_subdev · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | /* Create the i2c client */ |
| 76 | 76 | if (info->addr == 0 && probe_addrs) |
| 77 | − client = i2c_new_probed_device(adapter, info, probe_addrs, | |
| 78 | − NULL); | |
| 77 | + client = i2c_new_scanned_device(adapter, info, probe_addrs, | |
| 78 | + NULL); | |
| 79 | 79 | else |
| 80 | − client = i2c_new_device(adapter, info); | |
| 80 | + client = i2c_new_client_device(adapter, info); | |
| 81 | 81 | |
| 82 | 82 | /* |
| 83 | 83 | * Note: by loading the module first we are certain that c->driver |
| @@ -88,7 +88,7 @@ struct v4l2_subdev · 4 unmodified lines | ||
| 88 | 88 | * want to use the i2c device, so explicitly loading the module |
| 89 | 89 | * is the best alternative. |
| 90 | 90 | */ |
| 91 | − if (!client || !client->dev.driver) | |
| 91 | + if (!i2c_client_has_driver(client)) | |
| 92 | 92 | goto error; |
| 93 | 93 | |
| 94 | 94 | /* Lock the module so we can safely get the v4l2_subdev pointer */ |
| @@ -110,7 +110,7 @@ error: · 15 unmodified lines | ||
| 110 | 110 | * If we have a client but no subdev, then something went wrong and |
| 111 | 111 | * we must unregister the client. |
| 112 | 112 | */ |
| 113 | − if (client && !sd) | |
| 113 | + if (!IS_ERR(client) && !sd) | |
| 114 | 114 | i2c_unregister_device(client); |
| 115 | 115 | return sd; |
| 116 | 116 | } |
| @@ -941,12 +941,12 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) · 940 unmodified lines | ||
| 941 | 941 | V4L2_CAP_META_OUTPUT; |
| 942 | 942 | struct video_device *vfd = video_devdata(file); |
| 943 | 943 | const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; |
| 944 | − bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER && | |
| 944 | + bool is_vid = vfd->vfl_type == VFL_TYPE_VIDEO && | |
| 945 | 945 | (vfd->device_caps & vid_caps); |
| 946 | 946 | bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; |
| 947 | 947 | bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; |
| 948 | 948 | bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; |
| 949 | − bool is_meta = vfd->vfl_type == VFL_TYPE_GRABBER && | |
| 949 | + bool is_meta = vfd->vfl_type == VFL_TYPE_VIDEO && | |
| 950 | 950 | (vfd->device_caps & meta_caps); |
| 951 | 951 | bool is_rx = vfd->vfl_dir != VFL_DIR_TX; |
| 952 | 952 | bool is_tx = vfd->vfl_dir != VFL_DIR_RX; |
| @@ -1222,6 +1222,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 269 unmodified lines | ||
| 1222 | 1222 | case V4L2_PIX_FMT_Y6: descr = "6-bit Greyscale"; break; |
| 1223 | 1223 | case V4L2_PIX_FMT_Y10: descr = "10-bit Greyscale"; break; |
| 1224 | 1224 | case V4L2_PIX_FMT_Y12: descr = "12-bit Greyscale"; break; |
| 1225 | + case V4L2_PIX_FMT_Y14: descr = "14-bit Greyscale"; break; | |
| 1225 | 1226 | case V4L2_PIX_FMT_Y16: descr = "16-bit Greyscale"; break; |
| 1226 | 1227 | case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break; |
| 1227 | 1228 | case V4L2_PIX_FMT_Y10BPACK: descr = "10-bit Greyscale (Packed)"; break; |
| @@ -1306,6 +1307,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) · 78 unmodified lines | ||
| 1306 | 1307 | case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break; |
| 1307 | 1308 | case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break; |
| 1308 | 1309 | case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break; |
| 1310 | + case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break; | |
| 1311 | + case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break; | |
| 1312 | + case V4L2_PIX_FMT_SGRBG14: descr = "14-bit Bayer GRGR/BGBG"; break; | |
| 1313 | + case V4L2_PIX_FMT_SRGGB14: descr = "14-bit Bayer RGRG/GBGB"; break; | |
| 1309 | 1314 | case V4L2_PIX_FMT_SBGGR14P: descr = "14-bit Bayer BGBG/GRGR Packed"; break; |
| 1310 | 1315 | case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break; |
| 1311 | 1316 | case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break; |
| @@ -321,7 +321,7 @@ EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source); · 320 unmodified lines | ||
| 321 | 321 | * use_count field stores the total number of users of all video device nodes |
| 322 | 322 | * in the pipeline. |
| 323 | 323 | * |
| 324 | − * The v4l2_pipeline_pm_use() function must be called in the open() and | |
| 324 | + * The v4l2_pipeline_pm_{get, put}() functions must be called in the open() and | |
| 325 | 325 | * close() handlers of video device nodes. It increments or decrements the use |
| 326 | 326 | * count of all subdev entities in the pipeline. |
| 327 | 327 | * |
| @@ -423,7 +423,7 @@ static int pipeline_pm_power(struct media_entity *entity, int change, · 95 unmodified lines | ||
| 423 | 423 | return ret; |
| 424 | 424 | } |
| 425 | 425 | |
| 426 | −int v4l2_pipeline_pm_use(struct media_entity *entity, int use) | |
| 426 | +static int v4l2_pipeline_pm_use(struct media_entity *entity, unsigned int use) | |
| 427 | 427 | { |
| 428 | 428 | struct media_device *mdev = entity->graph_obj.mdev; |
| 429 | 429 | int change = use ? 1 : -1; |
| @@ -444,7 +444,19 @@ int v4l2_pipeline_pm_use(struct media_entity *entity, int use) · 14 unmodified lines | ||
| 444 | 444 | |
| 445 | 445 | return ret; |
| 446 | 446 | } |
| 447 | −EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_use); | |
| 447 | + | |
| 448 | +int v4l2_pipeline_pm_get(struct media_entity *entity) | |
| 449 | +{ | |
| 450 | + return v4l2_pipeline_pm_use(entity, 1); | |
| 451 | +} | |
| 452 | +EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_get); | |
| 453 | + | |
| 454 | +void v4l2_pipeline_pm_put(struct media_entity *entity) | |
| 455 | +{ | |
| 456 | + /* Powering off entities shouldn't fail. */ | |
| 457 | + WARN_ON(v4l2_pipeline_pm_use(entity, 0)); | |
| 458 | +} | |
| 459 | +EXPORT_SYMBOL_GPL(v4l2_pipeline_pm_put); | |
| 448 | 460 | |
| 449 | 461 | int v4l2_pipeline_link_notify(struct media_link *link, u32 flags, |
| 450 | 462 | unsigned int notification) |
| @@ -340,6 +340,11 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, · 339 unmodified lines | ||
| 340 | 340 | m2m_ctx->new_frame = !dst->vb2_buf.copied_timestamp || |
| 341 | 341 | dst->vb2_buf.timestamp != src->vb2_buf.timestamp; |
| 342 | 342 | |
| 343 | + if (m2m_ctx->has_stopped) { | |
| 344 | + dprintk("Device has stopped\n"); | |
| 345 | + goto job_unlock; | |
| 346 | + } | |
| 347 | + | |
| 343 | 348 | if (m2m_dev->m2m_ops->job_ready |
| 344 | 349 | && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { |
| 345 | 350 | dprintk("Driver not ready\n"); |
| @@ -556,6 +561,140 @@ int v4l2_m2m_querybuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, · 210 unmodified lines | ||
| 556 | 561 | } |
| 557 | 562 | EXPORT_SYMBOL_GPL(v4l2_m2m_querybuf); |
| 558 | 563 | |
| 564 | +/* | |
| 565 | + * This will add the LAST flag and mark the buffer management | |
| 566 | + * state as stopped. | |
| 567 | + * This is called when the last capture buffer must be flagged as LAST | |
| 568 | + * in draining mode from the encoder/decoder driver buf_queue() callback | |
| 569 | + * or from v4l2_update_last_buf_state() when a capture buffer is available. | |
| 570 | + */ | |
| 571 | +void v4l2_m2m_last_buffer_done(struct v4l2_m2m_ctx *m2m_ctx, | |
| 572 | + struct vb2_v4l2_buffer *vbuf) | |
| 573 | +{ | |
| 574 | + vbuf->flags |= V4L2_BUF_FLAG_LAST; | |
| 575 | + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); | |
| 576 | + | |
| 577 | + v4l2_m2m_mark_stopped(m2m_ctx); | |
| 578 | +} | |
| 579 | +EXPORT_SYMBOL_GPL(v4l2_m2m_last_buffer_done); | |
| 580 | + | |
| 581 | +/* When stop command is issued, update buffer management state */ | |
| 582 | +static int v4l2_update_last_buf_state(struct v4l2_m2m_ctx *m2m_ctx) | |
| 583 | +{ | |
| 584 | + struct vb2_v4l2_buffer *next_dst_buf; | |
| 585 | + | |
| 586 | + if (m2m_ctx->is_draining) | |
| 587 | + return -EBUSY; | |
| 588 | + | |
| 589 | + if (m2m_ctx->has_stopped) | |
| 590 | + return 0; | |
| 591 | + | |
| 592 | + m2m_ctx->last_src_buf = v4l2_m2m_last_src_buf(m2m_ctx); | |
| 593 | + m2m_ctx->is_draining = true; | |
| 594 | + | |
| 595 | + /* | |
| 596 | + * The processing of the last output buffer queued before | |
| 597 | + * the STOP command is expected to mark the buffer management | |
| 598 | + * state as stopped with v4l2_m2m_mark_stopped(). | |
| 599 | + */ | |
| 600 | + if (m2m_ctx->last_src_buf) | |
| 601 | + return 0; | |
| 602 | + | |
| 603 | + /* | |
| 604 | + * In case the output queue is empty, try to mark the last capture | |
| 605 | + * buffer as LAST. | |
| 606 | + */ | |
| 607 | + next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); | |
| 608 | + if (!next_dst_buf) { | |
| 609 | + /* | |
| 610 | + * Wait for the next queued one in encoder/decoder driver | |
| 611 | + * buf_queue() callback using the v4l2_m2m_dst_buf_is_last() | |
| 612 | + * helper or in v4l2_m2m_qbuf() if encoder/decoder is not yet | |
| 613 | + * streaming. | |
| 614 | + */ | |
| 615 | + m2m_ctx->next_buf_last = true; | |
| 616 | + return 0; | |
| 617 | + } | |
| 618 | + | |
| 619 | + v4l2_m2m_last_buffer_done(m2m_ctx, next_dst_buf); | |
| 620 | + | |
| 621 | + return 0; | |
| 622 | +} | |
| 623 | + | |
| 624 | +/* | |
| 625 | + * Updates the encoding/decoding buffer management state, should | |
| 626 | + * be called from encoder/decoder drivers start_streaming() | |
| 627 | + */ | |
| 628 | +void v4l2_m2m_update_start_streaming_state(struct v4l2_m2m_ctx *m2m_ctx, | |
| 629 | + struct vb2_queue *q) | |
| 630 | +{ | |
| 631 | + /* If start streaming again, untag the last output buffer */ | |
| 632 | + if (V4L2_TYPE_IS_OUTPUT(q->type)) | |
| 633 | + m2m_ctx->last_src_buf = NULL; | |
| 634 | +} | |
| 635 | +EXPORT_SYMBOL_GPL(v4l2_m2m_update_start_streaming_state); | |
| 636 | + | |
| 637 | +/* | |
| 638 | + * Updates the encoding/decoding buffer management state, should | |
| 639 | + * be called from encoder/decoder driver stop_streaming() | |
| 640 | + */ | |
| 641 | +void v4l2_m2m_update_stop_streaming_state(struct v4l2_m2m_ctx *m2m_ctx, | |
| 642 | + struct vb2_queue *q) | |
| 643 | +{ | |
| 644 | + if (V4L2_TYPE_IS_OUTPUT(q->type)) { | |
| 645 | + /* | |
| 646 | + * If in draining state, either mark next dst buffer as | |
| 647 | + * done or flag next one to be marked as done either | |
| 648 | + * in encoder/decoder driver buf_queue() callback using | |
| 649 | + * the v4l2_m2m_dst_buf_is_last() helper or in v4l2_m2m_qbuf() | |
| 650 | + * if encoder/decoder is not yet streaming | |
| 651 | + */ | |
| 652 | + if (m2m_ctx->is_draining) { | |
| 653 | + struct vb2_v4l2_buffer *next_dst_buf; | |
| 654 | + | |
| 655 | + m2m_ctx->last_src_buf = NULL; | |
| 656 | + next_dst_buf = v4l2_m2m_dst_buf_remove(m2m_ctx); | |
| 657 | + if (!next_dst_buf) | |
| 658 | + m2m_ctx->next_buf_last = true; | |
| 659 | + else | |
| 660 | + v4l2_m2m_last_buffer_done(m2m_ctx, | |
| 661 | + next_dst_buf); | |
| 662 | + } | |
| 663 | + } else { | |
| 664 | + v4l2_m2m_clear_state(m2m_ctx); | |
| 665 | + } | |
| 666 | +} | |
| 667 | +EXPORT_SYMBOL_GPL(v4l2_m2m_update_stop_streaming_state); | |
| 668 | + | |
| 669 | +static void v4l2_m2m_force_last_buf_done(struct v4l2_m2m_ctx *m2m_ctx, | |
| 670 | + struct vb2_queue *q) | |
| 671 | +{ | |
| 672 | + struct vb2_buffer *vb; | |
| 673 | + struct vb2_v4l2_buffer *vbuf; | |
| 674 | + unsigned int i; | |
| 675 | + | |
| 676 | + if (WARN_ON(q->is_output)) | |
| 677 | + return; | |
| 678 | + if (list_empty(&q->queued_list)) | |
| 679 | + return; | |
| 680 | + | |
| 681 | + vb = list_first_entry(&q->queued_list, struct vb2_buffer, queued_entry); | |
| 682 | + for (i = 0; i < vb->num_planes; i++) | |
| 683 | + vb2_set_plane_payload(vb, i, 0); | |
| 684 | + | |
| 685 | + /* | |
| 686 | + * Since the buffer hasn't been queued to the ready queue, | |
| 687 | + * mark is active and owned before marking it LAST and DONE | |
| 688 | + */ | |
| 689 | + vb->state = VB2_BUF_STATE_ACTIVE; | |
| 690 | + atomic_inc(&q->owned_by_drv_count); | |
| 691 | + | |
| 692 | + vbuf = to_vb2_v4l2_buffer(vb); | |
| 693 | + vbuf->field = V4L2_FIELD_NONE; | |
| 694 | + | |
| 695 | + v4l2_m2m_last_buffer_done(m2m_ctx, vbuf); | |
| 696 | +} | |
| 697 | + | |
| 559 | 698 | int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, |
| 560 | 699 | struct v4l2_buffer *buf) |
| 561 | 700 | { |
| @@ -570,11 +709,25 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, · 8 unmodified lines | ||
| 570 | 709 | __func__); |
| 571 | 710 | return -EPERM; |
| 572 | 711 | } |
| 712 | + | |
| 573 | 713 | ret = vb2_qbuf(vq, vdev->v4l2_dev->mdev, buf); |
| 574 | − if (!ret && !(buf->flags & V4L2_BUF_FLAG_IN_REQUEST)) | |
| 714 | + if (ret) | |
| 715 | + return ret; | |
| 716 | + | |
| 717 | + /* | |
| 718 | + * If the capture queue is streaming, but streaming hasn't started | |
| 719 | + * on the device, but was asked to stop, mark the previously queued | |
| 720 | + * buffer as DONE with LAST flag since it won't be queued on the | |
| 721 | + * device. | |
| 722 | + */ | |
| 723 | + if (!V4L2_TYPE_IS_OUTPUT(vq->type) && | |
| 724 | + vb2_is_streaming(vq) && !vb2_start_streaming_called(vq) && | |
| 725 | + (v4l2_m2m_has_stopped(m2m_ctx) || v4l2_m2m_dst_buf_is_last(m2m_ctx))) | |
| 726 | + v4l2_m2m_force_last_buf_done(m2m_ctx, vq); | |
| 727 | + else if (!(buf->flags & V4L2_BUF_FLAG_IN_REQUEST)) | |
| 575 | 728 | v4l2_m2m_try_schedule(m2m_ctx); |
| 576 | 729 | |
| 577 | − return ret; | |
| 730 | + return 0; | |
| 578 | 731 | } |
| 579 | 732 | EXPORT_SYMBOL_GPL(v4l2_m2m_qbuf); |
| 580 | 733 | |
| @@ -1225,6 +1378,70 @@ int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, · 644 unmodified lines | ||
| 1225 | 1378 | } |
| 1226 | 1379 | EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd); |
| 1227 | 1380 | |
| 1381 | +/* | |
| 1382 | + * Updates the encoding state on ENC_CMD_STOP/ENC_CMD_START | |
| 1383 | + * Should be called from the encoder driver encoder_cmd() callback | |
| 1384 | + */ | |
| 1385 | +int v4l2_m2m_encoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |
| 1386 | + struct v4l2_encoder_cmd *ec) | |
| 1387 | +{ | |
| 1388 | + if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START) | |
| 1389 | + return -EINVAL; | |
| 1390 | + | |
| 1391 | + if (ec->cmd == V4L2_ENC_CMD_STOP) | |
| 1392 | + return v4l2_update_last_buf_state(m2m_ctx); | |
| 1393 | + | |
| 1394 | + if (m2m_ctx->is_draining) | |
| 1395 | + return -EBUSY; | |
| 1396 | + | |
| 1397 | + if (m2m_ctx->has_stopped) | |
| 1398 | + m2m_ctx->has_stopped = false; | |
| 1399 | + | |
| 1400 | + return 0; | |
| 1401 | +} | |
| 1402 | +EXPORT_SYMBOL_GPL(v4l2_m2m_encoder_cmd); | |
| 1403 | + | |
| 1404 | +/* | |
| 1405 | + * Updates the decoding state on DEC_CMD_STOP/DEC_CMD_START | |
| 1406 | + * Should be called from the decoder driver decoder_cmd() callback | |
| 1407 | + */ | |
| 1408 | +int v4l2_m2m_decoder_cmd(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, | |
| 1409 | + struct v4l2_decoder_cmd *dc) | |
| 1410 | +{ | |
| 1411 | + if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START) | |
| 1412 | + return -EINVAL; | |
| 1413 | + | |
| 1414 | + if (dc->cmd == V4L2_DEC_CMD_STOP) | |
| 1415 | + return v4l2_update_last_buf_state(m2m_ctx); | |
| 1416 | + | |
| 1417 | + if (m2m_ctx->is_draining) | |
| 1418 | + return -EBUSY; | |
| 1419 | + | |
| 1420 | + if (m2m_ctx->has_stopped) | |
| 1421 | + m2m_ctx->has_stopped = false; | |
| 1422 | + | |
| 1423 | + return 0; | |
| 1424 | +} | |
| 1425 | +EXPORT_SYMBOL_GPL(v4l2_m2m_decoder_cmd); | |
| 1426 | + | |
| 1427 | +int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv, | |
| 1428 | + struct v4l2_encoder_cmd *ec) | |
| 1429 | +{ | |
| 1430 | + struct v4l2_fh *fh = file->private_data; | |
| 1431 | + | |
| 1432 | + return v4l2_m2m_encoder_cmd(file, fh->m2m_ctx, ec); | |
| 1433 | +} | |
| 1434 | +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_encoder_cmd); | |
| 1435 | + | |
| 1436 | +int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv, | |
| 1437 | + struct v4l2_decoder_cmd *dc) | |
| 1438 | +{ | |
| 1439 | + struct v4l2_fh *fh = file->private_data; | |
| 1440 | + | |
| 1441 | + return v4l2_m2m_decoder_cmd(file, fh->m2m_ctx, dc); | |
| 1442 | +} | |
| 1443 | +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_decoder_cmd); | |
| 1444 | + | |
| 1228 | 1445 | int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, |
| 1229 | 1446 | struct v4l2_decoder_cmd *dc) |
| 1230 | 1447 | { |
| @@ -42,4 +42,8 @@ source "drivers/staging/media/phy-rockchip-dphy-rx0/Kconfig" · 41 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | source "drivers/staging/media/rkisp1/Kconfig" |
| 44 | 44 | |
| 45 | +if MEDIA_ANALOG_TV_SUPPORT | |
| 46 | +source "drivers/staging/media/usbvision/Kconfig" | |
| 47 | +endif | |
| 48 | + | |
| 45 | 49 | endif |
| @@ -10,3 +10,4 @@ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ · 9 unmodified lines | ||
| 10 | 10 | obj-$(CONFIG_SOC_CAMERA) += soc_camera/ |
| 11 | 11 | obj-$(CONFIG_PHY_ROCKCHIP_DPHY_RX0) += phy-rockchip-dphy-rx0/ |
| 12 | 12 | obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rkisp1/ |
| 13 | +obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ | |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | |
| 3 | −allegro-objs := allegro-core.o nal-h264.o | |
| 3 | +allegro-objs := allegro-core.o nal-h264.o allegro-mail.o | |
| 4 | 4 | |
| 5 | 5 | obj-$(CONFIG_VIDEO_ALLEGRO_DVT) += allegro.o |
| @@ -5,7 +5,9 @@ · 4 unmodified lines | ||
| 5 | 5 | * Allegro DVT video encoder driver |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | +#include <linux/bits.h> | |
| 8 | 9 | #include <linux/firmware.h> |
| 10 | +#include <linux/gcd.h> | |
| 9 | 11 | #include <linux/interrupt.h> |
| 10 | 12 | #include <linux/io.h> |
| 11 | 13 | #include <linux/kernel.h> |
| @@ -26,6 +28,7 @@ · 14 unmodified lines | ||
| 26 | 28 | #include <media/videobuf2-dma-contig.h> |
| 27 | 29 | #include <media/videobuf2-v4l2.h> |
| 28 | 30 | |
| 31 | +#include "allegro-mail.h" | |
| 29 | 32 | #include "nal-h264.h" |
| 30 | 33 | |
| 31 | 34 | /* |
| @@ -40,6 +43,8 @@ · 8 unmodified lines | ||
| 40 | 43 | #define ALLEGRO_HEIGHT_DEFAULT 1080 |
| 41 | 44 | #define ALLEGRO_HEIGHT_MAX 2160 |
| 42 | 45 | |
| 46 | +#define ALLEGRO_FRAMERATE_DEFAULT ((struct v4l2_fract) { 30, 1 }) | |
| 47 | + | |
| 43 | 48 | #define ALLEGRO_GOP_SIZE_DEFAULT 25 |
| 44 | 49 | #define ALLEGRO_GOP_SIZE_MAX 1000 |
| 45 | 50 | |
| @@ -176,6 +181,7 @@ struct allegro_channel { · 130 unmodified lines | ||
| 176 | 181 | unsigned int width; |
| 177 | 182 | unsigned int height; |
| 178 | 183 | unsigned int stride; |
| 184 | + struct v4l2_fract framerate; | |
| 179 | 185 | |
| 180 | 186 | enum v4l2_colorspace colorspace; |
| 181 | 187 | enum v4l2_ycbcr_encoding ycbcr_enc; |
| @@ -192,7 +198,7 @@ struct allegro_channel { · 10 unmodified lines | ||
| 192 | 198 | unsigned int sizeimage_encoded; |
| 193 | 199 | unsigned int csequence; |
| 194 | 200 | |
| 195 | − enum v4l2_mpeg_video_bitrate_mode bitrate_mode; | |
| 201 | + bool frame_rc_enable; | |
| 196 | 202 | unsigned int bitrate; |
| 197 | 203 | unsigned int bitrate_peak; |
| 198 | 204 | unsigned int cpb_size; |
| @@ -200,9 +206,17 @@ struct allegro_channel { · 1 unmodified line | ||
| 200 | 206 | |
| 201 | 207 | struct v4l2_ctrl *mpeg_video_h264_profile; |
| 202 | 208 | struct v4l2_ctrl *mpeg_video_h264_level; |
| 203 | − struct v4l2_ctrl *mpeg_video_bitrate_mode; | |
| 204 | − struct v4l2_ctrl *mpeg_video_bitrate; | |
| 205 | − struct v4l2_ctrl *mpeg_video_bitrate_peak; | |
| 209 | + struct v4l2_ctrl *mpeg_video_h264_i_frame_qp; | |
| 210 | + struct v4l2_ctrl *mpeg_video_h264_max_qp; | |
| 211 | + struct v4l2_ctrl *mpeg_video_h264_min_qp; | |
| 212 | + struct v4l2_ctrl *mpeg_video_h264_p_frame_qp; | |
| 213 | + struct v4l2_ctrl *mpeg_video_h264_b_frame_qp; | |
| 214 | + struct v4l2_ctrl *mpeg_video_frame_rc_enable; | |
| 215 | + struct { /* video bitrate mode control cluster */ | |
| 216 | + struct v4l2_ctrl *mpeg_video_bitrate_mode; | |
| 217 | + struct v4l2_ctrl *mpeg_video_bitrate; | |
| 218 | + struct v4l2_ctrl *mpeg_video_bitrate_peak; | |
| 219 | + }; | |
| 206 | 220 | struct v4l2_ctrl *mpeg_video_cpb_size; |
| 207 | 221 | struct v4l2_ctrl *mpeg_video_gop_size; |
| 208 | 222 | |
| @@ -215,6 +229,11 @@ struct allegro_channel { · 6 unmodified lines | ||
| 215 | 229 | struct list_head buffers_reference; |
| 216 | 230 | struct list_head buffers_intermediate; |
| 217 | 231 | |
| 232 | + struct list_head source_shadow_list; | |
| 233 | + struct list_head stream_shadow_list; | |
| 234 | + /* protect shadow lists of buffers passed to firmware */ | |
| 235 | + struct mutex shadow_list_lock; | |
| 236 | + | |
| 218 | 237 | struct list_head list; |
| 219 | 238 | struct completion completion; |
| 220 | 239 | |
| @@ -236,6 +255,14 @@ allegro_get_state(struct allegro_channel *channel) · 15 unmodified lines | ||
| 236 | 255 | return channel->state; |
| 237 | 256 | } |
| 238 | 257 | |
| 258 | +struct allegro_m2m_buffer { | |
| 259 | + struct v4l2_m2m_buffer buf; | |
| 260 | + struct list_head head; | |
| 261 | +}; | |
| 262 | + | |
| 263 | +#define to_allegro_m2m_buffer(__buf) \ | |
| 264 | + container_of(__buf, struct allegro_m2m_buffer, buf) | |
| 265 | + | |
| 239 | 266 | struct fw_info { |
| 240 | 267 | unsigned int id; |
| 241 | 268 | unsigned int id_codec; |
| @@ -258,276 +285,33 @@ static const struct fw_info supported_firmware[] = { · 16 unmodified lines | ||
| 258 | 285 | }, |
| 259 | 286 | }; |
| 260 | 287 | |
| 261 | −enum mcu_msg_type { | |
| 262 | − MCU_MSG_TYPE_INIT = 0x0000, | |
| 263 | − MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005, | |
| 264 | − MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006, | |
| 265 | − MCU_MSG_TYPE_ENCODE_FRAME = 0x0007, | |
| 266 | − MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012, | |
| 267 | − MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e, | |
| 268 | − MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f, | |
| 269 | −}; | |
| 288 | +static inline u32 to_mcu_addr(struct allegro_dev *dev, dma_addr_t phys) | |
| 289 | +{ | |
| 290 | + if (upper_32_bits(phys) || (lower_32_bits(phys) & MCU_CACHE_OFFSET)) | |
| 291 | + v4l2_warn(&dev->v4l2_dev, | |
| 292 | + "address %pad is outside mcu window\n", &phys); | |
| 293 | + | |
| 294 | + return lower_32_bits(phys) | MCU_CACHE_OFFSET; | |
| 295 | +} | |
| 270 | 296 | |
| 271 | −static const char *msg_type_name(enum mcu_msg_type type) | |
| 297 | +static inline u32 to_mcu_size(struct allegro_dev *dev, size_t size) | |
| 272 | 298 | { |
| 273 | − static char buf[9]; | |
| 299 | + return lower_32_bits(size); | |
| 300 | +} | |
| 274 | 301 | |
| 275 | − switch (type) { | |
| 276 | − case MCU_MSG_TYPE_INIT: | |
| 277 | − return "INIT"; | |
| 278 | − case MCU_MSG_TYPE_CREATE_CHANNEL: | |
| 279 | − return "CREATE_CHANNEL"; | |
| 280 | − case MCU_MSG_TYPE_DESTROY_CHANNEL: | |
| 281 | − return "DESTROY_CHANNEL"; | |
| 282 | − case MCU_MSG_TYPE_ENCODE_FRAME: | |
| 283 | − return "ENCODE_FRAME"; | |
| 284 | − case MCU_MSG_TYPE_PUT_STREAM_BUFFER: | |
| 285 | − return "PUT_STREAM_BUFFER"; | |
| 286 | − case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: | |
| 287 | − return "PUSH_BUFFER_INTERMEDIATE"; | |
| 288 | − case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: | |
| 289 | − return "PUSH_BUFFER_REFERENCE"; | |
| 290 | − default: | |
| 291 | − snprintf(buf, sizeof(buf), "(0x%04x)", type); | |
| 292 | − return buf; | |
| 293 | − } | |
| 294 | −} | |
| 295 | − | |
| 296 | −struct mcu_msg_header { | |
| 297 | − u16 length; /* length of the body in bytes */ | |
| 298 | − u16 type; | |
| 299 | −} __attribute__ ((__packed__)); | |
| 300 | − | |
| 301 | −struct mcu_msg_init_request { | |
| 302 | − struct mcu_msg_header header; | |
| 303 | − u32 reserved0; /* maybe a unused channel id */ | |
| 304 | − u32 suballoc_dma; | |
| 305 | − u32 suballoc_size; | |
| 306 | − s32 l2_cache[3]; | |
| 307 | −} __attribute__ ((__packed__)); | |
| 308 | − | |
| 309 | −struct mcu_msg_init_response { | |
| 310 | − struct mcu_msg_header header; | |
| 311 | − u32 reserved0; | |
| 312 | −} __attribute__ ((__packed__)); | |
| 313 | − | |
| 314 | −struct mcu_msg_create_channel { | |
| 315 | − struct mcu_msg_header header; | |
| 316 | − u32 user_id; | |
| 317 | − u16 width; | |
| 318 | − u16 height; | |
| 319 | − u32 format; | |
| 320 | − u32 colorspace; | |
| 321 | − u32 src_mode; | |
| 322 | − u8 profile; | |
| 323 | − u16 constraint_set_flags; | |
| 324 | − s8 codec; | |
| 325 | − u16 level; | |
| 326 | − u16 tier; | |
| 327 | − u32 sps_param; | |
| 328 | − u32 pps_param; | |
| 329 | − | |
| 330 | − u32 enc_option; | |
| 331 | −#define AL_OPT_WPP BIT(0) | |
| 332 | −#define AL_OPT_TILE BIT(1) | |
| 333 | −#define AL_OPT_LF BIT(2) | |
| 334 | −#define AL_OPT_LF_X_SLICE BIT(3) | |
| 335 | −#define AL_OPT_LF_X_TILE BIT(4) | |
| 336 | −#define AL_OPT_SCL_LST BIT(5) | |
| 337 | −#define AL_OPT_CONST_INTRA_PRED BIT(6) | |
| 338 | −#define AL_OPT_QP_TAB_RELATIVE BIT(7) | |
| 339 | −#define AL_OPT_FIX_PREDICTOR BIT(8) | |
| 340 | −#define AL_OPT_CUSTOM_LDA BIT(9) | |
| 341 | −#define AL_OPT_ENABLE_AUTO_QP BIT(10) | |
| 342 | −#define AL_OPT_ADAPT_AUTO_QP BIT(11) | |
| 343 | −#define AL_OPT_TRANSFO_SKIP BIT(13) | |
| 344 | −#define AL_OPT_FORCE_REC BIT(15) | |
| 345 | −#define AL_OPT_FORCE_MV_OUT BIT(16) | |
| 346 | −#define AL_OPT_FORCE_MV_CLIP BIT(17) | |
| 347 | −#define AL_OPT_LOWLAT_SYNC BIT(18) | |
| 348 | −#define AL_OPT_LOWLAT_INT BIT(19) | |
| 349 | −#define AL_OPT_RDO_COST_MODE BIT(20) | |
| 350 | − | |
| 351 | − s8 beta_offset; | |
| 352 | − s8 tc_offset; | |
| 353 | − u16 reserved10; | |
| 354 | − u32 unknown11; | |
| 355 | − u32 unknown12; | |
| 356 | − u16 num_slices; | |
| 357 | − u16 prefetch_auto; | |
| 358 | − u32 prefetch_mem_offset; | |
| 359 | − u32 prefetch_mem_size; | |
| 360 | − u16 clip_hrz_range; | |
| 361 | − u16 clip_vrt_range; | |
| 362 | − u16 me_range[4]; | |
| 363 | − u8 max_cu_size; | |
| 364 | − u8 min_cu_size; | |
| 365 | − u8 max_tu_size; | |
| 366 | − u8 min_tu_size; | |
| 367 | − u8 max_transfo_depth_inter; | |
| 368 | − u8 max_transfo_depth_intra; | |
| 369 | − u16 reserved20; | |
| 370 | − u32 entropy_mode; | |
| 371 | − u32 wp_mode; | |
| 372 | − | |
| 373 | − /* rate control param */ | |
| 374 | − u32 rate_control_mode; | |
| 375 | − u32 initial_rem_delay; | |
| 376 | − u32 cpb_size; | |
| 377 | − u16 framerate; | |
| 378 | − u16 clk_ratio; | |
| 379 | − u32 target_bitrate; | |
| 380 | − u32 max_bitrate; | |
| 381 | − u16 initial_qp; | |
| 382 | − u16 min_qp; | |
| 383 | − u16 max_qp; | |
| 384 | − s16 ip_delta; | |
| 385 | − s16 pb_delta; | |
| 386 | − u16 golden_ref; | |
| 387 | − u16 golden_delta; | |
| 388 | − u16 golden_ref_frequency; | |
| 389 | − u32 rate_control_option; | |
| 390 | − | |
| 391 | − /* gop param */ | |
| 392 | − u32 gop_ctrl_mode; | |
| 393 | − u32 freq_ird; | |
| 394 | − u32 freq_lt; | |
| 395 | − u32 gdr_mode; | |
| 396 | − u32 gop_length; | |
| 397 | − u32 unknown39; | |
| 398 | − | |
| 399 | − u32 subframe_latency; | |
| 400 | − u32 lda_control_mode; | |
| 401 | −} __attribute__ ((__packed__)); | |
| 402 | − | |
| 403 | −struct mcu_msg_create_channel_response { | |
| 404 | − struct mcu_msg_header header; | |
| 405 | − u32 channel_id; | |
| 406 | − u32 user_id; | |
| 407 | − u32 options; | |
| 408 | − u32 num_core; | |
| 409 | − u32 pps_param; | |
| 410 | − u32 int_buffers_count; | |
| 411 | − u32 int_buffers_size; | |
| 412 | − u32 rec_buffers_count; | |
| 413 | − u32 rec_buffers_size; | |
| 414 | − u32 reserved; | |
| 415 | − u32 error_code; | |
| 416 | −} __attribute__ ((__packed__)); | |
| 417 | − | |
| 418 | −struct mcu_msg_destroy_channel { | |
| 419 | − struct mcu_msg_header header; | |
| 420 | − u32 channel_id; | |
| 421 | −} __attribute__ ((__packed__)); | |
| 422 | − | |
| 423 | −struct mcu_msg_destroy_channel_response { | |
| 424 | − struct mcu_msg_header header; | |
| 425 | − u32 channel_id; | |
| 426 | −} __attribute__ ((__packed__)); | |
| 427 | − | |
| 428 | −struct mcu_msg_push_buffers_internal_buffer { | |
| 429 | − u32 dma_addr; | |
| 430 | − u32 mcu_addr; | |
| 431 | − u32 size; | |
| 432 | −} __attribute__ ((__packed__)); | |
| 433 | − | |
| 434 | −struct mcu_msg_push_buffers_internal { | |
| 435 | − struct mcu_msg_header header; | |
| 436 | − u32 channel_id; | |
| 437 | − struct mcu_msg_push_buffers_internal_buffer buffer[0]; | |
| 438 | −} __attribute__ ((__packed__)); | |
| 439 | − | |
| 440 | −struct mcu_msg_put_stream_buffer { | |
| 441 | − struct mcu_msg_header header; | |
| 442 | − u32 channel_id; | |
| 443 | − u32 dma_addr; | |
| 444 | − u32 mcu_addr; | |
| 445 | − u32 size; | |
| 446 | − u32 offset; | |
| 447 | − u64 stream_id; | |
| 448 | −} __attribute__ ((__packed__)); | |
| 449 | − | |
| 450 | −struct mcu_msg_encode_frame { | |
| 451 | − struct mcu_msg_header header; | |
| 452 | − u32 channel_id; | |
| 453 | − u32 reserved; | |
| 454 | − | |
| 455 | − u32 encoding_options; | |
| 456 | −#define AL_OPT_USE_QP_TABLE BIT(0) | |
| 457 | −#define AL_OPT_FORCE_LOAD BIT(1) | |
| 458 | −#define AL_OPT_USE_L2 BIT(2) | |
| 459 | −#define AL_OPT_DISABLE_INTRA BIT(3) | |
| 460 | −#define AL_OPT_DEPENDENT_SLICES BIT(4) | |
| 461 | − | |
| 462 | − s16 pps_qp; | |
| 463 | − u16 padding; | |
| 464 | − u64 user_param; | |
| 465 | − u64 src_handle; | |
| 302 | +static inline u32 to_codec_addr(struct allegro_dev *dev, dma_addr_t phys) | |
| 303 | +{ | |
| 304 | + if (upper_32_bits(phys)) | |
| 305 | + v4l2_warn(&dev->v4l2_dev, | |
| 306 | + "address %pad cannot be used by codec\n", &phys); | |
| 466 | 307 | |
| 467 | − u32 request_options; | |
| 468 | −#define AL_OPT_SCENE_CHANGE BIT(0) | |
| 469 | −#define AL_OPT_RESTART_GOP BIT(1) | |
| 470 | −#define AL_OPT_USE_LONG_TERM BIT(2) | |
| 471 | −#define AL_OPT_UPDATE_PARAMS BIT(3) | |
| 472 | − | |
| 473 | − /* u32 scene_change_delay (optional) */ | |
| 474 | − /* rate control param (optional) */ | |
| 475 | − /* gop param (optional) */ | |
| 476 | − u32 src_y; | |
| 477 | − u32 src_uv; | |
| 478 | − u32 stride; | |
| 479 | − u32 ep2; | |
| 480 | − u64 ep2_v; | |
| 481 | −} __attribute__ ((__packed__)); | |
| 482 | − | |
| 483 | −struct mcu_msg_encode_frame_response { | |
| 484 | − struct mcu_msg_header header; | |
| 485 | − u32 channel_id; | |
| 486 | − u64 stream_id; /* see mcu_msg_put_stream_buffer */ | |
| 487 | − u64 user_param; /* see mcu_msg_encode_frame */ | |
| 488 | − u64 src_handle; /* see mcu_msg_encode_frame */ | |
| 489 | − u16 skip; | |
| 490 | − u16 is_ref; | |
| 491 | − u32 initial_removal_delay; | |
| 492 | − u32 dpb_output_delay; | |
| 493 | − u32 size; | |
| 494 | − u32 frame_tag_size; | |
| 495 | − s32 stuffing; | |
| 496 | − s32 filler; | |
| 497 | − u16 num_column; | |
| 498 | − u16 num_row; | |
| 499 | − u16 qp; | |
| 500 | − u8 num_ref_idx_l0; | |
| 501 | − u8 num_ref_idx_l1; | |
| 502 | − u32 partition_table_offset; | |
| 503 | − s32 partition_table_size; | |
| 504 | − u32 sum_complex; | |
| 505 | − s32 tile_width[4]; | |
| 506 | − s32 tile_height[22]; | |
| 507 | − u32 error_code; | |
| 508 | − | |
| 509 | − u32 slice_type; | |
| 510 | −#define AL_ENC_SLICE_TYPE_B 0 | |
| 511 | −#define AL_ENC_SLICE_TYPE_P 1 | |
| 512 | −#define AL_ENC_SLICE_TYPE_I 2 | |
| 513 | − | |
| 514 | − u32 pic_struct; | |
| 515 | − u8 is_idr; | |
| 516 | − u8 is_first_slice; | |
| 517 | − u8 is_last_slice; | |
| 518 | − u8 reserved; | |
| 519 | − u16 pps_qp; | |
| 520 | − u16 reserved1; | |
| 521 | − u32 reserved2; | |
| 522 | −} __attribute__ ((__packed__)); | |
| 523 | − | |
| 524 | −union mcu_msg_response { | |
| 525 | − struct mcu_msg_header header; | |
| 526 | − struct mcu_msg_init_response init; | |
| 527 | − struct mcu_msg_create_channel_response create_channel; | |
| 528 | − struct mcu_msg_destroy_channel_response destroy_channel; | |
| 529 | − struct mcu_msg_encode_frame_response encode_frame; | |
| 530 | −}; | |
| 308 | + return lower_32_bits(phys); | |
| 309 | +} | |
| 310 | + | |
| 311 | +static inline u64 ptr_to_u64(const void *ptr) | |
| 312 | +{ | |
| 313 | + return (uintptr_t)ptr; | |
| 314 | +} | |
| 531 | 315 | |
| 532 | 316 | /* Helper functions for channel and user operations */ |
| 533 | 317 | |
| @@ -572,6 +356,56 @@ static inline bool channel_exists(struct allegro_channel *channel) · 38 unmodified lines | ||
| 572 | 356 | return channel->mcu_channel_id != -1; |
| 573 | 357 | } |
| 574 | 358 | |
| 359 | +#define AL_ERROR 0x80 | |
| 360 | +#define AL_ERR_INIT_FAILED 0x81 | |
| 361 | +#define AL_ERR_NO_FRAME_DECODED 0x82 | |
| 362 | +#define AL_ERR_RESOLUTION_CHANGE 0x85 | |
| 363 | +#define AL_ERR_NO_MEMORY 0x87 | |
| 364 | +#define AL_ERR_STREAM_OVERFLOW 0x88 | |
| 365 | +#define AL_ERR_TOO_MANY_SLICES 0x89 | |
| 366 | +#define AL_ERR_BUF_NOT_READY 0x8c | |
| 367 | +#define AL_ERR_NO_CHANNEL_AVAILABLE 0x8d | |
| 368 | +#define AL_ERR_RESOURCE_UNAVAILABLE 0x8e | |
| 369 | +#define AL_ERR_NOT_ENOUGH_CORES 0x8f | |
| 370 | +#define AL_ERR_REQUEST_MALFORMED 0x90 | |
| 371 | +#define AL_ERR_CMD_NOT_ALLOWED 0x91 | |
| 372 | +#define AL_ERR_INVALID_CMD_VALUE 0x92 | |
| 373 | + | |
| 374 | +static inline const char *allegro_err_to_string(unsigned int err) | |
| 375 | +{ | |
| 376 | + switch (err) { | |
| 377 | + case AL_ERR_INIT_FAILED: | |
| 378 | + return "initialization failed"; | |
| 379 | + case AL_ERR_NO_FRAME_DECODED: | |
| 380 | + return "no frame decoded"; | |
| 381 | + case AL_ERR_RESOLUTION_CHANGE: | |
| 382 | + return "resolution change"; | |
| 383 | + case AL_ERR_NO_MEMORY: | |
| 384 | + return "out of memory"; | |
| 385 | + case AL_ERR_STREAM_OVERFLOW: | |
| 386 | + return "stream buffer overflow"; | |
| 387 | + case AL_ERR_TOO_MANY_SLICES: | |
| 388 | + return "too many slices"; | |
| 389 | + case AL_ERR_BUF_NOT_READY: | |
| 390 | + return "buffer not ready"; | |
| 391 | + case AL_ERR_NO_CHANNEL_AVAILABLE: | |
| 392 | + return "no channel available"; | |
| 393 | + case AL_ERR_RESOURCE_UNAVAILABLE: | |
| 394 | + return "resource unavailable"; | |
| 395 | + case AL_ERR_NOT_ENOUGH_CORES: | |
| 396 | + return "not enough cores"; | |
| 397 | + case AL_ERR_REQUEST_MALFORMED: | |
| 398 | + return "request malformed"; | |
| 399 | + case AL_ERR_CMD_NOT_ALLOWED: | |
| 400 | + return "command not allowed"; | |
| 401 | + case AL_ERR_INVALID_CMD_VALUE: | |
| 402 | + return "invalid command value"; | |
| 403 | + case AL_ERROR: | |
| 404 | + default: | |
| 405 | + return "unknown error"; | |
| 406 | + } | |
| 407 | +} | |
| 408 | + | |
| 575 | 409 | static unsigned int estimate_stream_size(unsigned int width, |
| 576 | 410 | unsigned int height) |
| 577 | 411 | { |
| @@ -781,7 +615,7 @@ static int allegro_mbox_write(struct allegro_dev *dev, · 203 unmodified lines | ||
| 781 | 615 | |
| 782 | 616 | if (size > mbox->size) { |
| 783 | 617 | v4l2_err(&dev->v4l2_dev, |
| 784 | − "message (%zu bytes) to large for mailbox (%zu bytes)\n", | |
| 618 | + "message (%zu bytes) too large for mailbox (%zu bytes)\n", | |
| 785 | 619 | size, mbox->size); |
| 786 | 620 | return -EINVAL; |
| 787 | 621 | } |
| @@ -894,8 +728,8 @@ static void allegro_mcu_send_init(struct allegro_dev *dev, · 106 unmodified lines | ||
| 894 | 728 | msg.header.type = MCU_MSG_TYPE_INIT; |
| 895 | 729 | msg.header.length = sizeof(msg) - sizeof(msg.header); |
| 896 | 730 | |
| 897 | − msg.suballoc_dma = lower_32_bits(suballoc_dma) | MCU_CACHE_OFFSET; | |
| 898 | − msg.suballoc_size = suballoc_size; | |
| 731 | + msg.suballoc_dma = to_mcu_addr(dev, suballoc_dma); | |
| 732 | + msg.suballoc_size = to_mcu_size(dev, suballoc_size); | |
| 899 | 733 | |
| 900 | 734 | /* disable L2 cache */ |
| 901 | 735 | msg.l2_cache[0] = -1; |
| @@ -1001,6 +835,103 @@ v4l2_bitrate_mode_to_mcu_mode(enum v4l2_mpeg_video_bitrate_mode mode) · 99 unmodified lines | ||
| 1001 | 835 | } |
| 1002 | 836 | } |
| 1003 | 837 | |
| 838 | +static u32 v4l2_cpb_size_to_mcu(unsigned int cpb_size, unsigned int bitrate) | |
| 839 | +{ | |
| 840 | + unsigned int cpb_size_kbit; | |
| 841 | + unsigned int bitrate_kbps; | |
| 842 | + | |
| 843 | + /* | |
| 844 | + * The mcu expects the CPB size in units of a 90 kHz clock, but the | |
| 845 | + * channel follows the V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE and stores | |
| 846 | + * the CPB size in kilobytes. | |
| 847 | + */ | |
| 848 | + cpb_size_kbit = cpb_size * BITS_PER_BYTE; | |
| 849 | + bitrate_kbps = bitrate / 1000; | |
| 850 | + | |
| 851 | + return (cpb_size_kbit * 90000) / bitrate_kbps; | |
| 852 | +} | |
| 853 | + | |
| 854 | +static s16 get_qp_delta(int minuend, int subtrahend) | |
| 855 | +{ | |
| 856 | + if (minuend == subtrahend) | |
| 857 | + return -1; | |
| 858 | + else | |
| 859 | + return minuend - subtrahend; | |
| 860 | +} | |
| 861 | + | |
| 862 | +static int fill_create_channel_param(struct allegro_channel *channel, | |
| 863 | + struct create_channel_param *param) | |
| 864 | +{ | |
| 865 | + int i_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_i_frame_qp); | |
| 866 | + int p_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_p_frame_qp); | |
| 867 | + int b_frame_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_b_frame_qp); | |
| 868 | + int bitrate_mode = v4l2_ctrl_g_ctrl(channel->mpeg_video_bitrate_mode); | |
| 869 | + | |
| 870 | + param->width = channel->width; | |
| 871 | + param->height = channel->height; | |
| 872 | + param->format = v4l2_pixelformat_to_mcu_format(channel->pixelformat); | |
| 873 | + param->colorspace = | |
| 874 | + v4l2_colorspace_to_mcu_colorspace(channel->colorspace); | |
| 875 | + param->src_mode = 0x0; | |
| 876 | + param->profile = v4l2_profile_to_mcu_profile(channel->profile); | |
| 877 | + param->constraint_set_flags = BIT(1); | |
| 878 | + param->codec = v4l2_pixelformat_to_mcu_codec(channel->codec); | |
| 879 | + param->level = v4l2_level_to_mcu_level(channel->level); | |
| 880 | + param->tier = 0; | |
| 881 | + param->sps_param = BIT(20) | 0x4a; | |
| 882 | + param->pps_param = BIT(2); | |
| 883 | + param->enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE | | |
| 884 | + AL_OPT_LF_X_SLICE | AL_OPT_LF; | |
| 885 | + param->beta_offset = -1; | |
| 886 | + param->tc_offset = -1; | |
| 887 | + param->num_slices = 1; | |
| 888 | + param->me_range[0] = 8; | |
| 889 | + param->me_range[1] = 8; | |
| 890 | + param->me_range[2] = 16; | |
| 891 | + param->me_range[3] = 16; | |
| 892 | + param->max_cu_size = ilog2(SIZE_MACROBLOCK); | |
| 893 | + param->min_cu_size = ilog2(8); | |
| 894 | + param->max_tu_size = 2; | |
| 895 | + param->min_tu_size = 2; | |
| 896 | + param->max_transfo_depth_intra = 1; | |
| 897 | + param->max_transfo_depth_inter = 1; | |
| 898 | + | |
| 899 | + param->prefetch_auto = 0; | |
| 900 | + param->prefetch_mem_offset = 0; | |
| 901 | + param->prefetch_mem_size = 0; | |
| 902 | + | |
| 903 | + param->rate_control_mode = channel->frame_rc_enable ? | |
| 904 | + v4l2_bitrate_mode_to_mcu_mode(bitrate_mode) : 0; | |
| 905 | + | |
| 906 | + param->cpb_size = v4l2_cpb_size_to_mcu(channel->cpb_size, | |
| 907 | + channel->bitrate_peak); | |
| 908 | + /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */ | |
| 909 | + param->initial_rem_delay = param->cpb_size; | |
| 910 | + param->framerate = DIV_ROUND_UP(channel->framerate.numerator, | |
| 911 | + channel->framerate.denominator); | |
| 912 | + param->clk_ratio = channel->framerate.denominator == 1001 ? 1001 : 1000; | |
| 913 | + param->target_bitrate = channel->bitrate; | |
| 914 | + param->max_bitrate = channel->bitrate_peak; | |
| 915 | + param->initial_qp = i_frame_qp; | |
| 916 | + param->min_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_min_qp); | |
| 917 | + param->max_qp = v4l2_ctrl_g_ctrl(channel->mpeg_video_h264_max_qp); | |
| 918 | + param->ip_delta = get_qp_delta(i_frame_qp, p_frame_qp); | |
| 919 | + param->pb_delta = get_qp_delta(p_frame_qp, b_frame_qp); | |
| 920 | + param->golden_ref = 0; | |
| 921 | + param->golden_delta = 2; | |
| 922 | + param->golden_ref_frequency = 10; | |
| 923 | + param->rate_control_option = 0x00000000; | |
| 924 | + | |
| 925 | + param->gop_ctrl_mode = 0x00000000; | |
| 926 | + param->freq_idr = channel->gop_size; | |
| 927 | + param->freq_lt = 0; | |
| 928 | + param->gdr_mode = 0x00000000; | |
| 929 | + param->gop_length = channel->gop_size; | |
| 930 | + param->subframe_latency = 0x00000000; | |
| 931 | + | |
| 932 | + return 0; | |
| 933 | +} | |
| 934 | + | |
| 1004 | 935 | static int allegro_mcu_send_create_channel(struct allegro_dev *dev, |
| 1005 | 936 | struct allegro_channel *channel) |
| 1006 | 937 | { |
| @@ -1012,63 +943,8 @@ static int allegro_mcu_send_create_channel(struct allegro_dev *dev, · 5 unmodified lines | ||
| 1012 | 943 | msg.header.length = sizeof(msg) - sizeof(msg.header); |
| 1013 | 944 | |
| 1014 | 945 | msg.user_id = channel->user_id; |
| 1015 | − msg.width = channel->width; | |
| 1016 | − msg.height = channel->height; | |
| 1017 | − msg.format = v4l2_pixelformat_to_mcu_format(channel->pixelformat); | |
| 1018 | − msg.colorspace = v4l2_colorspace_to_mcu_colorspace(channel->colorspace); | |
| 1019 | − msg.src_mode = 0x0; | |
| 1020 | − msg.profile = v4l2_profile_to_mcu_profile(channel->profile); | |
| 1021 | − msg.constraint_set_flags = BIT(1); | |
| 1022 | − msg.codec = v4l2_pixelformat_to_mcu_codec(channel->codec); | |
| 1023 | − msg.level = v4l2_level_to_mcu_level(channel->level); | |
| 1024 | − msg.tier = 0; | |
| 1025 | − msg.sps_param = BIT(20) | 0x4a; | |
| 1026 | − msg.pps_param = BIT(2); | |
| 1027 | − msg.enc_option = AL_OPT_RDO_COST_MODE | AL_OPT_LF_X_TILE | | |
| 1028 | − AL_OPT_LF_X_SLICE | AL_OPT_LF; | |
| 1029 | − msg.beta_offset = -1; | |
| 1030 | − msg.tc_offset = -1; | |
| 1031 | − msg.num_slices = 1; | |
| 1032 | − msg.me_range[0] = 8; | |
| 1033 | − msg.me_range[1] = 8; | |
| 1034 | − msg.me_range[2] = 16; | |
| 1035 | − msg.me_range[3] = 16; | |
| 1036 | − msg.max_cu_size = ilog2(SIZE_MACROBLOCK); | |
| 1037 | − msg.min_cu_size = ilog2(8); | |
| 1038 | − msg.max_tu_size = 2; | |
| 1039 | − msg.min_tu_size = 2; | |
| 1040 | − msg.max_transfo_depth_intra = 1; | |
| 1041 | − msg.max_transfo_depth_inter = 1; | |
| 1042 | − | |
| 1043 | − msg.rate_control_mode = | |
| 1044 | − v4l2_bitrate_mode_to_mcu_mode(channel->bitrate_mode); | |
| 1045 | − /* Shall be ]0;cpb_size in 90 kHz units]. Use maximum value. */ | |
| 1046 | − msg.initial_rem_delay = | |
| 1047 | − ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000; | |
| 1048 | − /* Encoder expects cpb_size in units of a 90 kHz clock. */ | |
| 1049 | − msg.cpb_size = | |
| 1050 | − ((channel->cpb_size * 1000) / channel->bitrate_peak) * 90000; | |
| 1051 | − msg.framerate = 25; | |
| 1052 | − msg.clk_ratio = 1000; | |
| 1053 | − msg.target_bitrate = channel->bitrate; | |
| 1054 | − msg.max_bitrate = channel->bitrate_peak; | |
| 1055 | − msg.initial_qp = 25; | |
| 1056 | − msg.min_qp = 10; | |
| 1057 | − msg.max_qp = 51; | |
| 1058 | − msg.ip_delta = -1; | |
| 1059 | − msg.pb_delta = -1; | |
| 1060 | − msg.golden_ref = 0; | |
| 1061 | − msg.golden_delta = 2; | |
| 1062 | − msg.golden_ref_frequency = 10; | |
| 1063 | − msg.rate_control_option = 0x00000000; | |
| 1064 | − | |
| 1065 | − msg.gop_ctrl_mode = 0x00000000; | |
| 1066 | − msg.freq_ird = 0x7fffffff; | |
| 1067 | − msg.freq_lt = 0; | |
| 1068 | − msg.gdr_mode = 0x00000000; | |
| 1069 | − msg.gop_length = channel->gop_size; | |
| 1070 | − msg.subframe_latency = 0x00000000; | |
| 1071 | − msg.lda_control_mode = 0x700d0000; | |
| 946 | + | |
| 947 | + fill_create_channel_param(channel, &msg.param); | |
| 1072 | 948 | |
| 1073 | 949 | allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); |
| 1074 | 950 | allegro_mcu_interrupt(dev); |
| @@ -1097,7 +973,8 @@ static int allegro_mcu_send_destroy_channel(struct allegro_dev *dev, · 22 unmodified lines | ||
| 1097 | 973 | static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev, |
| 1098 | 974 | struct allegro_channel *channel, |
| 1099 | 975 | dma_addr_t paddr, |
| 1100 | − unsigned long size) | |
| 976 | + unsigned long size, | |
| 977 | + u64 stream_id) | |
| 1101 | 978 | { |
| 1102 | 979 | struct mcu_msg_put_stream_buffer msg; |
| 1103 | 980 | |
| @@ -1107,11 +984,12 @@ static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev, · 3 unmodified lines | ||
| 1107 | 984 | msg.header.length = sizeof(msg) - sizeof(msg.header); |
| 1108 | 985 | |
| 1109 | 986 | msg.channel_id = channel->mcu_channel_id; |
| 1110 | − msg.dma_addr = paddr; | |
| 1111 | − msg.mcu_addr = paddr | MCU_CACHE_OFFSET; | |
| 987 | + msg.dma_addr = to_codec_addr(dev, paddr); | |
| 988 | + msg.mcu_addr = to_mcu_addr(dev, paddr); | |
| 1112 | 989 | msg.size = size; |
| 1113 | 990 | msg.offset = ENCODER_STREAM_OFFSET; |
| 1114 | − msg.stream_id = 0; /* copied to mcu_msg_encode_frame_response */ | |
| 991 | + /* copied to mcu_msg_encode_frame_response */ | |
| 992 | + msg.stream_id = stream_id; | |
| 1115 | 993 | |
| 1116 | 994 | allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); |
| 1117 | 995 | allegro_mcu_interrupt(dev); |
| @@ -1121,7 +999,8 @@ static int allegro_mcu_send_put_stream_buffer(struct allegro_dev *dev, · 3 unmodified lines | ||
| 1121 | 999 | |
| 1122 | 1000 | static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, |
| 1123 | 1001 | struct allegro_channel *channel, |
| 1124 | − dma_addr_t src_y, dma_addr_t src_uv) | |
| 1002 | + dma_addr_t src_y, dma_addr_t src_uv, | |
| 1003 | + u64 src_handle) | |
| 1125 | 1004 | { |
| 1126 | 1005 | struct mcu_msg_encode_frame msg; |
| 1127 | 1006 | |
| @@ -1134,12 +1013,13 @@ static int allegro_mcu_send_encode_frame(struct allegro_dev *dev, · 6 unmodified lines | ||
| 1134 | 1013 | msg.encoding_options = AL_OPT_FORCE_LOAD; |
| 1135 | 1014 | msg.pps_qp = 26; /* qp are relative to 26 */ |
| 1136 | 1015 | msg.user_param = 0; /* copied to mcu_msg_encode_frame_response */ |
| 1137 | − msg.src_handle = 0; /* copied to mcu_msg_encode_frame_response */ | |
| 1138 | − msg.src_y = src_y; | |
| 1139 | − msg.src_uv = src_uv; | |
| 1016 | + /* src_handle is copied to mcu_msg_encode_frame_response */ | |
| 1017 | + msg.src_handle = src_handle; | |
| 1018 | + msg.src_y = to_codec_addr(dev, src_y); | |
| 1019 | + msg.src_uv = to_codec_addr(dev, src_uv); | |
| 1140 | 1020 | msg.stride = channel->stride; |
| 1141 | 1021 | msg.ep2 = 0x0; |
| 1142 | − msg.ep2_v = msg.ep2 | MCU_CACHE_OFFSET; | |
| 1022 | + msg.ep2_v = to_mcu_addr(dev, msg.ep2); | |
| 1143 | 1023 | |
| 1144 | 1024 | allegro_mbox_write(dev, &dev->mbox_command, &msg, sizeof(msg)); |
| 1145 | 1025 | allegro_mcu_interrupt(dev); |
| @@ -1198,10 +1078,9 @@ static int allegro_mcu_push_buffer_internal(struct allegro_channel *channel, · 52 unmodified lines | ||
| 1198 | 1078 | |
| 1199 | 1079 | buffer = msg->buffer; |
| 1200 | 1080 | list_for_each_entry(al_buffer, list, head) { |
| 1201 | − buffer->dma_addr = lower_32_bits(al_buffer->paddr); | |
| 1202 | − buffer->mcu_addr = | |
| 1203 | − lower_32_bits(al_buffer->paddr) | MCU_CACHE_OFFSET; | |
| 1204 | − buffer->size = al_buffer->size; | |
| 1081 | + buffer->dma_addr = to_codec_addr(dev, al_buffer->paddr); | |
| 1082 | + buffer->mcu_addr = to_mcu_addr(dev, al_buffer->paddr); | |
| 1083 | + buffer->size = to_mcu_size(dev, al_buffer->size); | |
| 1205 | 1084 | buffer++; |
| 1206 | 1085 | } |
| 1207 | 1086 | |
| @@ -1360,9 +1239,11 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, · 152 unmodified lines | ||
| 1360 | 1239 | sps->vui.chroma_loc_info_present_flag = 1; |
| 1361 | 1240 | sps->vui.chroma_sample_loc_type_top_field = 0; |
| 1362 | 1241 | sps->vui.chroma_sample_loc_type_bottom_field = 0; |
| 1242 | + | |
| 1363 | 1243 | sps->vui.timing_info_present_flag = 1; |
| 1364 | − sps->vui.num_units_in_tick = 1; | |
| 1365 | − sps->vui.time_scale = 50; | |
| 1244 | + sps->vui.num_units_in_tick = channel->framerate.denominator; | |
| 1245 | + sps->vui.time_scale = 2 * channel->framerate.numerator; | |
| 1246 | + | |
| 1366 | 1247 | sps->vui.fixed_frame_rate_flag = 1; |
| 1367 | 1248 | sps->vui.nal_hrd_parameters_present_flag = 0; |
| 1368 | 1249 | sps->vui.vcl_hrd_parameters_present_flag = 1; |
| @@ -1375,7 +1256,8 @@ static ssize_t allegro_h264_write_sps(struct allegro_channel *channel, · 6 unmodified lines | ||
| 1375 | 1256 | /* See Rec. ITU-T H.264 (04/2017) p. 410 E-54 */ |
| 1376 | 1257 | sps->vui.vcl_hrd_parameters.cpb_size_value_minus1[0] = |
| 1377 | 1258 | (channel->cpb_size * 1000) / (1 << (4 + sps->vui.vcl_hrd_parameters.cpb_size_scale)) - 1; |
| 1378 | − sps->vui.vcl_hrd_parameters.cbr_flag[0] = 1; | |
| 1259 | + sps->vui.vcl_hrd_parameters.cbr_flag[0] = | |
| 1260 | + !v4l2_ctrl_g_ctrl(channel->mpeg_video_frame_rc_enable); | |
| 1379 | 1261 | sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 = 31; |
| 1380 | 1262 | sps->vui.vcl_hrd_parameters.cpb_removal_delay_length_minus1 = 31; |
| 1381 | 1263 | sps->vui.vcl_hrd_parameters.dpb_output_delay_length_minus1 = 31; |
| @@ -1438,8 +1320,11 @@ static bool allegro_channel_is_at_eos(struct allegro_channel *channel) · 56 unmodified lines | ||
| 1438 | 1320 | break; |
| 1439 | 1321 | case ALLEGRO_STATE_DRAIN: |
| 1440 | 1322 | case ALLEGRO_STATE_WAIT_FOR_BUFFER: |
| 1441 | − if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0) | |
| 1323 | + mutex_lock(&channel->shadow_list_lock); | |
| 1324 | + if (v4l2_m2m_num_src_bufs_ready(channel->fh.m2m_ctx) == 0 && | |
| 1325 | + list_empty(&channel->source_shadow_list)) | |
| 1442 | 1326 | is_at_eos = true; |
| 1327 | + mutex_unlock(&channel->shadow_list_lock); | |
| 1443 | 1328 | break; |
| 1444 | 1329 | default: |
| 1445 | 1330 | break; |
| @@ -1466,6 +1351,41 @@ static void allegro_channel_buf_done(struct allegro_channel *channel, · 20 unmodified lines | ||
| 1466 | 1351 | v4l2_m2m_buf_done(buf, state); |
| 1467 | 1352 | } |
| 1468 | 1353 | |
| 1354 | +static u64 allegro_put_buffer(struct allegro_channel *channel, | |
| 1355 | + struct list_head *list, | |
| 1356 | + struct vb2_v4l2_buffer *buffer) | |
| 1357 | +{ | |
| 1358 | + struct v4l2_m2m_buffer *b = container_of(buffer, | |
| 1359 | + struct v4l2_m2m_buffer, vb); | |
| 1360 | + struct allegro_m2m_buffer *shadow = to_allegro_m2m_buffer(b); | |
| 1361 | + | |
| 1362 | + mutex_lock(&channel->shadow_list_lock); | |
| 1363 | + list_add_tail(&shadow->head, list); | |
| 1364 | + mutex_unlock(&channel->shadow_list_lock); | |
| 1365 | + | |
| 1366 | + return ptr_to_u64(buffer); | |
| 1367 | +} | |
| 1368 | + | |
| 1369 | +static struct vb2_v4l2_buffer * | |
| 1370 | +allegro_get_buffer(struct allegro_channel *channel, | |
| 1371 | + struct list_head *list, u64 handle) | |
| 1372 | +{ | |
| 1373 | + struct allegro_m2m_buffer *shadow, *tmp; | |
| 1374 | + struct vb2_v4l2_buffer *buffer = NULL; | |
| 1375 | + | |
| 1376 | + mutex_lock(&channel->shadow_list_lock); | |
| 1377 | + list_for_each_entry_safe(shadow, tmp, list, head) { | |
| 1378 | + if (handle == ptr_to_u64(&shadow->buf.vb)) { | |
| 1379 | + buffer = &shadow->buf.vb; | |
| 1380 | + list_del_init(&shadow->head); | |
| 1381 | + break; | |
| 1382 | + } | |
| 1383 | + } | |
| 1384 | + mutex_unlock(&channel->shadow_list_lock); | |
| 1385 | + | |
| 1386 | + return buffer; | |
| 1387 | +} | |
| 1388 | + | |
| 1469 | 1389 | static void allegro_channel_finish_frame(struct allegro_channel *channel, |
| 1470 | 1390 | struct mcu_msg_encode_frame_response *msg) |
| 1471 | 1391 | { |
| @@ -1481,15 +1401,31 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel, · 9 unmodified lines | ||
| 1481 | 1401 | ssize_t len; |
| 1482 | 1402 | ssize_t free; |
| 1483 | 1403 | |
| 1484 | − src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx); | |
| 1404 | + src_buf = allegro_get_buffer(channel, &channel->source_shadow_list, | |
| 1405 | + msg->src_handle); | |
| 1406 | + if (!src_buf) | |
| 1407 | + v4l2_warn(&dev->v4l2_dev, | |
| 1408 | + "channel %d: invalid source buffer\n", | |
| 1409 | + channel->mcu_channel_id); | |
| 1410 | + | |
| 1411 | + dst_buf = allegro_get_buffer(channel, &channel->stream_shadow_list, | |
| 1412 | + msg->stream_id); | |
| 1413 | + if (!dst_buf) | |
| 1414 | + v4l2_warn(&dev->v4l2_dev, | |
| 1415 | + "channel %d: invalid stream buffer\n", | |
| 1416 | + channel->mcu_channel_id); | |
| 1417 | + | |
| 1418 | + if (!src_buf || !dst_buf) | |
| 1419 | + goto err; | |
| 1485 | 1420 | |
| 1486 | − dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx); | |
| 1487 | 1421 | dst_buf->sequence = channel->csequence++; |
| 1488 | 1422 | |
| 1489 | − if (msg->error_code) { | |
| 1423 | + if (msg->error_code & AL_ERROR) { | |
| 1490 | 1424 | v4l2_err(&dev->v4l2_dev, |
| 1491 | − "channel %d: error while encoding frame: %x\n", | |
| 1492 | − channel->mcu_channel_id, msg->error_code); | |
| 1425 | + "channel %d: failed to encode frame: %s (%x)\n", | |
| 1426 | + channel->mcu_channel_id, | |
| 1427 | + allegro_err_to_string(msg->error_code), | |
| 1428 | + msg->error_code); | |
| 1493 | 1429 | goto err; |
| 1494 | 1430 | } |
| 1495 | 1431 | |
| @@ -1562,17 +1498,22 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel, · 66 unmodified lines | ||
| 1562 | 1498 | channel->mcu_channel_id, len); |
| 1563 | 1499 | } |
| 1564 | 1500 | |
| 1565 | − len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free); | |
| 1566 | − if (len < 0) { | |
| 1567 | − v4l2_err(&dev->v4l2_dev, | |
| 1568 | − "failed to write %zd filler data\n", free); | |
| 1569 | − goto err; | |
| 1501 | + if (msg->slice_type != AL_ENC_SLICE_TYPE_I && !msg->is_idr) { | |
| 1502 | + dst_buf->vb2_buf.planes[0].data_offset = free; | |
| 1503 | + free = 0; | |
| 1504 | + } else { | |
| 1505 | + len = nal_h264_write_filler(&dev->plat_dev->dev, curr, free); | |
| 1506 | + if (len < 0) { | |
| 1507 | + v4l2_err(&dev->v4l2_dev, | |
| 1508 | + "failed to write %zd filler data\n", free); | |
| 1509 | + goto err; | |
| 1510 | + } | |
| 1511 | + curr += len; | |
| 1512 | + free -= len; | |
| 1513 | + v4l2_dbg(2, debug, &dev->v4l2_dev, | |
| 1514 | + "channel %d: wrote %zd bytes filler nal unit\n", | |
| 1515 | + channel->mcu_channel_id, len); | |
| 1570 | 1516 | } |
| 1571 | − curr += len; | |
| 1572 | − free -= len; | |
| 1573 | − v4l2_dbg(2, debug, &dev->v4l2_dev, | |
| 1574 | − "channel %d: wrote %zd bytes filler nal unit\n", | |
| 1575 | − channel->mcu_channel_id, len); | |
| 1576 | 1517 | |
| 1577 | 1518 | if (free != 0) { |
| 1578 | 1519 | v4l2_err(&dev->v4l2_dev, |
| @@ -1590,20 +1531,20 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel, · 11 unmodified lines | ||
| 1590 | 1531 | dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; |
| 1591 | 1532 | |
| 1592 | 1533 | v4l2_dbg(1, debug, &dev->v4l2_dev, |
| 1593 | − "channel %d: encoded frame #%03d (%s%s, %d bytes)\n", | |
| 1534 | + "channel %d: encoded frame #%03d (%s%s, QP %d, %d bytes)\n", | |
| 1594 | 1535 | channel->mcu_channel_id, |
| 1595 | 1536 | dst_buf->sequence, |
| 1596 | 1537 | msg->is_idr ? "IDR, " : "", |
| 1597 | 1538 | msg->slice_type == AL_ENC_SLICE_TYPE_I ? "I slice" : |
| 1598 | 1539 | msg->slice_type == AL_ENC_SLICE_TYPE_P ? "P slice" : "unknown", |
| 1599 | − partition->size); | |
| 1540 | + msg->qp, partition->size); | |
| 1600 | 1541 | |
| 1601 | 1542 | err: |
| 1602 | − v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | |
| 1603 | − | |
| 1604 | − allegro_channel_buf_done(channel, dst_buf, state); | |
| 1543 | + if (src_buf) | |
| 1544 | + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | |
| 1605 | 1545 | |
| 1606 | − v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx); | |
| 1546 | + if (dst_buf) | |
| 1547 | + allegro_channel_buf_done(channel, dst_buf, state); | |
| 1607 | 1548 | } |
| 1608 | 1549 | |
| 1609 | 1550 | static int allegro_handle_init(struct allegro_dev *dev, |
| @@ -1621,6 +1562,12 @@ allegro_handle_create_channel(struct allegro_dev *dev, · 11 unmodified lines | ||
| 1621 | 1562 | struct allegro_channel *channel; |
| 1622 | 1563 | int err = 0; |
| 1623 | 1564 | |
| 1565 | + if (msg->header.length != sizeof(*msg) - sizeof(msg->header)) | |
| 1566 | + v4l2_warn(&dev->v4l2_dev, | |
| 1567 | + "received message has %d bytes, but expected %zu\n", | |
| 1568 | + msg->header.length, | |
| 1569 | + sizeof(*msg) - sizeof(msg->header)); | |
| 1570 | + | |
| 1624 | 1571 | channel = allegro_find_channel_by_user_id(dev, msg->user_id); |
| 1625 | 1572 | if (IS_ERR(channel)) { |
| 1626 | 1573 | v4l2_warn(&dev->v4l2_dev, |
| @@ -1632,8 +1579,10 @@ allegro_handle_create_channel(struct allegro_dev *dev, · 5 unmodified lines | ||
| 1632 | 1579 | |
| 1633 | 1580 | if (msg->error_code) { |
| 1634 | 1581 | v4l2_err(&dev->v4l2_dev, |
| 1635 | − "user %d: mcu failed to create channel: error %x\n", | |
| 1636 | − channel->user_id, msg->error_code); | |
| 1582 | + "user %d: mcu failed to create channel: %s (%x)\n", | |
| 1583 | + channel->user_id, | |
| 1584 | + allegro_err_to_string(msg->error_code), | |
| 1585 | + msg->error_code); | |
| 1637 | 1586 | err = -EIO; |
| 1638 | 1587 | goto out; |
| 1639 | 1588 | } |
| @@ -1712,6 +1661,12 @@ allegro_handle_encode_frame(struct allegro_dev *dev, · 72 unmodified lines | ||
| 1712 | 1661 | { |
| 1713 | 1662 | struct allegro_channel *channel; |
| 1714 | 1663 | |
| 1664 | + if (msg->header.length != sizeof(*msg) - sizeof(msg->header)) | |
| 1665 | + v4l2_warn(&dev->v4l2_dev, | |
| 1666 | + "received message has %d bytes, but expected %zu\n", | |
| 1667 | + msg->header.length, | |
| 1668 | + sizeof(*msg) - sizeof(msg->header)); | |
| 1669 | + | |
| 1715 | 1670 | channel = allegro_find_channel_by_channel_id(dev, msg->channel_id); |
| 1716 | 1671 | if (IS_ERR(channel)) { |
| 1717 | 1672 | v4l2_err(&dev->v4l2_dev, |
| @@ -1920,6 +1875,14 @@ static int allegro_mcu_reset(struct allegro_dev *dev) · 202 unmodified lines | ||
| 1920 | 1875 | { |
| 1921 | 1876 | int err; |
| 1922 | 1877 | |
| 1878 | + /* | |
| 1879 | + * Ensure that the AL5_MCU_WAKEUP bit is set to 0 otherwise the mcu | |
| 1880 | + * does not go to sleep after the reset. | |
| 1881 | + */ | |
| 1882 | + err = regmap_write(dev->regmap, AL5_MCU_WAKEUP, 0); | |
| 1883 | + if (err) | |
| 1884 | + return err; | |
| 1885 | + | |
| 1923 | 1886 | err = regmap_write(dev->regmap, |
| 1924 | 1887 | AL5_MCU_RESET_MODE, AL5_MCU_RESET_MODE_SLEEP); |
| 1925 | 1888 | if (err < 0) |
| @@ -1955,6 +1918,12 @@ static void allegro_destroy_channel(struct allegro_channel *channel) · 29 unmodified lines | ||
| 1955 | 1918 | |
| 1956 | 1919 | v4l2_ctrl_grab(channel->mpeg_video_h264_profile, false); |
| 1957 | 1920 | v4l2_ctrl_grab(channel->mpeg_video_h264_level, false); |
| 1921 | + v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, false); | |
| 1922 | + v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, false); | |
| 1923 | + v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, false); | |
| 1924 | + v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, false); | |
| 1925 | + v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, false); | |
| 1926 | + v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, false); | |
| 1958 | 1927 | v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, false); |
| 1959 | 1928 | v4l2_ctrl_grab(channel->mpeg_video_bitrate, false); |
| 1960 | 1929 | v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, false); |
| @@ -2000,7 +1969,9 @@ static int allegro_create_channel(struct allegro_channel *channel) · 39 unmodified lines | ||
| 2000 | 1969 | v4l2_dbg(1, debug, &dev->v4l2_dev, |
| 2001 | 1970 | "user %d: creating channel (%4.4s, %dx%d@%d)\n", |
| 2002 | 1971 | channel->user_id, |
| 2003 | − (char *)&channel->codec, channel->width, channel->height, 25); | |
| 1972 | + (char *)&channel->codec, channel->width, channel->height, | |
| 1973 | + DIV_ROUND_UP(channel->framerate.numerator, | |
| 1974 | + channel->framerate.denominator)); | |
| 2004 | 1975 | |
| 2005 | 1976 | min_level = select_minimum_h264_level(channel->width, channel->height); |
| 2006 | 1977 | if (channel->level < min_level) { |
| @@ -2014,6 +1985,12 @@ static int allegro_create_channel(struct allegro_channel *channel) · 7 unmodified lines | ||
| 2014 | 1985 | |
| 2015 | 1986 | v4l2_ctrl_grab(channel->mpeg_video_h264_profile, true); |
| 2016 | 1987 | v4l2_ctrl_grab(channel->mpeg_video_h264_level, true); |
| 1988 | + v4l2_ctrl_grab(channel->mpeg_video_h264_i_frame_qp, true); | |
| 1989 | + v4l2_ctrl_grab(channel->mpeg_video_h264_max_qp, true); | |
| 1990 | + v4l2_ctrl_grab(channel->mpeg_video_h264_min_qp, true); | |
| 1991 | + v4l2_ctrl_grab(channel->mpeg_video_h264_p_frame_qp, true); | |
| 1992 | + v4l2_ctrl_grab(channel->mpeg_video_h264_b_frame_qp, true); | |
| 1993 | + v4l2_ctrl_grab(channel->mpeg_video_frame_rc_enable, true); | |
| 2017 | 1994 | v4l2_ctrl_grab(channel->mpeg_video_bitrate_mode, true); |
| 2018 | 1995 | v4l2_ctrl_grab(channel->mpeg_video_bitrate, true); |
| 2019 | 1996 | v4l2_ctrl_grab(channel->mpeg_video_bitrate_peak, true); |
| @@ -2046,6 +2023,7 @@ static void allegro_set_default_params(struct allegro_channel *channel) · 26 unmodified lines | ||
| 2046 | 2023 | channel->width = ALLEGRO_WIDTH_DEFAULT; |
| 2047 | 2024 | channel->height = ALLEGRO_HEIGHT_DEFAULT; |
| 2048 | 2025 | channel->stride = round_up(channel->width, 32); |
| 2026 | + channel->framerate = ALLEGRO_FRAMERATE_DEFAULT; | |
| 2049 | 2027 | |
| 2050 | 2028 | channel->colorspace = V4L2_COLORSPACE_REC709; |
| 2051 | 2029 | channel->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; |
| @@ -2062,7 +2040,6 @@ static void allegro_set_default_params(struct allegro_channel *channel) · 10 unmodified lines | ||
| 2062 | 2040 | channel->sizeimage_encoded = |
| 2063 | 2041 | estimate_stream_size(channel->width, channel->height); |
| 2064 | 2042 | |
| 2065 | − channel->bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; | |
| 2066 | 2043 | channel->bitrate = maximum_bitrate(channel->level); |
| 2067 | 2044 | channel->bitrate_peak = maximum_bitrate(channel->level); |
| 2068 | 2045 | channel->cpb_size = maximum_cpb_size(channel->level); |
| @@ -2163,16 +2140,33 @@ static void allegro_stop_streaming(struct vb2_queue *q) · 94 unmodified lines | ||
| 2163 | 2140 | struct allegro_channel *channel = vb2_get_drv_priv(q); |
| 2164 | 2141 | struct allegro_dev *dev = channel->dev; |
| 2165 | 2142 | struct vb2_v4l2_buffer *buffer; |
| 2143 | + struct allegro_m2m_buffer *shadow, *tmp; | |
| 2166 | 2144 | |
| 2167 | 2145 | v4l2_dbg(2, debug, &dev->v4l2_dev, |
| 2168 | 2146 | "%s: stop streaming\n", |
| 2169 | 2147 | V4L2_TYPE_IS_OUTPUT(q->type) ? "output" : "capture"); |
| 2170 | 2148 | |
| 2171 | 2149 | if (V4L2_TYPE_IS_OUTPUT(q->type)) { |
| 2150 | + mutex_lock(&channel->shadow_list_lock); | |
| 2151 | + list_for_each_entry_safe(shadow, tmp, | |
| 2152 | + &channel->source_shadow_list, head) { | |
| 2153 | + list_del(&shadow->head); | |
| 2154 | + v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR); | |
| 2155 | + } | |
| 2156 | + mutex_unlock(&channel->shadow_list_lock); | |
| 2157 | + | |
| 2172 | 2158 | allegro_set_state(channel, ALLEGRO_STATE_STOPPED); |
| 2173 | 2159 | while ((buffer = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx))) |
| 2174 | 2160 | v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR); |
| 2175 | 2161 | } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
| 2162 | + mutex_lock(&channel->shadow_list_lock); | |
| 2163 | + list_for_each_entry_safe(shadow, tmp, | |
| 2164 | + &channel->stream_shadow_list, head) { | |
| 2165 | + list_del(&shadow->head); | |
| 2166 | + v4l2_m2m_buf_done(&shadow->buf.vb, VB2_BUF_STATE_ERROR); | |
| 2167 | + } | |
| 2168 | + mutex_unlock(&channel->shadow_list_lock); | |
| 2169 | + | |
| 2176 | 2170 | allegro_destroy_channel(channel); |
| 2177 | 2171 | while ((buffer = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx))) |
| 2178 | 2172 | v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_ERROR); |
| @@ -2203,7 +2197,7 @@ static int allegro_queue_init(void *priv, · 24 unmodified lines | ||
| 2203 | 2197 | src_vq->drv_priv = channel; |
| 2204 | 2198 | src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 2205 | 2199 | src_vq->ops = &allegro_queue_ops; |
| 2206 | − src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | |
| 2200 | + src_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer); | |
| 2207 | 2201 | src_vq->lock = &channel->dev->lock; |
| 2208 | 2202 | err = vb2_queue_init(src_vq); |
| 2209 | 2203 | if (err) |
| @@ -2216,7 +2210,7 @@ static int allegro_queue_init(void *priv, · 6 unmodified lines | ||
| 2216 | 2210 | dst_vq->drv_priv = channel; |
| 2217 | 2211 | dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; |
| 2218 | 2212 | dst_vq->ops = &allegro_queue_ops; |
| 2219 | − dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); | |
| 2213 | + dst_vq->buf_struct_size = sizeof(struct allegro_m2m_buffer); | |
| 2220 | 2214 | dst_vq->lock = &channel->dev->lock; |
| 2221 | 2215 | err = vb2_queue_init(dst_vq); |
| 2222 | 2216 | if (err) |
| @@ -2225,6 +2219,52 @@ static int allegro_queue_init(void *priv, · 2 unmodified lines | ||
| 2225 | 2219 | return 0; |
| 2226 | 2220 | } |
| 2227 | 2221 | |
| 2222 | +static int allegro_clamp_qp(struct allegro_channel *channel, | |
| 2223 | + struct v4l2_ctrl *ctrl) | |
| 2224 | +{ | |
| 2225 | + struct v4l2_ctrl *next_ctrl; | |
| 2226 | + | |
| 2227 | + if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP) | |
| 2228 | + next_ctrl = channel->mpeg_video_h264_p_frame_qp; | |
| 2229 | + else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP) | |
| 2230 | + next_ctrl = channel->mpeg_video_h264_b_frame_qp; | |
| 2231 | + else | |
| 2232 | + return 0; | |
| 2233 | + | |
| 2234 | + /* Modify range automatically updates the value */ | |
| 2235 | + __v4l2_ctrl_modify_range(next_ctrl, ctrl->val, 51, 1, ctrl->val); | |
| 2236 | + | |
| 2237 | + return allegro_clamp_qp(channel, next_ctrl); | |
| 2238 | +} | |
| 2239 | + | |
| 2240 | +static int allegro_clamp_bitrate(struct allegro_channel *channel, | |
| 2241 | + struct v4l2_ctrl *ctrl) | |
| 2242 | +{ | |
| 2243 | + struct v4l2_ctrl *ctrl_bitrate = channel->mpeg_video_bitrate; | |
| 2244 | + struct v4l2_ctrl *ctrl_bitrate_peak = channel->mpeg_video_bitrate_peak; | |
| 2245 | + | |
| 2246 | + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && | |
| 2247 | + ctrl_bitrate_peak->val < ctrl_bitrate->val) | |
| 2248 | + ctrl_bitrate_peak->val = ctrl_bitrate->val; | |
| 2249 | + | |
| 2250 | + return 0; | |
| 2251 | +} | |
| 2252 | + | |
| 2253 | +static int allegro_try_ctrl(struct v4l2_ctrl *ctrl) | |
| 2254 | +{ | |
| 2255 | + struct allegro_channel *channel = container_of(ctrl->handler, | |
| 2256 | + struct allegro_channel, | |
| 2257 | + ctrl_handler); | |
| 2258 | + | |
| 2259 | + switch (ctrl->id) { | |
| 2260 | + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | |
| 2261 | + allegro_clamp_bitrate(channel, ctrl); | |
| 2262 | + break; | |
| 2263 | + } | |
| 2264 | + | |
| 2265 | + return 0; | |
| 2266 | +} | |
| 2267 | + | |
| 2228 | 2268 | static int allegro_s_ctrl(struct v4l2_ctrl *ctrl) |
| 2229 | 2269 | { |
| 2230 | 2270 | struct allegro_channel *channel = container_of(ctrl->handler, |
| @@ -2239,14 +2279,14 @@ static int allegro_s_ctrl(struct v4l2_ctrl *ctrl) · 8 unmodified lines | ||
| 2239 | 2279 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: |
| 2240 | 2280 | channel->level = ctrl->val; |
| 2241 | 2281 | break; |
| 2242 | − case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | |
| 2243 | − channel->bitrate_mode = ctrl->val; | |
| 2244 | − break; | |
| 2245 | − case V4L2_CID_MPEG_VIDEO_BITRATE: | |
| 2246 | − channel->bitrate = ctrl->val; | |
| 2282 | + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: | |
| 2283 | + channel->frame_rc_enable = ctrl->val; | |
| 2247 | 2284 | break; |
| 2248 | − case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: | |
| 2249 | − channel->bitrate_peak = ctrl->val; | |
| 2285 | + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: | |
| 2286 | + channel->bitrate = channel->mpeg_video_bitrate->val; | |
| 2287 | + channel->bitrate_peak = channel->mpeg_video_bitrate_peak->val; | |
| 2288 | + v4l2_ctrl_activate(channel->mpeg_video_bitrate_peak, | |
| 2289 | + ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR); | |
| 2250 | 2290 | break; |
| 2251 | 2291 | case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: |
| 2252 | 2292 | channel->cpb_size = ctrl->val; |
| @@ -2254,12 +2294,18 @@ static int allegro_s_ctrl(struct v4l2_ctrl *ctrl) · 1 unmodified line | ||
| 2254 | 2294 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: |
| 2255 | 2295 | channel->gop_size = ctrl->val; |
| 2256 | 2296 | break; |
| 2297 | + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: | |
| 2298 | + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: | |
| 2299 | + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: | |
| 2300 | + allegro_clamp_qp(channel, ctrl); | |
| 2301 | + break; | |
| 2257 | 2302 | } |
| 2258 | 2303 | |
| 2259 | 2304 | return 0; |
| 2260 | 2305 | } |
| 2261 | 2306 | |
| 2262 | 2307 | static const struct v4l2_ctrl_ops allegro_ctrl_ops = { |
| 2308 | + .try_ctrl = allegro_try_ctrl, | |
| 2263 | 2309 | .s_ctrl = allegro_s_ctrl, |
| 2264 | 2310 | }; |
| 2265 | 2311 | |
| @@ -2270,16 +2316,18 @@ static int allegro_open(struct file *file) · 4 unmodified lines | ||
| 2270 | 2316 | struct allegro_channel *channel = NULL; |
| 2271 | 2317 | struct v4l2_ctrl_handler *handler; |
| 2272 | 2318 | u64 mask; |
| 2319 | + int ret; | |
| 2273 | 2320 | |
| 2274 | 2321 | channel = kzalloc(sizeof(*channel), GFP_KERNEL); |
| 2275 | 2322 | if (!channel) |
| 2276 | 2323 | return -ENOMEM; |
| 2277 | 2324 | |
| 2278 | 2325 | v4l2_fh_init(&channel->fh, vdev); |
| 2279 | − file->private_data = &channel->fh; | |
| 2280 | − v4l2_fh_add(&channel->fh); | |
| 2281 | 2326 | |
| 2282 | 2327 | init_completion(&channel->completion); |
| 2328 | + INIT_LIST_HEAD(&channel->source_shadow_list); | |
| 2329 | + INIT_LIST_HEAD(&channel->stream_shadow_list); | |
| 2330 | + mutex_init(&channel->shadow_list_lock); | |
| 2283 | 2331 | |
| 2284 | 2332 | channel->dev = dev; |
| 2285 | 2333 | |
| @@ -2298,11 +2346,42 @@ static int allegro_open(struct file *file) · 12 unmodified lines | ||
| 2298 | 2346 | V4L2_CID_MPEG_VIDEO_H264_LEVEL, |
| 2299 | 2347 | V4L2_MPEG_VIDEO_H264_LEVEL_5_1, mask, |
| 2300 | 2348 | V4L2_MPEG_VIDEO_H264_LEVEL_5_1); |
| 2349 | + channel->mpeg_video_h264_i_frame_qp = | |
| 2350 | + v4l2_ctrl_new_std(handler, | |
| 2351 | + &allegro_ctrl_ops, | |
| 2352 | + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, | |
| 2353 | + 0, 51, 1, 30); | |
| 2354 | + channel->mpeg_video_h264_max_qp = | |
| 2355 | + v4l2_ctrl_new_std(handler, | |
| 2356 | + &allegro_ctrl_ops, | |
| 2357 | + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, | |
| 2358 | + 0, 51, 1, 51); | |
| 2359 | + channel->mpeg_video_h264_min_qp = | |
| 2360 | + v4l2_ctrl_new_std(handler, | |
| 2361 | + &allegro_ctrl_ops, | |
| 2362 | + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, | |
| 2363 | + 0, 51, 1, 0); | |
| 2364 | + channel->mpeg_video_h264_p_frame_qp = | |
| 2365 | + v4l2_ctrl_new_std(handler, | |
| 2366 | + &allegro_ctrl_ops, | |
| 2367 | + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, | |
| 2368 | + 0, 51, 1, 30); | |
| 2369 | + channel->mpeg_video_h264_b_frame_qp = | |
| 2370 | + v4l2_ctrl_new_std(handler, | |
| 2371 | + &allegro_ctrl_ops, | |
| 2372 | + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, | |
| 2373 | + 0, 51, 1, 30); | |
| 2374 | + channel->mpeg_video_frame_rc_enable = | |
| 2375 | + v4l2_ctrl_new_std(handler, | |
| 2376 | + &allegro_ctrl_ops, | |
| 2377 | + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, | |
| 2378 | + false, 0x1, | |
| 2379 | + true, false); | |
| 2301 | 2380 | channel->mpeg_video_bitrate_mode = v4l2_ctrl_new_std_menu(handler, |
| 2302 | 2381 | &allegro_ctrl_ops, |
| 2303 | 2382 | V4L2_CID_MPEG_VIDEO_BITRATE_MODE, |
| 2304 | 2383 | V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, |
| 2305 | − channel->bitrate_mode); | |
| 2384 | + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); | |
| 2306 | 2385 | channel->mpeg_video_bitrate = v4l2_ctrl_new_std(handler, |
| 2307 | 2386 | &allegro_ctrl_ops, |
| 2308 | 2387 | V4L2_CID_MPEG_VIDEO_BITRATE, |
| @@ -2328,8 +2407,15 @@ static int allegro_open(struct file *file) · 19 unmodified lines | ||
| 2328 | 2407 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, |
| 2329 | 2408 | 1, 32, |
| 2330 | 2409 | 1, 1); |
| 2410 | + if (handler->error != 0) { | |
| 2411 | + ret = handler->error; | |
| 2412 | + goto error; | |
| 2413 | + } | |
| 2414 | + | |
| 2331 | 2415 | channel->fh.ctrl_handler = handler; |
| 2332 | 2416 | |
| 2417 | + v4l2_ctrl_cluster(3, &channel->mpeg_video_bitrate_mode); | |
| 2418 | + | |
| 2333 | 2419 | channel->mcu_channel_id = -1; |
| 2334 | 2420 | channel->user_id = -1; |
| 2335 | 2421 | |
| @@ -2341,7 +2427,20 @@ static int allegro_open(struct file *file) · 5 unmodified lines | ||
| 2341 | 2427 | channel->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, channel, |
| 2342 | 2428 | allegro_queue_init); |
| 2343 | 2429 | |
| 2430 | + if (IS_ERR(channel->fh.m2m_ctx)) { | |
| 2431 | + ret = PTR_ERR(channel->fh.m2m_ctx); | |
| 2432 | + goto error; | |
| 2433 | + } | |
| 2434 | + | |
| 2435 | + file->private_data = &channel->fh; | |
| 2436 | + v4l2_fh_add(&channel->fh); | |
| 2437 | + | |
| 2344 | 2438 | return 0; |
| 2439 | + | |
| 2440 | +error: | |
| 2441 | + v4l2_ctrl_handler_free(handler); | |
| 2442 | + kfree(channel); | |
| 2443 | + return ret; | |
| 2345 | 2444 | } |
| 2346 | 2445 | |
| 2347 | 2446 | static int allegro_release(struct file *file) |
| @@ -2636,6 +2735,46 @@ static int allegro_ioctl_streamon(struct file *file, void *priv, · 288 unmodified lines | ||
| 2636 | 2735 | return v4l2_m2m_streamon(file, fh->m2m_ctx, type); |
| 2637 | 2736 | } |
| 2638 | 2737 | |
| 2738 | +static int allegro_g_parm(struct file *file, void *fh, | |
| 2739 | + struct v4l2_streamparm *a) | |
| 2740 | +{ | |
| 2741 | + struct allegro_channel *channel = fh_to_channel(fh); | |
| 2742 | + struct v4l2_fract *timeperframe; | |
| 2743 | + | |
| 2744 | + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
| 2745 | + return -EINVAL; | |
| 2746 | + | |
| 2747 | + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | |
| 2748 | + timeperframe = &a->parm.output.timeperframe; | |
| 2749 | + timeperframe->numerator = channel->framerate.denominator; | |
| 2750 | + timeperframe->denominator = channel->framerate.numerator; | |
| 2751 | + | |
| 2752 | + return 0; | |
| 2753 | +} | |
| 2754 | + | |
| 2755 | +static int allegro_s_parm(struct file *file, void *fh, | |
| 2756 | + struct v4l2_streamparm *a) | |
| 2757 | +{ | |
| 2758 | + struct allegro_channel *channel = fh_to_channel(fh); | |
| 2759 | + struct v4l2_fract *timeperframe; | |
| 2760 | + int div; | |
| 2761 | + | |
| 2762 | + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
| 2763 | + return -EINVAL; | |
| 2764 | + | |
| 2765 | + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | |
| 2766 | + timeperframe = &a->parm.output.timeperframe; | |
| 2767 | + | |
| 2768 | + if (timeperframe->numerator == 0 || timeperframe->denominator == 0) | |
| 2769 | + return allegro_g_parm(file, fh, a); | |
| 2770 | + | |
| 2771 | + div = gcd(timeperframe->denominator, timeperframe->numerator); | |
| 2772 | + channel->framerate.numerator = timeperframe->denominator / div; | |
| 2773 | + channel->framerate.denominator = timeperframe->numerator / div; | |
| 2774 | + | |
| 2775 | + return 0; | |
| 2776 | +} | |
| 2777 | + | |
| 2639 | 2778 | static int allegro_subscribe_event(struct v4l2_fh *fh, |
| 2640 | 2779 | const struct v4l2_event_subscription *sub) |
| 2641 | 2780 | { |
| @@ -2674,6 +2813,9 @@ static const struct v4l2_ioctl_ops allegro_ioctl_ops = { · 32 unmodified lines | ||
| 2674 | 2813 | .vidioc_encoder_cmd = allegro_encoder_cmd, |
| 2675 | 2814 | .vidioc_enum_framesizes = allegro_enum_framesizes, |
| 2676 | 2815 | |
| 2816 | + .vidioc_g_parm = allegro_g_parm, | |
| 2817 | + .vidioc_s_parm = allegro_s_parm, | |
| 2818 | + | |
| 2677 | 2819 | .vidioc_subscribe_event = allegro_subscribe_event, |
| 2678 | 2820 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
| 2679 | 2821 | }; |
| @@ -2701,7 +2843,7 @@ static int allegro_register_device(struct allegro_dev *dev) · 21 unmodified lines | ||
| 2701 | 2843 | video_dev->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; |
| 2702 | 2844 | video_set_drvdata(video_dev, dev); |
| 2703 | 2845 | |
| 2704 | − return video_register_device(video_dev, VFL_TYPE_GRABBER, 0); | |
| 2846 | + return video_register_device(video_dev, VFL_TYPE_VIDEO, 0); | |
| 2705 | 2847 | } |
| 2706 | 2848 | |
| 2707 | 2849 | static void allegro_device_run(void *priv) |
| @@ -2714,18 +2856,26 @@ static void allegro_device_run(void *priv) · 6 unmodified lines | ||
| 2714 | 2856 | dma_addr_t src_uv; |
| 2715 | 2857 | dma_addr_t dst_addr; |
| 2716 | 2858 | unsigned long dst_size; |
| 2859 | + u64 src_handle; | |
| 2860 | + u64 dst_handle; | |
| 2717 | 2861 | |
| 2718 | − dst_buf = v4l2_m2m_next_dst_buf(channel->fh.m2m_ctx); | |
| 2862 | + dst_buf = v4l2_m2m_dst_buf_remove(channel->fh.m2m_ctx); | |
| 2719 | 2863 | dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); |
| 2720 | 2864 | dst_size = vb2_plane_size(&dst_buf->vb2_buf, 0); |
| 2721 | − allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size); | |
| 2865 | + dst_handle = allegro_put_buffer(channel, &channel->stream_shadow_list, | |
| 2866 | + dst_buf); | |
| 2867 | + allegro_mcu_send_put_stream_buffer(dev, channel, dst_addr, dst_size, | |
| 2868 | + dst_handle); | |
| 2722 | 2869 | |
| 2723 | − src_buf = v4l2_m2m_next_src_buf(channel->fh.m2m_ctx); | |
| 2870 | + src_buf = v4l2_m2m_src_buf_remove(channel->fh.m2m_ctx); | |
| 2724 | 2871 | src_buf->sequence = channel->osequence++; |
| 2725 | − | |
| 2726 | 2872 | src_y = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); |
| 2727 | 2873 | src_uv = src_y + (channel->stride * channel->height); |
| 2728 | − allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv); | |
| 2874 | + src_handle = allegro_put_buffer(channel, &channel->source_shadow_list, | |
| 2875 | + src_buf); | |
| 2876 | + allegro_mcu_send_encode_frame(dev, channel, src_y, src_uv, src_handle); | |
| 2877 | + | |
| 2878 | + v4l2_m2m_job_finish(dev->m2m_dev, channel->fh.m2m_ctx); | |
| 2729 | 2879 | } |
| 2730 | 2880 | |
| 2731 | 2881 | static const struct v4l2_m2m_ops allegro_m2m_ops = { |
| @@ -0,0 +1,37 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> | |
| 4 | + * | |
| 5 | + * Helper functions for handling messages that are send via mailbox to the | |
| 6 | + * Allegro VCU firmware. | |
| 7 | + */ | |
| 8 | + | |
| 9 | +#include <linux/export.h> | |
| 10 | + | |
| 11 | +#include "allegro-mail.h" | |
| 12 | + | |
| 13 | +const char *msg_type_name(enum mcu_msg_type type) | |
| 14 | +{ | |
| 15 | + static char buf[9]; | |
| 16 | + | |
| 17 | + switch (type) { | |
| 18 | + case MCU_MSG_TYPE_INIT: | |
| 19 | + return "INIT"; | |
| 20 | + case MCU_MSG_TYPE_CREATE_CHANNEL: | |
| 21 | + return "CREATE_CHANNEL"; | |
| 22 | + case MCU_MSG_TYPE_DESTROY_CHANNEL: | |
| 23 | + return "DESTROY_CHANNEL"; | |
| 24 | + case MCU_MSG_TYPE_ENCODE_FRAME: | |
| 25 | + return "ENCODE_FRAME"; | |
| 26 | + case MCU_MSG_TYPE_PUT_STREAM_BUFFER: | |
| 27 | + return "PUT_STREAM_BUFFER"; | |
| 28 | + case MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE: | |
| 29 | + return "PUSH_BUFFER_INTERMEDIATE"; | |
| 30 | + case MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE: | |
| 31 | + return "PUSH_BUFFER_REFERENCE"; | |
| 32 | + default: | |
| 33 | + snprintf(buf, sizeof(buf), "(0x%04x)", type); | |
| 34 | + return buf; | |
| 35 | + } | |
| 36 | +} | |
| 37 | +EXPORT_SYMBOL(msg_type_name); | |
| @@ -0,0 +1,267 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2019 Pengutronix, Michael Tretter <kernel@pengutronix.de> | |
| 4 | + * | |
| 5 | + * Allegro VCU firmware mailbox mail definitions | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#ifndef ALLEGRO_MAIL_H | |
| 9 | +#define ALLEGRO_MAIL_H | |
| 10 | + | |
| 11 | +#include <linux/kernel.h> | |
| 12 | + | |
| 13 | +enum mcu_msg_type { | |
| 14 | + MCU_MSG_TYPE_INIT = 0x0000, | |
| 15 | + MCU_MSG_TYPE_CREATE_CHANNEL = 0x0005, | |
| 16 | + MCU_MSG_TYPE_DESTROY_CHANNEL = 0x0006, | |
| 17 | + MCU_MSG_TYPE_ENCODE_FRAME = 0x0007, | |
| 18 | + MCU_MSG_TYPE_PUT_STREAM_BUFFER = 0x0012, | |
| 19 | + MCU_MSG_TYPE_PUSH_BUFFER_INTERMEDIATE = 0x000e, | |
| 20 | + MCU_MSG_TYPE_PUSH_BUFFER_REFERENCE = 0x000f, | |
| 21 | +}; | |
| 22 | + | |
| 23 | +const char *msg_type_name(enum mcu_msg_type type); | |
| 24 | + | |
| 25 | +struct mcu_msg_header { | |
| 26 | + u16 length; /* length of the body in bytes */ | |
| 27 | + u16 type; | |
| 28 | +} __attribute__ ((__packed__)); | |
| 29 | + | |
| 30 | +struct mcu_msg_init_request { | |
| 31 | + struct mcu_msg_header header; | |
| 32 | + u32 reserved0; /* maybe a unused channel id */ | |
| 33 | + u32 suballoc_dma; | |
| 34 | + u32 suballoc_size; | |
| 35 | + s32 l2_cache[3]; | |
| 36 | +} __attribute__ ((__packed__)); | |
| 37 | + | |
| 38 | +struct mcu_msg_init_response { | |
| 39 | + struct mcu_msg_header header; | |
| 40 | + u32 reserved0; | |
| 41 | +} __attribute__ ((__packed__)); | |
| 42 | + | |
| 43 | +struct create_channel_param { | |
| 44 | + u16 width; | |
| 45 | + u16 height; | |
| 46 | + u32 format; | |
| 47 | + u32 colorspace; | |
| 48 | + u32 src_mode; | |
| 49 | + u8 profile; | |
| 50 | + u16 constraint_set_flags; | |
| 51 | + s8 codec; | |
| 52 | + u16 level; | |
| 53 | + u16 tier; | |
| 54 | + u32 sps_param; | |
| 55 | + u32 pps_param; | |
| 56 | + | |
| 57 | + u32 enc_option; | |
| 58 | +#define AL_OPT_WPP BIT(0) | |
| 59 | +#define AL_OPT_TILE BIT(1) | |
| 60 | +#define AL_OPT_LF BIT(2) | |
| 61 | +#define AL_OPT_LF_X_SLICE BIT(3) | |
| 62 | +#define AL_OPT_LF_X_TILE BIT(4) | |
| 63 | +#define AL_OPT_SCL_LST BIT(5) | |
| 64 | +#define AL_OPT_CONST_INTRA_PRED BIT(6) | |
| 65 | +#define AL_OPT_QP_TAB_RELATIVE BIT(7) | |
| 66 | +#define AL_OPT_FIX_PREDICTOR BIT(8) | |
| 67 | +#define AL_OPT_CUSTOM_LDA BIT(9) | |
| 68 | +#define AL_OPT_ENABLE_AUTO_QP BIT(10) | |
| 69 | +#define AL_OPT_ADAPT_AUTO_QP BIT(11) | |
| 70 | +#define AL_OPT_TRANSFO_SKIP BIT(13) | |
| 71 | +#define AL_OPT_FORCE_REC BIT(15) | |
| 72 | +#define AL_OPT_FORCE_MV_OUT BIT(16) | |
| 73 | +#define AL_OPT_FORCE_MV_CLIP BIT(17) | |
| 74 | +#define AL_OPT_LOWLAT_SYNC BIT(18) | |
| 75 | +#define AL_OPT_LOWLAT_INT BIT(19) | |
| 76 | +#define AL_OPT_RDO_COST_MODE BIT(20) | |
| 77 | + | |
| 78 | + s8 beta_offset; | |
| 79 | + s8 tc_offset; | |
| 80 | + u16 reserved10; | |
| 81 | + u32 unknown11; | |
| 82 | + u32 unknown12; | |
| 83 | + u16 num_slices; | |
| 84 | + u16 prefetch_auto; | |
| 85 | + u32 prefetch_mem_offset; | |
| 86 | + u32 prefetch_mem_size; | |
| 87 | + u16 clip_hrz_range; | |
| 88 | + u16 clip_vrt_range; | |
| 89 | + u16 me_range[4]; | |
| 90 | + u8 max_cu_size; | |
| 91 | + u8 min_cu_size; | |
| 92 | + u8 max_tu_size; | |
| 93 | + u8 min_tu_size; | |
| 94 | + u8 max_transfo_depth_inter; | |
| 95 | + u8 max_transfo_depth_intra; | |
| 96 | + u16 reserved20; | |
| 97 | + u32 entropy_mode; | |
| 98 | + u32 wp_mode; | |
| 99 | + | |
| 100 | + /* rate control param */ | |
| 101 | + u32 rate_control_mode; | |
| 102 | + u32 initial_rem_delay; | |
| 103 | + u32 cpb_size; | |
| 104 | + u16 framerate; | |
| 105 | + u16 clk_ratio; | |
| 106 | + u32 target_bitrate; | |
| 107 | + u32 max_bitrate; | |
| 108 | + u16 initial_qp; | |
| 109 | + u16 min_qp; | |
| 110 | + u16 max_qp; | |
| 111 | + s16 ip_delta; | |
| 112 | + s16 pb_delta; | |
| 113 | + u16 golden_ref; | |
| 114 | + u16 golden_delta; | |
| 115 | + u16 golden_ref_frequency; | |
| 116 | + u32 rate_control_option; | |
| 117 | + | |
| 118 | + /* gop param */ | |
| 119 | + u32 gop_ctrl_mode; | |
| 120 | + u32 freq_idr; | |
| 121 | + u32 freq_lt; | |
| 122 | + u32 gdr_mode; | |
| 123 | + u16 gop_length; | |
| 124 | + u8 num_b; | |
| 125 | + u8 freq_golden_ref; | |
| 126 | + | |
| 127 | + u32 subframe_latency; | |
| 128 | + u32 lda_control_mode; | |
| 129 | + u32 unknown41; | |
| 130 | +} __attribute__ ((__packed__)); | |
| 131 | + | |
| 132 | +struct mcu_msg_create_channel { | |
| 133 | + struct mcu_msg_header header; | |
| 134 | + u32 user_id; | |
| 135 | + struct create_channel_param param; | |
| 136 | +} __attribute__ ((__packed__)); | |
| 137 | + | |
| 138 | +struct mcu_msg_create_channel_response { | |
| 139 | + struct mcu_msg_header header; | |
| 140 | + u32 channel_id; | |
| 141 | + u32 user_id; | |
| 142 | + u32 options; | |
| 143 | + u32 num_core; | |
| 144 | + u32 pps_param; | |
| 145 | + u32 int_buffers_count; | |
| 146 | + u32 int_buffers_size; | |
| 147 | + u32 rec_buffers_count; | |
| 148 | + u32 rec_buffers_size; | |
| 149 | + u32 reserved; | |
| 150 | + u32 error_code; | |
| 151 | +} __attribute__ ((__packed__)); | |
| 152 | + | |
| 153 | +struct mcu_msg_destroy_channel { | |
| 154 | + struct mcu_msg_header header; | |
| 155 | + u32 channel_id; | |
| 156 | +} __attribute__ ((__packed__)); | |
| 157 | + | |
| 158 | +struct mcu_msg_destroy_channel_response { | |
| 159 | + struct mcu_msg_header header; | |
| 160 | + u32 channel_id; | |
| 161 | +} __attribute__ ((__packed__)); | |
| 162 | + | |
| 163 | +struct mcu_msg_push_buffers_internal_buffer { | |
| 164 | + u32 dma_addr; | |
| 165 | + u32 mcu_addr; | |
| 166 | + u32 size; | |
| 167 | +} __attribute__ ((__packed__)); | |
| 168 | + | |
| 169 | +struct mcu_msg_push_buffers_internal { | |
| 170 | + struct mcu_msg_header header; | |
| 171 | + u32 channel_id; | |
| 172 | + struct mcu_msg_push_buffers_internal_buffer buffer[0]; | |
| 173 | +} __attribute__ ((__packed__)); | |
| 174 | + | |
| 175 | +struct mcu_msg_put_stream_buffer { | |
| 176 | + struct mcu_msg_header header; | |
| 177 | + u32 channel_id; | |
| 178 | + u32 dma_addr; | |
| 179 | + u32 mcu_addr; | |
| 180 | + u32 size; | |
| 181 | + u32 offset; | |
| 182 | + u64 stream_id; | |
| 183 | +} __attribute__ ((__packed__)); | |
| 184 | + | |
| 185 | +struct mcu_msg_encode_frame { | |
| 186 | + struct mcu_msg_header header; | |
| 187 | + u32 channel_id; | |
| 188 | + u32 reserved; | |
| 189 | + | |
| 190 | + u32 encoding_options; | |
| 191 | +#define AL_OPT_USE_QP_TABLE BIT(0) | |
| 192 | +#define AL_OPT_FORCE_LOAD BIT(1) | |
| 193 | +#define AL_OPT_USE_L2 BIT(2) | |
| 194 | +#define AL_OPT_DISABLE_INTRA BIT(3) | |
| 195 | +#define AL_OPT_DEPENDENT_SLICES BIT(4) | |
| 196 | + | |
| 197 | + s16 pps_qp; | |
| 198 | + u16 padding; | |
| 199 | + u64 user_param; | |
| 200 | + u64 src_handle; | |
| 201 | + | |
| 202 | + u32 request_options; | |
| 203 | +#define AL_OPT_SCENE_CHANGE BIT(0) | |
| 204 | +#define AL_OPT_RESTART_GOP BIT(1) | |
| 205 | +#define AL_OPT_USE_LONG_TERM BIT(2) | |
| 206 | +#define AL_OPT_UPDATE_PARAMS BIT(3) | |
| 207 | + | |
| 208 | + /* u32 scene_change_delay (optional) */ | |
| 209 | + /* rate control param (optional) */ | |
| 210 | + /* gop param (optional) */ | |
| 211 | + u32 src_y; | |
| 212 | + u32 src_uv; | |
| 213 | + u32 stride; | |
| 214 | + u32 ep2; | |
| 215 | + u64 ep2_v; | |
| 216 | +} __attribute__ ((__packed__)); | |
| 217 | + | |
| 218 | +struct mcu_msg_encode_frame_response { | |
| 219 | + struct mcu_msg_header header; | |
| 220 | + u32 channel_id; | |
| 221 | + u64 stream_id; /* see mcu_msg_put_stream_buffer */ | |
| 222 | + u64 user_param; /* see mcu_msg_encode_frame */ | |
| 223 | + u64 src_handle; /* see mcu_msg_encode_frame */ | |
| 224 | + u16 skip; | |
| 225 | + u16 is_ref; | |
| 226 | + u32 initial_removal_delay; | |
| 227 | + u32 dpb_output_delay; | |
| 228 | + u32 size; | |
| 229 | + u32 frame_tag_size; | |
| 230 | + s32 stuffing; | |
| 231 | + s32 filler; | |
| 232 | + u16 num_column; | |
| 233 | + u16 num_row; | |
| 234 | + u16 qp; | |
| 235 | + u8 num_ref_idx_l0; | |
| 236 | + u8 num_ref_idx_l1; | |
| 237 | + u32 partition_table_offset; | |
| 238 | + s32 partition_table_size; | |
| 239 | + u32 sum_complex; | |
| 240 | + s32 tile_width[4]; | |
| 241 | + s32 tile_height[22]; | |
| 242 | + u32 error_code; | |
| 243 | + | |
| 244 | + u32 slice_type; | |
| 245 | +#define AL_ENC_SLICE_TYPE_B 0 | |
| 246 | +#define AL_ENC_SLICE_TYPE_P 1 | |
| 247 | +#define AL_ENC_SLICE_TYPE_I 2 | |
| 248 | + | |
| 249 | + u32 pic_struct; | |
| 250 | + u8 is_idr; | |
| 251 | + u8 is_first_slice; | |
| 252 | + u8 is_last_slice; | |
| 253 | + u8 reserved; | |
| 254 | + u16 pps_qp; | |
| 255 | + u16 reserved1; | |
| 256 | + u32 reserved2; | |
| 257 | +} __attribute__ ((__packed__)); | |
| 258 | + | |
| 259 | +union mcu_msg_response { | |
| 260 | + struct mcu_msg_header header; | |
| 261 | + struct mcu_msg_init_response init; | |
| 262 | + struct mcu_msg_create_channel_response create_channel; | |
| 263 | + struct mcu_msg_destroy_channel_response destroy_channel; | |
| 264 | + struct mcu_msg_encode_frame_response encode_frame; | |
| 265 | +}; | |
| 266 | + | |
| 267 | +#endif | |
| @@ -1,19 +1,27 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | 2 | config VIDEO_HANTRO |
| 3 | 3 | tristate "Hantro VPU driver" |
| 4 | − depends on ARCH_ROCKCHIP || COMPILE_TEST | |
| 4 | + depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST | |
| 5 | 5 | depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER |
| 6 | 6 | depends on MEDIA_CONTROLLER_REQUEST_API |
| 7 | 7 | select VIDEOBUF2_DMA_CONTIG |
| 8 | 8 | select VIDEOBUF2_VMALLOC |
| 9 | 9 | select V4L2_MEM2MEM_DEV |
| 10 | 10 | help |
| 11 | − Support for the Hantro IP based Video Processing Unit present on | |
| 12 | − Rockchip SoC, which accelerates video and image encoding and | |
| 13 | − decoding. | |
| 11 | + Support for the Hantro IP based Video Processing Units present on | |
| 12 | + Rockchip and NXP i.MX8M SoCs, which accelerate video and image | |
| 13 | + encoding and decoding. | |
| 14 | 14 | To compile this driver as a module, choose M here: the module |
| 15 | 15 | will be called hantro-vpu. |
| 16 | 16 | |
| 17 | +config VIDEO_HANTRO_IMX8M | |
| 18 | + bool "Hantro VPU i.MX8M support" | |
| 19 | + depends on VIDEO_HANTRO | |
| 20 | + depends on ARCH_MXC || COMPILE_TEST | |
| 21 | + default y | |
| 22 | + help | |
| 23 | + Enable support for i.MX8M SoCs. | |
| 24 | + | |
| 17 | 25 | config VIDEO_HANTRO_ROCKCHIP |
| 18 | 26 | bool "Hantro VPU Rockchip support" |
| 19 | 27 | depends on VIDEO_HANTRO |
| @@ -16,6 +16,9 @@ hantro-vpu-y += \ · 15 unmodified lines | ||
| 16 | 16 | hantro_mpeg2.o \ |
| 17 | 17 | hantro_vp8.o |
| 18 | 18 | |
| 19 | +hantro-vpu-$(CONFIG_VIDEO_HANTRO_IMX8M) += \ | |
| 20 | + imx8m_vpu_hw.o | |
| 21 | + | |
| 19 | 22 | hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ |
| 20 | 23 | rk3288_vpu_hw.o \ |
| 21 | 24 | rk3399_vpu_hw.o |
| @@ -423,7 +423,7 @@ hantro_get_dst_buf(struct hantro_ctx *ctx) · 422 unmodified lines | ||
| 423 | 423 | static inline bool |
| 424 | 424 | hantro_needs_postproc(struct hantro_ctx *ctx, const struct hantro_fmt *fmt) |
| 425 | 425 | { |
| 426 | − return fmt->fourcc != V4L2_PIX_FMT_NV12; | |
| 426 | + return !hantro_is_encoder_ctx(ctx) && fmt->fourcc != V4L2_PIX_FMT_NV12; | |
| 427 | 427 | } |
| 428 | 428 | |
| 429 | 429 | static inline dma_addr_t |
| @@ -361,6 +361,16 @@ static const struct hantro_ctrl controls[] = { · 360 unmodified lines | ||
| 361 | 361 | .def = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, |
| 362 | 362 | .max = V4L2_MPEG_VIDEO_H264_START_CODE_ANNEX_B, |
| 363 | 363 | }, |
| 364 | + }, { | |
| 365 | + .codec = HANTRO_H264_DECODER, | |
| 366 | + .cfg = { | |
| 367 | + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, | |
| 368 | + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, | |
| 369 | + .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, | |
| 370 | + .menu_skip_mask = | |
| 371 | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED), | |
| 372 | + .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, | |
| 373 | + } | |
| 364 | 374 | }, { |
| 365 | 375 | }, |
| 366 | 376 | }; |
| @@ -488,6 +498,9 @@ static const struct of_device_id of_hantro_match[] = { · 121 unmodified lines | ||
| 488 | 498 | { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, |
| 489 | 499 | { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, |
| 490 | 500 | { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, |
| 501 | +#endif | |
| 502 | +#ifdef CONFIG_VIDEO_HANTRO_IMX8M | |
| 503 | + { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, | |
| 491 | 504 | #endif |
| 492 | 505 | { /* sentinel */ } |
| 493 | 506 | }; |
| @@ -664,7 +677,7 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) · 170 unmodified lines | ||
| 664 | 677 | |
| 665 | 678 | video_set_drvdata(vfd, vpu); |
| 666 | 679 | |
| 667 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 680 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 668 | 681 | if (ret) { |
| 669 | 682 | v4l2_err(&vpu->v4l2_dev, "Failed to register video device\n"); |
| 670 | 683 | return ret; |
| @@ -67,12 +67,23 @@ hantro_h1_jpeg_enc_set_qtable(struct hantro_dev *vpu, · 66 unmodified lines | ||
| 67 | 67 | unsigned char *chroma_qtable) |
| 68 | 68 | { |
| 69 | 69 | u32 reg, i; |
| 70 | + __be32 *luma_qtable_p; | |
| 71 | + __be32 *chroma_qtable_p; | |
| 70 | 72 | |
| 73 | + luma_qtable_p = (__be32 *)luma_qtable; | |
| 74 | + chroma_qtable_p = (__be32 *)chroma_qtable; | |
| 75 | + | |
| 76 | + /* | |
| 77 | + * Quantization table registers must be written in contiguous blocks. | |
| 78 | + * DO NOT collapse the below two "for" loops into one. | |
| 79 | + */ | |
| 71 | 80 | for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) { |
| 72 | − reg = get_unaligned_be32(&luma_qtable[i]); | |
| 81 | + reg = get_unaligned_be32(&luma_qtable_p[i]); | |
| 73 | 82 | vepu_write_relaxed(vpu, reg, H1_REG_JPEG_LUMA_QUAT(i)); |
| 83 | + } | |
| 74 | 84 | |
| 75 | − reg = get_unaligned_be32(&chroma_qtable[i]); | |
| 85 | + for (i = 0; i < H1_JPEG_QUANT_TABLE_COUNT; i++) { | |
| 86 | + reg = get_unaligned_be32(&chroma_qtable_p[i]); | |
| 76 | 87 | vepu_write_relaxed(vpu, reg, H1_REG_JPEG_CHROMA_QUAT(i)); |
| 77 | 88 | } |
| 78 | 89 | } |
| @@ -103,8 +114,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) · 24 unmodified lines | ||
| 103 | 114 | hantro_h1_set_src_img_ctrl(vpu, ctx); |
| 104 | 115 | hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); |
| 105 | 116 | hantro_h1_jpeg_enc_set_qtable(vpu, |
| 106 | − hantro_jpeg_get_qtable(&jpeg_ctx, 0), | |
| 107 | − hantro_jpeg_get_qtable(&jpeg_ctx, 1)); | |
| 117 | + hantro_jpeg_get_qtable(0), | |
| 118 | + hantro_jpeg_get_qtable(1)); | |
| 108 | 119 | |
| 109 | 120 | reg = H1_REG_AXI_CTRL_OUTPUT_SWAP16 |
| 110 | 121 | | H1_REG_AXI_CTRL_INPUT_SWAP16 |
| @@ -151,6 +151,7 @@ enum hantro_enc_fmt { · 150 unmodified lines | ||
| 151 | 151 | extern const struct hantro_variant rk3399_vpu_variant; |
| 152 | 152 | extern const struct hantro_variant rk3328_vpu_variant; |
| 153 | 153 | extern const struct hantro_variant rk3288_vpu_variant; |
| 154 | +extern const struct hantro_variant imx8mq_vpu_variant; | |
| 154 | 155 | |
| 155 | 156 | extern const struct hantro_postproc_regs hantro_g1_postproc_regs; |
| 156 | 157 | |
| @@ -23,19 +23,21 @@ · 22 unmodified lines | ||
| 23 | 23 | #define HUFF_CHROMA_AC_OFF 409 |
| 24 | 24 | |
| 25 | 25 | /* Default tables from JPEG ITU-T.81 |
| 26 | − * (ISO/IEC 10918-1) Annex K.3, I | |
| 26 | + * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2 | |
| 27 | 27 | */ |
| 28 | 28 | static const unsigned char luma_q_table[] = { |
| 29 | − 0x10, 0x0b, 0x0a, 0x10, 0x7c, 0x8c, 0x97, 0xa1, | |
| 30 | − 0x0c, 0x0c, 0x0e, 0x13, 0x7e, 0x9e, 0xa0, 0x9b, | |
| 31 | − 0x0e, 0x0d, 0x10, 0x18, 0x8c, 0x9d, 0xa9, 0x9c, | |
| 32 | − 0x0e, 0x11, 0x16, 0x1d, 0x97, 0xbb, 0xb4, 0xa2, | |
| 33 | − 0x12, 0x16, 0x25, 0x38, 0xa8, 0x6d, 0x67, 0xb1, | |
| 34 | − 0x18, 0x23, 0x37, 0x40, 0xb5, 0x68, 0x71, 0xc0, | |
| 29 | + 0x10, 0x0b, 0x0a, 0x10, 0x18, 0x28, 0x33, 0x3d, | |
| 30 | + 0x0c, 0x0c, 0x0e, 0x13, 0x1a, 0x3a, 0x3c, 0x37, | |
| 31 | + 0x0e, 0x0d, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38, | |
| 32 | + 0x0e, 0x11, 0x16, 0x1d, 0x33, 0x57, 0x50, 0x3e, | |
| 33 | + 0x12, 0x16, 0x25, 0x38, 0x44, 0x6d, 0x67, 0x4d, | |
| 34 | + 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5c, | |
| 35 | 35 | 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65, |
| 36 | − 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0xc7, | |
| 36 | + 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0x63 | |
| 37 | 37 | }; |
| 38 | 38 | |
| 39 | +static unsigned char luma_q_table_reordered[ARRAY_SIZE(luma_q_table)]; | |
| 40 | + | |
| 39 | 41 | static const unsigned char chroma_q_table[] = { |
| 40 | 42 | 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63, |
| 41 | 43 | 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63, |
| @@ -47,6 +49,30 @@ static const unsigned char chroma_q_table[] = { · 5 unmodified lines | ||
| 47 | 49 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 |
| 48 | 50 | }; |
| 49 | 51 | |
| 52 | +static unsigned char chroma_q_table_reordered[ARRAY_SIZE(chroma_q_table)]; | |
| 53 | + | |
| 54 | +static const unsigned char zigzag[64] = { | |
| 55 | + 0, 1, 8, 16, 9, 2, 3, 10, | |
| 56 | + 17, 24, 32, 25, 18, 11, 4, 5, | |
| 57 | + 12, 19, 26, 33, 40, 48, 41, 34, | |
| 58 | + 27, 20, 13, 6, 7, 14, 21, 28, | |
| 59 | + 35, 42, 49, 56, 57, 50, 43, 36, | |
| 60 | + 29, 22, 15, 23, 30, 37, 44, 51, | |
| 61 | + 58, 59, 52, 45, 38, 31, 39, 46, | |
| 62 | + 53, 60, 61, 54, 47, 55, 62, 63 | |
| 63 | +}; | |
| 64 | + | |
| 65 | +static const u32 hw_reorder[64] = { | |
| 66 | + 0, 8, 16, 24, 1, 9, 17, 25, | |
| 67 | + 32, 40, 48, 56, 33, 41, 49, 57, | |
| 68 | + 2, 10, 18, 26, 3, 11, 19, 27, | |
| 69 | + 34, 42, 50, 58, 35, 43, 51, 59, | |
| 70 | + 4, 12, 20, 28, 5, 13, 21, 29, | |
| 71 | + 36, 44, 52, 60, 37, 45, 53, 61, | |
| 72 | + 6, 14, 22, 30, 7, 15, 23, 31, | |
| 73 | + 38, 46, 54, 62, 39, 47, 55, 63 | |
| 74 | +}; | |
| 75 | + | |
| 50 | 76 | /* Huffman tables are shared with CODA */ |
| 51 | 77 | static const unsigned char luma_dc_table[] = { |
| 52 | 78 | 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, |
| @@ -225,20 +251,29 @@ static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { · 172 unmodified lines | ||
| 225 | 251 | 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, |
| 226 | 252 | }; |
| 227 | 253 | |
| 254 | +static unsigned char jpeg_scale_qp(const unsigned char qp, int scale) | |
| 255 | +{ | |
| 256 | + unsigned int temp; | |
| 257 | + | |
| 258 | + temp = DIV_ROUND_CLOSEST((unsigned int)qp * scale, 100); | |
| 259 | + if (temp <= 0) | |
| 260 | + temp = 1; | |
| 261 | + if (temp > 255) | |
| 262 | + temp = 255; | |
| 263 | + | |
| 264 | + return (unsigned char)temp; | |
| 265 | +} | |
| 266 | + | |
| 228 | 267 | static void |
| 229 | −jpeg_scale_quant_table(unsigned char *q_tab, | |
| 268 | +jpeg_scale_quant_table(unsigned char *file_q_tab, | |
| 269 | + unsigned char *reordered_q_tab, | |
| 230 | 270 | const unsigned char *tab, int scale) |
| 231 | 271 | { |
| 232 | − unsigned int temp; | |
| 233 | 272 | int i; |
| 234 | 273 | |
| 235 | 274 | for (i = 0; i < 64; i++) { |
| 236 | − temp = DIV_ROUND_CLOSEST((unsigned int)tab[i] * scale, 100); | |
| 237 | − if (temp <= 0) | |
| 238 | − temp = 1; | |
| 239 | − if (temp > 255) | |
| 240 | − temp = 255; | |
| 241 | − q_tab[i] = (unsigned char)temp; | |
| 275 | + file_q_tab[i] = jpeg_scale_qp(tab[zigzag[i]], scale); | |
| 276 | + reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale); | |
| 242 | 277 | } |
| 243 | 278 | } |
| 244 | 279 | |
| @@ -256,17 +291,18 @@ static void jpeg_set_quality(unsigned char *buffer, int quality) · 11 unmodified lines | ||
| 256 | 291 | scale = 200 - 2 * quality; |
| 257 | 292 | |
| 258 | 293 | jpeg_scale_quant_table(buffer + LUMA_QUANT_OFF, |
| 294 | + luma_q_table_reordered, | |
| 259 | 295 | luma_q_table, scale); |
| 260 | 296 | jpeg_scale_quant_table(buffer + CHROMA_QUANT_OFF, |
| 297 | + chroma_q_table_reordered, | |
| 261 | 298 | chroma_q_table, scale); |
| 262 | 299 | } |
| 263 | 300 | |
| 264 | −unsigned char * | |
| 265 | −hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index) | |
| 301 | +unsigned char *hantro_jpeg_get_qtable(int index) | |
| 266 | 302 | { |
| 267 | 303 | if (index == 0) |
| 268 | − return ctx->buffer + LUMA_QUANT_OFF; | |
| 269 | − return ctx->buffer + CHROMA_QUANT_OFF; | |
| 304 | + return luma_q_table_reordered; | |
| 305 | + return chroma_q_table_reordered; | |
| 270 | 306 | } |
| 271 | 307 | |
| 272 | 308 | void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx) |
| @@ -9,5 +9,5 @@ struct hantro_jpeg_ctx { · 8 unmodified lines | ||
| 9 | 9 | unsigned char *buffer; |
| 10 | 10 | }; |
| 11 | 11 | |
| 12 | −unsigned char *hantro_jpeg_get_qtable(struct hantro_jpeg_ctx *ctx, int index); | |
| 12 | +unsigned char *hantro_jpeg_get_qtable(int index); | |
| 13 | 13 | void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx); |
| @@ -295,7 +295,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, · 294 unmodified lines | ||
| 295 | 295 | * +---------------------------+ |
| 296 | 296 | */ |
| 297 | 297 | if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE && |
| 298 | − !hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) | |
| 298 | + !hantro_needs_postproc(ctx, fmt)) | |
| 299 | 299 | pix_mp->plane_fmt[0].sizeimage += |
| 300 | 300 | 64 * MB_WIDTH(pix_mp->width) * |
| 301 | 301 | MB_WIDTH(pix_mp->height) + 32; |
| @@ -0,0 +1,220 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Hantro VPU codec driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2019 Pengutronix, Philipp Zabel <kernel@pengutronix.de> | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/clk.h> | |
| 9 | +#include <linux/delay.h> | |
| 10 | + | |
| 11 | +#include "hantro.h" | |
| 12 | +#include "hantro_jpeg.h" | |
| 13 | +#include "hantro_g1_regs.h" | |
| 14 | + | |
| 15 | +#define CTRL_SOFT_RESET 0x00 | |
| 16 | +#define RESET_G1 BIT(1) | |
| 17 | +#define RESET_G2 BIT(0) | |
| 18 | + | |
| 19 | +#define CTRL_CLOCK_ENABLE 0x04 | |
| 20 | +#define CLOCK_G1 BIT(1) | |
| 21 | +#define CLOCK_G2 BIT(0) | |
| 22 | + | |
| 23 | +#define CTRL_G1_DEC_FUSE 0x08 | |
| 24 | +#define CTRL_G1_PP_FUSE 0x0c | |
| 25 | +#define CTRL_G2_DEC_FUSE 0x10 | |
| 26 | + | |
| 27 | +static void imx8m_soft_reset(struct hantro_dev *vpu, u32 reset_bits) | |
| 28 | +{ | |
| 29 | + u32 val; | |
| 30 | + | |
| 31 | + /* Assert */ | |
| 32 | + val = readl(vpu->ctrl_base + CTRL_SOFT_RESET); | |
| 33 | + val &= ~reset_bits; | |
| 34 | + writel(val, vpu->ctrl_base + CTRL_SOFT_RESET); | |
| 35 | + | |
| 36 | + udelay(2); | |
| 37 | + | |
| 38 | + /* Release */ | |
| 39 | + val = readl(vpu->ctrl_base + CTRL_SOFT_RESET); | |
| 40 | + val |= reset_bits; | |
| 41 | + writel(val, vpu->ctrl_base + CTRL_SOFT_RESET); | |
| 42 | +} | |
| 43 | + | |
| 44 | +static void imx8m_clk_enable(struct hantro_dev *vpu, u32 clock_bits) | |
| 45 | +{ | |
| 46 | + u32 val; | |
| 47 | + | |
| 48 | + val = readl(vpu->ctrl_base + CTRL_CLOCK_ENABLE); | |
| 49 | + val |= clock_bits; | |
| 50 | + writel(val, vpu->ctrl_base + CTRL_CLOCK_ENABLE); | |
| 51 | +} | |
| 52 | + | |
| 53 | +static int imx8mq_runtime_resume(struct hantro_dev *vpu) | |
| 54 | +{ | |
| 55 | + int ret; | |
| 56 | + | |
| 57 | + ret = clk_bulk_prepare_enable(vpu->variant->num_clocks, vpu->clocks); | |
| 58 | + if (ret) { | |
| 59 | + dev_err(vpu->dev, "Failed to enable clocks\n"); | |
| 60 | + return ret; | |
| 61 | + } | |
| 62 | + | |
| 63 | + imx8m_soft_reset(vpu, RESET_G1 | RESET_G2); | |
| 64 | + imx8m_clk_enable(vpu, CLOCK_G1 | CLOCK_G2); | |
| 65 | + | |
| 66 | + /* Set values of the fuse registers */ | |
| 67 | + writel(0xffffffff, vpu->ctrl_base + CTRL_G1_DEC_FUSE); | |
| 68 | + writel(0xffffffff, vpu->ctrl_base + CTRL_G1_PP_FUSE); | |
| 69 | + writel(0xffffffff, vpu->ctrl_base + CTRL_G2_DEC_FUSE); | |
| 70 | + | |
| 71 | + clk_bulk_disable_unprepare(vpu->variant->num_clocks, vpu->clocks); | |
| 72 | + | |
| 73 | + return 0; | |
| 74 | +} | |
| 75 | + | |
| 76 | +/* | |
| 77 | + * Supported formats. | |
| 78 | + */ | |
| 79 | + | |
| 80 | +static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = { | |
| 81 | + { | |
| 82 | + .fourcc = V4L2_PIX_FMT_YUYV, | |
| 83 | + .codec_mode = HANTRO_MODE_NONE, | |
| 84 | + }, | |
| 85 | +}; | |
| 86 | + | |
| 87 | +static const struct hantro_fmt imx8m_vpu_dec_fmts[] = { | |
| 88 | + { | |
| 89 | + .fourcc = V4L2_PIX_FMT_NV12, | |
| 90 | + .codec_mode = HANTRO_MODE_NONE, | |
| 91 | + }, | |
| 92 | + { | |
| 93 | + .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, | |
| 94 | + .codec_mode = HANTRO_MODE_MPEG2_DEC, | |
| 95 | + .max_depth = 2, | |
| 96 | + .frmsize = { | |
| 97 | + .min_width = 48, | |
| 98 | + .max_width = 1920, | |
| 99 | + .step_width = MB_DIM, | |
| 100 | + .min_height = 48, | |
| 101 | + .max_height = 1088, | |
| 102 | + .step_height = MB_DIM, | |
| 103 | + }, | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + .fourcc = V4L2_PIX_FMT_VP8_FRAME, | |
| 107 | + .codec_mode = HANTRO_MODE_VP8_DEC, | |
| 108 | + .max_depth = 2, | |
| 109 | + .frmsize = { | |
| 110 | + .min_width = 48, | |
| 111 | + .max_width = 3840, | |
| 112 | + .step_width = 16, | |
| 113 | + .min_height = 48, | |
| 114 | + .max_height = 2160, | |
| 115 | + .step_height = 16, | |
| 116 | + }, | |
| 117 | + }, | |
| 118 | + { | |
| 119 | + .fourcc = V4L2_PIX_FMT_H264_SLICE, | |
| 120 | + .codec_mode = HANTRO_MODE_H264_DEC, | |
| 121 | + .max_depth = 2, | |
| 122 | + .frmsize = { | |
| 123 | + .min_width = 48, | |
| 124 | + .max_width = 3840, | |
| 125 | + .step_width = MB_DIM, | |
| 126 | + .min_height = 48, | |
| 127 | + .max_height = 2160, | |
| 128 | + .step_height = MB_DIM, | |
| 129 | + }, | |
| 130 | + }, | |
| 131 | +}; | |
| 132 | + | |
| 133 | +static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) | |
| 134 | +{ | |
| 135 | + struct hantro_dev *vpu = dev_id; | |
| 136 | + enum vb2_buffer_state state; | |
| 137 | + u32 status; | |
| 138 | + | |
| 139 | + status = vdpu_read(vpu, G1_REG_INTERRUPT); | |
| 140 | + state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? | |
| 141 | + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; | |
| 142 | + | |
| 143 | + vdpu_write(vpu, 0, G1_REG_INTERRUPT); | |
| 144 | + vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); | |
| 145 | + | |
| 146 | + hantro_irq_done(vpu, 0, state); | |
| 147 | + | |
| 148 | + return IRQ_HANDLED; | |
| 149 | +} | |
| 150 | + | |
| 151 | +static int imx8mq_vpu_hw_init(struct hantro_dev *vpu) | |
| 152 | +{ | |
| 153 | + vpu->dec_base = vpu->reg_bases[0]; | |
| 154 | + vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1]; | |
| 155 | + | |
| 156 | + return 0; | |
| 157 | +} | |
| 158 | + | |
| 159 | +static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx) | |
| 160 | +{ | |
| 161 | + struct hantro_dev *vpu = ctx->dev; | |
| 162 | + | |
| 163 | + imx8m_soft_reset(vpu, RESET_G1); | |
| 164 | +} | |
| 165 | + | |
| 166 | +/* | |
| 167 | + * Supported codec ops. | |
| 168 | + */ | |
| 169 | + | |
| 170 | +static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = { | |
| 171 | + [HANTRO_MODE_MPEG2_DEC] = { | |
| 172 | + .run = hantro_g1_mpeg2_dec_run, | |
| 173 | + .reset = imx8m_vpu_g1_reset, | |
| 174 | + .init = hantro_mpeg2_dec_init, | |
| 175 | + .exit = hantro_mpeg2_dec_exit, | |
| 176 | + }, | |
| 177 | + [HANTRO_MODE_VP8_DEC] = { | |
| 178 | + .run = hantro_g1_vp8_dec_run, | |
| 179 | + .reset = imx8m_vpu_g1_reset, | |
| 180 | + .init = hantro_vp8_dec_init, | |
| 181 | + .exit = hantro_vp8_dec_exit, | |
| 182 | + }, | |
| 183 | + [HANTRO_MODE_H264_DEC] = { | |
| 184 | + .run = hantro_g1_h264_dec_run, | |
| 185 | + .reset = imx8m_vpu_g1_reset, | |
| 186 | + .init = hantro_h264_dec_init, | |
| 187 | + .exit = hantro_h264_dec_exit, | |
| 188 | + }, | |
| 189 | +}; | |
| 190 | + | |
| 191 | +/* | |
| 192 | + * VPU variants. | |
| 193 | + */ | |
| 194 | + | |
| 195 | +static const struct hantro_irq imx8mq_irqs[] = { | |
| 196 | + { "g1", imx8m_vpu_g1_irq }, | |
| 197 | + { "g2", NULL /* TODO: imx8m_vpu_g2_irq */ }, | |
| 198 | +}; | |
| 199 | + | |
| 200 | +static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" }; | |
| 201 | +static const char * const imx8mq_reg_names[] = { "g1", "g2", "ctrl" }; | |
| 202 | + | |
| 203 | +const struct hantro_variant imx8mq_vpu_variant = { | |
| 204 | + .dec_fmts = imx8m_vpu_dec_fmts, | |
| 205 | + .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), | |
| 206 | + .postproc_fmts = imx8m_vpu_postproc_fmts, | |
| 207 | + .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts), | |
| 208 | + .postproc_regs = &hantro_g1_postproc_regs, | |
| 209 | + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | | |
| 210 | + HANTRO_H264_DECODER, | |
| 211 | + .codec_ops = imx8mq_vpu_codec_ops, | |
| 212 | + .init = imx8mq_vpu_hw_init, | |
| 213 | + .runtime_resume = imx8mq_runtime_resume, | |
| 214 | + .irqs = imx8mq_irqs, | |
| 215 | + .num_irqs = ARRAY_SIZE(imx8mq_irqs), | |
| 216 | + .clk_names = imx8mq_clk_names, | |
| 217 | + .num_clocks = ARRAY_SIZE(imx8mq_clk_names), | |
| 218 | + .reg_names = imx8mq_reg_names, | |
| 219 | + .num_regs = ARRAY_SIZE(imx8mq_reg_names) | |
| 220 | +}; | |
| @@ -18,9 +18,8 @@ · 17 unmodified lines | ||
| 18 | 18 | * |
| 19 | 19 | * Quantization luma table values are written to registers |
| 20 | 20 | * VEPU_swreg_0-VEPU_swreg_15, and chroma table values to |
| 21 | − * VEPU_swreg_16-VEPU_swreg_31. | |
| 22 | − * | |
| 23 | − * JPEG zigzag order is expected on the quantization tables. | |
| 21 | + * VEPU_swreg_16-VEPU_swreg_31. A special order is needed, neither | |
| 22 | + * zigzag, nor linear. | |
| 24 | 23 | */ |
| 25 | 24 | |
| 26 | 25 | #include <asm/unaligned.h> |
| @@ -98,12 +97,23 @@ rk3399_vpu_jpeg_enc_set_qtable(struct hantro_dev *vpu, · 71 unmodified lines | ||
| 98 | 97 | unsigned char *chroma_qtable) |
| 99 | 98 | { |
| 100 | 99 | u32 reg, i; |
| 100 | + __be32 *luma_qtable_p; | |
| 101 | + __be32 *chroma_qtable_p; | |
| 102 | + | |
| 103 | + luma_qtable_p = (__be32 *)luma_qtable; | |
| 104 | + chroma_qtable_p = (__be32 *)chroma_qtable; | |
| 101 | 105 | |
| 106 | + /* | |
| 107 | + * Quantization table registers must be written in contiguous blocks. | |
| 108 | + * DO NOT collapse the below two "for" loops into one. | |
| 109 | + */ | |
| 102 | 110 | for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { |
| 103 | − reg = get_unaligned_be32(&luma_qtable[i]); | |
| 111 | + reg = get_unaligned_be32(&luma_qtable_p[i]); | |
| 104 | 112 | vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_LUMA_QUAT(i)); |
| 113 | + } | |
| 105 | 114 | |
| 106 | − reg = get_unaligned_be32(&chroma_qtable[i]); | |
| 115 | + for (i = 0; i < VEPU_JPEG_QUANT_TABLE_COUNT; i++) { | |
| 116 | + reg = get_unaligned_be32(&chroma_qtable_p[i]); | |
| 107 | 117 | vepu_write_relaxed(vpu, reg, VEPU_REG_JPEG_CHROMA_QUAT(i)); |
| 108 | 118 | } |
| 109 | 119 | } |
| @@ -134,8 +144,8 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) · 24 unmodified lines | ||
| 134 | 144 | rk3399_vpu_set_src_img_ctrl(vpu, ctx); |
| 135 | 145 | rk3399_vpu_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); |
| 136 | 146 | rk3399_vpu_jpeg_enc_set_qtable(vpu, |
| 137 | − hantro_jpeg_get_qtable(&jpeg_ctx, 0), | |
| 138 | − hantro_jpeg_get_qtable(&jpeg_ctx, 1)); | |
| 147 | + hantro_jpeg_get_qtable(0), | |
| 148 | + hantro_jpeg_get_qtable(1)); | |
| 139 | 149 | |
| 140 | 150 | reg = VEPU_REG_OUTPUT_SWAP32 |
| 141 | 151 | | VEPU_REG_OUTPUT_SWAP16 |
| @@ -643,7 +643,7 @@ static int capture_open(struct file *file) · 642 unmodified lines | ||
| 643 | 643 | if (ret) |
| 644 | 644 | v4l2_err(priv->src_sd, "v4l2_fh_open failed\n"); |
| 645 | 645 | |
| 646 | − ret = v4l2_pipeline_pm_use(&vfd->entity, 1); | |
| 646 | + ret = v4l2_pipeline_pm_get(&vfd->entity); | |
| 647 | 647 | if (ret) |
| 648 | 648 | v4l2_fh_release(file); |
| 649 | 649 | |
| @@ -664,7 +664,7 @@ static int capture_release(struct file *file) · 14 unmodified lines | ||
| 664 | 664 | vq->owner = NULL; |
| 665 | 665 | } |
| 666 | 666 | |
| 667 | − v4l2_pipeline_pm_use(&vfd->entity, 0); | |
| 667 | + v4l2_pipeline_pm_put(&vfd->entity); | |
| 668 | 668 | |
| 669 | 669 | v4l2_fh_release(file); |
| 670 | 670 | mutex_unlock(&priv->mutex); |
| @@ -742,7 +742,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev) · 71 unmodified lines | ||
| 742 | 742 | |
| 743 | 743 | vfd->v4l2_dev = v4l2_dev; |
| 744 | 744 | |
| 745 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 745 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 746 | 746 | if (ret) { |
| 747 | 747 | v4l2_err(sd, "Failed to register video device\n"); |
| 748 | 748 | return ret; |
| @@ -778,7 +778,7 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev) · 29 unmodified lines | ||
| 778 | 778 | /* setup default format */ |
| 779 | 779 | fmt_src.pad = priv->src_sd_pad; |
| 780 | 780 | fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE; |
| 781 | − v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt_src); | |
| 781 | + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt_src); | |
| 782 | 782 | if (ret) { |
| 783 | 783 | v4l2_err(sd, "failed to get src_sd format\n"); |
| 784 | 784 | goto unreg; |
| @@ -849,7 +849,7 @@ int imx_media_csc_scaler_device_register(struct imx_media_video_dev *vdev) · 848 unmodified lines | ||
| 849 | 849 | |
| 850 | 850 | vfd->v4l2_dev = &priv->md->v4l2_dev; |
| 851 | 851 | |
| 852 | − ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); | |
| 852 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); | |
| 853 | 853 | if (ret) { |
| 854 | 854 | v4l2_err(vfd->v4l2_dev, "Failed to register video device\n"); |
| 855 | 855 | return ret; |
| @@ -457,7 +457,8 @@ static int csi_idmac_setup_channel(struct csi_priv *priv) · 456 unmodified lines | ||
| 457 | 457 | case V4L2_PIX_FMT_SGBRG16: |
| 458 | 458 | case V4L2_PIX_FMT_SGRBG16: |
| 459 | 459 | case V4L2_PIX_FMT_SRGGB16: |
| 460 | − case V4L2_PIX_FMT_Y16: | |
| 460 | + case V4L2_PIX_FMT_Y10: | |
| 461 | + case V4L2_PIX_FMT_Y12: | |
| 461 | 462 | burst_size = 8; |
| 462 | 463 | passthrough_bits = 16; |
| 463 | 464 | break; |
| @@ -1459,6 +1460,8 @@ static void csi_try_fmt(struct csi_priv *priv, · 995 unmodified lines | ||
| 1459 | 1460 | /* propagate colorimetry from sink */ |
| 1460 | 1461 | sdformat->format.colorspace = infmt->colorspace; |
| 1461 | 1462 | sdformat->format.xfer_func = infmt->xfer_func; |
| 1463 | + sdformat->format.quantization = infmt->quantization; | |
| 1464 | + sdformat->format.ycbcr_enc = infmt->ycbcr_enc; | |
| 1462 | 1465 | |
| 1463 | 1466 | break; |
| 1464 | 1467 | case CSI_SINK_PAD: |
| @@ -161,17 +161,24 @@ static const struct imx_media_pixfmt rgb_formats[] = { · 160 unmodified lines | ||
| 161 | 161 | .bayer = true, |
| 162 | 162 | }, { |
| 163 | 163 | .fourcc = V4L2_PIX_FMT_GREY, |
| 164 | − .codes = {MEDIA_BUS_FMT_Y8_1X8}, | |
| 165 | − .cs = IPUV3_COLORSPACE_RGB, | |
| 166 | − .bpp = 8, | |
| 167 | − .bayer = true, | |
| 168 | − }, { | |
| 169 | − .fourcc = V4L2_PIX_FMT_Y16, | |
| 170 | 164 | .codes = { |
| 165 | + MEDIA_BUS_FMT_Y8_1X8, | |
| 171 | 166 | MEDIA_BUS_FMT_Y10_1X10, |
| 172 | 167 | MEDIA_BUS_FMT_Y12_1X12, |
| 173 | 168 | }, |
| 174 | 169 | .cs = IPUV3_COLORSPACE_RGB, |
| 170 | + .bpp = 8, | |
| 171 | + .bayer = true, | |
| 172 | + }, { | |
| 173 | + .fourcc = V4L2_PIX_FMT_Y10, | |
| 174 | + .codes = {MEDIA_BUS_FMT_Y10_1X10}, | |
| 175 | + .cs = IPUV3_COLORSPACE_RGB, | |
| 176 | + .bpp = 16, | |
| 177 | + .bayer = true, | |
| 178 | + }, { | |
| 179 | + .fourcc = V4L2_PIX_FMT_Y12, | |
| 180 | + .codes = {MEDIA_BUS_FMT_Y12_1X12}, | |
| 181 | + .cs = IPUV3_COLORSPACE_RGB, | |
| 175 | 182 | .bpp = 16, |
| 176 | 183 | .bayer = true, |
| 177 | 184 | }, |
| @@ -292,7 +292,7 @@ static void imx7_csi_hw_disable(struct imx7_csi *csi) · 291 unmodified lines | ||
| 292 | 292 | |
| 293 | 293 | static void imx7_csi_dma_reflash(struct imx7_csi *csi) |
| 294 | 294 | { |
| 295 | − u32 cr3 = imx7_csi_reg_read(csi, CSI_CSICR18); | |
| 295 | + u32 cr3; | |
| 296 | 296 | |
| 297 | 297 | cr3 = imx7_csi_reg_read(csi, CSI_CSICR3); |
| 298 | 298 | cr3 |= BIT_DMA_REFLASH_RFF; |
| @@ -804,6 +804,22 @@ static int imx7_csi_configure(struct imx7_csi *csi) · 505 unmodified lines | ||
| 804 | 804 | case V4L2_PIX_FMT_YUYV: |
| 805 | 805 | cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B; |
| 806 | 806 | break; |
| 807 | + case V4L2_PIX_FMT_GREY: | |
| 808 | + if (in_code == MEDIA_BUS_FMT_Y8_1X8) | |
| 809 | + cr18 |= BIT_MIPI_DATA_FORMAT_RAW8; | |
| 810 | + else if (in_code == MEDIA_BUS_FMT_Y10_1X10) | |
| 811 | + cr18 |= BIT_MIPI_DATA_FORMAT_RAW10; | |
| 812 | + else | |
| 813 | + cr18 |= BIT_MIPI_DATA_FORMAT_RAW12; | |
| 814 | + break; | |
| 815 | + case V4L2_PIX_FMT_Y10: | |
| 816 | + cr18 |= BIT_MIPI_DATA_FORMAT_RAW10; | |
| 817 | + cr1 |= BIT_PIXEL_BIT; | |
| 818 | + break; | |
| 819 | + case V4L2_PIX_FMT_Y12: | |
| 820 | + cr18 |= BIT_MIPI_DATA_FORMAT_RAW12; | |
| 821 | + cr1 |= BIT_PIXEL_BIT; | |
| 822 | + break; | |
| 807 | 823 | case V4L2_PIX_FMT_SBGGR8: |
| 808 | 824 | cr18 |= BIT_MIPI_DATA_FORMAT_RAW8; |
| 809 | 825 | break; |
| @@ -1009,10 +1025,13 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, · 199 unmodified lines | ||
| 1009 | 1025 | sdformat->format.width = in_fmt->width; |
| 1010 | 1026 | sdformat->format.height = in_fmt->height; |
| 1011 | 1027 | sdformat->format.code = in_fmt->code; |
| 1028 | + sdformat->format.field = in_fmt->field; | |
| 1012 | 1029 | *cc = in_cc; |
| 1013 | 1030 | |
| 1014 | 1031 | sdformat->format.colorspace = in_fmt->colorspace; |
| 1015 | 1032 | sdformat->format.xfer_func = in_fmt->xfer_func; |
| 1033 | + sdformat->format.quantization = in_fmt->quantization; | |
| 1034 | + sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc; | |
| 1016 | 1035 | break; |
| 1017 | 1036 | case IMX7_CSI_PAD_SINK: |
| 1018 | 1037 | *cc = imx_media_find_mbus_format(sdformat->format.code, |
| @@ -1023,6 +1042,9 @@ static int imx7_csi_try_fmt(struct imx7_csi *csi, · 4 unmodified lines | ||
| 1023 | 1042 | false); |
| 1024 | 1043 | sdformat->format.code = (*cc)->codes[0]; |
| 1025 | 1044 | } |
| 1045 | + | |
| 1046 | + if (sdformat->format.field != V4L2_FIELD_INTERLACED) | |
| 1047 | + sdformat->format.field = V4L2_FIELD_NONE; | |
| 1026 | 1048 | break; |
| 1027 | 1049 | default: |
| 1028 | 1050 | return -EINVAL; |
| @@ -280,6 +280,18 @@ static const struct csis_pix_format mipi_csis_formats[] = { · 279 unmodified lines | ||
| 280 | 280 | .code = MEDIA_BUS_FMT_YUYV8_2X8, |
| 281 | 281 | .fmt_reg = MIPI_CSIS_ISPCFG_FMT_YCBCR422_8BIT, |
| 282 | 282 | .data_alignment = 16, |
| 283 | + }, { | |
| 284 | + .code = MEDIA_BUS_FMT_Y8_1X8, | |
| 285 | + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW8, | |
| 286 | + .data_alignment = 8, | |
| 287 | + }, { | |
| 288 | + .code = MEDIA_BUS_FMT_Y10_1X10, | |
| 289 | + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW10, | |
| 290 | + .data_alignment = 16, | |
| 291 | + }, { | |
| 292 | + .code = MEDIA_BUS_FMT_Y12_1X12, | |
| 293 | + .fmt_reg = MIPI_CSIS_ISPCFG_FMT_RAW12, | |
| 294 | + .data_alignment = 16, | |
| 283 | 295 | } |
| 284 | 296 | }; |
| 285 | 297 | |
| @@ -301,6 +313,7 @@ static int mipi_csis_dump_regs(struct csi_state *state) · 15 unmodified lines | ||
| 301 | 313 | { 0x20, "DPHYSTS" }, |
| 302 | 314 | { 0x10, "INTMSK" }, |
| 303 | 315 | { 0x40, "CONFIG_CH0" }, |
| 316 | + { 0x44, "RESOL_CH0" }, | |
| 304 | 317 | { 0xC0, "DBG_CONFIG" }, |
| 305 | 318 | { 0x38, "DPHYSLAVE_L" }, |
| 306 | 319 | { 0x3C, "DPHYSLAVE_H" }, |
| @@ -417,6 +430,7 @@ static void mipi_csis_set_params(struct csi_state *state) · 110 unmodified lines | ||
| 417 | 430 | val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); |
| 418 | 431 | val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; |
| 419 | 432 | val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; |
| 433 | + val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; | |
| 420 | 434 | mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); |
| 421 | 435 | |
| 422 | 436 | __mipi_csis_set_format(state); |
| @@ -577,7 +591,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable) · 154 unmodified lines | ||
| 577 | 591 | state->flags |= ST_STREAMING; |
| 578 | 592 | } else { |
| 579 | 593 | v4l2_subdev_call(state->src_sd, video, s_stream, 0); |
| 580 | − ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); | |
| 594 | + ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); | |
| 581 | 595 | mipi_csis_stop_stream(state); |
| 582 | 596 | state->flags &= ~ST_STREAMING; |
| 583 | 597 | if (state->debug) |
| @@ -13,8 +13,6 @@ staging directory. · 12 unmodified lines | ||
| 13 | 13 | - Elaborate the functionality of different selection rectangles in driver |
| 14 | 14 | documentation. This may require driver changes as well. |
| 15 | 15 | |
| 16 | −- More detailed documentation on calculating BDS, GCD etc. sizes needed. | |
| 17 | − | |
| 18 | 16 | - Document different operation modes, and which buffer queues are relevant |
| 19 | 17 | in each mode. To process an image, which queues require a buffer an in |
| 20 | 18 | which ones is it optional? |
| @@ -210,12 +210,12 @@ static int imgu_hw_wait(void __iomem *base, int reg, u32 mask, u32 cmp) · 209 unmodified lines | ||
| 210 | 210 | |
| 211 | 211 | /* Initialize the IPU3 CSS hardware and associated h/w blocks */ |
| 212 | 212 | |
| 213 | −int imgu_css_set_powerup(struct device *dev, void __iomem *base) | |
| 213 | +int imgu_css_set_powerup(struct device *dev, void __iomem *base, | |
| 214 | + unsigned int freq) | |
| 214 | 215 | { |
| 215 | − static const unsigned int freq = 450; | |
| 216 | 216 | u32 pm_ctrl, state, val; |
| 217 | 217 | |
| 218 | − dev_dbg(dev, "%s\n", __func__); | |
| 218 | + dev_dbg(dev, "%s with freq %u\n", __func__, freq); | |
| 219 | 219 | /* Clear the CSS busy signal */ |
| 220 | 220 | readl(base + IMGU_REG_GP_BUSY); |
| 221 | 221 | writel(0, base + IMGU_REG_GP_BUSY); |
| @@ -187,7 +187,8 @@ bool imgu_css_is_streaming(struct imgu_css *css); · 186 unmodified lines | ||
| 187 | 187 | bool imgu_css_pipe_queue_empty(struct imgu_css *css, unsigned int pipe); |
| 188 | 188 | |
| 189 | 189 | /******************* css hw *******************/ |
| 190 | −int imgu_css_set_powerup(struct device *dev, void __iomem *base); | |
| 190 | +int imgu_css_set_powerup(struct device *dev, void __iomem *base, | |
| 191 | + unsigned int freq); | |
| 191 | 192 | void imgu_css_set_powerdown(struct device *dev, void __iomem *base); |
| 192 | 193 | int imgu_css_irq_ack(struct imgu_css *css); |
| 193 | 194 | |
| @@ -130,7 +130,7 @@ static u32 *imgu_mmu_alloc_page_table(u32 pteval) · 129 unmodified lines | ||
| 130 | 130 | for (pte = 0; pte < IPU3_PT_PTES; pte++) |
| 131 | 131 | pt[pte] = pteval; |
| 132 | 132 | |
| 133 | − set_memory_uc((unsigned long int)pt, IPU3_PT_ORDER); | |
| 133 | + set_memory_uc((unsigned long)pt, IPU3_PT_ORDER); | |
| 134 | 134 | |
| 135 | 135 | return pt; |
| 136 | 136 | } |
| @@ -141,7 +141,7 @@ static u32 *imgu_mmu_alloc_page_table(u32 pteval) · 4 unmodified lines | ||
| 141 | 141 | */ |
| 142 | 142 | static void imgu_mmu_free_page_table(u32 *pt) |
| 143 | 143 | { |
| 144 | − set_memory_wb((unsigned long int)pt, IPU3_PT_ORDER); | |
| 144 | + set_memory_wb((unsigned long)pt, IPU3_PT_ORDER); | |
| 145 | 145 | free_page((unsigned long)pt); |
| 146 | 146 | } |
| 147 | 147 | |
| @@ -1245,7 +1245,7 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe, · 1244 unmodified lines | ||
| 1245 | 1245 | vdev->queue = &node->vbq; |
| 1246 | 1246 | vdev->vfl_dir = node->output ? VFL_DIR_TX : VFL_DIR_RX; |
| 1247 | 1247 | video_set_drvdata(vdev, imgu); |
| 1248 | − r = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | |
| 1248 | + r = video_register_device(vdev, VFL_TYPE_VIDEO, -1); | |
| 1249 | 1249 | if (r) { |
| 1250 | 1250 | dev_err(dev, "failed to register video device (%d)", r); |
| 1251 | 1251 | media_entity_cleanup(&vdev->entity); |
| @@ -345,8 +345,20 @@ failed: · 344 unmodified lines | ||
| 345 | 345 | static int imgu_powerup(struct imgu_device *imgu) |
| 346 | 346 | { |
| 347 | 347 | int r; |
| 348 | + unsigned int pipe; | |
| 349 | + unsigned int freq = 200; | |
| 350 | + struct v4l2_mbus_framefmt *fmt; | |
| 351 | + | |
| 352 | + /* input larger than 2048*1152, ask imgu to work on high freq */ | |
| 353 | + for_each_set_bit(pipe, imgu->css.enabled_pipes, IMGU_MAX_PIPE_NUM) { | |
| 354 | + fmt = &imgu->imgu_pipe[pipe].nodes[IMGU_NODE_IN].pad_fmt; | |
| 355 | + dev_dbg(&imgu->pci_dev->dev, "pipe %u input format = %ux%u", | |
| 356 | + pipe, fmt->width, fmt->height); | |
| 357 | + if ((fmt->width * fmt->height) >= (2048 * 1152)) | |
| 358 | + freq = 450; | |
| 359 | + } | |
| 348 | 360 | |
| 349 | − r = imgu_css_set_powerup(&imgu->pci_dev->dev, imgu->base); | |
| 361 | + r = imgu_css_set_powerup(&imgu->pci_dev->dev, imgu->base, freq); | |
| 350 | 362 | if (r) |
| 351 | 363 | return r; |
| 352 | 364 | |
| @@ -666,7 +678,7 @@ static int imgu_pci_probe(struct pci_dev *pci_dev, · 313 unmodified lines | ||
| 666 | 678 | atomic_set(&imgu->qbuf_barrier, 0); |
| 667 | 679 | init_waitqueue_head(&imgu->buf_drain_wq); |
| 668 | 680 | |
| 669 | − r = imgu_css_set_powerup(&pci_dev->dev, imgu->base); | |
| 681 | + r = imgu_css_set_powerup(&pci_dev->dev, imgu->base, 200); | |
| 670 | 682 | if (r) { |
| 671 | 683 | dev_err(&pci_dev->dev, |
| 672 | 684 | "failed to power up CSS (%d)\n", r); |
| @@ -2,7 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | # Makefile for Amlogic meson video decoder driver |
| 3 | 3 | |
| 4 | 4 | meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o |
| 5 | −meson-vdec-objs += vdec_1.o | |
| 6 | −meson-vdec-objs += codec_mpeg12.o | |
| 5 | +meson-vdec-objs += vdec_1.o vdec_hevc.o | |
| 6 | +meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o codec_vp9.o | |
| 7 | 7 | |
| 8 | 8 | obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o |
| @@ -0,0 +1,485 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2019 BayLibre, SAS | |
| 4 | + * Author: Maxime Jourdan <mjourdan@baylibre.com> | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#include <media/v4l2-mem2mem.h> | |
| 8 | +#include <media/videobuf2-dma-contig.h> | |
| 9 | + | |
| 10 | +#include "vdec_helpers.h" | |
| 11 | +#include "dos_regs.h" | |
| 12 | +#include "codec_h264.h" | |
| 13 | + | |
| 14 | +#define SIZE_EXT_FW (20 * SZ_1K) | |
| 15 | +#define SIZE_WORKSPACE 0x1ee000 | |
| 16 | +#define SIZE_SEI (8 * SZ_1K) | |
| 17 | + | |
| 18 | +/* | |
| 19 | + * Offset added by the firmware which must be substracted | |
| 20 | + * from the workspace phyaddr | |
| 21 | + */ | |
| 22 | +#define WORKSPACE_BUF_OFFSET 0x1000000 | |
| 23 | + | |
| 24 | +/* ISR status */ | |
| 25 | +#define CMD_MASK GENMASK(7, 0) | |
| 26 | +#define CMD_SRC_CHANGE 1 | |
| 27 | +#define CMD_FRAMES_READY 2 | |
| 28 | +#define CMD_FATAL_ERROR 6 | |
| 29 | +#define CMD_BAD_WIDTH 7 | |
| 30 | +#define CMD_BAD_HEIGHT 8 | |
| 31 | + | |
| 32 | +#define SEI_DATA_READY BIT(15) | |
| 33 | + | |
| 34 | +/* Picture type */ | |
| 35 | +#define PIC_TOP_BOT 5 | |
| 36 | +#define PIC_BOT_TOP 6 | |
| 37 | + | |
| 38 | +/* Size of Motion Vector per macroblock */ | |
| 39 | +#define MB_MV_SIZE 96 | |
| 40 | + | |
| 41 | +/* Frame status data */ | |
| 42 | +#define PIC_STRUCT_BIT 5 | |
| 43 | +#define PIC_STRUCT_MASK GENMASK(2, 0) | |
| 44 | +#define BUF_IDX_MASK GENMASK(4, 0) | |
| 45 | +#define ERROR_FLAG BIT(9) | |
| 46 | +#define OFFSET_BIT 16 | |
| 47 | +#define OFFSET_MASK GENMASK(15, 0) | |
| 48 | + | |
| 49 | +/* Bitstream parsed data */ | |
| 50 | +#define MB_TOTAL_BIT 8 | |
| 51 | +#define MB_TOTAL_MASK GENMASK(15, 0) | |
| 52 | +#define MB_WIDTH_MASK GENMASK(7, 0) | |
| 53 | +#define MAX_REF_BIT 24 | |
| 54 | +#define MAX_REF_MASK GENMASK(6, 0) | |
| 55 | +#define AR_IDC_BIT 16 | |
| 56 | +#define AR_IDC_MASK GENMASK(7, 0) | |
| 57 | +#define AR_PRESENT_FLAG BIT(0) | |
| 58 | +#define AR_EXTEND 0xff | |
| 59 | + | |
| 60 | +/* | |
| 61 | + * Buffer to send to the ESPARSER to signal End Of Stream for H.264. | |
| 62 | + * This is a 16x16 encoded picture that will trigger drain firmware-side. | |
| 63 | + * There is no known alternative. | |
| 64 | + */ | |
| 65 | +static const u8 eos_sequence[SZ_4K] = { | |
| 66 | + 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd, | |
| 67 | + 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, | |
| 68 | + 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, | |
| 69 | + 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37, | |
| 70 | + 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, | |
| 71 | + 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, | |
| 72 | + 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, | |
| 73 | + 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, | |
| 74 | + 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, | |
| 75 | + 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, | |
| 76 | + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, | |
| 77 | + 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, | |
| 78 | + 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65, | |
| 79 | + 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, | |
| 80 | + 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, | |
| 81 | + 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, | |
| 82 | + 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, | |
| 83 | + 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, | |
| 84 | + 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, | |
| 85 | + 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, | |
| 86 | + 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, | |
| 87 | + 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, | |
| 88 | + 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, | |
| 89 | + 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, | |
| 90 | + 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68, | |
| 91 | + 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, | |
| 92 | + 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, | |
| 93 | + 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, | |
| 94 | + 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66, | |
| 95 | + 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, | |
| 96 | + 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, | |
| 97 | + 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, | |
| 98 | + 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, | |
| 99 | + 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69, | |
| 100 | + 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74, | |
| 101 | + 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f, | |
| 102 | + 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, | |
| 103 | + 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35, | |
| 104 | + 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, | |
| 105 | + 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30, | |
| 106 | + 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, | |
| 107 | + 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20, | |
| 108 | + 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4, | |
| 109 | + 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01, | |
| 110 | + 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6, | |
| 111 | + 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4, | |
| 112 | + 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7, | |
| 113 | + 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09, | |
| 114 | + 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66, | |
| 115 | + 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b, | |
| 116 | + 0x00, 0x00, 0x01, 0x0ff, | |
| 117 | +}; | |
| 118 | + | |
| 119 | +static const u8 *codec_h264_eos_sequence(u32 *len) | |
| 120 | +{ | |
| 121 | + *len = ARRAY_SIZE(eos_sequence); | |
| 122 | + return eos_sequence; | |
| 123 | +} | |
| 124 | + | |
| 125 | +struct codec_h264 { | |
| 126 | + /* H.264 decoder requires an extended firmware */ | |
| 127 | + void *ext_fw_vaddr; | |
| 128 | + dma_addr_t ext_fw_paddr; | |
| 129 | + | |
| 130 | + /* Buffer for the H.264 Workspace */ | |
| 131 | + void *workspace_vaddr; | |
| 132 | + dma_addr_t workspace_paddr; | |
| 133 | + | |
| 134 | + /* Buffer for the H.264 references MV */ | |
| 135 | + void *ref_vaddr; | |
| 136 | + dma_addr_t ref_paddr; | |
| 137 | + u32 ref_size; | |
| 138 | + | |
| 139 | + /* Buffer for parsed SEI data */ | |
| 140 | + void *sei_vaddr; | |
| 141 | + dma_addr_t sei_paddr; | |
| 142 | + | |
| 143 | + u32 mb_width; | |
| 144 | + u32 mb_height; | |
| 145 | + u32 max_refs; | |
| 146 | +}; | |
| 147 | + | |
| 148 | +static int codec_h264_can_recycle(struct amvdec_core *core) | |
| 149 | +{ | |
| 150 | + return !amvdec_read_dos(core, AV_SCRATCH_7) || | |
| 151 | + !amvdec_read_dos(core, AV_SCRATCH_8); | |
| 152 | +} | |
| 153 | + | |
| 154 | +static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx) | |
| 155 | +{ | |
| 156 | + /* | |
| 157 | + * Tell the firmware it can recycle this buffer. | |
| 158 | + * AV_SCRATCH_8 serves the same purpose. | |
| 159 | + */ | |
| 160 | + if (!amvdec_read_dos(core, AV_SCRATCH_7)) | |
| 161 | + amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1); | |
| 162 | + else | |
| 163 | + amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1); | |
| 164 | +} | |
| 165 | + | |
| 166 | +static int codec_h264_start(struct amvdec_session *sess) | |
| 167 | +{ | |
| 168 | + u32 workspace_offset; | |
| 169 | + struct amvdec_core *core = sess->core; | |
| 170 | + struct codec_h264 *h264 = sess->priv; | |
| 171 | + | |
| 172 | + /* Allocate some memory for the H.264 decoder's state */ | |
| 173 | + h264->workspace_vaddr = | |
| 174 | + dma_alloc_coherent(core->dev, SIZE_WORKSPACE, | |
| 175 | + &h264->workspace_paddr, GFP_KERNEL); | |
| 176 | + if (!h264->workspace_vaddr) | |
| 177 | + return -ENOMEM; | |
| 178 | + | |
| 179 | + /* Allocate some memory for the H.264 SEI dump */ | |
| 180 | + h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI, | |
| 181 | + &h264->sei_paddr, GFP_KERNEL); | |
| 182 | + if (!h264->sei_vaddr) | |
| 183 | + return -ENOMEM; | |
| 184 | + | |
| 185 | + amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6)); | |
| 186 | + | |
| 187 | + workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET; | |
| 188 | + amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset); | |
| 189 | + amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr); | |
| 190 | + amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - | |
| 191 | + workspace_offset); | |
| 192 | + | |
| 193 | + /* Enable "error correction" */ | |
| 194 | + amvdec_write_dos(core, AV_SCRATCH_F, | |
| 195 | + (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | | |
| 196 | + BIT(4) | BIT(7)); | |
| 197 | + | |
| 198 | + amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); | |
| 199 | + | |
| 200 | + return 0; | |
| 201 | +} | |
| 202 | + | |
| 203 | +static int codec_h264_stop(struct amvdec_session *sess) | |
| 204 | +{ | |
| 205 | + struct codec_h264 *h264 = sess->priv; | |
| 206 | + struct amvdec_core *core = sess->core; | |
| 207 | + | |
| 208 | + if (h264->ext_fw_vaddr) | |
| 209 | + dma_free_coherent(core->dev, SIZE_EXT_FW, | |
| 210 | + h264->ext_fw_vaddr, h264->ext_fw_paddr); | |
| 211 | + | |
| 212 | + if (h264->workspace_vaddr) | |
| 213 | + dma_free_coherent(core->dev, SIZE_WORKSPACE, | |
| 214 | + h264->workspace_vaddr, h264->workspace_paddr); | |
| 215 | + | |
| 216 | + if (h264->ref_vaddr) | |
| 217 | + dma_free_coherent(core->dev, h264->ref_size, | |
| 218 | + h264->ref_vaddr, h264->ref_paddr); | |
| 219 | + | |
| 220 | + if (h264->sei_vaddr) | |
| 221 | + dma_free_coherent(core->dev, SIZE_SEI, | |
| 222 | + h264->sei_vaddr, h264->sei_paddr); | |
| 223 | + | |
| 224 | + return 0; | |
| 225 | +} | |
| 226 | + | |
| 227 | +static int codec_h264_load_extended_firmware(struct amvdec_session *sess, | |
| 228 | + const u8 *data, u32 len) | |
| 229 | +{ | |
| 230 | + struct codec_h264 *h264; | |
| 231 | + struct amvdec_core *core = sess->core; | |
| 232 | + | |
| 233 | + if (len < SIZE_EXT_FW) | |
| 234 | + return -EINVAL; | |
| 235 | + | |
| 236 | + h264 = kzalloc(sizeof(*h264), GFP_KERNEL); | |
| 237 | + if (!h264) | |
| 238 | + return -ENOMEM; | |
| 239 | + | |
| 240 | + h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW, | |
| 241 | + &h264->ext_fw_paddr, | |
| 242 | + GFP_KERNEL); | |
| 243 | + if (!h264->ext_fw_vaddr) { | |
| 244 | + kfree(h264); | |
| 245 | + return -ENOMEM; | |
| 246 | + } | |
| 247 | + | |
| 248 | + memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW); | |
| 249 | + sess->priv = h264; | |
| 250 | + | |
| 251 | + return 0; | |
| 252 | +} | |
| 253 | + | |
| 254 | +static const struct v4l2_fract par_table[] = { | |
| 255 | + { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 }, | |
| 256 | + { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 }, | |
| 257 | + { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 }, | |
| 258 | + { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, | |
| 259 | + { 2, 1 } | |
| 260 | +}; | |
| 261 | + | |
| 262 | +static void codec_h264_set_par(struct amvdec_session *sess) | |
| 263 | +{ | |
| 264 | + struct amvdec_core *core = sess->core; | |
| 265 | + u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2); | |
| 266 | + u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK; | |
| 267 | + | |
| 268 | + if (!(seq_info & AR_PRESENT_FLAG)) | |
| 269 | + return; | |
| 270 | + | |
| 271 | + if (ar_idc == AR_EXTEND) { | |
| 272 | + u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3); | |
| 273 | + | |
| 274 | + sess->pixelaspect.numerator = ar_info & 0xffff; | |
| 275 | + sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff; | |
| 276 | + return; | |
| 277 | + } | |
| 278 | + | |
| 279 | + if (ar_idc >= ARRAY_SIZE(par_table)) | |
| 280 | + return; | |
| 281 | + | |
| 282 | + sess->pixelaspect = par_table[ar_idc]; | |
| 283 | +} | |
| 284 | + | |
| 285 | +static void codec_h264_resume(struct amvdec_session *sess) | |
| 286 | +{ | |
| 287 | + struct amvdec_core *core = sess->core; | |
| 288 | + struct codec_h264 *h264 = sess->priv; | |
| 289 | + u32 mb_width, mb_height, mb_total; | |
| 290 | + | |
| 291 | + amvdec_set_canvases(sess, | |
| 292 | + (u32[]){ ANC0_CANVAS_ADDR, 0 }, | |
| 293 | + (u32[]){ 24, 0 }); | |
| 294 | + | |
| 295 | + dev_dbg(core->dev, "max_refs = %u; actual_dpb_size = %u\n", | |
| 296 | + h264->max_refs, sess->num_dst_bufs); | |
| 297 | + | |
| 298 | + /* Align to a multiple of 4 macroblocks */ | |
| 299 | + mb_width = ALIGN(h264->mb_width, 4); | |
| 300 | + mb_height = ALIGN(h264->mb_height, 4); | |
| 301 | + mb_total = mb_width * mb_height; | |
| 302 | + | |
| 303 | + h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs; | |
| 304 | + h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size, | |
| 305 | + &h264->ref_paddr, GFP_KERNEL); | |
| 306 | + if (!h264->ref_vaddr) { | |
| 307 | + amvdec_abort(sess); | |
| 308 | + return; | |
| 309 | + } | |
| 310 | + | |
| 311 | + /* Address to store the references' MVs */ | |
| 312 | + amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr); | |
| 313 | + /* End of ref MV */ | |
| 314 | + amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size); | |
| 315 | + | |
| 316 | + amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) | | |
| 317 | + (sess->num_dst_bufs << 16) | | |
| 318 | + ((h264->max_refs - 1) << 8)); | |
| 319 | +} | |
| 320 | + | |
| 321 | +/* | |
| 322 | + * Configure the H.264 decoder when the parser detected a parameter set change | |
| 323 | + */ | |
| 324 | +static void codec_h264_src_change(struct amvdec_session *sess) | |
| 325 | +{ | |
| 326 | + struct amvdec_core *core = sess->core; | |
| 327 | + struct codec_h264 *h264 = sess->priv; | |
| 328 | + u32 parsed_info, mb_total; | |
| 329 | + u32 crop_infor, crop_bottom, crop_right; | |
| 330 | + u32 frame_width, frame_height; | |
| 331 | + | |
| 332 | + sess->keyframe_found = 1; | |
| 333 | + | |
| 334 | + parsed_info = amvdec_read_dos(core, AV_SCRATCH_1); | |
| 335 | + | |
| 336 | + /* Total number of 16x16 macroblocks */ | |
| 337 | + mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK; | |
| 338 | + /* Number of macroblocks per line */ | |
| 339 | + h264->mb_width = parsed_info & MB_WIDTH_MASK; | |
| 340 | + /* Number of macroblock lines */ | |
| 341 | + h264->mb_height = mb_total / h264->mb_width; | |
| 342 | + | |
| 343 | + h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1; | |
| 344 | + | |
| 345 | + crop_infor = amvdec_read_dos(core, AV_SCRATCH_6); | |
| 346 | + crop_bottom = (crop_infor & 0xff); | |
| 347 | + crop_right = (crop_infor >> 16) & 0xff; | |
| 348 | + | |
| 349 | + frame_width = h264->mb_width * 16 - crop_right; | |
| 350 | + frame_height = h264->mb_height * 16 - crop_bottom; | |
| 351 | + | |
| 352 | + dev_dbg(core->dev, "frame: %ux%u; crop: %u %u\n", | |
| 353 | + frame_width, frame_height, crop_right, crop_bottom); | |
| 354 | + | |
| 355 | + codec_h264_set_par(sess); | |
| 356 | + amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5); | |
| 357 | +} | |
| 358 | + | |
| 359 | +/* | |
| 360 | + * The bitstream offset is split in half in 2 different registers. | |
| 361 | + * Fetch its MSB here, which location depends on the frame number. | |
| 362 | + */ | |
| 363 | +static u32 get_offset_msb(struct amvdec_core *core, int frame_num) | |
| 364 | +{ | |
| 365 | + int take_msb = frame_num % 2; | |
| 366 | + int reg_offset = (frame_num / 2) * 4; | |
| 367 | + u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset); | |
| 368 | + | |
| 369 | + if (take_msb) | |
| 370 | + return offset_msb & 0xffff0000; | |
| 371 | + | |
| 372 | + return (offset_msb & 0x0000ffff) << 16; | |
| 373 | +} | |
| 374 | + | |
| 375 | +static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status) | |
| 376 | +{ | |
| 377 | + struct amvdec_core *core = sess->core; | |
| 378 | + int error_count; | |
| 379 | + int num_frames; | |
| 380 | + int i; | |
| 381 | + | |
| 382 | + error_count = amvdec_read_dos(core, AV_SCRATCH_D); | |
| 383 | + num_frames = (status >> 8) & 0xff; | |
| 384 | + if (error_count) { | |
| 385 | + dev_warn(core->dev, | |
| 386 | + "decoder error(s) happened, count %d\n", error_count); | |
| 387 | + amvdec_write_dos(core, AV_SCRATCH_D, 0); | |
| 388 | + } | |
| 389 | + | |
| 390 | + for (i = 0; i < num_frames; i++) { | |
| 391 | + u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4); | |
| 392 | + u32 buffer_index = frame_status & BUF_IDX_MASK; | |
| 393 | + u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) & | |
| 394 | + PIC_STRUCT_MASK; | |
| 395 | + u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK; | |
| 396 | + u32 field = V4L2_FIELD_NONE; | |
| 397 | + | |
| 398 | + /* | |
| 399 | + * A buffer decode error means it was decoded, | |
| 400 | + * but part of the picture will have artifacts. | |
| 401 | + * Typical reason is a temporarily corrupted bitstream | |
| 402 | + */ | |
| 403 | + if (frame_status & ERROR_FLAG) | |
| 404 | + dev_dbg(core->dev, "Buffer %d decode error\n", | |
| 405 | + buffer_index); | |
| 406 | + | |
| 407 | + if (pic_struct == PIC_TOP_BOT) | |
| 408 | + field = V4L2_FIELD_INTERLACED_TB; | |
| 409 | + else if (pic_struct == PIC_BOT_TOP) | |
| 410 | + field = V4L2_FIELD_INTERLACED_BT; | |
| 411 | + | |
| 412 | + offset |= get_offset_msb(core, i); | |
| 413 | + amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); | |
| 414 | + } | |
| 415 | +} | |
| 416 | + | |
| 417 | +static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess) | |
| 418 | +{ | |
| 419 | + struct amvdec_core *core = sess->core; | |
| 420 | + u32 status; | |
| 421 | + u32 size; | |
| 422 | + u8 cmd; | |
| 423 | + | |
| 424 | + status = amvdec_read_dos(core, AV_SCRATCH_0); | |
| 425 | + cmd = status & CMD_MASK; | |
| 426 | + | |
| 427 | + switch (cmd) { | |
| 428 | + case CMD_SRC_CHANGE: | |
| 429 | + codec_h264_src_change(sess); | |
| 430 | + break; | |
| 431 | + case CMD_FRAMES_READY: | |
| 432 | + codec_h264_frames_ready(sess, status); | |
| 433 | + break; | |
| 434 | + case CMD_FATAL_ERROR: | |
| 435 | + dev_err(core->dev, "H.264 decoder fatal error\n"); | |
| 436 | + goto abort; | |
| 437 | + case CMD_BAD_WIDTH: | |
| 438 | + size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; | |
| 439 | + dev_err(core->dev, "Unsupported video width: %u\n", size); | |
| 440 | + goto abort; | |
| 441 | + case CMD_BAD_HEIGHT: | |
| 442 | + size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; | |
| 443 | + dev_err(core->dev, "Unsupported video height: %u\n", size); | |
| 444 | + goto abort; | |
| 445 | + case 0: /* Unused but not worth printing for */ | |
| 446 | + case 9: | |
| 447 | + break; | |
| 448 | + default: | |
| 449 | + dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd); | |
| 450 | + break; | |
| 451 | + } | |
| 452 | + | |
| 453 | + if (cmd && cmd != CMD_SRC_CHANGE) | |
| 454 | + amvdec_write_dos(core, AV_SCRATCH_0, 0); | |
| 455 | + | |
| 456 | + /* Decoder has some SEI data for us ; ignore */ | |
| 457 | + if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY) | |
| 458 | + amvdec_write_dos(core, AV_SCRATCH_J, 0); | |
| 459 | + | |
| 460 | + return IRQ_HANDLED; | |
| 461 | +abort: | |
| 462 | + amvdec_abort(sess); | |
| 463 | + return IRQ_HANDLED; | |
| 464 | +} | |
| 465 | + | |
| 466 | +static irqreturn_t codec_h264_isr(struct amvdec_session *sess) | |
| 467 | +{ | |
| 468 | + struct amvdec_core *core = sess->core; | |
| 469 | + | |
| 470 | + amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); | |
| 471 | + | |
| 472 | + return IRQ_WAKE_THREAD; | |
| 473 | +} | |
| 474 | + | |
| 475 | +struct amvdec_codec_ops codec_h264_ops = { | |
| 476 | + .start = codec_h264_start, | |
| 477 | + .stop = codec_h264_stop, | |
| 478 | + .load_extended_firmware = codec_h264_load_extended_firmware, | |
| 479 | + .isr = codec_h264_isr, | |
| 480 | + .threaded_isr = codec_h264_threaded_isr, | |
| 481 | + .can_recycle = codec_h264_can_recycle, | |
| 482 | + .recycle = codec_h264_recycle, | |
| 483 | + .eos_sequence = codec_h264_eos_sequence, | |
| 484 | + .resume = codec_h264_resume, | |
| 485 | +}; | |
| @@ -0,0 +1,14 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0+ */ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2019 BayLibre, SAS | |
| 4 | + * Author: Maxime Jourdan <mjourdan@baylibre.com> | |
| 5 | + */ | |
| 6 | + | |
| 7 | +#ifndef __MESON_VDEC_CODEC_H264_H_ | |
| 8 | +#define __MESON_VDEC_CODEC_H264_H_ | |
| 9 | + | |
| 10 | +#include "vdec.h" | |
| 11 | + | |
| 12 | +extern struct amvdec_codec_ops codec_h264_ops; | |
| 13 | + | |
| 14 | +#endif | |
| @@ -0,0 +1,297 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0+ | |
| 2 | +/* | |
| 3 | + * Copyright (C) 2018 Maxime Jourdan <mjourdan@baylibre.com> | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include <media/v4l2-mem2mem.h> | |
| 7 | +#include <media/videobuf2-dma-contig.h> | |
| 8 | + | |
| 9 | +#include "codec_hevc_common.h" | |
| 10 | +#include "vdec_helpers.h" | |
| 11 | +#include "hevc_regs.h" | |
| 12 | + | |
| 13 | +#define MMU_COMPRESS_HEADER_SIZE 0x48000 | |
| 14 | +#define MMU_MAP_SIZE 0x4800 | |
| 15 | + | |
| 16 | +const u16 vdec_hevc_parser_cmd[] = { | |
| 17 | + 0x0401, 0x8401, 0x0800, 0x0402, | |
| 18 | + 0x9002, 0x1423, 0x8CC3, 0x1423, | |
| 19 | + 0x8804, 0x9825, 0x0800, 0x04FE, | |
| 20 | + 0x8406, 0x8411, 0x1800, 0x8408, | |
| 21 | + 0x8409, 0x8C2A, 0x9C2B, 0x1C00, | |
| 22 | + 0x840F, 0x8407, 0x8000, 0x8408, | |
| 23 | + 0x2000, 0xA800, 0x8410, 0x04DE, | |
| 24 | + 0x840C, 0x840D, 0xAC00, 0xA000, | |
| 25 | + 0x08C0, 0x08E0, 0xA40E, 0xFC00, | |
| 26 | + 0x7C00 | |
| 27 | +}; | |
| 28 | + | |
| 29 | +/* Configure decode head read mode */ | |
| 30 | +void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) | |
| 31 | +{ | |
| 32 | + struct amvdec_core *core = sess->core; | |
| 33 | + u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); | |
| 34 | + u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); | |
| 35 | + | |
| 36 | + if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { | |
| 37 | + /* Enable 2-plane reference read mode */ | |
| 38 | + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); | |
| 39 | + return; | |
| 40 | + } | |
| 41 | + | |
| 42 | + if (codec_hevc_use_mmu(core->platform->revision, | |
| 43 | + sess->pixfmt_cap, is_10bit)) | |
| 44 | + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4)); | |
| 45 | + else | |
| 46 | + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); | |
| 47 | + | |
| 48 | + if (core->platform->revision < VDEC_REVISION_SM1) | |
| 49 | + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); | |
| 50 | + amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); | |
| 51 | + amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); | |
| 52 | + amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); | |
| 53 | +} | |
| 54 | +EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); | |
| 55 | + | |
| 56 | +static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, | |
| 57 | + struct codec_hevc_common *comm, | |
| 58 | + int is_10bit) | |
| 59 | +{ | |
| 60 | + struct amvdec_core *core = sess->core; | |
| 61 | + struct v4l2_m2m_buffer *buf; | |
| 62 | + u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); | |
| 63 | + dma_addr_t buf_y_paddr = 0; | |
| 64 | + dma_addr_t buf_uv_paddr = 0; | |
| 65 | + u32 idx = 0; | |
| 66 | + u32 val; | |
| 67 | + int i; | |
| 68 | + | |
| 69 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); | |
| 70 | + | |
| 71 | + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { | |
| 72 | + struct vb2_buffer *vb = &buf->vb.vb2_buf; | |
| 73 | + | |
| 74 | + idx = vb->index; | |
| 75 | + | |
| 76 | + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) | |
| 77 | + buf_y_paddr = comm->fbc_buffer_paddr[idx]; | |
| 78 | + else | |
| 79 | + buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); | |
| 80 | + | |
| 81 | + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { | |
| 82 | + val = buf_y_paddr | (idx << 8) | 1; | |
| 83 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, | |
| 84 | + val); | |
| 85 | + } else { | |
| 86 | + buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); | |
| 87 | + val = buf_y_paddr | ((idx * 2) << 8) | 1; | |
| 88 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, | |
| 89 | + val); | |
| 90 | + val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; | |
| 91 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, | |
| 92 | + val); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) | |
| 97 | + val = buf_y_paddr | (idx << 8) | 1; | |
| 98 | + else | |
| 99 | + val = buf_y_paddr | ((idx * 2) << 8) | 1; | |
| 100 | + | |
| 101 | + /* Fill the remaining unused slots with the last buffer's Y addr */ | |
| 102 | + for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) | |
| 103 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); | |
| 104 | + | |
| 105 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); | |
| 106 | + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); | |
| 107 | + for (i = 0; i < 32; ++i) | |
| 108 | + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); | |
| 109 | +} | |
| 110 | + | |
| 111 | +static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, | |
| 112 | + struct codec_hevc_common *comm, | |
| 113 | + int is_10bit) | |
| 114 | +{ | |
| 115 | + struct amvdec_core *core = sess->core; | |
| 116 | + struct v4l2_m2m_buffer *buf; | |
| 117 | + u32 revision = core->platform->revision; | |
| 118 | + u32 pixfmt_cap = sess->pixfmt_cap; | |
| 119 | + int i; | |
| 120 | + | |
| 121 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, | |
| 122 | + BIT(2) | BIT(1)); | |
| 123 | + | |
| 124 | + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { | |
| 125 | + struct vb2_buffer *vb = &buf->vb.vb2_buf; | |
| 126 | + dma_addr_t buf_y_paddr = 0; | |
| 127 | + dma_addr_t buf_uv_paddr = 0; | |
| 128 | + u32 idx = vb->index; | |
| 129 | + | |
| 130 | + if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit)) | |
| 131 | + buf_y_paddr = comm->mmu_header_paddr[idx]; | |
| 132 | + else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit)) | |
| 133 | + buf_y_paddr = comm->fbc_buffer_paddr[idx]; | |
| 134 | + else | |
| 135 | + buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); | |
| 136 | + | |
| 137 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, | |
| 138 | + buf_y_paddr >> 5); | |
| 139 | + | |
| 140 | + if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) { | |
| 141 | + buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); | |
| 142 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, | |
| 143 | + buf_uv_paddr >> 5); | |
| 144 | + } | |
| 145 | + } | |
| 146 | + | |
| 147 | + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); | |
| 148 | + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); | |
| 149 | + for (i = 0; i < 32; ++i) | |
| 150 | + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); | |
| 151 | +} | |
| 152 | + | |
| 153 | +void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, | |
| 154 | + struct codec_hevc_common *comm) | |
| 155 | +{ | |
| 156 | + struct device *dev = sess->core->dev; | |
| 157 | + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); | |
| 158 | + int i; | |
| 159 | + | |
| 160 | + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { | |
| 161 | + if (comm->fbc_buffer_vaddr[i]) { | |
| 162 | + dma_free_coherent(dev, am21_size, | |
| 163 | + comm->fbc_buffer_vaddr[i], | |
| 164 | + comm->fbc_buffer_paddr[i]); | |
| 165 | + comm->fbc_buffer_vaddr[i] = NULL; | |
| 166 | + } | |
| 167 | + } | |
| 168 | +} | |
| 169 | +EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); | |
| 170 | + | |
| 171 | +static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess, | |
| 172 | + struct codec_hevc_common *comm) | |
| 173 | +{ | |
| 174 | + struct device *dev = sess->core->dev; | |
| 175 | + struct v4l2_m2m_buffer *buf; | |
| 176 | + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); | |
| 177 | + | |
| 178 | + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { | |
| 179 | + u32 idx = buf->vb.vb2_buf.index; | |
| 180 | + dma_addr_t paddr; | |
| 181 | + void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, | |
| 182 | + GFP_KERNEL); | |
| 183 | + if (!vaddr) { | |
| 184 | + codec_hevc_free_fbc_buffers(sess, comm); | |
| 185 | + return -ENOMEM; | |
| 186 | + } | |
| 187 | + | |
| 188 | + comm->fbc_buffer_vaddr[idx] = vaddr; | |
| 189 | + comm->fbc_buffer_paddr[idx] = paddr; | |
| 190 | + } | |
| 191 | + | |
| 192 | + return 0; | |
| 193 | +} | |
104 more lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 2142 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 219 lines aren’t shown here.
This diff is large: its 275 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 240 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 232 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 210 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 204 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
File renamed without changes.
This diff is large: its 12 lines aren’t shown here.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This diff is large: its 9 lines aren’t shown here.
File renamed without changes.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 170 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 168 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 17 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.
This diff is large: its 9 lines aren’t shown here.