Linux-Media Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/8] media: sunxi: Add DE2 rotate driver
@ 2020-01-24 23:20 Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions Jernej Skrabec
                   ` (8 more replies)
  0 siblings, 9 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Some of Allwinner SoCs like A83T and A64 SoCs contain DE2 rotate core
which can flip image horizontal and vertical and rotate it in 90 deg.
steps. It support a lot of output formats, but a bit less capture
formats. All YUV input formats get converted to yuv420p, while RGB
formats are preserved.

Patches 1-2 fix few issues with DE2 clocks.

Patches 3-4 fix register range of DE2 clocks (it would overlap with
rotate driver)

Patches 5-8 provide binding, implement driver and add nodes.

v4l2-compliance SHA: ec55a961487b449bedbe07650674b4965814cf07, 32 bits, 32-bit time_t

Compliance test for sun8i-rotate device /dev/video0:

Driver Info:
        Driver name      : sun8i-rotate
        Card type        : sun8i-rotate
        Bus info         : platform:sun8i-rotate
        Driver version   : 5.5.0
        Capabilities     : 0x84208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps      : 0x04208000
                Video Memory-to-Memory
                Streaming
                Extended Pix Format

Required ioctls:
        test VIDIOC_QUERYCAP: OK

Allow for multiple opens:
        test second /dev/video0 open: OK
        test VIDIOC_QUERYCAP: OK
        test VIDIOC_G/S_PRIORITY: OK
        test for unlimited opens: OK

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

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

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

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

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

Format ioctls:
        test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
        test VIDIOC_G/S_PARM: OK (Not Supported)
        test VIDIOC_G_FBUF: OK (Not Supported)
        test VIDIOC_G_FMT: OK
        test VIDIOC_TRY_FMT: OK
        test VIDIOC_S_FMT: OK
        test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
        test Cropping: OK (Not Supported)
        test Composing: OK (Not Supported)
        test Scaling: OK (Not Supported)

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

Buffer ioctls:
        test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
        test VIDIOC_EXPBUF: OK
        test Requests: OK (Not Supported)

Total for sun8i-rotate device /dev/video0: 45, Succeeded: 45, Failed: 0, Warnings: 0

Best regards,
Jernej

Jernej Skrabec (8):
  clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
  clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset
  ARM: dts: sunxi: Fix DE2 clocks register range
  arm64: dts: allwinner: a64: Fix display clock register range
  media: dt-bindings: media: Add Allwinner A83T Rotate driver
  media: sun8i: Add Allwinner A83T Rotate driver
  ARM: dts: sun8i: a83t: Add device node for rotation core
  arm64: dts: allwinner: a64: add node for rotation core

 .../allwinner,sun8i-a83t-de2-rotate.yaml      |  70 ++
 MAINTAINERS                                   |   8 +
 arch/arm/boot/dts/sun8i-a83t.dtsi             |  13 +-
 arch/arm/boot/dts/sun8i-r40.dtsi              |   2 +-
 arch/arm/boot/dts/sun8i-v3s.dtsi              |   2 +-
 arch/arm/boot/dts/sunxi-h3-h5.dtsi            |   2 +-
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi |  14 +-
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c          |  49 +-
 drivers/media/platform/Kconfig                |  12 +
 drivers/media/platform/sunxi/Makefile         |   1 +
 .../platform/sunxi/sun8i-rotate/Makefile      |   2 +
 .../sunxi/sun8i-rotate/sun8i-formats.c        | 273 ++++++
 .../sunxi/sun8i-rotate/sun8i-formats.h        |  25 +
 .../sunxi/sun8i-rotate/sun8i-rotate.c         | 924 ++++++++++++++++++
 .../sunxi/sun8i-rotate/sun8i-rotate.h         | 135 +++
 15 files changed, 1512 insertions(+), 20 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/Makefile
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h

-- 
2.25.0


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

* [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
@ 2020-01-24 23:20 ` Jernej Skrabec
  2020-01-25  3:05   ` [linux-sunxi] " Chen-Yu Tsai
  2020-01-24 23:20 ` [PATCH 2/8] clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset Jernej Skrabec
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

For some reason, A64 and H6 have swapped clocks and resets definitions.
H6 doesn't have rotation unit while A64 has. Swap around to correct the
issue.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index d9668493c3f9..08074d935317 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -51,7 +51,7 @@ static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4,
 static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4,
 		   CLK_SET_RATE_PARENT);
 
-static struct ccu_common *sun50i_h6_de3_clks[] = {
+static struct ccu_common *sun50i_a64_de2_clks[] = {
 	&mixer0_clk.common,
 	&mixer1_clk.common,
 	&wb_clk.common,
@@ -156,7 +156,7 @@ static struct clk_hw_onecell_data sun8i_v3s_de2_hw_clks = {
 	.num	= CLK_NUMBER_WITHOUT_ROT,
 };
 
-static struct clk_hw_onecell_data sun50i_h6_de3_hw_clks = {
+static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = {
 	.hws	= {
 		[CLK_MIXER0]		= &mixer0_clk.common.hw,
 		[CLK_MIXER1]		= &mixer1_clk.common.hw,
@@ -190,13 +190,13 @@ static struct ccu_reset_map sun50i_a64_de2_resets[] = {
 	[RST_MIXER0]	= { 0x08, BIT(0) },
 	[RST_MIXER1]	= { 0x08, BIT(1) },
 	[RST_WB]	= { 0x08, BIT(2) },
+	[RST_ROT]	= { 0x08, BIT(3) },
 };
 
 static struct ccu_reset_map sun50i_h6_de3_resets[] = {
 	[RST_MIXER0]	= { 0x08, BIT(0) },
 	[RST_MIXER1]	= { 0x08, BIT(1) },
 	[RST_WB]	= { 0x08, BIT(2) },
-	[RST_ROT]	= { 0x08, BIT(3) },
 };
 
 static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
@@ -220,20 +220,20 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = {
 };
 
 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
-	.ccu_clks	= sun8i_h3_de2_clks,
-	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
+	.ccu_clks	= sun50i_a64_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun50i_a64_de2_clks),
 
-	.hw_clks	= &sun8i_h3_de2_hw_clks,
+	.hw_clks	= &sun50i_a64_de2_hw_clks,
 
 	.resets		= sun50i_a64_de2_resets,
 	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
 };
 
 static const struct sunxi_ccu_desc sun50i_h6_de3_clk_desc = {
-	.ccu_clks	= sun50i_h6_de3_clks,
-	.num_ccu_clks	= ARRAY_SIZE(sun50i_h6_de3_clks),
+	.ccu_clks	= sun8i_h3_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sun8i_h3_de2_clks),
 
-	.hw_clks	= &sun50i_h6_de3_hw_clks,
+	.hw_clks	= &sun8i_h3_de2_hw_clks,
 
 	.resets		= sun50i_h6_de3_resets,
 	.num_resets	= ARRAY_SIZE(sun50i_h6_de3_resets),
-- 
2.25.0


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

* [PATCH 2/8] clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions Jernej Skrabec
@ 2020-01-24 23:20 ` Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 3/8] ARM: dts: sunxi: Fix DE2 clocks register range Jernej Skrabec
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

A83T also contains rotation core, but related clocks and reset are
missing. Add them.

With that fixed, H3 and V3s capabilities no longer match (they don't
have rotation core), so create new struct for them.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 31 ++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 08074d935317..800659cf7347 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -50,6 +50,8 @@ static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4,
 		   CLK_SET_RATE_PARENT);
 static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4,
 		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(rot_div_a83_clk, "rot-div", "pll-de", 0x0c, 0x0c, 4,
+		   CLK_SET_RATE_PARENT);
 
 static struct ccu_common *sun50i_a64_de2_clks[] = {
 	&mixer0_clk.common,
@@ -81,6 +83,10 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = {
 	&mixer0_div_a83_clk.common,
 	&mixer1_div_a83_clk.common,
 	&wb_div_a83_clk.common,
+
+	&bus_rot_clk.common,
+	&rot_clk.common,
+	&rot_div_a83_clk.common,
 };
 
 static struct ccu_common *sun8i_h3_de2_clks[] = {
@@ -113,16 +119,19 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = {
 		[CLK_MIXER0]		= &mixer0_clk.common.hw,
 		[CLK_MIXER1]		= &mixer1_clk.common.hw,
 		[CLK_WB]		= &wb_clk.common.hw,
+		[CLK_ROT]		= &rot_clk.common.hw,
 
 		[CLK_BUS_MIXER0]	= &bus_mixer0_clk.common.hw,
 		[CLK_BUS_MIXER1]	= &bus_mixer1_clk.common.hw,
 		[CLK_BUS_WB]		= &bus_wb_clk.common.hw,
+		[CLK_BUS_ROT]		= &bus_rot_clk.common.hw,
 
 		[CLK_MIXER0_DIV]	= &mixer0_div_a83_clk.common.hw,
 		[CLK_MIXER1_DIV]	= &mixer1_div_a83_clk.common.hw,
 		[CLK_WB_DIV]		= &wb_div_a83_clk.common.hw,
+		[CLK_ROT_DIV]		= &rot_div_a83_clk.common.hw,
 	},
-	.num	= CLK_NUMBER_WITHOUT_ROT,
+	.num	= CLK_NUMBER_WITH_ROT,
 };
 
 static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = {
@@ -179,8 +188,18 @@ static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = {
 static struct ccu_reset_map sun8i_a83t_de2_resets[] = {
 	[RST_MIXER0]	= { 0x08, BIT(0) },
 	/*
-	 * For A83T, H3 and R40, mixer1 reset line is shared with wb, so
+	 * A83T and R40 mixer1 reset line is shared with wb, so
 	 * only RST_WB is exported here.
+	 */
+	[RST_WB]	= { 0x08, BIT(2) },
+	[RST_ROT]	= { 0x08, BIT(3) },
+};
+
+static struct ccu_reset_map sun8i_h3_de2_resets[] = {
+	[RST_MIXER0]	= { 0x08, BIT(0) },
+	/*
+	 * H3 mixer1 reset line is shared with wb, so only RST_WB
+	 * is exported here.
 	 * For V3s there's just no mixer1, so it also shares this struct.
 	 */
 	[RST_WB]	= { 0x08, BIT(2) },
@@ -215,8 +234,8 @@ static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = {
 
 	.hw_clks	= &sun8i_h3_de2_hw_clks,
 
-	.resets		= sun8i_a83t_de2_resets,
-	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
+	.resets		= sun8i_h3_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_h3_de2_resets),
 };
 
 static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
@@ -245,8 +264,8 @@ static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = {
 
 	.hw_clks	= &sun8i_v3s_de2_hw_clks,
 
-	.resets		= sun8i_a83t_de2_resets,
-	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
+	.resets		= sun8i_h3_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_h3_de2_resets),
 };
 
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
-- 
2.25.0


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

* [PATCH 3/8] ARM: dts: sunxi: Fix DE2 clocks register range
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 2/8] clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset Jernej Skrabec
@ 2020-01-24 23:20 ` Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 4/8] arm64: dts: allwinner: a64: Fix display clock " Jernej Skrabec
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

As it can be seen from DE2 manual, clock range is 0x10000.

Fix it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm/boot/dts/sun8i-a83t.dtsi  | 2 +-
 arch/arm/boot/dts/sun8i-r40.dtsi   | 2 +-
 arch/arm/boot/dts/sun8i-v3s.dtsi   | 2 +-
 arch/arm/boot/dts/sunxi-h3-h5.dtsi | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 74ac7ee9383c..053d439b01a7 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -314,7 +314,7 @@ soc {
 
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-a83t-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_PLL_DE>;
 			clock-names = "bus",
diff --git a/arch/arm/boot/dts/sun8i-r40.dtsi b/arch/arm/boot/dts/sun8i-r40.dtsi
index 8f09a24b36ec..a9d037667a83 100644
--- a/arch/arm/boot/dts/sun8i-r40.dtsi
+++ b/arch/arm/boot/dts/sun8i-r40.dtsi
@@ -119,7 +119,7 @@ soc {
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-r40-de2-clk",
 				     "allwinner,sun8i-h3-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 81ea50838cd5..e5312869c0d2 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -105,7 +105,7 @@ soc {
 
 		display_clocks: clock@1000000 {
 			compatible = "allwinner,sun8i-v3s-de2-clk";
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
index 5e9c3060aa08..799f32bafd80 100644
--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi
+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi
@@ -114,7 +114,7 @@ soc {
 
 		display_clocks: clock@1000000 {
 			/* compatible is in per SoC .dtsi file */
-			reg = <0x01000000 0x100000>;
+			reg = <0x01000000 0x10000>;
 			clocks = <&ccu CLK_BUS_DE>,
 				 <&ccu CLK_DE>;
 			clock-names = "bus",
-- 
2.25.0


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

* [PATCH 4/8] arm64: dts: allwinner: a64: Fix display clock register range
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (2 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 3/8] ARM: dts: sunxi: Fix DE2 clocks register range Jernej Skrabec
@ 2020-01-24 23:20 ` " Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver Jernej Skrabec
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Register range of display clocks is 0x10000, as it can be seen from
DE2 documentation.

Fix it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 862b47dc9dc9..baa6f08dc108 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -264,7 +264,7 @@ bus@1000000 {
 
 			display_clocks: clock@0 {
 				compatible = "allwinner,sun50i-a64-de2-clk";
-				reg = <0x0 0x100000>;
+				reg = <0x0 0x10000>;
 				clocks = <&ccu CLK_BUS_DE>,
 					 <&ccu CLK_DE>;
 				clock-names = "bus",
-- 
2.25.0


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

* [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (3 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 4/8] arm64: dts: allwinner: a64: Fix display clock " Jernej Skrabec
@ 2020-01-24 23:20 ` Jernej Skrabec
  2020-02-03 15:48   ` Rob Herring
  2020-01-24 23:20 ` [PATCH 6/8] media: sun8i: " Jernej Skrabec
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Some Allwinner SoCs like A83T and A64 contain rotate core which can
rotate and flip images.

Add a binding for it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 .../allwinner,sun8i-a83t-de2-rotate.yaml      | 70 +++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml

diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
new file mode 100644
index 000000000000..75196d11da58
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-de2-rotate.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A83T DE2 Rotate Device Tree Bindings
+
+maintainers:
+  - Jernej Skrabec <jernej.skrabec@siol.net>
+  - Chen-Yu Tsai <wens@csie.org>
+  - Maxime Ripard <mripard@kernel.org>
+
+description: |-
+  The Allwinner A83T and A64 have a rotation core used for
+  rotating and flipping images.
+
+properties:
+  compatible:
+    oneOf:
+      - const: allwinner,sun8i-a83t-de2-rotate
+      - items:
+        - const: allwinner,sun50i-a64-de2-rotate
+        - const: allwinner,sun8i-a83t-de2-rotate
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Rotate interface clock
+      - description: Rotate module clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun8i-de2.h>
+    #include <dt-bindings/reset/sun8i-de2.h>
+
+    rotate: rotate@1020000 {
+        compatible = "allwinner,sun8i-a83t-de2-rotate";
+        reg = <0x1020000 0x10000>;
+        interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&display_clocks CLK_BUS_ROT>,
+                 <&display_clocks CLK_ROT>;
+        clock-names = "bus",
+                      "mod";
+        resets = <&display_clocks RST_ROT>;
+    };
+
+...
-- 
2.25.0


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

* [PATCH 6/8] media: sun8i: Add Allwinner A83T Rotate driver
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (4 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver Jernej Skrabec
@ 2020-01-24 23:20 ` " Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 7/8] ARM: dts: sun8i: a83t: Add device node for rotation core Jernej Skrabec
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Allwinner A83T contains rotation core which can rotate and flip images.

Add a driver for it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 MAINTAINERS                                   |   8 +
 drivers/media/platform/Kconfig                |  12 +
 drivers/media/platform/sunxi/Makefile         |   1 +
 .../platform/sunxi/sun8i-rotate/Makefile      |   2 +
 .../sunxi/sun8i-rotate/sun8i-formats.c        | 273 ++++++
 .../sunxi/sun8i-rotate/sun8i-formats.h        |  25 +
 .../sunxi/sun8i-rotate/sun8i-rotate.c         | 924 ++++++++++++++++++
 .../sunxi/sun8i-rotate/sun8i-rotate.h         | 135 +++
 8 files changed, 1380 insertions(+)
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/Makefile
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c
 create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 98cf0b034f61..6aab509b8a2c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14322,6 +14322,14 @@ F:	include/net/rose.h
 F:	include/uapi/linux/rose.h
 F:	net/rose/
 
+ROTATION DRIVER FOR ALLWINNER A83T
+M:	Jernej Skrabec <jernej.skrabec@siol.net>
+L:	linux-media@vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+S:	Maintained
+F:	drivers/media/platform/sunxi/sun8i-rot/
+F:	Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-rotate.yaml
+
 RTL2830 MEDIA DRIVER
 M:	Antti Palosaari <crope@iki.fi>
 L:	linux-media@vger.kernel.org
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 995f4c67f764..fc2c8a009b2f 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -507,6 +507,18 @@ config VIDEO_SUN8I_DEINTERLACE
 	   capability found on some SoCs, like H3.
 	   To compile this driver as a module choose m here.
 
+config VIDEO_SUN8I_ROTATE
+	tristate "Allwinner DE2 rotation driver"
+	depends on VIDEO_DEV && VIDEO_V4L2
+	depends on ARCH_SUNXI || COMPILE_TEST
+	depends on COMMON_CLK && OF
+	depends on PM
+	select VIDEOBUF2_DMA_CONTIG
+	select V4L2_MEM2MEM_DEV
+	help
+	   Support for the Allwinner DE2 rotation unit.
+	   To compile this driver as a module choose m here.
+
 endif # V4L_MEM2MEM_DRIVERS
 
 # TI VIDEO PORT Helper Modules
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
index 3878cb4efdc2..ff0993f70dc3 100644
--- a/drivers/media/platform/sunxi/Makefile
+++ b/drivers/media/platform/sunxi/Makefile
@@ -1,3 +1,4 @@
 obj-y		+= sun4i-csi/
 obj-y		+= sun6i-csi/
 obj-y		+= sun8i-di/
+obj-y		+= sun8i-rotate/
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/Makefile b/drivers/media/platform/sunxi/sun8i-rotate/Makefile
new file mode 100644
index 000000000000..2f815f4af126
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-rotate/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_SUN8I_ROTATE) += sun8i-rotate.o sun8i-formats.o
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c
new file mode 100644
index 000000000000..cebfbc5def38
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
+
+#include "sun8i-formats.h"
+#include "sun8i-rotate.h"
+
+/*
+ * Formats not included in array:
+ * ROTATE_FORMAT_BGR565
+ * ROTATE_FORMAT_VYUV
+ */
+
+static const struct rotate_format rotate_formats[] = {
+	{
+		.fourcc = V4L2_PIX_FMT_ARGB32,
+		.hw_format = ROTATE_FORMAT_ARGB32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_ABGR32,
+		.hw_format = ROTATE_FORMAT_ABGR32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGBA32,
+		.hw_format = ROTATE_FORMAT_RGBA32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGRA32,
+		.hw_format = ROTATE_FORMAT_BGRA32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_XRGB32,
+		.hw_format = ROTATE_FORMAT_XRGB32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_XBGR32,
+		.hw_format = ROTATE_FORMAT_XBGR32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGB32,
+		.hw_format = ROTATE_FORMAT_RGBX32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR32,
+		.hw_format = ROTATE_FORMAT_BGRX32,
+		.planes = 1,
+		.bpp = { 4, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGB24,
+		.hw_format = ROTATE_FORMAT_RGB24,
+		.planes = 1,
+		.bpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGR24,
+		.hw_format = ROTATE_FORMAT_BGR24,
+		.planes = 1,
+		.bpp = { 3, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGB565,
+		.hw_format = ROTATE_FORMAT_RGB565,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_ARGB444,
+		.hw_format = ROTATE_FORMAT_ARGB4444,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_ABGR444,
+		.hw_format = ROTATE_FORMAT_ABGR4444,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGBA444,
+		.hw_format = ROTATE_FORMAT_RGBA4444,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGRA444,
+		.hw_format = ROTATE_FORMAT_BGRA4444,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_ARGB555,
+		.hw_format = ROTATE_FORMAT_ARGB1555,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_ABGR555,
+		.hw_format = ROTATE_FORMAT_ABGR1555,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_RGBA555,
+		.hw_format = ROTATE_FORMAT_RGBA5551,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_BGRA555,
+		.hw_format = ROTATE_FORMAT_BGRA5551,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 1,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_OUTPUT
+	}, {
+		.fourcc = V4L2_PIX_FMT_YVYU,
+		.hw_format = ROTATE_FORMAT_YVYU,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_UYVY,
+		.hw_format = ROTATE_FORMAT_UYVY,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_YUYV,
+		.hw_format = ROTATE_FORMAT_YUYV,
+		.planes = 1,
+		.bpp = { 2, 0, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV61,
+		.hw_format = ROTATE_FORMAT_NV61,
+		.planes = 2,
+		.bpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV16,
+		.hw_format = ROTATE_FORMAT_NV16,
+		.planes = 2,
+		.bpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_YUV422P,
+		.hw_format = ROTATE_FORMAT_YUV422P,
+		.planes = 3,
+		.bpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 1,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV21,
+		.hw_format = ROTATE_FORMAT_NV21,
+		.planes = 2,
+		.bpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_NV12,
+		.hw_format = ROTATE_FORMAT_NV12,
+		.planes = 2,
+		.bpp = { 1, 2, 0 },
+		.hsub = 2,
+		.vsub = 2,
+		.flags = ROTATE_FLAG_YUV
+	}, {
+		.fourcc = V4L2_PIX_FMT_YUV420,
+		.hw_format = ROTATE_FORMAT_YUV420P,
+		.planes = 3,
+		.bpp = { 1, 1, 1 },
+		.hsub = 2,
+		.vsub = 2,
+		.flags = ROTATE_FLAG_YUV | ROTATE_FLAG_OUTPUT
+	},
+};
+
+const struct rotate_format *rotate_find_format(u32 pixelformat)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(rotate_formats); i++)
+		if (rotate_formats[i].fourcc == pixelformat)
+			return &rotate_formats[i];
+
+	return NULL;
+}
+
+int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst)
+{
+	int i, index;
+
+	index = 0;
+
+	for (i = 0; i < ARRAY_SIZE(rotate_formats); i++) {
+		/* not all formats can be used for capture buffers */
+		if (dst && !(rotate_formats[i].flags & ROTATE_FLAG_OUTPUT))
+			continue;
+
+		if (index == f->index) {
+			f->pixelformat = rotate_formats[i].fourcc;
+
+			return 0;
+		}
+
+		index++;
+	}
+
+	return -EINVAL;
+}
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h
new file mode 100644
index 000000000000..697cd5fadd5f
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net> */
+
+#ifndef _SUN8I_FORMATS_H_
+#define _SUN8I_FORMATS_H_
+
+#include <linux/videodev2.h>
+
+#define ROTATE_FLAG_YUV    BIT(0)
+#define ROTATE_FLAG_OUTPUT BIT(1)
+
+struct rotate_format {
+	u32 fourcc;
+	u32 hw_format;
+	int planes;
+	int bpp[3];
+	int hsub;
+	int vsub;
+	unsigned int flags;
+};
+
+const struct rotate_format *rotate_find_format(u32 pixelformat);
+int rotate_enum_fmt(struct v4l2_fmtdesc *f, bool dst);
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c
new file mode 100644
index 000000000000..63bfa349d2b8
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c
@@ -0,0 +1,924 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner sun8i DE2 rotation driver
+ *
+ * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "sun8i-formats.h"
+#include "sun8i-rotate.h"
+
+static inline u32 rotate_read(struct rotate_dev *dev, u32 reg)
+{
+	return readl(dev->base + reg);
+}
+
+static inline void rotate_write(struct rotate_dev *dev, u32 reg, u32 value)
+{
+	writel(value, dev->base + reg);
+}
+
+static inline void rotate_set_bits(struct rotate_dev *dev, u32 reg, u32 bits)
+{
+	writel(readl(dev->base + reg) | bits, dev->base + reg);
+}
+
+static void rotate_calc_addr_pitch(dma_addr_t buffer,
+				   u32 bytesperline, u32 height,
+				   const struct rotate_format *fmt,
+				   dma_addr_t *addr, u32 *pitch)
+{
+	u32 size;
+	int i;
+
+	for (i = 0; i < fmt->planes; i++) {
+		pitch[i] = bytesperline;
+		addr[i] = buffer;
+		if (i > 0)
+			pitch[i] /= fmt->hsub / fmt->bpp[i];
+		size = pitch[i] * height;
+		if (i > 0)
+			size /= fmt->vsub;
+		buffer += size;
+	}
+}
+
+static void rotate_device_run(void *priv)
+{
+	struct rotate_ctx *ctx = priv;
+	struct rotate_dev *dev = ctx->dev;
+	struct vb2_v4l2_buffer *src, *dst;
+	const struct rotate_format *fmt;
+	dma_addr_t addr[3];
+	u32 val, pitch[3];
+
+	src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+	dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+	v4l2_m2m_buf_copy_metadata(src, dst, true);
+
+	val = ROTATE_GLB_CTL_MODE(ROTATE_MODE_COPY_ROTATE);
+	if (ctx->hflip)
+		val |= ROTATE_GLB_CTL_HFLIP;
+	if (ctx->vflip)
+		val |= ROTATE_GLB_CTL_VFLIP;
+	val |= ROTATE_GLB_CTL_ROTATION(ctx->rotate / 90);
+	if (ctx->rotate != 90 && ctx->rotate != 270)
+		val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_64);
+	else
+		val |= ROTATE_GLB_CTL_BURST_LEN(ROTATE_BURST_8);
+	rotate_write(dev, ROTATE_GLB_CTL, val);
+
+	fmt = rotate_find_format(ctx->src_fmt.pixelformat);
+	if (!fmt)
+		return;
+
+	rotate_write(dev, ROTATE_IN_FMT, ROTATE_IN_FMT_FORMAT(fmt->hw_format));
+
+	rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0),
+			       ctx->src_fmt.bytesperline, ctx->src_fmt.height,
+			       fmt, addr, pitch);
+
+	rotate_write(dev, ROTATE_IN_SIZE,
+		     ROTATE_SIZE(ctx->src_fmt.width, ctx->src_fmt.height));
+
+	rotate_write(dev, ROTATE_IN_PITCH0, pitch[0]);
+	rotate_write(dev, ROTATE_IN_PITCH1, pitch[1]);
+	rotate_write(dev, ROTATE_IN_PITCH2, pitch[2]);
+
+	rotate_write(dev, ROTATE_IN_ADDRL0, addr[0]);
+	rotate_write(dev, ROTATE_IN_ADDRL1, addr[1]);
+	rotate_write(dev, ROTATE_IN_ADDRL2, addr[2]);
+
+	rotate_write(dev, ROTATE_IN_ADDRH0, 0);
+	rotate_write(dev, ROTATE_IN_ADDRH1, 0);
+	rotate_write(dev, ROTATE_IN_ADDRH2, 0);
+
+	fmt = rotate_find_format(ctx->dst_fmt.pixelformat);
+	if (!fmt)
+		return;
+
+	rotate_calc_addr_pitch(vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0),
+			       ctx->dst_fmt.bytesperline, ctx->dst_fmt.height,
+			       fmt, addr, pitch);
+
+	rotate_write(dev, ROTATE_OUT_SIZE,
+		     ROTATE_SIZE(ctx->dst_fmt.width, ctx->dst_fmt.height));
+
+	rotate_write(dev, ROTATE_OUT_PITCH0, pitch[0]);
+	rotate_write(dev, ROTATE_OUT_PITCH1, pitch[1]);
+	rotate_write(dev, ROTATE_OUT_PITCH2, pitch[2]);
+
+	rotate_write(dev, ROTATE_OUT_ADDRL0, addr[0]);
+	rotate_write(dev, ROTATE_OUT_ADDRL1, addr[1]);
+	rotate_write(dev, ROTATE_OUT_ADDRL2, addr[2]);
+
+	rotate_write(dev, ROTATE_OUT_ADDRH0, 0);
+	rotate_write(dev, ROTATE_OUT_ADDRH1, 0);
+	rotate_write(dev, ROTATE_OUT_ADDRH2, 0);
+
+	rotate_set_bits(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ_EN);
+	rotate_set_bits(dev, ROTATE_GLB_CTL, ROTATE_GLB_CTL_START);
+}
+
+static irqreturn_t rotate_irq(int irq, void *data)
+{
+	struct vb2_v4l2_buffer *buffer;
+	struct rotate_dev *dev = data;
+	struct rotate_ctx *ctx;
+	unsigned int val;
+
+	ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+	if (!ctx) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Instance released before the end of transaction\n");
+		return IRQ_NONE;
+	}
+
+	val = rotate_read(dev, ROTATE_INT);
+	if (!(val & ROTATE_INT_FINISH_IRQ))
+		return IRQ_NONE;
+
+	/* clear flag and disable irq */
+	rotate_write(dev, ROTATE_INT, ROTATE_INT_FINISH_IRQ);
+
+	buffer = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE);
+
+	buffer = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+	v4l2_m2m_buf_done(buffer, VB2_BUF_STATE_DONE);
+
+	v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+
+	return IRQ_HANDLED;
+}
+
+static inline struct rotate_ctx *rotate_file2ctx(struct file *file)
+{
+	return container_of(file->private_data, struct rotate_ctx, fh);
+}
+
+static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt)
+{
+	unsigned int height, width, alignment, sizeimage, size, bpl;
+	const struct rotate_format *fmt;
+	int i;
+
+	fmt = rotate_find_format(pix_fmt->pixelformat);
+	if (!fmt)
+		return;
+
+	width = ALIGN(pix_fmt->width, fmt->hsub);
+	height = ALIGN(pix_fmt->height, fmt->vsub);
+
+	/* all pitches have to be 16 byte aligned */
+	alignment = 16;
+	if (fmt->planes > 1)
+		alignment *= fmt->hsub / fmt->bpp[1];
+	bpl = ALIGN(width * fmt->bpp[0], alignment);
+
+	sizeimage = 0;
+	for (i = 0; i < fmt->planes; i++) {
+		size = bpl * height;
+		if (i > 0) {
+			size *= fmt->bpp[i];
+			size /= fmt->hsub;
+			size /= fmt->vsub;
+		}
+		sizeimage += size;
+	}
+
+	pix_fmt->width = width;
+	pix_fmt->height = height;
+	pix_fmt->bytesperline = bpl;
+	pix_fmt->sizeimage = sizeimage;
+}
+
+static int rotate_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strscpy(cap->driver, ROTATE_NAME, sizeof(cap->driver));
+	strscpy(cap->card, ROTATE_NAME, sizeof(cap->card));
+	snprintf(cap->bus_info, sizeof(cap->bus_info),
+		 "platform:%s", ROTATE_NAME);
+
+	return 0;
+}
+
+static int rotate_enum_fmt_vid_cap(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return rotate_enum_fmt(f, true);
+}
+
+static int rotate_enum_fmt_vid_out(struct file *file, void *priv,
+				   struct v4l2_fmtdesc *f)
+{
+	return rotate_enum_fmt(f, false);
+}
+
+static int rotate_enum_framesizes(struct file *file, void *priv,
+				  struct v4l2_frmsizeenum *fsize)
+{
+	const struct rotate_format *fmt;
+
+	if (fsize->index != 0)
+		return -EINVAL;
+
+	fmt = rotate_find_format(fsize->pixel_format);
+	if (!fmt)
+		return -EINVAL;
+
+	fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+	fsize->stepwise.min_width = ROTATE_MIN_WIDTH;
+	fsize->stepwise.min_height = ROTATE_MIN_HEIGHT;
+	fsize->stepwise.max_width = ROTATE_MAX_WIDTH;
+	fsize->stepwise.max_height = ROTATE_MAX_HEIGHT;
+	fsize->stepwise.step_width = fmt->hsub;
+	fsize->stepwise.step_height = fmt->vsub;
+
+	return 0;
+}
+
+static int rotate_set_cap_format(struct rotate_ctx *ctx,
+				 struct v4l2_pix_format *f,
+				 u32 rotate)
+{
+	const struct rotate_format *fmt;
+
+	fmt = rotate_find_format(ctx->src_fmt.pixelformat);
+	if (!fmt)
+		return -EINVAL;
+
+	if (fmt->flags & ROTATE_FLAG_YUV)
+		f->pixelformat = V4L2_PIX_FMT_YUV420;
+	else
+		f->pixelformat = ctx->src_fmt.pixelformat;
+
+	f->field = V4L2_FIELD_NONE;
+
+	if (rotate == 90 || rotate == 270) {
+		f->width = ctx->src_fmt.height;
+		f->height = ctx->src_fmt.width;
+	} else {
+		f->width = ctx->src_fmt.width;
+		f->height = ctx->src_fmt.height;
+	}
+
+	rotate_prepare_format(f);
+
+	return 0;
+}
+
+static int rotate_g_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+	f->fmt.pix = ctx->dst_fmt;
+
+	return 0;
+}
+
+static int rotate_g_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+	f->fmt.pix = ctx->src_fmt;
+
+	return 0;
+}
+
+static int rotate_try_fmt_vid_cap(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	struct rotate_ctx *ctx = rotate_file2ctx(file);
+
+	return rotate_set_cap_format(ctx, &f->fmt.pix, ctx->rotate);
+}
+
+static int rotate_try_fmt_vid_out(struct file *file, void *priv,
+				  struct v4l2_format *f)
+{
+	if (!rotate_find_format(f->fmt.pix.pixelformat))
+		f->fmt.pix.pixelformat = V4L2_PIX_FMT_ARGB32;
+
+	if (f->fmt.pix.width < ROTATE_MIN_WIDTH)
+		f->fmt.pix.width = ROTATE_MIN_WIDTH;
+	if (f->fmt.pix.height < ROTATE_MIN_HEIGHT)
+		f->fmt.pix.height = ROTATE_MIN_HEIGHT;
+
+	if (f->fmt.pix.width > ROTATE_MAX_WIDTH)
+		f->fmt.pix.width = ROTATE_MAX_WIDTH;
+	if (f->fmt.pix.height > ROTATE_MAX_HEIGHT)
+		f->fmt.pix.height = ROTATE_MAX_HEIGHT;
+
+	f->fmt.pix.field = V4L2_FIELD_NONE;
+
+	rotate_prepare_format(&f->fmt.pix);
+
+	return 0;
+}
+
+static int rotate_s_fmt_vid_cap(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rotate_ctx *ctx = rotate_file2ctx(file);
+	struct vb2_queue *vq;
+	int ret;
+
+	ret = rotate_try_fmt_vid_cap(file, priv, f);
+	if (ret)
+		return ret;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	ctx->dst_fmt = f->fmt.pix;
+
+	return 0;
+}
+
+static int rotate_s_fmt_vid_out(struct file *file, void *priv,
+				struct v4l2_format *f)
+{
+	struct rotate_ctx *ctx = rotate_file2ctx(file);
+	struct vb2_queue *vq;
+	int ret;
+
+	ret = rotate_try_fmt_vid_out(file, priv, f);
+	if (ret)
+		return ret;
+
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	/*
+	 * Capture queue has to be also checked, because format and size
+	 * depends on output format and size.
+	 */
+	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+	if (vb2_is_busy(vq))
+		return -EBUSY;
+
+	ctx->src_fmt = f->fmt.pix;
+
+	/* Propagate colorspace information to capture. */
+	ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
+	ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
+	ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+	ctx->dst_fmt.quantization = f->fmt.pix.quantization;
+
+	return rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate);
+}
+
+static const struct v4l2_ioctl_ops rotate_ioctl_ops = {
+	.vidioc_querycap		= rotate_querycap,
+
+	.vidioc_enum_framesizes		= rotate_enum_framesizes,
+
+	.vidioc_enum_fmt_vid_cap	= rotate_enum_fmt_vid_cap,
+	.vidioc_g_fmt_vid_cap		= rotate_g_fmt_vid_cap,
+	.vidioc_try_fmt_vid_cap		= rotate_try_fmt_vid_cap,
+	.vidioc_s_fmt_vid_cap		= rotate_s_fmt_vid_cap,
+
+	.vidioc_enum_fmt_vid_out	= rotate_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out		= rotate_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out		= rotate_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out		= rotate_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_log_status		= v4l2_ctrl_log_status,
+	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
+	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
+};
+
+static int rotate_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+			      unsigned int *nplanes, unsigned int sizes[],
+			      struct device *alloc_devs[])
+{
+	struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+	struct v4l2_pix_format *pix_fmt;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type))
+		pix_fmt = &ctx->src_fmt;
+	else
+		pix_fmt = &ctx->dst_fmt;
+
+	if (*nplanes) {
+		if (sizes[0] < pix_fmt->sizeimage)
+			return -EINVAL;
+	} else {
+		sizes[0] = pix_fmt->sizeimage;
+		*nplanes = 1;
+	}
+
+	return 0;
+}
+
+static int rotate_buf_prepare(struct vb2_buffer *vb)
+{
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+	struct v4l2_pix_format *pix_fmt;
+
+	if (V4L2_TYPE_IS_OUTPUT(vq->type))
+		pix_fmt = &ctx->src_fmt;
+	else
+		pix_fmt = &ctx->dst_fmt;
+
+	if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
+		return -EINVAL;
+
+	vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+
+	return 0;
+}
+
+static void rotate_buf_queue(struct vb2_buffer *vb)
+{
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct rotate_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void rotate_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+	struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+	struct vb2_v4l2_buffer *vbuf;
+
+	do {
+		if (V4L2_TYPE_IS_OUTPUT(vq->type))
+			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+		else
+			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+		if (vbuf)
+			v4l2_m2m_buf_done(vbuf, state);
+	} while (vbuf);
+}
+
+static int rotate_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+		struct device *dev = ctx->dev->dev;
+		int ret;
+
+		ret = pm_runtime_get_sync(dev);
+		if (ret < 0) {
+			dev_err(dev, "Failed to enable module\n");
+
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void rotate_stop_streaming(struct vb2_queue *vq)
+{
+	if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+		struct rotate_ctx *ctx = vb2_get_drv_priv(vq);
+
+		pm_runtime_put(ctx->dev->dev);
+	}
+
+	rotate_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops rotate_qops = {
+	.queue_setup		= rotate_queue_setup,
+	.buf_prepare		= rotate_buf_prepare,
+	.buf_queue		= rotate_buf_queue,
+	.start_streaming	= rotate_start_streaming,
+	.stop_streaming		= rotate_stop_streaming,
+	.wait_prepare		= vb2_ops_wait_prepare,
+	.wait_finish		= vb2_ops_wait_finish,
+};
+
+static int rotate_queue_init(void *priv, struct vb2_queue *src_vq,
+			     struct vb2_queue *dst_vq)
+{
+	struct rotate_ctx *ctx = priv;
+	int ret;
+
+	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	src_vq->drv_priv = ctx;
+	src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	src_vq->min_buffers_needed = 1;
+	src_vq->ops = &rotate_qops;
+	src_vq->mem_ops = &vb2_dma_contig_memops;
+	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	src_vq->lock = &ctx->dev->dev_mutex;
+	src_vq->dev = ctx->dev->dev;
+
+	ret = vb2_queue_init(src_vq);
+	if (ret)
+		return ret;
+
+	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+	dst_vq->drv_priv = ctx;
+	dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+	dst_vq->min_buffers_needed = 2;
+	dst_vq->ops = &rotate_qops;
+	dst_vq->mem_ops = &vb2_dma_contig_memops;
+	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+	dst_vq->lock = &ctx->dev->dev_mutex;
+	dst_vq->dev = ctx->dev->dev;
+
+	ret = vb2_queue_init(dst_vq);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int rotate_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct rotate_ctx *ctx = container_of(ctrl->handler,
+					      struct rotate_ctx,
+					      ctrl_handler);
+	struct v4l2_pix_format fmt;
+
+	switch (ctrl->id) {
+	case V4L2_CID_HFLIP:
+		ctx->hflip = ctrl->val;
+		break;
+	case V4L2_CID_VFLIP:
+		ctx->vflip = ctrl->val;
+		break;
+	case V4L2_CID_ROTATE:
+		rotate_set_cap_format(ctx, &fmt, ctrl->val);
+
+		/* Check if capture format needs to be changed */
+		if (fmt.width != ctx->dst_fmt.width ||
+		    fmt.height != ctx->dst_fmt.height ||
+		    fmt.bytesperline != ctx->dst_fmt.bytesperline ||
+		    fmt.sizeimage != ctx->dst_fmt.sizeimage) {
+			struct vb2_queue *vq;
+
+			vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+					     V4L2_BUF_TYPE_VIDEO_CAPTURE);
+			if (vb2_is_busy(vq))
+				return -EBUSY;
+
+			rotate_set_cap_format(ctx, &ctx->dst_fmt, ctrl->val);
+		}
+
+		ctx->rotate = ctrl->val;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ctrl_ops rotate_ctrl_ops = {
+	.s_ctrl = rotate_s_ctrl,
+};
+
+static int rotate_setup_ctrls(struct rotate_ctx *ctx)
+{
+	v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+			  V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+			  V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+	v4l2_ctrl_new_std(&ctx->ctrl_handler, &rotate_ctrl_ops,
+			  V4L2_CID_ROTATE, 0, 270, 90, 0);
+
+	if (ctx->ctrl_handler.error) {
+		int err = ctx->ctrl_handler.error;
+
+		v4l2_err(&ctx->dev->v4l2_dev, "control setup failed!\n");
+		v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+
+		return err;
+	}
+
+	return v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+}
+
+static int rotate_open(struct file *file)
+{
+	struct rotate_dev *dev = video_drvdata(file);
+	struct rotate_ctx *ctx = NULL;
+	int ret;
+
+	if (mutex_lock_interruptible(&dev->dev_mutex))
+		return -ERESTARTSYS;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		mutex_unlock(&dev->dev_mutex);
+		return -ENOMEM;
+	}
+
+	/* default output format */
+	ctx->src_fmt.pixelformat = V4L2_PIX_FMT_ARGB32;
+	ctx->src_fmt.field = V4L2_FIELD_NONE;
+	ctx->src_fmt.width = 640;
+	ctx->src_fmt.height = 480;
+	rotate_prepare_format(&ctx->src_fmt);
+
+	/* default capture format */
+	rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate);
+
+	v4l2_fh_init(&ctx->fh, video_devdata(file));
+	file->private_data = &ctx->fh;
+	ctx->dev = dev;
+
+	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+					    &rotate_queue_init);
+	if (IS_ERR(ctx->fh.m2m_ctx)) {
+		ret = PTR_ERR(ctx->fh.m2m_ctx);
+		goto err_free;
+	}
+
+	v4l2_fh_add(&ctx->fh);
+
+	ret = rotate_setup_ctrls(ctx);
+	if (ret)
+		goto err_free;
+
+	ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+
+err_free:
+	kfree(ctx);
+	mutex_unlock(&dev->dev_mutex);
+
+	return ret;
+}
+
+static int rotate_release(struct file *file)
+{
+	struct rotate_dev *dev = video_drvdata(file);
+	struct rotate_ctx *ctx = container_of(file->private_data,
+						   struct rotate_ctx, fh);
+
+	mutex_lock(&dev->dev_mutex);
+
+	v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+	v4l2_fh_del(&ctx->fh);
+	v4l2_fh_exit(&ctx->fh);
+	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+	kfree(ctx);
+
+	mutex_unlock(&dev->dev_mutex);
+
+	return 0;
+}
+
+static const struct v4l2_file_operations rotate_fops = {
+	.owner		= THIS_MODULE,
+	.open		= rotate_open,
+	.release	= rotate_release,
+	.poll		= v4l2_m2m_fop_poll,
+	.unlocked_ioctl	= video_ioctl2,
+	.mmap		= v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device rotate_video_device = {
+	.name		= ROTATE_NAME,
+	.vfl_dir	= VFL_DIR_M2M,
+	.fops		= &rotate_fops,
+	.ioctl_ops	= &rotate_ioctl_ops,
+	.minor		= -1,
+	.release	= video_device_release_empty,
+	.device_caps	= V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops rotate_m2m_ops = {
+	.device_run	= rotate_device_run,
+};
+
+static int rotate_probe(struct platform_device *pdev)
+{
+	struct rotate_dev *dev;
+	struct video_device *vfd;
+	int irq, ret;
+
+	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->vfd = rotate_video_device;
+	dev->dev = &pdev->dev;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_err(dev->dev, "Failed to get IRQ\n");
+
+		return irq;
+	}
+
+	ret = devm_request_irq(dev->dev, irq, rotate_irq,
+			       0, dev_name(dev->dev), dev);
+	if (ret) {
+		dev_err(dev->dev, "Failed to request IRQ\n");
+
+		return ret;
+	}
+
+	dev->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(dev->base))
+		return PTR_ERR(dev->base);
+
+	dev->bus_clk = devm_clk_get(dev->dev, "bus");
+	if (IS_ERR(dev->bus_clk)) {
+		dev_err(dev->dev, "Failed to get bus clock\n");
+
+		return PTR_ERR(dev->bus_clk);
+	}
+
+	dev->mod_clk = devm_clk_get(dev->dev, "mod");
+	if (IS_ERR(dev->mod_clk)) {
+		dev_err(dev->dev, "Failed to get mod clock\n");
+
+		return PTR_ERR(dev->mod_clk);
+	}
+
+	dev->rstc = devm_reset_control_get(dev->dev, NULL);
+	if (IS_ERR(dev->rstc)) {
+		dev_err(dev->dev, "Failed to get reset control\n");
+
+		return PTR_ERR(dev->rstc);
+	}
+
+	mutex_init(&dev->dev_mutex);
+
+	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+	if (ret) {
+		dev_err(dev->dev, "Failed to register V4L2 device\n");
+
+		return ret;
+	}
+
+	vfd = &dev->vfd;
+	vfd->lock = &dev->dev_mutex;
+	vfd->v4l2_dev = &dev->v4l2_dev;
+
+	snprintf(vfd->name, sizeof(vfd->name), "%s",
+		 rotate_video_device.name);
+	video_set_drvdata(vfd, dev);
+
+	ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+	if (ret) {
+		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+
+		goto err_v4l2;
+	}
+
+	v4l2_info(&dev->v4l2_dev,
+		  "Device registered as /dev/video%d\n", vfd->num);
+
+	dev->m2m_dev = v4l2_m2m_init(&rotate_m2m_ops);
+	if (IS_ERR(dev->m2m_dev)) {
+		v4l2_err(&dev->v4l2_dev,
+			 "Failed to initialize V4L2 M2M device\n");
+		ret = PTR_ERR(dev->m2m_dev);
+
+		goto err_video;
+	}
+
+	platform_set_drvdata(pdev, dev);
+
+	pm_runtime_enable(dev->dev);
+
+	return 0;
+
+err_video:
+	video_unregister_device(&dev->vfd);
+err_v4l2:
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	return ret;
+}
+
+static int rotate_remove(struct platform_device *pdev)
+{
+	struct rotate_dev *dev = platform_get_drvdata(pdev);
+
+	v4l2_m2m_release(dev->m2m_dev);
+	video_unregister_device(&dev->vfd);
+	v4l2_device_unregister(&dev->v4l2_dev);
+
+	pm_runtime_force_suspend(&pdev->dev);
+
+	return 0;
+}
+
+static int rotate_runtime_resume(struct device *device)
+{
+	struct rotate_dev *dev = dev_get_drvdata(device);
+	int ret;
+
+	ret = clk_prepare_enable(dev->bus_clk);
+	if (ret) {
+		dev_err(dev->dev, "Failed to enable bus clock\n");
+
+		return ret;
+	}
+
+	ret = clk_prepare_enable(dev->mod_clk);
+	if (ret) {
+		dev_err(dev->dev, "Failed to enable mod clock\n");
+
+		goto err_bus_clk;
+	}
+
+	ret = reset_control_deassert(dev->rstc);
+	if (ret) {
+		dev_err(dev->dev, "Failed to apply reset\n");
+
+		goto err_mod_clk;
+	}
+
+	return 0;
+
+err_mod_clk:
+	clk_disable_unprepare(dev->mod_clk);
+err_bus_clk:
+	clk_disable_unprepare(dev->bus_clk);
+
+	return ret;
+}
+
+static int rotate_runtime_suspend(struct device *device)
+{
+	struct rotate_dev *dev = dev_get_drvdata(device);
+
+	reset_control_assert(dev->rstc);
+
+	clk_disable_unprepare(dev->mod_clk);
+	clk_disable_unprepare(dev->bus_clk);
+
+	return 0;
+}
+
+static const struct of_device_id rotate_dt_match[] = {
+	{ .compatible = "allwinner,sun8i-a83t-de2-rotate" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rotate_dt_match);
+
+static const struct dev_pm_ops rotate_pm_ops = {
+	.runtime_resume		= rotate_runtime_resume,
+	.runtime_suspend	= rotate_runtime_suspend,
+};
+
+static struct platform_driver rotate_driver = {
+	.probe		= rotate_probe,
+	.remove		= rotate_remove,
+	.driver		= {
+		.name		= ROTATE_NAME,
+		.of_match_table	= rotate_dt_match,
+		.pm		= &rotate_pm_ops,
+	},
+};
+module_platform_driver(rotate_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner DE2 rotate driver");
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h
new file mode 100644
index 000000000000..32ade97ba572
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allwinner DE2 rotation driver
+ *
+ * Copyright (C) 2020 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN8I_ROTATE_H_
+#define _SUN8I_ROTATE_H_
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <linux/platform_device.h>
+
+#define ROTATE_NAME		"sun8i-rotate"
+
+#define ROTATE_GLB_CTL			0x00
+#define ROTATE_GLB_CTL_START			BIT(31)
+#define ROTATE_GLB_CTL_RESET			BIT(30)
+#define ROTATE_GLB_CTL_BURST_LEN(x)		((x) << 16)
+#define ROTATE_GLB_CTL_HFLIP			BIT(7)
+#define ROTATE_GLB_CTL_VFLIP			BIT(6)
+#define ROTATE_GLB_CTL_ROTATION(x)		((x) << 4)
+#define ROTATE_GLB_CTL_MODE(x)			((x) << 0)
+
+#define ROTATE_INT			0x04
+#define ROTATE_INT_FINISH_IRQ_EN		BIT(16)
+#define ROTATE_INT_FINISH_IRQ			BIT(0)
+
+#define ROTATE_IN_FMT			0x20
+#define ROTATE_IN_FMT_FORMAT(x)			((x) << 0)
+
+#define ROTATE_IN_SIZE			0x24
+#define ROTATE_IN_PITCH0		0x30
+#define ROTATE_IN_PITCH1		0x34
+#define ROTATE_IN_PITCH2		0x38
+#define ROTATE_IN_ADDRL0		0x40
+#define ROTATE_IN_ADDRH0		0x44
+#define ROTATE_IN_ADDRL1		0x48
+#define ROTATE_IN_ADDRH1		0x4c
+#define ROTATE_IN_ADDRL2		0x50
+#define ROTATE_IN_ADDRH2		0x54
+#define ROTATE_OUT_SIZE			0x84
+#define ROTATE_OUT_PITCH0		0x90
+#define ROTATE_OUT_PITCH1		0x94
+#define ROTATE_OUT_PITCH2		0x98
+#define ROTATE_OUT_ADDRL0		0xA0
+#define ROTATE_OUT_ADDRH0		0xA4
+#define ROTATE_OUT_ADDRL1		0xA8
+#define ROTATE_OUT_ADDRH1		0xAC
+#define ROTATE_OUT_ADDRL2		0xB0
+#define ROTATE_OUT_ADDRH2		0xB4
+
+#define ROTATE_BURST_8			0x07
+#define ROTATE_BURST_16			0x0f
+#define ROTATE_BURST_32			0x1f
+#define ROTATE_BURST_64			0x3f
+
+#define ROTATE_MODE_COPY_ROTATE		0x01
+
+#define ROTATE_FORMAT_ARGB32		0x00
+#define ROTATE_FORMAT_ABGR32		0x01
+#define ROTATE_FORMAT_RGBA32		0x02
+#define ROTATE_FORMAT_BGRA32		0x03
+#define ROTATE_FORMAT_XRGB32		0x04
+#define ROTATE_FORMAT_XBGR32		0x05
+#define ROTATE_FORMAT_RGBX32		0x06
+#define ROTATE_FORMAT_BGRX32		0x07
+#define ROTATE_FORMAT_RGB24		0x08
+#define ROTATE_FORMAT_BGR24		0x09
+#define ROTATE_FORMAT_RGB565		0x0a
+#define ROTATE_FORMAT_BGR565		0x0b
+#define ROTATE_FORMAT_ARGB4444		0x0c
+#define ROTATE_FORMAT_ABGR4444		0x0d
+#define ROTATE_FORMAT_RGBA4444		0x0e
+#define ROTATE_FORMAT_BGRA4444		0x0f
+#define ROTATE_FORMAT_ARGB1555		0x10
+#define ROTATE_FORMAT_ABGR1555		0x11
+#define ROTATE_FORMAT_RGBA5551		0x12
+#define ROTATE_FORMAT_BGRA5551		0x13
+
+#define ROTATE_FORMAT_YUYV		0x20
+#define ROTATE_FORMAT_UYVY		0x21
+#define ROTATE_FORMAT_YVYU		0x22
+#define ROTATE_FORMAT_VYUV		0x23
+#define ROTATE_FORMAT_NV61		0x24
+#define ROTATE_FORMAT_NV16		0x25
+#define ROTATE_FORMAT_YUV422P		0x26
+#define ROTATE_FORMAT_NV21		0x28
+#define ROTATE_FORMAT_NV12		0x29
+#define ROTATE_FORMAT_YUV420P		0x2A
+
+#define ROTATE_SIZE(w, h)	(((h) - 1) << 16 | ((w) - 1))
+
+#define ROTATE_MIN_WIDTH	8U
+#define ROTATE_MIN_HEIGHT	8U
+#define ROTATE_MAX_WIDTH	4096U
+#define ROTATE_MAX_HEIGHT	4096U
+
+struct rotate_ctx {
+	struct v4l2_fh		fh;
+	struct rotate_dev	*dev;
+
+	struct v4l2_pix_format	src_fmt;
+	struct v4l2_pix_format	dst_fmt;
+
+	struct v4l2_ctrl_handler ctrl_handler;
+
+	u32 hflip;
+	u32 vflip;
+	u32 rotate;
+};
+
+struct rotate_dev {
+	struct v4l2_device	v4l2_dev;
+	struct video_device	vfd;
+	struct device		*dev;
+	struct v4l2_m2m_dev	*m2m_dev;
+
+	/* Device file mutex */
+	struct mutex		dev_mutex;
+
+	void __iomem		*base;
+
+	struct clk		*bus_clk;
+	struct clk		*mod_clk;
+
+	struct reset_control	*rstc;
+};
+
+#endif
-- 
2.25.0



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

* [PATCH 7/8] ARM: dts: sun8i: a83t: Add device node for rotation core
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (5 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 6/8] media: sun8i: " Jernej Skrabec
@ 2020-01-24 23:20 ` Jernej Skrabec
  2020-01-24 23:20 ` [PATCH 8/8] arm64: dts: allwinner: a64: add " Jernej Skrabec
  2020-02-11 19:12 ` [linux-sunxi] [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Škrabec
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Allwinner A83T contains rotation core. Add a node for it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm/boot/dts/sun8i-a83t.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 053d439b01a7..749d8e1e08cb 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -324,6 +324,17 @@ display_clocks: clock@1000000 {
 			#reset-cells = <1>;
 		};
 
+		rotate: rotate@1020000 {
+			compatible = "allwinner,sun8i-a83t-de2-rotate";
+			reg = <0x1020000 0x10000>;
+			interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&display_clocks CLK_BUS_ROT>,
+				 <&display_clocks CLK_ROT>;
+			clock-names = "bus",
+				      "mod";
+			resets = <&display_clocks RST_ROT>;
+		};
+
 		mixer0: mixer@1100000 {
 			compatible = "allwinner,sun8i-a83t-de2-mixer-0";
 			reg = <0x01100000 0x100000>;
-- 
2.25.0


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

* [PATCH 8/8] arm64: dts: allwinner: a64: add node for rotation core
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (6 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 7/8] ARM: dts: sun8i: a83t: Add device node for rotation core Jernej Skrabec
@ 2020-01-24 23:20 ` " Jernej Skrabec
  2020-02-11 19:12 ` [linux-sunxi] [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Škrabec
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Skrabec @ 2020-01-24 23:20 UTC (permalink / raw)
  To: mripard, wens
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Allwinner A64 contains rotation core compatible to A83T.

Add a node for it.

Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
 arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index baa6f08dc108..fd6ed305c14c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -274,6 +274,18 @@ display_clocks: clock@0 {
 				#reset-cells = <1>;
 			};
 
+			rotate: rotate@20000 {
+				compatible = "allwinner,sun50i-a64-de2-rotate",
+					     "allwinner,sun8i-a83t-de2-rotate";
+				reg = <0x20000 0x10000>;
+				interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+				clocks = <&display_clocks CLK_BUS_ROT>,
+					 <&display_clocks CLK_ROT>;
+				clock-names = "bus",
+					      "mod";
+				resets = <&display_clocks RST_ROT>;
+			};
+
 			mixer0: mixer@100000 {
 				compatible = "allwinner,sun50i-a64-de2-mixer-0";
 				reg = <0x100000 0x100000>;
-- 
2.25.0


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

* Re: [linux-sunxi] [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
  2020-01-24 23:20 ` [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions Jernej Skrabec
@ 2020-01-25  3:05   ` " Chen-Yu Tsai
  2020-01-25 11:20     ` Jernej Škrabec
  0 siblings, 1 reply; 14+ messages in thread
From: Chen-Yu Tsai @ 2020-01-25  3:05 UTC (permalink / raw)
  To: Jernej Skrabec
  Cc: Maxime Ripard, Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
	Mike Turquette, Stephen Boyd, Hans Verkuil,
	Linux Media Mailing List, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

On Sat, Jan 25, 2020 at 7:20 AM Jernej Skrabec <jernej.skrabec@siol.net> wrote:
>
> For some reason, A64 and H6 have swapped clocks and resets definitions.
> H6 doesn't have rotation unit while A64 has. Swap around to correct the
> issue.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

Could you add Fixes tags for this one?

ChenYu

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

* Re: [linux-sunxi] [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
  2020-01-25  3:05   ` [linux-sunxi] " Chen-Yu Tsai
@ 2020-01-25 11:20     ` Jernej Škrabec
  2020-01-25 11:24       ` Jernej Škrabec
  0 siblings, 1 reply; 14+ messages in thread
From: Jernej Škrabec @ 2020-01-25 11:20 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
	Mike Turquette, Stephen Boyd, Hans Verkuil,
	Linux Media Mailing List, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

Hi!

Dne sobota, 25. januar 2020 ob 04:05:33 CET je Chen-Yu Tsai napisal(a):
> On Sat, Jan 25, 2020 at 7:20 AM Jernej Skrabec <jernej.skrabec@siol.net> 
wrote:
> > For some reason, A64 and H6 have swapped clocks and resets definitions.
> > H6 doesn't have rotation unit while A64 has. Swap around to correct the
> > issue.
> > 
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> 
> Could you add Fixes tags for this one?

I'm not sure which commit to reference. H6 one? or also initial A64 one?

I just found out that H5 compatible uses A64 structure, which is not correct. 
H5 doesn't contain rotate core.

Do you have any better idea how to nicely solve this mess? I'm thinking that 
for v2 I would first decouple some compatibles, like this for H5 and R40 and 
V3s from A83T (as it can be seen in the next patch). After that, rather than 
switching definitions I would fix each compatible one by one. At the end, if any 
entry is duplicated, I can add one commit to merge same structures.

What do you think?

Best regards,
Jernej




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

* Re: [linux-sunxi] [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
  2020-01-25 11:20     ` Jernej Škrabec
@ 2020-01-25 11:24       ` Jernej Škrabec
  0 siblings, 0 replies; 14+ messages in thread
From: Jernej Škrabec @ 2020-01-25 11:24 UTC (permalink / raw)
  To: Chen-Yu Tsai, linux-sunxi
  Cc: Maxime Ripard, Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
	Mike Turquette, Stephen Boyd, Hans Verkuil,
	Linux Media Mailing List, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi, jernej.skrabec

Dne sobota, 25. januar 2020 ob 12:20:18 CET je Jernej Škrabec napisal(a):
> Hi!
> 
> Dne sobota, 25. januar 2020 ob 04:05:33 CET je Chen-Yu Tsai napisal(a):
> > On Sat, Jan 25, 2020 at 7:20 AM Jernej Skrabec <jernej.skrabec@siol.net>
> 
> wrote:
> > > For some reason, A64 and H6 have swapped clocks and resets definitions.
> > > H6 doesn't have rotation unit while A64 has. Swap around to correct the
> > > issue.
> > > 
> > > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> > 
> > Could you add Fixes tags for this one?
> 
> I'm not sure which commit to reference. H6 one? or also initial A64 one?
> 
> I just found out that H5 compatible uses A64 structure, which is not
> correct. H5 doesn't contain rotate core.
> 
> Do you have any better idea how to nicely solve this mess? I'm thinking that
> for v2 I would first decouple some compatibles, like this for H5 and R40
> and V3s from A83T (as it can be seen in the next patch). After that, rather
> than switching definitions I would fix each compatible one by one. At the
> end, if any entry is duplicated, I can add one commit to merge same
> structures.

This could also be a separate series of patches on which rotate driver series 
depends on.
 
Best regards,
Jernej





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

* Re: [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver
  2020-01-24 23:20 ` [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver Jernej Skrabec
@ 2020-02-03 15:48   ` Rob Herring
  0 siblings, 0 replies; 14+ messages in thread
From: Rob Herring @ 2020-02-03 15:48 UTC (permalink / raw)
  To: Jernej Skrabec
  Cc: mripard, wens, mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi

On Sat, 25 Jan 2020 00:20:11 +0100, Jernej Skrabec wrote:
> 
> Some Allwinner SoCs like A83T and A64 contain rotate core which can
> rotate and flip images.
> 
> Add a binding for it.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> ---
>  .../allwinner,sun8i-a83t-de2-rotate.yaml      | 70 +++++++++++++++++++
>  1 file changed, 70 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yaml
> 

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

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

* Re: [linux-sunxi] [PATCH 0/8] media: sunxi: Add DE2 rotate driver
  2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
                   ` (7 preceding siblings ...)
  2020-01-24 23:20 ` [PATCH 8/8] arm64: dts: allwinner: a64: add " Jernej Skrabec
@ 2020-02-11 19:12 ` Jernej Škrabec
  8 siblings, 0 replies; 14+ messages in thread
From: Jernej Škrabec @ 2020-02-11 19:12 UTC (permalink / raw)
  To: mripard, wens, linux-sunxi
  Cc: mchehab, robh+dt, mark.rutland, mturquette, sboyd,
	hverkuil-cisco, linux-media, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, linux-sunxi, jernej.skrabec

Dne sobota, 25. januar 2020 ob 00:20:06 CET je Jernej Skrabec napisal(a):
> Some of Allwinner SoCs like A83T and A64 SoCs contain DE2 rotate core
> which can flip image horizontal and vertical and rotate it in 90 deg.
> steps. It support a lot of output formats, but a bit less capture
> formats. All YUV input formats get converted to yuv420p, while RGB
> formats are preserved.
> 
> Patches 1-2 fix few issues with DE2 clocks.
> 
> Patches 3-4 fix register range of DE2 clocks (it would overlap with
> rotate driver)
> 
> Patches 5-8 provide binding, implement driver and add nodes.
> 
> v4l2-compliance SHA: ec55a961487b449bedbe07650674b4965814cf07, 32 bits,
> 32-bit time_t
> 
> Compliance test for sun8i-rotate device /dev/video0:
> 
> Driver Info:
>         Driver name      : sun8i-rotate
>         Card type        : sun8i-rotate
>         Bus info         : platform:sun8i-rotate
>         Driver version   : 5.5.0
>         Capabilities     : 0x84208000
>                 Video Memory-to-Memory
>                 Streaming
>                 Extended Pix Format
>                 Device Capabilities
>         Device Caps      : 0x04208000
>                 Video Memory-to-Memory
>                 Streaming
>                 Extended Pix Format
> 
> Required ioctls:
>         test VIDIOC_QUERYCAP: OK
> 
> Allow for multiple opens:
>         test second /dev/video0 open: OK
>         test VIDIOC_QUERYCAP: OK
>         test VIDIOC_G/S_PRIORITY: OK
>         test for unlimited opens: OK
> 
>         test invalid ioctls: OK
> Debug ioctls:
>         test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
>         test VIDIOC_LOG_STATUS: OK
> 
> Input ioctls:
>         test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
>         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>         test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
>         test VIDIOC_ENUMAUDIO: OK (Not Supported)
>         test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
>         test VIDIOC_G/S_AUDIO: OK (Not Supported)
>         Inputs: 0 Audio Inputs: 0 Tuners: 0
> 
> Output ioctls:
>         test VIDIOC_G/S_MODULATOR: OK (Not Supported)
>         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
>         test VIDIOC_ENUMAUDOUT: OK (Not Supported)
>         test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
>         test VIDIOC_G/S_AUDOUT: OK (Not Supported)
>         Outputs: 0 Audio Outputs: 0 Modulators: 0
> 
> Input/Output configuration ioctls:
>         test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
>         test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
>         test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
>         test VIDIOC_G/S_EDID: OK (Not Supported)
> 
> Control ioctls:
>         test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK
>         test VIDIOC_QUERYCTRL: OK
>         test VIDIOC_G/S_CTRL: OK
>         test VIDIOC_G/S/TRY_EXT_CTRLS: OK
>         test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK
>         test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
>         Standard Controls: 4 Private Controls: 0
> 
> Format ioctls:
>         test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
>         test VIDIOC_G/S_PARM: OK (Not Supported)
>         test VIDIOC_G_FBUF: OK (Not Supported)
>         test VIDIOC_G_FMT: OK
>         test VIDIOC_TRY_FMT: OK
>         test VIDIOC_S_FMT: OK
>         test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
>         test Cropping: OK (Not Supported)
>         test Composing: OK (Not Supported)
>         test Scaling: OK (Not Supported)
> 
> Codec ioctls:
>         test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
>         test VIDIOC_G_ENC_INDEX: OK (Not Supported)
>         test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
> 
> Buffer ioctls:
>         test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
>         test VIDIOC_EXPBUF: OK
>         test Requests: OK (Not Supported)
> 
> Total for sun8i-rotate device /dev/video0: 45, Succeeded: 45, Failed: 0,
> Warnings: 0
> 
> Best regards,
> Jernej
> 
> Jernej Skrabec (8):
>   clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions
>   clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset

Please disregard above two patches. It turns out that many more changes are 
required to fix mess with rotation clocks and reset. I sent separate patch 
series: http://lists.infradead.org/pipermail/linux-arm-kernel/2020-February/
710242.html

Comments on the rest of the series are welcome, though.

Best regards,
Jernej

>   ARM: dts: sunxi: Fix DE2 clocks register range
>   arm64: dts: allwinner: a64: Fix display clock register range
>   media: dt-bindings: media: Add Allwinner A83T Rotate driver
>   media: sun8i: Add Allwinner A83T Rotate driver
>   ARM: dts: sun8i: a83t: Add device node for rotation core
>   arm64: dts: allwinner: a64: add node for rotation core
> 
>  .../allwinner,sun8i-a83t-de2-rotate.yaml      |  70 ++
>  MAINTAINERS                                   |   8 +
>  arch/arm/boot/dts/sun8i-a83t.dtsi             |  13 +-
>  arch/arm/boot/dts/sun8i-r40.dtsi              |   2 +-
>  arch/arm/boot/dts/sun8i-v3s.dtsi              |   2 +-
>  arch/arm/boot/dts/sunxi-h3-h5.dtsi            |   2 +-
>  arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi |  14 +-
>  drivers/clk/sunxi-ng/ccu-sun8i-de2.c          |  49 +-
>  drivers/media/platform/Kconfig                |  12 +
>  drivers/media/platform/sunxi/Makefile         |   1 +
>  .../platform/sunxi/sun8i-rotate/Makefile      |   2 +
>  .../sunxi/sun8i-rotate/sun8i-formats.c        | 273 ++++++
>  .../sunxi/sun8i-rotate/sun8i-formats.h        |  25 +
>  .../sunxi/sun8i-rotate/sun8i-rotate.c         | 924 ++++++++++++++++++
>  .../sunxi/sun8i-rotate/sun8i-rotate.h         | 135 +++
>  15 files changed, 1512 insertions(+), 20 deletions(-)
>  create mode 100644
> Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-de2-rotate.yam
> l create mode 100644 drivers/media/platform/sunxi/sun8i-rotate/Makefile
> create mode 100644
> drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.c create mode
> 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-formats.h create
> mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.c create
> mode 100644 drivers/media/platform/sunxi/sun8i-rotate/sun8i-rotate.h





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

end of thread, back to index

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-24 23:20 [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Skrabec
2020-01-24 23:20 ` [PATCH 1/8] clk: sunxi-ng: sun8i-de2: Swap A64 and H6 definitions Jernej Skrabec
2020-01-25  3:05   ` [linux-sunxi] " Chen-Yu Tsai
2020-01-25 11:20     ` Jernej Škrabec
2020-01-25 11:24       ` Jernej Škrabec
2020-01-24 23:20 ` [PATCH 2/8] clk: sunxi-ng: sun8i-de2: Fix A83T clocks and reset Jernej Skrabec
2020-01-24 23:20 ` [PATCH 3/8] ARM: dts: sunxi: Fix DE2 clocks register range Jernej Skrabec
2020-01-24 23:20 ` [PATCH 4/8] arm64: dts: allwinner: a64: Fix display clock " Jernej Skrabec
2020-01-24 23:20 ` [PATCH 5/8] media: dt-bindings: media: Add Allwinner A83T Rotate driver Jernej Skrabec
2020-02-03 15:48   ` Rob Herring
2020-01-24 23:20 ` [PATCH 6/8] media: sun8i: " Jernej Skrabec
2020-01-24 23:20 ` [PATCH 7/8] ARM: dts: sun8i: a83t: Add device node for rotation core Jernej Skrabec
2020-01-24 23:20 ` [PATCH 8/8] arm64: dts: allwinner: a64: add " Jernej Skrabec
2020-02-11 19:12 ` [linux-sunxi] [PATCH 0/8] media: sunxi: Add DE2 rotate driver Jernej Škrabec

Linux-Media Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-media/0 linux-media/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-media linux-media/ https://lore.kernel.org/linux-media \
		linux-media@vger.kernel.org
	public-inbox-index linux-media

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-media


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git