linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] support of v4l2 encoder for STMicroelectronics SOC.
@ 2015-12-18 10:45 Yannick Fertre
  2015-12-18 10:45 ` [PATCH 1/3] Documentation: devicetree: add STI HVA binding Yannick Fertre
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Yannick Fertre @ 2015-12-18 10:45 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Gaignard, hugues.fruchet, kernel

version 1:
	- Initial submission.

Only one feature supported and tested:
- encode (RGB32, RGB24, RGB16, NV12, NV21, UYVY, VYUY) to h264 video format

The driver is mainly implemented across three files:
- hva-v4l2.c
- hva-h264.c
- hva-hw.c
hva-v4l2.c manages the V4L2 interface with the userland.
It calls the HW services that are implemented in hva-hw.c.
hva-h264.c manages specific part of h264 codec.

Below is the v4l2-compliance report for the sti hva driver.
Note: using patched v4l2-compliance:
"v4l2-compliance: test SELECTION only for the supported buf_type"

root@st-next:/# ./v4l2-compliance 
Driver Info:
        Driver name   : 8c85000.hva
        Card type     : 8c85000.hva
        Bus info      : platform:hva
        Driver version: 4.4.0
        Capabilities  : 0x84208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps   : 0x04208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second video open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
        test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

        Control ioctls:
                test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
                test VIDIOC_QUERYCTRL: OK (Not Supported)
                test VIDIOC_G/S_CTRL: OK
                test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
                test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
                test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
                Standard Controls: 0 Private Controls: 0

        Format ioctls:
                test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
                test VIDIOC_G/S_PARM: OK
                test VIDIOC_G_FBUF: OK (Not Supported)
                test VIDIOC_G_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_TRY_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_S_FMT: OK
                test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
                test Cropping: OK
                test Composing: OK (Not Supported)
                fail: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(1435): doioctl(node, VIDIOC_S_FMT, &fmt)
                test Scaling: OK

        Codec ioctls:
                test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
                test VIDIOC_G_ENC_INDEX: OK (Not Supported)
                test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

        Buffer ioctls:
                test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
                test VIDIOC_EXPBUF: OK

Test input 0:


Total: 42, Succeeded: 42, Failed: 0, Warnings: 12

root@st-next:/# ./v4l2-compliance -f
Driver Info:
        Driver name   : 8c85000.hva
        Card type     : 8c85000.hva
        Bus info      : platform:hva
        Driver version: 4.4.0
        Capabilities  : 0x84208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps   : 0x04208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second video open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
        test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

        Control ioctls:
                test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
                test VIDIOC_QUERYCTRL: OK (Not Supported)
                test VIDIOC_G/S_CTRL: OK
                test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
                test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
                test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
                Standard Controls: 0 Private Controls: 0

        Format ioctls:
                test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
                test VIDIOC_G/S_PARM: OK
                test VIDIOC_G_FBUF: OK (Not Supported)
                test VIDIOC_G_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_TRY_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_S_FMT: OK
                test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
                test Cropping: OK
                test Composing: OK (Not Supported)
                fail: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(1435): doioctl(node, VIDIOC_S_FMT, &fmt)
                test Scaling: OK

        Codec ioctls:
                test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
                test VIDIOC_G_ENC_INDEX: OK (Not Supported)
                test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

        Buffer ioctls:
                test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
                test VIDIOC_EXPBUF: OK

Test input 0:

Stream using all formats:
        Not supported for M2M devices

Total: 42, Succeeded: 42, Failed: 0, Warnings: 12

root@st-next:/# ./v4l2-compliance -s
Driver Info:
        Driver name   : 8c85000.hva
        Card type     : 8c85000.hva
        Bus info      : platform:hva
        Driver version: 4.4.0
        Capabilities  : 0x84208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps   : 0x04208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format

Compliance test for device /dev/video0 (not using libv4l2):

Required ioctls:
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second video open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK

Debug ioctls:
        test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
        test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
        test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
        test VIDIOC_ENUMAUDIO: OK (Not Supported)
        test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDIO: OK (Not Supported)
        Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
        test VIDIOC_G/S_MODULATOR: OK (Not Supported)
        test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
        test VIDIOC_ENUMAUDOUT: OK (Not Supported)
        test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
        test VIDIOC_G/S_AUDOUT: OK (Not Supported)
        Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
        test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
        test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
        test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
        test VIDIOC_G/S_EDID: OK (Not Supported)

        Control ioctls:
                test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
                test VIDIOC_QUERYCTRL: OK (Not Supported)
                test VIDIOC_G/S_CTRL: OK
                test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
                test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
                test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
                Standard Controls: 0 Private Controls: 0

        Format ioctls:
                test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
                test VIDIOC_G/S_PARM: OK
                test VIDIOC_G_FBUF: OK (Not Supported)
                test VIDIOC_G_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(707): TRY_FMT cannot handle an invalid pixelformat
.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(708): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(709): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_TRY_FMT: OK
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(923): S_FMT cannot handle an invalid pixelformat.
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(924): This may or may not be a problem. For more i
nformation see:
                warn: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(925): http://www.mail-archive.com/linux-media@vger
.kernel.org/msg56550.html
                test VIDIOC_S_FMT: OK
                test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
                test Cropping: OK
                test Composing: OK (Not Supported)
                fail: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-formats.cpp(1435): doioctl(node, VIDIOC_S_FMT, &fmt)
                test Scaling: OK

        Codec ioctls:
                test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
                test VIDIOC_G_ENC_INDEX: OK (Not Supported)
                test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

        Buffer ioctls:
                test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
                test VIDIOC_EXPBUF: OK

Test input 0:

Streaming ioctls:
        test read/write: OK (Not Supported)
                fail: /local/frq07647/views/opensdk-1.0.4/sources/v4l-utils/utils/v4l2-compliance/v4l2-test-buffers.cpp(948): ret != EINVAL
        test MMAP: FAIL
        test USERPTR: OK (Not Supported)
        test DMABUF: Cannot test, specify --expbuf-device


Total: 45, Succeeded: 44, Failed: 1, Warnings: 12


Yannick Fertre (3):
  Documentation: devicetree: add STI HVA binding
  [media] hva: STiH41x multi-format video encoder V4L2 driver
  [media] hva: add h264 support

 .../devicetree/bindings/media/st,sti-hva.txt       |   26 +
 drivers/media/platform/Kconfig                     |   13 +
 drivers/media/platform/Makefile                    |    1 +
 drivers/media/platform/sti/hva/Makefile            |    2 +
 drivers/media/platform/sti/hva/hva-h264.c          | 1225 ++++++++++++++++
 drivers/media/platform/sti/hva/hva-hw.c            |  561 +++++++
 drivers/media/platform/sti/hva/hva-hw.h            |   76 +
 drivers/media/platform/sti/hva/hva-mem.c           |   63 +
 drivers/media/platform/sti/hva/hva-mem.h           |   20 +
 drivers/media/platform/sti/hva/hva-v4l2.c          | 1530 ++++++++++++++++++++
 drivers/media/platform/sti/hva/hva.h               |  499 +++++++
 11 files changed, 4016 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/st,sti-hva.txt
 create mode 100644 drivers/media/platform/sti/hva/Makefile
 create mode 100644 drivers/media/platform/sti/hva/hva-h264.c
 create mode 100644 drivers/media/platform/sti/hva/hva-hw.c
 create mode 100644 drivers/media/platform/sti/hva/hva-hw.h
 create mode 100644 drivers/media/platform/sti/hva/hva-mem.c
 create mode 100644 drivers/media/platform/sti/hva/hva-mem.h
 create mode 100644 drivers/media/platform/sti/hva/hva-v4l2.c
 create mode 100644 drivers/media/platform/sti/hva/hva.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] Documentation: devicetree: add STI HVA binding
  2015-12-18 10:45 [PATCH 0/3] support of v4l2 encoder for STMicroelectronics SOC Yannick Fertre
@ 2015-12-18 10:45 ` Yannick Fertre
  2015-12-18 10:45 ` [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver Yannick Fertre
  2015-12-18 10:45 ` [PATCH 3/3] [media] hva: add h264 support Yannick Fertre
  2 siblings, 0 replies; 6+ messages in thread
From: Yannick Fertre @ 2015-12-18 10:45 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Gaignard, hugues.fruchet, kernel

This patch documents DT compatible string "st,st-hva".

Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
---
 .../devicetree/bindings/media/st,sti-hva.txt       | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/st,sti-hva.txt

diff --git a/Documentation/devicetree/bindings/media/st,sti-hva.txt b/Documentation/devicetree/bindings/media/st,sti-hva.txt
new file mode 100644
index 0000000..3dc431d
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/st,sti-hva.txt
@@ -0,0 +1,26 @@
+==============================================================================
+        hva: hardware video encoder accelerator
+==============================================================================
+
+Required properties:
+- compatible: should be "st,stih407-hva".
+- reg: HVA physical address location and length, esram address location and
+  length.
+- reg-names: names of the registers listed in registers property in the same
+  order.
+- interrupts: HVA interrupt number.
+- clocks: from common clock binding: handle hardware IP needed clocks, the
+  number of clocks may depend on the SoC type.
+  See ../clock/clock-bindings.txt for details.
+- clock-names: names of the clocks listed in clocks property in the same order.
+
+Example:
+
+hva@8c85000{
+	compatible = "st,stih407-hva";
+	reg= <0x8c85000 0x400>, <0x6000000 0x40000>;
+	reg-names = "hva_registers", "hva_esram";
+	interrupts = <0 58 0>, <0 59 0>;
+	clock-names = "clk_hva";
+	clocks = <&CLK_S_C0_FLEXGEN 3>;
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver
  2015-12-18 10:45 [PATCH 0/3] support of v4l2 encoder for STMicroelectronics SOC Yannick Fertre
  2015-12-18 10:45 ` [PATCH 1/3] Documentation: devicetree: add STI HVA binding Yannick Fertre
@ 2015-12-18 10:45 ` Yannick Fertre
  2015-12-18 11:42   ` kbuild test robot
  2016-01-11 10:10   ` Hans Verkuil
  2015-12-18 10:45 ` [PATCH 3/3] [media] hva: add h264 support Yannick Fertre
  2 siblings, 2 replies; 6+ messages in thread
From: Yannick Fertre @ 2015-12-18 10:45 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Gaignard, hugues.fruchet, kernel

This patch adds HVA (Hardware Video Accelerator) support for STI platform.

Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
---
 drivers/media/platform/Kconfig            |   13 +
 drivers/media/platform/Makefile           |    1 +
 drivers/media/platform/sti/hva/Makefile   |    2 +
 drivers/media/platform/sti/hva/hva-hw.c   |  561 ++++++++++++
 drivers/media/platform/sti/hva/hva-hw.h   |   76 ++
 drivers/media/platform/sti/hva/hva-mem.c  |   63 ++
 drivers/media/platform/sti/hva/hva-mem.h  |   20 +
 drivers/media/platform/sti/hva/hva-v4l2.c | 1404 +++++++++++++++++++++++++++++
 drivers/media/platform/sti/hva/hva.h      |  499 ++++++++++
 9 files changed, 2639 insertions(+)
 create mode 100644 drivers/media/platform/sti/hva/Makefile
 create mode 100644 drivers/media/platform/sti/hva/hva-hw.c
 create mode 100644 drivers/media/platform/sti/hva/hva-hw.h
 create mode 100644 drivers/media/platform/sti/hva/hva-mem.c
 create mode 100644 drivers/media/platform/sti/hva/hva-mem.h
 create mode 100644 drivers/media/platform/sti/hva/hva-v4l2.c
 create mode 100644 drivers/media/platform/sti/hva/hva.h

diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 5263594..50b5f83 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -221,6 +221,19 @@ config VIDEO_STI_BDISP
 	help
 	  This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC.
 
+config VIDEO_STI_HVA
+	tristate "STMicroelectronics STiH41x HVA multi-format video encoder V4L2 driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_STI || COMPILE_TEST
+	select VIDEOBUF2_DMA_CONTIG
+	help
+	  This V4L2 driver enables HVA multi-format video encoder of
+	  STMicroelectronics SoC STiH41x series, allowing hardware encoding of raw
+	  uncompressed formats in various compressed video & jpeg bitstreams format.
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called hva.
+
 config VIDEO_SH_VEU
 	tristate "SuperH VEU mem2mem video processing driver"
 	depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index efa0295..d7740d8 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D)	+= s5p-g2d/
 obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC)	+= exynos-gsc/
 
 obj-$(CONFIG_VIDEO_STI_BDISP)		+= sti/bdisp/
+obj-$(CONFIG_VIDEO_STI_HVA)		+= sti/hva/
 obj-$(CONFIG_DVB_C8SECTPFE)		+= sti/c8sectpfe/
 
 obj-$(CONFIG_BLACKFIN)                  += blackfin/
diff --git a/drivers/media/platform/sti/hva/Makefile b/drivers/media/platform/sti/hva/Makefile
new file mode 100644
index 0000000..7022a33
--- /dev/null
+++ b/drivers/media/platform/sti/hva/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_STI_HVA) := hva.o
+hva-y := hva-v4l2.o hva-hw.o hva-mem.o
diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c
new file mode 100644
index 0000000..00b915b
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-hw.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#include "hva.h"
+#include "hva-hw.h"
+
+/* HVA register offsets */
+#define HVA_HIF_REG_RST                 0x0100U
+#define HVA_HIF_REG_RST_ACK             0x0104U
+#define HVA_HIF_REG_MIF_CFG             0x0108U
+#define HVA_HIF_REG_HEC_MIF_CFG         0x010CU
+#define HVA_HIF_REG_CFL                 0x0110U
+#define HVA_HIF_FIFO_CMD                0x0114U
+#define HVA_HIF_FIFO_STS                0x0118U
+#define HVA_HIF_REG_SFL                 0x011CU
+#define HVA_HIF_REG_IT_ACK              0x0120U
+#define HVA_HIF_REG_ERR_IT_ACK          0x0124U
+#define HVA_HIF_REG_LMI_ERR             0x0128U
+#define HVA_HIF_REG_EMI_ERR             0x012CU
+#define HVA_HIF_REG_HEC_MIF_ERR         0x0130U
+#define HVA_HIF_REG_HEC_STS             0x0134U
+#define HVA_HIF_REG_HVC_STS             0x0138U
+#define HVA_HIF_REG_HJE_STS             0x013CU
+#define HVA_HIF_REG_CNT                 0x0140U
+#define HVA_HIF_REG_HEC_CHKSYN_DIS      0x0144U
+#define HVA_HIF_REG_CLK_GATING          0x0148U
+#define HVA_HIF_REG_VERSION             0x014CU
+#define HVA_HIF_REG_BSM                 0x0150U
+
+/* define value for version id register (HVA_HIF_REG_VERSION) */
+#define VERSION_ID_MASK	0x0000FFFF
+
+/* define values for BSM register (HVA_HIF_REG_BSM) */
+#define BSM_CFG_VAL1	0x0003F000
+#define BSM_CFG_VAL2	0x003F0000
+
+/* define values for memory interface register (HVA_HIF_REG_MIF_CFG) */
+#define MIF_CFG_VAL1	0x04460446
+#define MIF_CFG_VAL2	0x04460806
+#define MIF_CFG_VAL3	0x00000000
+
+/* define value for HEC memory interface register (HVA_HIF_REG_MIF_CFG) */
+#define HEC_MIF_CFG_VAL	0x000000C4
+
+/*  Bits definition for clock gating register (HVA_HIF_REG_CLK_GATING) */
+#define CLK_GATING_HVC	BIT(0)
+#define CLK_GATING_HEC	BIT(1)
+#define CLK_GATING_HJE	BIT(2)
+
+/* fix hva clock rate */
+#define CLK_RATE		300000000
+
+/* fix delay for pmruntime */
+#define AUTOSUSPEND_DELAY_MS	3
+
+static irqreturn_t hva_hw_its_interrupt(int irq, void *data)
+{
+	struct hva_device *hva = data;
+
+	/* read status registers */
+	hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS);
+	hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL);
+
+	/* acknowledge interruption */
+	writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t hva_hw_its_irq_thread(int irq, void *arg)
+{
+	struct hva_device *hva = arg;
+	struct device *dev = hva_to_dev(hva);
+	u32 status = hva->sts_reg & 0xFF;
+	u8 client_id = (hva->sts_reg & 0xFF00) >> 8;
+	struct hva_ctx *ctx = NULL;
+
+	dev_dbg(dev, "%s     %s: status :0x%02x fifo level :0x%02x\n",
+		HVA_PREFIX, __func__, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF);
+
+	/* check client ID */
+	if (client_id >= MAX_CONTEXT) {
+		dev_err(dev, "%s     %s: bad client identifier: %d\n",
+			ctx->name, __func__, client_id);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		goto out;
+	}
+
+	ctx = hva->contexts_list[client_id];
+
+	switch (status) {
+	case NO_ERROR:
+		dev_dbg(dev, "%s     %s: no error\n",
+			ctx->name, __func__);
+		ctx->hw_err = false;
+		break;
+	case H264_SLICE_READY:
+		dev_dbg(dev, "%s     %s: h264 slice ready\n",
+			ctx->name, __func__);
+		ctx->hw_err = false;
+		break;
+	case H264_FRAME_SKIPPED:
+		dev_dbg(dev, "%s     %s: h264 frame skipped\n",
+			ctx->name, __func__);
+		ctx->hw_err = false;
+		break;
+	case JPEG_BITSTREAM_OVERSIZE:
+		dev_err(dev, "%s     %s:jpeg bitstream oversize\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case H264_BITSTREAM_OVERSIZE:
+		dev_err(dev, "%s     %s:h264 bitstream oversize\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case H264_SLICE_LIMIT_SIZE:
+		dev_err(dev, "%s     %s: h264 slice limit size is reached\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case H264_MAX_SLICE_NUMBER:
+		dev_err(dev, "%s     %s: h264 max slice number is reached\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case TASK_LIST_FULL:
+		dev_err(dev, "%s     %s:task list full\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case UNKNOWN_COMMAND:
+		dev_err(dev, "%s     %s:command not known\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	case WRONG_CODEC_OR_RESOLUTION:
+		dev_err(dev, "%s     %s:wrong codec or resolution\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	default:
+		dev_err(dev, "%s     %s:status not recognized\n",
+			ctx->name, __func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+		break;
+	}
+out:
+	complete(&hva->interrupt);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t hva_hw_err_interrupt(int irq, void *data)
+{
+	struct hva_device *hva = data;
+
+	/* read status registers */
+	hva->sts_reg = readl_relaxed(hva->regs + HVA_HIF_FIFO_STS);
+	hva->sfl_reg = readl_relaxed(hva->regs + HVA_HIF_REG_SFL);
+
+	/* read error registers */
+	hva->lmi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_LMI_ERR);
+	hva->emi_err_reg = readl_relaxed(hva->regs + HVA_HIF_REG_EMI_ERR);
+	hva->hec_mif_err_reg = readl_relaxed(hva->regs +
+					     HVA_HIF_REG_HEC_MIF_ERR);
+
+	/* acknowledge interruption */
+	writel_relaxed(0x1, hva->regs + HVA_HIF_REG_IT_ACK);
+
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t hva_hw_err_irq_thread(int irq, void *arg)
+{
+	struct hva_device *hva = arg;
+	struct device *dev = hva_to_dev(hva);
+	u8 client_id = 0;
+	struct hva_ctx *ctx;
+
+	dev_dbg(dev, "%s     status :0x%02x fifo level :0x%02x\n",
+		HVA_PREFIX, hva->sts_reg & 0xFF, hva->sfl_reg & 0xF);
+
+	/* check client ID */
+	client_id = (hva->sts_reg & 0xFF00) >> 8;
+	if (client_id >= MAX_CONTEXT) {
+		dev_err(dev, "%s     bad client identifier: %d\n", HVA_PREFIX,
+			client_id);
+		goto out;
+	}
+
+	ctx = hva->contexts_list[client_id];
+
+	if (hva->lmi_err_reg) {
+		dev_err(dev, "%s     local memory interface error :0x%08x\n",
+			ctx->name, hva->lmi_err_reg);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+	}
+
+	if (hva->lmi_err_reg) {
+		dev_err(dev, "%s     external memory iterface error :0x%08x\n",
+			ctx->name, hva->emi_err_reg);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+	}
+
+	if (hva->hec_mif_err_reg) {
+		dev_err(dev, "%s     hec memory interface error :0x%08x\n",
+			ctx->name, hva->hec_mif_err_reg);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+	}
+out:
+	complete(&hva->interrupt);
+
+	return IRQ_HANDLED;
+}
+
+static unsigned long int hva_hw_get_chipset_id(struct hva_device *hva)
+{
+	struct device *dev = hva_to_dev(hva);
+	unsigned long int id;
+
+	mutex_lock(&hva->protect_mutex);
+
+	if (pm_runtime_get_sync(dev) < 0) {
+		dev_err(dev, "%s     get pm_runtime failed\n", HVA_PREFIX);
+		mutex_unlock(&hva->protect_mutex);
+		return -EFAULT;
+	}
+
+	id = readl_relaxed(hva->regs + HVA_HIF_REG_VERSION) &
+			   VERSION_ID_MASK;
+
+	pm_runtime_put_autosuspend(dev);
+
+	mutex_unlock(&hva->protect_mutex);
+
+	switch (id) {
+	case HVA_VERSION_V400:
+	case HVA_VERSION_V397:
+		dev_info(dev, "%s     chipset identifier 0x%lx\n",
+			 HVA_PREFIX, id);
+		break;
+	default:
+		dev_err(dev, "%s     unknown chipset identifier 0x%lx\n",
+			HVA_PREFIX, id);
+		id = HVA_VERSION_UNKNOWN;
+		break;
+	}
+
+	return id;
+}
+
+int hva_hw_probe(struct platform_device *pdev, struct hva_device *hva)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *regs;
+	struct resource *esram;
+	int irq = 0;
+	int ret = 0;
+
+	WARN_ON(!hva);
+	hva->pdev = pdev;
+	hva->dev = dev;
+
+	/* get a memory region for mmio */
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hva->regs = devm_ioremap_resource(dev, regs);
+	if (IS_ERR_OR_NULL(hva->regs)) {
+		dev_err(dev, "%s     failed to get regs\n", HVA_PREFIX);
+		return PTR_ERR(hva->regs);
+	}
+
+	/* get a memory region for esram from device tree */
+	esram = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (IS_ERR_OR_NULL(esram)) {
+		dev_err(dev, "%s     failed to get esram region\n", HVA_PREFIX);
+		return PTR_ERR(esram);
+	}
+
+	hva->esram_addr = esram->start;
+	hva->esram_size = esram->end - esram->start + 1;
+
+	/* get clock resource */
+	hva->clk = devm_clk_get(dev, "clk_hva");
+	if (IS_ERR(hva->clk)) {
+		dev_err(dev, "%s     failed to get clock\n", HVA_PREFIX);
+		return PTR_ERR(hva->clk);
+	}
+
+	ret = clk_prepare(hva->clk);
+	if (ret < 0) {
+		dev_err(dev, "%s     failed to prepare clock\n", HVA_PREFIX);
+		hva->clk = ERR_PTR(-EINVAL);
+		return ret;
+	}
+
+	/* retrieve irq number from board resources */
+	hva->irq_its = platform_get_irq(pdev, 0);
+	if (!hva->irq_its) {
+		dev_err(dev, "%s     failed to get IRQ resource\n", HVA_PREFIX);
+		goto err_clk;
+	}
+
+	/* request irq */
+	ret = devm_request_threaded_irq(dev, hva->irq_its, hva_hw_its_interrupt,
+					hva_hw_its_irq_thread,
+					IRQF_ONESHOT,
+					"hva_its_irq", (void *)hva);
+	if (ret) {
+		dev_err(dev, "%s     failed to register its IRQ 0x%x\n",
+			HVA_PREFIX, irq);
+		goto err_clk;
+	}
+	disable_irq(hva->irq_its);
+
+	/* retrieve irq number from board resources */
+	hva->irq_err = platform_get_irq(pdev, 1);
+	if (!hva->irq_err) {
+		dev_err(dev, "%s     failed to get IRQ resource\n", HVA_PREFIX);
+		goto err_clk;
+	}
+
+	/* request irq */
+	ret = devm_request_threaded_irq(dev, hva->irq_err, hva_hw_err_interrupt,
+					hva_hw_err_irq_thread,
+					IRQF_ONESHOT,
+					"hva_err_irq", (void *)hva);
+	if (ret) {
+		dev_err(dev, "%s     failed to register err IRQ 0x%x\n",
+			HVA_PREFIX, irq);
+		goto err_clk;
+	}
+	disable_irq(hva->irq_err);
+
+	/* initialisation of the protection mutex */
+	mutex_init(&hva->protect_mutex);
+
+	/* initialisation of completion signal */
+	init_completion(&hva->interrupt);
+
+	/* init pm_runtime used for power management */
+	pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY_MS);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_set_suspended(dev);
+	pm_runtime_enable(dev);
+
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		dev_err(dev, "%s     failed to set PM\n", HVA_PREFIX);
+		goto err_pm;
+	}
+
+	/* check hardware ID */
+	hva->chip_id = hva_hw_get_chipset_id(hva);
+
+	if (hva->chip_id == HVA_VERSION_UNKNOWN) {
+		ret = -EINVAL;
+		goto err_pm;
+	}
+
+	dev_info(dev, "%s     found hva device (id=%lx)\n", HVA_PREFIX,
+		 hva->chip_id);
+
+	return 0;
+err_pm:
+	pm_runtime_put(dev);
+err_clk:
+	if (hva->clk)
+		clk_unprepare(hva->clk);
+
+	return ret;
+}
+
+void hva_hw_remove(struct hva_device *hva)
+{
+	struct device *dev = hva_to_dev(hva);
+
+	/* disable interrupt */
+	disable_irq(hva->irq_its);
+	disable_irq(hva->irq_err);
+
+	pm_runtime_put_autosuspend(dev);
+	pm_runtime_disable(dev);
+}
+
+int hva_hw_runtime_suspend(struct device *dev)
+{
+	struct hva_device *hva = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(hva->clk);
+
+	return 0;
+}
+
+int hva_hw_runtime_resume(struct device *dev)
+{
+	struct hva_device *hva = dev_get_drvdata(dev);
+
+	if (clk_prepare_enable(hva->clk)) {
+		dev_err(hva->dev, "%s     failed to prepare hva clk\n",
+			HVA_PREFIX);
+		return -EINVAL;
+	}
+
+	if (clk_set_rate(hva->clk, CLK_RATE)) {
+		dev_err(dev, "%s     failed to set clock frequency\n",
+			HVA_PREFIX);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
+			struct hva_buffer *task)
+{
+	struct hva_device *hva = ctx_to_hdev(ctx);
+	struct device *dev = hva_to_dev(hva);
+	unsigned long int version = 0;
+	u8 client_id = ctx->client_id;
+	u32 reg = 0;
+
+	mutex_lock(&hva->protect_mutex);
+
+	/* enable irqs */
+	enable_irq(hva->irq_its);
+	enable_irq(hva->irq_err);
+
+	if (pm_runtime_get_sync(dev) < 0) {
+		dev_err(dev, "%s     get pm_runtime failed\n", ctx->name);
+		ctx->sys_errors++;
+		goto out;
+	}
+
+	version = readl_relaxed(hva->regs + HVA_HIF_REG_VERSION) &
+		  VERSION_ID_MASK;
+
+	reg = readl_relaxed(hva->regs + HVA_HIF_REG_CLK_GATING);
+	switch (cmd) {
+	case JPEG_ENC:
+		reg |= CLK_GATING_HJE;
+		break;
+	case H264_ENC:
+	case VP8_ENC:
+		reg |= CLK_GATING_HVC;
+		break;
+	default:
+		dev_warn(dev, "%s     unknown command 0x%x\n", ctx->name, cmd);
+		goto out;
+	}
+	writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING);
+
+	dev_dbg(dev, "%s     %s: Write configuration registers\n", ctx->name,
+		__func__);
+
+	/* byte swap config */
+	switch (version) {
+	case HVA_VERSION_V397:
+	case HVA_VERSION_V400:
+		writel_relaxed(BSM_CFG_VAL1,
+			       hva->regs + HVA_HIF_REG_BSM);
+		break;
+	default:
+		dev_err(dev, "%s     unknown chipset identifier 0x%lx\n",
+			ctx->name, version);
+		ctx->sys_errors++;
+		goto out;
+	}
+
+	/*
+	 * define Max Opcode Size and Max Message Size
+	 * for LMI and EMI
+	 */
+	switch (version) {
+	case HVA_VERSION_V397:
+	case HVA_VERSION_V400:
+		writel_relaxed(MIF_CFG_VAL3,
+			       hva->regs + HVA_HIF_REG_MIF_CFG);
+		writel_relaxed(HEC_MIF_CFG_VAL,
+			       hva->regs + HVA_HIF_REG_HEC_MIF_CFG);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	/* command FIFO: task_id[31:16] client_id[15:8] command_type[7:0] */
+	dev_dbg(dev, "%s     %s: Send task ( cmd:%d, task_desc:0x%x)\n",
+		ctx->name, __func__, cmd + (client_id << 8), task->paddr);
+	writel_relaxed(cmd + (client_id << 8), hva->regs + HVA_HIF_FIFO_CMD);
+	writel_relaxed(task->paddr, hva->regs + HVA_HIF_FIFO_CMD);
+
+	if (!wait_for_completion_timeout(&hva->interrupt,
+					 msecs_to_jiffies(2000))) {
+		dev_err(dev, "%s     %s:Time out on completion\n", ctx->name,
+			__func__);
+		ctx->encode_errors++;
+		ctx->hw_err = true;
+	}
+out:
+	disable_irq(hva->irq_its);
+	disable_irq(hva->irq_err);
+
+	switch (cmd) {
+	case JPEG_ENC:
+		reg &= ~CLK_GATING_HJE;
+		writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING);
+		break;
+	case H264_ENC:
+	case VP8_ENC:
+		reg &= ~CLK_GATING_HVC;
+		writel_relaxed(reg, hva->regs + HVA_HIF_REG_CLK_GATING);
+
+		break;
+	default:
+		dev_warn(dev, "%s     unknown command 0x%x\n", ctx->name, cmd);
+	}
+
+	pm_runtime_put_autosuspend(dev);
+	mutex_unlock(&hva->protect_mutex);
+
+	if (ctx->hw_err)
+		return -EFAULT;
+
+	return 0;
+}
diff --git a/drivers/media/platform/sti/hva/hva-hw.h b/drivers/media/platform/sti/hva/hva-hw.h
new file mode 100644
index 0000000..b27465a
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-hw.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef HVA_HW_H
+#define HVA_HW_H
+
+/* HVA Versions */
+#define HVA_VERSION_UNKNOWN    0x000
+#define HVA_VERSION_V397       0x397
+#define HVA_VERSION_V400       0x400
+
+enum hva_hw_cmd_type {
+	/* RESERVED = 0x00 */
+	/* RESERVED = 0x01 */
+	H264_ENC = 0x02,
+	JPEG_ENC = 0x03,
+	/* SW synchro task (reserved in HW) */
+	/* RESERVED = 0x04 */
+	/* RESERVED = 0x05 */
+	VP8_ENC = 0x06,
+	/* RESERVED = 0x07 */
+	REMOVE_CLIENT = 0x08,
+	FREEZE_CLIENT = 0x09,
+	START_CLIENT = 0x0A,
+	FREEZE_ALL = 0x0B,
+	START_ALL = 0x0C,
+	REMOVE_ALL = 0x0D
+};
+
+/**
+ * hw encode error values
+ * NO_ERROR: Success, Task OK
+ * JPEG_BITSTREAM_OVERSIZE: VECJPEG Picture size > Max bitstream size
+ * H264_BITSTREAM_OVERSIZE: VECH264 Bitstream size > bitstream buffer
+ * H264_FRAME_SKIPPED: VECH264 Frame skipped (refers to CPB Buffer Size)
+ * H264_SLICE_LIMIT_SIZE: VECH264 MB > slice limit size
+ * H264_MAX_SLICE_NUMBER: VECH264 max slice number reached
+ * H264_SLICE_READY: VECH264 Slice ready
+ * TASK_LIST_FULL: HVA/FPC task list full
+		   (discard latest transform command)
+ * UNKNOWN_COMMAND: Transform command not known by HVA/FPC
+ * WRONG_CODEC_OR_RESOLUTION: Wrong Codec or Resolution Selection
+ * NO_INT_COMPLETION: Time-out on interrupt completion
+ * LMI_ERR: Local Memory Interface Error
+ * EMI_ERR: External Memory Interface Error
+ * HECMI_ERR: HEC Memory Interface Error
+ */
+enum hva_hw_error {
+	NO_ERROR = 0x0,
+	JPEG_BITSTREAM_OVERSIZE = 0x1,
+	H264_BITSTREAM_OVERSIZE = 0x2,
+	H264_FRAME_SKIPPED = 0x4,
+	H264_SLICE_LIMIT_SIZE = 0x5,
+	H264_MAX_SLICE_NUMBER = 0x7,
+	H264_SLICE_READY = 0x8,
+	TASK_LIST_FULL = 0xF0,
+	UNKNOWN_COMMAND = 0xF1,
+	WRONG_CODEC_OR_RESOLUTION = 0xF4,
+	NO_INT_COMPLETION = 0x100,
+	LMI_ERR = 0x101,
+	EMI_ERR = 0x102,
+	HECMI_ERR = 0x103,
+};
+
+int hva_hw_probe(struct platform_device *pdev, struct hva_device *hva);
+void hva_hw_remove(struct hva_device *hva);
+int hva_hw_runtime_suspend(struct device *dev);
+int hva_hw_runtime_resume(struct device *dev);
+int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd,
+			struct hva_buffer *task);
+
+#endif /* HVA_HW_H */
diff --git a/drivers/media/platform/sti/hva/hva-mem.c b/drivers/media/platform/sti/hva/hva-mem.c
new file mode 100644
index 0000000..01da742
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-mem.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include "hva.h"
+#include "hva-mem.h"
+
+int hva_mem_alloc(struct hva_ctx *ctx, u32 size, const char *name,
+		  struct hva_buffer **buf)
+{
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_buffer *b;
+	dma_addr_t paddr;
+	void *base;
+	DEFINE_DMA_ATTRS(attrs);
+
+	b = devm_kzalloc(dev, sizeof(*b), GFP_KERNEL);
+	if (!b) {
+		ctx->sys_errors++;
+		return -ENOMEM;
+	}
+
+	dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+	base = dma_alloc_attrs(dev, size, &paddr, GFP_KERNEL | GFP_DMA, &attrs);
+	if (!base) {
+		dev_err(dev, "%s %s : dma_alloc_attrs failed for %s (size=%d)\n",
+			ctx->name, __func__, name, size);
+		ctx->sys_errors++;
+		devm_kfree(dev, b);
+		return -ENOMEM;
+	}
+
+	b->size = size;
+	b->paddr = paddr;
+	b->vaddr = base;
+	b->attrs = attrs;
+	b->name = name;
+
+	dev_dbg(dev,
+		"%s allocate %d bytes of HW memory @(virt=%p, phy=0x%x): %s\n",
+		ctx->name, size, b->vaddr, b->paddr, b->name);
+
+	/* return  hva buffer to user */
+	*buf = b;
+
+	return 0;
+}
+
+void hva_mem_free(struct hva_ctx *ctx, struct hva_buffer *buf)
+{
+	struct device *dev = ctx_to_dev(ctx);
+
+	dev_dbg(dev,
+		"%s free %d bytes of HW memory @(virt=%p, phy=0x%x): %s\n",
+		ctx->name, buf->size, buf->vaddr, buf->paddr, buf->name);
+
+	dma_free_attrs(dev, buf->size, buf->vaddr, buf->paddr, &buf->attrs);
+
+	devm_kfree(dev, buf);
+}
diff --git a/drivers/media/platform/sti/hva/hva-mem.h b/drivers/media/platform/sti/hva/hva-mem.h
new file mode 100644
index 0000000..f181115
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-mem.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef HVA_MEM_H
+#define HVA_MEM_H
+
+int hva_mem_alloc(struct hva_ctx *ctx,
+		  __u32 size,
+		  const char *name,
+		  struct hva_buffer **buf);
+
+void hva_mem_free(struct hva_ctx *ctx,
+		  struct hva_buffer *buf);
+
+#endif /* HVA_MEM_H */
+
diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c
new file mode 100644
index 0000000..051d2ea
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-v4l2.c
@@ -0,0 +1,1404 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <linux/of.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include "hva.h"
+#include "hva-hw.h"
+
+#define HVA_NAME "hva"
+
+/*
+ * 1 frame at least for user
+ * limit number of frames to 16
+ */
+#define MAX_FRAMES	16
+#define MIN_FRAMES	1
+
+#define HVA_MIN_WIDTH	32
+#define HVA_MAX_WIDTH	1920
+#define HVA_MIN_HEIGHT	32
+#define HVA_MAX_HEIGHT	1080
+
+#define DFT_CFG_WIDTH		HVA_MIN_WIDTH
+#define	DFT_CFG_HEIGHT		HVA_MIN_HEIGHT
+#define DFT_CFG_BITRATE_MODE	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+#define DFT_CFG_GOP_SIZE	16
+#define DFT_CFG_INTRA_REFRESH	true
+#define DFT_CFG_FRAME_NUM	1
+#define DFT_CFG_FRAME_DEN	30
+#define DFT_CFG_QPMIN		5
+#define DFT_CFG_QPMAX		51
+#define DFT_CFG_DCT8X8		false
+#define DFT_CFG_COMP_QUALITY	85
+#define DFT_CFG_SAR_ENABLE	1
+#define DFT_CFG_BITRATE		(20000 * 1024)
+#define DFT_CFG_CPB_SIZE	(25000 * 1024)
+
+static const struct hva_frameinfo frame_dflt_fmt = {
+	.fmt		= {
+				.pixelformat	= V4L2_PIX_FMT_NV12,
+				.nb_planes	= 2,
+				.bpp		= 12,
+				.bpp_plane0	= 8,
+				.w_align	= 2,
+				.h_align	= 2
+			  },
+	.width		= DFT_CFG_WIDTH,
+	.height		= DFT_CFG_HEIGHT,
+	.crop		= {0, 0, DFT_CFG_WIDTH, DFT_CFG_HEIGHT},
+	.frame_width	= DFT_CFG_WIDTH,
+	.frame_height	= DFT_CFG_HEIGHT
+};
+
+static const struct hva_streaminfo stream_dflt_fmt = {
+	.width		= DFT_CFG_WIDTH,
+	.height		= DFT_CFG_HEIGHT
+};
+
+/* list of stream formats supported by hva hardware */
+const u32 stream_fmt[] = {
+};
+
+/* list of pixel formats supported by hva hardware */
+static const struct hva_frame_fmt frame_fmts[] = {
+	/* NV12. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
+	{
+		.pixelformat	= V4L2_PIX_FMT_NV12,
+		.nb_planes	= 2,
+		.bpp		= 12,
+		.bpp_plane0	= 8,
+		.w_align	= 2,
+		.h_align	= 2
+	},
+	/* NV21. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
+	{
+		.pixelformat	= V4L2_PIX_FMT_NV21,
+		.nb_planes	= 2,
+		.bpp		= 12,
+		.bpp_plane0	= 8,
+		.w_align	= 2,
+		.h_align	= 2
+	},
+};
+
+/* offset to differentiate OUTPUT/CAPTURE @mmap */
+#define MMAP_FRAME_OFFSET (UL(0x100000000) / 2)
+
+/* registry of available encoders */
+const struct hva_encoder *hva_encoders[] = {
+};
+
+static const struct hva_frame_fmt *hva_find_frame_fmt(u32 pixelformat)
+{
+	const struct hva_frame_fmt *fmt;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(frame_fmts); i++) {
+		fmt = &frame_fmts[i];
+		if (fmt->pixelformat == pixelformat)
+			return fmt;
+	}
+
+	return NULL;
+}
+
+static void register_encoder(struct hva_device *hva,
+			     const struct hva_encoder *enc)
+{
+	if (hva->nb_of_encoders >= HVA_MAX_ENCODERS) {
+		dev_warn(hva->dev,
+			 "%s can' t register encoder (max nb (%d) is reached!)\n",
+			 enc->name, HVA_MAX_ENCODERS);
+		return;
+	}
+
+	/* those encoder ops are mandatory */
+	WARN_ON(!enc->open);
+	WARN_ON(!enc->close);
+	WARN_ON(!enc->encode);
+
+	hva->encoders[hva->nb_of_encoders] = enc;
+	hva->nb_of_encoders++;
+	dev_info(hva->dev, "%s encoder registered\n", enc->name);
+}
+
+static void register_all(struct hva_device *hva)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(hva_encoders); i++)
+		register_encoder(hva, hva_encoders[i]);
+}
+
+static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat,
+			    u32 pixelformat, struct hva_encoder **penc)
+{
+	struct hva_device *hva = ctx_to_hdev(ctx);
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_encoder *enc;
+	unsigned int i;
+	int ret;
+
+	/* find an encoder which can deal with these formats */
+	for (i = 0; i < hva->nb_of_encoders; i++) {
+		enc = (struct hva_encoder *)hva->encoders[i];
+		if ((enc->streamformat == streamformat) &&
+		    (enc->pixelformat == pixelformat))
+			break;	/* found */
+	}
+
+	if (i == hva->nb_of_encoders) {
+		dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n",
+			ctx->name, (char *)pixelformat, (char *)streamformat);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "%s one encoder matching %4.4s => %4.4s\n",
+		ctx->name, (char *)&pixelformat, (char *)&streamformat);
+
+	/* update name instance */
+	snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]",
+		 hva->instance_id, (char *)&streamformat);
+
+	/* open encoder instance */
+	ret = enc->open(ctx);
+	if (ret) {
+		dev_err(hva->dev, "%s enc->open failed (%d)\n",
+			ctx->name, ret);
+		return ret;
+	}
+
+	*penc = enc;
+
+	return ret;
+}
+
+/* v4l2 ioctl operations */
+
+static int hva_querycap(struct file *file, void *priv,
+			struct v4l2_capability *cap)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct hva_device *hva = ctx_to_hdev(ctx);
+
+	strlcpy(cap->driver, hva->pdev->name, sizeof(cap->driver));
+	strlcpy(cap->card, hva->pdev->name, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+		 HVA_NAME);
+
+	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+	return 0;
+}
+
+static int hva_enum_fmt_frame(struct file *file, void *priv,
+			      struct v4l2_fmtdesc *f)
+{
+	/* index don't have to exceed number of  format supported */
+	if (f->index >=  ARRAY_SIZE(frame_fmts))
+		return -EINVAL;
+
+	/* pixel format */
+	f->pixelformat = frame_fmts[f->index].pixelformat;
+
+	return 0;
+}
+
+static int hva_enum_fmt_stream(struct file *file, void *priv,
+			       struct v4l2_fmtdesc *f)
+{
+	/* index don't have to exceed number of stream format supported */
+	if (f->index >= ARRAY_SIZE(stream_fmt))
+		return -EINVAL;
+
+	/* pixel format */
+	f->pixelformat = stream_fmt[f->index];
+
+	/* compressed */
+	f->flags = V4L2_FMT_FLAG_COMPRESSED;
+
+	return 0;
+}
+
+static int hva_try_fmt_stream(struct file *file, void *priv,
+			      struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct hva_device *hva = ctx_to_hdev(ctx);
+	struct device *dev = ctx_to_dev(ctx);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	const struct hva_encoder *enc = NULL;
+	unsigned int i;
+
+	if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0))
+		goto out;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.priv = 0;
+
+	for (i = 0; i < hva->nb_of_encoders; i++) {
+		enc = hva->encoders[i];
+		if (enc->streamformat == pix->pixelformat)
+			if ((f->fmt.pix.height * f->fmt.pix.width) <=
+			    (enc->max_width * enc->max_height))
+				return 0;
+	}
+out:
+	dev_dbg(dev, "%s stream format or resolution %dx%d not supported\n",
+		ctx->name, f->fmt.pix.width, f->fmt.pix.height);
+	return -EINVAL;
+}
+
+static int hva_try_fmt_frame(struct file *file, void *priv,
+			     struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	const struct hva_frame_fmt *format;
+	u32 in_w, in_h;
+
+	format = hva_find_frame_fmt(pix->pixelformat);
+	if (!format) {
+		dev_dbg(dev, "%s Unknown format 0x%x\n", ctx->name,
+			pix->pixelformat);
+		return -EINVAL;
+	}
+
+	/* adjust width & height */
+	in_w = pix->width;
+	in_h = pix->height;
+	v4l_bound_align_image(&pix->width,
+			      HVA_MIN_WIDTH, HVA_MAX_WIDTH,
+			      ffs(format->w_align) - 1,
+			      &pix->height,
+			      HVA_MIN_HEIGHT, HVA_MAX_HEIGHT,
+			      ffs(format->h_align) - 1,
+			      0);
+
+	if ((pix->width != in_w) || (pix->height != in_h))
+		dev_dbg(dev, "%s size updated: %dx%d -> %dx%d\n", ctx->name,
+			in_w, in_h, pix->width, pix->height);
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.priv = 0;
+
+	return 0;
+}
+
+static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	int ret;
+
+	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
+		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
+		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+
+	ret = hva_try_fmt_stream(file, fh, f);
+	if (ret) {
+		dev_err(dev,
+			"%s %s %.4s format or %dx%d resolution not supported\n",
+			ctx->name, __func__, (char *)&f->fmt.pix.pixelformat,
+			f->fmt.pix.width, f->fmt.pix.height);
+		return ret;
+	}
+
+	/* update context */
+	ctx->streaminfo.width = f->fmt.pix.width;
+	ctx->streaminfo.height = f->fmt.pix.height;
+	ctx->streaminfo.streamformat = f->fmt.pix.pixelformat;
+	ctx->streaminfo.dpb = 1;
+	ctx->flags |= HVA_FLAG_STREAMINFO;
+
+	if ((!ctx->encoder) && (ctx->flags & HVA_FLAG_FRAMEINFO)) {
+		ret = hva_open_encoder(ctx,
+				       ctx->streaminfo.streamformat,
+				       ctx->frameinfo.fmt.pixelformat,
+				       &ctx->encoder);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	const struct hva_frame_fmt *fmt;
+	int ret = 0;
+
+	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
+		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
+		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+
+	ret = hva_try_fmt_frame(file, fh, f);
+	if (ret) {
+		dev_err(dev,
+			"%s %s %.4s format or %dx%d resolution not supported\n",
+			ctx->name, __func__, (char *)&f->fmt.pix.pixelformat,
+			f->fmt.pix.width, f->fmt.pix.height);
+		return ret;
+	}
+
+	fmt = hva_find_frame_fmt(pix->pixelformat);
+	if (!fmt) {
+		dev_dbg(dev, "%s %s unknown format 0x%x\n", ctx->name,
+			ctx->name, pix->pixelformat);
+		return -EINVAL;
+	}
+
+	memcpy(&ctx->frameinfo.fmt, fmt, sizeof(struct hva_frame_fmt));
+	ctx->frameinfo.frame_width = ALIGN(pix->width, 16);
+	ctx->frameinfo.frame_height = ALIGN(pix->height, 16);
+	ctx->frameinfo.width = pix->width;
+	ctx->frameinfo.height = pix->height;
+	ctx->frameinfo.crop.width = pix->width;
+	ctx->frameinfo.crop.height = pix->height;
+	ctx->frameinfo.crop.left = 0;
+	ctx->frameinfo.crop.top = 0;
+
+	ctx->flags |= HVA_FLAG_FRAMEINFO;
+
+	if ((!ctx->encoder) && (ctx->flags & HVA_FLAG_STREAMINFO))
+		ret = hva_open_encoder(ctx,
+				       ctx->streaminfo.streamformat,
+				       ctx->frameinfo.fmt.pixelformat,
+				       &ctx->encoder);
+
+	return ret;
+}
+
+static int hva_s_ext_ctrls(struct file *file, void *fh,
+			   struct v4l2_ext_controls *ctrls)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	unsigned int i;
+
+	dev_dbg(dev, "%s %s count controls %d\n", ctx->name, __func__,
+		ctrls->count);
+
+	for (i = 0; i < ctrls->count; i++) {
+		switch (ctrls->controls[i].id) {
+		case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+			ctx->ctrls.gop_size = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_GOP_SIZE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+			ctx->ctrls.bitrate_mode = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE_MODE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_BITRATE:
+			ctx->ctrls.bitrate = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+			ctx->ctrls.intra_refresh = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_ASPECT:
+			/* only one video aspect ratio supported (1/1) */
+			switch (ctrls->controls[i].value) {
+			case V4L2_MPEG_VIDEO_ASPECT_1x1:
+				dev_dbg(dev,
+					"%s V4L2_CID_MPEG_VIDEO_ASPECT 1x1\n",
+					ctx->name);
+				break;
+			case V4L2_MPEG_VIDEO_ASPECT_4x3:
+			case V4L2_MPEG_VIDEO_ASPECT_16x9:
+			case V4L2_MPEG_VIDEO_ASPECT_221x100:
+			default:
+				dev_err(dev,
+					"%s V4L2_CID_MPEG_VIDEO_ASPECT: Unsupported aspect ratio %d\n",
+					ctx->name, ctrls->controls[i].value);
+				return -EINVAL;
+			}
+			break;
+		default:
+			dev_err(dev,
+				"%s VIDIOC_S_EXT_CTRLS(): Unsupported control id %d\n",
+				ctx->name, ctrls->controls[i].id);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+
+	ctx->time_per_frame.numerator = sp->parm.capture.timeperframe.numerator;
+	ctx->time_per_frame.denominator =
+	    sp->parm.capture.timeperframe.denominator;
+
+	dev_dbg(dev, "%s set parameters %d/%d\n",
+		ctx->name, ctx->time_per_frame.numerator,
+		ctx->time_per_frame.denominator);
+
+	return 0;
+}
+
+static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+
+	sp->parm.capture.timeperframe.numerator = ctx->time_per_frame.numerator;
+	sp->parm.capture.timeperframe.denominator =
+	    ctx->time_per_frame.denominator;
+
+	dev_dbg(dev, "%s get parameters %d/%d\n",
+		ctx->name, ctx->time_per_frame.numerator,
+		ctx->time_per_frame.denominator);
+
+	return 0;
+}
+
+static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+
+	/* get stream format */
+	f->fmt.pix.width = ctx->streaminfo.width;
+	f->fmt.pix.height = ctx->streaminfo.height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	/* 32 bytes alignment */
+	f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width, 32);
+	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;
+	f->fmt.pix.pixelformat = ctx->streaminfo.streamformat;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
+		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
+		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+	return 0;
+}
+
+static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_frame_fmt *fmt = &ctx->frameinfo.fmt;
+	int width = ctx->frameinfo.frame_width;
+	int height = ctx->frameinfo.frame_height;
+
+	/* get source format */
+	f->fmt.pix.pixelformat = fmt->pixelformat;
+	f->fmt.pix.width = ctx->frameinfo.width;
+	f->fmt.pix.height = ctx->frameinfo.height;
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	f->fmt.pix.bytesperline = (width * fmt->bpp_plane0) / 8;
+	f->fmt.pix.sizeimage = (width * height * fmt->bpp) / 8;
+
+	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
+		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
+		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
+
+	return 0;
+}
+
+static int hva_reqbufs(struct file *file, void *priv,
+		       struct v4l2_requestbuffers *reqbufs)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	int ret = 0;
+
+	dev_dbg(dev, "%s %s %s\n", ctx->name, __func__,
+		to_type_str(reqbufs->type));
+
+	ret = vb2_reqbufs(get_queue(ctx, reqbufs->type), reqbufs);
+	if (ret) {
+		dev_err(dev, "%s vb2_reqbufs failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	if (reqbufs->count == 0) {
+		/*
+		 * buffers have been freed in vb2 __reqbufs()
+		 * now cleanup "allocation context" ...
+		 */
+		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+			vb2_dma_contig_cleanup_ctx(ctx->q_frame.alloc_ctx[0]);
+			ctx->q_frame.alloc_ctx[0] = NULL;
+		} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+			vb2_dma_contig_cleanup_ctx(ctx->q_stream.alloc_ctx[0]);
+			ctx->q_stream.alloc_ctx[0] = NULL;
+		}
+	}
+
+	return 0;
+}
+
+static int hva_create_bufs(struct file *file, void *priv,
+			   struct v4l2_create_buffers *create)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct vb2_queue *q = get_queue(ctx, create->format.type);
+
+	return vb2_create_bufs(q, create);
+}
+
+static int hva_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	int ret = 0;
+
+	dev_dbg(dev, "%s %s %s[%d]\n", ctx->name, __func__,
+		to_type_str(b->type), b->index);
+
+	/* vb2 call */
+	ret = vb2_querybuf(get_queue(ctx, b->type), b);
+	if (ret) {
+		dev_err(dev, "%s vb2_querybuf failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	/* add an offset to differentiate OUTPUT/CAPTURE @mmap time */
+	if ((b->memory == V4L2_MEMORY_MMAP) &&
+	    (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+		b->m.offset += MMAP_FRAME_OFFSET;
+	}
+
+	return 0;
+}
+
+static int hva_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *b)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	int ret = 0;
+
+	/* request validation */
+	if ((b->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) &&
+	    (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+		dev_err(dev,
+			"%s V4L2 EXPBUF: only type output/cature are supported\n",
+			ctx->name);
+		return -EINVAL;
+	}
+
+	/* vb2 call */
+	ret = vb2_expbuf(get_queue(ctx, b->type), b);
+	if (ret) {
+		dev_err(dev, "%s vb2_expbuf failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct vb2_queue *q = get_queue(ctx, b->type);
+	int ret = 0;
+
+	/* copy bytesused field from v4l2 buffer to vb2 buffer */
+	if ((b->index < MAX_FRAMES) &&
+	    (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
+		struct hva_stream *s = (struct hva_stream *)q->bufs[b->index];
+
+		s->payload = b->bytesused;
+	}
+
+	ret = vb2_qbuf(q, b);
+	if (ret) {
+		dev_err(dev, "%s vb2_qbuf failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int hva_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct vb2_queue *q = get_queue(ctx, b->type);
+	int ret = 0;
+
+	/* vb2 call */
+	ret = vb2_dqbuf(q, b, file->f_flags & O_NONBLOCK);
+	if (ret) {
+		dev_err(dev, "%s vb2_dqbuf failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	dev_dbg(dev, "%s %s %s[%d]\n", ctx->name, __func__,
+		to_type_str(b->type), b->index);
+
+	return 0;
+}
+
+static int hva_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	int ret = 0;
+
+	/* reset frame number */
+	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		ctx->frame_num = 0;
+
+	/* vb2 call */
+	ret = vb2_streamon(get_queue(ctx, type), type);
+	if (ret) {
+		dev_err(dev, "%s vb2_streamon failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int hva_streamoff(struct file *file, void *priv, enum v4l2_buf_type type)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_stream *sr, *node;
+	int ret = 0;
+
+	/* release all active buffers */
+	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+		list_for_each_entry_safe(sr, node, &ctx->list_stream, list) {
+			list_del_init(&sr->list);
+			vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
+		}
+	}
+
+	/* vb2 call */
+	ret = vb2_streamoff(get_queue(ctx, type), type);
+	if (ret) {
+		dev_err(dev, "%s vb2_streamoff failed (%d)\n", ctx->name, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int is_rect_enclosed(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+	/* return 1 if a is enclosed in b, or 0 otherwise. */
+	if (a->left < b->left || a->top < b->top)
+		return 0;
+
+	if (a->left + a->width > b->left + b->width)
+		return 0;
+
+	if (a->top + a->height > b->top + b->height)
+		return 0;
+
+	return 1;
+}
+
+static int hva_g_selection(struct file *file, void *fh,
+			   struct v4l2_selection *s)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+
+	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		dev_err(dev, "%s %s: G_SELECTION failed, invalid type (%d)\n",
+			ctx->name, __func__, s->type);
+		return -EINVAL;
+	}
+
+	switch (s->target) {
+	case V4L2_SEL_TGT_CROP:
+		/* cropped frame */
+		s->r = ctx->frameinfo.crop;
+		break;
+	case V4L2_SEL_TGT_CROP_DEFAULT:
+	case V4L2_SEL_TGT_CROP_BOUNDS:
+		/* complete frame */
+		s->r.left = 0;
+		s->r.top = 0;
+		s->r.width = ctx->frameinfo.width;
+		s->r.height = ctx->frameinfo.height;
+		break;
+	default:
+		dev_err(dev, "%s %s: G_SELECTION failed, invalid target (%d)\n",
+			ctx->name, __func__, s->target);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hva_s_selection(struct file *file, void *fh,
+			   struct v4l2_selection *s)
+{
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	struct v4l2_rect *in, out;
+
+	if ((s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
+	    (s->target != V4L2_SEL_TGT_CROP)) {
+		dev_err(dev, "%s %s: S_SELECTION failed, invalid type (%d)\n",
+			ctx->name, __func__, s->type);
+		return -EINVAL;
+	}
+
+	in = &s->r;
+	out = *in;
+
+	/* align and check origin */
+	out.left = ALIGN(in->left, ctx->frameinfo.fmt.w_align);
+	out.top = ALIGN(in->top, ctx->frameinfo.fmt.h_align);
+
+	if (((out.left + out.width) >  ctx->frameinfo.width) ||
+	    ((out.top + out.height) >  ctx->frameinfo.height)) {
+		dev_err(dev,
+			"%s %s: S_SELECTION failed, invalid crop %dx%d@(%d,%d)\n",
+			ctx->name, __func__, out.width, out.height,
+			out.left, out.top);
+		return -EINVAL;
+	}
+
+	/* checks adjust constraints flags */
+	if (s->flags & V4L2_SEL_FLAG_LE && !is_rect_enclosed(&out, in))
+		return -ERANGE;
+
+	if (s->flags & V4L2_SEL_FLAG_GE && !is_rect_enclosed(in, &out))
+		return -ERANGE;
+
+	if ((out.left != in->left) || (out.top != in->top) ||
+	    (out.width != in->width) || (out.height != in->height))
+		*in = out;
+
+	ctx->frameinfo.crop = s->r;
+
+	return 0;
+}
+
+/* vb2 ioctls operations */
+
+static int hva_vb2_frame_queue_setup(struct vb2_queue *q,
+				     const void *parg,
+				     unsigned int *num_buffers,
+				     unsigned int *num_planes,
+				     unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct device *dev = ctx_to_dev(ctx);
+	int width = ctx->frameinfo.frame_width;
+	int height = ctx->frameinfo.frame_height;
+
+	dev_dbg(dev, "%s %s *num_buffers=%d\n", ctx->name, __func__,
+		*num_buffers);
+
+	/* only one plane supported */
+	*num_planes = 1;
+
+	/* setup nb of input buffers needed =
+	 * user need (*num_buffer given, usually for grab pipeline) +
+	 * encoder internal need
+	 */
+	if (*num_buffers < MIN_FRAMES) {
+		dev_warn(dev,
+			 "%s num_buffers too low (%d), increasing to %d\n",
+			 ctx->name, *num_buffers, MIN_FRAMES);
+		*num_buffers = MIN_FRAMES;
+	}
+
+	if (*num_buffers > MAX_FRAMES) {
+		dev_warn(dev,
+			 "%s input frame count too high (%d), cut to %d\n",
+			 ctx->name, *num_buffers, MAX_FRAMES);
+		*num_buffers = MAX_FRAMES;
+	}
+
+	if (sizes[0])
+		dev_warn(dev, "%s psize[0] already set to %d\n", ctx->name,
+			 sizes[0]);
+
+	if (alloc_ctxs[0])
+		dev_warn(dev, "%s allocators[0] already set\n", ctx->name);
+
+	if (!(ctx->flags & HVA_FLAG_FRAMEINFO)) {
+		dev_err(dev, "%s %s frame format not set, using default format\n",
+			ctx->name, __func__);
+	}
+
+	sizes[0] = (width * height * ctx->frameinfo.fmt.bpp) / 8;
+	alloc_ctxs[0] = vb2_dma_contig_init_ctx(dev);
+	/* alloc_ctxs[0] will be freed @ reqbufs(0) or @ release */
+
+	return 0;
+}
+
+static int hva_vb2_frame_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_frame *fm = (struct hva_frame *)vb;
+
+	if (!fm->prepared) {
+		/* get memory addresses */
+		fm->vaddr = vb2_plane_vaddr(&fm->v4l2.vb2_buf, 0);
+		fm->paddr =
+			vb2_dma_contig_plane_dma_addr(&fm->v4l2.vb2_buf, 0);
+		fm->prepared = true;
+
+		ctx->num_frames++;
+
+		dev_dbg(dev, "%s frame[%d] prepared; virt=%p, phy=0x%x\n",
+			ctx->name, vb->index, fm->vaddr,
+			fm->paddr);
+	}
+
+	return 0;
+}
+
+static void hva_vb2_frame_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct device *dev = ctx_to_dev(ctx);
+	const struct hva_encoder *enc = ctx_to_enc(ctx);
+	struct hva_frame *fm = NULL;
+	struct hva_stream *sr = NULL;
+	int ret = 0;
+
+	fm = (struct hva_frame *)vb;
+
+	if (!vb2_is_streaming(q)) {
+		vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
+		return;
+	}
+
+	/* get a free destination buffer */
+	if (list_empty(&ctx->list_stream)) {
+		dev_err(dev, "%s no free buffer for destination stream!\n",
+			ctx->name);
+		ctx->sys_errors++;
+		goto err;
+	}
+	sr = list_first_entry(&ctx->list_stream, struct hva_stream, list);
+
+	if (!sr)
+		goto err;
+
+	list_del(&sr->list);
+
+	/* encode the frame & get stream unit */
+	ret = enc->encode(ctx, fm, sr);
+	if (ret)
+		goto err;
+
+	/* propagate frame timestamp */
+	sr->v4l2.timestamp = fm->v4l2.timestamp;
+
+	ctx->encoded_frames++;
+
+	vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_DONE);
+	vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_DONE);
+
+	return;
+err:
+	if (sr)
+		vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
+
+	vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
+}
+
+static int hva_vb2_stream_queue_setup(struct vb2_queue *q,
+				      const void *parg,
+				      unsigned int *num_buffers,
+				      unsigned int *num_planes,
+				      unsigned int sizes[], void *alloc_ctxs[])
+{
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct device *dev = ctx_to_dev(ctx);
+	int max_buf_size = 0;
+	u32 pixelformat;
+	int width;
+	int height;
+
+	dev_dbg(dev, "%s %s *num_buffers=%d\n", ctx->name, __func__,
+		*num_buffers);
+
+	/* only one plane supported */
+	*num_planes = 1;
+
+	/* number of buffers must be at least 1 */
+	if (*num_buffers < 1)
+		*num_buffers = 1;
+
+	if (sizes[0])
+		dev_warn(dev, "%s psize[0] already set to %d\n", ctx->name,
+			 sizes[0]);
+
+	if (alloc_ctxs[0])
+		dev_warn(dev, "%s allocators[0] already set\n", ctx->name);
+
+	if (!(ctx->flags & HVA_FLAG_STREAMINFO)) {
+		dev_err(dev, "%s %s stream format not set, using dflt format\n",
+			ctx->name, __func__);
+	}
+
+	pixelformat = ctx->streaminfo.streamformat;
+	width = ctx->streaminfo.width;
+	height = ctx->streaminfo.height;
+
+	switch (pixelformat) {
+	default:
+		dev_err(dev, "%s %s Unknown stream format\n", ctx->name,
+			__func__);
+	}
+
+	sizes[0] = max_buf_size;
+	alloc_ctxs[0] = vb2_dma_contig_init_ctx(dev);	/* free @ release */
+
+	return 0;
+}
+
+static int hva_vb2_stream_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct device *dev = ctx_to_dev(ctx);
+	struct hva_stream *sr = (struct hva_stream *)vb;
+
+	if (!sr->prepared) {
+		/* get memory addresses */
+		sr->vaddr = vb2_plane_vaddr(&sr->v4l2.vb2_buf, 0);
+		sr->paddr = vb2_dma_contig_plane_dma_addr(&sr->v4l2.vb2_buf, 0);
+		sr->prepared = true;
+
+		dev_dbg(dev, "%s stream[%d] prepared; virt=%p, phy=0x%x\n",
+			ctx->name, vb->index, sr->vaddr, sr->paddr);
+	}
+
+	return 0;
+}
+
+static void hva_vb2_stream_queue(struct vb2_buffer *vb)
+{
+	struct vb2_queue *q = vb->vb2_queue;
+	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
+	struct hva_stream *sr = (struct hva_stream *)vb;
+
+	/* check validity of video stream */
+	if (vb) {
+		/* enqueue to a list destination stream */
+		list_add(&sr->list, &ctx->list_stream);
+	}
+}
+
+static struct vb2_ops hva_vb2_frame_ops = {
+	.queue_setup = hva_vb2_frame_queue_setup,
+	.buf_prepare = hva_vb2_frame_prepare,
+	.buf_queue = hva_vb2_frame_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+static struct vb2_ops hva_vb2_stream_ops = {
+	.queue_setup = hva_vb2_stream_queue_setup,
+	.buf_prepare = hva_vb2_stream_prepare,
+	.buf_queue = hva_vb2_stream_queue,
+	.wait_prepare = vb2_ops_wait_prepare,
+	.wait_finish = vb2_ops_wait_finish,
+};
+
+/* file basics operations */
+
+static int hva_open(struct file *file)
+{
+	struct hva_device *hva = video_drvdata(file);
+	struct vb2_queue *q;
+	struct device *dev;
+	struct hva_ctx *ctx;
+	int ret = 0;
+	unsigned int i;
+
+	WARN_ON(!hva);
+	dev = hva->dev;
+
+	mutex_lock(&hva->lock);
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		mutex_unlock(&hva->lock);
+		return -ENOMEM;
+	}
+
+	/* store the context address in the contexts list */
+	for (i = 0; i < MAX_CONTEXT; i++) {
+		if (!hva->contexts_list[i]) {
+			hva->contexts_list[i] = ctx;
+			/* save client id in context */
+			ctx->client_id = i;
+			break;
+		}
+	}
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	v4l2_fh_add(&ctx->fh);
+
+	/* recopy device handlers */
+	ctx->dev = hva->dev;
+	ctx->hdev = hva;
+
+	/* setup vb2 queue for frame input */
+	q = &ctx->q_frame;
+	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; /* to say input, weird! */
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+
+	/* save file handle to private data field of the queue */
+	q->drv_priv = &ctx->fh;
+
+	/* overload vb2 buffer size with private struct */
+	q->buf_struct_size = sizeof(struct hva_frame);
+
+	q->ops = &hva_vb2_frame_ops;
+	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	q->lock = &hva->lock;
+
+	ret = vb2_queue_init(q);
+	if (ret) {
+		dev_err(dev, "%s [x:x] vb2_queue_init(frame) failed (%d)\n",
+			HVA_PREFIX,  ret);
+		ctx->sys_errors++;
+		goto err_fh_del;
+	}
+
+	/* setup vb2 queue of the destination */
+	q = &ctx->q_stream;
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_MMAP | VB2_DMABUF;
+
+	/* save file handle to private data field of the queue */
+	q->drv_priv = &ctx->fh;
+
+	/* overload vb2 buffer size with private struct */
+	q->buf_struct_size = sizeof(struct hva_stream);
+
+	q->ops = &hva_vb2_stream_ops;
+	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	q->lock = &hva->lock;
+
+	ret = vb2_queue_init(q);
+	if (ret) {
+		dev_err(dev, "%s [x:x] vb2_queue_init(stream) failed (%d)\n",
+			HVA_PREFIX, ret);
+		ctx->sys_errors++;
+		goto err_queue_del_frame;
+	}
+
+	/* initialize the list of stream buffers */
+	INIT_LIST_HEAD(&ctx->list_stream);
+
+	/* name this instance */
+	hva->instance_id++;	/* rolling id to identify this instance */
+	snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]", hva->instance_id);
+
+	/* initialize controls */
+	ctx->ctrls.bitrate_mode = DFT_CFG_BITRATE_MODE;
+	ctx->ctrls.bitrate = DFT_CFG_BITRATE;
+	ctx->ctrls.cpb_size = DFT_CFG_CPB_SIZE;
+	ctx->ctrls.gop_size = DFT_CFG_GOP_SIZE;
+	ctx->ctrls.intra_refresh = DFT_CFG_INTRA_REFRESH;
+	ctx->ctrls.dct8x8 = DFT_CFG_DCT8X8;
+	ctx->ctrls.qpmin = DFT_CFG_QPMIN;
+	ctx->ctrls.qpmax = DFT_CFG_QPMAX;
+	ctx->ctrls.jpeg_comp_quality = DFT_CFG_COMP_QUALITY;
+	ctx->ctrls.vui_sar = DFT_CFG_SAR_ENABLE;
+
+	/* set by default time per frame */
+	ctx->time_per_frame.numerator = DFT_CFG_FRAME_NUM;
+	ctx->time_per_frame.denominator = DFT_CFG_FRAME_DEN;
+
+	/* default format */
+	ctx->streaminfo = stream_dflt_fmt;
+	ctx->frameinfo = frame_dflt_fmt;
+
+	hva->nb_of_instances++;
+
+	mutex_unlock(&hva->lock);
+
+	return 0;
+
+err_queue_del_frame:
+	vb2_queue_release(&ctx->q_frame);
+err_fh_del:
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	hva->contexts_list[ctx->client_id] = NULL;
+	devm_kfree(dev, ctx);
+
+	mutex_unlock(&hva->lock);
+
+	return ret;
+}
+
+static int hva_release(struct file *file)
+{
+	struct hva_device *hva = video_drvdata(file);
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx_to_dev(ctx);
+	const struct hva_encoder *enc = ctx_to_enc(ctx);
+
+	mutex_lock(&hva->lock);
+
+	/* free queues: source & destination */
+	vb2_queue_release(&ctx->q_frame);
+	vb2_queue_release(&ctx->q_stream);
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	/* will free dma memory of each frame in queue */
+	vb2_queue_release(&ctx->q_frame);
+	if (ctx->q_frame.alloc_ctx[0])
+		vb2_dma_contig_cleanup_ctx(ctx->q_frame.alloc_ctx[0]);
+
+	/* will free dma memory of each aus in queue */
+	vb2_queue_release(&ctx->q_stream);
+	if (ctx->q_stream.alloc_ctx[0])
+		vb2_dma_contig_cleanup_ctx(ctx->q_stream.alloc_ctx[0]);
+
+	/* clear context in contexts list */
+	if ((ctx->client_id >= MAX_CONTEXT) ||
+	    (hva->contexts_list[ctx->client_id] != ctx)) {
+		dev_err(dev, "%s can't clear context in contexts list!\n",
+			ctx->name);
+		ctx->sys_errors++;
+	}
+	hva->contexts_list[ctx->client_id] = NULL;
+
+	/* close encoder */
+	if (enc)
+		enc->close(ctx);
+
+	devm_kfree(dev, ctx);
+
+	hva->nb_of_instances--;
+
+	mutex_unlock(&hva->lock);
+
+	return 0;
+}
+
+static int hva_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct hva_device *hva = video_drvdata(file);
+	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
+	struct device *dev = ctx->dev;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	enum v4l2_buf_type type;
+	int ret;
+
+	mutex_lock(&hva->lock);
+
+	/* offset used to differentiate OUTPUT/CAPTURE */
+	if (offset < MMAP_FRAME_OFFSET) {
+		type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	} else {
+		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		vma->vm_pgoff -= (MMAP_FRAME_OFFSET >> PAGE_SHIFT);
+	}
+
+	/* vb2 call */
+	ret = vb2_mmap(get_queue(ctx, type), vma);
+	if (ret) {
+		dev_err(dev, "%s vb2_mmap failed (%d)\n", ctx->name, ret);
+		ctx->sys_errors++;
+		mutex_unlock(&hva->lock);
+		return ret;
+	}
+
+	mutex_unlock(&hva->lock);
+
+	return 0;
+}
+
+/* v4l2 ops */
+static const struct v4l2_file_operations hva_fops = {
+	.owner = THIS_MODULE,
+	.open = hva_open,
+	.release = hva_release,
+	.unlocked_ioctl = video_ioctl2,
+	.mmap = hva_mmap,
+};
+
+/* v4l2 ioctl ops */
+static const struct v4l2_ioctl_ops hva_ioctl_ops = {
+	.vidioc_querycap = hva_querycap,
+	/* formats ioctl */
+	.vidioc_enum_fmt_vid_cap	= hva_enum_fmt_stream,
+	.vidioc_enum_fmt_vid_out	= hva_enum_fmt_frame,
+	.vidioc_g_fmt_vid_cap		= hva_g_fmt_stream,
+	.vidioc_g_fmt_vid_out		= hva_g_fmt_frame,
+	.vidioc_try_fmt_vid_cap		= hva_try_fmt_stream,
+	.vidioc_try_fmt_vid_out		= hva_try_fmt_frame,
+	.vidioc_s_fmt_vid_cap		= hva_s_fmt_stream,
+	.vidioc_s_fmt_vid_out		= hva_s_fmt_frame,
+	.vidioc_s_ext_ctrls		= hva_s_ext_ctrls,
+	.vidioc_g_parm			= hva_g_parm,
+	.vidioc_s_parm			= hva_s_parm,
+	/* buffers ioctls */
+	.vidioc_reqbufs			= hva_reqbufs,
+	.vidioc_create_bufs             = hva_create_bufs,
+	.vidioc_querybuf		= hva_querybuf,
+	.vidioc_expbuf			= hva_expbuf,
+	.vidioc_qbuf			= hva_qbuf,
+	.vidioc_dqbuf			= hva_dqbuf,
+	/* stream ioctls */
+	.vidioc_streamon		= hva_streamon,
+	.vidioc_streamoff		= hva_streamoff,
+	.vidioc_g_selection		= hva_g_selection,
+	.vidioc_s_selection		= hva_s_selection,
+};
+
+static int hva_probe(struct platform_device *pdev)
+{
+	struct hva_device *hva;
+	struct device *dev = &pdev->dev;
+	struct video_device *vdev;
+	int ret;
+
+	hva = devm_kzalloc(dev, sizeof(*hva), GFP_KERNEL);
+	if (!hva) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	hva->dev = dev;
+	hva->pdev = pdev;
+	platform_set_drvdata(pdev, hva);
+
+	mutex_init(&hva->lock);
+
+	/* probe hardware */
+	ret = hva_hw_probe(pdev, hva);
+	if (ret)
+		goto err;
+
+	/* register all available encoders */
+	register_all(hva);
+
+	/* register on V4L2 */
+	ret = v4l2_device_register(dev, &hva->v4l2_dev);
+	if (ret) {
+		dev_err(dev, "%s %s could not register v4l2 device\n",
+			HVA_PREFIX, HVA_NAME);
+		goto err_hw_remove;
+	}
+
+	vdev = video_device_alloc();
+	vdev->fops = &hva_fops;
+	vdev->ioctl_ops = &hva_ioctl_ops;
+	vdev->release = video_device_release;
+	vdev->lock = &hva->lock;
+	vdev->v4l2_dev = &hva->v4l2_dev;
+	snprintf(vdev->name, sizeof(vdev->name), "%s", HVA_NAME);
+	vdev->vfl_dir = VFL_DIR_M2M;
+	ret = video_register_device(vdev, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		dev_err(dev, "%s %s failed to register video device\n",
+			HVA_PREFIX, HVA_NAME);
+		goto err_vdev_release;
+	}
+
+	hva->vdev = vdev;
+	video_set_drvdata(vdev, hva);
+
+	dev_info(dev, "%s %s registered as /dev/video%d\n", HVA_PREFIX,
+		 HVA_NAME, vdev->num);
+
+	dev_info(dev, "%s %s esram reserved for address: %p size:%d\n",
+		 HVA_PREFIX, HVA_NAME, (void *)hva->esram_addr,
+		 hva->esram_size);
+
+	return 0;
+
+err_vdev_release:
+	video_device_release(vdev);
+
+err_hw_remove:
+	hva_hw_remove(hva);
+
+err:
+	return ret;
+}
+
+static int hva_remove(struct platform_device *pdev)
+{
+	struct hva_device *hva = platform_get_drvdata(pdev);
+	struct device *dev = hva_to_dev(hva);
+
+	dev_info(dev, "%s removing %s\n", HVA_PREFIX, pdev->name);
+
+	hva_hw_remove(hva);
+
+	video_unregister_device(hva->vdev);
+	v4l2_device_unregister(&hva->v4l2_dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops hva_pm_ops = {
+	.runtime_suspend = hva_hw_runtime_suspend,
+	.runtime_resume = hva_hw_runtime_resume,
+};
+
+static const struct of_device_id hva_match_types[] = {
+	{
+	 .compatible = "st,stih407-hva",
+	},
+	{ /* end node */ }
+};
+
+MODULE_DEVICE_TABLE(of, hva_match_types);
+
+struct platform_driver hva_driver = {
+	.probe  = hva_probe,
+	.remove = hva_remove,
+	.driver = {
+		.name           = HVA_NAME,
+		.owner          = THIS_MODULE,
+		.of_match_table = hva_match_types,
+		.pm             = &hva_pm_ops,
+		},
+};
+
+module_platform_driver(hva_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
+MODULE_DESCRIPTION("HVA video encoder V4L2 driver");
diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h
new file mode 100644
index 0000000..e646718
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef HVA_H
+#define HVA_H
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+#define get_queue(c, t) (t == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \
+			 &c->q_frame : &c->q_stream)
+
+#define to_type_str(type) (type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \
+			   "frame" : "stream")
+
+#define fh_to_ctx(f)    (container_of(f, struct hva_ctx, fh))
+
+#define hva_to_dev(h)   (h->dev)
+
+#define ctx_to_dev(c)   (c->dev)
+
+#define ctx_to_hdev(c)  (c->hdev)
+
+#define ctx_to_enc(c)   (c->encoder)
+
+#define HVA_PREFIX "[---:----]"
+
+#define MAX_CONTEXT 16
+
+extern const struct hva_encoder nv12h264enc;
+extern const struct hva_encoder nv21h264enc;
+extern const struct hva_encoder uyvyh264enc;
+extern const struct hva_encoder vyuyh264enc;
+extern const struct hva_encoder xrgb32h264enc;
+extern const struct hva_encoder xbgr32h264enc;
+extern const struct hva_encoder rgbx32h264enc;
+extern const struct hva_encoder bgrx32h264enc;
+extern const struct hva_encoder rgb24h264enc;
+extern const struct hva_encoder bgr24h264enc;
+
+/**
+ * struct hva_frame_fmt - driver's internal color format data
+ * @pixelformat:fourcc code for this format
+ * @nb_planes:  number of planes  (ex: [0]=RGB/Y - [1]=Cb/Cr, ...)
+ * @bpp:        bits per pixel (general)
+ * @bpp_plane0: byte per pixel for the 1st plane
+ * @w_align:    width alignment in pixel (multiple of)
+ * @h_align:    height alignment in pixel (multiple of)
+ */
+struct hva_frame_fmt {
+	u32                     pixelformat;
+	u8                      nb_planes;
+	u8                      bpp;
+	u8                      bpp_plane0;
+	u8                      w_align;
+	u8                      h_align;
+};
+
+/**
+ * struct hva_frameinfo - information of frame
+ *
+ * @flags		flags of input frame
+ * @fmt:		format of input frame
+ * @width:		width of input frame
+ * @height:		height of input frame
+ * @crop:		cropping window due to encoder alignment constraints
+ *			(1920x1080@0,0 inside 1920x1088 encoded frame for ex.)
+ * @pixelaspect:	pixel aspect ratio of video (4/3, 5/4)
+ * @frame_width:	width of output frame (encoder alignment constraint)
+ * @frame_height:	height ""
+*/
+struct hva_frameinfo {
+	u32 flags;
+	struct hva_frame_fmt fmt;
+	u32 width;
+	u32 height;
+	struct v4l2_rect crop;
+	struct v4l2_fract pixelaspect;
+	u32 frame_width;
+	u32 frame_height;
+};
+
+/**
+ * struct hva_streaminfo - information of stream
+ *
+ * @flags		flags of video stream
+ * @width:		width of video stream
+ * @height:		height ""
+ * @streamformat:	fourcc compressed format of video (H264, JPEG, ...)
+ * @dpb:		number of frames needed to encode a single frame
+ *			(h264 dpb, up to 16 in standard)
+ * @profile:		profile string
+ * @level:		level string
+ * @other:		other string information from codec
+ */
+struct hva_streaminfo {
+	u32 flags;
+	u32 streamformat;
+	u32 width;
+	u32 height;
+	u32 dpb;
+	u8 profile[32];
+	u8 level[32];
+	u8 other[32];
+};
+
+#define HVA_FRAMEINFO_FLAG_CROP		0x0001
+#define HVA_FRAMEINFO_FLAG_PIXELASPECT	0x0002
+
+#define HVA_STREAMINFO_FLAG_OTHER	0x0001
+#define HVA_STREAMINFO_FLAG_JPEG	0x0002
+#define HVA_STREAMINFO_FLAG_H264	0x0004
+#define HVA_STREAMINFO_FLAG_VP8	0x0008
+
+/**
+ * struct hva_controls
+ *
+ * @level: level enumerate
+ * @profile: video profile
+ * @entropy_mode: entropy mode (CABAC or CVLC)
+ * @bitrate_mode: bitrate mode (constant bitrate or variable bitrate)
+ * @gop_size: groupe of picture size
+ * @bitrate: bitrate
+ * @cpb_size: coded picture buffer size
+ * @intra_refresh: activate intra refresh
+ * @dct8x8: enable transform mode 8x8
+ * @qpmin: defines the minimum quantizer
+ * @qpmax: defines the maximum quantizer
+ * @jpeg_comp_quality: jpeg compression quality
+ * @vui_sar: pixel aspect ratio enable
+ * @vui_sar_idc: pixel aspect ratio identifier
+ * @sei_fp: sei frame packing arrangement enable
+ * @sei_fp_type: sei frame packing arrangement type
+ */
+struct hva_controls {
+	enum v4l2_mpeg_video_h264_level level;
+	enum v4l2_mpeg_video_h264_profile profile;
+	enum v4l2_mpeg_video_h264_entropy_mode entropy_mode;
+	enum v4l2_mpeg_video_bitrate_mode bitrate_mode;
+	u32 gop_size;
+	u32 bitrate;
+	u32 cpb_size;
+	bool intra_refresh;
+	bool dct8x8;
+	u32 qpmin;
+	u32 qpmax;
+	u32 jpeg_comp_quality;
+	bool vui_sar;
+	enum v4l2_mpeg_video_h264_vui_sar_idc vui_sar_idc;
+	bool sei_fp;
+	enum v4l2_mpeg_video_h264_sei_fp_arrangement_type sei_fp_type;
+};
+
+/**
+ * struct hva_frame - structure.
+ *
+ * @v4l2:	video buffer information for v4l2.
+ *		To be kept first and not to be wrote by driver.
+ *		Allows to get the hva_frame fields by just casting a vb2_buffer
+ *		with hva_frame struct. This is allowed through the use of
+ *		vb2 custom buffer mechanism, cf @buf_struct_size of
+ *		struct vb2_queue in include/media/videobuf2-core.h
+ * @paddr:	physical address (for hardware)
+ * @vaddr:	virtual address (kernel can read/write)
+ * @prepared:	boolean, if set vaddr/paddr are resolved
+ */
+struct hva_frame {
+	struct vb2_v4l2_buffer	v4l2; /* !keep first! */
+	dma_addr_t		paddr;
+	void			*vaddr;
+	int			prepared;
+};
+
+/**
+ * struct hva_stream - structure.
+ *
+ * @v4l2:	video buffer information for v4l2.
+ *		To be kept first and not to be wrote by driver.
+ *		Allows to get the hva_stream fields by just casting a vb2_buffer
+ *		with hva_stream struct. This is allowed through the use of
+ *		vb2 custom buffer mechanism, cf @buf_struct_size of
+ *		struct vb2_queue in include/media/videobuf2-core.h
+ * @list:	list element
+ * @paddr:	physical address (for hardware)
+ * @vaddr:	virtual address (kernel can read/write)
+ * @prepared:	boolean, if set vaddr/paddr are resolved
+ * @payload:	number of bytes occupied by data in the buffer
+ */
+struct hva_stream {
+	struct vb2_v4l2_buffer	v4l2; /* !keep first! */
+	struct list_head	list;
+	dma_addr_t		paddr;
+	void			*vaddr;
+	int			prepared;
+	unsigned int		payload;
+};
+
+/**
+ * struct hva_buffer - structure.
+ *
+ * @name:	name of requester
+ * @attrs:	dma attributes
+ * @paddr:	physical address (for hardware)
+ * @vaddr:	virtual address (kernel can read/write)
+ * @size:	size of buffer
+ */
+struct hva_buffer {
+	const char		*name;
+	struct dma_attrs	attrs;
+	dma_addr_t		paddr;
+	void			*vaddr;
+	u32			size;
+};
+
+struct hva_device;
+struct hva_encoder;
+
+#define HVA_MAX_ENCODERS 30
+
+#define HVA_FLAG_STREAMINFO 0x0001
+#define HVA_FLAG_FRAMEINFO 0x0002
+
+/**
+ * struct hva_ctx - context structure.
+ *
+ * @flags:		validity of fields (streaminfo,frameinfo)
+ * @fh:			keep track of V4L2 file handle
+ * @dev:		keep track of device context
+ * @client_id:		Client Identifier
+ * @q_frame:		V4L2 vb2 queue for access units, allocated by driver
+ *			but managed by vb2 framework.
+ * @q_stream:		V4L2 vb2 queue for frames, allocated by driver
+ *			but managed by vb2 framework.
+ * @name:		string naming this instance (debug purpose)
+ * @list_stream:	list of stream queued for destination only
+ * @frame_num		frame number
+ * @frames:		set of src frames (input, reconstructed & reference)
+ * @priv:		private codec context for this instance, allocated
+ *			by encoder @open time.
+ * @sys_errors:		number of system errors ( memory, resource, pm, ..)
+ * @encode_errors:	number of encoding errors ( hw/driver errors)
+ * @frames_errors:	number of frames errors ( format, size, header ..)
+ * @hw_err:		hardware error detected
+ */
+struct hva_ctx {
+	u32 flags;
+
+	struct v4l2_fh fh;
+	struct hva_device *hdev;
+	struct device *dev;
+
+	u8 client_id;
+
+	/* vb2 queues */
+	struct vb2_queue q_frame;
+	struct vb2_queue q_stream;
+
+	char name[100];
+
+	struct list_head list_stream;
+
+	u32 frame_num;
+
+	struct hva_controls ctrls;
+	struct v4l2_fract time_per_frame;
+	u32 num_frames;
+
+	/* stream */
+	struct hva_streaminfo streaminfo;
+
+	/* frame */
+	struct hva_frameinfo frameinfo;
+
+	/* current encoder */
+	struct hva_encoder *encoder;
+
+	/* stats */
+	u32 encoded_frames;
+
+	/* private data */
+	void *priv;
+
+	/* errors */
+	u32 sys_errors;
+	u32 encode_errors;
+	u32 frame_skipped;
+	u32 frame_errors;
+	bool hw_err;
+
+	/* hardware task descriptor*/
+	struct hva_buffer *task;
+};
+
+/**
+ * struct hva_device - device struct, 1 per probe (so single one for
+ * all platform life)
+ *
+ * @v4l2_dev:		v4l2 device
+ * @vdev:		v4l2 video device
+ * @pdev:		platform device
+ * @dev:		device
+ * @lock:		device lock for critical section &
+ *			V4L2 ops serialization
+ * @instance_id:	instance identifier
+ * @contexts_list:	contexts list
+ * @regs:		register io memory access
+ * @reg_size:		register size
+ * @irq_its:		its interruption
+ * @irq_err:		error interruption
+ * @chip_id:		chipset identifier
+ * @protect_mutex:	mutex use to lock access of hardware
+ * @interrupt:		completion interrupt
+ * @clk:		hva clock
+ * @esram_addr:		esram address
+ * @esram_size:		esram size
+ * @sfl_reg:		Status fifo level register value
+ * @sts_reg:		Status register value
+ * @lmi_err_reg:	Local memory interface Error register value
+ * @emi_err_reg:	External memory interface Error register value
+ * @hec_mif_err_reg:HEC memory interface Error register value
+ * @encoders:		list of all encoders registered
+ * @nb_of_encoders:	number of encoders registered
+ * @nb_of_instances:	number of instance
+ */
+struct hva_device {
+	/* device */
+	struct v4l2_device v4l2_dev;
+	struct video_device *vdev;
+	struct platform_device *pdev;
+	struct device *dev;
+	struct mutex lock; /* device lock for critical section & V4L2 ops */
+	int instance_id;
+	struct hva_ctx *contexts_list[MAX_CONTEXT];
+
+	/* hardware */
+	void __iomem *regs;
+	int regs_size;
+	int irq_its;
+	int irq_err;
+	unsigned long int chip_id;
+	struct mutex protect_mutex; /* mutex use to lock access of hardware */
+	struct completion interrupt;
+	struct clk *clk;
+	u32 esram_addr;
+	u32 esram_size;
+
+	/* registers */
+	u32 sfl_reg;
+	u32 sts_reg;
+	u32 lmi_err_reg;
+	u32 emi_err_reg;
+	u32 hec_mif_err_reg;
+
+	/* encoders */
+	const struct hva_encoder *encoders[HVA_MAX_ENCODERS];
+	u32 nb_of_encoders;
+	u32 nb_of_instances;
+};
+
+struct hva_encoder {
+	struct list_head list;
+	const char *name;
+	u32 streamformat;
+	u32 pixelformat;
+	u32 max_width;
+	u32 max_height;
+
+	/**
+	 * Encoder ops
+	 */
+	int (*open)(struct hva_ctx *ctx);
+	int (*close)(struct hva_ctx *ctx);
+
+	/**
+	 * encode() - encode a single access unit
+	 * @ctx:	(in) instance
+	 * @frame:		(in/out) access unit
+	 *  @frame.size	(in) size of frame to encode
+	 *  @frame.vaddr	(in) virtual address (kernel can read/write)
+	 *  @frame.paddr	(in) physical address (for hardware)
+	 *  @frame.flags	(out) frame type (V4L2_BUF_FLAG_KEYFRAME/
+	 *			PFRAME/BFRAME)
+	 * @stream:	(out) frame with encoded data:
+	 *  @stream.index	(out) identifier of frame
+	 *  @stream.vaddr	(out) virtual address (kernel can read/write)
+	 *  @stream.paddr	(out) physical address (for hardware)
+	 *  @stream.pix		(out) width/height/format/stride/...
+	 *  @stream.flags	(out) stream type (V4L2_BUF_FLAG_KEYFRAME/
+	 *			PFRAME/BFRAME)
+	 *
+	 * Encode the access unit given. Encode is synchronous;
+	 * access unit memory is no more needed after this call.
+	 * After this call, none, one or several frames could
+	 * have been encoded, which can be retrieved using
+	 * get_stream().
+	*/
+	int (*encode)(struct hva_ctx *ctx, struct hva_frame *frame,
+		      struct hva_stream *stream);
+};
+
+static inline const char *profile_str(unsigned int p)
+{
+	switch (p) {
+	case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+		return "baseline profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+		return "main profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
+		return "extended profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+		return "high profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
+		return "high 10 profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
+		return "high 422 profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
+		return "high 444 predictive profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA:
+		return "high 10 intra profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA:
+		return "high 422 intra profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA:
+		return "high 444 intra profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA:
+		return "calvc 444 intra profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE:
+		return "scalable baseline profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH:
+		return "scalable high profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA:
+		return "scalable high intra profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH:
+		return "stereo high profile";
+	case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH:
+		return "multiview high profile";
+	default:
+		return "unknown profile";
+	}
+}
+
+static inline const char *level_str(enum v4l2_mpeg_video_h264_level l)
+{
+	switch (l) {
+	case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+		return "level 1.0";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+		return "level 1b";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+		return "level 1.1";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+		return "level 1.2";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+		return "level 1.3";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+		return "level 2.0";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+		return "level 2.1";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+		return "level 2.2";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+		return "level 3.0";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+		return "level 3.1";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+		return "level 3.2";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+		return "level 4.0";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
+		return "level 4.1";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
+		return "level 4.2";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
+		return "level 5.0";
+	case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
+		return "level 5.1";
+	default:
+		return "unknown level";
+	}
+}
+
+static inline const char *bitrate_mode_str(enum v4l2_mpeg_video_bitrate_mode m)
+{
+	switch (m) {
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+		return "variable bitrate";
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+		return "constant bitrate";
+	default:
+		return "unknown bitrate mode";
+	}
+}
+
+#endif /* HVA_H */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] [media] hva: add h264 support
  2015-12-18 10:45 [PATCH 0/3] support of v4l2 encoder for STMicroelectronics SOC Yannick Fertre
  2015-12-18 10:45 ` [PATCH 1/3] Documentation: devicetree: add STI HVA binding Yannick Fertre
  2015-12-18 10:45 ` [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver Yannick Fertre
@ 2015-12-18 10:45 ` Yannick Fertre
  2 siblings, 0 replies; 6+ messages in thread
From: Yannick Fertre @ 2015-12-18 10:45 UTC (permalink / raw)
  To: linux-media; +Cc: Benjamin Gaignard, hugues.fruchet, kernel

Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
---
 drivers/media/platform/sti/hva/Makefile   |    2 +-
 drivers/media/platform/sti/hva/hva-h264.c | 1225 +++++++++++++++++++++++++++++
 drivers/media/platform/sti/hva/hva-v4l2.c |  126 +++
 3 files changed, 1352 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/platform/sti/hva/hva-h264.c

diff --git a/drivers/media/platform/sti/hva/Makefile b/drivers/media/platform/sti/hva/Makefile
index 7022a33..495894b 100644
--- a/drivers/media/platform/sti/hva/Makefile
+++ b/drivers/media/platform/sti/hva/Makefile
@@ -1,2 +1,2 @@
 obj-$(CONFIG_VIDEO_STI_HVA) := hva.o
-hva-y := hva-v4l2.o hva-hw.o hva-mem.o
+hva-y := hva-v4l2.o hva-hw.o hva-mem.o hva-h264.o
diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c
new file mode 100644
index 0000000..ae57f4b
--- /dev/null
+++ b/drivers/media/platform/sti/hva/hva-h264.c
@@ -0,0 +1,1225 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2015
+ * Authors: Yannick Fertre <yannick.fertre@st.com>
+ *          Hugues Fruchet <hugues.fruchet@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/dma-mapping.h>
+#include "hva.h"
+#include "hva-hw.h"
+#include "hva-mem.h"
+
+#define MAX_SPS_PPS_SIZE 128
+
+#define BITSTREAM_OFFSET_MASK 0x7F
+
+/* video max size*/
+#define H264_MAX_SIZE_W 1920
+#define H264_MAX_SIZE_H 1088
+
+/* macroBlocs number (width & height) */
+#define MB_W(w) ((w + 0xF)  / 0x10)
+#define MB_H(h) ((h + 0xF)  / 0x10)
+
+/* formula to get temporal or spatial data size */
+#define DATA_SIZE(w, h) (MB_W(w) * MB_H(h) * 16)
+
+#define SEARCH_WINDOW_BUFFER_MAX_SIZE(w) ((4 * MB_W(w) + 42) * 256 * 3 / 2)
+#define CABAC_CONTEXT_BUFFER_MAX_SIZE(w) (MB_W(w) * 16)
+#define CTX_MB_BUFFER_MAX_SIZE(w) (MB_W(w) * 16 * 8)
+#define SLICE_HEADER_SIZE (4 * 16)
+#define BRC_DATA_SIZE (5 * 16)
+
+/* source buffer copy in YUV 420 MB-tiled format with size=16*256*3/2 */
+#define CURRENT_WINDOW_BUFFER_MAX_SIZE (16 * 256 * 3 / 2)
+
+/*
+ * 4 lines of pixels (in Luma, Chroma blue and Chroma red) of top MB
+ * for deblocking with size=4*16*MBx*2
+ */
+#define LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(w) (4 * 16 * MB_W(w) * 2)
+
+/* factor for bitrate and cpb buffer size max values if profile >= high */
+#define H264_FACTOR_HIGH 1200
+
+/* factor for bitrate and cpb buffer size max values if profile < high */
+#define H264_FACTOR_BASELINE 1000
+
+struct h264_profile {
+	enum v4l2_mpeg_video_h264_level level;
+	u32 max_mb_per_seconds;
+	u32 max_frame_size;
+	u32 max_bitrate;
+	u32 max_cpb_size;
+	u32 min_comp_ratio;
+};
+
+static const struct h264_profile h264_infos_list[] = {
+	{V4L2_MPEG_VIDEO_H264_LEVEL_1_0, 1485, 99, 64, 175, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_1B, 1485, 99, 128, 350, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_1_1, 3000, 396, 192, 500, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_1_2, 6000, 396, 384, 1000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_1_3, 11880, 396, 768, 2000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_2_0, 11880, 396, 2000, 2000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_2_1, 19800, 792, 4000, 4000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_2_2, 20250, 1620, 4000, 4000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_3_0, 40500, 1620, 10000, 10000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_3_1, 108000, 3600, 14000, 14000, 4},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_3_2, 216000, 5120, 20000, 20000, 4},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 245760, 8192, 20000, 25000, 4},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_4_1, 245760, 8192, 50000, 62500, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_4_2, 522240, 8704, 50000, 62500, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_5_0, 589824, 22080, 135000, 135000, 2},
+	{V4L2_MPEG_VIDEO_H264_LEVEL_5_1, 983040, 36864, 240000, 240000, 2}
+};
+
+enum hva_brc_type {
+	BRC_TYPE_NONE = 0,
+	BRC_TYPE_CBR = 1,
+	BRC_TYPE_VBR = 2,
+	BRC_TYPE_VBR_LOW_DELAY = 3
+};
+
+enum hva_entropy_coding_mode {
+	CAVLC = 0,
+	CABAC = 1
+};
+
+enum hva_picture_coding_type {
+	PICTURE_CODING_TYPE_I = 0,
+	PICTURE_CODING_TYPE_P = 1,
+	PICTURE_CODING_TYPE_B = 2
+};
+
+enum hva_h264_sampling_mode {
+	SAMPLING_MODE_NV12 = 0,
+	SAMPLING_MODE_UYVY = 1,
+	SAMPLING_MODE_RGB3 = 3,
+	SAMPLING_MODE_XRGB4 = 4,
+	SAMPLING_MODE_NV21 = 8,
+	SAMPLING_MODE_VYUY = 9,
+	SAMPLING_MODE_BGR3 = 11,
+	SAMPLING_MODE_XBGR4 = 12,
+	SAMPLING_MODE_RGBX4 = 20,
+	SAMPLING_MODE_BGRX4 = 28
+};
+
+enum hva_h264_nalu_type {
+	NALU_TYPE_UNKNOWN = 0,
+	NALU_TYPE_SLICE = 1,
+	NALU_TYPE_SLICE_DPA = 2,
+	NALU_TYPE_SLICE_DPB = 3,
+	NALU_TYPE_SLICE_DPC = 4,
+	NALU_TYPE_SLICE_IDR = 5,
+	NALU_TYPE_SEI = 6,
+	NALU_TYPE_SPS = 7,
+	NALU_TYPE_PPS = 8,
+	NALU_TYPE_AU_DELIMITER = 9,
+	NALU_TYPE_SEQ_END = 10,
+	NALU_TYPE_STREAM_END = 11,
+	NALU_TYPE_FILLER_DATA = 12,
+	NALU_TYPE_SPS_EXT = 13,
+	NALU_TYPE_PREFIX_UNIT = 14,
+	NALU_TYPE_SUBSET_SPS = 15,
+	NALU_TYPE_SLICE_AUX = 19,
+	NALU_TYPE_SLICE_EXT = 20
+};
+
+enum hva_h264_sei_payload_type {
+	SEI_BUFFERING_PERIOD = 0,
+	SEI_PICTURE_TIMING = 1,
+	SEI_STEREO_VIDEO_INFO = 21,
+	SEI_FRAME_PACKING_ARRANGEMENT = 45
+};
+
+/**
+ * stereo Video Info struct
+ */
+struct hva_h264_stereo_video_sei {
+	u8 field_views_flag;
+	u8 top_field_is_left_view_flag;
+	u8 current_frame_is_left_view_flag;
+	u8 next_frame_is_second_view_flag;
+	u8 left_view_self_contained_flag;
+	u8 right_view_self_contained_flag;
+};
+
+/**
+ * @frame_width: width in pixels of the buffer containing the input frame
+ * @frame_height: height in pixels of the buffer containing the input frame
+ * @frame_num: the parameter to be written in the slice header
+ * @picture_coding_type: type I, P or B
+ * @pic_order_cnt_type: POC mode, as defined in H264 std : can be 0,1,2
+ * @first_picture_in_sequence: flag telling to encoder that this is the
+ *			       first picture in a video sequence.
+ *			       Used for VBR
+ * @slice_size_type: 0 = no constraint to close the slice
+ *		     1= a slice is closed as soon as the slice_mb_size limit
+ *			is reached
+ *		     2= a slice is closed as soon as the slice_byte_size limit
+ *			is reached
+ *		     3= a slice is closed as soon as either the slice_byte_size
+ *			limit or the slice_mb_size limit is reached
+ * @slice_mb_size: defines the slice size in number of macroblocks
+ *		   (used when slice_size_type=1 or slice_size_type=3)
+ * @ir_param_option: defines the number of macroblocks per frame to be
+ *		     refreshed by AIR algorithm OR the refresh period
+ *		     by CIR algorithm
+ * @intra_refresh_type: enables the adaptive intra refresh algorithm.
+ *			Disable=0 / Adaptative=1 and Cycle=2 as intra refresh
+ * @use_constrained_intra_flag: constrained_intra_pred_flag from PPS
+ * @transform_mode: controls the use of 4x4/8x8 transform mode
+ * @disable_deblocking_filter_idc:
+ *		     0: specifies that all luma and chroma block edges of
+ *			the slice are filtered.
+ *		     1: specifies that deblocking is disabled for all block
+ *			edges of the slice.
+ *		     2: specifies that all luma and chroma block edges of
+ *			the slice are filtered with exception of the block edges
+ *			that coincide with slice boundaries
+ * @slice_alpha_c0_offset_div2: to be written in slice header,
+ *				controls deblocking
+ * @slice_beta_offset_div2: to be written in slice header,
+ *			    controls deblocking
+ * @encoder_complexity: encoder complexity control (IME).
+ *		     0 = I_16x16, P_16x16, Full ME Complexity
+ *		     1 = I_16x16, I_NxN, P_16x16, Full ME Complexity
+ *		     2 = I_16x16, I_NXN, P_16x16, P_WxH, Full ME Complexity
+ *		     4 = I_16x16, P_16x16, Reduced ME Complexity
+ *		     5 = I_16x16, I_NxN, P_16x16, Reduced ME Complexity
+ *		     6 = I_16x16, I_NXN, P_16x16, P_WxH, Reduced ME Complexity
+ *  @chroma_qp_index_offset: coming from picture parameter set
+ *			     (PPS see [H.264 STD] §7.4.2.2)
+ *  @entropy_coding_mode: entropy coding mode.
+ *			  0 = CAVLC
+ *			  1 = CABAC
+ * @brc_type: selects the bit-rate control algorithm
+ *		     0 = constant Qp, (no BRC)
+ *		     1 = CBR
+ *		     2 = VBR
+ * @quant: Quantization param used in case of fix QP encoding (no BRC)
+ * @non_VCL_NALU_Size: size of non-VCL NALUs (SPS, PPS, filler),
+ *		       used by BRC
+ * @cpb_buffer_size: size of Coded Picture Buffer, used by BRC
+ * @bit_rate: target bitrate, for BRC
+ * @qp_min: min QP threshold
+ * @qp_max: max QP threshold
+ * @framerate_num: target framerate numerator , used by BRC
+ * @framerate_den: target framerate denomurator , used by BRC
+ * @delay: End-to-End Initial Delay
+ * @strict_HRD_compliancy: flag for HDR compliancy (1)
+ *			   May impact quality encoding
+ * @addr_source_buffer: address of input frame buffer for current frame
+ * @addr_fwd_Ref_Buffer: address of reference frame buffer
+ * @addr_rec_buffer: address of reconstructed frame buffer
+ * @addr_output_bitstream_start: output bitstream start address
+ * @addr_output_bitstream_end: output bitstream end address
+ * @addr_external_sw : address of external search window
+ * @addr_lctx : address of context picture buffer
+ * @addr_local_rec_buffer: address of local reconstructed buffer
+ * @addr_spatial_context: address of spatial context buffer
+ * @bitstream_offset: offset in bits between aligned bitstream start
+ *		      address and first bit to be written by HVA.
+ *		      Range value is [0..63]
+ * @sampling_mode: Input picture format .
+ *		     0: YUV420 semi_planar Interleaved
+ *		     1: YUV422 raster Interleaved
+ * @addr_param_out: address of output parameters structure
+ * @addr_scaling_matrix: address to the coefficient of
+ *			 the inverse scaling matrix
+ * @addr_scaling_matrix_dir: address to the coefficient of
+ *			     the direct scaling matrix
+ * @addr_cabac_context_buffer: address of cabac context buffer
+ * @GmvX: Input information about the horizontal global displacement of
+ *	  the encoded frame versus the previous one
+ * @GmvY: Input information about the vertical global displacement of
+ *	  the encoded frame versus the previous one
+ * @window_width: width in pixels of the window to be encoded inside
+ *		  the input frame
+ * @window_height: width in pixels of the window to be encoded inside
+ *		   the input frame
+ * @window_horizontal_offset: horizontal offset in pels for input window
+ *			      within input frame
+ * @window_vertical_offset: vertical offset in pels for input window
+ *			    within input frame
+ * @addr_roi: Map of QP offset for the Region of Interest algorithm and
+ *	      also used for Error map.
+ *	      Bit 0-6 used for qp offset (value -64 to 63).
+ *	      Bit 7 used to force intra
+ * @addr_slice_header: address to slice header
+ * @slice_header_size_in_bits: size in bits of the Slice header
+ * @slice_header_offset0: Slice header offset where to insert
+ *			  first_Mb_in_slice
+ * @slice_header_offset1: Slice header offset where to insert
+ *			  slice_qp_delta
+ * @slice_header_offset2: Slice header offset where to insert
+ *			  num_MBs_in_slice
+ * @slice_synchro_enable: enable "slice ready" interrupt after each slice
+ * @max_slice_number: Maximum number of slice in a frame
+ *		      (0 is strictly forbidden)
+ * @rgb2_yuv_y_coeff: Four coefficients (C0C1C2C3) to convert from RGB to
+ *		      YUV for the Y component.
+ *		      Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
+ * @rgb2_yuv_u_coeff: four coefficients (C0C1C2C3) to convert from RGB to
+ *		      YUV for the Y component.
+ *		      Y = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
+ * @rgb2_yuv_v_coeff: Four coefficients (C0C1C2C3) to convert from RGB to
+ *		      YUV for the U (Cb) component.
+ *		      U = C0*R + C1*G + C2*B + C3 (C0 is on byte 0)
+ * @slice_byte_size: maximum slice size in bytes
+ *		     (used when slice_size_type=2 or slice_size_type=3)
+ * @max_air_intra_mb_nb: Maximum number of intra macroblock in a frame
+ *			 for the AIR algorithm
+ * @brc_no_skip: Disable skipping in the Bitrate Controller
+ * @addr_brc_in_out_parameter: address of static buffer for BRC parameters
+ */
+struct hva_h264_td_v397 {
+	u16 frame_width;
+	u16 frame_height;
+	u32 frame_num;
+	u16 picture_coding_type;
+	u16 reserved1;
+	u16 pic_order_cnt_type;
+	u16 first_picture_in_sequence;
+	u16 slice_size_type;
+	u16 reserved2;
+	u32 slice_mb_size;
+	u16 ir_param_option;
+	u16 intra_refresh_type;
+	u16 use_constrained_intra_flag;
+	u16 transform_mode;
+	u16 disable_deblocking_filter_idc;
+	s16 slice_alpha_c0_offset_div2;
+	s16 slice_beta_offset_div2;
+	u16 encoder_complexity;
+	s16 chroma_qp_index_offset;
+	u16 entropy_coding_mode;
+	u16 brc_type;
+	u16 quant;
+	u32 non_vcl_nalu_size;
+	u32 cpb_buffer_size;
+	u32 bit_rate;
+	u16 qp_min;
+	u16 qp_max;
+	u16 framerate_num;
+	u16 framerate_den;
+	u16 delay;
+	u16 strict_hrd_compliancy;
+	u32 addr_source_buffer;
+	u32 addr_fwd_ref_buffer;
+	u32 addr_rec_buffer;
+	u32 addr_output_bitstream_start;
+	u32 addr_output_bitstream_end;
+	u32 addr_external_sw;
+	u32 addr_lctx;
+	u32 addr_local_rec_buffer;
+	u32 addr_spatial_context;
+	u16 bitstream_offset;
+	u16 sampling_mode;
+	u32 addr_param_out;
+	u32 addr_scaling_matrix;
+	u32 addr_scaling_matrix_dir;
+	u32 addr_cabac_context_buffer;
+	u32 reserved3;
+	u32 reserved4;
+	s16 gmv_x;
+	s16 gmv_y;
+	u16 window_width;
+	u16 window_height;
+	u16 window_horizontal_offset;
+	u16 window_vertical_offset;
+	u32 addr_roi;
+	u32 addr_slice_header;
+	u16 slice_header_size_in_bits;
+	u16 slice_header_offset0;
+	u16 slice_header_offset1;
+	u16 slice_header_offset2;
+	u32 reserved5;
+	u32 reserved6;
+	u16 reserved7;
+	u16 reserved8;
+	u16 slice_synchro_enable;
+	u16 max_slice_number;
+	u32 rgb2_yuv_y_coeff;
+	u32 rgb2_yuv_u_coeff;
+	u32 rgb2_yuv_v_coeff;
+	u32 slice_byte_size;
+	u16 max_air_intra_mb_nb;
+	u16 brc_no_skip;
+	u32 addr_temporal_context;
+	u32 addr_brc_in_out_parameter;
+};
+
+/**
+ * @ slice_size: slice size
+ * @ slice_start_time: start time
+ * @ slice_stop_time: stop time
+ * @ slice_num: slice number
+ */
+struct hva_h264_slice_po {
+	u32 slice_size;
+	u32 slice_start_time;
+	u32 slice_end_time;
+	u32 slice_num;
+};
+
+/**
+ * @ bitstream_size: bitstream size
+ * @ dct_bitstream_size: dtc bitstream size
+ * @ stuffing_bits: number of stuffing bits inserted by the encoder
+ * @ removal_time: removal time of current frame (nb of ticks 1/framerate)
+ * @ hvc_start_time: hvc start time
+ * @ hvc_stop_time: hvc stop time
+ * @ slice_count: slice count
+ */
+struct hva_h264_po_v397 {
+	u32 bitstream_size;
+	u32 dct_bitstream_size;
+	u32 stuffing_bits;
+	u32 removal_time;
+	u32 hvc_start_time;
+	u32 hvc_stop_time;
+	u32 slice_count;
+	u32 reserved0;
+	struct hva_h264_slice_po slice_params[16];
+};
+
+union hva_h264_td {
+	struct hva_h264_td_v397 v397;
+};
+
+union hva_h264_po {
+	struct hva_h264_po_v397 v397;
+};
+
+struct hva_h264_task {
+	union hva_h264_td td;
+	union hva_h264_po po;
+};
+
+struct hva_h264_ctx {
+	struct hva_buffer *seq_info_buf;
+	struct hva_buffer *ref_frame;
+	struct hva_buffer *rec_frame;
+};
+
+static int hva_h264_fill_slice_header(struct hva_ctx *pctx,
+				      u8 *slice_header_addr,
+				      struct hva_controls *ctrls,
+				      int frame_num,
+				      u16 *header_size,
+				      u16 *header_offset0,
+				      u16 *header_offset1,
+				      u16 *header_offset2)
+{
+	/*
+	 * with this HVA hardware version, part of the slice header is computed
+	 * on host and part by hardware.
+	 * in order to avoid introducing heavy bit-parsing code
+	 * (about 500 lines) - that we don't want on kernel side -,
+	 * the part of host is precomputed and available through this array.
+	 */
+	struct device *dev = ctx_to_dev(pctx);
+	int  cabac = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC;
+	const unsigned char slice_header[] = { 0x00, 0x00, 0x00, 0x01,
+					       0x41, 0x34, 0x07, 0x00};
+	int idr_pic_id = frame_num % 2;
+	enum hva_picture_coding_type type;
+	u32 frame_order = frame_num % ctrls->gop_size;
+
+	if (!(frame_num % ctrls->gop_size))
+		type = PICTURE_CODING_TYPE_I;
+	else
+		type = PICTURE_CODING_TYPE_P;
+
+	memcpy(slice_header_addr, slice_header, sizeof(slice_header));
+
+	*header_size = 56;
+	*header_offset0 = 40;
+	*header_offset1 = 13;
+	*header_offset2 = 0;
+
+	if (type == PICTURE_CODING_TYPE_I) {
+		slice_header_addr[4] = 0x65;
+		slice_header_addr[5] = 0x11;
+
+		/* toggle the I frame */
+		if ((frame_num / ctrls->gop_size) % 2) {
+			*header_size += 4;
+			*header_offset1 += 4;
+			slice_header_addr[6] = 0x04;
+			slice_header_addr[7] = 0x70;
+
+		} else {
+			*header_size += 2;
+			*header_offset1 += 2;
+			slice_header_addr[6] = 0x09;
+			slice_header_addr[7] = 0xC0;
+		}
+	} else {
+		if (ctrls->entropy_mode == cabac) {
+			*header_size += 1;
+			*header_offset1 += 1;
+			slice_header_addr[7] = 0x80;
+		}
+		/*
+		 * update slice header with P frame order
+		 * frame order is limited to 16 (coded on 4bits only)
+		 */
+		slice_header_addr[5] += ((frame_order & 0x0C) >> 2);
+		slice_header_addr[6] += ((frame_order & 0x03) << 6);
+	}
+
+	dev_dbg(dev,
+		"%s   %s slice header order %d idrPicId %d header size %d\n",
+		pctx->name, __func__, frame_order, idr_pic_id, *header_size);
+	return 0;
+}
+
+static int hva_h264_fill_data_nal(struct hva_ctx *pctx,
+				  unsigned int stuffing_bytes, u8 *addr,
+				  unsigned int *size)
+{
+	struct device *dev = ctx_to_dev(pctx);
+	const u8 start[] = { 0x00, 0x00, 0x00, 0x01 };
+
+	dev_dbg(dev, "%s   %s stuffing bytes %d\n", pctx->name, __func__,
+		stuffing_bytes);
+
+	/* start code */
+	memcpy(addr + *size, start, sizeof(start));
+	*size += sizeof(start);
+
+	/* nal_unit_type */
+	addr[*size] = NALU_TYPE_FILLER_DATA;
+	*size += 1;
+
+	memset(addr + *size, 0xff, stuffing_bytes);
+	*size += stuffing_bytes;
+
+	addr[*size] = 0x80;
+	*size += 1;
+
+	return 0;
+}
+
+static int hva_h264_fill_sei_nal(struct hva_ctx *pctx,
+				 enum hva_h264_sei_payload_type type,
+				 u8 *addr, u32 *size)
+{
+	struct device *dev = ctx_to_dev(pctx);
+	const u8 start[] = { 0x00, 0x00, 0x00, 0x01 };
+	struct hva_h264_stereo_video_sei info;
+	u8 offset = 7;
+	u8 msg = 0;
+
+	/* start code */
+	memcpy(addr + *size, start, sizeof(start));
+	*size += sizeof(start);
+
+	/* nal_unit_type */
+	addr[*size] = NALU_TYPE_SEI;
+	*size += 1;
+
+	/* payload type */
+	addr[*size] = type;
+	*size += 1;
+
+	switch (type) {
+	case SEI_STEREO_VIDEO_INFO:
+		memset(&info, 0, sizeof(info));
+
+		/* set to top/bottom frame packing arrangement */
+		info.field_views_flag = 1;
+		info.top_field_is_left_view_flag = 1;
+
+		/* payload size */
+		addr[*size] = 1;
+		*size += 1;
+
+		/* payload */
+		msg = info.field_views_flag << offset--;
+
+		if (info.field_views_flag) {
+			msg |= info.top_field_is_left_view_flag <<
+			       offset--;
+		} else {
+			msg |= info.current_frame_is_left_view_flag <<
+			       offset--;
+			msg |= info.next_frame_is_second_view_flag <<
+			       offset--;
+		}
+		msg |= info.left_view_self_contained_flag << offset--;
+		msg |= info.right_view_self_contained_flag << offset--;
+
+		addr[*size] = msg;
+		*size += 1;
+
+		addr[*size] = 0x80;
+		*size += 1;
+
+		return 0;
+	case SEI_BUFFERING_PERIOD:
+	case SEI_PICTURE_TIMING:
+	case SEI_FRAME_PACKING_ARRANGEMENT:
+	default:
+		dev_err(dev, " %s   sei nal type not supported %d\n",
+			pctx->name, type);
+		return -EINVAL;
+	}
+}
+
+static inline int hva_h264_prepare_task_v397(struct hva_ctx *pctx,
+					     struct hva_buffer *task,
+					     struct hva_h264_td_v397 *td,
+					     struct hva_frame *frame,
+					     struct hva_stream *stream)
+{
+	struct hva_device *hva = ctx_to_hdev(pctx);
+	struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv;
+	struct device *dev = ctx_to_dev(pctx);
+	struct hva_buffer *seq_info_buf = ctx->seq_info_buf;
+	struct hva_buffer *fwd_ref_frame = ctx->ref_frame;
+	struct hva_buffer *loc_rec_frame = ctx->rec_frame;
+	struct hva_controls *ctrls = &pctx->ctrls;
+	struct v4l2_fract *time_per_frame = &pctx->time_per_frame;
+	int cavlc =  V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC;
+	u32 frame_num = pctx->frame_num;
+	u32 addr_esram = hva->esram_addr;
+	enum v4l2_mpeg_video_h264_level level;
+	dma_addr_t paddr = 0;
+	u8 *slice_header_vaddr;
+	u32 frame_width = pctx->frameinfo.frame_width;
+	u32 frame_height = pctx->frameinfo.frame_height;
+	u32 max_cpb_buffer_size;
+	unsigned int payload = stream->payload;
+	u32 max_bitrate;
+
+	/* check width and height parameters */
+	if ((frame_width > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H)) ||
+	    (frame_height > max(H264_MAX_SIZE_W, H264_MAX_SIZE_H))) {
+		dev_err(dev,
+			"%s   width(%d) or height(%d) exceeds limits (%dx%d)\n",
+			pctx->name, frame_width, frame_height,
+			H264_MAX_SIZE_W, H264_MAX_SIZE_H);
+		pctx->frame_errors++;
+		return -EINVAL;
+	}
+
+	level = ctrls->level;
+
+	memset(td, 0, sizeof(struct hva_h264_td_v397));
+
+	td->frame_width = frame_width;
+	td->frame_height = frame_height;
+
+	/* set frame alignement */
+	td->window_width =  ALIGN(pctx->frameinfo.width, 16);
+	td->window_height = ALIGN(pctx->frameinfo.height, 16);
+	td->window_horizontal_offset = 0;
+	td->window_vertical_offset = 0;
+
+	td->first_picture_in_sequence = (!frame_num) ? 1 : 0;
+
+	/* pic_order_cnt_type hard coded to '2' as only I & P frames */
+	td->pic_order_cnt_type = 2;
+
+	/* useConstrainedIntraFlag set to false for better coding efficiency */
+	td->use_constrained_intra_flag = false;
+	td->brc_type = (ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+			? BRC_TYPE_CBR : BRC_TYPE_VBR;
+
+	/* enable/disable intra refresh type */
+	td->intra_refresh_type = ctrls->intra_refresh ? 1 : 0;
+
+	td->entropy_coding_mode = (ctrls->entropy_mode == cavlc) ? CAVLC :
+				  CABAC;
+
+	/* convert bitrate in bits per seconds */
+	td->bit_rate = ctrls->bitrate * 1000;
+
+	/* set framerate, framerate = 1 n/ time per frame */
+	if (time_per_frame->numerator >= 536) {
+		/*
+		 * due to a hardware bug, framerate denominator can't exceed
+		 * 536 (BRC overflow). Compute nearest framerate
+		 */
+		td->framerate_den = 1;
+		td->framerate_num = (time_per_frame->denominator +
+				    (time_per_frame->numerator >> 1) - 1) /
+				    time_per_frame->numerator;
+
+		/*
+		 * update bitrate to introduce a correction due to
+		 * the new framerate
+		 * new bitrate = (old bitrate * new framerate) / old framerate
+		 */
+		td->bit_rate /= time_per_frame->numerator;
+		td->bit_rate *= time_per_frame->denominator;
+		td->bit_rate /= td->framerate_num;
+	} else {
+		td->framerate_den = time_per_frame->numerator;
+		td->framerate_num = time_per_frame->denominator;
+	}
+
+	/* compute maximum bitrate depending on profile */
+	if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+		max_bitrate = h264_infos_list[level].max_bitrate *
+			      H264_FACTOR_HIGH;
+	else
+		max_bitrate = h264_infos_list[level].max_bitrate *
+			      H264_FACTOR_BASELINE;
+
+	/* check if bitrate doesn't exceed max size */
+	if (td->bit_rate > max_bitrate) {
+		dev_warn(dev,
+			 "%s   bitrate (%d) larger than level and profile allow, clip to %d\n",
+			 pctx->name, td->bit_rate, max_bitrate);
+		td->bit_rate = max_bitrate;
+	}
+
+	/* convert cpb_buffer_size in bits */
+	td->cpb_buffer_size = ctrls->cpb_size * 1000;
+
+	/* compute maximum cpb buffer size depending on profile */
+	if (ctrls->profile >= V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
+		max_cpb_buffer_size =
+		    h264_infos_list[level].max_cpb_size * H264_FACTOR_HIGH;
+	else
+		max_cpb_buffer_size =
+		    h264_infos_list[level].max_cpb_size * H264_FACTOR_BASELINE;
+
+	/* check if cpb buffer size doesn't exceed max size */
+	if (td->cpb_buffer_size > max_cpb_buffer_size) {
+		dev_warn(dev,
+			 "%s   cpb size larger than level %d allows, clip to %d\n",
+			pctx->name, td->cpb_buffer_size,
+			max_cpb_buffer_size);
+		td->cpb_buffer_size = max_cpb_buffer_size;
+	}
+
+	/* enable skipping in the Bitrate Controller */
+	td->brc_no_skip = 0;
+
+	/* initial delay */
+	if ((ctrls->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) &&
+	    td->bit_rate)
+		td->delay = 1000 * (td->cpb_buffer_size / td->bit_rate);
+	else
+		td->delay = 0;
+
+	switch (pctx->frameinfo.fmt.pixelformat) {
+	case V4L2_PIX_FMT_NV12:
+		td->sampling_mode = SAMPLING_MODE_NV12;
+		break;
+	case V4L2_PIX_FMT_NV21:
+		td->sampling_mode = SAMPLING_MODE_NV21;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		td->sampling_mode = SAMPLING_MODE_UYVY;
+		break;
+	case V4L2_PIX_FMT_VYUY:
+		td->sampling_mode = SAMPLING_MODE_VYUY;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		td->sampling_mode = SAMPLING_MODE_RGB3;
+		break;
+	case V4L2_PIX_FMT_BGR24:
+		td->sampling_mode = SAMPLING_MODE_BGR3;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+		td->sampling_mode = SAMPLING_MODE_RGBX4;
+		break;
+	case V4L2_PIX_FMT_BGR32:
+		td->sampling_mode = SAMPLING_MODE_BGRX4;
+		break;
+	case V4L2_PIX_FMT_XRGB32:
+		td->sampling_mode = SAMPLING_MODE_XRGB4;
+		break;
+	case V4L2_PIX_FMT_XBGR32:
+		td->sampling_mode = SAMPLING_MODE_XBGR4;
+		break;
+	default:
+		dev_err(dev, "%s   invalid source pixel format\n",
+			pctx->name);
+		pctx->frame_errors++;
+		return -EINVAL;
+	}
+
+	/*
+	 * fill matrix color converter (RGB to YUV)
+	 * Y = 0,299 R + 0,587 G + 0,114 B
+	 * Cb = -0,1687 R -0,3313 G + 0,5 B + 128
+	 * Cr = 0,5 R - 0,4187 G - 0,0813 B + 128
+	 */
+	td->rgb2_yuv_y_coeff = 0x12031008;
+	td->rgb2_yuv_u_coeff = 0x800EF7FB;
+	td->rgb2_yuv_v_coeff = 0x80FEF40E;
+
+	/* enable/disable transform mode */
+	td->transform_mode = ctrls->dct8x8;
+
+	/* encoder complexity fix to 2, ENCODE_I_16x16_I_NxN_P_16x16_P_WxH */
+	td->encoder_complexity = 2;
+
+	/* quant fix to 28, default VBR value */
+	td->quant = 28;
+
+	if (td->framerate_den == 0) {
+		dev_err(dev, "%s   invalid framerate\n", pctx->name);
+		pctx->frame_errors++;
+		return -EINVAL;
+	}
+
+	/* if automatic framerate, deactivate bitrate controller */
+	if (td->framerate_num == 0)
+		td->brc_type = 0;
+
+	/* compliancy fix to true */
+	td->strict_hrd_compliancy = 1;
+
+	/* set minimum & maximum quantizers */
+	td->qp_min = clamp_val(ctrls->qpmin, 0, 51);
+	td->qp_max = clamp_val(ctrls->qpmax, 0, 51);
+
+	td->addr_source_buffer = frame->paddr;
+	td->addr_fwd_ref_buffer = fwd_ref_frame->paddr;
+	td->addr_rec_buffer = loc_rec_frame->paddr;
+
+	td->addr_output_bitstream_end = (u32)stream->paddr +
+					vb2_plane_size(&stream->v4l2.vb2_buf,
+						       0);
+
+	td->addr_output_bitstream_start = (u32)stream->paddr;
+	td->bitstream_offset = (((u32)stream->paddr & 0xF) << 3) &
+			       BITSTREAM_OFFSET_MASK;
+
+	td->addr_param_out = (u32)task->paddr +
+			     offsetof(struct hva_h264_task, po);
+
+	/* swap spatial and temporal context */
+	if (frame_num % 2) {
+		paddr = seq_info_buf->paddr;
+		td->addr_spatial_context =  ALIGN(paddr, 0x100);
+		paddr = seq_info_buf->paddr + DATA_SIZE(frame_width,
+							frame_height);
+		td->addr_temporal_context = ALIGN(paddr, 0x100);
+	} else {
+		paddr = seq_info_buf->paddr;
+		td->addr_temporal_context = ALIGN(paddr, 0x100);
+		paddr = seq_info_buf->paddr + DATA_SIZE(frame_width,
+							frame_height);
+		td->addr_spatial_context =  ALIGN(paddr, 0x100);
+	}
+
+	paddr = seq_info_buf->paddr + 2 * DATA_SIZE(frame_width, frame_height);
+
+	td->addr_brc_in_out_parameter =  ALIGN(paddr, 0x100);
+
+	paddr = td->addr_brc_in_out_parameter + BRC_DATA_SIZE;
+	td->addr_slice_header =  ALIGN(paddr, 0x100);
+	td->addr_external_sw =  ALIGN(addr_esram, 0x100);
+
+	addr_esram += SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width);
+	td->addr_local_rec_buffer = ALIGN(addr_esram, 0x100);
+
+	addr_esram += LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width);
+	td->addr_lctx = ALIGN(addr_esram, 0x100);
+
+	addr_esram += CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height));
+	td->addr_cabac_context_buffer = ALIGN(addr_esram, 0x100);
+
+	if (!(frame_num % ctrls->gop_size)) {
+		td->picture_coding_type = PICTURE_CODING_TYPE_I;
+		stream->v4l2.flags |= V4L2_BUF_FLAG_KEYFRAME;
+	} else {
+		td->picture_coding_type = PICTURE_CODING_TYPE_P;
+		stream->v4l2.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+	}
+
+	/* fill the slice header part */
+	slice_header_vaddr = seq_info_buf->vaddr + (td->addr_slice_header -
+			     seq_info_buf->paddr);
+
+	hva_h264_fill_slice_header(pctx, slice_header_vaddr, ctrls, frame_num,
+				   &td->slice_header_size_in_bits,
+				   &td->slice_header_offset0,
+				   &td->slice_header_offset1,
+				   &td->slice_header_offset2);
+
+	td->chroma_qp_index_offset = 2;
+	td->slice_synchro_enable = 0;
+	td->max_slice_number = 1;
+
+	/*
+	 * check the sps/pps header size for key frame only
+	 * sps/pps header was previously fill by libv4l
+	 * during qbuf of stream buffer
+	 */
+	if ((stream->v4l2.flags == V4L2_BUF_FLAG_KEYFRAME) &&
+	    (payload > MAX_SPS_PPS_SIZE)) {
+		dev_err(dev, "%s   invalid sps/pps size %d\n", pctx->name,
+			payload);
+		pctx->frame_errors++;
+		return -EINVAL;
+	}
+
+	if (stream->v4l2.flags != V4L2_BUF_FLAG_KEYFRAME)
+		payload = 0;
+
+	/* add SEI nal (video stereo info) */
+	if (ctrls->sei_fp && hva_h264_fill_sei_nal(pctx, SEI_STEREO_VIDEO_INFO,
+						   (u8 *)stream->vaddr,
+						   &payload)) {
+		dev_err(dev, "%s   fail to get SEI nal\n", pctx->name);
+		pctx->frame_errors++;
+		return -EINVAL;
+	}
+
+	/* fill size of non-VCL NAL units (SPS, PPS, filler and SEI) */
+	td->non_vcl_nalu_size = payload * 8;
+
+	/* compute bitstream offset & new start address of bitstream */
+	td->addr_output_bitstream_start += ((payload >> 4) << 4);
+	td->bitstream_offset += (payload - ((payload >> 4) << 4)) * 8;
+
+	stream->payload = payload;
+
+	return 0;
+}
+
+static int hva_h264_prepare_task(struct hva_ctx *pctx,
+				 struct hva_buffer *task,
+				 struct hva_frame *frame,
+				 struct hva_stream *stream)
+{
+	struct hva_device *hva = ctx_to_hdev(pctx);
+	struct hva_h264_task *video_task = task->vaddr;
+	union hva_h264_td *td = &video_task->td;
+	int ret = 0;
+
+	mutex_lock(&hva->protect_mutex);
+
+	/* task descriptors on V397 & V400 are similar */
+	if ((hva->chip_id == HVA_VERSION_V397) ||
+	    (hva->chip_id == HVA_VERSION_V400)) {
+		ret = hva_h264_prepare_task_v397(pctx,
+						 task,
+						 &td->v397,
+						 frame,
+						 stream);
+	}
+
+	mutex_unlock(&hva->protect_mutex);
+	return ret;
+}
+
+static unsigned int hva_h264_get_au_size(struct hva_ctx *pctx,
+					 struct hva_buffer *task)
+{
+	struct hva_device *hva = ctx_to_hdev(pctx);
+	struct device *dev = ctx_to_dev(pctx);
+	struct hva_h264_task *video_task = task->vaddr;
+	union hva_h264_po *po = &video_task->po;
+
+	/* task descriptors on V397 & V400 are similar */
+	if ((hva->chip_id == HVA_VERSION_V397) ||
+	    (hva->chip_id == HVA_VERSION_V400))
+		return po->v397.bitstream_size;
+
+	dev_err(dev, "unknown chipset identifier 0x%lx\n", hva->chip_id);
+
+	return 0;
+}
+
+static u32 hva_h264_get_stuffing_bytes(struct hva_ctx *pctx,
+				       struct hva_buffer *task)
+{
+	struct hva_device *hva = ctx_to_hdev(pctx);
+	struct device *dev = ctx_to_dev(pctx);
+	struct hva_h264_task *video_task = task->vaddr;
+	union hva_h264_po *po = &video_task->po;
+
+	/* task descriptors on V397 & V400 are similar */
+	if ((hva->chip_id == HVA_VERSION_V397) ||
+	    (hva->chip_id == HVA_VERSION_V400))
+		return po->v397.stuffing_bits >> 3;
+
+	dev_err(dev, "unknown chipset identifier 0x%lx\n", hva->chip_id);
+
+	return 0;
+}
+
+/*
+ *              codec ioctls operations
+ */
+
+static int hva_h264_open(struct hva_ctx *pctx)
+{
+	struct device *dev = ctx_to_dev(pctx);
+	struct hva_h264_ctx *ctx = NULL;
+	struct hva_device *hva = ctx_to_hdev(pctx);
+	u32 frame_width = pctx->frameinfo.frame_width;
+	u32 frame_height = pctx->frameinfo.frame_height;
+	u32 size;
+	int ret = 0;
+
+	/* check esram size necessary to encode a frame */
+	size = SEARCH_WINDOW_BUFFER_MAX_SIZE(frame_width) +
+	       LOCAL_RECONSTRUCTED_BUFFER_MAX_SIZE(frame_width) +
+	       CTX_MB_BUFFER_MAX_SIZE(max(frame_width, frame_height)) +
+	       CABAC_CONTEXT_BUFFER_MAX_SIZE(frame_width);
+
+	if (hva->esram_size < size) {
+		dev_err(dev, "%s   not enough esram (max:%d request:%d)\n",
+			pctx->name, hva->esram_size, size);
+		pctx->sys_errors++;
+		return -EINVAL;
+	}
+
+	/* allocate context for codec */
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		ret = -ENOMEM;
+
+	pctx->priv = (void *)ctx;
+
+	/* set info flags for debugfs */
+	pctx->streaminfo.flags |= HVA_STREAMINFO_FLAG_H264;
+
+	return ret;
+}
+
+static int hva_h264_close(struct hva_ctx *pctx)
+{
+	struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv;
+	struct device *dev = ctx_to_dev(pctx);
+
+	if (ctx->seq_info_buf)
+		hva_mem_free(pctx, ctx->seq_info_buf);
+
+	if (ctx->rec_frame)
+		hva_mem_free(pctx, ctx->rec_frame);
+
+	if (ctx->ref_frame)
+		hva_mem_free(pctx, ctx->ref_frame);
+
+	if (pctx->task)
+		hva_mem_free(pctx, pctx->task);
+
+	devm_kfree(dev, ctx);
+
+	return 0;
+}
+
+static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame,
+			   struct hva_stream *au)
+{
+	struct device *dev = ctx_to_dev(pctx);
+	struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv;
+	struct hva_buffer *tmp_frame;
+	struct hva_buffer *task;
+	u32 width = pctx->frameinfo.frame_width;
+	u32 height = pctx->frameinfo.frame_height;
+	u32 stuffing_bytes = 0;
+	int ret = 0;
+
+	/* allocate sequence info buffer & local frames if needed */
+	if (!ctx->seq_info_buf) {
+		ret = hva_mem_alloc(pctx,
+				    2 * DATA_SIZE(width, height) +
+				    SLICE_HEADER_SIZE +
+				    BRC_DATA_SIZE,
+				    "hva sequence info buffer",
+				    &ctx->seq_info_buf);
+		if (ret || !ctx->seq_info_buf) {
+			dev_err(dev,
+				"%s   no more memory for sequence info buffer\n",
+				pctx->name);
+			pctx->sys_errors++;
+			return -ENOMEM;
+		}
+	}
+
+	if (!ctx->ref_frame) {
+		ret = hva_mem_alloc(pctx,
+				    width * height * 3 / 2,
+				    "hva reference frame", &ctx->ref_frame);
+		if (ret || !ctx->ref_frame) {
+			dev_err(dev, "%s   more memory for reference frame\n",
+				pctx->name);
+			pctx->sys_errors++;
+			return -ENOMEM;
+		}
+	}
+
+	if (!ctx->rec_frame) {
+		ret = hva_mem_alloc(pctx,
+				    width * height * 3 / 2,
+				    "hva reconstructed frame", &ctx->rec_frame);
+		if (ret || !ctx->rec_frame) {
+			dev_err(dev,
+				"%s   no more memory for reconstructed frame\n",
+				pctx->name);
+			pctx->sys_errors++;
+			return -ENOMEM;
+		}
+	}
+
+	/* allocate task descriptor if not already done */
+	if (!pctx->task) {
+		ret = hva_mem_alloc(pctx,
+				    sizeof(struct hva_h264_task),
+				    "hva task descriptor", &pctx->task);
+		if (ret || !pctx->task) {
+			dev_err(dev,
+				"%s   no more memory for task descriptor\n",
+				pctx->name);
+			return -ENOMEM;
+		}
+	}
+
+	/* only one task allocated & used */
+	task = pctx->task;
+
+	ret = hva_h264_prepare_task(pctx, task, frame, au);
+	if (ret)
+		goto err;
+
+	ret = hva_hw_execute_task(pctx, H264_ENC, task);
+	if (ret)
+		goto err;
+
+	pctx->frame_num++;
+	au->payload += hva_h264_get_au_size(pctx, task);
+
+	stuffing_bytes = hva_h264_get_stuffing_bytes(pctx, task);
+
+	if (stuffing_bytes)
+		hva_h264_fill_data_nal(pctx, stuffing_bytes,
+				       (u8 *)au->vaddr,
+				       &au->payload);
+
+	vb2_set_plane_payload(&au->v4l2.vb2_buf, 0, au->payload);
+
+	/* switch reference & reconstructed frame */
+	tmp_frame = ctx->ref_frame;
+	ctx->ref_frame = ctx->rec_frame;
+	ctx->rec_frame = tmp_frame;
+
+	return 0;
+err:
+	vb2_set_plane_payload(&au->v4l2.vb2_buf, 0, 0);
+	return ret;
+}
+
+const struct hva_encoder nv12h264enc = {
+	.name = "H264(NV12)",
+	.pixelformat = V4L2_PIX_FMT_NV12,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder nv21h264enc = {
+	.name = "H264(NV21)",
+	.pixelformat = V4L2_PIX_FMT_NV21,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder uyvyh264enc = {
+	.name = "H264(UYVY)",
+	.pixelformat = V4L2_PIX_FMT_UYVY,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder vyuyh264enc = {
+	.name = "H264(VYUY)",
+	.pixelformat = V4L2_PIX_FMT_VYUY,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder xrgb32h264enc = {
+	.name = "H264(XRGB32)",
+	.pixelformat = V4L2_PIX_FMT_XRGB32,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder xbgr32h264enc = {
+	.name = "H264(XBGR32)",
+	.pixelformat = V4L2_PIX_FMT_XBGR32,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder rgbx32h264enc = {
+	.name = "H264(RGBX32)",
+	.pixelformat = V4L2_PIX_FMT_RGB32,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder bgrx32h264enc = {
+	.name = "H264(BGRX32)",
+	.pixelformat = V4L2_PIX_FMT_BGR32,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder rgb24h264enc = {
+	.name = "H264(RGB3)",
+	.pixelformat = V4L2_PIX_FMT_RGB24,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
+
+const struct hva_encoder bgr24h264enc = {
+	.name = "H264(BGR3)",
+	.pixelformat = V4L2_PIX_FMT_BGR24,
+	.streamformat = V4L2_PIX_FMT_H264,
+	.max_width = H264_MAX_SIZE_W,
+	.max_height = H264_MAX_SIZE_H,
+	.open = hva_h264_open,
+	.close = hva_h264_close,
+	.encode = hva_h264_encode,
+};
diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c
index 051d2ea..ece4a2a 100644
--- a/drivers/media/platform/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/sti/hva/hva-v4l2.c
@@ -33,7 +33,10 @@
 
 #define DFT_CFG_WIDTH		HVA_MIN_WIDTH
 #define	DFT_CFG_HEIGHT		HVA_MIN_HEIGHT
+#define DFT_CFG_LEVEL		V4L2_MPEG_VIDEO_H264_LEVEL_4_0
+#define DFT_CFG_PROFILE		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH
 #define DFT_CFG_BITRATE_MODE	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
+#define DFT_CFG_ENTROPY_MODE	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC
 #define DFT_CFG_GOP_SIZE	16
 #define DFT_CFG_INTRA_REFRESH	true
 #define DFT_CFG_FRAME_NUM	1
@@ -43,6 +46,7 @@
 #define DFT_CFG_DCT8X8		false
 #define DFT_CFG_COMP_QUALITY	85
 #define DFT_CFG_SAR_ENABLE	1
+#define DFT_CFG_SAR_IDC		V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1
 #define DFT_CFG_BITRATE		(20000 * 1024)
 #define DFT_CFG_CPB_SIZE	(25000 * 1024)
 
@@ -63,12 +67,14 @@ static const struct hva_frameinfo frame_dflt_fmt = {
 };
 
 static const struct hva_streaminfo stream_dflt_fmt = {
+	.streamformat	= V4L2_PIX_FMT_H264,
 	.width		= DFT_CFG_WIDTH,
 	.height		= DFT_CFG_HEIGHT
 };
 
 /* list of stream formats supported by hva hardware */
 const u32 stream_fmt[] = {
+	V4L2_PIX_FMT_H264,
 };
 
 /* list of pixel formats supported by hva hardware */
@@ -98,6 +104,16 @@ static const struct hva_frame_fmt frame_fmts[] = {
 
 /* registry of available encoders */
 const struct hva_encoder *hva_encoders[] = {
+	&nv12h264enc,
+	&nv21h264enc,
+	&uyvyh264enc,
+	&vyuyh264enc,
+	&rgb24h264enc,
+	&bgr24h264enc,
+	&xrgb32h264enc,
+	&xbgr32h264enc,
+	&rgbx32h264enc,
+	&bgrx32h264enc,
 };
 
 static const struct hva_frame_fmt *hva_find_frame_fmt(u32 pixelformat)
@@ -391,6 +407,7 @@ static int hva_s_ext_ctrls(struct file *file, void *fh,
 {
 	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
 	struct device *dev = ctx_to_dev(ctx);
+	int top_bot = V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM;
 	unsigned int i;
 
 	dev_dbg(dev, "%s %s count controls %d\n", ctx->name, __func__,
@@ -398,6 +415,24 @@ static int hva_s_ext_ctrls(struct file *file, void *fh,
 
 	for (i = 0; i < ctrls->count; i++) {
 		switch (ctrls->controls[i].id) {
+		case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+			ctx->ctrls.level = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_H264_LEVEL %d\n",
+				ctx->name, ctrls->controls[i].value);
+			if (ctx->flags & HVA_FLAG_STREAMINFO)
+				snprintf(ctx->streaminfo.level,
+					 sizeof(ctx->streaminfo.level),
+					 "%s", level_str(ctx->ctrls.level));
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+			ctx->ctrls.profile = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_H264_PROFILE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			if (ctx->flags & HVA_FLAG_STREAMINFO)
+				snprintf(ctx->streaminfo.profile,
+					 sizeof(ctx->streaminfo.profile),
+					 "%s", profile_str(ctx->ctrls.profile));
+			break;
 		case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
 			ctx->ctrls.gop_size = ctrls->controls[i].value;
 			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_GOP_SIZE %d\n",
@@ -408,17 +443,51 @@ static int hva_s_ext_ctrls(struct file *file, void *fh,
 			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE_MODE %d\n",
 				ctx->name, ctrls->controls[i].value);
 			break;
+		case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
+			ctx->ctrls.entropy_mode = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
 		case V4L2_CID_MPEG_VIDEO_BITRATE:
 			ctx->ctrls.bitrate = ctrls->controls[i].value;
 			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE %d\n",
 				ctx->name, ctrls->controls[i].value);
 			break;
+		case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
+			ctx->ctrls.cpb_size = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
 		case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
 			ctx->ctrls.intra_refresh = ctrls->controls[i].value;
 			dev_dbg(dev,
 				"%s V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB %d\n",
 				ctx->name, ctrls->controls[i].value);
 			break;
+		case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
+			ctx->ctrls.dct8x8 = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+			ctx->ctrls.qpmin = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_H264_MIN_QP %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+			ctx->ctrls.qpmax = ctrls->controls[i].value;
+			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_H264_MAX_QP %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+			ctx->ctrls.jpeg_comp_quality = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_JPEG_COMPRESSION_QUALITY %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
 		case V4L2_CID_MPEG_VIDEO_ASPECT:
 			/* only one video aspect ratio supported (1/1) */
 			switch (ctrls->controls[i].value) {
@@ -437,6 +506,56 @@ static int hva_s_ext_ctrls(struct file *file, void *fh,
 				return -EINVAL;
 			}
 			break;
+		case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
+			ctx->ctrls.vui_sar = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
+			switch (ctrls->controls[i].value) {
+			/* only one pixel aspect ratio supported (1/1) */
+			case V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1:
+				ctx->ctrls.vui_sar_idc =
+				    ctrls->controls[i].value;
+				dev_dbg(dev,
+					"%s V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC %d\n",
+					ctx->name, ctrls->controls[i].value);
+				break;
+			default:
+				dev_err(dev,
+					"%s V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: Unsupported aspect ratio %d\n",
+					ctx->name, ctrls->controls[i].value);
+				return -EINVAL;
+			}
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
+		case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
+			dev_err(dev,
+				"%s VIDIOC_S_EXT_CTRLS(): Unsupported control id %d for Extended Aspect Ratio\n",
+				ctx->name, ctrls->controls[i].id);
+			return -EINVAL;
+		case V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING:
+			ctx->ctrls.sei_fp = ctrls->controls[i].value;
+			dev_dbg(dev,
+				"%s V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING %d\n",
+				ctx->name, ctrls->controls[i].value);
+			break;
+		case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE:
+			/* only top/bottom frame packing supported */
+			if (ctrls->controls[i].value == top_bot) {
+				ctx->ctrls.sei_fp_type =
+					ctrls->controls[i].value;
+				dev_dbg(dev,
+					"%s V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE %d\n",
+					ctx->name, ctrls->controls[i].value);
+			} else {
+				dev_err(dev,
+					"%s V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: Unsupported frame packing arrangement %d\n",
+					ctx->name, ctrls->controls[i].value);
+				return -EINVAL;
+			}
+			break;
 		default:
 			dev_err(dev,
 				"%s VIDIOC_S_EXT_CTRLS(): Unsupported control id %d\n",
@@ -972,6 +1091,9 @@ static int hva_vb2_stream_queue_setup(struct vb2_queue *q,
 	height = ctx->streaminfo.height;
 
 	switch (pixelformat) {
+	case V4L2_PIX_FMT_H264:
+		max_buf_size = width * height;
+		break;
 	default:
 		dev_err(dev, "%s %s Unknown stream format\n", ctx->name,
 			__func__);
@@ -1128,16 +1250,20 @@ static int hva_open(struct file *file)
 	snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]", hva->instance_id);
 
 	/* initialize controls */
+	ctx->ctrls.level = DFT_CFG_LEVEL;
+	ctx->ctrls.profile = DFT_CFG_PROFILE;
 	ctx->ctrls.bitrate_mode = DFT_CFG_BITRATE_MODE;
 	ctx->ctrls.bitrate = DFT_CFG_BITRATE;
 	ctx->ctrls.cpb_size = DFT_CFG_CPB_SIZE;
 	ctx->ctrls.gop_size = DFT_CFG_GOP_SIZE;
 	ctx->ctrls.intra_refresh = DFT_CFG_INTRA_REFRESH;
+	ctx->ctrls.entropy_mode = DFT_CFG_ENTROPY_MODE;
 	ctx->ctrls.dct8x8 = DFT_CFG_DCT8X8;
 	ctx->ctrls.qpmin = DFT_CFG_QPMIN;
 	ctx->ctrls.qpmax = DFT_CFG_QPMAX;
 	ctx->ctrls.jpeg_comp_quality = DFT_CFG_COMP_QUALITY;
 	ctx->ctrls.vui_sar = DFT_CFG_SAR_ENABLE;
+	ctx->ctrls.vui_sar_idc = DFT_CFG_SAR_IDC;
 
 	/* set by default time per frame */
 	ctx->time_per_frame.numerator = DFT_CFG_FRAME_NUM;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver
  2015-12-18 10:45 ` [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver Yannick Fertre
@ 2015-12-18 11:42   ` kbuild test robot
  2016-01-11 10:10   ` Hans Verkuil
  1 sibling, 0 replies; 6+ messages in thread
From: kbuild test robot @ 2015-12-18 11:42 UTC (permalink / raw)
  To: Yannick Fertre
  Cc: kbuild-all, linux-media, Benjamin Gaignard, hugues.fruchet, kernel

[-- Attachment #1: Type: text/plain, Size: 12223 bytes --]

Hi Yannick,

[auto build test ERROR on linuxtv-media/master]
[also build test ERROR on v4.4-rc5 next-20151217]

url:    https://github.com/0day-ci/linux/commits/Yannick-Fertre/Documentation-devicetree-add-STI-HVA-binding/20151218-184834
base:   git://linuxtv.org/media_tree.git master
config: x86_64-allmodconfig (attached as .config)
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All error/warnings (new ones prefixed by >>):

   drivers/media/platform/sti/hva/hva-v4l2.c: In function 'hva_open_encoder':
>> drivers/media/platform/sti/hva/hva-v4l2.c:164:15: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       ctx->name, (char *)pixelformat, (char *)streamformat);
                  ^
   drivers/media/platform/sti/hva/hva-v4l2.c:164:36: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       ctx->name, (char *)pixelformat, (char *)streamformat);
                                       ^
   drivers/media/platform/sti/hva/hva-v4l2.c: In function 'hva_querybuf':
>> drivers/media/platform/sti/hva/hva-v4l2.c:97:28: error: implicit declaration of function 'UL' [-Werror=implicit-function-declaration]
    #define MMAP_FRAME_OFFSET (UL(0x100000000) / 2)
                               ^
>> drivers/media/platform/sti/hva/hva-v4l2.c:589:18: note: in expansion of macro 'MMAP_FRAME_OFFSET'
      b->m.offset += MMAP_FRAME_OFFSET;
                     ^
   In file included from include/linux/printk.h:277:0,
                    from include/linux/kernel.h:13,
                    from include/linux/list.h:8,
                    from include/linux/kobject.h:20,
                    from include/linux/device.h:17,
                    from drivers/media/platform/sti/hva/hva-v4l2.c:8:
   drivers/media/platform/sti/hva/hva-v4l2.c: In function 'hva_vb2_frame_prepare':
>> drivers/media/platform/sti/hva/hva-v4l2.c:875:16: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=]
      dev_dbg(dev, "%s frame[%d] prepared; virt=%p, phy=0x%x\n",
                   ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
>> drivers/media/platform/sti/hva/hva-v4l2.c:875:3: note: in expansion of macro 'dev_dbg'
      dev_dbg(dev, "%s frame[%d] prepared; virt=%p, phy=0x%x\n",
      ^
   drivers/media/platform/sti/hva/hva-v4l2.c: In function 'hva_vb2_stream_prepare':
   drivers/media/platform/sti/hva/hva-v4l2.c:999:16: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=]
      dev_dbg(dev, "%s stream[%d] prepared; virt=%p, phy=0x%x\n",
                   ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
   drivers/media/platform/sti/hva/hva-v4l2.c:999:3: note: in expansion of macro 'dev_dbg'
      dev_dbg(dev, "%s stream[%d] prepared; virt=%p, phy=0x%x\n",
      ^
   In file included from drivers/media/platform/sti/hva/hva-v4l2.c:8:0:
   drivers/media/platform/sti/hva/hva-v4l2.c: In function 'hva_probe':
   drivers/media/platform/sti/hva/hva-v4l2.c:1345:26: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       HVA_PREFIX, HVA_NAME, (void *)hva->esram_addr,
                             ^
   include/linux/device.h:1174:58: note: in definition of macro 'dev_info'
    #define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
                                                             ^
   cc1: some warnings being treated as errors
--
   In file included from include/linux/printk.h:277:0,
                    from include/linux/kernel.h:13,
                    from include/linux/clk.h:16,
                    from drivers/media/platform/sti/hva/hva-hw.c:8:
   drivers/media/platform/sti/hva/hva-hw.c: In function 'hva_hw_execute_task':
>> drivers/media/platform/sti/hva/hva-hw.c:523:15: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=]
     dev_dbg(dev, "%s     %s: Send task ( cmd:%d, task_desc:0x%x)\n",
                  ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
>> drivers/media/platform/sti/hva/hva-hw.c:523:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(dev, "%s     %s: Send task ( cmd:%d, task_desc:0x%x)\n",
     ^
--
   In file included from include/linux/printk.h:277:0,
                    from include/linux/kernel.h:13,
                    from include/linux/list.h:8,
                    from include/linux/preempt.h:10,
                    from include/linux/spinlock.h:50,
                    from include/linux/seqlock.h:35,
                    from include/linux/time.h:5,
                    from include/linux/ktime.h:24,
                    from include/linux/poll.h:6,
                    from include/media/v4l2-dev.h:12,
                    from include/media/v4l2-common.h:29,
                    from drivers/media/platform/sti/hva/hva.h:11,
                    from drivers/media/platform/sti/hva/hva-mem.c:8:
   drivers/media/platform/sti/hva/hva-mem.c: In function 'hva_mem_alloc':
>> drivers/media/platform/sti/hva/hva-mem.c:43:3: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=]
      "%s allocate %d bytes of HW memory @(virt=%p, phy=0x%x): %s\n",
      ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
>> drivers/media/platform/sti/hva/hva-mem.c:42:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(dev,
     ^
   drivers/media/platform/sti/hva/hva-mem.c: In function 'hva_mem_free':
   drivers/media/platform/sti/hva/hva-mem.c:57:3: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=]
      "%s free %d bytes of HW memory @(virt=%p, phy=0x%x): %s\n",
      ^
   include/linux/dynamic_debug.h:86:39: note: in definition of macro 'dynamic_dev_dbg'
      __dynamic_dev_dbg(&descriptor, dev, fmt, \
                                          ^
   drivers/media/platform/sti/hva/hva-mem.c:56:2: note: in expansion of macro 'dev_dbg'
     dev_dbg(dev,
     ^

vim +/UL +97 drivers/media/platform/sti/hva/hva-v4l2.c

     2	 * Copyright (C) STMicroelectronics SA 2015
     3	 * Authors: Yannick Fertre <yannick.fertre@st.com>
     4	 *          Hugues Fruchet <hugues.fruchet@st.com>
     5	 * License terms:  GNU General Public License (GPL), version 2
     6	 */
     7	
   > 8	#include <linux/device.h>
     9	#include <linux/dma-mapping.h>
    10	#include <linux/module.h>
    11	#include <linux/platform_device.h>
    12	#include <linux/slab.h>
    13	#include <linux/version.h>
    14	#include <linux/of.h>
    15	#include <media/v4l2-ioctl.h>
    16	#include <media/videobuf2-dma-contig.h>
    17	#include "hva.h"
    18	#include "hva-hw.h"
    19	
    20	#define HVA_NAME "hva"
    21	
    22	/*
    23	 * 1 frame at least for user
    24	 * limit number of frames to 16
    25	 */
    26	#define MAX_FRAMES	16
    27	#define MIN_FRAMES	1
    28	
    29	#define HVA_MIN_WIDTH	32
    30	#define HVA_MAX_WIDTH	1920
    31	#define HVA_MIN_HEIGHT	32
    32	#define HVA_MAX_HEIGHT	1080
    33	
    34	#define DFT_CFG_WIDTH		HVA_MIN_WIDTH
    35	#define	DFT_CFG_HEIGHT		HVA_MIN_HEIGHT
    36	#define DFT_CFG_BITRATE_MODE	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
    37	#define DFT_CFG_GOP_SIZE	16
    38	#define DFT_CFG_INTRA_REFRESH	true
    39	#define DFT_CFG_FRAME_NUM	1
    40	#define DFT_CFG_FRAME_DEN	30
    41	#define DFT_CFG_QPMIN		5
    42	#define DFT_CFG_QPMAX		51
    43	#define DFT_CFG_DCT8X8		false
    44	#define DFT_CFG_COMP_QUALITY	85
    45	#define DFT_CFG_SAR_ENABLE	1
    46	#define DFT_CFG_BITRATE		(20000 * 1024)
    47	#define DFT_CFG_CPB_SIZE	(25000 * 1024)
    48	
    49	static const struct hva_frameinfo frame_dflt_fmt = {
    50		.fmt		= {
    51					.pixelformat	= V4L2_PIX_FMT_NV12,
    52					.nb_planes	= 2,
    53					.bpp		= 12,
    54					.bpp_plane0	= 8,
    55					.w_align	= 2,
    56					.h_align	= 2
    57				  },
    58		.width		= DFT_CFG_WIDTH,
    59		.height		= DFT_CFG_HEIGHT,
    60		.crop		= {0, 0, DFT_CFG_WIDTH, DFT_CFG_HEIGHT},
    61		.frame_width	= DFT_CFG_WIDTH,
    62		.frame_height	= DFT_CFG_HEIGHT
    63	};
    64	
    65	static const struct hva_streaminfo stream_dflt_fmt = {
    66		.width		= DFT_CFG_WIDTH,
    67		.height		= DFT_CFG_HEIGHT
    68	};
    69	
    70	/* list of stream formats supported by hva hardware */
    71	const u32 stream_fmt[] = {
    72	};
    73	
    74	/* list of pixel formats supported by hva hardware */
    75	static const struct hva_frame_fmt frame_fmts[] = {
    76		/* NV12. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
    77		{
    78			.pixelformat	= V4L2_PIX_FMT_NV12,
    79			.nb_planes	= 2,
    80			.bpp		= 12,
    81			.bpp_plane0	= 8,
    82			.w_align	= 2,
    83			.h_align	= 2
    84		},
    85		/* NV21. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
    86		{
    87			.pixelformat	= V4L2_PIX_FMT_NV21,
    88			.nb_planes	= 2,
    89			.bpp		= 12,
    90			.bpp_plane0	= 8,
    91			.w_align	= 2,
    92			.h_align	= 2
    93		},
    94	};
    95	
    96	/* offset to differentiate OUTPUT/CAPTURE @mmap */
  > 97	#define MMAP_FRAME_OFFSET (UL(0x100000000) / 2)
    98	
    99	/* registry of available encoders */
   100	const struct hva_encoder *hva_encoders[] = {
   101	};
   102	
   103	static const struct hva_frame_fmt *hva_find_frame_fmt(u32 pixelformat)
   104	{
   105		const struct hva_frame_fmt *fmt;
   106		unsigned int i;
   107	
   108		for (i = 0; i < ARRAY_SIZE(frame_fmts); i++) {
   109			fmt = &frame_fmts[i];
   110			if (fmt->pixelformat == pixelformat)
   111				return fmt;
   112		}
   113	
   114		return NULL;
   115	}
   116	
   117	static void register_encoder(struct hva_device *hva,
   118				     const struct hva_encoder *enc)
   119	{
   120		if (hva->nb_of_encoders >= HVA_MAX_ENCODERS) {
   121			dev_warn(hva->dev,
   122				 "%s can' t register encoder (max nb (%d) is reached!)\n",
   123				 enc->name, HVA_MAX_ENCODERS);
   124			return;
   125		}
   126	
   127		/* those encoder ops are mandatory */
   128		WARN_ON(!enc->open);
   129		WARN_ON(!enc->close);
   130		WARN_ON(!enc->encode);
   131	
   132		hva->encoders[hva->nb_of_encoders] = enc;
   133		hva->nb_of_encoders++;
   134		dev_info(hva->dev, "%s encoder registered\n", enc->name);
   135	}
   136	
   137	static void register_all(struct hva_device *hva)
   138	{
   139		unsigned int i;
   140	
   141		for (i = 0; i < ARRAY_SIZE(hva_encoders); i++)
   142			register_encoder(hva, hva_encoders[i]);
   143	}
   144	
   145	static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat,
   146				    u32 pixelformat, struct hva_encoder **penc)
   147	{
   148		struct hva_device *hva = ctx_to_hdev(ctx);
   149		struct device *dev = ctx_to_dev(ctx);
   150		struct hva_encoder *enc;
   151		unsigned int i;
   152		int ret;
   153	
   154		/* find an encoder which can deal with these formats */
   155		for (i = 0; i < hva->nb_of_encoders; i++) {
   156			enc = (struct hva_encoder *)hva->encoders[i];
   157			if ((enc->streamformat == streamformat) &&
   158			    (enc->pixelformat == pixelformat))
   159				break;	/* found */
   160		}
   161	
   162		if (i == hva->nb_of_encoders) {
   163			dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n",
 > 164				ctx->name, (char *)pixelformat, (char *)streamformat);
   165			return -EINVAL;
   166		}
   167	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 51054 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver
  2015-12-18 10:45 ` [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver Yannick Fertre
  2015-12-18 11:42   ` kbuild test robot
@ 2016-01-11 10:10   ` Hans Verkuil
  1 sibling, 0 replies; 6+ messages in thread
From: Hans Verkuil @ 2016-01-11 10:10 UTC (permalink / raw)
  To: Yannick Fertre, linux-media; +Cc: Benjamin Gaignard, hugues.fruchet, kernel

Hi Yannick,

I apologize for the delay in reviewing this, but I was on vacation.

But here it is:

On 12/18/2015 11:45 AM, Yannick Fertre wrote:
> This patch adds HVA (Hardware Video Accelerator) support for STI platform.
> 
> Signed-off-by: Yannick Fertre <yannick.fertre@st.com>
> ---
>  drivers/media/platform/Kconfig            |   13 +
>  drivers/media/platform/Makefile           |    1 +
>  drivers/media/platform/sti/hva/Makefile   |    2 +
>  drivers/media/platform/sti/hva/hva-hw.c   |  561 ++++++++++++
>  drivers/media/platform/sti/hva/hva-hw.h   |   76 ++
>  drivers/media/platform/sti/hva/hva-mem.c  |   63 ++
>  drivers/media/platform/sti/hva/hva-mem.h  |   20 +
>  drivers/media/platform/sti/hva/hva-v4l2.c | 1404 +++++++++++++++++++++++++++++
>  drivers/media/platform/sti/hva/hva.h      |  499 ++++++++++
>  9 files changed, 2639 insertions(+)
>  create mode 100644 drivers/media/platform/sti/hva/Makefile
>  create mode 100644 drivers/media/platform/sti/hva/hva-hw.c
>  create mode 100644 drivers/media/platform/sti/hva/hva-hw.h
>  create mode 100644 drivers/media/platform/sti/hva/hva-mem.c
>  create mode 100644 drivers/media/platform/sti/hva/hva-mem.h
>  create mode 100644 drivers/media/platform/sti/hva/hva-v4l2.c
>  create mode 100644 drivers/media/platform/sti/hva/hva.h
> 

<snip>

> diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c
> new file mode 100644
> index 0000000..051d2ea
> --- /dev/null
> +++ b/drivers/media/platform/sti/hva/hva-v4l2.c
> @@ -0,0 +1,1404 @@
> +/*
> + * Copyright (C) STMicroelectronics SA 2015
> + * Authors: Yannick Fertre <yannick.fertre@st.com>
> + *          Hugues Fruchet <hugues.fruchet@st.com>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/version.h>
> +#include <linux/of.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/videobuf2-dma-contig.h>
> +#include "hva.h"
> +#include "hva-hw.h"
> +
> +#define HVA_NAME "hva"
> +
> +/*
> + * 1 frame at least for user
> + * limit number of frames to 16
> + */
> +#define MAX_FRAMES	16
> +#define MIN_FRAMES	1
> +
> +#define HVA_MIN_WIDTH	32
> +#define HVA_MAX_WIDTH	1920
> +#define HVA_MIN_HEIGHT	32
> +#define HVA_MAX_HEIGHT	1080
> +
> +#define DFT_CFG_WIDTH		HVA_MIN_WIDTH
> +#define	DFT_CFG_HEIGHT		HVA_MIN_HEIGHT
> +#define DFT_CFG_BITRATE_MODE	V4L2_MPEG_VIDEO_BITRATE_MODE_CBR
> +#define DFT_CFG_GOP_SIZE	16
> +#define DFT_CFG_INTRA_REFRESH	true
> +#define DFT_CFG_FRAME_NUM	1
> +#define DFT_CFG_FRAME_DEN	30
> +#define DFT_CFG_QPMIN		5
> +#define DFT_CFG_QPMAX		51
> +#define DFT_CFG_DCT8X8		false
> +#define DFT_CFG_COMP_QUALITY	85
> +#define DFT_CFG_SAR_ENABLE	1
> +#define DFT_CFG_BITRATE		(20000 * 1024)
> +#define DFT_CFG_CPB_SIZE	(25000 * 1024)
> +
> +static const struct hva_frameinfo frame_dflt_fmt = {
> +	.fmt		= {
> +				.pixelformat	= V4L2_PIX_FMT_NV12,
> +				.nb_planes	= 2,
> +				.bpp		= 12,
> +				.bpp_plane0	= 8,
> +				.w_align	= 2,
> +				.h_align	= 2
> +			  },
> +	.width		= DFT_CFG_WIDTH,
> +	.height		= DFT_CFG_HEIGHT,
> +	.crop		= {0, 0, DFT_CFG_WIDTH, DFT_CFG_HEIGHT},
> +	.frame_width	= DFT_CFG_WIDTH,
> +	.frame_height	= DFT_CFG_HEIGHT
> +};
> +
> +static const struct hva_streaminfo stream_dflt_fmt = {
> +	.width		= DFT_CFG_WIDTH,
> +	.height		= DFT_CFG_HEIGHT
> +};
> +
> +/* list of stream formats supported by hva hardware */
> +const u32 stream_fmt[] = {
> +};
> +
> +/* list of pixel formats supported by hva hardware */
> +static const struct hva_frame_fmt frame_fmts[] = {
> +	/* NV12. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
> +	{
> +		.pixelformat	= V4L2_PIX_FMT_NV12,
> +		.nb_planes	= 2,
> +		.bpp		= 12,
> +		.bpp_plane0	= 8,
> +		.w_align	= 2,
> +		.h_align	= 2
> +	},
> +	/* NV21. YUV420SP - 1 plane for Y + 1 plane for (CbCr) */
> +	{
> +		.pixelformat	= V4L2_PIX_FMT_NV21,
> +		.nb_planes	= 2,
> +		.bpp		= 12,
> +		.bpp_plane0	= 8,
> +		.w_align	= 2,
> +		.h_align	= 2
> +	},
> +};
> +
> +/* offset to differentiate OUTPUT/CAPTURE @mmap */
> +#define MMAP_FRAME_OFFSET (UL(0x100000000) / 2)
> +
> +/* registry of available encoders */
> +const struct hva_encoder *hva_encoders[] = {
> +};
> +
> +static const struct hva_frame_fmt *hva_find_frame_fmt(u32 pixelformat)
> +{
> +	const struct hva_frame_fmt *fmt;
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(frame_fmts); i++) {
> +		fmt = &frame_fmts[i];
> +		if (fmt->pixelformat == pixelformat)
> +			return fmt;
> +	}
> +
> +	return NULL;
> +}
> +
> +static void register_encoder(struct hva_device *hva,
> +			     const struct hva_encoder *enc)
> +{
> +	if (hva->nb_of_encoders >= HVA_MAX_ENCODERS) {
> +		dev_warn(hva->dev,
> +			 "%s can' t register encoder (max nb (%d) is reached!)\n",
> +			 enc->name, HVA_MAX_ENCODERS);
> +		return;
> +	}
> +
> +	/* those encoder ops are mandatory */
> +	WARN_ON(!enc->open);
> +	WARN_ON(!enc->close);
> +	WARN_ON(!enc->encode);
> +
> +	hva->encoders[hva->nb_of_encoders] = enc;
> +	hva->nb_of_encoders++;
> +	dev_info(hva->dev, "%s encoder registered\n", enc->name);
> +}
> +
> +static void register_all(struct hva_device *hva)
> +{
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(hva_encoders); i++)
> +		register_encoder(hva, hva_encoders[i]);
> +}
> +
> +static int hva_open_encoder(struct hva_ctx *ctx, u32 streamformat,
> +			    u32 pixelformat, struct hva_encoder **penc)
> +{
> +	struct hva_device *hva = ctx_to_hdev(ctx);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct hva_encoder *enc;
> +	unsigned int i;
> +	int ret;
> +
> +	/* find an encoder which can deal with these formats */
> +	for (i = 0; i < hva->nb_of_encoders; i++) {
> +		enc = (struct hva_encoder *)hva->encoders[i];
> +		if ((enc->streamformat == streamformat) &&
> +		    (enc->pixelformat == pixelformat))
> +			break;	/* found */
> +	}
> +
> +	if (i == hva->nb_of_encoders) {
> +		dev_err(dev, "%s no encoder found matching %4.4s => %4.4s\n",
> +			ctx->name, (char *)pixelformat, (char *)streamformat);
> +		return -EINVAL;
> +	}
> +
> +	dev_dbg(dev, "%s one encoder matching %4.4s => %4.4s\n",
> +		ctx->name, (char *)&pixelformat, (char *)&streamformat);
> +
> +	/* update name instance */
> +	snprintf(ctx->name, sizeof(ctx->name), "[%3d:%4.4s]",
> +		 hva->instance_id, (char *)&streamformat);
> +
> +	/* open encoder instance */
> +	ret = enc->open(ctx);
> +	if (ret) {
> +		dev_err(hva->dev, "%s enc->open failed (%d)\n",
> +			ctx->name, ret);
> +		return ret;
> +	}
> +
> +	*penc = enc;
> +
> +	return ret;
> +}
> +
> +/* v4l2 ioctl operations */
> +
> +static int hva_querycap(struct file *file, void *priv,
> +			struct v4l2_capability *cap)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct hva_device *hva = ctx_to_hdev(ctx);
> +
> +	strlcpy(cap->driver, hva->pdev->name, sizeof(cap->driver));
> +	strlcpy(cap->card, hva->pdev->name, sizeof(cap->card));
> +	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
> +		 HVA_NAME);
> +
> +	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
> +	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
> +
> +	return 0;
> +}
> +
> +static int hva_enum_fmt_frame(struct file *file, void *priv,
> +			      struct v4l2_fmtdesc *f)
> +{
> +	/* index don't have to exceed number of  format supported */
> +	if (f->index >=  ARRAY_SIZE(frame_fmts))

Two spaces instead of one after '>='.

> +		return -EINVAL;
> +
> +	/* pixel format */
> +	f->pixelformat = frame_fmts[f->index].pixelformat;
> +
> +	return 0;
> +}
> +
> +static int hva_enum_fmt_stream(struct file *file, void *priv,
> +			       struct v4l2_fmtdesc *f)
> +{
> +	/* index don't have to exceed number of stream format supported */
> +	if (f->index >= ARRAY_SIZE(stream_fmt))
> +		return -EINVAL;
> +
> +	/* pixel format */
> +	f->pixelformat = stream_fmt[f->index];
> +
> +	/* compressed */
> +	f->flags = V4L2_FMT_FLAG_COMPRESSED;
> +
> +	return 0;
> +}
> +
> +static int hva_try_fmt_stream(struct file *file, void *priv,
> +			      struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct hva_device *hva = ctx_to_hdev(ctx);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct v4l2_pix_format *pix = &f->fmt.pix;
> +	const struct hva_encoder *enc = NULL;
> +	unsigned int i;
> +
> +	if ((f->fmt.pix.width == 0) || (f->fmt.pix.height == 0))
> +		goto out;

This is wrong (and I don't understand why v4l2-compliance doesn't complain about
it, possibly because m2m support in v4l2-compliance for codecs is limited). The
only reason try_fmt can ever return an error is if the pixelformat is not
supported. If a wrong width/height is passed in, then that should be replace by
a valid default width/height.

> +
> +	f->fmt.pix.field = V4L2_FIELD_NONE;
> +	f->fmt.pix.priv = 0;

No need to set priv to 0 anymore, just drop this line everywhere you use it.

Again, I don't understand how this can pass v4l2-compliance: it should complain
about uninitialized fields: colorspace, bytesperline (must be 0 for compressed
formats) and sizeimage (worst-case buffer size).

> +
> +	for (i = 0; i < hva->nb_of_encoders; i++) {
> +		enc = hva->encoders[i];
> +		if (enc->streamformat == pix->pixelformat)
> +			if ((f->fmt.pix.height * f->fmt.pix.width) <=
> +			    (enc->max_width * enc->max_height))
> +				return 0;
> +	}
> +out:
> +	dev_dbg(dev, "%s stream format or resolution %dx%d not supported\n",
> +		ctx->name, f->fmt.pix.width, f->fmt.pix.height);
> +	return -EINVAL;
> +}
> +
> +static int hva_try_fmt_frame(struct file *file, void *priv,
> +			     struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct v4l2_pix_format *pix = &f->fmt.pix;
> +	const struct hva_frame_fmt *format;
> +	u32 in_w, in_h;
> +
> +	format = hva_find_frame_fmt(pix->pixelformat);
> +	if (!format) {
> +		dev_dbg(dev, "%s Unknown format 0x%x\n", ctx->name,
> +			pix->pixelformat);
> +		return -EINVAL;
> +	}
> +
> +	/* adjust width & height */
> +	in_w = pix->width;
> +	in_h = pix->height;
> +	v4l_bound_align_image(&pix->width,
> +			      HVA_MIN_WIDTH, HVA_MAX_WIDTH,
> +			      ffs(format->w_align) - 1,
> +			      &pix->height,
> +			      HVA_MIN_HEIGHT, HVA_MAX_HEIGHT,
> +			      ffs(format->h_align) - 1,
> +			      0);
> +
> +	if ((pix->width != in_w) || (pix->height != in_h))
> +		dev_dbg(dev, "%s size updated: %dx%d -> %dx%d\n", ctx->name,
> +			in_w, in_h, pix->width, pix->height);
> +
> +	f->fmt.pix.field = V4L2_FIELD_NONE;
> +	f->fmt.pix.priv = 0;

Missing initializations for colorspace, bytesperline and sizeimage.

> +
> +	return 0;
> +}
> +
> +static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int ret;
> +
> +	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
> +		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
> +		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
> +
> +	ret = hva_try_fmt_stream(file, fh, f);
> +	if (ret) {
> +		dev_err(dev,
> +			"%s %s %.4s format or %dx%d resolution not supported\n",
> +			ctx->name, __func__, (char *)&f->fmt.pix.pixelformat,
> +			f->fmt.pix.width, f->fmt.pix.height);
> +		return ret;
> +	}
> +
> +	/* update context */
> +	ctx->streaminfo.width = f->fmt.pix.width;
> +	ctx->streaminfo.height = f->fmt.pix.height;
> +	ctx->streaminfo.streamformat = f->fmt.pix.pixelformat;
> +	ctx->streaminfo.dpb = 1;
> +	ctx->flags |= HVA_FLAG_STREAMINFO;
> +
> +	if ((!ctx->encoder) && (ctx->flags & HVA_FLAG_FRAMEINFO)) {
> +		ret = hva_open_encoder(ctx,
> +				       ctx->streaminfo.streamformat,
> +				       ctx->frameinfo.fmt.pixelformat,
> +				       &ctx->encoder);
> +		if (ret)
> +			return ret;

I'm not sure this is the right place: I would expect this in the start_streaming
op, because that's when the encoder really starts. I would also expect to see a check
here whether streaming is in progress: usually you can't change the format once
streaming is active.

> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct v4l2_pix_format *pix = &f->fmt.pix;
> +	const struct hva_frame_fmt *fmt;
> +	int ret = 0;
> +
> +	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
> +		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
> +		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
> +
> +	ret = hva_try_fmt_frame(file, fh, f);
> +	if (ret) {
> +		dev_err(dev,
> +			"%s %s %.4s format or %dx%d resolution not supported\n",
> +			ctx->name, __func__, (char *)&f->fmt.pix.pixelformat,
> +			f->fmt.pix.width, f->fmt.pix.height);
> +		return ret;
> +	}
> +
> +	fmt = hva_find_frame_fmt(pix->pixelformat);
> +	if (!fmt) {
> +		dev_dbg(dev, "%s %s unknown format 0x%x\n", ctx->name,
> +			ctx->name, pix->pixelformat);
> +		return -EINVAL;
> +	}
> +
> +	memcpy(&ctx->frameinfo.fmt, fmt, sizeof(struct hva_frame_fmt));
> +	ctx->frameinfo.frame_width = ALIGN(pix->width, 16);
> +	ctx->frameinfo.frame_height = ALIGN(pix->height, 16);
> +	ctx->frameinfo.width = pix->width;
> +	ctx->frameinfo.height = pix->height;
> +	ctx->frameinfo.crop.width = pix->width;
> +	ctx->frameinfo.crop.height = pix->height;
> +	ctx->frameinfo.crop.left = 0;
> +	ctx->frameinfo.crop.top = 0;
> +
> +	ctx->flags |= HVA_FLAG_FRAMEINFO;
> +
> +	if ((!ctx->encoder) && (ctx->flags & HVA_FLAG_STREAMINFO))
> +		ret = hva_open_encoder(ctx,
> +				       ctx->streaminfo.streamformat,
> +				       ctx->frameinfo.fmt.pixelformat,
> +				       &ctx->encoder);

Same comments as for the previous function.

> +
> +	return ret;
> +}
> +
> +static int hva_s_ext_ctrls(struct file *file, void *fh,
> +			   struct v4l2_ext_controls *ctrls)

Huh? You must use the control framework instead of implementing this directly.
Just look in other drivers how that's done and Documentation/video4linux/v4l2-controls.txt.

> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	unsigned int i;
> +
> +	dev_dbg(dev, "%s %s count controls %d\n", ctx->name, __func__,
> +		ctrls->count);
> +
> +	for (i = 0; i < ctrls->count; i++) {
> +		switch (ctrls->controls[i].id) {
> +		case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
> +			ctx->ctrls.gop_size = ctrls->controls[i].value;
> +			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_GOP_SIZE %d\n",
> +				ctx->name, ctrls->controls[i].value);
> +			break;
> +		case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
> +			ctx->ctrls.bitrate_mode = ctrls->controls[i].value;
> +			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE_MODE %d\n",
> +				ctx->name, ctrls->controls[i].value);
> +			break;
> +		case V4L2_CID_MPEG_VIDEO_BITRATE:
> +			ctx->ctrls.bitrate = ctrls->controls[i].value;
> +			dev_dbg(dev, "%s V4L2_CID_MPEG_VIDEO_BITRATE %d\n",
> +				ctx->name, ctrls->controls[i].value);
> +			break;
> +		case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
> +			ctx->ctrls.intra_refresh = ctrls->controls[i].value;
> +			dev_dbg(dev,
> +				"%s V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB %d\n",
> +				ctx->name, ctrls->controls[i].value);
> +			break;
> +		case V4L2_CID_MPEG_VIDEO_ASPECT:
> +			/* only one video aspect ratio supported (1/1) */
> +			switch (ctrls->controls[i].value) {
> +			case V4L2_MPEG_VIDEO_ASPECT_1x1:
> +				dev_dbg(dev,
> +					"%s V4L2_CID_MPEG_VIDEO_ASPECT 1x1\n",
> +					ctx->name);
> +				break;
> +			case V4L2_MPEG_VIDEO_ASPECT_4x3:
> +			case V4L2_MPEG_VIDEO_ASPECT_16x9:
> +			case V4L2_MPEG_VIDEO_ASPECT_221x100:
> +			default:
> +				dev_err(dev,
> +					"%s V4L2_CID_MPEG_VIDEO_ASPECT: Unsupported aspect ratio %d\n",
> +					ctx->name, ctrls->controls[i].value);
> +				return -EINVAL;
> +			}
> +			break;
> +		default:
> +			dev_err(dev,
> +				"%s VIDIOC_S_EXT_CTRLS(): Unsupported control id %d\n",
> +				ctx->name, ctrls->controls[i].id);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +
> +	ctx->time_per_frame.numerator = sp->parm.capture.timeperframe.numerator;
> +	ctx->time_per_frame.denominator =
> +	    sp->parm.capture.timeperframe.denominator;
> +
> +	dev_dbg(dev, "%s set parameters %d/%d\n",
> +		ctx->name, ctx->time_per_frame.numerator,
> +		ctx->time_per_frame.denominator);
> +
> +	return 0;
> +}
> +
> +static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +
> +	sp->parm.capture.timeperframe.numerator = ctx->time_per_frame.numerator;
> +	sp->parm.capture.timeperframe.denominator =
> +	    ctx->time_per_frame.denominator;
> +
> +	dev_dbg(dev, "%s get parameters %d/%d\n",
> +		ctx->name, ctx->time_per_frame.numerator,
> +		ctx->time_per_frame.denominator);
> +
> +	return 0;
> +}
> +
> +static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +
> +	/* get stream format */
> +	f->fmt.pix.width = ctx->streaminfo.width;
> +	f->fmt.pix.height = ctx->streaminfo.height;
> +	f->fmt.pix.field = V4L2_FIELD_NONE;
> +	/* 32 bytes alignment */
> +	f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width, 32);

Bytesperline makes no sense for compressed formats, so set this to 0.

> +	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;

FYI: for compressed formats the sizeimage field should return the worst-case buffer
size that is needed. Which you set to width * height. You know best whether that
is correct, but it feels a bit high.

> +	f->fmt.pix.pixelformat = ctx->streaminfo.streamformat;
> +	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
> +
> +	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
> +		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
> +		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
> +	return 0;
> +}
> +
> +static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct hva_frame_fmt *fmt = &ctx->frameinfo.fmt;
> +	int width = ctx->frameinfo.frame_width;
> +	int height = ctx->frameinfo.frame_height;
> +
> +	/* get source format */
> +	f->fmt.pix.pixelformat = fmt->pixelformat;
> +	f->fmt.pix.width = ctx->frameinfo.width;
> +	f->fmt.pix.height = ctx->frameinfo.height;
> +	f->fmt.pix.field = V4L2_FIELD_NONE;
> +	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
> +	f->fmt.pix.bytesperline = (width * fmt->bpp_plane0) / 8;
> +	f->fmt.pix.sizeimage = (width * height * fmt->bpp) / 8;
> +
> +	dev_dbg(dev, "%s %s %dx%d fmt:%.4s size:%d\n",
> +		ctx->name, __func__, f->fmt.pix.width, f->fmt.pix.height,
> +		(u8 *)&f->fmt.pix.pixelformat, f->fmt.pix.sizeimage);
> +
> +	return 0;
> +}
> +
> +static int hva_reqbufs(struct file *file, void *priv,
> +		       struct v4l2_requestbuffers *reqbufs)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int ret = 0;
> +
> +	dev_dbg(dev, "%s %s %s\n", ctx->name, __func__,
> +		to_type_str(reqbufs->type));
> +
> +	ret = vb2_reqbufs(get_queue(ctx, reqbufs->type), reqbufs);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_reqbufs failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	if (reqbufs->count == 0) {
> +		/*
> +		 * buffers have been freed in vb2 __reqbufs()
> +		 * now cleanup "allocation context" ...
> +		 */
> +		if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> +			vb2_dma_contig_cleanup_ctx(ctx->q_frame.alloc_ctx[0]);
> +			ctx->q_frame.alloc_ctx[0] = NULL;

Nack: you clean up the context when the driver is removed, not if the
buffer allocation fails.

> +		} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> +			vb2_dma_contig_cleanup_ctx(ctx->q_stream.alloc_ctx[0]);
> +			ctx->q_stream.alloc_ctx[0] = NULL;
> +		}
> +	}
> +
> +	return 0;
> +}

A general question: any reason why you can't use the v4l2-mem2mem.h framework for
this driver? It would likely simplify the driver code.

> +
> +static int hva_create_bufs(struct file *file, void *priv,
> +			   struct v4l2_create_buffers *create)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct vb2_queue *q = get_queue(ctx, create->format.type);
> +
> +	return vb2_create_bufs(q, create);
> +}
> +
> +static int hva_querybuf(struct file *file, void *priv, struct v4l2_buffer *b)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int ret = 0;
> +
> +	dev_dbg(dev, "%s %s %s[%d]\n", ctx->name, __func__,
> +		to_type_str(b->type), b->index);
> +
> +	/* vb2 call */
> +	ret = vb2_querybuf(get_queue(ctx, b->type), b);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_querybuf failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	/* add an offset to differentiate OUTPUT/CAPTURE @mmap time */
> +	if ((b->memory == V4L2_MEMORY_MMAP) &&
> +	    (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
> +		b->m.offset += MMAP_FRAME_OFFSET;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *b)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int ret = 0;
> +
> +	/* request validation */
> +	if ((b->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) &&
> +	    (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
> +		dev_err(dev,
> +			"%s V4L2 EXPBUF: only type output/cature are supported\n",

cature -> capture

But vb2_expbuf already checks for wrong buffer types, so you can drop this check.

> +			ctx->name);
> +		return -EINVAL;
> +	}
> +
> +	/* vb2 call */
> +	ret = vb2_expbuf(get_queue(ctx, b->type), b);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_expbuf failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct vb2_queue *q = get_queue(ctx, b->type);
> +	int ret = 0;
> +
> +	/* copy bytesused field from v4l2 buffer to vb2 buffer */
> +	if ((b->index < MAX_FRAMES) &&
> +	    (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)) {
> +		struct hva_stream *s = (struct hva_stream *)q->bufs[b->index];
> +
> +		s->payload = b->bytesused;
> +	}
> +
> +	ret = vb2_qbuf(q, b);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_qbuf failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +static int hva_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct vb2_queue *q = get_queue(ctx, b->type);
> +	int ret = 0;
> +
> +	/* vb2 call */
> +	ret = vb2_dqbuf(q, b, file->f_flags & O_NONBLOCK);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_dqbuf failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	dev_dbg(dev, "%s %s %s[%d]\n", ctx->name, __func__,
> +		to_type_str(b->type), b->index);

Drop this, vb2 already has all the debugging you need.

> +
> +	return 0;
> +}
> +
> +static int hva_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int ret = 0;
> +
> +	/* reset frame number */
> +	if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
> +		ctx->frame_num = 0;
> +
> +	/* vb2 call */
> +	ret = vb2_streamon(get_queue(ctx, type), type);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_streamon failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_streamoff(struct file *file, void *priv, enum v4l2_buf_type type)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct hva_stream *sr, *node;
> +	int ret = 0;
> +
> +	/* release all active buffers */
> +	if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> +		list_for_each_entry_safe(sr, node, &ctx->list_stream, list) {
> +			list_del_init(&sr->list);
> +			vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);

This belongs in stop_streaming.

> +		}
> +	}
> +
> +	/* vb2 call */
> +	ret = vb2_streamoff(get_queue(ctx, type), type);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_streamoff failed (%d)\n", ctx->name, ret);

Drop this, vb2 already has all the debugging you need.

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int is_rect_enclosed(struct v4l2_rect *a, struct v4l2_rect *b)
> +{
> +	/* return 1 if a is enclosed in b, or 0 otherwise. */
> +	if (a->left < b->left || a->top < b->top)
> +		return 0;
> +
> +	if (a->left + a->width > b->left + b->width)
> +		return 0;
> +
> +	if (a->top + a->height > b->top + b->height)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +static int hva_g_selection(struct file *file, void *fh,
> +			   struct v4l2_selection *s)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +
> +	if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
> +		dev_err(dev, "%s %s: G_SELECTION failed, invalid type (%d)\n",
> +			ctx->name, __func__, s->type);
> +		return -EINVAL;
> +	}
> +
> +	switch (s->target) {
> +	case V4L2_SEL_TGT_CROP:
> +		/* cropped frame */
> +		s->r = ctx->frameinfo.crop;
> +		break;
> +	case V4L2_SEL_TGT_CROP_DEFAULT:
> +	case V4L2_SEL_TGT_CROP_BOUNDS:
> +		/* complete frame */
> +		s->r.left = 0;
> +		s->r.top = 0;
> +		s->r.width = ctx->frameinfo.width;
> +		s->r.height = ctx->frameinfo.height;
> +		break;
> +	default:
> +		dev_err(dev, "%s %s: G_SELECTION failed, invalid target (%d)\n",
> +			ctx->name, __func__, s->target);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int hva_s_selection(struct file *file, void *fh,
> +			   struct v4l2_selection *s)
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct v4l2_rect *in, out;
> +
> +	if ((s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
> +	    (s->target != V4L2_SEL_TGT_CROP)) {
> +		dev_err(dev, "%s %s: S_SELECTION failed, invalid type (%d)\n",
> +			ctx->name, __func__, s->type);

Drop this or make it dev_dbg. Invalid user input should not cause kernel log spamming.

> +		return -EINVAL;
> +	}
> +
> +	in = &s->r;
> +	out = *in;
> +
> +	/* align and check origin */
> +	out.left = ALIGN(in->left, ctx->frameinfo.fmt.w_align);
> +	out.top = ALIGN(in->top, ctx->frameinfo.fmt.h_align);
> +
> +	if (((out.left + out.width) >  ctx->frameinfo.width) ||
> +	    ((out.top + out.height) >  ctx->frameinfo.height)) {
> +		dev_err(dev,
> +			"%s %s: S_SELECTION failed, invalid crop %dx%d@(%d,%d)\n",
> +			ctx->name, __func__, out.width, out.height,
> +			out.left, out.top);

Ditto.

> +		return -EINVAL;
> +	}
> +
> +	/* checks adjust constraints flags */
> +	if (s->flags & V4L2_SEL_FLAG_LE && !is_rect_enclosed(&out, in))
> +		return -ERANGE;
> +
> +	if (s->flags & V4L2_SEL_FLAG_GE && !is_rect_enclosed(in, &out))
> +		return -ERANGE;
> +
> +	if ((out.left != in->left) || (out.top != in->top) ||
> +	    (out.width != in->width) || (out.height != in->height))
> +		*in = out;
> +
> +	ctx->frameinfo.crop = s->r;
> +
> +	return 0;
> +}
> +
> +/* vb2 ioctls operations */
> +
> +static int hva_vb2_frame_queue_setup(struct vb2_queue *q,
> +				     const void *parg,
> +				     unsigned int *num_buffers,
> +				     unsigned int *num_planes,
> +				     unsigned int sizes[], void *alloc_ctxs[])
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int width = ctx->frameinfo.frame_width;
> +	int height = ctx->frameinfo.frame_height;
> +
> +	dev_dbg(dev, "%s %s *num_buffers=%d\n", ctx->name, __func__,
> +		*num_buffers);
> +
> +	/* only one plane supported */
> +	*num_planes = 1;
> +
> +	/* setup nb of input buffers needed =
> +	 * user need (*num_buffer given, usually for grab pipeline) +
> +	 * encoder internal need
> +	 */
> +	if (*num_buffers < MIN_FRAMES) {
> +		dev_warn(dev,
> +			 "%s num_buffers too low (%d), increasing to %d\n",
> +			 ctx->name, *num_buffers, MIN_FRAMES);

dev_dbg, same for the remainder of this function.

Also, just set min_buffers_needed in vb2_queue to the minimum required buffers
and vb2 will take care of this for you.

> +		*num_buffers = MIN_FRAMES;
> +	}
> +
> +	if (*num_buffers > MAX_FRAMES) {
> +		dev_warn(dev,
> +			 "%s input frame count too high (%d), cut to %d\n",
> +			 ctx->name, *num_buffers, MAX_FRAMES);
> +		*num_buffers = MAX_FRAMES;
> +	}
> +
> +	if (sizes[0])
> +		dev_warn(dev, "%s psize[0] already set to %d\n", ctx->name,
> +			 sizes[0]);
> +
> +	if (alloc_ctxs[0])
> +		dev_warn(dev, "%s allocators[0] already set\n", ctx->name);

This is a meaningless check, just drop it.

> +
> +	if (!(ctx->flags & HVA_FLAG_FRAMEINFO)) {
> +		dev_err(dev, "%s %s frame format not set, using default format\n",
> +			ctx->name, __func__);
> +	}
> +
> +	sizes[0] = (width * height * ctx->frameinfo.fmt.bpp) / 8;
> +	alloc_ctxs[0] = vb2_dma_contig_init_ctx(dev);

The probe should call this and store the result in the top-level struct.
When the driver is removed the alloc context should be cleaned up. It's a one-time
thing.

> +	/* alloc_ctxs[0] will be freed @ reqbufs(0) or @ release */
> +
> +	return 0;
> +}
> +
> +static int hva_vb2_frame_prepare(struct vb2_buffer *vb)
> +{
> +	struct vb2_queue *q = vb->vb2_queue;
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct hva_frame *fm = (struct hva_frame *)vb;
> +
> +	if (!fm->prepared) {
> +		/* get memory addresses */
> +		fm->vaddr = vb2_plane_vaddr(&fm->v4l2.vb2_buf, 0);
> +		fm->paddr =
> +			vb2_dma_contig_plane_dma_addr(&fm->v4l2.vb2_buf, 0);
> +		fm->prepared = true;
> +
> +		ctx->num_frames++;
> +
> +		dev_dbg(dev, "%s frame[%d] prepared; virt=%p, phy=0x%x\n",
> +			ctx->name, vb->index, fm->vaddr,
> +			fm->paddr);
> +	}
> +
> +	return 0;
> +}
> +
> +static void hva_vb2_frame_queue(struct vb2_buffer *vb)
> +{
> +	struct vb2_queue *q = vb->vb2_queue;
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct device *dev = ctx_to_dev(ctx);
> +	const struct hva_encoder *enc = ctx_to_enc(ctx);
> +	struct hva_frame *fm = NULL;
> +	struct hva_stream *sr = NULL;
> +	int ret = 0;
> +
> +	fm = (struct hva_frame *)vb;
> +
> +	if (!vb2_is_streaming(q)) {
> +		vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
> +		return;
> +	}
> +
> +	/* get a free destination buffer */
> +	if (list_empty(&ctx->list_stream)) {
> +		dev_err(dev, "%s no free buffer for destination stream!\n",
> +			ctx->name);
> +		ctx->sys_errors++;
> +		goto err;
> +	}
> +	sr = list_first_entry(&ctx->list_stream, struct hva_stream, list);
> +
> +	if (!sr)
> +		goto err;
> +
> +	list_del(&sr->list);
> +
> +	/* encode the frame & get stream unit */
> +	ret = enc->encode(ctx, fm, sr);
> +	if (ret)
> +		goto err;
> +
> +	/* propagate frame timestamp */
> +	sr->v4l2.timestamp = fm->v4l2.timestamp;
> +
> +	ctx->encoded_frames++;
> +
> +	vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_DONE);
> +	vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_DONE);
> +
> +	return;
> +err:
> +	if (sr)
> +		vb2_buffer_done(&sr->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
> +
> +	vb2_buffer_done(&fm->v4l2.vb2_buf, VB2_BUF_STATE_ERROR);
> +}
> +
> +static int hva_vb2_stream_queue_setup(struct vb2_queue *q,
> +				      const void *parg,
> +				      unsigned int *num_buffers,
> +				      unsigned int *num_planes,
> +				      unsigned int sizes[], void *alloc_ctxs[])
> +{
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct device *dev = ctx_to_dev(ctx);
> +	int max_buf_size = 0;
> +	u32 pixelformat;
> +	int width;
> +	int height;
> +
> +	dev_dbg(dev, "%s %s *num_buffers=%d\n", ctx->name, __func__,
> +		*num_buffers);
> +
> +	/* only one plane supported */
> +	*num_planes = 1;
> +
> +	/* number of buffers must be at least 1 */
> +	if (*num_buffers < 1)
> +		*num_buffers = 1;
> +
> +	if (sizes[0])
> +		dev_warn(dev, "%s psize[0] already set to %d\n", ctx->name,
> +			 sizes[0]);
> +
> +	if (alloc_ctxs[0])
> +		dev_warn(dev, "%s allocators[0] already set\n", ctx->name);
> +
> +	if (!(ctx->flags & HVA_FLAG_STREAMINFO)) {
> +		dev_err(dev, "%s %s stream format not set, using dflt format\n",
> +			ctx->name, __func__);
> +	}
> +
> +	pixelformat = ctx->streaminfo.streamformat;
> +	width = ctx->streaminfo.width;
> +	height = ctx->streaminfo.height;
> +
> +	switch (pixelformat) {
> +	default:
> +		dev_err(dev, "%s %s Unknown stream format\n", ctx->name,
> +			__func__);
> +	}
> +
> +	sizes[0] = max_buf_size;
> +	alloc_ctxs[0] = vb2_dma_contig_init_ctx(dev);	/* free @ release */
> +
> +	return 0;
> +}
> +
> +static int hva_vb2_stream_prepare(struct vb2_buffer *vb)
> +{
> +	struct vb2_queue *q = vb->vb2_queue;
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct device *dev = ctx_to_dev(ctx);
> +	struct hva_stream *sr = (struct hva_stream *)vb;
> +
> +	if (!sr->prepared) {
> +		/* get memory addresses */
> +		sr->vaddr = vb2_plane_vaddr(&sr->v4l2.vb2_buf, 0);
> +		sr->paddr = vb2_dma_contig_plane_dma_addr(&sr->v4l2.vb2_buf, 0);
> +		sr->prepared = true;
> +
> +		dev_dbg(dev, "%s stream[%d] prepared; virt=%p, phy=0x%x\n",
> +			ctx->name, vb->index, sr->vaddr, sr->paddr);
> +	}
> +
> +	return 0;
> +}
> +
> +static void hva_vb2_stream_queue(struct vb2_buffer *vb)
> +{
> +	struct vb2_queue *q = vb->vb2_queue;
> +	struct hva_ctx *ctx = fh_to_ctx(q->drv_priv);
> +	struct hva_stream *sr = (struct hva_stream *)vb;
> +
> +	/* check validity of video stream */
> +	if (vb) {
> +		/* enqueue to a list destination stream */
> +		list_add(&sr->list, &ctx->list_stream);
> +	}
> +}
> +
> +static struct vb2_ops hva_vb2_frame_ops = {
> +	.queue_setup = hva_vb2_frame_queue_setup,
> +	.buf_prepare = hva_vb2_frame_prepare,
> +	.buf_queue = hva_vb2_frame_queue,
> +	.wait_prepare = vb2_ops_wait_prepare,
> +	.wait_finish = vb2_ops_wait_finish,
> +};
> +
> +static struct vb2_ops hva_vb2_stream_ops = {
> +	.queue_setup = hva_vb2_stream_queue_setup,
> +	.buf_prepare = hva_vb2_stream_prepare,
> +	.buf_queue = hva_vb2_stream_queue,
> +	.wait_prepare = vb2_ops_wait_prepare,
> +	.wait_finish = vb2_ops_wait_finish,

You really need to add start/stop_streaming ops to setup/release the encoder.
That's the right place to do that.

> +};
> +
> +/* file basics operations */
> +
> +static int hva_open(struct file *file)
> +{
> +	struct hva_device *hva = video_drvdata(file);
> +	struct vb2_queue *q;
> +	struct device *dev;
> +	struct hva_ctx *ctx;
> +	int ret = 0;
> +	unsigned int i;
> +
> +	WARN_ON(!hva);
> +	dev = hva->dev;
> +
> +	mutex_lock(&hva->lock);
> +
> +	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx) {
> +		mutex_unlock(&hva->lock);
> +		return -ENOMEM;
> +	}
> +
> +	/* store the context address in the contexts list */
> +	for (i = 0; i < MAX_CONTEXT; i++) {
> +		if (!hva->contexts_list[i]) {
> +			hva->contexts_list[i] = ctx;
> +			/* save client id in context */
> +			ctx->client_id = i;
> +			break;
> +		}
> +	}
> +
> +	v4l2_fh_init(&ctx->fh, video_devdata(file));
> +	file->private_data = &ctx->fh;
> +	v4l2_fh_add(&ctx->fh);
> +
> +	/* recopy device handlers */
> +	ctx->dev = hva->dev;
> +	ctx->hdev = hva;
> +
> +	/* setup vb2 queue for frame input */
> +	q = &ctx->q_frame;
> +	q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; /* to say input, weird! */
> +	q->io_modes = VB2_MMAP | VB2_DMABUF;
> +
> +	/* save file handle to private data field of the queue */
> +	q->drv_priv = &ctx->fh;
> +
> +	/* overload vb2 buffer size with private struct */
> +	q->buf_struct_size = sizeof(struct hva_frame);
> +
> +	q->ops = &hva_vb2_frame_ops;
> +	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
> +	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	q->lock = &hva->lock;
> +
> +	ret = vb2_queue_init(q);
> +	if (ret) {
> +		dev_err(dev, "%s [x:x] vb2_queue_init(frame) failed (%d)\n",
> +			HVA_PREFIX,  ret);
> +		ctx->sys_errors++;
> +		goto err_fh_del;
> +	}
> +
> +	/* setup vb2 queue of the destination */
> +	q = &ctx->q_stream;
> +	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +	q->io_modes = VB2_MMAP | VB2_DMABUF;
> +
> +	/* save file handle to private data field of the queue */
> +	q->drv_priv = &ctx->fh;
> +
> +	/* overload vb2 buffer size with private struct */
> +	q->buf_struct_size = sizeof(struct hva_stream);
> +
> +	q->ops = &hva_vb2_stream_ops;
> +	q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
> +	q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +	q->lock = &hva->lock;
> +
> +	ret = vb2_queue_init(q);
> +	if (ret) {
> +		dev_err(dev, "%s [x:x] vb2_queue_init(stream) failed (%d)\n",
> +			HVA_PREFIX, ret);
> +		ctx->sys_errors++;
> +		goto err_queue_del_frame;
> +	}
> +
> +	/* initialize the list of stream buffers */
> +	INIT_LIST_HEAD(&ctx->list_stream);
> +
> +	/* name this instance */
> +	hva->instance_id++;	/* rolling id to identify this instance */
> +	snprintf(ctx->name, sizeof(ctx->name), "[%3d:----]", hva->instance_id);
> +
> +	/* initialize controls */
> +	ctx->ctrls.bitrate_mode = DFT_CFG_BITRATE_MODE;
> +	ctx->ctrls.bitrate = DFT_CFG_BITRATE;
> +	ctx->ctrls.cpb_size = DFT_CFG_CPB_SIZE;
> +	ctx->ctrls.gop_size = DFT_CFG_GOP_SIZE;
> +	ctx->ctrls.intra_refresh = DFT_CFG_INTRA_REFRESH;
> +	ctx->ctrls.dct8x8 = DFT_CFG_DCT8X8;
> +	ctx->ctrls.qpmin = DFT_CFG_QPMIN;
> +	ctx->ctrls.qpmax = DFT_CFG_QPMAX;
> +	ctx->ctrls.jpeg_comp_quality = DFT_CFG_COMP_QUALITY;
> +	ctx->ctrls.vui_sar = DFT_CFG_SAR_ENABLE;
> +
> +	/* set by default time per frame */
> +	ctx->time_per_frame.numerator = DFT_CFG_FRAME_NUM;
> +	ctx->time_per_frame.denominator = DFT_CFG_FRAME_DEN;
> +
> +	/* default format */
> +	ctx->streaminfo = stream_dflt_fmt;
> +	ctx->frameinfo = frame_dflt_fmt;
> +
> +	hva->nb_of_instances++;
> +
> +	mutex_unlock(&hva->lock);
> +
> +	return 0;
> +
> +err_queue_del_frame:
> +	vb2_queue_release(&ctx->q_frame);
> +err_fh_del:
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +	hva->contexts_list[ctx->client_id] = NULL;
> +	devm_kfree(dev, ctx);
> +
> +	mutex_unlock(&hva->lock);
> +
> +	return ret;
> +}
> +
> +static int hva_release(struct file *file)
> +{
> +	struct hva_device *hva = video_drvdata(file);
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx_to_dev(ctx);
> +	const struct hva_encoder *enc = ctx_to_enc(ctx);
> +
> +	mutex_lock(&hva->lock);
> +
> +	/* free queues: source & destination */
> +	vb2_queue_release(&ctx->q_frame);
> +	vb2_queue_release(&ctx->q_stream);
> +
> +	v4l2_fh_del(&ctx->fh);
> +	v4l2_fh_exit(&ctx->fh);
> +
> +	/* will free dma memory of each frame in queue */
> +	vb2_queue_release(&ctx->q_frame);
> +	if (ctx->q_frame.alloc_ctx[0])
> +		vb2_dma_contig_cleanup_ctx(ctx->q_frame.alloc_ctx[0]);
> +
> +	/* will free dma memory of each aus in queue */
> +	vb2_queue_release(&ctx->q_stream);
> +	if (ctx->q_stream.alloc_ctx[0])
> +		vb2_dma_contig_cleanup_ctx(ctx->q_stream.alloc_ctx[0]);
> +
> +	/* clear context in contexts list */
> +	if ((ctx->client_id >= MAX_CONTEXT) ||
> +	    (hva->contexts_list[ctx->client_id] != ctx)) {
> +		dev_err(dev, "%s can't clear context in contexts list!\n",
> +			ctx->name);
> +		ctx->sys_errors++;
> +	}
> +	hva->contexts_list[ctx->client_id] = NULL;
> +
> +	/* close encoder */
> +	if (enc)
> +		enc->close(ctx);
> +
> +	devm_kfree(dev, ctx);
> +
> +	hva->nb_of_instances--;
> +
> +	mutex_unlock(&hva->lock);
> +
> +	return 0;
> +}
> +
> +static int hva_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> +	struct hva_device *hva = video_drvdata(file);
> +	struct hva_ctx *ctx = fh_to_ctx(file->private_data);
> +	struct device *dev = ctx->dev;
> +	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
> +	enum v4l2_buf_type type;
> +	int ret;
> +
> +	mutex_lock(&hva->lock);
> +
> +	/* offset used to differentiate OUTPUT/CAPTURE */
> +	if (offset < MMAP_FRAME_OFFSET) {
> +		type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
> +	} else {
> +		type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		vma->vm_pgoff -= (MMAP_FRAME_OFFSET >> PAGE_SHIFT);
> +	}
> +
> +	/* vb2 call */
> +	ret = vb2_mmap(get_queue(ctx, type), vma);
> +	if (ret) {
> +		dev_err(dev, "%s vb2_mmap failed (%d)\n", ctx->name, ret);
> +		ctx->sys_errors++;
> +		mutex_unlock(&hva->lock);
> +		return ret;
> +	}
> +
> +	mutex_unlock(&hva->lock);
> +
> +	return 0;
> +}
> +
> +/* v4l2 ops */
> +static const struct v4l2_file_operations hva_fops = {
> +	.owner = THIS_MODULE,
> +	.open = hva_open,
> +	.release = hva_release,
> +	.unlocked_ioctl = video_ioctl2,
> +	.mmap = hva_mmap,
> +};
> +
> +/* v4l2 ioctl ops */
> +static const struct v4l2_ioctl_ops hva_ioctl_ops = {
> +	.vidioc_querycap = hva_querycap,
> +	/* formats ioctl */
> +	.vidioc_enum_fmt_vid_cap	= hva_enum_fmt_stream,
> +	.vidioc_enum_fmt_vid_out	= hva_enum_fmt_frame,
> +	.vidioc_g_fmt_vid_cap		= hva_g_fmt_stream,
> +	.vidioc_g_fmt_vid_out		= hva_g_fmt_frame,
> +	.vidioc_try_fmt_vid_cap		= hva_try_fmt_stream,
> +	.vidioc_try_fmt_vid_out		= hva_try_fmt_frame,
> +	.vidioc_s_fmt_vid_cap		= hva_s_fmt_stream,
> +	.vidioc_s_fmt_vid_out		= hva_s_fmt_frame,
> +	.vidioc_s_ext_ctrls		= hva_s_ext_ctrls,
> +	.vidioc_g_parm			= hva_g_parm,
> +	.vidioc_s_parm			= hva_s_parm,
> +	/* buffers ioctls */
> +	.vidioc_reqbufs			= hva_reqbufs,
> +	.vidioc_create_bufs             = hva_create_bufs,
> +	.vidioc_querybuf		= hva_querybuf,
> +	.vidioc_expbuf			= hva_expbuf,
> +	.vidioc_qbuf			= hva_qbuf,
> +	.vidioc_dqbuf			= hva_dqbuf,
> +	/* stream ioctls */
> +	.vidioc_streamon		= hva_streamon,
> +	.vidioc_streamoff		= hva_streamoff,
> +	.vidioc_g_selection		= hva_g_selection,
> +	.vidioc_s_selection		= hva_s_selection,
> +};
> +
> +static int hva_probe(struct platform_device *pdev)
> +{
> +	struct hva_device *hva;
> +	struct device *dev = &pdev->dev;
> +	struct video_device *vdev;
> +	int ret;
> +
> +	hva = devm_kzalloc(dev, sizeof(*hva), GFP_KERNEL);
> +	if (!hva) {
> +		ret = -ENOMEM;
> +		goto err;
> +	}
> +
> +	hva->dev = dev;
> +	hva->pdev = pdev;
> +	platform_set_drvdata(pdev, hva);
> +
> +	mutex_init(&hva->lock);
> +
> +	/* probe hardware */
> +	ret = hva_hw_probe(pdev, hva);
> +	if (ret)
> +		goto err;
> +
> +	/* register all available encoders */
> +	register_all(hva);
> +
> +	/* register on V4L2 */
> +	ret = v4l2_device_register(dev, &hva->v4l2_dev);
> +	if (ret) {
> +		dev_err(dev, "%s %s could not register v4l2 device\n",
> +			HVA_PREFIX, HVA_NAME);
> +		goto err_hw_remove;
> +	}
> +
> +	vdev = video_device_alloc();
> +	vdev->fops = &hva_fops;
> +	vdev->ioctl_ops = &hva_ioctl_ops;
> +	vdev->release = video_device_release;
> +	vdev->lock = &hva->lock;
> +	vdev->v4l2_dev = &hva->v4l2_dev;
> +	snprintf(vdev->name, sizeof(vdev->name), "%s", HVA_NAME);
> +	vdev->vfl_dir = VFL_DIR_M2M;
> +	ret = video_register_device(vdev, VFL_TYPE_GRABBER, 0);
> +	if (ret) {
> +		dev_err(dev, "%s %s failed to register video device\n",
> +			HVA_PREFIX, HVA_NAME);
> +		goto err_vdev_release;
> +	}
> +
> +	hva->vdev = vdev;
> +	video_set_drvdata(vdev, hva);
> +
> +	dev_info(dev, "%s %s registered as /dev/video%d\n", HVA_PREFIX,
> +		 HVA_NAME, vdev->num);
> +
> +	dev_info(dev, "%s %s esram reserved for address: %p size:%d\n",
> +		 HVA_PREFIX, HVA_NAME, (void *)hva->esram_addr,
> +		 hva->esram_size);
> +
> +	return 0;
> +
> +err_vdev_release:
> +	video_device_release(vdev);
> +
> +err_hw_remove:
> +	hva_hw_remove(hva);
> +
> +err:
> +	return ret;
> +}
> +
> +static int hva_remove(struct platform_device *pdev)
> +{
> +	struct hva_device *hva = platform_get_drvdata(pdev);
> +	struct device *dev = hva_to_dev(hva);
> +
> +	dev_info(dev, "%s removing %s\n", HVA_PREFIX, pdev->name);
> +
> +	hva_hw_remove(hva);
> +
> +	video_unregister_device(hva->vdev);
> +	v4l2_device_unregister(&hva->v4l2_dev);
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops hva_pm_ops = {
> +	.runtime_suspend = hva_hw_runtime_suspend,
> +	.runtime_resume = hva_hw_runtime_resume,
> +};
> +
> +static const struct of_device_id hva_match_types[] = {
> +	{
> +	 .compatible = "st,stih407-hva",
> +	},
> +	{ /* end node */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, hva_match_types);
> +
> +struct platform_driver hva_driver = {
> +	.probe  = hva_probe,
> +	.remove = hva_remove,
> +	.driver = {
> +		.name           = HVA_NAME,
> +		.owner          = THIS_MODULE,
> +		.of_match_table = hva_match_types,
> +		.pm             = &hva_pm_ops,
> +		},
> +};
> +
> +module_platform_driver(hva_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
> +MODULE_DESCRIPTION("HVA video encoder V4L2 driver");

<snip>

Regards,

	Hans

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-01-11 10:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-12-18 10:45 [PATCH 0/3] support of v4l2 encoder for STMicroelectronics SOC Yannick Fertre
2015-12-18 10:45 ` [PATCH 1/3] Documentation: devicetree: add STI HVA binding Yannick Fertre
2015-12-18 10:45 ` [PATCH 2/3] [media] hva: STiH41x multi-format video encoder V4L2 driver Yannick Fertre
2015-12-18 11:42   ` kbuild test robot
2016-01-11 10:10   ` Hans Verkuil
2015-12-18 10:45 ` [PATCH 3/3] [media] hva: add h264 support Yannick Fertre

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).