linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests
@ 2018-06-18 14:58 Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings Paul Kocialkowski
                   ` (18 more replies)
  0 siblings, 19 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This is the fourth iteration of the updated Sunxi-Cedrus driver,
that supports the Video Engine found in most Allwinner SoCs, starting
with the A10. It was tested on the A13, A20 and A33.

The initial version of this driver[0] was originally written and
submitted by Florent Revest using a previous version of the request API
that is necessary to provide coherency between controls and the buffers
they apply to.

The driver was adapted to use the latest version of the media request
API[1], as submitted by Hand Verkuil. Media request API support is a
hard requirement for the Sunxi-Cedrus driver.

The driver itself currently only supports MPEG2 and more codecs will be
added to the driver eventually. The output frames provided by the
Video Engine are in a multi-planar 32x32-tiled YUV format, with a plane
for luminance (Y) and a plane for chrominance (UV). A specific format is
introduced in the V4L2 API to describe it.

This implementation is based on the significant work that was conducted
by various members of the linux-sunxi community for understanding and
documenting the Video Engine's innards.

Remaining tasks:
* verifying that the defined PCT types apply as-is to all MPEG formats;
* cleaning up register descriptions and documenting the fields used;
* testing on more platforms.

Changes since v3:
* updated to version 15 of the media request API;
* got rid of untested MPEG1 support;
* added definitons for picture coding types;
* added documentation about MPEG2 slice header fields;
* added documentation about MPEG2 slice format;
* added documentation about the MB32 NV12 format;
* added MPEG2 slice header validation;
* removed the assigned-clocks property;
* reworked and fixed error paths;
* harmonized debug prints, with v4l2 helpers when applicable;
* checked the series through checkpatch;
* switched to SPDX license headers;
* renamed MPEG2 frame header to slice header for consistency and clarity;
* removed A20 SRAM compatible from the driver's list.

Changes since v2:
* updated to version 13 of the media request API;
* integrated various changes from Maxime Ripard;
* reworked memory reservation to use CMA, dynamic allocation and allow
  DMABUF;
* removed reserved memory binding since the CMA pool is the default one
  (and allow ENODEV in the driver, for that use case);
* added SRAM controller support for the SRAM region used by the VE;
* updated the device-tree bindings the for SRAM region;
* added per-platform bindings;
* added A13 support;
* renamed VE node name and label;
* fixed Florent's authorship for the MPEG2 headers;
* added a MAINTAINERS entry.

Changes since v1:
* use the latest version of the request API for Hans Verkuil;
* added media controller support and dependency
* renamed v4l2 format to the more explicit V4L2_PIX_FMT_MB32_NV12;
* reworked bindings documentation;
* moved driver to drivers/media/platforms/sunxi/cedrus to pair with
  incoming CSI support ;
* added a workqueue and lists to schedule buffer completion, since it
  cannot be done in interrupt context;
* split mpeg2 support into a setup and a trigger function to avoid race
  condition;
* split video-related ops to a dedicated sunxi_cedrus_video file;
* cleaned up the included headers for each file;
* used device PFN offset instead of subtracting PHYS_BASE;
* used reset_control_reset instead of assert+deassert;
* put the device in reset when removing driver;
* changed dt bindings to use the last 96 Mib of the first 256 MiB of
  DRAM;
* made it clear in the mpeg frame header structure that forward and
  backward indexes are used as reference frames for motion vectors;
* lots of small cosmetic and consistency changes, including naming
  harmonization and headers text rework.

Cheers!

[0]: https://patchwork.kernel.org/patch/9299073/
[1]: https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=reqv15

Maxime Ripard (4):
  drivers: soc: sunxi: Add support for the C1 SRAM region
  ARM: sun5i: Add support for the C1 SRAM region with the SRAM
    controller
  ARM: sun7i-a20: Add support for the C1 SRAM region with the SRAM
    controller
  ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region

Paul Kocialkowski (15):
  dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller
    bindings
  dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region
  dt-bindings: sram: sunxi: Add A13 binding for the C1 SRAM region
  dt-bindings: sram: sunxi: Add A20 binding for the C1 SRAM region
  dt-bindings: sram: sunxi: Add A33 binding for the C1 SRAM region
  drivers: soc: sunxi: Add dedicated compatibles for the A13 and A33
  ARM: dts: sun5i: Use dedicated SRAM controller compatible
  ARM: dts: sun7i-a20: Also use dedicated SRAM controller compatible
  media: v4l: Add definitions for MPEG2 slice format and header metadata
  media: v4l: Add definition for Allwinner's MB32-tiled NV12 format
  dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
  media: platform: Add Sunxi-Cedrus VPU decoder driver
  ARM: dts: sun5i: Add Video Engine and reserved memory nodes
  ARM: dts: sun7i-a20: Add Video Engine and reserved memory nodes
  ARM: dts: sun8i-a33: Add Video Engine and reserved memory nodes

 .../bindings/media/sunxi-cedrus.txt           |  53 ++
 .../devicetree/bindings/sram/sunxi-sram.txt   |  13 +
 .../media/uapi/v4l/extended-controls.rst      |  73 +++
 .../media/uapi/v4l/pixfmt-compressed.rst      |   5 +
 .../media/uapi/v4l/pixfmt-reserved.rst        |  15 +-
 MAINTAINERS                                   |   7 +
 arch/arm/boot/dts/sun5i.dtsi                  |  44 +-
 arch/arm/boot/dts/sun7i-a20.dtsi              |  45 +-
 arch/arm/boot/dts/sun8i-a33.dtsi              |  51 ++
 drivers/media/platform/Kconfig                |   2 +
 drivers/media/platform/Makefile               |   1 +
 drivers/media/platform/sunxi/Kconfig          |  15 +
 drivers/media/platform/sunxi/Makefile         |   1 +
 drivers/media/platform/sunxi/cedrus/Kconfig   |  13 +
 drivers/media/platform/sunxi/cedrus/Makefile  |   3 +
 drivers/media/platform/sunxi/cedrus/cedrus.c  | 327 ++++++++++++
 drivers/media/platform/sunxi/cedrus/cedrus.h  | 117 ++++
 .../media/platform/sunxi/cedrus/cedrus_dec.c  | 170 ++++++
 .../media/platform/sunxi/cedrus/cedrus_dec.h  |  27 +
 .../media/platform/sunxi/cedrus/cedrus_hw.c   | 262 +++++++++
 .../media/platform/sunxi/cedrus/cedrus_hw.h   |  30 ++
 .../platform/sunxi/cedrus/cedrus_mpeg2.c      | 146 +++++
 .../platform/sunxi/cedrus/cedrus_mpeg2.h      |  24 +
 .../media/platform/sunxi/cedrus/cedrus_regs.h | 167 ++++++
 .../platform/sunxi/cedrus/cedrus_video.c      | 502 ++++++++++++++++++
 .../platform/sunxi/cedrus/cedrus_video.h      |  23 +
 drivers/media/v4l2-core/v4l2-ctrls.c          |  44 ++
 drivers/media/v4l2-core/v4l2-ioctl.c          |   2 +
 drivers/soc/sunxi/sunxi_sram.c                |  12 +
 include/uapi/linux/v4l2-controls.h            |  30 ++
 include/uapi/linux/videodev2.h                |   4 +
 31 files changed, 2225 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt
 create mode 100644 drivers/media/platform/sunxi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/Makefile
 create mode 100644 drivers/media/platform/sunxi/cedrus/Kconfig
 create mode 100644 drivers/media/platform/sunxi/cedrus/Makefile
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_regs.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.h

-- 
2.17.0


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

* [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 16:02   ` Maxime Ripard
  2018-06-18 14:58 ` [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region Paul Kocialkowski
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces dedicated bindings for the SRAM controllers found on the
A13, A20 and A33 sunxi platforms.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index d087f04a4d7f..19cc0b892672 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -11,6 +11,9 @@ Controller Node
 Required properties:
 - compatible : should be:
     - "allwinner,sun4i-a10-sram-controller"
+    - "allwinner,sun5i-a13-sram-controller"
+    - "allwinner,sun7i-a20-sram-controller"
+    - "allwinner,sun8i-a33-sram-controller"
     - "allwinner,sun50i-a64-sram-controller"
 - reg : sram controller register offset + length
 
-- 
2.17.0


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

* [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-20 15:59   ` Rob Herring
  2018-06-18 14:58 ` [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 " Paul Kocialkowski
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces a dedicated binding for the C1 SRAM region for the A10
sunxi platform.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index 19cc0b892672..5af5bafd5572 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -29,6 +29,7 @@ once again the representation described in the mmio-sram binding.
 
 The valid sections compatible for A10 are:
     - allwinner,sun4i-a10-sram-a3-a4
+    - allwinner,sun4i-a10-sram-c1
     - allwinner,sun4i-a10-sram-d
 
 The valid sections compatible for A64 are:
-- 
2.17.0


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

* [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 binding for the C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 16:01   ` Maxime Ripard
  2018-06-18 14:58 ` [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 " Paul Kocialkowski
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces a dedicated binding for the C1 SRAM region for the A13
sunxi platform.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index 5af5bafd5572..ddc82cbd7f4d 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -32,6 +32,9 @@ The valid sections compatible for A10 are:
     - allwinner,sun4i-a10-sram-c1
     - allwinner,sun4i-a10-sram-d
 
+The valid sections compatible for A13 are:
+    - allwinner,sun5i-a13-sram-c1
+
 The valid sections compatible for A64 are:
     - allwinner,sun50i-a64-sram-c
 
-- 
2.17.0


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

* [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 binding for the C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (2 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 16:04   ` Maxime Ripard
  2018-06-18 14:58 ` [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 " Paul Kocialkowski
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces a dedicated binding for the C1 SRAM region for the A20
sunxi platform.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index ddc82cbd7f4d..221fa7b42c18 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -35,6 +35,9 @@ The valid sections compatible for A10 are:
 The valid sections compatible for A13 are:
     - allwinner,sun5i-a13-sram-c1
 
+The valid sections compatible for A20 are:
+    - allwinner,sun7i-a20-sram-c1
+
 The valid sections compatible for A64 are:
     - allwinner,sun50i-a64-sram-c
 
-- 
2.17.0


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

* [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 binding for the C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (3 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-20 16:00   ` Rob Herring
  2018-06-22 14:19   ` Maxime Ripard
  2018-06-18 14:58 ` [PATCH v4 06/19] drivers: soc: sunxi: Add support " Paul Kocialkowski
                   ` (13 subsequent siblings)
  18 siblings, 2 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces a dedicated binding for the C1 SRAM region for the A33
sunxi platform.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index 221fa7b42c18..d8d1aac0840b 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -38,6 +38,9 @@ The valid sections compatible for A13 are:
 The valid sections compatible for A20 are:
     - allwinner,sun7i-a20-sram-c1
 
+The valid sections compatible for A33 are:
+    - allwinner,sun8i-a33-sram-c1
+
 The valid sections compatible for A64 are:
     - allwinner,sun50i-a64-sram-c
 
-- 
2.17.0


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

* [PATCH v4 06/19] drivers: soc: sunxi: Add support for the C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (4 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 07/19] drivers: soc: sunxi: Add dedicated compatibles for the A13 and A33 Paul Kocialkowski
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

From: Maxime Ripard <maxime.ripard@bootlin.com>

This introduces support for the SRAM C1 section, that is controlled by
the system controller. This SRAM area can be muxed either to the CPU
or the Video Engine, that needs this area to store various tables (e.g.
the Huffman VLD decoding tables).

This only supports devices with the same layout as the A10 (which also
includes the A13, A20, A33 and other SoCs).

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 882be5ed7e84..74cb81f37bd6 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -63,6 +63,12 @@ static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = {
 				  SUNXI_SRAM_MAP(1, 1, "emac")),
 };
 
+static struct sunxi_sram_desc sun4i_a10_sram_c1 = {
+	.data	= SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31,
+				  SUNXI_SRAM_MAP(0, 0, "cpu"),
+				  SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")),
+};
+
 static struct sunxi_sram_desc sun4i_a10_sram_d = {
 	.data	= SUNXI_SRAM_DATA("D", 0x4, 0x0, 1,
 				  SUNXI_SRAM_MAP(0, 0, "cpu"),
@@ -80,6 +86,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = {
 		.compatible	= "allwinner,sun4i-a10-sram-a3-a4",
 		.data		= &sun4i_a10_sram_a3_a4.data,
 	},
+	{
+		.compatible	= "allwinner,sun4i-a10-sram-c1",
+		.data		= &sun4i_a10_sram_c1.data,
+	},
 	{
 		.compatible	= "allwinner,sun4i-a10-sram-d",
 		.data		= &sun4i_a10_sram_d.data,
-- 
2.17.0


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

* [PATCH v4 07/19] drivers: soc: sunxi: Add dedicated compatibles for the A13 and A33
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (5 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 06/19] drivers: soc: sunxi: Add support " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 08/19] ARM: dts: sun5i: Use dedicated SRAM controller compatible Paul Kocialkowski
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces platform-specific compatibles for the A13 and A33 SRAM
driver. No particular adaptation for these platforms is required at
this point, although this might become the case in the future.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c
index 74cb81f37bd6..99b514d679fd 100644
--- a/drivers/soc/sunxi/sunxi_sram.c
+++ b/drivers/soc/sunxi/sunxi_sram.c
@@ -315,6 +315,8 @@ static int sunxi_sram_probe(struct platform_device *pdev)
 
 static const struct of_device_id sunxi_sram_dt_match[] = {
 	{ .compatible = "allwinner,sun4i-a10-sram-controller" },
+	{ .compatible = "allwinner,sun5i-a13-sram-controller" },
+	{ .compatible = "allwinner,sun8i-a33-sram-controller" },
 	{ .compatible = "allwinner,sun50i-a64-sram-controller" },
 	{ },
 };
-- 
2.17.0


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

* [PATCH v4 08/19] ARM: dts: sun5i: Use dedicated SRAM controller compatible
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (6 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 07/19] drivers: soc: sunxi: Add dedicated compatibles for the A13 and A33 Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 09/19] ARM: dts: sun7i-a20: Also use " Paul Kocialkowski
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

Use the newly-introduced SRAM controller compatible for the A13 and
other sun5i platforms instead of its A10 fashion.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 07f2248ed5f8..72433f38b4e4 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -115,7 +115,7 @@
 		ranges;
 
 		sram-controller@1c00000 {
-			compatible = "allwinner,sun4i-a10-sram-controller";
+			compatible = "allwinner,sun5i-a13-sram-controller";
 			reg = <0x01c00000 0x30>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
2.17.0


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

* [PATCH v4 09/19] ARM: dts: sun7i-a20: Also use dedicated SRAM controller compatible
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (7 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 08/19] ARM: dts: sun5i: Use dedicated SRAM controller compatible Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 10/19] ARM: sun5i: Add support for the C1 SRAM region with the SRAM controller Paul Kocialkowski
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

Use the newly-introduced SRAM controller compatible for the A20, aside
of its A10 fashion.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index e529e4ff2174..f64eab4ce6f1 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -240,7 +240,8 @@
 		ranges;
 
 		sram-controller@1c00000 {
-			compatible = "allwinner,sun4i-a10-sram-controller";
+			compatible = "allwinner,sun7i-a20-sram-controller",
+				     "allwinner,sun4i-a10-sram-controller";
 			reg = <0x01c00000 0x30>;
 			#address-cells = <1>;
 			#size-cells = <1>;
-- 
2.17.0


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

* [PATCH v4 10/19] ARM: sun5i: Add support for the C1 SRAM region with the SRAM controller
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (8 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 09/19] ARM: dts: sun7i-a20: Also use " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 11/19] ARM: sun7i-a20: " Paul Kocialkowski
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

From: Maxime Ripard <maxime.ripard@bootlin.com>

This adds support for the C1 SRAM region (to be used with the SRAM
controller driver) for sun5i-based platforms. The region is shared
between the Video Engine and the CPU.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 72433f38b4e4..6fa9e28edc59 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -135,6 +135,20 @@
 				status = "disabled";
 			};
 
+			sram_c: sram@1d00000 {
+				compatible = "mmio-sram";
+				reg = <0x01d00000 0xd00000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x01d00000 0xd00000>;
+
+				ve_sram: sram-section@0 {
+					compatible = "allwinner,sun5i-a13-sram-c1",
+						     "allwinner,sun4i-a10-sram-c1";
+					reg = <0x000000 0x80000>;
+				};
+			};
+
 			sram_d: sram@10000 {
 				compatible = "mmio-sram";
 				reg = <0x00010000 0x1000>;
-- 
2.17.0


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

* [PATCH v4 11/19] ARM: sun7i-a20: Add support for the C1 SRAM region with the SRAM controller
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (9 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 10/19] ARM: sun5i: Add support for the C1 SRAM region with the SRAM controller Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region Paul Kocialkowski
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

From: Maxime Ripard <maxime.ripard@bootlin.com>

This adds support for the C1 SRAM region (to be used with the SRAM
controller driver) for the A20 platform. The region is shared
between the Video Engine and the CPU.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index f64eab4ce6f1..9afd82f9ec79 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -274,6 +274,20 @@
 					status = "disabled";
 				};
 			};
+
+			sram_c: sram@1d00000 {
+				compatible = "mmio-sram";
+				reg = <0x01d00000 0xd00000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x01d00000 0xd00000>;
+
+				ve_sram: sram-section@0 {
+					compatible = "allwinner,sun7i-a20-sram-c1",
+						     "allwinner,sun4i-a10-sram-c1";
+					reg = <0x000000 0x80000>;
+				};
+			};
 		};
 
 		nmi_intc: interrupt-controller@1c00030 {
-- 
2.17.0


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

* [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (10 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 11/19] ARM: sun7i-a20: " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-22 14:20   ` Maxime Ripard
  2018-06-18 14:58 ` [PATCH v4 13/19] media: v4l: Add definitions for MPEG2 slice format and header metadata Paul Kocialkowski
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

From: Maxime Ripard <maxime.ripard@bootlin.com>

This adds a SRAM controller node for the A33, with support for the C1
SRAM region that is shared between the Video Engine and the CPU.

Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index a21f2ed07a52..97a976b3b1ef 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -204,6 +204,28 @@
 	};
 
 	soc@1c00000 {
+		sram-controller@1c00000 {
+			compatible = "allwinner,sun8i-a33-sram-controller";
+			reg = <0x01c00000 0x30>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			sram_c: sram@1d00000 {
+				compatible = "mmio-sram";
+				reg = <0x01d00000 0xd00000>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+				ranges = <0 0x01d00000 0xd00000>;
+
+				ve_sram: sram-section@0 {
+					compatible = "allwinner,sun8i-a33-sram-c1",
+						     "allwinner,sun4i-a10-sram-c1";
+					reg = <0x000000 0x80000>;
+				};
+			};
+		};
+
 		tcon0: lcd-controller@1c0c000 {
 			compatible = "allwinner,sun8i-a33-tcon";
 			reg = <0x01c0c000 0x1000>;
-- 
2.17.0


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

* [PATCH v4 13/19] media: v4l: Add definitions for MPEG2 slice format and header metadata
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (11 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 14/19] media: v4l: Add definition for Allwinner's MB32-tiled NV12 format Paul Kocialkowski
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

Stateless video decoding engines require both the MPEG slices and
associated metadata from the video stream in order to decode frames.

This introduces definitions for a new pixel format, describing buffers
with MPEG2 slice data, as well as a control structure for passing the
frame header (metadata) to drivers.

This is based on work from both Florent Revest and Hugues Fruchet.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/media/uapi/v4l/extended-controls.rst b/Documentation/media/uapi/v4l/extended-controls.rst
index 03931f9b1285..54f0dd396df2 100644
--- a/Documentation/media/uapi/v4l/extended-controls.rst
+++ b/Documentation/media/uapi/v4l/extended-controls.rst
@@ -1497,6 +1497,79 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
 
 
 
+.. _v4l2-mpeg-mpeg2:
+
+``V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER (struct)``
+    Specifies the slice parameters (also known as slice header) for an
+    associated MPEG-2 slice data. This includes all the necessary
+    parameters for configuring a hardware decoder pipeline for MPEG-2.
+
+.. tabularcolumns:: |p{2.0cm}|p{4.0cm}|p{11.0cm}|
+
+.. c:type:: v4l2_ctrl_mpeg2_slice_header
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_mpeg2_slice_header
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u32
+      - ``slice_len``
+      - Length (in bits) of the current slice data.
+    * - __u32
+      - ``slice_pos``
+      - Position (in bits) of the current slice data, relative to the
+        frame start.
+    * - __u16
+      - ``width``
+      - Width of the corresponding output frame for the current slice.
+    * - __u16
+      - ``height``
+      - Height of the corresponding output frame for the current slice.
+    * - __u8
+      - ``picture_coding_type``
+      - Picture coding type for the frame covered by the current slice
+        (V4L2_SLICE_PCT_I, V4L2_SLICE_PCT_P or V4L2_SLICE_PCT_B).
+    * - __u8
+      - ``f_code[2][2]``
+      - Motion vector codes.
+    * - __u8
+      - ``intra_dc_precision``
+      - Precision of Discrete Cosine transform (0: 8 bits precision,
+        1: 9 bits precision, 2: 10 bits precision, 11: 11 bits precision).
+    * - __u8
+      - ``picture_structure``
+      - Picture structure (1: interlaced top field,
+        2: interlaced bottom field, 3: progressive frame).
+    * - __u8
+      - ``top_field_first``
+      - If set to 1 and interlaced stream, top field is output first.
+    * - __u8
+      - ``frame_pred_frame_dct``
+      - If set to 1, only frame-DCT and frame prediction are used.
+    * - __u8
+      - ``concealment_motion_vectors``
+      -  If set to 1, motion vectors are coded for intra macroblocks.
+    * - __u8
+      - ``q_scale_type``
+      - This flag affects the inverse quantisation process.
+    * - __u8
+      - ``intra_vlc_format``
+      - This flag affects the decoding of transform coefficient data.
+    * - __u8
+      - ``alternate_scan``
+      - This flag affects the decoding of transform coefficient data.
+    * - __u8
+      - ``backward_ref_index``
+      - Index for the V4L2 buffer to use as backward reference, used with
+        B-coded and P-coded frames.
+    * - __u8
+      - ``forward_ref_index``
+      - Index for the V4L2 buffer to use as forward reference, used with
+        P-coded frames.
+    * - :cspan:`2`
 
 MFC 5.1 MPEG Controls
 ---------------------
diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst
index abec03937bb3..4e73f62b5163 100644
--- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst
+++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst
@@ -60,6 +60,11 @@ Compressed Formats
       - ``V4L2_PIX_FMT_MPEG2``
       - 'MPG2'
       - MPEG2 video elementary stream.
+    * .. _V4L2-PIX-FMT-MPEG2-SLICE:
+
+      - ``V4L2_PIX_FMT_MPEG2_SLICE``
+      - 'MG2S'
+      - MPEG2 parsed slice data, as extracted from the MPEG2 bitstream.
     * .. _V4L2-PIX-FMT-MPEG4:
 
       - ``V4L2_PIX_FMT_MPEG4``
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index a0c7a7fb2ff3..f46584e4d511 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -826,6 +826,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:		return "Vertical MV Search Range";
 	case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER:		return "Repeat Sequence Header";
 	case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:		return "Force Key Frame";
+	case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER:		return "MPEG2 Slice Header";
 
 	/* VPX controls */
 	case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:		return "VPX Number of Partitions";
@@ -1271,6 +1272,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_RDS_TX_ALT_FREQS:
 		*type = V4L2_CTRL_TYPE_U32;
 		break;
+	case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER:
+		*type = V4L2_CTRL_TYPE_MPEG2_SLICE_HEADER;
+		break;
 	default:
 		*type = V4L2_CTRL_TYPE_INTEGER;
 		break;
@@ -1529,6 +1533,7 @@ static void std_log(const struct v4l2_ctrl *ctrl)
 static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
 			union v4l2_ctrl_ptr ptr)
 {
+	struct v4l2_ctrl_mpeg2_slice_header *p_mpeg2_slice_header;
 	size_t len;
 	u64 offset;
 	s64 val;
@@ -1591,6 +1596,42 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
 			return -ERANGE;
 		return 0;
 
+	case V4L2_CTRL_TYPE_MPEG2_SLICE_HEADER:
+		p_mpeg2_slice_header = ptr.p;
+
+		switch (p_mpeg2_slice_header->intra_dc_precision) {
+		case 0: /* 8 bits */
+		case 1: /* 9 bits */
+		case 11: /* 11 bits */
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (p_mpeg2_slice_header->picture_structure) {
+		case 1: /* interlaced top field */
+		case 2: /* interlaced bottom field */
+		case 3: /* progressive */
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		switch (p_mpeg2_slice_header->picture_coding_type) {
+		case V4L2_SLICE_PCT_I:
+		case V4L2_SLICE_PCT_P:
+		case V4L2_SLICE_PCT_B:
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		if (p_mpeg2_slice_header->backward_ref_index > VIDEO_MAX_FRAME ||
+		    p_mpeg2_slice_header->forward_ref_index > VIDEO_MAX_FRAME)
+			return -EINVAL;
+
+		return 0;
+
 	default:
 		return -EINVAL;
 	}
@@ -2165,6 +2206,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 	case V4L2_CTRL_TYPE_U32:
 		elem_size = sizeof(u32);
 		break;
+	case V4L2_CTRL_TYPE_MPEG2_SLICE_HEADER:
+		elem_size = sizeof(struct v4l2_ctrl_mpeg2_slice_header);
+		break;
 	default:
 		if (type < V4L2_CTRL_COMPOUND_TYPES)
 			elem_size = sizeof(s32);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index eee04f29f1d3..98961d5acb1a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1267,6 +1267,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 		case V4L2_PIX_FMT_H263:		descr = "H.263"; break;
 		case V4L2_PIX_FMT_MPEG1:	descr = "MPEG-1 ES"; break;
 		case V4L2_PIX_FMT_MPEG2:	descr = "MPEG-2 ES"; break;
+		case V4L2_PIX_FMT_MPEG2_SLICE:	descr = "MPEG-2 parsed slice data"; break;
 		case V4L2_PIX_FMT_MPEG4:	descr = "MPEG-4 part 2 ES"; break;
 		case V4L2_PIX_FMT_XVID:		descr = "Xvid"; break;
 		case V4L2_PIX_FMT_VC1_ANNEX_G:	descr = "VC-1 (SMPTE 412M Annex G)"; break;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 8d473c979b61..2caf1f03a293 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -557,6 +557,8 @@ enum v4l2_mpeg_video_mpeg4_profile {
 };
 #define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL		(V4L2_CID_MPEG_BASE+407)
 
+#define V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER  (V4L2_CID_MPEG_BASE+450)
+
 /*  Control IDs for VP8 streams
  *  Although VP8 is not part of MPEG we add these controls to the MPEG class
  *  as that class is already handling other video compression standards
@@ -1076,4 +1078,32 @@ enum v4l2_detect_md_mode {
 #define V4L2_CID_DETECT_MD_THRESHOLD_GRID	(V4L2_CID_DETECT_CLASS_BASE + 3)
 #define V4L2_CID_DETECT_MD_REGION_GRID		(V4L2_CID_DETECT_CLASS_BASE + 4)
 
+#define V4L2_SLICE_PCT_I			1
+#define V4L2_SLICE_PCT_P			2
+#define V4L2_SLICE_PCT_B			3
+#define V4L2_SLICE_PCT_D			4
+
+struct v4l2_ctrl_mpeg2_slice_header {
+	__u32	slice_len;
+	__u32	slice_pos;
+
+	__u16	width;
+	__u16	height;
+
+	__u8	picture_coding_type;
+	__u8	f_code[2][2];
+
+	__u8	intra_dc_precision;
+	__u8	picture_structure;
+	__u8	top_field_first;
+	__u8	frame_pred_frame_dct;
+	__u8	concealment_motion_vectors;
+	__u8	q_scale_type;
+	__u8	intra_vlc_format;
+	__u8	alternate_scan;
+
+	__u8	backward_ref_index;
+	__u8	forward_ref_index;
+};
+
 #endif
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 1f6c4b52baae..5e950a6f20df 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -629,6 +629,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_H263     v4l2_fourcc('H', '2', '6', '3') /* H263          */
 #define V4L2_PIX_FMT_MPEG1    v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES     */
 #define V4L2_PIX_FMT_MPEG2    v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES     */
+#define V4L2_PIX_FMT_MPEG2_SLICE v4l2_fourcc('M', 'G', '2', 'S') /* MPEG-2 parsed slice data */
 #define V4L2_PIX_FMT_MPEG4    v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 part 2 ES */
 #define V4L2_PIX_FMT_XVID     v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid           */
 #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
@@ -1587,6 +1588,7 @@ struct v4l2_ext_control {
 		__u8 __user *p_u8;
 		__u16 __user *p_u16;
 		__u32 __user *p_u32;
+		struct v4l2_ctrl_mpeg2_slice_header __user *p_mpeg2_slice_header;
 		void __user *ptr;
 	};
 } __attribute__ ((packed));
@@ -1632,6 +1634,7 @@ enum v4l2_ctrl_type {
 	V4L2_CTRL_TYPE_U8	     = 0x0100,
 	V4L2_CTRL_TYPE_U16	     = 0x0101,
 	V4L2_CTRL_TYPE_U32	     = 0x0102,
+	V4L2_CTRL_TYPE_MPEG2_SLICE_HEADER = 0x0103,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
-- 
2.17.0


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

* [PATCH v4 14/19] media: v4l: Add definition for Allwinner's MB32-tiled NV12 format
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (12 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 13/19] media: v4l: Add definitions for MPEG2 slice format and header metadata Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver Paul Kocialkowski
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces support for Allwinner's MB32-tiled NV12 format, where
each plane is divided into macroblocks of 32x32 pixels. Hence, the size
of each plane has to be aligned to 32 bytes. The pixels inside each
macroblock are coded as they would be if the macroblock was a single
plane, line after line.

The MB32-tiled NV12 format is used by the video engine on Allwinner
platforms: it is the default format for decoded frames (and the only one
available in the oldest supported platforms).

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/Documentation/media/uapi/v4l/pixfmt-reserved.rst b/Documentation/media/uapi/v4l/pixfmt-reserved.rst
index 38af1472a4b4..9a68b6a787bf 100644
--- a/Documentation/media/uapi/v4l/pixfmt-reserved.rst
+++ b/Documentation/media/uapi/v4l/pixfmt-reserved.rst
@@ -243,7 +243,20 @@ please make a proposal on the linux-media mailing list.
 	It is an opaque intermediate format and the MDP hardware must be
 	used to convert ``V4L2_PIX_FMT_MT21C`` to ``V4L2_PIX_FMT_NV12M``,
 	``V4L2_PIX_FMT_YUV420M`` or ``V4L2_PIX_FMT_YVU420``.
-
+    * .. _V4L2-PIX-FMT-MB32-NV12:
+
+      - ``V4L2_PIX_FMT_MB32_NV12``
+      - 'MN12'
+      - Two-planar NV12-based format used by the Allwinner video engine
+        hardware, with 32x32 tiles for the luminance plane and 32x64 tiles
+        for the chrominance plane. Each tile is a linear pixel data
+        representation within its own bounds. Each tile follows the previous
+        one linearly (as in, from left to right, top to bottom).
+
+        The frame dimensions are aligned to match an integer number of
+        tiles, resulting in 32-aligned resolutions for the luminance plane
+        and 16-aligned resolutions for the chrominance plane (with 2x2
+        subsampling).
 
 .. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}|
 
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 98961d5acb1a..c44d7134e8d5 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1294,6 +1294,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
 		case V4L2_PIX_FMT_SE401:	descr = "GSPCA SE401"; break;
 		case V4L2_PIX_FMT_S5C_UYVY_JPG:	descr = "S5C73MX interleaved UYVY/JPEG"; break;
 		case V4L2_PIX_FMT_MT21C:	descr = "Mediatek Compressed Format"; break;
+		case V4L2_PIX_FMT_MB32_NV12:	descr = "Allwinner tiled NV12 format"; break;
 		default:
 			WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
 			if (fmt->description[0])
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 5e950a6f20df..cbbeeaec9710 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -670,6 +670,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_Z16      v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
 #define V4L2_PIX_FMT_MT21C    v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode  */
 #define V4L2_PIX_FMT_INZI     v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */
+#define V4L2_PIX_FMT_MB32_NV12 v4l2_fourcc('M', 'N', '1', '2') /* Allwinner tiled NV12 format */
 
 /* 10bit raw bayer packed, 32 bytes for every 25 pixels, last LSB 6 bits unused */
 #define V4L2_PIX_FMT_IPU3_SBGGR10	v4l2_fourcc('i', 'p', '3', 'b') /* IPU3 packed 10-bit BGGR bayer */
-- 
2.17.0


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

* [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (13 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 14/19] media: v4l: Add definition for Allwinner's MB32-tiled NV12 format Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-20 15:40   ` Rob Herring
  2018-06-18 14:58 ` [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver Paul Kocialkowski
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This adds a device-tree binding document that specifies the properties
used by the Sunxi-Cedurs VPU driver, as well as examples.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

 create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt

diff --git a/Documentation/devicetree/bindings/media/sunxi-cedrus.txt b/Documentation/devicetree/bindings/media/sunxi-cedrus.txt
new file mode 100644
index 000000000000..5ddda595aa8f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/sunxi-cedrus.txt
@@ -0,0 +1,53 @@
+Device-tree bindings for the VPU found in Allwinner SoCs, referred to as the
+Video Engine (VE) in Allwinner literature.
+
+The VPU can only access the first 256 MiB of DRAM, that are DMA-mapped starting
+from the DRAM base. This requires specific memory allocation and handling.
+
+Required properties:
+- compatible		: must be one of the following compatibles:
+			- "allwinner,sun4i-a10-video-engine"
+			- "allwinner,sun5i-a13-video-engine"
+			- "allwinner,sun7i-a20-video-engine"
+			- "allwinner,sun8i-a33-video-engine"
+- reg			: register base and length of VE;
+- clocks		: list of clock specifiers, corresponding to entries in
+			  the clock-names property;
+- clock-names		: should contain "ahb", "mod" and "ram" entries;
+- resets		: phandle for reset;
+- interrupts		: VE interrupt number;
+- allwinner,sram	: SRAM region to use with the VE.
+
+Optional properties:
+- memory-region		: CMA pool to use for buffers allocation instead of the
+			  default CMA pool.
+
+Example:
+
+reserved-memory {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	ranges;
+
+	/* Address must be kept in the lower 256 MiBs of DRAM for VE. */
+	cma_pool: cma@4a000000 {
+		compatible = "shared-dma-pool";
+		size = <0x6000000>;
+		alloc-ranges = <0x4a000000 0x6000000>;
+		reusable;
+		linux,cma-default;
+	};
+};
+
+video-codec@1c0e000 {
+	compatible = "allwinner,sun7i-a20-video-engine";
+	reg = <0x01c0e000 0x1000>;
+
+	clocks = <&ccu CLK_AHB_VE>, <&ccu CLK_VE>,
+		 <&ccu CLK_DRAM_VE>;
+	clock-names = "ahb", "mod", "ram";
+
+	resets = <&ccu RST_VE>;
+	interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+	allwinner,sram = <&ve_sram 1>;
+};
-- 
2.17.0


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

* [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (14 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-07-10  1:41   ` [linux-sunxi] " Ezequiel Garcia
  2018-06-18 14:58 ` [PATCH v4 17/19] ARM: dts: sun5i: Add Video Engine and reserved memory nodes Paul Kocialkowski
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This introduces the Sunxi-Cedrus VPU driver that supports the VPU found
in Allwinner SoCs, also known as Video Engine. It is implemented through
a v4l2 m2m decoder device and a media device (used for media requests).
So far, it only supports MPEG2 decoding.

Since this VPU is stateless, synchronization with media requests is
required in order to ensure consistency between frame headers that
contain metadata about the frame to process and the raw slice data that
is used to generate the frame.

This driver was made possible thanks to the long-standing effort
carried out by the linux-sunxi community in the interest of reverse
engineering, documenting and implementing support for Allwinner VPU.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

 create mode 100644 drivers/media/platform/sunxi/Kconfig
 create mode 100644 drivers/media/platform/sunxi/Makefile
 create mode 100644 drivers/media/platform/sunxi/cedrus/Kconfig
 create mode 100644 drivers/media/platform/sunxi/cedrus/Makefile
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_regs.h
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.c
 create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 9c125f705f78..b47dee397475 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -656,6 +656,13 @@ L:	linux-crypto@vger.kernel.org
 S:	Maintained
 F:	drivers/crypto/sunxi-ss/
 
+ALLWINNER VPU DRIVER
+M:	Maxime Ripard <maxime.ripard@bootlin.com>
+M:	Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	drivers/media/platform/sunxi/cedrus/
+
 ALPHA PORT
 M:	Richard Henderson <rth@twiddle.net>
 M:	Ivan Kokshaysky <ink@jurassic.park.msu.ru>
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index c7a1cf8a1b01..26da88bcd87b 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -31,6 +31,8 @@ source "drivers/media/platform/davinci/Kconfig"
 
 source "drivers/media/platform/omap/Kconfig"
 
+source "drivers/media/platform/sunxi/Kconfig"
+
 config VIDEO_SH_VOU
 	tristate "SuperH VOU video output driver"
 	depends on MEDIA_CAMERA_SUPPORT
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 932515df4477..01ac00adcbc4 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)	+= rockchip/rga/
 obj-y	+= omap/
 
 obj-$(CONFIG_VIDEO_AM437X_VPFE)		+= am437x/
+obj-$(CONFIG_VIDEO_SUNXI)		+= sunxi/
 
 obj-$(CONFIG_VIDEO_XILINX)		+= xilinx/
 
diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
new file mode 100644
index 000000000000..a639b0949826
--- /dev/null
+++ b/drivers/media/platform/sunxi/Kconfig
@@ -0,0 +1,15 @@
+config VIDEO_SUNXI
+	bool "Allwinner sunXi family Video Devices"
+	depends on ARCH_SUNXI
+	help
+	  If you have an Allwinner SoC based on the sunXi family, say Y.
+
+	  Note that this option doesn't include new drivers in the
+	  kernel: saying N will just cause Kconfig to skip all the
+	  questions about Allwinner media devices.
+
+if VIDEO_SUNXI
+
+source "drivers/media/platform/sunxi/cedrus/Kconfig"
+
+endif
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
new file mode 100644
index 000000000000..cee2846c3ecf
--- /dev/null
+++ b/drivers/media/platform/sunxi/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS)	+= cedrus/
diff --git a/drivers/media/platform/sunxi/cedrus/Kconfig b/drivers/media/platform/sunxi/cedrus/Kconfig
new file mode 100644
index 000000000000..870a4b64a45c
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/Kconfig
@@ -0,0 +1,13 @@
+config VIDEO_SUNXI_CEDRUS
+	tristate "Allwinner Cedrus VPU driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
+	depends on HAS_DMA
+	select VIDEOBUF2_DMA_CONTIG
+	select MEDIA_REQUEST_API
+	select V4L2_MEM2MEM_DEV
+	help
+	  Support for the VPU found in Allwinner SoCs, also known as the Cedar
+	  video engine.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called cedrus.
diff --git a/drivers/media/platform/sunxi/cedrus/Makefile b/drivers/media/platform/sunxi/cedrus/Makefile
new file mode 100644
index 000000000000..632a0be90ed7
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus.o
+
+cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.c b/drivers/media/platform/sunxi/cedrus/cedrus.c
new file mode 100644
index 000000000000..1718db1b549b
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus.c
@@ -0,0 +1,327 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_video.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+static int cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct cedrus_ctx *ctx =
+		container_of(ctrl->handler, struct cedrus_ctx, hdl);
+	struct cedrus_dev *dev = ctx->dev;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER:
+		/* This is kept in memory and used directly. */
+		break;
+	default:
+		v4l2_err(&dev->v4l2_dev, "Invalid control to set\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
+	.s_ctrl = cedrus_s_ctrl,
+};
+
+static const struct cedrus_control controls[] = {
+	[CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER] = {
+		.id		= V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER,
+		.elem_size	= sizeof(struct v4l2_ctrl_mpeg2_slice_header),
+	},
+};
+
+static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
+{
+	struct v4l2_ctrl_handler *hdl = &ctx->hdl;
+	unsigned int num_ctrls = ARRAY_SIZE(controls);
+	unsigned int i;
+
+	v4l2_ctrl_handler_init(hdl, num_ctrls);
+	if (hdl->error) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize control handler\n");
+		return hdl->error;
+	}
+
+	for (i = 0; i < num_ctrls; i++) {
+		struct v4l2_ctrl_config cfg = { 0 };
+
+		cfg.ops = &cedrus_ctrl_ops;
+		cfg.elem_size = controls[i].elem_size;
+		cfg.id = controls[i].id;
+
+		ctx->ctrls[i] = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+		if (hdl->error) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Failed to create new custom control\n");
+
+			v4l2_ctrl_handler_free(hdl);
+			return hdl->error;
+		}
+	}
+
+	ctx->fh.ctrl_handler = hdl;
+	v4l2_ctrl_handler_setup(hdl);
+
+	return 0;
+}
+
+static int cedrus_open(struct file *file)
+{
+	struct cedrus_dev *dev = video_drvdata(file);
+	struct cedrus_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->dev_mutex))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		mutex_unlock(&dev->dev_mutex);
+		return -ENOMEM;
+	}
+
+	INIT_WORK(&ctx->run_work, cedrus_device_work);
+
+	INIT_LIST_HEAD(&ctx->src_list);
+	INIT_LIST_HEAD(&ctx->dst_list);
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	ctx->dev = dev;
+
+	ret = cedrus_init_ctrls(dev, ctx);
+	if (ret)
+		goto err_free;
+
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+					    &cedrus_queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		goto err_ctrls;
+	}
+
+	v4l2_fh_add(&ctx->fh);
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+
+err_ctrls:
+	v4l2_ctrl_handler_free(&ctx->hdl);
+err_free:
+	kfree(ctx);
+	mutex_unlock(&dev->dev_mutex);
+
+	return ret;
+}
+
+static int cedrus_release(struct file *file)
+{
+	struct cedrus_dev *dev = video_drvdata(file);
+	struct cedrus_ctx *ctx = container_of(file->private_data,
+					      struct cedrus_ctx, fh);
+
+	mutex_lock(&dev->dev_mutex);
+
+	v4l2_fh_del(&ctx->fh);
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	v4l2_ctrl_handler_free(&ctx->hdl);
+
+	v4l2_fh_exit(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+
+	kfree(ctx);
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations cedrus_fops = {
+	.owner		= THIS_MODULE,
+	.open		= cedrus_open,
+	.release	= cedrus_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device cedrus_video_device = {
+	.name		= CEDRUS_NAME,
+	.vfl_dir	= VFL_DIR_M2M,
+	.fops		= &cedrus_fops,
+	.ioctl_ops	= &cedrus_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release_empty,
+};
+
+static const struct v4l2_m2m_ops cedrus_m2m_ops = {
+	.device_run	= cedrus_device_run,
+	.job_abort	= cedrus_job_abort,
+};
+
+static const struct media_device_ops cedrus_m2m_media_ops = {
+	.req_validate = vb2_request_validate,
+	.req_queue = vb2_m2m_request_queue,
+};
+
+static int cedrus_probe(struct platform_device *pdev)
+{
+	struct cedrus_dev *dev;
+	struct video_device *vfd;
+	int ret;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->dev = &pdev->dev;
+	dev->pdev = pdev;
+
+	ret = cedrus_hw_probe(dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to probe hardware\n");
+		return ret;
+	}
+
+	mutex_init(&dev->dev_mutex);
+	spin_lock_init(&dev->irq_lock);
+
+	dev->vfd = cedrus_video_device;
+	vfd = &dev->vfd;
+	vfd->lock = &dev->dev_mutex;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+
+	dev->mdev.dev = &pdev->dev;
+	strlcpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
+
+	media_device_init(&dev->mdev);
+	dev->mdev.ops = &cedrus_m2m_media_ops;
+	dev->v4l2_dev.mdev = &dev->mdev;
+	dev->pad[0].flags = MEDIA_PAD_FL_SINK;
+	dev->pad[1].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&vfd->entity, 2, dev->pad);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize media entity pads\n");
+		return ret;
+	}
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register V4L2 device\n");
+		return ret;
+	}
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+		goto err_v4l2;
+	}
+
+	video_set_drvdata(vfd, dev);
+	snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
+
+	v4l2_info(&dev->v4l2_dev,
+		  "Device registered as /dev/video%d\n", vfd->num);
+
+	platform_set_drvdata(pdev, dev);
+
+	dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize V4L2 M2M device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+		goto err_video;
+	}
+
+	ret = media_device_register(&dev->mdev);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
+		goto err_m2m;
+	}
+
+	return 0;
+
+err_m2m:
+	v4l2_m2m_release(dev->m2m_dev);
+err_video:
+	video_unregister_device(&dev->vfd);
+err_v4l2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	return ret;
+}
+
+static int cedrus_remove(struct platform_device *pdev)
+{
+	struct cedrus_dev *dev = platform_get_drvdata(pdev);
+
+	v4l2_info(&dev->v4l2_dev, "Removing " CEDRUS_NAME);
+
+	if (media_devnode_is_registered(dev->mdev.devnode)) {
+		media_device_unregister(&dev->mdev);
+		media_device_cleanup(&dev->mdev);
+	}
+
+	v4l2_m2m_release(dev->m2m_dev);
+	video_unregister_device(&dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+	cedrus_hw_remove(dev);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_cedrus_match[] = {
+	{ .compatible = "allwinner,sun4i-a10-video-engine" },
+	{ .compatible = "allwinner,sun5i-a13-video-engine" },
+	{ .compatible = "allwinner,sun7i-a20-video-engine" },
+	{ .compatible = "allwinner,sun8i-a33-video-engine" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_cedrus_match);
+#endif
+
+static struct platform_driver cedrus_driver = {
+	.probe		= cedrus_probe,
+	.remove		= cedrus_remove,
+	.driver		= {
+		.name	= CEDRUS_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(of_cedrus_match),
+	},
+};
+module_platform_driver(cedrus_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
+MODULE_DESCRIPTION("Sunxi-Cedrus VPU driver");
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.h b/drivers/media/platform/sunxi/cedrus/cedrus.h
new file mode 100644
index 000000000000..106bda44a3c3
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus.h
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_H_
+#define _CEDRUS_H_
+
+#include <linux/platform_device.h>
+
+#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define CEDRUS_NAME	"cedrus"
+
+enum cedrus_control_id {
+	CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER = 0,
+	CEDRUS_CTRL_MAX,
+};
+
+struct cedrus_control {
+	u32	id;
+	u32	elem_size;
+};
+
+struct cedrus_fmt {
+	u32		fourcc;
+	int		depth;
+	u32		types;
+	unsigned int	num_planes;
+};
+
+struct cedrus_mpeg2_run {
+	const struct v4l2_ctrl_mpeg2_slice_header	*hdr;
+};
+
+struct cedrus_run {
+	struct vb2_v4l2_buffer	*src;
+	struct vb2_v4l2_buffer	*dst;
+
+	union {
+		struct cedrus_mpeg2_run	mpeg2;
+	};
+};
+
+struct cedrus_ctx {
+	struct v4l2_fh			fh;
+	struct cedrus_dev		*dev;
+
+	struct cedrus_fmt		*vpu_src_fmt;
+	struct v4l2_pix_format_mplane	src_fmt;
+	struct cedrus_fmt		*vpu_dst_fmt;
+	struct v4l2_pix_format_mplane	dst_fmt;
+
+	struct v4l2_ctrl_handler	hdl;
+	struct v4l2_ctrl		*ctrls[CEDRUS_CTRL_MAX];
+
+	struct vb2_buffer		*dst_bufs[VIDEO_MAX_FRAME];
+
+	int				job_abort;
+
+	struct work_struct		try_schedule_work;
+	struct work_struct		run_work;
+	struct list_head		src_list;
+	struct list_head		dst_list;
+};
+
+struct cedrus_buffer {
+	struct vb2_v4l2_buffer		vb;
+	enum vb2_buffer_state		state;
+	struct list_head		list;
+};
+
+struct cedrus_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	vfd;
+	struct media_device	mdev;
+	struct media_pad	pad[2];
+	struct platform_device	*pdev;
+	struct device		*dev;
+	struct v4l2_m2m_dev	*m2m_dev;
+
+	/* Device file mutex */
+	struct mutex		dev_mutex;
+	/* Interrupt spinlock */
+	spinlock_t		irq_lock;
+
+	void __iomem		*base;
+
+	struct clk		*mod_clk;
+	struct clk		*ahb_clk;
+	struct clk		*ram_clk;
+
+	struct reset_control	*rstc;
+};
+
+static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
+{
+	writel(val, dev->base + reg);
+}
+
+static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
+{
+	return readl(dev->base + reg);
+}
+
+#endif
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.c b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
new file mode 100644
index 000000000000..bd9727ae9f63
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
@@ -0,0 +1,170 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_mpeg2.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+static inline void *get_ctrl_ptr(struct cedrus_ctx *ctx,
+				 enum cedrus_control_id id)
+{
+	struct v4l2_ctrl *ctrl = ctx->ctrls[id];
+
+	return ctrl->p_cur.p;
+}
+
+void cedrus_device_work(struct work_struct *work)
+{
+	struct cedrus_ctx *ctx = container_of(work,
+					      struct cedrus_ctx, run_work);
+	struct cedrus_dev *dev = ctx->dev;
+	struct cedrus_buffer *buffer_entry;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+	if (list_empty(&ctx->src_list) || list_empty(&ctx->dst_list)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Empty source and/or destination buffer lists\n");
+		spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+		return;
+	}
+
+	buffer_entry = list_last_entry(&ctx->src_list, struct cedrus_buffer, list);
+	list_del(ctx->src_list.prev);
+
+	src_buf = &buffer_entry->vb;
+	v4l2_m2m_buf_done(src_buf, buffer_entry->state);
+
+	buffer_entry = list_last_entry(&ctx->dst_list, struct cedrus_buffer, list);
+	list_del(ctx->dst_list.prev);
+
+	dst_buf = &buffer_entry->vb;
+	v4l2_m2m_buf_done(dst_buf, buffer_entry->state);
+
+	spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+void cedrus_device_run(void *priv)
+{
+	struct cedrus_ctx *ctx = priv;
+	struct cedrus_dev *dev = ctx->dev;
+	struct cedrus_run run = { 0 };
+	struct media_request *src_req;
+	unsigned long flags;
+
+	run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	if (!run.src) {
+		v4l2_err(&dev->v4l2_dev, "No source buffer to prepare\n");
+		return;
+	}
+
+	run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+	if (!run.dst) {
+		v4l2_err(&dev->v4l2_dev, "No destination buffer to prepare\n");
+		return;
+	}
+
+	/* Apply request(s) controls if needed. */
+	src_req = run.src->vb2_buf.req_obj.req;
+
+	if (src_req)
+		v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+
+	ctx->job_abort = 0;
+
+	spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+	switch (ctx->vpu_src_fmt->fourcc) {
+	case V4L2_PIX_FMT_MPEG2_SLICE:
+		if (!ctx->ctrls[CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER]) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Invalid MPEG2 frame header control\n");
+			ctx->job_abort = 1;
+			goto unlock_complete;
+		}
+
+		run.mpeg2.hdr = get_ctrl_ptr(ctx, CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER);
+		cedrus_mpeg2_setup(ctx, &run);
+		break;
+
+	default:
+		ctx->job_abort = 1;
+	}
+
+unlock_complete:
+	spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+	/* Complete request(s) controls if needed. */
+
+	if (src_req)
+		v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
+	spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+	if (!ctx->job_abort) {
+		if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG2_SLICE)
+			cedrus_mpeg2_trigger(ctx);
+	} else {
+		v4l2_m2m_buf_done(run.src, VB2_BUF_STATE_ERROR);
+		v4l2_m2m_buf_done(run.dst, VB2_BUF_STATE_ERROR);
+	}
+
+	spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+	if (ctx->job_abort)
+		v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+void cedrus_job_abort(void *priv)
+{
+	struct cedrus_ctx *ctx = priv;
+	struct vb2_v4l2_buffer *src_buf, *dst_buf;
+	unsigned long flags;
+
+	ctx->job_abort = 1;
+
+	/*
+	 * V4L2 M2M and request API cleanup is done here while hardware state
+	 * cleanup is done in the interrupt context. Doing all the cleanup in
+	 * the interrupt context is a bit risky, since the job_abort call might
+	 * originate from the release hook, where interrupts have already been
+	 * disabled.
+	 */
+
+	spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+	src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	if (src_buf)
+		v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+
+	dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	if (dst_buf)
+		v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+
+	spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+}
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.h b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
new file mode 100644
index 000000000000..b38812136504
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_DEC_H_
+#define _CEDRUS_DEC_H_
+
+extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
+
+void cedrus_device_work(struct work_struct *work);
+void cedrus_device_run(void *priv);
+void cedrus_job_abort(void *priv);
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq);
+
+#endif
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.c b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
new file mode 100644
index 000000000000..9ee1380f4e30
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <linux/platform_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/soc/sunxi/sunxi_sram.h>
+
+#include <media/videobuf2-core.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine)
+{
+	u32 reg = 0;
+
+	/*
+	 * FIXME: This is only valid on 32-bits DDR's, we should test
+	 * it on the A13/A33.
+	 */
+	reg |= VE_CTRL_REC_WR_MODE_2MB;
+
+	reg |= VE_CTRL_CACHE_BUS_BW_128;
+
+	switch (engine) {
+	case CEDRUS_ENGINE_MPEG:
+		reg |= VE_CTRL_DEC_MODE_MPEG;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	cedrus_write(dev, VE_CTRL, reg);
+
+	return 0;
+}
+
+void cedrus_engine_disable(struct cedrus_dev *dev)
+{
+	cedrus_write(dev, VE_CTRL, VE_CTRL_DEC_MODE_DISABLED);
+}
+
+static irqreturn_t cedrus_ve_irq(int irq, void *data)
+{
+	struct cedrus_dev *dev = data;
+	struct cedrus_ctx *ctx;
+	struct cedrus_buffer *src_buffer, *dst_buffer;
+	struct vb2_v4l2_buffer *src_vb, *dst_vb;
+	unsigned long flags;
+	unsigned int value, status;
+
+	spin_lock_irqsave(&dev->irq_lock, flags);
+
+	/* Disable MPEG interrupts and stop the MPEG engine. */
+	value = cedrus_read(dev, VE_MPEG_CTRL);
+	cedrus_write(dev, VE_MPEG_CTRL, value & (~0xf));
+
+	status = cedrus_read(dev, VE_MPEG_STATUS);
+	cedrus_write(dev, VE_MPEG_STATUS, 0x0000c00f);
+	cedrus_engine_disable(dev);
+
+	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+	if (!ctx) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Instance released before the end of transaction\n");
+		spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+		return IRQ_HANDLED;
+	}
+
+	src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+	if (!src_vb || !dst_vb) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Missing source and/or destination buffers\n");
+		spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+		return IRQ_HANDLED;
+	}
+
+	src_buffer = container_of(src_vb, struct cedrus_buffer, vb);
+	dst_buffer = container_of(dst_vb, struct cedrus_buffer, vb);
+
+	/* First bit of MPEG_STATUS indicates success. */
+	if (ctx->job_abort || !(status & 0x01))
+		src_buffer->state = dst_buffer->state = VB2_BUF_STATE_ERROR;
+	else
+		src_buffer->state = dst_buffer->state = VB2_BUF_STATE_DONE;
+
+	list_add_tail(&src_buffer->list, &ctx->src_list);
+	list_add_tail(&dst_buffer->list, &ctx->dst_list);
+
+	spin_unlock_irqrestore(&dev->irq_lock, flags);
+
+	schedule_work(&ctx->run_work);
+
+	return IRQ_HANDLED;
+}
+
+int cedrus_hw_probe(struct cedrus_dev *dev)
+{
+	struct resource *res;
+	int irq_dec;
+	int ret;
+
+	irq_dec = platform_get_irq(dev->pdev, 0);
+	if (irq_dec <= 0) {
+		v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n");
+		return -ENXIO;
+	}
+	ret = devm_request_irq(dev->dev, irq_dec, cedrus_ve_irq, 0,
+			       dev_name(dev->dev), dev);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * The VPU is only able to handle bus addresses so we have to subtract
+	 * the RAM offset to the physcal addresses.
+	 */
+	dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
+
+	ret = of_reserved_mem_device_init(dev->dev);
+	if (ret && ret != -ENODEV) {
+		v4l2_err(&dev->v4l2_dev, "Failed to reserved memory\n");
+		return -ENODEV;
+	}
+
+	ret = sunxi_sram_claim(dev->dev);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n");
+		goto err_mem;
+	}
+
+	dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
+	if (IS_ERR(dev->ahb_clk)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n");
+
+		ret = PTR_ERR(dev->ahb_clk);
+		goto err_sram;
+	}
+
+	dev->mod_clk = devm_clk_get(dev->dev, "mod");
+	if (IS_ERR(dev->mod_clk)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n");
+
+		ret = PTR_ERR(dev->mod_clk);
+		goto err_sram;
+	}
+
+	dev->ram_clk = devm_clk_get(dev->dev, "ram");
+	if (IS_ERR(dev->ram_clk)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n");
+
+		ret = PTR_ERR(dev->ram_clk);
+		goto err_sram;
+	}
+
+	dev->rstc = devm_reset_control_get(dev->dev, NULL);
+	if (IS_ERR(dev->rstc)) {
+		v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n");
+
+		ret = PTR_ERR(dev->rstc);
+		goto err_sram;
+	}
+
+	res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
+	dev->base = devm_ioremap_resource(dev->dev, res);
+	if (!dev->base) {
+		v4l2_err(&dev->v4l2_dev, "Failed to map registers\n");
+
+		ret = -EFAULT;
+		goto err_sram;
+	}
+
+	ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n");
+		goto err_sram;
+	}
+
+	ret = clk_prepare_enable(dev->ahb_clk);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n");
+
+		ret = -EFAULT;
+		goto err_sram;
+	}
+
+	ret = clk_prepare_enable(dev->mod_clk);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n");
+
+		ret = -EFAULT;
+		goto err_ahb_clk;
+	}
+
+	ret = clk_prepare_enable(dev->ram_clk);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n");
+
+		ret = -EFAULT;
+		goto err_mod_clk;
+	}
+
+	ret = reset_control_reset(dev->rstc);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n");
+
+		ret = -EFAULT;
+		goto err_ram_clk;
+	}
+
+	return 0;
+
+err_ram_clk:
+	clk_disable_unprepare(dev->ram_clk);
+err_mod_clk:
+	clk_disable_unprepare(dev->mod_clk);
+err_ahb_clk:
+	clk_disable_unprepare(dev->ahb_clk);
+err_sram:
+	sunxi_sram_release(dev->dev);
+err_mem:
+	of_reserved_mem_device_release(dev->dev);
+
+	return ret;
+}
+
+void cedrus_hw_remove(struct cedrus_dev *dev)
+{
+	reset_control_assert(dev->rstc);
+
+	clk_disable_unprepare(dev->ram_clk);
+	clk_disable_unprepare(dev->mod_clk);
+	clk_disable_unprepare(dev->ahb_clk);
+
+	sunxi_sram_release(dev->dev);
+
+	of_reserved_mem_device_release(dev->dev);
+}
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.h b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
new file mode 100644
index 000000000000..ead4f5089881
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_HW_H_
+#define _CEDRUS_HW_H_
+
+#define CEDRUS_CLOCK_RATE_DEFAULT	320000000
+
+enum cedrus_engine {
+	CEDRUS_ENGINE_MPEG,
+};
+
+int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine);
+void cedrus_engine_disable(struct cedrus_dev *dev);
+
+int cedrus_hw_probe(struct cedrus_dev *dev);
+void cedrus_hw_remove(struct cedrus_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
new file mode 100644
index 000000000000..0d6dcaec73b3
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cedrus.h"
+#include "cedrus_hw.h"
+#include "cedrus_regs.h"
+
+static const u8 mpeg_default_intra_quant[64] = {
+	8, 16, 16, 19, 16, 19, 22, 22,
+	22, 22, 22, 22, 26, 24, 26, 27,
+	27, 27, 26, 26, 26, 26, 27, 27,
+	27, 29, 29, 29, 34, 34, 34, 29,
+	29, 29, 27, 27, 29, 29, 32, 32,
+	34, 34, 37, 38, 37, 35, 35, 34,
+	35, 38, 38, 40, 40, 40, 48, 48,
+	46, 46, 56, 56, 58, 69, 69, 83
+};
+
+#define m_iq(i) (((64 + i) << 8) | mpeg_default_intra_quant[i])
+
+static const u8 mpeg_default_non_intra_quant[64] = {
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16,
+	16, 16, 16, 16, 16, 16, 16, 16
+};
+
+#define m_niq(i) ((i << 8) | mpeg_default_non_intra_quant[i])
+
+void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
+{
+	struct cedrus_dev *dev = ctx->dev;
+	const struct v4l2_ctrl_mpeg2_slice_header *frame_hdr = run->mpeg2.hdr;
+
+	u16 width = DIV_ROUND_UP(frame_hdr->width, 16);
+	u16 height = DIV_ROUND_UP(frame_hdr->height, 16);
+
+	u32 pic_header = 0;
+	u32 vld_len = frame_hdr->slice_len - frame_hdr->slice_pos;
+	int i;
+
+	struct vb2_buffer *fwd_vb2_buf, *bwd_vb2_buf;
+	dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
+	dma_addr_t fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
+
+	fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_ref_index];
+	if (fwd_vb2_buf) {
+		fwd_luma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 0);
+		fwd_chroma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 1);
+	}
+
+	bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_ref_index];
+	if (bwd_vb2_buf) {
+		bwd_luma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 0);
+		bwd_chroma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 1);
+	}
+
+	/* Activate MPEG engine. */
+	cedrus_engine_enable(dev, CEDRUS_ENGINE_MPEG);
+
+	/* Set quantization matrices. */
+	for (i = 0; i < 64; i++) {
+		cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_iq(i));
+		cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_niq(i));
+	}
+
+	/* Set frame dimensions. */
+	cedrus_write(dev, VE_MPEG_SIZE, width << 8 | height);
+	cedrus_write(dev, VE_MPEG_FRAME_SIZE, width << 20 | height << 4);
+
+	/* Set MPEG picture header. */
+	pic_header |= (frame_hdr->picture_coding_type & 0xf) << 28;
+	pic_header |= (frame_hdr->f_code[0][0] & 0xf) << 24;
+	pic_header |= (frame_hdr->f_code[0][1] & 0xf) << 20;
+	pic_header |= (frame_hdr->f_code[1][0] & 0xf) << 16;
+	pic_header |= (frame_hdr->f_code[1][1] & 0xf) << 12;
+	pic_header |= (frame_hdr->intra_dc_precision & 0x3) << 10;
+	pic_header |= (frame_hdr->picture_structure & 0x3) << 8;
+	pic_header |= (frame_hdr->top_field_first & 0x1) << 7;
+	pic_header |= (frame_hdr->frame_pred_frame_dct & 0x1) << 6;
+	pic_header |= (frame_hdr->concealment_motion_vectors & 0x1) << 5;
+	pic_header |= (frame_hdr->q_scale_type & 0x1) << 4;
+	pic_header |= (frame_hdr->intra_vlc_format & 0x1) << 3;
+	pic_header |= (frame_hdr->alternate_scan & 0x1) << 2;
+	cedrus_write(dev, VE_MPEG_PIC_HDR, pic_header);
+
+	/* Enable interrupt and an unknown control flag. */
+	cedrus_write(dev, VE_MPEG_CTRL, VE_MPEG_CTRL_MPEG2);
+
+	/* Macroblock address. */
+	cedrus_write(dev, VE_MPEG_MBA, 0);
+
+	/* Clear previous errors. */
+	cedrus_write(dev, VE_MPEG_ERROR, 0);
+
+	/* Clear correct macroblocks register. */
+	cedrus_write(dev, VE_MPEG_CTR_MB, 0);
+
+	/* Forward and backward prediction reference buffers. */
+	cedrus_write(dev, VE_MPEG_FWD_LUMA, fwd_luma);
+	cedrus_write(dev, VE_MPEG_FWD_CHROMA, fwd_chroma);
+	cedrus_write(dev, VE_MPEG_BACK_LUMA, bwd_luma);
+	cedrus_write(dev, VE_MPEG_BACK_CHROMA, bwd_chroma);
+
+	/* Destination luma and chroma buffers. */
+	dst_luma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0);
+	dst_chroma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1);
+	cedrus_write(dev, VE_MPEG_REC_LUMA, dst_luma_addr);
+	cedrus_write(dev, VE_MPEG_REC_CHROMA, dst_chroma_addr);
+	cedrus_write(dev, VE_MPEG_ROT_LUMA, dst_luma_addr);
+	cedrus_write(dev, VE_MPEG_ROT_CHROMA, dst_chroma_addr);
+
+	/* Source offset and length in bits. */
+	cedrus_write(dev, VE_MPEG_VLD_OFFSET, frame_hdr->slice_pos);
+	cedrus_write(dev, VE_MPEG_VLD_LEN, vld_len);
+
+	/* Source beginning and end addresses. */
+	src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
+	cedrus_write(dev, VE_MPEG_VLD_ADDR, VE_MPEG_VLD_ADDR_VAL(src_buf_addr));
+	cedrus_write(dev, VE_MPEG_VLD_END, src_buf_addr + VBV_SIZE - 1);
+}
+
+void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
+{
+	struct cedrus_dev *dev = ctx->dev;
+
+	/* Trigger MPEG engine. */
+	cedrus_write(dev, VE_MPEG_TRIGGER, VE_TRIG_MPEG2);
+}
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
new file mode 100644
index 000000000000..fd864fab6986
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_MPEG2_H_
+#define _CEDRUS_MPEG2_H_
+
+struct cedrus_ctx;
+struct cedrus_run;
+
+void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run);
+void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx);
+
+#endif
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_regs.h b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
new file mode 100644
index 000000000000..442befcdb6ea
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_REGS_H_
+#define _CEDRUS_REGS_H_
+
+/*
+ * For more information, consult http://linux-sunxi.org/VE_Register_guide
+ */
+
+/* VE_MPEG_CTRL:
+ * The bit 3 (0x8) is used to enable IRQs
+ * The other bits are unknown but needed
+ */
+#define VE_MPEG_CTRL_MPEG2	0x800001b8
+#define VE_MPEG_CTRL_MPEG4	(0x80084118 | BIT(7))
+#define VE_MPEG_CTRL_MPEG4_P	(VE_MPEG_CTRL_MPEG4 | BIT(12))
+
+/* VE_MPEG_VLD_ADDR:
+ * The bits 27 to 4 are used for the address
+ * The bits 31 to 28 (0x7) are used to select the MPEG or JPEG engine
+ */
+#define VE_MPEG_VLD_ADDR_VAL(x)	((x & 0x0ffffff0) | (x >> 28) | (0x7 << 28))
+
+/* VE_MPEG_TRIGGER:
+ * The first three bits are used to trigger the engine
+ * The bits 24 to 26 are used to select the input format (1 for MPEG1, 2 for
+ *                           MPEG2, 4 for MPEG4)
+ * The bit 21 (0x8) is used to disable bitstream error handling
+ *
+ * In MPEG4 the w*h value is somehow used for an offset, unknown but needed
+ */
+#define VE_TRIG_MPEG1		0x8100000f
+#define VE_TRIG_MPEG2		0x8200000f
+#define VE_TRIG_MPEG4(w, h)	(0x8400000d | ((w * h) << 8))
+
+/* VE_MPEG_SDROT_CTRL:
+ * The bit 8 at zero is used to disable x downscaling
+ * The bit 10 at 0 is used to disable y downscaling
+ * The other bits are unknown but needed
+ */
+#define VE_NO_SDROT_CTRL	0x40620000
+
+/* Decent size fo video buffering verifier */
+#define VBV_SIZE		(1024 * 1024)
+
+/* Registers addresses */
+#define VE_CTRL				0x000
+/*
+ * The datasheet states that this should be set to 2MB on a 32bits
+ * DDR-3.
+ */
+#define VE_CTRL_REC_WR_MODE_2MB			(1 << 20)
+#define VE_CTRL_REC_WR_MODE_1MB			(0 << 20)
+
+#define VE_CTRL_CACHE_BUS_BW_128		(3 << 16)
+#define VE_CTRL_CACHE_BUS_BW_256		(2 << 16)
+
+#define VE_CTRL_DEC_MODE_DISABLED		(7 << 0)
+#define VE_CTRL_DEC_MODE_H265			(4 << 0)
+#define VE_CTRL_DEC_MODE_H264			(1 << 0)
+#define VE_CTRL_DEC_MODE_MPEG			(0 << 0)
+
+#define VE_VERSION			0x0f0
+
+#define VE_MPEG_PIC_HDR			0x100
+#define VE_MPEG_VOP_HDR			0x104
+#define VE_MPEG_SIZE			0x108
+#define VE_MPEG_FRAME_SIZE		0x10c
+#define VE_MPEG_MBA			0x110
+#define VE_MPEG_CTRL			0x114
+#define VE_MPEG_TRIGGER			0x118
+#define VE_MPEG_STATUS			0x11c
+#define VE_MPEG_TRBTRD_FIELD		0x120
+#define VE_MPEG_TRBTRD_FRAME		0x124
+#define VE_MPEG_VLD_ADDR		0x128
+#define VE_MPEG_VLD_OFFSET		0x12c
+#define VE_MPEG_VLD_LEN			0x130
+#define VE_MPEG_VLD_END			0x134
+#define VE_MPEG_MBH_ADDR		0x138
+#define VE_MPEG_DCAC_ADDR		0x13c
+#define VE_MPEG_NCF_ADDR		0x144
+#define VE_MPEG_REC_LUMA		0x148
+#define VE_MPEG_REC_CHROMA		0x14c
+#define VE_MPEG_FWD_LUMA		0x150
+#define VE_MPEG_FWD_CHROMA		0x154
+#define VE_MPEG_BACK_LUMA		0x158
+#define VE_MPEG_BACK_CHROMA		0x15c
+#define VE_MPEG_IQ_MIN_INPUT		0x180
+#define VE_MPEG_QP_INPUT		0x184
+#define VE_MPEG_JPEG_SIZE		0x1b8
+#define VE_MPEG_JPEG_RES_INT		0x1c0
+#define VE_MPEG_ERROR			0x1c4
+#define VE_MPEG_CTR_MB			0x1c8
+#define VE_MPEG_ROT_LUMA		0x1cc
+#define VE_MPEG_ROT_CHROMA		0x1d0
+#define VE_MPEG_SDROT_CTRL		0x1d4
+#define VE_MPEG_RAM_WRITE_PTR		0x1e0
+#define VE_MPEG_RAM_WRITE_DATA		0x1e4
+
+#define VE_H264_FRAME_SIZE		0x200
+#define VE_H264_PIC_HDR			0x204
+#define VE_H264_SLICE_HDR		0x208
+#define VE_H264_SLICE_HDR2		0x20c
+#define VE_H264_PRED_WEIGHT		0x210
+#define VE_H264_QP_PARAM		0x21c
+#define VE_H264_CTRL			0x220
+#define VE_H264_TRIGGER			0x224
+#define VE_H264_STATUS			0x228
+#define VE_H264_CUR_MB_NUM		0x22c
+#define VE_H264_VLD_ADDR		0x230
+#define VE_H264_VLD_OFFSET		0x234
+#define VE_H264_VLD_LEN			0x238
+#define VE_H264_VLD_END			0x23c
+#define VE_H264_SDROT_CTRL		0x240
+#define VE_H264_OUTPUT_FRAME_IDX	0x24c
+#define VE_H264_EXTRA_BUFFER1		0x250
+#define VE_H264_EXTRA_BUFFER2		0x254
+#define VE_H264_BASIC_BITS		0x2dc
+#define VE_H264_RAM_WRITE_PTR		0x2e0
+#define VE_H264_RAM_WRITE_DATA		0x2e4
+
+#define VE_SRAM_H264_PRED_WEIGHT_TABLE	0x000
+#define VE_SRAM_H264_FRAMEBUFFER_LIST	0x400
+#define VE_SRAM_H264_REF_LIST0		0x640
+#define VE_SRAM_H264_REF_LIST1		0x664
+#define VE_SRAM_H264_SCALING_LISTS	0x800
+
+#define VE_ISP_INPUT_SIZE		0xa00
+#define VE_ISP_INPUT_STRIDE		0xa04
+#define VE_ISP_CTRL			0xa08
+#define VE_ISP_INPUT_LUMA		0xa78
+#define VE_ISP_INPUT_CHROMA		0xa7c
+
+#define VE_AVC_PARAM			0xb04
+#define VE_AVC_QP			0xb08
+#define VE_AVC_MOTION_EST		0xb10
+#define VE_AVC_CTRL			0xb14
+#define VE_AVC_TRIGGER			0xb18
+#define VE_AVC_STATUS			0xb1c
+#define VE_AVC_BASIC_BITS		0xb20
+#define VE_AVC_UNK_BUF			0xb60
+#define VE_AVC_VLE_ADDR			0xb80
+#define VE_AVC_VLE_END			0xb84
+#define VE_AVC_VLE_OFFSET		0xb88
+#define VE_AVC_VLE_MAX			0xb8c
+#define VE_AVC_VLE_LENGTH		0xb90
+#define VE_AVC_REF_LUMA			0xba0
+#define VE_AVC_REF_CHROMA		0xba4
+#define VE_AVC_REC_LUMA			0xbb0
+#define VE_AVC_REC_CHROMA		0xbb4
+#define VE_AVC_REF_SLUMA		0xbb8
+#define VE_AVC_REC_SLUMA		0xbbc
+#define VE_AVC_MB_INFO			0xbc0
+
+#endif
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.c b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
new file mode 100644
index 000000000000..ad7da8d36966
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "cedrus.h"
+#include "cedrus_mpeg2.h"
+#include "cedrus_dec.h"
+#include "cedrus_hw.h"
+
+/* Flags that indicate a format can be used for capture/output. */
+#define CEDRUS_CAPTURE	BIT(0)
+#define CEDRUS_OUTPUT	BIT(1)
+
+#define CEDRUS_MIN_WIDTH	16U
+#define CEDRUS_MIN_HEIGHT	16U
+#define CEDRUS_MAX_WIDTH	3840U
+#define CEDRUS_MAX_HEIGHT	2160U
+
+static struct cedrus_fmt formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_MB32_NV12,
+		.types	= CEDRUS_CAPTURE,
+		.depth = 2,
+		.num_planes = 2,
+	},
+	{
+		.fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+		.types	= CEDRUS_OUTPUT,
+		.num_planes = 1,
+	},
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct cedrus_fmt *find_format(struct v4l2_format *f)
+{
+	struct cedrus_fmt *fmt;
+	unsigned int k;
+
+	for (k = 0; k < NUM_FORMATS; k++) {
+		fmt = &formats[k];
+		if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
+			break;
+	}
+
+	if (k == NUM_FORMATS)
+		return NULL;
+
+	return &formats[k];
+}
+
+static inline struct cedrus_ctx *file2ctx(struct file *file)
+{
+	return container_of(file->private_data, struct cedrus_ctx, fh);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strncpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver) - 1);
+	strncpy(cap->card, CEDRUS_NAME, sizeof(cap->card) - 1);
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "platform:%s", CEDRUS_NAME);
+	cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+	return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+	struct cedrus_fmt *fmt;
+	int i, num = 0;
+
+	for (i = 0; i < NUM_FORMATS; ++i) {
+		if (formats[i].types & type) {
+			/* index-th format of type type found ? */
+			if (num == f->index)
+				break;
+			/*
+			 * Correct type but haven't reached our index yet,
+			 * just increment per-type index
+			 */
+			++num;
+		}
+	}
+
+	if (i < NUM_FORMATS) {
+		fmt = &formats[i];
+		f->pixelformat = fmt->fourcc;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, CEDRUS_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return enum_fmt(f, CEDRUS_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
+{
+	struct cedrus_dev *dev = ctx->dev;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		f->fmt.pix_mp = ctx->dst_fmt;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		f->fmt.pix_mp = ctx->src_fmt;
+		break;
+	default:
+		v4l2_err(&dev->v4l2_dev,
+			 "Invalid buffer type for getting format\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	return vidioc_g_fmt(file2ctx(file), f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct cedrus_fmt *fmt)
+{
+	int i;
+	__u32 bpl;
+
+	f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+	f->fmt.pix_mp.num_planes = fmt->num_planes;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (f->fmt.pix_mp.plane_fmt[0].sizeimage == 0)
+			return -EINVAL;
+
+		f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		/* Limit to hardware min/max. */
+		f->fmt.pix_mp.width = clamp(f->fmt.pix_mp.width,
+					    CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
+		f->fmt.pix_mp.height = clamp(f->fmt.pix_mp.height,
+					     CEDRUS_MIN_HEIGHT,
+					     CEDRUS_MAX_HEIGHT);
+
+		for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) {
+			bpl = (f->fmt.pix_mp.width * fmt->depth) >> 3;
+			f->fmt.pix_mp.plane_fmt[i].bytesperline = bpl;
+			f->fmt.pix_mp.plane_fmt[i].sizeimage =
+				f->fmt.pix_mp.height * bpl;
+		}
+		break;
+	}
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct cedrus_fmt *fmt;
+	struct cedrus_ctx *ctx = file2ctx(file);
+	struct cedrus_dev *dev = ctx->dev;
+
+	fmt = find_format(f);
+	if (!fmt) {
+		f->fmt.pix_mp.pixelformat = formats[0].fourcc;
+		fmt = find_format(f);
+	}
+	if (!(fmt->types & CEDRUS_CAPTURE)) {
+		v4l2_err(&dev->v4l2_dev, "Invalid destination format: %08x\n",
+			 f->fmt.pix_mp.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct cedrus_fmt *fmt;
+	struct cedrus_ctx *ctx = file2ctx(file);
+	struct cedrus_dev *dev = ctx->dev;
+
+	fmt = find_format(f);
+	if (!fmt) {
+		f->fmt.pix_mp.pixelformat = formats[0].fourcc;
+		fmt = find_format(f);
+	}
+	if (!(fmt->types & CEDRUS_OUTPUT)) {
+		v4l2_err(&dev->v4l2_dev, "Invalid source format: %08x\n",
+			 f->fmt.pix_mp.pixelformat);
+		return -EINVAL;
+	}
+
+	return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
+{
+	struct cedrus_dev *dev = ctx->dev;
+	struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+	struct cedrus_fmt *fmt;
+	int i, ret = 0;
+
+	switch (f->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		ctx->vpu_src_fmt = find_format(f);
+		ctx->src_fmt = *pix_fmt_mp;
+		break;
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		fmt = find_format(f);
+		ctx->vpu_dst_fmt = fmt;
+
+		for (i = 0; i < fmt->num_planes; ++i) {
+			pix_fmt_mp->plane_fmt[i].bytesperline =
+				pix_fmt_mp->width * fmt->depth;
+			pix_fmt_mp->plane_fmt[i].sizeimage =
+				pix_fmt_mp->plane_fmt[i].bytesperline
+				* pix_fmt_mp->height;
+		}
+		ctx->dst_fmt = *pix_fmt_mp;
+		break;
+	default:
+		v4l2_err(&dev->v4l2_dev,
+			 "Invalid buffer type for setting format\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cedrus_ctx *ctx = file2ctx(file);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(ctx, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct cedrus_ctx *ctx = file2ctx(file);
+	int ret;
+
+	ret = vidioc_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	return vidioc_s_fmt(ctx, f);
+}
+
+const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
+	.vidioc_querycap		= vidioc_querycap,
+
+	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap_mplane	= vidioc_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap_mplane	= vidioc_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap_mplane	= vidioc_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out_mplane	= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out_mplane	= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out_mplane	= vidioc_s_fmt_vid_out,
+
+	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
+	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
+	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
+	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
+	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
+	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
+	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
+
+	.vidioc_streamon		= v4l2_m2m_ioctl_streamon,
+	.vidioc_streamoff		= v4l2_m2m_ioctl_streamoff,
+
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+			      unsigned int *nplanes, unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+	struct cedrus_dev *dev = ctx->dev;
+
+	switch (vq->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		*nplanes = ctx->vpu_src_fmt->num_planes;
+
+		sizes[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
+		break;
+
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		*nplanes = ctx->vpu_dst_fmt->num_planes;
+
+		sizes[0] = round_up(ctx->dst_fmt.plane_fmt[0].sizeimage, 8);
+		sizes[1] = sizes[0];
+		break;
+
+	default:
+		v4l2_err(&dev->v4l2_dev,
+			 "Invalid buffer type for queue setup\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int cedrus_buf_init(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct cedrus_ctx *ctx = container_of(vq->drv_priv,
+					      struct cedrus_ctx, fh);
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		ctx->dst_bufs[vb->index] = vb;
+
+	return 0;
+}
+
+static void cedrus_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct cedrus_ctx *ctx = container_of(vq->drv_priv,
+					      struct cedrus_ctx, fh);
+
+	if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+		ctx->dst_bufs[vb->index] = NULL;
+}
+
+static int cedrus_buf_prepare(struct vb2_buffer *vb)
+{
+	struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+	struct cedrus_dev *dev = ctx->dev;
+	struct vb2_queue *vq = vb->vb2_queue;
+	int i;
+
+	switch (vq->type) {
+	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+		if (vb2_plane_size(vb, 0)
+		    < ctx->src_fmt.plane_fmt[0].sizeimage) {
+			v4l2_err(&dev->v4l2_dev,
+				 "Buffer plane size too small for output\n");
+			return -EINVAL;
+		}
+		break;
+
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+		for (i = 0; i < ctx->vpu_dst_fmt->num_planes; ++i) {
+			if (vb2_plane_size(vb, i)
+			    < ctx->dst_fmt.plane_fmt[i].sizeimage) {
+				v4l2_err(&dev->v4l2_dev,
+					 "Buffer plane %d size too small for capture\n",
+					 i);
+				break;
+			}
+		}
+
+		if (i != ctx->vpu_dst_fmt->num_planes)
+			return -EINVAL;
+		break;
+
+	default:
+		v4l2_err(&dev->v4l2_dev,
+			 "Invalid buffer type for buffer preparation\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void cedrus_stop_streaming(struct vb2_queue *q)
+{
+	struct cedrus_ctx *ctx = vb2_get_drv_priv(q);
+	struct vb2_v4l2_buffer *vbuf;
+	unsigned long flags;
+
+	flush_scheduled_work();
+	for (;;) {
+		spin_lock_irqsave(&ctx->dev->irq_lock, flags);
+
+		if (V4L2_TYPE_IS_OUTPUT(q->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
+
+		if (vbuf == NULL)
+			return;
+
+		v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+					   &ctx->hdl);
+		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+	}
+}
+
+static void cedrus_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void cedrus_buf_request_complete(struct vb2_buffer *vb)
+{
+	struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
+static struct vb2_ops cedrus_qops = {
+	.queue_setup		= cedrus_queue_setup,
+	.buf_prepare		= cedrus_buf_prepare,
+	.buf_init		= cedrus_buf_init,
+	.buf_cleanup		= cedrus_buf_cleanup,
+	.buf_queue		= cedrus_buf_queue,
+	.buf_request_complete	= cedrus_buf_request_complete,
+	.stop_streaming		= cedrus_stop_streaming,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq)
+{
+	struct cedrus_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
+	src_vq->allow_zero_bytesused = 1;
+	src_vq->min_buffers_needed = 1;
+	src_vq->ops = &cedrus_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->dev->dev_mutex;
+	src_vq->dev = ctx->dev->dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
+	dst_vq->allow_zero_bytesused = 1;
+	dst_vq->min_buffers_needed = 1;
+	dst_vq->ops = &cedrus_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->dev->dev_mutex;
+	dst_vq->dev = ctx->dev->dev;
+
+	return vb2_queue_init(dst_vq);
+}
diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.h b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
new file mode 100644
index 000000000000..ed7cea8a6d8f
--- /dev/null
+++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sunxi-Cedrus VPU driver
+ *
+ * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on the vim2m driver, that is:
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ */
+
+#ifndef _CEDRUS_VIDEO_H_
+#define _CEDRUS_VIDEO_H_
+
+extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
+
+int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
+		      struct vb2_queue *dst_vq);
+
+#endif
-- 
2.17.0


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

* [PATCH v4 17/19] ARM: dts: sun5i: Add Video Engine and reserved memory nodes
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (15 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 18/19] ARM: dts: sun7i-a20: " Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 19/19] ARM: dts: sun8i-a33: " Paul Kocialkowski
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This adds nodes for the Video Engine and the associated reserved memory
for sun5i-based platforms. Up to 96 MiB of memory are dedicated to the
CMA pool.

The VPU can only map the first 256 MiB of DRAM, so the reserved memory
pool has to be located in that area. Following Allwinner's decision in
downstream software, the last 96 MiB of the first 256 MiB of RAM are
reserved for this purpose.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 6fa9e28edc59..3138f791b6b2 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -108,6 +108,21 @@
 		};
 	};
 
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* Address must be kept in the lower 256 MiBs of DRAM for VE. */
+		cma_pool: cma@4a000000 {
+			compatible = "shared-dma-pool";
+			size = <0x6000000>;
+			alloc-ranges = <0x4a000000 0x6000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
 	soc@1c00000 {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -292,6 +307,19 @@
 			};
 		};
 
+		vpu: video-codec@1c0e000 {
+			compatible = "allwinner,sun5i-a13-video-engine";
+			reg = <0x01c0e000 0x1000>;
+
+			clocks = <&ccu CLK_AHB_VE>, <&ccu CLK_VE>,
+				 <&ccu CLK_DRAM_VE>;
+			clock-names = "ahb", "mod", "ram";
+
+			resets = <&ccu RST_VE>;
+			interrupts = <53>;
+			allwinner,sram = <&ve_sram 1>;
+		};
+
 		mmc0: mmc@1c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
-- 
2.17.0


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

* [PATCH v4 18/19] ARM: dts: sun7i-a20: Add Video Engine and reserved memory nodes
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (16 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 17/19] ARM: dts: sun5i: Add Video Engine and reserved memory nodes Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  2018-06-18 14:58 ` [PATCH v4 19/19] ARM: dts: sun8i-a33: " Paul Kocialkowski
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This adds nodes for the Video Engine and the associated reserved memory
for the A20. Up to 96 MiB of memory are dedicated to the CMA pool.

The VPU can only map the first 256 MiB of DRAM, so the reserved memory
pool has to be located in that area. Following Allwinner's decision in
downstream software, the last 96 MiB of the first 256 MiB of RAM are
reserved for this purpose.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 9afd82f9ec79..479272f02686 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -161,6 +161,21 @@
 		reg = <0x40000000 0x80000000>;
 	};
 
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* Address must be kept in the lower 256 MiBs of DRAM for VE. */
+		cma_pool: cma@4a000000 {
+			compatible = "shared-dma-pool";
+			size = <0x6000000>;
+			alloc-ranges = <0x4a000000 0x6000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -464,6 +479,19 @@
 			};
 		};
 
+		vpu: video-codec@1c0e000 {
+			compatible = "allwinner,sun7i-a20-video-engine";
+			reg = <0x01c0e000 0x1000>;
+
+			clocks = <&ccu CLK_AHB_VE>, <&ccu CLK_VE>,
+				 <&ccu CLK_DRAM_VE>;
+			clock-names = "ahb", "mod", "ram";
+
+			resets = <&ccu RST_VE>;
+			interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+			allwinner,sram = <&ve_sram 1>;
+		};
+
 		mmc0: mmc@1c0f000 {
 			compatible = "allwinner,sun7i-a20-mmc";
 			reg = <0x01c0f000 0x1000>;
-- 
2.17.0


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

* [PATCH v4 19/19] ARM: dts: sun8i-a33: Add Video Engine and reserved memory nodes
  2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
                   ` (17 preceding siblings ...)
  2018-06-18 14:58 ` [PATCH v4 18/19] ARM: dts: sun7i-a20: " Paul Kocialkowski
@ 2018-06-18 14:58 ` Paul Kocialkowski
  18 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-18 14:58 UTC (permalink / raw)
  To: linux-media, devicetree, linux-arm-kernel, linux-kernel
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Paul Kocialkowski, Marco Franchi, Icenowy Zheng,
	Hans Verkuil, Sylwester Nawrocki, Tom Saeger, Smitha T Murthy,
	Sakari Ailus, Andrzej Hajda, Jonathan Corbet, David S . Miller,
	Andrew Morton, Greg Kroah-Hartman, Linus Walleij, Randy Dunlap,
	Arnd Bergmann, Stanimir Varbanov, Philipp Zabel,
	Ramesh Shanmugasundaram, Jacob Chen, Steve Longerbeam,
	Todor Tomov, Jacopo Mondi, Alexandre Courbot, Marek Szyprowski,
	Andy Shevchenko, Tomasz Figa, Ricardo Ribalda Delgado,
	Hans de Goede, Sami Tolvanen, Thomas Petazzoni, linux-sunxi,
	Hugues Fruchet, Randy Li

This adds nodes for the Video Engine and the associated reserved memory
for the A33. Up to 96 MiB of memory are dedicated to the CMA pool.

The VPU can only map the first 256 MiB of DRAM, so the reserved memory
pool has to be located in that area. Following Allwinner's decision in
downstream software, the last 96 MiB of the first 256 MiB of RAM are
reserved for this purpose.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 97a976b3b1ef..c5c108a11285 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -181,6 +181,21 @@
 		reg = <0x40000000 0x80000000>;
 	};
 
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		/* Address must be kept in the lower 256 MiBs of DRAM for VE. */
+		cma_pool: cma@4a000000 {
+			compatible = "shared-dma-pool";
+			size = <0x6000000>;
+			alloc-ranges = <0x4a000000 0x6000000>;
+			reusable;
+			linux,cma-default;
+		};
+	};
+
 	sound: sound {
 		compatible = "simple-audio-card";
 		simple-audio-card,name = "sun8i-a33-audio";
@@ -262,6 +277,20 @@
 			};
 		};
 
+		vpu: video-codec@01c0e000 {
+			compatible = "allwinner,sun8i-a33-video-engine";
+			reg = <0x01c0e000 0x1000>;
+
+			clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>,
+				 <&ccu CLK_DRAM_VE>;
+			clock-names = "ahb", "mod", "ram";
+
+			resets = <&ccu RST_BUS_VE>;
+
+			interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+			allwinner,sram = <&ve_sram 1>;
+		};
+
 		crypto: crypto-engine@1c15000 {
 			compatible = "allwinner,sun4i-a10-crypto";
 			reg = <0x01c15000 0x1000>;
-- 
2.17.0


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

* Re: [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 binding for the C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 " Paul Kocialkowski
@ 2018-06-18 16:01   ` Maxime Ripard
  0 siblings, 0 replies; 31+ messages in thread
From: Maxime Ripard @ 2018-06-18 16:01 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

On Mon, Jun 18, 2018 at 04:58:27PM +0200, Paul Kocialkowski wrote:
> This introduces a dedicated binding for the C1 SRAM region for the A13
> sunxi platform.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> 
> diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> index 5af5bafd5572..ddc82cbd7f4d 100644
> --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> @@ -32,6 +32,9 @@ The valid sections compatible for A10 are:
>      - allwinner,sun4i-a10-sram-c1
>      - allwinner,sun4i-a10-sram-d
>  
> +The valid sections compatible for A13 are:
> +    - allwinner,sun5i-a13-sram-c1

It supports more SRAM than that, namely the SRAM A3-A4, C1 and D, at
least.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings
  2018-06-18 14:58 ` [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings Paul Kocialkowski
@ 2018-06-18 16:02   ` Maxime Ripard
  0 siblings, 0 replies; 31+ messages in thread
From: Maxime Ripard @ 2018-06-18 16:02 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

On Mon, Jun 18, 2018 at 04:58:25PM +0200, Paul Kocialkowski wrote:
> This introduces dedicated bindings for the SRAM controllers found on the
> A13, A20 and A33 sunxi platforms.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

Explaining why you need to add these new compatibles would be great.

> diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> index d087f04a4d7f..19cc0b892672 100644
> --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> @@ -11,6 +11,9 @@ Controller Node
>  Required properties:
>  - compatible : should be:
>      - "allwinner,sun4i-a10-sram-controller"
> +    - "allwinner,sun5i-a13-sram-controller"
> +    - "allwinner,sun7i-a20-sram-controller"
> +    - "allwinner,sun8i-a33-sram-controller"

And I think Chen-Yu asked you to rename this compatible to
-system-controller for the previous iteration?

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 binding for the C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 " Paul Kocialkowski
@ 2018-06-18 16:04   ` Maxime Ripard
  0 siblings, 0 replies; 31+ messages in thread
From: Maxime Ripard @ 2018-06-18 16:04 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

1;5202;0c
On Mon, Jun 18, 2018 at 04:58:28PM +0200, Paul Kocialkowski wrote:
> This introduces a dedicated binding for the C1 SRAM region for the A20
> sunxi platform.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> 
> diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> index ddc82cbd7f4d..221fa7b42c18 100644
> --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> @@ -35,6 +35,9 @@ The valid sections compatible for A10 are:
>  The valid sections compatible for A13 are:
>      - allwinner,sun5i-a13-sram-c1
>  
> +The valid sections compatible for A20 are:
> +    - allwinner,sun7i-a20-sram-c1

Same thing here, there's more supported SRAM than that. And maybe we
should just merge everything into the first patch? This looks like the
same commit over and over again.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
  2018-06-18 14:58 ` [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver Paul Kocialkowski
@ 2018-06-20 15:40   ` Rob Herring
  2018-06-20 15:42     ` Paul Kocialkowski
  0 siblings, 1 reply; 31+ messages in thread
From: Rob Herring @ 2018-06-20 15:40 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Mark Rutland, Maxime Ripard, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

On Mon, Jun 18, 2018 at 04:58:39PM +0200, Paul Kocialkowski wrote:
> This adds a device-tree binding document that specifies the properties
> used by the Sunxi-Cedurs VPU driver, as well as examples.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> 
>  create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt

You are missing a '---' line so this is going to end up in the commit 
msg.

Please add acked/reviewed bys when posting new versions.

Rob

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

* Re: [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
  2018-06-20 15:40   ` Rob Herring
@ 2018-06-20 15:42     ` Paul Kocialkowski
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-06-20 15:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Mark Rutland, Maxime Ripard, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

Hi,

On Wed, 2018-06-20 at 09:40 -0600, Rob Herring wrote:
> On Mon, Jun 18, 2018 at 04:58:39PM +0200, Paul Kocialkowski wrote:
> > This adds a device-tree binding document that specifies the properties
> > used by the Sunxi-Cedurs VPU driver, as well as examples.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > 
> >  create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt
> 
> You are missing a '---' line so this is going to end up in the commit 
> msg.

Yes, I can't really explain how this happened. It seems related to
exporting patches with --summary.

> Please add acked/reviewed bys when posting new versions.

Oh, sorry for forgetting that. The bindings are indeed exactly the same
as the ones your reviewed and acked already.

Cheers,

Paul

-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region Paul Kocialkowski
@ 2018-06-20 15:59   ` Rob Herring
  0 siblings, 0 replies; 31+ messages in thread
From: Rob Herring @ 2018-06-20 15:59 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Mark Rutland, Maxime Ripard, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

On Mon, Jun 18, 2018 at 04:58:26PM +0200, Paul Kocialkowski wrote:
> This introduces a dedicated binding for the C1 SRAM region for the A10
> sunxi platform.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 binding for the C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 " Paul Kocialkowski
@ 2018-06-20 16:00   ` Rob Herring
  2018-06-22 14:19   ` Maxime Ripard
  1 sibling, 0 replies; 31+ messages in thread
From: Rob Herring @ 2018-06-20 16:00 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Mark Rutland, Maxime Ripard, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

On Mon, Jun 18, 2018 at 04:58:29PM +0200, Paul Kocialkowski wrote:
> This introduces a dedicated binding for the C1 SRAM region for the A33
> sunxi platform.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 binding for the C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 " Paul Kocialkowski
  2018-06-20 16:00   ` Rob Herring
@ 2018-06-22 14:19   ` Maxime Ripard
  1 sibling, 0 replies; 31+ messages in thread
From: Maxime Ripard @ 2018-06-22 14:19 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

On Mon, Jun 18, 2018 at 04:58:29PM +0200, Paul Kocialkowski wrote:
> This introduces a dedicated binding for the C1 SRAM region for the A33
> sunxi platform.
> 
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> 
> diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> index 221fa7b42c18..d8d1aac0840b 100644
> --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
> @@ -38,6 +38,9 @@ The valid sections compatible for A13 are:
>  The valid sections compatible for A20 are:
>      - allwinner,sun7i-a20-sram-c1
>  
> +The valid sections compatible for A33 are:
> +    - allwinner,sun8i-a33-sram-c1
> +

This is just a detail, but that got introduced with the A23, not the
A33, so it should be the A23 in the compatible instead. It applies for
the SRAM controller compatible too.

Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region
  2018-06-18 14:58 ` [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region Paul Kocialkowski
@ 2018-06-22 14:20   ` Maxime Ripard
  0 siblings, 0 replies; 31+ messages in thread
From: Maxime Ripard @ 2018-06-22 14:20 UTC (permalink / raw)
  To: Paul Kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Chen-Yu Tsai,
	Marco Franchi, Icenowy Zheng, Hans Verkuil, Sylwester Nawrocki,
	Tom Saeger, Smitha T Murthy, Sakari Ailus, Andrzej Hajda,
	Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

On Mon, Jun 18, 2018 at 04:58:36PM +0200, Paul Kocialkowski wrote:
> From: Maxime Ripard <maxime.ripard@bootlin.com>
> 
> This adds a SRAM controller node for the A33, with support for the C1
> SRAM region that is shared between the Video Engine and the CPU.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> 
> diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
> index a21f2ed07a52..97a976b3b1ef 100644
> --- a/arch/arm/boot/dts/sun8i-a33.dtsi
> +++ b/arch/arm/boot/dts/sun8i-a33.dtsi

This should be in the common DTSI between the A23 and A33.

Thnaks!
Maxime

-- 
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [linux-sunxi] [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver
  2018-06-18 14:58 ` [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver Paul Kocialkowski
@ 2018-07-10  1:41   ` Ezequiel Garcia
  2018-07-24 14:28     ` Paul Kocialkowski
  0 siblings, 1 reply; 31+ messages in thread
From: Ezequiel Garcia @ 2018-07-10  1:41 UTC (permalink / raw)
  To: paul.kocialkowski
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Marco Franchi, Icenowy Zheng, Hans Verkuil,
	Sylwester Nawrocki, Tom Saeger, Smitha T Murthy, Sakari Ailus,
	Andrzej Hajda, Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

Hi Paul,

A modest review round. Hope it helps!

I will be reviewing the driver some more later.

On 18 June 2018 at 11:58, Paul Kocialkowski
<paul.kocialkowski@bootlin.com> wrote:
> This introduces the Sunxi-Cedrus VPU driver that supports the VPU found
> in Allwinner SoCs, also known as Video Engine. It is implemented through
> a v4l2 m2m decoder device and a media device (used for media requests).
> So far, it only supports MPEG2 decoding.
>
> Since this VPU is stateless, synchronization with media requests is
> required in order to ensure consistency between frame headers that
> contain metadata about the frame to process and the raw slice data that
> is used to generate the frame.
>
> This driver was made possible thanks to the long-standing effort
> carried out by the linux-sunxi community in the interest of reverse
> engineering, documenting and implementing support for Allwinner VPU.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
>
>  create mode 100644 drivers/media/platform/sunxi/Kconfig
>  create mode 100644 drivers/media/platform/sunxi/Makefile
>  create mode 100644 drivers/media/platform/sunxi/cedrus/Kconfig
>  create mode 100644 drivers/media/platform/sunxi/cedrus/Makefile
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.c
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.h
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.c
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.h
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.c
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.h
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_regs.h
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.c
>  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9c125f705f78..b47dee397475 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -656,6 +656,13 @@ L: linux-crypto@vger.kernel.org
>  S:     Maintained
>  F:     drivers/crypto/sunxi-ss/
>
> +ALLWINNER VPU DRIVER
> +M:     Maxime Ripard <maxime.ripard@bootlin.com>
> +M:     Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> +L:     linux-media@vger.kernel.org
> +S:     Maintained
> +F:     drivers/media/platform/sunxi/cedrus/
> +
>  ALPHA PORT
>  M:     Richard Henderson <rth@twiddle.net>
>  M:     Ivan Kokshaysky <ink@jurassic.park.msu.ru>
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index c7a1cf8a1b01..26da88bcd87b 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -31,6 +31,8 @@ source "drivers/media/platform/davinci/Kconfig"
>
>  source "drivers/media/platform/omap/Kconfig"
>
> +source "drivers/media/platform/sunxi/Kconfig"
> +
>  config VIDEO_SH_VOU
>         tristate "SuperH VOU video output driver"
>         depends on MEDIA_CAMERA_SUPPORT
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index 932515df4477..01ac00adcbc4 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)      += rockchip/rga/
>  obj-y  += omap/
>
>  obj-$(CONFIG_VIDEO_AM437X_VPFE)                += am437x/
> +obj-$(CONFIG_VIDEO_SUNXI)              += sunxi/
>
>  obj-$(CONFIG_VIDEO_XILINX)             += xilinx/
>
> diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
> new file mode 100644
> index 000000000000..a639b0949826
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/Kconfig
> @@ -0,0 +1,15 @@
> +config VIDEO_SUNXI
> +       bool "Allwinner sunXi family Video Devices"
> +       depends on ARCH_SUNXI

You could add || COMPILE_TEST, to get covered
by build tests.

> +       help
> +         If you have an Allwinner SoC based on the sunXi family, say Y.
> +
> +         Note that this option doesn't include new drivers in the
> +         kernel: saying N will just cause Kconfig to skip all the
> +         questions about Allwinner media devices.
> +
> +if VIDEO_SUNXI
> +
> +source "drivers/media/platform/sunxi/cedrus/Kconfig"
> +
> +endif
> diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
> new file mode 100644
> index 000000000000..cee2846c3ecf
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_VIDEO_SUNXI_CEDRUS)       += cedrus/
> diff --git a/drivers/media/platform/sunxi/cedrus/Kconfig b/drivers/media/platform/sunxi/cedrus/Kconfig
> new file mode 100644
> index 000000000000..870a4b64a45c
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/Kconfig
> @@ -0,0 +1,13 @@
> +config VIDEO_SUNXI_CEDRUS
> +       tristate "Allwinner Cedrus VPU driver"
> +       depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
> +       depends on HAS_DMA
> +       select VIDEOBUF2_DMA_CONTIG
> +       select MEDIA_REQUEST_API
> +       select V4L2_MEM2MEM_DEV
> +       help
> +         Support for the VPU found in Allwinner SoCs, also known as the Cedar
> +         video engine.
> +
> +         To compile this driver as a module, choose M here: the module
> +         will be called cedrus.
> diff --git a/drivers/media/platform/sunxi/cedrus/Makefile b/drivers/media/platform/sunxi/cedrus/Makefile
> new file mode 100644
> index 000000000000..632a0be90ed7
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/Makefile
> @@ -0,0 +1,3 @@
> +obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus.o
> +
> +cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.c b/drivers/media/platform/sunxi/cedrus/cedrus.c
> new file mode 100644
> index 000000000000..1718db1b549b
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus.c
> @@ -0,0 +1,327 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_video.h"
> +#include "cedrus_dec.h"
> +#include "cedrus_hw.h"
> +
> +static int cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> +       struct cedrus_ctx *ctx =
> +               container_of(ctrl->handler, struct cedrus_ctx, hdl);
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       switch (ctrl->id) {
> +       case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER:
> +               /* This is kept in memory and used directly. */
> +               break;
> +       default:
> +               v4l2_err(&dev->v4l2_dev, "Invalid control to set\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
> +       .s_ctrl = cedrus_s_ctrl,
> +};
> +
> +static const struct cedrus_control controls[] = {
> +       [CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER] = {
> +               .id             = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER,
> +               .elem_size      = sizeof(struct v4l2_ctrl_mpeg2_slice_header),
> +       },
> +};
> +
> +static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
> +{
> +       struct v4l2_ctrl_handler *hdl = &ctx->hdl;
> +       unsigned int num_ctrls = ARRAY_SIZE(controls);
> +       unsigned int i;
> +
> +       v4l2_ctrl_handler_init(hdl, num_ctrls);
> +       if (hdl->error) {
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Failed to initialize control handler\n");
> +               return hdl->error;
> +       }
> +
> +       for (i = 0; i < num_ctrls; i++) {
> +               struct v4l2_ctrl_config cfg = { 0 };
> +
> +               cfg.ops = &cedrus_ctrl_ops;
> +               cfg.elem_size = controls[i].elem_size;
> +               cfg.id = controls[i].id;
> +
> +               ctx->ctrls[i] = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
> +               if (hdl->error) {
> +                       v4l2_err(&dev->v4l2_dev,
> +                                "Failed to create new custom control\n");
> +
> +                       v4l2_ctrl_handler_free(hdl);
> +                       return hdl->error;
> +               }
> +       }
> +
> +       ctx->fh.ctrl_handler = hdl;
> +       v4l2_ctrl_handler_setup(hdl);
> +
> +       return 0;
> +}
> +
> +static int cedrus_open(struct file *file)
> +{
> +       struct cedrus_dev *dev = video_drvdata(file);
> +       struct cedrus_ctx *ctx = NULL;
> +       int ret;
> +
> +       if (mutex_lock_interruptible(&dev->dev_mutex))
> +               return -ERESTARTSYS;
> +
> +       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +       if (!ctx) {
> +               mutex_unlock(&dev->dev_mutex);
> +               return -ENOMEM;
> +       }
> +
> +       INIT_WORK(&ctx->run_work, cedrus_device_work);
> +

This cedrus_device_work looks odd, but I think it's already
cleaned up in your WIP github branch.

> +       INIT_LIST_HEAD(&ctx->src_list);
> +       INIT_LIST_HEAD(&ctx->dst_list);
> +
> +       v4l2_fh_init(&ctx->fh, video_devdata(file));
> +       file->private_data = &ctx->fh;
> +       ctx->dev = dev;
> +
> +       ret = cedrus_init_ctrls(dev, ctx);
> +       if (ret)
> +               goto err_free;
> +
> +       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
> +                                           &cedrus_queue_init);
> +       if (IS_ERR(ctx->fh.m2m_ctx)) {
> +               ret = PTR_ERR(ctx->fh.m2m_ctx);
> +               goto err_ctrls;
> +       }
> +
> +       v4l2_fh_add(&ctx->fh);
> +
> +       mutex_unlock(&dev->dev_mutex);
> +
> +       return 0;
> +
> +err_ctrls:
> +       v4l2_ctrl_handler_free(&ctx->hdl);
> +err_free:
> +       kfree(ctx);
> +       mutex_unlock(&dev->dev_mutex);
> +
> +       return ret;
> +}
> +
> +static int cedrus_release(struct file *file)
> +{
> +       struct cedrus_dev *dev = video_drvdata(file);
> +       struct cedrus_ctx *ctx = container_of(file->private_data,
> +                                             struct cedrus_ctx, fh);
> +
> +       mutex_lock(&dev->dev_mutex);
> +
> +       v4l2_fh_del(&ctx->fh);
> +       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> +
> +       v4l2_ctrl_handler_free(&ctx->hdl);
> +
> +       v4l2_fh_exit(&ctx->fh);
> +       v4l2_fh_exit(&ctx->fh);
> +
> +       kfree(ctx);
> +
> +       mutex_unlock(&dev->dev_mutex);
> +
> +       return 0;
> +}
> +
> +static const struct v4l2_file_operations cedrus_fops = {
> +       .owner          = THIS_MODULE,
> +       .open           = cedrus_open,
> +       .release        = cedrus_release,
> +       .poll           = v4l2_m2m_fop_poll,
> +       .unlocked_ioctl = video_ioctl2,
> +       .mmap           = v4l2_m2m_fop_mmap,
> +};
> +
> +static const struct video_device cedrus_video_device = {
> +       .name           = CEDRUS_NAME,
> +       .vfl_dir        = VFL_DIR_M2M,
> +       .fops           = &cedrus_fops,
> +       .ioctl_ops      = &cedrus_ioctl_ops,
> +       .minor          = -1,
> +       .release        = video_device_release_empty,
> +};
> +
> +static const struct v4l2_m2m_ops cedrus_m2m_ops = {
> +       .device_run     = cedrus_device_run,
> +       .job_abort      = cedrus_job_abort,
> +};
> +
> +static const struct media_device_ops cedrus_m2m_media_ops = {
> +       .req_validate = vb2_request_validate,
> +       .req_queue = vb2_m2m_request_queue,
> +};
> +
> +static int cedrus_probe(struct platform_device *pdev)
> +{
> +       struct cedrus_dev *dev;
> +       struct video_device *vfd;
> +       int ret;
> +
> +       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
> +       if (!dev)
> +               return -ENOMEM;
> +
> +       dev->dev = &pdev->dev;
> +       dev->pdev = pdev;
> +
> +       ret = cedrus_hw_probe(dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Failed to probe hardware\n");
> +               return ret;
> +       }
> +
> +       mutex_init(&dev->dev_mutex);
> +       spin_lock_init(&dev->irq_lock);
> +
> +       dev->vfd = cedrus_video_device;
> +       vfd = &dev->vfd;
> +       vfd->lock = &dev->dev_mutex;
> +       vfd->v4l2_dev = &dev->v4l2_dev;
> +
> +       dev->mdev.dev = &pdev->dev;
> +       strlcpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
> +
> +       media_device_init(&dev->mdev);
> +       dev->mdev.ops = &cedrus_m2m_media_ops;
> +       dev->v4l2_dev.mdev = &dev->mdev;
> +       dev->pad[0].flags = MEDIA_PAD_FL_SINK;
> +       dev->pad[1].flags = MEDIA_PAD_FL_SOURCE;
> +
> +       ret = media_entity_pads_init(&vfd->entity, 2, dev->pad);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Failed to initialize media entity pads\n");
> +               return ret;
> +       }
> +
> +       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Failed to register V4L2 device\n");
> +               return ret;
> +       }
> +
> +       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
> +               goto err_v4l2;
> +       }
> +
> +       video_set_drvdata(vfd, dev);
> +       snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
> +
> +       v4l2_info(&dev->v4l2_dev,
> +                 "Device registered as /dev/video%d\n", vfd->num);
> +
> +       platform_set_drvdata(pdev, dev);
> +
> +       dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
> +       if (IS_ERR(dev->m2m_dev)) {
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Failed to initialize V4L2 M2M device\n");
> +               ret = PTR_ERR(dev->m2m_dev);
> +               goto err_video;
> +       }
> +
> +       ret = media_device_register(&dev->mdev);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
> +               goto err_m2m;
> +       }
> +
> +       return 0;
> +
> +err_m2m:
> +       v4l2_m2m_release(dev->m2m_dev);
> +err_video:
> +       video_unregister_device(&dev->vfd);
> +err_v4l2:
> +       v4l2_device_unregister(&dev->v4l2_dev);
> +
> +       return ret;
> +}
> +
> +static int cedrus_remove(struct platform_device *pdev)
> +{
> +       struct cedrus_dev *dev = platform_get_drvdata(pdev);
> +
> +       v4l2_info(&dev->v4l2_dev, "Removing " CEDRUS_NAME);
> +
> +       if (media_devnode_is_registered(dev->mdev.devnode)) {
> +               media_device_unregister(&dev->mdev);
> +               media_device_cleanup(&dev->mdev);
> +       }
> +
> +       v4l2_m2m_release(dev->m2m_dev);
> +       video_unregister_device(&dev->vfd);
> +       v4l2_device_unregister(&dev->v4l2_dev);
> +       cedrus_hw_remove(dev);
> +
> +       return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id of_cedrus_match[] = {
> +       { .compatible = "allwinner,sun4i-a10-video-engine" },
> +       { .compatible = "allwinner,sun5i-a13-video-engine" },
> +       { .compatible = "allwinner,sun7i-a20-video-engine" },
> +       { .compatible = "allwinner,sun8i-a33-video-engine" },
> +       { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, of_cedrus_match);
> +#endif
> +
> +static struct platform_driver cedrus_driver = {
> +       .probe          = cedrus_probe,
> +       .remove         = cedrus_remove,
> +       .driver         = {
> +               .name   = CEDRUS_NAME,
> +               .owner = THIS_MODULE,
> +               .of_match_table = of_match_ptr(of_cedrus_match),
> +       },
> +};
> +module_platform_driver(cedrus_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
> +MODULE_DESCRIPTION("Sunxi-Cedrus VPU driver");
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.h b/drivers/media/platform/sunxi/cedrus/cedrus.h
> new file mode 100644
> index 000000000000..106bda44a3c3
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus.h
> @@ -0,0 +1,117 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_H_
> +#define _CEDRUS_H_
> +
> +#include <linux/platform_device.h>
> +
> +#include <media/videobuf2-v4l2.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ctrls.h>
> +
> +#define CEDRUS_NAME    "cedrus"
> +
> +enum cedrus_control_id {
> +       CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER = 0,
> +       CEDRUS_CTRL_MAX,
> +};
> +
> +struct cedrus_control {
> +       u32     id;
> +       u32     elem_size;
> +};
> +
> +struct cedrus_fmt {
> +       u32             fourcc;
> +       int             depth;
> +       u32             types;
> +       unsigned int    num_planes;
> +};
> +
> +struct cedrus_mpeg2_run {
> +       const struct v4l2_ctrl_mpeg2_slice_header       *hdr;
> +};
> +
> +struct cedrus_run {
> +       struct vb2_v4l2_buffer  *src;
> +       struct vb2_v4l2_buffer  *dst;
> +
> +       union {
> +               struct cedrus_mpeg2_run mpeg2;
> +       };
> +};
> +
> +struct cedrus_ctx {
> +       struct v4l2_fh                  fh;
> +       struct cedrus_dev               *dev;
> +
> +       struct cedrus_fmt               *vpu_src_fmt;
> +       struct v4l2_pix_format_mplane   src_fmt;
> +       struct cedrus_fmt               *vpu_dst_fmt;
> +       struct v4l2_pix_format_mplane   dst_fmt;
> +
> +       struct v4l2_ctrl_handler        hdl;
> +       struct v4l2_ctrl                *ctrls[CEDRUS_CTRL_MAX];
> +
> +       struct vb2_buffer               *dst_bufs[VIDEO_MAX_FRAME];
> +
> +       int                             job_abort;
> +
> +       struct work_struct              try_schedule_work;
> +       struct work_struct              run_work;
> +       struct list_head                src_list;
> +       struct list_head                dst_list;
> +};
> +
> +struct cedrus_buffer {
> +       struct vb2_v4l2_buffer          vb;
> +       enum vb2_buffer_state           state;
> +       struct list_head                list;
> +};
> +
> +struct cedrus_dev {
> +       struct v4l2_device      v4l2_dev;
> +       struct video_device     vfd;
> +       struct media_device     mdev;
> +       struct media_pad        pad[2];
> +       struct platform_device  *pdev;
> +       struct device           *dev;
> +       struct v4l2_m2m_dev     *m2m_dev;
> +
> +       /* Device file mutex */
> +       struct mutex            dev_mutex;
> +       /* Interrupt spinlock */
> +       spinlock_t              irq_lock;
> +
> +       void __iomem            *base;
> +
> +       struct clk              *mod_clk;
> +       struct clk              *ahb_clk;
> +       struct clk              *ram_clk;
> +
> +       struct reset_control    *rstc;
> +};
> +
> +static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
> +{
> +       writel(val, dev->base + reg);
> +}
> +
> +static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
> +{
> +       return readl(dev->base + reg);
> +}
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.c b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
> new file mode 100644
> index 000000000000..bd9727ae9f63
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
> @@ -0,0 +1,170 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#include <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_mpeg2.h"
> +#include "cedrus_dec.h"
> +#include "cedrus_hw.h"
> +
> +static inline void *get_ctrl_ptr(struct cedrus_ctx *ctx,
> +                                enum cedrus_control_id id)
> +{
> +       struct v4l2_ctrl *ctrl = ctx->ctrls[id];
> +
> +       return ctrl->p_cur.p;
> +}
> +
> +void cedrus_device_work(struct work_struct *work)
> +{
> +       struct cedrus_ctx *ctx = container_of(work,
> +                                             struct cedrus_ctx, run_work);
> +       struct cedrus_dev *dev = ctx->dev;
> +       struct cedrus_buffer *buffer_entry;
> +       struct vb2_v4l2_buffer *src_buf, *dst_buf;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> +       if (list_empty(&ctx->src_list) || list_empty(&ctx->dst_list)) {
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Empty source and/or destination buffer lists\n");
> +               spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +               return;
> +       }
> +
> +       buffer_entry = list_last_entry(&ctx->src_list, struct cedrus_buffer, list);
> +       list_del(ctx->src_list.prev);
> +
> +       src_buf = &buffer_entry->vb;
> +       v4l2_m2m_buf_done(src_buf, buffer_entry->state);
> +
> +       buffer_entry = list_last_entry(&ctx->dst_list, struct cedrus_buffer, list);
> +       list_del(ctx->dst_list.prev);
> +
> +       dst_buf = &buffer_entry->vb;
> +       v4l2_m2m_buf_done(dst_buf, buffer_entry->state);
> +
> +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> +       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +void cedrus_device_run(void *priv)
> +{
> +       struct cedrus_ctx *ctx = priv;
> +       struct cedrus_dev *dev = ctx->dev;
> +       struct cedrus_run run = { 0 };
> +       struct media_request *src_req;
> +       unsigned long flags;
> +
> +       run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> +       if (!run.src) {
> +               v4l2_err(&dev->v4l2_dev, "No source buffer to prepare\n");

I believe it's a mem2mem core nasty bug if you can't get a source or destination
buffer in .device_run. Perhaps catch it with WARN or BUG?
Or just let the kernel burn, like other drivers do :-)

> +               return;
> +       }
> +
> +       run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> +       if (!run.dst) {
> +               v4l2_err(&dev->v4l2_dev, "No destination buffer to prepare\n");
> +               return;
> +       }
> +
> +       /* Apply request(s) controls if needed. */
> +       src_req = run.src->vb2_buf.req_obj.req;
> +
> +       if (src_req)
> +               v4l2_ctrl_request_setup(src_req, &ctx->hdl);
> +
> +       ctx->job_abort = 0;
> +
> +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> +       switch (ctx->vpu_src_fmt->fourcc) {
> +       case V4L2_PIX_FMT_MPEG2_SLICE:
> +               if (!ctx->ctrls[CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER]) {
> +                       v4l2_err(&dev->v4l2_dev,
> +                                "Invalid MPEG2 frame header control\n");
> +                       ctx->job_abort = 1;
> +                       goto unlock_complete;
> +               }
> +
> +               run.mpeg2.hdr = get_ctrl_ptr(ctx, CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER);
> +               cedrus_mpeg2_setup(ctx, &run);
> +               break;
> +
> +       default:
> +               ctx->job_abort = 1;
> +       }
> +
> +unlock_complete:
> +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> +       /* Complete request(s) controls if needed. */
> +
> +       if (src_req)
> +               v4l2_ctrl_request_complete(src_req, &ctx->hdl);
> +
> +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> +       if (!ctx->job_abort) {
> +               if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG2_SLICE)
> +                       cedrus_mpeg2_trigger(ctx);
> +       } else {
> +               v4l2_m2m_buf_done(run.src, VB2_BUF_STATE_ERROR);
> +               v4l2_m2m_buf_done(run.dst, VB2_BUF_STATE_ERROR);
> +       }
> +
> +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> +       if (ctx->job_abort)
> +               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +void cedrus_job_abort(void *priv)
> +{
> +       struct cedrus_ctx *ctx = priv;
> +       struct vb2_v4l2_buffer *src_buf, *dst_buf;
> +       unsigned long flags;
> +
> +       ctx->job_abort = 1;
> +

If you can't actually cancel the DMA operation,
then perhaps you want to simply not define .job_abort,
and wait for the running operation (if any) to finish.

See https://www.mail-archive.com/linux-media@vger.kernel.org/msg132881.html

It should also cleanup your impementation. The whole ctx->job_abort
dance looks kinda cumbersome.

> +       /*
> +        * V4L2 M2M and request API cleanup is done here while hardware state
> +        * cleanup is done in the interrupt context. Doing all the cleanup in
> +        * the interrupt context is a bit risky, since the job_abort call might
> +        * originate from the release hook, where interrupts have already been
> +        * disabled.
> +        */
> +
> +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> +       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +       if (src_buf)
> +               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
> +
> +       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +       if (dst_buf)
> +               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
> +
> +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> +       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.h b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
> new file mode 100644
> index 000000000000..b38812136504
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
> @@ -0,0 +1,27 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_DEC_H_
> +#define _CEDRUS_DEC_H_
> +
> +extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
> +
> +void cedrus_device_work(struct work_struct *work);
> +void cedrus_device_run(void *priv);
> +void cedrus_job_abort(void *priv);
> +
> +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> +                     struct vb2_queue *dst_vq);
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.c b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
> new file mode 100644
> index 000000000000..9ee1380f4e30
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
> @@ -0,0 +1,262 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/soc/sunxi/sunxi_sram.h>
> +
> +#include <media/videobuf2-core.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_hw.h"
> +#include "cedrus_regs.h"
> +
> +int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine)
> +{
> +       u32 reg = 0;
> +
> +       /*
> +        * FIXME: This is only valid on 32-bits DDR's, we should test
> +        * it on the A13/A33.
> +        */
> +       reg |= VE_CTRL_REC_WR_MODE_2MB;
> +
> +       reg |= VE_CTRL_CACHE_BUS_BW_128;
> +
> +       switch (engine) {
> +       case CEDRUS_ENGINE_MPEG:
> +               reg |= VE_CTRL_DEC_MODE_MPEG;
> +               break;
> +
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       cedrus_write(dev, VE_CTRL, reg);
> +
> +       return 0;
> +}
> +
> +void cedrus_engine_disable(struct cedrus_dev *dev)
> +{
> +       cedrus_write(dev, VE_CTRL, VE_CTRL_DEC_MODE_DISABLED);
> +}
> +
> +static irqreturn_t cedrus_ve_irq(int irq, void *data)
> +{
> +       struct cedrus_dev *dev = data;
> +       struct cedrus_ctx *ctx;
> +       struct cedrus_buffer *src_buffer, *dst_buffer;
> +       struct vb2_v4l2_buffer *src_vb, *dst_vb;
> +       unsigned long flags;
> +       unsigned int value, status;
> +
> +       spin_lock_irqsave(&dev->irq_lock, flags);
> +
> +       /* Disable MPEG interrupts and stop the MPEG engine. */
> +       value = cedrus_read(dev, VE_MPEG_CTRL);
> +       cedrus_write(dev, VE_MPEG_CTRL, value & (~0xf));
> +
> +       status = cedrus_read(dev, VE_MPEG_STATUS);
> +       cedrus_write(dev, VE_MPEG_STATUS, 0x0000c00f);
> +       cedrus_engine_disable(dev);
> +
> +       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
> +       if (!ctx) {
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Instance released before the end of transaction\n");
> +               spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> +               return IRQ_HANDLED;
> +       }
> +
> +       src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +       dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +
> +       if (!src_vb || !dst_vb) {
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Missing source and/or destination buffers\n");
> +               spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> +               return IRQ_HANDLED;
> +       }
> +
> +       src_buffer = container_of(src_vb, struct cedrus_buffer, vb);
> +       dst_buffer = container_of(dst_vb, struct cedrus_buffer, vb);
> +
> +       /* First bit of MPEG_STATUS indicates success. */
> +       if (ctx->job_abort || !(status & 0x01))
> +               src_buffer->state = dst_buffer->state = VB2_BUF_STATE_ERROR;
> +       else
> +               src_buffer->state = dst_buffer->state = VB2_BUF_STATE_DONE;
> +
> +       list_add_tail(&src_buffer->list, &ctx->src_list);
> +       list_add_tail(&dst_buffer->list, &ctx->dst_list);
> +
> +       spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> +       schedule_work(&ctx->run_work);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +int cedrus_hw_probe(struct cedrus_dev *dev)
> +{
> +       struct resource *res;
> +       int irq_dec;
> +       int ret;
> +
> +       irq_dec = platform_get_irq(dev->pdev, 0);
> +       if (irq_dec <= 0) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n");
> +               return -ENXIO;
> +       }
> +       ret = devm_request_irq(dev->dev, irq_dec, cedrus_ve_irq, 0,
> +                              dev_name(dev->dev), dev);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
> +               return -ENXIO;
> +       }
> +
> +       /*
> +        * The VPU is only able to handle bus addresses so we have to subtract
> +        * the RAM offset to the physcal addresses.
> +        */
> +       dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
> +
> +       ret = of_reserved_mem_device_init(dev->dev);
> +       if (ret && ret != -ENODEV) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to reserved memory\n");
> +               return -ENODEV;
> +       }
> +
> +       ret = sunxi_sram_claim(dev->dev);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n");
> +               goto err_mem;
> +       }
> +
> +       dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
> +       if (IS_ERR(dev->ahb_clk)) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n");
> +
> +               ret = PTR_ERR(dev->ahb_clk);
> +               goto err_sram;
> +       }
> +
> +       dev->mod_clk = devm_clk_get(dev->dev, "mod");
> +       if (IS_ERR(dev->mod_clk)) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n");
> +
> +               ret = PTR_ERR(dev->mod_clk);
> +               goto err_sram;
> +       }
> +
> +       dev->ram_clk = devm_clk_get(dev->dev, "ram");
> +       if (IS_ERR(dev->ram_clk)) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n");
> +
> +               ret = PTR_ERR(dev->ram_clk);
> +               goto err_sram;
> +       }
> +
> +       dev->rstc = devm_reset_control_get(dev->dev, NULL);
> +       if (IS_ERR(dev->rstc)) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n");
> +
> +               ret = PTR_ERR(dev->rstc);
> +               goto err_sram;
> +       }
> +
> +       res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
> +       dev->base = devm_ioremap_resource(dev->dev, res);
> +       if (!dev->base) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to map registers\n");
> +
> +               ret = -EFAULT;
> +               goto err_sram;
> +       }
> +
> +       ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n");
> +               goto err_sram;
> +       }
> +
> +       ret = clk_prepare_enable(dev->ahb_clk);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n");
> +
> +               ret = -EFAULT;
> +               goto err_sram;
> +       }
> +
> +       ret = clk_prepare_enable(dev->mod_clk);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n");
> +
> +               ret = -EFAULT;
> +               goto err_ahb_clk;
> +       }
> +
> +       ret = clk_prepare_enable(dev->ram_clk);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n");
> +
> +               ret = -EFAULT;
> +               goto err_mod_clk;
> +       }
> +

This might look cleaner with the clock bulk API.

Also, have you considered clock enable/disable in open/release,
or start/stop? (possibly, via pm runtime).

> +       ret = reset_control_reset(dev->rstc);
> +       if (ret) {
> +               v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n");
> +
> +               ret = -EFAULT;
> +               goto err_ram_clk;
> +       }
> +
> +       return 0;
> +
> +err_ram_clk:
> +       clk_disable_unprepare(dev->ram_clk);
> +err_mod_clk:
> +       clk_disable_unprepare(dev->mod_clk);
> +err_ahb_clk:
> +       clk_disable_unprepare(dev->ahb_clk);
> +err_sram:
> +       sunxi_sram_release(dev->dev);
> +err_mem:
> +       of_reserved_mem_device_release(dev->dev);
> +
> +       return ret;
> +}
> +
> +void cedrus_hw_remove(struct cedrus_dev *dev)
> +{
> +       reset_control_assert(dev->rstc);
> +
> +       clk_disable_unprepare(dev->ram_clk);
> +       clk_disable_unprepare(dev->mod_clk);
> +       clk_disable_unprepare(dev->ahb_clk);
> +
> +       sunxi_sram_release(dev->dev);
> +
> +       of_reserved_mem_device_release(dev->dev);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.h b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
> new file mode 100644
> index 000000000000..ead4f5089881
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_HW_H_
> +#define _CEDRUS_HW_H_
> +
> +#define CEDRUS_CLOCK_RATE_DEFAULT      320000000
> +

This define is only used in cedrus_hw.c. Perhaps shouldn't belong
in a header.

> +enum cedrus_engine {
> +       CEDRUS_ENGINE_MPEG,
> +};
> +
> +int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine);
> +void cedrus_engine_disable(struct cedrus_dev *dev);
> +
> +int cedrus_hw_probe(struct cedrus_dev *dev);
> +void cedrus_hw_remove(struct cedrus_dev *dev);
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
> new file mode 100644
> index 000000000000..0d6dcaec73b3
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
> @@ -0,0 +1,146 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#include <media/videobuf2-dma-contig.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_hw.h"
> +#include "cedrus_regs.h"
> +
> +static const u8 mpeg_default_intra_quant[64] = {
> +       8, 16, 16, 19, 16, 19, 22, 22,
> +       22, 22, 22, 22, 26, 24, 26, 27,
> +       27, 27, 26, 26, 26, 26, 27, 27,
> +       27, 29, 29, 29, 34, 34, 34, 29,
> +       29, 29, 27, 27, 29, 29, 32, 32,
> +       34, 34, 37, 38, 37, 35, 35, 34,
> +       35, 38, 38, 40, 40, 40, 48, 48,
> +       46, 46, 56, 56, 58, 69, 69, 83
> +};
> +
> +#define m_iq(i) (((64 + i) << 8) | mpeg_default_intra_quant[i])
> +
> +static const u8 mpeg_default_non_intra_quant[64] = {
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16,
> +       16, 16, 16, 16, 16, 16, 16, 16
> +};
> +
> +#define m_niq(i) ((i << 8) | mpeg_default_non_intra_quant[i])
> +
> +void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
> +{
> +       struct cedrus_dev *dev = ctx->dev;
> +       const struct v4l2_ctrl_mpeg2_slice_header *frame_hdr = run->mpeg2.hdr;
> +
> +       u16 width = DIV_ROUND_UP(frame_hdr->width, 16);
> +       u16 height = DIV_ROUND_UP(frame_hdr->height, 16);
> +
> +       u32 pic_header = 0;
> +       u32 vld_len = frame_hdr->slice_len - frame_hdr->slice_pos;
> +       int i;
> +
> +       struct vb2_buffer *fwd_vb2_buf, *bwd_vb2_buf;
> +       dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
> +       dma_addr_t fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
> +
> +       fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_ref_index];
> +       if (fwd_vb2_buf) {
> +               fwd_luma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 0);
> +               fwd_chroma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 1);
> +       }
> +
> +       bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_ref_index];
> +       if (bwd_vb2_buf) {
> +               bwd_luma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 0);
> +               bwd_chroma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 1);
> +       }
> +
> +       /* Activate MPEG engine. */
> +       cedrus_engine_enable(dev, CEDRUS_ENGINE_MPEG);
> +
> +       /* Set quantization matrices. */
> +       for (i = 0; i < 64; i++) {
> +               cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_iq(i));
> +               cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_niq(i));
> +       }
> +
> +       /* Set frame dimensions. */
> +       cedrus_write(dev, VE_MPEG_SIZE, width << 8 | height);
> +       cedrus_write(dev, VE_MPEG_FRAME_SIZE, width << 20 | height << 4);
> +
> +       /* Set MPEG picture header. */
> +       pic_header |= (frame_hdr->picture_coding_type & 0xf) << 28;
> +       pic_header |= (frame_hdr->f_code[0][0] & 0xf) << 24;
> +       pic_header |= (frame_hdr->f_code[0][1] & 0xf) << 20;
> +       pic_header |= (frame_hdr->f_code[1][0] & 0xf) << 16;
> +       pic_header |= (frame_hdr->f_code[1][1] & 0xf) << 12;
> +       pic_header |= (frame_hdr->intra_dc_precision & 0x3) << 10;
> +       pic_header |= (frame_hdr->picture_structure & 0x3) << 8;
> +       pic_header |= (frame_hdr->top_field_first & 0x1) << 7;
> +       pic_header |= (frame_hdr->frame_pred_frame_dct & 0x1) << 6;
> +       pic_header |= (frame_hdr->concealment_motion_vectors & 0x1) << 5;
> +       pic_header |= (frame_hdr->q_scale_type & 0x1) << 4;
> +       pic_header |= (frame_hdr->intra_vlc_format & 0x1) << 3;
> +       pic_header |= (frame_hdr->alternate_scan & 0x1) << 2;
> +       cedrus_write(dev, VE_MPEG_PIC_HDR, pic_header);
> +
> +       /* Enable interrupt and an unknown control flag. */
> +       cedrus_write(dev, VE_MPEG_CTRL, VE_MPEG_CTRL_MPEG2);
> +
> +       /* Macroblock address. */
> +       cedrus_write(dev, VE_MPEG_MBA, 0);
> +
> +       /* Clear previous errors. */
> +       cedrus_write(dev, VE_MPEG_ERROR, 0);
> +
> +       /* Clear correct macroblocks register. */
> +       cedrus_write(dev, VE_MPEG_CTR_MB, 0);
> +
> +       /* Forward and backward prediction reference buffers. */
> +       cedrus_write(dev, VE_MPEG_FWD_LUMA, fwd_luma);
> +       cedrus_write(dev, VE_MPEG_FWD_CHROMA, fwd_chroma);
> +       cedrus_write(dev, VE_MPEG_BACK_LUMA, bwd_luma);
> +       cedrus_write(dev, VE_MPEG_BACK_CHROMA, bwd_chroma);
> +
> +       /* Destination luma and chroma buffers. */
> +       dst_luma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0);
> +       dst_chroma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1);
> +       cedrus_write(dev, VE_MPEG_REC_LUMA, dst_luma_addr);
> +       cedrus_write(dev, VE_MPEG_REC_CHROMA, dst_chroma_addr);
> +       cedrus_write(dev, VE_MPEG_ROT_LUMA, dst_luma_addr);
> +       cedrus_write(dev, VE_MPEG_ROT_CHROMA, dst_chroma_addr);
> +
> +       /* Source offset and length in bits. */
> +       cedrus_write(dev, VE_MPEG_VLD_OFFSET, frame_hdr->slice_pos);
> +       cedrus_write(dev, VE_MPEG_VLD_LEN, vld_len);
> +
> +       /* Source beginning and end addresses. */
> +       src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
> +       cedrus_write(dev, VE_MPEG_VLD_ADDR, VE_MPEG_VLD_ADDR_VAL(src_buf_addr));
> +       cedrus_write(dev, VE_MPEG_VLD_END, src_buf_addr + VBV_SIZE - 1);
> +}
> +
> +void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
> +{
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       /* Trigger MPEG engine. */
> +       cedrus_write(dev, VE_MPEG_TRIGGER, VE_TRIG_MPEG2);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
> new file mode 100644
> index 000000000000..fd864fab6986
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
> @@ -0,0 +1,24 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_MPEG2_H_
> +#define _CEDRUS_MPEG2_H_
> +
> +struct cedrus_ctx;
> +struct cedrus_run;
> +
> +void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run);
> +void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx);
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_regs.h b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
> new file mode 100644
> index 000000000000..442befcdb6ea
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
> @@ -0,0 +1,167 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_REGS_H_
> +#define _CEDRUS_REGS_H_
> +
> +/*
> + * For more information, consult http://linux-sunxi.org/VE_Register_guide
> + */
> +
> +/* VE_MPEG_CTRL:
> + * The bit 3 (0x8) is used to enable IRQs
> + * The other bits are unknown but needed
> + */
> +#define VE_MPEG_CTRL_MPEG2     0x800001b8
> +#define VE_MPEG_CTRL_MPEG4     (0x80084118 | BIT(7))
> +#define VE_MPEG_CTRL_MPEG4_P   (VE_MPEG_CTRL_MPEG4 | BIT(12))
> +
> +/* VE_MPEG_VLD_ADDR:
> + * The bits 27 to 4 are used for the address
> + * The bits 31 to 28 (0x7) are used to select the MPEG or JPEG engine
> + */
> +#define VE_MPEG_VLD_ADDR_VAL(x)        ((x & 0x0ffffff0) | (x >> 28) | (0x7 << 28))
> +
> +/* VE_MPEG_TRIGGER:
> + * The first three bits are used to trigger the engine
> + * The bits 24 to 26 are used to select the input format (1 for MPEG1, 2 for
> + *                           MPEG2, 4 for MPEG4)
> + * The bit 21 (0x8) is used to disable bitstream error handling
> + *
> + * In MPEG4 the w*h value is somehow used for an offset, unknown but needed
> + */
> +#define VE_TRIG_MPEG1          0x8100000f
> +#define VE_TRIG_MPEG2          0x8200000f
> +#define VE_TRIG_MPEG4(w, h)    (0x8400000d | ((w * h) << 8))
> +
> +/* VE_MPEG_SDROT_CTRL:
> + * The bit 8 at zero is used to disable x downscaling
> + * The bit 10 at 0 is used to disable y downscaling
> + * The other bits are unknown but needed
> + */
> +#define VE_NO_SDROT_CTRL       0x40620000
> +
> +/* Decent size fo video buffering verifier */
> +#define VBV_SIZE               (1024 * 1024)
> +
> +/* Registers addresses */
> +#define VE_CTRL                                0x000
> +/*
> + * The datasheet states that this should be set to 2MB on a 32bits
> + * DDR-3.
> + */
> +#define VE_CTRL_REC_WR_MODE_2MB                        (1 << 20)
> +#define VE_CTRL_REC_WR_MODE_1MB                        (0 << 20)
> +
> +#define VE_CTRL_CACHE_BUS_BW_128               (3 << 16)
> +#define VE_CTRL_CACHE_BUS_BW_256               (2 << 16)
> +
> +#define VE_CTRL_DEC_MODE_DISABLED              (7 << 0)
> +#define VE_CTRL_DEC_MODE_H265                  (4 << 0)
> +#define VE_CTRL_DEC_MODE_H264                  (1 << 0)
> +#define VE_CTRL_DEC_MODE_MPEG                  (0 << 0)
> +
> +#define VE_VERSION                     0x0f0
> +
> +#define VE_MPEG_PIC_HDR                        0x100
> +#define VE_MPEG_VOP_HDR                        0x104
> +#define VE_MPEG_SIZE                   0x108
> +#define VE_MPEG_FRAME_SIZE             0x10c
> +#define VE_MPEG_MBA                    0x110
> +#define VE_MPEG_CTRL                   0x114
> +#define VE_MPEG_TRIGGER                        0x118
> +#define VE_MPEG_STATUS                 0x11c
> +#define VE_MPEG_TRBTRD_FIELD           0x120
> +#define VE_MPEG_TRBTRD_FRAME           0x124
> +#define VE_MPEG_VLD_ADDR               0x128
> +#define VE_MPEG_VLD_OFFSET             0x12c
> +#define VE_MPEG_VLD_LEN                        0x130
> +#define VE_MPEG_VLD_END                        0x134
> +#define VE_MPEG_MBH_ADDR               0x138
> +#define VE_MPEG_DCAC_ADDR              0x13c
> +#define VE_MPEG_NCF_ADDR               0x144
> +#define VE_MPEG_REC_LUMA               0x148
> +#define VE_MPEG_REC_CHROMA             0x14c
> +#define VE_MPEG_FWD_LUMA               0x150
> +#define VE_MPEG_FWD_CHROMA             0x154
> +#define VE_MPEG_BACK_LUMA              0x158
> +#define VE_MPEG_BACK_CHROMA            0x15c
> +#define VE_MPEG_IQ_MIN_INPUT           0x180
> +#define VE_MPEG_QP_INPUT               0x184
> +#define VE_MPEG_JPEG_SIZE              0x1b8
> +#define VE_MPEG_JPEG_RES_INT           0x1c0
> +#define VE_MPEG_ERROR                  0x1c4
> +#define VE_MPEG_CTR_MB                 0x1c8
> +#define VE_MPEG_ROT_LUMA               0x1cc
> +#define VE_MPEG_ROT_CHROMA             0x1d0
> +#define VE_MPEG_SDROT_CTRL             0x1d4
> +#define VE_MPEG_RAM_WRITE_PTR          0x1e0
> +#define VE_MPEG_RAM_WRITE_DATA         0x1e4
> +
> +#define VE_H264_FRAME_SIZE             0x200
> +#define VE_H264_PIC_HDR                        0x204
> +#define VE_H264_SLICE_HDR              0x208
> +#define VE_H264_SLICE_HDR2             0x20c
> +#define VE_H264_PRED_WEIGHT            0x210
> +#define VE_H264_QP_PARAM               0x21c
> +#define VE_H264_CTRL                   0x220
> +#define VE_H264_TRIGGER                        0x224
> +#define VE_H264_STATUS                 0x228
> +#define VE_H264_CUR_MB_NUM             0x22c
> +#define VE_H264_VLD_ADDR               0x230
> +#define VE_H264_VLD_OFFSET             0x234
> +#define VE_H264_VLD_LEN                        0x238
> +#define VE_H264_VLD_END                        0x23c
> +#define VE_H264_SDROT_CTRL             0x240
> +#define VE_H264_OUTPUT_FRAME_IDX       0x24c
> +#define VE_H264_EXTRA_BUFFER1          0x250
> +#define VE_H264_EXTRA_BUFFER2          0x254
> +#define VE_H264_BASIC_BITS             0x2dc
> +#define VE_H264_RAM_WRITE_PTR          0x2e0
> +#define VE_H264_RAM_WRITE_DATA         0x2e4
> +
> +#define VE_SRAM_H264_PRED_WEIGHT_TABLE 0x000
> +#define VE_SRAM_H264_FRAMEBUFFER_LIST  0x400
> +#define VE_SRAM_H264_REF_LIST0         0x640
> +#define VE_SRAM_H264_REF_LIST1         0x664
> +#define VE_SRAM_H264_SCALING_LISTS     0x800
> +
> +#define VE_ISP_INPUT_SIZE              0xa00
> +#define VE_ISP_INPUT_STRIDE            0xa04
> +#define VE_ISP_CTRL                    0xa08
> +#define VE_ISP_INPUT_LUMA              0xa78
> +#define VE_ISP_INPUT_CHROMA            0xa7c
> +
> +#define VE_AVC_PARAM                   0xb04
> +#define VE_AVC_QP                      0xb08
> +#define VE_AVC_MOTION_EST              0xb10
> +#define VE_AVC_CTRL                    0xb14
> +#define VE_AVC_TRIGGER                 0xb18
> +#define VE_AVC_STATUS                  0xb1c
> +#define VE_AVC_BASIC_BITS              0xb20
> +#define VE_AVC_UNK_BUF                 0xb60
> +#define VE_AVC_VLE_ADDR                        0xb80
> +#define VE_AVC_VLE_END                 0xb84
> +#define VE_AVC_VLE_OFFSET              0xb88
> +#define VE_AVC_VLE_MAX                 0xb8c
> +#define VE_AVC_VLE_LENGTH              0xb90
> +#define VE_AVC_REF_LUMA                        0xba0
> +#define VE_AVC_REF_CHROMA              0xba4
> +#define VE_AVC_REC_LUMA                        0xbb0
> +#define VE_AVC_REC_CHROMA              0xbb4
> +#define VE_AVC_REF_SLUMA               0xbb8
> +#define VE_AVC_REC_SLUMA               0xbbc
> +#define VE_AVC_MB_INFO                 0xbc0
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.c b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
> new file mode 100644
> index 000000000000..ad7da8d36966
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
> @@ -0,0 +1,502 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#include <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "cedrus.h"
> +#include "cedrus_mpeg2.h"
> +#include "cedrus_dec.h"
> +#include "cedrus_hw.h"
> +
> +/* Flags that indicate a format can be used for capture/output. */
> +#define CEDRUS_CAPTURE BIT(0)
> +#define CEDRUS_OUTPUT  BIT(1)
> +
> +#define CEDRUS_MIN_WIDTH       16U
> +#define CEDRUS_MIN_HEIGHT      16U
> +#define CEDRUS_MAX_WIDTH       3840U
> +#define CEDRUS_MAX_HEIGHT      2160U
> +
> +static struct cedrus_fmt formats[] = {
> +       {
> +               .fourcc = V4L2_PIX_FMT_MB32_NV12,
> +               .types  = CEDRUS_CAPTURE,
> +               .depth = 2,
> +               .num_planes = 2,
> +       },
> +       {
> +               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
> +               .types  = CEDRUS_OUTPUT,
> +               .num_planes = 1,
> +       },
> +};
> +
> +#define NUM_FORMATS ARRAY_SIZE(formats)
> +
> +static struct cedrus_fmt *find_format(struct v4l2_format *f)
> +{
> +       struct cedrus_fmt *fmt;
> +       unsigned int k;
> +
> +       for (k = 0; k < NUM_FORMATS; k++) {
> +               fmt = &formats[k];
> +               if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
> +                       break;
> +       }
> +
> +       if (k == NUM_FORMATS)
> +               return NULL;
> +
> +       return &formats[k];
> +}
> +
> +static inline struct cedrus_ctx *file2ctx(struct file *file)
> +{
> +       return container_of(file->private_data, struct cedrus_ctx, fh);
> +}
> +
> +static int vidioc_querycap(struct file *file, void *priv,
> +                          struct v4l2_capability *cap)
> +{
> +       strncpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver) - 1);
> +       strncpy(cap->card, CEDRUS_NAME, sizeof(cap->card) - 1);
> +       snprintf(cap->bus_info, sizeof(cap->bus_info),
> +                "platform:%s", CEDRUS_NAME);
> +       cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
> +       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
> +       return 0;
> +}
> +
> +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
> +{
> +       struct cedrus_fmt *fmt;
> +       int i, num = 0;
> +
> +       for (i = 0; i < NUM_FORMATS; ++i) {
> +               if (formats[i].types & type) {
> +                       /* index-th format of type type found ? */
> +                       if (num == f->index)
> +                               break;
> +                       /*
> +                        * Correct type but haven't reached our index yet,
> +                        * just increment per-type index
> +                        */
> +                       ++num;
> +               }
> +       }
> +
> +       if (i < NUM_FORMATS) {
> +               fmt = &formats[i];
> +               f->pixelformat = fmt->fourcc;
> +               return 0;
> +       }
> +
> +       return -EINVAL;
> +}
> +
> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
> +                                  struct v4l2_fmtdesc *f)
> +{
> +       return enum_fmt(f, CEDRUS_CAPTURE);
> +}
> +
> +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
> +                                  struct v4l2_fmtdesc *f)
> +{
> +       return enum_fmt(f, CEDRUS_OUTPUT);
> +}
> +
> +static int vidioc_g_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
> +{
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       switch (f->type) {
> +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +               f->fmt.pix_mp = ctx->dst_fmt;
> +               break;
> +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +               f->fmt.pix_mp = ctx->src_fmt;
> +               break;
> +       default:
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Invalid buffer type for getting format\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
> +                               struct v4l2_format *f)
> +{
> +       return vidioc_g_fmt(file2ctx(file), f);
> +}
> +
> +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
> +                               struct v4l2_format *f)
> +{
> +       return vidioc_g_fmt(file2ctx(file), f);
> +}
> +
> +static int vidioc_try_fmt(struct v4l2_format *f, struct cedrus_fmt *fmt)
> +{
> +       int i;
> +       __u32 bpl;
> +

nit: unsigned int -- or, given it's clamped, just use int.

> +       f->fmt.pix_mp.field = V4L2_FIELD_NONE;
> +       f->fmt.pix_mp.num_planes = fmt->num_planes;
> +
> +       switch (f->type) {
> +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +               if (f->fmt.pix_mp.plane_fmt[0].sizeimage == 0)
> +                       return -EINVAL;
> +
> +               f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
> +               break;
> +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +               /* Limit to hardware min/max. */
> +               f->fmt.pix_mp.width = clamp(f->fmt.pix_mp.width,
> +                                           CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
> +               f->fmt.pix_mp.height = clamp(f->fmt.pix_mp.height,
> +                                            CEDRUS_MIN_HEIGHT,
> +                                            CEDRUS_MAX_HEIGHT);
> +
> +               for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) {
> +                       bpl = (f->fmt.pix_mp.width * fmt->depth) >> 3;
> +                       f->fmt.pix_mp.plane_fmt[i].bytesperline = bpl;
> +                       f->fmt.pix_mp.plane_fmt[i].sizeimage =
> +                               f->fmt.pix_mp.height * bpl;
> +               }
> +               break;
> +       }
> +       return 0;
> +}
> +
> +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
> +                                 struct v4l2_format *f)
> +{
> +       struct cedrus_fmt *fmt;
> +       struct cedrus_ctx *ctx = file2ctx(file);
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       fmt = find_format(f);
> +       if (!fmt) {
> +               f->fmt.pix_mp.pixelformat = formats[0].fourcc;
> +               fmt = find_format(f);
> +       }
> +       if (!(fmt->types & CEDRUS_CAPTURE)) {
> +               v4l2_err(&dev->v4l2_dev, "Invalid destination format: %08x\n",
> +                        f->fmt.pix_mp.pixelformat);
> +               return -EINVAL;
> +       }
> +
> +       return vidioc_try_fmt(f, fmt);
> +}
> +
> +static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
> +                                 struct v4l2_format *f)
> +{
> +       struct cedrus_fmt *fmt;
> +       struct cedrus_ctx *ctx = file2ctx(file);
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       fmt = find_format(f);
> +       if (!fmt) {
> +               f->fmt.pix_mp.pixelformat = formats[0].fourcc;
> +               fmt = find_format(f);
> +       }
> +       if (!(fmt->types & CEDRUS_OUTPUT)) {
> +               v4l2_err(&dev->v4l2_dev, "Invalid source format: %08x\n",
> +                        f->fmt.pix_mp.pixelformat);
> +               return -EINVAL;
> +       }
> +
> +       return vidioc_try_fmt(f, fmt);
> +}
> +
> +static int vidioc_s_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
> +{
> +       struct cedrus_dev *dev = ctx->dev;
> +       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
> +       struct cedrus_fmt *fmt;
> +       int i, ret = 0;
> +
> +       switch (f->type) {
> +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +               ctx->vpu_src_fmt = find_format(f);
> +               ctx->src_fmt = *pix_fmt_mp;
> +               break;
> +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +               fmt = find_format(f);
> +               ctx->vpu_dst_fmt = fmt;
> +
> +               for (i = 0; i < fmt->num_planes; ++i) {
> +                       pix_fmt_mp->plane_fmt[i].bytesperline =
> +                               pix_fmt_mp->width * fmt->depth;
> +                       pix_fmt_mp->plane_fmt[i].sizeimage =
> +                               pix_fmt_mp->plane_fmt[i].bytesperline
> +                               * pix_fmt_mp->height;
> +               }
> +               ctx->dst_fmt = *pix_fmt_mp;
> +               break;
> +       default:
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Invalid buffer type for setting format\n");
> +               return -EINVAL;
> +       }
> +
> +       return ret;
> +}
> +
> +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
> +                               struct v4l2_format *f)
> +{
> +       struct cedrus_ctx *ctx = file2ctx(file);
> +       int ret;
> +
> +       ret = vidioc_try_fmt_vid_cap(file, priv, f);
> +       if (ret)
> +               return ret;
> +
> +       return vidioc_s_fmt(ctx, f);
> +}
> +
> +static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
> +                               struct v4l2_format *f)
> +{
> +       struct cedrus_ctx *ctx = file2ctx(file);
> +       int ret;
> +
> +       ret = vidioc_try_fmt_vid_out(file, priv, f);
> +       if (ret)
> +               return ret;
> +
> +       return vidioc_s_fmt(ctx, f);
> +}
> +
> +const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
> +       .vidioc_querycap                = vidioc_querycap,
> +
> +       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
> +       .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap,
> +       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap,
> +       .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap,
> +
> +       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
> +       .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out,
> +       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out,
> +       .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out,
> +
> +       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
> +       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
> +       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
> +       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
> +       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
> +       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
> +       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
> +
> +       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
> +       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
> +
> +       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
> +       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
> +};
> +
> +static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
> +                             unsigned int *nplanes, unsigned int sizes[],
> +                             struct device *alloc_devs[])
> +{
> +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
> +       struct cedrus_dev *dev = ctx->dev;
> +
> +       switch (vq->type) {
> +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +               *nplanes = ctx->vpu_src_fmt->num_planes;
> +
> +               sizes[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
> +               break;
> +
> +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +               *nplanes = ctx->vpu_dst_fmt->num_planes;
> +
> +               sizes[0] = round_up(ctx->dst_fmt.plane_fmt[0].sizeimage, 8);
> +               sizes[1] = sizes[0];
> +               break;
> +
> +       default:
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Invalid buffer type for queue setup\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int cedrus_buf_init(struct vb2_buffer *vb)
> +{
> +       struct vb2_queue *vq = vb->vb2_queue;
> +       struct cedrus_ctx *ctx = container_of(vq->drv_priv,
> +                                             struct cedrus_ctx, fh);
> +
> +       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> +               ctx->dst_bufs[vb->index] = vb;
> +
> +       return 0;
> +}
> +
> +static void cedrus_buf_cleanup(struct vb2_buffer *vb)
> +{
> +       struct vb2_queue *vq = vb->vb2_queue;
> +       struct cedrus_ctx *ctx = container_of(vq->drv_priv,
> +                                             struct cedrus_ctx, fh);
> +
> +       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> +               ctx->dst_bufs[vb->index] = NULL;
> +}
> +
> +static int cedrus_buf_prepare(struct vb2_buffer *vb)
> +{
> +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +       struct cedrus_dev *dev = ctx->dev;
> +       struct vb2_queue *vq = vb->vb2_queue;
> +       int i;
> +
> +       switch (vq->type) {
> +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> +               if (vb2_plane_size(vb, 0)
> +                   < ctx->src_fmt.plane_fmt[0].sizeimage) {
> +                       v4l2_err(&dev->v4l2_dev,
> +                                "Buffer plane size too small for output\n");
> +                       return -EINVAL;
> +               }
> +               break;
> +
> +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> +               for (i = 0; i < ctx->vpu_dst_fmt->num_planes; ++i) {
> +                       if (vb2_plane_size(vb, i)
> +                           < ctx->dst_fmt.plane_fmt[i].sizeimage) {
> +                               v4l2_err(&dev->v4l2_dev,
> +                                        "Buffer plane %d size too small for capture\n",
> +                                        i);
> +                               break;
> +                       }
> +               }
> +
> +               if (i != ctx->vpu_dst_fmt->num_planes)
> +                       return -EINVAL;
> +               break;
> +
> +       default:
> +               v4l2_err(&dev->v4l2_dev,
> +                        "Invalid buffer type for buffer preparation\n");
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static void cedrus_stop_streaming(struct vb2_queue *q)
> +{
> +       struct cedrus_ctx *ctx = vb2_get_drv_priv(q);
> +       struct vb2_v4l2_buffer *vbuf;
> +       unsigned long flags;
> +
> +       flush_scheduled_work();

Just like the other work stuff, flush_scheduled_work seems bogus.

> +       for (;;) {
> +               spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> +               if (V4L2_TYPE_IS_OUTPUT(q->type))
> +                       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> +               else
> +                       vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +
> +               spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> +               if (vbuf == NULL)
> +                       return;
> +
> +               v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
> +                                          &ctx->hdl);
> +               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
> +       }
> +}
> +
> +static void cedrus_buf_queue(struct vb2_buffer *vb)
> +{
> +       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +
> +       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
> +}
> +
> +static void cedrus_buf_request_complete(struct vb2_buffer *vb)
> +{
> +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +
> +       v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> +}
> +
> +static struct vb2_ops cedrus_qops = {
> +       .queue_setup            = cedrus_queue_setup,
> +       .buf_prepare            = cedrus_buf_prepare,
> +       .buf_init               = cedrus_buf_init,
> +       .buf_cleanup            = cedrus_buf_cleanup,
> +       .buf_queue              = cedrus_buf_queue,
> +       .buf_request_complete   = cedrus_buf_request_complete,
> +       .stop_streaming         = cedrus_stop_streaming,
> +       .wait_prepare           = vb2_ops_wait_prepare,
> +       .wait_finish            = vb2_ops_wait_finish,
> +};
> +
> +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> +                     struct vb2_queue *dst_vq)
> +{
> +       struct cedrus_ctx *ctx = priv;
> +       int ret;
> +
> +       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> +       src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> +       src_vq->drv_priv = ctx;
> +       src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
> +       src_vq->allow_zero_bytesused = 1;
> +       src_vq->min_buffers_needed = 1;
> +       src_vq->ops = &cedrus_qops;
> +       src_vq->mem_ops = &vb2_dma_contig_memops;
> +       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +       src_vq->lock = &ctx->dev->dev_mutex;
> +       src_vq->dev = ctx->dev->dev;
> +
> +       ret = vb2_queue_init(src_vq);
> +       if (ret)
> +               return ret;
> +
> +       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> +       dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> +       dst_vq->drv_priv = ctx;
> +       dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
> +       dst_vq->allow_zero_bytesused = 1;
> +       dst_vq->min_buffers_needed = 1;
> +       dst_vq->ops = &cedrus_qops;
> +       dst_vq->mem_ops = &vb2_dma_contig_memops;
> +       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> +       dst_vq->lock = &ctx->dev->dev_mutex;
> +       dst_vq->dev = ctx->dev->dev;
> +
> +       return vb2_queue_init(dst_vq);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.h b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
> new file mode 100644
> index 000000000000..ed7cea8a6d8f
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
> @@ -0,0 +1,23 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + */
> +
> +#ifndef _CEDRUS_VIDEO_H_
> +#define _CEDRUS_VIDEO_H_
> +
> +extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
> +
> +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> +                     struct vb2_queue *dst_vq);
> +
> +#endif
> --
> 2.17.0
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar

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

* Re: [linux-sunxi] [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver
  2018-07-10  1:41   ` [linux-sunxi] " Ezequiel Garcia
@ 2018-07-24 14:28     ` Paul Kocialkowski
  0 siblings, 0 replies; 31+ messages in thread
From: Paul Kocialkowski @ 2018-07-24 14:28 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: linux-media, devicetree, linux-arm-kernel, linux-kernel,
	Mauro Carvalho Chehab, Rob Herring, Mark Rutland, Maxime Ripard,
	Chen-Yu Tsai, Marco Franchi, Icenowy Zheng, Hans Verkuil,
	Sylwester Nawrocki, Tom Saeger, Smitha T Murthy, Sakari Ailus,
	Andrzej Hajda, Jonathan Corbet, David S . Miller, Andrew Morton,
	Greg Kroah-Hartman, Linus Walleij, Randy Dunlap, Arnd Bergmann,
	Stanimir Varbanov, Philipp Zabel, Ramesh Shanmugasundaram,
	Jacob Chen, Steve Longerbeam, Todor Tomov, Jacopo Mondi,
	Alexandre Courbot, Marek Szyprowski, Andy Shevchenko,
	Tomasz Figa, Ricardo Ribalda Delgado, Hans de Goede,
	Sami Tolvanen, Thomas Petazzoni, linux-sunxi, Hugues Fruchet,
	Randy Li

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

Hi,

On Mon, 2018-07-09 at 22:41 -0300, Ezequiel Garcia wrote:
> Hi Paul,
> 
> A modest review round. Hope it helps!
> 
> I will be reviewing the driver some more later.

Thanks a lot for the review, it is very appreciated!

> On 18 June 2018 at 11:58, Paul Kocialkowski
> <paul.kocialkowski@bootlin.com> wrote:
> > This introduces the Sunxi-Cedrus VPU driver that supports the VPU found
> > in Allwinner SoCs, also known as Video Engine. It is implemented through
> > a v4l2 m2m decoder device and a media device (used for media requests).
> > So far, it only supports MPEG2 decoding.
> > 
> > Since this VPU is stateless, synchronization with media requests is
> > required in order to ensure consistency between frame headers that
> > contain metadata about the frame to process and the raw slice data that
> > is used to generate the frame.
> > 
> > This driver was made possible thanks to the long-standing effort
> > carried out by the linux-sunxi community in the interest of reverse
> > engineering, documenting and implementing support for Allwinner VPU.
> > 
> > Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > 
> >  create mode 100644 drivers/media/platform/sunxi/Kconfig
> >  create mode 100644 drivers/media/platform/sunxi/Makefile
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/Kconfig
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/Makefile
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.c
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus.h
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.c
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_dec.h
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.c
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_hw.h
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_regs.h
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.c
> >  create mode 100644 drivers/media/platform/sunxi/cedrus/cedrus_video.h
> > 
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 9c125f705f78..b47dee397475 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -656,6 +656,13 @@ L: linux-crypto@vger.kernel.org
> >  S:     Maintained
> >  F:     drivers/crypto/sunxi-ss/
> > 
> > +ALLWINNER VPU DRIVER
> > +M:     Maxime Ripard <maxime.ripard@bootlin.com>
> > +M:     Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > +L:     linux-media@vger.kernel.org
> > +S:     Maintained
> > +F:     drivers/media/platform/sunxi/cedrus/
> > +
> >  ALPHA PORT
> >  M:     Richard Henderson <rth@twiddle.net>
> >  M:     Ivan Kokshaysky <ink@jurassic.park.msu.ru>
> > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > index c7a1cf8a1b01..26da88bcd87b 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -31,6 +31,8 @@ source "drivers/media/platform/davinci/Kconfig"
> > 
> >  source "drivers/media/platform/omap/Kconfig"
> > 
> > +source "drivers/media/platform/sunxi/Kconfig"
> > +
> >  config VIDEO_SH_VOU
> >         tristate "SuperH VOU video output driver"
> >         depends on MEDIA_CAMERA_SUPPORT
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index 932515df4477..01ac00adcbc4 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)      += rockchip/rga/
> >  obj-y  += omap/
> > 
> >  obj-$(CONFIG_VIDEO_AM437X_VPFE)                += am437x/
> > +obj-$(CONFIG_VIDEO_SUNXI)              += sunxi/
> > 
> >  obj-$(CONFIG_VIDEO_XILINX)             += xilinx/
> > 
> > diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
> > new file mode 100644
> > index 000000000000..a639b0949826
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/Kconfig
> > @@ -0,0 +1,15 @@
> > +config VIDEO_SUNXI
> > +       bool "Allwinner sunXi family Video Devices"
> > +       depends on ARCH_SUNXI
> 
> You could add || COMPILE_TEST, to get covered
> by build tests.

Thanks, will do.

> > +       help
> > +         If you have an Allwinner SoC based on the sunXi family, say Y.
> > +
> > +         Note that this option doesn't include new drivers in the
> > +         kernel: saying N will just cause Kconfig to skip all the
> > +         questions about Allwinner media devices.
> > +
> > +if VIDEO_SUNXI
> > +
> > +source "drivers/media/platform/sunxi/cedrus/Kconfig"
> > +
> > +endif
> > diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
> > new file mode 100644
> > index 000000000000..cee2846c3ecf
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/Makefile
> > @@ -0,0 +1 @@
> > +obj-$(CONFIG_VIDEO_SUNXI_CEDRUS)       += cedrus/
> > diff --git a/drivers/media/platform/sunxi/cedrus/Kconfig b/drivers/media/platform/sunxi/cedrus/Kconfig
> > new file mode 100644
> > index 000000000000..870a4b64a45c
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/Kconfig
> > @@ -0,0 +1,13 @@
> > +config VIDEO_SUNXI_CEDRUS
> > +       tristate "Allwinner Cedrus VPU driver"
> > +       depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER
> > +       depends on HAS_DMA
> > +       select VIDEOBUF2_DMA_CONTIG
> > +       select MEDIA_REQUEST_API
> > +       select V4L2_MEM2MEM_DEV
> > +       help
> > +         Support for the VPU found in Allwinner SoCs, also known as the Cedar
> > +         video engine.
> > +
> > +         To compile this driver as a module, choose M here: the module
> > +         will be called cedrus.
> > diff --git a/drivers/media/platform/sunxi/cedrus/Makefile b/drivers/media/platform/sunxi/cedrus/Makefile
> > new file mode 100644
> > index 000000000000..632a0be90ed7
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/Makefile
> > @@ -0,0 +1,3 @@
> > +obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += cedrus.o
> > +
> > +cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o cedrus_mpeg2.o
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.c b/drivers/media/platform/sunxi/cedrus/cedrus.c
> > new file mode 100644
> > index 000000000000..1718db1b549b
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus.c
> > @@ -0,0 +1,327 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#include <linux/platform_device.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +
> > +#include <media/videobuf2-dma-contig.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-ioctl.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-mem2mem.h>
> > +
> > +#include "cedrus.h"
> > +#include "cedrus_video.h"
> > +#include "cedrus_dec.h"
> > +#include "cedrus_hw.h"
> > +
> > +static int cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
> > +{
> > +       struct cedrus_ctx *ctx =
> > +               container_of(ctrl->handler, struct cedrus_ctx, hdl);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       switch (ctrl->id) {
> > +       case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER:
> > +               /* This is kept in memory and used directly. */
> > +               break;
> > +       default:
> > +               v4l2_err(&dev->v4l2_dev, "Invalid control to set\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct v4l2_ctrl_ops cedrus_ctrl_ops = {
> > +       .s_ctrl = cedrus_s_ctrl,
> > +};
> > +
> > +static const struct cedrus_control controls[] = {
> > +       [CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER] = {
> > +               .id             = V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_HEADER,
> > +               .elem_size      = sizeof(struct v4l2_ctrl_mpeg2_slice_header),
> > +       },
> > +};
> > +
> > +static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
> > +{
> > +       struct v4l2_ctrl_handler *hdl = &ctx->hdl;
> > +       unsigned int num_ctrls = ARRAY_SIZE(controls);
> > +       unsigned int i;
> > +
> > +       v4l2_ctrl_handler_init(hdl, num_ctrls);
> > +       if (hdl->error) {
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Failed to initialize control handler\n");
> > +               return hdl->error;
> > +       }
> > +
> > +       for (i = 0; i < num_ctrls; i++) {
> > +               struct v4l2_ctrl_config cfg = { 0 };
> > +
> > +               cfg.ops = &cedrus_ctrl_ops;
> > +               cfg.elem_size = controls[i].elem_size;
> > +               cfg.id = controls[i].id;
> > +
> > +               ctx->ctrls[i] = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
> > +               if (hdl->error) {
> > +                       v4l2_err(&dev->v4l2_dev,
> > +                                "Failed to create new custom control\n");
> > +
> > +                       v4l2_ctrl_handler_free(hdl);
> > +                       return hdl->error;
> > +               }
> > +       }
> > +
> > +       ctx->fh.ctrl_handler = hdl;
> > +       v4l2_ctrl_handler_setup(hdl);
> > +
> > +       return 0;
> > +}
> > +
> > +static int cedrus_open(struct file *file)
> > +{
> > +       struct cedrus_dev *dev = video_drvdata(file);
> > +       struct cedrus_ctx *ctx = NULL;
> > +       int ret;
> > +
> > +       if (mutex_lock_interruptible(&dev->dev_mutex))
> > +               return -ERESTARTSYS;
> > +
> > +       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > +       if (!ctx) {
> > +               mutex_unlock(&dev->dev_mutex);
> > +               return -ENOMEM;
> > +       }
> > +
> > +       INIT_WORK(&ctx->run_work, cedrus_device_work);
> > +
> 
> This cedrus_device_work looks odd, but I think it's already
> cleaned up in your WIP github branch.

Yes, it was replaced by the interrupt bottom-half, which we hopefully
can also eventually get rid of thanks to your patches!

> > +       INIT_LIST_HEAD(&ctx->src_list);
> > +       INIT_LIST_HEAD(&ctx->dst_list);
> > +
> > +       v4l2_fh_init(&ctx->fh, video_devdata(file));
> > +       file->private_data = &ctx->fh;
> > +       ctx->dev = dev;
> > +
> > +       ret = cedrus_init_ctrls(dev, ctx);
> > +       if (ret)
> > +               goto err_free;
> > +
> > +       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
> > +                                           &cedrus_queue_init);
> > +       if (IS_ERR(ctx->fh.m2m_ctx)) {
> > +               ret = PTR_ERR(ctx->fh.m2m_ctx);
> > +               goto err_ctrls;
> > +       }
> > +
> > +       v4l2_fh_add(&ctx->fh);
> > +
> > +       mutex_unlock(&dev->dev_mutex);
> > +
> > +       return 0;
> > +
> > +err_ctrls:
> > +       v4l2_ctrl_handler_free(&ctx->hdl);
> > +err_free:
> > +       kfree(ctx);
> > +       mutex_unlock(&dev->dev_mutex);
> > +
> > +       return ret;
> > +}
> > +
> > +static int cedrus_release(struct file *file)
> > +{
> > +       struct cedrus_dev *dev = video_drvdata(file);
> > +       struct cedrus_ctx *ctx = container_of(file->private_data,
> > +                                             struct cedrus_ctx, fh);
> > +
> > +       mutex_lock(&dev->dev_mutex);
> > +
> > +       v4l2_fh_del(&ctx->fh);
> > +       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> > +
> > +       v4l2_ctrl_handler_free(&ctx->hdl);
> > +
> > +       v4l2_fh_exit(&ctx->fh);
> > +       v4l2_fh_exit(&ctx->fh);
> > +
> > +       kfree(ctx);
> > +
> > +       mutex_unlock(&dev->dev_mutex);
> > +
> > +       return 0;
> > +}
> > +
> > +static const struct v4l2_file_operations cedrus_fops = {
> > +       .owner          = THIS_MODULE,
> > +       .open           = cedrus_open,
> > +       .release        = cedrus_release,
> > +       .poll           = v4l2_m2m_fop_poll,
> > +       .unlocked_ioctl = video_ioctl2,
> > +       .mmap           = v4l2_m2m_fop_mmap,
> > +};
> > +
> > +static const struct video_device cedrus_video_device = {
> > +       .name           = CEDRUS_NAME,
> > +       .vfl_dir        = VFL_DIR_M2M,
> > +       .fops           = &cedrus_fops,
> > +       .ioctl_ops      = &cedrus_ioctl_ops,
> > +       .minor          = -1,
> > +       .release        = video_device_release_empty,
> > +};
> > +
> > +static const struct v4l2_m2m_ops cedrus_m2m_ops = {
> > +       .device_run     = cedrus_device_run,
> > +       .job_abort      = cedrus_job_abort,
> > +};
> > +
> > +static const struct media_device_ops cedrus_m2m_media_ops = {
> > +       .req_validate = vb2_request_validate,
> > +       .req_queue = vb2_m2m_request_queue,
> > +};
> > +
> > +static int cedrus_probe(struct platform_device *pdev)
> > +{
> > +       struct cedrus_dev *dev;
> > +       struct video_device *vfd;
> > +       int ret;
> > +
> > +       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
> > +       if (!dev)
> > +               return -ENOMEM;
> > +
> > +       dev->dev = &pdev->dev;
> > +       dev->pdev = pdev;
> > +
> > +       ret = cedrus_hw_probe(dev);
> > +       if (ret) {
> > +               dev_err(&pdev->dev, "Failed to probe hardware\n");
> > +               return ret;
> > +       }
> > +
> > +       mutex_init(&dev->dev_mutex);
> > +       spin_lock_init(&dev->irq_lock);
> > +
> > +       dev->vfd = cedrus_video_device;
> > +       vfd = &dev->vfd;
> > +       vfd->lock = &dev->dev_mutex;
> > +       vfd->v4l2_dev = &dev->v4l2_dev;
> > +
> > +       dev->mdev.dev = &pdev->dev;
> > +       strlcpy(dev->mdev.model, CEDRUS_NAME, sizeof(dev->mdev.model));
> > +
> > +       media_device_init(&dev->mdev);
> > +       dev->mdev.ops = &cedrus_m2m_media_ops;
> > +       dev->v4l2_dev.mdev = &dev->mdev;
> > +       dev->pad[0].flags = MEDIA_PAD_FL_SINK;
> > +       dev->pad[1].flags = MEDIA_PAD_FL_SOURCE;
> > +
> > +       ret = media_entity_pads_init(&vfd->entity, 2, dev->pad);
> > +       if (ret) {
> > +               dev_err(&pdev->dev, "Failed to initialize media entity pads\n");
> > +               return ret;
> > +       }
> > +
> > +       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> > +       if (ret) {
> > +               dev_err(&pdev->dev, "Failed to register V4L2 device\n");
> > +               return ret;
> > +       }
> > +
> > +       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
> > +               goto err_v4l2;
> > +       }
> > +
> > +       video_set_drvdata(vfd, dev);
> > +       snprintf(vfd->name, sizeof(vfd->name), "%s", cedrus_video_device.name);
> > +
> > +       v4l2_info(&dev->v4l2_dev,
> > +                 "Device registered as /dev/video%d\n", vfd->num);
> > +
> > +       platform_set_drvdata(pdev, dev);
> > +
> > +       dev->m2m_dev = v4l2_m2m_init(&cedrus_m2m_ops);
> > +       if (IS_ERR(dev->m2m_dev)) {
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Failed to initialize V4L2 M2M device\n");
> > +               ret = PTR_ERR(dev->m2m_dev);
> > +               goto err_video;
> > +       }
> > +
> > +       ret = media_device_register(&dev->mdev);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to register media device\n");
> > +               goto err_m2m;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_m2m:
> > +       v4l2_m2m_release(dev->m2m_dev);
> > +err_video:
> > +       video_unregister_device(&dev->vfd);
> > +err_v4l2:
> > +       v4l2_device_unregister(&dev->v4l2_dev);
> > +
> > +       return ret;
> > +}
> > +
> > +static int cedrus_remove(struct platform_device *pdev)
> > +{
> > +       struct cedrus_dev *dev = platform_get_drvdata(pdev);
> > +
> > +       v4l2_info(&dev->v4l2_dev, "Removing " CEDRUS_NAME);
> > +
> > +       if (media_devnode_is_registered(dev->mdev.devnode)) {
> > +               media_device_unregister(&dev->mdev);
> > +               media_device_cleanup(&dev->mdev);
> > +       }
> > +
> > +       v4l2_m2m_release(dev->m2m_dev);
> > +       video_unregister_device(&dev->vfd);
> > +       v4l2_device_unregister(&dev->v4l2_dev);
> > +       cedrus_hw_remove(dev);
> > +
> > +       return 0;
> > +}
> > +
> > +#ifdef CONFIG_OF
> > +static const struct of_device_id of_cedrus_match[] = {
> > +       { .compatible = "allwinner,sun4i-a10-video-engine" },
> > +       { .compatible = "allwinner,sun5i-a13-video-engine" },
> > +       { .compatible = "allwinner,sun7i-a20-video-engine" },
> > +       { .compatible = "allwinner,sun8i-a33-video-engine" },
> > +       { /* sentinel */ }
> > +};
> > +MODULE_DEVICE_TABLE(of, of_cedrus_match);
> > +#endif
> > +
> > +static struct platform_driver cedrus_driver = {
> > +       .probe          = cedrus_probe,
> > +       .remove         = cedrus_remove,
> > +       .driver         = {
> > +               .name   = CEDRUS_NAME,
> > +               .owner = THIS_MODULE,
> > +               .of_match_table = of_match_ptr(of_cedrus_match),
> > +       },
> > +};
> > +module_platform_driver(cedrus_driver);
> > +
> > +MODULE_LICENSE("GPL v2");
> > +MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
> > +MODULE_DESCRIPTION("Sunxi-Cedrus VPU driver");
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus.h b/drivers/media/platform/sunxi/cedrus/cedrus.h
> > new file mode 100644
> > index 000000000000..106bda44a3c3
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus.h
> > @@ -0,0 +1,117 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_H_
> > +#define _CEDRUS_H_
> > +
> > +#include <linux/platform_device.h>
> > +
> > +#include <media/videobuf2-v4l2.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-ctrls.h>
> > +
> > +#define CEDRUS_NAME    "cedrus"
> > +
> > +enum cedrus_control_id {
> > +       CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER = 0,
> > +       CEDRUS_CTRL_MAX,
> > +};
> > +
> > +struct cedrus_control {
> > +       u32     id;
> > +       u32     elem_size;
> > +};
> > +
> > +struct cedrus_fmt {
> > +       u32             fourcc;
> > +       int             depth;
> > +       u32             types;
> > +       unsigned int    num_planes;
> > +};
> > +
> > +struct cedrus_mpeg2_run {
> > +       const struct v4l2_ctrl_mpeg2_slice_header       *hdr;
> > +};
> > +
> > +struct cedrus_run {
> > +       struct vb2_v4l2_buffer  *src;
> > +       struct vb2_v4l2_buffer  *dst;
> > +
> > +       union {
> > +               struct cedrus_mpeg2_run mpeg2;
> > +       };
> > +};
> > +
> > +struct cedrus_ctx {
> > +       struct v4l2_fh                  fh;
> > +       struct cedrus_dev               *dev;
> > +
> > +       struct cedrus_fmt               *vpu_src_fmt;
> > +       struct v4l2_pix_format_mplane   src_fmt;
> > +       struct cedrus_fmt               *vpu_dst_fmt;
> > +       struct v4l2_pix_format_mplane   dst_fmt;
> > +
> > +       struct v4l2_ctrl_handler        hdl;
> > +       struct v4l2_ctrl                *ctrls[CEDRUS_CTRL_MAX];
> > +
> > +       struct vb2_buffer               *dst_bufs[VIDEO_MAX_FRAME];
> > +
> > +       int                             job_abort;
> > +
> > +       struct work_struct              try_schedule_work;
> > +       struct work_struct              run_work;
> > +       struct list_head                src_list;
> > +       struct list_head                dst_list;
> > +};
> > +
> > +struct cedrus_buffer {
> > +       struct vb2_v4l2_buffer          vb;
> > +       enum vb2_buffer_state           state;
> > +       struct list_head                list;
> > +};
> > +
> > +struct cedrus_dev {
> > +       struct v4l2_device      v4l2_dev;
> > +       struct video_device     vfd;
> > +       struct media_device     mdev;
> > +       struct media_pad        pad[2];
> > +       struct platform_device  *pdev;
> > +       struct device           *dev;
> > +       struct v4l2_m2m_dev     *m2m_dev;
> > +
> > +       /* Device file mutex */
> > +       struct mutex            dev_mutex;
> > +       /* Interrupt spinlock */
> > +       spinlock_t              irq_lock;
> > +
> > +       void __iomem            *base;
> > +
> > +       struct clk              *mod_clk;
> > +       struct clk              *ahb_clk;
> > +       struct clk              *ram_clk;
> > +
> > +       struct reset_control    *rstc;
> > +};
> > +
> > +static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val)
> > +{
> > +       writel(val, dev->base + reg);
> > +}
> > +
> > +static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg)
> > +{
> > +       return readl(dev->base + reg);
> > +}
> > +
> > +#endif
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.c b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
> > new file mode 100644
> > index 000000000000..bd9727ae9f63
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.c
> > @@ -0,0 +1,170 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#include <media/videobuf2-dma-contig.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-ioctl.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-mem2mem.h>
> > +
> > +#include "cedrus.h"
> > +#include "cedrus_mpeg2.h"
> > +#include "cedrus_dec.h"
> > +#include "cedrus_hw.h"
> > +
> > +static inline void *get_ctrl_ptr(struct cedrus_ctx *ctx,
> > +                                enum cedrus_control_id id)
> > +{
> > +       struct v4l2_ctrl *ctrl = ctx->ctrls[id];
> > +
> > +       return ctrl->p_cur.p;
> > +}
> > +
> > +void cedrus_device_work(struct work_struct *work)
> > +{
> > +       struct cedrus_ctx *ctx = container_of(work,
> > +                                             struct cedrus_ctx, run_work);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +       struct cedrus_buffer *buffer_entry;
> > +       struct vb2_v4l2_buffer *src_buf, *dst_buf;
> > +       unsigned long flags;
> > +
> > +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> > +
> > +       if (list_empty(&ctx->src_list) || list_empty(&ctx->dst_list)) {
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Empty source and/or destination buffer lists\n");
> > +               spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +               return;
> > +       }
> > +
> > +       buffer_entry = list_last_entry(&ctx->src_list, struct cedrus_buffer, list);
> > +       list_del(ctx->src_list.prev);
> > +
> > +       src_buf = &buffer_entry->vb;
> > +       v4l2_m2m_buf_done(src_buf, buffer_entry->state);
> > +
> > +       buffer_entry = list_last_entry(&ctx->dst_list, struct cedrus_buffer, list);
> > +       list_del(ctx->dst_list.prev);
> > +
> > +       dst_buf = &buffer_entry->vb;
> > +       v4l2_m2m_buf_done(dst_buf, buffer_entry->state);
> > +
> > +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +
> > +       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> > +}
> > +
> > +void cedrus_device_run(void *priv)
> > +{
> > +       struct cedrus_ctx *ctx = priv;
> > +       struct cedrus_dev *dev = ctx->dev;
> > +       struct cedrus_run run = { 0 };
> > +       struct media_request *src_req;
> > +       unsigned long flags;
> > +
> > +       run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> > +       if (!run.src) {
> > +               v4l2_err(&dev->v4l2_dev, "No source buffer to prepare\n");
> 
> I believe it's a mem2mem core nasty bug if you can't get a source or destination
> buffer in .device_run. Perhaps catch it with WARN or BUG?
> Or just let the kernel burn, like other drivers do :-)

Yes you're right, this check is rather pointless, so I've just gotten
rid of it.

> > +               return;
> > +       }
> > +
> > +       run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> > +       if (!run.dst) {
> > +               v4l2_err(&dev->v4l2_dev, "No destination buffer to prepare\n");
> > +               return;
> > +       }
> > +
> > +       /* Apply request(s) controls if needed. */
> > +       src_req = run.src->vb2_buf.req_obj.req;
> > +
> > +       if (src_req)
> > +               v4l2_ctrl_request_setup(src_req, &ctx->hdl);
> > +
> > +       ctx->job_abort = 0;
> > +
> > +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> > +
> > +       switch (ctx->vpu_src_fmt->fourcc) {
> > +       case V4L2_PIX_FMT_MPEG2_SLICE:
> > +               if (!ctx->ctrls[CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER]) {
> > +                       v4l2_err(&dev->v4l2_dev,
> > +                                "Invalid MPEG2 frame header control\n");
> > +                       ctx->job_abort = 1;
> > +                       goto unlock_complete;
> > +               }
> > +
> > +               run.mpeg2.hdr = get_ctrl_ptr(ctx, CEDRUS_CTRL_DEC_MPEG2_SLICE_HEADER);
> > +               cedrus_mpeg2_setup(ctx, &run);
> > +               break;
> > +
> > +       default:
> > +               ctx->job_abort = 1;
> > +       }
> > +
> > +unlock_complete:
> > +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +
> > +       /* Complete request(s) controls if needed. */
> > +
> > +       if (src_req)
> > +               v4l2_ctrl_request_complete(src_req, &ctx->hdl);
> > +
> > +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> > +
> > +       if (!ctx->job_abort) {
> > +               if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG2_SLICE)
> > +                       cedrus_mpeg2_trigger(ctx);
> > +       } else {
> > +               v4l2_m2m_buf_done(run.src, VB2_BUF_STATE_ERROR);
> > +               v4l2_m2m_buf_done(run.dst, VB2_BUF_STATE_ERROR);
> > +       }
> > +
> > +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +
> > +       if (ctx->job_abort)
> > +               v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> > +}
> > +
> > +void cedrus_job_abort(void *priv)
> > +{
> > +       struct cedrus_ctx *ctx = priv;
> > +       struct vb2_v4l2_buffer *src_buf, *dst_buf;
> > +       unsigned long flags;
> > +
> > +       ctx->job_abort = 1;
> > +
> 
> If you can't actually cancel the DMA operation,
> then perhaps you want to simply not define .job_abort,
> and wait for the running operation (if any) to finish.
> 
> See https://www.mail-archive.com/linux-media@vger.kernel.org/msg132881.html
> 
> It should also cleanup your impementation. The whole ctx->job_abort
> dance looks kinda cumbersome.

Okay, I'll keep that in mind and probably get rid of the whole thing if
there is nothing sensible that we can do to abort the job at hardware
level. It used to be relevant to keep it around for controls validation,
but that's no longer the case.

Since it seems that your series has not landed yet, I'll keep it around
for v6.

> > +       /*
> > +        * V4L2 M2M and request API cleanup is done here while hardware state
> > +        * cleanup is done in the interrupt context. Doing all the cleanup in
> > +        * the interrupt context is a bit risky, since the job_abort call might
> > +        * originate from the release hook, where interrupts have already been
> > +        * disabled.
> > +        */
> > +
> > +       spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> > +
> > +       src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > +       if (src_buf)
> > +               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
> > +
> > +       dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > +       if (dst_buf)
> > +               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
> > +
> > +       spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +
> > +       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> > +}
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_dec.h b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
> > new file mode 100644
> > index 000000000000..b38812136504
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_dec.h
> > @@ -0,0 +1,27 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_DEC_H_
> > +#define _CEDRUS_DEC_H_
> > +
> > +extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
> > +
> > +void cedrus_device_work(struct work_struct *work);
> > +void cedrus_device_run(void *priv);
> > +void cedrus_job_abort(void *priv);
> > +
> > +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> > +                     struct vb2_queue *dst_vq);
> > +
> > +#endif
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.c b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
> > new file mode 100644
> > index 000000000000..9ee1380f4e30
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.c
> > @@ -0,0 +1,262 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#include <linux/platform_device.h>
> > +#include <linux/of_reserved_mem.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/clk.h>
> > +#include <linux/regmap.h>
> > +#include <linux/reset.h>
> > +#include <linux/soc/sunxi/sunxi_sram.h>
> > +
> > +#include <media/videobuf2-core.h>
> > +#include <media/v4l2-mem2mem.h>
> > +
> > +#include "cedrus.h"
> > +#include "cedrus_hw.h"
> > +#include "cedrus_regs.h"
> > +
> > +int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine)
> > +{
> > +       u32 reg = 0;
> > +
> > +       /*
> > +        * FIXME: This is only valid on 32-bits DDR's, we should test
> > +        * it on the A13/A33.
> > +        */
> > +       reg |= VE_CTRL_REC_WR_MODE_2MB;
> > +
> > +       reg |= VE_CTRL_CACHE_BUS_BW_128;
> > +
> > +       switch (engine) {
> > +       case CEDRUS_ENGINE_MPEG:
> > +               reg |= VE_CTRL_DEC_MODE_MPEG;
> > +               break;
> > +
> > +       default:
> > +               return -EINVAL;
> > +       }
> > +
> > +       cedrus_write(dev, VE_CTRL, reg);
> > +
> > +       return 0;
> > +}
> > +
> > +void cedrus_engine_disable(struct cedrus_dev *dev)
> > +{
> > +       cedrus_write(dev, VE_CTRL, VE_CTRL_DEC_MODE_DISABLED);
> > +}
> > +
> > +static irqreturn_t cedrus_ve_irq(int irq, void *data)
> > +{
> > +       struct cedrus_dev *dev = data;
> > +       struct cedrus_ctx *ctx;
> > +       struct cedrus_buffer *src_buffer, *dst_buffer;
> > +       struct vb2_v4l2_buffer *src_vb, *dst_vb;
> > +       unsigned long flags;
> > +       unsigned int value, status;
> > +
> > +       spin_lock_irqsave(&dev->irq_lock, flags);
> > +
> > +       /* Disable MPEG interrupts and stop the MPEG engine. */
> > +       value = cedrus_read(dev, VE_MPEG_CTRL);
> > +       cedrus_write(dev, VE_MPEG_CTRL, value & (~0xf));
> > +
> > +       status = cedrus_read(dev, VE_MPEG_STATUS);
> > +       cedrus_write(dev, VE_MPEG_STATUS, 0x0000c00f);
> > +       cedrus_engine_disable(dev);
> > +
> > +       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
> > +       if (!ctx) {
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Instance released before the end of transaction\n");
> > +               spin_unlock_irqrestore(&dev->irq_lock, flags);
> > +
> > +               return IRQ_HANDLED;
> > +       }
> > +
> > +       src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > +       dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > +
> > +       if (!src_vb || !dst_vb) {
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Missing source and/or destination buffers\n");
> > +               spin_unlock_irqrestore(&dev->irq_lock, flags);
> > +
> > +               return IRQ_HANDLED;
> > +       }
> > +
> > +       src_buffer = container_of(src_vb, struct cedrus_buffer, vb);
> > +       dst_buffer = container_of(dst_vb, struct cedrus_buffer, vb);
> > +
> > +       /* First bit of MPEG_STATUS indicates success. */
> > +       if (ctx->job_abort || !(status & 0x01))
> > +               src_buffer->state = dst_buffer->state = VB2_BUF_STATE_ERROR;
> > +       else
> > +               src_buffer->state = dst_buffer->state = VB2_BUF_STATE_DONE;
> > +
> > +       list_add_tail(&src_buffer->list, &ctx->src_list);
> > +       list_add_tail(&dst_buffer->list, &ctx->dst_list);
> > +
> > +       spin_unlock_irqrestore(&dev->irq_lock, flags);
> > +
> > +       schedule_work(&ctx->run_work);
> > +
> > +       return IRQ_HANDLED;
> > +}
> > +
> > +int cedrus_hw_probe(struct cedrus_dev *dev)
> > +{
> > +       struct resource *res;
> > +       int irq_dec;
> > +       int ret;
> > +
> > +       irq_dec = platform_get_irq(dev->pdev, 0);
> > +       if (irq_dec <= 0) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to get IRQ\n");
> > +               return -ENXIO;
> > +       }
> > +       ret = devm_request_irq(dev->dev, irq_dec, cedrus_ve_irq, 0,
> > +                              dev_name(dev->dev), dev);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to request IRQ\n");
> > +               return -ENXIO;
> > +       }
> > +
> > +       /*
> > +        * The VPU is only able to handle bus addresses so we have to subtract
> > +        * the RAM offset to the physcal addresses.
> > +        */
> > +       dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
> > +
> > +       ret = of_reserved_mem_device_init(dev->dev);
> > +       if (ret && ret != -ENODEV) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to reserved memory\n");
> > +               return -ENODEV;
> > +       }
> > +
> > +       ret = sunxi_sram_claim(dev->dev);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to claim SRAM\n");
> > +               goto err_mem;
> > +       }
> > +
> > +       dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
> > +       if (IS_ERR(dev->ahb_clk)) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to get AHB clock\n");
> > +
> > +               ret = PTR_ERR(dev->ahb_clk);
> > +               goto err_sram;
> > +       }
> > +
> > +       dev->mod_clk = devm_clk_get(dev->dev, "mod");
> > +       if (IS_ERR(dev->mod_clk)) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to get MOD clock\n");
> > +
> > +               ret = PTR_ERR(dev->mod_clk);
> > +               goto err_sram;
> > +       }
> > +
> > +       dev->ram_clk = devm_clk_get(dev->dev, "ram");
> > +       if (IS_ERR(dev->ram_clk)) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to get RAM clock\n");
> > +
> > +               ret = PTR_ERR(dev->ram_clk);
> > +               goto err_sram;
> > +       }
> > +
> > +       dev->rstc = devm_reset_control_get(dev->dev, NULL);
> > +       if (IS_ERR(dev->rstc)) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to get reset control\n");
> > +
> > +               ret = PTR_ERR(dev->rstc);
> > +               goto err_sram;
> > +       }
> > +
> > +       res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
> > +       dev->base = devm_ioremap_resource(dev->dev, res);
> > +       if (!dev->base) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to map registers\n");
> > +
> > +               ret = -EFAULT;
> > +               goto err_sram;
> > +       }
> > +
> > +       ret = clk_set_rate(dev->mod_clk, CEDRUS_CLOCK_RATE_DEFAULT);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to set clock rate\n");
> > +               goto err_sram;
> > +       }
> > +
> > +       ret = clk_prepare_enable(dev->ahb_clk);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to enable AHB clock\n");
> > +
> > +               ret = -EFAULT;
> > +               goto err_sram;
> > +       }
> > +
> > +       ret = clk_prepare_enable(dev->mod_clk);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to enable MOD clock\n");
> > +
> > +               ret = -EFAULT;
> > +               goto err_ahb_clk;
> > +       }
> > +
> > +       ret = clk_prepare_enable(dev->ram_clk);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to enable RAM clock\n");
> > +
> > +               ret = -EFAULT;
> > +               goto err_mod_clk;
> > +       }
> > +
> 
> This might look cleaner with the clock bulk API.
> 
> Also, have you considered clock enable/disable in open/release,
> or start/stop? (possibly, via pm runtime).

We are interested in implementing runtime pm, but this is not really on
our priorities for now so we'll probably keep it for after the driver is
merged.

> > +       ret = reset_control_reset(dev->rstc);
> > +       if (ret) {
> > +               v4l2_err(&dev->v4l2_dev, "Failed to apply reset\n");
> > +
> > +               ret = -EFAULT;
> > +               goto err_ram_clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_ram_clk:
> > +       clk_disable_unprepare(dev->ram_clk);
> > +err_mod_clk:
> > +       clk_disable_unprepare(dev->mod_clk);
> > +err_ahb_clk:
> > +       clk_disable_unprepare(dev->ahb_clk);
> > +err_sram:
> > +       sunxi_sram_release(dev->dev);
> > +err_mem:
> > +       of_reserved_mem_device_release(dev->dev);
> > +
> > +       return ret;
> > +}
> > +
> > +void cedrus_hw_remove(struct cedrus_dev *dev)
> > +{
> > +       reset_control_assert(dev->rstc);
> > +
> > +       clk_disable_unprepare(dev->ram_clk);
> > +       clk_disable_unprepare(dev->mod_clk);
> > +       clk_disable_unprepare(dev->ahb_clk);
> > +
> > +       sunxi_sram_release(dev->dev);
> > +
> > +       of_reserved_mem_device_release(dev->dev);
> > +}
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_hw.h b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
> > new file mode 100644
> > index 000000000000..ead4f5089881
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_hw.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_HW_H_
> > +#define _CEDRUS_HW_H_
> > +
> > +#define CEDRUS_CLOCK_RATE_DEFAULT      320000000
> > +
> 
> This define is only used in cedrus_hw.c. Perhaps shouldn't belong
> in a header.

I have a personal preference for keeping constants defines in headers,
but I can reconsider that if you think it's a bad practice.

> > +enum cedrus_engine {
> > +       CEDRUS_ENGINE_MPEG,
> > +};
> > +
> > +int cedrus_engine_enable(struct cedrus_dev *dev, enum cedrus_engine engine);
> > +void cedrus_engine_disable(struct cedrus_dev *dev);
> > +
> > +int cedrus_hw_probe(struct cedrus_dev *dev);
> > +void cedrus_hw_remove(struct cedrus_dev *dev);
> > +
> > +#endif
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
> > new file mode 100644
> > index 000000000000..0d6dcaec73b3
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.c
> > @@ -0,0 +1,146 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#include <media/videobuf2-dma-contig.h>
> > +
> > +#include "cedrus.h"
> > +#include "cedrus_hw.h"
> > +#include "cedrus_regs.h"
> > +
> > +static const u8 mpeg_default_intra_quant[64] = {
> > +       8, 16, 16, 19, 16, 19, 22, 22,
> > +       22, 22, 22, 22, 26, 24, 26, 27,
> > +       27, 27, 26, 26, 26, 26, 27, 27,
> > +       27, 29, 29, 29, 34, 34, 34, 29,
> > +       29, 29, 27, 27, 29, 29, 32, 32,
> > +       34, 34, 37, 38, 37, 35, 35, 34,
> > +       35, 38, 38, 40, 40, 40, 48, 48,
> > +       46, 46, 56, 56, 58, 69, 69, 83
> > +};
> > +
> > +#define m_iq(i) (((64 + i) << 8) | mpeg_default_intra_quant[i])
> > +
> > +static const u8 mpeg_default_non_intra_quant[64] = {
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16,
> > +       16, 16, 16, 16, 16, 16, 16, 16
> > +};
> > +
> > +#define m_niq(i) ((i << 8) | mpeg_default_non_intra_quant[i])
> > +
> > +void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
> > +{
> > +       struct cedrus_dev *dev = ctx->dev;
> > +       const struct v4l2_ctrl_mpeg2_slice_header *frame_hdr = run->mpeg2.hdr;
> > +
> > +       u16 width = DIV_ROUND_UP(frame_hdr->width, 16);
> > +       u16 height = DIV_ROUND_UP(frame_hdr->height, 16);
> > +
> > +       u32 pic_header = 0;
> > +       u32 vld_len = frame_hdr->slice_len - frame_hdr->slice_pos;
> > +       int i;
> > +
> > +       struct vb2_buffer *fwd_vb2_buf, *bwd_vb2_buf;
> > +       dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
> > +       dma_addr_t fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
> > +
> > +       fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_ref_index];
> > +       if (fwd_vb2_buf) {
> > +               fwd_luma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 0);
> > +               fwd_chroma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 1);
> > +       }
> > +
> > +       bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_ref_index];
> > +       if (bwd_vb2_buf) {
> > +               bwd_luma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 0);
> > +               bwd_chroma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 1);
> > +       }
> > +
> > +       /* Activate MPEG engine. */
> > +       cedrus_engine_enable(dev, CEDRUS_ENGINE_MPEG);
> > +
> > +       /* Set quantization matrices. */
> > +       for (i = 0; i < 64; i++) {
> > +               cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_iq(i));
> > +               cedrus_write(dev, VE_MPEG_IQ_MIN_INPUT, m_niq(i));
> > +       }
> > +
> > +       /* Set frame dimensions. */
> > +       cedrus_write(dev, VE_MPEG_SIZE, width << 8 | height);
> > +       cedrus_write(dev, VE_MPEG_FRAME_SIZE, width << 20 | height << 4);
> > +
> > +       /* Set MPEG picture header. */
> > +       pic_header |= (frame_hdr->picture_coding_type & 0xf) << 28;
> > +       pic_header |= (frame_hdr->f_code[0][0] & 0xf) << 24;
> > +       pic_header |= (frame_hdr->f_code[0][1] & 0xf) << 20;
> > +       pic_header |= (frame_hdr->f_code[1][0] & 0xf) << 16;
> > +       pic_header |= (frame_hdr->f_code[1][1] & 0xf) << 12;
> > +       pic_header |= (frame_hdr->intra_dc_precision & 0x3) << 10;
> > +       pic_header |= (frame_hdr->picture_structure & 0x3) << 8;
> > +       pic_header |= (frame_hdr->top_field_first & 0x1) << 7;
> > +       pic_header |= (frame_hdr->frame_pred_frame_dct & 0x1) << 6;
> > +       pic_header |= (frame_hdr->concealment_motion_vectors & 0x1) << 5;
> > +       pic_header |= (frame_hdr->q_scale_type & 0x1) << 4;
> > +       pic_header |= (frame_hdr->intra_vlc_format & 0x1) << 3;
> > +       pic_header |= (frame_hdr->alternate_scan & 0x1) << 2;
> > +       cedrus_write(dev, VE_MPEG_PIC_HDR, pic_header);
> > +
> > +       /* Enable interrupt and an unknown control flag. */
> > +       cedrus_write(dev, VE_MPEG_CTRL, VE_MPEG_CTRL_MPEG2);
> > +
> > +       /* Macroblock address. */
> > +       cedrus_write(dev, VE_MPEG_MBA, 0);
> > +
> > +       /* Clear previous errors. */
> > +       cedrus_write(dev, VE_MPEG_ERROR, 0);
> > +
> > +       /* Clear correct macroblocks register. */
> > +       cedrus_write(dev, VE_MPEG_CTR_MB, 0);
> > +
> > +       /* Forward and backward prediction reference buffers. */
> > +       cedrus_write(dev, VE_MPEG_FWD_LUMA, fwd_luma);
> > +       cedrus_write(dev, VE_MPEG_FWD_CHROMA, fwd_chroma);
> > +       cedrus_write(dev, VE_MPEG_BACK_LUMA, bwd_luma);
> > +       cedrus_write(dev, VE_MPEG_BACK_CHROMA, bwd_chroma);
> > +
> > +       /* Destination luma and chroma buffers. */
> > +       dst_luma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0);
> > +       dst_chroma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1);
> > +       cedrus_write(dev, VE_MPEG_REC_LUMA, dst_luma_addr);
> > +       cedrus_write(dev, VE_MPEG_REC_CHROMA, dst_chroma_addr);
> > +       cedrus_write(dev, VE_MPEG_ROT_LUMA, dst_luma_addr);
> > +       cedrus_write(dev, VE_MPEG_ROT_CHROMA, dst_chroma_addr);
> > +
> > +       /* Source offset and length in bits. */
> > +       cedrus_write(dev, VE_MPEG_VLD_OFFSET, frame_hdr->slice_pos);
> > +       cedrus_write(dev, VE_MPEG_VLD_LEN, vld_len);
> > +
> > +       /* Source beginning and end addresses. */
> > +       src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
> > +       cedrus_write(dev, VE_MPEG_VLD_ADDR, VE_MPEG_VLD_ADDR_VAL(src_buf_addr));
> > +       cedrus_write(dev, VE_MPEG_VLD_END, src_buf_addr + VBV_SIZE - 1);
> > +}
> > +
> > +void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
> > +{
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       /* Trigger MPEG engine. */
> > +       cedrus_write(dev, VE_MPEG_TRIGGER, VE_TRIG_MPEG2);
> > +}
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
> > new file mode 100644
> > index 000000000000..fd864fab6986
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_mpeg2.h
> > @@ -0,0 +1,24 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_MPEG2_H_
> > +#define _CEDRUS_MPEG2_H_
> > +
> > +struct cedrus_ctx;
> > +struct cedrus_run;
> > +
> > +void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run);
> > +void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx);
> > +
> > +#endif
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_regs.h b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
> > new file mode 100644
> > index 000000000000..442befcdb6ea
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_regs.h
> > @@ -0,0 +1,167 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_REGS_H_
> > +#define _CEDRUS_REGS_H_
> > +
> > +/*
> > + * For more information, consult http://linux-sunxi.org/VE_Register_guide
> > + */
> > +
> > +/* VE_MPEG_CTRL:
> > + * The bit 3 (0x8) is used to enable IRQs
> > + * The other bits are unknown but needed
> > + */
> > +#define VE_MPEG_CTRL_MPEG2     0x800001b8
> > +#define VE_MPEG_CTRL_MPEG4     (0x80084118 | BIT(7))
> > +#define VE_MPEG_CTRL_MPEG4_P   (VE_MPEG_CTRL_MPEG4 | BIT(12))
> > +
> > +/* VE_MPEG_VLD_ADDR:
> > + * The bits 27 to 4 are used for the address
> > + * The bits 31 to 28 (0x7) are used to select the MPEG or JPEG engine
> > + */
> > +#define VE_MPEG_VLD_ADDR_VAL(x)        ((x & 0x0ffffff0) | (x >> 28) | (0x7 << 28))
> > +
> > +/* VE_MPEG_TRIGGER:
> > + * The first three bits are used to trigger the engine
> > + * The bits 24 to 26 are used to select the input format (1 for MPEG1, 2 for
> > + *                           MPEG2, 4 for MPEG4)
> > + * The bit 21 (0x8) is used to disable bitstream error handling
> > + *
> > + * In MPEG4 the w*h value is somehow used for an offset, unknown but needed
> > + */
> > +#define VE_TRIG_MPEG1          0x8100000f
> > +#define VE_TRIG_MPEG2          0x8200000f
> > +#define VE_TRIG_MPEG4(w, h)    (0x8400000d | ((w * h) << 8))
> > +
> > +/* VE_MPEG_SDROT_CTRL:
> > + * The bit 8 at zero is used to disable x downscaling
> > + * The bit 10 at 0 is used to disable y downscaling
> > + * The other bits are unknown but needed
> > + */
> > +#define VE_NO_SDROT_CTRL       0x40620000
> > +
> > +/* Decent size fo video buffering verifier */
> > +#define VBV_SIZE               (1024 * 1024)
> > +
> > +/* Registers addresses */
> > +#define VE_CTRL                                0x000
> > +/*
> > + * The datasheet states that this should be set to 2MB on a 32bits
> > + * DDR-3.
> > + */
> > +#define VE_CTRL_REC_WR_MODE_2MB                        (1 << 20)
> > +#define VE_CTRL_REC_WR_MODE_1MB                        (0 << 20)
> > +
> > +#define VE_CTRL_CACHE_BUS_BW_128               (3 << 16)
> > +#define VE_CTRL_CACHE_BUS_BW_256               (2 << 16)
> > +
> > +#define VE_CTRL_DEC_MODE_DISABLED              (7 << 0)
> > +#define VE_CTRL_DEC_MODE_H265                  (4 << 0)
> > +#define VE_CTRL_DEC_MODE_H264                  (1 << 0)
> > +#define VE_CTRL_DEC_MODE_MPEG                  (0 << 0)
> > +
> > +#define VE_VERSION                     0x0f0
> > +
> > +#define VE_MPEG_PIC_HDR                        0x100
> > +#define VE_MPEG_VOP_HDR                        0x104
> > +#define VE_MPEG_SIZE                   0x108
> > +#define VE_MPEG_FRAME_SIZE             0x10c
> > +#define VE_MPEG_MBA                    0x110
> > +#define VE_MPEG_CTRL                   0x114
> > +#define VE_MPEG_TRIGGER                        0x118
> > +#define VE_MPEG_STATUS                 0x11c
> > +#define VE_MPEG_TRBTRD_FIELD           0x120
> > +#define VE_MPEG_TRBTRD_FRAME           0x124
> > +#define VE_MPEG_VLD_ADDR               0x128
> > +#define VE_MPEG_VLD_OFFSET             0x12c
> > +#define VE_MPEG_VLD_LEN                        0x130
> > +#define VE_MPEG_VLD_END                        0x134
> > +#define VE_MPEG_MBH_ADDR               0x138
> > +#define VE_MPEG_DCAC_ADDR              0x13c
> > +#define VE_MPEG_NCF_ADDR               0x144
> > +#define VE_MPEG_REC_LUMA               0x148
> > +#define VE_MPEG_REC_CHROMA             0x14c
> > +#define VE_MPEG_FWD_LUMA               0x150
> > +#define VE_MPEG_FWD_CHROMA             0x154
> > +#define VE_MPEG_BACK_LUMA              0x158
> > +#define VE_MPEG_BACK_CHROMA            0x15c
> > +#define VE_MPEG_IQ_MIN_INPUT           0x180
> > +#define VE_MPEG_QP_INPUT               0x184
> > +#define VE_MPEG_JPEG_SIZE              0x1b8
> > +#define VE_MPEG_JPEG_RES_INT           0x1c0
> > +#define VE_MPEG_ERROR                  0x1c4
> > +#define VE_MPEG_CTR_MB                 0x1c8
> > +#define VE_MPEG_ROT_LUMA               0x1cc
> > +#define VE_MPEG_ROT_CHROMA             0x1d0
> > +#define VE_MPEG_SDROT_CTRL             0x1d4
> > +#define VE_MPEG_RAM_WRITE_PTR          0x1e0
> > +#define VE_MPEG_RAM_WRITE_DATA         0x1e4
> > +
> > +#define VE_H264_FRAME_SIZE             0x200
> > +#define VE_H264_PIC_HDR                        0x204
> > +#define VE_H264_SLICE_HDR              0x208
> > +#define VE_H264_SLICE_HDR2             0x20c
> > +#define VE_H264_PRED_WEIGHT            0x210
> > +#define VE_H264_QP_PARAM               0x21c
> > +#define VE_H264_CTRL                   0x220
> > +#define VE_H264_TRIGGER                        0x224
> > +#define VE_H264_STATUS                 0x228
> > +#define VE_H264_CUR_MB_NUM             0x22c
> > +#define VE_H264_VLD_ADDR               0x230
> > +#define VE_H264_VLD_OFFSET             0x234
> > +#define VE_H264_VLD_LEN                        0x238
> > +#define VE_H264_VLD_END                        0x23c
> > +#define VE_H264_SDROT_CTRL             0x240
> > +#define VE_H264_OUTPUT_FRAME_IDX       0x24c
> > +#define VE_H264_EXTRA_BUFFER1          0x250
> > +#define VE_H264_EXTRA_BUFFER2          0x254
> > +#define VE_H264_BASIC_BITS             0x2dc
> > +#define VE_H264_RAM_WRITE_PTR          0x2e0
> > +#define VE_H264_RAM_WRITE_DATA         0x2e4
> > +
> > +#define VE_SRAM_H264_PRED_WEIGHT_TABLE 0x000
> > +#define VE_SRAM_H264_FRAMEBUFFER_LIST  0x400
> > +#define VE_SRAM_H264_REF_LIST0         0x640
> > +#define VE_SRAM_H264_REF_LIST1         0x664
> > +#define VE_SRAM_H264_SCALING_LISTS     0x800
> > +
> > +#define VE_ISP_INPUT_SIZE              0xa00
> > +#define VE_ISP_INPUT_STRIDE            0xa04
> > +#define VE_ISP_CTRL                    0xa08
> > +#define VE_ISP_INPUT_LUMA              0xa78
> > +#define VE_ISP_INPUT_CHROMA            0xa7c
> > +
> > +#define VE_AVC_PARAM                   0xb04
> > +#define VE_AVC_QP                      0xb08
> > +#define VE_AVC_MOTION_EST              0xb10
> > +#define VE_AVC_CTRL                    0xb14
> > +#define VE_AVC_TRIGGER                 0xb18
> > +#define VE_AVC_STATUS                  0xb1c
> > +#define VE_AVC_BASIC_BITS              0xb20
> > +#define VE_AVC_UNK_BUF                 0xb60
> > +#define VE_AVC_VLE_ADDR                        0xb80
> > +#define VE_AVC_VLE_END                 0xb84
> > +#define VE_AVC_VLE_OFFSET              0xb88
> > +#define VE_AVC_VLE_MAX                 0xb8c
> > +#define VE_AVC_VLE_LENGTH              0xb90
> > +#define VE_AVC_REF_LUMA                        0xba0
> > +#define VE_AVC_REF_CHROMA              0xba4
> > +#define VE_AVC_REC_LUMA                        0xbb0
> > +#define VE_AVC_REC_CHROMA              0xbb4
> > +#define VE_AVC_REF_SLUMA               0xbb8
> > +#define VE_AVC_REC_SLUMA               0xbbc
> > +#define VE_AVC_MB_INFO                 0xbc0
> > +
> > +#endif
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.c b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
> > new file mode 100644
> > index 000000000000..ad7da8d36966
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.c
> > @@ -0,0 +1,502 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#include <media/videobuf2-dma-contig.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-ioctl.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-event.h>
> > +#include <media/v4l2-mem2mem.h>
> > +
> > +#include "cedrus.h"
> > +#include "cedrus_mpeg2.h"
> > +#include "cedrus_dec.h"
> > +#include "cedrus_hw.h"
> > +
> > +/* Flags that indicate a format can be used for capture/output. */
> > +#define CEDRUS_CAPTURE BIT(0)
> > +#define CEDRUS_OUTPUT  BIT(1)
> > +
> > +#define CEDRUS_MIN_WIDTH       16U
> > +#define CEDRUS_MIN_HEIGHT      16U
> > +#define CEDRUS_MAX_WIDTH       3840U
> > +#define CEDRUS_MAX_HEIGHT      2160U
> > +
> > +static struct cedrus_fmt formats[] = {
> > +       {
> > +               .fourcc = V4L2_PIX_FMT_MB32_NV12,
> > +               .types  = CEDRUS_CAPTURE,
> > +               .depth = 2,
> > +               .num_planes = 2,
> > +       },
> > +       {
> > +               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
> > +               .types  = CEDRUS_OUTPUT,
> > +               .num_planes = 1,
> > +       },
> > +};
> > +
> > +#define NUM_FORMATS ARRAY_SIZE(formats)
> > +
> > +static struct cedrus_fmt *find_format(struct v4l2_format *f)
> > +{
> > +       struct cedrus_fmt *fmt;
> > +       unsigned int k;
> > +
> > +       for (k = 0; k < NUM_FORMATS; k++) {
> > +               fmt = &formats[k];
> > +               if (fmt->fourcc == f->fmt.pix_mp.pixelformat)
> > +                       break;
> > +       }
> > +
> > +       if (k == NUM_FORMATS)
> > +               return NULL;
> > +
> > +       return &formats[k];
> > +}
> > +
> > +static inline struct cedrus_ctx *file2ctx(struct file *file)
> > +{
> > +       return container_of(file->private_data, struct cedrus_ctx, fh);
> > +}
> > +
> > +static int vidioc_querycap(struct file *file, void *priv,
> > +                          struct v4l2_capability *cap)
> > +{
> > +       strncpy(cap->driver, CEDRUS_NAME, sizeof(cap->driver) - 1);
> > +       strncpy(cap->card, CEDRUS_NAME, sizeof(cap->card) - 1);
> > +       snprintf(cap->bus_info, sizeof(cap->bus_info),
> > +                "platform:%s", CEDRUS_NAME);
> > +       cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
> > +       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
> > +       return 0;
> > +}
> > +
> > +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
> > +{
> > +       struct cedrus_fmt *fmt;
> > +       int i, num = 0;
> > +
> > +       for (i = 0; i < NUM_FORMATS; ++i) {
> > +               if (formats[i].types & type) {
> > +                       /* index-th format of type type found ? */
> > +                       if (num == f->index)
> > +                               break;
> > +                       /*
> > +                        * Correct type but haven't reached our index yet,
> > +                        * just increment per-type index
> > +                        */
> > +                       ++num;
> > +               }
> > +       }
> > +
> > +       if (i < NUM_FORMATS) {
> > +               fmt = &formats[i];
> > +               f->pixelformat = fmt->fourcc;
> > +               return 0;
> > +       }
> > +
> > +       return -EINVAL;
> > +}
> > +
> > +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
> > +                                  struct v4l2_fmtdesc *f)
> > +{
> > +       return enum_fmt(f, CEDRUS_CAPTURE);
> > +}
> > +
> > +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
> > +                                  struct v4l2_fmtdesc *f)
> > +{
> > +       return enum_fmt(f, CEDRUS_OUTPUT);
> > +}
> > +
> > +static int vidioc_g_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
> > +{
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       switch (f->type) {
> > +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> > +               f->fmt.pix_mp = ctx->dst_fmt;
> > +               break;
> > +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > +               f->fmt.pix_mp = ctx->src_fmt;
> > +               break;
> > +       default:
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Invalid buffer type for getting format\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
> > +                               struct v4l2_format *f)
> > +{
> > +       return vidioc_g_fmt(file2ctx(file), f);
> > +}
> > +
> > +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
> > +                               struct v4l2_format *f)
> > +{
> > +       return vidioc_g_fmt(file2ctx(file), f);
> > +}
> > +
> > +static int vidioc_try_fmt(struct v4l2_format *f, struct cedrus_fmt *fmt)
> > +{
> > +       int i;
> > +       __u32 bpl;
> > +
> 
> nit: unsigned int -- or, given it's clamped, just use int.

Looks like this no longer applies :)

> > +       f->fmt.pix_mp.field = V4L2_FIELD_NONE;
> > +       f->fmt.pix_mp.num_planes = fmt->num_planes;
> > +
> > +       switch (f->type) {
> > +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > +               if (f->fmt.pix_mp.plane_fmt[0].sizeimage == 0)
> > +                       return -EINVAL;
> > +
> > +               f->fmt.pix_mp.plane_fmt[0].bytesperline = 0;
> > +               break;
> > +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> > +               /* Limit to hardware min/max. */
> > +               f->fmt.pix_mp.width = clamp(f->fmt.pix_mp.width,
> > +                                           CEDRUS_MIN_WIDTH, CEDRUS_MAX_WIDTH);
> > +               f->fmt.pix_mp.height = clamp(f->fmt.pix_mp.height,
> > +                                            CEDRUS_MIN_HEIGHT,
> > +                                            CEDRUS_MAX_HEIGHT);
> > +
> > +               for (i = 0; i < f->fmt.pix_mp.num_planes; ++i) {
> > +                       bpl = (f->fmt.pix_mp.width * fmt->depth) >> 3;
> > +                       f->fmt.pix_mp.plane_fmt[i].bytesperline = bpl;
> > +                       f->fmt.pix_mp.plane_fmt[i].sizeimage =
> > +                               f->fmt.pix_mp.height * bpl;
> > +               }
> > +               break;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
> > +                                 struct v4l2_format *f)
> > +{
> > +       struct cedrus_fmt *fmt;
> > +       struct cedrus_ctx *ctx = file2ctx(file);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       fmt = find_format(f);
> > +       if (!fmt) {
> > +               f->fmt.pix_mp.pixelformat = formats[0].fourcc;
> > +               fmt = find_format(f);
> > +       }
> > +       if (!(fmt->types & CEDRUS_CAPTURE)) {
> > +               v4l2_err(&dev->v4l2_dev, "Invalid destination format: %08x\n",
> > +                        f->fmt.pix_mp.pixelformat);
> > +               return -EINVAL;
> > +       }
> > +
> > +       return vidioc_try_fmt(f, fmt);
> > +}
> > +
> > +static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
> > +                                 struct v4l2_format *f)
> > +{
> > +       struct cedrus_fmt *fmt;
> > +       struct cedrus_ctx *ctx = file2ctx(file);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       fmt = find_format(f);
> > +       if (!fmt) {
> > +               f->fmt.pix_mp.pixelformat = formats[0].fourcc;
> > +               fmt = find_format(f);
> > +       }
> > +       if (!(fmt->types & CEDRUS_OUTPUT)) {
> > +               v4l2_err(&dev->v4l2_dev, "Invalid source format: %08x\n",
> > +                        f->fmt.pix_mp.pixelformat);
> > +               return -EINVAL;
> > +       }
> > +
> > +       return vidioc_try_fmt(f, fmt);
> > +}
> > +
> > +static int vidioc_s_fmt(struct cedrus_ctx *ctx, struct v4l2_format *f)
> > +{
> > +       struct cedrus_dev *dev = ctx->dev;
> > +       struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
> > +       struct cedrus_fmt *fmt;
> > +       int i, ret = 0;
> > +
> > +       switch (f->type) {
> > +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > +               ctx->vpu_src_fmt = find_format(f);
> > +               ctx->src_fmt = *pix_fmt_mp;
> > +               break;
> > +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> > +               fmt = find_format(f);
> > +               ctx->vpu_dst_fmt = fmt;
> > +
> > +               for (i = 0; i < fmt->num_planes; ++i) {
> > +                       pix_fmt_mp->plane_fmt[i].bytesperline =
> > +                               pix_fmt_mp->width * fmt->depth;
> > +                       pix_fmt_mp->plane_fmt[i].sizeimage =
> > +                               pix_fmt_mp->plane_fmt[i].bytesperline
> > +                               * pix_fmt_mp->height;
> > +               }
> > +               ctx->dst_fmt = *pix_fmt_mp;
> > +               break;
> > +       default:
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Invalid buffer type for setting format\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return ret;
> > +}
> > +
> > +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
> > +                               struct v4l2_format *f)
> > +{
> > +       struct cedrus_ctx *ctx = file2ctx(file);
> > +       int ret;
> > +
> > +       ret = vidioc_try_fmt_vid_cap(file, priv, f);
> > +       if (ret)
> > +               return ret;
> > +
> > +       return vidioc_s_fmt(ctx, f);
> > +}
> > +
> > +static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
> > +                               struct v4l2_format *f)
> > +{
> > +       struct cedrus_ctx *ctx = file2ctx(file);
> > +       int ret;
> > +
> > +       ret = vidioc_try_fmt_vid_out(file, priv, f);
> > +       if (ret)
> > +               return ret;
> > +
> > +       return vidioc_s_fmt(ctx, f);
> > +}
> > +
> > +const struct v4l2_ioctl_ops cedrus_ioctl_ops = {
> > +       .vidioc_querycap                = vidioc_querycap,
> > +
> > +       .vidioc_enum_fmt_vid_cap        = vidioc_enum_fmt_vid_cap,
> > +       .vidioc_g_fmt_vid_cap_mplane    = vidioc_g_fmt_vid_cap,
> > +       .vidioc_try_fmt_vid_cap_mplane  = vidioc_try_fmt_vid_cap,
> > +       .vidioc_s_fmt_vid_cap_mplane    = vidioc_s_fmt_vid_cap,
> > +
> > +       .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out,
> > +       .vidioc_g_fmt_vid_out_mplane    = vidioc_g_fmt_vid_out,
> > +       .vidioc_try_fmt_vid_out_mplane  = vidioc_try_fmt_vid_out,
> > +       .vidioc_s_fmt_vid_out_mplane    = vidioc_s_fmt_vid_out,
> > +
> > +       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
> > +       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
> > +       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
> > +       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
> > +       .vidioc_prepare_buf             = v4l2_m2m_ioctl_prepare_buf,
> > +       .vidioc_create_bufs             = v4l2_m2m_ioctl_create_bufs,
> > +       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
> > +
> > +       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
> > +       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
> > +
> > +       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
> > +       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
> > +};
> > +
> > +static int cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
> > +                             unsigned int *nplanes, unsigned int sizes[],
> > +                             struct device *alloc_devs[])
> > +{
> > +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vq);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +
> > +       switch (vq->type) {
> > +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > +               *nplanes = ctx->vpu_src_fmt->num_planes;
> > +
> > +               sizes[0] = ctx->src_fmt.plane_fmt[0].sizeimage;
> > +               break;
> > +
> > +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> > +               *nplanes = ctx->vpu_dst_fmt->num_planes;
> > +
> > +               sizes[0] = round_up(ctx->dst_fmt.plane_fmt[0].sizeimage, 8);
> > +               sizes[1] = sizes[0];
> > +               break;
> > +
> > +       default:
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Invalid buffer type for queue setup\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static int cedrus_buf_init(struct vb2_buffer *vb)
> > +{
> > +       struct vb2_queue *vq = vb->vb2_queue;
> > +       struct cedrus_ctx *ctx = container_of(vq->drv_priv,
> > +                                             struct cedrus_ctx, fh);
> > +
> > +       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> > +               ctx->dst_bufs[vb->index] = vb;
> > +
> > +       return 0;
> > +}
> > +
> > +static void cedrus_buf_cleanup(struct vb2_buffer *vb)
> > +{
> > +       struct vb2_queue *vq = vb->vb2_queue;
> > +       struct cedrus_ctx *ctx = container_of(vq->drv_priv,
> > +                                             struct cedrus_ctx, fh);
> > +
> > +       if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
> > +               ctx->dst_bufs[vb->index] = NULL;
> > +}
> > +
> > +static int cedrus_buf_prepare(struct vb2_buffer *vb)
> > +{
> > +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > +       struct cedrus_dev *dev = ctx->dev;
> > +       struct vb2_queue *vq = vb->vb2_queue;
> > +       int i;
> > +
> > +       switch (vq->type) {
> > +       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
> > +               if (vb2_plane_size(vb, 0)
> > +                   < ctx->src_fmt.plane_fmt[0].sizeimage) {
> > +                       v4l2_err(&dev->v4l2_dev,
> > +                                "Buffer plane size too small for output\n");
> > +                       return -EINVAL;
> > +               }
> > +               break;
> > +
> > +       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
> > +               for (i = 0; i < ctx->vpu_dst_fmt->num_planes; ++i) {
> > +                       if (vb2_plane_size(vb, i)
> > +                           < ctx->dst_fmt.plane_fmt[i].sizeimage) {
> > +                               v4l2_err(&dev->v4l2_dev,
> > +                                        "Buffer plane %d size too small for capture\n",
> > +                                        i);
> > +                               break;
> > +                       }
> > +               }
> > +
> > +               if (i != ctx->vpu_dst_fmt->num_planes)
> > +                       return -EINVAL;
> > +               break;
> > +
> > +       default:
> > +               v4l2_err(&dev->v4l2_dev,
> > +                        "Invalid buffer type for buffer preparation\n");
> > +               return -EINVAL;
> > +       }
> > +
> > +       return 0;
> > +}
> > +
> > +static void cedrus_stop_streaming(struct vb2_queue *q)
> > +{
> > +       struct cedrus_ctx *ctx = vb2_get_drv_priv(q);
> > +       struct vb2_v4l2_buffer *vbuf;
> > +       unsigned long flags;
> > +
> > +       flush_scheduled_work();
> 
> Just like the other work stuff, flush_scheduled_work seems bogus.
> 
> > +       for (;;) {
> > +               spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> > +
> > +               if (V4L2_TYPE_IS_OUTPUT(q->type))
> > +                       vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> > +               else
> > +                       vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> > +
> > +               spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> > +
> > +               if (vbuf == NULL)
> > +                       return;
> > +
> > +               v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
> > +                                          &ctx->hdl);
> > +               v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
> > +       }
> > +}
> > +
> > +static void cedrus_buf_queue(struct vb2_buffer *vb)
> > +{
> > +       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
> > +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > +
> > +       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
> > +}
> > +
> > +static void cedrus_buf_request_complete(struct vb2_buffer *vb)
> > +{
> > +       struct cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> > +
> > +       v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> > +}
> > +
> > +static struct vb2_ops cedrus_qops = {
> > +       .queue_setup            = cedrus_queue_setup,
> > +       .buf_prepare            = cedrus_buf_prepare,
> > +       .buf_init               = cedrus_buf_init,
> > +       .buf_cleanup            = cedrus_buf_cleanup,
> > +       .buf_queue              = cedrus_buf_queue,
> > +       .buf_request_complete   = cedrus_buf_request_complete,
> > +       .stop_streaming         = cedrus_stop_streaming,
> > +       .wait_prepare           = vb2_ops_wait_prepare,
> > +       .wait_finish            = vb2_ops_wait_finish,
> > +};
> > +
> > +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> > +                     struct vb2_queue *dst_vq)
> > +{
> > +       struct cedrus_ctx *ctx = priv;
> > +       int ret;
> > +
> > +       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
> > +       src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> > +       src_vq->drv_priv = ctx;
> > +       src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
> > +       src_vq->allow_zero_bytesused = 1;
> > +       src_vq->min_buffers_needed = 1;
> > +       src_vq->ops = &cedrus_qops;
> > +       src_vq->mem_ops = &vb2_dma_contig_memops;
> > +       src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> > +       src_vq->lock = &ctx->dev->dev_mutex;
> > +       src_vq->dev = ctx->dev->dev;
> > +
> > +       ret = vb2_queue_init(src_vq);
> > +       if (ret)
> > +               return ret;
> > +
> > +       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
> > +       dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
> > +       dst_vq->drv_priv = ctx;
> > +       dst_vq->buf_struct_size = sizeof(struct cedrus_buffer);
> > +       dst_vq->allow_zero_bytesused = 1;
> > +       dst_vq->min_buffers_needed = 1;
> > +       dst_vq->ops = &cedrus_qops;
> > +       dst_vq->mem_ops = &vb2_dma_contig_memops;
> > +       dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
> > +       dst_vq->lock = &ctx->dev->dev_mutex;
> > +       dst_vq->dev = ctx->dev->dev;
> > +
> > +       return vb2_queue_init(dst_vq);
> > +}
> > diff --git a/drivers/media/platform/sunxi/cedrus/cedrus_video.h b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
> > new file mode 100644
> > index 000000000000..ed7cea8a6d8f
> > --- /dev/null
> > +++ b/drivers/media/platform/sunxi/cedrus/cedrus_video.h
> > @@ -0,0 +1,23 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Sunxi-Cedrus VPU driver
> > + *
> > + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> > + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> > + *
> > + * Based on the vim2m driver, that is:
> > + *
> > + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> > + * Pawel Osciak, <pawel@osciak.com>
> > + * Marek Szyprowski, <m.szyprowski@samsung.com>
> > + */
> > +
> > +#ifndef _CEDRUS_VIDEO_H_
> > +#define _CEDRUS_VIDEO_H_
> > +
> > +extern const struct v4l2_ioctl_ops cedrus_ioctl_ops;
> > +
> > +int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> > +                     struct vb2_queue *dst_vq);
> > +
> > +#endif
> > --
> > 2.17.0
> > 
> > --
> > You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> > For more options, visit https://groups.google.com/d/optout.
> 
> 
> 
-- 
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

end of thread, other threads:[~2018-07-24 14:28 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-18 14:58 [PATCH v4 00/19] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 01/19] dt-bindings: sram: sunxi: Add A13, A20 and A33 SRAM controller bindings Paul Kocialkowski
2018-06-18 16:02   ` Maxime Ripard
2018-06-18 14:58 ` [PATCH v4 02/19] dt-bindings: sram: sunxi: Add A10 binding for the C1 SRAM region Paul Kocialkowski
2018-06-20 15:59   ` Rob Herring
2018-06-18 14:58 ` [PATCH v4 03/19] dt-bindings: sram: sunxi: Add A13 " Paul Kocialkowski
2018-06-18 16:01   ` Maxime Ripard
2018-06-18 14:58 ` [PATCH v4 04/19] dt-bindings: sram: sunxi: Add A20 " Paul Kocialkowski
2018-06-18 16:04   ` Maxime Ripard
2018-06-18 14:58 ` [PATCH v4 05/19] dt-bindings: sram: sunxi: Add A33 " Paul Kocialkowski
2018-06-20 16:00   ` Rob Herring
2018-06-22 14:19   ` Maxime Ripard
2018-06-18 14:58 ` [PATCH v4 06/19] drivers: soc: sunxi: Add support " Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 07/19] drivers: soc: sunxi: Add dedicated compatibles for the A13 and A33 Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 08/19] ARM: dts: sun5i: Use dedicated SRAM controller compatible Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 09/19] ARM: dts: sun7i-a20: Also use " Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 10/19] ARM: sun5i: Add support for the C1 SRAM region with the SRAM controller Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 11/19] ARM: sun7i-a20: " Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 12/19] ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region Paul Kocialkowski
2018-06-22 14:20   ` Maxime Ripard
2018-06-18 14:58 ` [PATCH v4 13/19] media: v4l: Add definitions for MPEG2 slice format and header metadata Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 14/19] media: v4l: Add definition for Allwinner's MB32-tiled NV12 format Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 15/19] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver Paul Kocialkowski
2018-06-20 15:40   ` Rob Herring
2018-06-20 15:42     ` Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 16/19] media: platform: Add Sunxi-Cedrus VPU decoder driver Paul Kocialkowski
2018-07-10  1:41   ` [linux-sunxi] " Ezequiel Garcia
2018-07-24 14:28     ` Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 17/19] ARM: dts: sun5i: Add Video Engine and reserved memory nodes Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 18/19] ARM: dts: sun7i-a20: " Paul Kocialkowski
2018-06-18 14:58 ` [PATCH v4 19/19] ARM: dts: sun8i-a33: " Paul Kocialkowski

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).