diff options
298 files changed, 12814 insertions, 4688 deletions
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml index 27f38eed389e..5dd1cf490cd9 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/allwinner,sun4i-a10-csi.yaml# +$id: http://devicetree.org/schemas/media/allwinner,sun4i-a10-csi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Allwinner A10 CMOS Sensor Interface (CSI) Device Tree Bindings diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml new file mode 100644 index 000000000000..2e40f700e84f --- /dev/null +++ b/Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/allwinner,sun8i-h3-deinterlace.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner H3 Deinterlace Device Tree Bindings + +maintainers: + - Jernej Skrabec <jernej.skrabec@siol.net> + - Chen-Yu Tsai <wens@csie.org> + - Maxime Ripard <mripard@kernel.org> + +description: |- + The Allwinner H3 and later has a deinterlace core used for + deinterlacing interlaced video content. + +properties: + compatible: + const: allwinner,sun8i-h3-deinterlace + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Deinterlace interface clock + - description: Deinterlace module clock + - description: Deinterlace DRAM clock + + clock-names: + items: + - const: bus + - const: mod + - const: ram + + resets: + maxItems: 1 + + interconnects: + maxItems: 1 + + interconnect-names: + const: dma-mem + +required: + - compatible + - reg + - interrupts + - clocks + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + #include <dt-bindings/clock/sun8i-h3-ccu.h> + #include <dt-bindings/reset/sun8i-h3-ccu.h> + + deinterlace: deinterlace@1400000 { + compatible = "allwinner,sun8i-h3-deinterlace"; + reg = <0x01400000 0x20000>; + clocks = <&ccu CLK_BUS_DEINTERLACE>, + <&ccu CLK_DEINTERLACE>, + <&ccu CLK_DRAM_DEINTERLACE>; + clock-names = "bus", "mod", "ram"; + resets = <&ccu RST_BUS_DEINTERLACE>; + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; + interconnects = <&mbus 9>; + interconnect-names = "dma-mem"; + }; + +... diff --git a/Documentation/devicetree/bindings/media/i2c/ad5820.txt b/Documentation/devicetree/bindings/media/i2c/ad5820.txt index 5940ca11c021..5764cbedf9b7 100644 --- a/Documentation/devicetree/bindings/media/i2c/ad5820.txt +++ b/Documentation/devicetree/bindings/media/i2c/ad5820.txt @@ -2,12 +2,20 @@ Required Properties: - - compatible: Must contain "adi,ad5820" + - compatible: Must contain one of: + - "adi,ad5820" + - "adi,ad5821" + - "adi,ad5823" - reg: I2C slave address - VANA-supply: supply of voltage for VANA pin +Optional properties: + + - enable-gpios : GPIO spec for the XSHUTDOWN pin. The XSHUTDOWN signal is +active low, a high level on the pin enables the device. + Example: ad5820: coil@c { @@ -15,5 +23,6 @@ Example: reg = <0x0c>; VANA-supply = <&vaux4>; + enable-gpios = <&msmgpio 26 GPIO_ACTIVE_HIGH>; }; diff --git a/Documentation/devicetree/bindings/media/i2c/imx290.txt b/Documentation/devicetree/bindings/media/i2c/imx290.txt new file mode 100644 index 000000000000..a3cc21410f7c --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/imx290.txt @@ -0,0 +1,57 @@ +* Sony IMX290 1/2.8-Inch CMOS Image Sensor + +The Sony IMX290 is a 1/2.8-Inch CMOS Solid-state image sensor with +Square Pixel for Color Cameras. It is programmable through I2C and 4-wire +interfaces. The sensor output is available via CMOS logic parallel SDR output, +Low voltage LVDS DDR output and CSI-2 serial data output. The CSI-2 bus is the +default. No bindings have been defined for the other busses. + +Required Properties: +- compatible: Should be "sony,imx290" +- reg: I2C bus address of the device +- clocks: Reference to the xclk clock. +- clock-names: Should be "xclk". +- clock-frequency: Frequency of the xclk clock in Hz. +- vdddo-supply: Sensor digital IO regulator. +- vdda-supply: Sensor analog regulator. +- vddd-supply: Sensor digital core regulator. + +Optional Properties: +- reset-gpios: Sensor reset GPIO + +The imx290 device node should contain one 'port' child node with +an 'endpoint' subnode. For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Required Properties on endpoint: +- data-lanes: check ../video-interfaces.txt +- link-frequencies: check ../video-interfaces.txt +- remote-endpoint: check ../video-interfaces.txt + +Example: + &i2c1 { + ... + imx290: camera-sensor@1a { + compatible = "sony,imx290"; + reg = <0x1a>; + + reset-gpios = <&msmgpio 35 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_default>; + + clocks = <&gcc GCC_CAMSS_MCLK0_CLK>; + clock-names = "xclk"; + clock-frequency = <37125000>; + + vdddo-supply = <&camera_vdddo_1v8>; + vdda-supply = <&camera_vdda_2v8>; + vddd-supply = <&camera_vddd_1v5>; + + port { + imx290_ep: endpoint { + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <445500000>; + remote-endpoint = <&csiphy0_ep>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt index c3c3479233c4..10ece8108081 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -27,8 +27,6 @@ Mandatory properties Optional properties ------------------- -- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, - the NVM contents will not be read. - reset-gpios: XSHUTDOWN GPIO - flash-leds: See ../video-interfaces.txt - lens-focus: See ../video-interfaces.txt diff --git a/Documentation/devicetree/bindings/media/i2c/ov2659.txt b/Documentation/devicetree/bindings/media/i2c/ov2659.txt index cabc7d827dfb..92989a619f29 100644 --- a/Documentation/devicetree/bindings/media/i2c/ov2659.txt +++ b/Documentation/devicetree/bindings/media/i2c/ov2659.txt @@ -12,6 +12,12 @@ Required Properties: - clock-names: should be "xvclk". - link-frequencies: target pixel clock frequency. +Optional Properties: +- powerdown-gpios: reference to the GPIO connected to the pwdn pin, if any. + Active high with internal pull down resistor. +- reset-gpios: reference to the GPIO connected to the resetb pin, if any. + Active low with internal pull up resistor. + For further reading on port node refer to Documentation/devicetree/bindings/media/video-interfaces.txt. @@ -27,6 +33,9 @@ Example: clocks = <&clk_ov2659 0>; clock-names = "xvclk"; + powerdown-gpios = <&gpio6 14 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio6 15 GPIO_ACTIVE_LOW>; + port { ov2659_0: endpoint { remote-endpoint = <&vpfe_ep>; diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index 3d5c154fd230..ceb283f7888a 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -39,6 +39,7 @@ properties: - rc-avermedia-rm-ks - rc-avertv-303 - rc-azurewave-ad-tu700 + - rc-beelink-gs1 - rc-behold - rc-behold-columbus - rc-budget-ci-old diff --git a/Documentation/devicetree/bindings/media/renesas,csi2.txt b/Documentation/devicetree/bindings/media/renesas,csi2.txt index 331409259752..2da6f60b2b56 100644 --- a/Documentation/devicetree/bindings/media/renesas,csi2.txt +++ b/Documentation/devicetree/bindings/media/renesas,csi2.txt @@ -9,6 +9,7 @@ Mandatory properties -------------------- - compatible: Must be one or more of the following - "renesas,r8a774a1-csi2" for the R8A774A1 device. + - "renesas,r8a774b1-csi2" for the R8A774B1 device. - "renesas,r8a774c0-csi2" for the R8A774C0 device. - "renesas,r8a7795-csi2" for the R8A7795 device. - "renesas,r8a7796-csi2" for the R8A7796 device. diff --git a/Documentation/devicetree/bindings/media/renesas,vin.txt b/Documentation/devicetree/bindings/media/renesas,vin.txt index aa217b096279..e30b0d4eefdd 100644 --- a/Documentation/devicetree/bindings/media/renesas,vin.txt +++ b/Documentation/devicetree/bindings/media/renesas,vin.txt @@ -14,6 +14,7 @@ on Gen3 and RZ/G2 platforms to a CSI-2 receiver. - "renesas,vin-r8a7744" for the R8A7744 device - "renesas,vin-r8a7745" for the R8A7745 device - "renesas,vin-r8a774a1" for the R8A774A1 device + - "renesas,vin-r8a774b1" for the R8A774B1 device - "renesas,vin-r8a774c0" for the R8A774C0 device - "renesas,vin-r8a7778" for the R8A7778 device - "renesas,vin-r8a7779" for the R8A7779 device @@ -43,7 +44,7 @@ on Gen3 and RZ/G2 platforms to a CSI-2 receiver. Additionally, an alias named vinX will need to be created to specify which video input device this is. -The per-board settings Gen2 platforms: +The per-board settings for Gen2 and RZ/G1 platforms: - port - sub-node describing a single endpoint connected to the VIN from external SoC pins as described in video-interfaces.txt[1]. @@ -63,7 +64,7 @@ The per-board settings Gen2 platforms: - data-enable-active: polarity of CLKENB signal, see [1] for description. Default is active high. -The per-board settings Gen3 and RZ/G2 platforms: +The per-board settings for Gen3 and RZ/G2 platforms: Gen3 and RZ/G2 platforms can support both a single connected parallel input source from external SoC pins (port@0) and/or multiple parallel input sources diff --git a/Documentation/devicetree/bindings/media/sh_mobile_ceu.txt b/Documentation/devicetree/bindings/media/sh_mobile_ceu.txt deleted file mode 100644 index cfa4ffada8ae..000000000000 --- a/Documentation/devicetree/bindings/media/sh_mobile_ceu.txt +++ /dev/null @@ -1,17 +0,0 @@ -Bindings, specific for the sh_mobile_ceu_camera.c driver: - - compatible: Should be "renesas,sh-mobile-ceu" - - reg: register base and size - - interrupts: the interrupt number - - renesas,max-width: maximum image width, supported on this SoC - - renesas,max-height: maximum image height, supported on this SoC - -Example: - -ceu0: ceu@fe910000 { - compatible = "renesas,sh-mobile-ceu"; - reg = <0xfe910000 0xa0>; - interrupt-parent = <&intcs>; - interrupts = <0x880>; - renesas,max-width = <8188>; - renesas,max-height = <8188>; -}; diff --git a/Documentation/devicetree/bindings/media/ti,vpe.yaml b/Documentation/devicetree/bindings/media/ti,vpe.yaml new file mode 100644 index 000000000000..f3a8a350e85f --- /dev/null +++ b/Documentation/devicetree/bindings/media/ti,vpe.yaml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/ti,vpe.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments DRA7x Video Processing Engine (VPE) Device Tree Bindings + +maintainers: + - Benoit Parrot <bparrot@ti.com> + +description: |- + The Video Processing Engine (VPE) is a key component for image post + processing applications. VPE consist of a single memory to memory + path which can perform chroma up/down sampling, deinterlacing, + scaling and color space conversion. + +properties: + compatible: + const: ti,dra7-vpe + + reg: + items: + - description: The VPE main register region + - description: Scaler (SC) register region + - description: Color Space Conversion (CSC) register region + - description: Video Port Direct Memory Access (VPDMA) register region + + reg-names: + items: + - const: vpe_top + - const: sc + - const: csc + - const: vpdma + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - reg-names + - interrupts + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + vpe: vpe@489d0000 { + compatible = "ti,dra7-vpe"; + reg = <0x489d0000 0x120>, + <0x489d0700 0x80>, + <0x489d5700 0x18>, + <0x489dd000 0x400>; + reg-names = "vpe_top", + "sc", + "csc", + "vpdma"; + interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>; + }; + +... diff --git a/Documentation/media/cec.h.rst.exceptions b/Documentation/media/cec.h.rst.exceptions index 014816d04b9e..d83790ccac8e 100644 --- a/Documentation/media/cec.h.rst.exceptions +++ b/Documentation/media/cec.h.rst.exceptions @@ -335,6 +335,95 @@ ignore define CEC_OP_MENU_STATE_DEACTIVATED ignore define CEC_MSG_USER_CONTROL_PRESSED +ignore define CEC_OP_UI_CMD_SELECT +ignore define CEC_OP_UI_CMD_UP +ignore define CEC_OP_UI_CMD_DOWN +ignore define CEC_OP_UI_CMD_LEFT +ignore define CEC_OP_UI_CMD_RIGHT +ignore define CEC_OP_UI_CMD_RIGHT_UP +ignore define CEC_OP_UI_CMD_RIGHT_DOWN +ignore define CEC_OP_UI_CMD_LEFT_UP +ignore define CEC_OP_UI_CMD_LEFT_DOWN +ignore define CEC_OP_UI_CMD_DEVICE_ROOT_MENU +ignore define CEC_OP_UI_CMD_DEVICE_SETUP_MENU +ignore define CEC_OP_UI_CMD_CONTENTS_MENU +ignore define CEC_OP_UI_CMD_FAVORITE_MENU +ignore define CEC_OP_UI_CMD_BACK +ignore define CEC_OP_UI_CMD_MEDIA_TOP_MENU +ignore define CEC_OP_UI_CMD_MEDIA_CONTEXT_SENSITIVE_MENU +ignore define CEC_OP_UI_CMD_NUMBER_ENTRY_MODE +ignore define CEC_OP_UI_CMD_NUMBER_11 +ignore define CEC_OP_UI_CMD_NUMBER_12 +ignore define CEC_OP_UI_CMD_NUMBER_0_OR_NUMBER_10 +ignore define CEC_OP_UI_CMD_NUMBER_1 +ignore define CEC_OP_UI_CMD_NUMBER_2 +ignore define CEC_OP_UI_CMD_NUMBER_3 +ignore define CEC_OP_UI_CMD_NUMBER_4 +ignore define CEC_OP_UI_CMD_NUMBER_5 +ignore define CEC_OP_UI_CMD_NUMBER_6 +ignore define CEC_OP_UI_CMD_NUMBER_7 +ignore define CEC_OP_UI_CMD_NUMBER_8 +ignore define CEC_OP_UI_CMD_NUMBER_9 +ignore define CEC_OP_UI_CMD_DOT +ignore define CEC_OP_UI_CMD_ENTER +ignore define CEC_OP_UI_CMD_CLEAR +ignore define CEC_OP_UI_CMD_NEXT_FAVORITE +ignore define CEC_OP_UI_CMD_CHANNEL_UP +ignore define CEC_OP_UI_CMD_CHANNEL_DOWN +ignore define CEC_OP_UI_CMD_PREVIOUS_CHANNEL +ignore define CEC_OP_UI_CMD_SOUND_SELECT +ignore define CEC_OP_UI_CMD_INPUT_SELECT +ignore define CEC_OP_UI_CMD_DISPLAY_INFORMATION +ignore define CEC_OP_UI_CMD_HELP +ignore define CEC_OP_UI_CMD_PAGE_UP +ignore define CEC_OP_UI_CMD_PAGE_DOWN +ignore define CEC_OP_UI_CMD_POWER +ignore define CEC_OP_UI_CMD_VOLUME_UP +ignore define CEC_OP_UI_CMD_VOLUME_DOWN +ignore define CEC_OP_UI_CMD_MUTE +ignore define CEC_OP_UI_CMD_PLAY +ignore define CEC_OP_UI_CMD_STOP +ignore define CEC_OP_UI_CMD_PAUSE +ignore define CEC_OP_UI_CMD_RECORD +ignore define CEC_OP_UI_CMD_REWIND +ignore define CEC_OP_UI_CMD_FAST_FORWARD +ignore define CEC_OP_UI_CMD_EJECT +ignore define CEC_OP_UI_CMD_SKIP_FORWARD +ignore define CEC_OP_UI_CMD_SKIP_BACKWARD +ignore define CEC_OP_UI_CMD_STOP_RECORD +ignore define CEC_OP_UI_CMD_PAUSE_RECORD +ignore define CEC_OP_UI_CMD_ANGLE +ignore define CEC_OP_UI_CMD_SUB_PICTURE +ignore define CEC_OP_UI_CMD_VIDEO_ON_DEMAND +ignore define CEC_OP_UI_CMD_ELECTRONIC_PROGRAM_GUIDE +ignore define CEC_OP_UI_CMD_TIMER_PROGRAMMING +ignore define CEC_OP_UI_CMD_INITIAL_CONFIGURATION +ignore define CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE +ignore define CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION +ignore define CEC_OP_UI_CMD_AUDIO_DESCRIPTION +ignore define CEC_OP_UI_CMD_INTERNET +ignore define CEC_OP_UI_CMD_3D_MODE +ignore define CEC_OP_UI_CMD_PLAY_FUNCTION +ignore define CEC_OP_UI_CMD_PAUSE_PLAY_FUNCTION +ignore define CEC_OP_UI_CMD_RECORD_FUNCTION +ignore define CEC_OP_UI_CMD_PAUSE_RECORD_FUNCTION +ignore define CEC_OP_UI_CMD_STOP_FUNCTION +ignore define CEC_OP_UI_CMD_MUTE_FUNCTION +ignore define CEC_OP_UI_CMD_RESTORE_VOLUME_FUNCTION +ignore define CEC_OP_UI_CMD_TUNE_FUNCTION +ignore define CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION +ignore define CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION +ignore define CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION +ignore define CEC_OP_UI_CMD_POWER_TOGGLE_FUNCTION +ignore define CEC_OP_UI_CMD_POWER_OFF_FUNCTION +ignore define CEC_OP_UI_CMD_POWER_ON_FUNCTION +ignore define CEC_OP_UI_CMD_F1_BLUE +ignore define CEC_OP_UI_CMD_F2_RED +ignore define CEC_OP_UI_CMD_F3_GREEN +ignore define CEC_OP_UI_CMD_F4_YELLOW +ignore define CEC_OP_UI_CMD_F5 +ignore define CEC_OP_UI_CMD_DATA + ignore define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL ignore define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA ignore define CEC_OP_UI_BCAST_TYPE_ANALOGUE diff --git a/Documentation/media/kapi/v4l2-controls.rst b/Documentation/media/kapi/v4l2-controls.rst index ebe2a55908be..b20800cae3f2 100644 --- a/Documentation/media/kapi/v4l2-controls.rst +++ b/Documentation/media/kapi/v4l2-controls.rst @@ -140,6 +140,15 @@ Menu controls with a driver specific menu are added by calling const struct v4l2_ctrl_ops *ops, u32 id, s32 max, s32 skip_mask, s32 def, const char * const *qmenu); +Standard compound controls can be added by calling +:c:func:`v4l2_ctrl_new_std_compound`: + +.. code-block:: c + + struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, + const union v4l2_ctrl_ptr p_def); + Integer menu controls with a driver specific menu can be added by calling :c:func:`v4l2_ctrl_new_int_menu`: diff --git a/Documentation/media/uapi/cec/cec-funcs.rst b/Documentation/media/uapi/cec/cec-funcs.rst index 620590b168c9..dc6da9c639a8 100644 --- a/Documentation/media/uapi/cec/cec-funcs.rst +++ b/Documentation/media/uapi/cec/cec-funcs.rst @@ -24,6 +24,7 @@ Function Reference cec-ioc-adap-g-caps cec-ioc-adap-g-log-addrs cec-ioc-adap-g-phys-addr + cec-ioc-adap-g-conn-info cec-ioc-dqevent cec-ioc-g-mode cec-ioc-receive diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst index 0c44f31a9b59..76761a98c312 100644 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst +++ b/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst @@ -135,8 +135,12 @@ returns the information to the application. The ioctl never fails. - The CEC hardware can monitor CEC pin changes from low to high voltage and vice versa. When in pin monitoring mode the application will receive ``CEC_EVENT_PIN_CEC_LOW`` and ``CEC_EVENT_PIN_CEC_HIGH`` events. + * .. _`CEC-CAP-CONNECTOR-INFO`: - + - ``CEC_CAP_CONNECTOR_INFO`` + - 0x00000100 + - If this capability is set, then :ref:`CEC_ADAP_G_CONNECTOR_INFO` can + be used. Return Value ============ diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst new file mode 100644 index 000000000000..a21659d55c6b --- /dev/null +++ b/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst @@ -0,0 +1,105 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. +.. Copyright 2019 Google LLC +.. +.. _CEC_ADAP_G_CONNECTOR_INFO: + +******************************* +ioctl CEC_ADAP_G_CONNECTOR_INFO +******************************* + +Name +==== + +CEC_ADAP_G_CONNECTOR_INFO - Query HDMI connector information + +Synopsis +======== + +.. c:function:: int ioctl( int fd, CEC_ADAP_G_CONNECTOR_INFO, struct cec_connector_info *argp ) + :name: CEC_ADAP_G_CONNECTOR_INFO + +Arguments +========= + +``fd`` + File descriptor returned by :c:func:`open() <cec-open>`. + +``argp`` + + +Description +=========== + +Using this ioctl an application can learn which HDMI connector this CEC +device corresponds to. While calling this ioctl the application should +provide a pointer to a cec_connector_info struct which will be populated +by the kernel with the info provided by the adapter's driver. This ioctl +is only available if the ``CEC_CAP_CONNECTOR_INFO`` capability is set. + +.. tabularcolumns:: |p{1.0cm}|p{4.4cm}|p{2.5cm}|p{9.6cm}| + +.. c:type:: cec_connector_info + +.. flat-table:: struct cec_connector_info + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 1 8 + + * - __u32 + - ``type`` + - The type of connector this adapter is associated with. + * - union + - ``(anonymous)`` + - + * - + - ``struct cec_drm_connector_info`` + - drm + - :ref:`cec-drm-connector-info` + + +.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| + +.. _connector-type: + +.. flat-table:: Connector types + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 8 + + * .. _`CEC-CONNECTOR-TYPE-NO-CONNECTOR`: + + - ``CEC_CONNECTOR_TYPE_NO_CONNECTOR`` + - 0 + - No connector is associated with the adapter/the information is not + provided by the driver. + * .. _`CEC-CONNECTOR-TYPE-DRM`: + + - ``CEC_CONNECTOR_TYPE_DRM`` + - 1 + - Indicates that a DRM connector is associated with this adapter. + Information about the connector can be found in + :ref:`cec-drm-connector-info`. + +.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| + +.. c:type:: cec_drm_connector_info + +.. _cec-drm-connector-info: + +.. flat-table:: struct cec_drm_connector_info + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 8 + + * .. _`CEC-DRM-CONNECTOR-TYPE-CARD-NO`: + + - __u32 + - ``card_no`` + - DRM card number: the number from a card's path, e.g. 0 in case of + /dev/card0. + * .. _`CEC-DRM-CONNECTOR-TYPE-CONNECTOR_ID`: + + - __u32 + - ``connector_id`` + - DRM connector ID. diff --git a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst index 46a1c99a595e..5e21b1fbfc01 100644 --- a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst +++ b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst @@ -70,6 +70,14 @@ it is guaranteed that the state did change in between the two events. addresses are claimed or if ``phys_addr`` is ``CEC_PHYS_ADDR_INVALID``. If bit 15 is set (``1 << CEC_LOG_ADDR_UNREGISTERED``) then this device has the unregistered logical address. In that case all other bits are 0. + * - __u16 + - ``have_conn_info`` + - If non-zero, then HDMI connector information is available. + This field is only valid if ``CEC_CAP_CONNECTOR_INFO`` is set. If that + capability is set and ``have_conn_info`` is zero, then that indicates + that the HDMI connector device is not instantiated, either because + the HDMI driver is still configuring the device or because the HDMI + device was unbound. .. c:type:: cec_event_lost_msgs diff --git a/Documentation/media/uapi/mediactl/request-api.rst b/Documentation/media/uapi/mediactl/request-api.rst index a74c82d95609..01abe8103bdd 100644 --- a/Documentation/media/uapi/mediactl/request-api.rst +++ b/Documentation/media/uapi/mediactl/request-api.rst @@ -53,8 +53,8 @@ with different configurations in advance, knowing that the configuration will be applied when needed to get the expected result. Configuration values at the time of request completion are also available for reading. -Usage -===== +General Usage +------------- The Request API extends the Media Controller API and cooperates with subsystem-specific APIs to support request usage. At the Media Controller diff --git a/Documentation/media/uapi/v4l/biblio.rst b/Documentation/media/uapi/v4l/biblio.rst index ad2ff258afa8..8095f57d3d75 100644 --- a/Documentation/media/uapi/v4l/biblio.rst +++ b/Documentation/media/uapi/v4l/biblio.rst @@ -131,6 +131,15 @@ ITU-T Rec. H.264 Specification (04/2017 Edition) :author: International Telecommunication Union (http://www.itu.ch) +.. _hevc: + +ITU H.265/HEVC +============== + +:title: ITU-T Rec. H.265 | ISO/IEC 23008-2 "High Efficiency Video Coding" + +:author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) + .. _jfif: JFIF diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst index 1cbd9cde57f3..9149b57728e5 100644 --- a/Documentation/media/uapi/v4l/buffer.rst +++ b/Documentation/media/uapi/v4l/buffer.rst @@ -607,6 +607,19 @@ Buffer Flags applications shall use this flag for output buffers if the data in this buffer has not been created by the CPU but by some DMA-capable unit, in which case caches have not been used. + * .. _`V4L2-BUF-FLAG-M2M-HOLD-CAPTURE-BUF`: + + - ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` + - 0x00000200 + - Only valid if ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` is + set. It is typically used with stateless decoders where multiple + output buffers each decode to a slice of the decoded frame. + Applications can set this flag when queueing the output buffer + to prevent the driver from dequeueing the capture buffer after + the output buffer has been decoded (i.e. the capture buffer is + 'held'). If the timestamp of this output buffer differs from that + of the previous output buffer, then that indicates the start of a + new frame and the previously held capture buffer is dequeued. * .. _`V4L2-BUF-FLAG-LAST`: - ``V4L2_BUF_FLAG_LAST`` diff --git a/Documentation/media/uapi/v4l/dev-mem2mem.rst b/Documentation/media/uapi/v4l/dev-mem2mem.rst index caa05f5f6380..70953958cee6 100644 --- a/Documentation/media/uapi/v4l/dev-mem2mem.rst +++ b/Documentation/media/uapi/v4l/dev-mem2mem.rst @@ -46,3 +46,4 @@ devices are given in the following sections. :maxdepth: 1 dev-decoder + dev-stateless-decoder diff --git a/Documentation/media/uapi/v4l/dev-stateless-decoder.rst b/Documentation/media/uapi/v4l/dev-stateless-decoder.rst new file mode 100644 index 000000000000..4a26646eeec5 --- /dev/null +++ b/Documentation/media/uapi/v4l/dev-stateless-decoder.rst @@ -0,0 +1,424 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _stateless_decoder: + +************************************************** +Memory-to-memory Stateless Video Decoder Interface +************************************************** + +A stateless decoder is a decoder that works without retaining any kind of state +between processed frames. This means that each frame is decoded independently +of any previous and future frames, and that the client is responsible for +maintaining the decoding state and providing it to the decoder with each +decoding request. This is in contrast to the stateful video decoder interface, +where the hardware and driver maintain the decoding state and all the client +has to do is to provide the raw encoded stream and dequeue decoded frames in +display order. + +This section describes how user-space ("the client") is expected to communicate +with stateless decoders in order to successfully decode an encoded stream. +Compared to stateful codecs, the decoder/client sequence is simpler, but the +cost of this simplicity is extra complexity in the client which is responsible +for maintaining a consistent decoding state. + +Stateless decoders make use of the :ref:`media-request-api`. A stateless +decoder must expose the ``V4L2_BUF_CAP_SUPPORTS_REQUESTS`` capability on its +``OUTPUT`` queue when :c:func:`VIDIOC_REQBUFS` or :c:func:`VIDIOC_CREATE_BUFS` +are invoked. + +Depending on the encoded formats supported by the decoder, a single decoded +frame may be the result of several decode requests (for instance, H.264 streams +with multiple slices per frame). Decoders that support such formats must also +expose the ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` capability on their +``OUTPUT`` queue. + +Querying capabilities +===================== + +1. To enumerate the set of coded formats supported by the decoder, the client + calls :c:func:`VIDIOC_ENUM_FMT` on the ``OUTPUT`` queue. + + * The driver must always return the full set of supported ``OUTPUT`` formats, + irrespective of the format currently set on the ``CAPTURE`` queue. + + * Simultaneously, the driver must restrain the set of values returned by + codec-specific capability controls (such as H.264 profiles) to the set + actually supported by the hardware. + +2. To enumerate the set of supported raw formats, the client calls + :c:func:`VIDIOC_ENUM_FMT` on the ``CAPTURE`` queue. + + * The driver must return only the formats supported for the format currently + active on the ``OUTPUT`` queue. + + * Depending on the currently set ``OUTPUT`` format, the set of supported raw + formats may depend on the value of some codec-dependent controls. + The client is responsible for making sure that these controls are set + before querying the ``CAPTURE`` queue. Failure to do so will result in the + default values for these controls being used, and a returned set of formats + that may not be usable for the media the client is trying to decode. + +3. The client may use :c:func:`VIDIOC_ENUM_FRAMESIZES` to detect supported + resolutions for a given format, passing desired pixel format in + :c:type:`v4l2_frmsizeenum`'s ``pixel_format``. + +4. Supported profiles and levels for the current ``OUTPUT`` format, if + applicable, may be queried using their respective controls via + :c:func:`VIDIOC_QUERYCTRL`. + +Initialization +============== + +1. Set the coded format on the ``OUTPUT`` queue via :c:func:`VIDIOC_S_FMT`. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + ``pixelformat`` + a coded pixel format. + + ``width``, ``height`` + coded width and height parsed from the stream. + + other fields + follow standard semantics. + + .. note:: + + Changing the ``OUTPUT`` format may change the currently set ``CAPTURE`` + format. The driver will derive a new ``CAPTURE`` format from the + ``OUTPUT`` format being set, including resolution, colorimetry + parameters, etc. If the client needs a specific ``CAPTURE`` format, + it must adjust it afterwards. + +2. Call :c:func:`VIDIOC_S_EXT_CTRLS` to set all the controls (parsed headers, + etc.) required by the ``OUTPUT`` format to enumerate the ``CAPTURE`` formats. + +3. Call :c:func:`VIDIOC_G_FMT` for ``CAPTURE`` queue to get the format for the + destination buffers parsed/decoded from the bytestream. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + * **Returned fields:** + + ``width``, ``height`` + frame buffer resolution for the decoded frames. + + ``pixelformat`` + pixel format for decoded frames. + + ``num_planes`` (for _MPLANE ``type`` only) + number of planes for pixelformat. + + ``sizeimage``, ``bytesperline`` + as per standard semantics; matching frame buffer format. + + .. note:: + + The value of ``pixelformat`` may be any pixel format supported for the + ``OUTPUT`` format, based on the hardware capabilities. It is suggested + that the driver chooses the preferred/optimal format for the current + configuration. For example, a YUV format may be preferred over an RGB + format, if an additional conversion step would be required for RGB. + +4. *[optional]* Enumerate ``CAPTURE`` formats via :c:func:`VIDIOC_ENUM_FMT` on + the ``CAPTURE`` queue. The client may use this ioctl to discover which + alternative raw formats are supported for the current ``OUTPUT`` format and + select one of them via :c:func:`VIDIOC_S_FMT`. + + .. note:: + + The driver will return only formats supported for the currently selected + ``OUTPUT`` format and currently set controls, even if more formats may be + supported by the decoder in general. + + For example, a decoder may support YUV and RGB formats for + resolutions 1920x1088 and lower, but only YUV for higher resolutions (due + to hardware limitations). After setting a resolution of 1920x1088 or lower + as the ``OUTPUT`` format, :c:func:`VIDIOC_ENUM_FMT` may return a set of + YUV and RGB pixel formats, but after setting a resolution higher than + 1920x1088, the driver will not return RGB pixel formats, since they are + unsupported for this resolution. + +5. *[optional]* Choose a different ``CAPTURE`` format than suggested via + :c:func:`VIDIOC_S_FMT` on ``CAPTURE`` queue. It is possible for the client to + choose a different format than selected/suggested by the driver in + :c:func:`VIDIOC_G_FMT`. + + * **Required fields:** + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``pixelformat`` + a raw pixel format. + + ``width``, ``height`` + frame buffer resolution of the decoded stream; typically unchanged from + what was returned with :c:func:`VIDIOC_G_FMT`, but it may be different + if the hardware supports composition and/or scaling. + + After performing this step, the client must perform step 3 again in order + to obtain up-to-date information about the buffers size and layout. + +6. Allocate source (bytestream) buffers via :c:func:`VIDIOC_REQBUFS` on + ``OUTPUT`` queue. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``OUTPUT``. + + ``memory`` + follows standard semantics. + + * **Return fields:** + + ``count`` + actual number of buffers allocated. + + * If required, the driver will adjust ``count`` to be equal or bigger to the + minimum of required number of ``OUTPUT`` buffers for the given format and + requested count. The client must check this value after the ioctl returns + to get the actual number of buffers allocated. + +7. Allocate destination (raw format) buffers via :c:func:`VIDIOC_REQBUFS` on the + ``CAPTURE`` queue. + + * **Required fields:** + + ``count`` + requested number of buffers to allocate; greater than zero. The client + is responsible for deducing the minimum number of buffers required + for the stream to be properly decoded (taking e.g. reference frames + into account) and pass an equal or bigger number. + + ``type`` + a ``V4L2_BUF_TYPE_*`` enum appropriate for ``CAPTURE``. + + ``memory`` + follows standard semantics. ``V4L2_MEMORY_USERPTR`` is not supported + for ``CAPTURE`` buffers. + + * **Return fields:** + + ``count`` + adjusted to allocated number of buffers, in case the codec requires + more buffers than requested. + + * The driver must adjust count to the minimum of required number of + ``CAPTURE`` buffers for the current format, stream configuration and + requested count. The client must check this value after the ioctl + returns to get the number of buffers allocated. + +8. Allocate requests (likely one per ``OUTPUT`` buffer) via + :c:func:`MEDIA_IOC_REQUEST_ALLOC` on the media device. + +9. Start streaming on both ``OUTPUT`` and ``CAPTURE`` queues via + :c:func:`VIDIOC_STREAMON`. + +Decoding +======== + +For each frame, the client is responsible for submitting at least one request to +which the following is attached: + +* The amount of encoded data expected by the codec for its current + configuration, as a buffer submitted to the ``OUTPUT`` queue. Typically, this + corresponds to one frame worth of encoded data, but some formats may allow (or + require) different amounts per unit. +* All the metadata needed to decode the submitted encoded data, in the form of + controls relevant to the format being decoded. + +The amount of data and contents of the source ``OUTPUT`` buffer, as well as the +controls that must be set on the request, depend on the active coded pixel +format and might be affected by codec-specific extended controls, as stated in +documentation of each format. + +If there is a possibility that the decoded frame will require one or more +decode requests after the current one in order to be produced, then the client +must set the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag on the ``OUTPUT`` +buffer. This will result in the (potentially partially) decoded ``CAPTURE`` +buffer not being made available for dequeueing, and reused for the next decode +request if the timestamp of the next ``OUTPUT`` buffer has not changed. + +A typical frame would thus be decoded using the following sequence: + +1. Queue an ``OUTPUT`` buffer containing one unit of encoded bytestream data for + the decoding request, using :c:func:`VIDIOC_QBUF`. + + * **Required fields:** + + ``index`` + index of the buffer being queued. + + ``type`` + type of the buffer. + + ``bytesused`` + number of bytes taken by the encoded data frame in the buffer. + + ``flags`` + the ``V4L2_BUF_FLAG_REQUEST_FD`` flag must be set. Additionally, if + we are not sure that the current decode request is the last one needed + to produce a fully decoded frame, then + ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` must also be set. + + ``request_fd`` + must be set to the file descriptor of the decoding request. + + ``timestamp`` + must be set to a unique value per frame. This value will be propagated + into the decoded frame's buffer and can also be used to use this frame + as the reference of another. If using multiple decode requests per + frame, then the timestamps of all the ``OUTPUT`` buffers for a given + frame must be identical. If the timestamp changes, then the currently + held ``CAPTURE`` buffer will be made available for dequeuing and the + current request will work on a new ``CAPTURE`` buffer. + +2. Set the codec-specific controls for the decoding request, using + :c:func:`VIDIOC_S_EXT_CTRLS`. + + * **Required fields:** + + ``which`` + must be ``V4L2_CTRL_WHICH_REQUEST_VAL``. + + ``request_fd`` + must be set to the file descriptor of the decoding request. + + other fields + other fields are set as usual when setting controls. The ``controls`` + array must contain all the codec-specific controls required to decode + a frame. + + .. note:: + + It is possible to specify the controls in different invocations of + :c:func:`VIDIOC_S_EXT_CTRLS`, or to overwrite a previously set control, as + long as ``request_fd`` and ``which`` are properly set. The controls state + at the moment of request submission is the one that will be considered. + + .. note:: + + The order in which steps 1 and 2 take place is interchangeable. + +3. Submit the request by invoking :c:func:`MEDIA_REQUEST_IOC_QUEUE` on the + request FD. + + If the request is submitted without an ``OUTPUT`` buffer, or if some of the + required controls are missing from the request, then + :c:func:`MEDIA_REQUEST_IOC_QUEUE` will return ``-ENOENT``. If more than one + ``OUTPUT`` buffer is queued, then it will return ``-EINVAL``. + :c:func:`MEDIA_REQUEST_IOC_QUEUE` returning non-zero means that no + ``CAPTURE`` buffer will be produced for this request. + +``CAPTURE`` buffers must not be part of the request, and are queued +independently. They are returned in decode order (i.e. the same order as coded +frames were submitted to the ``OUTPUT`` queue). + +Runtime decoding errors are signaled by the dequeued ``CAPTURE`` buffers +carrying the ``V4L2_BUF_FLAG_ERROR`` flag. If a decoded reference frame has an +error, then all following decoded frames that refer to it also have the +``V4L2_BUF_FLAG_ERROR`` flag set, although the decoder will still try to +produce (likely corrupted) frames. + +Buffer management while decoding +================================ +Contrary to stateful decoders, a stateless decoder does not perform any kind of +buffer management: it only guarantees that dequeued ``CAPTURE`` buffers can be +used by the client for as long as they are not queued again. "Used" here +encompasses using the buffer for compositing or display. + +A dequeued capture buffer can also be used as the reference frame of another +buffer. + +A frame is specified as reference by converting its timestamp into nanoseconds, +and storing it into the relevant member of a codec-dependent control structure. +The :c:func:`v4l2_timeval_to_ns` function must be used to perform that +conversion. The timestamp of a frame can be used to reference it as soon as all +its units of encoded data are successfully submitted to the ``OUTPUT`` queue. + +A decoded buffer containing a reference frame must not be reused as a decoding +target until all the frames referencing it have been decoded. The safest way to +achieve this is to refrain from queueing a reference buffer until all the +decoded frames referencing it have been dequeued. However, if the driver can +guarantee that buffers queued to the ``CAPTURE`` queue are processed in queued +order, then user-space can take advantage of this guarantee and queue a +reference buffer when the following conditions are met: + +1. All the requests for frames affected by the reference frame have been + queued, and + +2. A sufficient number of ``CAPTURE`` buffers to cover all the decoded + referencing frames have been queued. + +When queuing a decoding request, the driver will increase the reference count of +all the resources associated with reference frames. This means that the client +can e.g. close the DMABUF file descriptors of reference frame buffers if it +won't need them afterwards. + +Seeking +======= +In order to seek, the client just needs to submit requests using input buffers +corresponding to the new stream position. It must however be aware that +resolution may have changed and follow the dynamic resolution change sequence in +that case. Also depending on the codec used, picture parameters (e.g. SPS/PPS +for H.264) may have changed and the client is responsible for making sure that a +valid state is sent to the decoder. + +The client is then free to ignore any returned ``CAPTURE`` buffer that comes +from the pre-seek position. + +Pausing +======= + +In order to pause, the client can just cease queuing buffers onto the ``OUTPUT`` +queue. Without source bytestream data, there is no data to process and the codec +will remain idle. + +Dynamic resolution change +========================= + +If the client detects a resolution change in the stream, it will need to perform +the initialization sequence again with the new resolution: + +1. If the last submitted request resulted in a ``CAPTURE`` buffer being + held by the use of the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag, then the + last frame is not available on the ``CAPTURE`` queue. In this case, a + ``V4L2_DEC_CMD_FLUSH`` command shall be sent. This will make the driver + dequeue the held ``CAPTURE`` buffer. + +2. Wait until all submitted requests have completed and dequeue the + corresponding output buffers. + +3. Call :c:func:`VIDIOC_STREAMOFF` on both the ``OUTPUT`` and ``CAPTURE`` + queues. + +4. Free all ``CAPTURE`` buffers by calling :c:func:`VIDIOC_REQBUFS` on the + ``CAPTURE`` queue with a buffer count of zero. + +5. Perform the initialization sequence again (minus the allocation of + ``OUTPUT`` buffers), with the new resolution set on the ``OUTPUT`` queue. + Note that due to resolution constraints, a different format may need to be + picked on the ``CAPTURE`` queue. + +Drain +===== + +If the last submitted request resulted in a ``CAPTURE`` buffer being +held by the use of the ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag, then the +last frame is not available on the ``CAPTURE`` queue. In this case, a +``V4L2_DEC_CMD_FLUSH`` command shall be sent. This will make the driver +dequeue the held ``CAPTURE`` buffer. + +After that, in order to drain the stream on a stateless decoder, the client +just needs to wait until all the submitted requests are completed. diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst index bc5dd8e76567..28313c0f4e7c 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst @@ -1713,10 +1713,14 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - * - __u8 - ``scaling_list_4x4[6][16]`` - - + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Intra Cb, Intra Cr, Inter Y, + Inter Cb, Inter Cr. * - __u8 - ``scaling_list_8x8[6][64]`` - - + - Scaling matrix after applying the inverse scanning process. + Expected list order is Intra Y, Inter Y, Intra Cb, Inter Cb, + Intra Cr, Inter Cr. ``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)`` Specifies the slice parameters (as extracted from the bitstream) @@ -1796,7 +1800,7 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - * - __u32 - ``dec_ref_pic_marking_bit_size`` - - + - Size in bits of the dec_ref_pic_marking() syntax element. * - __u32 - ``pic_order_cnt_bit_size`` - @@ -1820,10 +1824,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - * - __u8 - ``num_ref_idx_l0_active_minus1`` - - + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l0_default_active_minus1. * - __u8 - ``num_ref_idx_l1_active_minus1`` - - + - If num_ref_idx_active_override_flag is not set, this field must be + set to the value of num_ref_idx_l1_default_active_minus1. * - __u32 - ``slice_group_change_cycle`` - @@ -1983,9 +1989,9 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - ``reference_ts`` - Timestamp of the V4L2 capture buffer to use as reference, used with B-coded and P-coded frames. The timestamp refers to the - ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the - :c:func:`v4l2_timeval_to_ns()` function to convert the struct - :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. * - __u16 - ``frame_num`` - @@ -3693,3 +3699,550 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - Indicates whether to generate SPS and PPS at every IDR. Setting it to 0 disables generating SPS and PPS at every IDR. Setting it to one enables generating SPS and PPS at every IDR. + +.. _v4l2-mpeg-hevc: + +``V4L2_CID_MPEG_VIDEO_HEVC_SPS (struct)`` + Specifies the Sequence Parameter Set fields (as extracted from the + bitstream) for the associated HEVC slice data. + These bitstream parameters are defined according to :ref:`hevc`. + They are described in section 7.4.3.2 "Sequence parameter set RBSP + semantics" of the specification. + +.. c:type:: v4l2_ctrl_hevc_sps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_hevc_sps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u16 + - ``pic_width_in_luma_samples`` + - + * - __u16 + - ``pic_height_in_luma_samples`` + - + * - __u8 + - ``bit_depth_luma_minus8`` + - + * - __u8 + - ``bit_depth_chroma_minus8`` + - + * - __u8 + - ``log2_max_pic_order_cnt_lsb_minus4`` + - + * - __u8 + - ``sps_max_dec_pic_buffering_minus1`` + - + * - __u8 + - ``sps_max_num_reorder_pics`` + - + * - __u8 + - ``sps_max_latency_increase_plus1`` + - + * - __u8 + - ``log2_min_luma_coding_block_size_minus3`` + - + * - __u8 + - ``log2_diff_max_min_luma_coding_block_size`` + - + * - __u8 + - ``log2_min_luma_transform_block_size_minus2`` + - + * - __u8 + - ``log2_diff_max_min_luma_transform_block_size`` + - + * - __u8 + - ``max_transform_hierarchy_depth_inter`` + - + * - __u8 + - ``max_transform_hierarchy_depth_intra`` + - + * - __u8 + - ``pcm_sample_bit_depth_luma_minus1`` + - + * - __u8 + - ``pcm_sample_bit_depth_chroma_minus1`` + - + * - __u8 + - ``log2_min_pcm_luma_coding_block_size_minus3`` + - + * - __u8 + - ``log2_diff_max_min_pcm_luma_coding_block_size`` + - + * - __u8 + - ``num_short_term_ref_pic_sets`` + - + * - __u8 + - ``num_long_term_ref_pics_sps`` + - + * - __u8 + - ``chroma_format_idc`` + - + * - __u64 + - ``flags`` + - See :ref:`Sequence Parameter Set Flags <hevc_sps_flags>` + +.. _hevc_sps_flags: + +``Sequence Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE`` + - 0x00000001 + - + * - ``V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED`` + - 0x00000002 + - + * - ``V4L2_HEVC_SPS_FLAG_AMP_ENABLED`` + - 0x00000004 + - + * - ``V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET`` + - 0x00000008 + - + * - ``V4L2_HEVC_SPS_FLAG_PCM_ENABLED`` + - 0x00000010 + - + * - ``V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED`` + - 0x00000020 + - + * - ``V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT`` + - 0x00000040 + - + * - ``V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED`` + - 0x00000080 + - + * - ``V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED`` + - 0x00000100 + - + +``V4L2_CID_MPEG_VIDEO_HEVC_PPS (struct)`` + Specifies the Picture Parameter Set fields (as extracted from the + bitstream) for the associated HEVC slice data. + These bitstream parameters are defined according to :ref:`hevc`. + They are described in section 7.4.3.3 "Picture parameter set RBSP + semantics" of the specification. + +.. c:type:: v4l2_ctrl_hevc_pps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_hevc_pps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``num_extra_slice_header_bits`` + - + * - __s8 + - ``init_qp_minus26`` + - + * - __u8 + - ``diff_cu_qp_delta_depth`` + - + * - __s8 + - ``pps_cb_qp_offset`` + - + * - __s8 + - ``pps_cr_qp_offset`` + - + * - __u8 + - ``num_tile_columns_minus1`` + - + * - __u8 + - ``num_tile_rows_minus1`` + - + * - __u8 + - ``column_width_minus1[20]`` + - + * - __u8 + - ``row_height_minus1[22]`` + - + * - __s8 + - ``pps_beta_offset_div2`` + - + * - __s8 + - ``pps_tc_offset_div2`` + - + * - __u8 + - ``log2_parallel_merge_level_minus2`` + - + * - __u8 + - ``padding[4]`` + - Applications and drivers must set this to zero. + * - __u64 + - ``flags`` + - See :ref:`Picture Parameter Set Flags <hevc_pps_flags>` + +.. _hevc_pps_flags: + +``Picture Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT`` + - 0x00000001 + - + * - ``V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT`` + - 0x00000002 + - + * - ``V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED`` + - 0x00000004 + - + * - ``V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT`` + - 0x00000008 + - + * - ``V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED`` + - 0x00000010 + - + * - ``V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED`` + - 0x00000020 + - + * - ``V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED`` + - 0x00000040 + - + * - ``V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT`` + - 0x00000080 + - + * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED`` + - 0x00000100 + - + * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED`` + - 0x00000200 + - + * - ``V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED`` + - 0x00000400 + - + * - ``V4L2_HEVC_PPS_FLAG_TILES_ENABLED`` + - 0x00000800 + - + * - ``V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED`` + - 0x00001000 + - + * - ``V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED`` + - 0x00002000 + - + * - ``V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED`` + - 0x00004000 + - + * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED`` + - 0x00008000 + - + * - ``V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER`` + - 0x00010000 + - + * - ``V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT`` + - 0x00020000 + - + * - ``V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT`` + - 0x00040000 + - + +``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (struct)`` + Specifies various slice-specific parameters, especially from the NAL unit + header, general slice segment header and weighted prediction parameter + parts of the bitstream. + These bitstream parameters are defined according to :ref:`hevc`. + They are described in section 7.4.7 "General slice segment header + semantics" of the specification. + +.. c:type:: v4l2_ctrl_hevc_slice_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_hevc_slice_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``bit_size`` + - Size (in bits) of the current slice data. + * - __u32 + - ``data_bit_offset`` + - Offset (in bits) to the video data in the current slice data. + * - __u8 + - ``nal_unit_type`` + - + * - __u8 + - ``nuh_temporal_id_plus1`` + - + * - __u8 + - ``slice_type`` + - + (V4L2_HEVC_SLICE_TYPE_I, V4L2_HEVC_SLICE_TYPE_P or + V4L2_HEVC_SLICE_TYPE_B). + * - __u8 + - ``colour_plane_id`` + - + * - __u16 + - ``slice_pic_order_cnt`` + - + * - __u8 + - ``num_ref_idx_l0_active_minus1`` + - + * - __u8 + - ``num_ref_idx_l1_active_minus1`` + - + * - __u8 + - ``collocated_ref_idx`` + - + * - __u8 + - ``five_minus_max_num_merge_cand`` + - + * - __s8 + - ``slice_qp_delta`` + - + * - __s8 + - ``slice_cb_qp_offset`` + - + * - __s8 + - ``slice_cr_qp_offset`` + - + * - __s8 + - ``slice_act_y_qp_offset`` + - + * - __s8 + - ``slice_act_cb_qp_offset`` + - + * - __s8 + - ``slice_act_cr_qp_offset`` + - + * - __s8 + - ``slice_beta_offset_div2`` + - + * - __s8 + - ``slice_tc_offset_div2`` + - + * - __u8 + - ``pic_struct`` + - + * - __u8 + - ``num_active_dpb_entries`` + - The number of entries in ``dpb``. + * - __u8 + - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - The list of L0 reference elements as indices in the DPB. + * - __u8 + - ``ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - The list of L1 reference elements as indices in the DPB. + * - __u8 + - ``num_rps_poc_st_curr_before`` + - The number of reference pictures in the short-term set that come before + the current frame. + * - __u8 + - ``num_rps_poc_st_curr_after`` + - The number of reference pictures in the short-term set that come after + the current frame. + * - __u8 + - ``num_rps_poc_lt_curr`` + - The number of reference pictures in the long-term set. + * - __u8 + - ``padding[7]`` + - Applications and drivers must set this to zero. + * - struct :c:type:`v4l2_hevc_dpb_entry` + - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - The decoded picture buffer, for meta-data about reference frames. + * - struct :c:type:`v4l2_hevc_pred_weight_table` + - ``pred_weight_table`` + - The prediction weight coefficients for inter-picture prediction. + * - __u64 + - ``flags`` + - See :ref:`Slice Parameters Flags <hevc_slice_params_flags>` + +.. _hevc_slice_params_flags: + +``Slice Parameters Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA`` + - 0x00000001 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA`` + - 0x00000002 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED`` + - 0x00000004 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO`` + - 0x00000008 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT`` + - 0x00000010 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0`` + - 0x00000020 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV`` + - 0x00000040 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED`` + - 0x00000080 + - + * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED`` + - 0x00000100 + - + +.. c:type:: v4l2_hevc_dpb_entry + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_hevc_dpb_entry + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``timestamp`` + - Timestamp of the V4L2 capture buffer to use as reference, used + with B-coded and P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u8 + - ``rps`` + - The reference set for the reference frame + (V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE, + V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER or + V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + * - __u8 + - ``field_pic`` + - Whether the reference is a field picture or a frame. + * - __u16 + - ``pic_order_cnt[2]`` + - The picture order count of the reference. Only the first element of the + array is used for frame pictures, while the first element identifies the + top field and the second the bottom field in field-coded pictures. + * - __u8 + - ``padding[2]`` + - Applications and drivers must set this to zero. + +.. c:type:: v4l2_hevc_pred_weight_table + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_hevc_pred_weight_table + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``luma_log2_weight_denom`` + - + * - __s8 + - ``delta_chroma_log2_weight_denom`` + - + * - __s8 + - ``delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - + * - __s8 + - ``luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - + * - __s8 + - ``delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]`` + - + * - __s8 + - ``chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]`` + - + * - __s8 + - ``delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - + * - __s8 + - ``luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` + - + * - __s8 + - ``delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]`` + - + * - __s8 + - ``chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]`` + - + * - __u8 + - ``padding[6]`` + - Applications and drivers must set this to zero. + +``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)`` + Specifies the decoding mode to use. Currently exposes slice-based and + frame-based decoding but new modes might be added later on. + This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE + pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE + are required to set this control in order to specify the decoding mode + that is expected for the buffer. + Drivers may expose a single or multiple decoding modes, depending + on what they can support. + + .. note:: + + This menu control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_mpeg_video_hevc_decode_mode + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED`` + - 0 + - Decoding is done at the slice granularity. + The OUTPUT buffer must contain a single slice. + * - ``V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED`` + - 1 + - Decoding is done at the frame granularity. + The OUTPUT buffer must contain all slices needed to decode the + frame. The OUTPUT buffer must also contain both fields. + +``V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (enum)`` + Specifies the HEVC slice start code expected for each slice. + This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE + pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE + are required to set this control in order to specify the start code + that is expected for the buffer. + Drivers may expose a single or multiple start codes, depending + on what they can support. + + .. note:: + + This menu control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_mpeg_video_hevc_start_code + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE`` + - 0 + - Selecting this value specifies that HEVC slices are passed + to the driver without any start code. + * - ``V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B`` + - 1 + - Selecting this value specifies that HEVC slices are expected + to be prefixed by Annex B start codes. According to :ref:`hevc` + valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001. diff --git a/Documentation/media/uapi/v4l/ext-ctrls-flash.rst b/Documentation/media/uapi/v4l/ext-ctrls-flash.rst index eff056b17167..b9a6b08fbf32 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-flash.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-flash.rst @@ -98,7 +98,7 @@ Flash Control IDs V4L2_CID_FLASH_STROBE control. * - ``V4L2_FLASH_STROBE_SOURCE_EXTERNAL`` - The flash strobe is triggered by an external source. Typically - this is a sensor, which makes it possible to synchronises the + this is a sensor, which makes it possible to synchronise the flash strobe start to exposure start. diff --git a/Documentation/media/uapi/v4l/ext-ctrls-image-source.rst b/Documentation/media/uapi/v4l/ext-ctrls-image-source.rst index 2c3ab5796d76..2d3e2b83d6dd 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-image-source.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-image-source.rst @@ -55,3 +55,13 @@ Image Source Control IDs ``V4L2_CID_TEST_PATTERN_GREENB (integer)`` Test pattern green (next to blue) colour component. + +``V4L2_CID_UNIT_CELL_SIZE (struct)`` + This control returns the unit cell size in nanometers. The struct + :c:type:`v4l2_area` provides the width and the height in separate + fields to take into consideration asymmetric pixels. + This control does not take into consideration any possible hardware + binning. + The unit cell consists of the whole area of the pixel, sensitive and + non-sensitive. + This control is required for automatic calibration of sensors/cameras. diff --git a/Documentation/media/uapi/v4l/meta-formats.rst b/Documentation/media/uapi/v4l/meta-formats.rst index b10ca9ee3968..74c8659ee9d6 100644 --- a/Documentation/media/uapi/v4l/meta-formats.rst +++ b/Documentation/media/uapi/v4l/meta-formats.rst @@ -24,3 +24,4 @@ These formats are used for the :ref:`metadata` interface only. pixfmt-meta-uvc pixfmt-meta-vsp1-hgo pixfmt-meta-vsp1-hgt + pixfmt-meta-vivid diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst index 292fdc116c77..561bda112809 100644 --- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst +++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -61,10 +61,10 @@ Compressed Formats - ``V4L2_PIX_FMT_H264_SLICE`` - 'S264' - - H264 parsed slice data, without the start code and as - extracted from the H264 bitstream. This format is adapted for - stateless video decoders that implement an H264 pipeline - (using the :ref:`mem2mem` and :ref:`media-request-api`). + - H264 parsed slice data, including slice headers, either with or + without the start code, as extracted from the H264 bitstream. + This format is adapted for stateless video decoders that implement an + H264 pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). This pixelformat has two modifiers that must be set at least once through the ``V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE`` and ``V4L2_CID_MPEG_VIDEO_H264_START_CODE`` controls. @@ -80,6 +80,10 @@ Compressed Formats appropriate number of macroblocks to decode a full corresponding frame to the matching capture buffer. + The syntax for this format is documented in :ref:`h264`, section + 7.3.2.8 "Slice layer without partitioning RBSP syntax" and the following + sections. + .. note:: This format is not yet part of the public kernel API and it @@ -188,6 +192,29 @@ Compressed Formats If :ref:`VIDIOC_ENUM_FMT` reports ``V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM`` then the decoder has no requirements since it can parse all the information from the raw bytestream. + * .. _V4L2-PIX-FMT-HEVC-SLICE: + + - ``V4L2_PIX_FMT_HEVC_SLICE`` + - 'S265' + - HEVC parsed slice data, as extracted from the HEVC bitstream. + This format is adapted for stateless video decoders that implement a + HEVC pipeline (using the :ref:`mem2mem` and :ref:`media-request-api`). + This pixelformat has two modifiers that must be set at least once + through the ``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE`` + and ``V4L2_CID_MPEG_VIDEO_HEVC_START_CODE`` controls. + Metadata associated with the frame to decode is required to be passed + through the following controls : + * ``V4L2_CID_MPEG_VIDEO_HEVC_SPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_PPS`` + * ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS`` + See the :ref:`associated Codec Control IDs <v4l2-mpeg-hevc>`. + Buffers associated with this pixel format must contain the appropriate + number of macroblocks to decode a full corresponding frame. + + .. note:: + + This format is not yet part of the public kernel API and it + is expected to change. * .. _V4L2-PIX-FMT-FWHT: - ``V4L2_PIX_FMT_FWHT`` diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-vivid.rst b/Documentation/media/uapi/v4l/pixfmt-meta-vivid.rst new file mode 100644 index 000000000000..eed20eaefe24 --- /dev/null +++ b/Documentation/media/uapi/v4l/pixfmt-meta-vivid.rst @@ -0,0 +1,60 @@ +.. This file is dual-licensed: you can use it either under the terms +.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this +.. dual licensing only applies to this file, and not this project as a +.. whole. +.. +.. a) This file is free software; you can redistribute it and/or +.. modify it under the terms of the GNU General Public License as +.. published by the Free Software Foundation version 2 of +.. the License. +.. +.. This file is distributed in the hope that it will be useful, +.. but WITHOUT ANY WARRANTY; without even the implied warranty of +.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.. GNU General Public License for more details. +.. +.. Or, alternatively, +.. +.. b) Permission is granted to copy, distribute and/or modify this +.. document under the terms of the GNU Free Documentation License, +.. Version 1.1 or any later version published by the Free Software +.. Foundation, with no Invariant Sections, no Front-Cover Texts +.. and no Back-Cover Texts. A copy of the license is included at +.. Documentation/media/uapi/fdl-appendix.rst. +.. +.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections + +.. _v4l2-meta-fmt-vivid: + +******************************* +V4L2_META_FMT_VIVID ('VIVD') +******************************* + +VIVID Metadata Format + + +Description +=========== + +This describes metadata format used by the vivid driver. + +It sets Brightness, Saturation, Contrast and Hue, each of which maps to +corresponding controls of the vivid driver with respect to the range and default values. + +It contains the following fields: + +.. flat-table:: VIVID Metadata + :widths: 1 4 + :header-rows: 1 + :stub-columns: 0 + + * - Field + - Description + * - u16 brightness; + - Image brightness, the value is in the range 0 to 255, with the default value as 128. + * - u16 contrast; + - Image contrast, the value is in the range 0 to 255, with the default value as 128. + * - u16 saturation; + - Image color saturation, the value is in the range 0 to 255, with the default value as 128. + * - s16 hue; + - Image color balance, the value is in the range -128 to 128, with the default value as 0. diff --git a/Documentation/media/uapi/v4l/v4l2-selection-targets.rst b/Documentation/media/uapi/v4l/v4l2-selection-targets.rst index f74f239b0510..aae0c0013eb1 100644 --- a/Documentation/media/uapi/v4l/v4l2-selection-targets.rst +++ b/Documentation/media/uapi/v4l/v4l2-selection-targets.rst @@ -38,8 +38,10 @@ of the two interfaces they are used. * - ``V4L2_SEL_TGT_CROP_DEFAULT`` - 0x0001 - Suggested cropping rectangle that covers the "whole picture". + This includes only active pixels and excludes other non-active + pixels such as black pixels. + - Yes - Yes - - No * - ``V4L2_SEL_TGT_CROP_BOUNDS`` - 0x0002 - Bounds of the crop rectangle. All valid crop rectangles fit inside diff --git a/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst b/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst index 57f0066f4cff..f1a504836f31 100644 --- a/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst +++ b/Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst @@ -208,7 +208,15 @@ introduced in Linux 3.3. They are, however, mandatory for stateful mem2mem decod been started yet, the driver will return an ``EPERM`` error code. When the decoder is already running, this command does nothing. No flags are defined for this command. - + * - ``V4L2_DEC_CMD_FLUSH`` + - 4 + - Flush any held capture buffers. Only valid for stateless decoders. + This command is typically used when the application reached the + end of the stream and the last output buffer had the + ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag set. This would prevent + dequeueing the capture buffer containing the last decoded frame. + So this command can be used to explicitly flush that final decoded + frame. This command does nothing if there are no held capture buffers. Return Value ============ diff --git a/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst b/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst index 13dc1a986249..271cac18afbb 100644 --- a/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst +++ b/Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst @@ -199,6 +199,11 @@ still cause this situation. - A pointer to a matrix control of unsigned 32-bit values. Valid if this control is of type ``V4L2_CTRL_TYPE_U32``. * - + - :c:type:`v4l2_area` * + - ``p_area`` + - A pointer to a struct :c:type:`v4l2_area`. Valid if this control is + of type ``V4L2_CTRL_TYPE_AREA``. + * - - void * - ``ptr`` - A pointer to a compound type which can be an N-dimensional array diff --git a/Documentation/media/uapi/v4l/vidioc-g-fbuf.rst b/Documentation/media/uapi/v4l/vidioc-g-fbuf.rst index 7b6179627803..2d197e6bba8f 100644 --- a/Documentation/media/uapi/v4l/vidioc-g-fbuf.rst +++ b/Documentation/media/uapi/v4l/vidioc-g-fbuf.rst @@ -63,7 +63,7 @@ EINVAL error code when overlays are not supported. To set the parameters for a *Video Output Overlay*, applications must initialize the ``flags`` field of a struct -struct :c:type:`v4l2_framebuffer`. Since the framebuffer is +:c:type:`v4l2_framebuffer`. Since the framebuffer is implemented on the TV card all other parameters are determined by the driver. When an application calls :ref:`VIDIOC_S_FBUF <VIDIOC_G_FBUF>` with a pointer to this structure, the driver prepares for the overlay and returns the diff --git a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst index a3d56ffbf4cc..6690928e657b 100644 --- a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst +++ b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst @@ -443,6 +443,12 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_mpeg2_quantization`, containing MPEG-2 quantization matrices for stateless video decoders. + * - ``V4L2_CTRL_TYPE_AREA`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_area`, containing the width and the height + of a rectangular area. Units depend on the use case. * - ``V4L2_CTRL_TYPE_H264_SPS`` - n/a - n/a @@ -473,6 +479,24 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_h264_decode_params`, containing H264 decode parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_HEVC_SPS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_hevc_sps`, containing HEVC Sequence + Parameter Set for stateless video decoders. + * - ``V4L2_CTRL_TYPE_HEVC_PPS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_hevc_pps`, containing HEVC Picture + Parameter Set for stateless video decoders. + * - ``V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_hevc_slice_params`, containing HEVC + slice parameters for stateless video decoders. .. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| diff --git a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst index d7faef10e39b..d0c643db477a 100644 --- a/Documentation/media/uapi/v4l/vidioc-reqbufs.rst +++ b/Documentation/media/uapi/v4l/vidioc-reqbufs.rst @@ -125,6 +125,7 @@ aborting or finishing any DMA in progress, an implicit .. _V4L2-BUF-CAP-SUPPORTS-DMABUF: .. _V4L2-BUF-CAP-SUPPORTS-REQUESTS: .. _V4L2-BUF-CAP-SUPPORTS-ORPHANED-BUFS: +.. _V4L2-BUF-CAP-SUPPORTS-M2M-HOLD-CAPTURE-BUF: .. cssclass:: longtable @@ -150,6 +151,11 @@ aborting or finishing any DMA in progress, an implicit - The kernel allows calling :ref:`VIDIOC_REQBUFS` while buffers are still mapped or exported via DMABUF. These orphaned buffers will be freed when they are unmapped or when the exported DMABUF fds are closed. + * - ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` + - 0x00000020 + - Only valid for stateless decoders. If set, then userspace can set the + ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` flag to hold off on returning the + capture buffer until the OUTPUT timestamp changes. Return Value ============ diff --git a/Documentation/media/v4l-drivers/imx.rst b/Documentation/media/v4l-drivers/imx.rst index 1d7eb8c7bd5c..1246573c1019 100644 --- a/Documentation/media/v4l-drivers/imx.rst +++ b/Documentation/media/v4l-drivers/imx.rst @@ -515,10 +515,10 @@ Streaming can then begin independently on the capture device nodes be used to select any supported YUV pixelformat on the capture device nodes, including planar. -SabreAuto with ADV7180 decoder ------------------------------- +i.MX6Q SabreAuto with ADV7180 decoder +------------------------------------- -On the SabreAuto, an on-board ADV7180 SD decoder is connected to the +On the i.MX6Q SabreAuto, an on-board ADV7180 SD decoder is connected to the parallel bus input on the internal video mux to IPU1 CSI0. The following example configures a pipeline to capture from the ADV7180 @@ -547,8 +547,6 @@ This example configures a pipeline to capture from the ADV7180 video decoder, assuming PAL 720x576 input signals, with Motion Compensated de-interlacing. The adv7180 must output sequential or alternating fields (field type 'seq-tb' for PAL, or 'alternate'). -$outputfmt can be any format supported by the ipu1_ic_prpvf entity -at its output pad: .. code-block:: none @@ -565,11 +563,70 @@ at its output pad: media-ctl -V "'ipu1_csi0':1 [fmt:AYUV32/720x576]" media-ctl -V "'ipu1_vdic':2 [fmt:AYUV32/720x576 field:none]" media-ctl -V "'ipu1_ic_prp':2 [fmt:AYUV32/720x576 field:none]" - media-ctl -V "'ipu1_ic_prpvf':1 [fmt:$outputfmt field:none]" + media-ctl -V "'ipu1_ic_prpvf':1 [fmt:AYUV32/720x576 field:none]" + # Configure "ipu1_ic_prpvf capture" interface (assumed at /dev/video2) + v4l2-ctl -d2 --set-fmt-video=field=none + +Streaming can then begin on /dev/video2. The v4l2-ctl tool can also be +used to select any supported YUV pixelformat on /dev/video2. + +This platform accepts Composite Video analog inputs to the ADV7180 on +Ain1 (connector J42). + +i.MX6DL SabreAuto with ADV7180 decoder +-------------------------------------- + +On the i.MX6DL SabreAuto, an on-board ADV7180 SD decoder is connected to the +parallel bus input on the internal video mux to IPU1 CSI0. + +The following example configures a pipeline to capture from the ADV7180 +video decoder, assuming NTSC 720x480 input signals, using simple +interweave (unconverted and without motion compensation). The adv7180 +must output sequential or alternating fields (field type 'seq-bt' for +NTSC, or 'alternate'): + +.. code-block:: none + + # Setup links + media-ctl -l "'adv7180 4-0021':0 -> 'ipu1_csi0_mux':4[1]" + media-ctl -l "'ipu1_csi0_mux':5 -> 'ipu1_csi0':0[1]" + media-ctl -l "'ipu1_csi0':2 -> 'ipu1_csi0 capture':0[1]" + # Configure pads + media-ctl -V "'adv7180 4-0021':0 [fmt:UYVY2X8/720x480 field:seq-bt]" + media-ctl -V "'ipu1_csi0_mux':5 [fmt:UYVY2X8/720x480]" + media-ctl -V "'ipu1_csi0':2 [fmt:AYUV32/720x480]" + # Configure "ipu1_csi0 capture" interface (assumed at /dev/video0) + v4l2-ctl -d0 --set-fmt-video=field=interlaced_bt + +Streaming can then begin on /dev/video0. The v4l2-ctl tool can also be +used to select any supported YUV pixelformat on /dev/video0. + +This example configures a pipeline to capture from the ADV7180 +video decoder, assuming PAL 720x576 input signals, with Motion +Compensated de-interlacing. The adv7180 must output sequential or +alternating fields (field type 'seq-tb' for PAL, or 'alternate'). + +.. code-block:: none + + # Setup links + media-ctl -l "'adv7180 4-0021':0 -> 'ipu1_csi0_mux':4[1]" + media-ctl -l "'ipu1_csi0_mux':5 -> 'ipu1_csi0':0[1]" + media-ctl -l "'ipu1_csi0':1 -> 'ipu1_vdic':0[1]" + media-ctl -l "'ipu1_vdic':2 -> 'ipu1_ic_prp':0[1]" + media-ctl -l "'ipu1_ic_prp':2 -> 'ipu1_ic_prpvf':0[1]" + media-ctl -l "'ipu1_ic_prpvf':1 -> 'ipu1_ic_prpvf capture':0[1]" + # Configure pads + media-ctl -V "'adv7180 4-0021':0 [fmt:UYVY2X8/720x576 field:seq-tb]" + media-ctl -V "'ipu1_csi0_mux':5 [fmt:UYVY2X8/720x576]" + media-ctl -V "'ipu1_csi0':1 [fmt:AYUV32/720x576]" + media-ctl -V "'ipu1_vdic':2 [fmt:AYUV32/720x576 field:none]" + media-ctl -V "'ipu1_ic_prp':2 [fmt:AYUV32/720x576 field:none]" + media-ctl -V "'ipu1_ic_prpvf':1 [fmt:AYUV32/720x576 field:none]" + # Configure "ipu1_ic_prpvf capture" interface (assumed at /dev/video2) + v4l2-ctl -d2 --set-fmt-video=field=none -Streaming can then begin on the capture device node at -"ipu1_ic_prpvf capture". The v4l2-ctl tool can be used to select any -supported YUV or RGB pixelformat on the capture device node. +Streaming can then begin on /dev/video2. The v4l2-ctl tool can also be +used to select any supported YUV pixelformat on /dev/video2. This platform accepts Composite Video analog inputs to the ADV7180 on Ain1 (connector J42). diff --git a/Documentation/media/v4l-drivers/ipu3.rst b/Documentation/media/v4l-drivers/ipu3.rst index c9f780404eee..e4904ab44e60 100644 --- a/Documentation/media/v4l-drivers/ipu3.rst +++ b/Documentation/media/v4l-drivers/ipu3.rst @@ -265,19 +265,56 @@ below. yavta -w "0x009819A1 1" /dev/v4l-subdev7 -RAW Bayer frames go through the following ImgU pipeline HW blocks to have the +Certain hardware blocks in ImgU pipeline can change the frame resolution by +cropping or scaling, these hardware blocks include Input Feeder(IF), Bayer Down +Scaler (BDS) and Geometric Distortion Correction (GDC). +There is also a block which can change the frame resolution - YUV Scaler, it is +only applicable to the secondary output. + +RAW Bayer frames go through these ImgU pipeline hardware blocks and the final processed image output to the DDR memory. -RAW Bayer frame -> Input Feeder -> Bayer Down Scaling (BDS) -> Geometric -Distortion Correction (GDC) -> DDR +.. kernel-figure:: ipu3_rcb.svg + :alt: ipu3 resolution blocks image -The ImgU V4L2 subdev has to be configured with the supported resolutions in all -the above HW blocks, for a given input resolution. + IPU3 resolution change hardware blocks + +**Input Feeder** + +Input Feeder gets the Bayer frame data from the sensor, it can enable cropping +of lines and columns from the frame and then store pixels into device's internal +pixel buffer which are ready to readout by following blocks. + +**Bayer Down Scaler** + +Bayer Down Scaler is capable of performing image scaling in Bayer domain, the +downscale factor can be configured from 1X to 1/4X in each axis with +configuration steps of 0.03125 (1/32). +**Geometric Distortion Correction** + +Geometric Distortion Correction is used to performe correction of distortions +and image filtering. It needs some extra filter and envelop padding pixels to +work, so the input resolution of GDC should be larger than the output +resolution. + +**YUV Scaler** + +YUV Scaler which similar with BDS, but it is mainly do image down scaling in +YUV domain, it can support up to 1/12X down scaling, but it can not be applied +to the main output. + +The ImgU V4L2 subdev has to be configured with the supported resolutions in all +the above hardware blocks, for a given input resolution. For a given supported resolution for an input frame, the Input Feeder, Bayer -Down Scaling and GDC blocks should be configured with the supported resolutions. -This information can be obtained by looking at the following IPU3 ImgU -configuration table. +Down Scaler and GDC blocks should be configured with the supported resolutions +as each hardware block has its own alignment requirement. + +You must configure the output resolution of the hardware blocks smartly to meet +the hardware requirement along with keeping the maximum field of view. +The intermediate resolutions can be generated by specific tool and this +information can be obtained by looking at the following IPU3 ImgU configuration +table. https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/master diff --git a/Documentation/media/v4l-drivers/ipu3_rcb.svg b/Documentation/media/v4l-drivers/ipu3_rcb.svg new file mode 100644 index 000000000000..d878421b42a0 --- /dev/null +++ b/Documentation/media/v4l-drivers/ipu3_rcb.svg @@ -0,0 +1,331 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="774pt" height="152pt" viewBox="0 0 774 152" version="1.1"> +<defs> +<g> +<symbol overflow="visible" id="glyph0-0"> +<path style="stroke:none;" d="M 1 0 L 1 -15 L 9 -15 L 9 0 Z M 8 -1 L 8 -14 L 2 -14 L 2 -1 Z M 8 -1 "/> +</symbol> +<symbol overflow="visible" id="glyph0-1"> +<path style="stroke:none;" d="M 4.6875 -1.15625 C 5.519531 -1.15625 6.15625 -1.316406 6.59375 -1.640625 C 7.039062 -1.960938 7.265625 -2.441406 7.265625 -3.078125 C 7.265625 -3.460938 7.179688 -3.789062 7.015625 -4.0625 C 6.859375 -4.34375 6.644531 -4.582031 6.375 -4.78125 C 6.113281 -4.988281 5.816406 -5.171875 5.484375 -5.328125 C 5.148438 -5.484375 4.804688 -5.628906 4.453125 -5.765625 C 4.054688 -5.921875 3.675781 -6.097656 3.3125 -6.296875 C 2.945312 -6.492188 2.617188 -6.726562 2.328125 -7 C 2.046875 -7.269531 1.820312 -7.582031 1.65625 -7.9375 C 1.488281 -8.300781 1.40625 -8.726562 1.40625 -9.21875 C 1.40625 -10.300781 1.742188 -11.144531 2.421875 -11.75 C 3.097656 -12.351562 4.046875 -12.65625 5.265625 -12.65625 C 5.597656 -12.65625 5.925781 -12.628906 6.25 -12.578125 C 6.570312 -12.535156 6.875 -12.476562 7.15625 -12.40625 C 7.4375 -12.34375 7.6875 -12.265625 7.90625 -12.171875 C 8.125 -12.085938 8.300781 -12 8.4375 -11.90625 L 7.921875 -10.515625 C 7.648438 -10.679688 7.28125 -10.84375 6.8125 -11 C 6.351562 -11.15625 5.835938 -11.234375 5.265625 -11.234375 C 4.660156 -11.234375 4.140625 -11.082031 3.703125 -10.78125 C 3.265625 -10.488281 3.046875 -10.039062 3.046875 -9.4375 C 3.046875 -9.09375 3.109375 -8.800781 3.234375 -8.5625 C 3.359375 -8.320312 3.53125 -8.109375 3.75 -7.921875 C 3.96875 -7.742188 4.222656 -7.582031 4.515625 -7.4375 C 4.804688 -7.289062 5.128906 -7.144531 5.484375 -7 C 5.984375 -6.789062 6.441406 -6.578125 6.859375 -6.359375 C 7.285156 -6.148438 7.648438 -5.894531 7.953125 -5.59375 C 8.253906 -5.300781 8.488281 -4.953125 8.65625 -4.546875 C 8.820312 -4.148438 8.90625 -3.664062 8.90625 -3.09375 C 8.90625 -2.019531 8.539062 -1.191406 7.8125 -0.609375 C 7.082031 -0.0234375 6.039062 0.265625 4.6875 0.265625 C 4.238281 0.265625 3.820312 0.234375 3.4375 0.171875 C 3.050781 0.109375 2.707031 0.03125 2.40625 -0.0625 C 2.101562 -0.15625 1.835938 -0.25 1.609375 -0.34375 C 1.390625 -0.4375 1.21875 -0.519531 1.09375 -0.59375 L 1.59375 -1.953125 C 1.863281 -1.804688 2.257812 -1.632812 2.78125 -1.4375 C 3.300781 -1.25 3.9375 -1.15625 4.6875 -1.15625 Z M 4.6875 -1.15625 "/> +</symbol> +<symbol overflow="visible" id="glyph0-2"> +<path style="stroke:none;" d="M 5.1875 -9.5 C 6.4375 -9.5 7.398438 -9.109375 8.078125 -8.328125 C 8.753906 -7.546875 9.09375 -6.363281 9.09375 -4.78125 L 9.09375 -4.203125 L 2.453125 -4.203125 C 2.523438 -3.242188 2.84375 -2.515625 3.40625 -2.015625 C 3.976562 -1.515625 4.773438 -1.265625 5.796875 -1.265625 C 6.390625 -1.265625 6.890625 -1.3125 7.296875 -1.40625 C 7.710938 -1.5 8.023438 -1.597656 8.234375 -1.703125 L 8.453125 -0.296875 C 8.253906 -0.191406 7.894531 -0.0820312 7.375 0.03125 C 6.851562 0.15625 6.269531 0.21875 5.625 0.21875 C 4.820312 0.21875 4.113281 0.0976562 3.5 -0.140625 C 2.894531 -0.390625 2.394531 -0.726562 2 -1.15625 C 1.601562 -1.582031 1.300781 -2.09375 1.09375 -2.6875 C 0.894531 -3.28125 0.796875 -3.925781 0.796875 -4.625 C 0.796875 -5.445312 0.921875 -6.164062 1.171875 -6.78125 C 1.429688 -7.394531 1.765625 -7.898438 2.171875 -8.296875 C 2.585938 -8.703125 3.054688 -9.003906 3.578125 -9.203125 C 4.097656 -9.398438 4.632812 -9.5 5.1875 -9.5 Z M 7.421875 -5.546875 C 7.421875 -6.328125 7.210938 -6.945312 6.796875 -7.40625 C 6.390625 -7.863281 5.84375 -8.09375 5.15625 -8.09375 C 4.769531 -8.09375 4.421875 -8.019531 4.109375 -7.875 C 3.796875 -7.726562 3.523438 -7.535156 3.296875 -7.296875 C 3.066406 -7.054688 2.882812 -6.78125 2.75 -6.46875 C 2.625 -6.164062 2.539062 -5.859375 2.5 -5.546875 Z M 7.421875 -5.546875 "/> +</symbol> +<symbol overflow="visible" id="glyph0-3"> +<path style="stroke:none;" d="M 1.421875 -9.015625 C 2.015625 -9.160156 2.609375 -9.273438 3.203125 -9.359375 C 3.796875 -9.441406 4.351562 -9.484375 4.875 -9.484375 C 6.113281 -9.484375 7.050781 -9.160156 7.6875 -8.515625 C 8.320312 -7.878906 8.640625 -6.851562 8.640625 -5.4375 L 8.640625 0 L 7 0 L 7 -5.140625 C 7 -5.742188 6.945312 -6.226562 6.84375 -6.59375 C 6.738281 -6.96875 6.585938 -7.257812 6.390625 -7.46875 C 6.191406 -7.675781 5.957031 -7.816406 5.6875 -7.890625 C 5.414062 -7.972656 5.117188 -8.015625 4.796875 -8.015625 C 4.535156 -8.015625 4.253906 -8 3.953125 -7.96875 C 3.648438 -7.9375 3.359375 -7.894531 3.078125 -7.84375 L 3.078125 0 L 1.421875 0 Z M 1.421875 -9.015625 "/> +</symbol> +<symbol overflow="visible" id="glyph0-4"> +<path style="stroke:none;" d="M 7.015625 -2.3125 C 7.015625 -2.644531 6.878906 -2.914062 6.609375 -3.125 C 6.335938 -3.34375 6 -3.53125 5.59375 -3.6875 C 5.1875 -3.851562 4.742188 -4.015625 4.265625 -4.171875 C 3.785156 -4.328125 3.335938 -4.515625 2.921875 -4.734375 C 2.515625 -4.960938 2.175781 -5.242188 1.90625 -5.578125 C 1.632812 -5.910156 1.5 -6.34375 1.5 -6.875 C 1.5 -7.625 1.800781 -8.25 2.40625 -8.75 C 3.007812 -9.25 3.960938 -9.5 5.265625 -9.5 C 5.765625 -9.5 6.285156 -9.460938 6.828125 -9.390625 C 7.367188 -9.316406 7.832031 -9.21875 8.21875 -9.09375 L 7.921875 -7.625 C 7.816406 -7.675781 7.671875 -7.726562 7.484375 -7.78125 C 7.296875 -7.84375 7.082031 -7.894531 6.84375 -7.9375 C 6.601562 -7.988281 6.34375 -8.023438 6.0625 -8.046875 C 5.789062 -8.078125 5.53125 -8.09375 5.28125 -8.09375 C 3.84375 -8.09375 3.125 -7.703125 3.125 -6.921875 C 3.125 -6.640625 3.257812 -6.398438 3.53125 -6.203125 C 3.800781 -6.015625 4.144531 -5.835938 4.5625 -5.671875 C 4.976562 -5.515625 5.425781 -5.351562 5.90625 -5.1875 C 6.382812 -5.019531 6.828125 -4.816406 7.234375 -4.578125 C 7.648438 -4.335938 7.992188 -4.046875 8.265625 -3.703125 C 8.546875 -3.367188 8.6875 -2.941406 8.6875 -2.421875 C 8.6875 -1.578125 8.359375 -0.925781 7.703125 -0.46875 C 7.046875 -0.0078125 6.007812 0.21875 4.59375 0.21875 C 3.957031 0.21875 3.375 0.164062 2.84375 0.0625 C 2.3125 -0.0390625 1.800781 -0.203125 1.3125 -0.421875 L 1.640625 -1.921875 C 2.109375 -1.703125 2.597656 -1.523438 3.109375 -1.390625 C 3.617188 -1.253906 4.171875 -1.1875 4.765625 -1.1875 C 6.265625 -1.1875 7.015625 -1.5625 7.015625 -2.3125 Z M 7.015625 -2.3125 "/> +</symbol> +<symbol overflow="visible" id="glyph0-5"> +<path style="stroke:none;" d="M 9.203125 -4.640625 C 9.203125 -3.910156 9.097656 -3.25 8.890625 -2.65625 C 8.679688 -2.0625 8.390625 -1.550781 8.015625 -1.125 C 7.640625 -0.695312 7.191406 -0.363281 6.671875 -0.125 C 6.160156 0.101562 5.597656 0.21875 4.984375 0.21875 C 4.378906 0.21875 3.820312 0.101562 3.3125 -0.125 C 2.800781 -0.363281 2.359375 -0.695312 1.984375 -1.125 C 1.609375 -1.550781 1.316406 -2.0625 1.109375 -2.65625 C 0.898438 -3.25 0.796875 -3.910156 0.796875 -4.640625 C 0.796875 -5.367188 0.898438 -6.035156 1.109375 -6.640625 C 1.316406 -7.242188 1.609375 -7.753906 1.984375 -8.171875 C 2.359375 -8.585938 2.800781 -8.910156 3.3125 -9.140625 C 3.820312 -9.378906 4.378906 -9.5 4.984375 -9.5 C 5.597656 -9.5 6.160156 -9.378906 6.671875 -9.140625 C 7.191406 -8.910156 7.640625 -8.585938 8.015625 -8.171875 C 8.390625 -7.753906 8.679688 -7.242188 8.890625 -6.640625 C 9.097656 -6.035156 9.203125 -5.367188 9.203125 -4.640625 Z M 7.5 -4.640625 C 7.5 -5.691406 7.269531 -6.519531 6.8125 -7.125 C 6.363281 -7.738281 5.753906 -8.046875 4.984375 -8.046875 C 4.222656 -8.046875 3.617188 -7.738281 3.171875 -7.125 C 2.722656 -6.519531 2.5 -5.691406 2.5 -4.640625 C 2.5 -3.597656 2.722656 -2.773438 3.171875 -2.171875 C 3.617188 -1.566406 4.222656 -1.265625 4.984375 -1.265625 C 5.753906 -1.265625 6.363281 -1.566406 6.8125 -2.171875 C 7.269531 -2.773438 7.5 -3.597656 7.5 -4.640625 Z M 7.5 -4.640625 "/> +</symbol> +<symbol overflow="visible" id="glyph0-6"> +<path style="stroke:none;" d="M 2.140625 0 L 2.140625 -8.78125 C 3.503906 -9.25 4.878906 -9.484375 6.265625 -9.484375 C 6.691406 -9.484375 7.097656 -9.460938 7.484375 -9.421875 C 7.867188 -9.390625 8.296875 -9.320312 8.765625 -9.21875 L 8.453125 -7.765625 C 8.023438 -7.878906 7.648438 -7.953125 7.328125 -7.984375 C 7.003906 -8.023438 6.648438 -8.046875 6.265625 -8.046875 C 5.453125 -8.046875 4.625 -7.929688 3.78125 -7.703125 L 3.78125 0 Z M 2.140625 0 "/> +</symbol> +<symbol overflow="visible" id="glyph0-7"> +<path style="stroke:none;" d="M 5.8125 -10.984375 L 5.8125 -1.40625 L 8.21875 -1.40625 L 8.21875 0 L 1.78125 0 L 1.78125 -1.40625 L 4.1875 -1.40625 L 4.1875 -10.984375 L 1.78125 -10.984375 L 1.78125 -12.375 L 8.21875 -12.375 L 8.21875 -10.984375 Z M 5.8125 -10.984375 "/> +</symbol> +<symbol overflow="visible" id="glyph0-8"> +<path style="stroke:none;" d="M 1.8125 0 L 1.8125 -12.375 L 8.84375 -12.375 L 8.84375 -10.984375 L 3.453125 -10.984375 L 3.453125 -7.125 L 8.203125 -7.125 L 8.203125 -5.734375 L 3.453125 -5.734375 L 3.453125 0 Z M 1.8125 0 "/> +</symbol> +<symbol overflow="visible" id="glyph0-9"> +<path style="stroke:none;" d="M 4.078125 0.09375 C 3.878906 0.09375 3.644531 0.0859375 3.375 0.078125 C 3.113281 0.0664062 2.847656 0.0507812 2.578125 0.03125 C 2.316406 0.0078125 2.050781 -0.0195312 1.78125 -0.0625 C 1.507812 -0.101562 1.273438 -0.148438 1.078125 -0.203125 L 1.078125 -12.203125 C 1.273438 -12.253906 1.503906 -12.300781 1.765625 -12.34375 C 2.023438 -12.382812 2.289062 -12.410156 2.5625 -12.421875 C 2.84375 -12.441406 3.113281 -12.457031 3.375 -12.46875 C 3.632812 -12.488281 3.867188 -12.5 4.078125 -12.5 C 4.691406 -12.5 5.265625 -12.445312 5.796875 -12.34375 C 6.328125 -12.238281 6.789062 -12.054688 7.1875 -11.796875 C 7.582031 -11.546875 7.890625 -11.210938 8.109375 -10.796875 C 8.328125 -10.390625 8.4375 -9.878906 8.4375 -9.265625 C 8.4375 -8.960938 8.390625 -8.675781 8.296875 -8.40625 C 8.203125 -8.132812 8.070312 -7.878906 7.90625 -7.640625 C 7.738281 -7.398438 7.546875 -7.1875 7.328125 -7 C 7.109375 -6.820312 6.875 -6.6875 6.625 -6.59375 C 7.300781 -6.40625 7.867188 -6.0625 8.328125 -5.5625 C 8.785156 -5.0625 9.015625 -4.414062 9.015625 -3.625 C 9.015625 -2.394531 8.617188 -1.46875 7.828125 -0.84375 C 7.046875 -0.21875 5.796875 0.09375 4.078125 0.09375 Z M 2.71875 -5.78125 L 2.71875 -1.359375 C 2.75 -1.347656 2.898438 -1.332031 3.171875 -1.3125 C 3.441406 -1.289062 3.785156 -1.28125 4.203125 -1.28125 C 4.609375 -1.28125 5 -1.3125 5.375 -1.375 C 5.757812 -1.445312 6.097656 -1.570312 6.390625 -1.75 C 6.691406 -1.925781 6.929688 -2.160156 7.109375 -2.453125 C 7.285156 -2.753906 7.375 -3.132812 7.375 -3.59375 C 7.375 -4.007812 7.289062 -4.359375 7.125 -4.640625 C 6.957031 -4.921875 6.738281 -5.144531 6.46875 -5.3125 C 6.195312 -5.476562 5.878906 -5.597656 5.515625 -5.671875 C 5.160156 -5.742188 4.789062 -5.78125 4.40625 -5.78125 Z M 2.71875 -7.140625 L 4.015625 -7.140625 C 4.347656 -7.140625 4.679688 -7.171875 5.015625 -7.234375 C 5.347656 -7.304688 5.644531 -7.414062 5.90625 -7.5625 C 6.175781 -7.707031 6.390625 -7.90625 6.546875 -8.15625 C 6.710938 -8.414062 6.796875 -8.738281 6.796875 -9.125 C 6.796875 -9.476562 6.722656 -9.78125 6.578125 -10.03125 C 6.429688 -10.289062 6.238281 -10.5 6 -10.65625 C 5.757812 -10.820312 5.484375 -10.9375 5.171875 -11 C 4.859375 -11.0625 4.53125 -11.09375 4.1875 -11.09375 C 3.832031 -11.09375 3.523438 -11.085938 3.265625 -11.078125 C 3.003906 -11.078125 2.820312 -11.066406 2.71875 -11.046875 Z M 2.71875 -7.140625 "/> +</symbol> +<symbol overflow="visible" id="glyph0-10"> +<path style="stroke:none;" d="M 9.203125 -6.203125 C 9.203125 -5.054688 9.054688 -4.082031 8.765625 -3.28125 C 8.484375 -2.476562 8.09375 -1.828125 7.59375 -1.328125 C 7.09375 -0.828125 6.5 -0.460938 5.8125 -0.234375 C 5.125 -0.015625 4.378906 0.09375 3.578125 0.09375 C 2.753906 0.09375 1.921875 -0.00390625 1.078125 -0.203125 L 1.078125 -12.203125 C 1.921875 -12.398438 2.753906 -12.5 3.578125 -12.5 C 4.378906 -12.5 5.125 -12.382812 5.8125 -12.15625 C 6.5 -11.925781 7.09375 -11.554688 7.59375 -11.046875 C 8.09375 -10.546875 8.484375 -9.894531 8.765625 -9.09375 C 9.054688 -8.300781 9.203125 -7.335938 9.203125 -6.203125 Z M 2.71875 -1.375 C 3.050781 -1.332031 3.390625 -1.3125 3.734375 -1.3125 C 4.335938 -1.3125 4.875 -1.398438 5.34375 -1.578125 C 5.8125 -1.765625 6.203125 -2.054688 6.515625 -2.453125 C 6.835938 -2.847656 7.082031 -3.351562 7.25 -3.96875 C 7.425781 -4.59375 7.515625 -5.335938 7.515625 -6.203125 C 7.515625 -7.878906 7.191406 -9.109375 6.546875 -9.890625 C 5.898438 -10.679688 4.945312 -11.078125 3.6875 -11.078125 C 3.507812 -11.078125 3.335938 -11.070312 3.171875 -11.0625 C 3.003906 -11.0625 2.851562 -11.046875 2.71875 -11.015625 Z M 2.71875 -1.375 "/> +</symbol> +<symbol overflow="visible" id="glyph0-11"> +<path style="stroke:none;" d="M 7.453125 -6.09375 L 9.09375 -6.09375 L 9.09375 -0.296875 C 8.84375 -0.203125 8.4375 -0.0859375 7.875 0.046875 C 7.320312 0.191406 6.664062 0.265625 5.90625 0.265625 C 5.15625 0.265625 4.472656 0.125 3.859375 -0.15625 C 3.242188 -0.445312 2.71875 -0.863281 2.28125 -1.40625 C 1.851562 -1.957031 1.519531 -2.632812 1.28125 -3.4375 C 1.039062 -4.25 0.921875 -5.171875 0.921875 -6.203125 C 0.921875 -7.242188 1.050781 -8.160156 1.3125 -8.953125 C 1.582031 -9.753906 1.945312 -10.425781 2.40625 -10.96875 C 2.863281 -11.519531 3.398438 -11.9375 4.015625 -12.21875 C 4.628906 -12.507812 5.289062 -12.65625 6 -12.65625 C 6.457031 -12.65625 6.859375 -12.617188 7.203125 -12.546875 C 7.546875 -12.484375 7.835938 -12.40625 8.078125 -12.3125 C 8.328125 -12.226562 8.53125 -12.132812 8.6875 -12.03125 C 8.851562 -11.925781 8.976562 -11.847656 9.0625 -11.796875 L 8.515625 -10.421875 C 8.210938 -10.660156 7.847656 -10.851562 7.421875 -11 C 7.003906 -11.15625 6.5625 -11.234375 6.09375 -11.234375 C 5.59375 -11.234375 5.125 -11.113281 4.6875 -10.875 C 4.257812 -10.632812 3.890625 -10.296875 3.578125 -9.859375 C 3.273438 -9.421875 3.035156 -8.890625 2.859375 -8.265625 C 2.679688 -7.648438 2.59375 -6.960938 2.59375 -6.203125 C 2.59375 -5.453125 2.671875 -4.769531 2.828125 -4.15625 C 2.984375 -3.539062 3.207031 -3.015625 3.5 -2.578125 C 3.789062 -2.140625 4.148438 -1.796875 4.578125 -1.546875 C 5.015625 -1.304688 5.515625 -1.1875 6.078125 -1.1875 C 6.460938 -1.1875 6.757812 -1.210938 6.96875 -1.265625 C 7.1875 -1.316406 7.347656 -1.367188 7.453125 -1.421875 Z M 7.453125 -6.09375 "/> +</symbol> +<symbol overflow="visible" id="glyph0-12"> +<path style="stroke:none;" d="M 9.203125 -0.515625 C 8.734375 -0.253906 8.234375 -0.0625 7.703125 0.0625 C 7.179688 0.195312 6.617188 0.265625 6.015625 0.265625 C 5.285156 0.265625 4.609375 0.132812 3.984375 -0.125 C 3.367188 -0.382812 2.832031 -0.773438 2.375 -1.296875 C 1.925781 -1.828125 1.570312 -2.5 1.3125 -3.3125 C 1.050781 -4.132812 0.921875 -5.097656 0.921875 -6.203125 C 0.921875 -7.253906 1.054688 -8.179688 1.328125 -8.984375 C 1.597656 -9.785156 1.96875 -10.457031 2.4375 -11 C 2.90625 -11.539062 3.453125 -11.953125 4.078125 -12.234375 C 4.703125 -12.515625 5.367188 -12.65625 6.078125 -12.65625 C 6.566406 -12.65625 7.066406 -12.585938 7.578125 -12.453125 C 8.097656 -12.328125 8.601562 -12.109375 9.09375 -11.796875 L 8.625 -10.4375 C 7.738281 -10.945312 6.910156 -11.203125 6.140625 -11.203125 C 5.585938 -11.203125 5.09375 -11.082031 4.65625 -10.84375 C 4.226562 -10.613281 3.859375 -10.28125 3.546875 -9.84375 C 3.242188 -9.40625 3.007812 -8.878906 2.84375 -8.265625 C 2.675781 -7.648438 2.59375 -6.960938 2.59375 -6.203125 C 2.59375 -5.347656 2.679688 -4.609375 2.859375 -3.984375 C 3.046875 -3.359375 3.296875 -2.835938 3.609375 -2.421875 C 3.929688 -2.003906 4.316406 -1.695312 4.765625 -1.5 C 5.210938 -1.300781 5.695312 -1.203125 6.21875 -1.203125 C 6.601562 -1.203125 7.007812 -1.25 7.4375 -1.34375 C 7.863281 -1.445312 8.304688 -1.625 8.765625 -1.875 Z M 9.203125 -0.515625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-0"> +<path style="stroke:none;" d="M 0.59375 0 L 0.59375 -9 L 5.40625 -9 L 5.40625 0 Z M 4.796875 -0.59375 L 4.796875 -8.40625 L 1.203125 -8.40625 L 1.203125 -0.59375 Z M 4.796875 -0.59375 "/> +</symbol> +<symbol overflow="visible" id="glyph1-1"> +<path style="stroke:none;" d="M 2.515625 0 L 2.515625 -2.765625 C 2.023438 -3.554688 1.582031 -4.332031 1.1875 -5.09375 C 0.789062 -5.851562 0.445312 -6.628906 0.15625 -7.421875 L 1.265625 -7.421875 C 1.492188 -6.753906 1.757812 -6.113281 2.0625 -5.5 C 2.363281 -4.882812 2.6875 -4.253906 3.03125 -3.609375 C 3.394531 -4.285156 3.71875 -4.929688 4 -5.546875 C 4.28125 -6.160156 4.539062 -6.785156 4.78125 -7.421875 L 5.859375 -7.421875 C 5.554688 -6.640625 5.207031 -5.875 4.8125 -5.125 C 4.414062 -4.382812 3.976562 -3.601562 3.5 -2.78125 L 3.5 0 Z M 2.515625 0 "/> +</symbol> +<symbol overflow="visible" id="glyph1-2"> +<path style="stroke:none;" d="M 3 0.15625 C 2.5625 0.15625 2.1875 0.09375 1.875 -0.03125 C 1.570312 -0.164062 1.320312 -0.347656 1.125 -0.578125 C 0.9375 -0.804688 0.796875 -1.085938 0.703125 -1.421875 C 0.617188 -1.765625 0.578125 -2.144531 0.578125 -2.5625 L 0.578125 -7.421875 L 1.5625 -7.421875 L 1.5625 -2.65625 C 1.5625 -2.28125 1.59375 -1.96875 1.65625 -1.71875 C 1.726562 -1.46875 1.828125 -1.265625 1.953125 -1.109375 C 2.078125 -0.960938 2.222656 -0.859375 2.390625 -0.796875 C 2.566406 -0.734375 2.769531 -0.703125 3 -0.703125 C 3.226562 -0.703125 3.425781 -0.734375 3.59375 -0.796875 C 3.769531 -0.859375 3.921875 -0.960938 4.046875 -1.109375 C 4.171875 -1.265625 4.265625 -1.46875 4.328125 -1.71875 C 4.398438 -1.96875 4.4375 -2.28125 4.4375 -2.65625 L 4.4375 -7.421875 L 5.421875 -7.421875 L 5.421875 -2.5625 C 5.421875 -2.144531 5.375 -1.765625 5.28125 -1.421875 C 5.195312 -1.085938 5.054688 -0.804688 4.859375 -0.578125 C 4.671875 -0.347656 4.421875 -0.164062 4.109375 -0.03125 C 3.804688 0.09375 3.4375 0.15625 3 0.15625 Z M 3 0.15625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-3"> +<path style="stroke:none;" d="M 1.21875 -7.421875 C 1.320312 -6.921875 1.445312 -6.375 1.59375 -5.78125 C 1.738281 -5.1875 1.890625 -4.585938 2.046875 -3.984375 C 2.210938 -3.390625 2.378906 -2.820312 2.546875 -2.28125 C 2.722656 -1.738281 2.882812 -1.265625 3.03125 -0.859375 C 3.15625 -1.265625 3.300781 -1.742188 3.46875 -2.296875 C 3.644531 -2.847656 3.816406 -3.421875 3.984375 -4.015625 C 4.148438 -4.609375 4.304688 -5.203125 4.453125 -5.796875 C 4.609375 -6.390625 4.734375 -6.929688 4.828125 -7.421875 L 5.859375 -7.421875 C 5.796875 -7.109375 5.691406 -6.679688 5.546875 -6.140625 C 5.398438 -5.597656 5.226562 -4.992188 5.03125 -4.328125 C 4.832031 -3.660156 4.609375 -2.953125 4.359375 -2.203125 C 4.117188 -1.453125 3.863281 -0.71875 3.59375 0 L 2.375 0 C 2.125 -0.71875 1.878906 -1.445312 1.640625 -2.1875 C 1.410156 -2.9375 1.195312 -3.644531 1 -4.3125 C 0.800781 -4.976562 0.628906 -5.582031 0.484375 -6.125 C 0.335938 -6.675781 0.226562 -7.109375 0.15625 -7.421875 Z M 1.21875 -7.421875 "/> +</symbol> +<symbol overflow="visible" id="glyph1-4"> +<path style="stroke:none;" d=""/> +</symbol> +<symbol overflow="visible" id="glyph1-5"> +<path style="stroke:none;" d="M 5.515625 -3.71875 C 5.515625 -3.03125 5.425781 -2.445312 5.25 -1.96875 C 5.082031 -1.488281 4.847656 -1.097656 4.546875 -0.796875 C 4.253906 -0.492188 3.898438 -0.273438 3.484375 -0.140625 C 3.078125 -0.00390625 2.628906 0.0625 2.140625 0.0625 C 1.648438 0.0625 1.148438 0 0.640625 -0.125 L 0.640625 -7.3125 C 1.148438 -7.4375 1.648438 -7.5 2.140625 -7.5 C 2.628906 -7.5 3.078125 -7.429688 3.484375 -7.296875 C 3.898438 -7.160156 4.253906 -6.941406 4.546875 -6.640625 C 4.847656 -6.335938 5.082031 -5.941406 5.25 -5.453125 C 5.425781 -4.972656 5.515625 -4.394531 5.515625 -3.71875 Z M 1.625 -0.828125 C 1.832031 -0.804688 2.039062 -0.796875 2.25 -0.796875 C 2.601562 -0.796875 2.921875 -0.847656 3.203125 -0.953125 C 3.484375 -1.054688 3.71875 -1.226562 3.90625 -1.46875 C 4.101562 -1.707031 4.253906 -2.007812 4.359375 -2.375 C 4.460938 -2.75 4.515625 -3.195312 4.515625 -3.71875 C 4.515625 -4.726562 4.316406 -5.46875 3.921875 -5.9375 C 3.535156 -6.40625 2.960938 -6.640625 2.203125 -6.640625 C 2.097656 -6.640625 1.992188 -6.640625 1.890625 -6.640625 C 1.796875 -6.640625 1.707031 -6.628906 1.625 -6.609375 Z M 1.625 -0.828125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-6"> +<path style="stroke:none;" d="M 5.515625 -2.78125 C 5.515625 -2.34375 5.453125 -1.945312 5.328125 -1.59375 C 5.203125 -1.238281 5.023438 -0.929688 4.796875 -0.671875 C 4.578125 -0.410156 4.3125 -0.210938 4 -0.078125 C 3.695312 0.0546875 3.359375 0.125 2.984375 0.125 C 2.628906 0.125 2.296875 0.0546875 1.984375 -0.078125 C 1.679688 -0.210938 1.414062 -0.410156 1.1875 -0.671875 C 0.96875 -0.929688 0.796875 -1.238281 0.671875 -1.59375 C 0.546875 -1.945312 0.484375 -2.34375 0.484375 -2.78125 C 0.484375 -3.21875 0.546875 -3.617188 0.671875 -3.984375 C 0.796875 -4.347656 0.96875 -4.65625 1.1875 -4.90625 C 1.414062 -5.15625 1.679688 -5.347656 1.984375 -5.484375 C 2.296875 -5.628906 2.628906 -5.703125 2.984375 -5.703125 C 3.359375 -5.703125 3.695312 -5.628906 4 -5.484375 C 4.3125 -5.347656 4.578125 -5.15625 4.796875 -4.90625 C 5.023438 -4.65625 5.203125 -4.347656 5.328125 -3.984375 C 5.453125 -3.617188 5.515625 -3.21875 5.515625 -2.78125 Z M 4.5 -2.78125 C 4.5 -3.414062 4.363281 -3.914062 4.09375 -4.28125 C 3.820312 -4.644531 3.453125 -4.828125 2.984375 -4.828125 C 2.523438 -4.828125 2.160156 -4.644531 1.890625 -4.28125 C 1.628906 -3.914062 1.5 -3.414062 1.5 -2.78125 C 1.5 -2.15625 1.628906 -1.660156 1.890625 -1.296875 C 2.160156 -0.929688 2.523438 -0.75 2.984375 -0.75 C 3.453125 -0.75 3.820312 -0.929688 4.09375 -1.296875 C 4.363281 -1.660156 4.5 -2.15625 4.5 -2.78125 Z M 4.5 -2.78125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-7"> +<path style="stroke:none;" d="M 4.109375 0 C 3.992188 -0.269531 3.890625 -0.515625 3.796875 -0.734375 C 3.710938 -0.960938 3.628906 -1.1875 3.546875 -1.40625 C 3.460938 -1.632812 3.378906 -1.867188 3.296875 -2.109375 C 3.210938 -2.359375 3.113281 -2.640625 3 -2.953125 C 2.882812 -2.640625 2.78125 -2.359375 2.6875 -2.109375 C 2.601562 -1.867188 2.519531 -1.632812 2.4375 -1.40625 C 2.351562 -1.1875 2.265625 -0.960938 2.171875 -0.734375 C 2.085938 -0.515625 1.984375 -0.269531 1.859375 0 L 1.109375 0 C 0.890625 -0.976562 0.707031 -1.953125 0.5625 -2.921875 C 0.414062 -3.890625 0.304688 -4.769531 0.234375 -5.5625 L 1.15625 -5.5625 C 1.1875 -5.25 1.210938 -4.941406 1.234375 -4.640625 C 1.265625 -4.347656 1.300781 -4.035156 1.34375 -3.703125 C 1.382812 -3.378906 1.429688 -3.023438 1.484375 -2.640625 C 1.535156 -2.253906 1.59375 -1.820312 1.65625 -1.34375 C 1.78125 -1.664062 1.882812 -1.945312 1.96875 -2.1875 C 2.0625 -2.425781 2.144531 -2.648438 2.21875 -2.859375 C 2.289062 -3.078125 2.359375 -3.296875 2.421875 -3.515625 C 2.492188 -3.742188 2.570312 -4 2.65625 -4.28125 L 3.390625 -4.28125 C 3.472656 -4 3.546875 -3.742188 3.609375 -3.515625 C 3.671875 -3.296875 3.738281 -3.078125 3.8125 -2.859375 C 3.882812 -2.648438 3.957031 -2.425781 4.03125 -2.1875 C 4.113281 -1.945312 4.21875 -1.671875 4.34375 -1.359375 C 4.414062 -1.796875 4.476562 -2.203125 4.53125 -2.578125 C 4.59375 -2.953125 4.640625 -3.304688 4.671875 -3.640625 C 4.710938 -3.972656 4.75 -4.296875 4.78125 -4.609375 C 4.820312 -4.921875 4.851562 -5.238281 4.875 -5.5625 L 5.765625 -5.5625 C 5.734375 -5.164062 5.6875 -4.738281 5.625 -4.28125 C 5.570312 -3.820312 5.503906 -3.351562 5.421875 -2.875 C 5.335938 -2.394531 5.25 -1.910156 5.15625 -1.421875 C 5.0625 -0.929688 4.960938 -0.457031 4.859375 0 Z M 4.109375 0 "/> +</symbol> +<symbol overflow="visible" id="glyph1-8"> +<path style="stroke:none;" d="M 0.859375 -5.40625 C 1.210938 -5.5 1.566406 -5.566406 1.921875 -5.609375 C 2.273438 -5.660156 2.609375 -5.6875 2.921875 -5.6875 C 3.671875 -5.6875 4.234375 -5.492188 4.609375 -5.109375 C 4.992188 -4.722656 5.1875 -4.109375 5.1875 -3.265625 L 5.1875 0 L 4.203125 0 L 4.203125 -3.078125 C 4.203125 -3.441406 4.171875 -3.734375 4.109375 -3.953125 C 4.046875 -4.179688 3.953125 -4.359375 3.828125 -4.484375 C 3.710938 -4.609375 3.570312 -4.691406 3.40625 -4.734375 C 3.25 -4.785156 3.070312 -4.8125 2.875 -4.8125 C 2.71875 -4.8125 2.546875 -4.800781 2.359375 -4.78125 C 2.179688 -4.757812 2.007812 -4.734375 1.84375 -4.703125 L 1.84375 0 L 0.859375 0 Z M 0.859375 -5.40625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-9"> +<path style="stroke:none;" d="M 4.21875 -1.390625 C 4.21875 -1.585938 4.132812 -1.75 3.96875 -1.875 C 3.800781 -2.007812 3.59375 -2.125 3.34375 -2.21875 C 3.101562 -2.3125 2.835938 -2.40625 2.546875 -2.5 C 2.265625 -2.59375 2 -2.707031 1.75 -2.84375 C 1.507812 -2.976562 1.304688 -3.144531 1.140625 -3.34375 C 0.984375 -3.539062 0.90625 -3.800781 0.90625 -4.125 C 0.90625 -4.570312 1.082031 -4.945312 1.4375 -5.25 C 1.800781 -5.550781 2.375 -5.703125 3.15625 -5.703125 C 3.457031 -5.703125 3.769531 -5.675781 4.09375 -5.625 C 4.414062 -5.582031 4.695312 -5.523438 4.9375 -5.453125 L 4.75 -4.578125 C 4.6875 -4.609375 4.597656 -4.640625 4.484375 -4.671875 C 4.367188 -4.710938 4.238281 -4.742188 4.09375 -4.765625 C 3.957031 -4.796875 3.804688 -4.816406 3.640625 -4.828125 C 3.472656 -4.847656 3.316406 -4.859375 3.171875 -4.859375 C 2.304688 -4.859375 1.875 -4.625 1.875 -4.15625 C 1.875 -3.988281 1.953125 -3.84375 2.109375 -3.71875 C 2.273438 -3.601562 2.484375 -3.5 2.734375 -3.40625 C 2.984375 -3.3125 3.25 -3.210938 3.53125 -3.109375 C 3.820312 -3.015625 4.09375 -2.894531 4.34375 -2.75 C 4.59375 -2.601562 4.796875 -2.425781 4.953125 -2.21875 C 5.117188 -2.019531 5.203125 -1.765625 5.203125 -1.453125 C 5.203125 -0.953125 5.003906 -0.5625 4.609375 -0.28125 C 4.222656 -0.0078125 3.609375 0.125 2.765625 0.125 C 2.378906 0.125 2.023438 0.09375 1.703125 0.03125 C 1.378906 -0.03125 1.078125 -0.125 0.796875 -0.25 L 0.984375 -1.15625 C 1.265625 -1.019531 1.554688 -0.910156 1.859375 -0.828125 C 2.171875 -0.742188 2.503906 -0.703125 2.859375 -0.703125 C 3.765625 -0.703125 4.21875 -0.929688 4.21875 -1.390625 Z M 4.21875 -1.390625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-10"> +<path style="stroke:none;" d="M 0.59375 -2.765625 C 0.59375 -3.273438 0.671875 -3.710938 0.828125 -4.078125 C 0.984375 -4.441406 1.203125 -4.742188 1.484375 -4.984375 C 1.765625 -5.234375 2.09375 -5.414062 2.46875 -5.53125 C 2.84375 -5.644531 3.238281 -5.703125 3.65625 -5.703125 C 3.925781 -5.703125 4.195312 -5.679688 4.46875 -5.640625 C 4.738281 -5.609375 5.023438 -5.546875 5.328125 -5.453125 L 5.09375 -4.59375 C 4.832031 -4.6875 4.59375 -4.75 4.375 -4.78125 C 4.15625 -4.8125 3.929688 -4.828125 3.703125 -4.828125 C 3.421875 -4.828125 3.148438 -4.785156 2.890625 -4.703125 C 2.640625 -4.628906 2.414062 -4.507812 2.21875 -4.34375 C 2.03125 -4.1875 1.878906 -3.976562 1.765625 -3.71875 C 1.660156 -3.457031 1.609375 -3.140625 1.609375 -2.765625 C 1.609375 -2.421875 1.660156 -2.117188 1.765625 -1.859375 C 1.867188 -1.609375 2.015625 -1.398438 2.203125 -1.234375 C 2.390625 -1.078125 2.613281 -0.957031 2.875 -0.875 C 3.144531 -0.789062 3.4375 -0.75 3.75 -0.75 C 4.007812 -0.75 4.253906 -0.765625 4.484375 -0.796875 C 4.722656 -0.828125 4.984375 -0.890625 5.265625 -0.984375 L 5.40625 -0.15625 C 5.125 -0.0507812 4.835938 0.0195312 4.546875 0.0625 C 4.265625 0.101562 3.957031 0.125 3.625 0.125 C 3.175781 0.125 2.765625 0.0664062 2.390625 -0.046875 C 2.023438 -0.171875 1.707031 -0.351562 1.4375 -0.59375 C 1.164062 -0.832031 0.957031 -1.132812 0.8125 -1.5 C 0.664062 -1.863281 0.59375 -2.285156 0.59375 -2.765625 Z M 0.59375 -2.765625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-11"> +<path style="stroke:none;" d="M 3.0625 -0.703125 C 3.3125 -0.703125 3.53125 -0.707031 3.71875 -0.71875 C 3.914062 -0.738281 4.082031 -0.765625 4.21875 -0.796875 L 4.21875 -2.453125 C 4.082031 -2.492188 3.925781 -2.523438 3.75 -2.546875 C 3.570312 -2.566406 3.382812 -2.578125 3.1875 -2.578125 C 3 -2.578125 2.816406 -2.5625 2.640625 -2.53125 C 2.460938 -2.507812 2.304688 -2.460938 2.171875 -2.390625 C 2.035156 -2.316406 1.921875 -2.222656 1.828125 -2.109375 C 1.742188 -1.992188 1.703125 -1.847656 1.703125 -1.671875 C 1.703125 -1.304688 1.820312 -1.050781 2.0625 -0.90625 C 2.3125 -0.769531 2.644531 -0.703125 3.0625 -0.703125 Z M 2.96875 -5.703125 C 3.382812 -5.703125 3.734375 -5.648438 4.015625 -5.546875 C 4.296875 -5.441406 4.523438 -5.296875 4.703125 -5.109375 C 4.878906 -4.929688 5.003906 -4.707031 5.078125 -4.4375 C 5.148438 -4.175781 5.1875 -3.890625 5.1875 -3.578125 L 5.1875 -0.09375 C 4.957031 -0.0507812 4.648438 -0.00390625 4.265625 0.046875 C 3.890625 0.0976562 3.5 0.125 3.09375 0.125 C 2.789062 0.125 2.492188 0.0976562 2.203125 0.046875 C 1.921875 -0.00390625 1.664062 -0.09375 1.4375 -0.21875 C 1.21875 -0.351562 1.039062 -0.535156 0.90625 -0.765625 C 0.769531 -0.992188 0.703125 -1.289062 0.703125 -1.65625 C 0.703125 -1.976562 0.769531 -2.25 0.90625 -2.46875 C 1.039062 -2.6875 1.21875 -2.863281 1.4375 -3 C 1.664062 -3.132812 1.921875 -3.234375 2.203125 -3.296875 C 2.484375 -3.359375 2.769531 -3.390625 3.0625 -3.390625 C 3.445312 -3.390625 3.832031 -3.34375 4.21875 -3.25 L 4.21875 -3.53125 C 4.21875 -3.695312 4.195312 -3.859375 4.15625 -4.015625 C 4.125 -4.171875 4.054688 -4.3125 3.953125 -4.4375 C 3.847656 -4.5625 3.707031 -4.660156 3.53125 -4.734375 C 3.363281 -4.816406 3.144531 -4.859375 2.875 -4.859375 C 2.53125 -4.859375 2.226562 -4.832031 1.96875 -4.78125 C 1.71875 -4.738281 1.523438 -4.691406 1.390625 -4.640625 L 1.265625 -5.453125 C 1.398438 -5.523438 1.625 -5.582031 1.9375 -5.625 C 2.257812 -5.675781 2.601562 -5.703125 2.96875 -5.703125 Z M 2.96875 -5.703125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-12"> +<path style="stroke:none;" d="M 4.0625 0.125 C 3.707031 0.125 3.410156 0.078125 3.171875 -0.015625 C 2.941406 -0.109375 2.757812 -0.25 2.625 -0.4375 C 2.488281 -0.632812 2.390625 -0.875 2.328125 -1.15625 C 2.273438 -1.4375 2.25 -1.765625 2.25 -2.140625 L 2.25 -7.421875 L 0.640625 -7.421875 L 0.640625 -8.25 L 3.234375 -8.25 L 3.234375 -2.140625 C 3.234375 -1.867188 3.25 -1.644531 3.28125 -1.46875 C 3.320312 -1.289062 3.378906 -1.144531 3.453125 -1.03125 C 3.535156 -0.925781 3.628906 -0.851562 3.734375 -0.8125 C 3.847656 -0.769531 3.984375 -0.75 4.140625 -0.75 C 4.367188 -0.75 4.582031 -0.773438 4.78125 -0.828125 C 4.988281 -0.890625 5.144531 -0.953125 5.25 -1.015625 L 5.40625 -0.1875 C 5.351562 -0.15625 5.28125 -0.117188 5.1875 -0.078125 C 5.101562 -0.046875 5 -0.015625 4.875 0.015625 C 4.757812 0.046875 4.628906 0.0703125 4.484375 0.09375 C 4.347656 0.113281 4.207031 0.125 4.0625 0.125 Z M 4.0625 0.125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-13"> +<path style="stroke:none;" d="M 2.515625 -6.4375 C 2.304688 -6.4375 2.125 -6.503906 1.96875 -6.640625 C 1.8125 -6.785156 1.734375 -6.984375 1.734375 -7.234375 C 1.734375 -7.484375 1.8125 -7.679688 1.96875 -7.828125 C 2.125 -7.972656 2.304688 -8.046875 2.515625 -8.046875 C 2.722656 -8.046875 2.898438 -7.972656 3.046875 -7.828125 C 3.203125 -7.679688 3.28125 -7.484375 3.28125 -7.234375 C 3.28125 -6.984375 3.203125 -6.785156 3.046875 -6.640625 C 2.898438 -6.503906 2.722656 -6.4375 2.515625 -6.4375 Z M 2.25 -4.734375 L 0.640625 -4.734375 L 0.640625 -5.5625 L 3.234375 -5.5625 L 3.234375 -2.140625 C 3.234375 -1.585938 3.3125 -1.21875 3.46875 -1.03125 C 3.625 -0.84375 3.851562 -0.75 4.15625 -0.75 C 4.382812 -0.75 4.597656 -0.773438 4.796875 -0.828125 C 4.992188 -0.890625 5.144531 -0.953125 5.25 -1.015625 L 5.40625 -0.1875 C 5.351562 -0.15625 5.28125 -0.117188 5.1875 -0.078125 C 5.101562 -0.046875 5.003906 -0.015625 4.890625 0.015625 C 4.773438 0.046875 4.644531 0.0703125 4.5 0.09375 C 4.363281 0.113281 4.21875 0.125 4.0625 0.125 C 3.71875 0.125 3.425781 0.078125 3.1875 -0.015625 C 2.957031 -0.109375 2.769531 -0.25 2.625 -0.4375 C 2.488281 -0.632812 2.390625 -0.875 2.328125 -1.15625 C 2.273438 -1.4375 2.25 -1.765625 2.25 -2.140625 Z M 2.25 -4.734375 "/> +</symbol> +<symbol overflow="visible" id="glyph1-14"> +<path style="stroke:none;" d="M 4.15625 -0.515625 C 4.039062 -0.453125 3.863281 -0.382812 3.625 -0.3125 C 3.394531 -0.238281 3.128906 -0.203125 2.828125 -0.203125 C 2.503906 -0.203125 2.195312 -0.253906 1.90625 -0.359375 C 1.625 -0.472656 1.378906 -0.640625 1.171875 -0.859375 C 0.960938 -1.078125 0.796875 -1.351562 0.671875 -1.6875 C 0.546875 -2.03125 0.484375 -2.4375 0.484375 -2.90625 C 0.484375 -3.3125 0.539062 -3.679688 0.65625 -4.015625 C 0.769531 -4.359375 0.9375 -4.65625 1.15625 -4.90625 C 1.375 -5.15625 1.644531 -5.347656 1.96875 -5.484375 C 2.289062 -5.628906 2.65625 -5.703125 3.0625 -5.703125 C 3.539062 -5.703125 3.945312 -5.664062 4.28125 -5.59375 C 4.625 -5.53125 4.910156 -5.46875 5.140625 -5.40625 L 5.140625 -0.4375 C 5.140625 0.425781 4.921875 1.050781 4.484375 1.4375 C 4.054688 1.820312 3.398438 2.015625 2.515625 2.015625 C 2.160156 2.015625 1.835938 1.984375 1.546875 1.921875 C 1.253906 1.867188 0.992188 1.804688 0.765625 1.734375 L 0.953125 0.859375 C 1.160156 0.941406 1.394531 1.007812 1.65625 1.0625 C 1.925781 1.125 2.222656 1.15625 2.546875 1.15625 C 3.117188 1.15625 3.53125 1.035156 3.78125 0.796875 C 4.03125 0.566406 4.15625 0.191406 4.15625 -0.328125 Z M 4.15625 -4.6875 C 4.0625 -4.71875 3.925781 -4.75 3.75 -4.78125 C 3.582031 -4.8125 3.359375 -4.828125 3.078125 -4.828125 C 2.554688 -4.828125 2.160156 -4.648438 1.890625 -4.296875 C 1.628906 -3.941406 1.5 -3.472656 1.5 -2.890625 C 1.5 -2.566406 1.535156 -2.289062 1.609375 -2.0625 C 1.691406 -1.84375 1.796875 -1.65625 1.921875 -1.5 C 2.054688 -1.351562 2.207031 -1.242188 2.375 -1.171875 C 2.539062 -1.109375 2.722656 -1.078125 2.921875 -1.078125 C 3.160156 -1.078125 3.390625 -1.113281 3.609375 -1.1875 C 3.835938 -1.257812 4.019531 -1.34375 4.15625 -1.4375 Z M 4.15625 -4.6875 "/> +</symbol> +<symbol overflow="visible" id="glyph1-15"> +<path style="stroke:none;" d="M 2.8125 -0.703125 C 3.3125 -0.703125 3.691406 -0.796875 3.953125 -0.984375 C 4.222656 -1.171875 4.359375 -1.457031 4.359375 -1.84375 C 4.359375 -2.082031 4.304688 -2.28125 4.203125 -2.4375 C 4.109375 -2.601562 3.984375 -2.75 3.828125 -2.875 C 3.671875 -3 3.488281 -3.109375 3.28125 -3.203125 C 3.082031 -3.296875 2.878906 -3.378906 2.671875 -3.453125 C 2.429688 -3.546875 2.203125 -3.648438 1.984375 -3.765625 C 1.765625 -3.890625 1.566406 -4.03125 1.390625 -4.1875 C 1.222656 -4.351562 1.085938 -4.546875 0.984375 -4.765625 C 0.890625 -4.984375 0.84375 -5.238281 0.84375 -5.53125 C 0.84375 -6.175781 1.046875 -6.679688 1.453125 -7.046875 C 1.859375 -7.410156 2.425781 -7.59375 3.15625 -7.59375 C 3.351562 -7.59375 3.550781 -7.578125 3.75 -7.546875 C 3.945312 -7.523438 4.128906 -7.492188 4.296875 -7.453125 C 4.460938 -7.410156 4.609375 -7.359375 4.734375 -7.296875 C 4.867188 -7.242188 4.976562 -7.191406 5.0625 -7.140625 L 4.75 -6.3125 C 4.59375 -6.40625 4.375 -6.5 4.09375 -6.59375 C 3.8125 -6.695312 3.5 -6.75 3.15625 -6.75 C 2.789062 -6.75 2.476562 -6.65625 2.21875 -6.46875 C 1.957031 -6.289062 1.828125 -6.019531 1.828125 -5.65625 C 1.828125 -5.457031 1.863281 -5.285156 1.9375 -5.140625 C 2.007812 -4.992188 2.113281 -4.863281 2.25 -4.75 C 2.382812 -4.644531 2.535156 -4.546875 2.703125 -4.453125 C 2.878906 -4.367188 3.070312 -4.285156 3.28125 -4.203125 C 3.59375 -4.078125 3.875 -3.945312 4.125 -3.8125 C 4.375 -3.6875 4.585938 -3.535156 4.765625 -3.359375 C 4.953125 -3.179688 5.09375 -2.972656 5.1875 -2.734375 C 5.289062 -2.492188 5.34375 -2.203125 5.34375 -1.859375 C 5.34375 -1.210938 5.125 -0.710938 4.6875 -0.359375 C 4.25 -0.015625 3.625 0.15625 2.8125 0.15625 C 2.539062 0.15625 2.289062 0.132812 2.0625 0.09375 C 1.832031 0.0625 1.625 0.0195312 1.4375 -0.03125 C 1.257812 -0.09375 1.101562 -0.148438 0.96875 -0.203125 C 0.832031 -0.253906 0.726562 -0.304688 0.65625 -0.359375 L 0.953125 -1.171875 C 1.117188 -1.085938 1.359375 -0.988281 1.671875 -0.875 C 1.984375 -0.757812 2.363281 -0.703125 2.8125 -0.703125 Z M 2.8125 -0.703125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-16"> +<path style="stroke:none;" d="M 3.109375 -5.703125 C 3.859375 -5.703125 4.4375 -5.46875 4.84375 -5 C 5.25 -4.53125 5.453125 -3.820312 5.453125 -2.875 L 5.453125 -2.515625 L 1.46875 -2.515625 C 1.507812 -1.941406 1.703125 -1.503906 2.046875 -1.203125 C 2.390625 -0.898438 2.867188 -0.75 3.484375 -0.75 C 3.835938 -0.75 4.132812 -0.773438 4.375 -0.828125 C 4.625 -0.890625 4.8125 -0.953125 4.9375 -1.015625 L 5.078125 -0.1875 C 4.953125 -0.113281 4.734375 -0.046875 4.421875 0.015625 C 4.109375 0.0859375 3.757812 0.125 3.375 0.125 C 2.894531 0.125 2.472656 0.0507812 2.109375 -0.09375 C 1.742188 -0.238281 1.441406 -0.4375 1.203125 -0.6875 C 0.960938 -0.945312 0.78125 -1.253906 0.65625 -1.609375 C 0.539062 -1.960938 0.484375 -2.347656 0.484375 -2.765625 C 0.484375 -3.265625 0.554688 -3.695312 0.703125 -4.0625 C 0.859375 -4.4375 1.0625 -4.742188 1.3125 -4.984375 C 1.5625 -5.222656 1.835938 -5.398438 2.140625 -5.515625 C 2.453125 -5.640625 2.773438 -5.703125 3.109375 -5.703125 Z M 4.453125 -3.328125 C 4.453125 -3.796875 4.328125 -4.164062 4.078125 -4.4375 C 3.828125 -4.71875 3.5 -4.859375 3.09375 -4.859375 C 2.863281 -4.859375 2.65625 -4.8125 2.46875 -4.71875 C 2.28125 -4.632812 2.117188 -4.519531 1.984375 -4.375 C 1.847656 -4.226562 1.738281 -4.0625 1.65625 -3.875 C 1.570312 -3.695312 1.519531 -3.515625 1.5 -3.328125 Z M 4.453125 -3.328125 "/> +</symbol> +<symbol overflow="visible" id="glyph1-17"> +<path style="stroke:none;" d="M 4.15625 -4.390625 C 4.039062 -4.492188 3.875 -4.59375 3.65625 -4.6875 C 3.445312 -4.78125 3.222656 -4.828125 2.984375 -4.828125 C 2.722656 -4.828125 2.5 -4.773438 2.3125 -4.671875 C 2.125 -4.566406 1.96875 -4.421875 1.84375 -4.234375 C 1.726562 -4.054688 1.640625 -3.84375 1.578125 -3.59375 C 1.523438 -3.34375 1.5 -3.070312 1.5 -2.78125 C 1.5 -2.132812 1.648438 -1.632812 1.953125 -1.28125 C 2.253906 -0.925781 2.648438 -0.75 3.140625 -0.75 C 3.390625 -0.75 3.597656 -0.757812 3.765625 -0.78125 C 3.941406 -0.8125 4.070312 -0.835938 4.15625 -0.859375 Z M 4.15625 -8.140625 L 5.140625 -8.3125 L 5.140625 -0.15625 C 4.929688 -0.09375 4.65625 -0.03125 4.3125 0.03125 C 3.976562 0.09375 3.585938 0.125 3.140625 0.125 C 2.742188 0.125 2.378906 0.0546875 2.046875 -0.078125 C 1.722656 -0.210938 1.441406 -0.40625 1.203125 -0.65625 C 0.972656 -0.90625 0.796875 -1.207031 0.671875 -1.5625 C 0.546875 -1.925781 0.484375 -2.332031 0.484375 -2.78125 C 0.484375 -3.21875 0.535156 -3.613281 0.640625 -3.96875 C 0.742188 -4.320312 0.898438 -4.625 1.109375 -4.875 C 1.316406 -5.132812 1.566406 -5.335938 1.859375 -5.484375 C 2.148438 -5.628906 2.488281 -5.703125 2.875 -5.703125 C 3.164062 -5.703125 3.421875 -5.664062 3.640625 -5.59375 C 3.867188 -5.519531 4.039062 -5.441406 4.15625 -5.359375 Z M 4.15625 -8.140625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-18"> +<path style="stroke:none;" d="M 1.28125 0 L 1.28125 -5.265625 C 2.101562 -5.546875 2.925781 -5.6875 3.75 -5.6875 C 4.007812 -5.6875 4.253906 -5.675781 4.484375 -5.65625 C 4.722656 -5.632812 4.976562 -5.59375 5.25 -5.53125 L 5.078125 -4.65625 C 4.816406 -4.726562 4.585938 -4.773438 4.390625 -4.796875 C 4.203125 -4.816406 3.988281 -4.828125 3.75 -4.828125 C 3.269531 -4.828125 2.773438 -4.757812 2.265625 -4.625 L 2.265625 0 Z M 1.28125 0 "/> +</symbol> +<symbol overflow="visible" id="glyph1-19"> +<path style="stroke:none;" d="M 0.609375 1.046875 C 0.679688 1.085938 0.78125 1.117188 0.90625 1.140625 C 1.039062 1.160156 1.164062 1.171875 1.28125 1.171875 C 1.675781 1.171875 1.984375 1.082031 2.203125 0.90625 C 2.421875 0.738281 2.625 0.460938 2.8125 0.078125 C 2.363281 -0.773438 1.941406 -1.6875 1.546875 -2.65625 C 1.148438 -3.625 0.828125 -4.59375 0.578125 -5.5625 L 1.65625 -5.5625 C 1.738281 -5.25 1.832031 -4.90625 1.9375 -4.53125 C 2.039062 -4.15625 2.160156 -3.769531 2.296875 -3.375 C 2.441406 -2.988281 2.585938 -2.597656 2.734375 -2.203125 C 2.890625 -1.804688 3.054688 -1.425781 3.234375 -1.0625 C 3.367188 -1.4375 3.488281 -1.800781 3.59375 -2.15625 C 3.707031 -2.519531 3.8125 -2.882812 3.90625 -3.25 C 4.007812 -3.613281 4.109375 -3.984375 4.203125 -4.359375 C 4.296875 -4.742188 4.394531 -5.144531 4.5 -5.5625 L 5.53125 -5.5625 C 5.269531 -4.53125 4.984375 -3.523438 4.671875 -2.546875 C 4.359375 -1.566406 4.019531 -0.660156 3.65625 0.171875 C 3.519531 0.484375 3.375 0.753906 3.21875 0.984375 C 3.0625 1.222656 2.890625 1.414062 2.703125 1.5625 C 2.523438 1.71875 2.316406 1.832031 2.078125 1.90625 C 1.847656 1.976562 1.585938 2.015625 1.296875 2.015625 C 1.140625 2.015625 0.972656 1.992188 0.796875 1.953125 C 0.617188 1.910156 0.5 1.875 0.4375 1.84375 Z M 0.609375 1.046875 "/> +</symbol> +<symbol overflow="visible" id="glyph1-20"> +<path style="stroke:none;" d="M 0.34375 -3.71875 C 0.34375 -4.382812 0.40625 -4.960938 0.53125 -5.453125 C 0.664062 -5.941406 0.847656 -6.34375 1.078125 -6.65625 C 1.304688 -6.96875 1.582031 -7.203125 1.90625 -7.359375 C 2.238281 -7.515625 2.601562 -7.59375 3 -7.59375 C 3.394531 -7.59375 3.753906 -7.515625 4.078125 -7.359375 C 4.410156 -7.203125 4.691406 -6.96875 4.921875 -6.65625 C 5.148438 -6.34375 5.328125 -5.941406 5.453125 -5.453125 C 5.585938 -4.960938 5.65625 -4.382812 5.65625 -3.71875 C 5.65625 -3.050781 5.585938 -2.472656 5.453125 -1.984375 C 5.328125 -1.503906 5.148438 -1.101562 4.921875 -0.78125 C 4.691406 -0.457031 4.410156 -0.21875 4.078125 -0.0625 C 3.753906 0.0820312 3.394531 0.15625 3 0.15625 C 2.601562 0.15625 2.238281 0.0820312 1.90625 -0.0625 C 1.582031 -0.21875 1.304688 -0.457031 1.078125 -0.78125 C 0.847656 -1.101562 0.664062 -1.503906 0.53125 -1.984375 C 0.40625 -2.472656 0.34375 -3.050781 0.34375 -3.71875 Z M 1.359375 -3.71875 C 1.359375 -2.738281 1.488281 -1.988281 1.75 -1.46875 C 2.007812 -0.957031 2.414062 -0.703125 2.96875 -0.703125 C 3.53125 -0.703125 3.953125 -0.957031 4.234375 -1.46875 C 4.515625 -1.988281 4.65625 -2.738281 4.65625 -3.71875 C 4.65625 -4.695312 4.515625 -5.445312 4.234375 -5.96875 C 3.953125 -6.488281 3.53125 -6.75 2.96875 -6.75 C 2.414062 -6.75 2.007812 -6.488281 1.75 -5.96875 C 1.488281 -5.445312 1.359375 -4.695312 1.359375 -3.71875 Z M 1.359375 -3.71875 "/> +</symbol> +<symbol overflow="visible" id="glyph1-21"> +<path style="stroke:none;" d="M 5.140625 -0.15625 C 4.929688 -0.101562 4.644531 -0.046875 4.28125 0.015625 C 3.925781 0.0859375 3.507812 0.125 3.03125 0.125 C 2.613281 0.125 2.265625 0.0625 1.984375 -0.0625 C 1.703125 -0.1875 1.472656 -0.363281 1.296875 -0.59375 C 1.117188 -0.820312 0.992188 -1.09375 0.921875 -1.40625 C 0.847656 -1.71875 0.8125 -2.0625 0.8125 -2.4375 L 0.8125 -5.5625 L 1.796875 -5.5625 L 1.796875 -2.65625 C 1.796875 -1.96875 1.894531 -1.476562 2.09375 -1.1875 C 2.300781 -0.894531 2.644531 -0.75 3.125 -0.75 C 3.226562 -0.75 3.332031 -0.753906 3.4375 -0.765625 C 3.550781 -0.773438 3.65625 -0.785156 3.75 -0.796875 C 3.851562 -0.804688 3.9375 -0.816406 4 -0.828125 C 4.070312 -0.847656 4.125 -0.859375 4.15625 -0.859375 L 4.15625 -5.5625 L 5.140625 -5.5625 Z M 5.140625 -0.15625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-22"> +<path style="stroke:none;" d="M 2.921875 -5.5625 L 5.265625 -5.5625 L 5.265625 -4.734375 L 2.921875 -4.734375 L 2.921875 -2.140625 C 2.921875 -1.867188 2.9375 -1.644531 2.96875 -1.46875 C 3.007812 -1.289062 3.078125 -1.144531 3.171875 -1.03125 C 3.265625 -0.925781 3.382812 -0.851562 3.53125 -0.8125 C 3.675781 -0.769531 3.851562 -0.75 4.0625 -0.75 C 4.34375 -0.75 4.570312 -0.773438 4.75 -0.828125 C 4.925781 -0.878906 5.09375 -0.941406 5.25 -1.015625 L 5.40625 -0.1875 C 5.289062 -0.132812 5.109375 -0.0703125 4.859375 0 C 4.617188 0.0820312 4.316406 0.125 3.953125 0.125 C 3.546875 0.125 3.207031 0.078125 2.9375 -0.015625 C 2.675781 -0.109375 2.46875 -0.25 2.3125 -0.4375 C 2.164062 -0.632812 2.066406 -0.875 2.015625 -1.15625 C 1.960938 -1.4375 1.9375 -1.765625 1.9375 -2.140625 L 1.9375 -4.734375 L 0.75 -4.734375 L 0.75 -5.5625 L 1.9375 -5.5625 L 1.9375 -7.125 L 2.921875 -7.296875 Z M 2.921875 -5.5625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-23"> +<path style="stroke:none;" d="M 4.5 -2.765625 C 4.5 -3.421875 4.347656 -3.925781 4.046875 -4.28125 C 3.742188 -4.632812 3.347656 -4.8125 2.859375 -4.8125 C 2.585938 -4.8125 2.375 -4.796875 2.21875 -4.765625 C 2.0625 -4.742188 1.9375 -4.71875 1.84375 -4.6875 L 1.84375 -1.171875 C 1.957031 -1.066406 2.117188 -0.96875 2.328125 -0.875 C 2.546875 -0.789062 2.773438 -0.75 3.015625 -0.75 C 3.273438 -0.75 3.5 -0.800781 3.6875 -0.90625 C 3.875 -1.007812 4.023438 -1.148438 4.140625 -1.328125 C 4.265625 -1.515625 4.351562 -1.726562 4.40625 -1.96875 C 4.46875 -2.21875 4.5 -2.484375 4.5 -2.765625 Z M 5.515625 -2.765625 C 5.515625 -2.347656 5.460938 -1.957031 5.359375 -1.59375 C 5.253906 -1.238281 5.097656 -0.929688 4.890625 -0.671875 C 4.679688 -0.421875 4.429688 -0.222656 4.140625 -0.078125 C 3.847656 0.0546875 3.507812 0.125 3.125 0.125 C 2.832031 0.125 2.570312 0.0859375 2.34375 0.015625 C 2.125 -0.046875 1.957031 -0.125 1.84375 -0.21875 L 1.84375 1.984375 L 0.859375 1.984375 L 0.859375 -5.40625 C 1.066406 -5.46875 1.34375 -5.53125 1.6875 -5.59375 C 2.03125 -5.65625 2.421875 -5.6875 2.859375 -5.6875 C 3.253906 -5.6875 3.613281 -5.617188 3.9375 -5.484375 C 4.269531 -5.347656 4.550781 -5.15625 4.78125 -4.90625 C 5.019531 -4.65625 5.203125 -4.347656 5.328125 -3.984375 C 5.453125 -3.617188 5.515625 -3.210938 5.515625 -2.765625 Z M 5.515625 -2.765625 "/> +</symbol> +<symbol overflow="visible" id="glyph1-24"> +<path style="stroke:none;" d="M 3.015625 -3.734375 L 4.15625 -7.421875 L 5.09375 -7.421875 C 5.25 -6.253906 5.359375 -5.054688 5.421875 -3.828125 C 5.492188 -2.609375 5.554688 -1.332031 5.609375 0 L 4.65625 0 C 4.644531 -0.425781 4.632812 -0.890625 4.625 -1.390625 C 4.625 -1.898438 4.613281 -2.421875 4.59375 -2.953125 C 4.582031 -3.492188 4.570312 -4.039062 4.5625 -4.59375 C 4.550781 -5.144531 4.539062 -5.679688 4.53125 -6.203125 L 3.4375 -2.8125 L 2.578125 -2.8125 L 1.46875 -6.203125 C 1.46875 -5.679688 1.457031 -5.144531 1.4375 -4.59375 C 1.425781 -4.050781 1.414062 -3.507812 1.40625 -2.96875 C 1.394531 -2.425781 1.382812 -1.898438 1.375 -1.390625 C 1.363281 -0.890625 1.351562 -0.425781 1.34375 0 L 0.390625 0 C 0.410156 -0.601562 0.4375 -1.222656 0.46875 -1.859375 C 0.5 -2.503906 0.535156 -3.144531 0.578125 -3.78125 C 0.617188 -4.414062 0.671875 -5.039062 0.734375 -5.65625 C 0.796875 -6.269531 0.863281 -6.859375 0.9375 -7.421875 L 1.84375 -7.421875 Z M 3.015625 -3.734375 "/> +</symbol> +<symbol overflow="visible" id="glyph2-0"> +<path style="stroke:none;" d="M 0.640625 2.296875 L 0.640625 -9.171875 L 7.140625 -9.171875 L 7.140625 2.296875 Z M 1.375 1.578125 L 6.421875 1.578125 L 6.421875 -8.4375 L 1.375 -8.4375 Z M 1.375 1.578125 "/> +</symbol> +<symbol overflow="visible" id="glyph2-1"> +<path style="stroke:none;" d="M 6.34375 -6.84375 L 6.34375 -5.75 C 6.007812 -5.925781 5.675781 -6.0625 5.34375 -6.15625 C 5.007812 -6.25 4.675781 -6.296875 4.34375 -6.296875 C 3.582031 -6.296875 2.992188 -6.050781 2.578125 -5.5625 C 2.160156 -5.082031 1.953125 -4.410156 1.953125 -3.546875 C 1.953125 -2.679688 2.160156 -2.007812 2.578125 -1.53125 C 2.992188 -1.050781 3.582031 -0.8125 4.34375 -0.8125 C 4.675781 -0.8125 5.007812 -0.851562 5.34375 -0.9375 C 5.675781 -1.03125 6.007812 -1.171875 6.34375 -1.359375 L 6.34375 -0.265625 C 6.019531 -0.117188 5.679688 -0.0078125 5.328125 0.0625 C 4.984375 0.144531 4.613281 0.1875 4.21875 0.1875 C 3.144531 0.1875 2.289062 -0.144531 1.65625 -0.8125 C 1.03125 -1.488281 0.71875 -2.398438 0.71875 -3.546875 C 0.71875 -4.703125 1.035156 -5.613281 1.671875 -6.28125 C 2.304688 -6.945312 3.179688 -7.28125 4.296875 -7.28125 C 4.648438 -7.28125 5 -7.242188 5.34375 -7.171875 C 5.6875 -7.097656 6.019531 -6.988281 6.34375 -6.84375 Z M 6.34375 -6.84375 "/> +</symbol> +<symbol overflow="visible" id="glyph2-2"> +<path style="stroke:none;" d="M 5.34375 -6.015625 C 5.207031 -6.085938 5.0625 -6.140625 4.90625 -6.171875 C 4.757812 -6.210938 4.59375 -6.234375 4.40625 -6.234375 C 3.75 -6.234375 3.242188 -6.019531 2.890625 -5.59375 C 2.535156 -5.164062 2.359375 -4.550781 2.359375 -3.75 L 2.359375 0 L 1.1875 0 L 1.1875 -7.109375 L 2.359375 -7.109375 L 2.359375 -6 C 2.597656 -6.4375 2.914062 -6.757812 3.3125 -6.96875 C 3.707031 -7.175781 4.1875 -7.28125 4.75 -7.28125 C 4.832031 -7.28125 4.921875 -7.273438 5.015625 -7.265625 C 5.109375 -7.253906 5.21875 -7.238281 5.34375 -7.21875 Z M 5.34375 -6.015625 "/> +</symbol> +<symbol overflow="visible" id="glyph2-3"> +<path style="stroke:none;" d="M 3.984375 -6.296875 C 3.359375 -6.296875 2.863281 -6.050781 2.5 -5.5625 C 2.132812 -5.070312 1.953125 -4.398438 1.953125 -3.546875 C 1.953125 -2.691406 2.128906 -2.019531 2.484375 -1.53125 C 2.847656 -1.050781 3.347656 -0.8125 3.984375 -0.8125 C 4.597656 -0.8125 5.085938 -1.054688 5.453125 -1.546875 C 5.816406 -2.035156 6 -2.703125 6 -3.546875 C 6 -4.390625 5.816406 -5.054688 5.453125 -5.546875 C 5.085938 -6.046875 4.597656 -6.296875 3.984375 -6.296875 Z M 3.984375 -7.28125 C 4.992188 -7.28125 5.789062 -6.945312 6.375 -6.28125 C 6.957031 -5.625 7.25 -4.710938 7.25 -3.546875 C 7.25 -2.378906 6.957031 -1.460938 6.375 -0.796875 C 5.789062 -0.140625 4.992188 0.1875 3.984375 0.1875 C 2.960938 0.1875 2.160156 -0.140625 1.578125 -0.796875 C 1.003906 -1.460938 0.71875 -2.378906 0.71875 -3.546875 C 0.71875 -4.710938 1.003906 -5.625 1.578125 -6.28125 C 2.160156 -6.945312 2.960938 -7.28125 3.984375 -7.28125 Z M 3.984375 -7.28125 "/> +</symbol> +<symbol overflow="visible" id="glyph2-4"> +<path style="stroke:none;" d="M 2.359375 -1.0625 L 2.359375 2.703125 L 1.1875 2.703125 L 1.1875 -7.109375 L 2.359375 -7.109375 L 2.359375 -6.03125 C 2.597656 -6.457031 2.90625 -6.769531 3.28125 -6.96875 C 3.65625 -7.175781 4.101562 -7.28125 4.625 -7.28125 C 5.488281 -7.28125 6.191406 -6.9375 6.734375 -6.25 C 7.273438 -5.5625 7.546875 -4.660156 7.546875 -3.546875 C 7.546875 -2.429688 7.273438 -1.53125 6.734375 -0.84375 C 6.191406 -0.15625 5.488281 0.1875 4.625 0.1875 C 4.101562 0.1875 3.65625 0.0820312 3.28125 -0.125 C 2.90625 -0.332031 2.597656 -0.644531 2.359375 -1.0625 Z M 6.328125 -3.546875 C 6.328125 -4.410156 6.148438 -5.082031 5.796875 -5.5625 C 5.441406 -6.050781 4.957031 -6.296875 4.34375 -6.296875 C 3.726562 -6.296875 3.242188 -6.050781 2.890625 -5.5625 C 2.535156 -5.082031 2.359375 -4.410156 2.359375 -3.546875 C 2.359375 -2.691406 2.535156 -2.019531 2.890625 -1.53125 C 3.242188 -1.039062 3.726562 -0.796875 4.34375 -0.796875 C 4.957031 -0.796875 5.441406 -1.039062 5.796875 -1.53125 C 6.148438 -2.019531 6.328125 -2.691406 6.328125 -3.546875 Z M 6.328125 -3.546875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-5"> +<path style="stroke:none;" d="M 5.75 -6.90625 L 5.75 -5.796875 C 5.425781 -5.960938 5.085938 -6.085938 4.734375 -6.171875 C 4.378906 -6.253906 4.007812 -6.296875 3.625 -6.296875 C 3.039062 -6.296875 2.601562 -6.207031 2.3125 -6.03125 C 2.03125 -5.851562 1.890625 -5.585938 1.890625 -5.234375 C 1.890625 -4.960938 1.988281 -4.75 2.1875 -4.59375 C 2.394531 -4.445312 2.816406 -4.300781 3.453125 -4.15625 L 3.84375 -4.0625 C 4.675781 -3.882812 5.265625 -3.632812 5.609375 -3.3125 C 5.960938 -2.988281 6.140625 -2.539062 6.140625 -1.96875 C 6.140625 -1.300781 5.878906 -0.773438 5.359375 -0.390625 C 4.835938 -0.00390625 4.117188 0.1875 3.203125 0.1875 C 2.816406 0.1875 2.414062 0.148438 2 0.078125 C 1.59375 0.00390625 1.160156 -0.109375 0.703125 -0.265625 L 0.703125 -1.46875 C 1.140625 -1.238281 1.566406 -1.066406 1.984375 -0.953125 C 2.398438 -0.847656 2.8125 -0.796875 3.21875 -0.796875 C 3.769531 -0.796875 4.191406 -0.890625 4.484375 -1.078125 C 4.785156 -1.265625 4.9375 -1.53125 4.9375 -1.875 C 4.9375 -2.1875 4.828125 -2.425781 4.609375 -2.59375 C 4.398438 -2.769531 3.9375 -2.9375 3.21875 -3.09375 L 2.8125 -3.1875 C 2.082031 -3.34375 1.554688 -3.578125 1.234375 -3.890625 C 0.910156 -4.203125 0.75 -4.632812 0.75 -5.1875 C 0.75 -5.851562 0.984375 -6.367188 1.453125 -6.734375 C 1.929688 -7.097656 2.609375 -7.28125 3.484375 -7.28125 C 3.910156 -7.28125 4.316406 -7.25 4.703125 -7.1875 C 5.085938 -7.125 5.4375 -7.03125 5.75 -6.90625 Z M 5.75 -6.90625 "/> +</symbol> +<symbol overflow="visible" id="glyph2-6"> +<path style="stroke:none;" d="M 4.453125 -3.578125 C 3.515625 -3.578125 2.863281 -3.46875 2.5 -3.25 C 2.132812 -3.03125 1.953125 -2.660156 1.953125 -2.140625 C 1.953125 -1.734375 2.085938 -1.40625 2.359375 -1.15625 C 2.628906 -0.914062 3 -0.796875 3.46875 -0.796875 C 4.113281 -0.796875 4.632812 -1.023438 5.03125 -1.484375 C 5.425781 -1.941406 5.625 -2.550781 5.625 -3.3125 L 5.625 -3.578125 Z M 6.78125 -4.0625 L 6.78125 0 L 5.625 0 L 5.625 -1.078125 C 5.351562 -0.648438 5.019531 -0.332031 4.625 -0.125 C 4.226562 0.0820312 3.738281 0.1875 3.15625 0.1875 C 2.425781 0.1875 1.847656 -0.015625 1.421875 -0.421875 C 0.992188 -0.835938 0.78125 -1.382812 0.78125 -2.0625 C 0.78125 -2.863281 1.046875 -3.46875 1.578125 -3.875 C 2.117188 -4.28125 2.921875 -4.484375 3.984375 -4.484375 L 5.625 -4.484375 L 5.625 -4.609375 C 5.625 -5.140625 5.445312 -5.550781 5.09375 -5.84375 C 4.738281 -6.144531 4.238281 -6.296875 3.59375 -6.296875 C 3.1875 -6.296875 2.789062 -6.242188 2.40625 -6.140625 C 2.019531 -6.046875 1.648438 -5.898438 1.296875 -5.703125 L 1.296875 -6.78125 C 1.722656 -6.945312 2.140625 -7.070312 2.546875 -7.15625 C 2.953125 -7.238281 3.34375 -7.28125 3.71875 -7.28125 C 4.75 -7.28125 5.515625 -7.015625 6.015625 -6.484375 C 6.523438 -5.953125 6.78125 -5.144531 6.78125 -4.0625 Z M 6.78125 -4.0625 "/> +</symbol> +<symbol overflow="visible" id="glyph2-7"> +<path style="stroke:none;" d="M 1.21875 -9.875 L 2.390625 -9.875 L 2.390625 0 L 1.21875 0 Z M 1.21875 -9.875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-8"> +<path style="stroke:none;" d="M 7.3125 -3.84375 L 7.3125 -3.28125 L 1.9375 -3.28125 C 1.988281 -2.46875 2.226562 -1.851562 2.65625 -1.4375 C 3.09375 -1.019531 3.695312 -0.8125 4.46875 -0.8125 C 4.914062 -0.8125 5.347656 -0.863281 5.765625 -0.96875 C 6.191406 -1.082031 6.613281 -1.25 7.03125 -1.46875 L 7.03125 -0.359375 C 6.613281 -0.179688 6.179688 -0.046875 5.734375 0.046875 C 5.296875 0.140625 4.851562 0.1875 4.40625 0.1875 C 3.269531 0.1875 2.367188 -0.140625 1.703125 -0.796875 C 1.046875 -1.460938 0.71875 -2.359375 0.71875 -3.484375 C 0.71875 -4.648438 1.03125 -5.570312 1.65625 -6.25 C 2.289062 -6.9375 3.140625 -7.28125 4.203125 -7.28125 C 5.160156 -7.28125 5.914062 -6.972656 6.46875 -6.359375 C 7.03125 -5.742188 7.3125 -4.90625 7.3125 -3.84375 Z M 6.140625 -4.1875 C 6.128906 -4.820312 5.945312 -5.332031 5.59375 -5.71875 C 5.25 -6.101562 4.789062 -6.296875 4.21875 -6.296875 C 3.5625 -6.296875 3.035156 -6.109375 2.640625 -5.734375 C 2.253906 -5.367188 2.03125 -4.851562 1.96875 -4.1875 Z M 6.140625 -4.1875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-9"> +<path style="stroke:none;" d="M 6.328125 -3.546875 C 6.328125 -4.410156 6.148438 -5.082031 5.796875 -5.5625 C 5.441406 -6.050781 4.957031 -6.296875 4.34375 -6.296875 C 3.726562 -6.296875 3.242188 -6.050781 2.890625 -5.5625 C 2.535156 -5.082031 2.359375 -4.410156 2.359375 -3.546875 C 2.359375 -2.691406 2.535156 -2.019531 2.890625 -1.53125 C 3.242188 -1.039062 3.726562 -0.796875 4.34375 -0.796875 C 4.957031 -0.796875 5.441406 -1.039062 5.796875 -1.53125 C 6.148438 -2.019531 6.328125 -2.691406 6.328125 -3.546875 Z M 2.359375 -6.03125 C 2.597656 -6.457031 2.90625 -6.769531 3.28125 -6.96875 C 3.65625 -7.175781 4.101562 -7.28125 4.625 -7.28125 C 5.488281 -7.28125 6.191406 -6.9375 6.734375 -6.25 C 7.273438 -5.5625 7.546875 -4.660156 7.546875 -3.546875 C 7.546875 -2.429688 7.273438 -1.53125 6.734375 -0.84375 C 6.191406 -0.15625 5.488281 0.1875 4.625 0.1875 C 4.101562 0.1875 3.65625 0.0820312 3.28125 -0.125 C 2.90625 -0.332031 2.597656 -0.644531 2.359375 -1.0625 L 2.359375 0 L 1.1875 0 L 1.1875 -9.875 L 2.359375 -9.875 Z M 2.359375 -6.03125 "/> +</symbol> +<symbol overflow="visible" id="glyph2-10"> +<path style="stroke:none;" d="M 1.21875 -7.109375 L 2.390625 -7.109375 L 2.390625 0 L 1.21875 0 Z M 1.21875 -9.875 L 2.390625 -9.875 L 2.390625 -8.390625 L 1.21875 -8.390625 Z M 1.21875 -9.875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-11"> +<path style="stroke:none;" d="M 7.140625 -4.296875 L 7.140625 0 L 5.96875 0 L 5.96875 -4.25 C 5.96875 -4.925781 5.835938 -5.429688 5.578125 -5.765625 C 5.316406 -6.097656 4.921875 -6.265625 4.390625 -6.265625 C 3.765625 -6.265625 3.269531 -6.0625 2.90625 -5.65625 C 2.539062 -5.257812 2.359375 -4.710938 2.359375 -4.015625 L 2.359375 0 L 1.1875 0 L 1.1875 -7.109375 L 2.359375 -7.109375 L 2.359375 -6 C 2.640625 -6.425781 2.96875 -6.742188 3.34375 -6.953125 C 3.71875 -7.171875 4.15625 -7.28125 4.65625 -7.28125 C 5.46875 -7.28125 6.082031 -7.023438 6.5 -6.515625 C 6.925781 -6.015625 7.140625 -5.273438 7.140625 -4.296875 Z M 7.140625 -4.296875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-12"> +<path style="stroke:none;" d="M 5.90625 -3.640625 C 5.90625 -4.484375 5.726562 -5.132812 5.375 -5.59375 C 5.03125 -6.0625 4.539062 -6.296875 3.90625 -6.296875 C 3.28125 -6.296875 2.789062 -6.0625 2.4375 -5.59375 C 2.09375 -5.132812 1.921875 -4.484375 1.921875 -3.640625 C 1.921875 -2.796875 2.09375 -2.140625 2.4375 -1.671875 C 2.789062 -1.210938 3.28125 -0.984375 3.90625 -0.984375 C 4.539062 -0.984375 5.03125 -1.210938 5.375 -1.671875 C 5.726562 -2.140625 5.90625 -2.796875 5.90625 -3.640625 Z M 7.078125 -0.875 C 7.078125 0.332031 6.804688 1.226562 6.265625 1.8125 C 5.722656 2.40625 4.898438 2.703125 3.796875 2.703125 C 3.390625 2.703125 3.003906 2.671875 2.640625 2.609375 C 2.273438 2.546875 1.921875 2.453125 1.578125 2.328125 L 1.578125 1.1875 C 1.921875 1.375 2.257812 1.507812 2.59375 1.59375 C 2.925781 1.6875 3.265625 1.734375 3.609375 1.734375 C 4.378906 1.734375 4.953125 1.535156 5.328125 1.140625 C 5.710938 0.742188 5.90625 0.140625 5.90625 -0.671875 L 5.90625 -1.25 C 5.664062 -0.832031 5.351562 -0.519531 4.96875 -0.3125 C 4.59375 -0.101562 4.144531 0 3.625 0 C 2.75 0 2.046875 -0.332031 1.515625 -1 C 0.984375 -1.664062 0.71875 -2.546875 0.71875 -3.640625 C 0.71875 -4.734375 0.984375 -5.613281 1.515625 -6.28125 C 2.046875 -6.945312 2.75 -7.28125 3.625 -7.28125 C 4.144531 -7.28125 4.59375 -7.175781 4.96875 -6.96875 C 5.351562 -6.757812 5.664062 -6.445312 5.90625 -6.03125 L 5.90625 -7.109375 L 7.078125 -7.109375 Z M 7.078125 -0.875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-13"> +<path style="stroke:none;" d="M 5.125 -8.609375 C 4.1875 -8.609375 3.441406 -8.257812 2.890625 -7.5625 C 2.347656 -6.875 2.078125 -5.929688 2.078125 -4.734375 C 2.078125 -3.535156 2.347656 -2.585938 2.890625 -1.890625 C 3.441406 -1.203125 4.1875 -0.859375 5.125 -0.859375 C 6.050781 -0.859375 6.785156 -1.203125 7.328125 -1.890625 C 7.878906 -2.585938 8.15625 -3.535156 8.15625 -4.734375 C 8.15625 -5.929688 7.878906 -6.875 7.328125 -7.5625 C 6.785156 -8.257812 6.050781 -8.609375 5.125 -8.609375 Z M 5.125 -9.65625 C 6.445312 -9.65625 7.503906 -9.207031 8.296875 -8.3125 C 9.097656 -7.414062 9.5 -6.222656 9.5 -4.734375 C 9.5 -3.234375 9.097656 -2.035156 8.296875 -1.140625 C 7.503906 -0.253906 6.445312 0.1875 5.125 0.1875 C 3.789062 0.1875 2.722656 -0.253906 1.921875 -1.140625 C 1.128906 -2.035156 0.734375 -3.234375 0.734375 -4.734375 C 0.734375 -6.222656 1.128906 -7.414062 1.921875 -8.3125 C 2.722656 -9.207031 3.789062 -9.65625 5.125 -9.65625 Z M 5.125 -9.65625 "/> +</symbol> +<symbol overflow="visible" id="glyph2-14"> +<path style="stroke:none;" d="M 1.109375 -2.8125 L 1.109375 -7.109375 L 2.265625 -7.109375 L 2.265625 -2.84375 C 2.265625 -2.175781 2.394531 -1.671875 2.65625 -1.328125 C 2.925781 -0.992188 3.320312 -0.828125 3.84375 -0.828125 C 4.476562 -0.828125 4.976562 -1.023438 5.34375 -1.421875 C 5.707031 -1.828125 5.890625 -2.378906 5.890625 -3.078125 L 5.890625 -7.109375 L 7.0625 -7.109375 L 7.0625 0 L 5.890625 0 L 5.890625 -1.09375 C 5.609375 -0.65625 5.28125 -0.332031 4.90625 -0.125 C 4.53125 0.0820312 4.09375 0.1875 3.59375 0.1875 C 2.78125 0.1875 2.160156 -0.0664062 1.734375 -0.578125 C 1.316406 -1.085938 1.109375 -1.832031 1.109375 -2.8125 Z M 4.046875 -7.28125 Z M 4.046875 -7.28125 "/> +</symbol> +<symbol overflow="visible" id="glyph2-15"> +<path style="stroke:none;" d="M 2.375 -9.125 L 2.375 -7.109375 L 4.78125 -7.109375 L 4.78125 -6.203125 L 2.375 -6.203125 L 2.375 -2.34375 C 2.375 -1.757812 2.453125 -1.382812 2.609375 -1.21875 C 2.773438 -1.0625 3.101562 -0.984375 3.59375 -0.984375 L 4.78125 -0.984375 L 4.78125 0 L 3.59375 0 C 2.6875 0 2.0625 -0.164062 1.71875 -0.5 C 1.375 -0.84375 1.203125 -1.457031 1.203125 -2.34375 L 1.203125 -6.203125 L 0.34375 -6.203125 L 0.34375 -7.109375 L 1.203125 -7.109375 L 1.203125 -9.125 Z M 2.375 -9.125 "/> +</symbol> +<symbol overflow="visible" id="glyph2-16"> +<path style="stroke:none;" d=""/> +</symbol> +<symbol overflow="visible" id="glyph2-17"> +<path style="stroke:none;" d="M 1.28125 -9.484375 L 6.71875 -9.484375 L 6.71875 -8.390625 L 2.5625 -8.390625 L 2.5625 -5.609375 L 6.3125 -5.609375 L 6.3125 -4.53125 L 2.5625 -4.53125 L 2.5625 0 L 1.28125 0 Z M 1.28125 -9.484375 "/> +</symbol> +<symbol overflow="visible" id="glyph2-18"> +<path style="stroke:none;" d="M 6.765625 -5.75 C 7.054688 -6.269531 7.40625 -6.65625 7.8125 -6.90625 C 8.21875 -7.15625 8.695312 -7.28125 9.25 -7.28125 C 9.988281 -7.28125 10.554688 -7.019531 10.953125 -6.5 C 11.359375 -5.976562 11.5625 -5.242188 11.5625 -4.296875 L 11.5625 0 L 10.390625 0 L 10.390625 -4.25 C 10.390625 -4.9375 10.265625 -5.441406 10.015625 -5.765625 C 9.773438 -6.097656 9.410156 -6.265625 8.921875 -6.265625 C 8.316406 -6.265625 7.835938 -6.0625 7.484375 -5.65625 C 7.128906 -5.257812 6.953125 -4.710938 6.953125 -4.015625 L 6.953125 0 L 5.78125 0 L 5.78125 -4.25 C 5.78125 -4.9375 5.660156 -5.441406 5.421875 -5.765625 C 5.179688 -6.097656 4.804688 -6.265625 4.296875 -6.265625 C 3.703125 -6.265625 3.226562 -6.0625 2.875 -5.65625 C 2.53125 -5.25 2.359375 -4.703125 2.359375 -4.015625 L 2.359375 0 L 1.1875 0 L 1.1875 -7.109375 L 2.359375 -7.109375 L 2.359375 -6 C 2.617188 -6.4375 2.9375 -6.757812 3.3125 -6.96875 C 3.6875 -7.175781 4.128906 -7.28125 4.640625 -7.28125 C 5.160156 -7.28125 5.597656 -7.148438 5.953125 -6.890625 C 6.316406 -6.628906 6.585938 -6.25 6.765625 -5.75 Z M 6.765625 -5.75 "/> +</symbol> +<symbol overflow="visible" id="glyph2-19"> +<path style="stroke:none;" d="M 6.953125 -9.171875 L 6.953125 -7.921875 C 6.472656 -8.148438 6.015625 -8.320312 5.578125 -8.4375 C 5.148438 -8.550781 4.734375 -8.609375 4.328125 -8.609375 C 3.628906 -8.609375 3.085938 -8.472656 2.703125 -8.203125 C 2.328125 -7.929688 2.140625 -7.546875 2.140625 -7.046875 C 2.140625 -6.628906 2.265625 -6.3125 2.515625 -6.09375 C 2.773438 -5.882812 3.253906 -5.710938 3.953125 -5.578125 L 4.734375 -5.421875 C 5.679688 -5.234375 6.382812 -4.910156 6.84375 -4.453125 C 7.300781 -3.992188 7.53125 -3.378906 7.53125 -2.609375 C 7.53125 -1.691406 7.222656 -0.992188 6.609375 -0.515625 C 5.992188 -0.046875 5.085938 0.1875 3.890625 0.1875 C 3.441406 0.1875 2.960938 0.132812 2.453125 0.03125 C 1.953125 -0.0703125 1.429688 -0.222656 0.890625 -0.421875 L 0.890625 -1.734375 C 1.410156 -1.441406 1.921875 -1.222656 2.421875 -1.078125 C 2.921875 -0.929688 3.410156 -0.859375 3.890625 -0.859375 C 4.628906 -0.859375 5.195312 -1 5.59375 -1.28125 C 5.988281 -1.570312 6.1875 -1.984375 6.1875 -2.515625 C 6.1875 -2.984375 6.039062 -3.347656 5.75 -3.609375 C 5.46875 -3.867188 5.003906 -4.066406 4.359375 -4.203125 L 3.578125 -4.359375 C 2.617188 -4.546875 1.925781 -4.84375 1.5 -5.25 C 1.070312 -5.65625 0.859375 -6.21875 0.859375 -6.9375 C 0.859375 -7.78125 1.148438 -8.441406 1.734375 -8.921875 C 2.328125 -9.410156 3.144531 -9.65625 4.1875 -9.65625 C 4.625 -9.65625 5.070312 -9.613281 5.53125 -9.53125 C 6 -9.445312 6.472656 -9.328125 6.953125 -9.171875 Z M 6.953125 -9.171875 "/> +</symbol> +<symbol overflow="visible" id="glyph2-20"> +<path style="stroke:none;" d="M 4.1875 0.65625 C 3.851562 1.507812 3.53125 2.0625 3.21875 2.3125 C 2.90625 2.570312 2.488281 2.703125 1.96875 2.703125 L 1.03125 2.703125 L 1.03125 1.734375 L 1.71875 1.734375 C 2.039062 1.734375 2.289062 1.65625 2.46875 1.5 C 2.644531 1.34375 2.835938 0.984375 3.046875 0.421875 L 3.265625 -0.109375 L 0.390625 -7.109375 L 1.625 -7.109375 L 3.84375 -1.546875 L 6.0625 -7.109375 L 7.3125 -7.109375 Z M 4.1875 0.65625 "/> +</symbol> +</g> +</defs> +<g id="surface268880"> +<rect x="0" y="0" width="774" height="152" style="fill:rgb(100%,100%,100%);fill-opacity:1;stroke:none;"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 21.75297 10.408118 L 26.433829 10.408118 L 26.433829 12.281165 L 21.75297 12.281165 Z M 21.75297 10.408118 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 29.079728 10.51222 L 32.829728 10.51222 L 32.829728 12.149915 L 29.079728 12.149915 Z M 29.079728 10.51222 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph0-1" x="20.171875" y="57.705621"/> + <use xlink:href="#glyph0-2" x="30.171875" y="57.705621"/> + <use xlink:href="#glyph0-3" x="40.171875" y="57.705621"/> + <use xlink:href="#glyph0-4" x="50.171875" y="57.705621"/> + <use xlink:href="#glyph0-5" x="60.171875" y="57.705621"/> + <use xlink:href="#glyph0-6" x="70.171875" y="57.705621"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph0-7" x="174.203125" y="60.053277"/> + <use xlink:href="#glyph0-8" x="184.203125" y="60.053277"/> +</g> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40.925236 10.544446 L 44.675236 10.544446 L 44.675236 12.090345 L 40.925236 12.090345 Z M 40.925236 10.544446 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 34.883439 10.536634 L 38.633439 10.536634 L 38.633439 12.120032 L 34.883439 12.120032 Z M 34.883439 10.536634 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 47.084806 10.484876 L 52.045743 10.484876 L 52.045743 12.130774 L 47.084806 12.130774 Z M 47.084806 10.484876 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 53.980118 10.376868 L 59.866642 10.376868 L 59.866642 12.279603 L 53.980118 12.279603 Z M 53.980118 10.376868 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(100%,100%,100%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 54.048478 13.825501 L 59.868009 13.825501 L 59.868009 15.490345 L 54.048478 15.490345 Z M 54.048478 13.825501 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 26.481876 11.338001 L 28.593009 11.332337 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 28.968009 11.33136 L 28.468595 11.582728 L 28.593009 11.332337 L 28.467228 11.082728 Z M 28.968009 11.33136 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 32.876798 11.329798 L 34.396525 11.328626 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 34.771525 11.328431 L 34.27172 11.578821 L 34.396525 11.328626 L 34.271329 11.078821 Z M 34.771525 11.328431 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 38.633439 11.328431 L 40.438517 11.319642 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40.813517 11.317884 L 40.314689 11.570228 L 40.438517 11.319642 L 40.312345 11.070423 Z M 40.813517 11.317884 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 44.675236 11.317298 L 46.597892 11.309876 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 46.972892 11.308313 L 46.473868 11.560267 L 46.597892 11.309876 L 46.471915 11.060267 Z M 46.972892 11.308313 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 52.045743 11.307923 L 53.4934 11.323157 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 53.8684 11.327063 L 53.365861 11.57179 L 53.4934 11.323157 L 53.370939 11.07179 Z M 53.8684 11.327063 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph0-9" x="286.757813" y="60.611871"/> + <use xlink:href="#glyph0-10" x="296.757813" y="60.611871"/> + <use xlink:href="#glyph0-1" x="306.757813" y="60.611871"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph0-11" x="405.660156" y="59.904839"/> + <use xlink:href="#glyph0-10" x="415.660156" y="59.904839"/> + <use xlink:href="#glyph0-12" x="425.660156" y="59.904839"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph1-1" x="511.308594" y="58.064616"/> + <use xlink:href="#glyph1-2" x="517.308757" y="58.064616"/> + <use xlink:href="#glyph1-3" x="523.308919" y="58.064616"/> + <use xlink:href="#glyph1-4" x="529.309082" y="58.064616"/> + <use xlink:href="#glyph1-5" x="535.309245" y="58.064616"/> + <use xlink:href="#glyph1-6" x="541.309408" y="58.064616"/> + <use xlink:href="#glyph1-7" x="547.30957" y="58.064616"/> + <use xlink:href="#glyph1-8" x="553.309733" y="58.064616"/> + <use xlink:href="#glyph1-9" x="559.309896" y="58.064616"/> + <use xlink:href="#glyph1-10" x="565.310059" y="58.064616"/> + <use xlink:href="#glyph1-11" x="571.310221" y="58.064616"/> + <use xlink:href="#glyph1-12" x="577.310384" y="58.064616"/> + <use xlink:href="#glyph1-13" x="583.310547" y="58.064616"/> + <use xlink:href="#glyph1-8" x="589.31071" y="58.064616"/> + <use xlink:href="#glyph1-14" x="595.310872" y="58.064616"/> +</g> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 45.671915 11.342298 L 45.655704 11.342298 L 45.655704 14.657923 L 53.561759 14.657923 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<path style="fill-rule:evenodd;fill:rgb(0%,0%,0%);fill-opacity:1;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 53.936759 14.657923 L 53.436759 14.907923 L 53.561759 14.657923 L 53.436759 14.407923 Z M 53.936759 14.657923 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph1-15" x="657.078125" y="57.724772"/> + <use xlink:href="#glyph1-16" x="663.078288" y="57.724772"/> + <use xlink:href="#glyph1-10" x="669.078451" y="57.724772"/> + <use xlink:href="#glyph1-6" x="675.078613" y="57.724772"/> + <use xlink:href="#glyph1-8" x="681.078776" y="57.724772"/> + <use xlink:href="#glyph1-17" x="687.078939" y="57.724772"/> + <use xlink:href="#glyph1-11" x="693.079102" y="57.724772"/> + <use xlink:href="#glyph1-18" x="699.079264" y="57.724772"/> + <use xlink:href="#glyph1-19" x="705.079427" y="57.724772"/> + <use xlink:href="#glyph1-4" x="711.07959" y="57.724772"/> + <use xlink:href="#glyph1-20" x="717.079753" y="57.724772"/> + <use xlink:href="#glyph1-21" x="723.079915" y="57.724772"/> + <use xlink:href="#glyph1-22" x="729.080078" y="57.724772"/> + <use xlink:href="#glyph1-23" x="735.080241" y="57.724772"/> + <use xlink:href="#glyph1-21" x="741.080404" y="57.724772"/> + <use xlink:href="#glyph1-22" x="747.080566" y="57.724772"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph1-24" x="673.335938" y="124.170085"/> + <use xlink:href="#glyph1-11" x="679.3361" y="124.170085"/> + <use xlink:href="#glyph1-13" x="685.336263" y="124.170085"/> + <use xlink:href="#glyph1-8" x="691.336426" y="124.170085"/> + <use xlink:href="#glyph1-4" x="697.336589" y="124.170085"/> + <use xlink:href="#glyph1-20" x="703.336751" y="124.170085"/> + <use xlink:href="#glyph1-21" x="709.336914" y="124.170085"/> + <use xlink:href="#glyph1-22" x="715.337077" y="124.170085"/> + <use xlink:href="#glyph1-23" x="721.33724" y="124.170085"/> + <use xlink:href="#glyph1-21" x="727.337402" y="124.170085"/> + <use xlink:href="#glyph1-22" x="733.337565" y="124.170085"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph2-1" x="168.71875" y="31.959093"/> + <use xlink:href="#glyph2-2" x="175.866102" y="31.959093"/> + <use xlink:href="#glyph2-3" x="180.92551" y="31.959093"/> + <use xlink:href="#glyph2-4" x="188.879069" y="31.959093"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph2-5" x="288.109375" y="31.681749"/> + <use xlink:href="#glyph2-1" x="294.882378" y="31.681749"/> + <use xlink:href="#glyph2-6" x="302.029731" y="31.681749"/> + <use xlink:href="#glyph2-7" x="309.996039" y="31.681749"/> + <use xlink:href="#glyph2-8" x="313.607964" y="31.681749"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph2-5" x="535.988281" y="33.365343"/> + <use xlink:href="#glyph2-1" x="542.761285" y="33.365343"/> + <use xlink:href="#glyph2-6" x="549.908637" y="33.365343"/> + <use xlink:href="#glyph2-7" x="557.874946" y="33.365343"/> + <use xlink:href="#glyph2-8" x="561.486871" y="33.365343"/> +</g> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph2-9" x="26.695313" y="32.365343"/> + <use xlink:href="#glyph2-10" x="34.947266" y="32.365343"/> + <use xlink:href="#glyph2-11" x="38.559191" y="32.365343"/> + <use xlink:href="#glyph2-11" x="46.798394" y="32.365343"/> + <use xlink:href="#glyph2-10" x="55.037598" y="32.365343"/> + <use xlink:href="#glyph2-11" x="58.649523" y="32.365343"/> + <use xlink:href="#glyph2-12" x="66.888726" y="32.365343"/> +</g> +<path style="fill:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.14,0.14;stroke-miterlimit:10;" d="M 45.300431 9.486438 L 60.373478 9.486438 L 60.373478 16.175696 L 45.300431 16.175696 Z M 45.300431 9.486438 " transform="matrix(20,0,0,20,-434.059401,-172.47877)"/> +<g style="fill:rgb(0%,0%,0%);fill-opacity:1;"> + <use xlink:href="#glyph2-13" x="532.003906" y="11.904405"/> + <use xlink:href="#glyph2-14" x="542.236382" y="11.904405"/> + <use xlink:href="#glyph2-15" x="550.475586" y="11.904405"/> + <use xlink:href="#glyph2-4" x="555.5727" y="11.904405"/> + <use xlink:href="#glyph2-14" x="563.824653" y="11.904405"/> + <use xlink:href="#glyph2-15" x="572.063856" y="11.904405"/> + <use xlink:href="#glyph2-16" x="577.16097" y="11.904405"/> + <use xlink:href="#glyph2-17" x="581.293186" y="11.904405"/> + <use xlink:href="#glyph2-3" x="588.307346" y="11.904405"/> + <use xlink:href="#glyph2-2" x="596.260905" y="11.904405"/> + <use xlink:href="#glyph2-18" x="601.377279" y="11.904405"/> + <use xlink:href="#glyph2-6" x="614.040853" y="11.904405"/> + <use xlink:href="#glyph2-15" x="622.007161" y="11.904405"/> + <use xlink:href="#glyph2-15" x="627.104275" y="11.904405"/> + <use xlink:href="#glyph2-8" x="632.201389" y="11.904405"/> + <use xlink:href="#glyph2-2" x="640.199436" y="11.904405"/> + <use xlink:href="#glyph2-16" x="645.544217" y="11.904405"/> + <use xlink:href="#glyph2-19" x="649.676432" y="11.904405"/> + <use xlink:href="#glyph2-20" x="657.928385" y="11.904405"/> + <use xlink:href="#glyph2-5" x="665.621799" y="11.904405"/> + <use xlink:href="#glyph2-15" x="672.394803" y="11.904405"/> + <use xlink:href="#glyph2-8" x="677.491916" y="11.904405"/> + <use xlink:href="#glyph2-18" x="685.489963" y="11.904405"/> +</g> +</g> +</svg> diff --git a/Documentation/media/v4l-drivers/vimc.rst b/Documentation/media/v4l-drivers/vimc.rst index 406417680db5..8f5d7f8d83bb 100644 --- a/Documentation/media/v4l-drivers/vimc.rst +++ b/Documentation/media/v4l-drivers/vimc.rst @@ -76,27 +76,19 @@ vimc-capture: * 1 Pad sink * 1 Pad source -Module options ---------------- -Vimc has a few module parameters to configure the driver. You should pass -those arguments to each subdevice, not to the vimc module. For example:: +Module options +-------------- - vimc_subdevice.param=value +Vimc has a module parameter to configure the driver. -* ``vimc_scaler.sca_mult=<unsigned int>`` +* ``sca_mult=<unsigned int>`` Image size multiplier factor to be used to multiply both width and height, so the image size will be ``sca_mult^2`` bigger than the original one. Currently, only supports scaling up (the default value is 3). -* ``vimc_debayer.deb_mean_win_size=<unsigned int>`` - - Window size to calculate the mean. Note: the window size needs to be an - odd number, as the main pixel stays in the center of the window, - otherwise the next odd number is considered (the default value is 3). - Source code documentation ------------------------- diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions index adeb6b7a15cb..cb6ccf91776e 100644 --- a/Documentation/media/videodev2.h.rst.exceptions +++ b/Documentation/media/videodev2.h.rst.exceptions @@ -141,6 +141,10 @@ replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_AREA :c:type:`v4l2_ctrl_type` # V4L2 capability defines replace define V4L2_CAP_VIDEO_CAPTURE device-capabilities @@ -434,6 +438,7 @@ replace define V4L2_DEC_CMD_START decoder-cmds replace define V4L2_DEC_CMD_STOP decoder-cmds replace define V4L2_DEC_CMD_PAUSE decoder-cmds replace define V4L2_DEC_CMD_RESUME decoder-cmds +replace define V4L2_DEC_CMD_FLUSH decoder-cmds replace define V4L2_DEC_CMD_START_MUTE_AUDIO decoder-cmds replace define V4L2_DEC_CMD_PAUSE_TO_BLACK decoder-cmds diff --git a/MAINTAINERS b/MAINTAINERS index 296de2b51c83..37a977cbac6f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4641,6 +4641,14 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org> S: Maintained F: drivers/net/fddi/defxx.* +DEINTERLACE DRIVERS FOR ALLWINNER H3 +M: Jernej Skrabec <jernej.skrabec@siol.net> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/platform/sunxi/sun8i-di/ +F: Documentation/devicetree/bindings/media/allwinner,sun8i-h3-deinterlace.yaml + DELL SMBIOS DRIVER M: Pali Rohár <pali.rohar@gmail.com> M: Mario Limonciello <mario.limonciello@dell.com> @@ -7546,6 +7554,13 @@ L: linux-kernel@vger.kernel.org S: Maintained F: arch/x86/kernel/cpu/hygon.c +HYNIX HI556 SENSOR DRIVER +M: Shawn Tu <shawnx.tu@intel.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/hi556.c + Hyper-V CORE AND DRIVERS M: "K. Y. Srinivasan" <kys@microsoft.com> M: Haiyang Zhang <haiyangz@microsoft.com> @@ -8327,6 +8342,7 @@ S: Maintained F: drivers/staging/media/ipu3/ F: Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst F: Documentation/media/v4l-drivers/ipu3.rst +F: Documentation/media/v4l-drivers/ipu3_rcb.svg INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT M: Krzysztof Halasa <khalasa@piap.pl> @@ -9860,7 +9876,7 @@ F: Documentation/hwmon/max16065.rst F: drivers/hwmon/max16065.c MAX2175 SDR TUNER DRIVER -M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com> +M: Ramesh Shanmugasundaram <rashanmu@gmail.com> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Maintained @@ -10122,7 +10138,7 @@ F: drivers/media/platform/renesas-ceu.c F: include/media/drv-intf/renesas-ceu.h MEDIA DRIVERS FOR RENESAS - DRIF -M: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com> +M: Ramesh Shanmugasundaram <rashanmu@gmail.com> L: linux-media@vger.kernel.org L: linux-renesas-soc@vger.kernel.org T: git git://linuxtv.org/media_tree.git @@ -10581,7 +10597,7 @@ W: http://linux-meson.com/ S: Supported F: drivers/media/platform/meson/ao-cec.c F: drivers/media/platform/meson/ao-cec-g12a.c -F: Documentation/devicetree/bindings/media/meson-ao-cec.txt +F: Documentation/devicetree/bindings/media/amlogic,meson-gx-ao-cec.yaml T: git git://linuxtv.org/media_tree.git MESON NAND CONTROLLER DRIVER FOR AMLOGIC SOCS @@ -15136,6 +15152,14 @@ S: Maintained F: drivers/media/i2c/imx274.c F: Documentation/devicetree/bindings/media/i2c/imx274.txt +SONY IMX290 SENSOR DRIVER +M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/imx290.c +F: Documentation/devicetree/bindings/media/i2c/imx290.txt + SONY IMX319 SENSOR DRIVER M: Bingbu Cao <bingbu.cao@intel.com> L: linux-media@vger.kernel.org @@ -16299,6 +16323,7 @@ W: http://linuxtv.org/ Q: http://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/platform/ti-vpe/ +F: Documentation/devicetree/bindings/media/ti,vpe.yaml TI WILINK WIRELESS DRIVERS L: linux-wireless@vger.kernel.org @@ -17196,6 +17221,7 @@ F: include/media/videobuf2-* VIMC VIRTUAL MEDIA CONTROLLER DRIVER M: Helen Koike <helen.koike@collabora.com> +R: Shuah Khan <skhan@linuxfoundation.org> L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: https://linuxtv.org diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts index 1d05d570142f..ce4b0679839d 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts @@ -252,6 +252,7 @@ }; &r_ir { + linux,rc-map-name = "rc-beelink-gs1"; status = "okay"; }; diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 5ef7daeb8cbd..9340435a94a0 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -319,6 +319,8 @@ static void cec_post_state_event(struct cec_adapter *adap) ev.state_change.phys_addr = adap->phys_addr; ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + ev.state_change.have_conn_info = + adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR; cec_queue_event(adap, &ev); } @@ -1976,7 +1978,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * Play function, this message can have variable length * depending on the specific play function that is used. */ - case 0x60: + case CEC_OP_UI_CMD_PLAY_FUNCTION: if (msg->len == 2) rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0); @@ -1993,8 +1995,12 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * For the time being these messages are not processed by the * framework and are simply forwarded to the user space. */ - case 0x56: case 0x57: - case 0x67: case 0x68: case 0x69: case 0x6a: + case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE: + case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION: + case CEC_OP_UI_CMD_TUNE_FUNCTION: + case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION: break; default: rc_keydown(adap->rc, RC_PROTO_CEC, msg->msg[2], 0); diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 12d676484472..17d1cb2e5f97 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -187,6 +187,21 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, return 0; } +static long cec_adap_g_connector_info(struct cec_adapter *adap, + struct cec_log_addrs __user *parg) +{ + int ret = 0; + + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) + return -ENOTTY; + + mutex_lock(&adap->lock); + if (copy_to_user(parg, &adap->conn_info, sizeof(adap->conn_info))) + ret = -EFAULT; + mutex_unlock(&adap->lock); + return ret; +} + static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, bool block, struct cec_msg __user *parg) { @@ -506,6 +521,9 @@ static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case CEC_ADAP_S_LOG_ADDRS: return cec_adap_s_log_addrs(adap, fh, block, parg); + case CEC_ADAP_G_CONNECTOR_INFO: + return cec_adap_g_connector_info(adap, parg); + case CEC_TRANSMIT: return cec_transmit(adap, fh, block, parg); @@ -578,6 +596,8 @@ static int cec_open(struct inode *inode, struct file *filp) /* Queue up initial state events */ ev.state_change.phys_addr = adap->phys_addr; ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + ev.state_change.have_conn_info = + adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR; cec_queue_event_fh(fh, &ev, 0); #ifdef CONFIG_CEC_PIN if (adap->pin && adap->pin->ops->read_hpd) { diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 9c610e1e99b8..db7adffcdc76 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -257,11 +257,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, struct cec_adapter *adap; int res; - /* - * Disable this capability until the connector info public API - * is ready. - */ - caps &= ~CEC_CAP_CONNECTOR_INFO; #ifndef CONFIG_MEDIA_CEC_RC caps &= ~CEC_CAP_RC; #endif diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index 8f987bc0dd88..660fe111f540 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -1279,6 +1279,15 @@ static void cec_pin_adap_free(struct cec_adapter *adap) kfree(pin); } +static int cec_pin_received(struct cec_adapter *adap, struct cec_msg *msg) +{ + struct cec_pin *pin = adap->pin; + + if (pin->ops->received) + return pin->ops->received(adap, msg); + return -ENOMSG; +} + void cec_pin_changed(struct cec_adapter *adap, bool value) { struct cec_pin *pin = adap->pin; @@ -1301,6 +1310,7 @@ static const struct cec_adap_ops cec_pin_adap_ops = { .error_inj_parse_line = cec_pin_error_inj_parse_line, .error_inj_show = cec_pin_error_inj_show, #endif + .received = cec_pin_received, }; struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 0ba51dacc580..c1511094fdc7 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -230,8 +230,8 @@ static char *siano_msgs[] = { [MSG_SMS_FLASH_DL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FLASH_DL_REQ", [MSG_SMS_EXEC_TEST_1_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_REQ", [MSG_SMS_EXEC_TEST_1_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_RES", - [MSG_SMS_ENBALE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_REQ", - [MSG_SMS_ENBALE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_RES", + [MSG_SMS_ENABLE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_TS_INTERFACE_REQ", + [MSG_SMS_ENABLE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_TS_INTERFACE_RES", [MSG_SMS_SPI_SET_BUS_WIDTH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_REQ", [MSG_SMS_SPI_SET_BUS_WIDTH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_RES", [MSG_SMS_SEND_EMM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_REQ", diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index a2f95f4899c2..b3b793b5caf3 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -434,8 +434,8 @@ enum msg_types { MSG_SMS_FLASH_DL_REQ = 732, MSG_SMS_EXEC_TEST_1_REQ = 734, MSG_SMS_EXEC_TEST_1_RES = 735, - MSG_SMS_ENBALE_TS_INTERFACE_REQ = 736, - MSG_SMS_ENBALE_TS_INTERFACE_RES = 737, + MSG_SMS_ENABLE_TS_INTERFACE_REQ = 736, + MSG_SMS_ENABLE_TS_INTERFACE_RES = 737, MSG_SMS_SPI_SET_BUS_WIDTH_REQ = 738, MSG_SMS_SPI_SET_BUS_WIDTH_RES = 739, MSG_SMS_SEND_EMM_REQ = 740, diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index b2c54c256e86..ada41d5c4e83 100644 --- a/drivers/media/common/siano/smsir.h +++ b/drivers/media/common/siano/smsir.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* - * SPDX-License-Identifier: GPL-2.0+ * * Siano Mobile Silicon, Inc. * MDTV receiver kernel modules. diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 5a9ba3846f0a..e652f4318284 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -49,8 +49,11 @@ module_param(debug, int, 0644); V4L2_BUF_FLAG_REQUEST_FD | \ V4L2_BUF_FLAG_TIMESTAMP_MASK) /* Output buffer flags that should be passed on to the driver */ -#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME | \ - V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_TIMECODE) +#define V4L2_BUFFER_OUT_FLAGS (V4L2_BUF_FLAG_PFRAME | \ + V4L2_BUF_FLAG_BFRAME | \ + V4L2_BUF_FLAG_KEYFRAME | \ + V4L2_BUF_FLAG_TIMECODE | \ + V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF) /* * __verify_planes_array() - verify that the planes array passed in struct @@ -194,6 +197,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b } vbuf->sequence = 0; vbuf->request_fd = -1; + vbuf->is_held = false; if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) { switch (b->memory) { @@ -321,6 +325,8 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b */ vbuf->flags &= ~V4L2_BUF_FLAG_TIMECODE; vbuf->field = b->field; + if (!(q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF)) + vbuf->flags &= ~V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; } else { /* Zero any output buffer flags as this is a capture buffer */ vbuf->flags &= ~V4L2_BUFFER_OUT_FLAGS; @@ -654,6 +660,8 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps) *caps |= V4L2_BUF_CAP_SUPPORTS_USERPTR; if (q->io_modes & VB2_DMABUF) *caps |= V4L2_BUF_CAP_SUPPORTS_DMABUF; + if (q->subsystem_flags & VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF) + *caps |= V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF; #ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API if (q->supports_requests) *caps |= V4L2_BUF_CAP_SUPPORTS_REQUESTS; diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 6f7eedb4c00e..0ba382948c51 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -298,7 +298,7 @@ int cxd2820r_sleep_c(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct i2c_client *client = priv->client[0]; int ret; - struct reg_val_mask tab[] = { + static const struct reg_val_mask tab[] = { { 0x000ff, 0x1f, 0xff }, { 0x00085, 0x00, 0xff }, { 0x00088, 0x01, 0xff }, diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index d56c6f788196..fbdfa6bf38dc 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -392,7 +392,7 @@ int cxd2820r_sleep_t(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct i2c_client *client = priv->client[0]; int ret; - struct reg_val_mask tab[] = { + static struct reg_val_mask tab[] = { { 0x000ff, 0x1f, 0xff }, { 0x00085, 0x00, 0xff }, { 0x00088, 0x01, 0xff }, diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index f924a80b968a..34ef2bb2de34 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -386,7 +386,7 @@ int cxd2820r_sleep_t2(struct dvb_frontend *fe) struct cxd2820r_priv *priv = fe->demodulator_priv; struct i2c_client *client = priv->client[0]; int ret; - struct reg_val_mask tab[] = { + static const struct reg_val_mask tab[] = { { 0x000ff, 0x1f, 0xff }, { 0x00085, 0x00, 0xff }, { 0x00088, 0x01, 0xff }, diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 1b30cf570803..758c95bc3b11 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -60,6 +60,7 @@ struct cxd2841er_priv { enum cxd2841er_xtal xtal; enum fe_caps caps; u32 flags; + unsigned long stats_time; }; static const struct cxd2841er_cnr_data s_cn_data[] = { @@ -3279,9 +3280,15 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; if (status & FE_HAS_LOCK) { + if (priv->stats_time && + (!time_after(jiffies, priv->stats_time))) + return 0; + + /* Prevent retrieving stats faster than once per second */ + priv->stats_time = jiffies + msecs_to_jiffies(1000); + cxd2841er_read_snr(fe); cxd2841er_read_ucblocks(fe); - cxd2841er_read_ber(fe); } else { p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; @@ -3360,6 +3367,9 @@ done: p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* Reset the wait for jiffies logic */ + priv->stats_time = 0; + return ret; } diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 2f5af4813a74..ac7be872f460 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -4201,7 +4201,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr, u16 *data, u32 flags) { u8 buf[2] = { 0 }; - int rc = -EIO; + int rc; u16 word = 0; if (!data) diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 4e50441c247a..a7faf0cf8788 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -517,7 +517,7 @@ static void mb86a20s_reset_frontend_cache(struct dvb_frontend *fe) * Estimates the bit rate using the per-segment bit rate given by * ABNT/NBR 15601 spec (table 4). */ -static u32 isdbt_rate[3][5][4] = { +static const u32 isdbt_rate[3][5][4] = { { /* DQPSK/QPSK */ { 280850, 312060, 330420, 340430 }, /* 1/2 */ { 374470, 416080, 440560, 453910 }, /* 2/3 */ @@ -539,13 +539,9 @@ static u32 isdbt_rate[3][5][4] = { } }; -static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, - u32 modulation, u32 forward_error_correction, - u32 guard_interval, - u32 segment) +static u32 isdbt_layer_min_bitrate(struct dtv_frontend_properties *c, + u32 layer) { - struct mb86a20s_state *state = fe->demodulator_priv; - u32 rate; int mod, fec, guard; /* @@ -553,7 +549,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, * to consider the lowest bit rate, to avoid taking too long time * to get BER. */ - switch (modulation) { + switch (c->layer[layer].modulation) { case DQPSK: case QPSK: default: @@ -567,7 +563,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, break; } - switch (forward_error_correction) { + switch (c->layer[layer].fec) { default: case FEC_1_2: case FEC_AUTO: @@ -587,7 +583,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, break; } - switch (guard_interval) { + switch (c->guard_interval) { default: case GUARD_INTERVAL_1_4: guard = 0; @@ -603,29 +599,14 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, break; } - /* Samples BER at BER_SAMPLING_RATE seconds */ - rate = isdbt_rate[mod][fec][guard] * segment * BER_SAMPLING_RATE; - - /* Avoids sampling too quickly or to overflow the register */ - if (rate < 256) - rate = 256; - else if (rate > (1 << 24) - 1) - rate = (1 << 24) - 1; - - dev_dbg(&state->i2c->dev, - "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n", - __func__, 'A' + layer, - segment * isdbt_rate[mod][fec][guard]/1000, - rate, rate); - - state->estimated_rate[layer] = rate; + return isdbt_rate[mod][fec][guard] * c->layer[layer].segment_count; } static int mb86a20s_get_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int layer, rc; + int layer, rc, rate, counter; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -676,10 +657,21 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe) dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n", __func__, rc); c->layer[layer].interleaving = rc; - mb86a20s_layer_bitrate(fe, layer, c->layer[layer].modulation, - c->layer[layer].fec, - c->guard_interval, - c->layer[layer].segment_count); + + rate = isdbt_layer_min_bitrate(c, layer); + counter = rate * BER_SAMPLING_RATE; + + /* Avoids sampling too quickly or to overflow the register */ + if (counter < 256) + counter = 256; + else if (counter > (1 << 24) - 1) + counter = (1 << 24) - 1; + + dev_dbg(&state->i2c->dev, + "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n", + __func__, 'A' + layer, rate / 1000, counter, counter); + + state->estimated_rate[layer] = counter; } rc = mb86a20s_writereg(state, 0x6d, 0x84); diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index 7cae7d632030..d43a67045dbe 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -135,11 +135,6 @@ static inline int mt312_writereg(struct mt312_state *state, return mt312_write(state, reg, &tmp, 1); } -static inline u32 mt312_div(u32 a, u32 b) -{ - return (a + (b / 2)) / b; -} - static int mt312_reset(struct mt312_state *state, const u8 full) { return mt312_writereg(state, RESET, full ? 0x80 : 0x40); @@ -187,7 +182,7 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr) monitor = (buf[0] << 8) | buf[1]; dprintk("sr(auto) = %u\n", - mt312_div(monitor * 15625, 4)); + DIV_ROUND_CLOSEST(monitor * 15625, 4)); } else { ret = mt312_writereg(state, MON_CTRL, 0x05); if (ret < 0) @@ -291,10 +286,10 @@ static int mt312_initfe(struct dvb_frontend *fe) } /* SYS_CLK */ - buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000); + buf[0] = DIV_ROUND_CLOSEST(state->xtal * state->freq_mult * 2, 1000000); /* DISEQC_RATIO */ - buf[1] = mt312_div(state->xtal, 22000 * 4); + buf[1] = DIV_ROUND_CLOSEST(state->xtal, 22000 * 4); ret = mt312_write(state, SYS_CLK, buf, sizeof(buf)); if (ret < 0) @@ -610,7 +605,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe) } /* sr = (u16)(sr * 256.0 / 1000000.0) */ - sr = mt312_div(p->symbol_rate * 4, 15625); + sr = DIV_ROUND_CLOSEST(p->symbol_rate * 4, 15625); /* SYM_RATE */ buf[0] = (sr >> 8) & 0x3f; diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 50dccb394efa..ecd21adf8950 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -9,38 +9,43 @@ #define SI2168_H #include <linux/dvb/frontend.h> -/* - * I2C address - * 0x64 +/** + * struct si2168_config - configuration parameters for si2168 + * + * @fe: + * frontend returned by driver + * @i2c_adapter: + * tuner I2C adapter returned by driver + * @ts_mode: + * Transport Stream mode. Can be: + * - %SI2168_TS_PARALLEL + * - %SI2168_TS_SERIAL + * - %SI2168_TS_TRISTATE + * - %SI2168_TS_CLK_MANUAL + * @ts_clock_inv: + * TS clock inverted + * @ts_clock_gapped: + * TS clock gapped + * @spectral_inversion: + * Inverted spectrum + * + * Note: + * The I2C address of this demod is 0x64. */ struct si2168_config { - /* - * frontend - * returned by driver - */ struct dvb_frontend **fe; - - /* - * tuner I2C adapter - * returned by driver - */ struct i2c_adapter **i2c_adapter; - /* TS mode */ #define SI2168_TS_PARALLEL 0x06 #define SI2168_TS_SERIAL 0x03 #define SI2168_TS_TRISTATE 0x00 #define SI2168_TS_CLK_MANUAL 0x20 u8 ts_mode; - /* TS clock inverted */ - bool ts_clock_inv; - - /* TS clock gapped */ - bool ts_clock_gapped; - - /* Inverted spectrum */ - bool spectral_inversion; + /* Flags */ + unsigned int ts_clock_inv:1; + unsigned int ts_clock_gapped:1; + unsigned int spectral_inversion:1; }; #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index 804d5b30c697..18bea5222082 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -34,12 +34,12 @@ struct si2168_dev { unsigned int chip_id; unsigned int version; const char *firmware_name; - bool active; - bool warm; u8 ts_mode; - bool ts_clock_inv; - bool ts_clock_gapped; - bool spectral_inversion; + unsigned int active:1; + unsigned int warm:1; + unsigned int ts_clock_inv:1; + unsigned int ts_clock_gapped:1; + unsigned int spectral_inversion:1; }; /* firmware command struct */ diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index 849d63dbc279..e83836b29715 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -685,10 +685,33 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) p += new_msgs[j].len; } - if (i < num) + if (i < num) { ret = -ENOMEM; - else + } else if (!state->cfg.split_tuner_read_i2c || rd_num == 0) { ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j); + } else { + /* + * Split transactions at each I2C_M_RD message. + * Some of the parent device require this, + * such as Friio (see. dvb-usb-gl861). + */ + int from, to; + + ret = 0; + from = 0; + do { + int r; + + to = from + 1; + while (to < j && !(new_msgs[to].flags & I2C_M_RD)) + to++; + r = i2c_transfer(state->i2c_client->adapter, + &new_msgs[from], to - from); + ret = (r <= 0) ? r : ret + r; + from = to; + } while (from < j && ret > 0); + } + if (ret >= 0 && ret < j) ret = -EIO; kfree(new_msgs); diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h index ac0e2ab51924..07e3813bf590 100644 --- a/drivers/media/dvb-frontends/tc90522.h +++ b/drivers/media/dvb-frontends/tc90522.h @@ -28,6 +28,9 @@ struct tc90522_config { /* [OUT] tuner I2C adapter returned by driver */ struct i2c_adapter *tuner_i2c; + + /* [IN] use two separate I2C transactions for one tuner read */ + bool split_tuner_read_i2c; }; #endif /* TC90522_H */ diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7eee1812bba3..c68e002d26ea 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -566,10 +566,23 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +if MEDIA_CAMERA_SUPPORT + +config VIDEO_HI556 + tristate "Hynix Hi-556 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Hynix + Hi-556 camera. + + To compile this driver as a module, choose M here: the + module will be called hi556. + config VIDEO_IMX214 tristate "Sony IMX214 sensor support" depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT depends on V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Sony @@ -581,7 +594,6 @@ config VIDEO_IMX214 config VIDEO_IMX258 tristate "Sony IMX258 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Sony IMX258 camera. @@ -592,16 +604,25 @@ config VIDEO_IMX258 config VIDEO_IMX274 tristate "Sony IMX274 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C help This is a V4L2 sensor driver for the Sony IMX274 CMOS image sensor. +config VIDEO_IMX290 + tristate "Sony IMX290 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX290 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called imx290. + config VIDEO_IMX319 tristate "Sony IMX319 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Sony IMX319 camera. @@ -612,7 +633,6 @@ config VIDEO_IMX319 config VIDEO_IMX355 tristate "Sony IMX355 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Sony IMX355 camera. @@ -623,7 +643,6 @@ config VIDEO_IMX355 config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" depends on VIDEO_V4L2 && I2C - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the OmniVision OV2640 camera. @@ -633,8 +652,7 @@ config VIDEO_OV2640 config VIDEO_OV2659 tristate "OmniVision OV2659 sensor support" - depends on VIDEO_V4L2 && I2C - depends on MEDIA_CAMERA_SUPPORT + depends on VIDEO_V4L2 && I2C && GPIOLIB select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -646,7 +664,6 @@ config VIDEO_OV2659 config VIDEO_OV2680 tristate "OmniVision OV2680 sensor support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -658,7 +675,6 @@ config VIDEO_OV2680 config VIDEO_OV2685 tristate "OmniVision OV2685 sensor support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -671,7 +687,6 @@ config VIDEO_OV5640 tristate "OmniVision OV5640 sensor support" depends on OF depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Omnivision @@ -681,7 +696,6 @@ config VIDEO_OV5645 tristate "OmniVision OV5645 sensor support" depends on OF depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -693,7 +707,6 @@ config VIDEO_OV5645 config VIDEO_OV5647 tristate "OmniVision OV5647 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -705,7 +718,6 @@ config VIDEO_OV5647 config VIDEO_OV6650 tristate "OmniVision OV6650 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the OmniVision OV6650 camera. @@ -716,7 +728,6 @@ config VIDEO_OV6650 config VIDEO_OV5670 tristate "OmniVision OV5670 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT depends on MEDIA_CONTROLLER select V4L2_FWNODE help @@ -729,7 +740,6 @@ config VIDEO_OV5670 config VIDEO_OV5675 tristate "OmniVision OV5675 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT depends on MEDIA_CONTROLLER select V4L2_FWNODE help @@ -742,7 +752,7 @@ config VIDEO_OV5675 config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT + select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision OV5695 camera. @@ -753,7 +763,6 @@ config VIDEO_OV5695 config VIDEO_OV7251 tristate "OmniVision OV7251 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -765,7 +774,6 @@ config VIDEO_OV7251 config VIDEO_OV772X tristate "OmniVision OV772x sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT select REGMAP_SCCB help This is a Video4Linux2 sensor driver for the OmniVision @@ -777,7 +785,6 @@ config VIDEO_OV772X config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the OmniVision OV7640 camera. @@ -788,7 +795,6 @@ config VIDEO_OV7640 config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -798,7 +804,6 @@ config VIDEO_OV7670 config VIDEO_OV7740 tristate "OmniVision OV7740 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the OmniVision OV7740 VGA camera sensor. @@ -806,7 +811,6 @@ config VIDEO_OV7740 config VIDEO_OV8856 tristate "OmniVision OV8856 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -833,7 +837,6 @@ config VIDEO_OV9650 config VIDEO_OV13858 tristate "OmniVision OV13858 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -842,7 +845,6 @@ config VIDEO_OV13858 config VIDEO_VS6624 tristate "ST VS6624 sensor support" depends on VIDEO_V4L2 && I2C - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the ST VS6624 camera. @@ -853,7 +855,6 @@ config VIDEO_VS6624 config VIDEO_MT9M001 tristate "mt9m001 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This driver supports MT9M001 cameras from Micron, monochrome and colour models. @@ -861,7 +862,6 @@ config VIDEO_MT9M001 config VIDEO_MT9M032 tristate "MT9M032 camera sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL help This driver supports MT9M032 camera sensors from Aptina, monochrome @@ -878,7 +878,6 @@ config VIDEO_MT9M111 config VIDEO_MT9P031 tristate "Aptina MT9P031 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL help This is a Video4Linux2 sensor driver for the Aptina @@ -887,7 +886,6 @@ config VIDEO_MT9P031 config VIDEO_MT9T001 tristate "Aptina MT9T001 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt0t001 3 Mpixel camera. @@ -895,7 +893,6 @@ config VIDEO_MT9T001 config VIDEO_MT9T112 tristate "Aptina MT9T111/MT9T112 support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Aptina (Micron) MT9T111 and MT9T112 3 Mpixel camera. @@ -906,7 +903,6 @@ config VIDEO_MT9T112 config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Micron mt0v011 1.3 Mpixel camera. It currently only works with the @@ -915,7 +911,6 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C select V4L2_FWNODE help @@ -925,7 +920,6 @@ config VIDEO_MT9V032 config VIDEO_MT9V111 tristate "Aptina MT9V111 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Aptina/Micron MT9V111 sensor. @@ -936,14 +930,12 @@ config VIDEO_MT9V111 config VIDEO_SR030PC30 tristate "Siliconfile SR030PC30 sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This driver supports SR030PC30 VGA camera from Siliconfile config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT help This driver supports NOON010PC30 CIF camera from Siliconfile @@ -952,7 +944,6 @@ source "drivers/media/i2c/m5mols/Kconfig" config VIDEO_RJ54N1 tristate "Sharp RJ54N1CB0C sensor support" depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help This is a V4L2 sensor driver for Sharp RJ54N1CB0C CMOS image sensor. @@ -962,7 +953,6 @@ config VIDEO_RJ54N1 config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" - depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API help This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M @@ -970,7 +960,6 @@ config VIDEO_S5K6AA config VIDEO_S5K6A3 tristate "Samsung S5K6A3 sensor support" - depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API help This is a V4L2 sensor driver for Samsung S5K6A3 raw @@ -1002,12 +991,15 @@ config VIDEO_S5C73M3 help This is a V4L2 sensor driver for Samsung S5C73M3 8 Mpixel camera. +endif comment "Lens drivers" +if MEDIA_CAMERA_SUPPORT + config VIDEO_AD5820 tristate "AD5820 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on GPIOLIB && I2C && VIDEO_V4L2 && MEDIA_CONTROLLER help This is a driver for the AD5820 camera lens voice coil. It is used for example in Nokia N900 (RX-51). @@ -1042,12 +1034,15 @@ config VIDEO_DW9807_VCM capability. This is designed for linear control of voice coil motors, controlled via I2C serial interface. +endif + comment "Flash devices" +if MEDIA_CAMERA_SUPPORT + config VIDEO_ADP1653 tristate "ADP1653 flash support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT help This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. @@ -1055,7 +1050,6 @@ config VIDEO_ADP1653 config VIDEO_LM3560 tristate "LM3560 dual flash driver support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C help This is a driver for the lm3560 dual flash controllers. It controls @@ -1064,12 +1058,13 @@ config VIDEO_LM3560 config VIDEO_LM3646 tristate "LM3646 dual flash driver support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C help This is a driver for the lm3646 dual flash controllers. It controls flash, torch LEDs. +endif + comment "Video improvement chips" config VIDEO_UPD64031A @@ -1113,6 +1108,7 @@ comment "SDR tuner chips" config SDR_MAX2175 tristate "Maxim 2175 RF to Bits tuner" depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C + select REGMAP_I2C help Support for Maxim 2175 tuner. It is an advanced analog/digital radio receiver with RF-to-Bits front-end designed for SDR solutions. diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index beb170b002dc..c147bb9d28db 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -109,9 +109,11 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o +obj-$(CONFIG_VIDEO_HI556) += hi556.o obj-$(CONFIG_VIDEO_IMX214) += imx214.o obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o +obj-$(CONFIG_VIDEO_IMX290) += imx290.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c index 925c171e7797..19c74db0649f 100644 --- a/drivers/media/i2c/ad5820.c +++ b/drivers/media/i2c/ad5820.c @@ -19,13 +19,12 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-subdev.h> -#define AD5820_NAME "ad5820" - /* Register definitions */ #define AD5820_POWER_DOWN (1 << 15) #define AD5820_DAC_SHIFT 4 @@ -47,6 +46,8 @@ struct ad5820_device { u32 focus_ramp_time; u32 focus_ramp_mode; + struct gpio_desc *enable_gpio; + struct mutex power_lock; int power_count; @@ -114,6 +115,8 @@ static int ad5820_power_off(struct ad5820_device *coil, bool standby) ret = ad5820_update_hw(coil); } + gpiod_set_value_cansleep(coil->enable_gpio, 0); + ret2 = regulator_disable(coil->vana); if (ret) return ret; @@ -128,6 +131,8 @@ static int ad5820_power_on(struct ad5820_device *coil, bool restore) if (ret < 0) return ret; + gpiod_set_value_cansleep(coil->enable_gpio, 1); + if (restore) { /* Restore the hardware settings. */ coil->standby = false; @@ -138,6 +143,7 @@ static int ad5820_power_on(struct ad5820_device *coil, bool restore) return 0; fail: + gpiod_set_value_cansleep(coil->enable_gpio, 0); coil->standby = true; regulator_disable(coil->vana); @@ -304,11 +310,21 @@ static int ad5820_probe(struct i2c_client *client, return ret; } + coil->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(coil->enable_gpio)) { + ret = PTR_ERR(coil->enable_gpio); + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, "could not get enable gpio\n"); + return ret; + } + mutex_init(&coil->power_lock); v4l2_i2c_subdev_init(&coil->subdev, client, &ad5820_ops); coil->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; coil->subdev.internal_ops = &ad5820_internal_ops; + coil->subdev.entity.function = MEDIA_ENT_F_LENS; strscpy(coil->subdev.name, "ad5820 focus", sizeof(coil->subdev.name)); ret = media_entity_pads_init(&coil->subdev.entity, 0, NULL); @@ -341,17 +357,28 @@ static int ad5820_remove(struct i2c_client *client) } static const struct i2c_device_id ad5820_id_table[] = { - { AD5820_NAME, 0 }, + { "ad5820", 0 }, + { "ad5821", 0 }, + { "ad5823", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ad5820_id_table); +static const struct of_device_id ad5820_of_table[] = { + { .compatible = "adi,ad5820" }, + { .compatible = "adi,ad5821" }, + { .compatible = "adi,ad5823" }, + { } +}; +MODULE_DEVICE_TABLE(of, ad5820_of_table); + static SIMPLE_DEV_PM_OPS(ad5820_pm, ad5820_suspend, ad5820_resume); static struct i2c_driver ad5820_i2c_driver = { .driver = { - .name = AD5820_NAME, + .name = "ad5820", .pm = &ad5820_pm, + .of_match_table = ad5820_of_table, }, .probe = ad5820_probe, .remove = ad5820_remove, diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index e780969cc2f2..6528e2343fc8 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1309,9 +1309,6 @@ static int adv7180_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr, client->adapter->name); - state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (state == NULL) return -ENOMEM; @@ -1382,6 +1379,9 @@ static int adv7180_probe(struct i2c_client *client, if (ret) goto err_free_irq; + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr, client->adapter->name); + return 0; err_free_irq: diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 885619841719..0855f648416d 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -2547,7 +2547,7 @@ struct adv7842_cfg_read_infoframe { u8 payload_addr; }; -static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri) +static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_infoframe *cri) { int i; u8 buffer[32]; @@ -2585,7 +2585,7 @@ static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infofr static void adv7842_log_infoframes(struct v4l2_subdev *sd) { int i; - struct adv7842_cfg_read_infoframe cri[] = { + static const struct adv7842_cfg_read_infoframe cri[] = { { "AVI", 0x01, 0xe0, 0x00 }, { "Audio", 0x02, 0xe3, 0x1c }, { "SDP", 0x04, 0xe6, 0x2a }, diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c index 43336175c7d9..73bc50c919d7 100644 --- a/drivers/media/i2c/bt819.c +++ b/drivers/media/i2c/bt819.c @@ -157,7 +157,7 @@ static int bt819_init(struct v4l2_subdev *sd) 0x12, 0x04, /* 0x12 Output Format */ 0x13, 0x20, /* 0x13 Vertical Scaling msb 0x00 chroma comb OFF, line drop scaling, interlace scaling - BUG? Why does turning the chroma comb on fuck up color? + BUG? Why does turning the chroma comb on screw up color? Bug in the bt819 stepping on my board? */ 0x14, 0x00, /* 0x14 Vertical Scaling lsb */ diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c new file mode 100644 index 000000000000..c66cd1446c0f --- /dev/null +++ b/drivers/media/i2c/hi556.c @@ -0,0 +1,1200 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation. + +#include <asm/unaligned.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define HI556_REG_VALUE_08BIT 1 +#define HI556_REG_VALUE_16BIT 2 +#define HI556_REG_VALUE_24BIT 3 + +#define HI556_LINK_FREQ_437MHZ 437000000ULL +#define HI556_MCLK 19200000 +#define HI556_DATA_LANES 2 +#define HI556_RGB_DEPTH 10 + +#define HI556_REG_CHIP_ID 0x0f16 +#define HI556_CHIP_ID 0x0556 + +#define HI556_REG_MODE_SELECT 0x0a00 +#define HI556_MODE_STANDBY 0x0000 +#define HI556_MODE_STREAMING 0x0100 + +/* vertical-timings from sensor */ +#define HI556_REG_FLL 0x0006 +#define HI556_FLL_30FPS 0x0814 +#define HI556_FLL_30FPS_MIN 0x0814 +#define HI556_FLL_MAX 0x7fff + +/* horizontal-timings from sensor */ +#define HI556_REG_LLP 0x0008 + +/* Exposure controls from sensor */ +#define HI556_REG_EXPOSURE 0x0074 +#define HI556_EXPOSURE_MIN 6 +#define HI556_EXPOSURE_MAX_MARGIN 2 +#define HI556_EXPOSURE_STEP 1 + +/* Analog gain controls from sensor */ +#define HI556_REG_ANALOG_GAIN 0x0077 +#define HI556_ANAL_GAIN_MIN 0 +#define HI556_ANAL_GAIN_MAX 240 +#define HI556_ANAL_GAIN_STEP 1 + +/* Digital gain controls from sensor */ +#define HI556_REG_MWB_GR_GAIN 0x0078 +#define HI556_REG_MWB_GB_GAIN 0x007a +#define HI556_REG_MWB_R_GAIN 0x007c +#define HI556_REG_MWB_B_GAIN 0x007e +#define HI556_DGTL_GAIN_MIN 0 +#define HI556_DGTL_GAIN_MAX 2048 +#define HI556_DGTL_GAIN_STEP 1 +#define HI556_DGTL_GAIN_DEFAULT 256 + +/* Test Pattern Control */ +#define HI556_REG_ISP 0X0a05 +#define HI556_REG_ISP_TPG_EN 0x01 +#define HI556_REG_TEST_PATTERN 0x0201 + +enum { + HI556_LINK_FREQ_437MHZ_INDEX, +}; + +struct hi556_reg { + u16 address; + u16 val; +}; + +struct hi556_reg_list { + u32 num_of_regs; + const struct hi556_reg *regs; +}; + +struct hi556_link_freq_config { + const struct hi556_reg_list reg_list; +}; + +struct hi556_mode { + /* Frame width in pixels */ + u32 width; + + /* Frame height in pixels */ + u32 height; + + /* Horizontal timining size */ + u32 llp; + + /* Default vertical timining size */ + u32 fll_def; + + /* Min vertical timining size */ + u32 fll_min; + + /* Link frequency needed for this resolution */ + u32 link_freq_index; + + /* Sensor register settings for this resolution */ + const struct hi556_reg_list reg_list; +}; + +#define to_hi556(_sd) container_of(_sd, struct hi556, sd) + +//SENSOR_INITIALIZATION +static const struct hi556_reg mipi_data_rate_874mbps[] = { + {0x0e00, 0x0102}, + {0x0e02, 0x0102}, + {0x0e0c, 0x0100}, + {0x2000, 0x7400}, + {0x2002, 0x001c}, + {0x2004, 0x0242}, + {0x2006, 0x0942}, + {0x2008, 0x7007}, + {0x200a, 0x0fd9}, + {0x200c, 0x0259}, + {0x200e, 0x7008}, + {0x2010, 0x160e}, + {0x2012, 0x0047}, + {0x2014, 0x2118}, + {0x2016, 0x0041}, + {0x2018, 0x00d8}, + {0x201a, 0x0145}, + {0x201c, 0x0006}, + {0x201e, 0x0181}, + {0x2020, 0x13cc}, + {0x2022, 0x2057}, + {0x2024, 0x7001}, + {0x2026, 0x0fca}, + {0x2028, 0x00cb}, + {0x202a, 0x009f}, + {0x202c, 0x7002}, + {0x202e, 0x13cc}, + {0x2030, 0x019b}, + {0x2032, 0x014d}, + {0x2034, 0x2987}, + {0x2036, 0x2766}, + {0x2038, 0x0020}, + {0x203a, 0x2060}, + {0x203c, 0x0e5d}, + {0x203e, 0x181d}, + {0x2040, 0x2066}, + {0x2042, 0x20c4}, + {0x2044, 0x5000}, + {0x2046, 0x0005}, + {0x2048, 0x0000}, + {0x204a, 0x01db}, + {0x204c, 0x025a}, + {0x204e, 0x00c0}, + {0x2050, 0x0005}, + {0x2052, 0x0006}, + {0x2054, 0x0ad9}, + {0x2056, 0x0259}, + {0x2058, 0x0618}, + {0x205a, 0x0258}, + {0x205c, 0x2266}, + {0x205e, 0x20c8}, + {0x2060, 0x2060}, + {0x2062, 0x707b}, + {0x2064, 0x0fdd}, + {0x2066, 0x81b8}, + {0x2068, 0x5040}, + {0x206a, 0x0020}, + {0x206c, 0x5060}, + {0x206e, 0x3143}, + {0x2070, 0x5081}, + {0x2072, 0x025c}, + {0x2074, 0x7800}, + {0x2076, 0x7400}, + {0x2078, 0x001c}, + {0x207a, 0x0242}, + {0x207c, 0x0942}, + {0x207e, 0x0bd9}, + {0x2080, 0x0259}, + {0x2082, 0x7008}, + {0x2084, 0x160e}, + {0x2086, 0x0047}, + {0x2088, 0x2118}, + {0x208a, 0x0041}, + {0x208c, 0x00d8}, + {0x208e, 0x0145}, + {0x2090, 0x0006}, + {0x2092, 0x0181}, + {0x2094, 0x13cc}, + {0x2096, 0x2057}, + {0x2098, 0x7001}, + {0x209a, 0x0fca}, + {0x209c, 0x00cb}, + {0x209e, 0x009f}, + {0x20a0, 0x7002}, + {0x20a2, 0x13cc}, + {0x20a4, 0x019b}, + {0x20a6, 0x014d}, + {0x20a8, 0x2987}, + {0x20aa, 0x2766}, + {0x20ac, 0x0020}, + {0x20ae, 0x2060}, + {0x20b0, 0x0e5d}, + {0x20b2, 0x181d}, + {0x20b4, 0x2066}, + {0x20b6, 0x20c4}, + {0x20b8, 0x50a0}, + {0x20ba, 0x0005}, + {0x20bc, 0x0000}, + {0x20be, 0x01db}, + {0x20c0, 0x025a}, + {0x20c2, 0x00c0}, + {0x20c4, 0x0005}, + {0x20c6, 0x0006}, + {0x20c8, 0x0ad9}, + {0x20ca, 0x0259}, + {0x20cc, 0x0618}, + {0x20ce, 0x0258}, + {0x20d0, 0x2266}, + {0x20d2, 0x20c8}, + {0x20d4, 0x2060}, + {0x20d6, 0x707b}, + {0x20d8, 0x0fdd}, + {0x20da, 0x86b8}, + {0x20dc, 0x50e0}, + {0x20de, 0x0020}, + {0x20e0, 0x5100}, + {0x20e2, 0x3143}, + {0x20e4, 0x5121}, + {0x20e6, 0x7800}, + {0x20e8, 0x3140}, + {0x20ea, 0x01c4}, + {0x20ec, 0x01c1}, + {0x20ee, 0x01c0}, + {0x20f0, 0x01c4}, + {0x20f2, 0x2700}, + {0x20f4, 0x3d40}, + {0x20f6, 0x7800}, + {0x20f8, 0xffff}, + {0x27fe, 0xe000}, + {0x3000, 0x60f8}, + {0x3002, 0x187f}, + {0x3004, 0x7060}, + {0x3006, 0x0114}, + {0x3008, 0x60b0}, + {0x300a, 0x1473}, + {0x300c, 0x0013}, + {0x300e, 0x140f}, + {0x3010, 0x0040}, + {0x3012, 0x100f}, + {0x3014, 0x60f8}, + {0x3016, 0x187f}, + {0x3018, 0x7060}, + {0x301a, 0x0114}, + {0x301c, 0x60b0}, + {0x301e, 0x1473}, + {0x3020, 0x0013}, + {0x3022, 0x140f}, + {0x3024, 0x0040}, + {0x3026, 0x000f}, + + {0x0b00, 0x0000}, + {0x0b02, 0x0045}, + {0x0b04, 0xb405}, + {0x0b06, 0xc403}, + {0x0b08, 0x0081}, + {0x0b0a, 0x8252}, + {0x0b0c, 0xf814}, + {0x0b0e, 0xc618}, + {0x0b10, 0xa828}, + {0x0b12, 0x004c}, + {0x0b14, 0x4068}, + {0x0b16, 0x0000}, + {0x0f30, 0x5b15}, + {0x0f32, 0x7067}, + {0x0954, 0x0009}, + {0x0956, 0x0000}, + {0x0958, 0xbb80}, + {0x095a, 0x5140}, + {0x0c00, 0x1110}, + {0x0c02, 0x0011}, + {0x0c04, 0x0000}, + {0x0c06, 0x0200}, + {0x0c10, 0x0040}, + {0x0c12, 0x0040}, + {0x0c14, 0x0040}, + {0x0c16, 0x0040}, + {0x0a10, 0x4000}, + {0x3068, 0xf800}, + {0x306a, 0xf876}, + {0x006c, 0x0000}, + {0x005e, 0x0200}, + {0x000e, 0x0100}, + {0x0e0a, 0x0001}, + {0x004a, 0x0100}, + {0x004c, 0x0000}, + {0x004e, 0x0100}, + {0x000c, 0x0022}, + {0x0008, 0x0b00}, + {0x005a, 0x0202}, + {0x0012, 0x000e}, + {0x0018, 0x0a33}, + {0x0022, 0x0008}, + {0x0028, 0x0017}, + {0x0024, 0x0028}, + {0x002a, 0x002d}, + {0x0026, 0x0030}, + {0x002c, 0x07c9}, + {0x002e, 0x1111}, + {0x0030, 0x1111}, + {0x0032, 0x1111}, + {0x0006, 0x07bc}, + {0x0a22, 0x0000}, + {0x0a12, 0x0a20}, + {0x0a14, 0x0798}, + {0x003e, 0x0000}, + {0x0074, 0x080e}, + {0x0070, 0x0407}, + {0x0002, 0x0000}, + {0x0a02, 0x0100}, + {0x0a24, 0x0100}, + {0x0046, 0x0000}, + {0x0076, 0x0000}, + {0x0060, 0x0000}, + {0x0062, 0x0530}, + {0x0064, 0x0500}, + {0x0066, 0x0530}, + {0x0068, 0x0500}, + {0x0122, 0x0300}, + {0x015a, 0xff08}, + {0x0804, 0x0300}, + {0x0806, 0x0100}, + {0x005c, 0x0102}, + {0x0a1a, 0x0800}, +}; + +static const struct hi556_reg mode_2592x1944_regs[] = { + {0x0a00, 0x0000}, + {0x0b0a, 0x8252}, + {0x0f30, 0x5b15}, + {0x0f32, 0x7067}, + {0x004a, 0x0100}, + {0x004c, 0x0000}, + {0x004e, 0x0100}, + {0x000c, 0x0022}, + {0x0008, 0x0b00}, + {0x005a, 0x0202}, + {0x0012, 0x000e}, + {0x0018, 0x0a33}, + {0x0022, 0x0008}, + {0x0028, 0x0017}, + {0x0024, 0x0028}, + {0x002a, 0x002d}, + {0x0026, 0x0030}, + {0x002c, 0x07c9}, + {0x002e, 0x1111}, + {0x0030, 0x1111}, + {0x0032, 0x1111}, + {0x0006, 0x0814}, + {0x0a22, 0x0000}, + {0x0a12, 0x0a20}, + {0x0a14, 0x0798}, + {0x003e, 0x0000}, + {0x0074, 0x0812}, + {0x0070, 0x0409}, + {0x0804, 0x0300}, + {0x0806, 0x0100}, + {0x0a04, 0x014a}, + {0x090c, 0x0fdc}, + {0x090e, 0x002d}, + + {0x0902, 0x4319}, + {0x0914, 0xc10a}, + {0x0916, 0x071f}, + {0x0918, 0x0408}, + {0x091a, 0x0c0d}, + {0x091c, 0x0f09}, + {0x091e, 0x0a00}, + {0x0958, 0xbb80}, +}; + +static const struct hi556_reg mode_1296x972_regs[] = { + {0x0a00, 0x0000}, + {0x0b0a, 0x8259}, + {0x0f30, 0x5b15}, + {0x0f32, 0x7167}, + {0x004a, 0x0100}, + {0x004c, 0x0000}, + {0x004e, 0x0100}, + {0x000c, 0x0122}, + {0x0008, 0x0b00}, + {0x005a, 0x0404}, + {0x0012, 0x000c}, + {0x0018, 0x0a33}, + {0x0022, 0x0008}, + {0x0028, 0x0017}, + {0x0024, 0x0022}, + {0x002a, 0x002b}, + {0x0026, 0x0030}, + {0x002c, 0x07c9}, + {0x002e, 0x3311}, + {0x0030, 0x3311}, + {0x0032, 0x3311}, + {0x0006, 0x0814}, + {0x0a22, 0x0000}, + {0x0a12, 0x0510}, + {0x0a14, 0x03cc}, + {0x003e, 0x0000}, + {0x0074, 0x0812}, + {0x0070, 0x0409}, + {0x0804, 0x0308}, + {0x0806, 0x0100}, + {0x0a04, 0x016a}, + {0x090e, 0x0010}, + {0x090c, 0x09c0}, + + {0x0902, 0x4319}, + {0x0914, 0xc106}, + {0x0916, 0x040e}, + {0x0918, 0x0304}, + {0x091a, 0x0708}, + {0x091c, 0x0e06}, + {0x091e, 0x0300}, + {0x0958, 0xbb80}, +}; + +static const char * const hi556_test_pattern_menu[] = { + "Disabled", + "Solid Colour", + "100% Colour Bars", + "Fade To Grey Colour Bars", + "PN9", + "Gradient Horizontal", + "Gradient Vertical", + "Check Board", + "Slant Pattern", +}; + +static const s64 link_freq_menu_items[] = { + HI556_LINK_FREQ_437MHZ, +}; + +static const struct hi556_link_freq_config link_freq_configs[] = { + [HI556_LINK_FREQ_437MHZ_INDEX] = { + .reg_list = { + .num_of_regs = ARRAY_SIZE(mipi_data_rate_874mbps), + .regs = mipi_data_rate_874mbps, + } + } +}; + +static const struct hi556_mode supported_modes[] = { + { + .width = 2592, + .height = 1944, + .fll_def = HI556_FLL_30FPS, + .fll_min = HI556_FLL_30FPS_MIN, + .llp = 0x0b00, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, + }, + { + .width = 1296, + .height = 972, + .fll_def = HI556_FLL_30FPS, + .fll_min = HI556_FLL_30FPS_MIN, + .llp = 0x0b00, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1296x972_regs), + .regs = mode_1296x972_regs, + }, + .link_freq_index = HI556_LINK_FREQ_437MHZ_INDEX, + } +}; + +struct hi556 { + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *exposure; + + /* Current mode */ + const struct hi556_mode *cur_mode; + + /* To serialize asynchronus callbacks */ + struct mutex mutex; + + /* Streaming on/off */ + bool streaming; +}; + +static u64 to_pixel_rate(u32 f_index) +{ + u64 pixel_rate = link_freq_menu_items[f_index] * 2 * HI556_DATA_LANES; + + do_div(pixel_rate, HI556_RGB_DEPTH); + + return pixel_rate; +} + +static int hi556_read_reg(struct hi556 *hi556, u16 reg, u16 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + struct i2c_msg msgs[2]; + u8 addr_buf[2]; + u8 data_buf[4] = {0}; + int ret; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = sizeof(addr_buf); + msgs[0].buf = addr_buf; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +static int hi556_write_reg(struct hi556 *hi556, u16 reg, u16 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + u8 buf[6]; + + if (len > 4) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << 8 * (4 - len), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +static int hi556_write_reg_list(struct hi556 *hi556, + const struct hi556_reg_list *r_list) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + unsigned int i; + int ret; + + for (i = 0; i < r_list->num_of_regs; i++) { + ret = hi556_write_reg(hi556, r_list->regs[i].address, + HI556_REG_VALUE_16BIT, + r_list->regs[i].val); + if (ret) { + dev_err_ratelimited(&client->dev, + "failed to write reg 0x%4.4x. error = %d", + r_list->regs[i].address, ret); + return ret; + } + } + + return 0; +} + +static int hi556_update_digital_gain(struct hi556 *hi556, u32 d_gain) +{ + int ret; + + ret = hi556_write_reg(hi556, HI556_REG_MWB_GR_GAIN, + HI556_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = hi556_write_reg(hi556, HI556_REG_MWB_GB_GAIN, + HI556_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + ret = hi556_write_reg(hi556, HI556_REG_MWB_R_GAIN, + HI556_REG_VALUE_16BIT, d_gain); + if (ret) + return ret; + + return hi556_write_reg(hi556, HI556_REG_MWB_B_GAIN, + HI556_REG_VALUE_16BIT, d_gain); +} + +static int hi556_test_pattern(struct hi556 *hi556, u32 pattern) +{ + int ret; + u32 val; + + if (pattern) { + ret = hi556_read_reg(hi556, HI556_REG_ISP, + HI556_REG_VALUE_08BIT, &val); + if (ret) + return ret; + + ret = hi556_write_reg(hi556, HI556_REG_ISP, + HI556_REG_VALUE_08BIT, + val | HI556_REG_ISP_TPG_EN); + if (ret) + return ret; + } + + return hi556_write_reg(hi556, HI556_REG_TEST_PATTERN, + HI556_REG_VALUE_08BIT, pattern); +} + +static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct hi556 *hi556 = container_of(ctrl->handler, + struct hi556, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + s64 exposure_max; + int ret = 0; + + /* Propagate change of current control to all related controls */ + if (ctrl->id == V4L2_CID_VBLANK) { + /* Update max exposure while meeting expected vblanking */ + exposure_max = hi556->cur_mode->height + ctrl->val - + HI556_EXPOSURE_MAX_MARGIN; + __v4l2_ctrl_modify_range(hi556->exposure, + hi556->exposure->minimum, + exposure_max, hi556->exposure->step, + exposure_max); + } + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = hi556_write_reg(hi556, HI556_REG_ANALOG_GAIN, + HI556_REG_VALUE_16BIT, ctrl->val); + break; + + case V4L2_CID_DIGITAL_GAIN: + ret = hi556_update_digital_gain(hi556, ctrl->val); + break; + + case V4L2_CID_EXPOSURE: + ret = hi556_write_reg(hi556, HI556_REG_EXPOSURE, + HI556_REG_VALUE_16BIT, ctrl->val); + break; + + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + ret = hi556_write_reg(hi556, HI556_REG_FLL, + HI556_REG_VALUE_16BIT, + hi556->cur_mode->height + ctrl->val); + break; + + case V4L2_CID_TEST_PATTERN: + ret = hi556_test_pattern(hi556, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops hi556_ctrl_ops = { + .s_ctrl = hi556_set_ctrl, +}; + +static int hi556_init_controls(struct hi556 *hi556) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + s64 exposure_max, h_blank; + int ret; + + ctrl_hdlr = &hi556->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 8); + if (ret) + return ret; + + ctrl_hdlr->lock = &hi556->mutex; + hi556->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, link_freq_menu_items); + if (hi556->link_freq) + hi556->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + hi556->pixel_rate = v4l2_ctrl_new_std + (ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX), + 1, + to_pixel_rate(HI556_LINK_FREQ_437MHZ_INDEX)); + hi556->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_VBLANK, + hi556->cur_mode->fll_min - + hi556->cur_mode->height, + HI556_FLL_MAX - + hi556->cur_mode->height, 1, + hi556->cur_mode->fll_def - + hi556->cur_mode->height); + + h_blank = hi556->cur_mode->llp - hi556->cur_mode->width; + + hi556->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_HBLANK, h_blank, h_blank, 1, + h_blank); + if (hi556->hblank) + hi556->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + HI556_ANAL_GAIN_MIN, HI556_ANAL_GAIN_MAX, + HI556_ANAL_GAIN_STEP, HI556_ANAL_GAIN_MIN); + v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + HI556_DGTL_GAIN_MIN, HI556_DGTL_GAIN_MAX, + HI556_DGTL_GAIN_STEP, HI556_DGTL_GAIN_DEFAULT); + exposure_max = hi556->cur_mode->fll_def - HI556_EXPOSURE_MAX_MARGIN; + hi556->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_EXPOSURE, + HI556_EXPOSURE_MIN, exposure_max, + HI556_EXPOSURE_STEP, + exposure_max); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &hi556_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(hi556_test_pattern_menu) - 1, + 0, 0, hi556_test_pattern_menu); + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + hi556->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static void hi556_assign_pad_format(const struct hi556_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->width = mode->width; + fmt->height = mode->height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->field = V4L2_FIELD_NONE; +} + +static int hi556_start_streaming(struct hi556 *hi556) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + const struct hi556_reg_list *reg_list; + int link_freq_index, ret; + + link_freq_index = hi556->cur_mode->link_freq_index; + reg_list = &link_freq_configs[link_freq_index].reg_list; + ret = hi556_write_reg_list(hi556, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set plls"); + return ret; + } + + reg_list = &hi556->cur_mode->reg_list; + ret = hi556_write_reg_list(hi556, reg_list); + if (ret) { + dev_err(&client->dev, "failed to set mode"); + return ret; + } + + ret = __v4l2_ctrl_handler_setup(hi556->sd.ctrl_handler); + if (ret) + return ret; + + ret = hi556_write_reg(hi556, HI556_REG_MODE_SELECT, + HI556_REG_VALUE_16BIT, HI556_MODE_STREAMING); + + if (ret) { + dev_err(&client->dev, "failed to set stream"); + return ret; + } + + return 0; +} + +static void hi556_stop_streaming(struct hi556 *hi556) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + + if (hi556_write_reg(hi556, HI556_REG_MODE_SELECT, + HI556_REG_VALUE_16BIT, HI556_MODE_STANDBY)) + dev_err(&client->dev, "failed to set stream"); +} + +static int hi556_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct hi556 *hi556 = to_hi556(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (hi556->streaming == enable) + return 0; + + mutex_lock(&hi556->mutex); + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + mutex_unlock(&hi556->mutex); + return ret; + } + + ret = hi556_start_streaming(hi556); + if (ret) { + enable = 0; + hi556_stop_streaming(hi556); + pm_runtime_put(&client->dev); + } + } else { + hi556_stop_streaming(hi556); + pm_runtime_put(&client->dev); + } + + hi556->streaming = enable; + mutex_unlock(&hi556->mutex); + + return ret; +} + +static int __maybe_unused hi556_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi556 *hi556 = to_hi556(sd); + + mutex_lock(&hi556->mutex); + if (hi556->streaming) + hi556_stop_streaming(hi556); + + mutex_unlock(&hi556->mutex); + + return 0; +} + +static int __maybe_unused hi556_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi556 *hi556 = to_hi556(sd); + int ret; + + mutex_lock(&hi556->mutex); + if (hi556->streaming) { + ret = hi556_start_streaming(hi556); + if (ret) + goto error; + } + + mutex_unlock(&hi556->mutex); + + return 0; + +error: + hi556_stop_streaming(hi556); + hi556->streaming = 0; + mutex_unlock(&hi556->mutex); + return ret; +} + +static int hi556_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct hi556 *hi556 = to_hi556(sd); + const struct hi556_mode *mode; + s32 vblank_def, h_blank; + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), width, + height, fmt->format.width, + fmt->format.height); + + mutex_lock(&hi556->mutex); + hi556_assign_pad_format(mode, &fmt->format); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format; + } else { + hi556->cur_mode = mode; + __v4l2_ctrl_s_ctrl(hi556->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(hi556->pixel_rate, + to_pixel_rate(mode->link_freq_index)); + + /* Update limits and set FPS to default */ + vblank_def = mode->fll_def - mode->height; + __v4l2_ctrl_modify_range(hi556->vblank, + mode->fll_min - mode->height, + HI556_FLL_MAX - mode->height, 1, + vblank_def); + __v4l2_ctrl_s_ctrl(hi556->vblank, vblank_def); + + h_blank = hi556->cur_mode->llp - hi556->cur_mode->width; + + __v4l2_ctrl_modify_range(hi556->hblank, h_blank, h_blank, 1, + h_blank); + } + + mutex_unlock(&hi556->mutex); + + return 0; +} + +static int hi556_get_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct hi556 *hi556 = to_hi556(sd); + + mutex_lock(&hi556->mutex); + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + fmt->format = *v4l2_subdev_get_try_format(&hi556->sd, cfg, + fmt->pad); + else + hi556_assign_pad_format(hi556->cur_mode, &fmt->format); + + mutex_unlock(&hi556->mutex); + + return 0; +} + +static int hi556_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int hi556_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int hi556_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct hi556 *hi556 = to_hi556(sd); + + mutex_lock(&hi556->mutex); + hi556_assign_pad_format(&supported_modes[0], + v4l2_subdev_get_try_format(sd, fh->pad, 0)); + mutex_unlock(&hi556->mutex); + + return 0; +} + +static const struct v4l2_subdev_video_ops hi556_video_ops = { + .s_stream = hi556_set_stream, +}; + +static const struct v4l2_subdev_pad_ops hi556_pad_ops = { + .set_fmt = hi556_set_format, + .get_fmt = hi556_get_format, + .enum_mbus_code = hi556_enum_mbus_code, + .enum_frame_size = hi556_enum_frame_size, +}; + +static const struct v4l2_subdev_ops hi556_subdev_ops = { + .video = &hi556_video_ops, + .pad = &hi556_pad_ops, +}; + +static const struct media_entity_operations hi556_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops hi556_internal_ops = { + .open = hi556_open, +}; + +static int hi556_identify_module(struct hi556 *hi556) +{ + struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); + int ret; + u32 val; + + ret = hi556_read_reg(hi556, HI556_REG_CHIP_ID, + HI556_REG_VALUE_16BIT, &val); + if (ret) + return ret; + + if (val != HI556_CHIP_ID) { + dev_err(&client->dev, "chip id mismatch: %x!=%x", + HI556_CHIP_ID, val); + return -ENXIO; + } + + return 0; +} + +static int hi556_check_hwcfg(struct device *dev) +{ + struct fwnode_handle *ep; + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + u32 mclk; + int ret = 0; + unsigned int i, j; + + if (!fwnode) + return -ENXIO; + + ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); + if (ret) { + dev_err(dev, "can't get clock frequency"); + return ret; + } + + if (mclk != HI556_MCLK) { + dev_err(dev, "external clock %d is not supported", mclk); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { + dev_err(dev, "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto check_hwcfg_error; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequencies defined"); + ret = -EINVAL; + goto check_hwcfg_error; + } + + for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { + for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { + if (link_freq_menu_items[i] == + bus_cfg.link_frequencies[j]) + break; + } + + if (j == bus_cfg.nr_of_link_frequencies) { + dev_err(dev, "no link frequency %lld supported", + link_freq_menu_items[i]); + ret = -EINVAL; + goto check_hwcfg_error; + } + } + +check_hwcfg_error: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int hi556_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct hi556 *hi556 = to_hi556(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(&client->dev); + mutex_destroy(&hi556->mutex); + + return 0; +} + +static int hi556_probe(struct i2c_client *client) +{ + struct hi556 *hi556; + int ret; + + ret = hi556_check_hwcfg(&client->dev); + if (ret) { + dev_err(&client->dev, "failed to check HW configuration: %d", + ret); + return ret; + } + + hi556 = devm_kzalloc(&client->dev, sizeof(*hi556), GFP_KERNEL); + if (!hi556) + return -ENOMEM; + + v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); + ret = hi556_identify_module(hi556); + if (ret) { + dev_err(&client->dev, "failed to find sensor: %d", ret); + return ret; + } + + mutex_init(&hi556->mutex); + hi556->cur_mode = &supported_modes[0]; + ret = hi556_init_controls(hi556); + if (ret) { + dev_err(&client->dev, "failed to init controls: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + hi556->sd.internal_ops = &hi556_internal_ops; + hi556->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + hi556->sd.entity.ops = &hi556_subdev_entity_ops; + hi556->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + hi556->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&hi556->sd.entity, 1, &hi556->pad); + if (ret) { + dev_err(&client->dev, "failed to init entity pads: %d", ret); + goto probe_error_v4l2_ctrl_handler_free; + } + + ret = v4l2_async_register_subdev_sensor_common(&hi556->sd); + if (ret < 0) { + dev_err(&client->dev, "failed to register V4L2 subdev: %d", + ret); + goto probe_error_media_entity_cleanup; + } + + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +probe_error_media_entity_cleanup: + media_entity_cleanup(&hi556->sd.entity); + +probe_error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(hi556->sd.ctrl_handler); + mutex_destroy(&hi556->mutex); + + return ret; +} + +static const struct dev_pm_ops hi556_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(hi556_suspend, hi556_resume) +}; + +#ifdef CONFIG_ACPI +static const struct acpi_device_id hi556_acpi_ids[] = { + {"INT3537"}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, hi556_acpi_ids); +#endif + +static struct i2c_driver hi556_i2c_driver = { + .driver = { + .name = "hi556", + .pm = &hi556_pm_ops, + .acpi_match_table = ACPI_PTR(hi556_acpi_ids), + }, + .probe_new = hi556_probe, + .remove = hi556_remove, +}; + +module_i2c_driver(hi556_i2c_driver); + +MODULE_AUTHOR("Shawn Tu <shawnx.tu@intel.com>"); +MODULE_DESCRIPTION("Hynix HI556 sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 159a3a604f0e..adcaaa8c86d1 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -47,6 +47,7 @@ struct imx214 { struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *link_freq; struct v4l2_ctrl *exposure; + struct v4l2_ctrl *unit_size; struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES]; @@ -948,6 +949,10 @@ static int imx214_probe(struct i2c_client *client) static const s64 link_freq[] = { IMX214_DEFAULT_LINK_FREQ, }; + static const struct v4l2_area unit_size = { + .width = 1120, + .height = 1120, + }; int ret; ret = imx214_parse_fwnode(dev); @@ -1029,6 +1034,10 @@ static int imx214_probe(struct i2c_client *client) V4L2_CID_EXPOSURE, 0, 3184, 1, 0x0c70); + imx214->unit_size = v4l2_ctrl_new_std_compound(&imx214->ctrls, + NULL, + V4L2_CID_UNIT_CELL_SIZE, + v4l2_ctrl_ptr_create((void *)&unit_size)); ret = imx214->ctrls.error; if (ret) { dev_err(&client->dev, "%s control init failed (%d)\n", diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c new file mode 100644 index 000000000000..f7678e5a5d87 --- /dev/null +++ b/drivers/media/i2c/imx290.c @@ -0,0 +1,884 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sony IMX290 CMOS Image Sensor Driver + * + * Copyright (C) 2019 FRAMOS GmbH. + * + * Copyright (C) 2019 Linaro Ltd. + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define IMX290_STANDBY 0x3000 +#define IMX290_REGHOLD 0x3001 +#define IMX290_XMSTA 0x3002 +#define IMX290_GAIN 0x3014 + +#define IMX290_DEFAULT_LINK_FREQ 445500000 + +static const char * const imx290_supply_name[] = { + "vdda", + "vddd", + "vdddo", +}; + +#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name) + +struct imx290_regval { + u16 reg; + u8 val; +}; + +struct imx290_mode { + u32 width; + u32 height; + u32 pixel_rate; + u32 link_freq_index; + + const struct imx290_regval *data; + u32 data_size; +}; + +struct imx290 { + struct device *dev; + struct clk *xclk; + struct regmap *regmap; + + struct v4l2_subdev sd; + struct v4l2_fwnode_endpoint ep; + struct media_pad pad; + struct v4l2_mbus_framefmt current_format; + const struct imx290_mode *current_mode; + + struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES]; + struct gpio_desc *rst_gpio; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + + struct mutex lock; +}; + +struct imx290_pixfmt { + u32 code; +}; + +static const struct imx290_pixfmt imx290_formats[] = { + { MEDIA_BUS_FMT_SRGGB10_1X10 }, +}; + +static const struct regmap_config imx290_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct imx290_regval imx290_global_init_settings[] = { + { 0x3007, 0x00 }, + { 0x3009, 0x00 }, + { 0x3018, 0x65 }, + { 0x3019, 0x04 }, + { 0x301a, 0x00 }, + { 0x3443, 0x03 }, + { 0x3444, 0x20 }, + { 0x3445, 0x25 }, + { 0x3407, 0x03 }, + { 0x303a, 0x0c }, + { 0x3040, 0x00 }, + { 0x3041, 0x00 }, + { 0x303c, 0x00 }, + { 0x303d, 0x00 }, + { 0x3042, 0x9c }, + { 0x3043, 0x07 }, + { 0x303e, 0x49 }, + { 0x303f, 0x04 }, + { 0x304b, 0x0a }, + { 0x300f, 0x00 }, + { 0x3010, 0x21 }, + { 0x3012, 0x64 }, + { 0x3016, 0x09 }, + { 0x3070, 0x02 }, + { 0x3071, 0x11 }, + { 0x309b, 0x10 }, + { 0x309c, 0x22 }, + { 0x30a2, 0x02 }, + { 0x30a6, 0x20 }, + { 0x30a8, 0x20 }, + { 0x30aa, 0x20 }, + { 0x30ac, 0x20 }, + { 0x30b0, 0x43 }, + { 0x3119, 0x9e }, + { 0x311c, 0x1e }, + { 0x311e, 0x08 }, + { 0x3128, 0x05 }, + { 0x313d, 0x83 }, + { 0x3150, 0x03 }, + { 0x317e, 0x00 }, + { 0x32b8, 0x50 }, + { 0x32b9, 0x10 }, + { 0x32ba, 0x00 }, + { 0x32bb, 0x04 }, + { 0x32c8, 0x50 }, + { 0x32c9, 0x10 }, + { 0x32ca, 0x00 }, + { 0x32cb, 0x04 }, + { 0x332c, 0xd3 }, + { 0x332d, 0x10 }, + { 0x332e, 0x0d }, + { 0x3358, 0x06 }, + { 0x3359, 0xe1 }, + { 0x335a, 0x11 }, + { 0x3360, 0x1e }, + { 0x3361, 0x61 }, + { 0x3362, 0x10 }, + { 0x33b0, 0x50 }, + { 0x33b2, 0x1a }, + { 0x33b3, 0x04 }, +}; + +static const struct imx290_regval imx290_1080p_settings[] = { + /* mode settings */ + { 0x3007, 0x00 }, + { 0x303a, 0x0c }, + { 0x3414, 0x0a }, + { 0x3472, 0x80 }, + { 0x3473, 0x07 }, + { 0x3418, 0x38 }, + { 0x3419, 0x04 }, + { 0x3012, 0x64 }, + { 0x3013, 0x00 }, + { 0x305c, 0x18 }, + { 0x305d, 0x03 }, + { 0x305e, 0x20 }, + { 0x305f, 0x01 }, + { 0x315e, 0x1a }, + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, + /* data rate settings */ + { 0x3009, 0x01 }, + { 0x3405, 0x10 }, + { 0x3446, 0x57 }, + { 0x3447, 0x00 }, + { 0x3448, 0x37 }, + { 0x3449, 0x00 }, + { 0x344a, 0x1f }, + { 0x344b, 0x00 }, + { 0x344c, 0x1f }, + { 0x344d, 0x00 }, + { 0x344e, 0x1f }, + { 0x344f, 0x00 }, + { 0x3450, 0x77 }, + { 0x3451, 0x00 }, + { 0x3452, 0x1f }, + { 0x3453, 0x00 }, + { 0x3454, 0x17 }, + { 0x3455, 0x00 }, + { 0x301c, 0x98 }, + { 0x301d, 0x08 }, +}; + +static const struct imx290_regval imx290_720p_settings[] = { + /* mode settings */ + { 0x3007, 0x10 }, + { 0x303a, 0x06 }, + { 0x3414, 0x04 }, + { 0x3472, 0x00 }, + { 0x3473, 0x05 }, + { 0x3418, 0xd0 }, + { 0x3419, 0x02 }, + { 0x3012, 0x64 }, + { 0x3013, 0x00 }, + { 0x305c, 0x20 }, + { 0x305d, 0x00 }, + { 0x305e, 0x20 }, + { 0x305f, 0x01 }, + { 0x315e, 0x1a }, + { 0x3164, 0x1a }, + { 0x3480, 0x49 }, + /* data rate settings */ + { 0x3009, 0x01 }, + { 0x3405, 0x10 }, + { 0x3446, 0x4f }, + { 0x3447, 0x00 }, + { 0x3448, 0x2f }, + { 0x3449, 0x00 }, + { 0x344a, 0x17 }, + { 0x344b, 0x00 }, + { 0x344c, 0x17 }, + { 0x344d, 0x00 }, + { 0x344e, 0x17 }, + { 0x344f, 0x00 }, + { 0x3450, 0x57 }, + { 0x3451, 0x00 }, + { 0x3452, 0x17 }, + { 0x3453, 0x00 }, + { 0x3454, 0x17 }, + { 0x3455, 0x00 }, + { 0x301c, 0xe4 }, + { 0x301d, 0x0c }, +}; + +static const struct imx290_regval imx290_10bit_settings[] = { + { 0x3005, 0x00}, + { 0x3046, 0x00}, + { 0x3129, 0x1d}, + { 0x317c, 0x12}, + { 0x31ec, 0x37}, + { 0x3441, 0x0a}, + { 0x3442, 0x0a}, + { 0x300a, 0x3c}, + { 0x300b, 0x00}, +}; + +/* supported link frequencies */ +static const s64 imx290_link_freq[] = { + IMX290_DEFAULT_LINK_FREQ, +}; + +/* Mode configs */ +static const struct imx290_mode imx290_modes[] = { + { + .width = 1920, + .height = 1080, + .data = imx290_1080p_settings, + .data_size = ARRAY_SIZE(imx290_1080p_settings), + .pixel_rate = 178200000, + .link_freq_index = 0, + }, + { + .width = 1280, + .height = 720, + .data = imx290_720p_settings, + .data_size = ARRAY_SIZE(imx290_720p_settings), + .pixel_rate = 178200000, + .link_freq_index = 0, + }, +}; + +static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx290, sd); +} + +static inline int imx290_read_reg(struct imx290 *imx290, u16 addr, u8 *value) +{ + unsigned int regval; + int ret; + + ret = regmap_read(imx290->regmap, addr, ®val); + if (ret) { + dev_err(imx290->dev, "I2C read failed for addr: %x\n", addr); + return ret; + } + + *value = regval & 0xff; + + return 0; +} + +static int imx290_write_reg(struct imx290 *imx290, u16 addr, u8 value) +{ + int ret; + + ret = regmap_write(imx290->regmap, addr, value); + if (ret) { + dev_err(imx290->dev, "I2C write failed for addr: %x\n", addr); + return ret; + } + + return ret; +} + +static int imx290_set_register_array(struct imx290 *imx290, + const struct imx290_regval *settings, + unsigned int num_settings) +{ + unsigned int i; + int ret; + + for (i = 0; i < num_settings; ++i, ++settings) { + ret = imx290_write_reg(imx290, settings->reg, settings->val); + if (ret < 0) + return ret; + + /* Settle time is 10ms for all registers */ + msleep(10); + } + + return 0; +} + +static int imx290_write_buffered_reg(struct imx290 *imx290, u16 address_low, + u8 nr_regs, u32 value) +{ + unsigned int i; + int ret; + + ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x01); + if (ret) { + dev_err(imx290->dev, "Error setting hold register\n"); + return ret; + } + + for (i = 0; i < nr_regs; i++) { + ret = imx290_write_reg(imx290, address_low + i, + (u8)(value >> (i * 8))); + if (ret) { + dev_err(imx290->dev, "Error writing buffered registers\n"); + return ret; + } + } + + ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x00); + if (ret) { + dev_err(imx290->dev, "Error setting hold register\n"); + return ret; + } + + return ret; +} + +static int imx290_set_gain(struct imx290 *imx290, u32 value) +{ + int ret; + + ret = imx290_write_buffered_reg(imx290, IMX290_GAIN, 1, value); + if (ret) + dev_err(imx290->dev, "Unable to write gain\n"); + + return ret; +} + +/* Stop streaming */ +static int imx290_stop_streaming(struct imx290 *imx290) +{ + int ret; + + ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x01); + if (ret < 0) + return ret; + + msleep(30); + + return imx290_write_reg(imx290, IMX290_XMSTA, 0x01); +} + +static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx290 *imx290 = container_of(ctrl->handler, + struct imx290, ctrls); + int ret = 0; + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(imx290->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_GAIN: + ret = imx290_set_gain(imx290, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(imx290->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx290_ctrl_ops = { + .s_ctrl = imx290_set_ctrl, +}; + +static int imx290_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(imx290_formats)) + return -EINVAL; + + code->code = imx290_formats[code->index].code; + + return 0; +} + +static int imx290_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx290 *imx290 = to_imx290(sd); + struct v4l2_mbus_framefmt *framefmt; + + mutex_lock(&imx290->lock); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + framefmt = v4l2_subdev_get_try_format(&imx290->sd, cfg, + fmt->pad); + else + framefmt = &imx290->current_format; + + fmt->format = *framefmt; + + mutex_unlock(&imx290->lock); + + return 0; +} + +static int imx290_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx290 *imx290 = to_imx290(sd); + const struct imx290_mode *mode; + struct v4l2_mbus_framefmt *format; + unsigned int i; + + mutex_lock(&imx290->lock); + + mode = v4l2_find_nearest_size(imx290_modes, + ARRAY_SIZE(imx290_modes), + width, height, + fmt->format.width, fmt->format.height); + + fmt->format.width = mode->width; + fmt->format.height = mode->height; + + for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) + if (imx290_formats[i].code == fmt->format.code) + break; + + if (i >= ARRAY_SIZE(imx290_formats)) + i = 0; + + fmt->format.code = imx290_formats[i].code; + fmt->format.field = V4L2_FIELD_NONE; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + } else { + format = &imx290->current_format; + __v4l2_ctrl_s_ctrl(imx290->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, mode->pixel_rate); + + imx290->current_mode = mode; + } + + *format = fmt->format; + + mutex_unlock(&imx290->lock); + + return 0; +} + +static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.format.width = 1920; + fmt.format.height = 1080; + + imx290_set_fmt(subdev, cfg, &fmt); + + return 0; +} + +static int imx290_write_current_format(struct imx290 *imx290, + struct v4l2_mbus_framefmt *format) +{ + int ret; + + switch (format->code) { + case MEDIA_BUS_FMT_SRGGB10_1X10: + ret = imx290_set_register_array(imx290, imx290_10bit_settings, + ARRAY_SIZE( + imx290_10bit_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set format registers\n"); + return ret; + } + break; + default: + dev_err(imx290->dev, "Unknown pixel format\n"); + return -EINVAL; + } + + return 0; +} + +/* Start streaming */ +static int imx290_start_streaming(struct imx290 *imx290) +{ + int ret; + + /* Set init register settings */ + ret = imx290_set_register_array(imx290, imx290_global_init_settings, + ARRAY_SIZE( + imx290_global_init_settings)); + if (ret < 0) { + dev_err(imx290->dev, "Could not set init registers\n"); + return ret; + } + + /* Set current frame format */ + ret = imx290_write_current_format(imx290, &imx290->current_format); + if (ret < 0) { + dev_err(imx290->dev, "Could not set frame format\n"); + return ret; + } + + /* Apply default values of current mode */ + ret = imx290_set_register_array(imx290, imx290->current_mode->data, + imx290->current_mode->data_size); + if (ret < 0) { + dev_err(imx290->dev, "Could not set current mode\n"); + return ret; + } + + /* Apply customized values from user */ + ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); + if (ret) { + dev_err(imx290->dev, "Could not sync v4l2 controls\n"); + return ret; + } + + ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x00); + if (ret < 0) + return ret; + + msleep(30); + + /* Start streaming */ + return imx290_write_reg(imx290, IMX290_XMSTA, 0x00); +} + +static int imx290_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx290 *imx290 = to_imx290(sd); + int ret = 0; + + if (enable) { + ret = pm_runtime_get_sync(imx290->dev); + if (ret < 0) { + pm_runtime_put_noidle(imx290->dev); + goto unlock_and_return; + } + + ret = imx290_start_streaming(imx290); + if (ret) { + dev_err(imx290->dev, "Start stream failed\n"); + pm_runtime_put(imx290->dev); + goto unlock_and_return; + } + } else { + imx290_stop_streaming(imx290); + pm_runtime_put(imx290->dev); + } + +unlock_and_return: + + return ret; +} + +static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) +{ + unsigned int i; + + for (i = 0; i < IMX290_NUM_SUPPLIES; i++) + imx290->supplies[i].supply = imx290_supply_name[i]; + + return devm_regulator_bulk_get(dev, IMX290_NUM_SUPPLIES, + imx290->supplies); +} + +static int imx290_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx290 *imx290 = to_imx290(sd); + int ret; + + ret = clk_prepare_enable(imx290->xclk); + if (ret) { + dev_err(imx290->dev, "Failed to enable clock\n"); + return ret; + } + + ret = regulator_bulk_enable(IMX290_NUM_SUPPLIES, imx290->supplies); + if (ret) { + dev_err(imx290->dev, "Failed to enable regulators\n"); + clk_disable_unprepare(imx290->xclk); + return ret; + } + + usleep_range(1, 2); + gpiod_set_value_cansleep(imx290->rst_gpio, 1); + usleep_range(30000, 31000); + + return 0; +} + +static int imx290_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx290 *imx290 = to_imx290(sd); + + clk_disable_unprepare(imx290->xclk); + gpiod_set_value_cansleep(imx290->rst_gpio, 0); + regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies); + + return 0; +} + +static const struct dev_pm_ops imx290_pm_ops = { + SET_RUNTIME_PM_OPS(imx290_power_on, imx290_power_off, NULL) +}; + +static const struct v4l2_subdev_video_ops imx290_video_ops = { + .s_stream = imx290_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx290_pad_ops = { + .init_cfg = imx290_entity_init_cfg, + .enum_mbus_code = imx290_enum_mbus_code, + .get_fmt = imx290_get_fmt, + .set_fmt = imx290_set_fmt, +}; + +static const struct v4l2_subdev_ops imx290_subdev_ops = { + .video = &imx290_video_ops, + .pad = &imx290_pad_ops, +}; + +static const struct media_entity_operations imx290_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int imx290_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct fwnode_handle *endpoint; + struct imx290 *imx290; + u32 xclk_freq; + int ret; + + imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); + if (!imx290) + return -ENOMEM; + + imx290->dev = dev; + imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config); + if (IS_ERR(imx290->regmap)) { + dev_err(dev, "Unable to initialize I2C\n"); + return -ENODEV; + } + + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); + if (!endpoint) { + dev_err(dev, "Endpoint node not found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &imx290->ep); + fwnode_handle_put(endpoint); + if (ret) { + dev_err(dev, "Parsing endpoint node failed\n"); + goto free_err; + } + + if (!imx290->ep.nr_of_link_frequencies) { + dev_err(dev, "link-frequency property not found in DT\n"); + ret = -EINVAL; + goto free_err; + } + + if (imx290->ep.link_frequencies[0] != IMX290_DEFAULT_LINK_FREQ) { + dev_err(dev, "Unsupported link frequency\n"); + ret = -EINVAL; + goto free_err; + } + + /* Only CSI2 is supported for now */ + if (imx290->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { + dev_err(dev, "Unsupported bus type, should be CSI2\n"); + ret = -EINVAL; + goto free_err; + } + + /* Set default mode to max resolution */ + imx290->current_mode = &imx290_modes[0]; + + /* get system clock (xclk) */ + imx290->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(imx290->xclk)) { + dev_err(dev, "Could not get xclk"); + ret = PTR_ERR(imx290->xclk); + goto free_err; + } + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &xclk_freq); + if (ret) { + dev_err(dev, "Could not get xclk frequency\n"); + goto free_err; + } + + /* external clock must be 37.125 MHz */ + if (xclk_freq != 37125000) { + dev_err(dev, "External clock frequency %u is not supported\n", + xclk_freq); + ret = -EINVAL; + goto free_err; + } + + ret = clk_set_rate(imx290->xclk, xclk_freq); + if (ret) { + dev_err(dev, "Could not set xclk frequency\n"); + goto free_err; + } + + ret = imx290_get_regulators(dev, imx290); + if (ret < 0) { + dev_err(dev, "Cannot get regulators\n"); + goto free_err; + } + + imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(imx290->rst_gpio)) { + dev_err(dev, "Cannot get reset gpio\n"); + ret = PTR_ERR(imx290->rst_gpio); + goto free_err; + } + + mutex_init(&imx290->lock); + + v4l2_ctrl_handler_init(&imx290->ctrls, 3); + + v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_GAIN, 0, 72, 1, 0); + imx290->link_freq = + v4l2_ctrl_new_int_menu(&imx290->ctrls, + &imx290_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(imx290_link_freq) - 1, + 0, imx290_link_freq); + if (imx290->link_freq) + imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, + INT_MAX, 1, + imx290_modes[0].pixel_rate); + + imx290->sd.ctrl_handler = &imx290->ctrls; + + if (imx290->ctrls.error) { + dev_err(dev, "Control initialization error %d\n", + imx290->ctrls.error); + ret = imx290->ctrls.error; + goto free_ctrl; + } + + v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); + imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx290->sd.dev = &client->dev; + imx290->sd.entity.ops = &imx290_subdev_entity_ops; + imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx290->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); + if (ret < 0) { + dev_err(dev, "Could not register media entity\n"); + goto free_ctrl; + } + + ret = v4l2_async_register_subdev(&imx290->sd); + if (ret < 0) { + dev_err(dev, "Could not register v4l2 device\n"); + goto free_entity; + } + + /* Power on the device to match runtime PM state below */ + ret = imx290_power_on(dev); + if (ret < 0) { + dev_err(dev, "Could not power on the device\n"); + goto free_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + v4l2_fwnode_endpoint_free(&imx290->ep); + + return 0; + +free_entity: + media_entity_cleanup(&imx290->sd.entity); +free_ctrl: + v4l2_ctrl_handler_free(&imx290->ctrls); + mutex_destroy(&imx290->lock); +free_err: + v4l2_fwnode_endpoint_free(&imx290->ep); + + return ret; +} + +static int imx290_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx290 *imx290 = to_imx290(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + mutex_destroy(&imx290->lock); + + pm_runtime_disable(imx290->dev); + if (!pm_runtime_status_suspended(imx290->dev)) + imx290_power_off(imx290->dev); + pm_runtime_set_suspended(imx290->dev); + + return 0; +} + +static const struct of_device_id imx290_of_match[] = { + { .compatible = "sony,imx290" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx290_of_match); + +static struct i2c_driver imx290_i2c_driver = { + .probe_new = imx290_probe, + .remove = imx290_remove, + .driver = { + .name = "imx290", + .pm = &imx290_pm_ops, + .of_match_table = of_match_ptr(imx290_of_match), + }, +}; + +module_i2c_driver(imx290_i2c_driver); + +MODULE_DESCRIPTION("Sony IMX290 CMOS Image Sensor Driver"); +MODULE_AUTHOR("FRAMOS GmbH"); +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c index d8a8853f9a2b..c76ccf67a909 100644 --- a/drivers/media/i2c/lm3646.c +++ b/drivers/media/i2c/lm3646.c @@ -134,7 +134,7 @@ static int lm3646_set_ctrl(struct v4l2_ctrl *ctrl) { struct lm3646_flash *flash = to_lm3646_flash(ctrl); unsigned int reg_val; - int rval = -EINVAL; + int rval; switch (ctrl->id) { case V4L2_CID_FLASH_LED_MODE: diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 19a3ceea3bc2..506a30e69ced 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -591,8 +591,8 @@ static int max2175_set_lo_freq(struct max2175 *ctx, u32 lo_freq) lo_freq *= lo_mult; int_desired = lo_freq / ctx->xtal_freq; - frac_desired = div_u64((u64)(lo_freq % ctx->xtal_freq) << 20, - ctx->xtal_freq); + frac_desired = div64_ul((u64)(lo_freq % ctx->xtal_freq) << 20, + ctx->xtal_freq); /* Check CSM is not busy */ ret = max2175_poll_csm_ready(ctx); diff --git a/drivers/media/i2c/max2175.h b/drivers/media/i2c/max2175.h index 1ece587c153d..4c722ea3e5f1 100644 --- a/drivers/media/i2c/max2175.h +++ b/drivers/media/i2c/max2175.h @@ -1,5 +1,5 @@ -/* SPDX-License-Identifier: GPL-2.0 - * +/* SPDX-License-Identifier: GPL-2.0 */ +/* * Maxim Integrated MAX2175 RF to Bits tuner driver * * This driver & most of the hard coded values are based on the reference diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 5613072908ac..210ea76adb53 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -167,7 +167,7 @@ static int multi_reg_write(struct i2c_client *client, static int mt9m001_init(struct i2c_client *client) { - const struct mt9m001_reg init_regs[] = { + static const struct mt9m001_reg init_regs[] = { /* * Issue a soft reset. This returns all registers to their * default values. diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index f4ded0669ff9..42f64175a6df 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Omnivision OV2659 CMOS Image Sensor driver * @@ -5,46 +6,21 @@ * * Benoit Parrot <bparrot@ti.com> * Lad, Prabhakar <prabhakar.csengg@gmail.com> - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/clk.h> #include <linux/delay.h> -#include <linux/err.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> -#include <linux/kernel.h> -#include <linux/media.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/of_graph.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/videodev2.h> +#include <linux/pm_runtime.h> -#include <media/media-entity.h> #include <media/i2c/ov2659.h> -#include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-image-sizes.h> -#include <media/v4l2-mediabus.h> #include <media/v4l2-subdev.h> #define DRIVER_NAME "ov2659" @@ -232,6 +208,10 @@ struct ov2659 { struct sensor_register *format_ctrl_regs; struct ov2659_pll_ctrl pll; int streaming; + /* used to control the sensor PWDN pin */ + struct gpio_desc *pwdn_gpio; + /* used to control the sensor RESETB pin */ + struct gpio_desc *resetb_gpio; }; static const struct sensor_register ov2659_init_regs[] = { @@ -419,10 +399,14 @@ static struct sensor_register ov2659_720p[] = { { REG_TIMING_YINC, 0x11 }, { REG_TIMING_VERT_FORMAT, 0x80 }, { REG_TIMING_HORIZ_FORMAT, 0x00 }, + { 0x370a, 0x12 }, { 0x3a03, 0xe8 }, { 0x3a09, 0x6f }, { 0x3a0b, 0x5d }, { 0x3a15, 0x9a }, + { REG_VFIFO_READ_START_H, 0x00 }, + { REG_VFIFO_READ_START_L, 0x80 }, + { REG_ISP_CTRL02, 0x00 }, { REG_NULL, 0x00 }, }; @@ -661,7 +645,7 @@ static struct sensor_register ov2659_vga[] = { { REG_TIMING_HORIZ_FORMAT, 0x01 }, { 0x370a, 0x52 }, { REG_VFIFO_READ_START_H, 0x00 }, - { REG_VFIFO_READ_START_L, 0x80 }, + { REG_VFIFO_READ_START_L, 0xa0 }, { REG_ISP_CTRL02, 0x10 }, { REG_NULL, 0x00 }, }; @@ -709,7 +693,7 @@ static struct sensor_register ov2659_qvga[] = { { REG_TIMING_HORIZ_FORMAT, 0x01 }, { 0x370a, 0x52 }, { REG_VFIFO_READ_START_H, 0x00 }, - { REG_VFIFO_READ_START_L, 0x80 }, + { REG_VFIFO_READ_START_L, 0xa0 }, { REG_ISP_CTRL02, 0x10 }, { REG_NULL, 0x00 }, }; @@ -1198,14 +1182,27 @@ static int ov2659_s_stream(struct v4l2_subdev *sd, int on) /* Stop Streaming Sequence */ ov2659_set_streaming(ov2659, 0); ov2659->streaming = on; + pm_runtime_put(&client->dev); goto unlock; } - ov2659_set_pixel_clock(ov2659); - ov2659_set_frame_size(ov2659); - ov2659_set_format(ov2659); - ov2659_set_streaming(ov2659, 1); - ov2659->streaming = on; + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto unlock; + } + + ret = ov2659_init(sd, 0); + if (!ret) + ret = ov2659_set_pixel_clock(ov2659); + if (!ret) + ret = ov2659_set_frame_size(ov2659); + if (!ret) + ret = ov2659_set_format(ov2659); + if (!ret) { + ov2659_set_streaming(ov2659, 1); + ov2659->streaming = on; + } unlock: mutex_unlock(&ov2659->lock); @@ -1239,12 +1236,18 @@ static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov2659 *ov2659 = container_of(ctrl->handler, struct ov2659, ctrls); + struct i2c_client *client = ov2659->client; + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; switch (ctrl->id) { case V4L2_CID_TEST_PATTERN: return ov2659_set_test_pattern(ov2659, ctrl->val); } + pm_runtime_put(&client->dev); return 0; } @@ -1257,6 +1260,39 @@ static const char * const ov2659_test_pattern_menu[] = { "Vertical Color Bars", }; +static int ov2659_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2659 *ov2659 = to_ov2659(sd); + + dev_dbg(&client->dev, "%s:\n", __func__); + + gpiod_set_value(ov2659->pwdn_gpio, 1); + + return 0; +} + +static int ov2659_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2659 *ov2659 = to_ov2659(sd); + + dev_dbg(&client->dev, "%s:\n", __func__); + + gpiod_set_value(ov2659->pwdn_gpio, 0); + + if (ov2659->resetb_gpio) { + gpiod_set_value(ov2659->resetb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(ov2659->resetb_gpio, 0); + usleep_range(3000, 5000); + } + + return 0; +} + /* ----------------------------------------------------------------------------- * V4L2 subdev internal operations */ @@ -1330,13 +1366,13 @@ static int ov2659_detect(struct v4l2_subdev *sd) unsigned short id; id = OV265X_ID(pid, ver); - if (id != OV2659_ID) + if (id != OV2659_ID) { dev_err(&client->dev, "Sensor detection failed (%04X, %d)\n", id, ret); - else { + ret = -ENODEV; + } else { dev_info(&client->dev, "Found OV%04X sensor\n", id); - ret = ov2659_init(sd, 0); } } @@ -1413,6 +1449,18 @@ static int ov2659_probe(struct i2c_client *client) ov2659->xvclk_frequency > 27000000) return -EINVAL; + /* Optional gpio don't fail if not present */ + ov2659->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(ov2659->pwdn_gpio)) + return PTR_ERR(ov2659->pwdn_gpio); + + /* Optional gpio don't fail if not present */ + ov2659->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov2659->resetb_gpio)) + return PTR_ERR(ov2659->resetb_gpio); + v4l2_ctrl_handler_init(&ov2659->ctrls, 2); ov2659->link_frequency = v4l2_ctrl_new_std(&ov2659->ctrls, &ov2659_ctrl_ops, @@ -1458,6 +1506,8 @@ static int ov2659_probe(struct i2c_client *client) ov2659->frame_size = &ov2659_framesizes[2]; ov2659->format_ctrl_regs = ov2659_formats[0].format_ctrl_regs; + ov2659_power_on(&client->dev); + ret = ov2659_detect(sd); if (ret < 0) goto error; @@ -1471,10 +1521,15 @@ static int ov2659_probe(struct i2c_client *client) dev_info(&client->dev, "%s sensor driver registered !!\n", sd->name); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + return 0; error: v4l2_ctrl_handler_free(&ov2659->ctrls); + ov2659_power_off(&client->dev); media_entity_cleanup(&sd->entity); mutex_destroy(&ov2659->lock); return ret; @@ -1490,9 +1545,18 @@ static int ov2659_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); mutex_destroy(&ov2659->lock); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov2659_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + return 0; } +static const struct dev_pm_ops ov2659_pm_ops = { + SET_RUNTIME_PM_OPS(ov2659_power_off, ov2659_power_on, NULL) +}; + static const struct i2c_device_id ov2659_id[] = { { "ov2659", 0 }, { /* sentinel */ }, @@ -1510,6 +1574,7 @@ MODULE_DEVICE_TABLE(of, ov2659_of_match); static struct i2c_driver ov2659_i2c_driver = { .driver = { .name = DRIVER_NAME, + .pm = &ov2659_pm_ops, .of_match_table = of_match_ptr(ov2659_of_match), }, .probe_new = ov2659_probe, diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 500d9bbff10b..5e495c833d32 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -193,6 +193,7 @@ struct ov5640_mode_info { struct ov5640_ctrls { struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *pixel_rate; struct { struct v4l2_ctrl *auto_exp; struct v4l2_ctrl *exposure; @@ -489,7 +490,6 @@ static const struct reg_value ov5640_setting_720P_1280_720[] = { }; static const struct reg_value ov5640_setting_1080P_1920_1080[] = { - {0x3008, 0x42, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x11, 0, 0}, @@ -517,7 +517,7 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = { {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, {0x3a15, 0x60, 0, 0}, {0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, - {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, + {0x4005, 0x1a, 0, 0}, }; static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { @@ -1611,9 +1611,24 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, !(mode->hact == 640 && mode->vact == 480)) return NULL; + /* 2592x1944 only works at 15fps max */ + if ((mode->hact == 2592 && mode->vact == 1944) && + fr > OV5640_15_FPS) + return NULL; + return mode; } +static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor) +{ + u64 rate; + + rate = sensor->current_mode->vtot * sensor->current_mode->htot; + rate *= ov5640_framerates[sensor->current_fr]; + + return rate; +} + /* * sensor changes between scaling and subsampling, go through * exposure calculation @@ -1818,8 +1833,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) * All the formats we support have 16 bits per pixel, seems to require * the same rate than YUV, so we can just use 16 bpp all the time. */ - rate = mode->vtot * mode->htot * 16; - rate *= ov5640_framerates[sensor->current_fr]; + rate = ov5640_calc_pixel_rate(sensor) * 16; if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) { rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes; ret = ov5640_set_mipi_pclk(sensor, rate); @@ -2233,6 +2247,8 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd, if (mbus_fmt->code != sensor->fmt.code) sensor->pending_fmt_change = true; + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, + ov5640_calc_pixel_rate(sensor)); out: mutex_unlock(&sensor->lock); return ret; @@ -2657,6 +2673,11 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) /* we can use our own mutex for the ctrl lock */ hdl->lock = &sensor->lock; + /* Clock related controls */ + ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, + 0, INT_MAX, 1, + ov5640_calc_pixel_rate(sensor)); + /* Auto/manual white balance */ ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, @@ -2704,6 +2725,7 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) goto free_ctrls; } + ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; @@ -2816,6 +2838,9 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, sensor->frame_interval = fi->interval; sensor->current_mode = mode; sensor->pending_mode_change = true; + + __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, + ov5640_calc_pixel_rate(sensor)); } out: mutex_unlock(&sensor->lock); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 34b7046d9702..d6cd15bb699a 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1325,7 +1325,7 @@ static int ov5695_probe(struct i2c_client *client, goto err_power_off; #endif - ret = v4l2_async_register_subdev(sd); + ret = v4l2_async_register_subdev_sensor_common(sd); if (ret) { dev_err(dev, "v4l2 async register subdev failed\n"); goto err_clean_entity; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 5b9af5e5b7f1..91906b94f978 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -124,12 +124,13 @@ #define DEF_AECH 0x4D -#define CLKRC_6MHz 0x00 +#define CLKRC_8MHz 0x00 #define CLKRC_12MHz 0x40 #define CLKRC_16MHz 0x80 #define CLKRC_24MHz 0xc0 #define CLKRC_DIV_MASK 0x3f #define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) +#define DEF_CLKRC 0x00 #define COMA_RESET BIT(7) #define COMA_QCIF BIT(5) @@ -196,13 +197,33 @@ struct ov6650 { struct v4l2_clk *clk; bool half_scale; /* scale down output by 2 */ struct v4l2_rect rect; /* sensor cropping window */ - unsigned long pclk_limit; /* from host */ - unsigned long pclk_max; /* from resolution and format */ struct v4l2_fract tpf; /* as requested with s_frame_interval */ u32 code; - enum v4l2_colorspace colorspace; }; +struct ov6650_xclk { + unsigned long rate; + u8 clkrc; +}; + +static const struct ov6650_xclk ov6650_xclk[] = { +{ + .rate = 8000000, + .clkrc = CLKRC_8MHz, +}, +{ + .rate = 12000000, + .clkrc = CLKRC_12MHz, +}, +{ + .rate = 16000000, + .clkrc = CLKRC_16MHz, +}, +{ + .rate = 24000000, + .clkrc = CLKRC_24MHz, +}, +}; static u32 ov6650_codes[] = { MEDIA_BUS_FMT_YUYV8_2X8, @@ -213,6 +234,17 @@ static u32 ov6650_codes[] = { MEDIA_BUS_FMT_Y8_1X8, }; +static const struct v4l2_mbus_framefmt ov6650_def_fmt = { + .width = W_CIF, + .height = H_CIF, + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, +}; + /* read a register */ static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) { @@ -465,38 +497,39 @@ static int ov6650_set_selection(struct v4l2_subdev *sd, { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect rect = sel->r; int ret; if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - v4l_bound_align_image(&rect.width, 2, W_CIF, 1, - &rect.height, 2, H_CIF, 1, 0); - v4l_bound_align_image(&rect.left, DEF_HSTRT << 1, - (DEF_HSTRT << 1) + W_CIF - (__s32)rect.width, 1, - &rect.top, DEF_VSTRT << 1, - (DEF_VSTRT << 1) + H_CIF - (__s32)rect.height, 1, - 0); + v4l_bound_align_image(&sel->r.width, 2, W_CIF, 1, + &sel->r.height, 2, H_CIF, 1, 0); + v4l_bound_align_image(&sel->r.left, DEF_HSTRT << 1, + (DEF_HSTRT << 1) + W_CIF - (__s32)sel->r.width, 1, + &sel->r.top, DEF_VSTRT << 1, + (DEF_VSTRT << 1) + H_CIF - (__s32)sel->r.height, + 1, 0); - ret = ov6650_reg_write(client, REG_HSTRT, rect.left >> 1); + ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1); if (!ret) { - priv->rect.left = rect.left; + priv->rect.width += priv->rect.left - sel->r.left; + priv->rect.left = sel->r.left; ret = ov6650_reg_write(client, REG_HSTOP, - (rect.left + rect.width) >> 1); + (sel->r.left + sel->r.width) >> 1); } if (!ret) { - priv->rect.width = rect.width; - ret = ov6650_reg_write(client, REG_VSTRT, rect.top >> 1); + priv->rect.width = sel->r.width; + ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1); } if (!ret) { - priv->rect.top = rect.top; + priv->rect.height += priv->rect.top - sel->r.top; + priv->rect.top = sel->r.top; ret = ov6650_reg_write(client, REG_VSTOP, - (rect.top + rect.height) >> 1); + (sel->r.top + sel->r.height) >> 1); } if (!ret) - priv->rect.height = rect.height; + priv->rect.height = sel->r.height; return ret; } @@ -512,12 +545,20 @@ static int ov6650_get_fmt(struct v4l2_subdev *sd, if (format->pad) return -EINVAL; - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - mf->colorspace = priv->colorspace; - mf->field = V4L2_FIELD_NONE; + /* initialize response with default media bus frame format */ + *mf = ov6650_def_fmt; + + /* update media bus format code and frame size */ + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + } else { + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } @@ -526,22 +567,7 @@ static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) return width > rect->width >> 1 || height > rect->height >> 1; } -static u8 to_clkrc(struct v4l2_fract *timeperframe, - unsigned long pclk_limit, unsigned long pclk_max) -{ - unsigned long pclk; - - if (timeperframe->numerator && timeperframe->denominator) - pclk = pclk_max * timeperframe->denominator / - (FRAME_RATE_MAX * timeperframe->numerator); - else - pclk = pclk_max; - - if (pclk_limit && pclk_limit < pclk) - pclk = pclk_limit; - - return (pclk_max - 1) / pclk; -} +#define to_clkrc(div) ((div) - 1) /* set the format we will capture in */ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) @@ -560,8 +586,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) .r.height = mf->height << half_scale, }; u32 code = mf->code; - unsigned long mclk, pclk; - u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc; + u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask; int ret; /* select color matrix configuration for given color encoding */ @@ -610,58 +635,35 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code); return -EINVAL; } - priv->code = code; if (code == MEDIA_BUS_FMT_Y8_1X8 || code == MEDIA_BUS_FMT_SBGGR8_1X8) { coml_mask = COML_ONE_CHANNEL; coml_set = 0; - priv->pclk_max = 4000000; } else { coml_mask = 0; coml_set = COML_ONE_CHANNEL; - priv->pclk_max = 8000000; } - if (code == MEDIA_BUS_FMT_SBGGR8_1X8) - priv->colorspace = V4L2_COLORSPACE_SRGB; - else if (code != 0) - priv->colorspace = V4L2_COLORSPACE_JPEG; - if (half_scale) { dev_dbg(&client->dev, "max resolution: QCIF\n"); coma_set |= COMA_QCIF; - priv->pclk_max /= 2; } else { dev_dbg(&client->dev, "max resolution: CIF\n"); coma_mask |= COMA_QCIF; } - priv->half_scale = half_scale; - - clkrc = CLKRC_12MHz; - mclk = 12000000; - priv->pclk_limit = 1334000; - dev_dbg(&client->dev, "using 12MHz input clock\n"); - - clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); - - pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc); - dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n", - mclk / pclk, 10 * mclk % pclk / pclk); ret = ov6650_set_selection(sd, NULL, &sel); if (!ret) ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); - if (!ret) - ret = ov6650_reg_write(client, REG_CLKRC, clkrc); - if (!ret) - ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); - if (!ret) { - mf->colorspace = priv->colorspace; - mf->width = priv->rect.width >> half_scale; - mf->height = priv->rect.height >> half_scale; + priv->half_scale = half_scale; + + ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); } + if (!ret) + priv->code = code; + return ret; } @@ -680,8 +682,6 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 2, W_CIF, 1, &mf->height, 2, H_CIF, 1, 0); - mf->field = V4L2_FIELD_NONE; - switch (mf->code) { case MEDIA_BUS_FMT_Y10_1X10: mf->code = MEDIA_BUS_FMT_Y8_1X8; @@ -691,20 +691,39 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd, case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; break; default: mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; /* fall through */ case MEDIA_BUS_FMT_SBGGR8_1X8: - mf->colorspace = V4L2_COLORSPACE_SRGB; break; } - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov6650_s_fmt(sd, mf); - cfg->try_fmt = *mf; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + /* store media bus format code and frame size in pad config */ + cfg->try_fmt.width = mf->width; + cfg->try_fmt.height = mf->height; + cfg->try_fmt.code = mf->code; + /* return default mbus frame format updated with pad config */ + *mf = ov6650_def_fmt; + mf->width = cfg->try_fmt.width; + mf->height = cfg->try_fmt.height; + mf->code = cfg->try_fmt.code; + + } else { + /* apply new media bus format code and frame size */ + int ret = ov6650_s_fmt(sd, mf); + + if (ret) + return ret; + + /* return default format updated with active size and code */ + *mf = ov6650_def_fmt; + mf->width = priv->rect.width >> priv->half_scale; + mf->height = priv->rect.height >> priv->half_scale; + mf->code = priv->code; + } return 0; } @@ -725,9 +744,7 @@ static int ov6650_g_frame_interval(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - ival->interval.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf, - priv->pclk_limit, priv->pclk_max)); - ival->interval.denominator = FRAME_RATE_MAX; + ival->interval = priv->tpf; dev_dbg(&client->dev, "Frame interval: %u/%u s\n", ival->interval.numerator, ival->interval.denominator); @@ -742,7 +759,6 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd, struct ov6650 *priv = to_ov6650(client); struct v4l2_fract *tpf = &ival->interval; int div, ret; - u8 clkrc; if (tpf->numerator == 0 || tpf->denominator == 0) div = 1; /* Reset to full rate */ @@ -754,19 +770,12 @@ static int ov6650_s_frame_interval(struct v4l2_subdev *sd, else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) div = GET_CLKRC_DIV(CLKRC_DIV_MASK); - /* - * Keep result to be used as tpf limit - * for subsequent clock divider calculations - */ - priv->tpf.numerator = div; - priv->tpf.denominator = FRAME_RATE_MAX; - - clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max); - - ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK); + ret = ov6650_reg_rmw(client, REG_CLKRC, to_clkrc(div), CLKRC_DIV_MASK); if (!ret) { - tpf->numerator = GET_CLKRC_DIV(clkrc); - tpf->denominator = FRAME_RATE_MAX; + priv->tpf.numerator = div; + priv->tpf.denominator = FRAME_RATE_MAX; + + *tpf = priv->tpf; } return ret; @@ -788,7 +797,7 @@ static int ov6650_reset(struct i2c_client *client) } /* program default register values */ -static int ov6650_prog_dflt(struct i2c_client *client) +static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc) { int ret; @@ -796,6 +805,8 @@ static int ov6650_prog_dflt(struct i2c_client *client) ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ if (!ret) + ret = ov6650_reg_write(client, REG_CLKRC, clkrc); + if (!ret) ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); return ret; @@ -805,8 +816,10 @@ static int ov6650_video_probe(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); - u8 pidh, pidl, midh, midl; - int ret; + const struct ov6650_xclk *xclk = NULL; + unsigned long rate; + u8 pidh, pidl, midh, midl; + int i, ret = 0; priv->clk = v4l2_clk_get(&client->dev, NULL); if (IS_ERR(priv->clk)) { @@ -815,6 +828,33 @@ static int ov6650_video_probe(struct v4l2_subdev *sd) return ret; } + rate = v4l2_clk_get_rate(priv->clk); + for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) { + if (rate != ov6650_xclk[i].rate) + continue; + + xclk = &ov6650_xclk[i]; + dev_info(&client->dev, "using host default clock rate %lukHz\n", + rate / 1000); + break; + } + for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) { + ret = v4l2_clk_set_rate(priv->clk, ov6650_xclk[i].rate); + if (ret || v4l2_clk_get_rate(priv->clk) != ov6650_xclk[i].rate) + continue; + + xclk = &ov6650_xclk[i]; + dev_info(&client->dev, "using negotiated clock rate %lukHz\n", + xclk->rate / 1000); + break; + } + if (!xclk) { + dev_err(&client->dev, "unable to get supported clock rate\n"); + if (!ret) + ret = -EINVAL; + goto eclkput; + } + ret = ov6650_s_power(sd, 1); if (ret < 0) goto eclkput; @@ -848,7 +888,12 @@ static int ov6650_video_probe(struct v4l2_subdev *sd) ret = ov6650_reset(client); if (!ret) - ret = ov6650_prog_dflt(client); + ret = ov6650_prog_dflt(client, xclk->clkrc); + if (!ret) { + struct v4l2_mbus_framefmt mf = ov6650_def_fmt; + + ret = ov6650_s_fmt(sd, &mf); + } if (!ret) ret = v4l2_ctrl_handler_setup(&priv->hdl); @@ -989,8 +1034,10 @@ static int ov6650_probe(struct i2c_client *client, V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; + if (priv->hdl.error) { + ret = priv->hdl.error; + goto ectlhdlfree; + } v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); @@ -1001,15 +1048,18 @@ static int ov6650_probe(struct i2c_client *client, priv->rect.top = DEF_VSTRT << 1; priv->rect.width = W_CIF; priv->rect.height = H_CIF; - priv->half_scale = false; - priv->code = MEDIA_BUS_FMT_YUYV8_2X8; - priv->colorspace = V4L2_COLORSPACE_JPEG; + + /* Hardware default frame interval */ + priv->tpf.numerator = GET_CLKRC_DIV(DEF_CLKRC); + priv->tpf.denominator = FRAME_RATE_MAX; priv->subdev.internal_ops = &ov6650_internal_ops; ret = v4l2_async_register_subdev(&priv->subdev); - if (ret) - v4l2_ctrl_handler_free(&priv->hdl); + if (!ret) + return 0; +ectlhdlfree: + v4l2_ctrl_handler_free(&priv->hdl); return ret; } @@ -1041,6 +1091,6 @@ static struct i2c_driver ov6650_i2c_driver = { module_i2c_driver(ov6650_i2c_driver); -MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650"); -MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>"); +MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera sensor"); +MODULE_AUTHOR("Janusz Krzysztofik <jmkrzyszt@gmail.com"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/saa711x_regs.h b/drivers/media/i2c/saa711x_regs.h index 44fabe08234d..4b5f6985710b 100644 --- a/drivers/media/i2c/saa711x_regs.h +++ b/drivers/media/i2c/saa711x_regs.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ /* - * SPDX-License-Identifier: GPL-2.0+ * saa711x - Philips SAA711x video decoder register specifications * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 9adf8e034e7d..84f9771b5fed 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -682,66 +682,6 @@ static int smiapp_get_all_limits(struct smiapp_sensor *sensor) return 0; } -static int smiapp_get_limits_binning(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - static u32 const limits[] = { - SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN, - SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN, - SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN, - SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN, - SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, - SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN, - SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, - }; - static u32 const limits_replace[] = { - SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES, - SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES, - SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK, - SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK, - SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK, - SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN, - SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN, - }; - unsigned int i; - int rval; - - if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] == - SMIAPP_BINNING_CAPABILITY_NO) { - for (i = 0; i < ARRAY_SIZE(limits); i++) - sensor->limits[limits[i]] = - sensor->limits[limits_replace[i]]; - - return 0; - } - - rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits)); - if (rval < 0) - return rval; - - /* - * Sanity check whether the binning limits are valid. If not, - * use the non-binning ones. - */ - if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]) - return 0; - - for (i = 0; i < ARRAY_SIZE(limits); i++) { - dev_dbg(&client->dev, - "replace limit 0x%8.8x \"%s\" = %d, 0x%x\n", - smiapp_reg_limits[limits[i]].addr, - smiapp_reg_limits[limits[i]].what, - sensor->limits[limits_replace[i]], - sensor->limits[limits_replace[i]]); - sensor->limits[limits[i]] = - sensor->limits[limits_replace[i]]; - } - - return 0; -} - static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -891,60 +831,47 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) { struct v4l2_ctrl *vblank = sensor->vblank; struct v4l2_ctrl *hblank = sensor->hblank; + uint16_t min_fll, max_fll, min_llp, max_llp, min_lbp; int min, max; + if (sensor->binning_vertical > 1 || sensor->binning_horizontal > 1) { + min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]; + max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN]; + min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]; + max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN]; + min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]; + } else { + min_fll = sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES]; + max_fll = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES]; + min_llp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK]; + max_llp = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK]; + min_lbp = sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK]; + } + min = max_t(int, sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - + min_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); - max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; + max = max_fll - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); min = max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - + min_llp - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); - max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; + min_lbp); + max = max_llp - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); __smiapp_update_exposure_limits(sensor); } -static int smiapp_update_mode(struct smiapp_sensor *sensor) +static int smiapp_pll_blanking_update(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int binning_mode; int rval; - /* Binning has to be set up here; it affects limits */ - if (sensor->binning_horizontal == 1 && - sensor->binning_vertical == 1) { - binning_mode = 0; - } else { - u8 binning_type = - (sensor->binning_horizontal << 4) - | sensor->binning_vertical; - - rval = smiapp_write( - sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type); - if (rval < 0) - return rval; - - binning_mode = 1; - } - rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode); - if (rval < 0) - return rval; - - /* Get updated limits due to binning */ - rval = smiapp_get_limits_binning(sensor); - if (rval < 0) - return rval; - rval = smiapp_pll_update(sensor); if (rval < 0) return rval; @@ -970,62 +897,91 @@ static int smiapp_update_mode(struct smiapp_sensor *sensor) * SMIA++ NVM handling * */ -static int smiapp_read_nvm(struct smiapp_sensor *sensor, - unsigned char *nvm) + +static int smiapp_read_nvm_page(struct smiapp_sensor *sensor, u32 p, u8 *nvm, + u8 *status) { - u32 i, s, p, np, v; - int rval = 0, rval2; + unsigned int i; + int rval; + u32 s; - np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE; - for (p = 0; p < np; p++) { - rval = smiapp_write( - sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p); - if (rval) - goto out; + *status = 0; - rval = smiapp_write(sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, - SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN | - SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN); - if (rval) - goto out; + rval = smiapp_write(sensor, + SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p); + if (rval) + return rval; - for (i = 1000; i > 0; i--) { - rval = smiapp_read( - sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); + rval = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, + SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN); + if (rval) + return rval; - if (rval) - goto out; + rval = smiapp_read(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, + &s); + if (rval) + return rval; + + if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE) { + *status = s; + return -ENODATA; + } + if (sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] & + SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL) { + for (i = 1000; i > 0; i--) { if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) break; - } - if (!i) { - rval = -ETIMEDOUT; - goto out; - } - - for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { rval = smiapp_read( sensor, - SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i, - &v); - if (rval) - goto out; + SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, + &s); - *nvm++ = v; + if (rval) + return rval; } + + if (!i) + return -ETIMEDOUT; } -out: + for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { + u32 v; + + rval = smiapp_read(sensor, + SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i, + &v); + if (rval) + return rval; + + *nvm++ = v; + } + + return 0; +} + +static int smiapp_read_nvm(struct smiapp_sensor *sensor, unsigned char *nvm, + size_t nvm_size) +{ + u8 status = 0; + u32 p; + int rval = 0, rval2; + + for (p = 0; p < nvm_size / SMIAPP_NVM_PAGE_SIZE && !rval; p++) { + rval = smiapp_read_nvm_page(sensor, p, nvm, &status); + nvm += SMIAPP_NVM_PAGE_SIZE; + } + + if (rval == -ENODATA && + status & SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE) + rval = 0; + rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0); if (rval < 0) return rval; else - return rval2; + return rval2 ?: p * SMIAPP_NVM_PAGE_SIZE; } /* @@ -1324,10 +1280,6 @@ static int smiapp_power_on(struct device *dev) rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); if (rval) goto out_cci_addr_fail; - - rval = smiapp_update_mode(sensor); - if (rval < 0) - goto out_cci_addr_fail; } mutex_unlock(&sensor->mutex); @@ -1387,6 +1339,7 @@ static int smiapp_power_off(struct device *dev) static int smiapp_start_streaming(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + unsigned int binning_mode; int rval; mutex_lock(&sensor->mutex); @@ -1397,6 +1350,27 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor) if (rval) goto out; + /* Binning configuration */ + if (sensor->binning_horizontal == 1 && + sensor->binning_vertical == 1) { + binning_mode = 0; + } else { + u8 binning_type = + (sensor->binning_horizontal << 4) + | sensor->binning_vertical; + + rval = smiapp_write( + sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type); + if (rval < 0) + goto out; + + binning_mode = 1; + } + rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode); + if (rval < 0) + goto out; + + /* Set up PLL */ rval = smiapp_pll_configure(sensor); if (rval) goto out; @@ -2073,7 +2047,7 @@ static int smiapp_set_compose(struct v4l2_subdev *subdev, smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return smiapp_update_mode(sensor); + return smiapp_pll_blanking_update(sensor); return 0; } @@ -2312,41 +2286,34 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); struct i2c_client *client = v4l2_get_subdevdata(subdev); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - unsigned int nbytes; + int rval; if (!sensor->dev_init_done) return -EBUSY; - if (!sensor->nvm_size) { - int rval; - - /* NVM not read yet - read it now */ - sensor->nvm_size = sensor->hwcfg->nvm_size; + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put_noidle(&client->dev); + return -ENODEV; + } - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) { - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(&client->dev); - pm_runtime_put(&client->dev); - return -ENODEV; - } + rval = smiapp_read_nvm(sensor, buf, PAGE_SIZE); + if (rval < 0) { + pm_runtime_put(&client->dev); + dev_err(&client->dev, "nvm read failed\n"); + return -ENODEV; + } - if (smiapp_read_nvm(sensor, sensor->nvm)) { - dev_err(&client->dev, "nvm read failed\n"); - return -ENODEV; - } + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); - pm_runtime_mark_last_busy(&client->dev); - pm_runtime_put_autosuspend(&client->dev); - } /* * NVM is still way below a PAGE_SIZE, so we can safely * assume this for now. */ - nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE); - memcpy(buf, sensor->nvm, nbytes); - - return nbytes; + return rval; } static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL); @@ -2810,16 +2777,13 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) } } - /* NVM size is not mandatory */ - fwnode_property_read_u32(fwnode, "nokia,nvm-size", &hwcfg->nvm_size); - rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &hwcfg->ext_clk); if (rval) dev_info(dev, "can't get clock-frequency\n"); - dev_dbg(dev, "nvm %d, clk %d, mode %d\n", - hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); + dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, + hwcfg->csi_signalling_mode); if (!bus_cfg.nr_of_link_frequencies) { dev_warn(dev, "no link frequencies defined\n"); @@ -2862,7 +2826,6 @@ static int smiapp_probe(struct i2c_client *client) return -ENOMEM; sensor->hwcfg = hwcfg; - mutex_init(&sensor->mutex); sensor->src = &sensor->ssds[sensor->ssds_used]; v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); @@ -2926,6 +2889,8 @@ static int smiapp_probe(struct i2c_client *client) if (rval < 0) return rval; + mutex_init(&sensor->mutex); + rval = smiapp_identify_module(sensor); if (rval) { rval = -ENODEV; @@ -3003,17 +2968,10 @@ static int smiapp_probe(struct i2c_client *client) rval = -ENOENT; goto out_power_off; } - /* SMIA++ NVM initialization - it will be read from the sensor - * when it is first requested by userspace. - */ - if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) { - sensor->nvm = devm_kzalloc(&client->dev, - sensor->hwcfg->nvm_size, GFP_KERNEL); - if (sensor->nvm == NULL) { - rval = -ENOMEM; - goto out_cleanup; - } + if (sensor->minfo.smiapp_version && + sensor->limits[SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY] & + SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED) { if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { dev_err(&client->dev, "sysfs nvm entry failed\n"); rval = -EBUSY; @@ -3086,7 +3044,7 @@ static int smiapp_probe(struct i2c_client *client) } mutex_lock(&sensor->mutex); - rval = smiapp_update_mode(sensor); + rval = smiapp_pll_blanking_update(sensor); mutex_unlock(&sensor->mutex); if (rval) { dev_err(&client->dev, "update mode failed\n"); @@ -3101,19 +3059,23 @@ static int smiapp_probe(struct i2c_client *client) if (rval < 0) goto out_media_entity_cleanup; - rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); - if (rval < 0) - goto out_media_entity_cleanup; - pm_runtime_set_active(&client->dev); pm_runtime_get_noresume(&client->dev); pm_runtime_enable(&client->dev); + + rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); + if (rval < 0) + goto out_disable_runtime_pm; + pm_runtime_set_autosuspend_delay(&client->dev, 1000); pm_runtime_use_autosuspend(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; +out_disable_runtime_pm: + pm_runtime_disable(&client->dev); + out_media_entity_cleanup: media_entity_cleanup(&sensor->src->sd.entity); @@ -3122,6 +3084,7 @@ out_cleanup: out_power_off: smiapp_power_off(&client->dev); + mutex_destroy(&sensor->mutex); return rval; } @@ -3144,6 +3107,7 @@ static int smiapp_remove(struct i2c_client *client) media_entity_cleanup(&sensor->ssds[i].sd.entity); } smiapp_cleanup(sensor); + mutex_destroy(&sensor->mutex); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h index 2804a4d9a4e1..43505cd0616e 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ b/drivers/media/i2c/smiapp/smiapp-reg.h @@ -11,25 +11,29 @@ #ifndef __SMIAPP_REG_H_ #define __SMIAPP_REG_H_ +#include <linux/bits.h> + #include "smiapp-reg-defs.h" /* Bits for above register */ -#define SMIAPP_IMAGE_ORIENTATION_HFLIP (1 << 0) -#define SMIAPP_IMAGE_ORIENTATION_VFLIP (1 << 1) - -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN (1 << 0) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN (0 << 1) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN (1 << 1) -#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR (1 << 2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY (1 << 0) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY (1 << 1) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA (1 << 2) -#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE (1 << 3) - -#define SMIAPP_SOFTWARE_RESET (1 << 0) - -#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE (1 << 0) -#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE (1 << 1) +#define SMIAPP_IMAGE_ORIENTATION_HFLIP BIT(0) +#define SMIAPP_IMAGE_ORIENTATION_VFLIP BIT(1) + +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY BIT(1) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA BIT(2) +#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE BIT(3) + +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_SUPPORTED BIT(0) +#define SMIAPP_DATA_TRANSFER_IF_CAPABILITY_POLL BIT(2) + +#define SMIAPP_SOFTWARE_RESET BIT(0) + +#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE BIT(0) +#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE BIT(1) #define SMIAPP_DPHY_CTRL_AUTOMATIC 0 /* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index ecf8a17dbe37..3ab874a5deba 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -208,9 +208,6 @@ struct smiapp_sensor { bool dev_init_done; u8 compressed_min_bpp; - u8 *nvm; /* nvm memory buffer */ - unsigned int nvm_size; /* bytes */ - struct smiapp_module_info minfo; struct smiapp_pll pll; diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 81285b8d5cfb..003ba22334cd 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -971,6 +971,11 @@ static int mipid02_probe(struct i2c_client *client) bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(bridge->reset_gpio)) { + dev_err(dev, "failed to get reset GPIO\n"); + return PTR_ERR(bridge->reset_gpio); + } + ret = mipid02_get_regulators(bridge); if (ret) { dev_err(dev, "failed to get regulators %d", ret); diff --git a/drivers/media/i2c/tda1997x_regs.h b/drivers/media/i2c/tda1997x_regs.h index ecf87534613b..d9b3daada07d 100644 --- a/drivers/media/i2c/tda1997x_regs.h +++ b/drivers/media/i2c/tda1997x_regs.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2018 Gateworks Corporation */ diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h index 9088186c24d1..f716129adf09 100644 --- a/drivers/media/i2c/tvp5150_reg.h +++ b/drivers/media/i2c/tvp5150_reg.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers * diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c index 39f66e7a0e42..8be03fe5928c 100644 --- a/drivers/media/i2c/vpx3220.c +++ b/drivers/media/i2c/vpx3220.c @@ -375,7 +375,7 @@ static int vpx3220_s_routing(struct v4l2_subdev *sd, input = 1: COMPOSITE input input = 2: SVHS input */ - const int input_vals[3][2] = { + static const int input_vals[3][2] = { {0x0c, 0}, {0x0d, 0}, {0x0e, 1} diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index e19df5165e78..da8088351135 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -575,6 +575,38 @@ static void media_device_release(struct media_devnode *devnode) dev_dbg(devnode->parent, "Media device released\n"); } +static void __media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + struct media_link *link, *tmp; + struct media_interface *intf; + unsigned int i; + + ida_free(&mdev->entity_internal_idx, entity->internal_idx); + + /* Remove all interface links pointing to this entity */ + list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { + list_for_each_entry_safe(link, tmp, &intf->links, list) { + if (link->entity == entity) + __media_remove_intf_link(link); + } + } + + /* Remove all data links that belong to this entity */ + __media_entity_remove_links(entity); + + /* Remove all pads that belong to this entity */ + for (i = 0; i < entity->num_pads; i++) + media_gobj_destroy(&entity->pads[i].graph_obj); + + /* Remove the entity */ + media_gobj_destroy(&entity->graph_obj); + + /* invoke entity_notify callbacks to handle entity removal?? */ + + entity->graph_obj.mdev = NULL; +} + /** * media_device_register_entity - Register an entity with a media device * @mdev: The media device @@ -632,6 +664,7 @@ int __must_check media_device_register_entity(struct media_device *mdev, */ ret = media_graph_walk_init(&new, mdev); if (ret) { + __media_device_unregister_entity(entity); mutex_unlock(&mdev->graph_mutex); return ret; } @@ -644,38 +677,6 @@ int __must_check media_device_register_entity(struct media_device *mdev, } EXPORT_SYMBOL_GPL(media_device_register_entity); -static void __media_device_unregister_entity(struct media_entity *entity) -{ - struct media_device *mdev = entity->graph_obj.mdev; - struct media_link *link, *tmp; - struct media_interface *intf; - unsigned int i; - - ida_free(&mdev->entity_internal_idx, entity->internal_idx); - - /* Remove all interface links pointing to this entity */ - list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { - list_for_each_entry_safe(link, tmp, &intf->links, list) { - if (link->entity == entity) - __media_remove_intf_link(link); - } - } - - /* Remove all data links that belong to this entity */ - __media_entity_remove_links(entity); - - /* Remove all pads that belong to this entity */ - for (i = 0; i < entity->num_pads; i++) - media_gobj_destroy(&entity->pads[i].graph_obj); - - /* Remove the entity */ - media_gobj_destroy(&entity->graph_obj); - - /* invoke entity_notify callbacks to handle entity removal?? */ - - entity->graph_obj.mdev = NULL; -} - void media_device_unregister_entity(struct media_entity *entity) { struct media_device *mdev = entity->graph_obj.mdev; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 85f3e7307538..fa57e12f2ac8 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -664,7 +664,7 @@ static int _cx18_process_idx_data(struct cx18_buffer *buf, struct cx18_enc_idx_entry *e_buf; /* Frame type lookup: 1=I, 2=P, 4=B */ - const int mapping[8] = { + static const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1 }; diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index e880afe37f15..d59ca3601785 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -1167,8 +1167,11 @@ int cx23888_ir_probe(struct cx23885_dev *dev) return -ENOMEM; spin_lock_init(&state->rx_kfifo_lock); - if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, GFP_KERNEL)) + if (kfifo_alloc(&state->rx_kfifo, CX23888_IR_RX_KFIFO_SIZE, + GFP_KERNEL)) { + kfree(state); return -ENOMEM; + } state->dev = dev; sd = &state->sd; diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 3cd87626cd79..9fa388626bae 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -1781,6 +1781,41 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_NOTONLYTV_LV3H] = { + .name = "NotOnlyTV LV3H", + .tuner_type = TUNER_XC2028, + .radio_type = UNSET, + .tuner_addr = 0x61, + .radio_addr = ADDR_UNSET, + /* if gpio1:bit9 is enabled, DVB-T won't work */ + + .input = { { + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000, + .gpio1 = 0xa141, + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000, + .gpio1 = 0xa161, + .gpio2 = 0x0000, + }, { + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000, + .gpio1 = 0xa161, + .gpio2 = 0x0000, + } }, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x0000, + .gpio1 = 0xa141, + .gpio2 = 0x0000, + }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = { .name = "DViCO FusionHDTV DVB-T PRO", .tuner_type = TUNER_XC2028, @@ -2654,6 +2689,7 @@ static const struct cx88_subid cx88_subids[] = { .subdevice = 0x6f18, .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL, }, { + /* Also NotOnlyTV LV3H (version 1.11 is silkscreened on the board) */ .subvendor = 0x14f1, .subdevice = 0x8852, .card = CX88_BOARD_GENIATECH_X8000_MT, @@ -3121,6 +3157,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO: case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: return cx88_dvico_xc2028_callback(core, command, arg); + case CX88_BOARD_NOTONLYTV_LV3H: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_WINFAST_DTV1800H: return cx88_xc3028_winfast1800h_callback(core, command, arg); @@ -3322,6 +3359,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) udelay(1000); break; + case CX88_BOARD_NOTONLYTV_LV3H: case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_WINFAST_DTV1800H: cx88_xc3028_winfast1800h_callback(core, XC2028_TUNER_RESET, 0); @@ -3378,6 +3416,11 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) */ ctl->disable_power_mgmt = 1; break; + case CX88_BOARD_NOTONLYTV_LV3H: + ctl->demod = XC3028_FE_ZARLINK456; + ctl->fname = XC3028L_DEFAULT_FIRMWARE; + ctl->read_not_reliable = 1; + break; case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: case CX88_BOARD_PROLINK_PV_GLOBAL_XTREME: case CX88_BOARD_PROLINK_PV_8000GT: diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 0292d0947cc7..202ff9e8c257 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1378,6 +1378,7 @@ static int dvb_register(struct cx8802_dev *dev) fe->ops.tuner_ops.set_config(fe, &ctl); } break; + case CX88_BOARD_NOTONLYTV_LV3H: case CX88_BOARD_PINNACLE_HYBRID_PCTV: case CX88_BOARD_WINFAST_DTV1800H: fe0->dvb.frontend = dvb_attach(zl10353_attach, diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index dcc0f02aeb70..b8abcd550604 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1277,7 +1277,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, core = cx88_core_get(dev->pci); if (!core) { err = -EINVAL; - goto fail_free; + goto fail_disable; } dev->core = core; @@ -1323,7 +1323,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, cc->step, cc->default_value); if (!vc) { err = core->audio_hdl.error; - goto fail_core; + goto fail_irq; } vc->priv = (void *)cc; } @@ -1337,7 +1337,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, cc->step, cc->default_value); if (!vc) { err = core->video_hdl.error; - goto fail_core; + goto fail_irq; } vc->priv = (void *)cc; if (vc->id == V4L2_CID_CHROMA_AGC) @@ -1509,11 +1509,14 @@ static int cx8800_initdev(struct pci_dev *pci_dev, fail_unreg: cx8800_unregister_video(dev); - free_irq(pci_dev->irq, dev); mutex_unlock(&core->lock); +fail_irq: + free_irq(pci_dev->irq, dev); fail_core: core->v4ldev = NULL; cx88_core_put(core, dev->pci); +fail_disable: + pci_disable_device(pci_dev); fail_free: kfree(dev); return err; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 744a22328ebc..ce4acf6de6aa 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -228,6 +228,7 @@ extern const struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_WINFAST_DTV1800H_XC4000 88 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F36 89 #define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL_6F43 90 +#define CX88_BOARD_NOTONLYTV_LV3H 91 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index bb3a8cc9de0c..9dce31d2b525 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -11,7 +11,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/proc_fs.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/slab.h> diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c index 6d22c0107d33..80478b026d75 100644 --- a/drivers/media/pci/ivtv/ivtv-vbi.c +++ b/drivers/media/pci/ivtv/ivtv-vbi.c @@ -325,7 +325,7 @@ static u32 compress_raw_buf(struct ivtv *itv, u8 *buf, u32 size) static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 sav) { u32 line_size = itv->vbi.sliced_decoder_line_size; - struct v4l2_decode_vbi_line vbi; + struct v4l2_decode_vbi_line vbi = {}; int i; unsigned lines = 0; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 67aebe759232..c0bd5d7e148b 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -60,10 +60,8 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) struct mantis_ca *ca; mantis = (struct mantis_pci *) dev_id; - if (unlikely(!mantis)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + if (unlikely(!mantis)) return IRQ_NONE; - } ca = mantis->mantis_ca; stat = mmread(MANTIS_INT_STAT); diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index deadd0b92233..906e4500d87d 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -69,10 +69,8 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) struct mantis_ca *ca; mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { - dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); + if (unlikely(!mantis)) return IRQ_NONE; - } ca = mantis->mantis_ca; stat = mmread(MANTIS_INT_STAT); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 9ae04e18e6c6..126d085be9a7 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -13,12 +13,10 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <asm/div64.h> -#ifdef CONFIG_PROC_FS -#include <linux/proc_fs.h> -#endif #include "saa7164.h" MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards"); @@ -1045,92 +1043,138 @@ static void saa7164_dev_unregister(struct saa7164_dev *dev) return; } -#ifdef CONFIG_PROC_FS -static int saa7164_proc_show(struct seq_file *m, void *v) +#ifdef CONFIG_DEBUG_FS +static void *saa7164_seq_start(struct seq_file *s, loff_t *pos) { struct saa7164_dev *dev; - struct tmComResBusInfo *b; - struct list_head *list; - int i, c; + loff_t index = *pos; - if (saa7164_devcount == 0) - return 0; + mutex_lock(&devlist); + list_for_each_entry(dev, &saa7164_devlist, devlist) { + if (index-- == 0) { + mutex_unlock(&devlist); + return dev; + } + } + mutex_unlock(&devlist); - list_for_each(list, &saa7164_devlist) { - dev = list_entry(list, struct saa7164_dev, devlist); - seq_printf(m, "%s = %p\n", dev->name, dev); + return NULL; +} - /* Lock the bus from any other access */ - b = &dev->bus; - mutex_lock(&b->lock); +static void *saa7164_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct saa7164_dev *dev = v; + void *ret; - seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n", - b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); + mutex_lock(&devlist); + if (list_is_last(&dev->devlist, &saa7164_devlist)) + ret = NULL; + else + ret = list_next_entry(dev, devlist); + mutex_unlock(&devlist); - seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n", - b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); + ++*pos; - seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n", - b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); + return ret; +} - seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n", - b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); - c = 0; - seq_printf(m, "\n Set Ring:\n"); - seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - for (i = 0; i < b->m_dwSizeSetRing; i++) { - if (c == 0) - seq_printf(m, " %04x:", i); +static void saa7164_seq_stop(struct seq_file *s, void *v) +{ +} - seq_printf(m, " %02x", readb(b->m_pdwSetRing + i)); +static int saa7164_seq_show(struct seq_file *m, void *v) +{ + struct saa7164_dev *dev = v; + struct tmComResBusInfo *b; + int i, c; - if (++c == 16) { - seq_printf(m, "\n"); - c = 0; - } - } + seq_printf(m, "%s = %p\n", dev->name, dev); - c = 0; - seq_printf(m, "\n Get Ring:\n"); - seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); - for (i = 0; i < b->m_dwSizeGetRing; i++) { - if (c == 0) - seq_printf(m, " %04x:", i); + /* Lock the bus from any other access */ + b = &dev->bus; + mutex_lock(&b->lock); - seq_printf(m, " %02x", readb(b->m_pdwGetRing + i)); + seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n", + b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos)); - if (++c == 16) { - seq_printf(m, "\n"); - c = 0; - } + seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n", + b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos)); + + seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n", + b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos)); + + seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n", + b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos)); + c = 0; + seq_puts(m, "\n Set Ring:\n"); + seq_puts(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); + for (i = 0; i < b->m_dwSizeSetRing; i++) { + if (c == 0) + seq_printf(m, " %04x:", i); + + seq_printf(m, " %02x", readb(b->m_pdwSetRing + i)); + + if (++c == 16) { + seq_puts(m, "\n"); + c = 0; } + } - mutex_unlock(&b->lock); + c = 0; + seq_puts(m, "\n Get Ring:\n"); + seq_puts(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); + for (i = 0; i < b->m_dwSizeGetRing; i++) { + if (c == 0) + seq_printf(m, " %04x:", i); + seq_printf(m, " %02x", readb(b->m_pdwGetRing + i)); + + if (++c == 16) { + seq_puts(m, "\n"); + c = 0; + } } + mutex_unlock(&b->lock); + return 0; } -static struct proc_dir_entry *saa7164_pe; +static const struct seq_operations saa7164_seq_ops = { + .start = saa7164_seq_start, + .next = saa7164_seq_next, + .stop = saa7164_seq_stop, + .show = saa7164_seq_show, +}; -static int saa7164_proc_create(void) +static int saa7164_open(struct inode *inode, struct file *file) { - saa7164_pe = proc_create_single("saa7164", 0444, NULL, saa7164_proc_show); - if (!saa7164_pe) - return -ENOMEM; + return seq_open(file, &saa7164_seq_ops); +} - return 0; +static const struct file_operations saa7164_operations = { + .owner = THIS_MODULE, + .open = saa7164_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static struct dentry *saa7614_dentry; + +static void __init saa7164_debugfs_create(void) +{ + saa7614_dentry = debugfs_create_file("saa7164", 0444, NULL, NULL, + &saa7164_operations); } -static void saa7164_proc_destroy(void) +static void __exit saa7164_debugfs_remove(void) { - if (saa7164_pe) - remove_proc_entry("saa7164", NULL); + debugfs_remove(saa7614_dentry); } #else -static int saa7164_proc_create(void) { return 0; } -static void saa7164_proc_destroy(void) {} +static void saa7164_debugfs_create(void) { } +static void saa7164_debugfs_remove(void) { } #endif static int saa7164_thread_function(void *data) @@ -1507,7 +1551,7 @@ static int __init saa7164_init(void) if (ret) return ret; - saa7164_proc_create(); + saa7164_debugfs_create(); pr_info("saa7164 driver loaded\n"); @@ -1516,7 +1560,7 @@ static int __init saa7164_init(void) static void __exit saa7164_fini(void) { - saa7164_proc_destroy(); + saa7164_debugfs_remove(); pci_unregister_driver(&saa7164_pci_driver); } diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 65bc7e29450b..2b5e0154814c 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -14,7 +14,6 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/proc_fs.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/slab.h> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f1f61419fd29..e84f35d3a68e 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -483,6 +483,7 @@ config VIDEO_QCOM_VENUS tristate "Qualcomm Venus V4L2 encoder/decoder driver" depends on VIDEO_DEV && VIDEO_V4L2 depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST + depends on INTERCONNECT || !INTERCONNECT select QCOM_MDT_LOADER if ARCH_QCOM select QCOM_SCM if ARCH_QCOM select VIDEOBUF2_DMA_SG @@ -493,6 +494,19 @@ config VIDEO_QCOM_VENUS on various Qualcomm SoCs. To compile this driver as a module choose m here. +config VIDEO_SUN8I_DEINTERLACE + tristate "Allwinner Deinterlace driver" + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_SUNXI || COMPILE_TEST + depends on COMMON_CLK && OF + depends on PM + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + Support for the Allwinner deinterlace unit with scaling + capability found on some SoCs, like H3. + To compile this driver as a module choose m here. + endif # V4L_MEM2MEM_DRIVERS # TI VIDEO PORT Helper Modules @@ -585,9 +599,10 @@ config VIDEO_MESON_G12A_AO_CEC config CEC_GPIO tristate "Generic GPIO-based CEC driver" - depends on PREEMPT || COMPILE_TEST + depends on PREEMPTION || COMPILE_TEST select CEC_CORE select CEC_PIN + select CEC_NOTIFIER select GPIOLIB help This is a generic GPIO-based CEC driver. diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 6ee7eb0d36f4..d13db96e3015 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -19,9 +19,7 @@ obj-$(CONFIG_VIDEO_VIVID) += vivid/ obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o obj-$(CONFIG_VIDEO_VICODEC) += vicodec/ -obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/ - -obj-$(CONFIG_VIDEO_TI_CAL) += ti-vpe/ +obj-y += ti-vpe/ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o obj-$(CONFIG_VIDEO_CODA) += coda/ diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 2b42ba1f5949..09104304bd06 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI VPFE capture Driver * @@ -5,19 +6,6 @@ * * Benoit Parrot <bparrot@ti.com> * Lad, Prabhakar <prabhakar.csengg@gmail.com> - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/delay.h> @@ -69,125 +57,64 @@ static const struct vpfe_standard vpfe_standards[] = { {V4L2_STD_625_50, 720, 576, {54, 59}, 1}, }; -struct bus_format { - unsigned int width; - unsigned int bpp; -}; - -/* - * struct vpfe_fmt - VPFE media bus format information - * @code: V4L2 media bus format code - * @shifted: V4L2 media bus format code for the same pixel layout but - * shifted to be 8 bits per pixel. =0 if format is not shiftable. - * @pixelformat: V4L2 pixel format FCC identifier - * @width: Bits per pixel (when transferred over a bus) - * @bpp: Bytes per pixel (when stored in memory) - * @supported: Indicates format supported by subdev - */ -struct vpfe_fmt { - u32 fourcc; - u32 code; - struct bus_format l; - struct bus_format s; - bool supported; - u32 index; -}; - -static struct vpfe_fmt formats[] = { +static struct vpfe_fmt formats[VPFE_NUM_FORMATS] = { { .fourcc = V4L2_PIX_FMT_YUYV, .code = MEDIA_BUS_FMT_YUYV8_2X8, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, { .fourcc = V4L2_PIX_FMT_UYVY, .code = MEDIA_BUS_FMT_UYVY8_2X8, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, { .fourcc = V4L2_PIX_FMT_YVYU, .code = MEDIA_BUS_FMT_YVYU8_2X8, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, { .fourcc = V4L2_PIX_FMT_VYUY, .code = MEDIA_BUS_FMT_VYUY8_2X8, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, { .fourcc = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .l.width = 10, - .l.bpp = 2, - .s.width = 8, - .s.bpp = 1, - .supported = false, + .bitsperpixel = 8, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .l.width = 10, - .l.bpp = 2, - .s.width = 8, - .s.bpp = 1, - .supported = false, + .bitsperpixel = 8, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .l.width = 10, - .l.bpp = 2, - .s.width = 8, - .s.bpp = 1, - .supported = false, + .bitsperpixel = 8, }, { .fourcc = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .l.width = 10, - .l.bpp = 2, - .s.width = 8, - .s.bpp = 1, - .supported = false, + .bitsperpixel = 8, }, { .fourcc = V4L2_PIX_FMT_RGB565, .code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, { .fourcc = V4L2_PIX_FMT_RGB565X, .code = MEDIA_BUS_FMT_RGB565_2X8_BE, - .l.width = 10, - .l.bpp = 4, - .s.width = 8, - .s.bpp = 2, - .supported = false, + .bitsperpixel = 16, }, }; -static int -__vpfe_get_format(struct vpfe_device *vpfe, - struct v4l2_format *format, unsigned int *bpp); +static int __subdev_get_format(struct vpfe_device *vpfe, + struct v4l2_mbus_framefmt *fmt); +static int vpfe_calc_format_size(struct vpfe_device *vpfe, + const struct vpfe_fmt *fmt, + struct v4l2_format *f); -static struct vpfe_fmt *find_format_by_code(unsigned int code) +static struct vpfe_fmt *find_format_by_code(struct vpfe_device *vpfe, + unsigned int code) { struct vpfe_fmt *fmt; unsigned int k; - for (k = 0; k < ARRAY_SIZE(formats); k++) { - fmt = &formats[k]; + for (k = 0; k < vpfe->num_active_fmt; k++) { + fmt = vpfe->active_fmt[k]; if (fmt->code == code) return fmt; } @@ -195,13 +122,14 @@ static struct vpfe_fmt *find_format_by_code(unsigned int code) return NULL; } -static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) +static struct vpfe_fmt *find_format_by_pix(struct vpfe_device *vpfe, + unsigned int pixelformat) { struct vpfe_fmt *fmt; unsigned int k; - for (k = 0; k < ARRAY_SIZE(formats); k++) { - fmt = &formats[k]; + for (k = 0; k < vpfe->num_active_fmt; k++) { + fmt = vpfe->active_fmt[k]; if (fmt->fourcc == pixelformat) return fmt; } @@ -209,48 +137,18 @@ static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat) return NULL; } -static void -mbus_to_pix(struct vpfe_device *vpfe, - const struct v4l2_mbus_framefmt *mbus, - struct v4l2_pix_format *pix, unsigned int *bpp) +static unsigned int __get_bytesperpixel(struct vpfe_device *vpfe, + const struct vpfe_fmt *fmt) { struct vpfe_subdev_info *sdinfo = vpfe->current_subdev; unsigned int bus_width = sdinfo->vpfe_param.bus_width; - struct vpfe_fmt *fmt; - - fmt = find_format_by_code(mbus->code); - if (WARN_ON(fmt == NULL)) { - pr_err("Invalid mbus code set\n"); - *bpp = 1; - return; - } - - memset(pix, 0, sizeof(*pix)); - v4l2_fill_pix_format(pix, mbus); - pix->pixelformat = fmt->fourcc; - *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp; + u32 bpp, bus_width_bytes, clocksperpixel; - /* pitch should be 32 bytes aligned */ - pix->bytesperline = ALIGN(pix->width * *bpp, 32); - pix->sizeimage = pix->bytesperline * pix->height; -} - -static void pix_to_mbus(struct vpfe_device *vpfe, - struct v4l2_pix_format *pix_fmt, - struct v4l2_mbus_framefmt *mbus_fmt) -{ - struct vpfe_fmt *fmt; - - fmt = find_format_by_pix(pix_fmt->pixelformat); - if (!fmt) { - /* default to first entry */ - vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", - pix_fmt->pixelformat); - fmt = &formats[0]; - } + bus_width_bytes = ALIGN(bus_width, 8) >> 3; + clocksperpixel = DIV_ROUND_UP(fmt->bitsperpixel, bus_width); + bpp = clocksperpixel * bus_width_bytes; - memset(mbus_fmt, 0, sizeof(*mbus_fmt)); - v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code); + return bpp; } /* Print Four-character-code (FOURCC) */ @@ -267,20 +165,6 @@ static char *print_fourcc(u32 fmt) return code; } -static int -cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs) -{ - return lhs->type == rhs->type && - lhs->fmt.pix.width == rhs->fmt.pix.width && - lhs->fmt.pix.height == rhs->fmt.pix.height && - lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat && - lhs->fmt.pix.field == rhs->fmt.pix.field && - lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace && - lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc && - lhs->fmt.pix.quantization == rhs->fmt.pix.quantization && - lhs->fmt.pix.xfer_func == rhs->fmt.pix.xfer_func; -} - static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset) { return ioread32(ccdc->ccdc_cfg.base_addr + offset); @@ -345,13 +229,9 @@ static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc, if (frm_fmt == CCDC_FRMFMT_INTERLACED) { vert_nr_lines = (image_win->height >> 1) - 1; vert_start >>= 1; - /* Since first line doesn't have any data */ - vert_start += 1; /* configure VDINT0 */ val = (vert_start << VPFE_VDINT_VDINT0_SHIFT); } else { - /* Since first line doesn't have any data */ - vert_start += 1; vert_nr_lines = image_win->height - 1; /* * configure VDINT0 and VDINT1. VDINT1 will be at half @@ -405,7 +285,6 @@ vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc, max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 || - ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 || max_gamma > max_data) { vpfe_dbg(1, vpfe, "Invalid data line select\n"); return -EINVAL; @@ -445,40 +324,25 @@ static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc) static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev) { - int dma_cntl, i, pcr; + struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); + u32 dma_cntl, pcr; - /* If the CCDC module is still busy wait for it to be done */ - for (i = 0; i < 10; i++) { - usleep_range(5000, 6000); - pcr = vpfe_reg_read(ccdc, VPFE_PCR); - if (!pcr) - break; + pcr = vpfe_reg_read(ccdc, VPFE_PCR); + if (pcr) + vpfe_dbg(1, vpfe, "VPFE_PCR is still set (%x)", pcr); - /* make sure it it is disabled */ - vpfe_pcr_enable(ccdc, 0); - } + dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); + if ((dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) + vpfe_dbg(1, vpfe, "VPFE_DMA_CNTL_OVERFLOW is still set (%x)", + dma_cntl); /* Disable CCDC by resetting all register to default POR values */ vpfe_ccdc_restore_defaults(ccdc); - /* if DMA_CNTL overflow bit is set. Clear it - * It appears to take a while for this to become quiescent ~20ms - */ - for (i = 0; i < 10; i++) { - dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL); - if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW)) - break; - - /* Clear the overflow bit */ - vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL); - usleep_range(5000, 6000); - } - /* Disabled the module at the CONFIG level */ vpfe_config_enable(ccdc, 0); pm_runtime_put_sync(dev); - return 0; } @@ -494,8 +358,8 @@ static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) x = copy_from_user(&raw_params, params, sizeof(raw_params)); if (x) { vpfe_dbg(1, vpfe, - "vpfe_ccdc_set_params: error in copying ccdc params, %d\n", - x); + "%s: error in copying ccdc params, %d\n", + __func__, x); return -EFAULT; } @@ -513,11 +377,9 @@ static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params) */ static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc) { - struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr; u32 syn_mode; - vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n"); /* * first restore the CCDC registers to default values * This is important since we assume default values to be set in @@ -649,8 +511,6 @@ static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc) unsigned int syn_mode; unsigned int val; - vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n"); - /* Reset CCDC */ vpfe_ccdc_restore_defaults(ccdc); @@ -751,8 +611,8 @@ static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt) { struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc); - vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n", - ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); + vpfe_dbg(1, vpfe, "%s: if_type: %d, pixfmt:%s\n", + __func__, ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt)); if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) { ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW; @@ -1036,10 +896,9 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe, static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) { enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED; + u32 bpp; int ret = 0; - vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n"); - vpfe_dbg(1, vpfe, "pixelformat: %s\n", print_fourcc(vpfe->fmt.fmt.pix.pixelformat)); @@ -1050,7 +909,8 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) } /* configure the image window */ - vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp); + bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt); + vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, bpp); switch (vpfe->fmt.fmt.pix.field) { case V4L2_FIELD_INTERLACED: @@ -1094,7 +954,8 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) static int vpfe_config_image_format(struct vpfe_device *vpfe, v4l2_std_id std_id) { - struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix; + struct vpfe_fmt *fmt; + struct v4l2_mbus_framefmt mbus_fmt; int i, ret; for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { @@ -1116,26 +977,29 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe, return -EINVAL; } - vpfe->crop.top = vpfe->crop.left = 0; - vpfe->crop.width = vpfe->std_info.active_pixels; - vpfe->crop.height = vpfe->std_info.active_lines; - pix->width = vpfe->crop.width; - pix->height = vpfe->crop.height; - pix->pixelformat = V4L2_PIX_FMT_YUYV; - - /* first field and frame format based on standard frame format */ - if (vpfe->std_info.frame_format) - pix->field = V4L2_FIELD_INTERLACED; - else - pix->field = V4L2_FIELD_NONE; - - ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp); + ret = __subdev_get_format(vpfe, &mbus_fmt); if (ret) return ret; + fmt = find_format_by_code(vpfe, mbus_fmt.code); + if (!fmt) { + vpfe_dbg(3, vpfe, "mbus code format (0x%08x) not found.\n", + mbus_fmt.code); + return -EINVAL; + } + + /* Save current subdev format */ + v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt); + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vpfe->fmt.fmt.pix.pixelformat = fmt->fourcc; + vpfe_calc_format_size(vpfe, fmt, &vpfe->fmt); + vpfe->current_vpfe_fmt = fmt; + /* Update the crop window based on found values */ - vpfe->crop.width = pix->width; - vpfe->crop.height = pix->height; + vpfe->crop.top = 0; + vpfe->crop.left = 0; + vpfe->crop.width = mbus_fmt.width; + vpfe->crop.height = mbus_fmt.height; return vpfe_config_ccdc_image_format(vpfe); } @@ -1237,22 +1101,29 @@ unlock: * This function will get next buffer from the dma queue and * set the buffer address in the vpfe register for capture. * the buffer is marked active - * - * Assumes caller is holding vpfe->dma_queue_lock already */ -static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) +static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe) { + dma_addr_t addr; + + spin_lock(&vpfe->dma_queue_lock); + if (list_empty(&vpfe->dma_queue)) { + spin_unlock(&vpfe->dma_queue_lock); + return; + } + vpfe->next_frm = list_entry(vpfe->dma_queue.next, struct vpfe_cap_buffer, list); list_del(&vpfe->next_frm->list); + spin_unlock(&vpfe->dma_queue_lock); - vpfe_set_sdr_addr(&vpfe->ccdc, - vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0)); + addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0); + vpfe_set_sdr_addr(&vpfe->ccdc, addr); } static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe) { - unsigned long addr; + dma_addr_t addr; addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0) + vpfe->field_off; @@ -1277,6 +1148,58 @@ static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) vpfe->cur_frm = vpfe->next_frm; } +static void vpfe_handle_interlaced_irq(struct vpfe_device *vpfe, + enum v4l2_field field) +{ + int fid; + + /* interlaced or TB capture check which field + * we are in hardware + */ + fid = vpfe_ccdc_getfid(&vpfe->ccdc); + + /* switch the software maintained field id */ + vpfe->field ^= 1; + if (fid == vpfe->field) { + /* we are in-sync here,continue */ + if (fid == 0) { + /* + * One frame is just being captured. If the + * next frame is available, release the + * current frame and move on + */ + if (vpfe->cur_frm != vpfe->next_frm) + vpfe_process_buffer_complete(vpfe); + + if (vpfe->stopping) + return; + + /* + * based on whether the two fields are stored + * interleave or separately in memory, + * reconfigure the CCDC memory address + */ + if (field == V4L2_FIELD_SEQ_TB) + vpfe_schedule_bottom_field(vpfe); + } else { + /* + * if one field is just being captured configure + * the next frame get the next frame from the empty + * queue if no frame is available hold on to the + * current buffer + */ + if (vpfe->cur_frm == vpfe->next_frm) + vpfe_schedule_next_buffer(vpfe); + } + } else if (fid == 0) { + /* + * out of sync. Recover from any hardware out-of-sync. + * May loose one frame + */ + vpfe->field = fid; + } +} + /* * vpfe_isr : ISR handler for vpfe capture (VINT0) * @irq: irq number @@ -1288,76 +1211,28 @@ static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe) static irqreturn_t vpfe_isr(int irq, void *dev) { struct vpfe_device *vpfe = (struct vpfe_device *)dev; - enum v4l2_field field; - int intr_status; - int fid; + enum v4l2_field field = vpfe->fmt.fmt.pix.field; + int intr_status, stopping = vpfe->stopping; intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS); if (intr_status & VPFE_VDINT0) { - field = vpfe->fmt.fmt.pix.field; - if (field == V4L2_FIELD_NONE) { - /* handle progressive frame capture */ if (vpfe->cur_frm != vpfe->next_frm) vpfe_process_buffer_complete(vpfe); - goto next_intr; + } else { + vpfe_handle_interlaced_irq(vpfe, field); } - - /* interlaced or TB capture check which field - we are in hardware */ - fid = vpfe_ccdc_getfid(&vpfe->ccdc); - - /* switch the software maintained field id */ - vpfe->field ^= 1; - if (fid == vpfe->field) { - /* we are in-sync here,continue */ - if (fid == 0) { - /* - * One frame is just being captured. If the - * next frame is available, release the - * current frame and move on - */ - if (vpfe->cur_frm != vpfe->next_frm) - vpfe_process_buffer_complete(vpfe); - /* - * based on whether the two fields are stored - * interleave or separately in memory, - * reconfigure the CCDC memory address - */ - if (field == V4L2_FIELD_SEQ_TB) - vpfe_schedule_bottom_field(vpfe); - - goto next_intr; - } - /* - * if one field is just being captured configure - * the next frame get the next frame from the empty - * queue if no frame is available hold on to the - * current buffer - */ - spin_lock(&vpfe->dma_queue_lock); - if (!list_empty(&vpfe->dma_queue) && - vpfe->cur_frm == vpfe->next_frm) - vpfe_schedule_next_buffer(vpfe); - spin_unlock(&vpfe->dma_queue_lock); - } else if (fid == 0) { - /* - * out of sync. Recover from any hardware out-of-sync. - * May loose one frame - */ - vpfe->field = fid; + if (stopping) { + vpfe->stopping = false; + complete(&vpfe->capture_stop); } } -next_intr: - if (intr_status & VPFE_VDINT1) { - spin_lock(&vpfe->dma_queue_lock); - if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE && - !list_empty(&vpfe->dma_queue) && + if (intr_status & VPFE_VDINT1 && !stopping) { + if (field == V4L2_FIELD_NONE && vpfe->cur_frm == vpfe->next_frm) vpfe_schedule_next_buffer(vpfe); - spin_unlock(&vpfe->dma_queue_lock); } vpfe_clear_intr(&vpfe->ccdc, intr_status); @@ -1394,8 +1269,6 @@ static int vpfe_querycap(struct file *file, void *priv, { struct vpfe_device *vpfe = video_drvdata(file); - vpfe_dbg(2, vpfe, "vpfe_querycap\n"); - strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), @@ -1404,83 +1277,74 @@ static int vpfe_querycap(struct file *file, void *priv, } /* get the format set at output pad of the adjacent subdev */ -static int __vpfe_get_format(struct vpfe_device *vpfe, - struct v4l2_format *format, unsigned int *bpp) +static int __subdev_get_format(struct vpfe_device *vpfe, + struct v4l2_mbus_framefmt *fmt) { - struct v4l2_mbus_framefmt mbus_fmt; - struct vpfe_subdev_info *sdinfo; - struct v4l2_subdev_format fmt; + struct v4l2_subdev *sd = vpfe->current_subdev->sd; + struct v4l2_subdev_format sd_fmt; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; int ret; - sdinfo = vpfe->current_subdev; - if (!sdinfo->sd) - return -EINVAL; - - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.pad = 0; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; - ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); + if (ret) return ret; - if (!ret) { - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); - } else { - ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, - sdinfo->grp_id, - pad, get_fmt, - NULL, &fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); - mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); - } - - format->type = vpfe->fmt.type; + *fmt = *mbus_fmt; - vpfe_dbg(1, vpfe, - "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", - __func__, format->fmt.pix.width, format->fmt.pix.height, - print_fourcc(format->fmt.pix.pixelformat), - format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + vpfe_dbg(1, vpfe, "%s: %dx%d code:%04X\n", __func__, + fmt->width, fmt->height, fmt->code); return 0; } /* set the format at output pad of the adjacent subdev */ -static int __vpfe_set_format(struct vpfe_device *vpfe, - struct v4l2_format *format, unsigned int *bpp) +static int __subdev_set_format(struct vpfe_device *vpfe, + struct v4l2_mbus_framefmt *fmt) { - struct vpfe_subdev_info *sdinfo; - struct v4l2_subdev_format fmt; + struct v4l2_subdev *sd = vpfe->current_subdev->sd; + struct v4l2_subdev_format sd_fmt; + struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format; int ret; - vpfe_dbg(2, vpfe, "__vpfe_set_format\n"); + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = 0; + *mbus_fmt = *fmt; - sdinfo = vpfe->current_subdev; - if (!sdinfo->sd) - return -EINVAL; + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt); + if (ret) + return ret; - fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt.pad = 0; + vpfe_dbg(1, vpfe, "%s %dx%d code:%04X\n", __func__, + fmt->width, fmt->height, fmt->code); - pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); + return 0; +} - ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); - if (ret) - return ret; +static int vpfe_calc_format_size(struct vpfe_device *vpfe, + const struct vpfe_fmt *fmt, + struct v4l2_format *f) +{ + u32 bpp; + + if (!fmt) { + vpfe_dbg(3, vpfe, "No vpfe_fmt provided!\n"); + return -EINVAL; + } - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); + bpp = __get_bytesperpixel(vpfe, fmt); - format->type = vpfe->fmt.type; + /* pitch should be 32 bytes aligned */ + f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width * bpp, 32); + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * + f->fmt.pix.height; - vpfe_dbg(1, vpfe, - "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n", - __func__, format->fmt.pix.width, format->fmt.pix.height, - print_fourcc(format->fmt.pix.pixelformat), - format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp); + vpfe_dbg(3, vpfe, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n", + __func__, print_fourcc(f->fmt.pix.pixelformat), + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); return 0; } @@ -1490,8 +1354,6 @@ static int vpfe_g_fmt(struct file *file, void *priv, { struct vpfe_device *vpfe = video_drvdata(file); - vpfe_dbg(2, vpfe, "vpfe_g_fmt\n"); - *fmt = vpfe->fmt; return 0; @@ -1502,82 +1364,124 @@ static int vpfe_enum_fmt(struct file *file, void *priv, { struct vpfe_device *vpfe = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - struct vpfe_fmt *fmt = NULL; - unsigned int k; - - vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n", - f->index); + struct vpfe_fmt *fmt; sdinfo = vpfe->current_subdev; if (!sdinfo->sd) return -EINVAL; - if (f->index > ARRAY_SIZE(formats)) + if (f->index >= vpfe->num_active_fmt) return -EINVAL; - for (k = 0; k < ARRAY_SIZE(formats); k++) { - if (formats[k].index == f->index) { - fmt = &formats[k]; - break; - } - } - if (!fmt) - return -EINVAL; + fmt = vpfe->active_fmt[f->index]; f->pixelformat = fmt->fourcc; - vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s\n", - f->index, fmt->code, print_fourcc(fmt->fourcc)); + vpfe_dbg(1, vpfe, "%s: mbus index: %d code: %x pixelformat: %s\n", + __func__, f->index, fmt->code, print_fourcc(fmt->fourcc)); return 0; } static int vpfe_try_fmt(struct file *file, void *priv, - struct v4l2_format *fmt) + struct v4l2_format *f) { struct vpfe_device *vpfe = video_drvdata(file); - unsigned int bpp; + struct v4l2_subdev *sd = vpfe->current_subdev->sd; + const struct vpfe_fmt *fmt; + struct v4l2_subdev_frame_size_enum fse; + int ret, found; + + fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat); + if (!fmt) { + /* default to first entry */ + vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", + f->fmt.pix.pixelformat); + fmt = vpfe->active_fmt[0]; + f->fmt.pix.pixelformat = fmt->fourcc; + } + + f->fmt.pix.field = vpfe->fmt.fmt.pix.field; + + /* check for/find a valid width/height */ + ret = 0; + found = false; + fse.pad = 0; + fse.code = fmt->code; + fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; + for (fse.index = 0; ; fse.index++) { + ret = v4l2_subdev_call(sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + break; + + if (f->fmt.pix.width == fse.max_width && + f->fmt.pix.height == fse.max_height) { + found = true; + break; + } else if (f->fmt.pix.width >= fse.min_width && + f->fmt.pix.width <= fse.max_width && + f->fmt.pix.height >= fse.min_height && + f->fmt.pix.height <= fse.max_height) { + found = true; + break; + } + } - vpfe_dbg(2, vpfe, "vpfe_try_fmt\n"); + if (!found) { + /* use existing values as default */ + f->fmt.pix.width = vpfe->fmt.fmt.pix.width; + f->fmt.pix.height = vpfe->fmt.fmt.pix.height; + } - return __vpfe_get_format(vpfe, fmt, &bpp); + /* + * Use current colorspace for now, it will get + * updated properly during s_fmt + */ + f->fmt.pix.colorspace = vpfe->fmt.fmt.pix.colorspace; + return vpfe_calc_format_size(vpfe, fmt, f); } static int vpfe_s_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { struct vpfe_device *vpfe = video_drvdata(file); - struct v4l2_format format; - unsigned int bpp; + struct vpfe_fmt *f; + struct v4l2_mbus_framefmt mbus_fmt; int ret; - vpfe_dbg(2, vpfe, "vpfe_s_fmt\n"); - /* If streaming is started, return error */ if (vb2_is_busy(&vpfe->buffer_queue)) { vpfe_err(vpfe, "%s device busy\n", __func__); return -EBUSY; } - ret = __vpfe_get_format(vpfe, &format, &bpp); - if (ret) + ret = vpfe_try_fmt(file, priv, fmt); + if (ret < 0) return ret; + f = find_format_by_pix(vpfe, fmt->fmt.pix.pixelformat); - if (!cmp_v4l2_format(fmt, &format)) { - /* Sensor format is different from the requested format - * so we need to change it - */ - ret = __vpfe_set_format(vpfe, fmt, &bpp); - if (ret) - return ret; - } else /* Just make sure all of the fields are consistent */ - *fmt = format; + v4l2_fill_mbus_format(&mbus_fmt, &fmt->fmt.pix, f->code); - /* First detach any IRQ if currently attached */ - vpfe_detach_irq(vpfe); - vpfe->fmt = *fmt; - vpfe->bpp = bpp; + ret = __subdev_set_format(vpfe, &mbus_fmt); + if (ret) + return ret; + + /* Just double check nothing has gone wrong */ + if (mbus_fmt.code != f->code) { + vpfe_dbg(3, vpfe, + "%s subdev changed format on us, this should not happen\n", + __func__); + return -EINVAL; + } + + v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt); + vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vpfe->fmt.fmt.pix.pixelformat = f->fourcc; + vpfe_calc_format_size(vpfe, f, &vpfe->fmt); + *fmt = vpfe->fmt; + vpfe->current_vpfe_fmt = f; /* Update the crop window based on found values */ vpfe->crop.width = fmt->fmt.pix.width; @@ -1592,57 +1496,40 @@ static int vpfe_enum_size(struct file *file, void *priv, { struct vpfe_device *vpfe = video_drvdata(file); struct v4l2_subdev_frame_size_enum fse; - struct vpfe_subdev_info *sdinfo; - struct v4l2_mbus_framefmt mbus; - struct v4l2_pix_format pix; + struct v4l2_subdev *sd = vpfe->current_subdev->sd; struct vpfe_fmt *fmt; int ret; - vpfe_dbg(2, vpfe, "vpfe_enum_size\n"); - /* check for valid format */ - fmt = find_format_by_pix(fsize->pixel_format); + fmt = find_format_by_pix(vpfe, fsize->pixel_format); if (!fmt) { - vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n", - fsize->pixel_format); + vpfe_dbg(3, vpfe, "Invalid pixel code: %x\n", + fsize->pixel_format); return -EINVAL; } memset(fsize->reserved, 0x0, sizeof(fsize->reserved)); - sdinfo = vpfe->current_subdev; - if (!sdinfo->sd) - return -EINVAL; - - memset(&pix, 0x0, sizeof(pix)); - /* Construct pix from parameter and use default for the rest */ - pix.pixelformat = fsize->pixel_format; - pix.width = 640; - pix.height = 480; - pix.colorspace = V4L2_COLORSPACE_SRGB; - pix.field = V4L2_FIELD_NONE; - pix_to_mbus(vpfe, &pix, &mbus); - memset(&fse, 0x0, sizeof(fse)); fse.index = fsize->index; fse.pad = 0; - fse.code = mbus.code; + fse.code = fmt->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse); + ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse); if (ret) - return -EINVAL; + return ret; - vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", - fse.index, fse.code, fse.min_width, fse.max_width, - fse.min_height, fse.max_height); + vpfe_dbg(1, vpfe, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n", + __func__, fse.index, fse.code, fse.min_width, fse.max_width, + fse.min_height, fse.max_height); fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = fse.max_width; fsize->discrete.height = fse.max_height; - vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n", - fsize->index, print_fourcc(fsize->pixel_format), - fsize->discrete.width, fsize->discrete.height); + vpfe_dbg(1, vpfe, "%s: index: %d pixformat: %s size: %dx%d\n", + __func__, fsize->index, print_fourcc(fsize->pixel_format), + fsize->discrete.width, fsize->discrete.height); return 0; } @@ -1707,8 +1594,6 @@ static int vpfe_enum_input(struct file *file, void *priv, struct vpfe_subdev_info *sdinfo; int subdev, index; - vpfe_dbg(2, vpfe, "vpfe_enum_input\n"); - if (vpfe_get_subdev_input_index(vpfe, &subdev, &index, inp->index) < 0) { vpfe_dbg(1, vpfe, @@ -1725,8 +1610,6 @@ static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) { struct vpfe_device *vpfe = video_drvdata(file); - vpfe_dbg(2, vpfe, "vpfe_g_input\n"); - return vpfe_get_app_input_index(vpfe, index); } @@ -1739,8 +1622,6 @@ static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index) u32 input, output; int ret; - vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index); - /* If streaming is started, return error */ if (vb2_is_busy(&vpfe->buffer_queue)) { vpfe_err(vpfe, "%s device busy\n", __func__); @@ -1796,9 +1677,6 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) { struct vpfe_device *vpfe = video_drvdata(file); - vpfe_dbg(2, vpfe, - "vpfe_s_input: index: %d\n", index); - return vpfe_set_input(vpfe, index); } @@ -1807,8 +1685,6 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) struct vpfe_device *vpfe = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - vpfe_dbg(2, vpfe, "vpfe_querystd\n"); - sdinfo = vpfe->current_subdev; if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) return -ENODATA; @@ -1824,12 +1700,14 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) struct vpfe_subdev_info *sdinfo; int ret; - vpfe_dbg(2, vpfe, "vpfe_s_std\n"); - sdinfo = vpfe->current_subdev; if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD)) return -ENODATA; + /* if trying to set the same std then nothing to do */ + if (vpfe_standards[vpfe->std_index].std_id == std_id) + return 0; + /* If streaming is started, return error */ if (vb2_is_busy(&vpfe->buffer_queue)) { vpfe_err(vpfe, "%s device busy\n", __func__); @@ -1853,8 +1731,6 @@ static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id) struct vpfe_device *vpfe = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - vpfe_dbg(2, vpfe, "vpfe_g_std\n"); - sdinfo = vpfe->current_subdev; if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD) return -ENODATA; @@ -1872,8 +1748,6 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe) { struct v4l2_rect image_win; - vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n"); - vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win); vpfe->field_off = image_win.height * image_win.width; } @@ -1957,6 +1831,29 @@ static void vpfe_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); } +static void vpfe_return_all_buffers(struct vpfe_device *vpfe, + enum vb2_buffer_state state) +{ + struct vpfe_cap_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&vpfe->dma_queue_lock, flags); + list_for_each_entry_safe(buf, node, &vpfe->dma_queue, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } + + if (vpfe->cur_frm) + vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, state); + + if (vpfe->next_frm && vpfe->next_frm != vpfe->cur_frm) + vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, state); + + vpfe->cur_frm = NULL; + vpfe->next_frm = NULL; + spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); +} + /* * vpfe_start_streaming : Starts the DMA engine for streaming * @vb: ptr to vb2_buffer @@ -1965,7 +1862,6 @@ static void vpfe_buffer_queue(struct vb2_buffer *vb) static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) { struct vpfe_device *vpfe = vb2_get_drv_priv(vq); - struct vpfe_cap_buffer *buf, *tmp; struct vpfe_subdev_info *sdinfo; unsigned long flags; unsigned long addr; @@ -1980,6 +1876,9 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) vpfe_attach_irq(vpfe); + vpfe->stopping = false; + init_completion(&vpfe->capture_stop); + if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER) vpfe_ccdc_config_raw(&vpfe->ccdc); else @@ -2008,11 +1907,8 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; err: - list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); - } - + vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_QUEUED); + vpfe_pcr_enable(&vpfe->ccdc, 0); return ret; } @@ -2027,11 +1923,15 @@ static void vpfe_stop_streaming(struct vb2_queue *vq) { struct vpfe_device *vpfe = vb2_get_drv_priv(vq); struct vpfe_subdev_info *sdinfo; - unsigned long flags; int ret; vpfe_pcr_enable(&vpfe->ccdc, 0); + /* Wait for the last frame to be captured */ + vpfe->stopping = true; + wait_for_completion_timeout(&vpfe->capture_stop, + msecs_to_jiffies(250)); + vpfe_detach_irq(vpfe); sdinfo = vpfe->current_subdev; @@ -2040,27 +1940,7 @@ static void vpfe_stop_streaming(struct vb2_queue *vq) vpfe_dbg(1, vpfe, "stream off failed in subdev\n"); /* release all active buffers */ - spin_lock_irqsave(&vpfe->dma_queue_lock, flags); - if (vpfe->cur_frm == vpfe->next_frm) { - vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } else { - if (vpfe->cur_frm != NULL) - vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - if (vpfe->next_frm != NULL) - vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - - while (!list_empty(&vpfe->dma_queue)) { - vpfe->next_frm = list_entry(vpfe->dma_queue.next, - struct vpfe_cap_buffer, list); - list_del(&vpfe->next_frm->list); - vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } - spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags); + vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_ERROR); } static int vpfe_g_pixelaspect(struct file *file, void *priv, @@ -2068,8 +1948,6 @@ static int vpfe_g_pixelaspect(struct file *file, void *priv, { struct vpfe_device *vpfe = video_drvdata(file); - vpfe_dbg(2, vpfe, "vpfe_g_pixelaspect\n"); - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || vpfe->std_index >= ARRAY_SIZE(vpfe_standards)) return -EINVAL; @@ -2128,6 +2006,7 @@ vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) struct vpfe_device *vpfe = video_drvdata(file); struct v4l2_rect cr = vpfe->crop; struct v4l2_rect r = s->r; + u32 bpp; /* If streaming is started, return error */ if (vb2_is_busy(&vpfe->buffer_queue)) { @@ -2153,10 +2032,12 @@ vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) s->r = vpfe->crop = r; - vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp); + bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt); + vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, bpp); vpfe->fmt.fmt.pix.width = r.width; vpfe->fmt.fmt.pix.height = r.height; - vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc); + vpfe->fmt.fmt.pix.bytesperline = + vpfe_ccdc_get_line_length(&vpfe->ccdc); vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline * vpfe->fmt.fmt.pix.height; @@ -2172,8 +2053,6 @@ static long vpfe_ioctl_default(struct file *file, void *priv, struct vpfe_device *vpfe = video_drvdata(file); int ret; - vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n"); - if (!valid_prio) { vpfe_err(vpfe, "%s device busy\n", __func__); return -EBUSY; @@ -2279,10 +2158,10 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, struct vpfe_device, v4l2_dev); struct v4l2_subdev_mbus_code_enum mbus_code; struct vpfe_subdev_info *sdinfo; + struct vpfe_fmt *fmt; + int ret = 0; bool found = false; - int i, j; - - vpfe_dbg(1, vpfe, "vpfe_async_bound\n"); + int i, j, k; for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) { if (vpfe->cfg->asd[i]->match.fwnode == @@ -2302,27 +2181,37 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier, vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std; - /* setup the supported formats & indexes */ - for (j = 0, i = 0; ; ++j) { - struct vpfe_fmt *fmt; - int ret; - + vpfe->num_active_fmt = 0; + for (j = 0, i = 0; (ret != -EINVAL); ++j) { memset(&mbus_code, 0, sizeof(mbus_code)); mbus_code.index = j; mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, - NULL, &mbus_code); + NULL, &mbus_code); if (ret) - break; - - fmt = find_format_by_code(mbus_code.code); - if (!fmt) continue; - fmt->supported = true; - fmt->index = i++; + vpfe_dbg(3, vpfe, + "subdev %s: code: %04x idx: %d\n", + subdev->name, mbus_code.code, j); + + for (k = 0; k < ARRAY_SIZE(formats); k++) { + fmt = &formats[k]; + if (mbus_code.code != fmt->code) + continue; + vpfe->active_fmt[i] = fmt; + vpfe_dbg(3, vpfe, + "matched fourcc: %s code: %04x idx: %d\n", + print_fourcc(fmt->fourcc), mbus_code.code, i); + vpfe->num_active_fmt = ++i; + } } + if (!i) { + vpfe_err(vpfe, "No suitable format reported by subdev %s\n", + subdev->name); + return -EINVAL; + } return 0; } @@ -2605,8 +2494,6 @@ static int vpfe_remove(struct platform_device *pdev) { struct vpfe_device *vpfe = platform_get_drvdata(pdev); - vpfe_dbg(2, vpfe, "vpfe_remove\n"); - pm_runtime_disable(&pdev->dev); v4l2_async_notifier_unregister(&vpfe->notifier); @@ -2653,22 +2540,21 @@ static int vpfe_suspend(struct device *dev) struct vpfe_device *vpfe = dev_get_drvdata(dev); struct vpfe_ccdc *ccdc = &vpfe->ccdc; - /* if streaming has not started we don't care */ - if (!vb2_start_streaming_called(&vpfe->buffer_queue)) - return 0; - - pm_runtime_get_sync(dev); - vpfe_config_enable(ccdc, 1); + /* only do full suspend if streaming has started */ + if (vb2_start_streaming_called(&vpfe->buffer_queue)) { + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); - /* Save VPFE context */ - vpfe_save_context(ccdc); + /* Save VPFE context */ + vpfe_save_context(ccdc); - /* Disable CCDC */ - vpfe_pcr_enable(ccdc, 0); - vpfe_config_enable(ccdc, 0); + /* Disable CCDC */ + vpfe_pcr_enable(ccdc, 0); + vpfe_config_enable(ccdc, 0); - /* Disable both master and slave clock */ - pm_runtime_put_sync(dev); + /* Disable both master and slave clock */ + pm_runtime_put_sync(dev); + } /* Select sleep pin state */ pinctrl_pm_select_sleep_state(dev); @@ -2710,19 +2596,18 @@ static int vpfe_resume(struct device *dev) struct vpfe_device *vpfe = dev_get_drvdata(dev); struct vpfe_ccdc *ccdc = &vpfe->ccdc; - /* if streaming has not started we don't care */ - if (!vb2_start_streaming_called(&vpfe->buffer_queue)) - return 0; - - /* Enable both master and slave clock */ - pm_runtime_get_sync(dev); - vpfe_config_enable(ccdc, 1); + /* only do full resume if streaming has started */ + if (vb2_start_streaming_called(&vpfe->buffer_queue)) { + /* Enable both master and slave clock */ + pm_runtime_get_sync(dev); + vpfe_config_enable(ccdc, 1); - /* Restore VPFE context */ - vpfe_restore_context(ccdc); + /* Restore VPFE context */ + vpfe_restore_context(ccdc); - vpfe_config_enable(ccdc, 0); - pm_runtime_put_sync(dev); + vpfe_config_enable(ccdc, 0); + pm_runtime_put_sync(dev); + } /* Select default pin state */ pinctrl_pm_select_default_state(dev); diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h index 4678285f34c6..05ee37db0273 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.h +++ b/drivers/media/platform/am437x/am437x-vpfe.h @@ -1,21 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 - 2014 Texas Instruments, Inc. * * Benoit Parrot <bparrot@ti.com> * Lad, Prabhakar <prabhakar.csengg@gmail.com> - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef AM437X_VPFE_H @@ -23,6 +11,7 @@ #include <linux/am437x-vpfe.h> #include <linux/clk.h> +#include <linux/completion.h> #include <linux/device.h> #include <linux/io.h> #include <linux/i2c.h> @@ -214,6 +203,25 @@ struct vpfe_ccdc { u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)]; }; +/* + * struct vpfe_fmt - VPFE media bus format information + * fourcc: V4L2 pixel format code + * code: V4L2 media bus format code + * bitsperpixel: Bits per pixel over the bus + */ +struct vpfe_fmt { + u32 fourcc; + u32 code; + u32 bitsperpixel; +}; + +/* + * When formats[] is modified make sure to adjust this value also. + * Expect compile time warnings if VPFE_NUM_FORMATS is smaller then + * the number of elements in formats[]. + */ +#define VPFE_NUM_FORMATS 10 + struct vpfe_device { /* V4l2 specific parameters */ /* Identifies video device for this channel */ @@ -249,8 +257,11 @@ struct vpfe_device { struct vpfe_cap_buffer *next_frm; /* Used to store pixel format */ struct v4l2_format fmt; - /* Used to store current bytes per pixel based on current format */ - unsigned int bpp; + /* Used to keep a reference to the current vpfe_fmt */ + struct vpfe_fmt *current_vpfe_fmt; + struct vpfe_fmt *active_fmt[VPFE_NUM_FORMATS]; + unsigned int num_active_fmt; + /* * used when IMP is chained to store the crop window which * is different from the image window @@ -270,6 +281,8 @@ struct vpfe_device { */ u32 field_off; struct vpfe_ccdc ccdc; + int stopping; + struct completion capture_stop; }; #endif /* AM437X_VPFE_H */ diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h index 0746c48ec23f..63ecdca3b908 100644 --- a/drivers/media/platform/am437x/am437x-vpfe_regs.h +++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI AM437x Image Sensor Interface Registers * @@ -5,15 +6,6 @@ * * Benoit Parrot <bparrot@ti.com> * Lad, Prabhakar <prabhakar.csengg@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef AM437X_VPFE_REGS_H diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index eb12f3793062..d8593cb2ae84 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -606,6 +606,16 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) aspeed_video_start_frame(video); } + /* + * CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these + * are disabled in the VE_INTERRUPT_CTRL register so clear them to + * prevent unnecessary interrupt calls. + */ + if (sts & VE_INTERRUPT_CAPTURE_COMPLETE) + sts &= ~VE_INTERRUPT_CAPTURE_COMPLETE; + if (sts & VE_INTERRUPT_FRAME_COMPLETE) + sts &= ~VE_INTERRUPT_FRAME_COMPLETE; + return sts ? IRQ_NONE : IRQ_HANDLED; } @@ -614,7 +624,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) int i; int hsync_counter = 0; int vsync_counter = 0; - u32 sts; + u32 sts, ctrl; for (i = 0; i < NUM_POLARITY_CHECKS; ++i) { sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS); @@ -629,30 +639,29 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) hsync_counter++; } - if (hsync_counter < 0 || vsync_counter < 0) { - u32 ctrl = 0; + ctrl = aspeed_video_read(video, VE_CTRL); - if (hsync_counter < 0) { - ctrl = VE_CTRL_HSYNC_POL; - video->detected_timings.polarities &= - ~V4L2_DV_HSYNC_POS_POL; - } else { - video->detected_timings.polarities |= - V4L2_DV_HSYNC_POS_POL; - } - - if (vsync_counter < 0) { - ctrl = VE_CTRL_VSYNC_POL; - video->detected_timings.polarities &= - ~V4L2_DV_VSYNC_POS_POL; - } else { - video->detected_timings.polarities |= - V4L2_DV_VSYNC_POS_POL; - } + if (hsync_counter < 0) { + ctrl |= VE_CTRL_HSYNC_POL; + video->detected_timings.polarities &= + ~V4L2_DV_HSYNC_POS_POL; + } else { + ctrl &= ~VE_CTRL_HSYNC_POL; + video->detected_timings.polarities |= + V4L2_DV_HSYNC_POS_POL; + } - if (ctrl) - aspeed_video_update(video, VE_CTRL, 0, ctrl); + if (vsync_counter < 0) { + ctrl |= VE_CTRL_VSYNC_POL; + video->detected_timings.polarities &= + ~V4L2_DV_VSYNC_POS_POL; + } else { + ctrl &= ~VE_CTRL_VSYNC_POL; + video->detected_timings.polarities |= + V4L2_DV_VSYNC_POS_POL; } + + aspeed_video_write(video, VE_CTRL, ctrl); } static bool aspeed_video_alloc_buf(struct aspeed_video *video, @@ -741,6 +750,8 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) } set_bit(VIDEO_RES_DETECT, &video->flags); + aspeed_video_update(video, VE_CTRL, + VE_CTRL_VSYNC_POL | VE_CTRL_HSYNC_POL, 0); aspeed_video_enable_mode_detect(video); rc = wait_event_interruptible_timeout(video->wait, @@ -1646,7 +1657,8 @@ static int aspeed_video_probe(struct platform_device *pdev) { int rc; struct resource *res; - struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL); + struct aspeed_video *video = + devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); if (!video) return -ENOMEM; diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 31ace114eda1..be9ec59774d6 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -129,7 +129,7 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) */ for (i = csi2rx->num_lanes; i < csi2rx->max_lanes; i++) { unsigned int idx = find_first_zero_bit(&lanes_used, - sizeof(lanes_used)); + csi2rx->max_lanes); set_bit(idx, &lanes_used); reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1); } diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index 5b17d3a31896..7be91e712c4a 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -8,10 +8,12 @@ #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/gpio/consumer.h> +#include <media/cec-notifier.h> #include <media/cec-pin.h> struct cec_gpio { struct cec_adapter *adap; + struct cec_notifier *notifier; struct device *dev; struct gpio_desc *cec_gpio; @@ -173,9 +175,17 @@ static const struct cec_pin_ops cec_gpio_pin_ops = { static int cec_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device *hdmi_dev; struct cec_gpio *cec; + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; int ret; + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); + if (PTR_ERR(hdmi_dev) == -EPROBE_DEFER) + return PTR_ERR(hdmi_dev); + if (IS_ERR(hdmi_dev)) + caps |= CEC_CAP_PHYS_ADDR; + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); if (!cec) return -ENOMEM; @@ -196,8 +206,7 @@ static int cec_gpio_probe(struct platform_device *pdev) return PTR_ERR(cec->v5_gpio); cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops, - cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | - CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN); + cec, pdev->name, caps); if (IS_ERR(cec->adap)) return PTR_ERR(cec->adap); @@ -205,7 +214,7 @@ static int cec_gpio_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, cec->adap->name, cec); if (ret) - return ret; + goto del_adap; cec_gpio_disable_irq(cec->adap); @@ -218,7 +227,7 @@ static int cec_gpio_probe(struct platform_device *pdev) IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "hpd-gpio", cec); if (ret) - return ret; + goto del_adap; } if (cec->v5_gpio) { @@ -230,23 +239,37 @@ static int cec_gpio_probe(struct platform_device *pdev) IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "v5-gpio", cec); if (ret) - return ret; + goto del_adap; } - ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; + if (!IS_ERR(hdmi_dev)) { + cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL, + cec->adap); + if (!cec->notifier) { + ret = -ENOMEM; + goto del_adap; + } } + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) + goto unreg_notifier; + platform_set_drvdata(pdev, cec); return 0; + +unreg_notifier: + cec_notifier_cec_adap_unregister(cec->notifier); +del_adap: + cec_delete_adapter(cec->adap); + return ret; } static int cec_gpio_remove(struct platform_device *pdev) { struct cec_gpio *cec = platform_get_drvdata(pdev); + cec_notifier_cec_adap_unregister(cec->notifier); cec_unregister_adapter(cec->adap); return 0; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 73222c0615c0..94fb4d2ecc43 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -933,7 +933,8 @@ static int coda_g_selection(struct file *file, void *fh, rsel = &r; /* fallthrough */ case V4L2_SEL_TGT_CROP: - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + ctx->inst_type == CODA_INST_DECODER) return -EINVAL; break; case V4L2_SEL_TGT_COMPOSE_BOUNDS: @@ -942,7 +943,8 @@ static int coda_g_selection(struct file *file, void *fh, /* fallthrough */ case V4L2_SEL_TGT_COMPOSE: case V4L2_SEL_TGT_COMPOSE_DEFAULT: - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + ctx->inst_type == CODA_INST_ENCODER) return -EINVAL; break; default: @@ -1084,16 +1086,16 @@ static int coda_decoder_cmd(struct file *file, void *fh, switch (dc->cmd) { case V4L2_DEC_CMD_START: - mutex_lock(&ctx->bitstream_mutex); mutex_lock(&dev->coda_mutex); + mutex_lock(&ctx->bitstream_mutex); coda_bitstream_flush(ctx); - mutex_unlock(&dev->coda_mutex); dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); vb2_clear_last_buffer_dequeued(dst_vq); ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; coda_fill_bitstream(ctx, NULL); mutex_unlock(&ctx->bitstream_mutex); + mutex_unlock(&dev->coda_mutex); break; case V4L2_DEC_CMD_STOP: stream_end = false; @@ -2387,6 +2389,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING; dst_vq->mem_ops = &vb2_dma_contig_memops; return coda_queue_init(priv, dst_vq); @@ -2959,8 +2962,6 @@ static int coda_probe(struct platform_device *pdev) else return -EINVAL; - spin_lock_init(&dev->irqlock); - dev->dev = &pdev->dev; dev->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(dev->clk_per)) { diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 848bf1da401e..9f226140b486 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -86,7 +86,6 @@ struct coda_dev { struct gen_pool *iram_pool; struct coda_aux_buf iram; - spinlock_t irqlock; struct mutex dev_mutex; struct mutex coda_mutex; struct workqueue_struct *workqueue; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index 378cc302e1f8..d2cbcdca0463 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -313,7 +313,7 @@ static int isp_video_release(struct file *file) ivc->streaming = 0; } - vb2_fop_release(file); + _vb2_fop_release(file, NULL); if (v4l2_fh_is_singular_file(file)) { fimc_pipeline_call(&ivc->ve, close); diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a838189d4490..9aaf3b8060d5 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1457,12 +1457,12 @@ static int fimc_md_probe(struct platform_device *pdev) ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); - return ret; + goto err_md; } ret = fimc_md_get_clocks(fmd); if (ret) - goto err_md; + goto err_v4l2dev; ret = fimc_md_get_pinctrl(fmd); if (ret < 0) { @@ -1519,9 +1519,10 @@ err_m_ent: fimc_md_unregister_entities(fmd); err_clk: fimc_md_put_clocks(fmd); +err_v4l2dev: + v4l2_device_unregister(&fmd->v4l2_dev); err_md: media_device_cleanup(&fmd->media_dev); - v4l2_device_unregister(&fmd->v4l2_dev); return ret; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 26a55c3e807e..858727824889 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -284,7 +284,7 @@ static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, fmt = &mtk_video_formats[k]; if (fmt->fourcc == pixelformat) { mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", - dst_q_data->fmt.fourcc, pixelformat); + dst_q_data->fmt->fourcc, pixelformat); dst_q_data->fmt = fmt; return; } @@ -841,12 +841,20 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, return -EINVAL; pix_mp = &f->fmt.pix_mp; + /* + * Setting OUTPUT format after OUTPUT buffers are allocated is invalid + * if using the stateful API. + */ if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) { mtk_v4l2_err("out_q_ctx buffers already requested"); ret = -EBUSY; } + /* + * Setting CAPTURE format after CAPTURE buffers are allocated is + * invalid. + */ if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) { mtk_v4l2_err("cap_q_ctx buffers already requested"); @@ -865,6 +873,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, fmt = mtk_vdec_find_format(f); } } + if (fmt == NULL) + return -EINVAL; q_data->fmt = fmt; vidioc_try_fmt(f, q_data->fmt); @@ -873,10 +883,10 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, q_data->coded_width = pix_mp->width; q_data->coded_height = pix_mp->height; - ctx->colorspace = f->fmt.pix_mp.colorspace; - ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; - ctx->quantization = f->fmt.pix_mp.quantization; - ctx->xfer_func = f->fmt.pix_mp.xfer_func; + ctx->colorspace = pix_mp->colorspace; + ctx->ycbcr_enc = pix_mp->ycbcr_enc; + ctx->quantization = pix_mp->quantization; + ctx->xfer_func = pix_mp->xfer_func; if (ctx->state == MTK_STATE_FREE) { ret = vdec_if_init(ctx, q_data->fmt->fourcc); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 00d090df11bb..944771ee5f5c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -253,13 +253,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) { - res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res == NULL) { - dev_err(&pdev->dev, "get memory resource failed."); - ret = -ENXIO; - goto err_res; - } - dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); + dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i); if (IS_ERR((__force void *)dev->reg_base[i])) { ret = PTR_ERR((__force void *)dev->reg_base[i]); goto err_res; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 49aa85a9bb5a..50048c170b99 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -283,7 +283,6 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx) inst->vpu.id = IPI_VDEC_H264; inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; - inst->vpu.handler = vpu_dec_ipi_handler; err = vpu_dec_init(&inst->vpu); if (err) { diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 63a8708ce682..6011fdd60a22 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -402,7 +402,6 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx) inst->vpu.id = IPI_VDEC_VP8; inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; - inst->vpu.handler = vpu_dec_ipi_handler; err = vpu_dec_init(&inst->vpu); if (err) { diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 5066c283d86d..24c1f0bf2147 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -793,7 +793,6 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx) inst->vpu.id = IPI_VDEC_VP9; inst->vpu.dev = ctx->dev->vpu_plat_dev; inst->vpu.ctx = ctx; - inst->vpu.handler = vpu_dec_ipi_handler; if (vpu_dec_init(&inst->vpu)) { mtk_vcodec_err(inst, "vp9_dec_vpu_init failed"); diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 3f38cc4509ef..70abfd4cd4b9 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -25,10 +25,16 @@ static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg) } /* + * vpu_dec_ipi_handler - Handler for VPU ipi message. + * + * @data: ipi message + * @len : length of ipi message + * @priv: callback private data which is passed by decoder when register. + * * This function runs in interrupt context and it means there's an IPI MSG * from VPU. */ -void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) +static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) { struct vdec_vpu_ipi_ack *msg = data; struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) @@ -102,6 +108,7 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu) mtk_vcodec_debug_enter(vpu); init_waitqueue_head(&vpu->wq); + vpu->handler = vpu_dec_ipi_handler; err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL); if (err != 0) { diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index b76f717e4fd7..f779b0676fbd 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -76,13 +76,4 @@ int vpu_dec_deinit(struct vdec_vpu_inst *vpu); */ int vpu_dec_reset(struct vdec_vpu_inst *vpu); -/** - * vpu_dec_ipi_handler - Handler for VPU ipi message. - * - * @data: ipi message - * @len : length of ipi message - * @priv: callback private data which is passed by decoder when register. - */ -void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv); - #endif diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index cc2ff40d060d..a768707abb94 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -273,7 +273,7 @@ int vpu_ipi_register(struct platform_device *pdev, return -EPROBE_DEFER; } - if (id >= 0 && id < IPI_MAX && handler) { + if (id < IPI_MAX && handler) { ipi_desc = vpu->ipi_desc; ipi_desc[id].name = name; ipi_desc[id].handler = handler; @@ -398,7 +398,7 @@ int vpu_wdt_reg_handler(struct platform_device *pdev, handler = vpu->wdt.handler; - if (id >= 0 && id < VPU_RST_MAX && wdt_reset) { + if (id < VPU_RST_MAX && wdt_reset) { dev_dbg(vpu->dev, "wdt register id %d\n", id); mutex_lock(&vpu->vpu_mutex); handler[id].reset_func = wdt_reset; diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index e6eff512a8a1..07312a2fab24 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -5,6 +5,7 @@ */ #include <linux/clk.h> #include <linux/init.h> +#include <linux/interconnect.h> #include <linux/ioctl.h> #include <linux/list.h> #include <linux/module.h> @@ -239,6 +240,14 @@ static int venus_probe(struct platform_device *pdev) if (IS_ERR(core->base)) return PTR_ERR(core->base); + core->video_path = of_icc_get(dev, "video-mem"); + if (IS_ERR(core->video_path)) + return PTR_ERR(core->video_path); + + core->cpucfg_path = of_icc_get(dev, "cpu-cfg"); + if (IS_ERR(core->cpucfg_path)) + return PTR_ERR(core->cpucfg_path); + core->irq = platform_get_irq(pdev, 0); if (core->irq < 0) return core->irq; @@ -273,6 +282,10 @@ static int venus_probe(struct platform_device *pdev) if (ret) return ret; + ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000)); + if (ret) + return ret; + ret = hfi_create(core, &venus_core_ops); if (ret) return ret; @@ -355,6 +368,9 @@ static int venus_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); pm_runtime_disable(dev); + icc_put(core->video_path); + icc_put(core->cpucfg_path); + v4l2_device_unregister(&core->v4l2_dev); return ret; @@ -427,10 +443,11 @@ static const struct venus_resources msm8916_res = { }; static const struct freq_tbl msm8996_freq_table[] = { - { 1944000, 490000000 }, /* 4k UHD @ 60 */ - { 972000, 320000000 }, /* 4k UHD @ 30 */ - { 489600, 150000000 }, /* 1080p @ 60 */ - { 244800, 75000000 }, /* 1080p @ 30 */ + { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */ + { 972000, 520000000 }, /* 4k UHD @ 30 */ + { 489600, 346666667 }, /* 1080p @ 60 */ + { 244800, 150000000 }, /* 1080p @ 30 */ + { 108000, 75000000 }, /* 720p @ 30 */ }; static const struct reg_val msm8996_reg_preset[] = { @@ -464,9 +481,40 @@ static const struct freq_tbl sdm845_freq_table[] = { { 244800, 100000000 }, /* 1920x1080@30 */ }; +static struct codec_freq_data sdm845_codec_freq_data[] = { + { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 }, + { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 }, + { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 }, + { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 }, + { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 }, + { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 }, + { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 }, + { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 }, +}; + +static const struct bw_tbl sdm845_bw_table_enc[] = { + { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */ + { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */ + { 489600, 723000, 0, 973000, 0 }, /* 1920x1080@60 */ + { 244800, 370000, 0, 495000, 0 }, /* 1920x1080@30 */ +}; + +static const struct bw_tbl sdm845_bw_table_dec[] = { + { 2073600, 3929000, 0, 5551000, 0 }, /* 4096x2160@60 */ + { 1036800, 1987000, 0, 2797000, 0 }, /* 4096x2160@30 */ + { 489600, 1040000, 0, 1298000, 0 }, /* 1920x1080@60 */ + { 244800, 530000, 0, 659000, 0 }, /* 1920x1080@30 */ +}; + static const struct venus_resources sdm845_res = { .freq_tbl = sdm845_freq_table, .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), + .bw_tbl_enc = sdm845_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc), + .bw_tbl_dec = sdm845_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec), + .codec_freq_data = sdm845_codec_freq_data, + .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data), .clks = {"core", "iface", "bus" }, .clks_num = 3, .max_load = 3110400, /* 4096x2160@90 */ diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 922cb7e64bfa..11585fb3cae3 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -26,12 +26,33 @@ struct reg_val { u32 value; }; +struct codec_freq_data { + u32 pixfmt; + u32 session_type; + unsigned long vpp_freq; + unsigned long vsp_freq; +}; + +struct bw_tbl { + u32 mbs_per_sec; + u32 avg; + u32 peak; + u32 avg_10bit; + u32 peak_10bit; +}; + struct venus_resources { u64 dma_mask; const struct freq_tbl *freq_tbl; unsigned int freq_tbl_size; + const struct bw_tbl *bw_tbl_enc; + unsigned int bw_tbl_enc_size; + const struct bw_tbl *bw_tbl_dec; + unsigned int bw_tbl_dec_size; const struct reg_val *reg_tbl; unsigned int reg_tbl_size; + const struct codec_freq_data *codec_freq_data; + unsigned int codec_freq_data_size; const char * const clks[VIDC_CLKS_NUM_MAX]; unsigned int clks_num; enum hfi_version hfi_version; @@ -115,6 +136,8 @@ struct venus_core { struct clk *core1_clk; struct clk *core0_bus_clk; struct clk *core1_bus_clk; + struct icc_path *video_path; + struct icc_path *cpucfg_path; struct video_device *vdev_dec; struct video_device *vdev_enc; struct v4l2_device v4l2_dev; @@ -208,6 +231,12 @@ struct venus_buffer { struct list_head ref_list; }; +struct clock_data { + u32 core_id; + unsigned long freq; + const struct codec_freq_data *codec_freq_data; +}; + #define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb) enum venus_dec_state { @@ -288,6 +317,7 @@ struct venus_inst { struct list_head list; struct mutex lock; struct venus_core *core; + struct clock_data clk_data; struct list_head dpbbufs; struct list_head internalbufs; struct list_head registeredbufs; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 1ad96c25ab09..a172f1ac0b35 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -5,6 +5,7 @@ */ #include <linux/clk.h> #include <linux/iopoll.h> +#include <linux/interconnect.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> @@ -388,12 +389,91 @@ static u32 load_per_type(struct venus_core *core, u32 session_type) return mbs_per_sec; } -int venus_helper_load_scale_clocks(struct venus_core *core) +static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak) { + const struct venus_resources *res = inst->core->res; + const struct bw_tbl *bw_tbl; + unsigned int num_rows, i; + + *avg = 0; + *peak = 0; + + if (mbs == 0) + return; + + if (inst->session_type == VIDC_SESSION_TYPE_ENC) { + num_rows = res->bw_tbl_enc_size; + bw_tbl = res->bw_tbl_enc; + } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) { + num_rows = res->bw_tbl_dec_size; + bw_tbl = res->bw_tbl_dec; + } else { + return; + } + + if (!bw_tbl || num_rows == 0) + return; + + for (i = 0; i < num_rows; i++) { + if (mbs > bw_tbl[i].mbs_per_sec) + break; + + if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) { + *avg = bw_tbl[i].avg_10bit; + *peak = bw_tbl[i].peak_10bit; + } else { + *avg = bw_tbl[i].avg; + *peak = bw_tbl[i].peak; + } + } +} + +static int load_scale_bw(struct venus_core *core) +{ + struct venus_inst *inst = NULL; + u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + mbs_per_sec = load_per_instance(inst); + mbs_to_bw(inst, mbs_per_sec, &avg, &peak); + total_avg += avg; + total_peak += peak; + } + mutex_unlock(&core->lock); + + dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n", + total_avg, total_peak); + + return icc_set_bw(core->video_path, total_avg, total_peak); +} + +static int set_clk_freq(struct venus_core *core, unsigned long freq) +{ + struct clk *clk = core->clks[0]; + int ret; + + ret = clk_set_rate(clk, freq); + if (ret) + return ret; + + ret = clk_set_rate(core->core0_clk, freq); + if (ret) + return ret; + + ret = clk_set_rate(core->core1_clk, freq); + if (ret) + return ret; + + return 0; +} + +static int scale_clocks(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; const struct freq_tbl *table = core->res->freq_tbl; unsigned int num_rows = core->res->freq_tbl_size; unsigned long freq = table[0].freq; - struct clk *clk = core->clks[0]; struct device *dev = core->dev; u32 mbs_per_sec; unsigned int i; @@ -419,23 +499,124 @@ int venus_helper_load_scale_clocks(struct venus_core *core) set_freq: - ret = clk_set_rate(clk, freq); - if (ret) - goto err; + ret = set_clk_freq(core, freq); + if (ret) { + dev_err(dev, "failed to set clock rate %lu (%d)\n", + freq, ret); + return ret; + } - ret = clk_set_rate(core->core0_clk, freq); - if (ret) - goto err; + ret = load_scale_bw(core); + if (ret) { + dev_err(dev, "failed to set bandwidth (%d)\n", + ret); + return ret; + } - ret = clk_set_rate(core->core1_clk, freq); - if (ret) - goto err; + return 0; +} + +static unsigned long calculate_inst_freq(struct venus_inst *inst, + unsigned long filled_len) +{ + unsigned long vpp_freq = 0, vsp_freq = 0; + u32 fps = (u32)inst->fps; + u32 mbs_per_sec; + + mbs_per_sec = load_per_instance(inst) / fps; + + vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq; + /* 21 / 20 is overhead factor */ + vpp_freq += vpp_freq / 20; + vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq; + + /* 10 / 7 is overhead factor */ + if (inst->session_type == VIDC_SESSION_TYPE_ENC) + vsp_freq += (inst->controls.enc.bitrate * 10) / 7; + else + vsp_freq += ((fps * filled_len * 8) * 10) / 7; + + return max(vpp_freq, vsp_freq); +} + +static int scale_clocks_v4(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + const struct freq_tbl *table = core->res->freq_tbl; + unsigned int num_rows = core->res->freq_tbl_size; + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct device *dev = core->dev; + unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0; + unsigned long filled_len = 0; + struct venus_buffer *buf, *n; + struct vb2_buffer *vb; + int i, ret; + + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) { + vb = &buf->vb.vb2_buf; + filled_len = max(filled_len, vb2_get_plane_payload(vb, 0)); + } + + if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len) + return 0; + + freq = calculate_inst_freq(inst, filled_len); + inst->clk_data.freq = freq; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->clk_data.core_id == VIDC_CORE_ID_1) { + freq_core1 += inst->clk_data.freq; + } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) { + freq_core2 += inst->clk_data.freq; + } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) { + freq_core1 += inst->clk_data.freq; + freq_core2 += inst->clk_data.freq; + } + } + mutex_unlock(&core->lock); + + freq = max(freq_core1, freq_core2); + + if (freq >= table[0].freq) { + freq = table[0].freq; + dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", + freq, table[0].freq); + goto set_freq; + } + + for (i = num_rows - 1 ; i >= 0; i--) { + if (freq <= table[i].freq) { + freq = table[i].freq; + break; + } + } + +set_freq: + + ret = set_clk_freq(core, freq); + if (ret) { + dev_err(dev, "failed to set clock rate %lu (%d)\n", + freq, ret); + return ret; + } + + ret = load_scale_bw(core); + if (ret) { + dev_err(dev, "failed to set bandwidth (%d)\n", + ret); + return ret; + } return 0; +} -err: - dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret); - return ret; +int venus_helper_load_scale_clocks(struct venus_inst *inst) +{ + if (IS_V4(inst->core)) + return scale_clocks_v4(inst); + + return scale_clocks(inst); } EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks); @@ -541,6 +722,8 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf) if (inst->session_type == VIDC_SESSION_TYPE_DEC) put_ts_metadata(inst, vbuf); + + venus_helper_load_scale_clocks(inst); } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { if (inst->session_type == VIDC_SESSION_TYPE_ENC) fdata.buffer_type = HFI_BUFFER_OUTPUT; @@ -809,6 +992,7 @@ int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage) const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; struct hfi_videocores_usage_type cu; + inst->clk_data.core_id = usage; if (!IS_V4(inst->core)) return 0; @@ -818,6 +1002,36 @@ int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage) } EXPORT_SYMBOL_GPL(venus_helper_set_core_usage); +int venus_helper_init_codec_freq_data(struct venus_inst *inst) +{ + const struct codec_freq_data *data; + unsigned int i, data_size; + u32 pixfmt; + int ret = 0; + + if (!IS_V4(inst->core)) + return 0; + + data = inst->core->res->codec_freq_data; + data_size = inst->core->res->codec_freq_data_size; + pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ? + inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt; + + for (i = 0; i < data_size; i++) { + if (data[i].pixfmt == pixfmt && + data[i].session_type == inst->session_type) { + inst->clk_data.codec_freq_data = &data[i]; + break; + } + } + + if (!inst->clk_data.codec_freq_data) + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data); + int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, unsigned int output_bufs, unsigned int output2_bufs) @@ -1140,7 +1354,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) venus_helper_free_dpb_bufs(inst); - venus_helper_load_scale_clocks(core); + venus_helper_load_scale_clocks(inst); INIT_LIST_HEAD(&inst->registeredbufs); } @@ -1193,7 +1407,6 @@ EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs); int venus_helper_vb2_start_streaming(struct venus_inst *inst) { - struct venus_core *core = inst->core; int ret; ret = venus_helper_intbufs_alloc(inst); @@ -1204,7 +1417,7 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst) if (ret) goto err_bufs_free; - venus_helper_load_scale_clocks(core); + venus_helper_load_scale_clocks(inst); ret = hfi_session_load_res(inst); if (ret) diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 01f411b12f81..34dcd0c13f06 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -33,6 +33,7 @@ int venus_helper_set_output_resolution(struct venus_inst *inst, unsigned int width, unsigned int height, u32 buftype); int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode); +int venus_helper_init_codec_freq_data(struct venus_inst *inst); int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage); int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, unsigned int output_bufs, @@ -59,7 +60,7 @@ int venus_helper_intbufs_free(struct venus_inst *inst); int venus_helper_intbufs_realloc(struct venus_inst *inst); int venus_helper_queue_dpb_bufs(struct venus_inst *inst); int venus_helper_unregister_bufs(struct venus_inst *inst); -int venus_helper_load_scale_clocks(struct venus_core *core); +int venus_helper_load_scale_clocks(struct venus_inst *inst); int venus_helper_process_initial_cap_bufs(struct venus_inst *inst); int venus_helper_process_initial_out_bufs(struct venus_inst *inst); void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us, diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 7129a2aea09a..0d8855014ab3 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -1472,6 +1472,7 @@ static int venus_suspend_3xx(struct venus_core *core) { struct venus_hfi_device *hdev = to_hfi_priv(core); struct device *dev = core->dev; + u32 ctrl_status; bool val; int ret; @@ -1487,6 +1488,10 @@ static int venus_suspend_3xx(struct venus_core *core) return -EINVAL; } + ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY) + goto power_off; + /* * Power collapse sequence for Venus 3xx and 4xx versions: * 1. Check for ARM9 and video core to be idle by checking WFI bit @@ -1511,6 +1516,7 @@ static int venus_suspend_3xx(struct venus_core *core) if (ret) return ret; +power_off: mutex_lock(&hdev->lock); ret = venus_power_off(hdev); diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 7f4660555ddb..8feaf5daece9 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -685,6 +685,10 @@ static int vdec_session_init(struct venus_inst *inst) if (ret) goto deinit; + ret = venus_helper_init_codec_freq_data(inst); + if (ret) + goto deinit; + return 0; deinit: hfi_session_deinit(inst); @@ -864,7 +868,7 @@ reconfigure: if (ret) goto free_dpb_bufs; - venus_helper_load_scale_clocks(inst->core); + venus_helper_load_scale_clocks(inst); ret = hfi_session_continue(inst); if (ret) @@ -1072,7 +1076,7 @@ static void vdec_session_release(struct venus_inst *inst) hfi_session_abort(inst); venus_helper_free_dpb_bufs(inst); - venus_helper_load_scale_clocks(core); + venus_helper_load_scale_clocks(inst); INIT_LIST_HEAD(&inst->registeredbufs); mutex_unlock(&inst->lock); @@ -1412,9 +1416,6 @@ static const struct v4l2_file_operations vdec_fops = { .unlocked_ioctl = video_ioctl2, .poll = v4l2_m2m_fop_poll, .mmap = v4l2_m2m_fop_mmap, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = v4l2_compat_ioctl32, -#endif }; static int vdec_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 1b7fb2d5887c..453edf966d4f 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -842,6 +842,10 @@ static int venc_init_session(struct venus_inst *inst) if (ret) goto deinit; + ret = venus_helper_init_codec_freq_data(inst); + if (ret) + goto deinit; + ret = venc_set_properties(inst); if (ret) goto deinit; @@ -1235,9 +1239,6 @@ static const struct v4l2_file_operations venc_fops = { .unlocked_ioctl = video_ioctl2, .poll = v4l2_m2m_fop_poll, .mmap = v4l2_m2m_fop_mmap, -#ifdef CONFIG_COMPAT - .compat_ioctl32 = v4l2_compat_ioctl32, -#endif }; static int venc_probe(struct platform_device *pdev) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 6993484ff0f3..7440c8965d27 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -983,6 +983,7 @@ static const struct rvin_group_route rcar_info_r8a7795_routes[] = { static const struct rvin_info rcar_info_r8a7795 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a7795_routes, @@ -1077,6 +1078,7 @@ static const struct rvin_group_route rcar_info_r8a7796_routes[] = { static const struct rvin_info rcar_info_r8a7796 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a7796_routes, @@ -1121,6 +1123,7 @@ static const struct rvin_group_route rcar_info_r8a77965_routes[] = { static const struct rvin_info rcar_info_r8a77965 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77965_routes, @@ -1168,6 +1171,7 @@ static const struct rvin_group_route rcar_info_r8a77980_routes[] = { static const struct rvin_info rcar_info_r8a77980 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77980_routes, @@ -1184,6 +1188,7 @@ static const struct rvin_group_route rcar_info_r8a77990_routes[] = { static const struct rvin_info rcar_info_r8a77990 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77990_routes, @@ -1196,6 +1201,7 @@ static const struct rvin_group_route rcar_info_r8a77995_routes[] = { static const struct rvin_info rcar_info_r8a77995 = { .model = RCAR_GEN3, .use_mc = true, + .nv12 = true, .max_width = 4096, .max_height = 4096, .routes = rcar_info_r8a77995_routes, @@ -1207,6 +1213,10 @@ static const struct of_device_id rvin_of_id_table[] = { .data = &rcar_info_r8a7796, }, { + .compatible = "renesas,vin-r8a774b1", + .data = &rcar_info_r8a77965, + }, + { .compatible = "renesas,vin-r8a774c0", .data = &rcar_info_r8a77990, }, @@ -1282,7 +1292,6 @@ static int rcar_vin_probe(struct platform_device *pdev) { const struct soc_device_attribute *attr; struct rvin_dev *vin; - struct resource *mem; int irq, ret; vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL); @@ -1301,11 +1310,7 @@ static int rcar_vin_probe(struct platform_device *pdev) if (attr) vin->info = attr->data; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mem == NULL) - return -EINVAL; - - vin->base = devm_ioremap_resource(vin->dev, mem); + vin->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(vin->base)) return PTR_ERR(vin->base); diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index c14af1b929df..faa9fb23a2e9 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1082,6 +1082,10 @@ static const struct of_device_id rcar_csi2_of_table[] = { .data = &rcar_csi2_info_r8a7796, }, { + .compatible = "renesas,r8a774b1-csi2", + .data = &rcar_csi2_info_r8a77965, + }, + { .compatible = "renesas,r8a774c0-csi2", .data = &rcar_csi2_info_r8a77990, }, diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 3cb29b2e0b2b..cf9029efeb04 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -118,6 +118,7 @@ #define VNDMR_ABIT (1 << 2) #define VNDMR_DTMD_YCSEP (1 << 1) #define VNDMR_DTMD_ARGB (1 << 0) +#define VNDMR_DTMD_YCSEP_420 (3 << 0) /* Video n Data Mode Register 2 bits */ #define VNDMR2_VPS (1 << 30) @@ -529,12 +530,17 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) { + unsigned int crop_height; u32 xs, ys; /* Set scaling coefficient */ + crop_height = vin->crop.height; + if (V4L2_FIELD_IS_INTERLACED(vin->format.field)) + crop_height *= 2; + ys = 0; - if (vin->crop.height != vin->compose.height) - ys = (4096 * vin->crop.height) / vin->compose.height; + if (crop_height != vin->compose.height) + ys = (4096 * crop_height) / vin->compose.height; rvin_write(vin, ys, VNYS_REG); xs = 0; @@ -557,16 +563,11 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin) rvin_write(vin, 0, VNSPPOC_REG); rvin_write(vin, 0, VNSLPOC_REG); rvin_write(vin, vin->format.width - 1, VNEPPOC_REG); - switch (vin->format.field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: + + if (V4L2_FIELD_IS_INTERLACED(vin->format.field)) rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG); - break; - default: + else rvin_write(vin, vin->format.height - 1, VNELPOC_REG); - break; - } vin_dbg(vin, "Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n", @@ -583,21 +584,9 @@ void rvin_crop_scale_comp(struct rvin_dev *vin) /* Set Start/End Pixel/Line Pre-Clip */ rvin_write(vin, vin->crop.left, VNSPPRC_REG); rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG); + rvin_write(vin, vin->crop.top, VNSLPRC_REG); + rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG); - switch (vin->format.field) { - case V4L2_FIELD_INTERLACED: - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG); - rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1, - VNELPRC_REG); - break; - default: - rvin_write(vin, vin->crop.top, VNSLPRC_REG); - rvin_write(vin, vin->crop.top + vin->crop.height - 1, - VNELPRC_REG); - break; - } /* TODO: Add support for the UDS scaler. */ if (vin->info->model != RCAR_GEN3) @@ -641,6 +630,9 @@ static int rvin_setup(struct rvin_dev *vin) vnmc = VNMC_IM_ODD_EVEN; progressive = true; break; + case V4L2_FIELD_ALTERNATE: + vnmc = VNMC_IM_ODD_EVEN; + break; default: vnmc = VNMC_IM_ODD; break; @@ -710,11 +702,13 @@ static int rvin_setup(struct rvin_dev *vin) * Output format */ switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: rvin_write(vin, - ALIGN(vin->format.width * vin->format.height, 0x80), - VNUVAOF_REG); - dmr = VNDMR_DTMD_YCSEP; + ALIGN(vin->format.bytesperline * vin->format.height, + 0x80), VNUVAOF_REG); + dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ? + VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP; output_is_yuv = true; break; case V4L2_PIX_FMT_YUYV: @@ -799,6 +793,18 @@ static bool rvin_capture_active(struct rvin_dev *vin) return rvin_read(vin, VNMS_REG) & VNMS_CA; } +static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) +{ + if (vin->format.field == V4L2_FIELD_ALTERNATE) { + /* If FS is set it is an Even field. */ + if (vnms & VNMS_FS) + return V4L2_FIELD_BOTTOM; + return V4L2_FIELD_TOP; + } + + return vin->format.field; +} + static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) { const struct rvin_video_format *fmt; @@ -948,7 +954,7 @@ static irqreturn_t rvin_irq(int irq, void *data) /* Capture frame */ if (vin->queue_buf[slot]) { - vin->queue_buf[slot]->field = vin->format.field; + vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); vin->queue_buf[slot]->sequence = vin->sequence; vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, @@ -1075,6 +1081,7 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd, case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_NONE: + case V4L2_FIELD_ALTERNATE: break; case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index cbc1c07f0a96..9e2e63ffcc47 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -31,6 +31,10 @@ static const struct rvin_video_format rvin_formats[] = { { + .fourcc = V4L2_PIX_FMT_NV12, + .bpp = 1, + }, + { .fourcc = V4L2_PIX_FMT_NV16, .bpp = 1, }, @@ -72,6 +76,9 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin, if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32) return NULL; + if (pixelformat == V4L2_PIX_FMT_NV12 && !vin->info->nv12) + return NULL; + for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) if (rvin_formats[i].fourcc == pixelformat) return rvin_formats + i; @@ -90,17 +97,29 @@ static u32 rvin_format_bytesperline(struct rvin_dev *vin, if (WARN_ON(!fmt)) return -EINVAL; - align = pix->pixelformat == V4L2_PIX_FMT_NV16 ? 0x20 : 0x10; + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + align = 0x20; + break; + default: + align = 0x10; + break; + } return ALIGN(pix->width, align) * fmt->bpp; } static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix) { - if (pix->pixelformat == V4L2_PIX_FMT_NV16) + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV12: + return pix->bytesperline * pix->height * 3 / 2; + case V4L2_PIX_FMT_NV16: return pix->bytesperline * pix->height * 2; - - return pix->bytesperline * pix->height; + default: + return pix->bytesperline * pix->height; + } } static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) @@ -117,23 +136,23 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix) case V4L2_FIELD_INTERLACED_TB: case V4L2_FIELD_INTERLACED_BT: case V4L2_FIELD_INTERLACED: - break; case V4L2_FIELD_ALTERNATE: - /* - * Driver does not (yet) support outputting ALTERNATE to a - * userspace. It does support outputting INTERLACED so use - * the VIN hardware to combine the two fields. - */ - pix->field = V4L2_FIELD_INTERLACED; - pix->height *= 2; break; default: pix->field = RVIN_DEFAULT_FIELD; break; } - /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */ - walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1; + /* HW limit width to a multiple of 32 (2^5) for NV12/16 else 2 (2^1) */ + switch (vin->format.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + walign = 5; + break; + default: + walign = 1; + break; + } /* Limit to VIN capabilities */ v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign, @@ -164,22 +183,32 @@ static int rvin_reset_format(struct rvin_dev *vin) v4l2_fill_pix_format(&vin->format, &fmt.format); + vin->src_rect.top = 0; + vin->src_rect.left = 0; + vin->src_rect.width = vin->format.width; + vin->src_rect.height = vin->format.height; + + /* Make use of the hardware interlacer by default. */ + if (vin->format.field == V4L2_FIELD_ALTERNATE) { + vin->format.field = V4L2_FIELD_INTERLACED; + vin->format.height *= 2; + } + rvin_format_align(vin, &vin->format); - vin->source.top = 0; - vin->source.left = 0; - vin->source.width = vin->format.width; - vin->source.height = vin->format.height; + vin->crop = vin->src_rect; - vin->crop = vin->source; - vin->compose = vin->source; + vin->compose.top = 0; + vin->compose.left = 0; + vin->compose.width = vin->format.width; + vin->compose.height = vin->format.height; return 0; } static int rvin_try_format(struct rvin_dev *vin, u32 which, struct v4l2_pix_format *pix, - struct v4l2_rect *crop, struct v4l2_rect *compose) + struct v4l2_rect *src_rect) { struct v4l2_subdev *sd = vin_to_source(vin); struct v4l2_subdev_pad_config *pad_cfg; @@ -208,21 +237,15 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format); if (ret < 0 && ret != -ENOIOCTLCMD) goto done; + ret = 0; v4l2_fill_pix_format(pix, &format.format); - if (crop) { - crop->top = 0; - crop->left = 0; - crop->width = pix->width; - crop->height = pix->height; - - /* - * If source is ALTERNATE the driver will use the VIN hardware - * to INTERLACE it. The crop height then needs to be doubled. - */ - if (pix->field == V4L2_FIELD_ALTERNATE) - crop->height *= 2; + if (src_rect) { + src_rect->top = 0; + src_rect->left = 0; + src_rect->width = pix->width; + src_rect->height = pix->height; } if (field != V4L2_FIELD_ANY) @@ -232,17 +255,10 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, pix->height = height; rvin_format_align(vin, pix); - - if (compose) { - compose->top = 0; - compose->left = 0; - compose->width = pix->width; - compose->height = pix->height; - } done: v4l2_subdev_free_pad_config(pad_cfg); - return 0; + return ret; } static int rvin_querycap(struct file *file, void *priv, @@ -262,29 +278,34 @@ static int rvin_try_fmt_vid_cap(struct file *file, void *priv, { struct rvin_dev *vin = video_drvdata(file); - return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL, - NULL); + return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL); } static int rvin_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct rvin_dev *vin = video_drvdata(file); - struct v4l2_rect crop, compose; + struct v4l2_rect fmt_rect, src_rect; int ret; if (vb2_is_busy(&vin->queue)) return -EBUSY; ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix, - &crop, &compose); + &src_rect); if (ret) return ret; vin->format = f->fmt.pix; - vin->crop = crop; - vin->compose = compose; - vin->source = crop; + + fmt_rect.top = 0; + fmt_rect.left = 0; + fmt_rect.width = vin->format.width; + fmt_rect.height = vin->format.height; + + v4l2_rect_map_inside(&vin->crop, &src_rect); + v4l2_rect_map_inside(&vin->compose, &fmt_rect); + vin->src_rect = src_rect; return 0; } @@ -302,12 +323,22 @@ static int rvin_g_fmt_vid_cap(struct file *file, void *priv, static int rvin_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= ARRAY_SIZE(rvin_formats)) - return -EINVAL; - - f->pixelformat = rvin_formats[f->index].fourcc; + struct rvin_dev *vin = video_drvdata(file); + unsigned int i; + int matched; + + matched = -1; + for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) { + if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc)) + matched++; + + if (matched == f->index) { + f->pixelformat = rvin_formats[i].fourcc; + return 0; + } + } - return 0; + return -EINVAL; } static int rvin_g_selection(struct file *file, void *fh, @@ -322,8 +353,8 @@ static int rvin_g_selection(struct file *file, void *fh, case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: s->r.left = s->r.top = 0; - s->r.width = vin->source.width; - s->r.height = vin->source.height; + s->r.width = vin->src_rect.width; + s->r.height = vin->src_rect.height; break; case V4L2_SEL_TGT_CROP: s->r = vin->crop; @@ -365,21 +396,22 @@ static int rvin_s_selection(struct file *file, void *fh, case V4L2_SEL_TGT_CROP: /* Can't crop outside of source input */ max_rect.top = max_rect.left = 0; - max_rect.width = vin->source.width; - max_rect.height = vin->source.height; + max_rect.width = vin->src_rect.width; + max_rect.height = vin->src_rect.height; v4l2_rect_map_inside(&r, &max_rect); - v4l_bound_align_image(&r.width, 6, vin->source.width, 0, - &r.height, 2, vin->source.height, 0, 0); + v4l_bound_align_image(&r.width, 6, vin->src_rect.width, 0, + &r.height, 2, vin->src_rect.height, 0, 0); - r.top = clamp_t(s32, r.top, 0, vin->source.height - r.height); - r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width); + r.top = clamp_t(s32, r.top, 0, + vin->src_rect.height - r.height); + r.left = clamp_t(s32, r.left, 0, vin->src_rect.width - r.width); vin->crop = s->r = r; vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n", r.width, r.height, r.left, r.top, - vin->source.width, vin->source.height); + vin->src_rect.width, vin->src_rect.height); break; case V4L2_SEL_TGT_COMPOSE: /* Make sure compose rect fits inside output format */ diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index e562c2ff21ec..a36b0824f81d 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -126,6 +126,7 @@ struct rvin_group_route { * struct rvin_info - Information about the particular VIN implementation * @model: VIN model * @use_mc: use media controller instead of controlling subdevice + * @nv12: support outputing NV12 pixel format * @max_width: max input width the VIN supports * @max_height: max input height the VIN supports * @routes: list of possible routes from the CSI-2 recivers to @@ -134,6 +135,7 @@ struct rvin_group_route { struct rvin_info { enum model_id model; bool use_mc; + bool nv12; unsigned int max_width; unsigned int max_height; @@ -176,7 +178,7 @@ struct rvin_info { * * @crop: active cropping * @compose: active composing - * @source: active size of the video source + * @src_rect: active size of the video source * @std: active video standard of the video source * * @alpha: Alpha component to fill in for supported pixel formats @@ -215,7 +217,7 @@ struct rvin_dev { struct v4l2_rect crop; struct v4l2_rect compose; - struct v4l2_rect source; + struct v4l2_rect src_rect; v4l2_std_id std; unsigned int alpha; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 608e5217ccd5..0f267a237b42 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -912,6 +912,7 @@ static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv, { struct rcar_drif_sdr *sdr = video_drvdata(file); + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; f->fmt.sdr.buffersize = sdr->fmt->buffersize; diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index cb93a13e1777..97bed45360f0 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2369,7 +2369,7 @@ static int fdp1_probe(struct platform_device *pdev) dprintk(fdp1, "FDP1 Version R-Car H3\n"); break; case FD1_IP_M3N: - dprintk(fdp1, "FDP1 Version R-Car M3N\n"); + dprintk(fdp1, "FDP1 Version R-Car M3-N\n"); break; case FD1_IP_E3: dprintk(fdp1, "FDP1 Version R-Car E3\n"); diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c index 1a65532dc36d..e80204f5720c 100644 --- a/drivers/media/platform/s3c-camif/camif-regs.c +++ b/drivers/media/platform/s3c-camif/camif-regs.c @@ -553,7 +553,7 @@ void camif_hw_disable_capture(struct camif_vp *vp) void camif_hw_dump_regs(struct camif_dev *camif, const char *label) { - struct { + static const struct { u32 offset; const char * const name; } registers[] = { diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 8dbbd5f2a40a..ac2162235cef 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1236,7 +1236,6 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, } result->sof = sof; result->sof_len = sof_len; - result->components = components; return true; } diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 3bc52f83f5bc..4407fe775afa 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -190,7 +190,6 @@ struct s5p_jpeg_marker { * @dqt: DQT markers' positions relative to the buffer beginning * @sof: SOF0 marker's position relative to the buffer beginning * @sof_len: SOF0 marker's payload length (without length field itself) - * @components: number of image components * @size: image buffer size in bytes */ struct s5p_jpeg_q_data { @@ -202,7 +201,6 @@ struct s5p_jpeg_q_data { struct s5p_jpeg_marker dqt; u32 sof; u32 sof_len; - u32 components; u32 size; }; diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index 9cd60fe1867c..a86b6e8f9196 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -675,6 +675,7 @@ err_notifier: err_delete_adapter: cec_delete_adapter(secocec->cec_adap); err: + release_region(BRA_SMB_BASE_ADDR, 7); dev_err(dev, "%s device probe failed\n", dev_name(dev)); return ret; diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index e90f1ba30574..675b5f2b4c2e 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -651,8 +651,7 @@ static int bdisp_release(struct file *file) dev_dbg(bdisp->dev, "%s\n", __func__); - if (mutex_lock_interruptible(&bdisp->lock)) - return -ERESTARTSYS; + mutex_lock(&bdisp->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index a05127529006..3878cb4efdc2 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -1,2 +1,3 @@ obj-y += sun4i-csi/ obj-y += sun6i-csi/ +obj-y += sun8i-di/ diff --git a/drivers/media/platform/sunxi/sun8i-di/Makefile b/drivers/media/platform/sunxi/sun8i-di/Makefile new file mode 100644 index 000000000000..109f7e5442b7 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-di/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_SUN8I_DEINTERLACE) += sun8i-di.o diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c new file mode 100644 index 000000000000..aaa1dc159ac2 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -0,0 +1,1028 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner sun8i deinterlacer with scaler driver + * + * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@siol.net> + * + * Based on vim2m driver. + */ + +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mem2mem.h> + +#include "sun8i-di.h" + +#define FLAG_SIZE (DEINTERLACE_MAX_WIDTH * DEINTERLACE_MAX_HEIGHT / 4) + +static u32 deinterlace_formats[] = { + V4L2_PIX_FMT_NV12, + V4L2_PIX_FMT_NV21, +}; + +static inline u32 deinterlace_read(struct deinterlace_dev *dev, u32 reg) +{ + return readl(dev->base + reg); +} + +static inline void deinterlace_write(struct deinterlace_dev *dev, + u32 reg, u32 value) +{ + writel(value, dev->base + reg); +} + +static inline void deinterlace_set_bits(struct deinterlace_dev *dev, + u32 reg, u32 bits) +{ + writel(readl(dev->base + reg) | bits, dev->base + reg); +} + +static inline void deinterlace_clr_set_bits(struct deinterlace_dev *dev, + u32 reg, u32 clr, u32 set) +{ + u32 val = readl(dev->base + reg); + + val &= ~clr; + val |= set; + + writel(val, dev->base + reg); +} + +static void deinterlace_device_run(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + struct deinterlace_dev *dev = ctx->dev; + u32 size, stride, width, height, val; + struct vb2_v4l2_buffer *src, *dst; + unsigned int hstep, vstep; + dma_addr_t addr; + + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + v4l2_m2m_buf_copy_metadata(src, dst, true); + + deinterlace_write(dev, DEINTERLACE_MOD_ENABLE, + DEINTERLACE_MOD_ENABLE_EN); + + if (ctx->field) { + deinterlace_write(dev, DEINTERLACE_TILE_FLAG0, + ctx->flag1_buf_dma); + deinterlace_write(dev, DEINTERLACE_TILE_FLAG1, + ctx->flag2_buf_dma); + } else { + deinterlace_write(dev, DEINTERLACE_TILE_FLAG0, + ctx->flag2_buf_dma); + deinterlace_write(dev, DEINTERLACE_TILE_FLAG1, + ctx->flag1_buf_dma); + } + deinterlace_write(dev, DEINTERLACE_FLAG_LINE_STRIDE, 0x200); + + width = ctx->src_fmt.width; + height = ctx->src_fmt.height; + stride = ctx->src_fmt.bytesperline; + size = stride * height; + + addr = vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0); + deinterlace_write(dev, DEINTERLACE_BUF_ADDR0, addr); + deinterlace_write(dev, DEINTERLACE_BUF_ADDR1, addr + size); + deinterlace_write(dev, DEINTERLACE_BUF_ADDR2, 0); + + deinterlace_write(dev, DEINTERLACE_LINE_STRIDE0, stride); + deinterlace_write(dev, DEINTERLACE_LINE_STRIDE1, stride); + + deinterlace_write(dev, DEINTERLACE_CH0_IN_SIZE, + DEINTERLACE_SIZE(width, height)); + deinterlace_write(dev, DEINTERLACE_CH1_IN_SIZE, + DEINTERLACE_SIZE(width / 2, height / 2)); + + val = DEINTERLACE_IN_FMT_FMT(DEINTERLACE_IN_FMT_YUV420) | + DEINTERLACE_IN_FMT_MOD(DEINTERLACE_MODE_UV_COMBINED); + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12: + val |= DEINTERLACE_IN_FMT_PS(DEINTERLACE_PS_UVUV); + break; + case V4L2_PIX_FMT_NV21: + val |= DEINTERLACE_IN_FMT_PS(DEINTERLACE_PS_VUVU); + break; + } + deinterlace_write(dev, DEINTERLACE_IN_FMT, val); + + if (ctx->prev) + addr = vb2_dma_contig_plane_dma_addr(&ctx->prev->vb2_buf, 0); + + deinterlace_write(dev, DEINTERLACE_PRELUMA, addr); + deinterlace_write(dev, DEINTERLACE_PRECHROMA, addr + size); + + val = DEINTERLACE_OUT_FMT_FMT(DEINTERLACE_OUT_FMT_YUV420SP); + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_NV12: + val |= DEINTERLACE_OUT_FMT_PS(DEINTERLACE_PS_UVUV); + break; + case V4L2_PIX_FMT_NV21: + val |= DEINTERLACE_OUT_FMT_PS(DEINTERLACE_PS_VUVU); + break; + } + deinterlace_write(dev, DEINTERLACE_OUT_FMT, val); + + width = ctx->dst_fmt.width; + height = ctx->dst_fmt.height; + stride = ctx->dst_fmt.bytesperline; + size = stride * height; + + deinterlace_write(dev, DEINTERLACE_CH0_OUT_SIZE, + DEINTERLACE_SIZE(width, height)); + deinterlace_write(dev, DEINTERLACE_CH1_OUT_SIZE, + DEINTERLACE_SIZE(width / 2, height / 2)); + + deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE0, stride); + deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE1, stride); + + addr = vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0); + deinterlace_write(dev, DEINTERLACE_WB_ADDR0, addr); + deinterlace_write(dev, DEINTERLACE_WB_ADDR1, addr + size); + deinterlace_write(dev, DEINTERLACE_WB_ADDR2, 0); + + hstep = (ctx->src_fmt.width << 16) / ctx->dst_fmt.width; + vstep = (ctx->src_fmt.height << 16) / ctx->dst_fmt.height; + deinterlace_write(dev, DEINTERLACE_CH0_HORZ_FACT, hstep); + deinterlace_write(dev, DEINTERLACE_CH0_VERT_FACT, vstep); + deinterlace_write(dev, DEINTERLACE_CH1_HORZ_FACT, hstep); + deinterlace_write(dev, DEINTERLACE_CH1_VERT_FACT, vstep); + + deinterlace_clr_set_bits(dev, DEINTERLACE_FIELD_CTRL, + DEINTERLACE_FIELD_CTRL_FIELD_CNT_MSK, + DEINTERLACE_FIELD_CTRL_FIELD_CNT(ctx->field)); + + deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_START); + + deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_REG_READY); + + deinterlace_set_bits(dev, DEINTERLACE_INT_ENABLE, + DEINTERLACE_INT_ENABLE_WB_EN); + + deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_WB_EN); +} + +static int deinterlace_job_ready(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + + return v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) >= 1 && + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) >= 2; +} + +static void deinterlace_job_abort(void *priv) +{ + struct deinterlace_ctx *ctx = priv; + + /* Will cancel the transaction in the next interrupt handler */ + ctx->aborting = 1; +} + +static irqreturn_t deinterlace_irq(int irq, void *data) +{ + struct deinterlace_dev *dev = data; + struct vb2_v4l2_buffer *src, *dst; + enum vb2_buffer_state state; + struct deinterlace_ctx *ctx; + unsigned int val; + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (!ctx) { + v4l2_err(&dev->v4l2_dev, + "Instance released before the end of transaction\n"); + return IRQ_NONE; + } + + val = deinterlace_read(dev, DEINTERLACE_INT_STATUS); + if (!(val & DEINTERLACE_INT_STATUS_WRITEBACK)) + return IRQ_NONE; + + deinterlace_write(dev, DEINTERLACE_INT_ENABLE, 0); + deinterlace_set_bits(dev, DEINTERLACE_INT_STATUS, + DEINTERLACE_INT_STATUS_WRITEBACK); + deinterlace_write(dev, DEINTERLACE_MOD_ENABLE, 0); + deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_START, 0); + + val = deinterlace_read(dev, DEINTERLACE_STATUS); + if (val & DEINTERLACE_STATUS_WB_ERROR) + state = VB2_BUF_STATE_ERROR; + else + state = VB2_BUF_STATE_DONE; + + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(dst, state); + + if (ctx->field != ctx->first_field || ctx->aborting) { + ctx->field = ctx->first_field; + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + if (ctx->prev) + v4l2_m2m_buf_done(ctx->prev, state); + ctx->prev = src; + + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + } else { + ctx->field = !ctx->first_field; + deinterlace_device_run(ctx); + } + + return IRQ_HANDLED; +} + +static void deinterlace_init(struct deinterlace_dev *dev) +{ + u32 val; + int i; + + deinterlace_write(dev, DEINTERLACE_BYPASS, + DEINTERLACE_BYPASS_CSC); + deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE_CTRL, + DEINTERLACE_WB_LINE_STRIDE_CTRL_EN); + deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_OUT_CTRL); + deinterlace_write(dev, DEINTERLACE_AGTH_SEL, + DEINTERLACE_AGTH_SEL_LINEBUF); + + val = DEINTERLACE_CTRL_EN | + DEINTERLACE_CTRL_MODE_MIXED | + DEINTERLACE_CTRL_DIAG_INTP_EN | + DEINTERLACE_CTRL_TEMP_DIFF_EN; + deinterlace_write(dev, DEINTERLACE_CTRL, val); + + deinterlace_clr_set_bits(dev, DEINTERLACE_LUMA_TH, + DEINTERLACE_LUMA_TH_MIN_LUMA_MSK, + DEINTERLACE_LUMA_TH_MIN_LUMA(4)); + + deinterlace_clr_set_bits(dev, DEINTERLACE_SPAT_COMP, + DEINTERLACE_SPAT_COMP_TH2_MSK, + DEINTERLACE_SPAT_COMP_TH2(5)); + + deinterlace_clr_set_bits(dev, DEINTERLACE_TEMP_DIFF, + DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH_MSK, + DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH(5)); + + val = DEINTERLACE_DIAG_INTP_TH0(60) | + DEINTERLACE_DIAG_INTP_TH1(0) | + DEINTERLACE_DIAG_INTP_TH3(30); + deinterlace_write(dev, DEINTERLACE_DIAG_INTP, val); + + deinterlace_clr_set_bits(dev, DEINTERLACE_CHROMA_DIFF, + DEINTERLACE_CHROMA_DIFF_TH_MSK, + DEINTERLACE_CHROMA_DIFF_TH(5)); + + /* neutral filter coefficients */ + deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_COEF_ACCESS); + readl_poll_timeout(dev->base + DEINTERLACE_STATUS, val, + val & DEINTERLACE_STATUS_COEF_STATUS, 2, 40); + + for (i = 0; i < 32; i++) { + deinterlace_write(dev, DEINTERLACE_CH0_HORZ_COEF0 + i * 4, + DEINTERLACE_IDENTITY_COEF); + deinterlace_write(dev, DEINTERLACE_CH0_VERT_COEF + i * 4, + DEINTERLACE_IDENTITY_COEF); + deinterlace_write(dev, DEINTERLACE_CH1_HORZ_COEF0 + i * 4, + DEINTERLACE_IDENTITY_COEF); + deinterlace_write(dev, DEINTERLACE_CH1_VERT_COEF + i * 4, + DEINTERLACE_IDENTITY_COEF); + } + + deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL, + DEINTERLACE_FRM_CTRL_COEF_ACCESS, 0); +} + +static inline struct deinterlace_ctx *deinterlace_file2ctx(struct file *file) +{ + return container_of(file->private_data, struct deinterlace_ctx, fh); +} + +static bool deinterlace_check_format(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(deinterlace_formats); i++) + if (deinterlace_formats[i] == pixelformat) + return true; + + return false; +} + +static void deinterlace_prepare_format(struct v4l2_pix_format *pix_fmt) +{ + unsigned int height = pix_fmt->height; + unsigned int width = pix_fmt->width; + unsigned int bytesperline; + unsigned int sizeimage; + + width = clamp(width, DEINTERLACE_MIN_WIDTH, + DEINTERLACE_MAX_WIDTH); + height = clamp(height, DEINTERLACE_MIN_HEIGHT, + DEINTERLACE_MAX_HEIGHT); + + bytesperline = ALIGN(width, 2); + /* luma */ + sizeimage = bytesperline * height; + /* chroma */ + sizeimage += bytesperline * height / 2; + + pix_fmt->width = width; + pix_fmt->height = height; + pix_fmt->bytesperline = bytesperline; + pix_fmt->sizeimage = sizeimage; +} + +static int deinterlace_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, DEINTERLACE_NAME, sizeof(cap->driver)); + strscpy(cap->card, DEINTERLACE_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", DEINTERLACE_NAME); + + return 0; +} + +static int deinterlace_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index < ARRAY_SIZE(deinterlace_formats)) { + f->pixelformat = deinterlace_formats[f->index]; + + return 0; + } + + return -EINVAL; +} + +static int deinterlace_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0) + return -EINVAL; + + if (!deinterlace_check_format(fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = DEINTERLACE_MIN_WIDTH; + fsize->stepwise.min_height = DEINTERLACE_MIN_HEIGHT; + fsize->stepwise.max_width = DEINTERLACE_MAX_WIDTH; + fsize->stepwise.max_height = DEINTERLACE_MAX_HEIGHT; + fsize->stepwise.step_width = 2; + fsize->stepwise.step_height = 1; + + return 0; +} + +static int deinterlace_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); + + f->fmt.pix = ctx->dst_fmt; + + return 0; +} + +static int deinterlace_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); + + f->fmt.pix = ctx->src_fmt; + + return 0; +} + +static int deinterlace_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + if (!deinterlace_check_format(f->fmt.pix.pixelformat)) + f->fmt.pix.pixelformat = deinterlace_formats[0]; + + if (f->fmt.pix.field != V4L2_FIELD_NONE) + f->fmt.pix.field = V4L2_FIELD_NONE; + + deinterlace_prepare_format(&f->fmt.pix); + + return 0; +} + +static int deinterlace_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + if (!deinterlace_check_format(f->fmt.pix.pixelformat)) + f->fmt.pix.pixelformat = deinterlace_formats[0]; + + if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB && + f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT && + f->fmt.pix.field != V4L2_FIELD_INTERLACED) + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + + deinterlace_prepare_format(&f->fmt.pix); + + return 0; +} + +static int deinterlace_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); + struct vb2_queue *vq; + int ret; + + ret = deinterlace_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + ctx->dst_fmt = f->fmt.pix; + + return 0; +} + +static int deinterlace_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); + struct vb2_queue *vq; + int ret; + + ret = deinterlace_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) + return -EBUSY; + + ctx->src_fmt = f->fmt.pix; + + /* Propagate colorspace information to capture. */ + ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; + ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; + ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->dst_fmt.quantization = f->fmt.pix.quantization; + + return 0; +} + +static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { + .vidioc_querycap = deinterlace_querycap, + + .vidioc_enum_framesizes = deinterlace_enum_framesizes, + + .vidioc_enum_fmt_vid_cap = deinterlace_enum_fmt, + .vidioc_g_fmt_vid_cap = deinterlace_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = deinterlace_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = deinterlace_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = deinterlace_enum_fmt, + .vidioc_g_fmt_vid_out = deinterlace_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = deinterlace_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = deinterlace_s_fmt_vid_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, +}; + +static int deinterlace_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix_fmt; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + pix_fmt = &ctx->src_fmt; + else + pix_fmt = &ctx->dst_fmt; + + if (*nplanes) { + if (sizes[0] < pix_fmt->sizeimage) + return -EINVAL; + } else { + sizes[0] = pix_fmt->sizeimage; + *nplanes = 1; + } + + return 0; +} + +static int deinterlace_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix_fmt; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + pix_fmt = &ctx->src_fmt; + else + pix_fmt = &ctx->dst_fmt; + + if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage); + + return 0; +} + +static void deinterlace_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static void deinterlace_queue_cleanup(struct vb2_queue *vq, u32 state) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + struct vb2_v4l2_buffer *vbuf; + + do { + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (vbuf) + v4l2_m2m_buf_done(vbuf, state); + } while (vbuf); + + if (V4L2_TYPE_IS_OUTPUT(vq->type) && ctx->prev) + v4l2_m2m_buf_done(ctx->prev, state); +} + +static int deinterlace_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + struct device *dev = ctx->dev->dev; + int ret; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "Failed to enable module\n"); + + goto err_runtime_get; + } + + ctx->first_field = + ctx->src_fmt.field == V4L2_FIELD_INTERLACED_BT; + ctx->field = ctx->first_field; + + ctx->prev = NULL; + ctx->aborting = 0; + + ctx->flag1_buf = dma_alloc_coherent(dev, FLAG_SIZE, + &ctx->flag1_buf_dma, + GFP_KERNEL); + if (!ctx->flag1_buf) { + ret = -ENOMEM; + + goto err_no_mem1; + } + + ctx->flag2_buf = dma_alloc_coherent(dev, FLAG_SIZE, + &ctx->flag2_buf_dma, + GFP_KERNEL); + if (!ctx->flag2_buf) { + ret = -ENOMEM; + + goto err_no_mem2; + } + } + + return 0; + +err_no_mem2: + dma_free_coherent(dev, FLAG_SIZE, ctx->flag1_buf, + ctx->flag1_buf_dma); +err_no_mem1: + pm_runtime_put(dev); +err_runtime_get: + deinterlace_queue_cleanup(vq, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void deinterlace_stop_streaming(struct vb2_queue *vq) +{ + struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + struct device *dev = ctx->dev->dev; + + dma_free_coherent(dev, FLAG_SIZE, ctx->flag1_buf, + ctx->flag1_buf_dma); + dma_free_coherent(dev, FLAG_SIZE, ctx->flag2_buf, + ctx->flag2_buf_dma); + + pm_runtime_put(dev); + } + + deinterlace_queue_cleanup(vq, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops deinterlace_qops = { + .queue_setup = deinterlace_queue_setup, + .buf_prepare = deinterlace_buf_prepare, + .buf_queue = deinterlace_buf_queue, + .start_streaming = deinterlace_start_streaming, + .stop_streaming = deinterlace_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct deinterlace_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->min_buffers_needed = 1; + src_vq->ops = &deinterlace_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->dev_mutex; + src_vq->dev = ctx->dev->dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->min_buffers_needed = 2; + dst_vq->ops = &deinterlace_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->dev->dev_mutex; + dst_vq->dev = ctx->dev->dev; + + ret = vb2_queue_init(dst_vq); + if (ret) + return ret; + + return 0; +} + +static int deinterlace_open(struct file *file) +{ + struct deinterlace_dev *dev = video_drvdata(file); + struct deinterlace_ctx *ctx = NULL; + int ret; + + if (mutex_lock_interruptible(&dev->dev_mutex)) + return -ERESTARTSYS; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + mutex_unlock(&dev->dev_mutex); + return -ENOMEM; + } + + /* default output format */ + ctx->src_fmt.pixelformat = deinterlace_formats[0]; + ctx->src_fmt.field = V4L2_FIELD_INTERLACED; + ctx->src_fmt.width = 640; + ctx->src_fmt.height = 480; + deinterlace_prepare_format(&ctx->src_fmt); + + /* default capture format */ + ctx->dst_fmt.pixelformat = deinterlace_formats[0]; + ctx->dst_fmt.field = V4L2_FIELD_NONE; + ctx->dst_fmt.width = 640; + ctx->dst_fmt.height = 480; + deinterlace_prepare_format(&ctx->dst_fmt); + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + ctx->dev = dev; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, + &deinterlace_queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto err_free; + } + + v4l2_fh_add(&ctx->fh); + + mutex_unlock(&dev->dev_mutex); + + return 0; + +err_free: + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + + return ret; +} + +static int deinterlace_release(struct file *file) +{ + struct deinterlace_dev *dev = video_drvdata(file); + struct deinterlace_ctx *ctx = container_of(file->private_data, + struct deinterlace_ctx, fh); + + mutex_lock(&dev->dev_mutex); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + kfree(ctx); + + mutex_unlock(&dev->dev_mutex); + + return 0; +} + +static const struct v4l2_file_operations deinterlace_fops = { + .owner = THIS_MODULE, + .open = deinterlace_open, + .release = deinterlace_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device deinterlace_video_device = { + .name = DEINTERLACE_NAME, + .vfl_dir = VFL_DIR_M2M, + .fops = &deinterlace_fops, + .ioctl_ops = &deinterlace_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +static const struct v4l2_m2m_ops deinterlace_m2m_ops = { + .device_run = deinterlace_device_run, + .job_ready = deinterlace_job_ready, + .job_abort = deinterlace_job_abort, +}; + +static int deinterlace_probe(struct platform_device *pdev) +{ + struct deinterlace_dev *dev; + struct video_device *vfd; + struct resource *res; + int irq, ret; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->vfd = deinterlace_video_device; + dev->dev = &pdev->dev; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) { + dev_err(dev->dev, "Failed to get IRQ\n"); + + return irq; + } + + ret = devm_request_irq(dev->dev, irq, deinterlace_irq, + 0, dev_name(dev->dev), dev); + if (ret) { + dev_err(dev->dev, "Failed to request IRQ\n"); + + return ret; + } + + ret = of_dma_configure(dev->dev, dev->dev->of_node, true); + if (ret) + return ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dev->base)) { + dev_err(dev->dev, "Failed to map registers\n"); + + return PTR_ERR(dev->base); + } + + dev->bus_clk = devm_clk_get(dev->dev, "bus"); + if (IS_ERR(dev->bus_clk)) { + dev_err(dev->dev, "Failed to get bus clock\n"); + + return PTR_ERR(dev->bus_clk); + } + + dev->mod_clk = devm_clk_get(dev->dev, "mod"); + if (IS_ERR(dev->mod_clk)) { + dev_err(dev->dev, "Failed to get mod clock\n"); + + return PTR_ERR(dev->mod_clk); + } + + dev->ram_clk = devm_clk_get(dev->dev, "ram"); + if (IS_ERR(dev->ram_clk)) { + dev_err(dev->dev, "Failed to get ram clock\n"); + + return PTR_ERR(dev->ram_clk); + } + + dev->rstc = devm_reset_control_get(dev->dev, NULL); + if (IS_ERR(dev->rstc)) { + dev_err(dev->dev, "Failed to get reset control\n"); + + return PTR_ERR(dev->rstc); + } + + mutex_init(&dev->dev_mutex); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + dev_err(dev->dev, "Failed to register V4L2 device\n"); + + return ret; + } + + vfd = &dev->vfd; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + + snprintf(vfd->name, sizeof(vfd->name), "%s", + deinterlace_video_device.name); + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + + goto err_v4l2; + } + + v4l2_info(&dev->v4l2_dev, + "Device registered as /dev/video%d\n", vfd->num); + + dev->m2m_dev = v4l2_m2m_init(&deinterlace_m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, + "Failed to initialize V4L2 M2M device\n"); + ret = PTR_ERR(dev->m2m_dev); + + goto err_video; + } + + platform_set_drvdata(pdev, dev); + + pm_runtime_enable(dev->dev); + + return 0; + +err_video: + video_unregister_device(&dev->vfd); +err_v4l2: + v4l2_device_unregister(&dev->v4l2_dev); + + return ret; +} + +static int deinterlace_remove(struct platform_device *pdev) +{ + struct deinterlace_dev *dev = platform_get_drvdata(pdev); + + v4l2_m2m_release(dev->m2m_dev); + video_unregister_device(&dev->vfd); + v4l2_device_unregister(&dev->v4l2_dev); + + pm_runtime_force_suspend(&pdev->dev); + + return 0; +} + +static int deinterlace_runtime_resume(struct device *device) +{ + struct deinterlace_dev *dev = dev_get_drvdata(device); + int ret; + + ret = clk_set_rate_exclusive(dev->mod_clk, 300000000); + if (ret) { + dev_err(dev->dev, "Failed to set exclusive mod clock rate\n"); + + return ret; + } + + ret = clk_prepare_enable(dev->bus_clk); + if (ret) { + dev_err(dev->dev, "Failed to enable bus clock\n"); + + goto err_exlusive_rate; + } + + ret = clk_prepare_enable(dev->mod_clk); + if (ret) { + dev_err(dev->dev, "Failed to enable mod clock\n"); + + goto err_bus_clk; + } + + ret = clk_prepare_enable(dev->ram_clk); + if (ret) { + dev_err(dev->dev, "Failed to enable ram clock\n"); + + goto err_mod_clk; + } + + ret = reset_control_deassert(dev->rstc); + if (ret) { + dev_err(dev->dev, "Failed to apply reset\n"); + + goto err_ram_clk; + } + + deinterlace_init(dev); + + return 0; + +err_exlusive_rate: + clk_rate_exclusive_put(dev->mod_clk); +err_ram_clk: + clk_disable_unprepare(dev->ram_clk); +err_mod_clk: + clk_disable_unprepare(dev->mod_clk); +err_bus_clk: + clk_disable_unprepare(dev->bus_clk); + + return ret; +} + +static int deinterlace_runtime_suspend(struct device *device) +{ + struct deinterlace_dev *dev = dev_get_drvdata(device); + + reset_control_assert(dev->rstc); + + clk_disable_unprepare(dev->ram_clk); + clk_disable_unprepare(dev->mod_clk); + clk_disable_unprepare(dev->bus_clk); + clk_rate_exclusive_put(dev->mod_clk); + + return 0; +} + +static const struct of_device_id deinterlace_dt_match[] = { + { .compatible = "allwinner,sun8i-h3-deinterlace" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, deinterlace_dt_match); + +static const struct dev_pm_ops deinterlace_pm_ops = { + .runtime_resume = deinterlace_runtime_resume, + .runtime_suspend = deinterlace_runtime_suspend, +}; + +static struct platform_driver deinterlace_driver = { + .probe = deinterlace_probe, + .remove = deinterlace_remove, + .driver = { + .name = DEINTERLACE_NAME, + .of_match_table = deinterlace_dt_match, + .pm = &deinterlace_pm_ops, + }, +}; +module_platform_driver(deinterlace_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>"); +MODULE_DESCRIPTION("Allwinner Deinterlace driver"); diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h new file mode 100644 index 000000000000..0254251d8687 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Allwinner Deinterlace driver + * + * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@siol.net> + */ + +#ifndef _SUN8I_DEINTERLACE_H_ +#define _SUN8I_DEINTERLACE_H_ + +#include <media/v4l2-device.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-v4l2.h> +#include <media/videobuf2-dma-contig.h> + +#include <linux/platform_device.h> + +#define DEINTERLACE_NAME "sun8i-di" + +#define DEINTERLACE_MOD_ENABLE 0x00 +#define DEINTERLACE_MOD_ENABLE_EN BIT(0) + +#define DEINTERLACE_FRM_CTRL 0x04 +#define DEINTERLACE_FRM_CTRL_REG_READY BIT(0) +#define DEINTERLACE_FRM_CTRL_WB_EN BIT(2) +#define DEINTERLACE_FRM_CTRL_OUT_CTRL BIT(11) +#define DEINTERLACE_FRM_CTRL_START BIT(16) +#define DEINTERLACE_FRM_CTRL_COEF_ACCESS BIT(23) + +#define DEINTERLACE_BYPASS 0x08 +#define DEINTERLACE_BYPASS_CSC BIT(1) + +#define DEINTERLACE_AGTH_SEL 0x0c +#define DEINTERLACE_AGTH_SEL_LINEBUF BIT(8) + +#define DEINTERLACE_LINT_CTRL 0x10 +#define DEINTERLACE_TRD_PRELUMA 0x1c +#define DEINTERLACE_BUF_ADDR0 0x20 +#define DEINTERLACE_BUF_ADDR1 0x24 +#define DEINTERLACE_BUF_ADDR2 0x28 + +#define DEINTERLACE_FIELD_CTRL 0x2c +#define DEINTERLACE_FIELD_CTRL_FIELD_CNT(v) ((v) & 0xff) +#define DEINTERLACE_FIELD_CTRL_FIELD_CNT_MSK (0xff) + +#define DEINTERLACE_TB_OFFSET0 0x30 +#define DEINTERLACE_TB_OFFSET1 0x34 +#define DEINTERLACE_TB_OFFSET2 0x38 +#define DEINTERLACE_TRD_PRECHROMA 0x3c +#define DEINTERLACE_LINE_STRIDE0 0x40 +#define DEINTERLACE_LINE_STRIDE1 0x44 +#define DEINTERLACE_LINE_STRIDE2 0x48 + +#define DEINTERLACE_IN_FMT 0x4c +#define DEINTERLACE_IN_FMT_PS(v) ((v) & 3) +#define DEINTERLACE_IN_FMT_FMT(v) (((v) & 7) << 4) +#define DEINTERLACE_IN_FMT_MOD(v) (((v) & 7) << 8) + +#define DEINTERLACE_WB_ADDR0 0x50 +#define DEINTERLACE_WB_ADDR1 0x54 +#define DEINTERLACE_WB_ADDR2 0x58 + +#define DEINTERLACE_OUT_FMT 0x5c +#define DEINTERLACE_OUT_FMT_FMT(v) ((v) & 0xf) +#define DEINTERLACE_OUT_FMT_PS(v) (((v) & 3) << 5) + +#define DEINTERLACE_INT_ENABLE 0x60 +#define DEINTERLACE_INT_ENABLE_WB_EN BIT(7) + +#define DEINTERLACE_INT_STATUS 0x64 +#define DEINTERLACE_INT_STATUS_WRITEBACK BIT(7) + +#define DEINTERLACE_STATUS 0x68 +#define DEINTERLACE_STATUS_COEF_STATUS BIT(11) +#define DEINTERLACE_STATUS_WB_ERROR BIT(12) + +#define DEINTERLACE_CSC_COEF 0x70 /* 12 registers */ + +#define DEINTERLACE_CTRL 0xa0 +#define DEINTERLACE_CTRL_EN BIT(0) +#define DEINTERLACE_CTRL_FLAG_OUT_EN BIT(8) +#define DEINTERLACE_CTRL_MODE_PASSTROUGH (0 << 16) +#define DEINTERLACE_CTRL_MODE_WEAVE (1 << 16) +#define DEINTERLACE_CTRL_MODE_BOB (2 << 16) +#define DEINTERLACE_CTRL_MODE_MIXED (3 << 16) +#define DEINTERLACE_CTRL_DIAG_INTP_EN BIT(24) +#define DEINTERLACE_CTRL_TEMP_DIFF_EN BIT(25) + +#define DEINTERLACE_DIAG_INTP 0xa4 +#define DEINTERLACE_DIAG_INTP_TH0(v) ((v) & 0x7f) +#define DEINTERLACE_DIAG_INTP_TH0_MSK (0x7f) +#define DEINTERLACE_DIAG_INTP_TH1(v) (((v) & 0x7f) << 8) +#define DEINTERLACE_DIAG_INTP_TH1_MSK (0x7f << 8) +#define DEINTERLACE_DIAG_INTP_TH3(v) (((v) & 0xff) << 24) +#define DEINTERLACE_DIAG_INTP_TH3_MSK (0xff << 24) + +#define DEINTERLACE_TEMP_DIFF 0xa8 +#define DEINTERLACE_TEMP_DIFF_SAD_CENTRAL_TH(v) ((v) & 0x7f) +#define DEINTERLACE_TEMP_DIFF_SAD_CENTRAL_TH_MSK (0x7f) +#define DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH(v) (((v) & 0x7f) << 8) +#define DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH_MSK (0x7f << 8) +#define DEINTERLACE_TEMP_DIFF_DIRECT_DITHER_TH(v) (((v) & 0x7ff) << 16) +#define DEINTERLACE_TEMP_DIFF_DIRECT_DITHER_TH_MSK (0x7ff << 16) + +#define DEINTERLACE_LUMA_TH 0xac +#define DEINTERLACE_LUMA_TH_MIN_LUMA(v) ((v) & 0xff) +#define DEINTERLACE_LUMA_TH_MIN_LUMA_MSK (0xff) +#define DEINTERLACE_LUMA_TH_MAX_LUMA(v) (((v) & 0xff) << 8) +#define DEINTERLACE_LUMA_TH_MAX_LUMA_MSK (0xff << 8) +#define DEINTERLACE_LUMA_TH_AVG_LUMA_SHIFT(v) (((v) & 0xff) << 16) +#define DEINTERLACE_LUMA_TH_AVG_LUMA_SHIFT_MSK (0xff << 16) +#define DEINTERLACE_LUMA_TH_PIXEL_STATIC(v) (((v) & 3) << 24) +#define DEINTERLACE_LUMA_TH_PIXEL_STATIC_MSK (3 << 24) + +#define DEINTERLACE_SPAT_COMP 0xb0 +#define DEINTERLACE_SPAT_COMP_TH2(v) ((v) & 0xff) +#define DEINTERLACE_SPAT_COMP_TH2_MSK (0xff) +#define DEINTERLACE_SPAT_COMP_TH3(v) (((v) & 0xff) << 16) +#define DEINTERLACE_SPAT_COMP_TH3_MSK (0xff << 16) + +#define DEINTERLACE_CHROMA_DIFF 0xb4 +#define DEINTERLACE_CHROMA_DIFF_TH(v) ((v) & 0xff) +#define DEINTERLACE_CHROMA_DIFF_TH_MSK (0xff) +#define DEINTERLACE_CHROMA_DIFF_LUMA(v) (((v) & 0x3f) << 16) +#define DEINTERLACE_CHROMA_DIFF_LUMA_MSK (0x3f << 16) +#define DEINTERLACE_CHROMA_DIFF_CHROMA(v) (((v) & 0x3f) << 24) +#define DEINTERLACE_CHROMA_DIFF_CHROMA_MSK (0x3f << 24) + +#define DEINTERLACE_PRELUMA 0xb8 +#define DEINTERLACE_PRECHROMA 0xbc +#define DEINTERLACE_TILE_FLAG0 0xc0 +#define DEINTERLACE_TILE_FLAG1 0xc4 +#define DEINTERLACE_FLAG_LINE_STRIDE 0xc8 +#define DEINTERLACE_FLAG_SEQ 0xcc + +#define DEINTERLACE_WB_LINE_STRIDE_CTRL 0xd0 +#define DEINTERLACE_WB_LINE_STRIDE_CTRL_EN BIT(0) + +#define DEINTERLACE_WB_LINE_STRIDE0 0xd4 +#define DEINTERLACE_WB_LINE_STRIDE1 0xd8 +#define DEINTERLACE_WB_LINE_STRIDE2 0xdc +#define DEINTERLACE_TRD_CTRL 0xe0 +#define DEINTERLACE_TRD_BUF_ADDR0 0xe4 +#define DEINTERLACE_TRD_BUF_ADDR1 0xe8 +#define DEINTERLACE_TRD_BUF_ADDR2 0xec +#define DEINTERLACE_TRD_TB_OFF0 0xf0 +#define DEINTERLACE_TRD_TB_OFF1 0xf4 +#define DEINTERLACE_TRD_TB_OFF2 0xf8 +#define DEINTERLACE_TRD_WB_STRIDE 0xfc +#define DEINTERLACE_CH0_IN_SIZE 0x100 +#define DEINTERLACE_CH0_OUT_SIZE 0x104 +#define DEINTERLACE_CH0_HORZ_FACT 0x108 +#define DEINTERLACE_CH0_VERT_FACT 0x10c +#define DEINTERLACE_CH0_HORZ_PHASE 0x110 +#define DEINTERLACE_CH0_VERT_PHASE0 0x114 +#define DEINTERLACE_CH0_VERT_PHASE1 0x118 +#define DEINTERLACE_CH0_HORZ_TAP0 0x120 +#define DEINTERLACE_CH0_HORZ_TAP1 0x124 +#define DEINTERLACE_CH0_VERT_TAP 0x128 +#define DEINTERLACE_CH1_IN_SIZE 0x200 +#define DEINTERLACE_CH1_OUT_SIZE 0x204 +#define DEINTERLACE_CH1_HORZ_FACT 0x208 +#define DEINTERLACE_CH1_VERT_FACT 0x20c +#define DEINTERLACE_CH1_HORZ_PHASE 0x210 +#define DEINTERLACE_CH1_VERT_PHASE0 0x214 +#define DEINTERLACE_CH1_VERT_PHASE1 0x218 +#define DEINTERLACE_CH1_HORZ_TAP0 0x220 +#define DEINTERLACE_CH1_HORZ_TAP1 0x224 +#define DEINTERLACE_CH1_VERT_TAP 0x228 +#define DEINTERLACE_CH0_HORZ_COEF0 0x400 /* 32 registers */ +#define DEINTERLACE_CH0_HORZ_COEF1 0x480 /* 32 registers */ +#define DEINTERLACE_CH0_VERT_COEF 0x500 /* 32 registers */ +#define DEINTERLACE_CH1_HORZ_COEF0 0x600 /* 32 registers */ +#define DEINTERLACE_CH1_HORZ_COEF1 0x680 /* 32 registers */ +#define DEINTERLACE_CH1_VERT_COEF 0x700 /* 32 registers */ +#define DEINTERLACE_CH3_HORZ_COEF0 0x800 /* 32 registers */ +#define DEINTERLACE_CH3_HORZ_COEF1 0x880 /* 32 registers */ +#define DEINTERLACE_CH3_VERT_COEF 0x900 /* 32 registers */ + +#define DEINTERLACE_MIN_WIDTH 2U +#define DEINTERLACE_MIN_HEIGHT 2U +#define DEINTERLACE_MAX_WIDTH 2048U +#define DEINTERLACE_MAX_HEIGHT 1100U + +#define DEINTERLACE_MODE_UV_COMBINED 2 + +#define DEINTERLACE_IN_FMT_YUV420 2 + +#define DEINTERLACE_OUT_FMT_YUV420SP 13 + +#define DEINTERLACE_PS_UVUV 0 +#define DEINTERLACE_PS_VUVU 1 + +#define DEINTERLACE_IDENTITY_COEF 0x4000 + +#define DEINTERLACE_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1)) + +struct deinterlace_ctx { + struct v4l2_fh fh; + struct deinterlace_dev *dev; + + struct v4l2_pix_format src_fmt; + struct v4l2_pix_format dst_fmt; + + void *flag1_buf; + dma_addr_t flag1_buf_dma; + + void *flag2_buf; + dma_addr_t flag2_buf_dma; + + struct vb2_v4l2_buffer *prev; + + unsigned int first_field; + unsigned int field; + + int aborting; +}; + +struct deinterlace_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; + struct device *dev; + struct v4l2_m2m_dev *m2m_dev; + + /* Device file mutex */ + struct mutex dev_mutex; + + void __iomem *base; + + struct clk *bus_clk; + struct clk *mod_clk; + struct clk *ram_clk; + + struct reset_control *rstc; +}; + +#endif diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c index eda2a5985da7..834114a4eebe 100644 --- a/drivers/media/platform/ti-vpe/csc.c +++ b/drivers/media/platform/ti-vpe/csc.c @@ -15,76 +15,96 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/videodev2.h> +#include <media/v4l2-common.h> #include "csc.h" /* - * 16 coefficients in the order: + * 12 coefficients in the order: * a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2 - * (we may need to pass non-default values from user space later on, we might - * need to make the coefficient struct more easy to populate) */ -struct colorspace_coeffs { - u16 sd[12]; - u16 hd[12]; +struct quantization { + u16 coeff[12]; }; -/* VIDEO_RANGE: limited range, GRAPHICS_RANGE: full range */ -#define CSC_COEFFS_VIDEO_RANGE_Y2R 0 -#define CSC_COEFFS_GRAPHICS_RANGE_Y2R 1 -#define CSC_COEFFS_VIDEO_RANGE_R2Y 2 -#define CSC_COEFFS_GRAPHICS_RANGE_R2Y 3 +struct colorspace { + struct quantization limited; + struct quantization full; +}; + +struct encoding_direction { + struct colorspace r601; + struct colorspace r709; +}; + +struct csc_coeffs { + struct encoding_direction y2r; + struct encoding_direction r2y; +}; /* default colorspace coefficients */ -static struct colorspace_coeffs colorspace_coeffs[4] = { - [CSC_COEFFS_VIDEO_RANGE_Y2R] = { - { - /* SDTV */ - 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35, - 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88, +static struct csc_coeffs csc_coeffs = { + .y2r = { + .r601 = { + .limited = { + { /* SDTV */ + 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35, + 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88, + } + }, + .full = { + { /* SDTV */ + 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF, + 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC, + } + }, }, - { - /* HDTV */ - 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B, - 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60, + .r709 = { + .limited = { + { /* HDTV */ + 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B, + 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60, + } + }, + .full = { + { /* HDTV */ + 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, + 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, + } + }, }, }, - [CSC_COEFFS_GRAPHICS_RANGE_Y2R] = { - { - /* SDTV */ - 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF, - 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC, + .r2y = { + .r601 = { + .limited = { + { /* SDTV */ + 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B, + 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200, + } + }, + .full = { + { /* SDTV */ + 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2, + 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200, + } + }, }, - { - /* HDTV */ - 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, - 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, - }, - }, - [CSC_COEFFS_VIDEO_RANGE_R2Y] = { - { - /* SDTV */ - 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B, - 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200, - }, - { - /* HDTV */ - 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C, - 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200, - }, - }, - [CSC_COEFFS_GRAPHICS_RANGE_R2Y] = { - { - /* SDTV */ - 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2, - 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200, - }, - { - /* HDTV */ - 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE, - 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C, + .r709 = { + .limited = { + { /* HDTV */ + 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C, + 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200, + } + }, + .full = { + { /* HDTV */ + 0x00bb, 0x0275, 0x003f, 0x1f99, 0x1ea5, 0x01c2, + 0x01c2, 0x1e67, 0x1fd7, 0x0040, 0x0200, 0x0200, + } + }, }, }, + }; void csc_dump_regs(struct csc_data *csc) @@ -117,46 +137,114 @@ EXPORT_SYMBOL(csc_set_coeff_bypass); * set the color space converter coefficient shadow register values */ void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, - enum v4l2_colorspace src_colorspace, - enum v4l2_colorspace dst_colorspace) + struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt) { u32 *csc_reg5 = csc_reg0 + 5; u32 *shadow_csc = csc_reg0; - struct colorspace_coeffs *sd_hd_coeffs; u16 *coeff, *end_coeff; - enum v4l2_colorspace yuv_colorspace; - int sel = 0; - - /* - * support only graphics data range(full range) for now, a control ioctl - * would be nice here - */ - /* Y2R */ - if (dst_colorspace == V4L2_COLORSPACE_SRGB && - (src_colorspace == V4L2_COLORSPACE_SMPTE170M || - src_colorspace == V4L2_COLORSPACE_REC709)) { + const struct v4l2_pix_format *pix; + const struct v4l2_pix_format_mplane *mp; + const struct v4l2_format_info *src_finfo, *dst_finfo; + enum v4l2_ycbcr_encoding src_ycbcr_enc, dst_ycbcr_enc; + enum v4l2_quantization src_quantization, dst_quantization; + u32 src_pixelformat, dst_pixelformat; + + switch (src_fmt->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &src_fmt->fmt.pix; + src_pixelformat = pix->pixelformat; + src_ycbcr_enc = pix->ycbcr_enc; + src_quantization = pix->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + default: + mp = &src_fmt->fmt.pix_mp; + src_pixelformat = mp->pixelformat; + src_ycbcr_enc = mp->ycbcr_enc; + src_quantization = mp->quantization; + break; + } + + switch (dst_fmt->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &dst_fmt->fmt.pix; + dst_pixelformat = pix->pixelformat; + dst_ycbcr_enc = pix->ycbcr_enc; + dst_quantization = pix->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + default: + mp = &dst_fmt->fmt.pix_mp; + dst_pixelformat = mp->pixelformat; + dst_ycbcr_enc = mp->ycbcr_enc; + dst_quantization = mp->quantization; + break; + } + + src_finfo = v4l2_format_info(src_pixelformat); + dst_finfo = v4l2_format_info(dst_pixelformat); + + if (v4l2_is_format_yuv(src_finfo) && + v4l2_is_format_rgb(dst_finfo)) { /* Y2R */ - sel = 1; - yuv_colorspace = src_colorspace; - } else if ((dst_colorspace == V4L2_COLORSPACE_SMPTE170M || - dst_colorspace == V4L2_COLORSPACE_REC709) && - src_colorspace == V4L2_COLORSPACE_SRGB) { + + /* + * These are not the standard default values but are + * set this way for historical compatibility + */ + if (src_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + src_ycbcr_enc = V4L2_YCBCR_ENC_601; + + if (src_quantization == V4L2_QUANTIZATION_DEFAULT) + src_quantization = V4L2_QUANTIZATION_FULL_RANGE; + + if (src_ycbcr_enc == V4L2_YCBCR_ENC_601) { + if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.y2r.r601.full.coeff; + else + coeff = csc_coeffs.y2r.r601.limited.coeff; + } else if (src_ycbcr_enc == V4L2_YCBCR_ENC_709) { + if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.y2r.r709.full.coeff; + else + coeff = csc_coeffs.y2r.r709.limited.coeff; + } else { + /* Should never reach this, but it keeps gcc happy */ + coeff = csc_coeffs.y2r.r601.full.coeff; + } + } else if (v4l2_is_format_rgb(src_finfo) && + v4l2_is_format_yuv(dst_finfo)) { /* R2Y */ - sel = 3; - yuv_colorspace = dst_colorspace; + + /* + * These are not the standard default values but are + * set this way for historical compatibility + */ + if (dst_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + dst_ycbcr_enc = V4L2_YCBCR_ENC_601; + + if (dst_quantization == V4L2_QUANTIZATION_DEFAULT) + dst_quantization = V4L2_QUANTIZATION_FULL_RANGE; + + if (dst_ycbcr_enc == V4L2_YCBCR_ENC_601) { + if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.r2y.r601.full.coeff; + else + coeff = csc_coeffs.r2y.r601.limited.coeff; + } else if (dst_ycbcr_enc == V4L2_YCBCR_ENC_709) { + if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE) + coeff = csc_coeffs.r2y.r709.full.coeff; + else + coeff = csc_coeffs.r2y.r709.limited.coeff; + } else { + /* Should never reach this, but it keeps gcc happy */ + coeff = csc_coeffs.r2y.r601.full.coeff; + } } else { *csc_reg5 |= CSC_BYPASS; return; } - sd_hd_coeffs = &colorspace_coeffs[sel]; - - /* select between SD or HD coefficients */ - if (yuv_colorspace == V4L2_COLORSPACE_SMPTE170M) - coeff = sd_hd_coeffs->sd; - else - coeff = sd_hd_coeffs->hd; - end_coeff = coeff + 12; for (; coeff < end_coeff; coeff += 2) diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h index de9a58af2ca8..af2e86bccf57 100644 --- a/drivers/media/platform/ti-vpe/csc.h +++ b/drivers/media/platform/ti-vpe/csc.h @@ -58,8 +58,8 @@ struct csc_data { void csc_dump_regs(struct csc_data *csc); void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5); void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, - enum v4l2_colorspace src_colorspace, - enum v4l2_colorspace dst_colorspace); + struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt); + struct csc_data *csc_create(struct platform_device *pdev, const char *res_name); #endif diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 53d27cd6e10a..2e5148ae7a0f 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -56,6 +56,11 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = { .data_type = DATA_TYPE_C420, .depth = 4, }, + [VPDMA_DATA_FMT_CB420] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CB420, + .depth = 4, + }, [VPDMA_DATA_FMT_YCR422] = { .type = VPDMA_DATA_FMT_TYPE_YUV, .data_type = DATA_TYPE_YCR422, @@ -759,7 +764,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) pr_debug("word1: line_length = %d, xfer_height = %d\n", dtd_get_line_length(dtd), dtd_get_xfer_height(dtd)); - pr_debug("word2: start_addr = %pad\n", &dtd->start_addr); + pr_debug("word2: start_addr = %x\n", dtd->start_addr); pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n", dtd_get_pkt_type(dtd), @@ -825,7 +830,8 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, channel = next_chan = raw_vpdma_chan; if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && - fmt->data_type == DATA_TYPE_C420) { + (fmt->data_type == DATA_TYPE_C420 || + fmt->data_type == DATA_TYPE_CB420)) { rect.height >>= 1; rect.top >>= 1; depth = 8; @@ -893,7 +899,8 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, channel = next_chan = chan_info[chan].num; if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && - fmt->data_type == DATA_TYPE_C420) { + (fmt->data_type == DATA_TYPE_C420 || + fmt->data_type == DATA_TYPE_CB420)) { rect.height >>= 1; rect.top >>= 1; depth = 8; diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 28bc94129348..393fcbb3cb40 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -57,6 +57,7 @@ struct vpdma_data_format { * line stride of source and dest * buffers should be 16 byte aligned */ +#define VPDMA_MAX_STRIDE 65520 /* Max line stride 16 byte aligned */ #define VPDMA_DTD_DESC_SIZE 32 /* 8 words */ #define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */ @@ -71,6 +72,7 @@ enum vpdma_yuv_formats { VPDMA_DATA_FMT_C444, VPDMA_DATA_FMT_C422, VPDMA_DATA_FMT_C420, + VPDMA_DATA_FMT_CB420, VPDMA_DATA_FMT_YCR422, VPDMA_DATA_FMT_YC444, VPDMA_DATA_FMT_CRY422, diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index c488609bc162..0bbee45338bd 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -92,6 +92,7 @@ #define DATA_TYPE_C444 0x4 #define DATA_TYPE_C422 0x5 #define DATA_TYPE_C420 0x6 +#define DATA_TYPE_CB420 0x16 #define DATA_TYPE_YC444 0x8 #define DATA_TYPE_YCB422 0x7 #define DATA_TYPE_YCR422 0x17 @@ -165,11 +166,11 @@ struct vpdma_dtd { u32 xfer_length_height; u32 w1; }; - dma_addr_t start_addr; + u32 start_addr; u32 pkt_ctl; union { u32 frame_width_height; /* inbound */ - dma_addr_t desc_write_addr; /* outbound */ + u32 desc_write_addr; /* outbound */ }; union { u32 start_h_v; /* inbound */ diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 60b575bb44c4..65c2c048b018 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -52,7 +52,7 @@ #define MIN_W 32 #define MIN_H 32 #define MAX_W 2048 -#define MAX_H 1184 +#define MAX_H 2048 /* required alignments */ #define S_ALIGN 0 /* multiple of 1 */ @@ -249,6 +249,14 @@ static struct vpe_fmt vpe_formats[] = { }, }, { + .fourcc = V4L2_PIX_FMT_NV21, + .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, + .coplanar = 1, + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420], + &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420], + }, + }, + { .fourcc = V4L2_PIX_FMT_YUYV, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 0, @@ -311,14 +319,9 @@ static struct vpe_fmt vpe_formats[] = { * there is one source queue and one destination queue for each m2m context. */ struct vpe_q_data { - unsigned int width; /* frame width */ - unsigned int height; /* frame height */ - unsigned int nplanes; /* Current number of planes */ - unsigned int bytesperline[VPE_MAX_PLANES]; /* bytes per line in memory */ - enum v4l2_colorspace colorspace; - enum v4l2_field field; /* supported field value */ + /* current v4l2 format info */ + struct v4l2_format format; unsigned int flags; - unsigned int sizeimage[VPE_MAX_PLANES]; /* image size in memory */ struct v4l2_rect c_rect; /* crop/compose rectangle */ struct vpe_fmt *fmt; /* format info */ }; @@ -328,9 +331,14 @@ struct vpe_q_data { #define Q_DATA_MODE_TILED BIT(1) #define Q_DATA_INTERLACED_ALTERNATE BIT(2) #define Q_DATA_INTERLACED_SEQ_TB BIT(3) +#define Q_DATA_INTERLACED_SEQ_BT BIT(4) + +#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \ + Q_DATA_INTERLACED_SEQ_BT) #define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \ - Q_DATA_INTERLACED_SEQ_TB) + Q_DATA_INTERLACED_SEQ_TB | \ + Q_DATA_INTERLACED_SEQ_BT) enum { Q_DATA_SRC = 0, @@ -338,20 +346,25 @@ enum { }; /* find our format description corresponding to the passed v4l2_format */ -static struct vpe_fmt *find_format(struct v4l2_format *f) +static struct vpe_fmt *__find_format(u32 fourcc) { struct vpe_fmt *fmt; unsigned int k; for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) { fmt = &vpe_formats[k]; - if (fmt->fourcc == f->fmt.pix.pixelformat) + if (fmt->fourcc == fourcc) return fmt; } return NULL; } +static struct vpe_fmt *find_format(struct v4l2_format *f) +{ + return __find_format(f->fmt.pix.pixelformat); +} + /* * there is one vpe_dev structure in the driver, it is shared by * all instances. @@ -681,7 +694,8 @@ static void set_cfg_modes(struct vpe_ctx *ctx) * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing. */ - if (fmt->fourcc == V4L2_PIX_FMT_NV12) + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) cfg_mode = 0; write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); @@ -696,7 +710,8 @@ static void set_line_modes(struct vpe_ctx *ctx) struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; int line_mode = 1; - if (fmt->fourcc == V4L2_PIX_FMT_NV12) + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) line_mode = 0; /* double lines to line buffer */ /* regs for now */ @@ -741,11 +756,12 @@ static void set_src_registers(struct vpe_ctx *ctx) static void set_dst_registers(struct vpe_ctx *ctx) { struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; - enum v4l2_colorspace clrspc = ctx->q_data[Q_DATA_DST].colorspace; struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; + const struct v4l2_format_info *finfo; u32 val = 0; - if (clrspc == V4L2_COLORSPACE_SRGB) { + finfo = v4l2_format_info(fmt->fourcc); + if (v4l2_is_format_rgb(finfo)) { val |= VPE_RGB_OUT_SELECT; vpdma_set_bg_color(ctx->dev->vpdma, (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff); @@ -758,7 +774,8 @@ static void set_dst_registers(struct vpe_ctx *ctx) */ val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER; - if (fmt->fourcc != V4L2_PIX_FMT_NV12) + if (fmt->fourcc != V4L2_PIX_FMT_NV12 && + fmt->fourcc != V4L2_PIX_FMT_NV21) val |= VPE_DS_BYPASS; mmr_adb->out_fmt_reg[0] = val; @@ -847,11 +864,13 @@ static int set_srcdst_params(struct vpe_ctx *ctx) unsigned int src_h = s_q_data->c_rect.height; unsigned int dst_w = d_q_data->c_rect.width; unsigned int dst_h = d_q_data->c_rect.height; + struct v4l2_pix_format_mplane *spix; size_t mv_buf_size; int ret; ctx->sequence = 0; ctx->field = V4L2_FIELD_TOP; + spix = &s_q_data->format.fmt.pix_mp; if ((s_q_data->flags & Q_IS_INTERLACED) && !(d_q_data->flags & Q_IS_INTERLACED)) { @@ -866,9 +885,9 @@ static int set_srcdst_params(struct vpe_ctx *ctx) * extra space will not be used by the de-interlacer, but will * ensure that vpdma operates correctly */ - bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3, - VPDMA_STRIDE_ALIGN); - mv_buf_size = bytes_per_line * s_q_data->height; + bytes_per_line = ALIGN((spix->width * mv->depth) >> 3, + VPDMA_STRIDE_ALIGN); + mv_buf_size = bytes_per_line * spix->height; ctx->deinterlacing = true; src_h <<= 1; @@ -888,7 +907,7 @@ static int set_srcdst_params(struct vpe_ctx *ctx) set_dei_regs(ctx); csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], - s_q_data->colorspace, d_q_data->colorspace); + &s_q_data->format, &d_q_data->format); sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w); sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h); @@ -901,14 +920,6 @@ static int set_srcdst_params(struct vpe_ctx *ctx) } /* - * Return the vpe_ctx structure for a given struct file - */ -static struct vpe_ctx *file2ctx(struct file *file) -{ - return container_of(file->private_data, struct vpe_ctx, fh); -} - -/* * mem2mem callbacks */ @@ -1010,27 +1021,33 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) struct vpe_fmt *fmt = q_data->fmt; const struct vpdma_data_format *vpdma_fmt; int mv_buf_selector = !ctx->src_mv_buf_selector; + struct v4l2_pix_format_mplane *pix; dma_addr_t dma_addr; u32 flags = 0; u32 offset = 0; + u32 stride; if (port == VPE_PORT_MV_OUT) { vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; dma_addr = ctx->mv_buf_dma[mv_buf_selector]; q_data = &ctx->q_data[Q_DATA_SRC]; + pix = &q_data->format.fmt.pix_mp; + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, + VPDMA_STRIDE_ALIGN); } else { /* to incorporate interleaved formats */ int plane = fmt->coplanar ? p_data->vb_part : 0; + pix = &q_data->format.fmt.pix_mp; vpdma_fmt = fmt->vpdma_fmt[plane]; /* * If we are using a single plane buffer and * we need to set a separate vpdma chroma channel. */ - if (q_data->nplanes == 1 && plane) { + if (pix->num_planes == 1 && plane) { dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); /* Compute required offset */ - offset = q_data->bytesperline[0] * q_data->height; + offset = pix->plane_fmt[0].bytesperline * pix->height; } else { dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); /* Use address as is, no offset */ @@ -1044,6 +1061,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) } /* Apply the offset */ dma_addr += offset; + stride = pix->plane_fmt[VPE_LUMA].bytesperline; } if (q_data->flags & Q_DATA_FRAME_1D) @@ -1054,8 +1072,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, MAX_W, MAX_H); - vpdma_add_out_dtd(&ctx->desc_list, q_data->width, - q_data->bytesperline[VPE_LUMA], &q_data->c_rect, + vpdma_add_out_dtd(&ctx->desc_list, pix->width, + stride, &q_data->c_rect, vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, MAX_OUT_HEIGHT_REG1, p_data->channel, flags); } @@ -1067,6 +1085,7 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf; struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vpe_fmt *fmt = q_data->fmt; + struct v4l2_pix_format_mplane *pix; const struct vpdma_data_format *vpdma_fmt; int mv_buf_selector = ctx->src_mv_buf_selector; int field = vbuf->field == V4L2_FIELD_BOTTOM; @@ -1074,10 +1093,14 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) dma_addr_t dma_addr; u32 flags = 0; u32 offset = 0; + u32 stride; + pix = &q_data->format.fmt.pix_mp; if (port == VPE_PORT_MV_IN) { vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; dma_addr = ctx->mv_buf_dma[mv_buf_selector]; + stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3, + VPDMA_STRIDE_ALIGN); } else { /* to incorporate interleaved formats */ int plane = fmt->coplanar ? p_data->vb_part : 0; @@ -1087,10 +1110,10 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) * If we are using a single plane buffer and * we need to set a separate vpdma chroma channel. */ - if (q_data->nplanes == 1 && plane) { + if (pix->num_planes == 1 && plane) { dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); /* Compute required offset */ - offset = q_data->bytesperline[0] * q_data->height; + offset = pix->plane_fmt[0].bytesperline * pix->height; } else { dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); /* Use address as is, no offset */ @@ -1104,26 +1127,39 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) } /* Apply the offset */ dma_addr += offset; + stride = pix->plane_fmt[VPE_LUMA].bytesperline; - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) { - /* - * Use top or bottom field from same vb alternately - * f,f-1,f-2 = TBT when seq is even - * f,f-1,f-2 = BTB when seq is odd - */ - field = (p_data->vb_index + (ctx->sequence % 2)) % 2; + /* + * field used in VPDMA desc = 0 (top) / 1 (bottom) + * Use top or bottom field from same vb alternately + * For each de-interlacing operation, f,f-1,f-2 should be one + * of TBT or BTB + */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB || + q_data->flags & Q_DATA_INTERLACED_SEQ_BT) { + /* Select initial value based on format */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT) + field = 1; + else + field = 0; + + /* Toggle for each vb_index and each operation */ + field = (field + p_data->vb_index + ctx->sequence) % 2; if (field) { - /* - * bottom field of a SEQ_TB buffer - * Skip the top field data by - */ - int height = q_data->height / 2; - int bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ? - 1 : (vpdma_fmt->depth >> 3); + int height = pix->height / 2; + int bpp; + + if (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21) + bpp = 1; + else + bpp = vpdma_fmt->depth >> 3; + if (plane) height /= 2; - dma_addr += q_data->width * height * bpp; + + dma_addr += pix->width * height * bpp; } } } @@ -1136,13 +1172,14 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) frame_width = q_data->c_rect.width; frame_height = q_data->c_rect.height; - if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12) + if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 || + fmt->fourcc == V4L2_PIX_FMT_NV21)) frame_height /= 2; - vpdma_add_in_dtd(&ctx->desc_list, q_data->width, - q_data->bytesperline[VPE_LUMA], &q_data->c_rect, - vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width, - frame_height, 0, 0); + vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride, + &q_data->c_rect, vpdma_fmt, dma_addr, + p_data->channel, field, flags, frame_width, + frame_height, 0, 0); } /* @@ -1176,13 +1213,18 @@ static void device_run(void *priv) struct sc_data *sc = ctx->dev->sc; struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; - - if (ctx->deinterlacing && s_q_data->flags & Q_DATA_INTERLACED_SEQ_TB && - ctx->sequence % 2 == 0) { - /* When using SEQ_TB buffers, When using it first time, - * No need to remove the buffer as the next field is present - * in the same buffer. (so that job_ready won't fail) - * It will be removed when using bottom field + const struct v4l2_format_info *d_finfo; + + d_finfo = v4l2_format_info(d_q_data->fmt->fourcc); + + if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX && + ctx->sequence % 2 == 0) { + /* When using SEQ_XX type buffers, each buffer has two fields + * each buffer has two fields (top & bottom) + * Removing one buffer is actually getting two fields + * Alternate between two operations:- + * Even : consume one field but DO NOT REMOVE from queue + * Odd : consume other field and REMOVE from queue */ ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[0] == NULL); @@ -1246,7 +1288,7 @@ static void device_run(void *priv) if (ctx->deinterlacing) add_out_dtd(ctx, VPE_PORT_MV_OUT); - if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { + if (v4l2_is_format_rgb(d_finfo)) { add_out_dtd(ctx, VPE_PORT_RGB_OUT); } else { add_out_dtd(ctx, VPE_PORT_LUMA_OUT); @@ -1288,7 +1330,7 @@ static void device_run(void *priv) } /* sync on channel control descriptors for output ports */ - if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) { + if (v4l2_is_format_rgb(d_finfo)) { vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_RGB_OUT); } else { @@ -1391,9 +1433,6 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) /* the previous dst mv buffer becomes the next src mv buffer */ ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector; - if (ctx->aborting) - goto finished; - s_vb = ctx->src_vbs[0]; d_vb = ctx->dst_vb; @@ -1404,6 +1443,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) d_vb->timecode = s_vb->timecode; d_vb->sequence = ctx->sequence; + s_vb->sequence = ctx->sequence; d_q_data = &ctx->q_data[Q_DATA_DST]; if (d_q_data->flags & Q_IS_INTERLACED) { @@ -1457,6 +1497,9 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) ctx->src_vbs[0] = NULL; ctx->dst_vb = NULL; + if (ctx->aborting) + goto finished; + ctx->bufs_completed++; if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) { device_run(ctx); @@ -1519,38 +1562,32 @@ static int vpe_enum_fmt(struct file *file, void *priv, static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; struct vb2_queue *vq; struct vpe_q_data *q_data; - int i; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) return -EINVAL; q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; - pix->width = q_data->width; - pix->height = q_data->height; - pix->pixelformat = q_data->fmt->fourcc; - pix->field = q_data->field; + *f = q_data->format; - if (V4L2_TYPE_IS_OUTPUT(f->type)) { - pix->colorspace = q_data->colorspace; - } else { + if (!V4L2_TYPE_IS_OUTPUT(f->type)) { struct vpe_q_data *s_q_data; + struct v4l2_pix_format_mplane *spix; - /* get colorspace from the source queue */ + /* get colorimetry from the source queue */ s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + spix = &s_q_data->format.fmt.pix_mp; - pix->colorspace = s_q_data->colorspace; - } - - pix->num_planes = q_data->nplanes; - - for (i = 0; i < pix->num_planes; i++) { - pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; - pix->plane_fmt[i].sizeimage = q_data->sizeimage[i]; + pix->colorspace = spix->colorspace; + pix->xfer_func = spix->xfer_func; + pix->ycbcr_enc = spix->ycbcr_enc; + pix->quantization = spix->quantization; } return 0; @@ -1564,15 +1601,18 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, unsigned int w_align; int i, depth, depth_bytes, height; unsigned int stride = 0; + const struct v4l2_format_info *finfo; if (!fmt || !(fmt->types & type)) { - vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", + vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n", pix->pixelformat); - return -EINVAL; + fmt = __find_format(V4L2_PIX_FMT_YUYV); } - if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE - && pix->field != V4L2_FIELD_SEQ_TB) + if (pix->field != V4L2_FIELD_NONE && + pix->field != V4L2_FIELD_ALTERNATE && + pix->field != V4L2_FIELD_SEQ_TB && + pix->field != V4L2_FIELD_SEQ_BT) pix->field = V4L2_FIELD_NONE; depth = fmt->vpdma_fmt[VPE_LUMA]->depth; @@ -1615,27 +1655,25 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, &pix->height, MIN_H, MAX_H, H_ALIGN, S_ALIGN); - if (!pix->num_planes) + if (!pix->num_planes || pix->num_planes > 2) pix->num_planes = fmt->coplanar ? 2 : 1; else if (pix->num_planes > 1 && !fmt->coplanar) pix->num_planes = 1; pix->pixelformat = fmt->fourcc; + finfo = v4l2_format_info(fmt->fourcc); /* * For the actual image parameters, we need to consider the field - * height of the image for SEQ_TB buffers. + * height of the image for SEQ_XX buffers. */ - if (pix->field == V4L2_FIELD_SEQ_TB) + if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT) height = pix->height / 2; else height = pix->height; if (!pix->colorspace) { - if (fmt->fourcc == V4L2_PIX_FMT_RGB24 || - fmt->fourcc == V4L2_PIX_FMT_BGR24 || - fmt->fourcc == V4L2_PIX_FMT_RGB32 || - fmt->fourcc == V4L2_PIX_FMT_BGR32) { + if (v4l2_is_format_rgb(finfo)) { pix->colorspace = V4L2_COLORSPACE_SRGB; } else { if (height > 1280) /* HD */ @@ -1654,6 +1692,10 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, if (stride > plane_fmt->bytesperline) plane_fmt->bytesperline = stride; + plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline, + stride, + VPDMA_MAX_STRIDE); + plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline, VPDMA_STRIDE_ALIGN); @@ -1679,7 +1721,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; struct vpe_fmt *fmt = find_format(f); if (V4L2_TYPE_IS_OUTPUT(f->type)) @@ -1691,10 +1733,9 @@ static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *plane_fmt; + struct v4l2_pix_format_mplane *qpix; struct vpe_q_data *q_data; struct vb2_queue *vq; - int i; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); if (!vq) @@ -1709,42 +1750,34 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) if (!q_data) return -EINVAL; + qpix = &q_data->format.fmt.pix_mp; q_data->fmt = find_format(f); - q_data->width = pix->width; - q_data->height = pix->height; - q_data->colorspace = pix->colorspace; - q_data->field = pix->field; - q_data->nplanes = pix->num_planes; - - for (i = 0; i < pix->num_planes; i++) { - plane_fmt = &pix->plane_fmt[i]; - - q_data->bytesperline[i] = plane_fmt->bytesperline; - q_data->sizeimage[i] = plane_fmt->sizeimage; - } + q_data->format = *f; q_data->c_rect.left = 0; q_data->c_rect.top = 0; - q_data->c_rect.width = q_data->width; - q_data->c_rect.height = q_data->height; + q_data->c_rect.width = pix->width; + q_data->c_rect.height = pix->height; - if (q_data->field == V4L2_FIELD_ALTERNATE) + if (qpix->field == V4L2_FIELD_ALTERNATE) q_data->flags |= Q_DATA_INTERLACED_ALTERNATE; - else if (q_data->field == V4L2_FIELD_SEQ_TB) + else if (qpix->field == V4L2_FIELD_SEQ_TB) q_data->flags |= Q_DATA_INTERLACED_SEQ_TB; + else if (qpix->field == V4L2_FIELD_SEQ_BT) + q_data->flags |= Q_DATA_INTERLACED_SEQ_BT; else q_data->flags &= ~Q_IS_INTERLACED; - /* the crop height is halved for the case of SEQ_TB buffers */ - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) + /* the crop height is halved for the case of SEQ_XX buffers */ + if (q_data->flags & Q_IS_SEQ_XX) q_data->c_rect.height /= 2; vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", - f->type, q_data->width, q_data->height, q_data->fmt->fourcc, - q_data->bytesperline[VPE_LUMA]); - if (q_data->nplanes == 2) + f->type, pix->width, pix->height, pix->pixelformat, + pix->plane_fmt[0].bytesperline); + if (pix->num_planes == 2) vpe_dbg(ctx->dev, " bpl_uv %d\n", - q_data->bytesperline[VPE_CHROMA]); + pix->plane_fmt[1].bytesperline); return 0; } @@ -1752,7 +1785,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { int ret; - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; ret = vpe_try_fmt(file, priv, f); if (ret) @@ -1773,6 +1806,7 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) { struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; int height; if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && @@ -1783,6 +1817,8 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) if (!q_data) return -EINVAL; + pix = &q_data->format.fmt.pix_mp; + switch (s->target) { case V4L2_SEL_TGT_COMPOSE: /* @@ -1809,27 +1845,27 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) } /* - * For SEQ_TB buffers, crop height should be less than the height of + * For SEQ_XX buffers, crop height should be less than the height of * the field height, not the buffer height */ - if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) - height = q_data->height / 2; + if (q_data->flags & Q_IS_SEQ_XX) + height = pix->height / 2; else - height = q_data->height; + height = pix->height; if (s->r.top < 0 || s->r.left < 0) { vpe_err(ctx->dev, "negative values for top and left\n"); s->r.top = s->r.left = 0; } - v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1, + v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1, &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN); /* adjust left/top if cropping rectangle is out of bounds */ - if (s->r.left + s->r.width > q_data->width) - s->r.left = q_data->width - s->r.width; - if (s->r.top + s->r.height > q_data->height) - s->r.top = q_data->height - s->r.height; + if (s->r.left + s->r.width > pix->width) + s->r.left = pix->width - s->r.width; + if (s->r.top + s->r.height > pix->height) + s->r.top = pix->height - s->r.height; return 0; } @@ -1837,8 +1873,9 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) static int vpe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; bool use_c_rect = false; if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && @@ -1849,6 +1886,8 @@ static int vpe_g_selection(struct file *file, void *fh, if (!q_data) return -EINVAL; + pix = &q_data->format.fmt.pix_mp; + switch (s->target) { case V4L2_SEL_TGT_COMPOSE_DEFAULT: case V4L2_SEL_TGT_COMPOSE_BOUNDS: @@ -1887,8 +1926,8 @@ static int vpe_g_selection(struct file *file, void *fh, */ s->r.left = 0; s->r.top = 0; - s->r.width = q_data->width; - s->r.height = q_data->height; + s->r.width = pix->width; + s->r.height = pix->height; } return 0; @@ -1898,7 +1937,7 @@ static int vpe_g_selection(struct file *file, void *fh, static int vpe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; struct vpe_q_data *q_data; struct v4l2_selection sel = *s; int ret; @@ -1991,17 +2030,21 @@ static int vpe_queue_setup(struct vb2_queue *vq, int i; struct vpe_ctx *ctx = vb2_get_drv_priv(vq); struct vpe_q_data *q_data; + struct v4l2_pix_format_mplane *pix; q_data = get_q_data(ctx, vq->type); + if (!q_data) + return -EINVAL; - *nplanes = q_data->nplanes; + pix = &q_data->format.fmt.pix_mp; + *nplanes = pix->num_planes; for (i = 0; i < *nplanes; i++) - sizes[i] = q_data->sizeimage[i]; + sizes[i] = pix->plane_fmt[i].sizeimage; vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers, sizes[VPE_LUMA]); - if (q_data->nplanes == 2) + if (*nplanes == 2) vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]); return 0; @@ -2012,12 +2055,16 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vpe_q_data *q_data; - int i, num_planes; + struct v4l2_pix_format_mplane *pix; + int i; vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type); q_data = get_q_data(ctx, vb->vb2_queue->type); - num_planes = q_data->nplanes; + if (!q_data) + return -EINVAL; + + pix = &q_data->format.fmt.pix_mp; if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (!(q_data->flags & Q_IS_INTERLACED)) { @@ -2025,23 +2072,24 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) } else { if (vbuf->field != V4L2_FIELD_TOP && vbuf->field != V4L2_FIELD_BOTTOM && - vbuf->field != V4L2_FIELD_SEQ_TB) + vbuf->field != V4L2_FIELD_SEQ_TB && + vbuf->field != V4L2_FIELD_SEQ_BT) return -EINVAL; } } - for (i = 0; i < num_planes; i++) { - if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { + for (i = 0; i < pix->num_planes; i++) { + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { vpe_err(ctx->dev, "data will not fit into plane (%lu < %lu)\n", vb2_plane_size(vb, i), - (long) q_data->sizeimage[i]); + (long)pix->plane_fmt[i].sizeimage); return -EINVAL; } } - for (i = 0; i < num_planes; i++) - vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); + for (i = 0; i < pix->num_planes; i++) + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); return 0; } @@ -2226,6 +2274,7 @@ static int vpe_open(struct file *file) struct vpe_q_data *s_q_data; struct v4l2_ctrl_handler *hdl; struct vpe_ctx *ctx; + struct v4l2_pix_format_mplane *pix; int ret; vpe_dbg(dev, "vpe_open\n"); @@ -2261,7 +2310,7 @@ static int vpe_open(struct file *file) init_adb_hdrs(ctx); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; + file->private_data = ctx; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 1); @@ -2274,23 +2323,32 @@ static int vpe_open(struct file *file) v4l2_ctrl_handler_setup(hdl); s_q_data = &ctx->q_data[Q_DATA_SRC]; - s_q_data->fmt = &vpe_formats[2]; - s_q_data->width = 1920; - s_q_data->height = 1080; - s_q_data->nplanes = 1; - s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width * + pix = &s_q_data->format.fmt.pix_mp; + s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV); + pix->pixelformat = s_q_data->fmt->fourcc; + s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + pix->width = 1920; + pix->height = 1080; + pix->num_planes = 1; + pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width * s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; - s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] * - s_q_data->height); - s_q_data->colorspace = V4L2_COLORSPACE_REC709; - s_q_data->field = V4L2_FIELD_NONE; + pix->plane_fmt[VPE_LUMA].sizeimage = + pix->plane_fmt[VPE_LUMA].bytesperline * + pix->height; + pix->colorspace = V4L2_COLORSPACE_REC709; + pix->xfer_func = V4L2_XFER_FUNC_DEFAULT; + pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix->quantization = V4L2_QUANTIZATION_DEFAULT; + pix->field = V4L2_FIELD_NONE; s_q_data->c_rect.left = 0; s_q_data->c_rect.top = 0; - s_q_data->c_rect.width = s_q_data->width; - s_q_data->c_rect.height = s_q_data->height; + s_q_data->c_rect.width = pix->width; + s_q_data->c_rect.height = pix->height; s_q_data->flags = 0; ctx->q_data[Q_DATA_DST] = *s_q_data; + ctx->q_data[Q_DATA_DST].format.type = + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; set_dei_shadow_registers(ctx); set_src_registers(ctx); @@ -2346,12 +2404,18 @@ free_ctx: static int vpe_release(struct file *file) { struct vpe_dev *dev = video_drvdata(file); - struct vpe_ctx *ctx = file2ctx(file); + struct vpe_ctx *ctx = file->private_data; vpe_dbg(dev, "releasing instance %p\n", ctx); mutex_lock(&dev->dev_mutex); free_mv_buffers(ctx); + + vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h); + vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v); + vpdma_free_desc_list(&ctx->desc_list); vpdma_free_desc_buf(&ctx->mmr_adb); @@ -2459,6 +2523,13 @@ static int vpe_probe(struct platform_device *pdev) struct vpe_dev *dev; int ret, irq, func; + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, + "32-bit consistent DMA enable failed\n"); + return ret; + } + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -2473,7 +2544,12 @@ static int vpe_probe(struct platform_device *pdev) mutex_init(&dev->dev_mutex); dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "vpe_top"); + "vpe_top"); + if (!dev->res) { + dev_err(&pdev->dev, "missing 'vpe_top' resources data\n"); + return -ENODEV; + } + /* * HACK: we get resource info from device tree in the form of a list of * VPE sub blocks, the driver currently uses only the base of vpe_top @@ -2568,7 +2644,7 @@ static int vpe_remove(struct platform_device *pdev) #if defined(CONFIG_OF) static const struct of_device_id vpe_of_match[] = { { - .compatible = "ti,vpe", + .compatible = "ti,dra7-vpe", }, {}, }; diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 0ee143ae0f6b..82350097503e 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -2139,6 +2139,9 @@ static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) v4l2_m2m_release(dev->stateful_enc.m2m_dev); v4l2_m2m_release(dev->stateful_dec.m2m_dev); v4l2_m2m_release(dev->stateless_dec.m2m_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif kfree(dev); } @@ -2250,7 +2253,6 @@ static int vicodec_remove(struct platform_device *pdev) v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); - media_device_cleanup(&dev->mdev); #endif video_unregister_device(&dev->stateful_enc.vfd); diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index acd3bd48c7e2..8d6b09623d88 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -1073,6 +1073,9 @@ static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count) if (!q_data) return -EINVAL; + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->aborting = 0; + q_data->sequence = 0; return 0; } @@ -1272,6 +1275,9 @@ static void vim2m_device_release(struct video_device *vdev) v4l2_device_unregister(&dev->v4l2_dev); v4l2_m2m_release(dev->m2m_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif kfree(dev); } @@ -1343,6 +1349,7 @@ static int vim2m_probe(struct platform_device *pdev) if (IS_ERR(dev->m2m_dev)) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(dev->m2m_dev); + dev->m2m_dev = NULL; goto error_dev; } @@ -1395,7 +1402,6 @@ static int vim2m_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); v4l2_m2m_unregister_media_controller(dev->m2m_dev); - media_device_cleanup(&dev->mdev); #endif video_unregister_device(&dev->vfd); diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile index 96d06f030c31..a53b2b532e9f 100644 --- a/drivers/media/platform/vimc/Makefile +++ b/drivers/media/platform/vimc/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -vimc-y := vimc-core.o vimc-common.o vimc-streamer.o +vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \ + vimc-debayer.o vimc-scaler.o vimc-sensor.o + +obj-$(CONFIG_VIDEO_VIMC) += vimc.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \ - vimc-scaler.o vimc-sensor.o diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 1d56b91830ba..76c015898cfd 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -5,10 +5,6 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ -#include <linux/component.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/platform_device.h> #include <media/v4l2-ioctl.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> @@ -16,12 +12,9 @@ #include "vimc-common.h" #include "vimc-streamer.h" -#define VIMC_CAP_DRV_NAME "vimc-capture" - struct vimc_cap_device { struct vimc_ent_device ved; struct video_device vdev; - struct device *dev; struct v4l2_pix_format format; struct vb2_queue queue; struct list_head buf_list; @@ -36,6 +29,7 @@ struct vimc_cap_device { struct mutex lock; u32 sequence; struct vimc_stream stream; + struct media_pad pad; }; static const struct v4l2_pix_format fmt_default = { @@ -130,7 +124,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - dev_dbg(vcap->dev, "%s: format update: " + dev_dbg(vcap->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, /* old */ @@ -306,7 +300,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) unsigned long size = vcap->format.sizeimage; if (vb2_plane_size(vb, 0) < size) { - dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n", + dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n", vcap->vdev.name, vb2_plane_size(vb, 0), size); return -EINVAL; } @@ -328,7 +322,7 @@ static const struct vb2_ops vimc_cap_qops = { }; static const struct media_entity_operations vimc_cap_mops = { - .link_validate = vimc_link_validate, + .link_validate = vimc_vdev_link_validate, }; static void vimc_cap_release(struct video_device *vdev) @@ -336,19 +330,16 @@ static void vimc_cap_release(struct video_device *vdev) struct vimc_cap_device *vcap = container_of(vdev, struct vimc_cap_device, vdev); - vimc_pads_cleanup(vcap->ved.pads); + media_entity_cleanup(vcap->ved.ent); kfree(vcap); } -static void vimc_cap_comp_unbind(struct device *comp, struct device *master, - void *master_data) +void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) { - struct vimc_ent_device *ved = dev_get_drvdata(comp); - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); + struct vimc_cap_device *vcap; + vcap = container_of(ved, struct vimc_cap_device, ved); vb2_queue_release(&vcap->queue); - media_entity_cleanup(ved->ent); video_unregister_device(&vcap->vdev); } @@ -391,11 +382,10 @@ static void *vimc_cap_process_frame(struct vimc_ent_device *ved, return NULL; } -static int vimc_cap_comp_bind(struct device *comp, struct device *master, - void *master_data) +struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, + const char *vcfg_name) { - struct v4l2_device *v4l2_dev = master_data; - struct vimc_platform_data *pdata = comp->platform_data; + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; const struct vimc_pix_map *vpix; struct vimc_cap_device *vcap; struct video_device *vdev; @@ -405,23 +395,16 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, /* Allocate the vimc_cap_device struct */ vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); if (!vcap) - return -ENOMEM; - - /* Allocate the pads */ - vcap->ved.pads = - vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK}); - if (IS_ERR(vcap->ved.pads)) { - ret = PTR_ERR(vcap->ved.pads); - goto err_free_vcap; - } + return NULL; /* Initialize the media entity */ - vcap->vdev.entity.name = pdata->entity_name; + vcap->vdev.entity.name = vcfg_name; vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; + vcap->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vcap->vdev.entity, - 1, vcap->ved.pads); + 1, &vcap->pad); if (ret) - goto err_clean_pads; + goto err_free_vcap; /* Initialize the lock */ mutex_init(&vcap->lock); @@ -440,8 +423,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, ret = vb2_queue_init(q); if (ret) { - dev_err(comp, "%s: vb2 queue init failed (err=%d)\n", - pdata->entity_name, ret); + dev_err(&vimc->pdev.dev, "%s: vb2 queue init failed (err=%d)\n", + vcfg_name, ret); goto err_clean_m_ent; } @@ -460,8 +443,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, vcap->ved.ent = &vcap->vdev.entity; vcap->ved.process_frame = vimc_cap_process_frame; vcap->ved.vdev_get_format = vimc_cap_get_format; - dev_set_drvdata(comp, &vcap->ved); - vcap->dev = comp; + vcap->ved.dev = &vimc->pdev.dev; /* Initialize the video_device struct */ vdev = &vcap->vdev; @@ -474,68 +456,25 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, vdev->queue = q; vdev->v4l2_dev = v4l2_dev; vdev->vfl_dir = VFL_DIR_RX; - strscpy(vdev->name, pdata->entity_name, sizeof(vdev->name)); + strscpy(vdev->name, vcfg_name, sizeof(vdev->name)); video_set_drvdata(vdev, &vcap->ved); /* Register the video_device with the v4l2 and the media framework */ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); if (ret) { - dev_err(comp, "%s: video register failed (err=%d)\n", + dev_err(&vimc->pdev.dev, "%s: video register failed (err=%d)\n", vcap->vdev.name, ret); goto err_release_queue; } - return 0; + return &vcap->ved; err_release_queue: vb2_queue_release(q); err_clean_m_ent: media_entity_cleanup(&vcap->vdev.entity); -err_clean_pads: - vimc_pads_cleanup(vcap->ved.pads); err_free_vcap: kfree(vcap); - return ret; -} - -static const struct component_ops vimc_cap_comp_ops = { - .bind = vimc_cap_comp_bind, - .unbind = vimc_cap_comp_unbind, -}; - -static int vimc_cap_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &vimc_cap_comp_ops); -} - -static int vimc_cap_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &vimc_cap_comp_ops); - - return 0; + return NULL; } - -static const struct platform_device_id vimc_cap_driver_ids[] = { - { - .name = VIMC_CAP_DRV_NAME, - }, - { } -}; - -static struct platform_driver vimc_cap_pdrv = { - .probe = vimc_cap_probe, - .remove = vimc_cap_remove, - .id_table = vimc_cap_driver_ids, - .driver = { - .name = VIMC_CAP_DRV_NAME, - }, -}; - -module_platform_driver(vimc_cap_pdrv); - -MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture"); -MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 7e1ae0b12f1e..16ce9f3b7c75 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -164,6 +164,16 @@ static const struct vimc_pix_map vimc_pix_map_list[] = { }, }; +bool vimc_is_source(struct media_entity *ent) +{ + unsigned int i; + + for (i = 0; i < ent->num_pads; i++) + if (ent->pads[i].flags & MEDIA_PAD_FL_SINK) + return false; + return true; +} + const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) { if (i >= ARRAY_SIZE(vimc_pix_map_list)) @@ -171,7 +181,6 @@ const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) return &vimc_pix_map_list[i]; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_index); const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) { @@ -183,7 +192,6 @@ const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) } return NULL; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_code); const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) { @@ -195,87 +203,37 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) } return NULL; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); - -/* Helper function to allocate and initialize pads */ -struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) -{ - struct media_pad *pads; - unsigned int i; - - /* Allocate memory for the pads */ - pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL); - if (!pads) - return ERR_PTR(-ENOMEM); - - /* Initialize the pads */ - for (i = 0; i < num_pads; i++) { - pads[i].index = i; - pads[i].flags = pads_flag[i]; - } - - return pads; -} -EXPORT_SYMBOL_GPL(vimc_pads_init); -int vimc_pipeline_s_stream(struct media_entity *ent, int enable) -{ - struct v4l2_subdev *sd; - struct media_pad *pad; - unsigned int i; - int ret; - - for (i = 0; i < ent->num_pads; i++) { - if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) - continue; - - /* Start the stream in the subdevice direct connected */ - pad = media_entity_remote_pad(&ent->pads[i]); - if (!pad) - continue; - - if (!is_media_entity_v4l2_subdev(pad->entity)) - return -EINVAL; - - sd = media_entity_to_v4l2_subdev(pad->entity); - ret = v4l2_subdev_call(sd, video, s_stream, enable); - if (ret && ret != -ENOIOCTLCMD) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(vimc_pipeline_s_stream); - -static int vimc_get_mbus_format(struct media_pad *pad, - struct v4l2_subdev_format *fmt) +static int vimc_get_pix_format(struct media_pad *pad, + struct v4l2_pix_format *fmt) { if (is_media_entity_v4l2_subdev(pad->entity)) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(pad->entity); + struct v4l2_subdev_format sd_fmt; + const struct vimc_pix_map *pix_map; int ret; - fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; - fmt->pad = pad->index; + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = pad->index; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; + v4l2_fill_pix_format(fmt, &sd_fmt.format); + pix_map = vimc_pix_map_by_code(sd_fmt.format.code); + fmt->pixelformat = pix_map->pixelformat; } else if (is_media_entity_v4l2_video_device(pad->entity)) { struct video_device *vdev = container_of(pad->entity, struct video_device, entity); struct vimc_ent_device *ved = video_get_drvdata(vdev); - const struct vimc_pix_map *vpix; - struct v4l2_pix_format vdev_fmt; if (!ved->vdev_get_format) return -ENOIOCTLCMD; - ved->vdev_get_format(ved, &vdev_fmt); - vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); - v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); + ved->vdev_get_format(ved, fmt); } else { return -EINVAL; } @@ -283,16 +241,16 @@ static int vimc_get_mbus_format(struct media_pad *pad, return 0; } -int vimc_link_validate(struct media_link *link) +int vimc_vdev_link_validate(struct media_link *link) { - struct v4l2_subdev_format source_fmt, sink_fmt; + struct v4l2_pix_format source_fmt, sink_fmt; int ret; - ret = vimc_get_mbus_format(link->source, &source_fmt); + ret = vimc_get_pix_format(link->source, &source_fmt); if (ret) return ret; - ret = vimc_get_mbus_format(link->sink, &sink_fmt); + ret = vimc_get_pix_format(link->sink, &sink_fmt); if (ret) return ret; @@ -301,21 +259,21 @@ int vimc_link_validate(struct media_link *link) "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", /* src */ link->source->entity->name, - source_fmt.format.width, source_fmt.format.height, - source_fmt.format.code, source_fmt.format.colorspace, - source_fmt.format.quantization, source_fmt.format.xfer_func, - source_fmt.format.ycbcr_enc, + source_fmt.width, source_fmt.height, + source_fmt.pixelformat, source_fmt.colorspace, + source_fmt.quantization, source_fmt.xfer_func, + source_fmt.ycbcr_enc, /* sink */ link->sink->entity->name, - sink_fmt.format.width, sink_fmt.format.height, - sink_fmt.format.code, sink_fmt.format.colorspace, - sink_fmt.format.quantization, sink_fmt.format.xfer_func, - sink_fmt.format.ycbcr_enc); - - /* The width, height and code must match. */ - if (source_fmt.format.width != sink_fmt.format.width - || source_fmt.format.height != sink_fmt.format.height - || source_fmt.format.code != sink_fmt.format.code) + sink_fmt.width, sink_fmt.height, + sink_fmt.pixelformat, sink_fmt.colorspace, + sink_fmt.quantization, sink_fmt.xfer_func, + sink_fmt.ycbcr_enc); + + /* The width, height and pixelformat must match. */ + if (source_fmt.width != sink_fmt.width || + source_fmt.height != sink_fmt.height || + source_fmt.pixelformat != sink_fmt.pixelformat) return -EPIPE; /* @@ -323,44 +281,43 @@ int vimc_link_validate(struct media_link *link) * to support interlaced hardware connected to bridges that support * progressive formats only. */ - if (source_fmt.format.field != sink_fmt.format.field && - sink_fmt.format.field != V4L2_FIELD_NONE) + if (source_fmt.field != sink_fmt.field && + sink_fmt.field != V4L2_FIELD_NONE) return -EPIPE; /* * If colorspace is DEFAULT, then assume all the colorimetry is also * DEFAULT, return 0 to skip comparing the other colorimetry parameters */ - if (source_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT - || sink_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT) + if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT || + sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT) return 0; /* Colorspace must match. */ - if (source_fmt.format.colorspace != sink_fmt.format.colorspace) + if (source_fmt.colorspace != sink_fmt.colorspace) return -EPIPE; /* Colorimetry must match if they are not set to DEFAULT */ - if (source_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT - && sink_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT - && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc) + if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && + sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && + source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc) return -EPIPE; - if (source_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT - && sink_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT - && source_fmt.format.quantization != sink_fmt.format.quantization) + if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && + sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && + source_fmt.quantization != sink_fmt.quantization) return -EPIPE; - if (source_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT - && sink_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT - && source_fmt.format.xfer_func != sink_fmt.format.xfer_func) + if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && + sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && + source_fmt.xfer_func != sink_fmt.xfer_func) return -EPIPE; return 0; } -EXPORT_SYMBOL_GPL(vimc_link_validate); static const struct media_entity_operations vimc_ent_sd_mops = { - .link_validate = vimc_link_validate, + .link_validate = v4l2_subdev_link_validate, }; int vimc_ent_sd_register(struct vimc_ent_device *ved, @@ -369,17 +326,12 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, const char *const name, u32 function, u16 num_pads, - const unsigned long *pads_flag, + struct media_pad *pads, const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops) { int ret; - /* Allocate the pads */ - ved->pads = vimc_pads_init(num_pads, pads_flag); - if (IS_ERR(ved->pads)) - return PTR_ERR(ved->pads); - /* Fill the vimc_ent_device struct */ ved->ent = &sd->entity; @@ -398,9 +350,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; /* Initialize the media entity */ - ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads); + ret = media_entity_pads_init(&sd->entity, num_pads, pads); if (ret) - goto err_clean_pads; + return ret; /* Register the subdev with the v4l2 and the media framework */ ret = v4l2_device_register_subdev(v4l2_dev, sd); @@ -415,16 +367,5 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, err_clean_m_ent: media_entity_cleanup(&sd->entity); -err_clean_pads: - vimc_pads_cleanup(ved->pads); return ret; } -EXPORT_SYMBOL_GPL(vimc_ent_sd_register); - -void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) -{ - media_entity_cleanup(ved->ent); - vimc_pads_cleanup(ved->pads); - v4l2_device_unregister_subdev(sd); -} -EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 9c2e0e216c6b..87eb8259c2a8 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -8,6 +8,7 @@ #ifndef _VIMC_COMMON_H_ #define _VIMC_COMMON_H_ +#include <linux/platform_device.h> #include <linux/slab.h> #include <media/media-device.h> #include <media/v4l2-device.h> @@ -18,6 +19,7 @@ #define VIMC_CID_VIMC_BASE (0x00f00000 | 0xf000) #define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) #define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0) +#define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1) #define VIMC_FRAME_MAX_WIDTH 4096 #define VIMC_FRAME_MAX_HEIGHT 2160 @@ -26,6 +28,10 @@ #define VIMC_FRAME_INDEX(lin, col, width, bpp) ((lin * width + col) * bpp) +/* Source and sink pad checks */ +#define VIMC_IS_SRC(pad) (pad) +#define VIMC_IS_SINK(pad) (!(pad)) + /** * struct vimc_colorimetry_clamp - Adjust colorimetry parameters * @@ -53,21 +59,6 @@ do { \ } while (0) /** - * struct vimc_platform_data - platform data to components - * - * @entity_name: The name of the entity to be created - * - * Board setup code will often provide additional information using the device's - * platform_data field to hold additional information. - * When injecting a new platform_device in the component system the core needs - * to provide to the corresponding submodules the name of the entity that should - * be used when registering the subdevice in the Media Controller system. - */ -struct vimc_platform_data { - char entity_name[32]; -}; - -/** * struct vimc_pix_map - maps media bus code with v4l2 pixel format * * @code: media bus format code defined by MEDIA_BUS_FMT_* macros @@ -85,10 +76,11 @@ struct vimc_pix_map { }; /** - * struct vimc_ent_device - core struct that represents a node in the topology + * struct vimc_ent_device - core struct that represents an entity in the + * topology * + * @dev: a pointer of the device struct of the driver * @ent: the pointer to struct media_entity for the node - * @pads: the list of pads of the node * @process_frame: callback send a frame to that node * @vdev_get_format: callback that returns the current format a pad, used * only when is_media_entity_v4l2_video_device(ent) returns @@ -103,8 +95,8 @@ struct vimc_pix_map { * media_entity */ struct vimc_ent_device { + struct device *dev; struct media_entity *ent; - struct media_pad *pads; void * (*process_frame)(struct vimc_ent_device *ved, const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, @@ -112,38 +104,65 @@ struct vimc_ent_device { }; /** - * vimc_pads_init - initialize pads - * - * @num_pads: number of pads to initialize - * @pads_flags: flags to use in each pad + * struct vimc_device - main device for vimc driver * - * Helper functions to allocate/initialize pads + * @pdev pointer to the platform device + * @pipe_cfg pointer to the vimc pipeline configuration structure + * @ent_devs array of vimc_ent_device pointers + * @mdev the associated media_device parent + * @v4l2_dev Internal v4l2 parent device */ -struct media_pad *vimc_pads_init(u16 num_pads, - const unsigned long *pads_flag); +struct vimc_device { + struct platform_device pdev; + const struct vimc_pipeline_config *pipe_cfg; + struct vimc_ent_device **ent_devs; + struct media_device mdev; + struct v4l2_device v4l2_dev; +}; /** - * vimc_pads_cleanup - free pads - * - * @pads: pointer to the pads - * - * Helper function to free the pads initialized with vimc_pads_init + * struct vimc_ent_config Structure which describes individual + * configuration for each entity + * + * @name entity name + * @ved pointer to vimc_ent_device (a node in the + * topology) + * @add subdev add hook - initializes and registers + * subdev called from vimc-core + * @rm subdev rm hook - unregisters and frees + * subdev called from vimc-core */ -static inline void vimc_pads_cleanup(struct media_pad *pads) -{ - kfree(pads); -} +struct vimc_ent_config { + const char *name; + struct vimc_ent_device *(*add)(struct vimc_device *vimc, + const char *vcfg_name); + void (*rm)(struct vimc_device *vimc, struct vimc_ent_device *ved); +}; /** - * vimc_pipeline_s_stream - start stream through the pipeline + * vimc_is_source - returns true if the entity has only source pads * - * @ent: the pointer to struct media_entity for the node - * @enable: 1 to start the stream and 0 to stop + * @ent: pointer to &struct media_entity * - * Helper function to call the s_stream of the subdevices connected - * in all the sink pads of the entity */ -int vimc_pipeline_s_stream(struct media_entity *ent, int enable); +bool vimc_is_source(struct media_entity *ent); + +/* prototypes for vimc_ent_config add and rm hooks */ +struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved); /** * vimc_pix_map_by_index - get vimc_pix_map struct by its index @@ -176,7 +195,8 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); * unique. * @function: media entity function defined by MEDIA_ENT_F_* macros * @num_pads: number of pads to initialize - * @pads_flag: flags to use in each pad + * @pads: the array of pads of the entity, the caller should set the + flags of the pads * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops * @sd_ops: pointer to &struct v4l2_subdev_ops. * @@ -189,29 +209,17 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, const char *const name, u32 function, u16 num_pads, - const unsigned long *pads_flag, + struct media_pad *pads, const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops); /** - * vimc_ent_sd_unregister - cleanup and unregister a subdev node - * - * @ved: the vimc_ent_device struct to be cleaned up - * @sd: the v4l2_subdev struct to be unregistered - * - * Helper function cleanup and unregister the struct vimc_ent_device and struct - * v4l2_subdev which represents a subdev node in the topology - */ -void vimc_ent_sd_unregister(struct vimc_ent_device *ved, - struct v4l2_subdev *sd); - -/** - * vimc_link_validate - validates a media link + * vimc_vdev_link_validate - validates a media link * * @link: pointer to &struct media_link * * This function calls validates if a media link is valid for streaming. */ -int vimc_link_validate(struct media_link *link); +int vimc_vdev_link_validate(struct media_link *link); #endif diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 571c55aa0e16..97a272f3350a 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -5,7 +5,6 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ -#include <linux/component.h> #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> @@ -24,29 +23,6 @@ .flags = link_flags, \ } -struct vimc_device { - /* The platform device */ - struct platform_device pdev; - - /* The pipeline configuration */ - const struct vimc_pipeline_config *pipe_cfg; - - /* The Associated media_device parent */ - struct media_device mdev; - - /* Internal v4l2 parent device*/ - struct v4l2_device v4l2_dev; - - /* Subdevices */ - struct platform_device **subdevs; -}; - -/* Structure which describes individual configuration for each entity */ -struct vimc_ent_config { - const char *name; - const char *drv; -}; - /* Structure which describes links between entities */ struct vimc_ent_link { unsigned int src_ent; @@ -68,43 +44,52 @@ struct vimc_pipeline_config { * Topology Configuration */ -static const struct vimc_ent_config ent_config[] = { +static struct vimc_ent_config ent_config[] = { { .name = "Sensor A", - .drv = "vimc-sensor", + .add = vimc_sen_add, + .rm = vimc_sen_rm, }, { .name = "Sensor B", - .drv = "vimc-sensor", + .add = vimc_sen_add, + .rm = vimc_sen_rm, }, { .name = "Debayer A", - .drv = "vimc-debayer", + .add = vimc_deb_add, + .rm = vimc_deb_rm, }, { .name = "Debayer B", - .drv = "vimc-debayer", + .add = vimc_deb_add, + .rm = vimc_deb_rm, }, { .name = "Raw Capture 0", - .drv = "vimc-capture", + .add = vimc_cap_add, + .rm = vimc_cap_rm, }, { .name = "Raw Capture 1", - .drv = "vimc-capture", + .add = vimc_cap_add, + .rm = vimc_cap_rm, }, { - .name = "RGB/YUV Input", /* TODO: change this to vimc-input when it is implemented */ - .drv = "vimc-sensor", + .name = "RGB/YUV Input", + .add = vimc_sen_add, + .rm = vimc_sen_rm, }, { .name = "Scaler", - .drv = "vimc-scaler", + .add = vimc_sca_add, + .rm = vimc_sca_rm, }, { .name = "RGB/YUV Capture", - .drv = "vimc-capture", + .add = vimc_cap_add, + .rm = vimc_cap_rm, }, }; @@ -127,7 +112,7 @@ static const struct vimc_ent_link ent_links[] = { VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), }; -static const struct vimc_pipeline_config pipe_cfg = { +static struct vimc_pipeline_config pipe_cfg = { .ents = ent_config, .num_ents = ARRAY_SIZE(ent_config), .links = ent_links, @@ -136,6 +121,14 @@ static const struct vimc_pipeline_config pipe_cfg = { /* -------------------------------------------------------------------------- */ +static void vimc_rm_links(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) + media_entity_remove_links(vimc->ent_devs[i]->ent); +} + static int vimc_create_links(struct vimc_device *vimc) { unsigned int i; @@ -144,32 +137,56 @@ static int vimc_create_links(struct vimc_device *vimc) /* Initialize the links between entities */ for (i = 0; i < vimc->pipe_cfg->num_links; i++) { const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; - /* - * TODO: Check another way of retrieving ved struct without - * relying on platform_get_drvdata - */ + struct vimc_ent_device *ved_src = - platform_get_drvdata(vimc->subdevs[link->src_ent]); + vimc->ent_devs[link->src_ent]; struct vimc_ent_device *ved_sink = - platform_get_drvdata(vimc->subdevs[link->sink_ent]); + vimc->ent_devs[link->sink_ent]; ret = media_create_pad_link(ved_src->ent, link->src_pad, ved_sink->ent, link->sink_pad, link->flags); if (ret) - return ret; + goto err_rm_links; } return 0; + +err_rm_links: + vimc_rm_links(vimc); + return ret; } -static int vimc_comp_bind(struct device *master) +static int vimc_add_subdevs(struct vimc_device *vimc) { - struct vimc_device *vimc = container_of(to_platform_device(master), - struct vimc_device, pdev); - int ret; + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { + dev_dbg(&vimc->pdev.dev, "new entity for %s\n", + vimc->pipe_cfg->ents[i].name); + vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc, + vimc->pipe_cfg->ents[i].name); + if (!vimc->ent_devs[i]) { + dev_err(&vimc->pdev.dev, "add new entity for %s\n", + vimc->pipe_cfg->ents[i].name); + return -EINVAL; + } + } + return 0; +} + +static void vimc_rm_subdevs(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) + if (vimc->ent_devs[i]) + vimc->pipe_cfg->ents[i].rm(vimc, vimc->ent_devs[i]); +} - dev_dbg(master, "bind"); +static int vimc_register_devices(struct vimc_device *vimc) +{ + int ret; /* Register the v4l2 struct */ ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); @@ -179,22 +196,31 @@ static int vimc_comp_bind(struct device *master) return ret; } - /* Bind subdevices */ - ret = component_bind_all(master, &vimc->v4l2_dev); - if (ret) + /* allocate ent_devs */ + vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, + sizeof(*vimc->ent_devs), GFP_KERNEL); + if (!vimc->ent_devs) { + ret = -ENOMEM; goto err_v4l2_unregister; + } + + /* Invoke entity config hooks to initialize and register subdevs */ + ret = vimc_add_subdevs(vimc); + if (ret) + /* remove sundevs that got added */ + goto err_rm_subdevs; /* Initialize links */ ret = vimc_create_links(vimc); if (ret) - goto err_comp_unbind_all; + goto err_rm_subdevs; /* Register the media device */ ret = media_device_register(&vimc->mdev); if (ret) { dev_err(vimc->mdev.dev, "media device register failed (err=%d)\n", ret); - goto err_comp_unbind_all; + goto err_rm_subdevs; } /* Expose all subdev's nodes*/ @@ -211,98 +237,32 @@ static int vimc_comp_bind(struct device *master) err_mdev_unregister: media_device_unregister(&vimc->mdev); media_device_cleanup(&vimc->mdev); -err_comp_unbind_all: - component_unbind_all(master, NULL); +err_rm_subdevs: + vimc_rm_subdevs(vimc); + kfree(vimc->ent_devs); err_v4l2_unregister: v4l2_device_unregister(&vimc->v4l2_dev); return ret; } -static void vimc_comp_unbind(struct device *master) +static void vimc_unregister(struct vimc_device *vimc) { - struct vimc_device *vimc = container_of(to_platform_device(master), - struct vimc_device, pdev); - - dev_dbg(master, "unbind"); - media_device_unregister(&vimc->mdev); media_device_cleanup(&vimc->mdev); - component_unbind_all(master, NULL); v4l2_device_unregister(&vimc->v4l2_dev); + kfree(vimc->ent_devs); } -static int vimc_comp_compare(struct device *comp, void *data) -{ - return comp == data; -} - -static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) -{ - struct component_match *match = NULL; - struct vimc_platform_data pdata; - int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { - dev_dbg(&vimc->pdev.dev, "new pdev for %s\n", - vimc->pipe_cfg->ents[i].drv); - - strscpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name, - sizeof(pdata.entity_name)); - - vimc->subdevs[i] = platform_device_register_data(&vimc->pdev.dev, - vimc->pipe_cfg->ents[i].drv, - PLATFORM_DEVID_AUTO, - &pdata, - sizeof(pdata)); - if (IS_ERR(vimc->subdevs[i])) { - match = ERR_CAST(vimc->subdevs[i]); - while (--i >= 0) - platform_device_unregister(vimc->subdevs[i]); - - return match; - } - - component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, - &vimc->subdevs[i]->dev); - } - - return match; -} - -static void vimc_rm_subdevs(struct vimc_device *vimc) -{ - unsigned int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) - platform_device_unregister(vimc->subdevs[i]); -} - -static const struct component_master_ops vimc_comp_ops = { - .bind = vimc_comp_bind, - .unbind = vimc_comp_unbind, -}; - static int vimc_probe(struct platform_device *pdev) { struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev); - struct component_match *match = NULL; int ret; dev_dbg(&pdev->dev, "probe"); memset(&vimc->mdev, 0, sizeof(vimc->mdev)); - /* Create platform_device for each entity in the topology*/ - vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents, - sizeof(*vimc->subdevs), GFP_KERNEL); - if (!vimc->subdevs) - return -ENOMEM; - - match = vimc_add_subdevs(vimc); - if (IS_ERR(match)) - return PTR_ERR(match); - /* Link the media device within the v4l2_device */ vimc->v4l2_dev.mdev = &vimc->mdev; @@ -314,12 +274,9 @@ static int vimc_probe(struct platform_device *pdev) vimc->mdev.dev = &pdev->dev; media_device_init(&vimc->mdev); - /* Add self to the component system */ - ret = component_master_add_with_match(&pdev->dev, &vimc_comp_ops, - match); + ret = vimc_register_devices(vimc); if (ret) { media_device_cleanup(&vimc->mdev); - vimc_rm_subdevs(vimc); return ret; } @@ -332,8 +289,8 @@ static int vimc_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "remove"); - component_master_del(&pdev->dev, &vimc_comp_ops); vimc_rm_subdevs(vimc); + vimc_unregister(vimc); return 0; } diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index b72b8385067b..5d1b67d684bb 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -5,28 +5,16 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ -#include <linux/component.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> +#include <linux/moduleparam.h> #include <linux/platform_device.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/v4l2-subdev.h> #include "vimc-common.h" -#define VIMC_DEB_DRV_NAME "vimc-debayer" - -static unsigned int deb_mean_win_size = 3; -module_param(deb_mean_win_size, uint, 0000); -MODULE_PARM_DESC(deb_mean_win_size, " the window size to calculate the mean.\n" - "NOTE: the window size needs to be an odd number, as the main pixel " - "stays in the center of the window, otherwise the next odd number " - "is considered"); - -#define IS_SINK(pad) (!pad) -#define IS_SRC(pad) (pad) - enum vimc_deb_rgb_colors { VIMC_DEB_RED = 0, VIMC_DEB_GREEN = 1, @@ -41,7 +29,6 @@ struct vimc_deb_pix_map { struct vimc_deb_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - struct device *dev; /* The active format */ struct v4l2_mbus_framefmt sink_fmt; u32 src_code; @@ -51,6 +38,9 @@ struct vimc_deb_device { u8 *src_frame; const struct vimc_deb_pix_map *sink_pix_map; unsigned int sink_bpp; + unsigned int mean_win_size; + struct v4l2_ctrl_handler hdl; + struct media_pad pads[2]; }; static const struct v4l2_mbus_framefmt sink_fmt_default = { @@ -159,7 +149,7 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_mbus_code_enum *code) { /* We only support one format for source pads */ - if (IS_SRC(code->pad)) { + if (VIMC_IS_SRC(code->pad)) { struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); if (code->index) @@ -185,7 +175,7 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, if (fse->index) return -EINVAL; - if (IS_SINK(fse->pad)) { + if (VIMC_IS_SINK(fse->pad)) { const struct vimc_deb_pix_map *vpix = vimc_deb_pix_map_by_code(fse->code); @@ -215,7 +205,7 @@ static int vimc_deb_get_fmt(struct v4l2_subdev *sd, vdeb->sink_fmt; /* Set the right code for the source pad */ - if (IS_SRC(fmt->pad)) + if (VIMC_IS_SRC(fmt->pad)) fmt->format.code = vdeb->src_code; return 0; @@ -262,7 +252,7 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, * Do not change the format of the source pad, * it is propagated from the sink */ - if (IS_SRC(fmt->pad)) { + if (VIMC_IS_SRC(fmt->pad)) { fmt->format = *sink_fmt; /* TODO: Add support for other formats */ fmt->format.code = vdeb->src_code; @@ -270,7 +260,7 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, /* Set the new format in the sink pad */ vimc_deb_adjust_sink_fmt(&fmt->format); - dev_dbg(vdeb->dev, "%s: sink format update: " + dev_dbg(vdeb->ved.dev, "%s: sink format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name, /* old */ @@ -351,11 +341,18 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static const struct v4l2_subdev_core_ops vimc_deb_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { .s_stream = vimc_deb_s_stream, }; static const struct v4l2_subdev_ops vimc_deb_ops = { + .core = &vimc_deb_core_ops, .pad = &vimc_deb_pad_ops, .video = &vimc_deb_video_ops, }; @@ -389,11 +386,11 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, * the top left corner of the mean window (considering the current * pixel as the center) */ - seek = deb_mean_win_size / 2; + seek = vdeb->mean_win_size / 2; /* Sum the values of the colors in the mean window */ - dev_dbg(vdeb->dev, + dev_dbg(vdeb->ved.dev, "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); @@ -426,7 +423,7 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, vdeb->sink_fmt.width, vdeb->sink_bpp); - dev_dbg(vdeb->dev, + dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", vdeb->sd.name, index, wlin, wcol, color); @@ -437,21 +434,21 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, /* Save how many values we already added */ n_rgb[color]++; - dev_dbg(vdeb->dev, "deb: %s: RGB CALC: val %d, n %d\n", + dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", vdeb->sd.name, rgb[color], n_rgb[color]); } } /* Calculate the mean */ for (i = 0; i < 3; i++) { - dev_dbg(vdeb->dev, + dev_dbg(vdeb->ved.dev, "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n", vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); if (n_rgb[i]) rgb[i] = rgb[i] / n_rgb[i]; - dev_dbg(vdeb->dev, + dev_dbg(vdeb->ved.dev, "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n", vdeb->sd.name, lin, col, i, rgb[i]); } @@ -476,14 +473,34 @@ static void *vimc_deb_process_frame(struct vimc_ent_device *ved, } return vdeb->src_frame; +} +static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vimc_deb_device *vdeb = + container_of(ctrl->handler, struct vimc_deb_device, hdl); + + switch (ctrl->id) { + case VIMC_CID_MEAN_WIN_SIZE: + vdeb->mean_win_size = ctrl->val; + break; + default: + return -EINVAL; + } + return 0; } +static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { + .s_ctrl = vimc_deb_s_ctrl, +}; + static void vimc_deb_release(struct v4l2_subdev *sd) { struct vimc_deb_device *vdeb = container_of(sd, struct vimc_deb_device, sd); + v4l2_ctrl_handler_free(&vdeb->hdl); + media_entity_cleanup(vdeb->ved.ent); kfree(vdeb); } @@ -491,44 +508,69 @@ static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = { .release = vimc_deb_release, }; -static void vimc_deb_comp_unbind(struct device *comp, struct device *master, - void *master_data) +void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) { - struct vimc_ent_device *ved = dev_get_drvdata(comp); - struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, - ved); + struct vimc_deb_device *vdeb; - vimc_ent_sd_unregister(ved, &vdeb->sd); + vdeb = container_of(ved, struct vimc_deb_device, ved); + v4l2_device_unregister_subdev(&vdeb->sd); } -static int vimc_deb_comp_bind(struct device *comp, struct device *master, - void *master_data) +static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, + .id = VIMC_CID_VIMC_CLASS, + .name = "VIMC Controls", + .type = V4L2_CTRL_TYPE_CTRL_CLASS, +}; + +static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { + .ops = &vimc_deb_ctrl_ops, + .id = VIMC_CID_MEAN_WIN_SIZE, + .name = "Debayer Mean Window Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 25, + .step = 2, + .def = 3, +}; + +struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, + const char *vcfg_name) { - struct v4l2_device *v4l2_dev = master_data; - struct vimc_platform_data *pdata = comp->platform_data; + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; struct vimc_deb_device *vdeb; int ret; /* Allocate the vdeb struct */ vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL); if (!vdeb) - return -ENOMEM; + return NULL; + + /* Create controls: */ + v4l2_ctrl_handler_init(&vdeb->hdl, 2); + v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL); + vdeb->sd.ctrl_handler = &vdeb->hdl; + if (vdeb->hdl.error) { + ret = vdeb->hdl.error; + goto err_free_vdeb; + } /* Initialize ved and sd */ + vdeb->pads[0].flags = MEDIA_PAD_FL_SINK; + vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, - pdata->entity_name, + vcfg_name, MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, - (const unsigned long[2]) {MEDIA_PAD_FL_SINK, - MEDIA_PAD_FL_SOURCE}, + vdeb->pads, &vimc_deb_int_ops, &vimc_deb_ops); - if (ret) { - kfree(vdeb); - return ret; - } + if (ret) + goto err_free_hdl; vdeb->ved.process_frame = vimc_deb_process_frame; - dev_set_drvdata(comp, &vdeb->ved); - vdeb->dev = comp; + vdeb->ved.dev = &vimc->pdev.dev; + vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; /* Initialize the frame format */ vdeb->sink_fmt = sink_fmt_default; @@ -541,46 +583,12 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; - return 0; -} - -static const struct component_ops vimc_deb_comp_ops = { - .bind = vimc_deb_comp_bind, - .unbind = vimc_deb_comp_unbind, -}; + return &vdeb->ved; -static int vimc_deb_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &vimc_deb_comp_ops); -} - -static int vimc_deb_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &vimc_deb_comp_ops); +err_free_hdl: + v4l2_ctrl_handler_free(&vdeb->hdl); +err_free_vdeb: + kfree(vdeb); - return 0; + return NULL; } - -static const struct platform_device_id vimc_deb_driver_ids[] = { - { - .name = VIMC_DEB_DRV_NAME, - }, - { } -}; - -static struct platform_driver vimc_deb_pdrv = { - .probe = vimc_deb_probe, - .remove = vimc_deb_remove, - .id_table = vimc_deb_driver_ids, - .driver = { - .name = VIMC_DEB_DRV_NAME, - }, -}; - -module_platform_driver(vimc_deb_pdrv); - -MODULE_DEVICE_TABLE(platform, vimc_deb_driver_ids); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Debayer"); -MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 49ab8d9dd9c9..2f88a7d9d67b 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -5,30 +5,22 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ -#include <linux/component.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/platform_device.h> +#include <linux/moduleparam.h> #include <linux/vmalloc.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-subdev.h> #include "vimc-common.h" -#define VIMC_SCA_DRV_NAME "vimc-scaler" - static unsigned int sca_mult = 3; module_param(sca_mult, uint, 0000); MODULE_PARM_DESC(sca_mult, " the image size multiplier"); -#define IS_SINK(pad) (!pad) -#define IS_SRC(pad) (pad) #define MAX_ZOOM 8 struct vimc_sca_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - struct device *dev; /* NOTE: the source fmt is the same as the sink * with the width and hight multiplied by mult */ @@ -37,6 +29,7 @@ struct vimc_sca_device { u8 *src_frame; unsigned int src_line_size; unsigned int bpp; + struct media_pad pads[2]; }; static const struct v4l2_mbus_framefmt sink_fmt_default = { @@ -98,7 +91,7 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, fse->min_width = VIMC_FRAME_MIN_WIDTH; fse->min_height = VIMC_FRAME_MIN_HEIGHT; - if (IS_SINK(fse->pad)) { + if (VIMC_IS_SINK(fse->pad)) { fse->max_width = VIMC_FRAME_MAX_WIDTH; fse->max_height = VIMC_FRAME_MAX_HEIGHT; } else { @@ -121,7 +114,7 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd, vsca->sink_fmt; /* Scale the frame size for the source pad */ - if (IS_SRC(format->pad)) { + if (VIMC_IS_SRC(format->pad)) { format->format.width = vsca->sink_fmt.width * sca_mult; format->format.height = vsca->sink_fmt.height * sca_mult; } @@ -170,7 +163,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, * Do not change the format of the source pad, * it is propagated from the sink */ - if (IS_SRC(fmt->pad)) { + if (VIMC_IS_SRC(fmt->pad)) { fmt->format = *sink_fmt; fmt->format.width = sink_fmt->width * sca_mult; fmt->format.height = sink_fmt->height * sca_mult; @@ -178,7 +171,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, /* Set the new format in the sink pad */ vimc_sca_adjust_sink_fmt(&fmt->format); - dev_dbg(vsca->dev, "%s: sink format update: " + dev_dbg(vsca->ved.dev, "%s: sink format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name, /* old */ @@ -278,7 +271,7 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, vsca->bpp); pixel = &sink_frame[index]; - dev_dbg(vsca->dev, + dev_dbg(vsca->ved.dev, "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n", vsca->sd.name, lin, col, index); @@ -288,7 +281,7 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult, vsca->sink_fmt.width * sca_mult, vsca->bpp); - dev_dbg(vsca->dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", + dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", vsca->sd.name, lin * sca_mult, col * sca_mult, index); /* Repeat this pixel mult times */ @@ -297,7 +290,7 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, * pixel repetition in a line */ for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) { - dev_dbg(vsca->dev, + dev_dbg(vsca->ved.dev, "sca: %s: sca: scale_pix src pos %d\n", vsca->sd.name, index + j); @@ -343,6 +336,7 @@ static void vimc_sca_release(struct v4l2_subdev *sd) struct vimc_sca_device *vsca = container_of(sd, struct vimc_sca_device, sd); + media_entity_cleanup(vsca->ved.ent); kfree(vsca); } @@ -350,89 +344,45 @@ static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = { .release = vimc_sca_release, }; -static void vimc_sca_comp_unbind(struct device *comp, struct device *master, - void *master_data) +void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) { - struct vimc_ent_device *ved = dev_get_drvdata(comp); - struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, - ved); + struct vimc_sca_device *vsca; - vimc_ent_sd_unregister(ved, &vsca->sd); + vsca = container_of(ved, struct vimc_sca_device, ved); + v4l2_device_unregister_subdev(&vsca->sd); } - -static int vimc_sca_comp_bind(struct device *comp, struct device *master, - void *master_data) +struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, + const char *vcfg_name) { - struct v4l2_device *v4l2_dev = master_data; - struct vimc_platform_data *pdata = comp->platform_data; + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; struct vimc_sca_device *vsca; int ret; /* Allocate the vsca struct */ vsca = kzalloc(sizeof(*vsca), GFP_KERNEL); if (!vsca) - return -ENOMEM; + return NULL; /* Initialize ved and sd */ + vsca->pads[0].flags = MEDIA_PAD_FL_SINK; + vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE; + ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, - pdata->entity_name, + vcfg_name, MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, - (const unsigned long[2]) {MEDIA_PAD_FL_SINK, - MEDIA_PAD_FL_SOURCE}, + vsca->pads, &vimc_sca_int_ops, &vimc_sca_ops); if (ret) { kfree(vsca); - return ret; + return NULL; } vsca->ved.process_frame = vimc_sca_process_frame; - dev_set_drvdata(comp, &vsca->ved); - vsca->dev = comp; + vsca->ved.dev = &vimc->pdev.dev; /* Initialize the frame format */ vsca->sink_fmt = sink_fmt_default; - return 0; -} - -static const struct component_ops vimc_sca_comp_ops = { - .bind = vimc_sca_comp_bind, - .unbind = vimc_sca_comp_unbind, -}; - -static int vimc_sca_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &vimc_sca_comp_ops); -} - -static int vimc_sca_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &vimc_sca_comp_ops); - - return 0; + return &vsca->ved; } - -static const struct platform_device_id vimc_sca_driver_ids[] = { - { - .name = VIMC_SCA_DRV_NAME, - }, - { } -}; - -static struct platform_driver vimc_sca_pdrv = { - .probe = vimc_sca_probe, - .remove = vimc_sca_remove, - .id_table = vimc_sca_driver_ids, - .driver = { - .name = VIMC_SCA_DRV_NAME, - }, -}; - -module_platform_driver(vimc_sca_pdrv); - -MODULE_DEVICE_TABLE(platform, vimc_sca_driver_ids); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Scaler"); -MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 6c53b9fc1617..32380f504591 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -5,10 +5,6 @@ * Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com> */ -#include <linux/component.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/platform_device.h> #include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-ctrls.h> @@ -18,18 +14,15 @@ #include "vimc-common.h" -#define VIMC_SEN_DRV_NAME "vimc-sensor" - struct vimc_sen_device { struct vimc_ent_device ved; struct v4l2_subdev sd; - struct device *dev; struct tpg_data tpg; - struct task_struct *kthread_sen; u8 *frame; /* The active format */ struct v4l2_mbus_framefmt mbus_format; struct v4l2_ctrl_handler hdl; + struct media_pad pad; }; static const struct v4l2_mbus_framefmt fmt_default = { @@ -164,7 +157,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, /* Set the new format */ vimc_sen_adjust_fmt(&fmt->format); - dev_dbg(vsen->dev, "%s: format update: " + dev_dbg(vsen->ved.dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, /* old */ @@ -208,10 +201,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) const struct vimc_pix_map *vpix; unsigned int frame_size; - if (vsen->kthread_sen) - /* tpg is already executing */ - return 0; - /* Calculate the frame size */ vpix = vimc_pix_map_by_code(vsen->mbus_format.code); frame_size = vsen->mbus_format.width * vpix->bpp * @@ -297,6 +286,7 @@ static void vimc_sen_release(struct v4l2_subdev *sd) v4l2_ctrl_handler_free(&vsen->hdl); tpg_free(&vsen->tpg); + media_entity_cleanup(vsen->ved.ent); kfree(vsen); } @@ -304,14 +294,12 @@ static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = { .release = vimc_sen_release, }; -static void vimc_sen_comp_unbind(struct device *comp, struct device *master, - void *master_data) +void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved) { - struct vimc_ent_device *ved = dev_get_drvdata(comp); - struct vimc_sen_device *vsen = - container_of(ved, struct vimc_sen_device, ved); + struct vimc_sen_device *vsen; - vimc_ent_sd_unregister(ved, &vsen->sd); + vsen = container_of(ved, struct vimc_sen_device, ved); + v4l2_device_unregister_subdev(&vsen->sd); } /* Image Processing Controls */ @@ -331,18 +319,17 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { .qmenu = tpg_pattern_strings, }; -static int vimc_sen_comp_bind(struct device *comp, struct device *master, - void *master_data) +struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, + const char *vcfg_name) { - struct v4l2_device *v4l2_dev = master_data; - struct vimc_platform_data *pdata = comp->platform_data; + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; struct vimc_sen_device *vsen; int ret; /* Allocate the vsen struct */ vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); if (!vsen) - return -ENOMEM; + return NULL; v4l2_ctrl_handler_init(&vsen->hdl, 4); @@ -366,78 +353,36 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, goto err_free_vsen; } + /* Initialize the test pattern generator */ + tpg_init(&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); + if (ret) + goto err_free_hdl; + /* Initialize ved and sd */ + vsen->pad.flags = MEDIA_PAD_FL_SOURCE; ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, - pdata->entity_name, - MEDIA_ENT_F_CAM_SENSOR, 1, - (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, + vcfg_name, + MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, &vimc_sen_int_ops, &vimc_sen_ops); if (ret) - goto err_free_hdl; + goto err_free_tpg; vsen->ved.process_frame = vimc_sen_process_frame; - dev_set_drvdata(comp, &vsen->ved); - vsen->dev = comp; + vsen->ved.dev = &vimc->pdev.dev; /* Initialize the frame format */ vsen->mbus_format = fmt_default; - /* Initialize the test pattern generator */ - tpg_init(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); - if (ret) - goto err_unregister_ent_sd; - - return 0; + return &vsen->ved; -err_unregister_ent_sd: - vimc_ent_sd_unregister(&vsen->ved, &vsen->sd); +err_free_tpg: + tpg_free(&vsen->tpg); err_free_hdl: v4l2_ctrl_handler_free(&vsen->hdl); err_free_vsen: kfree(vsen); - return ret; -} - -static const struct component_ops vimc_sen_comp_ops = { - .bind = vimc_sen_comp_bind, - .unbind = vimc_sen_comp_unbind, -}; - -static int vimc_sen_probe(struct platform_device *pdev) -{ - return component_add(&pdev->dev, &vimc_sen_comp_ops); -} - -static int vimc_sen_remove(struct platform_device *pdev) -{ - component_del(&pdev->dev, &vimc_sen_comp_ops); - - return 0; + return NULL; } - -static const struct platform_device_id vimc_sen_driver_ids[] = { - { - .name = VIMC_SEN_DRV_NAME, - }, - { } -}; - -static struct platform_driver vimc_sen_pdrv = { - .probe = vimc_sen_probe, - .remove = vimc_sen_remove, - .id_table = vimc_sen_driver_ids, - .driver = { - .name = VIMC_SEN_DRV_NAME, - }, -}; - -module_platform_driver(vimc_sen_pdrv); - -MODULE_DEVICE_TABLE(platform, vimc_sen_driver_ids); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Sensor"); -MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index 048d770e498b..cd6b55433c9e 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -7,7 +7,6 @@ */ #include <linux/init.h> -#include <linux/module.h> #include <linux/freezer.h> #include <linux/kthread.h> @@ -97,17 +96,26 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, sd = media_entity_to_v4l2_subdev(ved->ent); ret = v4l2_subdev_call(sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) { - pr_err("subdev_call error %s\n", - ved->ent->name); + dev_err(ved->dev, "subdev_call error %s\n", + ved->ent->name); vimc_streamer_pipeline_terminate(stream); return ret; } } entity = vimc_get_source_entity(ved->ent); - /* Check if the end of the pipeline was reached*/ - if (!entity) + /* Check if the end of the pipeline was reached */ + if (!entity) { + /* the first entity of the pipe should be source only */ + if (!vimc_is_source(ved->ent)) { + dev_err(ved->dev, + "first entity in the pipe '%s' is not a source\n", + ved->ent->name); + vimc_streamer_pipeline_terminate(stream); + return -EPIPE; + } return 0; + } /* Get the next device in the pipeline */ if (is_media_entity_v4l2_subdev(entity)) { @@ -217,4 +225,3 @@ int vimc_streamer_s_stream(struct vimc_stream *stream, return 0; } -EXPORT_SYMBOL_GPL(vimc_streamer_s_stream); diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile index 2f5762e3309a..e8a50c506dc9 100644 --- a/drivers/media/platform/vivid/Makefile +++ b/drivers/media/platform/vivid/Makefile @@ -3,7 +3,7 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ - vivid-osd.o + vivid-osd.o vivid-meta-cap.o vivid-meta-out.o ifeq ($(CONFIG_VIDEO_VIVID_CEC),y) vivid-objs += vivid-cec.o endif diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index 4d822dbed972..4d2413e87730 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -276,12 +276,11 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, unsigned int idx, bool is_source) { - char name[sizeof(dev->vid_out_dev.name) + 2]; u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; + char name[32]; - snprintf(name, sizeof(name), "%s%d", - is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name, - idx); + snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", + dev->inst, is_source ? "out" : "cap", idx); return cec_allocate_adapter(&vivid_cec_adap_ops, dev, name, caps, 1); } diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 53315c8dd2bb..c184f9b0be69 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -37,6 +37,8 @@ #include "vivid-osd.h" #include "vivid-cec.h" #include "vivid-ctrls.h" +#include "vivid-meta-cap.h" +#include "vivid-meta-out.h" #define VIVID_MODULE_NAME "vivid" @@ -79,6 +81,14 @@ static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; module_param_array(radio_tx_nr, int, NULL, 0444); MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); +static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(meta_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect"); + +static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(meta_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect"); + static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; module_param_array(ccs_cap_mode, int, NULL, 0444); MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n" @@ -95,10 +105,15 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1 module_param_array(multiplanar, uint, NULL, 0444); MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device."); -/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */ -static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d }; +/* + * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + + * vbi-out + vid-out + meta-cap + */ +static unsigned int node_types[VIVID_MAX_DEVS] = { + [0 ... (VIVID_MAX_DEVS - 1)] = 0x61d3d +}; module_param_array(node_types, uint, NULL, 0444); -MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n" +MODULE_PARM_DESC(node_types, " node types, default is 0x61d3d. Bitmask with the following meaning:\n" "\t\t bit 0: Video Capture node\n" "\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" "\t\t bit 4: Radio Receiver node\n" @@ -106,7 +121,9 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f "\t\t bit 8: Video Output node\n" "\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" "\t\t bit 12: Radio Transmitter node\n" - "\t\t bit 16: Framebuffer for testing overlays"); + "\t\t bit 16: Framebuffer for testing overlays\n" + "\t\t bit 17: Metadata Capture node\n" + "\t\t bit 18: Metadata Output node\n"); /* Default: 4 inputs */ static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; @@ -205,7 +222,8 @@ static int vidioc_querycap(struct file *file, void *priv, cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | dev->vbi_cap_caps | dev->vbi_out_caps | dev->radio_rx_caps | dev->radio_tx_caps | - dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS; + dev->sdr_cap_caps | dev->meta_cap_caps | + dev->meta_out_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -433,7 +451,9 @@ static bool vivid_is_last_user(struct vivid_dev *dev) vivid_is_in_use(&dev->vbi_out_dev) + vivid_is_in_use(&dev->sdr_cap_dev) + vivid_is_in_use(&dev->radio_rx_dev) + - vivid_is_in_use(&dev->radio_tx_dev); + vivid_is_in_use(&dev->radio_tx_dev) + + vivid_is_in_use(&dev->meta_cap_dev) + + vivid_is_in_use(&dev->meta_out_dev); return uses == 1; } @@ -459,6 +479,8 @@ static int vivid_fop_release(struct file *file) set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); } mutex_unlock(&dev->mutex); if (file->private_data == dev->overlay_cap_owner) @@ -604,6 +626,16 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = vidioc_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = vidioc_g_fmt_meta_cap, + + .vidioc_enum_fmt_meta_out = vidioc_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = vidioc_g_fmt_meta_out, }; /* ----------------------------------------------------------------- @@ -616,6 +648,9 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev) vivid_free_controls(dev); v4l2_device_unregister(&dev->v4l2_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif vfree(dev->scaled_line); vfree(dev->blended_line); vfree(dev->edid); @@ -645,14 +680,44 @@ static const struct media_device_ops vivid_media_ops = { }; #endif +static int vivid_create_queue(struct vivid_dev *dev, + struct vb2_queue *q, + u32 buf_type, + unsigned int min_buffers_needed, + const struct vb2_ops *ops) +{ + if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE && !dev->has_raw_vbi_cap) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + else if (buf_type == V4L2_BUF_TYPE_VBI_OUTPUT && !dev->has_raw_vbi_out) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + + q->type = buf_type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ; + if (allocators[dev->inst] != 1) + q->io_modes |= VB2_USERPTR; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = ops; + q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : + &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = min_buffers_needed; + q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; + q->supports_requests = true; + + return vb2_queue_init(q); +} + static int vivid_create_instance(struct platform_device *pdev, int inst) { static const struct v4l2_dv_timings def_dv_timings = V4L2_DV_BT_CEA_1280X720P60; - static const struct vb2_mem_ops * const vivid_mem_ops[2] = { - &vb2_vmalloc_memops, - &vb2_dma_contig_memops, - }; unsigned in_type_counter[4] = { 0, 0, 0, 0 }; unsigned out_type_counter[4] = { 0, 0, 0, 0 }; int ccs_cap = ccs_cap_mode[inst]; @@ -661,9 +726,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) bool has_modulator; struct vivid_dev *dev; struct video_device *vfd; - struct vb2_queue *q; unsigned node_type = node_types[inst]; - unsigned int allocator = allocators[inst]; v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; int ret; int i; @@ -758,6 +821,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap; } + /* do we create a meta capture device */ + dev->has_meta_cap = node_type & 0x20000; + + /* sanity checks */ + if ((in_type_counter[WEBCAM] || in_type_counter[HDMI]) && + !dev->has_vid_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "Webcam or HDMI input without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if ((in_type_counter[TV] || in_type_counter[SVID]) && + !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "TV or S-Video input without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + /* do we create a video output device? */ dev->has_vid_out = node_type & 0x0100; @@ -768,6 +850,24 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out; } + /* do we create a metadata output device */ + dev->has_meta_out = node_type & 0x40000; + + /* sanity checks */ + if (out_type_counter[SVID] && + !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "S-Video output without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "HDMI output without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + /* do we create a radio receiver device? */ dev->has_radio_rx = node_type & 0x0010; @@ -777,6 +877,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* do we create a software defined radio capture device? */ dev->has_sdr_cap = node_type & 0x0020; + /* do we have a TV tuner? */ + dev->has_tv_tuner = in_type_counter[TV]; + /* do we have a tuner? */ has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) || dev->has_radio_rx || dev->has_sdr_cap; @@ -828,7 +931,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; if (dev->has_audio_inputs) dev->vid_cap_caps |= V4L2_CAP_AUDIO; - if (in_type_counter[TV]) + if (dev->has_tv_tuner) dev->vid_cap_caps |= V4L2_CAP_TUNER; } if (dev->has_vid_out) { @@ -849,7 +952,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; if (dev->has_audio_inputs) dev->vbi_cap_caps |= V4L2_CAP_AUDIO; - if (in_type_counter[TV]) + if (dev->has_tv_tuner) dev->vbi_cap_caps |= V4L2_CAP_TUNER; } if (dev->has_vbi_out) { @@ -875,6 +978,23 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | V4L2_CAP_READWRITE; + /* set up the capabilities of meta capture device */ + if (dev->has_meta_cap) { + dev->meta_cap_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->meta_cap_caps |= V4L2_CAP_AUDIO; + if (dev->has_tv_tuner) + dev->meta_cap_caps |= V4L2_CAP_TUNER; + } + /* set up the capabilities of meta output device */ + if (dev->has_meta_out) { + dev->meta_out_caps = V4L2_CAP_META_OUTPUT | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->meta_out_caps |= V4L2_CAP_AUDIO; + } + ret = -ENOMEM; /* initialize the test pattern generator */ tpg_init(&dev->tpg, 640, 360); @@ -934,6 +1054,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO); } if (!dev->has_audio_outputs) { v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); @@ -942,6 +1065,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT); } if (!in_type_counter[TV] && !in_type_counter[SVID]) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD); @@ -959,12 +1085,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY); } if (!has_tuner) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER); } if (in_type_counter[HDMI] == 0) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); @@ -990,12 +1120,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES); v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY); v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY); /* configure internal data */ dev->fmt_cap = &vivid_formats[0]; @@ -1078,6 +1211,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) INIT_LIST_HEAD(&dev->vbi_cap_active); INIT_LIST_HEAD(&dev->vbi_out_active); INIT_LIST_HEAD(&dev->sdr_cap_active); + INIT_LIST_HEAD(&dev->meta_cap_active); + INIT_LIST_HEAD(&dev->meta_out_active); INIT_LIST_HEAD(&dev->cec_work_list); spin_lock_init(&dev->cec_slock); @@ -1092,126 +1227,69 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) goto unreg_dev; } - if (allocator == 1) + if (allocators[inst] == 1) dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - else if (allocator >= ARRAY_SIZE(vivid_mem_ops)) - allocator = 0; /* start creating the vb2 queues */ if (dev->has_vid_cap) { - snprintf(dev->vid_cap_dev.name, sizeof(dev->vid_cap_dev.name), - "vivid-%03d-vid-cap", inst); /* initialize vid_cap queue */ - q = &dev->vb_vid_cap_q; - q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vid_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vid_cap_q, + V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + &vivid_vid_cap_qops); if (ret) goto unreg_dev; } if (dev->has_vid_out) { - snprintf(dev->vid_out_dev.name, sizeof(dev->vid_out_dev.name), - "vivid-%03d-vid-out", inst); /* initialize vid_out queue */ - q = &dev->vb_vid_out_q; - q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : - V4L2_BUF_TYPE_VIDEO_OUTPUT; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vid_out_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vid_out_q, + V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + &vivid_vid_out_qops); if (ret) goto unreg_dev; } if (dev->has_vbi_cap) { /* initialize vbi_cap queue */ - q = &dev->vb_vbi_cap_q; - q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE : - V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vbi_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vbi_cap_q, + V4L2_BUF_TYPE_VBI_CAPTURE, 2, + &vivid_vbi_cap_qops); if (ret) goto unreg_dev; } if (dev->has_vbi_out) { /* initialize vbi_out queue */ - q = &dev->vb_vbi_out_q; - q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT : - V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_vbi_out_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_vbi_out_q, + V4L2_BUF_TYPE_VBI_OUTPUT, 2, + &vivid_vbi_out_qops); if (ret) goto unreg_dev; } if (dev->has_sdr_cap) { /* initialize sdr_cap queue */ - q = &dev->vb_sdr_cap_q; - q->type = V4L2_BUF_TYPE_SDR_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; - if (!allocator) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = &vivid_sdr_cap_qops; - q->mem_ops = vivid_mem_ops[allocator]; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 8; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - ret = vb2_queue_init(q); + ret = vivid_create_queue(dev, &dev->vb_sdr_cap_q, + V4L2_BUF_TYPE_SDR_CAPTURE, 8, + &vivid_sdr_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_cap) { + /* initialize meta_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_cap_q, + V4L2_BUF_TYPE_META_CAPTURE, 2, + &vivid_meta_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_out) { + /* initialize meta_out queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_out_q, + V4L2_BUF_TYPE_META_OUTPUT, 1, + &vivid_meta_out_qops); if (ret) goto unreg_dev; } @@ -1222,7 +1300,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret) goto unreg_dev; v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", - dev->fb_info.node); + dev->fb_info.node); } #ifdef CONFIG_VIDEO_VIVID_CEC @@ -1265,10 +1343,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out); /* finally start creating the device nodes */ if (dev->has_vid_cap) { vfd = &dev->vid_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-cap", inst); vfd->fops = &vivid_fops; vfd->ioctl_ops = &vivid_ioctl_ops; vfd->device_caps = dev->vid_cap_caps; @@ -1314,6 +1396,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (dev->has_vid_out) { vfd = &dev->vid_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-out", inst); vfd->vfl_dir = VFL_DIR_TX; vfd->fops = &vivid_fops; vfd->ioctl_ops = &vivid_ioctl_ops; @@ -1492,6 +1576,65 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) video_device_node_name(vfd)); } + if (dev->has_meta_cap) { + vfd = &dev->meta_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_cap_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_cap; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_cap_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_GRABBER, + meta_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_meta_out) { + vfd = &dev->meta_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-out", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_out_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_out_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_out; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_out_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_GRABBER, + meta_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata output device registered as %s\n", + video_device_node_name(vfd)); + } + #ifdef CONFIG_MEDIA_CONTROLLER /* Register the media device */ ret = media_device_register(&dev->mdev); @@ -1508,6 +1651,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) return 0; unreg_dev: + video_unregister_device(&dev->meta_out_dev); + video_unregister_device(&dev->meta_cap_dev); video_unregister_device(&dev->radio_tx_dev); video_unregister_device(&dev->radio_rx_dev); video_unregister_device(&dev->sdr_cap_dev); @@ -1580,7 +1725,6 @@ static int vivid_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); - media_device_cleanup(&dev->mdev); #endif if (dev->has_vid_cap) { @@ -1624,6 +1768,16 @@ static int vivid_remove(struct platform_device *pdev) unregister_framebuffer(&dev->fb_info); vivid_fb_release_buffers(dev); } + if (dev->has_meta_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_cap_dev)); + video_unregister_device(&dev->meta_cap_dev); + } + if (dev->has_meta_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_out_dev)); + video_unregister_device(&dev->meta_out_dev); + } cec_unregister_adapter(dev->cec_rx_adap); for (j = 0; j < MAX_OUTPUTS; j++) cec_unregister_adapter(dev->cec_tx_adap[j]); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 7ebb14673c75..59192b67231c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -131,6 +131,8 @@ struct vivid_dev { struct media_pad vbi_cap_pad; struct media_pad vbi_out_pad; struct media_pad sdr_cap_pad; + struct media_pad meta_cap_pad; + struct media_pad meta_out_pad; #endif struct v4l2_ctrl_handler ctrl_hdl_user_gen; struct v4l2_ctrl_handler ctrl_hdl_user_vid; @@ -153,6 +155,11 @@ struct vivid_dev { struct v4l2_ctrl_handler ctrl_hdl_radio_tx; struct video_device sdr_cap_dev; struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; + struct video_device meta_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_cap; + struct video_device meta_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_out; + spinlock_t slock; struct mutex mutex; @@ -164,6 +171,8 @@ struct vivid_dev { u32 sdr_cap_caps; u32 radio_rx_caps; u32 radio_tx_caps; + u32 meta_cap_caps; + u32 meta_out_caps; /* supported features */ bool multiplanar; @@ -189,6 +198,9 @@ struct vivid_dev { bool has_radio_tx; bool has_sdr_cap; bool has_fb; + bool has_meta_cap; + bool has_meta_out; + bool has_tv_tuner; bool can_loop_video; @@ -390,6 +402,8 @@ struct vivid_dev { struct list_head vid_cap_active; struct vb2_queue vb_vbi_cap_q; struct list_head vbi_cap_active; + struct vb2_queue vb_meta_cap_q; + struct list_head meta_cap_active; /* thread for generating video capture stream */ struct task_struct *kthread_vid_cap; @@ -407,6 +421,9 @@ struct vivid_dev { u32 vbi_cap_seq_count; bool vbi_cap_streaming; bool stream_sliced_vbi_cap; + u32 meta_cap_seq_start; + u32 meta_cap_seq_count; + bool meta_cap_streaming; /* video output */ const struct vivid_fmt *fmt_out; @@ -421,6 +438,8 @@ struct vivid_dev { struct list_head vid_out_active; struct vb2_queue vb_vbi_out_q; struct list_head vbi_out_active; + struct vb2_queue vb_meta_out_q; + struct list_head meta_out_active; /* video loop precalculated rectangles */ @@ -461,6 +480,9 @@ struct vivid_dev { u32 vbi_out_seq_count; bool vbi_out_streaming; bool stream_sliced_vbi_out; + u32 meta_out_seq_start; + u32 meta_out_seq_count; + bool meta_out_streaming; /* SDR capture */ struct vb2_queue vb_sdr_cap_q; @@ -527,6 +549,9 @@ struct vivid_dev { /* CEC OSD String */ char osd[14]; unsigned long osd_jiffies; + + bool meta_pts; + bool meta_scr; }; static inline bool vivid_is_webcam(const struct vivid_dev *dev) diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index cb19a9a73092..68e8124c7973 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -32,6 +32,7 @@ #define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8) #define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9) #define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) +#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) #define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) #define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) @@ -94,6 +95,9 @@ #define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110) +#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111) +#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112) + /* General User Controls */ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) @@ -110,6 +114,7 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); break; case VIVID_CID_BUTTON: dev->button_pressed = 30; @@ -262,6 +267,18 @@ static const struct v4l2_ctrl_config vivid_ctrl_disconnect = { .type = V4L2_CTRL_TYPE_BUTTON, }; +static const struct v4l2_area area = { + .width = 1000, + .height = 2000, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_area = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_AREA, + .name = "Area", + .type = V4L2_CTRL_TYPE_AREA, + .p_def.p_const = &area, +}; /* Framebuffer Controls */ @@ -1421,6 +1438,47 @@ static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = { .step = 1, }; +/* Metadata Capture Control */ + +static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, + ctrl_hdl_meta_cap); + + switch (ctrl->id) { + case VIVID_CID_META_CAP_GENERATE_PTS: + dev->meta_pts = ctrl->val; + break; + case VIVID_CID_META_CAP_GENERATE_SCR: + dev->meta_scr = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = { + .s_ctrl = vivid_meta_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_PTS, + .name = "Generate PTS", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_SCR, + .name = "Generate SCR", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; static const struct v4l2_ctrl_config vivid_ctrl_class = { .ops = &vivid_user_gen_ctrl_ops, @@ -1448,6 +1506,9 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap; + struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap; + struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out; + struct v4l2_ctrl_config vivid_ctrl_dv_timings = { .ops = &vivid_vid_cap_ctrl_ops, .id = VIVID_CID_DV_TIMINGS, @@ -1486,6 +1547,10 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); v4l2_ctrl_handler_init(hdl_sdr_cap, 19); v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_meta_cap, 2); + v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_meta_out, 2); + v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL); /* User Controls */ dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, @@ -1522,6 +1587,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); @@ -1743,6 +1809,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_sdr_cap_fm_deviation, NULL); } + if (dev->has_meta_cap) { + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_pts, NULL); + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_src_clk, NULL); + } + if (hdl_user_gen->error) return hdl_user_gen->error; if (hdl_user_vid->error) @@ -1817,6 +1890,20 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, return hdl_sdr_cap->error; dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; } + if (dev->has_meta_cap) { + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false); + if (hdl_meta_cap->error) + return hdl_meta_cap->error; + dev->meta_cap_dev.ctrl_handler = hdl_meta_cap; + } + if (dev->has_meta_out) { + v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false); + if (hdl_meta_out->error) + return hdl_meta_out->error; + dev->meta_out_dev.ctrl_handler = hdl_meta_out; + } return 0; } @@ -1836,4 +1923,6 @@ void vivid_free_controls(struct vivid_dev *dev) v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out); } diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 003319d7816d..01a9d671b947 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -39,6 +39,7 @@ #include "vivid-osd.h" #include "vivid-ctrls.h" #include "vivid-kthread-cap.h" +#include "vivid-meta-cap.h" static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) { @@ -677,6 +678,7 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, { struct vivid_buffer *vid_cap_buf = NULL; struct vivid_buffer *vbi_cap_buf = NULL; + struct vivid_buffer *meta_cap_buf = NULL; u64 f_time = 0; dprintk(dev, 1, "Video Capture Thread Tick\n"); @@ -704,15 +706,19 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, list_del(&vbi_cap_buf->list); } } + if (!list_empty(&dev->meta_cap_active)) { + meta_cap_buf = list_entry(dev->meta_cap_active.next, + struct vivid_buffer, list); + list_del(&meta_cap_buf->list); + } + spin_unlock(&dev->slock); - if (!vid_cap_buf && !vbi_cap_buf) + if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf) goto update_mv; f_time = dev->cap_frame_period * dev->vid_cap_seq_count + dev->cap_stream_start + dev->time_wrap_offset; - if (!dev->tstamp_src_is_soe) - f_time += dev->cap_frame_eof_offset; if (vid_cap_buf) { v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, @@ -735,6 +741,8 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, vid_cap_buf->vb.vb2_buf.index); vid_cap_buf->vb.vb2_buf.timestamp = f_time; + if (!dev->tstamp_src_is_soe) + vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset; } if (vbi_cap_buf) { @@ -756,8 +764,22 @@ static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, /* If capturing a VBI, offset by 0.05 */ vbi_period = dev->cap_frame_period * 5; do_div(vbi_period, 100); - vbi_cap_buf->vb.vb2_buf.timestamp = f_time + vbi_period; + vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period; + } + + if (meta_cap_buf) { + v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time); + v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_cap %d done\n", + meta_cap_buf->vb.vb2_buf.index); + meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset; } + dev->dqbuf_error = false; update_mv: @@ -796,7 +818,11 @@ static int vivid_thread_vid_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->cap_seq_resync) { dev->jiffies_vid_cap = cur_jiffies; @@ -835,6 +861,7 @@ static int vivid_thread_vid_cap(void *data) dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; + dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start; vivid_thread_vid_cap_tick(dev, dropped_bufs); @@ -883,8 +910,10 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) if (pstreaming == &dev->vid_cap_streaming) dev->vid_cap_seq_start = seq_count; - else + else if (pstreaming == &dev->vbi_cap_streaming) dev->vbi_cap_seq_start = seq_count; + else + dev->meta_cap_seq_start = seq_count; *pstreaming = true; return 0; } @@ -894,6 +923,7 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) dev->vid_cap_seq_start = dev->seq_wrap * 128; dev->vbi_cap_seq_start = dev->seq_wrap * 128; + dev->meta_cap_seq_start = dev->seq_wrap * 128; dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, "%s-vid-cap", dev->v4l2_dev.name); @@ -951,13 +981,27 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) } } - if (dev->vid_cap_streaming || dev->vbi_cap_streaming) + if (pstreaming == &dev->meta_cap_streaming) { + while (!list_empty(&dev->meta_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_cap_streaming || dev->vbi_cap_streaming || + dev->meta_cap_streaming) return; /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_cap); dev->kthread_vid_cap = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index ce5bcda2348c..6780687978f9 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -38,11 +38,13 @@ #include "vivid-osd.h" #include "vivid-ctrls.h" #include "vivid-kthread-out.h" +#include "vivid-meta-out.h" static void vivid_thread_vid_out_tick(struct vivid_dev *dev) { struct vivid_buffer *vid_out_buf = NULL; struct vivid_buffer *vbi_out_buf = NULL; + struct vivid_buffer *meta_out_buf = NULL; dprintk(dev, 1, "Video Output Thread Tick\n"); @@ -69,9 +71,14 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) struct vivid_buffer, list); list_del(&vbi_out_buf->list); } + if (!list_empty(&dev->meta_out_active)) { + meta_out_buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&meta_out_buf->list); + } spin_unlock(&dev->slock); - if (!vid_out_buf && !vbi_out_buf) + if (!vid_out_buf && !vbi_out_buf && !meta_out_buf) return; if (vid_out_buf) { @@ -111,6 +118,21 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev) dprintk(dev, 2, "vbi_out buffer %d done\n", vbi_out_buf->vb.vb2_buf.index); } + if (meta_out_buf) { + v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vivid_meta_out_process(dev, meta_out_buf); + meta_out_buf->vb.sequence = dev->meta_out_seq_count; + meta_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_out buffer %d done\n", + meta_out_buf->vb.vb2_buf.index); + } + dev->dqbuf_error = false; } @@ -136,6 +158,7 @@ static int vivid_thread_vid_out(void *data) dev->out_seq_count = 0xffffff80U; dev->jiffies_vid_out = jiffies; dev->vid_out_seq_start = dev->vbi_out_seq_start = 0; + dev->meta_out_seq_start = 0; dev->out_seq_resync = false; for (;;) { @@ -143,7 +166,11 @@ static int vivid_thread_vid_out(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->out_seq_resync) { dev->jiffies_vid_out = cur_jiffies; @@ -178,6 +205,7 @@ static int vivid_thread_vid_out(void *data) dev->out_seq_count = buffers_since_start + dev->out_seq_offset; dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; + dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start; vivid_thread_vid_out_tick(dev); mutex_unlock(&dev->mutex); @@ -229,8 +257,10 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) if (pstreaming == &dev->vid_out_streaming) dev->vid_out_seq_start = seq_count; - else + else if (pstreaming == &dev->vbi_out_streaming) dev->vbi_out_seq_start = seq_count; + else + dev->meta_out_seq_start = seq_count; *pstreaming = true; return 0; } @@ -239,6 +269,7 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) dev->jiffies_vid_out = jiffies; dev->vid_out_seq_start = dev->seq_wrap * 128; dev->vbi_out_seq_start = dev->seq_wrap * 128; + dev->meta_out_seq_start = dev->seq_wrap * 128; dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, "%s-vid-out", dev->v4l2_dev.name); @@ -296,13 +327,27 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) } } - if (dev->vid_out_streaming || dev->vbi_out_streaming) + if (pstreaming == &dev->meta_out_streaming) { + while (!list_empty(&dev->meta_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_out buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_out_streaming || dev->vbi_out_streaming || + dev->meta_out_streaming) return; /* shutdown control thread */ vivid_grab_controls(dev, false); - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_vid_out); dev->kthread_vid_out = NULL; - mutex_lock(&dev->mutex); } diff --git a/drivers/media/platform/vivid/vivid-meta-cap.c b/drivers/media/platform/vivid/vivid-meta-cap.c new file mode 100644 index 000000000000..780f96860a6d --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-cap.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-cap.c - meta capture support functions. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/usb/video.h> + +#include "vivid-core.h" +#include "vivid-kthread-cap.h" +#include "vivid-meta-cap.h" + +static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int size = sizeof(struct vivid_uvc_meta_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + } else { + sizes[0] = size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int meta_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_uvc_meta_buf); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void meta_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->meta_cap_active); + spin_unlock(&dev->slock); +} + +static int meta_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->meta_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, + &dev->meta_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void meta_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->meta_cap_streaming); +} + +static void meta_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_cap); +} + +const struct vb2_ops vivid_meta_cap_qops = { + .queue_setup = meta_cap_queue_setup, + .buf_prepare = meta_cap_buf_prepare, + .buf_queue = meta_cap_buf_queue, + .start_streaming = meta_cap_start_streaming, + .stop_streaming = meta_cap_stop_streaming, + .buf_request_complete = meta_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_CAPTURE; + f->pixelformat = V4L2_META_FMT_UVC; + return 0; +} + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_cap) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_UVC; + meta->buffersize = sizeof(struct vivid_uvc_meta_buf); + return 0; +} + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe) +{ + struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + int buf_off = 0; + + buf->vb.sequence = dev->meta_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.sequence /= 2; + memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0)); + + meta->ns = ktime_get_ns(); + meta->sof = buf->vb.sequence * 30; + meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length); + meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF; + + if ((buf->vb.sequence % 2) == 0) + meta->flags |= UVC_STREAM_FID; + + dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x", + __func__, meta->ns, meta->sof, meta->length, meta->flags); + if (dev->meta_pts) { + meta->flags |= UVC_STREAM_PTS; + meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT); + buf_off = 4; + dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf)); + } + + if (dev->meta_scr) { + meta->flags |= UVC_STREAM_SCR; + meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset), + VIVID_META_CLOCK_UNIT); + + meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000; + dprintk(dev, 2, " stc: %u, sof counter: %u\n", + *(__u32 *)(meta->buf + buf_off), + *(__u16 *)(meta->buf + buf_off + 4)); + } + dprintk(dev, 2, "\n"); +} diff --git a/drivers/media/platform/vivid/vivid-meta-cap.h b/drivers/media/platform/vivid/vivid-meta-cap.h new file mode 100644 index 000000000000..4670d00d1576 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-cap.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-cap.h - meta capture support functions. + */ +#ifndef _VIVID_META_CAP_H_ +#define _VIVID_META_CAP_H_ + +#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */ + +struct vivid_uvc_meta_buf { + __u64 ns; + __u16 sof; + __u8 length; + __u8 flags; + __u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */ +} __packed; + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe); + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f); + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_cap_qops; + +#endif diff --git a/drivers/media/platform/vivid/vivid-meta-out.c b/drivers/media/platform/vivid/vivid-meta-out.c new file mode 100644 index 000000000000..ff8a039aba72 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-out.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-out.c - meta output support functions. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/videodev2.h> +#include <media/v4l2-common.h> +#include <linux/usb/video.h> + +#include "vivid-core.h" +#include "vivid-kthread-out.h" +#include "vivid-meta-out.h" + +static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int size = sizeof(struct vivid_meta_out_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + } else { + sizes[0] = size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int meta_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_meta_out_buf); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void meta_out_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->meta_out_active); + spin_unlock(&dev->slock); +} + +static int meta_out_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->meta_out_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, + &dev->meta_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void meta_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->meta_out_streaming); +} + +static void meta_out_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_out); +} + +const struct vb2_ops vivid_meta_out_qops = { + .queue_setup = meta_out_queue_setup, + .buf_prepare = meta_out_buf_prepare, + .buf_queue = meta_out_buf_queue, + .start_streaming = meta_out_start_streaming, + .stop_streaming = meta_out_stop_streaming, + .buf_request_complete = meta_out_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_OUTPUT; + f->pixelformat = V4L2_META_FMT_VIVID; + return 0; +} + +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_out) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_VIVID; + meta->buffersize = sizeof(struct vivid_meta_out_buf); + return 0; +} + +void vivid_meta_out_process(struct vivid_dev *dev, + struct vivid_buffer *buf) +{ + struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + tpg_s_brightness(&dev->tpg, meta->brightness); + tpg_s_contrast(&dev->tpg, meta->contrast); + tpg_s_saturation(&dev->tpg, meta->saturation); + tpg_s_hue(&dev->tpg, meta->hue); + dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", + __func__, meta->brightness, meta->contrast, + meta->saturation, meta->hue); +} diff --git a/drivers/media/platform/vivid/vivid-meta-out.h b/drivers/media/platform/vivid/vivid-meta-out.h new file mode 100644 index 000000000000..0c639b7c2842 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-meta-out.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-out.h - meta output support functions. + */ +#ifndef _VIVID_META_OUT_H_ +#define _VIVID_META_OUT_H_ + +struct vivid_meta_out_buf { + u16 brightness; + u16 contrast; + u16 saturation; + s16 hue; +}; + +void vivid_meta_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_out_qops; + +#endif diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 9acc709b0740..2b7522e16efc 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -141,7 +141,11 @@ static int vivid_thread_sdr_cap(void *data) if (kthread_should_stop()) break; - mutex_lock(&dev->mutex); + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; if (dev->sdr_cap_seq_resync) { dev->jiffies_sdr_cap = cur_jiffies; @@ -303,10 +307,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq) } /* shutdown control thread */ - mutex_unlock(&dev->mutex); kthread_stop(dev->kthread_sdr_cap); dev->kthread_sdr_cap = NULL; - mutex_lock(&dev->mutex); } static void sdr_cap_buf_request_complete(struct vb2_buffer *vb) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 8cbaa0c998ed..e94beef008c8 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -223,9 +223,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_out_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_cap) - return 0; - dev->vid_cap_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); for (i = 0; i < VIDEO_MAX_FRAME; i++) @@ -1359,7 +1356,9 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) if (i == dev->input) return 0; - if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) + if (vb2_is_busy(&dev->vb_vid_cap_q) || + vb2_is_busy(&dev->vb_vbi_cap_q) || + vb2_is_busy(&dev->vb_meta_cap_q)) return -EBUSY; dev->input = i; @@ -1369,6 +1368,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; } dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; + dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; vivid_update_format_cap(dev, false); if (dev->colorspace) { diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 148b663a6075..ee3446e3217c 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -161,9 +161,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) if (vb2_is_streaming(&dev->vb_vid_cap_q)) dev->can_loop_video = vivid_vid_can_loop(dev); - if (dev->kthread_vid_out) - return 0; - dev->vid_out_seq_count = 0; dprintk(dev, 1, "%s\n", __func__); if (dev->start_streaming_error) { @@ -1082,7 +1079,9 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) if (o == dev->output) return 0; - if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) + if (vb2_is_busy(&dev->vb_vid_out_q) || + vb2_is_busy(&dev->vb_vbi_out_q) || + vb2_is_busy(&dev->vb_meta_out_q)) return -EBUSY; dev->output = o; @@ -1093,6 +1092,7 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) dev->vid_out_dev.tvnorms = 0; dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; + dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms; vivid_update_format_out(dev); v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h index 5aec4d17eb21..2378bdae57ae 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.h +++ b/drivers/media/platform/xilinx/xilinx-dma.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Xilinx Video DMA * diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h index f71e2b650453..a528a32ea1dc 100644 --- a/drivers/media/platform/xilinx/xilinx-vip.h +++ b/drivers/media/platform/xilinx/xilinx-vip.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Xilinx Video IP Core * diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h index e65fce9538f9..cc52c1854dbd 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.h +++ b/drivers/media/platform/xilinx/xilinx-vipp.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Xilinx Video IP Composite Device * diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h index 90cf44245283..855845911ffc 100644 --- a/drivers/media/platform/xilinx/xilinx-vtc.h +++ b/drivers/media/platform/xilinx/xilinx-vtc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * Xilinx Video Timing Controller * diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 104ac41c6f96..112376873167 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1148,8 +1148,7 @@ static int wl1273_fm_fops_release(struct file *file) if (radio->rds_users > 0) { radio->rds_users--; if (radio->rds_users == 0) { - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; + mutex_lock(&core->lock); radio->irq_flags &= ~WL1273_RDS_EVENT; diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 7541698a0be1..f491420d7b53 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -482,6 +482,8 @@ static int si470x_i2c_remove(struct i2c_client *client) if (radio->gpio_reset) gpiod_set_value(radio->gpio_reset, 0); + v4l2_ctrl_handler_free(&radio->hdl); + v4l2_device_unregister(&radio->v4l2_dev); return 0; } diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 37a850421fbb..ed95244da894 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -83,6 +83,7 @@ struct imon_usb_dev_descr { __u16 flags; #define IMON_NO_FLAGS 0 #define IMON_NEED_20MS_PKT_DELAY 1 +#define IMON_SUPPRESS_REPEATED_KEYS 2 struct imon_panel_key_table key_table[]; }; @@ -149,8 +150,9 @@ struct imon_context { struct timer_list ttimer; /* touch screen timer */ int touch_x; /* x coordinate on touchscreen */ int touch_y; /* y coordinate on touchscreen */ - struct imon_usb_dev_descr *dev_descr; /* device description with key - table for front panels */ + const struct imon_usb_dev_descr *dev_descr; + /* device description with key */ + /* table for front panels */ }; #define TOUCH_TIMEOUT (HZ/30) @@ -315,6 +317,32 @@ static const struct imon_usb_dev_descr imon_DH102 = { } }; +/* imon ultrabay front panel key table */ +static const struct imon_usb_dev_descr ultrabay_table = { + .flags = IMON_SUPPRESS_REPEATED_KEYS, + .key_table = { + { 0x0000000f0000ffeell, KEY_MEDIA }, /* Go */ + { 0x000000000100ffeell, KEY_UP }, + { 0x000000000001ffeell, KEY_DOWN }, + { 0x000000160000ffeell, KEY_ENTER }, + { 0x0000001f0000ffeell, KEY_AUDIO }, /* Music */ + { 0x000000200000ffeell, KEY_VIDEO }, /* Movie */ + { 0x000000210000ffeell, KEY_CAMERA }, /* Photo */ + { 0x000000270000ffeell, KEY_DVD }, /* DVD */ + { 0x000000230000ffeell, KEY_TV }, /* TV */ + { 0x000000050000ffeell, KEY_PREVIOUS }, /* Previous */ + { 0x000000070000ffeell, KEY_REWIND }, + { 0x000000040000ffeell, KEY_STOP }, + { 0x000000020000ffeell, KEY_PLAYPAUSE }, + { 0x000000080000ffeell, KEY_FASTFORWARD }, + { 0x000000060000ffeell, KEY_NEXT }, /* Next */ + { 0x000100000000ffeell, KEY_VOLUMEUP }, + { 0x010000000000ffeell, KEY_VOLUMEDOWN }, + { 0x000000010000ffeell, KEY_MUTE }, + { 0, KEY_RESERVED }, + } +}; + /* * USB Device ID for iMON USB Control Boards * @@ -1264,9 +1292,11 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode) static u32 imon_panel_key_lookup(struct imon_context *ictx, u64 code) { - int i; + const struct imon_panel_key_table *key_table; u32 keycode = KEY_RESERVED; - struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; + int i; + + key_table = ictx->dev_descr->key_table; for (i = 0; key_table[i].hw_code != 0; i++) { if (key_table[i].hw_code == (code | 0xffee)) { @@ -1550,7 +1580,6 @@ static void imon_incoming_packet(struct imon_context *ictx, u32 kc; u64 scancode; int press_type = 0; - long msec; ktime_t t; static ktime_t prev_time; u8 ktype; @@ -1598,8 +1627,7 @@ static void imon_incoming_packet(struct imon_context *ictx, spin_unlock_irqrestore(&ictx->kc_lock, flags); /* send touchscreen events through input subsystem if touchpad data */ - if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 && - buf[7] == 0x86) { + if (ictx->touch && len == 8 && buf[7] == 0x86) { imon_touch_event(ictx, buf); return; @@ -1653,14 +1681,16 @@ static void imon_incoming_packet(struct imon_context *ictx, spin_lock_irqsave(&ictx->kc_lock, flags); t = ktime_get(); - /* KEY_MUTE repeats from knob need to be suppressed */ - if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) { - msec = ktime_ms_delta(t, prev_time); - if (msec < ictx->idev->rep[REP_DELAY]) { + /* KEY repeats from knob and panel that need to be suppressed */ + if (ictx->kc == KEY_MUTE || + ictx->dev_descr->flags & IMON_SUPPRESS_REPEATED_KEYS) { + if (ictx->kc == ictx->last_keycode && + ktime_ms_delta(t, prev_time) < ictx->idev->rep[REP_DELAY]) { spin_unlock_irqrestore(&ictx->kc_lock, flags); return; } } + prev_time = t; kc = ictx->kc; @@ -1848,6 +1878,14 @@ static void imon_get_ffdc_type(struct imon_context *ictx) dev_info(ictx->dev, "0xffdc iMON Inside, iMON IR"); ictx->display_supported = false; break; + /* Soundgraph iMON UltraBay */ + case 0x98: + dev_info(ictx->dev, "0xffdc iMON UltraBay, LCD + IR"); + detected_display_type = IMON_DISPLAY_TYPE_LCD; + allowed_protos = RC_PROTO_BIT_IMON | RC_PROTO_BIT_RC6_MCE; + ictx->dev_descr = &ultrabay_table; + break; + default: dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; @@ -1979,10 +2017,12 @@ out: static struct input_dev *imon_init_idev(struct imon_context *ictx) { - struct imon_panel_key_table *key_table = ictx->dev_descr->key_table; + const struct imon_panel_key_table *key_table; struct input_dev *idev; int ret, i; + key_table = ictx->dev_descr->key_table; + idev = input_allocate_device(); if (!idev) goto out; diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c index d4aedcf76418..aae0a3cc9479 100644 --- a/drivers/media/rc/imon_raw.c +++ b/drivers/media/rc/imon_raw.c @@ -57,32 +57,18 @@ static void imon_ir_data(struct imon *imon) * fls will tell us the highest bit set plus 1 (or 0 if no * bits are set). */ + rawir.pulse = !rawir.pulse; bit = fls64(data & (BIT_ULL(offset) - 1)); if (bit < offset) { - dev_dbg(imon->dev, "pulse: %d bits", offset - bit); - rawir.pulse = true; + dev_dbg(imon->dev, "%s: %d bits", + rawir.pulse ? "pulse" : "space", offset - bit); rawir.duration = (offset - bit) * BIT_DURATION; ir_raw_event_store_with_filter(imon->rcdev, &rawir); - if (bit == 0) - break; - offset = bit; } - /* - * Find highest clear bit which is less than offset. - * - * Just invert the data and use same trick as above. - */ - bit = fls64(~data & (BIT_ULL(offset) - 1)); - dev_dbg(imon->dev, "space: %d bits", offset - bit); - - rawir.pulse = false; - rawir.duration = (offset - bit) * BIT_DURATION; - ir_raw_event_store_with_filter(imon->rcdev, &rawir); - - offset = bit; + data = ~data; } while (offset > 0); if (packet_no == 0x0a && !imon->rcdev->idle) { diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c index 64fb65a9a19f..028df5cb1828 100644 --- a/drivers/media/rc/ir-rcmm-decoder.c +++ b/drivers/media/rc/ir-rcmm-decoder.c @@ -79,7 +79,7 @@ static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!ev.pulse) break; - if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT / 2)) + if (!eq_margin(ev.duration, RCMM_PREFIX_PULSE, RCMM_UNIT)) break; data->state = STATE_LOW; @@ -91,7 +91,7 @@ static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) if (ev.pulse) break; - if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT / 2)) + if (!eq_margin(ev.duration, RCMM_PULSE_0, RCMM_UNIT)) break; data->state = STATE_BUMP; @@ -164,6 +164,8 @@ static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev) break; } + dev_dbg(&dev->dev, "RC-MM decode failed at count %d state %d (%uus %s)\n", + data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse)); data->state = STATE_INACTIVE; return -EINVAL; } diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 3ab6cec0dc3b..07667c04c1d2 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -382,7 +382,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) ite_dbg("%s called", __func__); /* clear the array just in case */ - memset(last_sent, 0, ARRAY_SIZE(last_sent)); + memset(last_sent, 0, sizeof(last_sent)); spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index a56fc634d2d6..63261ef6380a 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-avermedia-rm-ks.o \ rc-avertv-303.o \ rc-azurewave-ad-tu700.o \ + rc-beelink-gs1.o \ rc-behold.o \ rc-behold-columbus.o \ rc-budget-ci-old.o \ @@ -114,6 +115,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-tt-1500.o \ rc-twinhan-dtv-cab-ci.o \ rc-twinhan1027.o \ + rc-vega-s9x.o \ rc-videomate-m1f.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ diff --git a/drivers/media/rc/keymaps/rc-beelink-gs1.c b/drivers/media/rc/keymaps/rc-beelink-gs1.c new file mode 100644 index 000000000000..cedbd5d20bc7 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-beelink-gs1.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright (c) 2019 Clément Péron + +#include <media/rc-map.h> +#include <linux/module.h> + +/* + * Keymap for the Beelink GS1 remote control + */ + +static struct rc_map_table beelink_gs1_table[] = { + /* + * TV Keys (Power, Learn and Volume) + * { 0x40400d, KEY_TV }, + * { 0x80f1, KEY_TV }, + * { 0x80f3, KEY_TV }, + * { 0x80f4, KEY_TV }, + */ + + { 0x8051, KEY_POWER }, + { 0x804d, KEY_MUTE }, + { 0x8040, KEY_CONFIG }, + + { 0x8026, KEY_UP }, + { 0x8028, KEY_DOWN }, + { 0x8025, KEY_LEFT }, + { 0x8027, KEY_RIGHT }, + { 0x800d, KEY_OK }, + + { 0x8053, KEY_HOME }, + { 0x80bc, KEY_MEDIA }, + { 0x801b, KEY_BACK }, + { 0x8049, KEY_MENU }, + + { 0x804e, KEY_VOLUMEUP }, + { 0x8056, KEY_VOLUMEDOWN }, + + { 0x8054, KEY_SUBTITLE }, /* Web */ + { 0x8052, KEY_EPG }, /* Media */ + + { 0x8041, KEY_CHANNELUP }, + { 0x8042, KEY_CHANNELDOWN }, + + { 0x8031, KEY_1 }, + { 0x8032, KEY_2 }, + { 0x8033, KEY_3 }, + + { 0x8034, KEY_4 }, + { 0x8035, KEY_5 }, + { 0x8036, KEY_6 }, + + { 0x8037, KEY_7 }, + { 0x8038, KEY_8 }, + { 0x8039, KEY_9 }, + + { 0x8044, KEY_DELETE }, + { 0x8030, KEY_0 }, + { 0x8058, KEY_MODE }, /* # Input Method */ +}; + +static struct rc_map_list beelink_gs1_map = { + .map = { + .scan = beelink_gs1_table, + .size = ARRAY_SIZE(beelink_gs1_table), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_BEELINK_GS1, + } +}; + +static int __init init_rc_map_beelink_gs1(void) +{ + return rc_map_register(&beelink_gs1_map); +} + +static void __exit exit_rc_map_beelink_gs1(void) +{ + rc_map_unregister(&beelink_gs1_map); +} + +module_init(init_rc_map_beelink_gs1) +module_exit(exit_rc_map_beelink_gs1) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Clément Péron <peron.clem@gmail.com>"); diff --git a/drivers/media/rc/keymaps/rc-vega-s9x.c b/drivers/media/rc/keymaps/rc-vega-s9x.c new file mode 100644 index 000000000000..bf210c4dc535 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-vega-s9x.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2019 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the Tronsmart Vega S9x remote control +// + +static struct rc_map_table vega_s9x[] = { + { 0x18, KEY_POWER }, + { 0x17, KEY_MUTE }, // mouse + + { 0x46, KEY_UP }, + { 0x47, KEY_LEFT }, + { 0x55, KEY_OK }, + { 0x15, KEY_RIGHT }, + { 0x16, KEY_DOWN }, + + { 0x06, KEY_HOME }, + { 0x42, KEY_PLAYPAUSE}, + { 0x40, KEY_BACK }, + + { 0x14, KEY_VOLUMEDOWN }, + { 0x04, KEY_MENU }, + { 0x10, KEY_VOLUMEUP }, +}; + +static struct rc_map_list vega_s9x_map = { + .map = { + .scan = vega_s9x, + .size = ARRAY_SIZE(vega_s9x), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_VEGA_S9X, + } +}; + +static int __init init_rc_map_vega_s9x(void) +{ + return rc_map_register(&vega_s9x_map); +} + +static void __exit exit_rc_map_vega_s9x(void) +{ + rc_map_unregister(&vega_s9x_map); +} + +module_init(init_rc_map_vega_s9x) +module_exit(exit_rc_map_vega_s9x) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 3fc9829a9233..f9616158bcf4 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -564,7 +564,7 @@ static int mceusb_cmd_datasize(u8 cmd, u8 subcmd) datasize = 4; break; case MCE_CMD_G_REVISION: - datasize = 2; + datasize = 4; break; case MCE_RSP_EQWAKESUPPORT: case MCE_RSP_GETWAKESOURCE: @@ -600,14 +600,9 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, char *inout; u8 cmd, subcmd, *data; struct device *dev = ir->dev; - int start, skip = 0; u32 carrier, period; - /* skip meaningless 0xb1 0x60 header bytes on orig receiver */ - if (ir->flags.microsoft_gen1 && !out && !offset) - skip = 2; - - if (len <= skip) + if (offset < 0 || offset >= buf_len) return; dev_dbg(dev, "%cx data[%d]: %*ph (len=%d sz=%d)", @@ -616,11 +611,32 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, inout = out ? "Request" : "Got"; - start = offset + skip; - cmd = buf[start] & 0xff; - subcmd = buf[start + 1] & 0xff; - data = buf + start + 2; + cmd = buf[offset]; + subcmd = (offset + 1 < buf_len) ? buf[offset + 1] : 0; + data = &buf[offset] + 2; + + /* Trace meaningless 0xb1 0x60 header bytes on original receiver */ + if (ir->flags.microsoft_gen1 && !out && !offset) { + dev_dbg(dev, "MCE gen 1 header"); + return; + } + + /* Trace IR data header or trailer */ + if (cmd != MCE_CMD_PORT_IR && + (cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA) { + if (cmd == MCE_IRDATA_TRAILER) + dev_dbg(dev, "End of raw IR data"); + else + dev_dbg(dev, "Raw IR data, %d pulse/space samples", + cmd & MCE_PACKET_LENGTH_MASK); + return; + } + + /* Unexpected end of buffer? */ + if (offset + len > buf_len) + return; + /* Decode MCE command/response */ switch (cmd) { case MCE_CMD_NULL: if (subcmd == MCE_CMD_NULL) @@ -644,7 +660,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, dev_dbg(dev, "Get hw/sw rev?"); else dev_dbg(dev, "hw/sw rev %*ph", - 4, &buf[start + 2]); + 4, &buf[offset + 2]); break; case MCE_CMD_RESUME: dev_dbg(dev, "Device resume requested"); @@ -746,13 +762,6 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len, default: break; } - - if (cmd == MCE_IRDATA_TRAILER) - dev_dbg(dev, "End of raw IR data"); - else if ((cmd != MCE_CMD_PORT_IR) && - ((cmd & MCE_PORT_MASK) == MCE_COMMAND_IRDATA)) - dev_dbg(dev, "Raw IR data, %d pulse/space samples", - cmd & MCE_PACKET_LENGTH_MASK); #endif } @@ -1136,32 +1145,62 @@ static int mceusb_set_rx_carrier_report(struct rc_dev *dev, int enable) } /* + * Handle PORT_SYS/IR command response received from the MCE device. + * + * Assumes single response with all its data (not truncated) + * in buf_in[]. The response itself determines its total length + * (mceusb_cmd_datasize() + 2) and hence the minimum size of buf_in[]. + * * We don't do anything but print debug spew for many of the command bits * we receive from the hardware, but some of them are useful information * we want to store so that we can use them. */ -static void mceusb_handle_command(struct mceusb_dev *ir, int index) +static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in) { + u8 cmd = buf_in[0]; + u8 subcmd = buf_in[1]; + u8 *hi = &buf_in[2]; /* read only when required */ + u8 *lo = &buf_in[3]; /* read only when required */ struct ir_raw_event rawir = {}; - u8 hi = ir->buf_in[index + 1] & 0xff; - u8 lo = ir->buf_in[index + 2] & 0xff; u32 carrier_cycles; u32 cycles_fix; - switch (ir->buf_in[index]) { - /* the one and only 5-byte return value command */ - case MCE_RSP_GETPORTSTATUS: - if ((ir->buf_in[index + 4] & 0xff) == 0x00) - ir->txports_cabled |= 1 << hi; - break; + if (cmd == MCE_CMD_PORT_SYS) { + switch (subcmd) { + /* the one and only 5-byte return value command */ + case MCE_RSP_GETPORTSTATUS: + if (buf_in[5] == 0) + ir->txports_cabled |= 1 << *hi; + break; + + /* 1-byte return value commands */ + case MCE_RSP_EQEMVER: + ir->emver = *hi; + break; + + /* No return value commands */ + case MCE_RSP_CMD_ILLEGAL: + ir->need_reset = true; + break; + + default: + break; + } + + return; + } + if (cmd != MCE_CMD_PORT_IR) + return; + + switch (subcmd) { /* 2-byte return value commands */ case MCE_RSP_EQIRTIMEOUT: - ir->rc->timeout = US_TO_NS((hi << 8 | lo) * MCE_TIME_UNIT); + ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT); break; case MCE_RSP_EQIRNUMPORTS: - ir->num_txports = hi; - ir->num_rxports = lo; + ir->num_txports = *hi; + ir->num_rxports = *lo; break; case MCE_RSP_EQIRRXCFCNT: /* @@ -1174,7 +1213,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) */ if (ir->carrier_report_enabled && ir->learning_active && ir->pulse_tunit > 0) { - carrier_cycles = (hi << 8 | lo); + carrier_cycles = (*hi << 8 | *lo); /* * Adjust carrier cycle count by adding * 1 missed count per pulse "on" @@ -1192,24 +1231,24 @@ static void mceusb_handle_command(struct mceusb_dev *ir, int index) break; /* 1-byte return value commands */ - case MCE_RSP_EQEMVER: - ir->emver = hi; - break; case MCE_RSP_EQIRTXPORTS: - ir->tx_mask = hi; + ir->tx_mask = *hi; break; case MCE_RSP_EQIRRXPORTEN: - ir->learning_active = ((hi & 0x02) == 0x02); - if (ir->rxports_active != hi) { + ir->learning_active = ((*hi & 0x02) == 0x02); + if (ir->rxports_active != *hi) { dev_info(ir->dev, "%s-range (0x%x) receiver active", - ir->learning_active ? "short" : "long", hi); - ir->rxports_active = hi; + ir->learning_active ? "short" : "long", *hi); + ir->rxports_active = *hi; } break; + + /* No return value commands */ case MCE_RSP_CMD_ILLEGAL: case MCE_RSP_TX_TIMEOUT: ir->need_reset = true; break; + default: break; } @@ -1235,7 +1274,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]); mceusb_dev_printdata(ir, ir->buf_in, buf_len, i - 1, ir->rem + 2, false); - mceusb_handle_command(ir, i); + if (i + ir->rem < buf_len) + mceusb_handle_command(ir, &ir->buf_in[i - 1]); ir->parser_state = CMD_DATA; break; case PARSE_IRDATA: @@ -1264,15 +1304,22 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) ir->rem--; break; case CMD_HEADER: - /* decode mce packets of the form (84),AA,BB,CC,DD */ - /* IR data packets can span USB messages - rem */ ir->cmd = ir->buf_in[i]; if ((ir->cmd == MCE_CMD_PORT_IR) || ((ir->cmd & MCE_PORT_MASK) != MCE_COMMAND_IRDATA)) { + /* + * got PORT_SYS, PORT_IR, or unknown + * command response prefix + */ ir->parser_state = SUBCMD; continue; } + /* + * got IR data prefix (0x80 + num_bytes) + * decode MCE packets of the form {0x83, AA, BB, CC} + * IR data packets can span USB messages + */ ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK); mceusb_dev_printdata(ir, ir->buf_in, buf_len, i, ir->rem + 1, false); @@ -1296,6 +1343,14 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) if (ir->parser_state != CMD_HEADER && !ir->rem) ir->parser_state = CMD_HEADER; } + + /* + * Accept IR data spanning multiple rx buffers. + * Reject MCE command response spanning multiple rx buffers. + */ + if (ir->parser_state != PARSE_IRDATA || !ir->rem) + ir->parser_state = CMD_HEADER; + if (event) { dev_dbg(ir->dev, "processed IR data"); ir_raw_event_handle(ir->rc); diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 9f21b3e8b377..5f36244cc34f 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * Remote Controller core raw events header * * Copyright (C) 2010 by Mauro Carvalho Chehab diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 13da4c5c7d17..7741151606ef 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1773,6 +1773,7 @@ static int rc_prepare_rx_device(struct rc_dev *dev) set_bit(MSC_SCAN, dev->input_dev->mscbit); /* Pointer/mouse events */ + set_bit(INPUT_PROP_POINTING_STICK, dev->input_dev->propbit); set_bit(EV_REL, dev->input_dev->evbit); set_bit(REL_X, dev->input_dev->relbit); set_bit(REL_Y, dev->input_dev->relbit); diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c index 451ec4e9dcfa..b8eb5bc4d9be 100644 --- a/drivers/media/rc/tango-ir.c +++ b/drivers/media/rc/tango-ir.c @@ -157,20 +157,10 @@ static int tango_ir_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rc_dev *rc; struct tango_ir *ir; - struct resource *rc5_res; - struct resource *rc6_res; u64 clkrate, clkdiv; int irq, err; u32 val; - rc5_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!rc5_res) - return -EINVAL; - - rc6_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!rc6_res) - return -EINVAL; - irq = platform_get_irq(pdev, 0); if (irq <= 0) return -EINVAL; @@ -179,11 +169,11 @@ static int tango_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; - ir->rc5_base = devm_ioremap_resource(dev, rc5_res); + ir->rc5_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ir->rc5_base)) return PTR_ERR(ir->rc5_base); - ir->rc6_base = devm_ioremap_resource(dev, rc6_res); + ir->rc6_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(ir->rc6_base)) return PTR_ERR(ir->rc6_base); diff --git a/drivers/media/tuners/qm1d1c0042.c b/drivers/media/tuners/qm1d1c0042.c index 83ca5dc047ea..0e26d22f0b26 100644 --- a/drivers/media/tuners/qm1d1c0042.c +++ b/drivers/media/tuners/qm1d1c0042.c @@ -206,7 +206,7 @@ static int qm1d1c0042_set_params(struct dvb_frontend *fe) if (ret < 0) return ret; - a = (freq + state->cfg.xtal_freq / 2) / state->cfg.xtal_freq; + a = DIV_ROUND_CLOSEST(freq, state->cfg.xtal_freq); state->regs[0x06] &= 0x40; state->regs[0x06] |= (a - 12) / 4; diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index e87040d6eca7..898e0f9f8b70 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -118,6 +118,11 @@ static int si2157_init(struct dvb_frontend *fe) goto err; } + if (dev->dont_load_firmware) { + dev_info(&client->dev, "device is buggy, skipping firmware download\n"); + goto skip_fw_download; + } + /* query chip revision */ memcpy(cmd.args, "\x02", 1); cmd.wlen = 1; @@ -440,6 +445,7 @@ static int si2157_probe(struct i2c_client *client, i2c_set_clientdata(client, dev); dev->fe = cfg->fe; dev->inversion = cfg->inversion; + dev->dont_load_firmware = cfg->dont_load_firmware; dev->if_port = cfg->if_port; dev->chiptype = (u8)id->driver_data; dev->if_frequency = 5000000; /* default value of property 0x0706 */ diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h index c22ca784f43f..ffdece3c2eaa 100644 --- a/drivers/media/tuners/si2157.h +++ b/drivers/media/tuners/si2157.h @@ -11,29 +11,34 @@ #include <media/media-device.h> #include <media/dvb_frontend.h> -/* - * I2C address - * 0x60 +/** + * struct si2157_config - configuration parameters for si2157 + * + * @fe: + * frontend returned by driver + * @mdev: + * media device returned by driver + * @inversion: + * spectral inversion + * @dont_load_firmware: + * Instead of uploading a new firmware, use the existing one + * @if_port: + * Port selection + * Select the RF interface to use (pins 9+11 or 12+13) + * + * Note: + * The I2C address of this demod is 0x60. */ struct si2157_config { - /* - * frontend - */ struct dvb_frontend *fe; #if defined(CONFIG_MEDIA_CONTROLLER) struct media_device *mdev; #endif - /* - * Spectral Inversion - */ - bool inversion; + unsigned int inversion:1; + unsigned int dont_load_firmware:1; - /* - * Port selection - * Select the RF interface to use (pins 9+11 or 12+13) - */ u8 if_port; }; diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 2bda903358da..778f81b39996 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -23,8 +23,9 @@ enum si2157_pads { struct si2157_dev { struct mutex i2c_mutex; struct dvb_frontend *fe; - bool active; - bool inversion; + unsigned int active:1; + unsigned int inversion:1; + unsigned int dont_load_firmware:1; u8 chiptype; u8 if_port; u32 if_frequency; diff --git a/drivers/media/tuners/tuner-xc2028-types.h b/drivers/media/tuners/tuner-xc2028-types.h index 50d017a4822a..fcca39d3e006 100644 --- a/drivers/media/tuners/tuner-xc2028-types.h +++ b/drivers/media/tuners/tuner-xc2028-types.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * tuner-xc2028_types * * This file includes internal tipes to be used inside tuner-xc2028. diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h index 7b58bc06e35c..2dd45d0765d7 100644 --- a/drivers/media/tuners/tuner-xc2028.h +++ b/drivers/media/tuners/tuner-xc2028.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * tuner-xc2028 * * Copyright (c) 2007-2008 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 1826ff825c2e..039963a7765b 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -295,7 +295,7 @@ static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c, mutex_unlock(&fc_usb->data_mutex); - return 0; + return ret; } /* actual bus specific access functions, @@ -504,7 +504,13 @@ urb_error: static int flexcop_usb_init(struct flexcop_usb *fc_usb) { /* use the alternate setting with the larges buffer */ - usb_set_interface(fc_usb->udev,0,1); + int ret = usb_set_interface(fc_usb->udev, 0, 1); + + if (ret) { + err("set interface failed."); + return ret; + } + switch (fc_usb->udev->speed) { case USB_SPEED_LOW: err("cannot handle USB speed because it is too slow."); @@ -538,6 +544,9 @@ static int flexcop_usb_probe(struct usb_interface *intf, struct flexcop_device *fc = NULL; int ret; + if (intf->cur_altsetting->desc.bNumEndpoints < 1) + return -ENODEV; + if ((fc = flexcop_device_kmalloc(sizeof(struct flexcop_usb))) == NULL) { err("out of memory\n"); return -ENOMEM; diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 74f3b29d9c60..2fe2b2d335ba 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_CX231XX depends on VIDEO_DEV && I2C && I2C_MUX select VIDEO_TUNER select VIDEO_TVEEPROM - select VIDEOBUF_VMALLOC + select VIDEOBUF2_VMALLOC select VIDEO_CX25840 select VIDEO_CX2341X diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 6d218a036966..1aec4459f50a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -60,10 +60,6 @@ #define MCI_MODE_MEMORY_READ 0x000 #define MCI_MODE_MEMORY_WRITE 0x4000 -static unsigned int mpegbufs = 8; -module_param(mpegbufs, int, 0644); -MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); - static unsigned int mpeglines = 128; module_param(mpeglines, int, 0644); MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); @@ -1080,16 +1076,6 @@ static int cx231xx_load_firmware(struct cx231xx *dev) return 0; } -static void cx231xx_417_check_encoder(struct cx231xx *dev) -{ - u32 status, seq; - - status = 0; - seq = 0; - cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq); - dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq); -} - static void cx231xx_codec_settings(struct cx231xx *dev) { dprintk(1, "%s()\n", __func__); @@ -1227,40 +1213,25 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) /* ------------------------------------------------------------------ */ -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) { - struct cx231xx_fh *fh = q->priv_data; + struct cx231xx *dev = vb2_get_drv_priv(vq); + unsigned int size = mpeglinesize * mpeglines; - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; + dev->ts1.ts_packet_size = mpeglinesize; + dev->ts1.ts_packet_count = mpeglines; - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - *count = mpegbufs; + if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; - return 0; -} - -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = mpeglinesize * mpeglines; - BUG_ON(in_interrupt()); - - spin_lock_irqsave(&dev->video_mode.slock, flags); - if (dev->USE_ISO) { - if (dev->video_mode.isoc_ctl.buf == buf) - dev->video_mode.isoc_ctl.buf = NULL; - } else { - if (dev->video_mode.bulk_ctl.buf == buf) - dev->video_mode.bulk_ctl.buf = NULL; - } - spin_unlock_irqrestore(&dev->video_mode.slock, flags); - videobuf_waiton(vq, &buf->vb, 0, 0); - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + return 0; } static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb, @@ -1276,13 +1247,13 @@ static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *ur return; buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); + struct cx231xx_buffer, list); dev->video_mode.isoc_ctl.buf = buf; dma_q->mpeg_buffer_done = 1; } /* Fill buffer */ buf = dev->video_mode.isoc_ctl.buf; - vbuf = videobuf_to_vmalloc(&buf->vb); + vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); if ((dma_q->mpeg_buffer_completed+len) < mpeglines*mpeglinesize) { @@ -1306,11 +1277,10 @@ static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *ur memcpy(vbuf+dma_q->mpeg_buffer_completed, data, tail_data); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - buf->vb.ts = ktime_get_ns(); - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = dma_q->sequence++; + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); dma_q->mpeg_buffer_completed = 0; if (len - tail_data > 0) { @@ -1331,17 +1301,15 @@ static void buffer_filled(char *data, int len, struct urb *urb, if (list_empty(&dma_q->active)) return; - buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); + buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list); /* Fill buffer */ - vbuf = videobuf_to_vmalloc(&buf->vb); + vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); memcpy(vbuf, data, len); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - buf->vb.ts = ktime_get_ns(); - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + buf->vb.sequence = dma_q->sequence++; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } static int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) @@ -1394,100 +1362,104 @@ static int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) return 0; } -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) +static void buffer_queue(struct vb2_buffer *vb) { - struct cx231xx_fh *fh = q->priv_data; struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; - int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; + container_of(vb, struct cx231xx_buffer, vb.vb2_buf); + struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + unsigned long flags; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; - buf->vb.width = fh->dev->ts1.ts_packet_size; - buf->vb.height = fh->dev->ts1.ts_packet_count; - buf->vb.size = size; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc < 0) - goto fail; - } + spin_lock_irqsave(&dev->video_mode.slock, flags); + list_add_tail(&buf->list, &vidq->active); + spin_unlock_irqrestore(&dev->video_mode.slock, flags); +} - if (dev->USE_ISO) { - if (!dev->video_mode.isoc_ctl.num_bufs) - urb_init = 1; - } else { - if (!dev->video_mode.bulk_ctl.num_bufs) - urb_init = 1; +static void return_all_buffers(struct cx231xx *dev, + enum vb2_buffer_state state) +{ + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + struct cx231xx_buffer *buf, *node; + unsigned long flags; + + spin_lock_irqsave(&dev->video_mode.slock, flags); + list_for_each_entry_safe(buf, node, &vidq->active, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); } - dev_dbg(dev->dev, - "urb_init=%d dev->video_mode.max_pkt_size=%d\n", - urb_init, dev->video_mode.max_pkt_size); + spin_unlock_irqrestore(&dev->video_mode.slock, flags); +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct cx231xx *dev = vb2_get_drv_priv(vq); + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + int ret = 0; + + vidq->sequence = 0; dev->mode_tv = 1; - if (urb_init) { - rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - rc = cx231xx_unmute_audio(dev); - if (dev->USE_ISO) { - cx231xx_set_alt_setting(dev, INDEX_TS1, 4); - rc = cx231xx_init_isoc(dev, mpeglines, - mpegbufs, - dev->ts1_mode.max_pkt_size, - cx231xx_isoc_copy); - } else { - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - rc = cx231xx_init_bulk(dev, mpeglines, - mpegbufs, - dev->ts1_mode.max_pkt_size, - cx231xx_bulk_copy); - } - if (rc < 0) - goto fail; - } + cx231xx_set_alt_setting(dev, INDEX_VANC, 1); + cx231xx_set_gpio_value(dev, 2, 0); - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + cx231xx_initialize_codec(dev); + + cx231xx_start_TS1(dev); + + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + if (dev->USE_ISO) + ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->ts1_mode.max_pkt_size, + cx231xx_isoc_copy); + else + ret = cx231xx_init_bulk(dev, 320, 5, + dev->ts1_mode.max_pkt_size, + cx231xx_bulk_copy); + if (ret) + return_all_buffers(dev, VB2_BUF_STATE_QUEUED); -fail: - free_buffer(q, buf); - return rc; + call_all(dev, video, s_stream, 1); + return ret; } -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void stop_streaming(struct vb2_queue *vq) { - struct cx231xx_fh *fh = q->priv_data; + struct cx231xx *dev = vb2_get_drv_priv(vq); + unsigned long flags; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + call_all(dev, video, s_stream, 0); - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + cx231xx_stop_TS1(dev); -} + /* do this before setting alternate! */ + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + cx231xx_set_mode(dev, CX231XX_SUSPEND); -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - /*struct cx231xx_fh *fh = q->priv_data;*/ - /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/ + cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, + CX231xx_RAW_BITS_NONE); - free_buffer(q, buf); + spin_lock_irqsave(&dev->video_mode.slock, flags); + if (dev->USE_ISO) + dev->video_mode.isoc_ctl.buf = NULL; + else + dev->video_mode.bulk_ctl.buf = NULL; + spin_unlock_irqrestore(&dev->video_mode.slock, flags); + return_all_buffers(dev, VB2_BUF_STATE_ERROR); } -static const struct videobuf_queue_ops cx231xx_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, +static struct vb2_ops cx231xx_video_qops = { + .queue_setup = queue_setup, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ */ @@ -1495,8 +1467,7 @@ static const struct videobuf_queue_ops cx231xx_qops = { static int vidioc_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1511,8 +1482,7 @@ static int vidioc_g_pixelaspect(struct file *file, void *priv, static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1533,8 +1503,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) { - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); *norm = dev->encodernorm.id; return 0; @@ -1542,8 +1511,7 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); unsigned int i; for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++) @@ -1575,8 +1543,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctl) { - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); struct v4l2_subdev *sd; dprintk(3, "enter vidioc_s_ctrl()\n"); @@ -1601,8 +1568,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); dprintk(3, "enter vidioc_g_fmt_vid_cap()\n"); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; @@ -1621,8 +1587,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); dprintk(3, "enter vidioc_try_fmt_vid_cap()\n"); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; @@ -1636,230 +1601,21 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->vidq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->vidq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->vidq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - - return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_streamon()\n"); - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - if (dev->USE_ISO) - cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_isoc_copy); - else { - cx231xx_init_bulk(dev, 320, - 5, - dev->ts1_mode.max_pkt_size, - cx231xx_bulk_copy); - } - dprintk(3, "exit vidioc_streamon()\n"); - return videobuf_streamon(&fh->vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx231xx_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->vidq); -} - static int vidioc_log_status(struct file *file, void *priv) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); call_all(dev, core, log_status); return v4l2_ctrl_log_status(file, priv); } -static int mpeg_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct cx231xx *dev = video_drvdata(file); - struct cx231xx_fh *fh; - - dprintk(2, "%s()\n", __func__); - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) { - mutex_unlock(&dev->lock); - return -ENOMEM; - } - - file->private_data = fh; - v4l2_fh_init(&fh->fh, vdev); - fh->dev = dev; - - - videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops, - NULL, &dev->video_mode.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), fh, &dev->lock); -/* - videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops, - dev->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), - fh, &dev->lock); -*/ - - cx231xx_set_alt_setting(dev, INDEX_VANC, 1); - cx231xx_set_gpio_value(dev, 2, 0); - - cx231xx_initialize_codec(dev); - - mutex_unlock(&dev->lock); - v4l2_fh_add(&fh->fh); - cx231xx_start_TS1(dev); - - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(3, "mpeg_release()! dev=0x%p\n", dev); - - mutex_lock(&dev->lock); - - cx231xx_stop_TS1(dev); - - /* do this before setting alternate! */ - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - cx231xx_set_mode(dev, CX231XX_SUSPEND); - - cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, - CX231xx_RAW_BITS_NONE); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - - msleep(500); - cx231xx_417_check_encoder(dev); - - } - } - - if (fh->vidq.streaming) - videobuf_streamoff(&fh->vidq); - if (fh->vidq.reading) - videobuf_read_stop(&fh->vidq); - - videobuf_mmap_free(&fh->vidq); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh); - mutex_unlock(&dev->lock); - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ - /* Start mpeg encoder on first read. */ - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx231xx_initialize_codec(dev) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static __poll_t mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - __poll_t req_events = poll_requested_events(wait); - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - __poll_t res = 0; - - if (v4l2_event_pending(&fh->fh)) - res |= EPOLLPRI; - else - poll_wait(file, &fh->fh.wait, wait); - - if (!(req_events & (EPOLLIN | EPOLLRDNORM))) - return res; - - mutex_lock(&dev->lock); - res |= videobuf_poll_stream(file, &fh->vidq, wait); - mutex_unlock(&dev->lock); - return res; -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx231xx_fh *fh = file->private_data; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->vidq, vma); -} - static const struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; @@ -1881,12 +1637,12 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = vidioc_log_status, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = cx231xx_g_register, @@ -1980,6 +1736,7 @@ int cx231xx_417_register(struct cx231xx *dev) /* FIXME: Port1 hardcoded here */ int err = -ENODEV; struct cx231xx_tsport *tsport = &dev->ts1; + struct vb2_queue *q; dprintk(1, "%s()\n", __func__); @@ -2017,6 +1774,21 @@ int cx231xx_417_register(struct cx231xx *dev) /* Allocate and initialize V4L video device */ cx231xx_video_dev_init(dev, dev->udev, &dev->v4l_device, &cx231xx_mpeg_template, "mpeg"); + q = &dev->mpegq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx231xx_buffer); + q->ops = &cx231xx_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; + q->lock = &dev->lock; + err = vb2_queue_init(q); + if (err) + return err; + dev->v4l_device.queue = q; + err = video_register_device(&dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 9ef362e221df..fd6e2df3d1b7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -14,7 +14,6 @@ #include <linux/soundcard.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#include <linux/proc_fs.h> #include <linux/module.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index d417b5fe4093..0974965e848f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -1240,7 +1240,7 @@ int cx231xx_init_ctrl_pin_status(struct cx231xx *dev) int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev, u8 analog_or_digital) { - int status = 0; + int status; /* first set the direction to output */ status = cx231xx_set_gpio_direction(dev, diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index e123e74c549e..92efe6c1f47b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1479,13 +1479,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev, goto err_dev_init; } - /* init video dma queues */ + /* init video dma queue */ INIT_LIST_HEAD(&dev->video_mode.vidq.active); - INIT_LIST_HEAD(&dev->video_mode.vidq.queued); - /* init vbi dma queues */ + /* init vbi dma queue */ INIT_LIST_HEAD(&dev->vbi_mode.vidq.active); - INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued); /* Reset other chips required if they are tied up with GPIO pins */ cx231xx_add_into_devlist(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index fba7ccdf5a25..d2f143a096d1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -153,131 +153,98 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb) Vbi buf operations ------------------------------------------------------------------*/ -static int -vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int vbi_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) { - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = vb2_get_drv_priv(vq); u32 height = 0; height = ((dev->norm & V4L2_STD_625_50) ? PAL_VBI_LINES : NTSC_VBI_LINES); - *size = (dev->width * height * 2 * 2); - if (0 == *count) - *count = CX231XX_DEF_VBI_BUF; - - if (*count < CX231XX_MIN_BUF) - *count = CX231XX_MIN_BUF; - + *nplanes = 1; + sizes[0] = (dev->width * height * 2 * 2); return 0; } /* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) -{ - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; - BUG_ON(in_interrupt()); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->vbi_mode.slock, flags); - if (dev->vbi_mode.bulk_ctl.buf == buf) - dev->vbi_mode.bulk_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) +static int vbi_buf_prepare(struct vb2_buffer *vb) { - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; + struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); u32 height = 0; + u32 size; height = ((dev->norm & V4L2_STD_625_50) ? PAL_VBI_LINES : NTSC_VBI_LINES); - buf->vb.size = ((dev->width << 1) * height * 2); + size = ((dev->width << 1) * height * 2); - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + if (vb2_plane_size(vb, 0) < size) return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = height; - buf->vb.field = field; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (!dev->vbi_mode.bulk_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS, - CX231XX_NUM_VBI_BUFS, - dev->vbi_mode.alt_max_pkt_size[0], - cx231xx_isoc_vbi_copy); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; + vb2_set_plane_payload(vb, 0, size); return 0; - -fail: - free_buffer(vq, buf); - return rc; } -static void -vbi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static void vbi_buf_queue(struct vb2_buffer *vb) { + struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; + container_of(vb, struct cx231xx_buffer, vb.vb2_buf); struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; + unsigned long flags; - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + spin_lock_irqsave(&dev->vbi_mode.slock, flags); + list_add_tail(&buf->list, &vidq->active); + spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); +} + +static void return_all_buffers(struct cx231xx *dev, + enum vb2_buffer_state state) +{ + struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; + struct cx231xx_buffer *buf, *node; + unsigned long flags; + spin_lock_irqsave(&dev->vbi_mode.slock, flags); + dev->vbi_mode.bulk_ctl.buf = NULL; + list_for_each_entry_safe(buf, node, &vidq->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + spin_unlock_irqrestore(&dev->vbi_mode.slock, flags); } -static void vbi_buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static int vbi_start_streaming(struct vb2_queue *vq, unsigned int count) { - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); + struct cx231xx *dev = vb2_get_drv_priv(vq); + struct cx231xx_dmaqueue *vidq = &dev->vbi_mode.vidq; + int ret; + + vidq->sequence = 0; + ret = cx231xx_init_vbi_isoc(dev, CX231XX_NUM_VBI_PACKETS, + CX231XX_NUM_VBI_BUFS, + dev->vbi_mode.alt_max_pkt_size[0], + cx231xx_isoc_vbi_copy); + if (ret) + return_all_buffers(dev, VB2_BUF_STATE_QUEUED); + return ret; +} +static void vbi_stop_streaming(struct vb2_queue *vq) +{ + struct cx231xx *dev = vb2_get_drv_priv(vq); - free_buffer(vq, buf); + return_all_buffers(dev, VB2_BUF_STATE_ERROR); } -const struct videobuf_queue_ops cx231xx_vbi_qops = { - .buf_setup = vbi_buffer_setup, - .buf_prepare = vbi_buffer_prepare, - .buf_queue = vbi_buffer_queue, - .buf_release = vbi_buffer_release, +struct vb2_ops cx231xx_vbi_qops = { + .queue_setup = vbi_queue_setup, + .buf_prepare = vbi_buf_prepare, + .buf_queue = vbi_buf_queue, + .start_streaming = vbi_start_streaming, + .stop_streaming = vbi_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* ------------------------------------------------------------------ @@ -512,16 +479,15 @@ static inline void vbi_buffer_filled(struct cx231xx *dev, struct cx231xx_buffer *buf) { /* Advice that buffer was filled */ - /* dev_dbg(dev->dev, "[%p/%d] wakeup\n", buf, buf->vb.i); */ + /* dev_dbg(dev->dev, "[%p/%d] wakeup\n", buf, buf->vb.index); */ - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - buf->vb.ts = ktime_get_ns(); + buf->vb.sequence = dma_q->sequence++; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); dev->vbi_mode.bulk_ctl.buf = NULL; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, @@ -611,11 +577,11 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, } /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); + *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list); /* Cleans up buffer - Useful for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); + outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0); + memset(outp, 0, vb2_plane_size(&(*buf)->vb.vb2_buf, 0)); dev->vbi_mode.bulk_ctl.buf = *buf; @@ -656,7 +622,7 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, if (buf == NULL) return -EINVAL; - p_out_buffer = videobuf_to_vmalloc(&buf->vb); + p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); if (dma_q->bytes_left_in_line != _line_size) { current_line_bytes_copied = diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.h b/drivers/media/usb/cx231xx/cx231xx-vbi.h index 7cddd629fbfc..0b21bee5fa30 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.h +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.h @@ -10,7 +10,7 @@ #ifndef _CX231XX_VBI_H #define _CX231XX_VBI_H -extern const struct videobuf_queue_ops cx231xx_vbi_qops; +extern struct vb2_ops cx231xx_vbi_qops; #define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ #define NTSC_VBI_END_LINE 21 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 9b51f07a729e..69abafaebbf3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -58,10 +58,10 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(CX231XX_VERSION); -static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U }; +static unsigned int video_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U }; +static unsigned int vbi_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U }; +static unsigned int radio_nr[] = {[0 ... (CX231XX_MAXBOARDS - 1)] = -1U }; module_param_array(card, int, NULL, 0444); module_param_array(video_nr, int, NULL, 0444); @@ -166,18 +166,19 @@ static inline void buffer_filled(struct cx231xx *dev, struct cx231xx_buffer *buf) { /* Advice that buffer was filled */ - cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - buf->vb.ts = ktime_get_ns(); + cx231xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.vb2_buf.index); + buf->vb.sequence = dma_q->sequence++; + buf->vb.field = V4L2_FIELD_INTERLACED; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, dev->size); if (dev->USE_ISO) dev->video_mode.isoc_ctl.buf = NULL; else dev->video_mode.bulk_ctl.buf = NULL; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } static inline void print_err_status(struct cx231xx *dev, int packet, int status) @@ -241,11 +242,11 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, } /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); + *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, list); /* Cleans up buffer - Useful for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); + outp = vb2_plane_vaddr(&(*buf)->vb.vb2_buf, 0); + memset(outp, 0, dev->size); if (dev->USE_ISO) dev->video_mode.isoc_ctl.buf = *buf; @@ -653,7 +654,7 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, if (buf == NULL) return -1; - p_out_buffer = videobuf_to_vmalloc(&buf->vb); + p_out_buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line; @@ -672,7 +673,7 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? bytes_to_copy : dma_q->bytes_left_in_line; - if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + buf->vb.size)) + if ((u8 *)(startwrite + lencopy) > (u8 *)(p_out_buffer + dev->size)) return 0; /* The below copies the UYVY data straight into video buffer */ @@ -708,149 +709,98 @@ u8 cx231xx_is_buffer_done(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q) Videobuf operations ------------------------------------------------------------------*/ -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) { - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = vb2_get_drv_priv(vq); - *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3; - if (0 == *count) - *count = CX231XX_DEF_BUF; + dev->size = (dev->width * dev->height * dev->format->depth + 7) >> 3; - if (*count < CX231XX_MIN_BUF) - *count = CX231XX_MIN_BUF; + if (vq->num_buffers + *nbuffers < CX231XX_MIN_BUF) + *nbuffers = CX231XX_MIN_BUF - vq->num_buffers; - - cx231xx_enable_analog_tuner(dev); + if (*nplanes) + return sizes[0] < dev->size ? -EINVAL : 0; + *nplanes = 1; + sizes[0] = dev->size; return 0; } -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) +static void buffer_queue(struct vb2_buffer *vb) { - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; - unsigned long flags = 0; - - BUG_ON(in_interrupt()); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) + struct cx231xx_buffer *buf = + container_of(vb, struct cx231xx_buffer, vb.vb2_buf); + struct cx231xx *dev = vb2_get_drv_priv(vb->vb2_queue); + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + unsigned long flags; - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ spin_lock_irqsave(&dev->video_mode.slock, flags); - if (dev->USE_ISO) { - if (dev->video_mode.isoc_ctl.buf == buf) - dev->video_mode.isoc_ctl.buf = NULL; - } else { - if (dev->video_mode.bulk_ctl.buf == buf) - dev->video_mode.bulk_ctl.buf = NULL; - } + list_add_tail(&buf->list, &vidq->active); spin_unlock_irqrestore(&dev->video_mode.slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; } -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) +static void return_all_buffers(struct cx231xx *dev, + enum vb2_buffer_state state) { - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx *dev = fh->dev; - int rc = 0, urb_init = 0; - - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth - + 7) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } + struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + struct cx231xx_buffer *buf, *node; + unsigned long flags; - if (dev->USE_ISO) { - if (!dev->video_mode.isoc_ctl.num_bufs) - urb_init = 1; - } else { - if (!dev->video_mode.bulk_ctl.num_bufs) - urb_init = 1; - } - dev_dbg(dev->dev, - "urb_init=%d dev->video_mode.max_pkt_size=%d\n", - urb_init, dev->video_mode.max_pkt_size); - if (urb_init) { - dev->mode_tv = 0; - if (dev->USE_ISO) - rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_isoc_copy); - else - rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_bulk_copy); - if (rc < 0) - goto fail; + spin_lock_irqsave(&dev->video_mode.slock, flags); + if (dev->USE_ISO) + dev->video_mode.isoc_ctl.buf = NULL; + else + dev->video_mode.bulk_ctl.buf = NULL; + list_for_each_entry_safe(buf, node, &vidq->active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, state); } - - buf->vb.state = VIDEOBUF_PREPARED; - - return 0; - -fail: - free_buffer(vq, buf); - return rc; + spin_unlock_irqrestore(&dev->video_mode.slock, flags); } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +static int start_streaming(struct vb2_queue *vq, unsigned int count) { - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = vb2_get_drv_priv(vq); struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq; + int ret = 0; - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); + vidq->sequence = 0; + dev->mode_tv = 0; + cx231xx_enable_analog_tuner(dev); + if (dev->USE_ISO) + ret = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_isoc_copy); + else + ret = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_bulk_copy); + if (ret) + return_all_buffers(dev, VB2_BUF_STATE_QUEUED); + call_all(dev, video, s_stream, 1); + return ret; } -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void stop_streaming(struct vb2_queue *vq) { - struct cx231xx_buffer *buf = - container_of(vb, struct cx231xx_buffer, vb); - struct cx231xx_fh *fh = vq->priv_data; - struct cx231xx *dev = (struct cx231xx *)fh->dev; - - cx231xx_isocdbg("cx231xx: called buffer_release\n"); + struct cx231xx *dev = vb2_get_drv_priv(vq); - free_buffer(vq, buf); + call_all(dev, video, s_stream, 0); + return_all_buffers(dev, VB2_BUF_STATE_ERROR); } -static const struct videobuf_queue_ops cx231xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, +static struct vb2_ops cx231xx_video_qops = { + .queue_setup = queue_setup, + .buf_queue = buffer_queue, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /********************* v4l2 interface **************************************/ @@ -872,58 +822,6 @@ void video_mux(struct cx231xx *dev, int index) cx231xx_do_mode_ctrl_overrides(dev); } -/* Usage lock check functions */ -static int res_get(struct cx231xx_fh *fh) -{ - struct cx231xx *dev = fh->dev; - int rc = 0; - - /* This instance already has stream_on */ - if (fh->stream_on) - return rc; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (dev->stream_on) - return -EBUSY; - dev->stream_on = 1; - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - if (dev->vbi_stream_on) - return -EBUSY; - dev->vbi_stream_on = 1; - } else - return -EINVAL; - - fh->stream_on = 1; - - return rc; -} - -static int res_check(struct cx231xx_fh *fh) -{ - return fh->stream_on; -} - -static void res_free(struct cx231xx_fh *fh) -{ - struct cx231xx *dev = fh->dev; - - fh->stream_on = 0; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - dev->stream_on = 0; - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) - dev->vbi_stream_on = 0; -} - -static int check_dev(struct cx231xx *dev) -{ - if (dev->state & DEV_DISCONNECTED) { - dev_err(dev->dev, "v4l2 ioctl: device not present\n"); - return -ENODEV; - } - return 0; -} - /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ @@ -931,8 +829,7 @@ static int check_dev(struct cx231xx *dev) static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; @@ -960,8 +857,7 @@ static struct cx231xx_fmt *format_by_fourcc(unsigned int fourcc) static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); unsigned int width = f->fmt.pix.width; unsigned int height = f->fmt.pix.height; unsigned int maxw = norm_maxw(dev); @@ -993,39 +889,25 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - struct cx231xx_fmt *fmt; + struct cx231xx *dev = video_drvdata(file); struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; + int rc; - rc = check_dev(dev); - if (rc < 0) + rc = vidioc_try_fmt_vid_cap(file, priv, f); + if (rc) return rc; - vidioc_try_fmt_vid_cap(file, priv, f); - - fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (!fmt) - return -EINVAL; - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { + if (vb2_is_busy(&dev->vidq)) { dev_err(dev->dev, "%s: queue busy\n", __func__); return -EBUSY; } - if (dev->stream_on && !fh->stream_on) { - dev_err(dev->dev, - "%s: device in use by another fh\n", __func__); - return -EBUSY; - } - /* set new image size */ dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; - dev->format = fmt; + dev->format = format_by_fourcc(f->fmt.pix.pixelformat); v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); call_all(dev, pad, set_fmt, NULL, &format); @@ -1036,8 +918,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); *id = dev->norm; return 0; @@ -1045,21 +926,15 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; if (dev->norm == norm) return 0; - if (videobuf_queue_is_busy(&fh->vb_vidq)) + if (vb2_is_busy(&dev->vidq)) return -EBUSY; dev->norm = norm; @@ -1141,8 +1016,7 @@ void cx231xx_v4l2_create_entities(struct cx231xx *dev) int cx231xx_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); u32 gen_stat; unsigned int n; int ret; @@ -1181,8 +1055,7 @@ int cx231xx_enum_input(struct file *file, void *priv, int cx231xx_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); *i = dev->video_input; @@ -1191,14 +1064,9 @@ int cx231xx_g_input(struct file *file, void *priv, unsigned int *i) int cx231xx_s_input(struct file *file, void *priv, unsigned int i) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; + struct cx231xx *dev = video_drvdata(file); dev->mode_tv = 0; - rc = check_dev(dev); - if (rc < 0) - return rc; if (i >= MAX_CX231XX_INPUT) return -EINVAL; @@ -1220,13 +1088,7 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i) int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; + struct cx231xx *dev = video_drvdata(file); if (0 != t->index) return -EINVAL; @@ -1244,27 +1106,15 @@ int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - if (0 != t->index) return -EINVAL; -#if 0 - call_all(dev, tuner, s_tuner, t); -#endif return 0; } int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); if (f->tuner) return -EINVAL; @@ -1277,8 +1127,7 @@ int cx231xx_g_frequency(struct file *file, void *priv, int cx231xx_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); struct v4l2_frequency new_freq = *f; int rc; u32 if_frequency = 5400000; @@ -1287,10 +1136,6 @@ int cx231xx_s_frequency(struct file *file, void *priv, "Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n", f->frequency, f->type); - rc = check_dev(dev); - if (rc < 0) - return rc; - if (0 != f->tuner) return -EINVAL; @@ -1365,8 +1210,7 @@ int cx231xx_g_chip_info(struct file *file, void *fh, int cx231xx_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); int ret; u8 value[4] = { 0, 0, 0, 0 }; u32 data = 0; @@ -1424,8 +1268,7 @@ int cx231xx_g_register(struct file *file, void *priv, int cx231xx_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); int ret; u8 data[4] = { 0, 0, 0, 0 }; @@ -1472,8 +1315,7 @@ int cx231xx_s_register(struct file *file, void *priv, static int vidioc_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); bool is_50hz = dev->norm & V4L2_STD_625_50; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1488,8 +1330,7 @@ static int vidioc_g_pixelaspect(struct file *file, void *priv, static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1508,54 +1349,10 @@ static int vidioc_g_selection(struct file *file, void *priv, return 0; } -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = res_get(fh); - - if (likely(rc >= 0)) - rc = videobuf_streamon(&fh->vb_vidq); - - call_all(dev, video, s_stream, 1); - - return rc; -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (type != fh->type) - return -EINVAL; - - cx25840_call(dev, video, s_stream, 0); - - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - - return 0; -} - int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); strscpy(cap->driver, "cx231xx", sizeof(cap->driver)); strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); @@ -1587,8 +1384,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; @@ -1610,8 +1406,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(file); f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; @@ -1634,77 +1429,16 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - if (dev->vbi_stream_on && !fh->stream_on) { - dev_err(dev->dev, - "%s device in use by another fh\n", __func__); - return -EBUSY; - } return vidioc_try_fmt_vbi_cap(file, priv, f); } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_reqbufs(&fh->vb_vidq, rb); -} - -static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_querybuf(&fh->vb_vidq, b); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_qbuf(&fh->vb_vidq, b); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); -} - /* ----------------------------------------------------------- */ /* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; + struct cx231xx *dev = video_drvdata(file); if (t->index) return -EINVAL; @@ -1717,7 +1451,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) } static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; + struct cx231xx *dev = video_drvdata(file); if (t->index) return -EINVAL; @@ -1733,52 +1467,20 @@ static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner */ static int cx231xx_v4l2_open(struct file *filp) { - int radio = 0; struct video_device *vdev = video_devdata(filp); struct cx231xx *dev = video_drvdata(filp); - struct cx231xx_fh *fh; - enum v4l2_buf_type fh_type = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - default: - return -EINVAL; - } - - cx231xx_videodbg("open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[fh_type], - dev->users); - -#if 0 - errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); - if (errCode < 0) { - dev_err(dev->dev, - "Device locked on digital mode. Can't open analog\n"); - return -EBUSY; - } -#endif + int ret; - fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - if (mutex_lock_interruptible(&dev->lock)) { - kfree(fh); + if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; + + ret = v4l2_fh_open(filp); + if (ret) { + mutex_unlock(&dev->lock); + return ret; } - fh->dev = dev; - fh->type = fh_type; - filp->private_data = fh; - v4l2_fh_init(&fh->fh, vdev); - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + if (dev->users++ == 0) { /* Power up in Analog TV mode */ if (dev->board.external_av) cx231xx_set_power_mode(dev, @@ -1786,10 +1488,6 @@ static int cx231xx_v4l2_open(struct file *filp) else cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV); -#if 0 - cx231xx_set_mode(dev, CX231XX_ANALOG_MODE); -#endif - /* set video alternate setting */ cx231xx_set_video_alternate(dev); @@ -1799,38 +1497,21 @@ static int cx231xx_v4l2_open(struct file *filp) /* device needs to be initialized before isoc transfer */ dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; - } - if (radio) { + + if (vdev->vfl_type == VFL_TYPE_RADIO) { cx231xx_videodbg("video_open: setting radio device\n"); /* cx231xx_start_radio(dev); */ call_all(dev, tuner, s_radio); } - - dev->users++; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops, - NULL, &dev->video_mode.slock, - fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), - fh, &dev->lock); - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (vdev->vfl_type == VFL_TYPE_VBI) { /* Set the required alternate setting VBI interface works in Bulk mode only */ cx231xx_set_alt_setting(dev, INDEX_VANC, 0); - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops, - NULL, &dev->vbi_mode.slock, - fh->type, V4L2_FIELD_SEQ_TB, - sizeof(struct cx231xx_buffer), - fh, &dev->lock); } mutex_unlock(&dev->lock); - v4l2_fh_add(&fh->fh); - return 0; } @@ -1871,68 +1552,12 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) */ static int cx231xx_close(struct file *filp) { - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - - cx231xx_videodbg("users=%d\n", dev->users); - - cx231xx_videodbg("users=%d\n", dev->users); - if (res_check(fh)) - res_free(fh); - - /* - * To workaround error number=-71 on EP0 for VideoGrabber, - * need exclude following. - * FIXME: It is probably safe to remove most of these, as we're - * now avoiding the alternate setting for INDEX_VANC - */ - if (!dev->board.no_alt_vanc) - if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - if (atomic_read(&dev->devlist_count) > 0) { - cx231xx_release_resources(dev); - fh->dev = NULL; - return 0; - } - return 0; - } - - /* do this before setting alternate! */ - cx231xx_uninit_vbi_isoc(dev); - - /* set alternate 0 */ - if (!dev->vbi_or_sliced_cc_mode) - cx231xx_set_alt_setting(dev, INDEX_VANC, 0); - else - cx231xx_set_alt_setting(dev, INDEX_HANC, 0); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh); - dev->users--; - wake_up_interruptible(&dev->open); - return 0; - } + struct cx231xx *dev = video_drvdata(filp); + struct video_device *vdev = video_devdata(filp); - v4l2_fh_del(&fh->fh); - dev->users--; - if (!dev->users) { - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - cx231xx_release_resources(dev); - fh->dev = NULL; - return 0; - } + _vb2_fop_release(filp, NULL); + if (--dev->users == 0) { /* Save some power by putting tuner to sleep */ call_all(dev, tuner, standby); @@ -1942,20 +1567,40 @@ static int cx231xx_close(struct file *filp) else cx231xx_uninit_bulk(dev); cx231xx_set_mode(dev, CX231XX_SUSPEND); + } + + /* + * To workaround error number=-71 on EP0 for VideoGrabber, + * need exclude following. + * FIXME: It is probably safe to remove most of these, as we're + * now avoiding the alternate setting for INDEX_VANC + */ + if (!dev->board.no_alt_vanc && vdev->vfl_type == VFL_TYPE_VBI) { + /* do this before setting alternate! */ + cx231xx_uninit_vbi_isoc(dev); /* set alternate 0 */ + if (!dev->vbi_or_sliced_cc_mode) + cx231xx_set_alt_setting(dev, INDEX_VANC, 0); + else + cx231xx_set_alt_setting(dev, INDEX_HANC, 0); + + wake_up_interruptible_nr(&dev->open, 1); + return 0; + } + + if (dev->users == 0) { + /* set alternate 0 */ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); } - v4l2_fh_exit(&fh->fh); - kfree(fh); + wake_up_interruptible(&dev->open); return 0; } static int cx231xx_v4l2_close(struct file *filp) { - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; + struct cx231xx *dev = video_drvdata(filp); int rc; mutex_lock(&dev->lock); @@ -1964,116 +1609,13 @@ static int cx231xx_v4l2_close(struct file *filp) return rc; } -/* - * cx231xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || - (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) { - rc = res_get(fh); - - if (unlikely(rc < 0)) - return rc; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - mutex_unlock(&dev->lock); - return rc; - } - return 0; -} - -/* - * cx231xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static __poll_t cx231xx_v4l2_poll(struct file *filp, poll_table *wait) -{ - __poll_t req_events = poll_requested_events(wait); - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - __poll_t res = 0; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return EPOLLERR; - - rc = res_get(fh); - - if (unlikely(rc < 0)) - return EPOLLERR; - - if (v4l2_event_pending(&fh->fh)) - res |= EPOLLPRI; - else - poll_wait(filp, &fh->fh.wait, wait); - - if (!(req_events & (EPOLLIN | EPOLLRDNORM))) - return res; - - if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) || - (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) { - mutex_lock(&dev->lock); - res |= videobuf_poll_stream(filp, &fh->vb_vidq, wait); - mutex_unlock(&dev->lock); - return res; - } - return res | EPOLLERR; -} - -/* - * cx231xx_v4l2_mmap() - */ -static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct cx231xx_fh *fh = filp->private_data; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = res_get(fh); - - if (unlikely(rc < 0)) - return rc; - - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - mutex_unlock(&dev->lock); - - cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end - - (unsigned long)vma->vm_start, rc); - - return rc; -} - static const struct v4l2_file_operations cx231xx_v4l_fops = { .owner = THIS_MODULE, .open = cx231xx_v4l2_open, .release = cx231xx_v4l2_close, - .read = cx231xx_v4l2_read, - .poll = cx231xx_v4l2_poll, - .mmap = cx231xx_v4l2_mmap, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; @@ -2088,17 +1630,17 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, .vidioc_g_pixelaspect = vidioc_g_pixelaspect, .vidioc_g_selection = vidioc_g_selection, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = cx231xx_enum_input, .vidioc_g_input = cx231xx_g_input, .vidioc_s_input = cx231xx_s_input, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_tuner = cx231xx_g_tuner, .vidioc_s_tuner = cx231xx_s_tuner, .vidioc_g_frequency = cx231xx_g_frequency, @@ -2175,6 +1717,7 @@ static void cx231xx_vdev_init(struct cx231xx *dev, int cx231xx_register_analog_devices(struct cx231xx *dev) { + struct vb2_queue *q; int ret; dev_info(dev->dev, "v4l2 driver version %s\n", CX231XX_VERSION); @@ -2221,6 +1764,21 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize video media entity!\n"); #endif dev->vdev.ctrl_handler = &dev->ctrl_handler; + + q = &dev->vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx231xx_buffer); + q->ops = &cx231xx_video_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; + q->lock = &dev->lock; + ret = vb2_queue_init(q); + if (ret) + return ret; + dev->vdev.queue = q; dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; if (dev->tuner_type != TUNER_ABSENT) @@ -2254,6 +1812,21 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize vbi media entity!\n"); #endif dev->vbi_dev.ctrl_handler = &dev->ctrl_handler; + + q = &dev->vbiq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; + q->io_modes = VB2_USERPTR | VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx231xx_buffer); + q->ops = &cx231xx_vbi_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 1; + q->lock = &dev->lock; + ret = vb2_queue_init(q); + if (ret) + return ret; + dev->vbi_dev.queue = q; dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE; if (dev->tuner_type != TUNER_ABSENT) diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index b007611abc37..b32eab641793 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -20,7 +20,7 @@ #include <media/drv-intf/cx2341x.h> -#include <media/videobuf-vmalloc.h> +#include <media/videobuf2-vmalloc.h> #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> @@ -223,8 +223,8 @@ struct cx231xx_fmt { /* buffer for one video frame */ struct cx231xx_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - + struct vb2_v4l2_buffer vb; + struct list_head list; struct list_head frame; int top_field; int receiving; @@ -237,7 +237,6 @@ enum ps_package_head { struct cx231xx_dmaqueue { struct list_head active; - struct list_head queued; wait_queue_head_t wq; @@ -251,6 +250,7 @@ struct cx231xx_dmaqueue { u32 lines_completed; u8 field1_done; u32 lines_per_field; + u32 sequence; /*Mpeg2 control buffer*/ u8 *p_left_data; @@ -427,23 +427,6 @@ struct cx231xx_audio { struct cx231xx; -struct cx231xx_fh { - struct v4l2_fh fh; - struct cx231xx *dev; - unsigned int stream_on:1; /* Locks streams */ - enum v4l2_buf_type type; - - struct videobuf_queue vb_vidq; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - - atomic_t v4l_reading; -}; - /*****************************************************************/ /* set/get i2c */ /* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */ @@ -634,6 +617,7 @@ struct cx231xx { int width; /* current frame width */ int height; /* current frame height */ int interlaced; /* 1=interlace fields, 0=just top fields */ + unsigned int size; struct cx231xx_audio adev; @@ -657,6 +641,9 @@ struct cx231xx { struct media_pad input_pad[MAX_CX231XX_INPUT]; #endif + struct vb2_queue vidq; + struct vb2_queue vbiq; + unsigned char eedata[256]; struct cx231xx_video_mode video_mode; @@ -717,6 +704,7 @@ struct cx231xx { u8 USE_ISO; struct cx231xx_tvnorm encodernorm; struct cx231xx_tsport ts1, ts2; + struct vb2_queue mpegq; struct video_device v4l_device; atomic_t v4l_reader_count; u32 freq; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 3afd18733614..792667ee5ebc 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1197,6 +1197,15 @@ err: return ret; } +/* + * The I2C speed register is calculated with: + * I2C speed register = (1000000000 / (24.4 * 16 * I2C_speed)) + * + * The default speed register for it930x is 7, with means a + * speed of ~366 kbps + */ +#define I2C_SPEED_366K 7 + static int it930x_frontend_attach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1208,13 +1217,13 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); - /* I2C master bus 2 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f6a7, 0x07); + /* I2C master bus 2 clock speed 366k */ + ret = af9035_wr_reg(d, 0x00f6a7, I2C_SPEED_366K); if (ret < 0) goto err; - /* I2C master bus 1,3 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f103, 0x07); + /* I2C master bus 1,3 clock speed 366k */ + ret = af9035_wr_reg(d, 0x00f103, I2C_SPEED_366K); if (ret < 0) goto err; @@ -1610,6 +1619,24 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; + + /* + * HACK: The Logilink VG0022A has a bug: when the si2157 + * firmware that came with the device is replaced by a new + * one, the I2C transfers to the tuner will return just 0xff. + * + * Probably, the vendor firmware has some patch specifically + * designed for this device. So, we can't replace by the + * generic firmware. The right solution would be to extract + * the si2157 firmware from the original driver and ask the + * driver to load the specifically designed firmware, but, + * while we don't have that, the next best solution is to just + * keep the original firmware at the device. + */ + if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_DEXATEK && + le16_to_cpu(d->udev->descriptor.idProduct) == 0x0100) + si2157_config.dont_load_firmware = true; + si2157_config.if_port = it930x_addresses_table[state->it930x_addresses].tuner_if_port; ret = af9035_add_i2c_dev(d, "si2157", it930x_addresses_table[state->it930x_addresses].tuner_i2c_addr, @@ -2121,6 +2148,8 @@ static const struct usb_device_id af9035_id_table[] = { &it930x_props, "ITE 9303 Generic", NULL) }, { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310, &it930x_props, "AVerMedia TD310 DVB-T2", NULL) }, + { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100, + &it930x_props, "Logilink VG0022A", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index b874a49ececf..52bcc2d2efe5 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -121,6 +121,7 @@ struct dvb_usb_driver_info { * @interval: time in ms between two queries * @driver_type: used to point if a device supports raw mode * @bulk_mode: device supports bulk mode for rc (disable polling mode) + * @timeout: set to length of last space before raw IR goes idle */ struct dvb_usb_rc { const char *map_name; @@ -130,6 +131,7 @@ struct dvb_usb_rc { unsigned int interval; enum rc_driver_type driver_type; bool bulk_mode; + int timeout; }; /** diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index e5e056bf9dfa..f1c79f351ec8 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -150,6 +150,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) dev->map_name = d->rc.map_name; dev->allowed_protocols = d->rc.allowed_protos; dev->change_protocol = d->rc.change_protocol; + dev->timeout = d->rc.timeout; dev->priv = d; ret = rc_register_device(dev); diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 617a306f6815..356fd8e66834 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -22,7 +22,6 @@ MODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); struct dvbsky_state { - struct mutex stream_mutex; u8 ibuf[DVBSKY_BUF_LEN]; u8 obuf[DVBSKY_BUF_LEN]; u8 last_lock; @@ -60,17 +59,19 @@ static int dvbsky_usb_generic_rw(struct dvb_usb_device *d, static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff) { struct dvbsky_state *state = d_to_priv(d); + static const u8 obuf_pre[3] = { 0x37, 0, 0 }; + static const u8 obuf_post[3] = { 0x36, 3, 0 }; int ret; - u8 obuf_pre[3] = { 0x37, 0, 0 }; - u8 obuf_post[3] = { 0x36, 3, 0 }; - mutex_lock(&state->stream_mutex); - ret = dvbsky_usb_generic_rw(d, obuf_pre, 3, NULL, 0); + mutex_lock(&d->usb_mutex); + memcpy(state->obuf, obuf_pre, 3); + ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3); if (!ret && onoff) { msleep(20); - ret = dvbsky_usb_generic_rw(d, obuf_post, 3, NULL, 0); + memcpy(state->obuf, obuf_post, 3); + ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3); } - mutex_unlock(&state->stream_mutex); + mutex_unlock(&d->usb_mutex); return ret; } @@ -591,17 +592,7 @@ static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name) static int dvbsky_init(struct dvb_usb_device *d) { struct dvbsky_state *state = d_to_priv(d); - - /* use default interface */ - /* - ret = usb_set_interface(d->udev, 0, 0); - if (ret) - return ret; - */ - mutex_init(&state->stream_mutex); - state->last_lock = 0; - return 0; } @@ -792,6 +783,9 @@ static const struct usb_device_id dvbsky_id_table[] = { { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE, + &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C Lite", + NULL) }, { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, &mygica_t230c_props, "MyGica Mini DVB-T2 USB Stick T230C v2", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index c7197e534c02..19217dcf20f1 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -5,7 +5,7 @@ */ #include <linux/string.h> -#include "gl861.h" +#include "dvb_usb.h" #include "zl10353.h" #include "qt1010.h" @@ -14,93 +14,157 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr, - u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) -{ - u16 index; - u16 value = addr << (8 + 1); - int wo = (rbuf == NULL || rlen == 0); /* write-only */ - u8 req, type; - u8 *buf; - int ret; +struct gl861 { + /* USB control message buffer */ + u8 buf[16]; - if (wo) { - req = GL861_REQ_I2C_WRITE; - type = GL861_WRITE; - buf = kmemdup(wbuf, wlen, GFP_KERNEL); - } else { /* rw */ - req = GL861_REQ_I2C_READ; - type = GL861_READ; - buf = kmalloc(rlen, GFP_KERNEL); - } - if (!buf) - return -ENOMEM; + struct i2c_adapter *demod_sub_i2c; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; +}; - switch (wlen) { - case 1: - index = wbuf[0]; +#define CMD_WRITE_SHORT 0x01 +#define CMD_READ 0x02 +#define CMD_WRITE 0x03 + +static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value, + u16 index, void *data, u16 size) +{ + struct gl861 *ctx = d_to_priv(d); + struct usb_interface *intf = d->intf; + int ret; + unsigned int pipe; + u8 requesttype; + + mutex_lock(&d->usb_mutex); + + switch (request) { + case CMD_WRITE: + memcpy(ctx->buf, data, size); + /* Fall through */ + case CMD_WRITE_SHORT: + pipe = usb_sndctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_OUT; break; - case 2: - index = wbuf[0]; - value = value + wbuf[1]; + case CMD_READ: + pipe = usb_rcvctrlpipe(d->udev, 0); + requesttype = USB_TYPE_VENDOR | USB_DIR_IN; break; default: - dev_err(&d->udev->dev, "%s: wlen=%d, aborting\n", - KBUILD_MODNAME, wlen); - kfree(buf); - return -EINVAL; + ret = -EINVAL; + goto err_mutex_unlock; } - usleep_range(1000, 2000); /* avoid I2C errors */ + ret = usb_control_msg(d->udev, pipe, request, requesttype, value, + index, ctx->buf, size, 200); + dev_dbg(&intf->dev, "%d | %02x %02x %*ph %*ph %*ph %s %*ph\n", + ret, requesttype, request, 2, &value, 2, &index, 2, &size, + (requesttype & USB_DIR_IN) ? "<<<" : ">>>", size, ctx->buf); + if (ret < 0) + goto err_mutex_unlock; - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type, - value, index, buf, rlen, 2000); + if (request == CMD_READ) + memcpy(data, ctx->buf, size); - if (!wo && ret > 0) - memcpy(rbuf, buf, rlen); + usleep_range(1000, 2000); /* Avoid I2C errors */ - kfree(buf); + mutex_unlock(&d->usb_mutex); + + return 0; + +err_mutex_unlock: + mutex_unlock(&d->usb_mutex); + dev_dbg(&intf->dev, "failed %d\n", ret); return ret; } -/* I2C */ -static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) +static int gl861_short_write(struct dvb_usb_device *d, u8 addr, u8 reg, u8 val) +{ + return gl861_ctrl_msg(d, CMD_WRITE_SHORT, + (addr << 9) | val, reg, NULL, 0); +} + +static int gl861_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], + int num) { struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; + struct usb_interface *intf = d->intf; + struct gl861 *ctx = d_to_priv(d); + int ret; + u8 request, *data; + u16 value, index, size; + + /* XXX: I2C adapter maximum data lengths are not tested */ + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { + /* I2C write */ + if (msg[0].len < 2 || msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + + if (msg[0].len == 2) { + request = CMD_WRITE_SHORT; + value |= msg[0].buf[1]; + size = 0; + data = NULL; + } else { + request = CMD_WRITE; + size = msg[0].len - 1; + data = &msg[0].buf[1]; + } + + ret = gl861_ctrl_msg(d, request, value, index, data, size); + } else if (num == 2 && !(msg[0].flags & I2C_M_RD) && + (msg[1].flags & I2C_M_RD)) { + /* I2C write + read */ + if (msg[0].len > 1 || msg[1].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - /* write/read request */ - if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) { - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, msg[i+1].buf, msg[i+1].len) < 0) - break; - i++; - } else - if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf, - msg[i].len, NULL, 0) < 0) - break; + value = (msg[0].addr << 1) << 8; + index = msg[0].buf[0]; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, + msg[1].buf, msg[1].len); + } else if (num == 1 && (msg[0].flags & I2C_M_RD)) { + /* I2C read */ + if (msg[0].len > sizeof(ctx->buf)) { + ret = -EOPNOTSUPP; + goto err; + } + value = (msg[0].addr << 1) << 8; + index = 0x0100; + request = CMD_READ; + + ret = gl861_ctrl_msg(d, request, value, index, + msg[0].buf, msg[0].len); + } else { + /* Unsupported I2C message */ + dev_dbg(&intf->dev, "unknown i2c msg, num %u\n", num); + ret = -EOPNOTSUPP; } + if (ret) + goto err; - mutex_unlock(&d->i2c_mutex); - return i; + return num; +err: + dev_dbg(&intf->dev, "failed %d\n", ret); + return ret; } -static u32 gl861_i2c_func(struct i2c_adapter *adapter) +static u32 gl861_i2c_functionality(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } static struct i2c_algorithm gl861_i2c_algo = { - .master_xfer = gl861_i2c_xfer, - .functionality = gl861_i2c_func, + .master_xfer = gl861_i2c_master_xfer, + .functionality = gl861_i2c_functionality, }; /* Callbacks for DVB USB */ @@ -149,6 +213,8 @@ static struct dvb_usb_device_properties gl861_props = { .owner = THIS_MODULE, .adapter_nr = adapter_nr, + .size_of_priv = sizeof(struct gl861), + .i2c_algo = &gl861_i2c_algo, .frontend_attach = gl861_frontend_attach, .tuner_attach = gl861_tuner_attach, @@ -166,14 +232,6 @@ static struct dvb_usb_device_properties gl861_props = { /* * For Friio */ - -struct friio_priv { - struct i2c_adapter *demod_sub_i2c; - struct i2c_client *i2c_client_demod; - struct i2c_client *i2c_client_tuner; - struct i2c_adapter tuner_adap; -}; - struct friio_config { struct i2c_board_info demod_info; struct tc90522_config demod_cfg; @@ -184,132 +242,10 @@ struct friio_config { static const struct friio_config friio_config = { .demod_info = { I2C_BOARD_INFO(TC90522_I2C_DEV_TER, 0x18), }, + .demod_cfg = { .split_tuner_read_i2c = true, }, .tuner_info = { I2C_BOARD_INFO("tua6034_friio", 0x60), }, }; -/* For another type of I2C: - * message sent by a USB control-read/write transaction with data stage. - * Used in init/config of Friio. - */ -static int -gl861_i2c_write_ex(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen) -{ - u8 *buf; - int ret; - - buf = kmemdup(wbuf, wlen, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GL861_REQ_I2C_RAW, GL861_WRITE, - addr << (8 + 1), 0x0100, buf, wlen, 2000); - kfree(buf); - return ret; -} - -static int -gl861_i2c_read_ex(struct dvb_usb_device *d, u8 addr, u8 *rbuf, u16 rlen) -{ - u8 *buf; - int ret; - - buf = kmalloc(rlen, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), - GL861_REQ_I2C_READ, GL861_READ, - addr << (8 + 1), 0x0100, buf, rlen, 2000); - if (ret > 0 && rlen > 0) - memcpy(buf, rbuf, rlen); - kfree(buf); - return ret; -} - -/* For I2C transactions to the tuner of Friio (dvb_pll). - * - * Friio uses irregular USB encapsulation for tuner i2c transactions: - * write transacions are encapsulated with a different USB 'request' value. - * - * Although all transactions are sent via the demod(tc90522) - * and the demod provides an i2c adapter for them, it cannot be used in Friio - * since it assumes using the same parent adapter with the demod, - * which does not use the request value and uses same one for both read/write. - * So we define a dedicated i2c adapter here. - */ - -static int -friio_i2c_tuner_read(struct dvb_usb_device *d, struct i2c_msg *msg) -{ - struct friio_priv *priv; - u8 addr; - - priv = d_to_priv(d); - addr = priv->i2c_client_demod->addr; - return gl861_i2c_read_ex(d, addr, msg->buf, msg->len); -} - -static int -friio_i2c_tuner_write(struct dvb_usb_device *d, struct i2c_msg *msg) -{ - u8 *buf; - int ret; - struct friio_priv *priv; - - priv = d_to_priv(d); - - if (msg->len < 1) - return -EINVAL; - - buf = kmalloc(msg->len + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - buf[0] = msg->addr << 1; - memcpy(buf + 1, msg->buf, msg->len); - - ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0), - GL861_REQ_I2C_RAW, GL861_WRITE, - priv->i2c_client_demod->addr << (8 + 1), - 0xFE, buf, msg->len + 1, 2000); - kfree(buf); - return ret; -} - -static int friio_tuner_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], - int num) -{ - struct dvb_usb_device *d = i2c_get_adapdata(adap); - int i; - - if (num > 2) - return -EINVAL; - - if (mutex_lock_interruptible(&d->i2c_mutex) < 0) - return -EAGAIN; - - for (i = 0; i < num; i++) { - int ret; - - if (msg[i].flags & I2C_M_RD) - ret = friio_i2c_tuner_read(d, &msg[i]); - else - ret = friio_i2c_tuner_write(d, &msg[i]); - - if (ret < 0) - break; - - usleep_range(1000, 2000); /* avoid I2C errors */ - } - - mutex_unlock(&d->i2c_mutex); - return i; -} - -static struct i2c_algorithm friio_tuner_i2c_algo = { - .master_xfer = friio_tuner_i2c_xfer, - .functionality = gl861_i2c_func, -}; /* GPIO control in Friio */ @@ -377,9 +313,11 @@ static int friio_ext_ctl(struct dvb_usb_device *d, /* init/config of gl861 for Friio */ /* NOTE: * This function cannot be moved to friio_init()/dvb_usbv2_init(), - * because the init defined here must be done before any activities like I2C, + * because the init defined here includes a whole device reset, + * it must be run early before any activities like I2C, * but friio_init() is called by dvb-usbv2 after {_frontend, _tuner}_attach(), * where I2C communication is used. + * In addition, this reset is required in reset_resume() as well. * Thus this function is set to be called from _power_ctl(). * * Since it will be called on the early init stage @@ -389,7 +327,7 @@ static int friio_ext_ctl(struct dvb_usb_device *d, static int friio_reset(struct dvb_usb_device *d) { int i, ret; - u8 wbuf[2], rbuf[2]; + u8 wbuf[1], rbuf[2]; static const u8 friio_init_cmds[][2] = { {0x33, 0x08}, {0x37, 0x40}, {0x3a, 0x1f}, {0x3b, 0xff}, @@ -401,16 +339,12 @@ static int friio_reset(struct dvb_usb_device *d) if (ret < 0) return ret; - wbuf[0] = 0x11; - wbuf[1] = 0x02; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + ret = gl861_short_write(d, 0x00, 0x11, 0x02); if (ret < 0) return ret; usleep_range(2000, 3000); - wbuf[0] = 0x11; - wbuf[1] = 0x00; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + ret = gl861_short_write(d, 0x00, 0x11, 0x00); if (ret < 0) return ret; @@ -420,14 +354,13 @@ static int friio_reset(struct dvb_usb_device *d) */ usleep_range(1000, 2000); - wbuf[0] = 0x03; - wbuf[1] = 0x80; - ret = gl861_i2c_write_ex(d, 0x09, wbuf, 2); + wbuf[0] = 0x80; + ret = gl861_ctrl_msg(d, CMD_WRITE, 0x09 << 9, 0x03, wbuf, 1); if (ret < 0) return ret; usleep_range(2000, 3000); - ret = gl861_i2c_read_ex(d, 0x09, rbuf, 2); + ret = gl861_ctrl_msg(d, CMD_READ, 0x09 << 9, 0x0100, rbuf, 2); if (ret < 0) return ret; if (rbuf[0] != 0xff || rbuf[1] != 0xff) @@ -435,38 +368,33 @@ static int friio_reset(struct dvb_usb_device *d) usleep_range(1000, 2000); - ret = gl861_i2c_write_ex(d, 0x48, wbuf, 2); + wbuf[0] = 0x80; + ret = gl861_ctrl_msg(d, CMD_WRITE, 0x48 << 9, 0x03, wbuf, 1); if (ret < 0) return ret; usleep_range(2000, 3000); - ret = gl861_i2c_read_ex(d, 0x48, rbuf, 2); + ret = gl861_ctrl_msg(d, CMD_READ, 0x48 << 9, 0x0100, rbuf, 2); if (ret < 0) return ret; if (rbuf[0] != 0xff || rbuf[1] != 0xff) return -ENODEV; - wbuf[0] = 0x30; - wbuf[1] = 0x04; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + ret = gl861_short_write(d, 0x00, 0x30, 0x04); if (ret < 0) return ret; - wbuf[0] = 0x00; - wbuf[1] = 0x01; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + ret = gl861_short_write(d, 0x00, 0x00, 0x01); if (ret < 0) return ret; - wbuf[0] = 0x06; - wbuf[1] = 0x0f; - ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0); + ret = gl861_short_write(d, 0x00, 0x06, 0x0f); if (ret < 0) return ret; for (i = 0; i < ARRAY_SIZE(friio_init_cmds); i++) { - ret = gl861_i2c_msg(d, 0x00, (u8 *)friio_init_cmds[i], 2, - NULL, 0); + ret = gl861_short_write(d, 0x00, friio_init_cmds[i][0], + friio_init_cmds[i][1]); if (ret < 0) return ret; } @@ -488,9 +416,10 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap) struct dvb_usb_device *d; struct tc90522_config cfg; struct i2c_client *cl; - struct friio_priv *priv; + struct gl861 *priv; info = &friio_config.demod_info; + cfg = friio_config.demod_cfg; d = adap_to_d(adap); cl = dvb_module_probe("tc90522", info->type, &d->i2c_adap, info->addr, &cfg); @@ -498,25 +427,17 @@ static int friio_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; adap->fe[0] = cfg.fe; - /* ignore cfg.tuner_i2c and create new one */ priv = adap_to_priv(adap); priv->i2c_client_demod = cl; - priv->tuner_adap.algo = &friio_tuner_i2c_algo; - priv->tuner_adap.dev.parent = &d->udev->dev; - strscpy(priv->tuner_adap.name, d->name, sizeof(priv->tuner_adap.name)); - strlcat(priv->tuner_adap.name, "-tuner", sizeof(priv->tuner_adap.name)); - priv->demod_sub_i2c = &priv->tuner_adap; - i2c_set_adapdata(&priv->tuner_adap, d); - - return i2c_add_adapter(&priv->tuner_adap); + priv->demod_sub_i2c = cfg.tuner_i2c; + return 0; } static int friio_frontend_detach(struct dvb_usb_adapter *adap) { - struct friio_priv *priv; + struct gl861 *priv; priv = adap_to_priv(adap); - i2c_del_adapter(&priv->tuner_adap); dvb_module_release(priv->i2c_client_demod); return 0; } @@ -526,7 +447,7 @@ static int friio_tuner_attach(struct dvb_usb_adapter *adap) const struct i2c_board_info *info; struct dvb_pll_config cfg; struct i2c_client *cl; - struct friio_priv *priv; + struct gl861 *priv; priv = adap_to_priv(adap); info = &friio_config.tuner_info; @@ -543,7 +464,7 @@ static int friio_tuner_attach(struct dvb_usb_adapter *adap) static int friio_tuner_detach(struct dvb_usb_adapter *adap) { - struct friio_priv *priv; + struct gl861 *priv; priv = adap_to_priv(adap); dvb_module_release(priv->i2c_client_tuner); @@ -554,7 +475,7 @@ static int friio_init(struct dvb_usb_device *d) { int i; int ret; - struct friio_priv *priv; + struct gl861 *priv; static const u8 demod_init[][2] = { {0x01, 0x40}, {0x04, 0x38}, {0x05, 0x40}, {0x07, 0x40}, @@ -606,7 +527,7 @@ static struct dvb_usb_device_properties friio_props = { .owner = THIS_MODULE, .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct friio_priv), + .size_of_priv = sizeof(struct gl861), .i2c_algo = &gl861_i2c_algo, .power_ctrl = friio_power_ctrl, diff --git a/drivers/media/usb/dvb-usb-v2/gl861.h b/drivers/media/usb/dvb-usb-v2/gl861.h deleted file mode 100644 index 02c00e10748a..000000000000 --- a/drivers/media/usb/dvb-usb-v2/gl861.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _DVB_USB_GL861_H_ -#define _DVB_USB_GL861_H_ - -#include "dvb_usb.h" - -#define GL861_WRITE 0x40 -#define GL861_READ 0xc0 - -#define GL861_REQ_I2C_WRITE 0x01 -#define GL861_REQ_I2C_READ 0x02 -#define GL861_REQ_I2C_RAW 0x03 - -#endif diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 1a36bda28542..5016ede7b35f 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1781,7 +1781,6 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d) } /* 'flush' ir_raw_event_store_with_filter() */ - ir_raw_event_set_idle(d->rc_dev, true); ir_raw_event_handle(d->rc_dev); exit: return ret; @@ -1804,6 +1803,8 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, rc->driver_type = RC_DRIVER_IR_RAW; rc->query = rtl2832u_rc_query; rc->interval = 200; + /* we program idle len to 0xc0, set timeout to one less */ + rc->timeout = 0xbf * 50800; return 0; } @@ -1957,7 +1958,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { /* RTL2832P devices: */ { DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131, - &rtl28xxu_props, "Astrometa DVB-T2", NULL) }, + &rtl28xxu_props, "Astrometa DVB-T2", + RC_MAP_ASTROMETA_T2HYBRID) }, { DVB_USB_DEVICE(0x5654, 0xca42, &rtl28xxu_props, "GoTView MasterHD 3", NULL) }, { } diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index 02697d86e8c1..ac93e88d7038 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -976,8 +976,9 @@ static int af9005_identify_state(struct usb_device *udev, else if (reply == 0x02) *cold = 0; else - return -EIO; - deb_info("Identify state cold = %d\n", *cold); + ret = -EIO; + if (!ret) + deb_info("Identify state cold = %d\n", *cold); err: kfree(buf); diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index f02fa0a67aa4..fac19ec46089 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -521,7 +521,8 @@ static int cxusb_rc_query(struct dvb_usb_device *d) { u8 ircode[4]; - cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4); + if (cxusb_ctrl_msg(d, CMD_GET_IR_CODE, NULL, 0, ircode, 4) < 0) + return 0; if (ircode[2] || ircode[3]) rc_keydown(d->rc_dev, RC_PROTO_NEC, diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 49c9b70b632b..79dfbb25714b 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -31,7 +31,6 @@ #include <linux/soundcard.h> #include <linux/slab.h> #include <linux/vmalloc.h> -#include <linux/proc_fs.h> #include <linux/module.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 5983e72a0622..def9cdd931a9 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2487,6 +2487,24 @@ const struct em28xx_board em28xx_boards[] = { .ir_codes = RC_MAP_HAUPPAUGE, .leds = hauppauge_dualhd_leds, }, + /* + * 1b80:e349 Magix USB Videowandler-2 + * (same chips as Honestech VIDBOX NW03) + * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner + */ + [EM2861_BOARD_MAGIX_VIDEOWANDLER2] = { + .name = "Magix USB Videowandler-2", + .tuner_type = TUNER_ABSENT, + .decoder = EM28XX_SAA711X, + .input = { { + .type = EM28XX_VMUX_COMPOSITE, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, }; EXPORT_SYMBOL_GPL(em28xx_boards); @@ -2696,6 +2714,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28178_BOARD_PLEX_PX_BCUD }, { USB_DEVICE(0xeb1a, 0x5051), /* Ion Video 2 PC MKII / Startech svid2usb23 / Raygo R12-41373 */ .driver_info = EM2860_BOARD_TVP5150_REFERENCE_DESIGN }, + { USB_DEVICE(0x1b80, 0xe349), /* Magix USB Videowandler-2 */ + .driver_info = EM2861_BOARD_MAGIX_VIDEOWANDLER2 }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index a73faf12f7e4..0ab6c493bc74 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -471,13 +471,13 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) { int i; - struct em28xx_reg_seq hauppauge_hvr930c_init[] = { + static const struct em28xx_reg_seq hauppauge_hvr930c_init[] = { {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0x65}, {EM2874_R80_GPIO_P0_CTRL, 0xfb, 0xff, 0x32}, {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0xb8}, { -1, -1, -1, -1}, }; - struct em28xx_reg_seq hauppauge_hvr930c_end[] = { + static const struct em28xx_reg_seq hauppauge_hvr930c_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x01}, {EM2874_R80_GPIO_P0_CTRL, 0xaf, 0xff, 0x65}, {EM2874_R80_GPIO_P0_CTRL, 0xef, 0xff, 0x76}, @@ -493,7 +493,7 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) { -1, -1, -1, -1}, }; - struct { + static const struct { unsigned char r[4]; int len; } regs[] = { @@ -537,20 +537,20 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) static void terratec_h5_init(struct em28xx *dev) { int i; - struct em28xx_reg_seq terratec_h5_init[] = { + static const struct em28xx_reg_seq terratec_h5_init[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf2, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, { -1, -1, -1, -1}, }; - struct em28xx_reg_seq terratec_h5_end[] = { + static const struct em28xx_reg_seq terratec_h5_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, { -1, -1, -1, -1}, }; - struct { + static const struct { unsigned char r[4]; int len; } regs[] = { @@ -594,14 +594,14 @@ static void terratec_htc_stick_init(struct em28xx *dev) * 0xe6: unknown (does not affect DVB-T). * 0xb6: unknown (does not affect DVB-T). */ - struct em28xx_reg_seq terratec_htc_stick_init[] = { + static const struct em28xx_reg_seq terratec_htc_stick_init[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 100}, { -1, -1, -1, -1}, }; - struct em28xx_reg_seq terratec_htc_stick_end[] = { + static const struct em28xx_reg_seq terratec_htc_stick_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xf6, 0xff, 50}, { -1, -1, -1, -1}, @@ -611,7 +611,7 @@ static void terratec_htc_stick_init(struct em28xx *dev) * Init the analog decoder (not yet supported), but * it's probably still a good idea. */ - struct { + static const struct { unsigned char r[4]; int len; } regs[] = { @@ -642,14 +642,14 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) { int i; - struct em28xx_reg_seq terratec_htc_usb_xs_init[] = { + static const struct em28xx_reg_seq terratec_htc_usb_xs_init[] = { {EM2820_R08_GPIO_CTRL, 0xff, 0xff, 10}, {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xb2, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xb6, 0xff, 100}, { -1, -1, -1, -1}, }; - struct em28xx_reg_seq terratec_htc_usb_xs_end[] = { + static const struct em28xx_reg_seq terratec_htc_usb_xs_end[] = { {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 100}, {EM2874_R80_GPIO_P0_CTRL, 0xa6, 0xff, 50}, {EM2874_R80_GPIO_P0_CTRL, 0xe6, 0xff, 100}, @@ -660,7 +660,7 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) * Init the analog decoder (not yet supported), but * it's probably still a good idea. */ - struct { + static const struct { unsigned char r[4]; int len; } regs[] = { @@ -704,7 +704,7 @@ static void pctv_520e_init(struct em28xx *dev) * digital demodulator and tuner are routed via AVF4910B. */ int i; - struct { + static const struct { unsigned char r[4]; int len; } regs[] = { @@ -800,7 +800,7 @@ static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe) static void px_bcud_init(struct em28xx *dev) { int i; - struct { + static const struct { unsigned char r[4]; int len; } regs1[] = { @@ -818,7 +818,7 @@ static void px_bcud_init(struct em28xx *dev) {{ 0x85, 0x7a }, 2}, {{ 0x87, 0x04 }, 2}, }; - static struct em28xx_reg_seq gpio[] = { + static const struct em28xx_reg_seq gpio[] = { {EM28XX_R06_I2C_CLK, 0x40, 0xff, 300}, {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 60}, {EM28XX_R15_RGAIN, 0x20, 0xff, 0}, diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index a3155ec196cc..592b98b3643a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -949,7 +949,7 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus) unsigned char buf; int i, rc; - memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); + memset(i2c_devicelist, 0, sizeof(i2c_devicelist)); for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { dev->i2c_client[bus].addr = i; @@ -964,7 +964,7 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned int bus) if (bus == dev->def_i2c_bus) dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, - ARRAY_SIZE(i2c_devicelist), 32); + sizeof(i2c_devicelist), 32); } /* diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index c8bc59059a19..4ecadd57dac7 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -149,6 +149,7 @@ #define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 100 #define EM2884_BOARD_TERRATEC_H6 101 #define EM2882_BOARD_ZOLID_HYBRID_TV_STICK 102 +#define EM2861_BOARD_MAGIX_VIDEOWANDLER2 103 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index 863c485f4275..97799cfb832e 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -378,6 +378,9 @@ static int sd_start(struct gspca_dev *gspca_dev) } /* Start the workqueue function to do the streaming */ dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + if (!dev->work_thread) + return -ENOMEM; + queue_work(dev->work_thread, &dev->work_struct); return 0; diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c index 3d7f6dcdd7a8..6ca947aef298 100644 --- a/drivers/media/usb/gspca/sq905c.c +++ b/drivers/media/usb/gspca/sq905c.c @@ -276,6 +276,9 @@ static int sd_start(struct gspca_dev *gspca_dev) } /* Start the workqueue function to do the streaming */ dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + if (!dev->work_thread) + return -ENOMEM; + queue_work(dev->work_thread, &dev->work_struct); return 0; diff --git a/drivers/media/usb/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c index f869eb6065ce..b23988d8c7bc 100644 --- a/drivers/media/usb/gspca/stv0680.c +++ b/drivers/media/usb/gspca/stv0680.c @@ -35,7 +35,7 @@ struct sd { static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, int size) { - int ret = -1; + int ret; u8 req_type = 0; unsigned int pipe = 0; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c index 7104a88b1e43..aac19d449be2 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c @@ -117,7 +117,7 @@ static int st6422_init(struct sd *sd) { int err = 0, i; - const u16 st6422_bridge_init[][2] = { + static const u16 st6422_bridge_init[][2] = { { STV_ISO_ENABLE, 0x00 }, /* disable capture */ { 0x1436, 0x00 }, { 0x1432, 0x03 }, /* 0x00-0x1F brightness */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index a34717eba409..eaa08c7999d4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -898,8 +898,12 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) pvr2_v4l2_dev_disassociate_parent(vp->dev_video); pvr2_v4l2_dev_disassociate_parent(vp->dev_radio); if (!list_empty(&vp->dev_video->devbase.fh_list) || - !list_empty(&vp->dev_radio->devbase.fh_list)) + (vp->dev_radio && + !list_empty(&vp->dev_radio->devbase.fh_list))) { + pvr2_trace(PVR2_TRACE_STRUCT, + "pvr2_v4l2 internal_check exit-empty id=%p", vp); return; + } pvr2_v4l2_destroy_no_lock(vp); } @@ -935,7 +939,8 @@ static int pvr2_v4l2_release(struct file *file) kfree(fhp); if (vp->channel.mc_head->disconnect_flag && list_empty(&vp->dev_video->devbase.fh_list) && - list_empty(&vp->dev_radio->devbase.fh_list)) { + (!vp->dev_radio || + list_empty(&vp->dev_radio->devbase.fh_list))) { pvr2_v4l2_destroy_no_lock(vp); } return 0; diff --git a/drivers/media/usb/tm6000/tm6000-regs.h b/drivers/media/usb/tm6000/tm6000-regs.h index d10424673db9..6a181f2e7ef2 100644 --- a/drivers/media/usb/tm6000/tm6000-regs.h +++ b/drivers/media/usb/tm6000/tm6000-regs.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * tm6000-regs.h - driver for TM5600/TM6000/TM6010 USB video capture devices * * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/usb/tm6000/tm6000-usb-isoc.h b/drivers/media/usb/tm6000/tm6000-usb-isoc.h index b275dbce3a1b..e3c6933f854d 100644 --- a/drivers/media/usb/tm6000/tm6000-usb-isoc.h +++ b/drivers/media/usb/tm6000/tm6000-usb-isoc.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * tm6000-buf.c - driver for TM5600/TM6000/TM6010 USB video capture devices * * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/usb/tm6000/tm6000.h b/drivers/media/usb/tm6000/tm6000.h index bf396544da9a..c08c95312739 100644 --- a/drivers/media/usb/tm6000/tm6000.h +++ b/drivers/media/usb/tm6000/tm6000.h @@ -1,5 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* - * SPDX-License-Identifier: GPL-2.0 * tm6000.h - driver for TM5600/TM6000/TM6010 USB video capture devices * * Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org> diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index cdc66adda755..93d36aab824f 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -314,6 +314,10 @@ static int usbvision_v4l2_open(struct file *file) if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto unlock; + } if (usbvision->user) { err_code = -EBUSY; } else { @@ -377,6 +381,7 @@ unlock: static int usbvision_v4l2_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, "close"); @@ -391,9 +396,10 @@ static int usbvision_v4l2_close(struct file *file) usbvision_scratch_free(usbvision); usbvision->user--; + r = usbvision->remove_pending; mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); return 0; @@ -453,6 +459,9 @@ static int vidioc_querycap(struct file *file, void *priv, { struct usb_usbvision *usbvision = video_drvdata(file); + if (!usbvision->dev) + return -ENODEV; + strscpy(vc->driver, "USBVision", sizeof(vc->driver)); strscpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, @@ -1061,6 +1070,11 @@ static int usbvision_radio_open(struct file *file) if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + + if (usbvision->remove_pending) { + err_code = -ENODEV; + goto out; + } err_code = v4l2_fh_open(file); if (err_code) goto out; @@ -1093,21 +1107,24 @@ out: static int usbvision_radio_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); + int r; PDEBUG(DBG_IO, ""); mutex_lock(&usbvision->v4l2_lock); /* Set packet size to 0 */ usbvision->iface_alt = 0; - usb_set_interface(usbvision->dev, usbvision->iface, - usbvision->iface_alt); + if (usbvision->dev) + usb_set_interface(usbvision->dev, usbvision->iface, + usbvision->iface_alt); usbvision_audio_off(usbvision); usbvision->radio = 0; usbvision->user--; + r = usbvision->remove_pending; mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->remove_pending) { + if (r) { printk(KERN_INFO "%s: Final disconnect\n", __func__); v4l2_fh_release(file); usbvision_release(usbvision); @@ -1539,6 +1556,7 @@ err_usb: static void usbvision_disconnect(struct usb_interface *intf) { struct usb_usbvision *usbvision = to_usbvision(usb_get_intfdata(intf)); + int u; PDEBUG(DBG_PROBE, ""); @@ -1555,13 +1573,14 @@ static void usbvision_disconnect(struct usb_interface *intf) v4l2_device_disconnect(&usbvision->v4l2_dev); usbvision_i2c_unregister(usbvision); usbvision->remove_pending = 1; /* Now all ISO data will be ignored */ + u = usbvision->user; usb_put_dev(usbvision->dev); usbvision->dev = NULL; /* USB device is no more */ mutex_unlock(&usbvision->v4l2_lock); - if (usbvision->user) { + if (u) { printk(KERN_INFO "%s: In use, disconnect pending\n", __func__); wake_up_interruptible(&usbvision->wait_frame); diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 66ee168ddc7e..428235ca2635 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2151,6 +2151,20 @@ static int uvc_probe(struct usb_interface *intf, sizeof(dev->name) - len); } + /* Initialize the media device. */ +#ifdef CONFIG_MEDIA_CONTROLLER + dev->mdev.dev = &intf->dev; + strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); + if (udev->serial) + strscpy(dev->mdev.serial, udev->serial, + sizeof(dev->mdev.serial)); + usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info)); + dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + media_device_init(&dev->mdev); + + dev->vdev.mdev = &dev->mdev; +#endif + /* Parse the Video Class control descriptor. */ if (uvc_parse_control(dev) < 0) { uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC " @@ -2171,19 +2185,7 @@ static int uvc_probe(struct usb_interface *intf, "linux-uvc-devel mailing list.\n"); } - /* Initialize the media device and register the V4L2 device. */ -#ifdef CONFIG_MEDIA_CONTROLLER - dev->mdev.dev = &intf->dev; - strscpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); - if (udev->serial) - strscpy(dev->mdev.serial, udev->serial, - sizeof(dev->mdev.serial)); - usb_make_path(udev, dev->mdev.bus_info, sizeof(dev->mdev.bus_info)); - dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); - media_device_init(&dev->mdev); - - dev->vdev.mdev = &dev->mdev; -#endif + /* Register the V4L2 device. */ if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) goto error; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 99bb71b47117..b6279ad7ac84 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -51,7 +51,7 @@ static int uvc_meta_v4l2_get_format(struct file *file, void *fh, memset(fmt, 0, sizeof(*fmt)); fmt->dataformat = stream->meta.format; - fmt->buffersize = UVC_METATADA_BUF_SIZE; + fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } @@ -72,7 +72,7 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, fmt->dataformat = fmeta == dev->info->meta_format ? fmeta : V4L2_META_FMT_UVC; - fmt->buffersize = UVC_METATADA_BUF_SIZE; + fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index da72577c2998..cd60c6c1749e 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -79,7 +79,7 @@ static int uvc_queue_setup(struct vb2_queue *vq, switch (vq->type) { case V4L2_BUF_TYPE_META_CAPTURE: - size = UVC_METATADA_BUF_SIZE; + size = UVC_METADATA_BUF_SIZE; break; default: diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c7c1baa90dea..f773dc5d802c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -491,7 +491,7 @@ struct uvc_stats_stream { unsigned int max_sof; /* Maximum STC.SOF value */ }; -#define UVC_METATADA_BUF_SIZE 1024 +#define UVC_METADATA_BUF_SIZE 1024 /** * struct uvc_copy_op: Context structure to schedule asynchronous memcpy diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 637962825d7a..57dbcc8083bf 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -20,7 +20,6 @@ #include <linux/usb.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/proc_fs.h> #include <linux/highmem.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -556,14 +555,12 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, { unsigned char *pdest; unsigned char *psrc; - s32 idx = -1; - struct zr364xx_framei *frm; + s32 idx = cam->cur_frame; + struct zr364xx_framei *frm = &cam->buffer.frame[idx]; int i = 0; unsigned char *ptr = NULL; _DBG("buffer to user\n"); - idx = cam->cur_frame; - frm = &cam->buffer.frame[idx]; /* swap bytes if camera needs it */ if (cam->method == METHOD0) { diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 62f7aa92ac29..d0e5ebc736f9 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -236,77 +236,79 @@ const struct v4l2_format_info *v4l2_format_info(u32 format) { static const struct v4l2_format_info formats[] = { /* RGB formats */ - { .format = V4L2_PIX_FMT_BGR24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_RGB24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_HSV24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_BGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_XBGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_BGRX32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_RGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_XRGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_RGBX32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_HSV32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_ARGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_RGBA32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_ABGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_BGRA32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_GREY, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV24, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XBGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGRX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XRGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBX32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ARGB32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGBA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_GREY, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, /* YUV packed formats */ - { .format = V4L2_PIX_FMT_YUYV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_YVYU, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_UYVY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_VYUY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUYV, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVYU, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_UYVY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_VYUY, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, /* YUV planar formats */ - { .format = V4L2_PIX_FMT_NV12, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_NV21, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_NV16, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_NV61, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_NV24, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_NV42, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - - { .format = V4L2_PIX_FMT_YUV410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, - { .format = V4L2_PIX_FMT_YVU410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, - { .format = V4L2_PIX_FMT_YUV411P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_YUV420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_YVU420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_YUV422P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YUV411P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422P, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, /* YUV planar formats, non contiguous variant */ - { .format = V4L2_PIX_FMT_YUV420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_YVU420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_YUV422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_YVU422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_YUV444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_YVU444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, - - { .format = V4L2_PIX_FMT_NV12M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_NV21M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, - { .format = V4L2_PIX_FMT_NV16M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_NV61M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU422M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU444M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_NV12M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, /* Bayer RGB formats */ - { .format = V4L2_PIX_FMT_SBGGR8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGBRG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGRBG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SRGGB8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SBGGR10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGBRG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGRBG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SRGGB10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SBGGR12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGBRG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SGRBG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, - { .format = V4L2_PIX_FMT_SRGGB12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, }; unsigned int i; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 1d8f38824631..2928c5e0a73d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -29,6 +29,8 @@ #define call_op(master, op) \ (has_op(master, op) ? master->ops->op(master) : 0) +static const union v4l2_ctrl_ptr ptr_null; + /* Internal temporary helper struct, one for each v4l2_ext_control */ struct v4l2_ctrl_helper { /* Pointer to the control reference of the master control */ @@ -566,6 +568,16 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Disabled at slice boundary", "NULL", }; + static const char * const hevc_decode_mode[] = { + "Slice-Based", + "Frame-Based", + NULL, + }; + static const char * const hevc_start_code[] = { + "No Start Code", + "Annex B Start Code", + NULL, + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -687,7 +699,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return hevc_tier; case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: return hevc_loop_filter_mode; - + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: + return hevc_decode_mode; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + return hevc_start_code; default: return NULL; } @@ -957,6 +972,11 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field"; case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame"; case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR"; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode"; + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -994,6 +1014,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range"; case V4L2_CID_PAN_SPEED: return "Pan, Speed"; case V4L2_CID_TILT_SPEED: return "Tilt, Speed"; + case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size"; /* FM Radio Modulator controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1265,6 +1286,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: case V4L2_CID_MPEG_VIDEO_HEVC_TIER: case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: + case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -1375,6 +1398,19 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; break; + case V4L2_CID_MPEG_VIDEO_HEVC_SPS: + *type = V4L2_CTRL_TYPE_HEVC_SPS; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PPS: + *type = V4L2_CTRL_TYPE_HEVC_PPS; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS; + break; + case V4L2_CID_UNIT_CELL_SIZE: + *type = V4L2_CTRL_TYPE_AREA; + *flags |= V4L2_CTRL_FLAG_READ_ONLY; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1520,7 +1556,8 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, if (ctrl->is_int) return ptr1.p_s32[idx] == ptr2.p_s32[idx]; idx *= ctrl->elem_size; - return !memcmp(ptr1.p + idx, ptr2.p + idx, ctrl->elem_size); + return !memcmp(ptr1.p_const + idx, ptr2.p_const + idx, + ctrl->elem_size); } } @@ -1530,7 +1567,10 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; void *p = ptr.p + idx * ctrl->elem_size; - memset(p, 0, ctrl->elem_size); + if (ctrl->p_def.p_const) + memcpy(p, ctrl->p_def.p_const, ctrl->elem_size); + else + memset(p, 0, ctrl->elem_size); /* * The cast is needed to get rid of a gcc warning complaining that @@ -1672,7 +1712,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_area *area; void *p = ptr.p + idx * ctrl->elem_size; + unsigned int i; switch ((u32)ctrl->type) { case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: @@ -1748,6 +1793,76 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, zero_padding(p_vp8_frame_header->entropy_header); zero_padding(p_vp8_frame_header->coder_state); break; + + case V4L2_CTRL_TYPE_HEVC_SPS: + p_hevc_sps = p; + + if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) { + p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0; + p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0; + p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0; + p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0; + } + + if (!(p_hevc_sps->flags & + V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) + p_hevc_sps->num_long_term_ref_pics_sps = 0; + break; + + case V4L2_CTRL_TYPE_HEVC_PPS: + p_hevc_pps = p; + + if (!(p_hevc_pps->flags & + V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED)) + p_hevc_pps->diff_cu_qp_delta_depth = 0; + + if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) { + p_hevc_pps->num_tile_columns_minus1 = 0; + p_hevc_pps->num_tile_rows_minus1 = 0; + memset(&p_hevc_pps->column_width_minus1, 0, + sizeof(p_hevc_pps->column_width_minus1)); + memset(&p_hevc_pps->row_height_minus1, 0, + sizeof(p_hevc_pps->row_height_minus1)); + + p_hevc_pps->flags &= + ~V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED; + } + + if (p_hevc_pps->flags & + V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) { + p_hevc_pps->pps_beta_offset_div2 = 0; + p_hevc_pps->pps_tc_offset_div2 = 0; + } + + zero_padding(*p_hevc_pps); + break; + + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + p_hevc_slice_params = p; + + if (p_hevc_slice_params->num_active_dpb_entries > + V4L2_HEVC_DPB_ENTRIES_NUM_MAX) + return -EINVAL; + + zero_padding(p_hevc_slice_params->pred_weight_table); + + for (i = 0; i < p_hevc_slice_params->num_active_dpb_entries; + i++) { + struct v4l2_hevc_dpb_entry *dpb_entry = + &p_hevc_slice_params->dpb[i]; + + zero_padding(*dpb_entry); + } + + zero_padding(*p_hevc_slice_params); + break; + + case V4L2_CTRL_TYPE_AREA: + area = p; + if (!area->width || !area->height) + return -EINVAL; + break; + default: return -EINVAL; } @@ -1840,7 +1955,7 @@ static int ptr_to_user(struct v4l2_ext_control *c, u32 len; if (ctrl->is_ptr && !ctrl->is_string) - return copy_to_user(c->ptr, ptr.p, c->size) ? + return copy_to_user(c->ptr, ptr.p_const, c->size) ? -EFAULT : 0; switch (ctrl->type) { @@ -1955,7 +2070,7 @@ static void ptr_to_ptr(struct v4l2_ctrl *ctrl, { if (ctrl == NULL) return; - memcpy(to.p, from.p, ctrl->elems * ctrl->elem_size); + memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size); } /* Copy the new value to the current value. */ @@ -2354,7 +2469,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, s64 min, s64 max, u64 step, s64 def, const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size, u32 flags, const char * const *qmenu, - const s64 *qmenu_int, void *priv) + const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def, + void *priv) { struct v4l2_ctrl *ctrl; unsigned sz_extra; @@ -2421,6 +2537,18 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); break; + case V4L2_CTRL_TYPE_HEVC_SPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_sps); + break; + case V4L2_CTRL_TYPE_HEVC_PPS: + elem_size = sizeof(struct v4l2_ctrl_hevc_pps); + break; + case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); + break; + case V4L2_CTRL_TYPE_AREA: + elem_size = sizeof(struct v4l2_area); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); @@ -2460,6 +2588,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, is_array) sz_extra += 2 * tot_ctrl_size; + if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) + sz_extra += elem_size; + ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL); if (ctrl == NULL) { handler_set_err(hdl, -ENOMEM); @@ -2503,6 +2634,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, ctrl->p_new.p = &ctrl->val; ctrl->p_cur.p = &ctrl->cur.val; } + + if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) { + ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size; + memcpy(ctrl->p_def.p, p_def.p_const, elem_size); + } + for (idx = 0; idx < elems; idx++) { ctrl->type_ops->init(ctrl, idx, ctrl->p_cur); ctrl->type_ops->init(ctrl, idx, ctrl->p_new); @@ -2554,7 +2691,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, type, min, max, is_menu ? cfg->menu_skip_mask : step, def, cfg->dims, cfg->elem_size, - flags, qmenu, qmenu_int, priv); + flags, qmenu, qmenu_int, cfg->p_def, priv); if (ctrl) ctrl->is_private = cfg->is_private; return ctrl; @@ -2579,7 +2716,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl, } return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, min, max, step, def, NULL, 0, - flags, NULL, NULL, NULL); + flags, NULL, NULL, ptr_null, NULL); } EXPORT_SYMBOL(v4l2_ctrl_new_std); @@ -2612,7 +2749,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl, } return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, 0, max, mask, def, NULL, 0, - flags, qmenu, qmenu_int, NULL); + flags, qmenu, qmenu_int, ptr_null, NULL); } EXPORT_SYMBOL(v4l2_ctrl_new_std_menu); @@ -2644,11 +2781,32 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, } return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, 0, max, mask, def, NULL, 0, - flags, qmenu, NULL, NULL); + flags, qmenu, NULL, ptr_null, NULL); } EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items); +/* Helper function for standard compound controls */ +struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, u32 id, + const union v4l2_ctrl_ptr p_def) +{ + const char *name; + enum v4l2_ctrl_type type; + u32 flags; + s64 min, max, step, def; + + v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags); + if (type < V4L2_CTRL_COMPOUND_TYPES) { + handler_set_err(hdl, -EINVAL); + return NULL; + } + return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, + min, max, step, def, NULL, 0, + flags, NULL, NULL, p_def, NULL); +} +EXPORT_SYMBOL(v4l2_ctrl_new_std_compound); + /* Helper function for standard integer menu controls */ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, const struct v4l2_ctrl_ops *ops, @@ -2669,7 +2827,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl, } return v4l2_ctrl_new(hdl, ops, NULL, id, name, type, 0, max, 0, def, NULL, 0, - flags, NULL, qmenu_int, NULL); + flags, NULL, qmenu_int, ptr_null, NULL); } EXPORT_SYMBOL(v4l2_ctrl_new_int_menu); @@ -3144,6 +3302,7 @@ static void v4l2_ctrl_request_queue(struct media_request_object *obj) struct v4l2_ctrl_handler *prev_hdl = NULL; struct v4l2_ctrl_ref *ref_ctrl, *ref_ctrl_prev = NULL; + mutex_lock(main_hdl->lock); if (list_empty(&main_hdl->requests_queued)) goto queue; @@ -3175,18 +3334,22 @@ static void v4l2_ctrl_request_queue(struct media_request_object *obj) queue: list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued); hdl->request_is_queued = true; + mutex_unlock(main_hdl->lock); } static void v4l2_ctrl_request_unbind(struct media_request_object *obj) { struct v4l2_ctrl_handler *hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); + struct v4l2_ctrl_handler *main_hdl = obj->priv; list_del_init(&hdl->requests); + mutex_lock(main_hdl->lock); if (hdl->request_is_queued) { list_del_init(&hdl->requests_queued); hdl->request_is_queued = false; } + mutex_unlock(main_hdl->lock); } static void v4l2_ctrl_request_release(struct media_request_object *obj) @@ -4080,6 +4243,18 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); +int __v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, + const struct v4l2_area *area) +{ + lockdep_assert_held(ctrl->handler->lock); + + /* It's a driver bug if this happens. */ + WARN_ON(ctrl->type != V4L2_CTRL_TYPE_AREA); + *ctrl->p_new.p_area = *area; + return set_ctrl(NULL, ctrl, 0); +} +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_area); + void v4l2_ctrl_request_complete(struct media_request *req, struct v4l2_ctrl_handler *main_hdl) { @@ -4128,9 +4303,11 @@ void v4l2_ctrl_request_complete(struct media_request *req, v4l2_ctrl_unlock(ctrl); } + mutex_lock(main_hdl->lock); WARN_ON(!hdl->request_is_queued); list_del_init(&hdl->requests_queued); hdl->request_is_queued = false; + mutex_unlock(main_hdl->lock); media_request_object_complete(obj); media_request_object_put(obj); } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 4037689a945a..da42d172714a 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -533,13 +533,23 @@ static int get_index(struct video_device *vdev) */ static void determine_valid_ioctls(struct video_device *vdev) { + const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE; + const u32 meta_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; - bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER; + bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER && + (vdev->device_caps & vid_caps); bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH; + bool is_meta = vdev->vfl_type == VFL_TYPE_GRABBER && + (vdev->device_caps & meta_caps); bool is_rx = vdev->vfl_dir != VFL_DIR_TX; bool is_tx = vdev->vfl_dir != VFL_DIR_RX; @@ -571,8 +581,10 @@ static void determine_valid_ioctls(struct video_device *vdev) set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls); if (vdev->ctrl_handler || ops->vidioc_querymenu) set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls); - SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); - SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); + if (!is_tch) { + SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); + SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); + } SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); #ifdef CONFIG_VIDEO_ADV_DEBUG set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls); @@ -586,40 +598,32 @@ static void determine_valid_ioctls(struct video_device *vdev) if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator) set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); - if (is_vid || is_tch) { - /* video and metadata specific ioctls */ + if (is_vid) { + /* video specific ioctls */ if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || - ops->vidioc_enum_fmt_vid_overlay || - ops->vidioc_enum_fmt_meta_cap)) || - (is_tx && (ops->vidioc_enum_fmt_vid_out || - ops->vidioc_enum_fmt_meta_out))) + ops->vidioc_enum_fmt_vid_overlay)) || + (is_tx && ops->vidioc_enum_fmt_vid_out)) set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_g_fmt_vid_cap || ops->vidioc_g_fmt_vid_cap_mplane || - ops->vidioc_g_fmt_vid_overlay || - ops->vidioc_g_fmt_meta_cap)) || + ops->vidioc_g_fmt_vid_overlay)) || (is_tx && (ops->vidioc_g_fmt_vid_out || ops->vidioc_g_fmt_vid_out_mplane || - ops->vidioc_g_fmt_vid_out_overlay || - ops->vidioc_g_fmt_meta_out))) + ops->vidioc_g_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_s_fmt_vid_cap || ops->vidioc_s_fmt_vid_cap_mplane || - ops->vidioc_s_fmt_vid_overlay || - ops->vidioc_s_fmt_meta_cap)) || + ops->vidioc_s_fmt_vid_overlay)) || (is_tx && (ops->vidioc_s_fmt_vid_out || ops->vidioc_s_fmt_vid_out_mplane || - ops->vidioc_s_fmt_vid_out_overlay || - ops->vidioc_s_fmt_meta_out))) + ops->vidioc_s_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_try_fmt_vid_cap || ops->vidioc_try_fmt_vid_cap_mplane || - ops->vidioc_try_fmt_vid_overlay || - ops->vidioc_try_fmt_meta_cap)) || + ops->vidioc_try_fmt_vid_overlay)) || (is_tx && (ops->vidioc_try_fmt_vid_out || ops->vidioc_try_fmt_vid_out_mplane || - ops->vidioc_try_fmt_vid_out_overlay || - ops->vidioc_try_fmt_meta_out))) + ops->vidioc_try_fmt_vid_out_overlay))) set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay); SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf); @@ -641,7 +645,21 @@ static void determine_valid_ioctls(struct video_device *vdev) set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); - } else if (is_vbi) { + } + if (is_meta && is_rx) { + /* metadata capture specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_cap); + } else if (is_meta && is_tx) { + /* metadata output specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_out); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_out); + } + if (is_vbi) { /* vbi specific ioctls */ if ((is_rx && (ops->vidioc_g_fmt_vbi_cap || ops->vidioc_g_fmt_sliced_vbi_cap)) || @@ -659,30 +677,35 @@ static void determine_valid_ioctls(struct video_device *vdev) ops->vidioc_try_fmt_sliced_vbi_out))) set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap); + } else if (is_tch) { + /* touch specific ioctls */ + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_vid_cap); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); + SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input); + SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input); + SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input); + SET_VALID_IOCTL(ops, VIDIOC_G_PARM, vidioc_g_parm); + SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); } else if (is_sdr && is_rx) { /* SDR receiver specific ioctls */ - if (ops->vidioc_enum_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); - if (ops->vidioc_g_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); - if (ops->vidioc_s_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); - if (ops->vidioc_try_fmt_sdr_cap) - set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_cap); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_cap); } else if (is_sdr && is_tx) { /* SDR transmitter specific ioctls */ - if (ops->vidioc_enum_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); - if (ops->vidioc_g_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); - if (ops->vidioc_s_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); - if (ops->vidioc_try_fmt_sdr_out) - set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); + SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_out); + SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_out); } - if (is_vid || is_vbi || is_sdr || is_tch) { - /* ioctls valid for video, metadata, vbi or sdr */ + if (is_vid || is_vbi || is_sdr || is_tch || is_meta) { + /* ioctls valid for video, vbi, sdr, touch and metadata */ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); @@ -694,8 +717,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); } - if (is_vid || is_vbi || is_tch) { - /* ioctls valid for video or vbi */ + if (is_vid || is_vbi || is_meta) { + /* ioctls valid for video, vbi and metadata */ if (ops->vidioc_s_std) set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std); @@ -719,8 +742,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout); SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout); } - if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER && - ops->vidioc_g_std)) + if (ops->vidioc_g_parm || ops->vidioc_g_std) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings); @@ -734,7 +756,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator); SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator); } - if (is_rx) { + if (is_rx && !is_tch) { /* receiver only ioctls */ SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner); SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner); diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 4f23e939ead0..230d65a64217 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -293,7 +293,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, if (prefix == NULL) prefix = ""; - pr_info("%s: %s%ux%u%s%u.%u (%ux%u)\n", dev_prefix, prefix, + pr_info("%s: %s%ux%u%s%u.%02u (%ux%u)\n", dev_prefix, prefix, bt->width, bt->height, bt->interlaced ? "i" : "p", fps / 100, fps % 100, htot, vtot); @@ -757,7 +757,7 @@ bool v4l2_detect_gtf(unsigned frame_height, pix_clk = pix_clk / GTF_PXL_CLK_GRAN * GTF_PXL_CLK_GRAN; hsync = (frame_width * 8 + 50) / 100; - hsync = ((hsync + GTF_CELL_GRAN / 2) / GTF_CELL_GRAN) * GTF_CELL_GRAN; + hsync = DIV_ROUND_CLOSEST(hsync, GTF_CELL_GRAN) * GTF_CELL_GRAN; h_fp = h_blank / 2 - hsync; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 3bd1888787eb..192cac076761 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -512,6 +512,7 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) return; kfree(vep->link_frequencies); + vep->link_frequencies = NULL; } EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 51b912743f0f..4e700583659b 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -932,12 +932,22 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) static int check_fmt(struct file *file, enum v4l2_buf_type type) { + const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE; + const u32 meta_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_META_OUTPUT; struct video_device *vfd = video_devdata(file); const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; - bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER; + bool is_vid = vfd->vfl_type == VFL_TYPE_GRABBER && + (vfd->device_caps & vid_caps); bool is_vbi = vfd->vfl_type == VFL_TYPE_VBI; bool is_sdr = vfd->vfl_type == VFL_TYPE_SDR; bool is_tch = vfd->vfl_type == VFL_TYPE_TOUCH; + bool is_meta = vfd->vfl_type == VFL_TYPE_GRABBER && + (vfd->device_caps & meta_caps); bool is_rx = vfd->vfl_dir != VFL_DIR_TX; bool is_tx = vfd->vfl_dir != VFL_DIR_RX; @@ -996,11 +1006,11 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type) return 0; break; case V4L2_BUF_TYPE_META_CAPTURE: - if (is_vid && is_rx && ops->vidioc_g_fmt_meta_cap) + if (is_meta && is_rx && ops->vidioc_g_fmt_meta_cap) return 0; break; case V4L2_BUF_TYPE_META_OUTPUT: - if (is_vid && is_tx && ops->vidioc_g_fmt_meta_out) + if (is_meta && is_tx && ops->vidioc_g_fmt_meta_out) return 0; break; default: @@ -1330,6 +1340,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break; case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break; case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break; + case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break; default: /* Compressed formats */ @@ -1356,6 +1367,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VP8_FRAME: descr = "VP8 Frame"; break; case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ + case V4L2_PIX_FMT_HEVC_SLICE: descr = "HEVC Parsed Slice Data"; break; case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ case V4L2_PIX_FMT_FWHT_STATELESS: descr = "FWHT Stateless"; break; /* used in vicodec */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; @@ -1466,10 +1478,26 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, return ret; } +static void v4l_pix_format_touch(struct v4l2_pix_format *p) +{ + /* + * The v4l2_pix_format structure contains fields that make no sense for + * touch. Set them to default values in this case. + */ + + p->field = V4L2_FIELD_NONE; + p->colorspace = V4L2_COLORSPACE_RAW; + p->flags = 0; + p->ycbcr_enc = 0; + p->quantization = 0; + p->xfer_func = 0; +} + static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct v4l2_format *p = arg; + struct video_device *vfd = video_devdata(file); int ret = check_fmt(file, p->type); if (ret) @@ -1507,6 +1535,8 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; + if (vfd->vfl_type == VFL_TYPE_TOUCH) + v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); @@ -1544,21 +1574,6 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, return -EINVAL; } -static void v4l_pix_format_touch(struct v4l2_pix_format *p) -{ - /* - * The v4l2_pix_format structure contains fields that make no sense for - * touch. Set them to default values in this case. - */ - - p->field = V4L2_FIELD_NONE; - p->colorspace = V4L2_COLORSPACE_RAW; - p->flags = 0; - p->ycbcr_enc = 0; - p->quantization = 0; - p->xfer_func = 0; -} - static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1602,12 +1617,12 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vid_out)) @@ -1633,22 +1648,22 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_s_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_s_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_meta_cap)) @@ -1704,12 +1719,12 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vid_out)) @@ -1735,22 +1750,22 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.vbi); + CLEAR_AFTER_FIELD(p, fmt.vbi.flags); return ops->vidioc_try_fmt_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sliced); + CLEAR_AFTER_FIELD(p, fmt.sliced.io_size); return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sdr_out)) break; - CLEAR_AFTER_FIELD(p, fmt.sdr); + CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize); return ops->vidioc_try_fmt_sdr_out(file, fh, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_meta_cap)) @@ -2637,7 +2652,7 @@ struct v4l2_ioctl_info { /* Zero struct from after the field to the end */ #define INFO_FL_CLEAR(v4l2_struct, field) \ ((offsetof(struct v4l2_struct, field) + \ - sizeof(((struct v4l2_struct *)0)->field)) << 16) + FIELD_SIZEOF(struct v4l2_struct, field)) << 16) #define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16) #define DEFINE_V4L_STUB_FUNC(_vidioc) \ diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 19937dd3c6f6..1afd9c6ad908 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -284,7 +284,8 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev) static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx) { - unsigned long flags_job, flags_out, flags_cap; + unsigned long flags_job; + struct vb2_v4l2_buffer *dst, *src; dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx); @@ -307,20 +308,37 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, goto job_unlock; } - spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); - if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue) - && !m2m_ctx->out_q_ctx.buffered) { + src = v4l2_m2m_next_src_buf(m2m_ctx); + dst = v4l2_m2m_next_dst_buf(m2m_ctx); + if (!src && !m2m_ctx->out_q_ctx.buffered) { dprintk("No input buffers available\n"); - goto out_unlock; + goto job_unlock; } - spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); - if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue) - && !m2m_ctx->cap_q_ctx.buffered) { + if (!dst && !m2m_ctx->cap_q_ctx.buffered) { dprintk("No output buffers available\n"); - goto cap_unlock; + goto job_unlock; } - spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); + + m2m_ctx->new_frame = true; + + if (src && dst && dst->is_held && + dst->vb2_buf.copied_timestamp && + dst->vb2_buf.timestamp != src->vb2_buf.timestamp) { + dst->is_held = false; + v4l2_m2m_dst_buf_remove(m2m_ctx); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + dst = v4l2_m2m_next_dst_buf(m2m_ctx); + + if (!dst && !m2m_ctx->cap_q_ctx.buffered) { + dprintk("No output buffers available after returning held buffer\n"); + goto job_unlock; + } + } + + if (src && dst && (m2m_ctx->out_q_ctx.q.subsystem_flags & + VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF)) + m2m_ctx->new_frame = !dst->vb2_buf.copied_timestamp || + dst->vb2_buf.timestamp != src->vb2_buf.timestamp; if (m2m_dev->m2m_ops->job_ready && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) { @@ -331,13 +349,6 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue); m2m_ctx->job_flags |= TRANS_QUEUED; - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); - return; - -cap_unlock: - spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap); -out_unlock: - spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out); job_unlock: spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); } @@ -412,37 +423,97 @@ static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx) } } -void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, - struct v4l2_m2m_ctx *m2m_ctx) +/* + * Schedule the next job, called from v4l2_m2m_job_finish() or + * v4l2_m2m_buf_done_and_job_finish(). + */ +static void v4l2_m2m_schedule_next_job(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx) { - unsigned long flags; + /* + * This instance might have more buffers ready, but since we do not + * allow more than one job on the job_queue per instance, each has + * to be scheduled separately after the previous one finishes. + */ + __v4l2_m2m_try_queue(m2m_dev, m2m_ctx); - spin_lock_irqsave(&m2m_dev->job_spinlock, flags); + /* + * We might be running in atomic context, + * but the job must be run in non-atomic context. + */ + schedule_work(&m2m_dev->job_work); +} + +/* + * Assumes job_spinlock is held, called from v4l2_m2m_job_finish() or + * v4l2_m2m_buf_done_and_job_finish(). + */ +static bool _v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx) +{ if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) { - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); dprintk("Called by an instance not currently running\n"); - return; + return false; } list_del(&m2m_dev->curr_ctx->queue); m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING); wake_up(&m2m_dev->curr_ctx->finished); m2m_dev->curr_ctx = NULL; + return true; +} - spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); - - /* This instance might have more buffers ready, but since we do not - * allow more than one job on the job_queue per instance, each has - * to be scheduled separately after the previous one finishes. */ - __v4l2_m2m_try_queue(m2m_dev, m2m_ctx); +void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx) +{ + unsigned long flags; + bool schedule_next; - /* We might be running in atomic context, - * but the job must be run in non-atomic context. + /* + * This function should not be used for drivers that support + * holding capture buffers. Those should use + * v4l2_m2m_buf_done_and_job_finish() instead. */ - schedule_work(&m2m_dev->job_work); + WARN_ON(m2m_ctx->out_q_ctx.q.subsystem_flags & + VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF); + spin_lock_irqsave(&m2m_dev->job_spinlock, flags); + schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); + + if (schedule_next) + v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx); } EXPORT_SYMBOL(v4l2_m2m_job_finish); +void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *src_buf, *dst_buf; + bool schedule_next = false; + unsigned long flags; + + spin_lock_irqsave(&m2m_dev->job_spinlock, flags); + src_buf = v4l2_m2m_src_buf_remove(m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx); + + if (WARN_ON(!src_buf || !dst_buf)) + goto unlock; + v4l2_m2m_buf_done(src_buf, state); + dst_buf->is_held = src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; + if (!dst_buf->is_held) { + v4l2_m2m_dst_buf_remove(m2m_ctx); + v4l2_m2m_buf_done(dst_buf, state); + } + schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); +unlock: + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); + + if (schedule_next) + v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx); +} +EXPORT_SYMBOL(v4l2_m2m_buf_done_and_job_finish); + int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_requestbuffers *reqbufs) { @@ -1154,6 +1225,59 @@ int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd); +int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + if (dc->cmd != V4L2_DEC_CMD_FLUSH) + return -EINVAL; + + dc->flags = 0; + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_try_decoder_cmd); + +int v4l2_m2m_ioctl_stateless_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *dc) +{ + struct v4l2_fh *fh = file->private_data; + struct vb2_v4l2_buffer *out_vb, *cap_vb; + struct v4l2_m2m_dev *m2m_dev = fh->m2m_ctx->m2m_dev; + unsigned long flags; + int ret; + + ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, dc); + if (ret < 0) + return ret; + + spin_lock_irqsave(&m2m_dev->job_spinlock, flags); + out_vb = v4l2_m2m_last_src_buf(fh->m2m_ctx); + cap_vb = v4l2_m2m_last_dst_buf(fh->m2m_ctx); + + /* + * If there is an out buffer pending, then clear any HOLD flag. + * + * By clearing this flag we ensure that when this output + * buffer is processed any held capture buffer will be released. + */ + if (out_vb) { + out_vb->flags &= ~V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF; + } else if (cap_vb && cap_vb->is_held) { + /* + * If there were no output buffers, but there is a + * capture buffer that is held, then release that + * buffer. + */ + cap_vb->is_held = false; + v4l2_m2m_dst_buf_remove(fh->m2m_ctx); + v4l2_m2m_buf_done(cap_vb, VB2_BUF_STATE_DONE); + } + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_decoder_cmd); + /* * v4l2_file_operations helpers. It is assumed here same lock is used * for the output and the capture buffer queue. diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f725cd9b66b9..9e987c0f840e 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -112,7 +112,7 @@ static int subdev_close(struct file *file) return 0; } -static inline int check_which(__u32 which) +static inline int check_which(u32 which) { if (which != V4L2_SUBDEV_FORMAT_TRY && which != V4L2_SUBDEV_FORMAT_ACTIVE) @@ -121,7 +121,7 @@ static inline int check_which(__u32 which) return 0; } -static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) +static inline int check_pad(struct v4l2_subdev *sd, u32 pad) { #if defined(CONFIG_MEDIA_CONTROLLER) if (sd->entity.num_pads) { @@ -136,7 +136,7 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) return 0; } -static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg) +static int check_cfg(u32 which, struct v4l2_subdev_pad_config *cfg) { if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg) return -EINVAL; diff --git a/drivers/staging/media/allegro-dvt/nal-h264.c b/drivers/staging/media/allegro-dvt/nal-h264.c index 4e14b77851e1..bd48b8883572 100644 --- a/drivers/staging/media/allegro-dvt/nal-h264.c +++ b/drivers/staging/media/allegro-dvt/nal-h264.c @@ -235,7 +235,7 @@ static inline int rbsp_write_bit(struct rbsp *rbsp, bool value) rbsp->pos++; - if (value == 1 || + if (value || (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) { rbsp->num_consecutive_zeros = 0; } else { diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index f670bbde4159..deb90ae37859 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -26,21 +26,9 @@ #include "hantro_hw.h" -#define VP8_MB_DIM 16 -#define VP8_MB_WIDTH(w) DIV_ROUND_UP(w, VP8_MB_DIM) -#define VP8_MB_HEIGHT(h) DIV_ROUND_UP(h, VP8_MB_DIM) - -#define H264_MB_DIM 16 -#define H264_MB_WIDTH(w) DIV_ROUND_UP(w, H264_MB_DIM) -#define H264_MB_HEIGHT(h) DIV_ROUND_UP(h, H264_MB_DIM) - -#define MPEG2_MB_DIM 16 -#define MPEG2_MB_WIDTH(w) DIV_ROUND_UP(w, MPEG2_MB_DIM) -#define MPEG2_MB_HEIGHT(h) DIV_ROUND_UP(h, MPEG2_MB_DIM) - -#define JPEG_MB_DIM 16 -#define JPEG_MB_WIDTH(w) DIV_ROUND_UP(w, JPEG_MB_DIM) -#define JPEG_MB_HEIGHT(h) DIV_ROUND_UP(h, JPEG_MB_DIM) +#define MB_DIM 16 +#define MB_WIDTH(w) DIV_ROUND_UP(w, MB_DIM) +#define MB_HEIGHT(h) DIV_ROUND_UP(h, MB_DIM) struct hantro_ctx; struct hantro_codec_ops; @@ -379,7 +367,7 @@ static inline void hantro_reg_write(struct hantro_dev *vpu, bool hantro_is_encoder_ctx(const struct hantro_ctx *ctx); void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id); -dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts); +dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts); static inline struct vb2_v4l2_buffer * hantro_get_src_buf(struct hantro_ctx *ctx) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 6d9d41170832..26108c96b674 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -43,8 +43,9 @@ void *hantro_get_ctrl(struct hantro_ctx *ctx, u32 id) return ctrl ? ctrl->p_cur.p : NULL; } -dma_addr_t hantro_get_ref(struct vb2_queue *q, u64 ts) +dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) { + struct vb2_queue *q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); struct vb2_buffer *buf; int index; @@ -413,20 +414,18 @@ static int hantro_open(struct file *filp) if (func->id == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { allowed_codecs = vpu->variant->codec & HANTRO_ENCODERS; ctx->buf_finish = hantro_enc_buf_finish; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, - queue_init); } else if (func->id == MEDIA_ENT_F_PROC_VIDEO_DECODER) { allowed_codecs = vpu->variant->codec & HANTRO_DECODERS; ctx->buf_finish = hantro_dec_buf_finish; - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, - queue_init); } else { - ctx->fh.m2m_ctx = ERR_PTR(-ENODEV); + ret = -ENODEV; + goto err_ctx_free; } + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(vpu->m2m_dev, ctx, queue_init); if (IS_ERR(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); - kfree(ctx); - return ret; + goto err_ctx_free; } v4l2_fh_init(&ctx->fh, vdev); @@ -447,6 +446,7 @@ static int hantro_open(struct file *filp) err_fh_free: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); +err_ctx_free: kfree(ctx); return ret; } diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 7ab534936843..3cd40a8f0daa 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -34,9 +34,11 @@ static void set_params(struct hantro_ctx *ctx) reg = G1_REG_DEC_CTRL0_DEC_AXI_WR_ID(0x0); if (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) reg |= G1_REG_DEC_CTRL0_SEQ_MBAFF_E; - reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E; - if (dec_param->nal_ref_idc) - reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E; + if (sps->profile_idc > 66) { + reg |= G1_REG_DEC_CTRL0_PICORD_COUNT_E; + if (dec_param->nal_ref_idc) + reg |= G1_REG_DEC_CTRL0_WRITE_MVS_E; + } if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || @@ -49,8 +51,8 @@ static void set_params(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); /* Decoder control register 1. */ - reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(sps->pic_width_in_mbs_minus1 + 1) | - G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(sps->pic_height_in_map_units_minus1 + 1) | + reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) | + G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | G1_REG_DEC_CTRL1_REF_FRAMES(sps->max_num_ref_frames); vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL1); @@ -61,7 +63,7 @@ static void set_params(struct hantro_ctx *ctx) /* always use the matrix sent from userspace */ reg |= G1_REG_DEC_CTRL2_TYPE1_QUANT_E; - if (slices[0].flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) reg |= G1_REG_DEC_CTRL2_FIELDPIC_FLAG_E; vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL2); @@ -79,7 +81,7 @@ static void set_params(struct hantro_ctx *ctx) reg |= G1_REG_DEC_CTRL4_CABAC_E; if (sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) reg |= G1_REG_DEC_CTRL4_DIR_8X8_INFER_E; - if (sps->chroma_format_idc == 0) + if (sps->profile_idc >= 100 && sps->chroma_format_idc == 0) reg |= G1_REG_DEC_CTRL4_BLACKWHITE_E; if (pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) reg |= G1_REG_DEC_CTRL4_WEIGHT_PRED_E; @@ -220,10 +222,9 @@ static void set_ref(struct hantro_ctx *ctx) /* Set up addresses of DPB buffers. */ for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { - struct vb2_buffer *buf = hantro_h264_get_ref_buf(ctx, i); + dma_addr_t dma_addr = hantro_h264_get_ref_buf(ctx, i); - vdpu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(buf, 0), - G1_REG_ADDR_REF(i)); + vdpu_write_relaxed(vpu, dma_addr, G1_REG_ADDR_REF(i)); } } @@ -233,6 +234,7 @@ static void set_buffers(struct hantro_ctx *ctx) struct vb2_v4l2_buffer *src_buf, *dst_buf; struct hantro_dev *vpu = ctx->dev; dma_addr_t src_dma, dst_dma; + size_t offset = 0; src_buf = hantro_get_src_buf(ctx); dst_buf = hantro_get_dst_buf(ctx); @@ -243,18 +245,30 @@ static void set_buffers(struct hantro_ctx *ctx) /* Destination (decoded frame) buffer. */ dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - vdpu_write_relaxed(vpu, dst_dma, G1_REG_ADDR_DST); + /* Adjust dma addr to start at second line for bottom field */ + if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) + offset = ALIGN(ctx->src_fmt.width, MB_DIM); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DST); /* Higher profiles require DMV buffer appended to reference frames. */ - if (ctrls->sps->profile_idc > 66) { - size_t pic_size = ctx->h264_dec.pic_size; - size_t mv_offset = round_up(pic_size, 8); - + if (ctrls->sps->profile_idc > 66 && ctrls->decode->nal_ref_idc) { + unsigned int bytes_per_mb = 384; + + /* DMV buffer for monochrome start directly after Y-plane */ + if (ctrls->sps->profile_idc >= 100 && + ctrls->sps->chroma_format_idc == 0) + bytes_per_mb = 256; + offset = bytes_per_mb * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + + /* + * DMV buffer is split in two for field encoded frames, + * adjust offset for bottom field + */ if (ctrls->slices[0].flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) - mv_offset += 32 * H264_MB_WIDTH(ctx->dst_fmt.width); - - vdpu_write_relaxed(vpu, dst_dma + mv_offset, - G1_REG_ADDR_DIR_MV); + offset += 32 * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV); } /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ diff --git a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c index 80f0e94f8afa..f3bf67d8a289 100644 --- a/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_mpeg2_dec.c @@ -105,17 +105,14 @@ hantro_g1_mpeg2_dec_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); switch (picture->picture_coding_type) { case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = hantro_get_ref(vq, + backward_addr = hantro_get_ref(ctx, slice_params->backward_ref_ts); /* fall-through */ case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = hantro_get_ref(vq, + forward_addr = hantro_get_ref(ctx, slice_params->forward_ref_ts); } @@ -207,8 +204,8 @@ void hantro_g1_mpeg2_dec_run(struct hantro_ctx *ctx) G1_REG_DEC_AXI_WR_ID(0); vdpu_write_relaxed(vpu, reg, G1_SWREG(3)); - reg = G1_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | - G1_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + reg = G1_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | + G1_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | G1_REG_ALT_SCAN_E(picture->alternate_scan) | G1_REG_TOPFIELDFIRST_E(picture->top_field_first); vdpu_write_relaxed(vpu, reg, G1_SWREG(4)); diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 6d99c2be01cf..cad18094fee0 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -370,19 +370,18 @@ static void cfg_tap(struct hantro_ctx *ctx, static void cfg_ref(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp8_frame_header *hdr) { - struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; vb2_dst = hantro_get_dst_buf(ctx); - ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + ref = hantro_get_ref(ctx, hdr->last_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0)); - ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + ref = hantro_get_ref(ctx, hdr->golden_frame_ts); WARN_ON(!ref && hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); @@ -390,7 +389,7 @@ static void cfg_ref(struct hantro_ctx *ctx, ref |= G1_REG_ADDR_REF_TOPC_E; vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4)); - ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + ref = hantro_get_ref(ctx, hdr->alt_frame_ts); WARN_ON(!ref && hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); @@ -470,8 +469,8 @@ void hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) vdpu_write_relaxed(vpu, reg, G1_REG_DEC_CTRL0); /* Frame dimensions */ - mb_width = VP8_MB_WIDTH(width); - mb_height = VP8_MB_HEIGHT(height); + mb_width = MB_WIDTH(width); + mb_height = MB_HEIGHT(height); reg = G1_REG_DEC_CTRL1_PIC_MB_WIDTH(mb_width) | G1_REG_DEC_CTRL1_PIC_MB_HEIGHT_P(mb_height) | G1_REG_DEC_CTRL1_PIC_MB_W_EXT(mb_width >> 9) | diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index ecd34a7db190..938b48d4d3d9 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -116,8 +116,8 @@ void hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) /* Make sure that all registers are written at this point. */ vepu_write(vpu, reg, H1_REG_AXI_CTRL); - reg = H1_REG_ENC_CTRL_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) - | H1_REG_ENC_CTRL_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) + reg = H1_REG_ENC_CTRL_WIDTH(MB_WIDTH(ctx->src_fmt.width)) + | H1_REG_ENC_CTRL_HEIGHT(MB_HEIGHT(ctx->src_fmt.height)) | H1_REG_ENC_CTRL_ENC_MODE_JPEG | H1_REG_ENC_PIC_INTRA | H1_REG_ENC_CTRL_EN_BIT; diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index 0d758e0c0f99..568640eab3a6 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -20,9 +20,9 @@ /* Size with u32 units. */ #define CABAC_INIT_BUFFER_SIZE (460 * 2) #define POC_BUFFER_SIZE 34 -#define SCALING_LIST_SIZE (6 * 16 + 6 * 64) +#define SCALING_LIST_SIZE (6 * 16 + 2 * 64) -#define POC_CMP(p0, p1) ((p0) < (p1) ? -1 : 1) +#define HANTRO_CMP(a, b) ((a) < (b) ? -1 : 1) /* Data structure describing auxiliary buffer format. */ struct hantro_h264_dec_priv_tbl { @@ -194,23 +194,6 @@ static const u32 h264_cabac_table[] = { 0x1f0c2517, 0x1f261440 }; -/* - * NOTE: The scaling lists are in zig-zag order, apply inverse scanning process - * to get the values in matrix order. In addition, the hardware requires bytes - * swapped within each subsequent 4 bytes. Both arrays below include both - * transformations. - */ -static const u32 zig_zag_4x4[] = { - 3, 2, 7, 11, 6, 1, 0, 5, 10, 15, 14, 9, 4, 8, 13, 12 -}; - -static const u32 zig_zag_8x8[] = { - 3, 2, 11, 19, 10, 1, 0, 9, 18, 27, 35, 26, 17, 8, 7, 6, - 15, 16, 25, 34, 43, 51, 42, 33, 24, 23, 14, 5, 4, 13, 22, 31, - 32, 41, 50, 59, 58, 49, 40, 39, 30, 21, 12, 20, 29, 38, 47, 48, - 57, 56, 55, 46, 37, 28, 36, 45, 54, 63, 62, 53, 44, 52, 61, 60 -}; - static void reorder_scaling_list(struct hantro_ctx *ctx) { @@ -218,33 +201,23 @@ reorder_scaling_list(struct hantro_ctx *ctx) const struct v4l2_ctrl_h264_scaling_matrix *scaling = ctrls->scaling; const size_t num_list_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4); const size_t list_len_4x4 = ARRAY_SIZE(scaling->scaling_list_4x4[0]); - const size_t num_list_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8); const size_t list_len_8x8 = ARRAY_SIZE(scaling->scaling_list_8x8[0]); struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; - u8 *dst = tbl->scaling_list; - const u8 *src; + u32 *dst = (u32 *)tbl->scaling_list; + const u32 *src; int i, j; - BUILD_BUG_ON(ARRAY_SIZE(zig_zag_4x4) != list_len_4x4); - BUILD_BUG_ON(ARRAY_SIZE(zig_zag_8x8) != list_len_8x8); - BUILD_BUG_ON(ARRAY_SIZE(tbl->scaling_list) != - num_list_4x4 * list_len_4x4 + - num_list_8x8 * list_len_8x8); - - src = &scaling->scaling_list_4x4[0][0]; - for (i = 0; i < num_list_4x4; ++i) { - for (j = 0; j < list_len_4x4; ++j) - dst[zig_zag_4x4[j]] = src[j]; - src += list_len_4x4; - dst += list_len_4x4; + for (i = 0; i < num_list_4x4; i++) { + src = (u32 *)&scaling->scaling_list_4x4[i]; + for (j = 0; j < list_len_4x4 / 4; j++) + *dst++ = swab32(src[j]); } - src = &scaling->scaling_list_8x8[0][0]; - for (i = 0; i < num_list_8x8; ++i) { - for (j = 0; j < list_len_8x8; ++j) - dst[zig_zag_8x8[j]] = src[j]; - src += list_len_8x8; - dst += list_len_8x8; + /* Only Intra/Inter Y lists */ + for (i = 0; i < 2; i++) { + src = (u32 *)&scaling->scaling_list_8x8[i]; + for (j = 0; j < list_len_8x8 / 4; j++) + *dst++ = swab32(src[j]); } } @@ -271,6 +244,7 @@ struct hantro_h264_reflist_builder { const struct v4l2_h264_dpb_entry *dpb; s32 pocs[HANTRO_H264_DPB_SIZE]; u8 unordered_reflist[HANTRO_H264_DPB_SIZE]; + int frame_nums[HANTRO_H264_DPB_SIZE]; s32 curpoc; u8 num_valid; }; @@ -294,13 +268,20 @@ static void init_reflist_builder(struct hantro_ctx *ctx, struct hantro_h264_reflist_builder *b) { + const struct v4l2_ctrl_h264_slice_params *slice_params; const struct v4l2_ctrl_h264_decode_params *dec_param; + const struct v4l2_ctrl_h264_sps *sps; struct vb2_v4l2_buffer *buf = hantro_get_dst_buf(ctx); const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + int cur_frame_num, max_frame_num; unsigned int i; dec_param = ctx->h264_dec.ctrls.decode; + slice_params = &ctx->h264_dec.ctrls.slices[0]; + sps = ctx->h264_dec.ctrls.sps; + max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); + cur_frame_num = slice_params->frame_num; memset(b, 0, sizeof(*b)); b->dpb = dpb; @@ -318,6 +299,18 @@ init_reflist_builder(struct hantro_ctx *ctx, continue; buf = to_vb2_v4l2_buffer(vb2_get_buffer(cap_q, buf_idx)); + + /* + * Handle frame_num wraparound as described in section + * '8.2.4.1 Decoding process for picture numbers' of the spec. + * TODO: This logic will have to be adjusted when we start + * supporting interlaced content. + */ + if (dpb[i].frame_num > cur_frame_num) + b->frame_nums[i] = (int)dpb[i].frame_num - max_frame_num; + else + b->frame_nums[i] = dpb[i].frame_num; + b->pocs[i] = get_poc(buf->field, dpb[i].top_field_order_cnt, dpb[i].bottom_field_order_cnt); b->unordered_reflist[b->num_valid] = i; @@ -353,9 +346,10 @@ static int p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) * ascending order. */ if (!(a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) - return b->frame_num - a->frame_num; + return HANTRO_CMP(builder->frame_nums[idxb], + builder->frame_nums[idxa]); - return a->pic_num - b->pic_num; + return HANTRO_CMP(a->pic_num, b->pic_num); } static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) @@ -381,7 +375,7 @@ static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) /* Long term pics in ascending pic num order. */ if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - return a->pic_num - b->pic_num; + return HANTRO_CMP(a->pic_num, b->pic_num); poca = builder->pocs[idxa]; pocb = builder->pocs[idxb]; @@ -392,11 +386,11 @@ static int b0_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) * order. */ if ((poca < builder->curpoc) != (pocb < builder->curpoc)) - return POC_CMP(poca, pocb); + return HANTRO_CMP(poca, pocb); else if (poca < builder->curpoc) - return POC_CMP(pocb, poca); + return HANTRO_CMP(pocb, poca); - return POC_CMP(poca, pocb); + return HANTRO_CMP(poca, pocb); } static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) @@ -422,22 +416,22 @@ static int b1_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) /* Long term pics in ascending pic num order. */ if (a->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - return a->pic_num - b->pic_num; + return HANTRO_CMP(a->pic_num, b->pic_num); poca = builder->pocs[idxa]; pocb = builder->pocs[idxb]; /* * Short term pics with POC > cur POC first in POC ascending order - * followed by short term pics with POC > cur POC in POC descending + * followed by short term pics with POC < cur POC in POC descending * order. */ if ((poca < builder->curpoc) != (pocb < builder->curpoc)) - return POC_CMP(pocb, poca); + return HANTRO_CMP(pocb, poca); else if (poca < builder->curpoc) - return POC_CMP(pocb, poca); + return HANTRO_CMP(pocb, poca); - return POC_CMP(poca, pocb); + return HANTRO_CMP(poca, pocb); } static void @@ -537,22 +531,18 @@ static void update_dpb(struct hantro_ctx *ctx) } } -struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - unsigned int dpb_idx) +dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx) { - struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; - struct vb2_buffer *buf; - int buf_idx = -1; + dma_addr_t dma_addr = 0; if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - buf_idx = vb2_find_timestamp(cap_q, - dpb[dpb_idx].reference_ts, 0); + dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); - if (buf_idx >= 0) { - buf = vb2_get_buffer(cap_q, buf_idx); - } else { + if (!dma_addr) { struct vb2_v4l2_buffer *dst_buf; + struct vb2_buffer *buf; /* * If a DPB entry is unused or invalid, address of current @@ -560,9 +550,10 @@ struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, */ dst_buf = hantro_get_dst_buf(ctx); buf = &dst_buf->vb2_buf; + dma_addr = vb2_dma_contig_plane_dma_addr(buf, 0); } - return buf; + return dma_addr; } int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) @@ -627,7 +618,6 @@ int hantro_h264_dec_init(struct hantro_ctx *ctx) struct hantro_h264_dec_hw_ctx *h264_dec = &ctx->h264_dec; struct hantro_aux_buf *priv = &h264_dec->priv; struct hantro_h264_dec_priv_tbl *tbl; - struct v4l2_pix_format_mplane pix_mp; priv->cpu = dma_alloc_coherent(vpu->dev, sizeof(*tbl), &priv->dma, GFP_KERNEL); @@ -638,9 +628,5 @@ int hantro_h264_dec_init(struct hantro_ctx *ctx) tbl = priv->cpu; memcpy(tbl->cabac_table, h264_cabac_table, sizeof(tbl->cabac_table)); - v4l2_fill_pixfmt_mp(&pix_mp, ctx->dst_fmt.pixelformat, - ctx->dst_fmt.width, ctx->dst_fmt.height); - h264_dec->pic_size = pix_mp.plane_fmt[0].sizeimage; - return 0; } diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 2fab655bf098..fa91dd1848b7 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -80,15 +80,12 @@ struct hantro_h264_dec_reflists { * @dpb: DPB * @reflists: P/B0/B1 reflists * @ctrls: V4L2 controls attached to a run - * @pic_size: Size in bytes of decoded picture, this is needed - * to pass the location of motion vectors. */ struct hantro_h264_dec_hw_ctx { struct hantro_aux_buf priv; struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; struct hantro_h264_dec_reflists reflists; struct hantro_h264_dec_ctrls ctrls; - size_t pic_size; }; /** @@ -158,8 +155,8 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx); int hantro_jpeg_enc_init(struct hantro_ctx *ctx); void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); -struct vb2_buffer *hantro_h264_get_ref_buf(struct hantro_ctx *ctx, - unsigned int dpb_idx); +dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, + unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); void hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 3dae52abb96c..1dae76f20034 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -240,14 +240,30 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f, v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, pix_mp->height); /* + * A decoded 8-bit 4:2:0 NV12 frame may need memory for up to + * 448 bytes per macroblock with additional 32 bytes on + * multi-core variants. + * * The H264 decoder needs extra space on the output buffers * to store motion vectors. This is needed for reference * frames. + * + * Memory layout is as follow: + * + * +---------------------------+ + * | Y-plane 256 bytes x MBs | + * +---------------------------+ + * | UV-plane 128 bytes x MBs | + * +---------------------------+ + * | MV buffer 64 bytes x MBs | + * +---------------------------+ + * | MC sync 32 bytes | + * +---------------------------+ */ if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE) pix_mp->plane_fmt[0].sizeimage += - 128 * DIV_ROUND_UP(pix_mp->width, 16) * - DIV_ROUND_UP(pix_mp->height, 16); + 64 * MB_WIDTH(pix_mp->width) * + MB_WIDTH(pix_mp->height) + 32; } else if (!pix_mp->plane_fmt[0].sizeimage) { /* * For coded formats the application can specify @@ -367,20 +383,27 @@ vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; struct hantro_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); const struct hantro_fmt *formats; unsigned int num_fmts; - struct vb2_queue *vq; int ret; - /* Change not allowed if queue is busy. */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (vb2_is_busy(vq)) - return -EBUSY; + ret = vidioc_try_fmt_out_mplane(file, priv, f); + if (ret) + return ret; if (!hantro_is_encoder_ctx(ctx)) { struct vb2_queue *peer_vq; /* + * In order to support dynamic resolution change, + * the decoder admits a resolution change, as long + * as the pixelformat remains. Can't be done if streaming. + */ + if (vb2_is_streaming(vq) || (vb2_is_busy(vq) && + pix_mp->pixelformat != ctx->src_fmt.pixelformat)) + return -EBUSY; + /* * Since format change on the OUTPUT queue will reset * the CAPTURE queue, we can't allow doing so * when the CAPTURE queue has buffers allocated. @@ -389,12 +412,15 @@ vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); if (vb2_is_busy(peer_vq)) return -EBUSY; + } else { + /* + * The encoder doesn't admit a format change if + * there are OUTPUT buffers allocated. + */ + if (vb2_is_busy(vq)) + return -EBUSY; } - ret = vidioc_try_fmt_out_mplane(file, priv, f); - if (ret) - return ret; - formats = hantro_get_formats(ctx, &num_fmts); ctx->vpu_src_fmt = hantro_find_format(formats, num_fmts, pix_mp->pixelformat); diff --git a/drivers/staging/media/hantro/rk3288_vpu_hw.c b/drivers/staging/media/hantro/rk3288_vpu_hw.c index 6bfcc47d1e58..f8db6fcaad73 100644 --- a/drivers/staging/media/hantro/rk3288_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3288_vpu_hw.c @@ -48,10 +48,10 @@ static const struct hantro_fmt rk3288_vpu_enc_fmts[] = { .frmsize = { .min_width = 96, .max_width = 8192, - .step_width = JPEG_MB_DIM, + .step_width = MB_DIM, .min_height = 32, .max_height = 8192, - .step_height = JPEG_MB_DIM, + .step_height = MB_DIM, }, }, }; @@ -67,11 +67,11 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .max_depth = 2, .frmsize = { .min_width = 48, - .max_width = 3840, - .step_width = H264_MB_DIM, + .max_width = 4096, + .step_width = MB_DIM, .min_height = 48, - .max_height = 2160, - .step_height = H264_MB_DIM, + .max_height = 2304, + .step_height = MB_DIM, }, }, { @@ -81,10 +81,10 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 1920, - .step_width = MPEG2_MB_DIM, + .step_width = MB_DIM, .min_height = 48, .max_height = 1088, - .step_height = MPEG2_MB_DIM, + .step_height = MB_DIM, }, }, { @@ -94,10 +94,10 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 3840, - .step_width = VP8_MB_DIM, + .step_width = MB_DIM, .min_height = 48, .max_height = 2160, - .step_height = VP8_MB_DIM, + .step_height = MB_DIM, }, }, }; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw.c b/drivers/staging/media/hantro/rk3399_vpu_hw.c index 14d14bc6b12b..9ac1f2cb6a16 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw.c @@ -47,10 +47,10 @@ static const struct hantro_fmt rk3399_vpu_enc_fmts[] = { .frmsize = { .min_width = 96, .max_width = 8192, - .step_width = JPEG_MB_DIM, + .step_width = MB_DIM, .min_height = 32, .max_height = 8192, - .step_height = JPEG_MB_DIM, + .step_height = MB_DIM, }, }, }; @@ -67,10 +67,10 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 1920, - .step_width = MPEG2_MB_DIM, + .step_width = MB_DIM, .min_height = 48, .max_height = 1088, - .step_height = MPEG2_MB_DIM, + .step_height = MB_DIM, }, }, { @@ -80,10 +80,10 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 3840, - .step_width = VP8_MB_DIM, + .step_width = MB_DIM, .min_height = 48, .max_height = 2160, - .step_height = VP8_MB_DIM, + .step_height = MB_DIM, }, }, }; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c index 06162f569b5e..067892345b5d 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_jpeg_enc.c @@ -149,8 +149,8 @@ void rk3399_vpu_jpeg_enc_run(struct hantro_ctx *ctx) reg = VEPU_REG_AXI_CTRL_BURST_LEN(16); vepu_write_relaxed(vpu, reg, VEPU_REG_AXI_CTRL); - reg = VEPU_REG_MB_WIDTH(JPEG_MB_WIDTH(ctx->src_fmt.width)) - | VEPU_REG_MB_HEIGHT(JPEG_MB_HEIGHT(ctx->src_fmt.height)) + reg = VEPU_REG_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)) + | VEPU_REG_MB_HEIGHT(MB_HEIGHT(ctx->src_fmt.height)) | VEPU_REG_FRAME_TYPE_INTRA | VEPU_REG_ENCODE_FORMAT_JPEG | VEPU_REG_ENCODE_ENABLE; diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c index e7ba5c0441cc..b40d2cdf832f 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_mpeg2_dec.c @@ -107,17 +107,14 @@ rk3399_vpu_mpeg2_dec_set_buffers(struct hantro_dev *vpu, { dma_addr_t forward_addr = 0, backward_addr = 0; dma_addr_t current_addr, addr; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx); switch (picture->picture_coding_type) { case V4L2_MPEG2_PICTURE_CODING_TYPE_B: - backward_addr = hantro_get_ref(vq, + backward_addr = hantro_get_ref(ctx, slice_params->backward_ref_ts); /* fall-through */ case V4L2_MPEG2_PICTURE_CODING_TYPE_P: - forward_addr = hantro_get_ref(vq, + forward_addr = hantro_get_ref(ctx, slice_params->forward_ref_ts); } @@ -223,8 +220,8 @@ void rk3399_vpu_mpeg2_dec_run(struct hantro_ctx *ctx) VDPU_REG_DEC_CLK_GATE_E(1); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); - reg = VDPU_REG_PIC_MB_WIDTH(MPEG2_MB_WIDTH(ctx->dst_fmt.width)) | - VDPU_REG_PIC_MB_HEIGHT_P(MPEG2_MB_HEIGHT(ctx->dst_fmt.height)) | + reg = VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->dst_fmt.width)) | + VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->dst_fmt.height)) | VDPU_REG_ALT_SCAN_E(picture->alternate_scan) | VDPU_REG_TOPFIELDFIRST_E(picture->top_field_first); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(120)); diff --git a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c index f17e32620b08..76d7ed3fd69a 100644 --- a/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rk3399_vpu_hw_vp8_dec.c @@ -449,18 +449,16 @@ static void cfg_ref(struct hantro_ctx *ctx, { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *vb2_dst; - struct vb2_queue *cap_q; dma_addr_t ref; - cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); vb2_dst = hantro_get_dst_buf(ctx); - ref = hantro_get_ref(cap_q, hdr->last_frame_ts); + ref = hantro_get_ref(ctx, hdr->last_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0); - ref = hantro_get_ref(cap_q, hdr->golden_frame_ts); + ref = hantro_get_ref(ctx, hdr->golden_frame_ts); WARN_ON(!ref && hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); @@ -468,7 +466,7 @@ static void cfg_ref(struct hantro_ctx *ctx, ref |= VDPU_REG_VP8_GREF_SIGN_BIAS; vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2)); - ref = hantro_get_ref(cap_q, hdr->alt_frame_ts); + ref = hantro_get_ref(ctx, hdr->alt_frame_ts); WARN_ON(!ref && hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); @@ -563,8 +561,8 @@ void rk3399_vpu_vp8_dec_run(struct hantro_ctx *ctx) hantro_reg_write(vpu, &vp8_dec_filter_disable, 1); /* Frame dimensions */ - mb_width = VP8_MB_WIDTH(width); - mb_height = VP8_MB_HEIGHT(height); + mb_width = MB_WIDTH(width); + mb_height = MB_HEIGHT(height); hantro_reg_write(vpu, &vp8_dec_mb_width, mb_width); hantro_reg_write(vpu, &vp8_dec_mb_height, mb_height); diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index 35e60a120dc1..2a4f77e83ed3 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -428,32 +428,19 @@ static int prp_s_frame_interval(struct v4l2_subdev *sd, return 0; } -/* - * retrieve our pads parsed from the OF graph by the media device - */ static int prp_registered(struct v4l2_subdev *sd) { struct prp_priv *priv = sd_to_priv(sd); - int i, ret; u32 code; - for (i = 0; i < PRP_NUM_PADS; i++) { - priv->pad[i].flags = (i == PRP_SINK_PAD) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - } - /* init default frame interval */ priv->frame_interval.numerator = 1; priv->frame_interval.denominator = 30; /* set a default mbus format */ imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); - ret = imx_media_init_mbus_fmt(&priv->format_mbus, 640, 480, code, - V4L2_FIELD_NONE, NULL); - if (ret) - return ret; - - return media_entity_pads_init(&sd->entity, PRP_NUM_PADS, priv->pad); + return imx_media_init_mbus_fmt(&priv->format_mbus, 640, 480, code, + V4L2_FIELD_NONE, NULL); } static const struct v4l2_subdev_pad_ops prp_pad_ops = { @@ -487,6 +474,7 @@ static const struct v4l2_subdev_internal_ops prp_internal_ops = { static int prp_init(struct imx_ic_priv *ic_priv) { struct prp_priv *priv; + int i; priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -496,7 +484,12 @@ static int prp_init(struct imx_ic_priv *ic_priv) ic_priv->task_priv = priv; priv->ic_priv = ic_priv; - return 0; + for (i = 0; i < PRP_NUM_PADS; i++) + priv->pad[i].flags = (i == PRP_SINK_PAD) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + return media_entity_pads_init(&ic_priv->sd.entity, PRP_NUM_PADS, + priv->pad); } static void prp_remove(struct imx_ic_priv *ic_priv) diff --git a/drivers/staging/media/imx/imx-ic-prpencvf.c b/drivers/staging/media/imx/imx-ic-prpencvf.c index 67ffa46a8e96..09c4e3f33807 100644 --- a/drivers/staging/media/imx/imx-ic-prpencvf.c +++ b/drivers/staging/media/imx/imx-ic-prpencvf.c @@ -1240,21 +1240,16 @@ static int prp_s_frame_interval(struct v4l2_subdev *sd, return 0; } -/* - * retrieve our pads parsed from the OF graph by the media device - */ static int prp_registered(struct v4l2_subdev *sd) { struct prp_priv *priv = sd_to_priv(sd); + struct imx_ic_priv *ic_priv = priv->ic_priv; int i, ret; u32 code; + /* set a default mbus format */ + imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); for (i = 0; i < PRPENCVF_NUM_PADS; i++) { - priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - - /* set a default mbus format */ - imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); ret = imx_media_init_mbus_fmt(&priv->format_mbus[i], 640, 480, code, V4L2_FIELD_NONE, &priv->cc[i]); @@ -1266,22 +1261,26 @@ static int prp_registered(struct v4l2_subdev *sd) priv->frame_interval.numerator = 1; priv->frame_interval.denominator = 30; - ret = media_entity_pads_init(&sd->entity, PRPENCVF_NUM_PADS, - priv->pad); - if (ret) - return ret; + priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev, + &ic_priv->sd, + PRPENCVF_SRC_PAD); + if (IS_ERR(priv->vdev)) + return PTR_ERR(priv->vdev); ret = imx_media_capture_device_register(priv->vdev); if (ret) - return ret; + goto remove_vdev; ret = prp_init_controls(priv); if (ret) - goto unreg; + goto unreg_vdev; return 0; -unreg: + +unreg_vdev: imx_media_capture_device_unregister(priv->vdev); +remove_vdev: + imx_media_capture_device_remove(priv->vdev); return ret; } @@ -1290,6 +1289,8 @@ static void prp_unregistered(struct v4l2_subdev *sd) struct prp_priv *priv = sd_to_priv(sd); imx_media_capture_device_unregister(priv->vdev); + imx_media_capture_device_remove(priv->vdev); + v4l2_ctrl_handler_free(&priv->ctrl_hdlr); } @@ -1325,6 +1326,7 @@ static const struct v4l2_subdev_internal_ops prp_internal_ops = { static int prp_init(struct imx_ic_priv *ic_priv) { struct prp_priv *priv; + int i, ret; priv = devm_kzalloc(ic_priv->ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1336,15 +1338,19 @@ static int prp_init(struct imx_ic_priv *ic_priv) spin_lock_init(&priv->irqlock); timer_setup(&priv->eof_timeout_timer, prp_eof_timeout, 0); - priv->vdev = imx_media_capture_device_init(ic_priv->ipu_dev, - &ic_priv->sd, - PRPENCVF_SRC_PAD); - if (IS_ERR(priv->vdev)) - return PTR_ERR(priv->vdev); - mutex_init(&priv->lock); - return 0; + for (i = 0; i < PRPENCVF_NUM_PADS; i++) { + priv->pad[i].flags = (i == PRPENCVF_SINK_PAD) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + } + + ret = media_entity_pads_init(&ic_priv->sd.entity, PRPENCVF_NUM_PADS, + priv->pad); + if (ret) + mutex_destroy(&priv->lock); + + return ret; } static void prp_remove(struct imx_ic_priv *ic_priv) @@ -1352,7 +1358,6 @@ static void prp_remove(struct imx_ic_priv *ic_priv) struct prp_priv *priv = ic_priv->task_priv; mutex_destroy(&priv->lock); - imx_media_capture_device_remove(priv->vdev); } struct imx_ic_ops imx_ic_prpencvf_ops = { diff --git a/drivers/staging/media/imx/imx-media-capture.c b/drivers/staging/media/imx/imx-media-capture.c index b33a07bc9105..7712e7be8625 100644 --- a/drivers/staging/media/imx/imx-media-capture.c +++ b/drivers/staging/media/imx/imx-media-capture.c @@ -26,6 +26,8 @@ #include <media/imx.h> #include "imx-media.h" +#define IMX_CAPTURE_NAME "imx-capture" + struct capture_priv { struct imx_media_video_dev vdev; @@ -69,8 +71,8 @@ static int vidioc_querycap(struct file *file, void *fh, { struct capture_priv *priv = video_drvdata(file); - strscpy(cap->driver, "imx-media-capture", sizeof(cap->driver)); - strscpy(cap->card, "imx-media-capture", sizeof(cap->card)); + strscpy(cap->driver, IMX_CAPTURE_NAME, sizeof(cap->driver)); + strscpy(cap->card, IMX_CAPTURE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", priv->src_sd->name); @@ -765,13 +767,6 @@ int imx_media_capture_device_register(struct imx_media_video_dev *vdev) INIT_LIST_HEAD(&priv->ready_q); - priv->vdev_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &priv->vdev_pad); - if (ret) { - v4l2_err(sd, "failed to init dev pad\n"); - goto unreg; - } - /* create the link from the src_sd devnode pad to device node */ ret = media_create_pad_link(&sd->entity, priv->src_sd_pad, &vfd->entity, 0, 0); @@ -834,6 +829,7 @@ imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd, { struct capture_priv *priv; struct video_device *vfd; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -858,6 +854,13 @@ imx_media_capture_device_init(struct device *dev, struct v4l2_subdev *src_sd, vfd->queue = &priv->q; priv->vdev.vfd = vfd; + priv->vdev_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &priv->vdev_pad); + if (ret) { + video_device_release(vfd); + return ERR_PTR(ret); + } + INIT_LIST_HEAD(&priv->vdev.list); video_set_drvdata(vfd, priv); diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index 367e39f5b382..b60ed4f22f6d 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -627,8 +627,8 @@ static int csi_idmac_start(struct csi_priv *priv) } priv->nfb4eof_irq = ipu_idmac_channel_irq(priv->ipu, - priv->idmac_ch, - IPU_IRQ_NFB4EOF); + priv->idmac_ch, + IPU_IRQ_NFB4EOF); ret = devm_request_irq(priv->dev, priv->nfb4eof_irq, csi_idmac_nfb4eof_interrupt, 0, "imx-smfc-nfb4eof", priv); @@ -1472,7 +1472,7 @@ static void csi_try_fmt(struct csi_priv *priv, imx_media_enum_mbus_format(&code, 0, CS_SEL_ANY, false); *cc = imx_media_find_mbus_format(code, - CS_SEL_ANY, false); + CS_SEL_ANY, false); sdformat->format.code = (*cc)->codes[0]; } @@ -1740,9 +1740,6 @@ static int csi_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, return v4l2_event_unsubscribe(fh, sub); } -/* - * retrieve our pads parsed from the OF graph by the media device - */ static int csi_registered(struct v4l2_subdev *sd) { struct csi_priv *priv = v4l2_get_subdevdata(sd); @@ -1759,9 +1756,6 @@ static int csi_registered(struct v4l2_subdev *sd) priv->csi = csi; for (i = 0; i < CSI_NUM_PADS; i++) { - priv->pad[i].flags = (i == CSI_SINK_PAD) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - code = 0; if (i != CSI_SINK_PAD) imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); @@ -1793,16 +1787,22 @@ static int csi_registered(struct v4l2_subdev *sd) goto put_csi; } - ret = media_entity_pads_init(&sd->entity, CSI_NUM_PADS, priv->pad); - if (ret) + priv->vdev = imx_media_capture_device_init(priv->sd.dev, + &priv->sd, + CSI_SRC_PAD_IDMAC); + if (IS_ERR(priv->vdev)) { + ret = PTR_ERR(priv->vdev); goto free_fim; + } ret = imx_media_capture_device_register(priv->vdev); if (ret) - goto free_fim; + goto remove_vdev; return 0; +remove_vdev: + imx_media_capture_device_remove(priv->vdev); free_fim: if (priv->fim) imx_media_fim_free(priv->fim); @@ -1816,6 +1816,7 @@ static void csi_unregistered(struct v4l2_subdev *sd) struct csi_priv *priv = v4l2_get_subdevdata(sd); imx_media_capture_device_unregister(priv->vdev); + imx_media_capture_device_remove(priv->vdev); if (priv->fim) imx_media_fim_free(priv->fim); @@ -1923,7 +1924,7 @@ static int imx_csi_probe(struct platform_device *pdev) struct ipu_client_platformdata *pdata; struct pinctrl *pinctrl; struct csi_priv *priv; - int ret; + int i, ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1963,10 +1964,14 @@ static int imx_csi_probe(struct platform_device *pdev) imx_media_grp_id_to_sd_name(priv->sd.name, sizeof(priv->sd.name), priv->sd.grp_id, ipu_get_num(priv->ipu)); - priv->vdev = imx_media_capture_device_init(priv->sd.dev, &priv->sd, - CSI_SRC_PAD_IDMAC); - if (IS_ERR(priv->vdev)) - return PTR_ERR(priv->vdev); + for (i = 0; i < CSI_NUM_PADS; i++) + priv->pad[i].flags = (i == CSI_SINK_PAD) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&priv->sd.entity, CSI_NUM_PADS, + priv->pad); + if (ret) + return ret; mutex_init(&priv->lock); @@ -1997,7 +2002,6 @@ static int imx_csi_probe(struct platform_device *pdev) free: v4l2_ctrl_handler_free(&priv->ctrl_hdlr); mutex_destroy(&priv->lock); - imx_media_capture_device_remove(priv->vdev); return ret; } @@ -2008,7 +2012,6 @@ static int imx_csi_remove(struct platform_device *pdev) v4l2_ctrl_handler_free(&priv->ctrl_hdlr); mutex_destroy(&priv->lock); - imx_media_capture_device_remove(priv->vdev); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); diff --git a/drivers/staging/media/imx/imx-media-utils.c b/drivers/staging/media/imx/imx-media-utils.c index 4cc6a7462ae2..0788a1874557 100644 --- a/drivers/staging/media/imx/imx-media-utils.c +++ b/drivers/staging/media/imx/imx-media-utils.c @@ -184,7 +184,15 @@ static const struct imx_media_pixfmt rgb_formats[] = { .cs = IPUV3_COLORSPACE_RGB, .bpp = 24, }, { - .fourcc = V4L2_PIX_FMT_BGR32, + .fourcc = V4L2_PIX_FMT_XBGR32, + .cs = IPUV3_COLORSPACE_RGB, + .bpp = 32, + }, { + .fourcc = V4L2_PIX_FMT_BGRX32, + .cs = IPUV3_COLORSPACE_RGB, + .bpp = 32, + }, { + .fourcc = V4L2_PIX_FMT_RGBX32, .cs = IPUV3_COLORSPACE_RGB, .bpp = 32, }, diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index cfad65a16917..0d83c2c41606 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -841,9 +841,6 @@ out: return ret; } -/* - * retrieve our pads parsed from the OF graph by the media device - */ static int vdic_registered(struct v4l2_subdev *sd) { struct vdic_priv *priv = v4l2_get_subdevdata(sd); @@ -851,9 +848,6 @@ static int vdic_registered(struct v4l2_subdev *sd) u32 code; for (i = 0; i < VDIC_NUM_PADS; i++) { - priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ? - MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; - code = 0; if (i != VDIC_SINK_PAD_IDMAC) imx_media_enum_ipu_format(&code, 0, CS_SEL_YUV); @@ -874,15 +868,7 @@ static int vdic_registered(struct v4l2_subdev *sd) priv->active_input_pad = VDIC_SINK_PAD_DIRECT; - ret = vdic_init_controls(priv); - if (ret) - return ret; - - ret = media_entity_pads_init(&sd->entity, VDIC_NUM_PADS, priv->pad); - if (ret) - v4l2_ctrl_handler_free(&priv->ctrl_hdlr); - - return ret; + return vdic_init_controls(priv); } static void vdic_unregistered(struct v4l2_subdev *sd) @@ -927,7 +913,7 @@ struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev, u32 grp_id) { struct vdic_priv *priv; - int ret; + int i, ret; priv = devm_kzalloc(ipu_dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -949,6 +935,15 @@ struct v4l2_subdev *imx_media_vdic_register(struct v4l2_device *v4l2_dev, mutex_init(&priv->lock); + for (i = 0; i < VDIC_NUM_PADS; i++) + priv->pad[i].flags = (i == VDIC_SRC_PAD_DIRECT) ? + MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; + + ret = media_entity_pads_init(&priv->sd.entity, VDIC_NUM_PADS, + priv->pad); + if (ret) + goto free; + ret = v4l2_device_register_subdev(v4l2_dev, &priv->sd); if (ret) goto free; diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index bfa4b254c4e4..cd3dd6e33ef0 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -497,26 +497,13 @@ out: return ret; } -/* - * retrieve our pads parsed from the OF graph by the media device - */ static int csi2_registered(struct v4l2_subdev *sd) { struct csi2_dev *csi2 = sd_to_dev(sd); - int i, ret; - - for (i = 0; i < CSI2_NUM_PADS; i++) { - csi2->pad[i].flags = (i == CSI2_SINK_PAD) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - } /* set a default mbus format */ - ret = imx_media_init_mbus_fmt(&csi2->format_mbus, + return imx_media_init_mbus_fmt(&csi2->format_mbus, 640, 480, 0, V4L2_FIELD_NONE, NULL); - if (ret) - return ret; - - return media_entity_pads_init(&sd->entity, CSI2_NUM_PADS, csi2->pad); } static const struct media_entity_operations csi2_entity_ops = { @@ -573,7 +560,7 @@ static int csi2_probe(struct platform_device *pdev) unsigned int sink_port = 0; struct csi2_dev *csi2; struct resource *res; - int ret; + int i, ret; csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL); if (!csi2) @@ -592,6 +579,16 @@ static int csi2_probe(struct platform_device *pdev) csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; csi2->sd.grp_id = IMX_MEDIA_GRP_ID_CSI2; + for (i = 0; i < CSI2_NUM_PADS; i++) { + csi2->pad[i].flags = (i == CSI2_SINK_PAD) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + } + + ret = media_entity_pads_init(&csi2->sd.entity, CSI2_NUM_PADS, + csi2->pad); + if (ret) + return ret; + csi2->pllref_clk = devm_clk_get(&pdev->dev, "ref"); if (IS_ERR(csi2->pllref_clk)) { v4l2_err(&csi2->sd, "failed to get pll reference clock\n"); diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index bfd6b5fbf484..db30e2c70f2f 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1100,9 +1100,6 @@ static int imx7_csi_registered(struct v4l2_subdev *sd) int i; for (i = 0; i < IMX7_CSI_PADS_NUM; i++) { - csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? - MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; - /* set a default mbus format */ ret = imx_media_init_mbus_fmt(&csi->format_mbus[i], 800, 600, 0, V4L2_FIELD_NONE, @@ -1115,11 +1112,16 @@ static int imx7_csi_registered(struct v4l2_subdev *sd) csi->frame_interval[i].denominator = 30; } - ret = media_entity_pads_init(&sd->entity, IMX7_CSI_PADS_NUM, csi->pad); - if (ret < 0) - return ret; + csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd, + IMX7_CSI_PAD_SRC); + if (IS_ERR(csi->vdev)) + return PTR_ERR(csi->vdev); + + ret = imx_media_capture_device_register(csi->vdev); + if (ret) + imx_media_capture_device_remove(csi->vdev); - return imx_media_capture_device_register(csi->vdev); + return ret; } static void imx7_csi_unregistered(struct v4l2_subdev *sd) @@ -1127,6 +1129,7 @@ static void imx7_csi_unregistered(struct v4l2_subdev *sd) struct imx7_csi *csi = v4l2_get_subdevdata(sd); imx_media_capture_device_unregister(csi->vdev); + imx_media_capture_device_remove(csi->vdev); } static int imx7_csi_init_cfg(struct v4l2_subdev *sd, @@ -1189,7 +1192,7 @@ static int imx7_csi_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct imx_media_dev *imxmd; struct imx7_csi *csi; - int ret; + int i, ret; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); if (!csi) @@ -1251,14 +1254,18 @@ static int imx7_csi_probe(struct platform_device *pdev) csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI; snprintf(csi->sd.name, sizeof(csi->sd.name), "csi"); - csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd, - IMX7_CSI_PAD_SRC); - if (IS_ERR(csi->vdev)) - return PTR_ERR(csi->vdev); - v4l2_ctrl_handler_init(&csi->ctrl_hdlr, 0); csi->sd.ctrl_handler = &csi->ctrl_hdlr; + for (i = 0; i < IMX7_CSI_PADS_NUM; i++) + csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM, + csi->pad); + if (ret < 0) + goto free; + ret = v4l2_async_register_fwnode_subdev(&csi->sd, sizeof(struct v4l2_async_subdev), NULL, 0, @@ -1269,8 +1276,6 @@ static int imx7_csi_probe(struct platform_device *pdev) return 0; free: - imx_media_capture_device_unregister(csi->vdev); - imx_media_capture_device_remove(csi->vdev); v4l2_ctrl_handler_free(&csi->ctrl_hdlr); cleanup: @@ -1298,9 +1303,6 @@ static int imx7_csi_remove(struct platform_device *pdev) v4l2_device_unregister(&imxmd->v4l2_dev); media_device_cleanup(&imxmd->md); - imx_media_capture_device_unregister(csi->vdev); - imx_media_capture_device_remove(csi->vdev); - v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&csi->ctrl_hdlr); diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 73d8354e618c..99166afca071 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -293,7 +293,7 @@ static int mipi_csis_dump_regs(struct csi_state *state) struct device *dev = &state->pdev->dev; unsigned int i; u32 cfg; - struct { + static const struct { u32 offset; const char * const name; } registers[] = { @@ -350,6 +350,8 @@ static void mipi_csis_sw_reset(struct csi_state *state) static int mipi_csis_phy_init(struct csi_state *state) { state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); + if (IS_ERR(state->mipi_phy_regulator)) + return PTR_ERR(state->mipi_phy_regulator); return regulator_set_voltage(state->mipi_phy_regulator, 1000000, 1000000); @@ -780,17 +782,6 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } -static int mipi_csis_registered(struct v4l2_subdev *mipi_sd) -{ - struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); - - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - - return media_entity_pads_init(&state->mipi_sd.entity, CSIS_PADS_NUM, - state->pads); -} - static const struct v4l2_subdev_core_ops mipi_csis_core_ops = { .log_status = mipi_csis_log_status, }; @@ -816,10 +807,6 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { .pad = &mipi_csis_pad_ops, }; -static const struct v4l2_subdev_internal_ops mipi_csis_internal_ops = { - .registered = mipi_csis_registered, -}; - static int mipi_csis_parse_dt(struct platform_device *pdev, struct csi_state *state) { @@ -880,7 +867,6 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; mipi_sd->entity.ops = &mipi_csis_entity_ops; - mipi_sd->internal_ops = &mipi_csis_internal_ops; mipi_sd->dev = &pdev->dev; @@ -892,6 +878,13 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, v4l2_set_subdevdata(mipi_sd, &pdev->dev); + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM, + state->pads); + if (ret) + return ret; + ret = v4l2_async_register_fwnode_subdev(mipi_sd, sizeof(struct v4l2_async_subdev), &sink_port, 1, @@ -947,7 +940,6 @@ static void mipi_csis_debugfs_exit(struct csi_state *state) static int mipi_csis_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct resource *mem_res; struct csi_state *state; int ret; @@ -966,11 +958,13 @@ static int mipi_csis_probe(struct platform_device *pdev) return ret; } - mipi_csis_phy_init(state); + ret = mipi_csis_phy_init(state); + if (ret < 0) + return ret; + mipi_csis_phy_reset(state); - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(dev, mem_res); + state->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(state->regs)) return PTR_ERR(state->regs); diff --git a/drivers/staging/media/ipu3/Makefile b/drivers/staging/media/ipu3/Makefile index cc288ae6d5f2..9def80ef28f3 100644 --- a/drivers/staging/media/ipu3/Makefile +++ b/drivers/staging/media/ipu3/Makefile @@ -10,9 +10,3 @@ ipu3-imgu-objs += \ ipu3-css.o ipu3-v4l2.o ipu3.o obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3-imgu.o - -# HACK! While this driver is in bad shape, don't enable several warnings -# that would be otherwise enabled with W=1 -ccflags-y += $(call cc-disable-warning, packed-not-aligned) -ccflags-y += $(call cc-disable-warning, type-limits) -ccflags-y += $(call cc-disable-warning, unused-const-variable) diff --git a/drivers/staging/media/ipu3/TODO b/drivers/staging/media/ipu3/TODO index 5e55baeaea1a..b44bb4a72ca7 100644 --- a/drivers/staging/media/ipu3/TODO +++ b/drivers/staging/media/ipu3/TODO @@ -9,12 +9,9 @@ staging directory. relevant. (Sakari) - IPU3 driver documentation (Laurent) - Add diagram in driver rst to describe output capability. Comments on configuring v4l2 subdevs for CIO2 and ImgU. - uAPI documentation: - Further clarification on some ambiguities such as data type conversion of - IEFD CU inputs. (Sakari) Move acronyms to doc-rst file. (Mauro) - Switch to yavta from v4l2n in driver docs. @@ -27,5 +24,3 @@ staging directory. - Document different operation modes, and which buffer queues are relevant in each mode. To process an image, which queues require a buffer an in which ones is it optional? - -- Make sure it builds fine with no warnings with W=1 diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h index c7cd27efac8a..08eaa0bad0de 100644 --- a/drivers/staging/media/ipu3/include/intel-ipu3.h +++ b/drivers/staging/media/ipu3/include/intel-ipu3.h @@ -1217,6 +1217,11 @@ struct ipu3_uapi_shd_config { * * All CU inputs are unsigned, they will be converted to signed when written * to register, i.e. a01 will be written to 9 bit register in s4.4 format. + * The data precision s4.4 means 4 bits for integer parts and 4 bits for the + * fractional part, the first bit indicates positive or negative value. + * For userspace software (commonly the imaging library), the computation for + * the CU slope values should be based on the slope resolution 1/16 (binary + * 0.0001 - the minimal interval value), the slope value range is [-256, +255]. * This applies to &ipu3_uapi_iefd_cux6_ed, &ipu3_uapi_iefd_cux2_1, * &ipu3_uapi_iefd_cux2_1, &ipu3_uapi_iefd_cux4 and &ipu3_uapi_iefd_cux6_rad. */ diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index 1a966cb2f3a6..6fb60b58447a 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -908,11 +908,7 @@ static int iss_map_mem_resource(struct platform_device *pdev, struct iss_device *iss, enum iss_mem_resources res) { - struct resource *mem; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, res); - - iss->regs[res] = devm_ioremap_resource(iss->dev, mem); + iss->regs[res] = devm_platform_ioremap_resource(pdev, res); return PTR_ERR_OR_ZERO(iss->regs[res]); } diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 54144dc9f509..673aa3a5f2bd 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -671,7 +671,7 @@ iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel) return -EINVAL; } subdev = iss_video_remote_subdev(video, &pad); - if (subdev == NULL) + if (!subdev) return -EINVAL; /* @@ -726,7 +726,7 @@ iss_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) return -EINVAL; } subdev = iss_video_remote_subdev(video, &pad); - if (subdev == NULL) + if (!subdev) return -EINVAL; sdsel.pad = pad; diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile index c85ac6db0302..1bce49d3e7e2 100644 --- a/drivers/staging/media/sunxi/cedrus/Makefile +++ b/drivers/staging/media/sunxi/cedrus/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \ - cedrus_mpeg2.o cedrus_h264.o + cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 2d3ea8b74dfd..c6ddd46eff82 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -95,6 +95,45 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_H264, .required = false, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS, + }, + .codec = CEDRUS_CODEC_H265, + .required = true, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS, + }, + .codec = CEDRUS_CODEC_H265, + .required = true, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS, + }, + .codec = CEDRUS_CODEC_H265, + .required = true, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE, + .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, + .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, + }, + .codec = CEDRUS_CODEC_H265, + .required = false, + }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE, + .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, + .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, + }, + .codec = CEDRUS_CODEC_H265, + .required = false, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) @@ -241,6 +280,16 @@ static int cedrus_open(struct file *file) ret = PTR_ERR(ctx->fh.m2m_ctx); goto err_ctrls; } + ctx->dst_fmt.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; + cedrus_prepare_format(&ctx->dst_fmt); + ctx->src_fmt.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; + /* + * TILED_NV12 has more strict requirements, so copy the width and + * height to src_fmt to ensure that is matches the dst_fmt resolution. + */ + ctx->src_fmt.width = ctx->dst_fmt.width; + ctx->src_fmt.height = ctx->dst_fmt.height; + cedrus_prepare_format(&ctx->src_fmt); v4l2_fh_add(&ctx->fh); @@ -330,6 +379,7 @@ static int cedrus_probe(struct platform_device *pdev) dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; + dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265; mutex_init(&dev->dev_mutex); @@ -357,6 +407,8 @@ static int cedrus_probe(struct platform_device *pdev) dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:" CEDRUS_NAME, + sizeof(dev->mdev.bus_info)); media_device_init(&dev->mdev); dev->mdev.ops = &cedrus_m2m_media_ops; @@ -438,22 +490,26 @@ static const struct cedrus_variant sun8i_a33_cedrus_variant = { }; static const struct cedrus_variant sun8i_h3_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_a64_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h5_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h6_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H265_DEC, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .mod_rate = 600000000, }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 2f017a651848..96765555ab8a 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -27,12 +27,14 @@ #define CEDRUS_NAME "cedrus" #define CEDRUS_CAPABILITY_UNTILED BIT(0) +#define CEDRUS_CAPABILITY_H265_DEC BIT(1) #define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) enum cedrus_codec { CEDRUS_CODEC_MPEG2, CEDRUS_CODEC_H264, + CEDRUS_CODEC_H265, CEDRUS_CODEC_LAST, }; @@ -67,6 +69,12 @@ struct cedrus_mpeg2_run { const struct v4l2_ctrl_mpeg2_quantization *quantization; }; +struct cedrus_h265_run { + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; + const struct v4l2_ctrl_hevc_slice_params *slice_params; +}; + struct cedrus_run { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; @@ -74,6 +82,7 @@ struct cedrus_run { union { struct cedrus_h264_run h264; struct cedrus_mpeg2_run mpeg2; + struct cedrus_h265_run h265; }; }; @@ -107,9 +116,24 @@ struct cedrus_ctx { ssize_t mv_col_buf_size; void *pic_info_buf; dma_addr_t pic_info_buf_dma; + ssize_t pic_info_buf_size; void *neighbor_info_buf; dma_addr_t neighbor_info_buf_dma; + void *deblk_buf; + dma_addr_t deblk_buf_dma; + ssize_t deblk_buf_size; + void *intra_pred_buf; + dma_addr_t intra_pred_buf_dma; + ssize_t intra_pred_buf_size; } h264; + struct { + void *mv_col_buf; + dma_addr_t mv_col_buf_addr; + ssize_t mv_col_buf_size; + ssize_t mv_col_buf_unit_size; + void *neighbor_info_buf; + dma_addr_t neighbor_info_buf_addr; + } h265; } codec; }; @@ -155,6 +179,7 @@ struct cedrus_dev { extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; extern struct cedrus_dec_ops cedrus_dec_ops_h264; +extern struct cedrus_dec_ops cedrus_dec_ops_h265; static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val) { @@ -179,12 +204,16 @@ static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf, static inline dma_addr_t cedrus_dst_buf_addr(struct cedrus_ctx *ctx, int index, unsigned int plane) { - struct vb2_buffer *buf; + struct vb2_buffer *buf = NULL; + struct vb2_queue *vq; if (index < 0) return 0; - buf = ctx->fh.m2m_ctx->cap_q_ctx.q.bufs[index]; + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (vq) + buf = vb2_get_buffer(vq, index); + return buf ? cedrus_buf_addr(buf, &ctx->dst_fmt, plane) : 0; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 56ca4c9ad01c..4a2fc33a1d79 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -59,6 +59,15 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_H264_SPS); break; + case V4L2_PIX_FMT_HEVC_SLICE: + run.h265.sps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_SPS); + run.h265.pps = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_PPS); + run.h265.slice_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); + break; + default: break; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index d6a782703c9b..bfb4a4820a67 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -6,6 +6,7 @@ * Copyright (c) 2018 Bootlin */ +#include <linux/delay.h> #include <linux/types.h> #include <media/videobuf2-dma-contig.h> @@ -38,7 +39,7 @@ struct cedrus_h264_sram_ref_pic { #define CEDRUS_H264_FRAME_NUM 18 #define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) -#define CEDRUS_PIC_INFO_BUF_SIZE (128 * SZ_1K) +#define CEDRUS_MIN_PIC_INFO_BUF_SIZE (130 * SZ_1K) static void cedrus_h264_write_sram(struct cedrus_dev *dev, enum cedrus_h264_sram_off off, @@ -96,7 +97,7 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; const struct v4l2_ctrl_h264_slice_params *slice = run->h264.slice_params; const struct v4l2_ctrl_h264_sps *sps = run->h264.sps; - struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct vb2_queue *cap_q; struct cedrus_buffer *output_buf; struct cedrus_dev *dev = ctx->dev; unsigned long used_dpbs = 0; @@ -104,6 +105,8 @@ static void cedrus_write_frame_list(struct cedrus_ctx *ctx, unsigned int output = 0; unsigned int i; + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + memset(pic_list, 0, sizeof(pic_list)); for (i = 0; i < ARRAY_SIZE(decode->dpb); i++) { @@ -167,12 +170,14 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx, enum cedrus_h264_sram_off sram) { const struct v4l2_ctrl_h264_decode_params *decode = run->h264.decode_params; - struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct vb2_queue *cap_q; struct cedrus_dev *dev = ctx->dev; u8 sram_array[CEDRUS_MAX_REF_IDX]; unsigned int i; size_t size; + cap_q = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + memset(sram_array, 0, sizeof(sram_array)); for (i = 0; i < num_ref; i++) { @@ -240,8 +245,8 @@ static void cedrus_write_scaling_lists(struct cedrus_ctx *ctx, sizeof(scaling->scaling_list_8x8[0])); cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_8x8_1, - scaling->scaling_list_8x8[3], - sizeof(scaling->scaling_list_8x8[3])); + scaling->scaling_list_8x8[1], + sizeof(scaling->scaling_list_8x8[1])); cedrus_h264_write_sram(dev, CEDRUS_SRAM_H264_SCALING_LIST_4x4, scaling->scaling_list_4x4, @@ -289,6 +294,28 @@ static void cedrus_write_pred_weight_table(struct cedrus_ctx *ctx, } } +/* + * It turns out that using VE_H264_VLD_OFFSET to skip bits is not reliable. In + * rare cases frame is not decoded correctly. However, setting offset to 0 and + * skipping appropriate amount of bits with flush bits trigger always works. + */ +static void cedrus_skip_bits(struct cedrus_dev *dev, int num) +{ + int count = 0; + + while (count < num) { + int tmp = min(num - count, 32); + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_FLUSH_BITS | + VE_H264_TRIGGER_TYPE_N_BITS(tmp)); + while (cedrus_read(dev, VE_H264_STATUS) & VE_H264_STATUS_VLD_BUSY) + udelay(1); + + count += tmp; + } +} + static void cedrus_set_params(struct cedrus_ctx *ctx, struct cedrus_run *run) { @@ -299,12 +326,13 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, struct vb2_buffer *src_buf = &run->src->vb2_buf; struct cedrus_dev *dev = ctx->dev; dma_addr_t src_buf_addr; - u32 offset = slice->header_bit_size; - u32 len = (slice->size * 8) - offset; + u32 len = slice->size * 8; + unsigned int pic_width_in_mbs; + bool mbaff_pic; u32 reg; cedrus_write(dev, VE_H264_VLD_LEN, len); - cedrus_write(dev, VE_H264_VLD_OFFSET, offset); + cedrus_write(dev, VE_H264_VLD_OFFSET, 0); src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); cedrus_write(dev, VE_H264_VLD_END, @@ -314,6 +342,20 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | VE_H264_VLD_ADDR_LAST); + if (ctx->src_fmt.width > 2048) { + cedrus_write(dev, VE_BUF_CTRL, + VE_BUF_CTRL_INTRAPRED_MIXED_RAM | + VE_BUF_CTRL_DBLK_MIXED_RAM); + cedrus_write(dev, VE_DBLK_DRAM_BUF_ADDR, + ctx->codec.h264.deblk_buf_dma); + cedrus_write(dev, VE_INTRAPRED_DRAM_BUF_ADDR, + ctx->codec.h264.intra_pred_buf_dma); + } else { + cedrus_write(dev, VE_BUF_CTRL, + VE_BUF_CTRL_INTRAPRED_INT_SRAM | + VE_BUF_CTRL_DBLK_INT_SRAM); + } + /* * FIXME: Since the bitstream parsing is done in software, and * in userspace, this shouldn't be needed anymore. But it @@ -323,6 +365,8 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_INIT_SWDEC); + cedrus_skip_bits(dev, slice->header_bit_size); + if (((pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) && (slice->slice_type == V4L2_H264_SLICE_TYPE_P || slice->slice_type == V4L2_H264_SLICE_TYPE_SP)) || @@ -370,12 +414,20 @@ static void cedrus_set_params(struct cedrus_ctx *ctx, reg |= VE_H264_SPS_DIRECT_8X8_INFERENCE; cedrus_write(dev, VE_H264_SPS, reg); + mbaff_pic = !(slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + pic_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1; + // slice parameters reg = 0; + reg |= ((slice->first_mb_in_slice % pic_width_in_mbs) & 0xff) << 24; + reg |= (((slice->first_mb_in_slice / pic_width_in_mbs) * + (mbaff_pic + 1)) & 0xff) << 16; reg |= decode->nal_ref_idc ? BIT(12) : 0; reg |= (slice->slice_type & 0xf) << 8; reg |= slice->cabac_init_idc & 0x3; - reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC; + if (ctx->fh.m2m_ctx->new_frame) + reg |= VE_H264_SHS_FIRST_SLICE_IN_PIC; if (slice->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC) reg |= VE_H264_SHS_FIELD_PIC; if (slice->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) @@ -447,7 +499,7 @@ static void cedrus_h264_setup(struct cedrus_ctx *ctx, { struct cedrus_dev *dev = ctx->dev; - cedrus_engine_enable(dev, CEDRUS_CODEC_H264); + cedrus_engine_enable(ctx, CEDRUS_CODEC_H264); cedrus_write(dev, VE_H264_SDROT_CTRL, 0); cedrus_write(dev, VE_H264_EXTRA_BUFFER1, @@ -464,18 +516,30 @@ static void cedrus_h264_setup(struct cedrus_ctx *ctx, static int cedrus_h264_start(struct cedrus_ctx *ctx) { struct cedrus_dev *dev = ctx->dev; + unsigned int pic_info_size; unsigned int field_size; unsigned int mv_col_size; int ret; + /* Formula for picture buffer size is taken from CedarX source. */ + + if (ctx->src_fmt.width > 2048) + pic_info_size = CEDRUS_H264_FRAME_NUM * 0x4000; + else + pic_info_size = CEDRUS_H264_FRAME_NUM * 0x1000; + /* - * FIXME: It seems that the H6 cedarX code is using a formula - * here based on the size of the frame, while all the older - * code is using a fixed size, so that might need to be - * changed at some point. + * FIXME: If V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is set, + * there is no need to multiply by 2. */ + pic_info_size += ctx->src_fmt.height * 2 * 64; + + if (pic_info_size < CEDRUS_MIN_PIC_INFO_BUF_SIZE) + pic_info_size = CEDRUS_MIN_PIC_INFO_BUF_SIZE; + + ctx->codec.h264.pic_info_buf_size = pic_info_size; ctx->codec.h264.pic_info_buf = - dma_alloc_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + dma_alloc_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, &ctx->codec.h264.pic_info_buf_dma, GFP_KERNEL); if (!ctx->codec.h264.pic_info_buf) @@ -528,15 +592,56 @@ static int cedrus_h264_start(struct cedrus_ctx *ctx) goto err_neighbor_buf; } + if (ctx->src_fmt.width > 2048) { + /* + * Formulas for deblock and intra prediction buffer sizes + * are taken from CedarX source. + */ + + ctx->codec.h264.deblk_buf_size = + ALIGN(ctx->src_fmt.width, 32) * 12; + ctx->codec.h264.deblk_buf = + dma_alloc_coherent(dev->dev, + ctx->codec.h264.deblk_buf_size, + &ctx->codec.h264.deblk_buf_dma, + GFP_KERNEL); + if (!ctx->codec.h264.deblk_buf) { + ret = -ENOMEM; + goto err_mv_col_buf; + } + + ctx->codec.h264.intra_pred_buf_size = + ALIGN(ctx->src_fmt.width, 64) * 5; + ctx->codec.h264.intra_pred_buf = + dma_alloc_coherent(dev->dev, + ctx->codec.h264.intra_pred_buf_size, + &ctx->codec.h264.intra_pred_buf_dma, + GFP_KERNEL); + if (!ctx->codec.h264.intra_pred_buf) { + ret = -ENOMEM; + goto err_deblk_buf; + } + } + return 0; +err_deblk_buf: + dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size, + ctx->codec.h264.deblk_buf, + ctx->codec.h264.deblk_buf_dma); + +err_mv_col_buf: + dma_free_coherent(dev->dev, ctx->codec.h264.mv_col_buf_size, + ctx->codec.h264.mv_col_buf, + ctx->codec.h264.mv_col_buf_dma); + err_neighbor_buf: dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, ctx->codec.h264.neighbor_info_buf, ctx->codec.h264.neighbor_info_buf_dma); err_pic_buf: - dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, ctx->codec.h264.pic_info_buf, ctx->codec.h264.pic_info_buf_dma); return ret; @@ -552,9 +657,17 @@ static void cedrus_h264_stop(struct cedrus_ctx *ctx) dma_free_coherent(dev->dev, CEDRUS_NEIGHBOR_INFO_BUF_SIZE, ctx->codec.h264.neighbor_info_buf, ctx->codec.h264.neighbor_info_buf_dma); - dma_free_coherent(dev->dev, CEDRUS_PIC_INFO_BUF_SIZE, + dma_free_coherent(dev->dev, ctx->codec.h264.pic_info_buf_size, ctx->codec.h264.pic_info_buf, ctx->codec.h264.pic_info_buf_dma); + if (ctx->codec.h264.deblk_buf_size) + dma_free_coherent(dev->dev, ctx->codec.h264.deblk_buf_size, + ctx->codec.h264.deblk_buf, + ctx->codec.h264.deblk_buf_dma); + if (ctx->codec.h264.intra_pred_buf_size) + dma_free_coherent(dev->dev, ctx->codec.h264.intra_pred_buf_size, + ctx->codec.h264.intra_pred_buf, + ctx->codec.h264.intra_pred_buf_dma); } static void cedrus_h264_trigger(struct cedrus_ctx *ctx) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c new file mode 100644 index 000000000000..6945dc74e1d7 --- /dev/null +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cedrus VPU driver + * + * Copyright (C) 2013 Jens Kuske <jenskuske@gmail.com> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com> + * Copyright (C) 2018 Bootlin + */ + +#include <linux/types.h> + +#include <media/videobuf2-dma-contig.h> + +#include "cedrus.h" +#include "cedrus_hw.h" +#include "cedrus_regs.h" + +/* + * These are the sizes for side buffers required by the hardware for storing + * internal decoding metadata. They match the values used by the early BSP + * implementations, that were initially exposed in libvdpau-sunxi. + * Subsequent BSP implementations seem to double the neighbor info buffer size + * for the H6 SoC, which may be related to 10 bit H265 support. + */ +#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) +#define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) +#define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 + +struct cedrus_h265_sram_frame_info { + __le32 top_pic_order_cnt; + __le32 bottom_pic_order_cnt; + __le32 top_mv_col_buf_addr; + __le32 bottom_mv_col_buf_addr; + __le32 luma_addr; + __le32 chroma_addr; +} __packed; + +struct cedrus_h265_sram_pred_weight { + __s8 delta_weight; + __s8 offset; +} __packed; + +static enum cedrus_irq_status cedrus_h265_irq_status(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg; + + reg = cedrus_read(dev, VE_DEC_H265_STATUS); + reg &= VE_DEC_H265_STATUS_CHECK_MASK; + + if (reg & VE_DEC_H265_STATUS_CHECK_ERROR || + !(reg & VE_DEC_H265_STATUS_SUCCESS)) + return CEDRUS_IRQ_ERROR; + + return CEDRUS_IRQ_OK; +} + +static void cedrus_h265_irq_clear(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_DEC_H265_STATUS, VE_DEC_H265_STATUS_CHECK_MASK); +} + +static void cedrus_h265_irq_disable(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_DEC_H265_CTRL); + + reg &= ~VE_DEC_H265_CTRL_IRQ_MASK; + + cedrus_write(dev, VE_DEC_H265_CTRL, reg); +} + +static void cedrus_h265_sram_write_offset(struct cedrus_dev *dev, u32 offset) +{ + cedrus_write(dev, VE_DEC_H265_SRAM_OFFSET, offset); +} + +static void cedrus_h265_sram_write_data(struct cedrus_dev *dev, void *data, + unsigned int size) +{ + u32 *word = data; + + while (size >= sizeof(u32)) { + cedrus_write(dev, VE_DEC_H265_SRAM_DATA, *word++); + size -= sizeof(u32); + } +} + +static inline dma_addr_t +cedrus_h265_frame_info_mv_col_buf_addr(struct cedrus_ctx *ctx, + unsigned int index, unsigned int field) +{ + return ctx->codec.h265.mv_col_buf_addr + index * + ctx->codec.h265.mv_col_buf_unit_size + + field * ctx->codec.h265.mv_col_buf_unit_size / 2; +} + +static void cedrus_h265_frame_info_write_single(struct cedrus_ctx *ctx, + unsigned int index, + bool field_pic, + u32 pic_order_cnt[], + int buffer_index) +{ + struct cedrus_dev *dev = ctx->dev; + dma_addr_t dst_luma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 0); + dma_addr_t dst_chroma_addr = cedrus_dst_buf_addr(ctx, buffer_index, 1); + dma_addr_t mv_col_buf_addr[2] = { + cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, 0), + cedrus_h265_frame_info_mv_col_buf_addr(ctx, buffer_index, + field_pic ? 1 : 0) + }; + u32 offset = VE_DEC_H265_SRAM_OFFSET_FRAME_INFO + + VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT * index; + struct cedrus_h265_sram_frame_info frame_info = { + .top_pic_order_cnt = cpu_to_le32(pic_order_cnt[0]), + .bottom_pic_order_cnt = cpu_to_le32(field_pic ? + pic_order_cnt[1] : + pic_order_cnt[0]), + .top_mv_col_buf_addr = + cpu_to_le32(VE_DEC_H265_SRAM_DATA_ADDR_BASE(mv_col_buf_addr[0])), + .bottom_mv_col_buf_addr = cpu_to_le32(field_pic ? + VE_DEC_H265_SRAM_DATA_ADDR_BASE(mv_col_buf_addr[1]) : + VE_DEC_H265_SRAM_DATA_ADDR_BASE(mv_col_buf_addr[0])), + .luma_addr = cpu_to_le32(VE_DEC_H265_SRAM_DATA_ADDR_BASE(dst_luma_addr)), + .chroma_addr = cpu_to_le32(VE_DEC_H265_SRAM_DATA_ADDR_BASE(dst_chroma_addr)), + }; + + cedrus_h265_sram_write_offset(dev, offset); + cedrus_h265_sram_write_data(dev, &frame_info, sizeof(frame_info)); +} + +static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx, + const struct v4l2_hevc_dpb_entry *dpb, + u8 num_active_dpb_entries) +{ + struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + unsigned int i; + + for (i = 0; i < num_active_dpb_entries; i++) { + int buffer_index = vb2_find_timestamp(vq, dpb[i].timestamp, 0); + u32 pic_order_cnt[2] = { + dpb[i].pic_order_cnt[0], + dpb[i].pic_order_cnt[1] + }; + + cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic, + pic_order_cnt, + buffer_index); + } +} + +static void cedrus_h265_ref_pic_list_write(struct cedrus_dev *dev, + const struct v4l2_hevc_dpb_entry *dpb, + const u8 list[], + u8 num_ref_idx_active, + u32 sram_offset) +{ + unsigned int i; + u32 word = 0; + + cedrus_h265_sram_write_offset(dev, sram_offset); + + for (i = 0; i < num_ref_idx_active; i++) { + unsigned int shift = (i % 4) * 8; + unsigned int index = list[i]; + u8 value = list[i]; + + if (dpb[index].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + value |= VE_DEC_H265_SRAM_REF_PIC_LIST_LT_REF; + + /* Each SRAM word gathers up to 4 references. */ + word |= value << shift; + + /* Write the word to SRAM and clear it for the next batch. */ + if ((i % 4) == 3 || i == (num_ref_idx_active - 1)) { + cedrus_h265_sram_write_data(dev, &word, sizeof(word)); + word = 0; + } + } +} + +static void cedrus_h265_pred_weight_write(struct cedrus_dev *dev, + const s8 delta_luma_weight[], + const s8 luma_offset[], + const s8 delta_chroma_weight[][2], + const s8 chroma_offset[][2], + u8 num_ref_idx_active, + u32 sram_luma_offset, + u32 sram_chroma_offset) +{ + struct cedrus_h265_sram_pred_weight pred_weight[2] = { { 0 } }; + unsigned int i, j; + + cedrus_h265_sram_write_offset(dev, sram_luma_offset); + + for (i = 0; i < num_ref_idx_active; i++) { + unsigned int index = i % 2; + + pred_weight[index].delta_weight = delta_luma_weight[i]; + pred_weight[index].offset = luma_offset[i]; + + if (index == 1 || i == (num_ref_idx_active - 1)) + cedrus_h265_sram_write_data(dev, (u32 *)&pred_weight, + sizeof(pred_weight)); + } + + cedrus_h265_sram_write_offset(dev, sram_chroma_offset); + + for (i = 0; i < num_ref_idx_active; i++) { + for (j = 0; j < 2; j++) { + pred_weight[j].delta_weight = delta_chroma_weight[i][j]; + pred_weight[j].offset = chroma_offset[i][j]; + } + + cedrus_h265_sram_write_data(dev, &pred_weight, + sizeof(pred_weight)); + } +} + +static void cedrus_h265_setup(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + struct cedrus_dev *dev = ctx->dev; + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; + const struct v4l2_ctrl_hevc_slice_params *slice_params; + const struct v4l2_hevc_pred_weight_table *pred_weight_table; + dma_addr_t src_buf_addr; + dma_addr_t src_buf_end_addr; + u32 chroma_log2_weight_denom; + u32 output_pic_list_index; + u32 pic_order_cnt[2]; + u32 reg; + + sps = run->h265.sps; + pps = run->h265.pps; + slice_params = run->h265.slice_params; + pred_weight_table = &slice_params->pred_weight_table; + + /* MV column buffer size and allocation. */ + if (!ctx->codec.h265.mv_col_buf_size) { + unsigned int num_buffers = + run->dst->vb2_buf.vb2_queue->num_buffers; + unsigned int log2_max_luma_coding_block_size = + sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size; + unsigned int ctb_size_luma = + 1UL << log2_max_luma_coding_block_size; + + /* + * Each CTB requires a MV col buffer with a specific unit size. + * Since the address is given with missing lsb bits, 1 KiB is + * added to each buffer to ensure proper alignment. + */ + ctx->codec.h265.mv_col_buf_unit_size = + DIV_ROUND_UP(ctx->src_fmt.width, ctb_size_luma) * + DIV_ROUND_UP(ctx->src_fmt.height, ctb_size_luma) * + CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE + SZ_1K; + + ctx->codec.h265.mv_col_buf_size = num_buffers * + ctx->codec.h265.mv_col_buf_unit_size; + + ctx->codec.h265.mv_col_buf = + dma_alloc_coherent(dev->dev, + ctx->codec.h265.mv_col_buf_size, + &ctx->codec.h265.mv_col_buf_addr, + GFP_KERNEL); + if (!ctx->codec.h265.mv_col_buf) { + ctx->codec.h265.mv_col_buf_size = 0; + // TODO: Abort the process here. + return; + } + } + + /* Activate H265 engine. */ + cedrus_engine_enable(ctx, CEDRUS_CODEC_H265); + + /* Source offset and length in bits. */ + + reg = slice_params->data_bit_offset; + cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, reg); + + reg = slice_params->bit_size - slice_params->data_bit_offset; + cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg); + + /* Source beginning and end addresses. */ + + src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0); + + reg = VE_DEC_H265_BITS_ADDR_BASE(src_buf_addr); + reg |= VE_DEC_H265_BITS_ADDR_VALID_SLICE_DATA; + reg |= VE_DEC_H265_BITS_ADDR_LAST_SLICE_DATA; + reg |= VE_DEC_H265_BITS_ADDR_FIRST_SLICE_DATA; + + cedrus_write(dev, VE_DEC_H265_BITS_ADDR, reg); + + src_buf_end_addr = src_buf_addr + + DIV_ROUND_UP(slice_params->bit_size, 8); + + reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr); + cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg); + + /* Coding tree block address: start at the beginning. */ + reg = VE_DEC_H265_DEC_CTB_ADDR_X(0) | VE_DEC_H265_DEC_CTB_ADDR_Y(0); + cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg); + + cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0); + cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0); + + /* Clear the number of correctly-decoded coding tree blocks. */ + cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0); + + /* Initialize bitstream access. */ + cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); + + /* Bitstream parameters. */ + + reg = VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(slice_params->nal_unit_type) | + VE_DEC_H265_DEC_NAL_HDR_NUH_TEMPORAL_ID_PLUS1(slice_params->nuh_temporal_id_plus1); + + cedrus_write(dev, VE_DEC_H265_DEC_NAL_HDR, reg); + + /* SPS. */ + + reg = VE_DEC_H265_DEC_SPS_HDR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA(sps->max_transform_hierarchy_depth_intra) | + VE_DEC_H265_DEC_SPS_HDR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER(sps->max_transform_hierarchy_depth_inter) | + VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE(sps->log2_diff_max_min_luma_transform_block_size) | + VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2(sps->log2_min_luma_transform_block_size_minus2) | + VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE(sps->log2_diff_max_min_luma_coding_block_size) | + VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3(sps->log2_min_luma_coding_block_size_minus3) | + VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_CHROMA_MINUS8(sps->bit_depth_chroma_minus8) | + VE_DEC_H265_DEC_SPS_HDR_CHROMA_FORMAT_IDC(sps->chroma_format_idc); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_STRONG_INTRA_SMOOTHING_ENABLE, + V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED, + sps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_SPS_TEMPORAL_MVP_ENABLED, + V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED, + sps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_SAMPLE_ADAPTIVE_OFFSET_ENABLED, + V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET, + sps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_AMP_ENABLED, + V4L2_HEVC_SPS_FLAG_AMP_ENABLED, sps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_SEPARATE_COLOUR_PLANE, + V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE, + sps->flags); + + cedrus_write(dev, VE_DEC_H265_DEC_SPS_HDR, reg); + + reg = VE_DEC_H265_DEC_PCM_CTRL_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE(sps->log2_diff_max_min_pcm_luma_coding_block_size) | + VE_DEC_H265_DEC_PCM_CTRL_LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3(sps->log2_min_pcm_luma_coding_block_size_minus3) | + VE_DEC_H265_DEC_PCM_CTRL_PCM_SAMPLE_BIT_DEPTH_CHROMA_MINUS1(sps->pcm_sample_bit_depth_chroma_minus1) | + VE_DEC_H265_DEC_PCM_CTRL_PCM_SAMPLE_BIT_DEPTH_LUMA_MINUS1(sps->pcm_sample_bit_depth_luma_minus1); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PCM_CTRL_FLAG_PCM_ENABLED, + V4L2_HEVC_SPS_FLAG_PCM_ENABLED, sps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PCM_CTRL_FLAG_PCM_LOOP_FILTER_DISABLED, + V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED, + sps->flags); + + cedrus_write(dev, VE_DEC_H265_DEC_PCM_CTRL, reg); + + /* PPS. */ + + reg = VE_DEC_H265_DEC_PPS_CTRL0_PPS_CR_QP_OFFSET(pps->pps_cr_qp_offset) | + VE_DEC_H265_DEC_PPS_CTRL0_PPS_CB_QP_OFFSET(pps->pps_cb_qp_offset) | + VE_DEC_H265_DEC_PPS_CTRL0_INIT_QP_MINUS26(pps->init_qp_minus26) | + VE_DEC_H265_DEC_PPS_CTRL0_DIFF_CU_QP_DELTA_DEPTH(pps->diff_cu_qp_delta_depth); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL0_FLAG_CU_QP_DELTA_ENABLED, + V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL0_FLAG_TRANSFORM_SKIP_ENABLED, + V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL0_FLAG_CONSTRAINED_INTRA_PRED, + V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL0_FLAG_SIGN_DATA_HIDING_ENABLED, + V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED, + pps->flags); + + cedrus_write(dev, VE_DEC_H265_DEC_PPS_CTRL0, reg); + + reg = VE_DEC_H265_DEC_PPS_CTRL1_LOG2_PARALLEL_MERGE_LEVEL_MINUS2(pps->log2_parallel_merge_level_minus2); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, + V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, + V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_ENTROPY_CODING_SYNC_ENABLED, + V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED, + pps->flags); + + /* TODO: VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED */ + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED, + V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED, + pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_WEIGHTED_BIPRED, + V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED, pps->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_WEIGHTED_PRED, + V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED, pps->flags); + + cedrus_write(dev, VE_DEC_H265_DEC_PPS_CTRL1, reg); + + /* Slice Parameters. */ + + reg = VE_DEC_H265_DEC_SLICE_HDR_INFO0_PICTURE_TYPE(slice_params->pic_struct) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_FIVE_MINUS_MAX_NUM_MERGE_CAND(slice_params->five_minus_max_num_merge_cand) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_NUM_REF_IDX_L1_ACTIVE_MINUS1(slice_params->num_ref_idx_l1_active_minus1) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_NUM_REF_IDX_L0_ACTIVE_MINUS1(slice_params->num_ref_idx_l0_active_minus1) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_COLLOCATED_REF_IDX(slice_params->collocated_ref_idx) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_COLOUR_PLANE_ID(slice_params->colour_plane_id) | + VE_DEC_H265_DEC_SLICE_HDR_INFO0_SLICE_TYPE(slice_params->slice_type); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_COLLOCATED_FROM_L0, + V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_CABAC_INIT, + V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_MVD_L1_ZERO, + V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_SAO_CHROMA, + V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_SAO_LUMA, + V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_TEMPORAL_MVP_ENABLE, + V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT, + V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT, + pps->flags); + + /* FIXME: For multi-slice support. */ + reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; + + cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO0, reg); + + reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(slice_params->num_rps_poc_st_curr_after == 0) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) | + VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, + V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED, + slice_params->flags); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, + V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED, + slice_params->flags); + + cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO1, reg); + + chroma_log2_weight_denom = pred_weight_table->luma_log2_weight_denom + + pred_weight_table->delta_chroma_log2_weight_denom; + reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(0) | + VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(chroma_log2_weight_denom) | + VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(pred_weight_table->luma_log2_weight_denom); + + cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO2, reg); + + /* Decoded picture size. */ + + reg = VE_DEC_H265_DEC_PIC_SIZE_WIDTH(ctx->src_fmt.width) | + VE_DEC_H265_DEC_PIC_SIZE_HEIGHT(ctx->src_fmt.height); + + cedrus_write(dev, VE_DEC_H265_DEC_PIC_SIZE, reg); + + /* Scaling list. */ + + reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT; + cedrus_write(dev, VE_DEC_H265_SCALING_LIST_CTRL0, reg); + + /* Neightbor information address. */ + reg = VE_DEC_H265_NEIGHBOR_INFO_ADDR_BASE(ctx->codec.h265.neighbor_info_buf_addr); + cedrus_write(dev, VE_DEC_H265_NEIGHBOR_INFO_ADDR, reg); + + /* Write decoded picture buffer in pic list. */ + cedrus_h265_frame_info_write_dpb(ctx, slice_params->dpb, + slice_params->num_active_dpb_entries); + + /* Output frame. */ + + output_pic_list_index = V4L2_HEVC_DPB_ENTRIES_NUM_MAX; + pic_order_cnt[0] = slice_params->slice_pic_order_cnt; + pic_order_cnt[1] = slice_params->slice_pic_order_cnt; + + cedrus_h265_frame_info_write_single(ctx, output_pic_list_index, + slice_params->pic_struct != 0, + pic_order_cnt, + run->dst->vb2_buf.index); + + cedrus_write(dev, VE_DEC_H265_OUTPUT_FRAME_IDX, output_pic_list_index); + + /* Reference picture list 0 (for P/B frames). */ + if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) { + cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + slice_params->ref_idx_l0, + slice_params->num_ref_idx_l0_active_minus1 + 1, + VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0); + + if ((pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED) || + (pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED)) + cedrus_h265_pred_weight_write(dev, + pred_weight_table->delta_luma_weight_l0, + pred_weight_table->luma_offset_l0, + pred_weight_table->delta_chroma_weight_l0, + pred_weight_table->chroma_offset_l0, + slice_params->num_ref_idx_l0_active_minus1 + 1, + VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_LUMA_L0, + VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L0); + } + + /* Reference picture list 1 (for B frames). */ + if (slice_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) { + cedrus_h265_ref_pic_list_write(dev, slice_params->dpb, + slice_params->ref_idx_l1, + slice_params->num_ref_idx_l1_active_minus1 + 1, + VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1); + + if (pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED) + cedrus_h265_pred_weight_write(dev, + pred_weight_table->delta_luma_weight_l1, + pred_weight_table->luma_offset_l1, + pred_weight_table->delta_chroma_weight_l1, + pred_weight_table->chroma_offset_l1, + slice_params->num_ref_idx_l1_active_minus1 + 1, + VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_LUMA_L1, + VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L1); + } + + /* Enable appropriate interruptions. */ + cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK); +} + +static int cedrus_h265_start(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + /* The buffer size is calculated at setup time. */ + ctx->codec.h265.mv_col_buf_size = 0; + + ctx->codec.h265.neighbor_info_buf = + dma_alloc_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, + &ctx->codec.h265.neighbor_info_buf_addr, + GFP_KERNEL); + if (!ctx->codec.h265.neighbor_info_buf) + return -ENOMEM; + + return 0; +} + +static void cedrus_h265_stop(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + if (ctx->codec.h265.mv_col_buf_size > 0) { + dma_free_coherent(dev->dev, ctx->codec.h265.mv_col_buf_size, + ctx->codec.h265.mv_col_buf, + ctx->codec.h265.mv_col_buf_addr); + + ctx->codec.h265.mv_col_buf_size = 0; + } + + dma_free_coherent(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE, + ctx->codec.h265.neighbor_info_buf, + ctx->codec.h265.neighbor_info_buf_addr); +} + +static void cedrus_h265_trigger(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE); +} + +struct cedrus_dec_ops cedrus_dec_ops_h265 = { + .irq_clear = cedrus_h265_irq_clear, + .irq_disable = cedrus_h265_irq_disable, + .irq_status = cedrus_h265_irq_status, + .setup = cedrus_h265_setup, + .start = cedrus_h265_start, + .stop = cedrus_h265_stop, + .trigger = cedrus_h265_trigger, +}; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index a942cd9bed57..daf5f244f93b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -30,7 +30,7 @@ #include "cedrus_hw.h" #include "cedrus_regs.h" -int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec) +int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec) { u32 reg = 0; @@ -50,11 +50,20 @@ int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec) reg |= VE_MODE_DEC_H264; break; + case CEDRUS_CODEC_H265: + reg |= VE_MODE_DEC_H265; + break; + default: return -EINVAL; } - cedrus_write(dev, VE_MODE, reg); + if (ctx->src_fmt.width == 4096) + reg |= VE_MODE_PIC_WIDTH_IS_4096; + if (ctx->src_fmt.width > 2048) + reg |= VE_MODE_PIC_WIDTH_MORE_2048; + + cedrus_write(ctx->dev, VE_MODE, reg); return 0; } @@ -103,7 +112,6 @@ static irqreturn_t cedrus_irq(int irq, void *data) { struct cedrus_dev *dev = data; struct cedrus_ctx *ctx; - struct vb2_v4l2_buffer *src_buf, *dst_buf; enum vb2_buffer_state state; enum cedrus_irq_status status; @@ -121,24 +129,13 @@ static irqreturn_t cedrus_irq(int irq, void *data) dev->dec_ops[ctx->current_codec]->irq_disable(ctx); dev->dec_ops[ctx->current_codec]->irq_clear(ctx); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - if (!src_buf || !dst_buf) { - v4l2_err(&dev->v4l2_dev, - "Missing source and/or destination buffers\n"); - return IRQ_HANDLED; - } - if (status == CEDRUS_IRQ_ERROR) state = VB2_BUF_STATE_ERROR; else state = VB2_BUF_STATE_DONE; - v4l2_m2m_buf_done(src_buf, state); - v4l2_m2m_buf_done(dst_buf, state); - - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, + state); return IRQ_HANDLED; } @@ -146,7 +143,6 @@ static irqreturn_t cedrus_irq(int irq, void *data) int cedrus_hw_probe(struct cedrus_dev *dev) { const struct cedrus_variant *variant; - struct resource *res; int irq_dec; int ret; @@ -225,8 +221,7 @@ int cedrus_hw_probe(struct cedrus_dev *dev) goto err_sram; } - res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(dev->dev, res); + dev->base = devm_platform_ioremap_resource(dev->pdev, 0); if (IS_ERR(dev->base)) { dev_err(dev->dev, "Failed to map registers\n"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h index 27d0882397aa..604ff932fbf5 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h @@ -16,7 +16,7 @@ #ifndef _CEDRUS_HW_H_ #define _CEDRUS_HW_H_ -int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_codec codec); +int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec); void cedrus_engine_disable(struct cedrus_dev *dev); void cedrus_dst_format_set(struct cedrus_dev *dev, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c index 13c34927bad5..8bcd6b8f9e2d 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c @@ -96,7 +96,7 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run) quantization = run->mpeg2.quantization; /* Activate MPEG engine. */ - cedrus_engine_enable(dev, CEDRUS_CODEC_MPEG2); + cedrus_engine_enable(ctx, CEDRUS_CODEC_MPEG2); /* Set intra quantization matrix. */ diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index ddd29788d685..7beb03d3bb39 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -10,6 +10,9 @@ #ifndef _CEDRUS_REGS_H_ #define _CEDRUS_REGS_H_ +#define SHIFT_AND_MASK_BITS(v, h, l) \ + (((unsigned long)(v) << (l)) & GENMASK(h, l)) + /* * Common acronyms and contractions used in register descriptions: * * VLD : Variable-Length Decoder @@ -18,13 +21,22 @@ * * MC: Motion Compensation * * STCD: Start Code Detect * * SDRT: Scale Down and Rotate + * * WB: Writeback + * * BITS/BS: Bitstream + * * MB: Macroblock + * * CTU: Coding Tree Unit + * * CTB: Coding Tree Block + * * IDX: Index */ #define VE_ENGINE_DEC_MPEG 0x100 #define VE_ENGINE_DEC_H264 0x200 +#define VE_ENGINE_DEC_H265 0x500 #define VE_MODE 0x00 +#define VE_MODE_PIC_WIDTH_IS_4096 BIT(22) +#define VE_MODE_PIC_WIDTH_MORE_2048 BIT(21) #define VE_MODE_REC_WR_MODE_2MB (0x01 << 20) #define VE_MODE_REC_WR_MODE_1MB (0x00 << 20) #define VE_MODE_DDR_MODE_BW_128 (0x03 << 16) @@ -34,11 +46,22 @@ #define VE_MODE_DEC_H264 (0x01 << 0) #define VE_MODE_DEC_MPEG (0x00 << 0) +#define VE_BUF_CTRL 0x50 + +#define VE_BUF_CTRL_INTRAPRED_EXT_RAM (0x02 << 2) +#define VE_BUF_CTRL_INTRAPRED_MIXED_RAM (0x01 << 2) +#define VE_BUF_CTRL_INTRAPRED_INT_SRAM (0x00 << 2) +#define VE_BUF_CTRL_DBLK_EXT_RAM (0x02 << 0) +#define VE_BUF_CTRL_DBLK_MIXED_RAM (0x01 << 0) +#define VE_BUF_CTRL_DBLK_INT_SRAM (0x00 << 0) + +#define VE_DBLK_DRAM_BUF_ADDR 0x54 +#define VE_INTRAPRED_DRAM_BUF_ADDR 0x58 #define VE_PRIMARY_CHROMA_BUF_LEN 0xc4 #define VE_PRIMARY_FB_LINE_STRIDE 0xc8 -#define VE_PRIMARY_FB_LINE_STRIDE_CHROMA(s) (((s) << 16) & GENMASK(31, 16)) -#define VE_PRIMARY_FB_LINE_STRIDE_LUMA(s) (((s) << 0) & GENMASK(15, 0)) +#define VE_PRIMARY_FB_LINE_STRIDE_CHROMA(s) SHIFT_AND_MASK_BITS(s, 31, 16) +#define VE_PRIMARY_FB_LINE_STRIDE_LUMA(s) SHIFT_AND_MASK_BITS(s, 15, 0) #define VE_CHROMA_BUF_LEN 0xe8 @@ -46,7 +69,7 @@ #define VE_SECONDARY_OUT_FMT_EXT (0x01 << 30) #define VE_SECONDARY_OUT_FMT_YU12 (0x02 << 30) #define VE_SECONDARY_OUT_FMT_YV12 (0x03 << 30) -#define VE_CHROMA_BUF_LEN_SDRT(l) ((l) & GENMASK(27, 0)) +#define VE_CHROMA_BUF_LEN_SDRT(l) SHIFT_AND_MASK_BITS(l, 27, 0) #define VE_PRIMARY_OUT_FMT 0xec @@ -69,15 +92,15 @@ #define VE_DEC_MPEG_MP12HDR (VE_ENGINE_DEC_MPEG + 0x00) -#define VE_DEC_MPEG_MP12HDR_SLICE_TYPE(t) (((t) << 28) & GENMASK(30, 28)) +#define VE_DEC_MPEG_MP12HDR_SLICE_TYPE(t) SHIFT_AND_MASK_BITS(t, 30, 28) #define VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(x, y) (24 - 4 * (y) - 8 * (x)) #define VE_DEC_MPEG_MP12HDR_F_CODE(__x, __y, __v) \ - (((__v) & GENMASK(3, 0)) << VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(__x, __y)) + (((unsigned long)(__v) & GENMASK(3, 0)) << VE_DEC_MPEG_MP12HDR_F_CODE_SHIFT(__x, __y)) #define VE_DEC_MPEG_MP12HDR_INTRA_DC_PRECISION(p) \ - (((p) << 10) & GENMASK(11, 10)) + SHIFT_AND_MASK_BITS(p, 11, 10) #define VE_DEC_MPEG_MP12HDR_INTRA_PICTURE_STRUCTURE(s) \ - (((s) << 8) & GENMASK(9, 8)) + SHIFT_AND_MASK_BITS(s, 9, 8) #define VE_DEC_MPEG_MP12HDR_TOP_FIELD_FIRST(v) \ ((v) ? BIT(7) : 0) #define VE_DEC_MPEG_MP12HDR_FRAME_PRED_FRAME_DCT(v) \ @@ -98,19 +121,19 @@ #define VE_DEC_MPEG_PICCODEDSIZE (VE_ENGINE_DEC_MPEG + 0x08) #define VE_DEC_MPEG_PICCODEDSIZE_WIDTH(w) \ - ((DIV_ROUND_UP((w), 16) << 8) & GENMASK(15, 8)) + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8) #define VE_DEC_MPEG_PICCODEDSIZE_HEIGHT(h) \ - ((DIV_ROUND_UP((h), 16) << 0) & GENMASK(7, 0)) + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0) #define VE_DEC_MPEG_PICBOUNDSIZE (VE_ENGINE_DEC_MPEG + 0x0c) -#define VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(w) (((w) << 16) & GENMASK(27, 16)) -#define VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(h) (((h) << 0) & GENMASK(11, 0)) +#define VE_DEC_MPEG_PICBOUNDSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16) +#define VE_DEC_MPEG_PICBOUNDSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0) #define VE_DEC_MPEG_MBADDR (VE_ENGINE_DEC_MPEG + 0x10) -#define VE_DEC_MPEG_MBADDR_X(w) (((w) << 8) & GENMASK(15, 8)) -#define VE_DEC_MPEG_MBADDR_Y(h) (((h) << 0) & GENMASK(7, 0)) +#define VE_DEC_MPEG_MBADDR_X(w) SHIFT_AND_MASK_BITS(w, 15, 8) +#define VE_DEC_MPEG_MBADDR_Y(h) SHIFT_AND_MASK_BITS(h, 7, 0) #define VE_DEC_MPEG_CTRL (VE_ENGINE_DEC_MPEG + 0x14) @@ -225,13 +248,277 @@ #define VE_DEC_MPEG_IQMINPUT_FLAG_INTRA (0x01 << 14) #define VE_DEC_MPEG_IQMINPUT_FLAG_NON_INTRA (0x00 << 14) #define VE_DEC_MPEG_IQMINPUT_WEIGHT(i, v) \ - (((v) & GENMASK(7, 0)) | (((i) << 8) & GENMASK(13, 8))) + (SHIFT_AND_MASK_BITS(i, 13, 8) | SHIFT_AND_MASK_BITS(v, 7, 0)) #define VE_DEC_MPEG_ERROR (VE_ENGINE_DEC_MPEG + 0xc4) #define VE_DEC_MPEG_CRTMBADDR (VE_ENGINE_DEC_MPEG + 0xc8) #define VE_DEC_MPEG_ROT_LUMA (VE_ENGINE_DEC_MPEG + 0xcc) #define VE_DEC_MPEG_ROT_CHROMA (VE_ENGINE_DEC_MPEG + 0xd0) +#define VE_DEC_H265_DEC_NAL_HDR (VE_ENGINE_DEC_H265 + 0x00) + +#define VE_DEC_H265_DEC_NAL_HDR_NUH_TEMPORAL_ID_PLUS1(v) \ + SHIFT_AND_MASK_BITS(v, 8, 6) +#define VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(v) \ + SHIFT_AND_MASK_BITS(v, 5, 0) + +#define VE_DEC_H265_FLAG(reg_flag, ctrl_flag, flags) \ + (((flags) & (ctrl_flag)) ? reg_flag : 0) + +#define VE_DEC_H265_DEC_SPS_HDR (VE_ENGINE_DEC_H265 + 0x04) + +#define VE_DEC_H265_DEC_SPS_HDR_FLAG_STRONG_INTRA_SMOOTHING_ENABLE BIT(26) +#define VE_DEC_H265_DEC_SPS_HDR_FLAG_SPS_TEMPORAL_MVP_ENABLED BIT(25) +#define VE_DEC_H265_DEC_SPS_HDR_FLAG_SAMPLE_ADAPTIVE_OFFSET_ENABLED BIT(24) +#define VE_DEC_H265_DEC_SPS_HDR_FLAG_AMP_ENABLED BIT(23) +#define VE_DEC_H265_DEC_SPS_HDR_FLAG_SEPARATE_COLOUR_PLANE BIT(2) + +#define VE_DEC_H265_DEC_SPS_HDR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA(v) \ + SHIFT_AND_MASK_BITS(v, 22, 20) +#define VE_DEC_H265_DEC_SPS_HDR_MAX_TRANSFORM_HIERARCHY_DEPTH_INTER(v) \ + SHIFT_AND_MASK_BITS(v, 19, 17) +#define VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_TRANSFORM_BLOCK_SIZE(v) \ + SHIFT_AND_MASK_BITS(v, 16, 15) +#define VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_TRANSFORM_BLOCK_SIZE_MINUS2(v) \ + SHIFT_AND_MASK_BITS(v, 14, 13) +#define VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE(v) \ + SHIFT_AND_MASK_BITS(v, 12, 11) +#define VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3(v) \ + SHIFT_AND_MASK_BITS(v, 10, 9) +#define VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_CHROMA_MINUS8(v) \ + SHIFT_AND_MASK_BITS(v, 8, 6) +#define VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_LUMA_MINUS8(v) \ + SHIFT_AND_MASK_BITS(v, 5, 3) +#define VE_DEC_H265_DEC_SPS_HDR_CHROMA_FORMAT_IDC(v) \ + SHIFT_AND_MASK_BITS(v, 1, 0) + +#define VE_DEC_H265_DEC_PIC_SIZE (VE_ENGINE_DEC_H265 + 0x08) + +#define VE_DEC_H265_DEC_PIC_SIZE_WIDTH(w) (((w) << 0) & GENMASK(13, 0)) +#define VE_DEC_H265_DEC_PIC_SIZE_HEIGHT(h) (((h) << 16) & GENMASK(29, 16)) + +#define VE_DEC_H265_DEC_PCM_CTRL (VE_ENGINE_DEC_H265 + 0x0c) + +#define VE_DEC_H265_DEC_PCM_CTRL_FLAG_PCM_ENABLED BIT(15) +#define VE_DEC_H265_DEC_PCM_CTRL_FLAG_PCM_LOOP_FILTER_DISABLED BIT(14) + +#define VE_DEC_H265_DEC_PCM_CTRL_LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE(v) \ + SHIFT_AND_MASK_BITS(v, 11, 10) +#define VE_DEC_H265_DEC_PCM_CTRL_LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE_MINUS3(v) \ + SHIFT_AND_MASK_BITS(v, 9, 8) +#define VE_DEC_H265_DEC_PCM_CTRL_PCM_SAMPLE_BIT_DEPTH_CHROMA_MINUS1(v) \ + SHIFT_AND_MASK_BITS(v, 7, 4) +#define VE_DEC_H265_DEC_PCM_CTRL_PCM_SAMPLE_BIT_DEPTH_LUMA_MINUS1(v) \ + SHIFT_AND_MASK_BITS(v, 3, 0) + +#define VE_DEC_H265_DEC_PPS_CTRL0 (VE_ENGINE_DEC_H265 + 0x10) + +#define VE_DEC_H265_DEC_PPS_CTRL0_FLAG_CU_QP_DELTA_ENABLED BIT(3) +#define VE_DEC_H265_DEC_PPS_CTRL0_FLAG_TRANSFORM_SKIP_ENABLED BIT(2) +#define VE_DEC_H265_DEC_PPS_CTRL0_FLAG_CONSTRAINED_INTRA_PRED BIT(1) +#define VE_DEC_H265_DEC_PPS_CTRL0_FLAG_SIGN_DATA_HIDING_ENABLED BIT(0) + +#define VE_DEC_H265_DEC_PPS_CTRL0_PPS_CR_QP_OFFSET(v) \ + SHIFT_AND_MASK_BITS(v, 29, 24) +#define VE_DEC_H265_DEC_PPS_CTRL0_PPS_CB_QP_OFFSET(v) \ + SHIFT_AND_MASK_BITS(v, 21, 16) +#define VE_DEC_H265_DEC_PPS_CTRL0_INIT_QP_MINUS26(v) \ + SHIFT_AND_MASK_BITS(v, 14, 8) +#define VE_DEC_H265_DEC_PPS_CTRL0_DIFF_CU_QP_DELTA_DEPTH(v) \ + SHIFT_AND_MASK_BITS(v, 5, 4) + +#define VE_DEC_H265_DEC_PPS_CTRL1 (VE_ENGINE_DEC_H265 + 0x14) + +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED BIT(6) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED BIT(5) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_ENTROPY_CODING_SYNC_ENABLED BIT(4) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED BIT(3) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED BIT(2) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_WEIGHTED_BIPRED BIT(1) +#define VE_DEC_H265_DEC_PPS_CTRL1_FLAG_WEIGHTED_PRED BIT(0) + +#define VE_DEC_H265_DEC_PPS_CTRL1_LOG2_PARALLEL_MERGE_LEVEL_MINUS2(v) \ + SHIFT_AND_MASK_BITS(v, 10, 8) + +#define VE_DEC_H265_SCALING_LIST_CTRL0 (VE_ENGINE_DEC_H265 + 0x18) + +#define VE_DEC_H265_SCALING_LIST_CTRL0_FLAG_ENABLED BIT(31) + +#define VE_DEC_H265_SCALING_LIST_CTRL0_SRAM (0 << 30) +#define VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT (1 << 30) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0 (VE_ENGINE_DEC_H265 + 0x20) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_COLLOCATED_FROM_L0 BIT(11) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_CABAC_INIT BIT(10) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_MVD_L1_ZERO BIT(9) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_SAO_CHROMA BIT(8) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_SAO_LUMA BIT(7) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_SLICE_TEMPORAL_MVP_ENABLE BIT(6) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_DEPENDENT_SLICE_SEGMENT BIT(1) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC BIT(0) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_PICTURE_TYPE(v) \ + SHIFT_AND_MASK_BITS(v, 29, 28) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_FIVE_MINUS_MAX_NUM_MERGE_CAND(v) \ + SHIFT_AND_MASK_BITS(v, 26, 24) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_NUM_REF_IDX_L1_ACTIVE_MINUS1(v) \ + SHIFT_AND_MASK_BITS(v, 23, 20) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_NUM_REF_IDX_L0_ACTIVE_MINUS1(v) \ + SHIFT_AND_MASK_BITS(v, 19, 16) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_COLLOCATED_REF_IDX(v) \ + SHIFT_AND_MASK_BITS(v, 15, 12) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_COLOUR_PLANE_ID(v) \ + SHIFT_AND_MASK_BITS(v, 5, 4) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO0_SLICE_TYPE(v) \ + SHIFT_AND_MASK_BITS(v, 3, 2) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1 (VE_ENGINE_DEC_H265 + 0x24) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED BIT(23) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED BIT(22) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(v) \ + SHIFT_AND_MASK_BITS(v, 31, 28) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(v) \ + SHIFT_AND_MASK_BITS(v, 27, 24) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(v) \ + ((v) ? BIT(21) : 0) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(v) \ + SHIFT_AND_MASK_BITS(v, 20, 16) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(v) \ + SHIFT_AND_MASK_BITS(v, 12, 8) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(v) \ + SHIFT_AND_MASK_BITS(v, 6, 0) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO2 (VE_ENGINE_DEC_H265 + 0x28) + +#define VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(v) \ + SHIFT_AND_MASK_BITS(v, 21, 8) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(v) \ + SHIFT_AND_MASK_BITS(v, 6, 4) +#define VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(v) \ + SHIFT_AND_MASK_BITS(v, 2, 0) + +#define VE_DEC_H265_DEC_CTB_ADDR (VE_ENGINE_DEC_H265 + 0x2c) + +#define VE_DEC_H265_DEC_CTB_ADDR_Y(y) SHIFT_AND_MASK_BITS(y, 25, 16) +#define VE_DEC_H265_DEC_CTB_ADDR_X(x) SHIFT_AND_MASK_BITS(x, 9, 0) + +#define VE_DEC_H265_CTRL (VE_ENGINE_DEC_H265 + 0x30) + +#define VE_DEC_H265_CTRL_DDR_CONSISTENCY_EN BIT(31) +#define VE_DEC_H265_CTRL_STCD_EN BIT(25) +#define VE_DEC_H265_CTRL_EPTB_DEC_BYPASS_EN BIT(24) +#define VE_DEC_H265_CTRL_TQ_BYPASS_EN BIT(12) +#define VE_DEC_H265_CTRL_VLD_BYPASS_EN BIT(11) +#define VE_DEC_H265_CTRL_NCRI_CACHE_DISABLE BIT(10) +#define VE_DEC_H265_CTRL_ROTATE_SCALE_OUT_EN BIT(9) +#define VE_DEC_H265_CTRL_MC_NO_WRITEBACK BIT(8) +#define VE_DEC_H265_CTRL_VLD_DATA_REQ_IRQ_EN BIT(2) +#define VE_DEC_H265_CTRL_ERROR_IRQ_EN BIT(1) +#define VE_DEC_H265_CTRL_FINISH_IRQ_EN BIT(0) +#define VE_DEC_H265_CTRL_IRQ_MASK \ + (VE_DEC_H265_CTRL_FINISH_IRQ_EN | VE_DEC_H265_CTRL_ERROR_IRQ_EN | \ + VE_DEC_H265_CTRL_VLD_DATA_REQ_IRQ_EN) + +#define VE_DEC_H265_TRIGGER (VE_ENGINE_DEC_H265 + 0x34) + +#define VE_DEC_H265_TRIGGER_STCD_VC1 (0x02 << 4) +#define VE_DEC_H265_TRIGGER_STCD_AVS (0x01 << 4) +#define VE_DEC_H265_TRIGGER_STCD_HEVC (0x00 << 4) +#define VE_DEC_H265_TRIGGER_DEC_SLICE (0x08 << 0) +#define VE_DEC_H265_TRIGGER_INIT_SWDEC (0x07 << 0) +#define VE_DEC_H265_TRIGGER_BYTE_ALIGN (0x06 << 0) +#define VE_DEC_H265_TRIGGER_GET_VLCUE (0x05 << 0) +#define VE_DEC_H265_TRIGGER_GET_VLCSE (0x04 << 0) +#define VE_DEC_H265_TRIGGER_FLUSH_BITS (0x03 << 0) +#define VE_DEC_H265_TRIGGER_GET_BITS (0x02 << 0) +#define VE_DEC_H265_TRIGGER_SHOW_BITS (0x01 << 0) + +#define VE_DEC_H265_STATUS (VE_ENGINE_DEC_H265 + 0x38) + +#define VE_DEC_H265_STATUS_STCD BIT(24) +#define VE_DEC_H265_STATUS_STCD_BUSY BIT(21) +#define VE_DEC_H265_STATUS_WB_BUSY BIT(20) +#define VE_DEC_H265_STATUS_BS_DMA_BUSY BIT(19) +#define VE_DEC_H265_STATUS_IQIT_BUSY BIT(18) +#define VE_DEC_H265_STATUS_INTER_BUSY BIT(17) +#define VE_DEC_H265_STATUS_MORE_DATA BIT(16) +#define VE_DEC_H265_STATUS_VLD_BUSY BIT(14) +#define VE_DEC_H265_STATUS_DEBLOCKING_BUSY BIT(13) +#define VE_DEC_H265_STATUS_DEBLOCKING_DRAM_BUSY BIT(12) +#define VE_DEC_H265_STATUS_INTRA_BUSY BIT(11) +#define VE_DEC_H265_STATUS_SAO_BUSY BIT(10) +#define VE_DEC_H265_STATUS_MVP_BUSY BIT(9) +#define VE_DEC_H265_STATUS_SWDEC_BUSY BIT(8) +#define VE_DEC_H265_STATUS_OVER_TIME BIT(3) +#define VE_DEC_H265_STATUS_VLD_DATA_REQ BIT(2) +#define VE_DEC_H265_STATUS_ERROR BIT(1) +#define VE_DEC_H265_STATUS_SUCCESS BIT(0) +#define VE_DEC_H265_STATUS_STCD_TYPE_MASK GENMASK(23, 22) +#define VE_DEC_H265_STATUS_CHECK_MASK \ + (VE_DEC_H265_STATUS_SUCCESS | VE_DEC_H265_STATUS_ERROR | \ + VE_DEC_H265_STATUS_VLD_DATA_REQ) +#define VE_DEC_H265_STATUS_CHECK_ERROR \ + (VE_DEC_H265_STATUS_ERROR | VE_DEC_H265_STATUS_VLD_DATA_REQ) + +#define VE_DEC_H265_DEC_CTB_NUM (VE_ENGINE_DEC_H265 + 0x3c) + +#define VE_DEC_H265_BITS_ADDR (VE_ENGINE_DEC_H265 + 0x40) + +#define VE_DEC_H265_BITS_ADDR_FIRST_SLICE_DATA BIT(30) +#define VE_DEC_H265_BITS_ADDR_LAST_SLICE_DATA BIT(29) +#define VE_DEC_H265_BITS_ADDR_VALID_SLICE_DATA BIT(28) +#define VE_DEC_H265_BITS_ADDR_BASE(a) (((a) >> 8) & GENMASK(27, 0)) + +#define VE_DEC_H265_BITS_OFFSET (VE_ENGINE_DEC_H265 + 0x44) +#define VE_DEC_H265_BITS_LEN (VE_ENGINE_DEC_H265 + 0x48) + +#define VE_DEC_H265_BITS_END_ADDR (VE_ENGINE_DEC_H265 + 0x4c) + +#define VE_DEC_H265_BITS_END_ADDR_BASE(a) ((a) >> 8) + +#define VE_DEC_H265_SDRT_CTRL (VE_ENGINE_DEC_H265 + 0x50) +#define VE_DEC_H265_SDRT_LUMA_ADDR (VE_ENGINE_DEC_H265 + 0x54) +#define VE_DEC_H265_SDRT_CHROMA_ADDR (VE_ENGINE_DEC_H265 + 0x58) + +#define VE_DEC_H265_OUTPUT_FRAME_IDX (VE_ENGINE_DEC_H265 + 0x5c) + +#define VE_DEC_H265_NEIGHBOR_INFO_ADDR (VE_ENGINE_DEC_H265 + 0x60) + +#define VE_DEC_H265_NEIGHBOR_INFO_ADDR_BASE(a) ((a) >> 8) + +#define VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR (VE_ENGINE_DEC_H265 + 0x64) +#define VE_DEC_H265_TILE_START_CTB (VE_ENGINE_DEC_H265 + 0x68) +#define VE_DEC_H265_TILE_END_CTB (VE_ENGINE_DEC_H265 + 0x6c) + +#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80) + +#define VE_DEC_H265_LOW_ADDR_PRIMARY_CHROMA(a) \ + SHIFT_AND_MASK_BITS(a, 31, 24) +#define VE_DEC_H265_LOW_ADDR_SECONDARY_CHROMA(a) \ + SHIFT_AND_MASK_BITS(a, 23, 16) +#define VE_DEC_H265_LOW_ADDR_ENTRY_POINTS_BUF(a) \ + SHIFT_AND_MASK_BITS(a, 7, 0) + +#define VE_DEC_H265_SRAM_OFFSET (VE_ENGINE_DEC_H265 + 0xe0) + +#define VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_LUMA_L0 0x00 +#define VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L0 0x20 +#define VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_LUMA_L1 0x60 +#define VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L1 0x80 +#define VE_DEC_H265_SRAM_OFFSET_FRAME_INFO 0x400 +#define VE_DEC_H265_SRAM_OFFSET_FRAME_INFO_UNIT 0x20 +#define VE_DEC_H265_SRAM_OFFSET_SCALING_LISTS 0x800 +#define VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST0 0xc00 +#define VE_DEC_H265_SRAM_OFFSET_REF_PIC_LIST1 0xc10 + +#define VE_DEC_H265_SRAM_DATA (VE_ENGINE_DEC_H265 + 0xe4) + +#define VE_DEC_H265_SRAM_DATA_ADDR_BASE(a) ((a) >> 8) +#define VE_DEC_H265_SRAM_REF_PIC_LIST_LT_REF BIT(7) + #define VE_H264_SPS 0x200 #define VE_H264_SPS_MBS_ONLY BIT(18) #define VE_H264_SPS_MB_ADAPTIVE_FRAME_FIELD BIT(17) @@ -267,13 +554,16 @@ VE_H264_CTRL_SLICE_DECODE_INT) #define VE_H264_TRIGGER_TYPE 0x224 +#define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8) #define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0) #define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0) +#define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0) #define VE_H264_STATUS 0x228 #define VE_H264_STATUS_VLD_DATA_REQ_INT VE_H264_CTRL_VLD_DATA_REQ_INT #define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT #define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT +#define VE_H264_STATUS_VLD_BUSY BIT(8) #define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index eeee3efd247b..15cf1f10221b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -29,8 +29,8 @@ #define CEDRUS_MIN_WIDTH 16U #define CEDRUS_MIN_HEIGHT 16U -#define CEDRUS_MAX_WIDTH 3840U -#define CEDRUS_MAX_HEIGHT 2160U +#define CEDRUS_MAX_WIDTH 4096U +#define CEDRUS_MAX_HEIGHT 2304U static struct cedrus_format cedrus_formats[] = { { @@ -42,6 +42,11 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, }, { + .pixelformat = V4L2_PIX_FMT_HEVC_SLICE, + .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_H265_DEC, + }, + { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .directions = CEDRUS_DECODE_DST, }, @@ -62,34 +67,31 @@ static inline struct cedrus_ctx *cedrus_file2ctx(struct file *file) static struct cedrus_format *cedrus_find_format(u32 pixelformat, u32 directions, unsigned int capabilities) { + struct cedrus_format *first_valid_fmt = NULL; struct cedrus_format *fmt; unsigned int i; for (i = 0; i < CEDRUS_FORMATS_COUNT; i++) { fmt = &cedrus_formats[i]; - if (fmt->capabilities && (fmt->capabilities & capabilities) != - fmt->capabilities) + if ((fmt->capabilities & capabilities) != fmt->capabilities || + !(fmt->directions & directions)) continue; - if (fmt->pixelformat == pixelformat && - (fmt->directions & directions) != 0) + if (fmt->pixelformat == pixelformat) break; + + if (!first_valid_fmt) + first_valid_fmt = fmt; } if (i == CEDRUS_FORMATS_COUNT) - return NULL; + return first_valid_fmt; return &cedrus_formats[i]; } -static bool cedrus_check_format(u32 pixelformat, u32 directions, - unsigned int capabilities) -{ - return cedrus_find_format(pixelformat, directions, capabilities); -} - -static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) +void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) { unsigned int width = pix_fmt->width; unsigned int height = pix_fmt->height; @@ -105,9 +107,11 @@ static void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) switch (pix_fmt->pixelformat) { case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_HEVC_SLICE: /* Zero bytes per line for encoded source. */ bytesperline = 0; - + /* Choose some minimum size since this can't be 0 */ + sizeimage = max_t(u32, SZ_1K, sizeimage); break; case V4L2_PIX_FMT_SUNXI_TILED_NV12: @@ -214,16 +218,7 @@ static int cedrus_g_fmt_vid_cap(struct file *file, void *priv, { struct cedrus_ctx *ctx = cedrus_file2ctx(file); - /* Fall back to dummy default by lack of hardware configuration. */ - if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12; - cedrus_prepare_format(&f->fmt.pix); - - return 0; - } - f->fmt.pix = ctx->dst_fmt; - return 0; } @@ -232,17 +227,7 @@ static int cedrus_g_fmt_vid_out(struct file *file, void *priv, { struct cedrus_ctx *ctx = cedrus_file2ctx(file); - /* Fall back to dummy default by lack of hardware configuration. */ - if (!ctx->dst_fmt.width || !ctx->dst_fmt.height) { - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG2_SLICE; - f->fmt.pix.sizeimage = SZ_1K; - cedrus_prepare_format(&f->fmt.pix); - - return 0; - } - f->fmt.pix = ctx->src_fmt; - return 0; } @@ -252,11 +237,14 @@ static int cedrus_try_fmt_vid_cap(struct file *file, void *priv, struct cedrus_ctx *ctx = cedrus_file2ctx(file); struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct cedrus_format *fmt = + cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, + dev->capabilities); - if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_DST, - dev->capabilities)) + if (!fmt) return -EINVAL; + pix_fmt->pixelformat = fmt->pixelformat; cedrus_prepare_format(pix_fmt); return 0; @@ -268,15 +256,14 @@ static int cedrus_try_fmt_vid_out(struct file *file, void *priv, struct cedrus_ctx *ctx = cedrus_file2ctx(file); struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt = &f->fmt.pix; + struct cedrus_format *fmt = + cedrus_find_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, + dev->capabilities); - if (!cedrus_check_format(pix_fmt->pixelformat, CEDRUS_DECODE_SRC, - dev->capabilities)) - return -EINVAL; - - /* Source image size has to be provided by userspace. */ - if (pix_fmt->sizeimage == 0) + if (!fmt) return -EINVAL; + pix_fmt->pixelformat = fmt->pixelformat; cedrus_prepare_format(pix_fmt); return 0; @@ -322,6 +309,17 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv, ctx->src_fmt = f->fmt.pix; + switch (ctx->src_fmt.pixelformat) { + case V4L2_PIX_FMT_H264_SLICE: + vq->subsystem_flags |= + VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + break; + default: + vq->subsystem_flags &= + ~VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + break; + } + /* Propagate colorspace information to capture. */ ctx->dst_fmt.colorspace = f->fmt.pix.colorspace; ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func; @@ -355,6 +353,9 @@ const struct v4l2_ioctl_ops cedrus_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, + .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; @@ -364,21 +365,12 @@ static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, struct device *alloc_devs[]) { struct cedrus_ctx *ctx = vb2_get_drv_priv(vq); - struct cedrus_dev *dev = ctx->dev; struct v4l2_pix_format *pix_fmt; - u32 directions; - if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - directions = CEDRUS_DECODE_SRC; + if (V4L2_TYPE_IS_OUTPUT(vq->type)) pix_fmt = &ctx->src_fmt; - } else { - directions = CEDRUS_DECODE_DST; + else pix_fmt = &ctx->dst_fmt; - } - - if (!cedrus_check_format(pix_fmt->pixelformat, directions, - dev->capabilities)) - return -EINVAL; if (*nplanes) { if (sizes[0] < pix_fmt->sizeimage) @@ -453,6 +445,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_H264; break; + case V4L2_PIX_FMT_HEVC_SLICE: + ctx->current_codec = CEDRUS_CODEC_H265; + break; + default: return -EINVAL; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.h b/drivers/staging/media/sunxi/cedrus/cedrus_video.h index 0e4f7a8cccf2..05050c0a0921 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.h @@ -26,5 +26,6 @@ extern const struct v4l2_ioctl_ops cedrus_ioctl_ops; int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq); +void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt); #endif diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h index 604e79cb6cbf..88c8b016eb09 100644 --- a/include/media/cec-pin.h +++ b/include/media/cec-pin.h @@ -29,8 +29,11 @@ * an error if negative. If NULL or -ENOTTY is returned, * then this is not supported. * - * These operations are used by the cec pin framework to manipulate - * the CEC pin. + * @received: optional. High-level CEC message callback. Allows the driver + * to process CEC messages. + * + * These operations (except for the @received op) are used by the + * cec pin framework to manipulate the CEC pin. */ struct cec_pin_ops { bool (*read)(struct cec_adapter *adap); @@ -42,6 +45,9 @@ struct cec_pin_ops { void (*status)(struct cec_adapter *adap, struct seq_file *file); int (*read_hpd)(struct cec_adapter *adap); int (*read_5v)(struct cec_adapter *adap); + + /* High-level CEC message callback */ + int (*received)(struct cec_adapter *adap, struct cec_msg *msg); }; /** diff --git a/include/media/cec.h b/include/media/cec.h index 4d59387bc61b..0a4f69cc9dd4 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -18,9 +18,6 @@ #include <linux/cec-funcs.h> #include <media/rc-core.h> -/* CEC_ADAP_G_CONNECTOR_INFO is available */ -#define CEC_CAP_CONNECTOR_INFO (1 << 8) - #define CEC_CAP_DEFAULTS (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | \ CEC_CAP_PASSTHROUGH | CEC_CAP_RC) @@ -147,34 +144,6 @@ struct cec_adap_ops { */ #define CEC_MAX_MSG_TX_QUEUE_SZ (18 * 1) -/** - * struct cec_drm_connector_info - tells which drm connector is - * associated with the CEC adapter. - * @card_no: drm card number - * @connector_id: drm connector ID - */ -struct cec_drm_connector_info { - __u32 card_no; - __u32 connector_id; -}; - -#define CEC_CONNECTOR_TYPE_NO_CONNECTOR 0 -#define CEC_CONNECTOR_TYPE_DRM 1 - -/** - * struct cec_connector_info - tells if and which connector is - * associated with the CEC adapter. - * @type: connector type (if any) - * @drm: drm connector info - */ -struct cec_connector_info { - __u32 type; - union { - struct cec_drm_connector_info drm; - __u32 raw[16]; - }; -}; - struct cec_adapter { struct module *owner; char name[32]; diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index 7ce4e8332421..1409230ad3a4 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -389,6 +389,7 @@ #define USB_PID_MYGICA_T230 0xc688 #define USB_PID_MYGICA_T230C 0xc689 #define USB_PID_MYGICA_T230C2 0xc68a +#define USB_PID_MYGICA_T230C_LITE 0xc699 #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h new file mode 100644 index 000000000000..1009cf0891cc --- /dev/null +++ b/include/media/hevc-ctrls.h @@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * These are the HEVC state controls for use with stateless HEVC + * codec drivers. + * + * It turns out that these structs are not stable yet and will undergo + * more changes. So keep them private until they are stable and ready to + * become part of the official public API. + */ + +#ifndef _HEVC_CTRLS_H_ +#define _HEVC_CTRLS_H_ + +#include <linux/videodev2.h> + +/* The pixel format isn't stable at the moment and will likely be renamed. */ +#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */ + +#define V4L2_CID_MPEG_VIDEO_HEVC_SPS (V4L2_CID_MPEG_BASE + 1008) +#define V4L2_CID_MPEG_VIDEO_HEVC_PPS (V4L2_CID_MPEG_BASE + 1009) +#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (V4L2_CID_MPEG_BASE + 1010) +#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (V4L2_CID_MPEG_BASE + 1015) +#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (V4L2_CID_MPEG_BASE + 1016) + +/* enum v4l2_ctrl_type type values */ +#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120 +#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121 +#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122 + +enum v4l2_mpeg_video_hevc_decode_mode { + V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED, + V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED, +}; + +enum v4l2_mpeg_video_hevc_start_code { + V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE, + V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B, +}; + +#define V4L2_HEVC_SLICE_TYPE_B 0 +#define V4L2_HEVC_SLICE_TYPE_P 1 +#define V4L2_HEVC_SLICE_TYPE_I 2 + +#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE (1ULL << 0) +#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED (1ULL << 1) +#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED (1ULL << 2) +#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET (1ULL << 3) +#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED (1ULL << 4) +#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED (1ULL << 5) +#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT (1ULL << 6) +#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED (1ULL << 7) +#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED (1ULL << 8) + +/* The controls are not stable at the moment and will likely be reworked. */ +struct v4l2_ctrl_hevc_sps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */ + __u16 pic_width_in_luma_samples; + __u16 pic_height_in_luma_samples; + __u8 bit_depth_luma_minus8; + __u8 bit_depth_chroma_minus8; + __u8 log2_max_pic_order_cnt_lsb_minus4; + __u8 sps_max_dec_pic_buffering_minus1; + __u8 sps_max_num_reorder_pics; + __u8 sps_max_latency_increase_plus1; + __u8 log2_min_luma_coding_block_size_minus3; + __u8 log2_diff_max_min_luma_coding_block_size; + __u8 log2_min_luma_transform_block_size_minus2; + __u8 log2_diff_max_min_luma_transform_block_size; + __u8 max_transform_hierarchy_depth_inter; + __u8 max_transform_hierarchy_depth_intra; + __u8 pcm_sample_bit_depth_luma_minus1; + __u8 pcm_sample_bit_depth_chroma_minus1; + __u8 log2_min_pcm_luma_coding_block_size_minus3; + __u8 log2_diff_max_min_pcm_luma_coding_block_size; + __u8 num_short_term_ref_pic_sets; + __u8 num_long_term_ref_pics_sps; + __u8 chroma_format_idc; + + __u8 padding; + + __u64 flags; +}; + +#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT (1ULL << 0) +#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT (1ULL << 1) +#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED (1ULL << 2) +#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT (1ULL << 3) +#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED (1ULL << 4) +#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED (1ULL << 5) +#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED (1ULL << 6) +#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7) +#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED (1ULL << 8) +#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED (1ULL << 9) +#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED (1ULL << 10) +#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED (1ULL << 11) +#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED (1ULL << 12) +#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED (1ULL << 13) +#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14) +#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED (1ULL << 15) +#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER (1ULL << 16) +#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT (1ULL << 17) +#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18) + +struct v4l2_ctrl_hevc_pps { + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */ + __u8 num_extra_slice_header_bits; + __s8 init_qp_minus26; + __u8 diff_cu_qp_delta_depth; + __s8 pps_cb_qp_offset; + __s8 pps_cr_qp_offset; + __u8 num_tile_columns_minus1; + __u8 num_tile_rows_minus1; + __u8 column_width_minus1[20]; + __u8 row_height_minus1[22]; + __s8 pps_beta_offset_div2; + __s8 pps_tc_offset_div2; + __u8 log2_parallel_merge_level_minus2; + + __u8 padding[4]; + __u64 flags; +}; + +#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE 0x01 +#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER 0x02 +#define V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR 0x03 + +#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16 + +struct v4l2_hevc_dpb_entry { + __u64 timestamp; + __u8 rps; + __u8 field_pic; + __u16 pic_order_cnt[2]; + __u8 padding[2]; +}; + +struct v4l2_hevc_pred_weight_table { + __s8 delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __s8 luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __s8 delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; + __s8 chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; + + __s8 delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __s8 luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __s8 delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; + __s8 chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]; + + __u8 padding[6]; + + __u8 luma_log2_weight_denom; + __s8 delta_chroma_log2_weight_denom; +}; + +#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA (1ULL << 0) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA (1ULL << 1) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO (1ULL << 3) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT (1ULL << 4) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0 (1ULL << 5) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV (1ULL << 6) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7) +#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8) + +struct v4l2_ctrl_hevc_slice_params { + __u32 bit_size; + __u32 data_bit_offset; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */ + __u8 nal_unit_type; + __u8 nuh_temporal_id_plus1; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u8 slice_type; + __u8 colour_plane_id; + __u16 slice_pic_order_cnt; + __u8 num_ref_idx_l0_active_minus1; + __u8 num_ref_idx_l1_active_minus1; + __u8 collocated_ref_idx; + __u8 five_minus_max_num_merge_cand; + __s8 slice_qp_delta; + __s8 slice_cb_qp_offset; + __s8 slice_cr_qp_offset; + __s8 slice_act_y_qp_offset; + __s8 slice_act_cb_qp_offset; + __s8 slice_act_cr_qp_offset; + __s8 slice_beta_offset_div2; + __s8 slice_tc_offset_div2; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */ + __u8 pic_struct; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u8 num_active_dpb_entries; + __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + + __u8 num_rps_poc_st_curr_before; + __u8 num_rps_poc_st_curr_after; + __u8 num_rps_poc_lt_curr; + + __u8 padding; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + struct v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; + + /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ + struct v4l2_hevc_pred_weight_table pred_weight_table; + + __u64 flags; +}; + +#endif diff --git a/include/media/i2c/smiapp.h b/include/media/i2c/smiapp.h index d6ccc859bfcd..80f8251d87a3 100644 --- a/include/media/i2c/smiapp.h +++ b/include/media/i2c/smiapp.h @@ -49,7 +49,6 @@ struct smiapp_hwconfig { unsigned short i2c_addr_dfl; /* Default i2c addr */ unsigned short i2c_addr_alt; /* Alternate i2c addr */ - uint32_t nvm_size; /* bytes */ uint32_t ext_clk; /* sensor external clk */ unsigned int lanes; /* Number of CSI-2 lanes */ diff --git a/include/media/rc-map.h b/include/media/rc-map.h index afd2ab31bdf2..f99575a0d29c 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -159,21 +159,22 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_ASUS_PS3_100 "rc-asus-ps3-100" #define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600" #define RC_MAP_ATI_X10 "rc-ati-x10" +#define RC_MAP_AVERMEDIA "rc-avermedia" #define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d" #define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" #define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" #define RC_MAP_AVERMEDIA_M135A "rc-avermedia-m135a" #define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6" #define RC_MAP_AVERMEDIA_RM_KS "rc-avermedia-rm-ks" -#define RC_MAP_AVERMEDIA "rc-avermedia" #define RC_MAP_AVERTV_303 "rc-avertv-303" #define RC_MAP_AZUREWAVE_AD_TU700 "rc-azurewave-ad-tu700" -#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" +#define RC_MAP_BEELINK_GS1 "rc-beelink-gs1" #define RC_MAP_BEHOLD "rc-behold" +#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" #define RC_MAP_CEC "rc-cec" -#define RC_MAP_CINERGY_1400 "rc-cinergy-1400" #define RC_MAP_CINERGY "rc-cinergy" +#define RC_MAP_CINERGY_1400 "rc-cinergy-1400" #define RC_MAP_D680_DMB "rc-d680-dmb" #define RC_MAP_DELOCK_61959 "rc-delock-61959" #define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec" @@ -181,17 +182,17 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_DIGITALNOW_TINYTWIN "rc-digitalnow-tinytwin" #define RC_MAP_DIGITTRADE "rc-digittrade" #define RC_MAP_DM1105_NEC "rc-dm1105-nec" -#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" +#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" #define RC_MAP_DTT200U "rc-dtt200u" #define RC_MAP_DVBSKY "rc-dvbsky" #define RC_MAP_DVICO_MCE "rc-dvico-mce" #define RC_MAP_DVICO_PORTABLE "rc-dvico-portable" #define RC_MAP_EMPTY "rc-empty" #define RC_MAP_EM_TERRATEC "rc-em-terratec" +#define RC_MAP_ENCORE_ENLTV "rc-encore-enltv" #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2" #define RC_MAP_ENCORE_ENLTV_FM53 "rc-encore-enltv-fm53" -#define RC_MAP_ENCORE_ENLTV "rc-encore-enltv" #define RC_MAP_EVGA_INDTUBE "rc-evga-indtube" #define RC_MAP_EZTV "rc-eztv" #define RC_MAP_FLYDVB "rc-flydvb" @@ -201,6 +202,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_GEEKBOX "rc-geekbox" #define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" #define RC_MAP_GOTVIEW7135 "rc-gotview7135" +#define RC_MAP_HAUPPAUGE "rc-hauppauge" #define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" #define RC_MAP_HISI_POPLAR "rc-hisi-poplar" #define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" @@ -223,8 +225,8 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_MEDION_X10_OR2X "rc-medion-x10-or2x" #define RC_MAP_MSI_DIGIVOX_II "rc-msi-digivox-ii" #define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii" -#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" #define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" +#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" #define RC_MAP_NEBULA "rc-nebula" #define RC_MAP_NEC_TERRATEC_CINERGY_XS "rc-nec-terratec-cinergy-xs" #define RC_MAP_NORWOOD "rc-norwood" @@ -234,21 +236,21 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" -#define RC_MAP_PIXELVIEW_NEW "rc-pixelview-new" #define RC_MAP_PIXELVIEW "rc-pixelview" -#define RC_MAP_PIXELVIEW_002T "rc-pixelview-002t" +#define RC_MAP_PIXELVIEW_002T "rc-pixelview-002t" #define RC_MAP_PIXELVIEW_MK12 "rc-pixelview-mk12" +#define RC_MAP_PIXELVIEW_NEW "rc-pixelview-new" #define RC_MAP_POWERCOLOR_REAL_ANGEL "rc-powercolor-real-angel" #define RC_MAP_PROTEUS_2309 "rc-proteus-2309" #define RC_MAP_PURPLETV "rc-purpletv" #define RC_MAP_PV951 "rc-pv951" -#define RC_MAP_HAUPPAUGE "rc-hauppauge" #define RC_MAP_RC5_TV "rc-rc5-tv" #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" #define RC_MAP_REDDO "rc-reddo" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" +#define RC_MAP_SU3000 "rc-su3000" #define RC_MAP_TANGO "rc-tango" #define RC_MAP_TANIX_TX3MINI "rc-tanix-tx3mini" #define RC_MAP_TANIX_TX5MAX "rc-tanix-tx5max" @@ -268,6 +270,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_TT_1500 "rc-tt-1500" #define RC_MAP_TWINHAN_DTV_CAB_CI "rc-twinhan-dtv-cab-ci" #define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027" +#define RC_MAP_VEGA_S9X "rc-vega-s9x" #define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" @@ -275,9 +278,8 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_WETEK_PLAY2 "rc-wetek-play2" #define RC_MAP_WINFAST "rc-winfast" #define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe" -#define RC_MAP_SU3000 "rc-su3000" -#define RC_MAP_XBOX_DVD "rc-xbox-dvd" #define RC_MAP_X96MAX "rc-x96max" +#define RC_MAP_XBOX_DVD "rc-xbox-dvd" #define RC_MAP_ZX_IRDEC "rc-zx-irdec" /* diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index c070d8ae11e5..d8c29e089000 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -457,8 +457,24 @@ int v4l2_s_parm_cap(struct video_device *vdev, /* Pixel format and FourCC helpers */ /** + * enum v4l2_pixel_encoding - specifies the pixel encoding value + * + * @V4L2_PIXEL_ENC_UNKNOWN: Pixel encoding is unknown/un-initialized + * @V4L2_PIXEL_ENC_YUV: Pixel encoding is YUV + * @V4L2_PIXEL_ENC_RGB: Pixel encoding is RGB + * @V4L2_PIXEL_ENC_BAYER: Pixel encoding is Bayer + */ +enum v4l2_pixel_encoding { + V4L2_PIXEL_ENC_UNKNOWN = 0, + V4L2_PIXEL_ENC_YUV = 1, + V4L2_PIXEL_ENC_RGB = 2, + V4L2_PIXEL_ENC_BAYER = 3, +}; + +/** * struct v4l2_format_info - information about a V4L2 format * @format: 4CC format identifier (V4L2_PIX_FMT_*) + * @pixel_enc: Pixel encoding (see enum v4l2_pixel_encoding above) * @mem_planes: Number of memory planes, which includes the alpha plane (1 to 4). * @comp_planes: Number of component planes, which includes the alpha plane (1 to 4). * @bpp: Array of per-plane bytes per pixel @@ -469,6 +485,7 @@ int v4l2_s_parm_cap(struct video_device *vdev, */ struct v4l2_format_info { u32 format; + u8 pixel_enc; u8 mem_planes; u8 comp_planes; u8 bpp[4]; @@ -478,8 +495,22 @@ struct v4l2_format_info { u8 block_h[4]; }; -const struct v4l2_format_info *v4l2_format_info(u32 format); +static inline bool v4l2_is_format_rgb(const struct v4l2_format_info *f) +{ + return f && f->pixel_enc == V4L2_PIXEL_ENC_RGB; +} +static inline bool v4l2_is_format_yuv(const struct v4l2_format_info *f) +{ + return f && f->pixel_enc == V4L2_PIXEL_ENC_YUV; +} + +static inline bool v4l2_is_format_bayer(const struct v4l2_format_info *f) +{ + return f && f->pixel_enc == V4L2_PIXEL_ENC_BAYER; +} + +const struct v4l2_format_info *v4l2_format_info(u32 format); void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, const struct v4l2_frmsize_stepwise *frmsize); int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 570ff4b0205a..7db9e719a583 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -21,6 +21,7 @@ #include <media/fwht-ctrls.h> #include <media/h264-ctrls.h> #include <media/vp8-ctrls.h> +#include <media/hevc-ctrls.h> /* forward references */ struct file; @@ -50,7 +51,12 @@ struct poll_table_struct; * @p_h264_slice_params: Pointer to a struct v4l2_ctrl_h264_slice_params. * @p_h264_decode_params: Pointer to a struct v4l2_ctrl_h264_decode_params. * @p_vp8_frame_header: Pointer to a VP8 frame header structure. + * @p_hevc_sps: Pointer to an HEVC sequence parameter set structure. + * @p_hevc_pps: Pointer to an HEVC picture parameter set structure. + * @p_hevc_slice_params: Pointer to an HEVC slice parameters structure. + * @p_area: Pointer to an area. * @p: Pointer to a compound value. + * @p_const: Pointer to a constant compound value. */ union v4l2_ctrl_ptr { s32 *p_s32; @@ -68,10 +74,27 @@ union v4l2_ctrl_ptr { struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; struct v4l2_ctrl_h264_decode_params *p_h264_decode_params; struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_hevc_sps *p_hevc_sps; + struct v4l2_ctrl_hevc_pps *p_hevc_pps; + struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_area *p_area; void *p; + const void *p_const; }; /** + * v4l2_ctrl_ptr_create() - Helper function to return a v4l2_ctrl_ptr from a + * void pointer + * @ptr: The void pointer + */ +static inline union v4l2_ctrl_ptr v4l2_ctrl_ptr_create(void *ptr) +{ + union v4l2_ctrl_ptr p = { .p = ptr }; + + return p; +} + +/** * struct v4l2_ctrl_ops - The control operations that the driver has to provide. * * @g_volatile_ctrl: Get a new value for this control. Generally only relevant @@ -200,6 +223,9 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv); * not freed when the control is deleted. Should this be needed * then a new internal bitfield can be added to tell the framework * to free this pointer. + * @p_def: The control's default value represented via a union which + * provides a standard way of accessing control types + * through a pointer (for compound controls only). * @p_cur: The control's current value represented via a union which * provides a standard way of accessing control types * through a pointer. @@ -254,6 +280,7 @@ struct v4l2_ctrl { s32 val; } cur; + union v4l2_ctrl_ptr p_def; union v4l2_ctrl_ptr p_new; union v4l2_ctrl_ptr p_cur; }; @@ -357,6 +384,7 @@ struct v4l2_ctrl_handler { * @max: The control's maximum value. * @step: The control's step value for non-menu controls. * @def: The control's default value. + * @p_def: The control's default value for compound controls. * @dims: The size of each dimension. * @elem_size: The size in bytes of the control. * @flags: The control's flags. @@ -385,6 +413,7 @@ struct v4l2_ctrl_config { s64 max; u64 step; s64 def; + union v4l2_ctrl_ptr p_def; u32 dims[V4L2_CTRL_MAX_DIMS]; u32 elem_size; u32 flags; @@ -647,6 +676,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, const char * const *qmenu); /** + * v4l2_ctrl_new_std_compound() - Allocate and initialize a new standard V4L2 + * compound control. + * + * @hdl: The control handler. + * @ops: The control ops. + * @id: The control ID. + * @p_def: The control's default value. + * + * Sames as v4l2_ctrl_new_std(), but with support to compound controls, thanks + * to the @p_def field. + * + */ +struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ops, + u32 id, + const union v4l2_ctrl_ptr p_def); + +/** * v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control. * * @hdl: The control handler. @@ -1065,6 +1112,46 @@ static inline int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) return rval; } +/** + * __v4l2_ctrl_s_ctrl_area() - Unlocked variant of v4l2_ctrl_s_ctrl_area(). + * + * @ctrl: The control. + * @area: The new area. + * + * This sets the control's new area safely by going through the control + * framework. This function assumes the control's handler is already locked, + * allowing it to be used from within the &v4l2_ctrl_ops functions. + * + * This function is for area type controls only. + */ +int __v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, + const struct v4l2_area *area); + +/** + * v4l2_ctrl_s_ctrl_area() - Helper function to set a control's area value + * from within a driver. + * + * @ctrl: The control. + * @area: The new area. + * + * This sets the control's new area safely by going through the control + * framework. This function will lock the control's handler, so it cannot be + * used from within the &v4l2_ctrl_ops functions. + * + * This function is for area type controls only. + */ +static inline int v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, + const struct v4l2_area *area) +{ + int rval; + + v4l2_ctrl_lock(ctrl); + rval = __v4l2_ctrl_s_ctrl_area(ctrl, area); + v4l2_ctrl_unlock(ctrl); + + return rval; +} + /* Internal helper functions that deal with control events. */ extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops; diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index e0b8f2602670..5f36e0d2ede6 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -72,7 +72,7 @@ static inline void v4l2_device_get(struct v4l2_device *v4l2_dev) } /** - * v4l2_device_put - putss a V4L2 device reference + * v4l2_device_put - puts a V4L2 device reference * * @v4l2_dev: pointer to struct &v4l2_device * diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 0b9c3a287061..1d85e24791e4 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -21,7 +21,8 @@ * callback. * The job does NOT have to end before this callback returns * (and it will be the usual case). When the job finishes, - * v4l2_m2m_job_finish() has to be called. + * v4l2_m2m_job_finish() or v4l2_m2m_buf_done_and_job_finish() + * has to be called. * @job_ready: optional. Should return 0 if the driver does not have a job * fully prepared to run yet (i.e. it will not be able to finish a * transaction without sleeping). If not provided, it will be @@ -33,7 +34,8 @@ * stop the device safely; e.g. in the next interrupt handler), * even if the transaction would not have been finished by then. * After the driver performs the necessary steps, it has to call - * v4l2_m2m_job_finish() (as if the transaction ended normally). + * v4l2_m2m_job_finish() or v4l2_m2m_buf_done_and_job_finish() as + * if the transaction ended normally. * This function does not have to (and will usually not) wait * until the device enters a state when it can be stopped. */ @@ -73,6 +75,11 @@ struct v4l2_m2m_queue_ctx { * struct v4l2_m2m_ctx - Memory to memory context structure * * @q_lock: struct &mutex lock + * @new_frame: valid in the device_run callback: if true, then this + * starts a new frame; if false, then this is a new slice + * for an existing frame. This is always true unless + * V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF is set, which + * indicates slicing support. * @m2m_dev: opaque pointer to the internal data to handle M2M context * @cap_q_ctx: Capture (output to memory) queue context * @out_q_ctx: Output (input from memory) queue context @@ -89,6 +96,8 @@ struct v4l2_m2m_ctx { /* optional cap/out vb2 queues lock */ struct mutex *q_lock; + bool new_frame; + /* internal use only */ struct v4l2_m2m_dev *m2m_dev; @@ -173,6 +182,33 @@ void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx); void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx); +/** + * v4l2_m2m_buf_done_and_job_finish() - return source/destination buffers with + * state and inform the framework that a job has been finished and have it + * clean up + * + * @m2m_dev: opaque pointer to the internal data to handle M2M context + * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx + * @state: vb2 buffer state passed to v4l2_m2m_buf_done(). + * + * Drivers that set V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF must use this + * function instead of job_finish() to take held buffers into account. It is + * optional for other drivers. + * + * This function removes the source buffer from the ready list and returns + * it with the given state. The same is done for the destination buffer, unless + * it is marked 'held'. In that case the buffer is kept on the ready list. + * + * After that the job is finished (see job_finish()). + * + * This allows for multiple output buffers to be used to fill in a single + * capture buffer. This is typically used by stateless decoders where + * multiple e.g. H.264 slices contribute to a single decoded frame. + */ +void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state); + static inline void v4l2_m2m_buf_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state) { @@ -672,6 +708,10 @@ int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec); int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc); +int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc); +int v4l2_m2m_ioctl_stateless_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *dc); int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma); __poll_t v4l2_m2m_fop_poll(struct file *file, poll_table *wait); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 640aabe69450..a2b2208b02da 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -505,6 +505,8 @@ struct vb2_buf_ops { * @buf_ops: callbacks to deliver buffer information. * between user-space and kernel-space. * @drv_priv: driver private data. + * @subsystem_flags: Flags specific to the subsystem (V4L2/DVB/etc.). Not used + * by the vb2 core. * @buf_struct_size: size of the driver-specific buffer structure; * "0" indicates the driver doesn't want to use a custom buffer * structure type. for example, ``sizeof(struct vb2_v4l2_buffer)`` @@ -571,6 +573,7 @@ struct vb2_queue { const struct vb2_buf_ops *buf_ops; void *drv_priv; + u32 subsystem_flags; unsigned int buf_struct_size; u32 timestamp_flags; gfp_t gfp_flags; diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h index 8a10889dc2fd..59bf33a12648 100644 --- a/include/media/videobuf2-v4l2.h +++ b/include/media/videobuf2-v4l2.h @@ -33,6 +33,7 @@ * @timecode: frame timecode. * @sequence: sequence count of this frame. * @request_fd: the request_fd associated with this buffer + * @is_held: if true, then this capture buffer was held * @planes: plane information (userptr/fd, length, bytesused, data_offset). * * Should contain enough information to be able to cover all the fields @@ -46,9 +47,13 @@ struct vb2_v4l2_buffer { struct v4l2_timecode timecode; __u32 sequence; __s32 request_fd; + bool is_held; struct vb2_plane planes[VB2_MAX_PLANES]; }; +/* VB2 V4L2 flags as set in vb2_queue.subsystem_flags */ +#define VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 0) + /* * to_vb2_v4l2_buffer() - cast struct vb2_buffer * to struct vb2_v4l2_buffer * */ diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h index 8997d5068c08..37590027b604 100644 --- a/include/uapi/linux/cec-funcs.h +++ b/include/uapi/linux/cec-funcs.h @@ -923,7 +923,8 @@ static inline void cec_msg_give_deck_status(struct cec_msg *msg, msg->len = 3; msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS; msg->msg[2] = status_req; - msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; + msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ? + CEC_MSG_DECK_STATUS : 0; } static inline void cec_ops_give_deck_status(const struct cec_msg *msg, @@ -1027,7 +1028,8 @@ static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, msg->len = 3; msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS; msg->msg[2] = status_req; - msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; + msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ? + CEC_MSG_TUNER_DEVICE_STATUS : 0; } static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg, @@ -1302,17 +1304,17 @@ static inline void cec_msg_user_control_pressed(struct cec_msg *msg, if (!ui_cmd->has_opt_arg) return; switch (ui_cmd->ui_cmd) { - case 0x56: - case 0x57: - case 0x60: - case 0x68: - case 0x69: - case 0x6a: + case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE: + case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION: + case CEC_OP_UI_CMD_PLAY_FUNCTION: + case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION: /* The optional operand is one byte for all these ui commands */ msg->len++; msg->msg[3] = ui_cmd->play_mode; break; - case 0x67: + case CEC_OP_UI_CMD_TUNE_FUNCTION: msg->len += 4; msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) | (ui_cmd->channel_identifier.major >> 8); @@ -1331,17 +1333,17 @@ static inline void cec_ops_user_control_pressed(const struct cec_msg *msg, if (msg->len == 3) return; switch (ui_cmd->ui_cmd) { - case 0x56: - case 0x57: - case 0x60: - case 0x68: - case 0x69: - case 0x6a: + case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE: + case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION: + case CEC_OP_UI_CMD_PLAY_FUNCTION: + case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION: + case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION: /* The optional operand is one byte for all these ui commands */ ui_cmd->play_mode = msg->msg[3]; ui_cmd->has_opt_arg = 1; break; - case 0x67: + case CEC_OP_UI_CMD_TUNE_FUNCTION: if (msg->len < 7) break; ui_cmd->has_opt_arg = 1; diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 5704fa0292b5..7d1a06c52469 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -317,6 +317,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask) #define CEC_CAP_NEEDS_HPD (1 << 6) /* Hardware can monitor CEC pin transitions */ #define CEC_CAP_MONITOR_PIN (1 << 7) +/* CEC_ADAP_G_CONNECTOR_INFO is available */ +#define CEC_CAP_CONNECTOR_INFO (1 << 8) /** * struct cec_caps - CEC capabilities structure. @@ -375,6 +377,34 @@ struct cec_log_addrs { /* CDC-Only device: supports only CDC messages */ #define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2) +/** + * struct cec_drm_connector_info - tells which drm connector is + * associated with the CEC adapter. + * @card_no: drm card number + * @connector_id: drm connector ID + */ +struct cec_drm_connector_info { + __u32 card_no; + __u32 connector_id; +}; + +#define CEC_CONNECTOR_TYPE_NO_CONNECTOR 0 +#define CEC_CONNECTOR_TYPE_DRM 1 + +/** + * struct cec_connector_info - tells if and which connector is + * associated with the CEC adapter. + * @type: connector type (if any) + * @drm: drm connector info + */ +struct cec_connector_info { + __u32 type; + union { + struct cec_drm_connector_info drm; + __u32 raw[16]; + }; +}; + /* Events */ /* Event that occurs when the adapter state changes */ @@ -398,10 +428,17 @@ struct cec_log_addrs { * struct cec_event_state_change - used when the CEC adapter changes state. * @phys_addr: the current physical address * @log_addr_mask: the current logical address mask + * @have_conn_info: if non-zero, then HDMI connector information is available. + * This field is only valid if CEC_CAP_CONNECTOR_INFO is set. If that + * capability is set and @have_conn_info is zero, then that indicates + * that the HDMI connector device is not instantiated, either because + * the HDMI driver is still configuring the device or because the HDMI + * device was unbound. */ struct cec_event_state_change { __u16 phys_addr; __u16 log_addr_mask; + __u16 have_conn_info; }; /** @@ -476,6 +513,9 @@ struct cec_event { #define CEC_G_MODE _IOR('a', 8, __u32) #define CEC_S_MODE _IOW('a', 9, __u32) +/* Get the connector info */ +#define CEC_ADAP_G_CONNECTOR_INFO _IOR('a', 10, struct cec_connector_info) + /* * The remainder of this header defines all CEC messages and operands. * The format matters since it the cec-ctl utility parses it to generate @@ -768,8 +808,8 @@ struct cec_event { #define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93 #define CEC_MSG_TUNER_DEVICE_STATUS 0x07 /* Recording Flag Operand (rec_flag) */ -#define CEC_OP_REC_FLAG_USED 0 -#define CEC_OP_REC_FLAG_NOT_USED 1 +#define CEC_OP_REC_FLAG_NOT_USED 0 +#define CEC_OP_REC_FLAG_USED 1 /* Tuner Display Info Operand (tuner_display_info) */ #define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0 #define CEC_OP_TUNER_DISPLAY_INFO_NONE 1 @@ -820,6 +860,95 @@ struct cec_event { #define CEC_OP_MENU_STATE_DEACTIVATED 0x01 #define CEC_MSG_USER_CONTROL_PRESSED 0x44 +/* UI Command Operand (ui_cmd) */ +#define CEC_OP_UI_CMD_SELECT 0x00 +#define CEC_OP_UI_CMD_UP 0x01 +#define CEC_OP_UI_CMD_DOWN 0x02 +#define CEC_OP_UI_CMD_LEFT 0x03 +#define CEC_OP_UI_CMD_RIGHT 0x04 +#define CEC_OP_UI_CMD_RIGHT_UP 0x05 +#define CEC_OP_UI_CMD_RIGHT_DOWN 0x06 +#define CEC_OP_UI_CMD_LEFT_UP 0x07 +#define CEC_OP_UI_CMD_LEFT_DOWN 0x08 +#define CEC_OP_UI_CMD_DEVICE_ROOT_MENU 0x09 +#define CEC_OP_UI_CMD_DEVICE_SETUP_MENU 0x0a +#define CEC_OP_UI_CMD_CONTENTS_MENU 0x0b +#define CEC_OP_UI_CMD_FAVORITE_MENU 0x0c +#define CEC_OP_UI_CMD_BACK 0x0d +#define CEC_OP_UI_CMD_MEDIA_TOP_MENU 0x10 +#define CEC_OP_UI_CMD_MEDIA_CONTEXT_SENSITIVE_MENU 0x11 +#define CEC_OP_UI_CMD_NUMBER_ENTRY_MODE 0x1d +#define CEC_OP_UI_CMD_NUMBER_11 0x1e +#define CEC_OP_UI_CMD_NUMBER_12 0x1f +#define CEC_OP_UI_CMD_NUMBER_0_OR_NUMBER_10 0x20 +#define CEC_OP_UI_CMD_NUMBER_1 0x21 +#define CEC_OP_UI_CMD_NUMBER_2 0x22 +#define CEC_OP_UI_CMD_NUMBER_3 0x23 +#define CEC_OP_UI_CMD_NUMBER_4 0x24 +#define CEC_OP_UI_CMD_NUMBER_5 0x25 +#define CEC_OP_UI_CMD_NUMBER_6 0x26 +#define CEC_OP_UI_CMD_NUMBER_7 0x27 +#define CEC_OP_UI_CMD_NUMBER_8 0x28 +#define CEC_OP_UI_CMD_NUMBER_9 0x29 +#define CEC_OP_UI_CMD_DOT 0x2a +#define CEC_OP_UI_CMD_ENTER 0x2b +#define CEC_OP_UI_CMD_CLEAR 0x2c +#define CEC_OP_UI_CMD_NEXT_FAVORITE 0x2f +#define CEC_OP_UI_CMD_CHANNEL_UP 0x30 +#define CEC_OP_UI_CMD_CHANNEL_DOWN 0x31 +#define CEC_OP_UI_CMD_PREVIOUS_CHANNEL 0x32 +#define CEC_OP_UI_CMD_SOUND_SELECT 0x33 +#define CEC_OP_UI_CMD_INPUT_SELECT 0x34 +#define CEC_OP_UI_CMD_DISPLAY_INFORMATION 0x35 +#define CEC_OP_UI_CMD_HELP 0x36 +#define CEC_OP_UI_CMD_PAGE_UP 0x37 +#define CEC_OP_UI_CMD_PAGE_DOWN 0x38 +#define CEC_OP_UI_CMD_POWER 0x40 +#define CEC_OP_UI_CMD_VOLUME_UP 0x41 +#define CEC_OP_UI_CMD_VOLUME_DOWN 0x42 +#define CEC_OP_UI_CMD_MUTE 0x43 +#define CEC_OP_UI_CMD_PLAY 0x44 +#define CEC_OP_UI_CMD_STOP 0x45 +#define CEC_OP_UI_CMD_PAUSE 0x46 +#define CEC_OP_UI_CMD_RECORD 0x47 +#define CEC_OP_UI_CMD_REWIND 0x48 +#define CEC_OP_UI_CMD_FAST_FORWARD 0x49 +#define CEC_OP_UI_CMD_EJECT 0x4a +#define CEC_OP_UI_CMD_SKIP_FORWARD 0x4b +#define CEC_OP_UI_CMD_SKIP_BACKWARD 0x4c +#define CEC_OP_UI_CMD_STOP_RECORD 0x4d +#define CEC_OP_UI_CMD_PAUSE_RECORD 0x4e +#define CEC_OP_UI_CMD_ANGLE 0x50 +#define CEC_OP_UI_CMD_SUB_PICTURE 0x51 +#define CEC_OP_UI_CMD_VIDEO_ON_DEMAND 0x52 +#define CEC_OP_UI_CMD_ELECTRONIC_PROGRAM_GUIDE 0x53 +#define CEC_OP_UI_CMD_TIMER_PROGRAMMING 0x54 +#define CEC_OP_UI_CMD_INITIAL_CONFIGURATION 0x55 +#define CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE 0x56 +#define CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION 0x57 +#define CEC_OP_UI_CMD_AUDIO_DESCRIPTION 0x58 +#define CEC_OP_UI_CMD_INTERNET 0x59 +#define CEC_OP_UI_CMD_3D_MODE 0x5a +#define CEC_OP_UI_CMD_PLAY_FUNCTION 0x60 +#define CEC_OP_UI_CMD_PAUSE_PLAY_FUNCTION 0x61 +#define CEC_OP_UI_CMD_RECORD_FUNCTION 0x62 +#define CEC_OP_UI_CMD_PAUSE_RECORD_FUNCTION 0x63 +#define CEC_OP_UI_CMD_STOP_FUNCTION 0x64 +#define CEC_OP_UI_CMD_MUTE_FUNCTION 0x65 +#define CEC_OP_UI_CMD_RESTORE_VOLUME_FUNCTION 0x66 +#define CEC_OP_UI_CMD_TUNE_FUNCTION 0x67 +#define CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION 0x68 +#define CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION 0x69 +#define CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION 0x6a +#define CEC_OP_UI_CMD_POWER_TOGGLE_FUNCTION 0x6b +#define CEC_OP_UI_CMD_POWER_OFF_FUNCTION 0x6c +#define CEC_OP_UI_CMD_POWER_ON_FUNCTION 0x6d +#define CEC_OP_UI_CMD_F1_BLUE 0x71 +#define CEC_OP_UI_CMD_F2_RED 0x72 +#define CEC_OP_UI_CMD_F3_GREEN 0x73 +#define CEC_OP_UI_CMD_F4_YELLOW 0x74 +#define CEC_OP_UI_CMD_F5 0x75 +#define CEC_OP_UI_CMD_DATA 0x76 /* UI Broadcast Type Operand (ui_bcast_type) */ #define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00 #define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01 diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index a2669b79b294..5a7bedee2b0e 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -1034,6 +1034,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_GREENR (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 5) #define V4L2_CID_TEST_PATTERN_BLUE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 6) #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) +#define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) /* Image processing controls */ diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 530638dffd93..04481c717fee 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -422,6 +422,11 @@ struct v4l2_fract { __u32 denominator; }; +struct v4l2_area { + __u32 width; + __u32 height; +}; + /** * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP * @@ -755,6 +760,7 @@ struct v4l2_pix_format { #define V4L2_META_FMT_VSP1_HGT v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */ #define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */ #define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */ +#define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */ /* priv field value to indicates that subsequent fields are valid. */ #define V4L2_PIX_FMT_PRIV_MAGIC 0xfeedcafe @@ -915,11 +921,12 @@ struct v4l2_requestbuffers { }; /* capabilities for struct v4l2_requestbuffers and v4l2_create_buffers */ -#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0) -#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1) -#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2) -#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3) -#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) +#define V4L2_BUF_CAP_SUPPORTS_MMAP (1 << 0) +#define V4L2_BUF_CAP_SUPPORTS_USERPTR (1 << 1) +#define V4L2_BUF_CAP_SUPPORTS_DMABUF (1 << 2) +#define V4L2_BUF_CAP_SUPPORTS_REQUESTS (1 << 3) +#define V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS (1 << 4) +#define V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF (1 << 5) /** * struct v4l2_plane - plane info for multi-planar buffers @@ -1041,6 +1048,8 @@ static inline __u64 v4l2_timeval_to_ns(const struct timeval *tv) #define V4L2_BUF_FLAG_IN_REQUEST 0x00000080 /* timecode field is valid */ #define V4L2_BUF_FLAG_TIMECODE 0x00000100 +/* Don't return the capture buffer until OUTPUT timestamp changes */ +#define V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF 0x00000200 /* Buffer is prepared for queuing */ #define V4L2_BUF_FLAG_PREPARED 0x00000400 /* Cache handling flags */ @@ -1675,6 +1684,7 @@ struct v4l2_ext_control { __u8 __user *p_u8; __u16 __user *p_u16; __u32 __user *p_u32; + struct v4l2_area __user *p_area; void __user *ptr; }; } __attribute__ ((packed)); @@ -1720,6 +1730,7 @@ enum v4l2_ctrl_type { V4L2_CTRL_TYPE_U8 = 0x0100, V4L2_CTRL_TYPE_U16 = 0x0101, V4L2_CTRL_TYPE_U32 = 0x0102, + V4L2_CTRL_TYPE_AREA = 0x0106, }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ @@ -1975,6 +1986,7 @@ struct v4l2_encoder_cmd { #define V4L2_DEC_CMD_STOP (1) #define V4L2_DEC_CMD_PAUSE (2) #define V4L2_DEC_CMD_RESUME (3) +#define V4L2_DEC_CMD_FLUSH (4) /* Flags for V4L2_DEC_CMD_START */ #define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) |