From patchwork Thu Aug 25 09:39:40 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711059
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S933256AbcHYJm0 (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:42:26 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34161 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1757777AbcHYJkE (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:04 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 01/10] clk: sunxi-ng: Add a couple of A13 clocks
Date: Thu, 25 Aug 2016 11:39:40 +0200
Message-Id:
<1472117989-21455-2-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 11513
Lines: 324
Add a new style driver for the clock control unit in Allwinner A13.
Only AVS and VE are supported since they weren't provided until now and are
needed for "sunxi-cedrus".
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
.../devicetree/bindings/clock/sunxi-ccu.txt | 1 +
arch/arm/boot/dts/sun5i-a13.dtsi | 11 +++
drivers/clk/sunxi-ng/Kconfig | 11 +++
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun5i-a13.c | 80 ++++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun5i-a13.h | 25 +++++++
include/dt-bindings/clock/sun5i-a13-ccu.h | 49 +++++++++++++
include/dt-bindings/reset/sun5i-a13-ccu.h | 48 +++++++++++++
8 files changed, 226 insertions(+)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun5i-a13.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun5i-a13.h
create mode 100644 include/dt-bindings/clock/sun5i-a13-ccu.h
create mode 100644 include/dt-bindings/reset/sun5i-a13-ccu.h
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
index cb91507..7bb7a6a 100644
--- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
@@ -4,6 +4,7 @@ Allwinner Clock Control Unit Binding
Required properties :
- compatible: must contain one of the following compatible:
- "allwinner,sun8i-h3-ccu"
+ - "allwinner,sun5i-a13-ccu"
- reg: Must contain the registers base address and length
- clocks: phandle to the oscillators feeding the CCU. Two are needed:
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index e012890..2afe05fb 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -46,8 +46,10 @@
#include "sun5i.dtsi"
+#include <dt-bindings/clock/sun5i-a13-ccu.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/reset/sun5i-a13-ccu.h>
/ {
interrupt-parent = <&intc>;
@@ -327,6 +329,15 @@
};
};
};
+
+ ccu: clock@01c20000 {
+ compatible = "allwinner,sun5i-a13-ccu";
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc32k>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
};
};
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 2afcbd3..8faba4e 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -51,6 +51,17 @@ config SUNXI_CCU_MP
# SoC Drivers
+config SUN5I_A13_CCU
+ bool "Support for the Allwinner A13 CCU"
+ select SUNXI_CCU_DIV
+ select SUNXI_CCU_NK
+ select SUNXI_CCU_NKM
+ select SUNXI_CCU_NKMP
+ select SUNXI_CCU_NM
+ select SUNXI_CCU_MP
+ select SUNXI_CCU_PHASE
+ default ARCH_SUN5I
+
config SUN8I_H3_CCU
bool "Support for the Allwinner H3 CCU"
select SUNXI_CCU_DIV
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 633ce64..1710745 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_SUNXI_CCU_NM) += ccu_nm.o
obj-$(CONFIG_SUNXI_CCU_MP) += ccu_mp.o
# SoC support
+obj-$(CONFIG_SUN5I_A13_CCU) += ccu-sun5i-a13.o
obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun5i-a13.c b/drivers/clk/sunxi-ng/ccu-sun5i-a13.c
new file mode 100644
index 0000000..7f1da20
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun5i-a13.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2016 Maxime Ripard. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_mult.h"
+#include "ccu_nk.h"
+#include "ccu_nkm.h"
+#include "ccu_nkmp.h"
+#include "ccu_nm.h"
+#include "ccu_phase.h"
+
+#include "ccu-sun5i-a13.h"
+
+static SUNXI_CCU_GATE(ve_clk, "ve", "pll4",
+ 0x13c, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
+ 0x144, BIT(31), 0);
+
+static struct ccu_common *sun5i_a13_ccu_clks[] = {
+ &ve_clk.common,
+ &avs_clk.common,
+};
+
+static struct clk_hw_onecell_data sun5i_a13_hw_clks = {
+ .hws = {
+ [CLK_VE] = &ve_clk.common.hw,
+ [CLK_AVS] = &avs_clk.common.hw,
+ },
+ .num = CLK_NUMBER,
+};
+
+static struct ccu_reset_map sun5i_a13_ccu_resets[] = {
+ [RST_VE] = { 0x13c, BIT(0) },
+};
+
+static const struct sunxi_ccu_desc sun5i_a13_ccu_desc = {
+ .ccu_clks = sun5i_a13_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sun5i_a13_ccu_clks),
+
+ .hw_clks = &sun5i_a13_hw_clks,
+
+ .resets = sun5i_a13_ccu_resets,
+ .num_resets = ARRAY_SIZE(sun5i_a13_ccu_resets),
+};
+
+static void __init sun5i_a13_ccu_setup(struct device_node *node)
+{
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (IS_ERR(reg)) {
+ pr_err("%s: Could not map the clock registers\n",
+ of_node_full_name(node));
+ return;
+ }
+
+ sunxi_ccu_probe(node, reg, &sun5i_a13_ccu_desc);
+}
+
+CLK_OF_DECLARE(sun5i_A13_ccu, "allwinner,sun5i-a13-ccu",
+ sun5i_a13_ccu_setup);
diff --git a/drivers/clk/sunxi-ng/ccu-sun5i-a13.h b/drivers/clk/sunxi-ng/ccu-sun5i-a13.h
new file mode 100644
index 0000000..a52af0b
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun5i-a13.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CCU_SUN5I_A13_H_
+#define _CCU_SUN5I_A13_H_
+
+#include <dt-bindings/clock/sun5i-a13-ccu.h>
+#include <dt-bindings/reset/sun5i-a13-ccu.h>
+
+#define CLK_NUMBER 2
+
+#endif /* _CCU_SUN5I_A13_H_ */
diff --git a/include/dt-bindings/clock/sun5i-a13-ccu.h b/include/dt-bindings/clock/sun5i-a13-ccu.h
new file mode 100644
index 0000000..1218338
--- /dev/null
+++ b/include/dt-bindings/clock/sun5i-a13-ccu.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_CLK_SUN8I_a13_H_
+#define _DT_BINDINGS_CLK_SUN8I_a13_H_
+
+#define CLK_VE 0
+#define CLK_AVS 1
+
+#endif /* _DT_BINDINGS_CLK_SUN8I_A13_H_ */
diff --git a/include/dt-bindings/reset/sun5i-a13-ccu.h b/include/dt-bindings/reset/sun5i-a13-ccu.h
new file mode 100644
index 0000000..f20b4f6
--- /dev/null
+++ b/include/dt-bindings/reset/sun5i-a13-ccu.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_RST_SUN5I_A13_H_
+#define _DT_BINDINGS_RST_SUN5I_A13_H_
+
+#define RST_VE 0
+
+#endif /* _DT_BINDINGS_RST_SUN5I_A13_H_ */
From patchwork Thu Aug 25 09:39:41 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711058
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S933138AbcHYJmM (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:42:12 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34171 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1757885AbcHYJkE (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:04 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 02/10] v4l: Add private compound control type.
Date: Thu, 25 Aug 2016 11:39:41 +0200
Message-Id:
<1472117989-21455-3-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 1370
Lines: 43
From: Pawel Osciak <posciak@chromium.org>
V4L2_CTRL_TYPE_PRIVATE is to be used for private driver compound
controls that use the "ptr" member of struct v4l2_ext_control.
Signed-off-by: Pawel Osciak <posciak@chromium.org>
Signed-off-by: Jung Zhao <jung.zhao@rock-chips.com>
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 4 ++++
include/uapi/linux/videodev2.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index f7333fe..60056b0 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1543,6 +1543,10 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
return -ERANGE;
return 0;
+ /* FIXME:just return 0 for now */
+ case V4L2_CTRL_TYPE_PRIVATE:
+ return 0;
+
default:
return -EINVAL;
}
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 3eafd3f..904c44c 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1521,6 +1521,8 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_U8 = 0x0100,
V4L2_CTRL_TYPE_U16 = 0x0101,
V4L2_CTRL_TYPE_U32 = 0x0102,
+
+ V4L2_CTRL_TYPE_PRIVATE = 0xffff,
};
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
From patchwork Thu Aug 25 09:39:42 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711051
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1758923AbcHYJkN (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:13 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34179 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758718AbcHYJkL (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:11 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 03/10] v4l: Add sunxi Video Engine pixel format
Date: Thu, 25 Aug 2016 11:39:42 +0200
Message-Id:
<1472117989-21455-4-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 1140
Lines: 25
Add support for the allwinner's proprietary pixel format described in
details here: http://linux-sunxi.org/File:Ve_tile_format_v1.pdf
This format is similar to V4L2_PIX_FMT_NV12M but the planes are divided
in tiles of 32x32px.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
include/uapi/linux/videodev2.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 904c44c..96e034d 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -627,6 +627,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_Y8I v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */
#define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */
#define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */
+#define V4L2_PIX_FMT_SUNXI v4l2_fourcc('S', 'X', 'I', 'Y') /* Sunxi VE's 32x32 tiled NV12 */
/* SDR formats - used only for Software Defined Radio devices */
#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
From patchwork Thu Aug 25 09:39:43 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711050
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1758784AbcHYJkK (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:10 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34187 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1757887AbcHYJkI (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:08 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 04/10] v4l: Add MPEG2 low-level decoder API control
Date: Thu, 25 Aug 2016 11:39:43 +0200
Message-Id:
<1472117989-21455-5-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 5301
Lines: 139
This control is to be used with the new low-level decoder API for
MPEG2 to provide additional parameters for the hardware that cannot parse
the input stream.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 11 +++++++++++
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/uapi/linux/v4l2-controls.h | 26 ++++++++++++++++++++++++++
include/uapi/linux/videodev2.h | 3 +++
4 files changed, 41 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 60056b0..331d009 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -760,6 +760,8 @@ const char *v4l2_ctrl_get_name(u32 id)
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_FRAME_HDR: return "MPEG2 Frame Header";
+
/* VPX controls */
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: return "VPX Intra Mode Decision Disable";
@@ -1143,6 +1145,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_FRAME_HDR:
+ *type = V4L2_CTRL_TYPE_MPEG2_FRAME_HDR;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
@@ -1543,6 +1548,9 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
return -ERANGE;
return 0;
+ case V4L2_CTRL_TYPE_MPEG2_FRAME_HDR:
+ return 0;
+
/* FIXME:just return 0 for now */
case V4L2_CTRL_TYPE_PRIVATE:
return 0;
@@ -2096,6 +2104,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_FRAME_HDR:
+ elem_size = sizeof(struct v4l2_ctrl_mpeg2_frame_hdr);
+ 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 f19b666..de382a1 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1273,6 +1273,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break;
case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break;
case V4L2_PIX_FMT_VP8: descr = "VP8"; break;
+ case V4L2_PIX_FMT_MPEG2_FRAME: descr = "MPEG2 FRAME"; break;
case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break;
case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break;
case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index b6a357a..cdf9497 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -547,6 +547,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_FRAME_HDR (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
@@ -974,4 +976,28 @@ 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)
+struct v4l2_ctrl_mpeg2_frame_hdr {
+ __u32 slice_len;
+ __u32 slice_pos;
+ enum { MPEG1, MPEG2 } type;
+
+ __u16 width;
+ __u16 height;
+
+ enum { PCT_I = 1, PCT_P, PCT_B, PCT_D } 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_index;
+ __u8 forward_index;
+};
+
#endif
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 96e034d..feff200 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -596,6 +596,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
+#define V4L2_PIX_FMT_MPEG2_FRAME v4l2_fourcc('M', 'G', '2', 'F') /* MPEG2 frame */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1478,6 +1479,7 @@ struct v4l2_ext_control {
__u8 __user *p_u8;
__u16 __user *p_u16;
__u32 __user *p_u32;
+ struct v4l2_ctrl_mpeg2_frame_hdr __user *p_mpeg2_frame_hdr;
void __user *ptr;
};
} __attribute__ ((packed));
@@ -1522,6 +1524,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_U8 = 0x0100,
V4L2_CTRL_TYPE_U16 = 0x0101,
V4L2_CTRL_TYPE_U32 = 0x0102,
+ V4L2_CTRL_TYPE_MPEG2_FRAME_HDR = 0x0109,
V4L2_CTRL_TYPE_PRIVATE = 0xffff,
};
From patchwork Thu Aug 25 09:39:44 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711054
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1759139AbcHYJkd (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:33 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34231 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1759034AbcHYJka (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:30 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 05/10] v4l: Add MPEG4 low-level decoder API control
Date: Thu, 25 Aug 2016 11:39:44 +0200
Message-Id:
<1472117989-21455-6-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 5754
Lines: 154
This control is to be used with the new low-level decoder API for MPEG4
to provide additional parameters for the hardware that cannot parse the
input stream.
Some fields are still missing for this structure to be complete.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/v4l2-core/v4l2-ctrls.c | 8 +++++++
drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
include/uapi/linux/v4l2-controls.h | 42 ++++++++++++++++++++++++++++++++++++
include/uapi/linux/videodev2.h | 3 +++
4 files changed, 54 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 331d009..302c744 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -761,6 +761,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame";
case V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR: return "MPEG2 Frame Header";
+ case V4L2_CID_MPEG_VIDEO_MPEG4_FRAME_HDR: return "MPEG4 Frame Header";
/* VPX controls */
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions";
@@ -1148,6 +1149,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR:
*type = V4L2_CTRL_TYPE_MPEG2_FRAME_HDR;
break;
+ case V4L2_CID_MPEG_VIDEO_MPEG4_FRAME_HDR:
+ *type = V4L2_CTRL_TYPE_MPEG4_FRAME_HDR;
+ break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
break;
@@ -1549,6 +1553,7 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx,
return 0;
case V4L2_CTRL_TYPE_MPEG2_FRAME_HDR:
+ case V4L2_CTRL_TYPE_MPEG4_FRAME_HDR:
return 0;
/* FIXME:just return 0 for now */
@@ -2107,6 +2112,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_MPEG2_FRAME_HDR:
elem_size = sizeof(struct v4l2_ctrl_mpeg2_frame_hdr);
break;
+ case V4L2_CTRL_TYPE_MPEG4_FRAME_HDR:
+ elem_size = sizeof(struct v4l2_ctrl_mpeg4_frame_hdr);
+ 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 de382a1..be7973e 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1274,6 +1274,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break;
case V4L2_PIX_FMT_VP8: descr = "VP8"; break;
case V4L2_PIX_FMT_MPEG2_FRAME: descr = "MPEG2 FRAME"; break;
+ case V4L2_PIX_FMT_MPEG4_FRAME: descr = "MPEG4 FRAME"; break;
case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break;
case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break;
case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index cdf9497..af466ca 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -548,6 +548,7 @@ enum v4l2_mpeg_video_mpeg4_profile {
#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_MPEG_BASE+407)
#define V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR (V4L2_CID_MPEG_BASE+450)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_FRAME_HDR (V4L2_CID_MPEG_BASE+451)
/* Control IDs for VP8 streams
* Although VP8 is not part of MPEG we add these controls to the MPEG class
@@ -1000,4 +1001,45 @@ struct v4l2_ctrl_mpeg2_frame_hdr {
__u8 forward_index;
};
+struct v4l2_ctrl_mpeg4_frame_hdr {
+ __u32 slice_len;
+ __u32 slice_pos;
+ unsigned char quant_scale;
+
+ __u16 width;
+ __u16 height;
+
+ struct {
+ unsigned int short_video_header : 1;
+ unsigned int chroma_format : 2;
+ unsigned int interlaced : 1;
+ unsigned int obmc_disable : 1;
+ unsigned int sprite_enable : 2;
+ unsigned int sprite_warping_accuracy : 2;
+ unsigned int quant_type : 1;
+ unsigned int quarter_sample : 1;
+ unsigned int data_partitioned : 1;
+ unsigned int reversible_vlc : 1;
+ unsigned int resync_marker_disable : 1;
+ } vol_fields;
+
+ struct {
+ unsigned int vop_coding_type : 2;
+ unsigned int backward_reference_vop_coding_type : 2;
+ unsigned int vop_rounding_type : 1;
+ unsigned int intra_dc_vlc_thr : 3;
+ unsigned int top_field_first : 1;
+ unsigned int alternate_vertical_scan_flag : 1;
+ } vop_fields;
+
+ unsigned char vop_fcode_forward;
+ unsigned char vop_fcode_backward;
+
+ short trb;
+ short trd;
+
+ __u8 backward_index;
+ __u8 forward_index;
+};
+
#endif
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index feff200..18958e2 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -597,6 +597,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* VP8 */
#define V4L2_PIX_FMT_MPEG2_FRAME v4l2_fourcc('M', 'G', '2', 'F') /* MPEG2 frame */
+#define V4L2_PIX_FMT_MPEG4_FRAME v4l2_fourcc('M', 'G', '4', 'F') /* MPEG4 frame */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1480,6 +1481,7 @@ struct v4l2_ext_control {
__u16 __user *p_u16;
__u32 __user *p_u32;
struct v4l2_ctrl_mpeg2_frame_hdr __user *p_mpeg2_frame_hdr;
+ struct v4l2_ctrl_mpeg4_frame_hdr __user *p_mpeg4_frame_hdr;
void __user *ptr;
};
} __attribute__ ((packed));
@@ -1525,6 +1527,7 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_U16 = 0x0101,
V4L2_CTRL_TYPE_U32 = 0x0102,
V4L2_CTRL_TYPE_MPEG2_FRAME_HDR = 0x0109,
+ V4L2_CTRL_TYPE_MPEG4_FRAME_HDR = 0x010A,
V4L2_CTRL_TYPE_PRIVATE = 0xffff,
};
From patchwork Thu Aug 25 09:39:45 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711057
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S933084AbcHYJle (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:41:34 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34197 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758928AbcHYJkV (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:21 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 06/10] media: platform: Add Sunxi Cedrus decoder driver
Date: Thu, 25 Aug 2016 11:39:45 +0200
Message-Id:
<1472117989-21455-7-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 39950
Lines: 1387
This patch adds a "sunxi-cedrus" v4l2 m2m decoder driver for
Allwinner's Video Processing Unit. This VPU has a low-level interface
which requires manual registers writing for frame headers. Hence, it
depends on the Request API to synchronize buffers with controls.
Most of the reverse engineering on which I based my work comes from the
"Cedrus" project: http://linux-sunxi.org/Cedrus
The driver currently only runs on the A13 and this patch doesn't
include any codec.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/platform/Kconfig | 13 +
drivers/media/platform/Makefile | 1 +
drivers/media/platform/sunxi-cedrus/Makefile | 2 +
drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c | 248 ++++++++++
.../platform/sunxi-cedrus/sunxi_cedrus_common.h | 86 ++++
.../media/platform/sunxi-cedrus/sunxi_cedrus_dec.c | 544 +++++++++++++++++++++
.../media/platform/sunxi-cedrus/sunxi_cedrus_dec.h | 33 ++
.../media/platform/sunxi-cedrus/sunxi_cedrus_hw.c | 153 ++++++
.../media/platform/sunxi-cedrus/sunxi_cedrus_hw.h | 32 ++
.../platform/sunxi-cedrus/sunxi_cedrus_regs.h | 170 +++++++
10 files changed, 1282 insertions(+)
create mode 100644 drivers/media/platform/sunxi-cedrus/Makefile
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.h
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_regs.h
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index f25344b..92c92d3 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -315,6 +315,19 @@ config VIDEO_TI_VPE
Support for the TI VPE(Video Processing Engine) block
found on DRA7XX SoC.
+config VIDEO_SUNXI_CEDRUS
+ tristate "Sunxi CEDRUS VPU driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on ARCH_SUNXI
+ depends on HAS_DMA
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ Support for the VPU video codec found on Sunxi SoC.
+
+ To compile this driver as a module, choose M here: the module
+ will be called sunxi-cedrus.
+
config VIDEO_TI_VPE_DEBUG
bool "VPE debug messages"
depends on VIDEO_TI_VPE
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 21771c1..1419749 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
obj-y += omap/
obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus/
obj-$(CONFIG_VIDEO_XILINX) += xilinx/
diff --git a/drivers/media/platform/sunxi-cedrus/Makefile b/drivers/media/platform/sunxi-cedrus/Makefile
new file mode 100644
index 0000000..14c2f7a
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi_cedrus.o sunxi_cedrus_hw.o \
+ sunxi_cedrus_dec.o
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
new file mode 100644
index 0000000..17af34c
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
@@ -0,0 +1,248 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sunxi_cedrus_common.h"
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <linux/platform_device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "sunxi_cedrus_dec.h"
+#include "sunxi_cedrus_hw.h"
+
+static int sunxi_cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct sunxi_cedrus_ctx *ctx =
+ container_of(ctrl->handler, struct sunxi_cedrus_ctx, hdl);
+
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops sunxi_cedrus_ctrl_ops = {
+ .s_ctrl = sunxi_cedrus_s_ctrl,
+};
+
+/*
+ * File operations
+ */
+static int sunxi_cedrus_open(struct file *file)
+{
+ struct sunxi_cedrus_dev *dev = video_drvdata(file);
+ struct sunxi_cedrus_ctx *ctx = NULL;
+ struct v4l2_ctrl_handler *hdl;
+ int rc = 0;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto open_unlock;
+ }
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+ hdl = &ctx->hdl;
+ v4l2_ctrl_handler_init(hdl, 1);
+
+ if (hdl->error) {
+ rc = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ goto open_unlock;
+ }
+ ctx->fh.ctrl_handler = hdl;
+ v4l2_ctrl_handler_setup(hdl);
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ rc = PTR_ERR(ctx->fh.m2m_ctx);
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(ctx);
+ goto open_unlock;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+
+ dev_dbg(dev->dev, "Created instance: %p, m2m_ctx: %p\n",
+ ctx, ctx->fh.m2m_ctx);
+
+open_unlock:
+ mutex_unlock(&dev->dev_mutex);
+ return rc;
+}
+
+static int sunxi_cedrus_release(struct file *file)
+{
+ struct sunxi_cedrus_dev *dev = video_drvdata(file);
+ struct sunxi_cedrus_ctx *ctx = container_of(file->private_data,
+ struct sunxi_cedrus_ctx, fh);
+
+ dev_dbg(dev->dev, "Releasing instance %p\n", ctx);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ mutex_lock(&dev->dev_mutex);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ mutex_unlock(&dev->dev_mutex);
+ kfree(ctx);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations sunxi_cedrus_fops = {
+ .owner = THIS_MODULE,
+ .open = sunxi_cedrus_open,
+ .release = sunxi_cedrus_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static struct video_device sunxi_cedrus_viddev = {
+ .name = SUNXI_CEDRUS_NAME,
+ .vfl_dir = VFL_DIR_M2M,
+ .fops = &sunxi_cedrus_fops,
+ .ioctl_ops = &sunxi_cedrus_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = device_run,
+ .job_abort = job_abort,
+};
+
+static int sunxi_cedrus_probe(struct platform_device *pdev)
+{
+ struct sunxi_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 = sunxi_cedrus_hw_probe(dev);
+ if (ret) {
+ dev_err(&pdev->dev, "sunxi_cedrus_hw_probe failed\n");
+ return ret;
+ }
+
+ spin_lock_init(&dev->irqlock);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret)
+ return ret;
+
+ mutex_init(&dev->dev_mutex);
+
+ dev->vfd = sunxi_cedrus_viddev;
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+ goto unreg_dev;
+ }
+
+ video_set_drvdata(vfd, dev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", sunxi_cedrus_viddev.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(&m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+ goto err_m2m;
+ }
+
+ return 0;
+
+err_m2m:
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+unreg_dev:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return ret;
+}
+
+static int sunxi_cedrus_remove(struct platform_device *pdev)
+{
+ struct sunxi_cedrus_dev *dev = platform_get_drvdata(pdev);
+
+ v4l2_info(&dev->v4l2_dev, "Removing " SUNXI_CEDRUS_NAME);
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ sunxi_cedrus_hw_remove(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_sunxi_cedrus_match[] = {
+ { .compatible = "allwinner,sun5i-a13-video-engine" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, of_sunxi_cedrus_match);
+#endif
+
+static struct platform_driver sunxi_cedrus_driver = {
+ .probe = sunxi_cedrus_probe,
+ .remove = sunxi_cedrus_remove,
+ .driver = {
+ .name = SUNXI_CEDRUS_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(of_sunxi_cedrus_match),
+ },
+};
+module_platform_driver(sunxi_cedrus_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Florent Revest <florent.revest@free-electrons.com>");
+MODULE_DESCRIPTION("Sunxi Cedrus codec driver");
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
new file mode 100644
index 0000000..6b8d87a
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
@@ -0,0 +1,86 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUNXI_CEDRUS_COMMON_H_
+#define SUNXI_CEDRUS_COMMON_H_
+
+#include "sunxi_cedrus_regs.h"
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define SUNXI_CEDRUS_NAME "sunxi-cedrus"
+
+struct sunxi_cedrus_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+ struct platform_device *pdev;
+ struct device *dev;
+ struct v4l2_m2m_dev *m2m_dev;
+
+ /* Mutex for device file */
+ struct mutex dev_mutex;
+ /* Spinlock for interrupt */
+ spinlock_t irqlock;
+
+ struct clk *mod_clk;
+ struct clk *ahb_clk;
+ struct clk *ram_clk;
+
+ struct reset_control *rstc;
+
+ char *base;
+};
+
+struct sunxi_cedrus_fmt {
+ u32 fourcc;
+ int depth;
+ u32 types;
+ unsigned int num_planes;
+};
+
+struct sunxi_cedrus_ctx {
+ struct v4l2_fh fh;
+ struct sunxi_cedrus_dev *dev;
+
+ struct sunxi_cedrus_fmt *vpu_src_fmt;
+ struct v4l2_pix_format_mplane src_fmt;
+ struct sunxi_cedrus_fmt *vpu_dst_fmt;
+ struct v4l2_pix_format_mplane dst_fmt;
+
+ struct v4l2_ctrl_handler hdl;
+
+ struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
+};
+
+static inline void sunxi_cedrus_write(struct sunxi_cedrus_dev *vpu,
+ u32 val, u32 reg)
+{
+ writel(val, vpu->base + reg);
+}
+
+static inline u32 sunxi_cedrus_read(struct sunxi_cedrus_dev *vpu, u32 reg)
+{
+ return readl(vpu->base + reg);
+}
+
+#endif /* SUNXI_CEDRUS_COMMON_H_ */
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
new file mode 100644
index 0000000..71ef34b
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
@@ -0,0 +1,544 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sunxi_cedrus_common.h"
+
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "sunxi_cedrus_dec.h"
+#include "sunxi_cedrus_hw.h"
+
+/* Flags that indicate a format can be used for capture/output */
+#define SUNXI_CEDRUS_CAPTURE BIT(0)
+#define SUNXI_CEDRUS_OUTPUT BIT(1)
+
+#define SUNXI_CEDRUS_MIN_WIDTH 16U
+#define SUNXI_CEDRUS_MIN_HEIGHT 16U
+#define SUNXI_CEDRUS_MAX_WIDTH 3840U
+#define SUNXI_CEDRUS_MAX_HEIGHT 2160U
+
+static struct sunxi_cedrus_fmt formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_SUNXI,
+ .types = SUNXI_CEDRUS_CAPTURE,
+ .depth = 8,
+ .num_planes = 2,
+ },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static struct sunxi_cedrus_fmt *find_format(struct v4l2_format *f)
+{
+ struct sunxi_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 sunxi_cedrus_ctx *file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct sunxi_cedrus_ctx, fh);
+}
+
+/*
+ * mem2mem callbacks
+ */
+
+void job_abort(void *priv)
+{}
+
+/*
+ * device_run() - prepares and starts processing
+ */
+void device_run(void *priv)
+{
+ struct sunxi_cedrus_ctx *ctx = priv;
+ struct vb2_v4l2_buffer *in_vb, *out_vb;
+ dma_addr_t in_buf, out_luma, out_chroma;
+
+ in_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ out_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ v4l2_ctrl_apply_request(&ctx->hdl, in_vb->request);
+
+ in_buf = vb2_dma_contig_plane_dma_addr(&in_vb->vb2_buf, 0);
+ out_luma = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 0);
+ out_chroma = vb2_dma_contig_plane_dma_addr(&out_vb->vb2_buf, 1);
+ if (!in_buf || !out_luma || !out_chroma) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Acquiring kernel pointers to buffers failed\n");
+ return;
+ }
+
+ /*
+ * The VPU is only able to handle bus addresses so we have to subtract
+ * the RAM offset to the physcal addresses
+ */
+ in_buf -= PHYS_OFFSET;
+ out_luma -= PHYS_OFFSET;
+ out_chroma -= PHYS_OFFSET;
+
+ out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
+ if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
+ out_vb->timecode = in_vb->timecode;
+ out_vb->field = in_vb->field;
+ out_vb->flags = in_vb->flags & (V4L2_BUF_FLAG_TIMECODE |
+ V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME | V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
+
+ v4l2_m2m_buf_done(in_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(out_vb, VB2_BUF_STATE_ERROR);
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strncpy(cap->driver, SUNXI_CEDRUS_NAME, sizeof(cap->driver) - 1);
+ strncpy(cap->card, SUNXI_CEDRUS_NAME, sizeof(cap->card) - 1);
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", SUNXI_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)
+{
+ int i, num;
+ struct sunxi_cedrus_fmt *fmt;
+
+ 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) {
+ /* Format found */
+ fmt = &formats[i];
+ f->pixelformat = fmt->fourcc;
+ return 0;
+ }
+
+ /* Format not found */
+ return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return enum_fmt(f, SUNXI_CEDRUS_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return enum_fmt(f, SUNXI_CEDRUS_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct sunxi_cedrus_ctx *ctx, struct v4l2_format *f)
+{
+ 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:
+ dev_dbg(ctx->dev->dev, "invalid buf type\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 sunxi_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,
+ SUNXI_CEDRUS_MIN_WIDTH, SUNXI_CEDRUS_MAX_WIDTH);
+ f->fmt.pix_mp.height = clamp(f->fmt.pix_mp.height,
+ SUNXI_CEDRUS_MIN_HEIGHT, SUNXI_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 sunxi_cedrus_fmt *fmt;
+ struct sunxi_cedrus_ctx *ctx = file2ctx(file);
+
+ fmt = find_format(f);
+ if (!fmt) {
+ f->fmt.pix_mp.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & SUNXI_CEDRUS_CAPTURE)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\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 sunxi_cedrus_fmt *fmt;
+ struct sunxi_cedrus_ctx *ctx = file2ctx(file);
+
+ fmt = find_format(f);
+ if (!fmt) {
+ f->fmt.pix_mp.pixelformat = formats[0].fourcc;
+ fmt = find_format(f);
+ }
+ if (!(fmt->types & SUNXI_CEDRUS_OUTPUT)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "Fourcc format (0x%08x) invalid.\n",
+ f->fmt.pix_mp.pixelformat);
+ return -EINVAL;
+ }
+
+ return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct sunxi_cedrus_ctx *ctx, struct v4l2_format *f)
+{
+ struct sunxi_cedrus_dev *dev = ctx->dev;
+ struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ struct sunxi_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:
+ dev_dbg(ctx->dev->dev, "invalid buf type\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ return vidioc_s_fmt(file2ctx(file), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = vidioc_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ ret = vidioc_s_fmt(file2ctx(file), f);
+ return ret;
+}
+
+const struct v4l2_ioctl_ops sunxi_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,
+};
+
+/*
+ * Queue operations
+ */
+
+static int sunxi_cedrus_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct sunxi_cedrus_ctx *ctx = vb2_get_drv_priv(vq);
+
+ if (*nbufs < 1)
+ *nbufs = 1;
+
+ if (*nbufs > VIDEO_MAX_FRAME)
+ *nbufs = VIDEO_MAX_FRAME;
+
+ 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:
+ dev_dbg(ctx->dev->dev, "invalid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sunxi_cedrus_buf_init(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct sunxi_cedrus_ctx *ctx = container_of(vq->drv_priv,
+ struct sunxi_cedrus_ctx, fh);
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ctx->dst_bufs[vb->index] = vb;
+
+ return 0;
+}
+
+static void sunxi_cedrus_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct sunxi_cedrus_ctx *ctx = container_of(vq->drv_priv,
+ struct sunxi_cedrus_ctx, fh);
+
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ctx->dst_bufs[vb->index] = NULL;
+}
+
+static int sunxi_cedrus_buf_prepare(struct vb2_buffer *vb)
+{
+ struct sunxi_cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_queue *vq = vb->vb2_queue;
+ int i;
+
+ dev_dbg(ctx->dev->dev, "type: %d\n", vb->vb2_queue->type);
+
+ switch (vq->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (vb2_plane_size(vb, 0)
+ < ctx->src_fmt.plane_fmt[0].sizeimage) {
+ dev_dbg(ctx->dev->dev, "plane 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) {
+ dev_dbg(ctx->dev->dev,
+ "plane %d too small for capture\n", i);
+ break;
+ }
+ }
+
+ if (i != ctx->vpu_dst_fmt->num_planes)
+ return -EINVAL;
+ break;
+
+ default:
+ dev_dbg(ctx->dev->dev, "invalid queue type: %d\n", vq->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void sunxi_cedrus_stop_streaming(struct vb2_queue *q)
+{
+ struct sunxi_cedrus_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_v4l2_buffer *vbuf;
+ unsigned long flags;
+
+ for (;;) {
+ 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);
+ if (!vbuf)
+ return;
+ spin_lock_irqsave(&ctx->dev->irqlock, flags);
+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
+ }
+}
+
+static void sunxi_cedrus_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct sunxi_cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static struct vb2_ops sunxi_cedrus_qops = {
+ .queue_setup = sunxi_cedrus_queue_setup,
+ .buf_prepare = sunxi_cedrus_buf_prepare,
+ .buf_init = sunxi_cedrus_buf_init,
+ .buf_cleanup = sunxi_cedrus_buf_cleanup,
+ .buf_queue = sunxi_cedrus_buf_queue,
+ .stop_streaming = sunxi_cedrus_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct sunxi_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 v4l2_m2m_buffer);
+ src_vq->ops = &sunxi_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->v4l2_allow_requests = true;
+ 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 v4l2_m2m_buffer);
+ dst_vq->ops = &sunxi_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->v4l2_allow_requests = true;
+ dst_vq->dev = ctx->dev->dev;
+
+ return vb2_queue_init(dst_vq);
+}
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.h
new file mode 100644
index 0000000..f0ac921
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.h
@@ -0,0 +1,33 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUNXI_CEDRUS_DEC_H_
+#define SUNXI_CEDRUS_DEC_H_
+
+int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq);
+
+void job_abort(void *priv);
+void device_run(void *priv);
+
+extern const struct v4l2_ioctl_ops sunxi_cedrus_ioctl_ops;
+
+#endif /* SUNXI_CEDRUS_DEC_H_ */
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
new file mode 100644
index 0000000..72b9df4
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
@@ -0,0 +1,153 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * And reverse engineering efforts of the 'Cedrus' project
+ * Copyright (c) 2013-2014 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sunxi_cedrus_common.h"
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+
+/*
+ * Interrupt handlers.
+ */
+
+static irqreturn_t sunxi_cedrus_ve_irq(int irq, void *dev_id)
+{
+ struct sunxi_cedrus_dev *vpu = dev_id;
+ struct sunxi_cedrus_ctx *curr_ctx;
+ struct vb2_v4l2_buffer *src_vb, *dst_vb;
+ int val;
+ unsigned long flags;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
+
+ if (!curr_ctx) {
+ pr_err("Instance released before the end of transaction\n");
+ return IRQ_HANDLED;
+ }
+
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+
+ spin_lock_irqsave(&vpu->irqlock, flags);
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&vpu->irqlock, flags);
+
+ v4l2_m2m_job_finish(vpu->m2m_dev, curr_ctx->fh.m2m_ctx);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Initialization/clean-up.
+ */
+
+int sunxi_cedrus_hw_probe(struct sunxi_cedrus_dev *vpu)
+{
+ struct resource *res;
+ int irq_dec;
+ int ret;
+
+ irq_dec = platform_get_irq(vpu->pdev, 0);
+ if (irq_dec <= 0) {
+ dev_err(vpu->dev, "could not get ve IRQ\n");
+ return -ENXIO;
+ }
+ ret = devm_request_irq(vpu->dev, irq_dec, sunxi_cedrus_ve_irq, 0,
+ dev_name(vpu->dev), vpu);
+ if (ret) {
+ dev_err(vpu->dev, "could not request ve IRQ\n");
+ return -ENXIO;
+ }
+
+ ret = of_reserved_mem_device_init(vpu->dev);
+ if (ret) {
+ dev_err(vpu->dev, "could not reserve memory\n");
+ return -ENODEV;
+ }
+
+ vpu->ahb_clk = devm_clk_get(vpu->dev, "ahb");
+ if (IS_ERR(vpu->ahb_clk)) {
+ dev_err(vpu->dev, "failed to get ahb clock\n");
+ return PTR_ERR(vpu->ahb_clk);
+ }
+ vpu->mod_clk = devm_clk_get(vpu->dev, "mod");
+ if (IS_ERR(vpu->mod_clk)) {
+ dev_err(vpu->dev, "failed to get mod clock\n");
+ return PTR_ERR(vpu->mod_clk);
+ }
+ vpu->ram_clk = devm_clk_get(vpu->dev, "ram");
+ if (IS_ERR(vpu->ram_clk)) {
+ dev_err(vpu->dev, "failed to get ram clock\n");
+ return PTR_ERR(vpu->ram_clk);
+ }
+
+ vpu->rstc = devm_reset_control_get(vpu->dev, NULL);
+
+ res = platform_get_resource(vpu->pdev, IORESOURCE_MEM, 0);
+ vpu->base = devm_ioremap_resource(vpu->dev, res);
+ if (!vpu->base)
+ dev_err(vpu->dev, "could not maps MACC registers\n");
+
+ ret = clk_prepare_enable(vpu->ahb_clk);
+ if (ret) {
+ dev_err(vpu->dev, "could not enable ahb clock\n");
+ return -EFAULT;
+ }
+ ret = clk_prepare_enable(vpu->mod_clk);
+ if (ret) {
+ clk_disable_unprepare(vpu->ahb_clk);
+ dev_err(vpu->dev, "could not enable mod clock\n");
+ return -EFAULT;
+ }
+ ret = clk_prepare_enable(vpu->ram_clk);
+ if (ret) {
+ clk_disable_unprepare(vpu->mod_clk);
+ clk_disable_unprepare(vpu->ahb_clk);
+ dev_err(vpu->dev, "could not enable ram clock\n");
+ return -EFAULT;
+ }
+
+ reset_control_assert(vpu->rstc);
+ reset_control_deassert(vpu->rstc);
+
+ return 0;
+}
+
+void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *vpu)
+{
+ clk_disable_unprepare(vpu->ram_clk);
+ clk_disable_unprepare(vpu->mod_clk);
+ clk_disable_unprepare(vpu->ahb_clk);
+
+ of_reserved_mem_device_release(vpu->dev);
+}
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
new file mode 100644
index 0000000..3c9199b
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
@@ -0,0 +1,32 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on vim2m
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ * Pawel Osciak, <pawel@osciak.com>
+ * Marek Szyprowski, <m.szyprowski@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUNXI_CEDRUS_HW_H_
+#define SUNXI_CEDRUS_HW_H_
+
+struct sunxi_cedrus_dev;
+struct sunxi_cedrus_ctx;
+
+int sunxi_cedrus_hw_probe(struct sunxi_cedrus_dev *vpu);
+void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *vpu);
+
+#endif /* SUNXI_CEDRUS_HW_H_ */
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_regs.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_regs.h
new file mode 100644
index 0000000..7384daa
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_regs.h
@@ -0,0 +1,170 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on Cedrus
+ *
+ * Copyright (c) 2013 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SUNXI_CEDRUS_REGS_H
+#define SUNXI_CEDRUS_REGS_H
+
+/*
+ * For more information consult http://linux-sunxi.org/VE_Register_guide
+ */
+
+/* Special registers values */
+
+/* VE_CTRL:
+ * The first 3 bits indicate the engine (0 for MPEG, 1 for H264, b for AVC...)
+ * The 16th and 17th bits indicate the memory type (3 for DDR3 32 bits)
+ * The 20th bit is unknown but needed
+ */
+#define VE_CTRL_MPEG 0x130000
+#define VE_CTRL_H264 0x130001
+#define VE_CTRL_AVC 0x13000b
+#define VE_CTRL_REINIT 0x130007
+
+/* 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
+#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 /* SUNXI_CEDRUS_REGS_H */
From patchwork Thu Aug 25 09:39:46 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711052
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1758966AbcHYJkZ (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:25 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34204 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758941AbcHYJkW (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:22 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 07/10] sunxi-cedrus: Add a MPEG 2 codec
Date: Thu, 25 Aug 2016 11:39:46 +0200
Message-Id:
<1472117989-21455-8-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 12799
Lines: 335
This patch introduces the support of MPEG2 video decoding to the
sunxi-cedrus video decoder driver.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/platform/sunxi-cedrus/Makefile | 2 +-
drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c | 26 +++-
.../platform/sunxi-cedrus/sunxi_cedrus_common.h | 2 +
.../media/platform/sunxi-cedrus/sunxi_cedrus_dec.c | 15 +-
.../media/platform/sunxi-cedrus/sunxi_cedrus_hw.c | 17 ++-
.../media/platform/sunxi-cedrus/sunxi_cedrus_hw.h | 4 +
.../platform/sunxi-cedrus/sunxi_cedrus_mpeg2.c | 152 +++++++++++++++++++++
7 files changed, 211 insertions(+), 7 deletions(-)
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg2.c
diff --git a/drivers/media/platform/sunxi-cedrus/Makefile b/drivers/media/platform/sunxi-cedrus/Makefile
index 14c2f7a..2d495a2 100644
--- a/drivers/media/platform/sunxi-cedrus/Makefile
+++ b/drivers/media/platform/sunxi-cedrus/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi_cedrus.o sunxi_cedrus_hw.o \
- sunxi_cedrus_dec.o
+ sunxi_cedrus_dec.o sunxi_cedrus_mpeg2.o
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
index 17af34c..d1c957a 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
@@ -46,14 +46,31 @@ static int sunxi_cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
struct sunxi_cedrus_ctx *ctx =
container_of(ctrl->handler, struct sunxi_cedrus_ctx, hdl);
- v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
- return -EINVAL;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR:
+ /* This is kept in memory and used directly. */
+ break;
+ default:
+ v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+ }
+
+ return 0;
}
static const struct v4l2_ctrl_ops sunxi_cedrus_ctrl_ops = {
.s_ctrl = sunxi_cedrus_s_ctrl,
};
+static const struct v4l2_ctrl_config sunxi_cedrus_ctrl_mpeg2_frame_hdr = {
+ .ops = &sunxi_cedrus_ctrl_ops,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR,
+ .type = V4L2_CTRL_TYPE_PRIVATE,
+ .name = "MPEG2 Frame Header Parameters",
+ .max_reqs = VIDEO_MAX_FRAME,
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg2_frame_hdr),
+};
+
/*
* File operations
*/
@@ -78,6 +95,10 @@ static int sunxi_cedrus_open(struct file *file)
hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 1);
+ ctx->mpeg2_frame_hdr_ctrl = v4l2_ctrl_new_custom(hdl,
+ &sunxi_cedrus_ctrl_mpeg2_frame_hdr, NULL);
+ ctx->mpeg2_frame_hdr_ctrl->flags |= V4L2_CTRL_FLAG_REQ_KEEP;
+
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -117,6 +138,7 @@ static int sunxi_cedrus_release(struct file *file)
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
+ ctx->mpeg2_frame_hdr_ctrl = NULL;
mutex_lock(&dev->dev_mutex);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(&dev->dev_mutex);
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
index 6b8d87a..e715184 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
@@ -70,6 +70,8 @@ struct sunxi_cedrus_ctx {
struct v4l2_ctrl_handler hdl;
struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
+
+ struct v4l2_ctrl *mpeg2_frame_hdr_ctrl;
};
static inline void sunxi_cedrus_write(struct sunxi_cedrus_dev *vpu,
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
index 71ef34b..38e8a3a 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
@@ -48,6 +48,11 @@ static struct sunxi_cedrus_fmt formats[] = {
.depth = 8,
.num_planes = 2,
},
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG2_FRAME,
+ .types = SUNXI_CEDRUS_OUTPUT,
+ .num_planes = 1,
+ },
};
#define NUM_FORMATS ARRAY_SIZE(formats)
@@ -120,8 +125,14 @@ void device_run(void *priv)
V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME |
V4L2_BUF_FLAG_BFRAME | V4L2_BUF_FLAG_TSTAMP_SRC_MASK);
- v4l2_m2m_buf_done(in_vb, VB2_BUF_STATE_ERROR);
- v4l2_m2m_buf_done(out_vb, VB2_BUF_STATE_ERROR);
+ if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG2_FRAME) {
+ struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr =
+ ctx->mpeg2_frame_hdr_ctrl->p_new.p;
+ process_mpeg2(ctx, in_buf, out_luma, out_chroma, frame_hdr);
+ } else {
+ v4l2_m2m_buf_done(in_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(out_vb, VB2_BUF_STATE_ERROR);
+ }
}
/*
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
index 72b9df4..160de17 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.c
@@ -47,6 +47,13 @@ static irqreturn_t sunxi_cedrus_ve_irq(int irq, void *dev_id)
int val;
unsigned long flags;
+ /* Disable MPEG interrupts and stop the MPEG engine */
+ val = sunxi_cedrus_read(vpu, VE_MPEG_CTRL);
+ sunxi_cedrus_write(vpu, val & (~0xf), VE_MPEG_CTRL);
+ val = sunxi_cedrus_read(vpu, VE_MPEG_STATUS);
+ sunxi_cedrus_write(vpu, 0x0000c00f, VE_MPEG_STATUS);
+ sunxi_cedrus_write(vpu, VE_CTRL_REINIT, VE_CTRL);
+
curr_ctx = v4l2_m2m_get_curr_priv(vpu->m2m_dev);
if (!curr_ctx) {
@@ -57,9 +64,15 @@ static irqreturn_t sunxi_cedrus_ve_irq(int irq, void *dev_id)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+ /* First bit of MPEG_STATUS means success */
spin_lock_irqsave(&vpu->irqlock, flags);
- v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
- v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ if (val & 0x1) {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+ } else {
+ v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+ }
spin_unlock_irqrestore(&vpu->irqlock, flags);
v4l2_m2m_job_finish(vpu->m2m_dev, curr_ctx->fh.m2m_ctx);
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
index 3c9199b..78625e5 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
@@ -29,4 +29,8 @@ struct sunxi_cedrus_ctx;
int sunxi_cedrus_hw_probe(struct sunxi_cedrus_dev *vpu);
void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *vpu);
+void process_mpeg2(struct sunxi_cedrus_ctx *ctx, dma_addr_t in_buf,
+ dma_addr_t out_luma, dma_addr_t out_chroma,
+ struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr);
+
#endif /* SUNXI_CEDRUS_HW_H_ */
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg2.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg2.c
new file mode 100644
index 0000000..9381c63
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg2.c
@@ -0,0 +1,152 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on reverse engineering efforts of the 'Cedrus' project
+ * Copyright (c) 2013-2014 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sunxi_cedrus_common.h"
+
+#include <media/videobuf2-dma-contig.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 process_mpeg2(struct sunxi_cedrus_ctx *ctx, dma_addr_t in_buf,
+ dma_addr_t out_luma, dma_addr_t out_chroma,
+ struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr)
+{
+ struct sunxi_cedrus_dev *dev = ctx->dev;
+
+ 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 fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
+
+ /*
+ * The VPU is only able to handle bus addresses so we have to subtract
+ * the RAM offset to the physcal addresses
+ */
+ fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_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);
+ fwd_luma -= PHYS_OFFSET;
+ fwd_chroma -= PHYS_OFFSET;
+ }
+
+ bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_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);
+ bwd_chroma -= PHYS_OFFSET;
+ bwd_luma -= PHYS_OFFSET;
+ }
+
+ /* Activates MPEG engine */
+ sunxi_cedrus_write(dev, VE_CTRL_MPEG, VE_CTRL);
+
+ /* Upload quantization matrices */
+ for (i = 0; i < 64; i++) {
+ sunxi_cedrus_write(dev, m_iq(i), VE_MPEG_IQ_MIN_INPUT);
+ sunxi_cedrus_write(dev, m_niq(i), VE_MPEG_IQ_MIN_INPUT);
+ }
+
+ /* Image's dimensions */
+ sunxi_cedrus_write(dev, width << 8 | height, VE_MPEG_SIZE);
+ sunxi_cedrus_write(dev, width << 20 | height << 4, VE_MPEG_FRAME_SIZE);
+
+ /* MPEG picture's 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;
+ sunxi_cedrus_write(dev, pic_header, VE_MPEG_PIC_HDR);
+
+ /* Enable interrupt and an unknown control flag */
+ sunxi_cedrus_write(dev, VE_MPEG_CTRL_MPEG2, VE_MPEG_CTRL);
+
+ /* Macroblock address */
+ sunxi_cedrus_write(dev, 0, VE_MPEG_MBA);
+
+ /* Clear previous errors */
+ sunxi_cedrus_write(dev, 0, VE_MPEG_ERROR);
+
+ /* Unknown register */
+ sunxi_cedrus_write(dev, 0, VE_MPEG_CTR_MB);
+
+ /* Forward and backward prediction buffers (cached in dst_bufs) */
+ sunxi_cedrus_write(dev, fwd_luma, VE_MPEG_FWD_LUMA);
+ sunxi_cedrus_write(dev, fwd_chroma, VE_MPEG_FWD_CHROMA);
+ sunxi_cedrus_write(dev, bwd_luma, VE_MPEG_BACK_LUMA);
+ sunxi_cedrus_write(dev, bwd_chroma, VE_MPEG_BACK_CHROMA);
+
+ /* Output luma and chroma buffers */
+ sunxi_cedrus_write(dev, out_luma, VE_MPEG_REC_LUMA);
+ sunxi_cedrus_write(dev, out_chroma, VE_MPEG_REC_CHROMA);
+ sunxi_cedrus_write(dev, out_luma, VE_MPEG_ROT_LUMA);
+ sunxi_cedrus_write(dev, out_chroma, VE_MPEG_ROT_CHROMA);
+
+ /* Input offset and length in bits */
+ sunxi_cedrus_write(dev, frame_hdr->slice_pos, VE_MPEG_VLD_OFFSET);
+ sunxi_cedrus_write(dev, vld_len, VE_MPEG_VLD_LEN);
+
+ /* Input beginning and end addresses */
+ sunxi_cedrus_write(dev, VE_MPEG_VLD_ADDR_VAL(in_buf), VE_MPEG_VLD_ADDR);
+ sunxi_cedrus_write(dev, in_buf + VBV_SIZE - 1, VE_MPEG_VLD_END);
+
+ /* Starts the MPEG engine */
+ if (frame_hdr->type == MPEG2)
+ sunxi_cedrus_write(dev, VE_TRIG_MPEG2, VE_MPEG_TRIGGER);
+ else
+ sunxi_cedrus_write(dev, VE_TRIG_MPEG1, VE_MPEG_TRIGGER);
+}
From patchwork Thu Aug 25 09:39:47 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711055
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1759323AbcHYJkw (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:52 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34217 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758992AbcHYJk2 (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:28 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 08/10] sunxi-cedrus: Add a MPEG 4 codec
Date: Thu, 25 Aug 2016 11:39:47 +0200
Message-Id:
<1472117989-21455-9-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 12626
Lines: 322
This patch introduces the support of MPEG4 video decoding to the
sunxi-cedrus video decoder driver.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
drivers/media/platform/sunxi-cedrus/Makefile | 3 +-
drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c | 15 +++
.../platform/sunxi-cedrus/sunxi_cedrus_common.h | 13 ++
.../media/platform/sunxi-cedrus/sunxi_cedrus_dec.c | 33 +++++
.../media/platform/sunxi-cedrus/sunxi_cedrus_hw.h | 3 +
.../platform/sunxi-cedrus/sunxi_cedrus_mpeg4.c | 140 +++++++++++++++++++++
6 files changed, 206 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg4.c
diff --git a/drivers/media/platform/sunxi-cedrus/Makefile b/drivers/media/platform/sunxi-cedrus/Makefile
index 2d495a2..823d611 100644
--- a/drivers/media/platform/sunxi-cedrus/Makefile
+++ b/drivers/media/platform/sunxi-cedrus/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi_cedrus.o sunxi_cedrus_hw.o \
- sunxi_cedrus_dec.o sunxi_cedrus_mpeg2.o
+ sunxi_cedrus_dec.o sunxi_cedrus_mpeg2.o \
+ sunxi_cedrus_mpeg4.o
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
index d1c957a..3001440 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus.c
@@ -47,6 +47,7 @@ static int sunxi_cedrus_s_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct sunxi_cedrus_ctx, hdl);
switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_MPEG4_FRAME_HDR:
case V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR:
/* This is kept in memory and used directly. */
break;
@@ -71,6 +72,15 @@ static const struct v4l2_ctrl_config sunxi_cedrus_ctrl_mpeg2_frame_hdr = {
.elem_size = sizeof(struct v4l2_ctrl_mpeg2_frame_hdr),
};
+static const struct v4l2_ctrl_config sunxi_cedrus_ctrl_mpeg4_frame_hdr = {
+ .ops = &sunxi_cedrus_ctrl_ops,
+ .id = V4L2_CID_MPEG_VIDEO_MPEG4_FRAME_HDR,
+ .type = V4L2_CTRL_TYPE_PRIVATE,
+ .name = "MPEG4 Frame Header Parameters",
+ .max_reqs = VIDEO_MAX_FRAME,
+ .elem_size = sizeof(struct v4l2_ctrl_mpeg4_frame_hdr),
+};
+
/*
* File operations
*/
@@ -99,6 +109,10 @@ static int sunxi_cedrus_open(struct file *file)
&sunxi_cedrus_ctrl_mpeg2_frame_hdr, NULL);
ctx->mpeg2_frame_hdr_ctrl->flags |= V4L2_CTRL_FLAG_REQ_KEEP;
+ ctx->mpeg4_frame_hdr_ctrl = v4l2_ctrl_new_custom(hdl,
+ &sunxi_cedrus_ctrl_mpeg4_frame_hdr, NULL);
+ ctx->mpeg4_frame_hdr_ctrl->flags |= V4L2_CTRL_FLAG_REQ_KEEP;
+
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -139,6 +153,7 @@ static int sunxi_cedrus_release(struct file *file)
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
ctx->mpeg2_frame_hdr_ctrl = NULL;
+ ctx->mpeg4_frame_hdr_ctrl = NULL;
mutex_lock(&dev->dev_mutex);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(&dev->dev_mutex);
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
index e715184..33fa891 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_common.h
@@ -49,6 +49,18 @@ struct sunxi_cedrus_dev {
struct reset_control *rstc;
char *base;
+
+ unsigned int mbh_buf;
+ unsigned int dcac_buf;
+ unsigned int ncf_buf;
+
+ void *mbh_buf_virt;
+ void *dcac_buf_virt;
+ void *ncf_buf_virt;
+
+ unsigned int mbh_buf_size;
+ unsigned int dcac_buf_size;
+ unsigned int ncf_buf_size;
};
struct sunxi_cedrus_fmt {
@@ -72,6 +84,7 @@ struct sunxi_cedrus_ctx {
struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
struct v4l2_ctrl *mpeg2_frame_hdr_ctrl;
+ struct v4l2_ctrl *mpeg4_frame_hdr_ctrl;
};
static inline void sunxi_cedrus_write(struct sunxi_cedrus_dev *vpu,
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
index 38e8a3a..8ce635d 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_dec.c
@@ -53,6 +53,11 @@ static struct sunxi_cedrus_fmt formats[] = {
.types = SUNXI_CEDRUS_OUTPUT,
.num_planes = 1,
},
+ {
+ .fourcc = V4L2_PIX_FMT_MPEG4_FRAME,
+ .types = SUNXI_CEDRUS_OUTPUT,
+ .num_planes = 1,
+ },
};
#define NUM_FORMATS ARRAY_SIZE(formats)
@@ -129,6 +134,10 @@ void device_run(void *priv)
struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr =
ctx->mpeg2_frame_hdr_ctrl->p_new.p;
process_mpeg2(ctx, in_buf, out_luma, out_chroma, frame_hdr);
+ } else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG4_FRAME) {
+ struct v4l2_ctrl_mpeg4_frame_hdr *frame_hdr =
+ ctx->mpeg4_frame_hdr_ctrl->p_new.p;
+ process_mpeg4(ctx, in_buf, out_luma, out_chroma, frame_hdr);
} else {
v4l2_m2m_buf_done(in_vb, VB2_BUF_STATE_ERROR);
v4l2_m2m_buf_done(out_vb, VB2_BUF_STATE_ERROR);
@@ -306,8 +315,32 @@ static int vidioc_s_fmt(struct sunxi_cedrus_ctx *ctx, struct v4l2_format *f)
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (ctx->vpu_src_fmt && ctx->vpu_src_fmt->fourcc ==
+ V4L2_PIX_FMT_MPEG4_FRAME && dev->mbh_buf_virt) {
+ dma_free_coherent(dev->dev, dev->mbh_buf_size,
+ dev->mbh_buf_virt, dev->mbh_buf);
+ dma_free_coherent(dev->dev, dev->dcac_buf_size,
+ dev->dcac_buf_virt, dev->dcac_buf);
+ dma_free_coherent(dev->dev, dev->ncf_buf_size,
+ dev->ncf_buf_virt, dev->ncf_buf);
+ }
+
ctx->vpu_src_fmt = find_format(f);
ctx->src_fmt = *pix_fmt_mp;
+
+ if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG4_FRAME) {
+ dev->mbh_buf_size = pix_fmt_mp->height * 2048;
+ dev->dcac_buf_size = 2 * pix_fmt_mp->width *
+ pix_fmt_mp->height;
+ dev->ncf_buf_size = 4 * 1024;
+
+ dev->mbh_buf_virt = dma_alloc_coherent(dev->dev,
+ dev->mbh_buf_size, &dev->mbh_buf, GFP_KERNEL);
+ dev->dcac_buf_virt = dma_alloc_coherent(dev->dev,
+ dev->dcac_buf_size, &dev->dcac_buf, GFP_KERNEL);
+ dev->ncf_buf_virt = dma_alloc_coherent(dev->dev,
+ dev->ncf_buf_size, &dev->ncf_buf, GFP_KERNEL);
+ }
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
fmt = find_format(f);
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
index 78625e5..d5f8b47 100644
--- a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_hw.h
@@ -32,5 +32,8 @@ void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *vpu);
void process_mpeg2(struct sunxi_cedrus_ctx *ctx, dma_addr_t in_buf,
dma_addr_t out_luma, dma_addr_t out_chroma,
struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr);
+void process_mpeg4(struct sunxi_cedrus_ctx *ctx, dma_addr_t in_buf,
+ dma_addr_t out_luma, dma_addr_t out_chroma,
+ struct v4l2_ctrl_mpeg4_frame_hdr *frame_hdr);
#endif /* SUNXI_CEDRUS_HW_H_ */
diff --git a/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg4.c b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg4.c
new file mode 100644
index 0000000..656fb6f
--- /dev/null
+++ b/drivers/media/platform/sunxi-cedrus/sunxi_cedrus_mpeg4.c
@@ -0,0 +1,140 @@
+/*
+ * Sunxi Cedrus codec driver
+ *
+ * Copyright (C) 2016 Florent Revest
+ * Florent Revest <florent.revest@free-electrons.com>
+ *
+ * Based on reverse engineering efforts of the 'Cedrus' project
+ * Copyright (c) 2013-2014 Jens Kuske <jenskuske@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sunxi_cedrus_common.h"
+
+#include <media/videobuf2-dma-contig.h>
+
+#define VOP_I 0
+#define VOP_P 1
+#define VOP_B 2
+#define VOP_S 3
+
+void process_mpeg4(struct sunxi_cedrus_ctx *ctx, dma_addr_t in_buf,
+ dma_addr_t out_luma, dma_addr_t out_chroma,
+ struct v4l2_ctrl_mpeg4_frame_hdr *frame_hdr)
+{
+ struct sunxi_cedrus_dev *dev = ctx->dev;
+
+ u16 width = DIV_ROUND_UP(frame_hdr->width, 16);
+ u16 height = DIV_ROUND_UP(frame_hdr->height, 16);
+
+ u32 vop_header = 0;
+ u32 vld_len = frame_hdr->slice_len - frame_hdr->slice_pos;
+
+ struct vb2_buffer *fwd_vb2_buf, *bwd_vb2_buf;
+ dma_addr_t fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
+
+ /*
+ * The VPU is only able to handle bus addresses so we have to subtract
+ * the RAM offset to the physcal addresses
+ */
+ fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_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);
+ fwd_luma -= PHYS_OFFSET;
+ fwd_chroma -= PHYS_OFFSET;
+ }
+
+ bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_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);
+ bwd_chroma -= PHYS_OFFSET;
+ bwd_luma -= PHYS_OFFSET;
+ }
+
+ /* Activates MPEG engine */
+ sunxi_cedrus_write(dev, VE_CTRL_MPEG, VE_CTRL);
+
+ /* Quantization parameter */
+ sunxi_cedrus_write(dev, frame_hdr->quant_scale, VE_MPEG_QP_INPUT);
+
+ /* Intermediate buffers needed by the VPU */
+ sunxi_cedrus_write(dev, dev->mbh_buf - PHYS_OFFSET, VE_MPEG_MBH_ADDR);
+ sunxi_cedrus_write(dev, dev->dcac_buf - PHYS_OFFSET, VE_MPEG_DCAC_ADDR);
+ sunxi_cedrus_write(dev, dev->ncf_buf - PHYS_OFFSET, VE_MPEG_NCF_ADDR);
+
+ /* Image's dimensions */
+ sunxi_cedrus_write(dev, width << 8 | height, VE_MPEG_SIZE);
+ sunxi_cedrus_write(dev, width << 20 | height << 4, VE_MPEG_FRAME_SIZE);
+
+ /* MPEG VOP's header */
+ vop_header |= (frame_hdr->vop_fields.vop_coding_type == VOP_B) << 28;
+ vop_header |= frame_hdr->vol_fields.quant_type << 24;
+ vop_header |= frame_hdr->vol_fields.quarter_sample << 23;
+ vop_header |= frame_hdr->vol_fields.resync_marker_disable << 22;
+ vop_header |= frame_hdr->vop_fields.vop_coding_type << 18;
+ vop_header |= frame_hdr->vop_fields.vop_rounding_type << 17;
+ vop_header |= frame_hdr->vop_fields.intra_dc_vlc_thr << 8;
+ vop_header |= frame_hdr->vop_fields.top_field_first << 7;
+ vop_header |= frame_hdr->vop_fields.alternate_vertical_scan_flag << 6;
+ if (frame_hdr->vop_fields.vop_coding_type != VOP_I)
+ vop_header |= frame_hdr->vop_fcode_forward << 3;
+ if (frame_hdr->vop_fields.vop_coding_type == VOP_B)
+ vop_header |= frame_hdr->vop_fcode_backward << 0;
+ sunxi_cedrus_write(dev, vop_header, VE_MPEG_VOP_HDR);
+
+ /* Enable interrupt and an unknown control flag */
+ if (frame_hdr->vop_fields.vop_coding_type == VOP_P)
+ sunxi_cedrus_write(dev, VE_MPEG_CTRL_MPEG4_P, VE_MPEG_CTRL);
+ else
+ sunxi_cedrus_write(dev, VE_MPEG_CTRL_MPEG4, VE_MPEG_CTRL);
+
+ /* Temporal distances of B frames */
+ if (frame_hdr->vop_fields.vop_coding_type == VOP_B) {
+ u32 trbtrd = (frame_hdr->trb << 16) | frame_hdr->trd;
+
+ sunxi_cedrus_write(dev, trbtrd, VE_MPEG_TRBTRD_FRAME);
+ sunxi_cedrus_write(dev, 0, VE_MPEG_TRBTRD_FIELD);
+ }
+
+ /* Don't rotate or scale buffer */
+ sunxi_cedrus_write(dev, VE_NO_SDROT_CTRL, VE_MPEG_SDROT_CTRL);
+
+ /* Macroblock number */
+ sunxi_cedrus_write(dev, 0, VE_MPEG_MBA);
+
+ /* Clear previous status */
+ sunxi_cedrus_write(dev, 0xffffffff, VE_MPEG_STATUS);
+
+ /* Forward and backward prediction buffers (cached in dst_bufs) */
+ sunxi_cedrus_write(dev, fwd_luma, VE_MPEG_FWD_LUMA);
+ sunxi_cedrus_write(dev, fwd_chroma, VE_MPEG_FWD_CHROMA);
+ sunxi_cedrus_write(dev, bwd_luma, VE_MPEG_BACK_LUMA);
+ sunxi_cedrus_write(dev, bwd_chroma, VE_MPEG_BACK_CHROMA);
+
+ /* Output luma and chroma buffers */
+ sunxi_cedrus_write(dev, out_luma, VE_MPEG_REC_LUMA);
+ sunxi_cedrus_write(dev, out_chroma, VE_MPEG_REC_CHROMA);
+ sunxi_cedrus_write(dev, out_luma, VE_MPEG_ROT_LUMA);
+ sunxi_cedrus_write(dev, out_chroma, VE_MPEG_ROT_CHROMA);
+
+ /* Input offset and length in bits */
+ sunxi_cedrus_write(dev, frame_hdr->slice_pos, VE_MPEG_VLD_OFFSET);
+ sunxi_cedrus_write(dev, vld_len, VE_MPEG_VLD_LEN);
+
+ /* Input beginning and end addresses */
+ sunxi_cedrus_write(dev, VE_MPEG_VLD_ADDR_VAL(in_buf), VE_MPEG_VLD_ADDR);
+ sunxi_cedrus_write(dev, in_buf + VBV_SIZE - 1, VE_MPEG_VLD_END);
+
+ /* Starts the MPEG engine */
+ sunxi_cedrus_write(dev, VE_TRIG_MPEG4(width, height), VE_MPEG_TRIGGER);
+}
From patchwork Thu Aug 25 09:39:48 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711056
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1759295AbcHYJkv (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:51 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34220 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758997AbcHYJk2 (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:28 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 09/10] ARM: dts: sun5i: Use video-engine node
Date: Thu, 25 Aug 2016 11:39:48 +0200
Message-Id:
<1472117989-21455-10-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 1480
Lines: 63
Now that we have a driver matching "allwinner,sun5i-a13-video-engine" we
can load it.
The "video-engine" node depends on the new sunxi-ng's CCU clock and
reset bindings. This patch also includes a ve_reserved DMA pool for
videobuf2 buffer allocations in sunxi-cedrus.
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
arch/arm/boot/dts/sun5i-a13.dtsi | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 2afe05fb..384b645 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -69,6 +69,19 @@
};
};
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ ve_reserved: cma {
+ compatible = "shared-dma-pool";
+ reg = <0x43d00000 0x9000000>;
+ no-map;
+ linux,cma-default;
+ };
+ };
+
thermal-zones {
cpu_thermal {
/* milliseconds */
@@ -330,6 +343,24 @@
};
};
+ video-engine {
+ compatible = "allwinner,sun5i-a13-video-engine";
+ memory-region = <&ve_reserved>;
+
+ clocks = <&ahb_gates 32>, <&ccu CLK_VE>,
+ <&dram_gates 0>;
+ clock-names = "ahb", "mod", "ram";
+
+ assigned-clocks = <&ccu CLK_VE>;
+ assigned-clock-rates = <320000000>;
+
+ resets = <&ccu RST_VE>;
+
+ interrupts = <53>;
+
+ reg = <0x01c0e000 4096>;
+ };
+
ccu: clock@01c20000 {
compatible = "allwinner,sun5i-a13-ccu";
reg = <0x01c20000 0x400>;
From patchwork Thu Aug 25 09:39:49 2016
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
X-Patchwork-Submitter: Florent Revest <florent.revest@free-electrons.com>
X-Patchwork-Id: 711053
Return-Path: <linux-kernel-owner@vger.kernel.org>
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1759049AbcHYJka (ORCPT <rfc822;w@1wt.eu>);
Thu, 25 Aug 2016 05:40:30 -0400
Received: from down.free-electrons.com ([37.187.137.238]:34209 "EHLO
mail.free-electrons.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org
with ESMTP id S1758962AbcHYJk0 (ORCPT
<rfc822;linux-kernel@vger.kernel.org>);
Thu, 25 Aug 2016 05:40:26 -0400
From: Florent Revest <florent.revest@free-electrons.com>
To: linux-media@vger.kernel.org
Cc: florent.revest@free-electrons.com, linux-sunxi@googlegroups.com,
maxime.ripard@free-electrons.com, posciak@chromium.org,
hans.verkuil@cisco.com, thomas.petazzoni@free-electrons.com,
mchehab@kernel.org, linux-kernel@vger.kernel.org, wens@csie.org
Subject: [RFC 10/10] sunxi-cedrus: Add device tree binding document
Date: Thu, 25 Aug 2016 11:39:49 +0200
Message-Id:
<1472117989-21455-11-git-send-email-florent.revest@free-electrons.com>
X-Mailer: git-send-email 2.7.4
In-Reply-To:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
References:
<1472117989-21455-1-git-send-email-florent.revest@free-electrons.com>
Sender: linux-kernel-owner@vger.kernel.org
List-ID: <linux-kernel.vger.kernel.org>
X-Mailing-List: linux-kernel@vger.kernel.org
Content-Length: 1708
Lines: 60
Device Tree bindings for the Allwinner's video engine
Signed-off-by: Florent Revest <florent.revest@free-electrons.com>
---
.../devicetree/bindings/media/sunxi-cedrus.txt | 44 ++++++++++++++++++++++
1 file changed, 44 insertions(+)
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 0000000..26f2e09
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/sunxi-cedrus.txt
@@ -0,0 +1,44 @@
+Device-Tree bindings for SUNXI video engine found in sunXi SoC family
+
+Required properties:
+- compatible : "allwinner,sun5i-a13-video-engine";
+- memory-region : DMA pool for buffers allocation;
+- clocks : list of clock specifiers, corresponding to
+ entries in clock-names property;
+- clock-names : should contain "ahb", "mod" and "ram" entries;
+- resets : phandle for reset;
+- interrupts : should contain VE interrupt number;
+- reg : should contain register base and length of VE.
+
+Example:
+
+reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ ve_reserved: cma {
+ compatible = "shared-dma-pool";
+ reg = <0x43d00000 0x9000000>;
+ no-map;
+ linux,cma-default;
+ };
+};
+
+video-engine {
+ compatible = "allwinner,sun5i-a13-video-engine";
+ memory-region = <&ve_reserved>;
+
+ clocks = <&ahb_gates 32>, <&ccu CLK_VE>,
+ <&dram_gates 0>;
+ clock-names = "ahb", "mod", "ram";
+
+ assigned-clocks = <&ccu CLK_VE>;
+ assigned-clock-rates = <320000000>;
+
+ resets = <&ccu RST_VE>;
+
+ interrupts = <53>;
+
+ reg = <0x01c0e000 4096>;
+};