* [PATCHv4 4/7] dt-bindings: fpga: add Stratix10 SoC FPGA manager binding
From: Rob Herring @ 2018-05-07 16:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-5-git-send-email-richard.gong@linux.intel.com>
On Fri, May 04, 2018 at 09:21:34AM -0500, richard.gong at linux.intel.com wrote:
> From: Alan Tull <atull@kernel.org>
>
> Add a Device Tree binding for the Intel Stratix10 SoC FPGA manager.
>
> Signed-off-by: Alan Tull <atull@kernel.org>
> Signed-off-by: Richard Gong <richard.gong@intel.com>
> ---
> v2: this patch is added in patch set version 2
> v3: change to put fpga_mgr node under firmware/svc node
> v4: s/fpga-mgr at 0/fpga-mgr/ to remove unit_address
> Add Richard's signed-off-by
> ---
> .../bindings/fpga/intel-stratix10-soc-fpga-mgr.txt | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH v5 10/14] dt-bindings: qcom_spmi: Add support for SAW documentation
From: Rob Herring @ 2018-05-07 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525348355-25471-11-git-send-email-ilialin@codeaurora.org>
On Thu, May 03, 2018 at 02:52:31PM +0300, Ilia Lin wrote:
> Add support for SAW controlled regulators.
> The regulators defined as SAW controlled in the device tree
> will be controlled through special CPU registers instead of direct
> SPMI accesses.
> This is required especially for CPU supply regulators to synchronize
> with clock scaling and for Automatic Voltage Switching.
> Document it.
>
> Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
> ---
> .../bindings/regulator/qcom,spmi-regulator.txt | 45 ++++++++++++++++++++++
> 1 file changed, 45 insertions(+)
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH v3 11/14] media: platform: Add Sunxi-Cedrus VPU decoder driver
From: Maxime Ripard @ 2018-05-07 15:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507124500.20434-12-paul.kocialkowski@bootlin.com>
On Mon, May 07, 2018 at 02:44:57PM +0200, Paul Kocialkowski wrote:
> +#define SYSCON_SRAM_CTRL_REG0 0x0
> +#define SYSCON_SRAM_C1_MAP_VE 0x7fffffff
This isn't needed anymore
> + dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
> + if (IS_ERR(dev->ahb_clk)) {
> + dev_err(dev->dev, "failed to get ahb clock\n");
> + return PTR_ERR(dev->ahb_clk);
> + }
> + dev->mod_clk = devm_clk_get(dev->dev, "mod");
> + if (IS_ERR(dev->mod_clk)) {
> + dev_err(dev->dev, "failed to get mod clock\n");
> + return PTR_ERR(dev->mod_clk);
> + }
> + dev->ram_clk = devm_clk_get(dev->dev, "ram");
> + if (IS_ERR(dev->ram_clk)) {
> + dev_err(dev->dev, "failed to get ram clock\n");
> + return PTR_ERR(dev->ram_clk);
> + }
Please add some blank lines between those blocks
> + dev->rstc = devm_reset_control_get(dev->dev, NULL);
You're not checking the error code here
> + dev->syscon = syscon_regmap_lookup_by_phandle(dev->dev->of_node,
> + "syscon");
> + if (IS_ERR(dev->syscon)) {
> + dev->syscon = NULL;
> + } else {
> + regmap_write_bits(dev->syscon, SYSCON_SRAM_CTRL_REG0,
> + SYSCON_SRAM_C1_MAP_VE,
> + SYSCON_SRAM_C1_MAP_VE);
> + }
You don't need the syscon part anymore either
> + ret = clk_prepare_enable(dev->ahb_clk);
> + if (ret) {
> + dev_err(dev->dev, "could not enable ahb clock\n");
> + return -EFAULT;
> + }
> + ret = clk_prepare_enable(dev->mod_clk);
> + if (ret) {
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not enable mod clock\n");
> + return -EFAULT;
> + }
> + ret = clk_prepare_enable(dev->ram_clk);
> + if (ret) {
> + clk_disable_unprepare(dev->mod_clk);
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not enable ram clock\n");
> + return -EFAULT;
> + }
> +
> + ret = reset_control_reset(dev->rstc);
> + if (ret) {
> + clk_disable_unprepare(dev->ram_clk);
> + clk_disable_unprepare(dev->mod_clk);
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not reset device\n");
> + return -EFAULT;
labels would simplify this greatly, and you should also release the
sram and the memory region here.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [GIT PULL] one bug fix and few other fixes for v4.17-rc cycle
From: Tony Lindgren @ 2018-05-07 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAHCN7xJ8yAU=zjJuS6rPh61qNuRc7nr2e+i0z-YHCZQREcs0Yg@mail.gmail.com>
* Adam Ford <aford173@gmail.com> [180505 23:45]:
> On Sat, May 5, 2018 at 2:43 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Tony Lindgren <tony@atomide.com> [180504 15:51]:
> >> From: "Tony Lindgren" <tony@atomide.com>
> >>
> >> The following changes since commit fb289e3ab10c16834741bb02be740fa9d025fde0:
> >>
> >> Merge branch 'omap-for-v4.17/fixes-ti-sysc' into omap-for-v4.17/fixes (2018-04-19 15:48:46 -0700)
> >>
> >> are available in the Git repository at:
> >>
> >> git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap tags/omap-for-v4.17/fixes-rc3
> >>
> >> for you to fetch changes up to 647efef69de483f1dd7944ede31b4cae16acb124:
> >>
> >> ARM: dts: correct missing "compatible" entry for ti81xx SoCs (2018-05-03 10:07:47 -0700)
> >>
> >> ----------------------------------------------------------------
> >> Fixes for omap variants for v4.17-rc cycle
> >>
> >> This series of patches contains one BUG fix for trace if
> >> CONFIG_DEBUG_PREEMPT is enabled and a regression fix for omap1
> >> FIQ handling on ams-delta. Then there's a dts fix for missing SoC
> >> compatible on ti81xx board dts files that did matter until we added
> >> the clkctrl clocks and without that some clocks are now not found.
> >>
> >> Then there are three minor logicpd-som-lv specific dts fixes that
> >> fix misconfigured pins for WLAN, audio and USB.
> >>
> >> ----------------------------------------------------------------
> >> Adam Ford (3):
> >> ARM: dts: logicpd-som-lv: Fix WL127x Startup Issues
> >> ARM: dts: logicpd-som-lv: Fix Audio Mute
> >> ARM: dts: logicpd-som-lv: Fix pinmux controller references
> >
> > Adam emailled that one of these has a side effect for breaking
> > USB. So let's not use this pull request if not yet merged, I'll
> > send an updated pull request early next week.
> >
> The WL127x and Audio patches are good, but pinmux controller fails on
> cold-boot, so I'd like to revert that one.
OK reverted and pushed out omap-for-v4.17/fixes. Can you please
test that branch and make sure things are OK now?
Regards,
Tony
^ permalink raw reply
* [PATCH v2 1/2] clk: davinci: pll-dm355: fix SYSCLKn parent names
From: Sekhar Nori @ 2018-05-07 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507144307.32364-1-david@lechnology.com>
On Monday 07 May 2018 08:13 PM, David Lechner wrote:
> This fixes the parent clock names of the SYSCLKn clocks for the DM355
> SoC in the TI DaVinici PLL clock driver.
>
> It appears that this name just didn't get updated to the correct name
> like the other SoCs during the driver's development.
>
> Reported-by: Sekhar Nori <nsekhar@ti.com>
> Signed-off-by: David Lechner <david@lechnology.com>
> ---
>
> v2 changes:
> - add second patch to fix additional problems with DM355
>
> drivers/clk/davinci/pll-dm355.c | 12 ++++++------
> 1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c
> index 5345f8286c50..1f746d2fc894 100644
> --- a/drivers/clk/davinci/pll-dm355.c
> +++ b/drivers/clk/davinci/pll-dm355.c
> @@ -22,10 +22,10 @@ static const struct davinci_pll_clk_info dm355_pll1_info = {
> PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
> };
>
> -SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
> -SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
> -SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED);
> -SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED);
> +SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
> +SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
> +SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
> +SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
>
> int dm355_pll1_init(struct device *dev, void __iomem *base)
> {
> @@ -62,8 +62,8 @@ static const struct davinci_pll_clk_info dm355_pll2_info = {
> PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
> };
>
> -SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV);
> -SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
> +SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV);
> +SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
Good find with PLL2 SYSCLK2. Can you reverse the patch order so we are
not fixing up a non-existent clock?
Thanks,
Sekhar
^ permalink raw reply
* [PATCH 5/5] arm64: allwinner: h6: enable USB3 port on Pine H64
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507151817.55663-1-icenowy@aosc.io>
Pine H64 board have a USB3 port, which is connected to the USB3 pins of
the H6 SoC, and the 5V power supply is controlled via GPIO (shared with
the power USB ports).
Enable this port.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
.../boot/dts/allwinner/sun50i-h6-pine-h64.dts | 23 +++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index b6f2d6b2ecae..e2e262b4e3d8 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -20,6 +20,20 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ reg_usb_vbus: vbus {
+ compatible = "regulator-fixed";
+ regulator-name = "usb-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <100000>;
+ gpio = <&r_pio 0 5 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+};
+
+&dwc3 {
+ status = "okay";
};
&r_i2c {
@@ -37,3 +51,12 @@
pinctrl-0 = <&uart0_ph_pins>;
status = "okay";
};
+
+&usb3 {
+ status = "okay";
+};
+
+&usb3phy {
+ phy-supply = <®_usb_vbus>;
+ status = "okay";
+};
--
2.17.0
^ permalink raw reply related
* [PATCH 4/5] arm64: allwinner: h6: add USB3 device nodes
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507151817.55663-1-icenowy@aosc.io>
Allwinner H6 SoC features USB3 functionality, with a DWC3 controller and
a custom PHY.
Add device tree nodes for them.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 38 ++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index c72da8cd9ef5..9564c938717c 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -174,6 +174,44 @@
status = "disabled";
};
+ usb3: usb at 5200000 {
+ compatible = "allwinner,sun50i-h6-dwc3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clocks = <&ccu CLK_BUS_XHCI>;
+ clock-names = "bus";
+ resets = <&ccu RST_BUS_XHCI>;
+ reset-names = "bus";
+ status = "disabled";
+
+ dwc3: dwc3 {
+ compatible = "snps,dwc3";
+ reg = <0x5200000 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ /*
+ * According to Wink from Allwinner, the
+ * USB3 port on H6 is not capable of OTG;
+ * the datasheet doesn't mention OTG at all
+ * either, so the dr_mode is default to
+ * "host" here.
+ */
+ dr_mode = "host";
+ phys = <&usb3phy>;
+ phy-names = "usb3-phy";
+ status = "disabled";
+ };
+ };
+
+ usb3phy: phy at 5210000 {
+ compatible = "allwinner,sun50i-h6-usb3-phy";
+ reg = <0x5210000 0x10000>;
+ clocks = <&ccu CLK_USB_PHY1>;
+ resets = <&ccu RST_USB_PHY1>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
+
r_ccu: clock at 7010000 {
compatible = "allwinner,sun50i-h6-r-ccu";
reg = <0x07010000 0x400>;
--
2.17.0
^ permalink raw reply related
* [PATCH 3/5] usb: dwc3: of-simple: Add compatible for Allwinner H6 platform
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507151817.55663-1-icenowy@aosc.io>
Add compatible string to use this generic glue layer to support
Allwinner H6 platform's dwc3 controller.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
drivers/usb/dwc3/dwc3-of-simple.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index cb2ee96fd3e8..a92a8e4c6b92 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -215,6 +215,7 @@ static const struct of_device_id of_dwc3_simple_match[] = {
{ .compatible = "sprd,sc9860-dwc3" },
{ .compatible = "amlogic,meson-axg-dwc3" },
{ .compatible = "amlogic,meson-gxl-dwc3" },
+ { .compatible = "allwinner,sun50i-h6-dwc3" },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, of_dwc3_simple_match);
--
2.17.0
^ permalink raw reply related
* [PATCH 2/5] dt-bindings: usb: add binding for the DWC3 controller on Allwinner SoC
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507151817.55663-1-icenowy@aosc.io>
The Allwinner H6 SoC uses DWC3 controller for USB3.
Add its device tree binding document.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
.../bindings/usb/allwinner,dwc3.txt | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 Documentation/devicetree/bindings/usb/allwinner,dwc3.txt
diff --git a/Documentation/devicetree/bindings/usb/allwinner,dwc3.txt b/Documentation/devicetree/bindings/usb/allwinner,dwc3.txt
new file mode 100644
index 000000000000..3f7714636785
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/allwinner,dwc3.txt
@@ -0,0 +1,39 @@
+Allwinner SuperSpeed DWC3 USB SoC controller
+
+Required properties:
+- compatible: should contain "allwinner,sun50i-h6-dwc3" for H6 SoC
+- clocks: A list of phandle + clock-specifier pairs for the
+ clocks listed in clock-names
+- clock-names: Should contain the following:
+ "bus" The bus clock of the DWC3 part
+- resets: A list of phandle + reset-specifier pairs for the
+ resets listed in reset-names
+- reset-names: Should contain the following:
+ "bus" The bus reset of the DWC3 part
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+Phy documentation is provided in the following places:
+Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt
+
+Example device nodes:
+ usb3: usb at 5200000 {
+ compatible = "allwinner,sun50i-h6-dwc3";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ clocks = <&ccu CLK_BUS_XHCI>;
+ clock-names = "bus";
+ resets = <&ccu RST_BUS_XHCI>;
+ reset-names = "bus";
+
+ dwc3: dwc3 {
+ compatible = "snps,dwc3";
+ reg = <0x5200000 0x10000>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usb3phy>;
+ phy-names = "usb3-phy";
+ };
+ };
--
2.17.0
^ permalink raw reply related
* [PATCH 1/5] phy: allwinner: add phy driver for USB3 PHY on Allwinner H6 SoC
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507151817.55663-1-icenowy@aosc.io>
Allwinner H6 SoC contains a USB3 PHY (with USB2 DP/DM lines also
controlled).
Add a driver for it.
The register operations in this driver is mainly extracted from the BSP
USB3 driver.
Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
.../bindings/phy/sun50i-usb3-phy.txt | 24 +++
drivers/phy/allwinner/Kconfig | 13 ++
drivers/phy/allwinner/Makefile | 1 +
drivers/phy/allwinner/phy-sun50i-usb3.c | 195 ++++++++++++++++++
4 files changed, 233 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt
create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c
diff --git a/Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt b/Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt
new file mode 100644
index 000000000000..912d55f9f69d
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt
@@ -0,0 +1,24 @@
+Allwinner sun50i USB3 PHY
+-----------------------
+
+Required properties:
+- compatible : should be one of
+ * allwinner,sun60i-h6-usb3-phy
+- reg : a list of offset + length pairs
+- #phy-cells : from the generic phy bindings, must be 0
+- clocks : phandle + clock specifier for the phy clock
+- resets : phandle + reset specifier for the phy reset
+
+Optional Properties:
+- phy-supply : from the generic phy bindings, a phandle to a regulator that
+ provides power to VBUS.
+
+Example:
+ usb3phy: phy at 5210000 {
+ compatible = "allwinner,sun50i-h6-usb3-phy";
+ reg = <0x5210000 0x10000>;
+ clocks = <&ccu CLK_USB_PHY1>;
+ resets = <&ccu RST_USB_PHY1>;
+ #phy-cells = <0>;
+ status = "disabled";
+ };
diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
index cdc1e745ba47..cf373bcee034 100644
--- a/drivers/phy/allwinner/Kconfig
+++ b/drivers/phy/allwinner/Kconfig
@@ -29,3 +29,16 @@ config PHY_SUN9I_USB
sun9i SoCs.
This driver controls each individual USB 2 host PHY.
+
+config PHY_SUN50I_USB3
+ tristate "Allwinner sun50i SoC USB3 PHY driver"
+ depends on ARCH_SUNXI && HAS_IOMEM && OF
+ depends on RESET_CONTROLLER
+ depends on USB_SUPPORT
+ select USB_COMMON
+ select GENERIC_PHY
+ help
+ Enable this to support the USB3.0-capable transceiver that is
+ part of some Allwinner sun50i SoCs.
+
+ This driver controls each individual USB 2+3 host PHY combo.
diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile
index 8605529c01a1..a8d01e9073c2 100644
--- a/drivers/phy/allwinner/Makefile
+++ b/drivers/phy/allwinner/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
+obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o
diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c
new file mode 100644
index 000000000000..000a3e04e6d1
--- /dev/null
+++ b/drivers/phy/allwinner/phy-sun50i-usb3.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Allwinner sun50i(H6) USB 3.0 phy driver
+ *
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on phy-sun9i-usb.c, which is:
+ *
+ * Copyright (C) 2014-2015 Chen-Yu Tsai <wens@csie.org>
+ *
+ * Based on code from Allwinner BSP, which is:
+ *
+ * Copyright (c) 2010-2015 Allwinner Technology Co., Ltd.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/* Interface Status and Control Registers */
+#define SUNXI_ISCR 0x00
+#define SUNXI_PIPE_CLOCK_CONTROL 0x14
+#define SUNXI_PHY_TUNE_LOW 0x18
+#define SUNXI_PHY_TUNE_HIGH 0x1c
+#define SUNXI_PHY_EXTERNAL_CONTROL 0x20
+
+/* USB2.0 Interface Status and Control Register */
+#define SUNXI_ISCR_FORCE_VBUS (3 << 12)
+
+/* PIPE Clock Control Register */
+#define SUNXI_PCC_PIPE_CLK_OPEN (1 << 6)
+
+/* PHY External Control Register */
+#define SUNXI_PEC_EXTERN_VBUS (3 << 1)
+#define SUNXI_PEC_SSC_EN (1 << 24)
+#define SUNXI_PEC_REF_SSP_EN (1 << 26)
+
+/* PHY Tune High Register */
+#define SUNXI_TX_DEEMPH_3P5DB(n) ((n) << 19)
+#define SUNXI_TX_DEEMPH_3P5DB_MASK GENMASK(24, 19)
+#define SUNXI_TX_DEEMPH_6DB(n) ((n) << 13)
+#define SUNXI_TX_DEEMPH_6GB_MASK GENMASK(18, 13)
+#define SUNXI_TX_SWING_FULL(n) ((n) << 6)
+#define SUNXI_TX_SWING_FULL_MASK GENMASK(12, 6)
+#define SUNXI_LOS_BIAS(n) ((n) << 3)
+#define SUNXI_LOS_BIAS_MASK GENMASK(5, 3)
+#define SUNXI_TXVBOOSTLVL(n) ((n) << 0)
+#define SUNXI_TXVBOOSTLVL_MASK GENMASK(0, 2)
+
+struct sun50i_usb3_phy {
+ struct phy *phy;
+ void __iomem *regs;
+ struct reset_control *reset;
+ struct clk *clk;
+};
+
+static void sun50i_usb3_phy_open(struct sun50i_usb3_phy *phy)
+{
+ u32 val;
+
+ val = readl(phy->regs + SUNXI_PHY_EXTERNAL_CONTROL);
+ val |= SUNXI_PEC_EXTERN_VBUS;
+ val |= SUNXI_PEC_SSC_EN | SUNXI_PEC_REF_SSP_EN;
+ writel(val, phy->regs + SUNXI_PHY_EXTERNAL_CONTROL);
+
+ val = readl(phy->regs + SUNXI_PIPE_CLOCK_CONTROL);
+ val |= SUNXI_PCC_PIPE_CLK_OPEN;
+ writel(val, phy->regs + SUNXI_PIPE_CLOCK_CONTROL);
+
+ val = readl(phy->regs + SUNXI_ISCR);
+ val |= SUNXI_ISCR_FORCE_VBUS;
+ writel(val, phy->regs + SUNXI_ISCR);
+
+ /*
+ * All the magic numbers written to the PHY_TUNE_{LOW_HIGH}
+ * registers are directly taken from the BSP USB3 driver from
+ * Allwiner.
+ */
+ writel(0x0047fc87, phy->regs + SUNXI_PHY_TUNE_LOW);
+
+ val = readl(phy->regs + SUNXI_PHY_TUNE_HIGH);
+ val &= ~(SUNXI_TXVBOOSTLVL_MASK | SUNXI_LOS_BIAS_MASK |
+ SUNXI_TX_SWING_FULL_MASK | SUNXI_TX_DEEMPH_6GB_MASK |
+ SUNXI_TX_DEEMPH_3P5DB_MASK);
+ val |= SUNXI_TXVBOOSTLVL(0x7);
+ val |= SUNXI_LOS_BIAS(0x7);
+ val |= SUNXI_TX_SWING_FULL(0x55);
+ val |= SUNXI_TX_DEEMPH_6DB(0x20);
+ val |= SUNXI_TX_DEEMPH_3P5DB(0x15);
+ writel(val, phy->regs + SUNXI_PHY_TUNE_HIGH);
+}
+
+static int sun50i_usb3_phy_init(struct phy *_phy)
+{
+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy);
+ int ret;
+
+ ret = clk_prepare_enable(phy->clk);
+ if (ret)
+ goto err_clk;
+
+ ret = reset_control_deassert(phy->reset);
+ if (ret)
+ goto err_reset;
+
+ sun50i_usb3_phy_open(phy);
+ return 0;
+
+err_reset:
+ clk_disable_unprepare(phy->clk);
+
+err_clk:
+ return ret;
+}
+
+static int sun50i_usb3_phy_exit(struct phy *_phy)
+{
+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy);
+
+ reset_control_assert(phy->reset);
+ clk_disable_unprepare(phy->clk);
+
+ return 0;
+}
+
+static const struct phy_ops sun50i_usb3_phy_ops = {
+ .init = sun50i_usb3_phy_init,
+ .exit = sun50i_usb3_phy_exit,
+ .owner = THIS_MODULE,
+};
+
+static int sun50i_usb3_phy_probe(struct platform_device *pdev)
+{
+ struct sun50i_usb3_phy *phy;
+ struct device *dev = &pdev->dev;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(phy->clk)) {
+ dev_err(dev, "failed to get phy clock\n");
+ return PTR_ERR(phy->clk);
+ }
+
+ phy->reset = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(phy->reset)) {
+ dev_err(dev, "failed to get reset control\n");
+ return PTR_ERR(phy->reset);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ phy->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(phy->regs))
+ return PTR_ERR(phy->regs);
+
+ phy->phy = devm_phy_create(dev, NULL, &sun50i_usb3_phy_ops);
+ if (IS_ERR(phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(phy->phy);
+ }
+
+ phy_set_drvdata(phy->phy, phy);
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id sun50i_usb3_phy_of_match[] = {
+ { .compatible = "allwinner,sun50i-h6-usb3-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sun50i_usb3_phy_of_match);
+
+static struct platform_driver sun50i_usb3_phy_driver = {
+ .probe = sun50i_usb3_phy_probe,
+ .driver = {
+ .of_match_table = sun50i_usb3_phy_of_match,
+ .name = "sun50i-usb3-phy",
+ }
+};
+module_platform_driver(sun50i_usb3_phy_driver);
+
+MODULE_DESCRIPTION("Allwinner sun50i USB 3.0 phy driver");
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_LICENSE("GPL");
--
2.17.0
^ permalink raw reply related
* [PATCH 0/5] Allwinner H6 USB3 support
From: Icenowy Zheng @ 2018-05-07 15:18 UTC (permalink / raw)
To: linux-arm-kernel
This patchset contains USB3 support for Allwinner H6 SoC (DWC3 with a custom PHY).
The first patch adds the PHY driver, and the second/third patch adds
compatible to adapt DWC3 platform glue to Allwinner platform. The last
two patches are DT changes.
Icenowy Zheng (5):
phy: allwinner: add phy driver for USB3 PHY on Allwinner H6 SoC
dt-bindings: usb: add binding for the DWC3 controller on Allwinner SoC
usb: dwc3: of-simple: Add compatible for Allwinner H6 platform
arm64: allwinner: h6: add USB3 device nodes
arm64: allwinner: h6: enable USB3 port on Pine H64
.../bindings/phy/sun50i-usb3-phy.txt | 24 +++
.../bindings/usb/allwinner,dwc3.txt | 39 ++++
.../boot/dts/allwinner/sun50i-h6-pine-h64.dts | 23 +++
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 38 ++++
drivers/phy/allwinner/Kconfig | 13 ++
drivers/phy/allwinner/Makefile | 1 +
drivers/phy/allwinner/phy-sun50i-usb3.c | 195 ++++++++++++++++++
drivers/usb/dwc3/dwc3-of-simple.c | 1 +
8 files changed, 334 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/sun50i-usb3-phy.txt
create mode 100644 Documentation/devicetree/bindings/usb/allwinner,dwc3.txt
create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c
--
2.17.0
^ permalink raw reply
* [Tee-dev] [PATCH] tee: shm: fix use-after-free via temporarily dropped reference
From: Volodymyr Babchuk @ 2018-05-07 14:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507095841.6452-1-jens.wiklander@linaro.org>
Hi Jens,
On 7 May 2018 at 12:58, Jens Wiklander <jens.wiklander@linaro.org> wrote:
> From: Jann Horn <jannh@google.com>
>
> Bump the file's refcount before moving the reference into the fd table,
> not afterwards. The old code could drop the file's refcount to zero for a
> short moment before calling get_file() via get_dma_buf().
>
> This code can only be triggered on ARM systems that use Linaro's OP-TEE.
>
> Fixes: 967c9cca2cc5 ("tee: generic TEE subsystem")
> Signed-off-by: Jann Horn <jannh@google.com>
> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Volodymyr Babchuk <vlad.babchuk@gmail.com>
--
WBR Volodymyr Babchuk aka lorc [+380976646013]
mailto: vlad.babchuk at gmail.com
^ permalink raw reply
* [PATCH v3 00/14] Sunxi-Cedrus driver for the Allwinner Video Engine, using media requests
From: Paul Kocialkowski @ 2018-05-07 14:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507124500.20434-1-paul.kocialkowski@bootlin.com>
[...]
On Mon, 2018-05-07 at 14:44 +0200, Paul Kocialkowski wrote:
> Remaining tasks:
> * cleaning up registers description and documenting the fields used;
> * removing the assigned-clocks property and setting the clock rate
> in the driver directly;
> * checking the series with checkpatch and fixing warnings;
> * documenting the MB32 NV12 format and adding it to v4l_fill_fmtdesc;
> * reworking and documenting the MPEG2 header, then adding it to
> v4l_fill_fmtdesc;
> * checking and fixing the error paths;
> * testing on more platforms.
Another item for the tasks list that is not yet in this revision:
* changing the id for V4L2_CTRL_TYPE_MPEG2_FRAME_HDR\x0f;
Paul
> Cheers!
>
> [0]: https://patchwork.kernel.org/patch/9299073/
> [1]: https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=reqv13
>
> Florent Revest (1):
> media: v4l: Add definitions for MPEG2 frame format and header metadata
>
> Maxime Ripard (4):
> drivers: soc: sunxi: Add support for the C1 SRAM region
> ARM: sun5i: Add support for the C1 SRAM region with the SRAM
> controller
> ARM: sun7i-a20: Add support for the C1 SRAM region with the SRAM
> controller
> ARM: sun8i-a33: Add SRAM controller node and C1 SRAM region
>
> Paul Kocialkowski (9):
> drivers: soc: sunxi: Add dedicated compatibles for the A13, A20 and
> A33
> ARM: dts: sun5i: Use dedicated SRAM controller compatible
> ARM: dts: sun7i-a20: Use dedicated SRAM controller compatible
> media: v4l: Add definition for Allwinner's MB32-tiled NV12 format
> dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
> media: platform: Add Sunxi-Cedrus VPU decoder driver
> ARM: dts: sun5i: Add Video Engine and reserved memory nodes
> ARM: dts: sun7i-a20: Add Video Engine and reserved memory nodes
> ARM: dts: sun8i-a33: Add Video Engine and reserved memory nodes
>
> .../devicetree/bindings/media/sunxi-cedrus.txt | 58 +++
> MAINTAINERS | 7 +
> arch/arm/boot/dts/sun5i.dtsi | 47 +-
> arch/arm/boot/dts/sun7i-a20.dtsi | 47 +-
> arch/arm/boot/dts/sun8i-a33.dtsi | 54 +++
> drivers/media/platform/Kconfig | 15 +
> drivers/media/platform/Makefile | 1 +
> drivers/media/platform/sunxi/cedrus/Makefile | 4 +
> drivers/media/platform/sunxi/cedrus/sunxi_cedrus.c | 333 ++++++++++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_common.h | 128 ++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_dec.c | 188 ++++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_dec.h | 35 ++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_hw.c | 240 ++++++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_hw.h | 37 ++
> .../platform/sunxi/cedrus/sunxi_cedrus_mpeg2.c | 160 +++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h | 33 ++
> .../platform/sunxi/cedrus/sunxi_cedrus_regs.h | 175 +++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_video.c | 505 +++++++++++++++++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_video.h | 31 ++
> drivers/media/v4l2-core/v4l2-ctrls.c | 10 +
> drivers/media/v4l2-core/v4l2-ioctl.c | 1 +
> drivers/soc/sunxi/sunxi_sram.c | 13 +
> include/uapi/linux/v4l2-controls.h | 26 ++
> include/uapi/linux/videodev2.h | 4 +
> 24 files changed, 2150 insertions(+), 2 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt
> 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_mpeg2.c
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_regs.h
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.c
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.h
>
--
Paul Kocialkowski, Bootlin (formerly Free Electrons)
Embedded Linux and kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: This is a digitally signed message part
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180507/deac3f09/attachment-0001.sig>
^ permalink raw reply
* [PATCH v2 2/2] clk: davinci: pll-dm355: drop pll2_sysclk2
From: David Lechner @ 2018-05-07 14:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507144307.32364-1-david@lechnology.com>
This removes pll2_sysclk2 from the TI DM355 clock driver. This SoC
doesn't have such a clock. Also, SYSCLK_ALWAYS_ENABLED is transferred
to pll2_sysclk1 since it drives the DDR and doesn't have another
mechanism to keep it on.
Reported-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: David Lechner <david@lechnology.com>
---
drivers/clk/davinci/pll-dm355.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c
index 1f746d2fc894..93f4a53d6b44 100644
--- a/drivers/clk/davinci/pll-dm355.c
+++ b/drivers/clk/davinci/pll-dm355.c
@@ -62,8 +62,7 @@ static const struct davinci_pll_clk_info dm355_pll2_info = {
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
};
-SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV);
-SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
int dm355_pll2_init(struct device *dev, void __iomem *base)
{
@@ -71,8 +70,6 @@ int dm355_pll2_init(struct device *dev, void __iomem *base)
davinci_pll_sysclk_register(dev, &pll2_sysclk1, base);
- davinci_pll_sysclk_register(dev, &pll2_sysclk2, base);
-
davinci_pll_sysclkbp_clk_register(dev, "pll2_sysclkbp", base);
return 0;
--
2.17.0
^ permalink raw reply related
* [PATCH v2 1/2] clk: davinci: pll-dm355: fix SYSCLKn parent names
From: David Lechner @ 2018-05-07 14:43 UTC (permalink / raw)
To: linux-arm-kernel
This fixes the parent clock names of the SYSCLKn clocks for the DM355
SoC in the TI DaVinici PLL clock driver.
It appears that this name just didn't get updated to the correct name
like the other SoCs during the driver's development.
Reported-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: David Lechner <david@lechnology.com>
---
v2 changes:
- add second patch to fix additional problems with DM355
drivers/clk/davinci/pll-dm355.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c
index 5345f8286c50..1f746d2fc894 100644
--- a/drivers/clk/davinci/pll-dm355.c
+++ b/drivers/clk/davinci/pll-dm355.c
@@ -22,10 +22,10 @@ static const struct davinci_pll_clk_info dm355_pll1_info = {
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
};
-SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
-SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
-SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED);
-SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED);
+SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
+SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
int dm355_pll1_init(struct device *dev, void __iomem *base)
{
@@ -62,8 +62,8 @@ static const struct davinci_pll_clk_info dm355_pll2_info = {
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
};
-SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV);
-SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV);
+SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
int dm355_pll2_init(struct device *dev, void __iomem *base)
{
--
2.17.0
^ permalink raw reply related
* [PATCH RESEND] phy: stm32: fix usbphyc static checker and checkpatch warnings
From: Amelie Delaunay @ 2018-05-07 14:28 UTC (permalink / raw)
To: linux-arm-kernel
This patch fixes the following issues:
* warning reported by checkpatch:
WARNING: line over 80 characters
#87: FILE: drivers/phy/st/phy-stm32-usbphyc.c:87:
+static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params)
* bug reported by static checker (Dan Carpenter):
drivers/phy/st/phy-stm32-usbphyc.c:371 stm32_usbphyc_probe()
error: uninitialized symbol 'i'.
* unused stm32_usbphyc structure member: bool pll_enabled.
* unnecessary extra line in stm32_usbphyc_of_xlate
Fixes: 94c358da3a05 "phy: stm32: add support for STM32 USB PHY Controller (USBPHYC)"
Signed-off-by: Amelie Delaunay <amelie.delaunay@st.com>
---
drivers/phy/st/phy-stm32-usbphyc.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c
index bc4e78a..1255cd1 100644
--- a/drivers/phy/st/phy-stm32-usbphyc.c
+++ b/drivers/phy/st/phy-stm32-usbphyc.c
@@ -71,7 +71,6 @@ struct stm32_usbphyc {
struct stm32_usbphyc_phy **phys;
int nphys;
int switch_setup;
- bool pll_enabled;
};
static inline void stm32_usbphyc_set_bits(void __iomem *reg, u32 bits)
@@ -84,7 +83,8 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits)
writel_relaxed(readl_relaxed(reg) & ~bits, reg);
}
-static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params)
+static void stm32_usbphyc_get_pll_params(u32 clk_rate,
+ struct pll_params *pll_params)
{
unsigned long long fvco, ndiv, frac;
@@ -271,7 +271,6 @@ static struct phy *stm32_usbphyc_of_xlate(struct device *dev,
struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev);
struct stm32_usbphyc_phy *usbphyc_phy = NULL;
struct device_node *phynode = args->np;
-
int port = 0;
for (port = 0; port < usbphyc->nphys; port++) {
@@ -367,8 +366,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev)
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
if (ret != -EPROBE_DEFER)
- dev_err(dev,
- "failed to create phy%d: %d\n", i, ret);
+ dev_err(dev, "failed to create phy%d: %d\n",
+ port, ret);
goto put_child;
}
--
2.7.4
^ permalink raw reply related
* [PATCH] clk: davinci: psc-da830: fix USB0 48MHz PHY clock registration
From: David Lechner @ 2018-05-07 14:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507113457.4716-1-nsekhar@ti.com>
On 05/07/2018 06:34 AM, Sekhar Nori wrote:
> USB0 48MHz PHY clock registration fails on DA830 because the
> da8xx-cfgchip clock driver cannot get a reference to USB0
> LPSC clock.
>
> The USB0 LPSC needs to be enabled during PHY clock enable. Setup
> the clock lookup correctly to fix this.
>
> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
> ---
> drivers/clk/davinci/psc-da830.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/davinci/psc-da830.c b/drivers/clk/davinci/psc-da830.c
> index f61abf5632ff..081b039fcb02 100644
> --- a/drivers/clk/davinci/psc-da830.c
> +++ b/drivers/clk/davinci/psc-da830.c
> @@ -55,7 +55,8 @@ const struct davinci_psc_init_data da830_psc0_init_data = {
> .psc_init = &da830_psc0_init,
> };
>
> -LPSC_CLKDEV2(usb0_clkdev, NULL, "musb-da8xx",
> +LPSC_CLKDEV3(usb0_clkdev, "fck", "da830-usb-phy-clks",
> + NULL, "musb-da8xx",
> NULL, "cppi41-dmaengine");
> LPSC_CLKDEV1(usb1_clkdev, NULL, "ohci-da8xx");
> /* REVISIT: gpio-davinci.c should be modified to drop con_id */
>
Reviewed-by: David Lechner <david@lechnology.com>
^ permalink raw reply
* [PATCH 1/3] drm/sti: do not remove the drm_bridge that was never added
From: Peter Rosin @ 2018-05-07 14:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d378241f-7420-bbaf-c447-18cdfd4f9dd3@axentia.se>
On 2018-05-07 15:59, Peter Rosin wrote:
> On 2018-05-07 15:39, Daniel Vetter wrote:
>> On Thu, May 03, 2018 at 11:12:21PM +0200, Peter Rosin wrote:
>>> On 2018-05-03 11:06, Daniel Vetter wrote:
>>>> On Wed, May 02, 2018 at 09:40:23AM +0200, Peter Rosin wrote:
>>>>> The more natural approach would perhaps be to add an drm_bridge_add,
>>>>> but there are several other bridges that never call drm_bridge_add.
>>>>> Just removing the drm_bridge_remove is the easier fix.
>>>>>
>>>>> Signed-off-by: Peter Rosin <peda@axentia.se>
>>>>
>>>> This mess is much bigger. There's 2 pairs of bridge functions:
>>>>
>>>> - drm_bridge_attach/detach. Those are meant to be called by the overall
>>>> drm driver to connect/disconnect a drm_bridge.
>>>>
>>>> - drm_bridge_add/remove. These are supposed to be called by the bridge
>>>> driver itself to register/unregister itself. Maybe we should rename
>>>> them, since the same issue happens with drm_panel, with the same
>>>> confusion.
>>>>
>>>> I thought someone was working on a cleanup series to fix this mess, but I
>>>> didn't find anything.
>>>
>>> Ok, I just spotted the imbalance and didn't really dig into what
>>> actually happens in these error paths. Now that I have done so I
>>> believe that the removed drm_bridge_remove calls causes NULL
>>> dereferences if/when the error paths are triggered.
>>>
>>> So, I don't think this can wait for some bigger cleanup.
>>>
>>> drm_bridge_remove calls list_del_init calls __list_del_entry calls
>>> __list_del with NULL in both prev and next since the list member
>>> is never initialized. prev and next are dereferenced by __list_del
>>> and you have *boom*
>>>
>>> I recommend adding the tag
>>>
>>> Fixes: 84601dbdea36 ("drm: sti: rework init sequence")
>>>
>>> so that stable picks this one up.
>>
>> I just wanted to correct your commit message text - the correct solution
>> is definitely _not_ for sti here to call drm_bridge_add.
>
> Ah, I see what you mean. Do you want me to respin?
Hold on, no I don't agree. sti_hda.c does create a bridge for it's own
internal use. It does not drm_bridge_add it, because all that ever does
is adding the bridge to the global lost of bridges. But since this is
a bridge for internal use, there is little point in calling drm_bridge_add,
the driver currently gains nothing by doing so.
But, drm_bridge_add might be a good place to put common stuff for every
bridge in the system, so it might be worthwhile to start requiring all
bridges to be drm_bridge_add-ed. And IMHO, it would not be wrong to have
the sti-hda driver call drm_bridge_add on the bridge it creates.
Do you really think it is actively wrong to call drm_bridge_add for
internal bridges such as this?
Cheers,
Peter
^ permalink raw reply
* [PATCH v3 10/14] dt-bindings: media: Document bindings for the Sunxi-Cedrus VPU driver
From: Rob Herring @ 2018-05-07 14:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507124500.20434-11-paul.kocialkowski@bootlin.com>
On Mon, May 07, 2018 at 02:44:56PM +0200, Paul Kocialkowski wrote:
> This adds a device-tree binding document that specifies the properties
> used by the Sunxi-Cedurs VPU driver, as well as examples.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> ---
> .../devicetree/bindings/media/sunxi-cedrus.txt | 58 ++++++++++++++++++++++
> 1 file changed, 58 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/media/sunxi-cedrus.txt
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply
* [PATCH v2 00/26] device link, bridge supplier <-> drm device
From: Peter Rosin @ 2018-05-07 14:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507135601.GJ12521@phenom.ffwll.local>
On 2018-05-07 15:56, Daniel Vetter wrote:
> On Fri, May 04, 2018 at 03:51:46PM +0200, Peter Rosin wrote:
>> Hi!
>>
>> It was noted by Russel King [1] that bridges (not using components)
>> might disappear unexpectedly if the owner of the bridge was unbound.
>> Jyri Sarha had previously noted the same thing with panels [2]. Jyri
>> came up with using device links to resolve the panel issue, which
>> was also my (independent) reaction to the note from Russel.
>>
>> This series builds up to the addition of that link in the last
>> patch, but in my opinion the other 25 patches do have merit on their
>> own.
>>
>> The last patch needs testing, while the others look trivial. Jyri, are
>> you able to test? That said, I might have missed some subtlety.
>>
>> Oh and the reason I'm pushing this is of course so that the issue
>> noted by Russel in [1] is addressed which in turn means that the
>> tda998x bridge driver can be patched according to that series without
>> objection (hopefully) and then used from the atmel-hlcdc driver (and
>> other drivers that are not componentized).
>>
>> Changes since v1 https://lkml.org/lkml/2018/4/26/1018
>>
>> - rename .owner to .odev to not get mixed up with the module owner.
>> - added patches for new recent drivers thc63lvd1024 and cdns-dsi
>> - fix for problem in the rockchip_lvds driver reported by 0day
>> - added a WARN in drm_bridge_add if there is no .odev owner device
>>
>> I did *not*:
>> - add any ack from Daniel since he suggested "pdev", and I ended up
>> with "odev" in the rename since I disliked "pdev" about as much
>> as "owner".
>
> As long as it's not owner, I'm fine :-) Ack on the idea still holds.
>
>> - add any port id. The current .of_node (that this series removes)
>> does not identify the port, so that problem seems orthogonal
>> to me.
>
> Hm, from my cursory DT/of code reading last week I thought the port is
> used to lookup the right node, but there's no port thing on the target for
> a phandle? At least that's how current drm_of_find_panel_or_bridge seems
> to work ...
drm_of_find_panel_or_bridge calls of_graph_get_remote_node and that
function looks up the main remote device node, i.e. not the remote
port or endpoint node but the parent node. So, bridges using .of_node
have stored their main device node in the .of_node member. I.e. the
same value as of_node in struct device for all current cases.
Cheers,
Peter
> -Daniel
>>
>> Cheers,
>> Peter
>>
>> [1] https://lkml.org/lkml/2018/4/23/769
>> [2] https://www.spinics.net/lists/dri-devel/msg174275.html
>>
>> Peter Rosin (26):
>> drm/bridge: allow optionally specifying an owner .odev device
>> drm/bridge: adv7511: provide an owner .odev device
>> drm/bridge/analogix: core: specify the owner .odev of the bridge
>> drm/bridge: analogix-anx78xx: provide an owner .odev device
>> drm/bridge: cdns-dsi: provide an owner .odev device
>> drm/bridge: vga-dac: provide an owner .odev device
>> drm/bridge: lvds-encoder: provide an owner .odev device
>> drm/bridge: megachips-stdpxxxx-ge-b850v3-fw: provide an owner .odev
>> device
>> drm/bridge: nxp-ptn3460: provide an owner .odev device
>> drm/bridge: panel: provide an owner .odev device
>> drm/bridge: ps8622: provide an owner .odev device
>> drm/bridge: sii902x: provide an owner .odev device
>> drm/bridge: sii9234: provide an owner .odev device
>> drm/bridge: sii8620: provide an owner .odev device
>> drm/bridge: synopsys: provide an owner .odev device for the bridges
>> drm/bridge: tc358767: provide an owner .odev device
>> drm/bridge: thc63lvd1024: provide an owner .odev device
>> drm/bridge: ti-tfp410: provide an owner .odev device
>> drm/exynos: mic: provide an owner .odev device for the bridge
>> drm/mediatek: hdmi: provide an owner .odev device for the bridge
>> drm/msm: specify the owner .odev of the bridges
>> drm/rcar-du: lvds: provide an owner .odev device for the bridge
>> drm/sti: provide an owner .odev device for the bridges
>> drm/bridge: remove the .of_node member
>> drm/bridge: require the owner .odev to be filled in on
>> drm_bridge_add/attach
>> drm/bridge: establish a link between the bridge supplier and consumer
>>
>> drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 2 +-
>> drivers/gpu/drm/bridge/analogix-anx78xx.c | 5 +----
>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 1 +
>> drivers/gpu/drm/bridge/cdns-dsi.c | 2 +-
>> drivers/gpu/drm/bridge/dumb-vga-dac.c | 2 +-
>> drivers/gpu/drm/bridge/lvds-encoder.c | 2 +-
>> .../drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 2 +-
>> drivers/gpu/drm/bridge/nxp-ptn3460.c | 2 +-
>> drivers/gpu/drm/bridge/panel.c | 4 +---
>> drivers/gpu/drm/bridge/parade-ps8622.c | 2 +-
>> drivers/gpu/drm/bridge/sii902x.c | 2 +-
>> drivers/gpu/drm/bridge/sii9234.c | 2 +-
>> drivers/gpu/drm/bridge/sil-sii8620.c | 2 +-
>> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 +---
>> drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 4 +---
>> drivers/gpu/drm/bridge/tc358767.c | 2 +-
>> drivers/gpu/drm/bridge/thc63lvd1024.c | 2 +-
>> drivers/gpu/drm/bridge/ti-tfp410.c | 2 +-
>> drivers/gpu/drm/drm_bridge.c | 26 +++++++++++++++++++++-
>> drivers/gpu/drm/exynos/exynos_drm_mic.c | 2 +-
>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 2 +-
>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 1 +
>> drivers/gpu/drm/msm/edp/edp_bridge.c | 1 +
>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 1 +
>> drivers/gpu/drm/rcar-du/rcar_lvds.c | 2 +-
>> drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +-
>> drivers/gpu/drm/sti/sti_dvo.c | 2 +-
>> drivers/gpu/drm/sti/sti_hda.c | 1 +
>> drivers/gpu/drm/sti/sti_hdmi.c | 1 +
>> include/drm/drm_bridge.h | 8 +++----
>> 30 files changed, 57 insertions(+), 36 deletions(-)
>>
>> --
>> 2.11.0
>>
>
^ permalink raw reply
* [PATCH 4/4] ARM: dts: i.MX6: imx6dl-mamoj: Add usb host and device support
From: Fabio Estevam @ 2018-05-07 14:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180425173932.7213-4-jagan@amarulasolutions.com>
On Wed, Apr 25, 2018 at 2:39 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> From: Michael Trimarchi <michael@amarulasolutions.com>
>
> Add USB host and device support for BTicino i.MX6DL Mamoj board.
>
> Signed-off-by: Simone CIANNI <simone.cianni@bticino.it>
> Signed-off-by: Raffaele RECALCATI <raffaele.recalcati@bticino.it>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH 3/4] ARM: dts: i.MX6: imx6dl-mamoj: Add Wifi support
From: Fabio Estevam @ 2018-05-07 14:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180425173932.7213-3-jagan@amarulasolutions.com>
On Wed, Apr 25, 2018 at 2:39 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> Add TI WL18XX Wifi for BTicino i.MX6DL board.
>
> Signed-off-by: Simone CIANNI <simone.cianni@bticino.it>
> Signed-off-by: Raffaele RECALCATI <raffaele.recalcati@bticino.it>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH 2/4] ARM: dts: i.MX6: imx6dl-mamoj: Add parallel display support
From: Fabio Estevam @ 2018-05-07 14:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180425173932.7213-2-jagan@amarulasolutions.com>
On Wed, Apr 25, 2018 at 2:39 PM, Jagan Teki <jagan@amarulasolutions.com> wrote:
> This patch adds parallel display support for i.MX6DL Mamoj board
> along with relevant backlight through pwm.
>
> LCD power sequence is added by 'Michael Trimarchi'.
>
> Signed-off-by: Simone CIANNI <simone.cianni@bticino.it>
> Signed-off-by: Raffaele RECALCATI <raffaele.recalcati@bticino.it>
> Signed-off-by: Michael Trimarchi <michael@amarulasolutions.com>
> Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
* [PATCH v3 11/14] media: platform: Add Sunxi-Cedrus VPU decoder driver
From: Hans Verkuil @ 2018-05-07 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507124500.20434-12-paul.kocialkowski@bootlin.com>
On 07/05/18 14:44, Paul Kocialkowski wrote:
> This introduces the Sunxi-Cedrus VPU driver that supports the VPU found
> in Allwinner SoCs, also known as Video Engine. It is implemented through
> a v4l2 m2m decoder device and a media device (used for media requests).
> So far, it only supports MPEG2 decoding.
>
> Since this VPU is stateless, synchronization with media requests is
> required in order to ensure consistency between frame headers that
> contain metadata about the frame to process and the raw slice data that
> is used to generate the frame.
>
> This driver was made possible thanks to the long-standing effort
> carried out by the linux-sunxi community in the interest of reverse
> engineering, documenting and implementing support for Allwinner VPU.
>
> Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> ---
> MAINTAINERS | 7 +
> drivers/media/platform/Kconfig | 15 +
> drivers/media/platform/Makefile | 1 +
> drivers/media/platform/sunxi/cedrus/Makefile | 4 +
> drivers/media/platform/sunxi/cedrus/sunxi_cedrus.c | 333 ++++++++++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_common.h | 128 ++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_dec.c | 188 ++++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_dec.h | 35 ++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_hw.c | 240 ++++++++++
> .../media/platform/sunxi/cedrus/sunxi_cedrus_hw.h | 37 ++
> .../platform/sunxi/cedrus/sunxi_cedrus_mpeg2.c | 160 +++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h | 33 ++
> .../platform/sunxi/cedrus/sunxi_cedrus_regs.h | 175 +++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_video.c | 505 +++++++++++++++++++++
> .../platform/sunxi/cedrus/sunxi_cedrus_video.h | 31 ++
> 15 files changed, 1892 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_mpeg2.c
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_regs.h
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.c
> create mode 100644 drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 79bb02ff812f..489f1dccc810 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -656,6 +656,13 @@ L: linux-crypto at vger.kernel.org
> S: Maintained
> F: drivers/crypto/sunxi-ss/
>
> +ALLWINNER VPU DRIVER
> +M: Maxime Ripard <maxime.ripard@bootlin.com>
> +M: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> +L: linux-media at vger.kernel.org
> +S: Maintained
> +F: drivers/media/platform/sunxi/cedrus/
> +
> ALPHA PORT
> M: Richard Henderson <rth@twiddle.net>
> M: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 5af07b620094..72d37cd2f7a2 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -476,6 +476,21 @@ 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 && MEDIA_CONTROLLER
> + depends on ARCH_SUNXI
> + depends on HAS_DMA
> + select VIDEOBUF2_DMA_CONTIG
> + select MEDIA_REQUEST_API
> + select V4L2_MEM2MEM_DEV
> + ---help---
> + Support for the VPU found in Allwinner SoCs, also known as the Cedar
> + video engine.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called 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 932515df4477..444b995424a5 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/
> obj-y += omap/
>
> obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
> +obj-$(CONFIG_VIDEO_SUNXI_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 000000000000..98f30df626a9
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/Makefile
> @@ -0,0 +1,4 @@
> +obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o
> +
> +sunxi-cedrus-y = sunxi_cedrus.o sunxi_cedrus_video.o sunxi_cedrus_hw.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
> new file mode 100644
> index 000000000000..ccd41d9a3e41
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus.c
> @@ -0,0 +1,333 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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/platform_device.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +
> +#include <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "sunxi_cedrus_common.h"
> +#include "sunxi_cedrus_video.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);
> +
> + switch (ctrl->id) {
> + case V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR:
> + /* This is kept in memory and used directly. */
Is there any validation done/needed for the contents of this control?
I noticed it is just ignored in std_validate() in v4l2-ctrls.c, but I expected
to see some validation here.
What happens if someone puts in rubbish data? How robust is the hardware?
> + 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 sunxi_cedrus_control controls[] = {
> + [SUNXI_CEDRUS_CTRL_DEC_MPEG2_FRAME_HDR] = {
> + .id = V4L2_CID_MPEG_VIDEO_MPEG2_FRAME_HDR,
> + .elem_size = sizeof(struct v4l2_ctrl_mpeg2_frame_hdr),
> + },
> +};
> +
> +static int sunxi_cedrus_init_ctrls(struct sunxi_cedrus_dev *dev,
> + struct sunxi_cedrus_ctx *ctx)
> +{
> + struct v4l2_ctrl_handler *hdl = &ctx->hdl;
> + unsigned int num_ctrls = ARRAY_SIZE(controls);
> + unsigned int i;
> +
> + v4l2_ctrl_handler_init(hdl, num_ctrls);
> + if (hdl->error) {
> + dev_err(dev->dev, "Couldn't initialize our control handler\n");
> + return hdl->error;
> + }
> +
> + for (i = 0; i < num_ctrls; i++) {
> + struct v4l2_ctrl_config cfg = { 0 };
> +
> + cfg.ops = &sunxi_cedrus_ctrl_ops;
> + cfg.elem_size = controls[i].elem_size;
> + cfg.id = controls[i].id;
> +
> + ctx->ctrls[i] = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
> + if (hdl->error) {
> + v4l2_ctrl_handler_free(hdl);
> + return hdl->error;
> + }
> + }
> +
> + ctx->fh.ctrl_handler = hdl;
> + v4l2_ctrl_handler_setup(hdl);
This initializes the header with all zeroes, is that what you want?
Just checking.
> +
> + return 0;
> +}
> +
> +static void sunxi_cedrus_deinit_ctrls(struct sunxi_cedrus_dev *dev,
> + struct sunxi_cedrus_ctx *ctx)
> +{
> + unsigned int num_ctrls = ARRAY_SIZE(controls);
> + unsigned int i;
> +
> + v4l2_ctrl_handler_free(&ctx->hdl);
> + for (i = 0; i < num_ctrls; i++)
> + ctx->ctrls[0] = NULL;
Is this necessary? Since ctx is freed right after this call?
> +}
> +
> +static int sunxi_cedrus_open(struct file *file)
> +{
> + struct sunxi_cedrus_dev *dev = video_drvdata(file);
> + struct sunxi_cedrus_ctx *ctx = NULL;
> + int rc;
> +
> + if (mutex_lock_interruptible(&dev->dev_mutex))
> + return -ERESTARTSYS;
> +
> + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> + if (!ctx) {
> + mutex_unlock(&dev->dev_mutex);
> + return -ENOMEM;
> + }
> +
> + INIT_WORK(&ctx->run_work, sunxi_cedrus_device_work);
> +
> + INIT_LIST_HEAD(&ctx->src_list);
> + INIT_LIST_HEAD(&ctx->dst_list);
> +
> + v4l2_fh_init(&ctx->fh, video_devdata(file));
> + file->private_data = &ctx->fh;
> + ctx->dev = dev;
> +
> + rc = sunxi_cedrus_init_ctrls(dev, ctx);
> + if (rc)
> + goto err_free;
> +
> + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
> + &sunxi_cedrus_queue_init);
> + if (IS_ERR(ctx->fh.m2m_ctx)) {
> + rc = PTR_ERR(ctx->fh.m2m_ctx);
> + goto err_ctrl_deinit;
> + }
> +
> + v4l2_fh_add(&ctx->fh);
> +
> + dev_dbg(dev->dev, "Created instance: %p, m2m_ctx: %p\n",
> + ctx, ctx->fh.m2m_ctx);
> +
> + mutex_unlock(&dev->dev_mutex);
> + return 0;
> +
> +err_ctrl_deinit:
> + sunxi_cedrus_deinit_ctrls(dev, ctx);
> +err_free:
> + kfree(ctx);
> + 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);
> +
> + mutex_lock(&dev->dev_mutex);
> + v4l2_fh_del(&ctx->fh);
> + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
> + sunxi_cedrus_deinit_ctrls(dev, ctx);
> + v4l2_fh_exit(&ctx->fh);
> + v4l2_fh_exit(&ctx->fh);
> + kfree(ctx);
> + mutex_unlock(&dev->dev_mutex);
> +
> + return 0;
> +}
> +
> +static const struct v4l2_file_operations 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 const struct video_device sunxi_cedrus_video_device = {
> + .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 const struct v4l2_m2m_ops sunxi_cedrus_m2m_ops = {
> + .device_run = sunxi_cedrus_device_run,
> + .job_abort = sunxi_cedrus_job_abort,
> +};
> +
> +static const struct media_device_ops sunxi_cedrus_m2m_media_ops = {
> + .req_validate = vb2_request_validate,
> + .req_queue = vb2_m2m_request_queue,
> +};
> +
> +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, "Failed to probe hardware\n");
> + return ret;
> + }
> +
> + mutex_init(&dev->dev_mutex);
> + spin_lock_init(&dev->irq_lock);
> +
> + dev->vfd = sunxi_cedrus_video_device;
> + vfd = &dev->vfd;
> + vfd->lock = &dev->dev_mutex;
> + vfd->v4l2_dev = &dev->v4l2_dev;
> +
> + dev->mdev.dev = &pdev->dev;
> + strlcpy(dev->mdev.model, SUNXI_CEDRUS_NAME, sizeof(dev->mdev.model));
> + media_device_init(&dev->mdev);
> + dev->mdev.ops = &sunxi_cedrus_m2m_media_ops;
> + dev->v4l2_dev.mdev = &dev->mdev;
> + dev->pad[0].flags = MEDIA_PAD_FL_SINK;
> + dev->pad[1].flags = MEDIA_PAD_FL_SOURCE;
> + ret = media_entity_pads_init(&vfd->entity, 2, dev->pad);
> + if (ret)
> + return ret;
> +
> + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
> + if (ret)
> + goto unreg_media;
> +
> + 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_video_device.name);
> + v4l2_info(&dev->v4l2_dev,
> + "Device registered as /dev/video%d\n", vfd->num);
> +
> + platform_set_drvdata(pdev, dev);
> +
> + dev->m2m_dev = v4l2_m2m_init(&sunxi_cedrus_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;
> + }
> +
> + /* Register the media device node */
> + ret = media_device_register(&dev->mdev);
> + if (ret)
> + goto err_m2m;
> +
> + return 0;
> +
> +err_m2m:
> + v4l2_m2m_release(dev->m2m_dev);
> + video_unregister_device(&dev->vfd);
> +unreg_media:
> + media_device_unregister(&dev->mdev);
> +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);
> +
> + if (media_devnode_is_registered(dev->mdev.devnode)) {
> + media_device_unregister(&dev->mdev);
> + media_device_cleanup(&dev->mdev);
> + }
> +
> + v4l2_m2m_release(dev->m2m_dev);
> + video_unregister_device(&dev->vfd);
> + v4l2_device_unregister(&dev->v4l2_dev);
> + sunxi_cedrus_hw_remove(dev);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id of_sunxi_cedrus_match[] = {
> + { .compatible = "allwinner,sun4i-a10-video-engine" },
> + { .compatible = "allwinner,sun5i-a13-video-engine" },
> + { .compatible = "allwinner,sun7i-a20-video-engine" },
> + { .compatible = "allwinner,sun8i-a33-video-engine" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, of_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 VPU 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 000000000000..ee6883ef9cb7
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_common.h
> @@ -0,0 +1,128 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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 <linux/platform_device.h>
> +
> +#include <media/videobuf2-v4l2.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ctrls.h>
> +
> +#define SUNXI_CEDRUS_NAME "sunxi-cedrus"
> +
> +enum sunxi_cedrus_control_id {
> + SUNXI_CEDRUS_CTRL_DEC_MPEG2_FRAME_HDR = 0,
> + SUNXI_CEDRUS_CTRL_MAX,
> +};
> +
> +struct sunxi_cedrus_control {
> + u32 id;
> + u32 elem_size;
> +};
> +
> +struct sunxi_cedrus_fmt {
> + u32 fourcc;
> + int depth;
> + u32 types;
> + unsigned int num_planes;
> +};
> +
> +struct sunxi_cedrus_mpeg2_run {
> + const struct v4l2_ctrl_mpeg2_frame_hdr *hdr;
> +};
> +
> +struct sunxi_cedrus_run {
> + struct vb2_v4l2_buffer *src;
> + struct vb2_v4l2_buffer *dst;
> +
> + union {
> + struct sunxi_cedrus_mpeg2_run mpeg2;
> + };
> +};
> +
> +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 v4l2_ctrl *ctrls[SUNXI_CEDRUS_CTRL_MAX];
> +
> + struct vb2_buffer *dst_bufs[VIDEO_MAX_FRAME];
> +
> + int job_abort;
> +
> + struct work_struct try_schedule_work;
> + struct work_struct run_work;
> + struct list_head src_list;
> + struct list_head dst_list;
> +};
> +
> +struct sunxi_cedrus_buffer {
> + struct vb2_v4l2_buffer vb;
> + enum vb2_buffer_state state;
> + struct list_head list;
> +};
> +
> +struct sunxi_cedrus_dev {
> + struct v4l2_device v4l2_dev;
> + struct video_device vfd;
> + struct media_device mdev;
> + struct media_pad pad[2];
> + struct platform_device *pdev;
> + struct device *dev;
> + struct v4l2_m2m_dev *m2m_dev;
> +
> + /* Mutex for device file */
> + struct mutex dev_mutex;
> + /* Spinlock for interrupt */
> + spinlock_t irq_lock;
> +
> + void __iomem *base;
> +
> + struct clk *mod_clk;
> + struct clk *ahb_clk;
> + struct clk *ram_clk;
> +
> + struct reset_control *rstc;
> +
> + struct regmap *syscon;
> +};
> +
> +static inline void sunxi_cedrus_write(struct sunxi_cedrus_dev *dev,
> + u32 val, u32 reg)
> +{
> + writel(val, dev->base + reg);
> +}
> +
> +static inline u32 sunxi_cedrus_read(struct sunxi_cedrus_dev *dev, u32 reg)
> +{
> + return readl(dev->base + reg);
> +}
> +
> +#endif
> 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 000000000000..8c92af34ebeb
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_dec.c
> @@ -0,0 +1,188 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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 <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "sunxi_cedrus_common.h"
> +#include "sunxi_cedrus_mpeg2.h"
> +#include "sunxi_cedrus_dec.h"
> +#include "sunxi_cedrus_hw.h"
> +
> +static inline void *get_ctrl_ptr(struct sunxi_cedrus_ctx *ctx,
> + enum sunxi_cedrus_control_id id)
> +{
> + struct v4l2_ctrl *ctrl = ctx->ctrls[id];
> +
> + return ctrl->p_cur.p;
> +}
> +
> +void sunxi_cedrus_device_work(struct work_struct *work)
> +{
> + struct sunxi_cedrus_ctx *ctx = container_of(work,
> + struct sunxi_cedrus_ctx, run_work);
> + struct sunxi_cedrus_buffer *buffer_entry;
> + struct vb2_v4l2_buffer *src_buf, *dst_buf;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> + if (list_empty(&ctx->src_list) ||
> + list_empty(&ctx->dst_list)) {
> + pr_err("Empty source and/or destination buffers lists\n");
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> + return;
> + }
> +
> + buffer_entry = list_last_entry(&ctx->src_list, struct sunxi_cedrus_buffer, list);
> + list_del(ctx->src_list.prev);
> +
> + src_buf = &buffer_entry->vb;
> + v4l2_m2m_buf_done(src_buf, buffer_entry->state);
> +
> + buffer_entry = list_last_entry(&ctx->dst_list, struct sunxi_cedrus_buffer, list);
> + list_del(ctx->dst_list.prev);
> +
> + dst_buf = &buffer_entry->vb;
> + v4l2_m2m_buf_done(dst_buf, buffer_entry->state);
> +
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +void sunxi_cedrus_device_run(void *priv)
> +{
> + struct sunxi_cedrus_ctx *ctx = priv;
> + struct sunxi_cedrus_run run = { 0 };
> + struct media_request *src_req, *dst_req;
> + unsigned long flags;
> + bool mpeg1 = false;
> +
> + run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
> + if (!run.src) {
> + v4l2_err(&ctx->dev->v4l2_dev,
> + "No source buffer to prepare\n");
> + return;
> + }
> +
> + run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
> + if (!run.dst) {
> + v4l2_err(&ctx->dev->v4l2_dev,
> + "No destination buffer to prepare\n");
> + return;
> + }
> +
> + /* Apply request(s) controls if needed. */
> + src_req = run.src->vb2_buf.req_obj.req;
> + dst_req = run.dst->vb2_buf.req_obj.req;
> +
> + if (src_req)
> + v4l2_ctrl_request_setup(src_req, &ctx->hdl);
> +
> + if (dst_req && dst_req != src_req)
> + v4l2_ctrl_request_setup(dst_req, &ctx->hdl);
> +
> + ctx->job_abort = 0;
> +
> + spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> + switch (ctx->vpu_src_fmt->fourcc) {
> + case V4L2_PIX_FMT_MPEG2_FRAME:
> + if (!ctx->ctrls[SUNXI_CEDRUS_CTRL_DEC_MPEG2_FRAME_HDR]) {
> + v4l2_err(&ctx->dev->v4l2_dev,
> + "Invalid MPEG2 frame header control\n");
> + ctx->job_abort = 1;
> + goto unlock_complete;
> + }
> +
> + run.mpeg2.hdr = get_ctrl_ptr(ctx, SUNXI_CEDRUS_CTRL_DEC_MPEG2_FRAME_HDR);
> + sunxi_cedrus_mpeg2_setup(ctx, &run);
> +
> + mpeg1 = run.mpeg2.hdr->type == MPEG1;
> + break;
> +
> + default:
> + ctx->job_abort = 1;
> + }
> +
> +unlock_complete:
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> + /* Complete request(s) controls if needed. */
> +
> + if (src_req)
> + v4l2_ctrl_request_complete(src_req, &ctx->hdl);
> +
> + if (dst_req && dst_req != src_req)
> + v4l2_ctrl_request_complete(dst_req, &ctx->hdl);
> +
> + spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> + if (!ctx->job_abort) {
> + if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_MPEG2_FRAME)
> + sunxi_cedrus_mpeg2_trigger(ctx, mpeg1);
> + } else {
> + v4l2_m2m_buf_done(run.src, VB2_BUF_STATE_ERROR);
> + v4l2_m2m_buf_done(run.dst, VB2_BUF_STATE_ERROR);
> + }
> +
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> + if (ctx->job_abort)
> + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> +
> +void sunxi_cedrus_job_abort(void *priv)
> +{
> + struct sunxi_cedrus_ctx *ctx = priv;
> + struct vb2_v4l2_buffer *src_buf, *dst_buf;
> + unsigned long flags;
> +
> + ctx->job_abort = 1;
> +
> + /*
> + * V4L2 m2m and request API cleanup is done here while hardware state
> + * cleanup is done in the interrupt context. Doing all the cleanup in
> + * the interrupt context is a bit risky, since the job_abort call might
> + * originate from the release hook, where interrupts have already been
> + * disabled.
> + */
> +
> + spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> + if (src_buf)
> + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
> +
> + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> + if (dst_buf)
> + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
> +
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_dec.h b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_dec.h
> new file mode 100644
> index 000000000000..9899b399b2ba
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_dec.h
> @@ -0,0 +1,35 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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_
> +
> +extern const struct v4l2_ioctl_ops sunxi_cedrus_ioctl_ops;
> +
> +void sunxi_cedrus_device_work(struct work_struct *work);
> +void sunxi_cedrus_device_run(void *priv);
> +void sunxi_cedrus_job_abort(void *priv);
> +
> +int sunxi_cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> + struct vb2_queue *dst_vq);
> +
> +#endif
> 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 000000000000..5783bd985855
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_hw.c
> @@ -0,0 +1,240 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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/platform_device.h>
> +#include <linux/of_reserved_mem.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/interrupt.h>
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/soc/sunxi/sunxi_sram.h>
> +
> +#include <media/videobuf2-core.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "sunxi_cedrus_common.h"
> +#include "sunxi_cedrus_hw.h"
> +#include "sunxi_cedrus_regs.h"
> +
> +#define SYSCON_SRAM_CTRL_REG0 0x0
> +#define SYSCON_SRAM_C1_MAP_VE 0x7fffffff
> +
> +int sunxi_cedrus_engine_enable(struct sunxi_cedrus_dev *dev,
> + enum sunxi_cedrus_engine engine)
> +{
> + u32 reg = 0;
> +
> + /*
> + * FIXME: This is only valid on 32-bits DDR's, we should test
> + * it on the A13/A33.
> + */
> + reg |= VE_CTRL_REC_WR_MODE_2MB;
> +
> + reg |= VE_CTRL_CACHE_BUS_BW_128;
> +
> + switch (engine) {
> + case SUNXI_CEDRUS_ENGINE_MPEG:
> + reg |= VE_CTRL_DEC_MODE_MPEG;
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + sunxi_cedrus_write(dev, reg, VE_CTRL);
> + return 0;
> +}
> +
> +void sunxi_cedrus_engine_disable(struct sunxi_cedrus_dev *dev)
> +{
> + sunxi_cedrus_write(dev, VE_CTRL_DEC_MODE_DISABLED, VE_CTRL);
> +}
> +
> +static irqreturn_t sunxi_cedrus_ve_irq(int irq, void *dev_id)
> +{
> + struct sunxi_cedrus_dev *dev = dev_id;
> + struct sunxi_cedrus_ctx *ctx;
> + struct sunxi_cedrus_buffer *src_buffer, *dst_buffer;
> + struct vb2_v4l2_buffer *src_vb, *dst_vb;
> + unsigned long flags;
> + unsigned int value, status;
> +
> + spin_lock_irqsave(&dev->irq_lock, flags);
> +
> + /* Disable MPEG interrupts and stop the MPEG engine */
> + value = sunxi_cedrus_read(dev, VE_MPEG_CTRL);
> + sunxi_cedrus_write(dev, value & (~0xf), VE_MPEG_CTRL);
> +
> + status = sunxi_cedrus_read(dev, VE_MPEG_STATUS);
> + sunxi_cedrus_write(dev, 0x0000c00f, VE_MPEG_STATUS);
> + sunxi_cedrus_engine_disable(dev);
> +
> + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
> + if (!ctx) {
> + pr_err("Instance released before the end of transaction\n");
> + spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> + return IRQ_HANDLED;
> + }
> +
> + src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> + dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +
> + if (!src_vb || !dst_vb) {
> + pr_err("Unable to get source and/or destination buffers\n");
> + spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> + return IRQ_HANDLED;
> + }
> +
> + src_buffer = container_of(src_vb, struct sunxi_cedrus_buffer, vb);
> + dst_buffer = container_of(dst_vb, struct sunxi_cedrus_buffer, vb);
> +
> + /* First bit of MPEG_STATUS indicates success. */
> + if (ctx->job_abort || !(status & 0x01))
> + src_buffer->state = dst_buffer->state = VB2_BUF_STATE_ERROR;
> + else
> + src_buffer->state = dst_buffer->state = VB2_BUF_STATE_DONE;
> +
> + list_add_tail(&src_buffer->list, &ctx->src_list);
> + list_add_tail(&dst_buffer->list, &ctx->dst_list);
> +
> + spin_unlock_irqrestore(&dev->irq_lock, flags);
> +
> + schedule_work(&ctx->run_work);
> +
> + return IRQ_HANDLED;
> +}
> +
> +int sunxi_cedrus_hw_probe(struct sunxi_cedrus_dev *dev)
> +{
> + struct resource *res;
> + int irq_dec;
> + int ret;
> +
> + irq_dec = platform_get_irq(dev->pdev, 0);
> + if (irq_dec <= 0) {
> + dev_err(dev->dev, "could not get ve IRQ\n");
> + return -ENXIO;
> + }
> + ret = devm_request_irq(dev->dev, irq_dec, sunxi_cedrus_ve_irq, 0,
> + dev_name(dev->dev), dev);
> + if (ret) {
> + dev_err(dev->dev, "could not request ve IRQ\n");
> + return -ENXIO;
> + }
> +
> + /*
> + * The VPU is only able to handle bus addresses so we have to subtract
> + * the RAM offset to the physcal addresses.
> + */
> + dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
> +
> + ret = of_reserved_mem_device_init(dev->dev);
> + if (ret && ret != -ENODEV) {
> + dev_err(dev->dev, "could not reserve memory\n");
> + return -ENODEV;
> + }
> +
> + ret = sunxi_sram_claim(dev->dev);
> + if (ret) {
> + dev_err(dev->dev, "couldn't map SRAM to device\n");
> + return ret;
> + }
> +
> + dev->ahb_clk = devm_clk_get(dev->dev, "ahb");
> + if (IS_ERR(dev->ahb_clk)) {
> + dev_err(dev->dev, "failed to get ahb clock\n");
> + return PTR_ERR(dev->ahb_clk);
> + }
> + dev->mod_clk = devm_clk_get(dev->dev, "mod");
> + if (IS_ERR(dev->mod_clk)) {
> + dev_err(dev->dev, "failed to get mod clock\n");
> + return PTR_ERR(dev->mod_clk);
> + }
> + dev->ram_clk = devm_clk_get(dev->dev, "ram");
> + if (IS_ERR(dev->ram_clk)) {
> + dev_err(dev->dev, "failed to get ram clock\n");
> + return PTR_ERR(dev->ram_clk);
> + }
> +
> + dev->rstc = devm_reset_control_get(dev->dev, NULL);
> +
> + res = platform_get_resource(dev->pdev, IORESOURCE_MEM, 0);
> + dev->base = devm_ioremap_resource(dev->dev, res);
> + if (!dev->base)
> + dev_err(dev->dev, "could not maps MACC registers\n");
> +
> + dev->syscon = syscon_regmap_lookup_by_phandle(dev->dev->of_node,
> + "syscon");
> + if (IS_ERR(dev->syscon)) {
> + dev->syscon = NULL;
> + } else {
> + regmap_write_bits(dev->syscon, SYSCON_SRAM_CTRL_REG0,
> + SYSCON_SRAM_C1_MAP_VE,
> + SYSCON_SRAM_C1_MAP_VE);
> + }
> +
> + ret = clk_prepare_enable(dev->ahb_clk);
> + if (ret) {
> + dev_err(dev->dev, "could not enable ahb clock\n");
> + return -EFAULT;
> + }
> + ret = clk_prepare_enable(dev->mod_clk);
> + if (ret) {
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not enable mod clock\n");
> + return -EFAULT;
> + }
> + ret = clk_prepare_enable(dev->ram_clk);
> + if (ret) {
> + clk_disable_unprepare(dev->mod_clk);
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not enable ram clock\n");
> + return -EFAULT;
> + }
> +
> + ret = reset_control_reset(dev->rstc);
> + if (ret) {
> + clk_disable_unprepare(dev->ram_clk);
> + clk_disable_unprepare(dev->mod_clk);
> + clk_disable_unprepare(dev->ahb_clk);
> + dev_err(dev->dev, "could not reset device\n");
> + return -EFAULT;
> + }
> +
> + return 0;
> +}
> +
> +void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *dev)
> +{
> + reset_control_assert(dev->rstc);
> +
> + clk_disable_unprepare(dev->ram_clk);
> + clk_disable_unprepare(dev->mod_clk);
> + clk_disable_unprepare(dev->ahb_clk);
> +
> + sunxi_sram_release(dev->dev);
> + of_reserved_mem_device_release(dev->dev);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_hw.h b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_hw.h
> new file mode 100644
> index 000000000000..34f3fae462a8
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_hw.h
> @@ -0,0 +1,37 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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_
> +
> +enum sunxi_cedrus_engine {
> + SUNXI_CEDRUS_ENGINE_MPEG,
> +};
> +
> +int sunxi_cedrus_engine_enable(struct sunxi_cedrus_dev *dev,
> + enum sunxi_cedrus_engine engine);
> +void sunxi_cedrus_engine_disable(struct sunxi_cedrus_dev *dev);
> +
> +int sunxi_cedrus_hw_probe(struct sunxi_cedrus_dev *dev);
> +void sunxi_cedrus_hw_remove(struct sunxi_cedrus_dev *dev);
> +
> +#endif
> 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 000000000000..5be3e3b9ceef
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.c
> @@ -0,0 +1,160 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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 <media/videobuf2-dma-contig.h>
> +
> +#include "sunxi_cedrus_common.h"
> +#include "sunxi_cedrus_hw.h"
> +#include "sunxi_cedrus_regs.h"
> +
> +static const u8 mpeg_default_intra_quant[64] = {
> + 8, 16, 16, 19, 16, 19, 22, 22,
> + 22, 22, 22, 22, 26, 24, 26, 27,
> + 27, 27, 26, 26, 26, 26, 27, 27,
> + 27, 29, 29, 29, 34, 34, 34, 29,
> + 29, 29, 27, 27, 29, 29, 32, 32,
> + 34, 34, 37, 38, 37, 35, 35, 34,
> + 35, 38, 38, 40, 40, 40, 48, 48,
> + 46, 46, 56, 56, 58, 69, 69, 83
> +};
> +
> +#define m_iq(i) (((64 + i) << 8) | mpeg_default_intra_quant[i])
> +
> +static const u8 mpeg_default_non_intra_quant[64] = {
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16,
> + 16, 16, 16, 16, 16, 16, 16, 16
> +};
> +
> +#define m_niq(i) ((i << 8) | mpeg_default_non_intra_quant[i])
> +
> +void sunxi_cedrus_mpeg2_setup(struct sunxi_cedrus_ctx *ctx,
> + struct sunxi_cedrus_run *run)
> +{
> + struct sunxi_cedrus_dev *dev = ctx->dev;
> + const struct v4l2_ctrl_mpeg2_frame_hdr *frame_hdr = run->mpeg2.hdr;
> +
> + u16 width = DIV_ROUND_UP(frame_hdr->width, 16);
> + u16 height = DIV_ROUND_UP(frame_hdr->height, 16);
> +
> + u32 pic_header = 0;
> + u32 vld_len = frame_hdr->slice_len - frame_hdr->slice_pos;
> + int i;
> +
> + struct vb2_buffer *fwd_vb2_buf, *bwd_vb2_buf;
> + dma_addr_t src_buf_addr, dst_luma_addr, dst_chroma_addr;
> + dma_addr_t fwd_luma = 0, fwd_chroma = 0, bwd_luma = 0, bwd_chroma = 0;
> +
> +
> + fwd_vb2_buf = ctx->dst_bufs[frame_hdr->forward_ref_index];
> + if (fwd_vb2_buf) {
> + fwd_luma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 0);
> + fwd_chroma = vb2_dma_contig_plane_dma_addr(fwd_vb2_buf, 1);
> + }
> +
> + bwd_vb2_buf = ctx->dst_bufs[frame_hdr->backward_ref_index];
> + if (bwd_vb2_buf) {
> + bwd_luma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 0);
> + bwd_chroma = vb2_dma_contig_plane_dma_addr(bwd_vb2_buf, 1);
> + }
> +
> + /* Activate MPEG engine. */
> + sunxi_cedrus_engine_enable(dev, SUNXI_CEDRUS_ENGINE_MPEG);
> +
> + /* Set 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);
> + }
> +
> + /* Set frame dimensions. */
> + sunxi_cedrus_write(dev, width << 8 | height, VE_MPEG_SIZE);
> + sunxi_cedrus_write(dev, width << 20 | height << 4, VE_MPEG_FRAME_SIZE);
> +
> + /* Set MPEG picture header. */
> + pic_header |= (frame_hdr->picture_coding_type & 0xf) << 28;
> + pic_header |= (frame_hdr->f_code[0][0] & 0xf) << 24;
> + pic_header |= (frame_hdr->f_code[0][1] & 0xf) << 20;
> + pic_header |= (frame_hdr->f_code[1][0] & 0xf) << 16;
> + pic_header |= (frame_hdr->f_code[1][1] & 0xf) << 12;
> + pic_header |= (frame_hdr->intra_dc_precision & 0x3) << 10;
> + pic_header |= (frame_hdr->picture_structure & 0x3) << 8;
> + pic_header |= (frame_hdr->top_field_first & 0x1) << 7;
> + pic_header |= (frame_hdr->frame_pred_frame_dct & 0x1) << 6;
> + pic_header |= (frame_hdr->concealment_motion_vectors & 0x1) << 5;
> + pic_header |= (frame_hdr->q_scale_type & 0x1) << 4;
> + pic_header |= (frame_hdr->intra_vlc_format & 0x1) << 3;
> + pic_header |= (frame_hdr->alternate_scan & 0x1) << 2;
> + 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);
> +
> + /* Clear correct macroblocks register. */
> + sunxi_cedrus_write(dev, 0, VE_MPEG_CTR_MB);
> +
> + /* Forward and backward prediction reference buffers. */
> + 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);
> +
> + /* Destination luma and chroma buffers. */
> + dst_luma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 0);
> + dst_chroma_addr = vb2_dma_contig_plane_dma_addr(&run->dst->vb2_buf, 1);
> + sunxi_cedrus_write(dev, dst_luma_addr, VE_MPEG_REC_LUMA);
> + sunxi_cedrus_write(dev, dst_chroma_addr, VE_MPEG_REC_CHROMA);
> + sunxi_cedrus_write(dev, dst_luma_addr, VE_MPEG_ROT_LUMA);
> + sunxi_cedrus_write(dev, dst_chroma_addr, VE_MPEG_ROT_CHROMA);
> +
> + /* Source 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);
> +
> + /* Source beginning and end addresses. */
> + src_buf_addr = vb2_dma_contig_plane_dma_addr(&run->src->vb2_buf, 0);
> + sunxi_cedrus_write(dev, VE_MPEG_VLD_ADDR_VAL(src_buf_addr),
> + VE_MPEG_VLD_ADDR);
> + sunxi_cedrus_write(dev, src_buf_addr + VBV_SIZE - 1, VE_MPEG_VLD_END);
> +}
> +
> +void sunxi_cedrus_mpeg2_trigger(struct sunxi_cedrus_ctx *ctx, bool mpeg1)
> +{
> + struct sunxi_cedrus_dev *dev = ctx->dev;
> +
> + /* Trigger MPEG engine. */
> + if (mpeg1)
> + sunxi_cedrus_write(dev, VE_TRIG_MPEG1, VE_MPEG_TRIGGER);
> + else
> + sunxi_cedrus_write(dev, VE_TRIG_MPEG2, VE_MPEG_TRIGGER);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h
> new file mode 100644
> index 000000000000..b572001d47f2
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_mpeg2.h
> @@ -0,0 +1,33 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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_MPEG2_H_
> +#define _SUNXI_CEDRUS_MPEG2_H_
> +
> +struct sunxi_cedrus_ctx;
> +struct sunxi_cedrus_run;
> +
> +void sunxi_cedrus_mpeg2_setup(struct sunxi_cedrus_ctx *ctx,
> + struct sunxi_cedrus_run *run);
> +void sunxi_cedrus_mpeg2_trigger(struct sunxi_cedrus_ctx *ctx, bool mpeg1);
> +
> +#endif
> 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 000000000000..6705d41dad07
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_regs.h
> @@ -0,0 +1,175 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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
> + */
> +
> +/* VE_MPEG_CTRL:
> + * The bit 3 (0x8) is used to enable IRQs
> + * The other bits are unknown but needed
> + */
> +#define VE_MPEG_CTRL_MPEG2 0x800001b8
> +#define VE_MPEG_CTRL_MPEG4 (0x80084118 | BIT(7))
> +#define VE_MPEG_CTRL_MPEG4_P (VE_MPEG_CTRL_MPEG4 | BIT(12))
> +
> +/* VE_MPEG_VLD_ADDR:
> + * The bits 27 to 4 are used for the address
> + * The bits 31 to 28 (0x7) are used to select the MPEG or JPEG engine
> + */
> +#define VE_MPEG_VLD_ADDR_VAL(x) ((x & 0x0ffffff0) | (x >> 28) | (0x7 << 28))
> +
> +/* VE_MPEG_TRIGGER:
> + * The first three bits are used to trigger the engine
> + * The bits 24 to 26 are used to select the input format (1 for MPEG1, 2 for
> + * MPEG2, 4 for MPEG4)
> + * The bit 21 (0x8) is used to disable bitstream error handling
> + *
> + * In MPEG4 the w*h value is somehow used for an offset, unknown but needed
> + */
> +#define VE_TRIG_MPEG1 0x8100000f
> +#define VE_TRIG_MPEG2 0x8200000f
> +#define VE_TRIG_MPEG4(w, h) (0x8400000d | ((w * h) << 8))
> +
> +/* VE_MPEG_SDROT_CTRL:
> + * The bit 8 at zero is used to disable x downscaling
> + * The bit 10 at 0 is used to disable y downscaling
> + * The other bits are unknown but needed
> + */
> +#define VE_NO_SDROT_CTRL 0x40620000
> +
> +/* Decent size fo video buffering verifier */
> +#define VBV_SIZE (1024 * 1024)
> +
> +/* Registers addresses */
> +#define VE_CTRL 0x000
> +/*
> + * The datasheet states that this should be set to 2MB on a 32bits
> + * DDR-3.
> + */
> +#define VE_CTRL_REC_WR_MODE_2MB (1 << 20)
> +#define VE_CTRL_REC_WR_MODE_1MB (0 << 20)
> +
> +#define VE_CTRL_CACHE_BUS_BW_128 (3 << 16)
> +#define VE_CTRL_CACHE_BUS_BW_256 (2 << 16)
> +
> +#define VE_CTRL_DEC_MODE_DISABLED (7 << 0)
> +#define VE_CTRL_DEC_MODE_H265 (4 << 0)
> +#define VE_CTRL_DEC_MODE_H264 (1 << 0)
> +#define VE_CTRL_DEC_MODE_MPEG (0 << 0)
> +
> +#define VE_VERSION 0x0f0
> +
> +#define VE_MPEG_PIC_HDR 0x100
> +#define VE_MPEG_VOP_HDR 0x104
> +#define VE_MPEG_SIZE 0x108
> +#define VE_MPEG_FRAME_SIZE 0x10c
> +#define VE_MPEG_MBA 0x110
> +#define VE_MPEG_CTRL 0x114
> +#define VE_MPEG_TRIGGER 0x118
> +#define VE_MPEG_STATUS 0x11c
> +#define VE_MPEG_TRBTRD_FIELD 0x120
> +#define VE_MPEG_TRBTRD_FRAME 0x124
> +#define VE_MPEG_VLD_ADDR 0x128
> +#define VE_MPEG_VLD_OFFSET 0x12c
> +#define VE_MPEG_VLD_LEN 0x130
> +#define VE_MPEG_VLD_END 0x134
> +#define VE_MPEG_MBH_ADDR 0x138
> +#define VE_MPEG_DCAC_ADDR 0x13c
> +#define VE_MPEG_NCF_ADDR 0x144
> +#define VE_MPEG_REC_LUMA 0x148
> +#define VE_MPEG_REC_CHROMA 0x14c
> +#define VE_MPEG_FWD_LUMA 0x150
> +#define VE_MPEG_FWD_CHROMA 0x154
> +#define VE_MPEG_BACK_LUMA 0x158
> +#define VE_MPEG_BACK_CHROMA 0x15c
> +#define VE_MPEG_IQ_MIN_INPUT 0x180
> +#define VE_MPEG_QP_INPUT 0x184
> +#define VE_MPEG_JPEG_SIZE 0x1b8
> +#define VE_MPEG_JPEG_RES_INT 0x1c0
> +#define VE_MPEG_ERROR 0x1c4
> +#define VE_MPEG_CTR_MB 0x1c8
> +#define VE_MPEG_ROT_LUMA 0x1cc
> +#define VE_MPEG_ROT_CHROMA 0x1d0
> +#define VE_MPEG_SDROT_CTRL 0x1d4
> +#define VE_MPEG_RAM_WRITE_PTR 0x1e0
> +#define VE_MPEG_RAM_WRITE_DATA 0x1e4
> +
> +#define VE_H264_FRAME_SIZE 0x200
> +#define VE_H264_PIC_HDR 0x204
> +#define VE_H264_SLICE_HDR 0x208
> +#define VE_H264_SLICE_HDR2 0x20c
> +#define VE_H264_PRED_WEIGHT 0x210
> +#define VE_H264_QP_PARAM 0x21c
> +#define VE_H264_CTRL 0x220
> +#define VE_H264_TRIGGER 0x224
> +#define VE_H264_STATUS 0x228
> +#define VE_H264_CUR_MB_NUM 0x22c
> +#define VE_H264_VLD_ADDR 0x230
> +#define VE_H264_VLD_OFFSET 0x234
> +#define VE_H264_VLD_LEN 0x238
> +#define VE_H264_VLD_END 0x23c
> +#define VE_H264_SDROT_CTRL 0x240
> +#define VE_H264_OUTPUT_FRAME_IDX 0x24c
> +#define VE_H264_EXTRA_BUFFER1 0x250
> +#define VE_H264_EXTRA_BUFFER2 0x254
> +#define VE_H264_BASIC_BITS 0x2dc
> +#define VE_H264_RAM_WRITE_PTR 0x2e0
> +#define VE_H264_RAM_WRITE_DATA 0x2e4
> +
> +#define VE_SRAM_H264_PRED_WEIGHT_TABLE 0x000
> +#define VE_SRAM_H264_FRAMEBUFFER_LIST 0x400
> +#define VE_SRAM_H264_REF_LIST0 0x640
> +#define VE_SRAM_H264_REF_LIST1 0x664
> +#define VE_SRAM_H264_SCALING_LISTS 0x800
> +
> +#define VE_ISP_INPUT_SIZE 0xa00
> +#define VE_ISP_INPUT_STRIDE 0xa04
> +#define VE_ISP_CTRL 0xa08
> +#define VE_ISP_INPUT_LUMA 0xa78
> +#define VE_ISP_INPUT_CHROMA 0xa7c
> +
> +#define VE_AVC_PARAM 0xb04
> +#define VE_AVC_QP 0xb08
> +#define VE_AVC_MOTION_EST 0xb10
> +#define VE_AVC_CTRL 0xb14
> +#define VE_AVC_TRIGGER 0xb18
> +#define VE_AVC_STATUS 0xb1c
> +#define VE_AVC_BASIC_BITS 0xb20
> +#define VE_AVC_UNK_BUF 0xb60
> +#define VE_AVC_VLE_ADDR 0xb80
> +#define VE_AVC_VLE_END 0xb84
> +#define VE_AVC_VLE_OFFSET 0xb88
> +#define VE_AVC_VLE_MAX 0xb8c
> +#define VE_AVC_VLE_LENGTH 0xb90
> +#define VE_AVC_REF_LUMA 0xba0
> +#define VE_AVC_REF_CHROMA 0xba4
> +#define VE_AVC_REC_LUMA 0xbb0
> +#define VE_AVC_REC_CHROMA 0xbb4
> +#define VE_AVC_REF_SLUMA 0xbb8
> +#define VE_AVC_REC_SLUMA 0xbbc
> +#define VE_AVC_MB_INFO 0xbc0
> +
> +#endif
> diff --git a/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.c b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.c
> new file mode 100644
> index 000000000000..089abfe6bfeb
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.c
> @@ -0,0 +1,505 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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 <media/videobuf2-dma-contig.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-ioctl.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-mem2mem.h>
> +
> +#include "sunxi_cedrus_common.h"
> +#include "sunxi_cedrus_mpeg2.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_MB32_NV12,
> + .types = SUNXI_CEDRUS_CAPTURE,
> + .depth = 2,
> + .num_planes = 2,
> + },
> + {
> + .fourcc = V4L2_PIX_FMT_MPEG2_FRAME,
> + .types = SUNXI_CEDRUS_OUTPUT,
> + .num_planes = 1,
> + },
> +};
> +
> +#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);
> +}
> +
> +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)
> +{
> + struct sunxi_cedrus_fmt *fmt;
> + int i, num = 0;
> +
> + for (i = 0; i < NUM_FORMATS; ++i) {
> + if (formats[i].types & type) {
> + /* index-th format of type type found ? */
> + if (num == f->index)
> + break;
> + /*
> + * Correct type but haven't reached our index yet,
> + * just increment per-type index
> + */
> + ++num;
> + }
> + }
> +
> + if (i < NUM_FORMATS) {
> + fmt = &formats[i];
> + f->pixelformat = fmt->fourcc;
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
> + struct v4l2_fmtdesc *f)
> +{
> + return enum_fmt(f, 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 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,
> +};
> +
> +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;
No need for these two checks, the vb2 core takes care of that.
> +
> + 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;
> +
> + flush_scheduled_work();
> + for (;;) {
> + spin_lock_irqsave(&ctx->dev->irq_lock, flags);
> +
> + if (V4L2_TYPE_IS_OUTPUT(q->type))
> + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
> + else
> + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
> +
> + spin_unlock_irqrestore(&ctx->dev->irq_lock, flags);
> +
> + if (vbuf == NULL)
> + return;
> +
> + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
> + &ctx->hdl);
> + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
> + }
> +}
> +
> +static void 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 void sunxi_cedrus_buf_request_complete(struct vb2_buffer *vb)
> +{
> + struct sunxi_cedrus_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
> +
> + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
> +}
> +
> +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,
> + .buf_request_complete = sunxi_cedrus_buf_request_complete,
> + .stop_streaming = sunxi_cedrus_stop_streaming,
> + .wait_prepare = vb2_ops_wait_prepare,
> + .wait_finish = vb2_ops_wait_finish,
> +};
> +
> +int sunxi_cedrus_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 sunxi_cedrus_buffer);
> + src_vq->allow_zero_bytesused = 1;
> + src_vq->min_buffers_needed = 1;
> + 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->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 sunxi_cedrus_buffer);
> + dst_vq->allow_zero_bytesused = 1;
> + dst_vq->min_buffers_needed = 1;
> + 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->dev = ctx->dev->dev;
> +
> + return vb2_queue_init(dst_vq);
> +}
> diff --git a/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.h b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.h
> new file mode 100644
> index 000000000000..d5b7f881c386
> --- /dev/null
> +++ b/drivers/media/platform/sunxi/cedrus/sunxi_cedrus_video.h
> @@ -0,0 +1,31 @@
> +/*
> + * Sunxi-Cedrus VPU driver
> + *
> + * Copyright (C) 2018 Paul Kocialkowski <paul.kocialkowski@bootlin.com>
> + * Copyright (C) 2016 Florent Revest <florent.revest@free-electrons.com>
> + *
> + * Based on the vim2m driver, that is:
> + *
> + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
> + * Pawel Osciak, <pawel@osciak.com>
> + * Marek Szyprowski, <m.szyprowski@samsung.com>
> + *
> + * 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_VIDEO_H_
> +#define _SUNXI_CEDRUS_VIDEO_H_
> +
> +extern const struct v4l2_ioctl_ops sunxi_cedrus_ioctl_ops;
> +
> +int sunxi_cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
> + struct vb2_queue *dst_vq);
> +
> +#endif
>
Regards,
Hans
^ permalink raw reply
* [PATCH] ARM: dts: imx51-zii-rdu1: fix touchscreen bindings
From: Fabio Estevam @ 2018-05-07 14:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180507135309.32580-1-nikita.yoush@cogentembedded.com>
Hi Nikita,
On Mon, May 7, 2018 at 10:53 AM, Nikita Yushchenko
<nikita.yoush@cogentembedded.com> wrote:
> This fixes errors in RDU1 device tree that cause touch screens not
> working.
Fixes: ceef0396f367 ("ARM: dts: imx: add ZII RDU1 board")
Cc: stable at vger.kernel.org #4.15+
> Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox