aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--testing/linux-amlogic/0001-ARM64-defconfig-enable-CEC-support.patch (renamed from testing/linux-amlogic/0003-ARM64-defconfig-enable-CEC-support.patch)11
-rw-r--r--testing/linux-amlogic/0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch81
-rw-r--r--testing/linux-amlogic/0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch62
-rw-r--r--testing/linux-amlogic/0001-drm-meson-fix-max-mode_config-height-width.patch33
-rw-r--r--testing/linux-amlogic/0001-libretech-cc-disable-CVBS-connector.patch24
-rw-r--r--testing/linux-amlogic/0002-ASoC-meson-add-meson-audio-core-driver.patch (renamed from testing/linux-amlogic/0006-ASoC-meson-add-meson-audio-core-driver.patch)62
-rw-r--r--testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch1314
-rw-r--r--testing/linux-amlogic/0003-ASoC-meson-add-register-definitions.patch (renamed from testing/linux-amlogic/0007-ASoC-meson-add-register-definitions.patch)3
-rw-r--r--testing/linux-amlogic/0004-ASoC-meson-add-aiu-i2s-dma-support.patch (renamed from testing/linux-amlogic/0008-ASoC-meson-add-aiu-i2s-dma-support.patch)24
-rw-r--r--testing/linux-amlogic/0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch44
-rw-r--r--testing/linux-amlogic/0005-ASoC-meson-add-initial-i2s-dai-support.patch (renamed from testing/linux-amlogic/0009-ASoC-meson-add-initial-i2s-dai-support.patch)25
-rw-r--r--testing/linux-amlogic/0005-clk-meson-remove-unused-clk-audio-divider-driver.patch48
-rw-r--r--testing/linux-amlogic/0006-ASoC-meson-add-aiu-spdif-dma-support.patch (renamed from testing/linux-amlogic/0010-ASoC-meson-add-aiu-spdif-dma-support.patch)27
-rw-r--r--testing/linux-amlogic/0007-ASoC-meson-add-initial-spdif-dai-support.patch (renamed from testing/linux-amlogic/0011-ASoC-meson-add-initial-spdif-dai-support.patch)28
-rw-r--r--testing/linux-amlogic/0008-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch (renamed from testing/linux-amlogic/0012-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch)18
-rw-r--r--testing/linux-amlogic/0008-drm-meson-Add-HDMI-1.4-4k-modes.patch165
-rw-r--r--testing/linux-amlogic/0009-ARM64-dts-meson-gx-add-audio-controller-nodes.patch (renamed from testing/linux-amlogic/0013-ARM64-dts-meson-gx-add-audio-controller-nodes.patch)3
-rw-r--r--testing/linux-amlogic/0009-drm-meson-Use-drm_fbdev_generic_setup.patch100
-rw-r--r--testing/linux-amlogic/0010-fixup-drm-meson-Use-optional-canvas-provider.patch21
-rw-r--r--testing/linux-amlogic/0010-snd-meson-activate-HDMI-audio-path.patch (renamed from testing/linux-amlogic/0014-snd-meson-activate-HDMI-audio-path.patch)3
-rw-r--r--testing/linux-amlogic/0011-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch (renamed from testing/linux-amlogic/0015-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch)3
-rw-r--r--testing/linux-amlogic/0012-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch (renamed from testing/linux-amlogic/0016-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch)3
-rw-r--r--testing/linux-amlogic/0012-drm-meson-add-support-for-1080p25-mode.patch21
-rw-r--r--testing/linux-amlogic/0013-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch (renamed from testing/linux-amlogic/0017-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch)15
-rw-r--r--testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch147
-rw-r--r--testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch (renamed from testing/linux-amlogic/0018-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch)5
-rw-r--r--testing/linux-amlogic/0015-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch61
-rw-r--r--testing/linux-amlogic/0015-drm-meson-add-HDMI-div40-TMDS-mode.patch69
-rw-r--r--testing/linux-amlogic/0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch28
-rw-r--r--testing/linux-amlogic/0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch198
-rw-r--r--testing/linux-amlogic/0017-soc-amlogic-add-meson-canvas-driver.patch314
-rw-r--r--testing/linux-amlogic/0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch39
-rw-r--r--testing/linux-amlogic/0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch102
-rw-r--r--testing/linux-amlogic/0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch46
-rw-r--r--testing/linux-amlogic/0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch36
-rw-r--r--testing/linux-amlogic/0020-drm-meson-Add-YUV420-output-support.patch582
-rw-r--r--testing/linux-amlogic/0020-drm-meson-Use-optional-canvas-provider.patch172
-rw-r--r--testing/linux-amlogic/0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch32
-rw-r--r--testing/linux-amlogic/0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch25
-rw-r--r--testing/linux-amlogic/0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch31
-rw-r--r--testing/linux-amlogic/0021-soc-amlogic-add-meson-canvas-driver.patch280
-rw-r--r--testing/linux-amlogic/0022-drm-meson-Fixes-for-drm_crtc_vblank_on-off-support.patch130
-rw-r--r--testing/linux-amlogic/0022-drm-meson-Support-Overlay-plane-for-video-rendering.patch (renamed from testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch)457
-rw-r--r--testing/linux-amlogic/0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch55
-rw-r--r--testing/linux-amlogic/0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch40
-rw-r--r--testing/linux-amlogic/0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch124
-rw-r--r--testing/linux-amlogic/0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch198
-rw-r--r--testing/linux-amlogic/0024-drm-meson-Add-primary-plane-scaling.patch285
-rw-r--r--testing/linux-amlogic/0024-drm-meson-convert-to-the-new-canvas-module.patch399
-rw-r--r--testing/linux-amlogic/0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch5906
-rw-r--r--testing/linux-amlogic/0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch55
-rw-r--r--testing/linux-amlogic/0027-ARM64-dts-meson-gx-add-vdec-entry.patch35
-rw-r--r--testing/linux-amlogic/0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch79
-rw-r--r--testing/linux-amlogic/0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch38
-rw-r--r--testing/linux-amlogic/0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch38
-rw-r--r--testing/linux-amlogic/0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch38
-rw-r--r--testing/linux-amlogic/0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch38
-rw-r--r--testing/linux-amlogic/0032-drm-meson-Add-support-for-VIC-alternate-timings.patch328
-rw-r--r--testing/linux-amlogic/0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch2969
-rw-r--r--testing/linux-amlogic/0034-MAINTAINERS-Add-meson-video-decoder.patch32
-rw-r--r--testing/linux-amlogic/0035-arm64-dts-meson-gx-add-vdec-entry.patch38
-rw-r--r--testing/linux-amlogic/0036-arm64-dts-meson-add-vdec-entries.patch (renamed from testing/linux-amlogic/0001-ARM64-dts-meson-add-vdec-entries.patch)45
-rw-r--r--testing/linux-amlogic/0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch153
-rw-r--r--testing/linux-amlogic/0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch49
-rw-r--r--testing/linux-amlogic/0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch270
-rw-r--r--testing/linux-amlogic/0040-media-meson-vdec-add-H.264-decoding-support.patch591
-rw-r--r--testing/linux-amlogic/0041-media-meson-vdec-add-MPEG4-decoding-support.patch313
-rw-r--r--testing/linux-amlogic/0042-media-meson-vdec-add-MJPEG-decoding-support.patch253
-rw-r--r--testing/linux-amlogic/0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch42
-rw-r--r--testing/linux-amlogic/APKBUILD182
-rw-r--r--testing/linux-amlogic/add-phicomm-n1.patch8
-rw-r--r--testing/linux-amlogic/brcmfmac-Disable-power-management.patch13
-rw-r--r--testing/linux-amlogic/off_error_text_offset.patch13
-rw-r--r--testing/linux-amlogic/offset.patch13
-rw-r--r--testing/linux-amlogic/text_offset.patch26
75 files changed, 8854 insertions, 8704 deletions
diff --git a/testing/linux-amlogic/0003-ARM64-defconfig-enable-CEC-support.patch b/testing/linux-amlogic/0001-ARM64-defconfig-enable-CEC-support.patch
index 7c04717531..41791a5c25 100644
--- a/testing/linux-amlogic/0003-ARM64-defconfig-enable-CEC-support.patch
+++ b/testing/linux-amlogic/0001-ARM64-defconfig-enable-CEC-support.patch
@@ -1,4 +1,4 @@
-From e41c06328d1cd0989899d6a0897c6857d0cf9a4b Mon Sep 17 00:00:00 2001
+From 0c815d66dbaa54b53e4b54105992ce44dfe8c36f Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Mon, 13 Nov 2017 12:09:40 +0100
Subject: [PATCH] ARM64: defconfig: enable CEC support
@@ -9,15 +9,16 @@ Turn on CONFIG_DRM_DW_HDMI_CEC as module
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
---
arch/arm64/configs/defconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
-index f9a186f..2584605 100644
+index db8d364..ab1cb51 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
-@@ -402,6 +402,7 @@ CONFIG_MEDIA_SUPPORT=m
+@@ -413,6 +413,7 @@ CONFIG_MEDIA_SUPPORT=m
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
@@ -25,7 +26,7 @@ index f9a186f..2584605 100644
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
# CONFIG_DVB_NET is not set
-@@ -411,6 +412,8 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
+@@ -424,6 +425,8 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
CONFIG_VIDEO_RENESAS_FCP=m
CONFIG_VIDEO_RENESAS_VSP1=m
@@ -34,7 +35,7 @@ index f9a186f..2584605 100644
CONFIG_DRM=m
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_EXYNOS=m
-@@ -431,6 +434,7 @@ CONFIG_DRM_RCAR_LVDS=m
+@@ -444,6 +447,7 @@ CONFIG_DRM_RCAR_LVDS=m
CONFIG_DRM_TEGRA=m
CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_I2C_ADV7511=m
diff --git a/testing/linux-amlogic/0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch b/testing/linux-amlogic/0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch
deleted file mode 100644
index aad63ba8fe..0000000000
--- a/testing/linux-amlogic/0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch
+++ /dev/null
@@ -1,81 +0,0 @@
-From 6c5aaf27886c9b308e9c4e4d613990e540f23ec8 Mon Sep 17 00:00:00 2001
-From: Neil Armstrong <narmstrong@baylibre.com>
-Date: Tue, 26 Jun 2018 09:37:39 +0200
-Subject: [PATCH] ARM64: dts: meson-gxbb-nanopi-k2: Add HDMI, CEC and CVBS
- nodes
-
-The Amlogic Meson GXBB based Nanopi-K2 board has an HDMI connector
-with CEC and CVBS available on the 40pin header.
-This patch adds the nodes to enable HDMI, CEC and CVBS functionnalities.
-
-Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
----
- .../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 48 ++++++++++++++++++++++
- 1 file changed, 48 insertions(+)
-
-diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
-index 7d5709c..cbe99bd 100644
---- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
-+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
-@@ -106,6 +106,42 @@
- compatible = "mmc-pwrseq-emmc";
- reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
- };
-+
-+ /* CVBS is available on CON1 pin 36, disabled by default */
-+ cvbs-connector {
-+ compatible = "composite-video-connector";
-+ status = "disabled";
-+
-+ port {
-+ cvbs_connector_in: endpoint {
-+ remote-endpoint = <&cvbs_vdac_out>;
-+ };
-+ };
-+ };
-+
-+ hdmi-connector {
-+ compatible = "hdmi-connector";
-+ type = "a";
-+
-+ port {
-+ hdmi_connector_in: endpoint {
-+ remote-endpoint = <&hdmi_tx_tmds_out>;
-+ };
-+ };
-+ };
-+};
-+
-+&cec_AO {
-+ status = "okay";
-+ pinctrl-0 = <&ao_cec_pins>;
-+ pinctrl-names = "default";
-+ hdmi-phandle = <&hdmi_tx>;
-+};
-+
-+&cvbs_vdac_port {
-+ cvbs_vdac_out: endpoint {
-+ remote-endpoint = <&cvbs_connector_in>;
-+ };
- };
-
- &ethmac {
-@@ -137,6 +173,18 @@
- };
- };
-
-+&hdmi_tx {
-+ status = "okay";
-+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
-+ pinctrl-names = "default";
-+};
-+
-+&hdmi_tx_tmds_port {
-+ hdmi_tx_tmds_out: endpoint {
-+ remote-endpoint = <&hdmi_connector_in>;
-+ };
-+};
-+
- &ir {
- status = "okay";
- pinctrl-0 = <&remote_input_ao_pins>;
diff --git a/testing/linux-amlogic/0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch b/testing/linux-amlogic/0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch
new file mode 100644
index 0000000000..5bcec06be2
--- /dev/null
+++ b/testing/linux-amlogic/0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch
@@ -0,0 +1,62 @@
+From e2c70445f3533e8fa62f8c645713508148f8e4f6 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <ccaione@baylibre.com>
+Date: Tue, 4 Dec 2018 16:04:46 +0000
+Subject: [PATCH] arm64: dts: meson: Fix IRQ trigger type for macirq
+
+A long running stress test on a custom board shipping an AXG SoCs and a
+Realtek RTL8211F PHY revealed that after a few hours the connection
+speed would drop drastically, from ~1000Mbps to ~3Mbps. At the same time
+the 'macirq' (eth0) IRQ would stop being triggered at all and as
+consequence the GMAC IRQs never ACKed.
+
+After a painful investigation the problem seemed to be due to a wrong
+defined IRQ type for the GMAC IRQ that should be LEVEL_HIGH instead of
+EDGE_RISING.
+
+Signed-off-by: Carlo Caione <ccaione@baylibre.com>
+Acked-by: Neil Armstrong <narmstrong@baylibre.com>
+---
+ arch/arm/boot/dts/meson.dtsi | 2 +-
+ arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 2 +-
+ arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 +-
+ 3 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/boot/dts/meson.dtsi b/arch/arm/boot/dts/meson.dtsi
+index 0d9faf1a51ea..a86b89086334 100644
+--- a/arch/arm/boot/dts/meson.dtsi
++++ b/arch/arm/boot/dts/meson.dtsi
+@@ -263,7 +263,7 @@
+ compatible = "amlogic,meson6-dwmac", "snps,dwmac";
+ reg = <0xc9410000 0x10000
+ 0xc1108108 0x4>;
+- interrupts = <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>;
++ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ status = "disabled";
+ };
+diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+index c518130e5ce7..81dcbde9e674 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
+@@ -461,7 +461,7 @@
+ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac";
+ reg = <0x0 0xff3f0000 0x0 0x10000
+ 0x0 0xff634540 0x0 0x8>;
+- interrupts = <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>;
++ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ clocks = <&clkc CLKID_ETH>,
+ <&clkc CLKID_FCLK_DIV2>,
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+index 5d2820ef9a88..d03737acbae1 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+@@ -511,7 +511,7 @@
+ compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac";
+ reg = <0x0 0xc9410000 0x0 0x10000
+ 0x0 0xc8834540 0x0 0x4>;
+- interrupts = <GIC_SPI 8 IRQ_TYPE_EDGE_RISING>;
++ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ status = "disabled";
+ };
diff --git a/testing/linux-amlogic/0001-drm-meson-fix-max-mode_config-height-width.patch b/testing/linux-amlogic/0001-drm-meson-fix-max-mode_config-height-width.patch
new file mode 100644
index 0000000000..b9c5c2ca50
--- /dev/null
+++ b/testing/linux-amlogic/0001-drm-meson-fix-max-mode_config-height-width.patch
@@ -0,0 +1,33 @@
+From a2b8a766c2fb57096c065e539d93f9f4fbd7ace4 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Thu, 4 Oct 2018 10:42:43 +0200
+Subject: [PATCH] drm/meson: fix max mode_config height/width
+
+The mode_config max_width/max_height determines the maximum framebuffer
+size the pixel reader can handle. But the values were set thinking they
+were determining the maximum screen dimensions.
+
+This patch changes the values to the maximum height/width the CANVAS block
+can handle rounded to some coherent values.
+
+Fixes: a41e82e6c457 ("drm/meson: Add support for components")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+---
+ drivers/gpu/drm/meson/meson_drv.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
+index 3ee4d4a4ecba..b3c04ecc75f3 100644
+--- a/drivers/gpu/drm/meson/meson_drv.c
++++ b/drivers/gpu/drm/meson/meson_drv.c
+@@ -263,8 +263,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ goto free_drm;
+
+ drm_mode_config_init(drm);
+- drm->mode_config.max_width = 3840;
+- drm->mode_config.max_height = 2160;
++ drm->mode_config.max_width = 16384;
++ drm->mode_config.max_height = 8192;
+ drm->mode_config.funcs = &meson_mode_config_funcs;
+
+ /* Hardware Initialization */
diff --git a/testing/linux-amlogic/0001-libretech-cc-disable-CVBS-connector.patch b/testing/linux-amlogic/0001-libretech-cc-disable-CVBS-connector.patch
deleted file mode 100644
index 7f82981189..0000000000
--- a/testing/linux-amlogic/0001-libretech-cc-disable-CVBS-connector.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From baa0a8ee8b8a0a14ddab6b14c37846dfed261007 Mon Sep 17 00:00:00 2001
-From: Koen Kooi <koen@dominion.thruhere.net>
-Date: Fri, 11 May 2018 13:51:20 +0200
-Subject: [PATCH] libretech-cc: disable CVBS connector
-
-Signed-off-by: Koen Kooi <koen@dominion.thruhere.net>
----
- arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
-index f56969e..ac3a150 100644
---- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
-+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
-@@ -24,7 +24,8 @@
- stdout-path = "serial0:115200n8";
- };
-
-- cvbs-connector {
-+ cvbs_connector: cvbs-connector {
-+ status = "disabled";
- compatible = "composite-video-connector";
-
- port {
diff --git a/testing/linux-amlogic/0006-ASoC-meson-add-meson-audio-core-driver.patch b/testing/linux-amlogic/0002-ASoC-meson-add-meson-audio-core-driver.patch
index 69c0ab2995..6acbf80c86 100644
--- a/testing/linux-amlogic/0006-ASoC-meson-add-meson-audio-core-driver.patch
+++ b/testing/linux-amlogic/0002-ASoC-meson-add-meson-audio-core-driver.patch
@@ -1,4 +1,4 @@
-From 878d41be386f0bcbe1475f65acd8b9fb304529a0 Mon Sep 17 00:00:00 2001
+From 4770a464de7b87bc849e4e110f197ef9fa7bccf6 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 11:49:55 +0200
Subject: [PATCH] ASoC: meson: add meson audio core driver
@@ -15,49 +15,25 @@ of the S905 (gxbb). This datasheet is available here: [0].
[0]: http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
- sound/soc/Kconfig | 1 +
- sound/soc/Makefile | 1 +
- sound/soc/meson/Kconfig | 9 ++
- sound/soc/meson/Makefile | 3 +
+ sound/soc/meson/Kconfig | 10 +++
+ sound/soc/meson/Makefile | 4 +
sound/soc/meson/audio-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/meson/audio-core.h | 28 +++++++
- 6 files changed, 232 insertions(+)
- create mode 100644 sound/soc/meson/Kconfig
- create mode 100644 sound/soc/meson/Makefile
+ 4 files changed, 232 insertions(+)
create mode 100644 sound/soc/meson/audio-core.c
create mode 100644 sound/soc/meson/audio-core.h
-diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
-index 41af6b9..1cf11cf 100644
---- a/sound/soc/Kconfig
-+++ b/sound/soc/Kconfig
-@@ -57,6 +57,7 @@ source "sound/soc/kirkwood/Kconfig"
- source "sound/soc/img/Kconfig"
- source "sound/soc/intel/Kconfig"
- source "sound/soc/mediatek/Kconfig"
-+source "sound/soc/meson/Kconfig"
- source "sound/soc/mxs/Kconfig"
- source "sound/soc/pxa/Kconfig"
- source "sound/soc/qcom/Kconfig"
-diff --git a/sound/soc/Makefile b/sound/soc/Makefile
-index 06389a5..62a5f87 100644
---- a/sound/soc/Makefile
-+++ b/sound/soc/Makefile
-@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
- obj-$(CONFIG_SND_SOC) += img/
- obj-$(CONFIG_SND_SOC) += intel/
- obj-$(CONFIG_SND_SOC) += mediatek/
-+obj-$(CONFIG_SND_SOC) += meson/
- obj-$(CONFIG_SND_SOC) += mxs/
- obj-$(CONFIG_SND_SOC) += nuc900/
- obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
-new file mode 100644
-index 0000000..ca0e3e9
---- /dev/null
+index 8af8bc3..ed432d4 100644
+--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
-@@ -0,0 +1,9 @@
+@@ -63,3 +63,13 @@ config SND_MESON_AXG_SPDIFOUT
+ in the Amlogic AXG SoC family
+
+ endmenu
++
+menuconfig SND_SOC_MESON
+ tristate "ASoC support for Amlogic Meson SoCs"
+ depends on ARCH_MESON
@@ -68,14 +44,18 @@ index 0000000..ca0e3e9
+ the Amlogic Meson SoCs Audio interfaces. You will also need to
+ select the audio interfaces to support below.
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
-new file mode 100644
-index 0000000..22028ab
---- /dev/null
+index c5e003b..768d7c4 100644
+--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
-@@ -0,0 +1,3 @@
+@@ -19,3 +19,7 @@ obj-$(CONFIG_SND_MESON_AXG_TDMIN) += snd-soc-meson-axg-tdmin.o
+ obj-$(CONFIG_SND_MESON_AXG_TDMOUT) += snd-soc-meson-axg-tdmout.o
+ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
++
+snd-soc-meson-audio-core-objs := audio-core.o
+
-+obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
++obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+\ No newline at end of file
diff --git a/sound/soc/meson/audio-core.c b/sound/soc/meson/audio-core.c
new file mode 100644
index 0000000..99993ec
diff --git a/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch b/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch
deleted file mode 100644
index 7625f11f5b..0000000000
--- a/testing/linux-amlogic/0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch
+++ /dev/null
@@ -1,1314 +0,0 @@
-From 8ea8dd0432a9964e3e2642433d942c3aa9116fd3 Mon Sep 17 00:00:00 2001
-From: Neil Armstrong <narmstrong@baylibre.com>
-Date: Fri, 27 Apr 2018 17:19:46 +0200
-Subject: [PATCH] drm/meson: Make DMT timings parameters and pixel clock
- generic
-
-Remove the modes timings tables for DMT modes and calculate the HW
-paremeters from the modes timings.
-
-Switch the DMT modes pixel clock calculation out of the static frequency
-list to a generic calculation from a range of possible PLL dividers.
-
-This setup permits setting non-CEA modes like :
-- 1600x900-60Hz
-- 1280x1024-75Hz
-- 1280x1024-60Hz
-- 1440x900-60Hz
-- 1366x768-60Hz
-- 1280x800-60Hz
-- 1152x864-75Hz
-- 1024x768-75Hz
-- 1024x768-70Hz
-- 1024x768-60Hz
-- 832x624-75Hz
-- 800x600-75Hz
-- 800x600-72Hz
-- 800x600-60Hz
-- 640x480-75Hz
-- 640x480-73Hz
-- 640x480-67Hz
-
-Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
----
- drivers/gpu/drm/meson/meson_dw_hdmi.c | 22 +-
- drivers/gpu/drm/meson/meson_vclk.c | 658 +++++++++++++++-------------------
- drivers/gpu/drm/meson/meson_vclk.h | 4 +
- drivers/gpu/drm/meson/meson_venc.c | 379 +++-----------------
- drivers/gpu/drm/meson/meson_venc.h | 3 +-
- 5 files changed, 352 insertions(+), 714 deletions(-)
-
-diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
-index c9ad456..df7247c 100644
---- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
-+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
-@@ -329,6 +329,12 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
-
- vclk_freq = mode->clock;
-
-+ if (!vic) {
-+ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
-+ vclk_freq, vclk_freq, false);
-+ return;
-+ }
-+
- if (mode->flags & DRM_MODE_FLAG_DBLCLK)
- vclk_freq *= 2;
-
-@@ -542,10 +548,12 @@ static enum drm_mode_status
- dw_hdmi_mode_valid(struct drm_connector *connector,
- const struct drm_display_mode *mode)
- {
-+ struct meson_drm *priv = connector->dev->dev_private;
- unsigned int vclk_freq;
- unsigned int venc_freq;
- unsigned int hdmi_freq;
- int vic = drm_match_cea_mode(mode);
-+ enum drm_mode_status status;
-
- DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
- mode->base.id, mode->name, mode->vrefresh, mode->clock,
-@@ -556,8 +564,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
-
- /* Check against non-VIC supported modes */
- if (!vic) {
-- if (!meson_venc_hdmi_supported_mode(mode))
-- return MODE_BAD;
-+ status = meson_venc_hdmi_supported_mode(mode);
-+ if (status != MODE_OK)
-+ return status;
-+
-+ return meson_vclk_dmt_supported_freq(priv, mode->clock);
- /* Check against supported VIC modes */
- } else if (!meson_venc_hdmi_supported_vic(vic))
- return MODE_BAD;
-@@ -583,16 +594,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
- vclk_freq, venc_freq, hdmi_freq);
-
-- /* Finally filter by configurable vclk frequencies */
-+ /* Finally filter by configurable vclk frequencies for VIC modes */
- switch (vclk_freq) {
-- case 25175:
-- case 40000:
- case 54000:
-- case 65000:
- case 74250:
-- case 108000:
- case 148500:
-- case 162000:
- case 297000:
- case 594000:
- return MODE_OK;
-diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
-index f051122..0b17788 100644
---- a/drivers/gpu/drm/meson/meson_vclk.c
-+++ b/drivers/gpu/drm/meson/meson_vclk.c
-@@ -320,32 +320,23 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
- CTS_VDAC_EN, CTS_VDAC_EN);
- }
-
--
-+enum {
- /* PLL O1 O2 O3 VP DV EN TX */
- /* 4320 /4 /4 /1 /5 /1 => /2 /2 */
--#define MESON_VCLK_HDMI_ENCI_54000 1
-+ MESON_VCLK_HDMI_ENCI_54000 = 1,
- /* 4320 /4 /4 /1 /5 /1 => /1 /2 */
--#define MESON_VCLK_HDMI_DDR_54000 2
-+ MESON_VCLK_HDMI_DDR_54000,
- /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
--#define MESON_VCLK_HDMI_DDR_148500 3
--/* 4028 /4 /4 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_25175 4
--/* 3200 /4 /2 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_40000 5
--/* 5200 /4 /2 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_65000 6
-+ MESON_VCLK_HDMI_DDR_148500,
- /* 2970 /2 /2 /2 /5 /1 => /1 /1 */
--#define MESON_VCLK_HDMI_74250 7
--/* 4320 /4 /1 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_108000 8
-+ MESON_VCLK_HDMI_74250,
- /* 2970 /1 /2 /2 /5 /1 => /1 /1 */
--#define MESON_VCLK_HDMI_148500 9
--/* 3240 /2 /1 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_162000 10
-+ MESON_VCLK_HDMI_148500,
- /* 2970 /1 /1 /1 /5 /2 => /1 /1 */
--#define MESON_VCLK_HDMI_297000 11
-+ MESON_VCLK_HDMI_297000,
- /* 5940 /1 /1 /2 /5 /1 => /1 /1 */
--#define MESON_VCLK_HDMI_594000 12
-+ MESON_VCLK_HDMI_594000
-+};
-
- struct meson_vclk_params {
- unsigned int pll_base_freq;
-@@ -411,46 +402,6 @@ struct meson_vclk_params {
- .vid_pll_div = VID_PLL_DIV_5,
- .vclk_div = 1,
- },
-- [MESON_VCLK_HDMI_25175] = {
-- .pll_base_freq = 4028000,
-- .pll_od1 = 4,
-- .pll_od2 = 4,
-- .pll_od3 = 1,
-- .vid_pll_div = VID_PLL_DIV_5,
-- .vclk_div = 2,
-- },
-- [MESON_VCLK_HDMI_40000] = {
-- .pll_base_freq = 3200000,
-- .pll_od1 = 4,
-- .pll_od2 = 2,
-- .pll_od3 = 1,
-- .vid_pll_div = VID_PLL_DIV_5,
-- .vclk_div = 2,
-- },
-- [MESON_VCLK_HDMI_65000] = {
-- .pll_base_freq = 5200000,
-- .pll_od1 = 4,
-- .pll_od2 = 2,
-- .pll_od3 = 1,
-- .vid_pll_div = VID_PLL_DIV_5,
-- .vclk_div = 2,
-- },
-- [MESON_VCLK_HDMI_108000] = {
-- .pll_base_freq = 4320000,
-- .pll_od1 = 4,
-- .pll_od2 = 1,
-- .pll_od3 = 1,
-- .vid_pll_div = VID_PLL_DIV_5,
-- .vclk_div = 2,
-- },
-- [MESON_VCLK_HDMI_162000] = {
-- .pll_base_freq = 3240000,
-- .pll_od1 = 2,
-- .pll_od2 = 1,
-- .pll_od3 = 1,
-- .vid_pll_div = VID_PLL_DIV_5,
-- .vclk_div = 2,
-- },
- };
-
- static inline unsigned int pll_od_to_reg(unsigned int od)
-@@ -470,358 +421,217 @@ static inline unsigned int pll_od_to_reg(unsigned int od)
- return 0;
- }
-
--void meson_hdmi_pll_set(struct meson_drm *priv,
-- unsigned int base,
-- unsigned int od1,
-- unsigned int od2,
-- unsigned int od3)
-+void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m,
-+ unsigned int frac, unsigned int od1,
-+ unsigned int od2, unsigned int od3)
- {
- unsigned int val;
-
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
-- switch (base) {
-- case 2970000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* Enable and unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- 0x7 << 28, 0x4 << 28);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
--
-- /* div_frac */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4e00);
-- break;
--
-- case 3200000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000242);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
--
-- /* div_frac */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4aab);
-- break;
--
-- case 3240000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000243);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
--
-- /* div_frac */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4800);
-- break;
--
-- case 3865000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000250);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
--
-- /* div_frac */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4855);
-- break;
--
-- case 4028000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000253);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
--
-- /* div_frac */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4eab);
-- break;
--
-- case 4320000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
-- break;
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x58000200 | m);
-+ if (frac)
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
-+ 0x00004000 | frac);
-+ else
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2,
-+ 0x00000000);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
-
-- case 5940000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b);
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 0xFFFF, 0x4c00);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
-- break;
-+ /* Enable and unreset */
-+ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-+ 0x7 << 28, 0x4 << 28);
-
-- case 5200000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800026c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
--
-- /* unreset */
-- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- BIT(28), 0);
--
-- /* Poll for lock bit */
-- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-- val, (val & HDMI_PLL_LOCK), 10, 0);
-- break;
-- };
-+ /* Poll for lock bit */
-+ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
-+ val, (val & HDMI_PLL_LOCK), 10, 0);
- } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
-- switch (base) {
-- case 2970000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 3200000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000285);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb155);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 3240000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000287);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 3865000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a1);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb02b);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 4028000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002a7);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb355);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 4320000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 5940000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- case 5200000:
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002d8);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb2ab);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-- regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-- break;
--
-- };
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x40000200 | m);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000 | frac);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
-+ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
-
- /* Reset PLL */
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- HDMI_PLL_RESET, HDMI_PLL_RESET);
-+ HDMI_PLL_RESET, HDMI_PLL_RESET);
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
-- HDMI_PLL_RESET, 0);
-+ HDMI_PLL_RESET, 0);
-
- /* Poll for lock bit */
- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
- (val & HDMI_PLL_LOCK), 10, 0);
-- };
-+ }
-
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 3 << 16, pll_od_to_reg(od1) << 16);
-+ 3 << 16, pll_od_to_reg(od1) << 16);
- else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-- 3 << 21, pll_od_to_reg(od1) << 21);
-+ 3 << 21, pll_od_to_reg(od1) << 21);
-
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 3 << 22, pll_od_to_reg(od2) << 22);
-+ 3 << 22, pll_od_to_reg(od2) << 22);
- else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-- 3 << 23, pll_od_to_reg(od2) << 23);
-+ 3 << 23, pll_od_to_reg(od2) << 23);
-
- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
-- 3 << 18, pll_od_to_reg(od3) << 18);
-+ 3 << 18, pll_od_to_reg(od3) << 18);
- else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
- regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
-- 3 << 19, pll_od_to_reg(od3) << 19);
-+ 3 << 19, pll_od_to_reg(od3) << 19);
-+
- }
-
--void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-- unsigned int vclk_freq, unsigned int venc_freq,
-- unsigned int dac_freq, bool hdmi_use_enci)
-+#define XTAL_FREQ 24000
-+
-+static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv,
-+ unsigned int pll_freq)
- {
-- unsigned int freq;
-- unsigned int hdmi_tx_div;
-- unsigned int venc_div;
-+ /* The GXBB PLL has a /2 pre-multiplier */
-+ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
-+ pll_freq /= 2;
-
-- if (target == MESON_VCLK_TARGET_CVBS) {
-- meson_venci_cvbs_clock_config(priv);
-- return;
-+ return pll_freq / XTAL_FREQ;
-+}
-+
-+#define HDMI_FRAC_MAX_GXBB 4096
-+#define HDMI_FRAC_MAX_GXL 1024
-+
-+static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv,
-+ unsigned int m,
-+ unsigned int pll_freq)
-+{
-+ unsigned int parent_freq = XTAL_FREQ;
-+ unsigned int frac_max = HDMI_FRAC_MAX_GXL;
-+ unsigned int frac_m;
-+ unsigned int frac;
-+
-+ /* The GXBB PLL has a /2 pre-multiplier and a larger FRAC width */
-+ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
-+ frac_max = HDMI_FRAC_MAX_GXBB;
-+ parent_freq *= 2;
- }
-
-- hdmi_tx_div = vclk_freq / dac_freq;
-+ /* We can have a perfect match !*/
-+ if (pll_freq / m == parent_freq &&
-+ pll_freq % m == 0)
-+ return 0;
-
-- if (hdmi_tx_div == 0) {
-- pr_err("Fatal Error, invalid HDMI-TX freq %d\n",
-- dac_freq);
-- return;
-+ frac = div_u64((u64)pll_freq * (u64)frac_max, parent_freq);
-+ frac_m = m * frac_max;
-+ if (frac_m > frac)
-+ return frac_max;
-+ frac -= frac_m;
-+
-+ return min((u16)frac, (u16)(frac_max - 1));
-+}
-+
-+static bool meson_hdmi_pll_validate_params(struct meson_drm *priv,
-+ unsigned int m,
-+ unsigned int frac)
-+{
-+ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
-+ /* Empiric supported min/max dividers */
-+ if (m < 53 || m > 123)
-+ return false;
-+ if (frac >= HDMI_FRAC_MAX_GXBB)
-+ return false;
-+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
-+ /* Empiric supported min/max dividers */
-+ if (m < 106 || m > 247)
-+ return false;
-+ if (frac >= HDMI_FRAC_MAX_GXL)
-+ return false;
- }
-
-- venc_div = vclk_freq / venc_freq;
-+ return true;
-+}
-
-- if (venc_div == 0) {
-- pr_err("Fatal Error, invalid HDMI venc freq %d\n",
-- venc_freq);
-- return;
-+static bool meson_hdmi_pll_find_params(struct meson_drm *priv,
-+ unsigned int freq,
-+ unsigned int *m,
-+ unsigned int *frac,
-+ unsigned int *od)
-+{
-+ /* Cycle from /16 to /2 */
-+ for (*od = 16 ; *od > 1 ; *od >>= 1) {
-+ *m = meson_hdmi_pll_get_m(priv, freq * *od);
-+ if (!*m)
-+ continue;
-+ *frac = meson_hdmi_pll_get_frac(priv, *m, freq * *od);
-+
-+ DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d\n",
-+ freq, *m, *frac, *od);
-+
-+ if (meson_hdmi_pll_validate_params(priv, *m, *frac))
-+ return true;
- }
-
-- switch (vclk_freq) {
-- case 54000:
-- if (hdmi_use_enci)
-- freq = MESON_VCLK_HDMI_ENCI_54000;
-- else
-- freq = MESON_VCLK_HDMI_DDR_54000;
-- break;
-- case 25175:
-- freq = MESON_VCLK_HDMI_25175;
-- break;
-- case 40000:
-- freq = MESON_VCLK_HDMI_40000;
-- break;
-- case 65000:
-- freq = MESON_VCLK_HDMI_65000;
-- break;
-- case 74250:
-- freq = MESON_VCLK_HDMI_74250;
-- break;
-- case 108000:
-- freq = MESON_VCLK_HDMI_108000;
-- break;
-- case 148500:
-- if (dac_freq != 148500)
-- freq = MESON_VCLK_HDMI_DDR_148500;
-- else
-- freq = MESON_VCLK_HDMI_148500;
-- break;
-- case 162000:
-- freq = MESON_VCLK_HDMI_162000;
-- break;
-- case 297000:
-- freq = MESON_VCLK_HDMI_297000;
-- break;
-- case 594000:
-- freq = MESON_VCLK_HDMI_594000;
-- break;
-- default:
-- pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
-- vclk_freq);
-+ return false;
-+}
-+
-+/* pll_freq is the frequency after the OD dividers */
-+enum drm_mode_status
-+meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq)
-+{
-+ unsigned int od, m, frac;
-+
-+ /* In DMT mode, path after PLL is always /10 */
-+ freq *= 10;
-+
-+ if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
-+ return MODE_OK;
-+
-+ return MODE_CLOCK_RANGE;
-+}
-+EXPORT_SYMBOL_GPL(meson_vclk_dmt_supported_freq);
-+
-+/* pll_freq is the frequency after the OD dividers */
-+static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
-+ unsigned int pll_freq)
-+{
-+ unsigned int od, m, frac, od1, od2, od3;
-+
-+ if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
-+ od3 = 1;
-+ if (od < 4) {
-+ od1 = 2;
-+ od2 = 1;
-+ } else {
-+ od2 = od / 4;
-+ od1 = od / od2;
-+ }
-+
-+ DRM_DEBUG_DRIVER("PLL params for %dkHz: m=%x frac=%x od=%d/%d/%d\n",
-+ pll_freq, m, frac, od1, od2, od3);
-+
-+ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
-+
- return;
- }
-
-+ DRM_ERROR("Fatal, unable to find parameters for PLL freq %d\n",
-+ pll_freq);
-+}
-+
-+static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
-+ unsigned int od1, unsigned int od2, unsigned int od3,
-+ unsigned int vid_pll_div, unsigned int vclk_div,
-+ unsigned int hdmi_tx_div, unsigned int venc_div,
-+ bool hdmi_use_enci)
-+{
- /* Set HDMI-TX sys clock */
- regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
- CTS_HDMI_SYS_SEL_MASK, 0);
-@@ -831,19 +641,49 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
- CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
-
- /* Set HDMI PLL rate */
-- meson_hdmi_pll_set(priv, params[freq].pll_base_freq,
-- params[freq].pll_od1,
-- params[freq].pll_od2,
-- params[freq].pll_od3);
-+ if (!od1 && !od2 && !od3)
-+ meson_hdmi_pll_generic_set(priv, pll_base_freq);
-+ else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
-+ switch (pll_base_freq) {
-+ case 2970000:
-+ meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
-+ od1, od2, od3);
-+ break;
-+ case 4320000:
-+ meson_hdmi_pll_set_params(priv, 0x5a, 0,
-+ od1, od2, od3);
-+ break;
-+ case 5940000:
-+ meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
-+ od1, od2, od3);
-+ break;
-+ }
-+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
-+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
-+ switch (pll_base_freq) {
-+ case 2970000:
-+ meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
-+ od1, od2, od3);
-+ break;
-+ case 4320000:
-+ meson_hdmi_pll_set_params(priv, 0xb4, 0,
-+ od1, od2, od3);
-+ break;
-+ case 5940000:
-+ meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
-+ od1, od2, od3);
-+ break;
-+ }
-+ }
-
- /* Setup vid_pll divider */
-- meson_vid_pll_set(priv, params[freq].vid_pll_div);
-+ meson_vid_pll_set(priv, vid_pll_div);
-
- /* Set VCLK div */
- regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
- VCLK_SEL_MASK, 0);
- regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
-- VCLK_DIV_MASK, params[freq].vclk_div - 1);
-+ VCLK_DIV_MASK, vclk_div - 1);
-
- /* Set HDMI-TX source */
- switch (hdmi_tx_div) {
-@@ -981,4 +821,80 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-
- regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
- }
-+
-+void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-+ unsigned int vclk_freq, unsigned int venc_freq,
-+ unsigned int dac_freq, bool hdmi_use_enci)
-+{
-+ unsigned int freq;
-+ unsigned int hdmi_tx_div;
-+ unsigned int venc_div;
-+
-+ if (target == MESON_VCLK_TARGET_CVBS) {
-+ meson_venci_cvbs_clock_config(priv);
-+ return;
-+ } else if (target == MESON_VCLK_TARGET_DMT) {
-+ /* The DMT clock path is fixed after the PLL:
-+ * - automatic PLL freq + OD management
-+ * - vid_pll_div = VID_PLL_DIV_5
-+ * - vclk_div = 2
-+ * - hdmi_tx_div = 1
-+ * - venc_div = 1
-+ * - encp encoder
-+ */
-+ meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
-+ VID_PLL_DIV_5, 2, 1, 1, false);
-+ return;
-+ }
-+
-+ hdmi_tx_div = vclk_freq / dac_freq;
-+
-+ if (hdmi_tx_div == 0) {
-+ pr_err("Fatal Error, invalid HDMI-TX freq %d\n",
-+ dac_freq);
-+ return;
-+ }
-+
-+ venc_div = vclk_freq / venc_freq;
-+
-+ if (venc_div == 0) {
-+ pr_err("Fatal Error, invalid HDMI venc freq %d\n",
-+ venc_freq);
-+ return;
-+ }
-+
-+ switch (vclk_freq) {
-+ case 54000:
-+ if (hdmi_use_enci)
-+ freq = MESON_VCLK_HDMI_ENCI_54000;
-+ else
-+ freq = MESON_VCLK_HDMI_DDR_54000;
-+ break;
-+ case 74250:
-+ freq = MESON_VCLK_HDMI_74250;
-+ break;
-+ case 148500:
-+ if (dac_freq != 148500)
-+ freq = MESON_VCLK_HDMI_DDR_148500;
-+ else
-+ freq = MESON_VCLK_HDMI_148500;
-+ break;
-+ case 297000:
-+ freq = MESON_VCLK_HDMI_297000;
-+ break;
-+ case 594000:
-+ freq = MESON_VCLK_HDMI_594000;
-+ break;
-+ default:
-+ pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
-+ vclk_freq);
-+ return;
-+ }
-+
-+ meson_vclk_set(priv, params[freq].pll_base_freq,
-+ params[freq].pll_od1, params[freq].pll_od2,
-+ params[freq].pll_od3, params[freq].vid_pll_div,
-+ params[freq].vclk_div, hdmi_tx_div, venc_div,
-+ hdmi_use_enci);
-+}
- EXPORT_SYMBOL_GPL(meson_vclk_setup);
-diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
-index 0401b52..869fa3a 100644
---- a/drivers/gpu/drm/meson/meson_vclk.h
-+++ b/drivers/gpu/drm/meson/meson_vclk.h
-@@ -24,11 +24,15 @@
- enum {
- MESON_VCLK_TARGET_CVBS = 0,
- MESON_VCLK_TARGET_HDMI = 1,
-+ MESON_VCLK_TARGET_DMT = 2,
- };
-
- /* 27MHz is the CVBS Pixel Clock */
- #define MESON_VCLK_CVBS 27000
-
-+enum drm_mode_status
-+meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
-+
- void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
- unsigned int vclk_freq, unsigned int venc_freq,
- unsigned int dac_freq, bool hdmi_use_enci);
-diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
-index 6e27013..d9f33b0 100644
---- a/drivers/gpu/drm/meson/meson_venc.c
-+++ b/drivers/gpu/drm/meson/meson_venc.c
-@@ -697,314 +697,6 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
- },
- };
-
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_640x480_60 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 0x31f,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 0x90,
-- .havon_end = 0x30f,
-- .vavon_bline = 0x23,
-- .vavon_eline = 0x202,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 0x60,
-- .vso_begin = 0x1e,
-- .vso_end = 0x32,
-- .vso_bline = 0,
-- .vso_eline = 2,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 0x20c,
-- },
--};
--
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_800x600_60 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 0x41f,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 0xD8,
-- .havon_end = 0x3f7,
-- .vavon_bline = 0x1b,
-- .vavon_eline = 0x272,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 0x80,
-- .vso_begin = 0x1e,
-- .vso_end = 0x32,
-- .vso_bline = 0,
-- .vso_eline = 4,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 0x273,
-- },
--};
--
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_1024x768_60 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 1343,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 296,
-- .havon_end = 1319,
-- .vavon_bline = 35,
-- .vavon_eline = 802,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 136,
-- .vso_begin = 30,
-- .vso_end = 50,
-- .vso_bline = 0,
-- .vso_eline = 6,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 805,
-- },
--};
--
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_1152x864_75 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 0x63f,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 0x180,
-- .havon_end = 0x5ff,
-- .vavon_bline = 0x23,
-- .vavon_eline = 0x382,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 0x80,
-- .vso_begin = 0x1e,
-- .vso_end = 0x32,
-- .vso_bline = 0,
-- .vso_eline = 3,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 0x383,
-- },
--};
--
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_1280x1024_60 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 0x697,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 0x168,
-- .havon_end = 0x667,
-- .vavon_bline = 0x29,
-- .vavon_eline = 0x428,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 0x70,
-- .vso_begin = 0x1e,
-- .vso_end = 0x32,
-- .vso_bline = 0,
-- .vso_eline = 3,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 0x429,
-- },
--};
--
--union meson_hdmi_venc_mode meson_hdmi_encp_mode_1600x1200_60 = {
-- .encp = {
-- .dvi_settings = 0x21,
-- .video_mode = 0x4040,
-- .video_mode_adv = 0x18,
-- /* video_prog_mode */
-- /* video_sync_mode */
-- /* video_yc_dly */
-- /* video_rgb_ctrl */
-- /* video_filt_ctrl */
-- /* video_ofld_voav_ofst */
-- /* yfp1_htime */
-- /* yfp2_htime */
-- .max_pxcnt = 0x86f,
-- /* hspuls_begin */
-- /* hspuls_end */
-- /* hspuls_switch */
-- /* vspuls_begin */
-- /* vspuls_end */
-- /* vspuls_bline */
-- /* vspuls_eline */
-- .havon_begin = 0x1f0,
-- .havon_end = 0x82f,
-- .vavon_bline = 0x31,
-- .vavon_eline = 0x4e0,
-- /* eqpuls_begin */
-- /* eqpuls_end */
-- /* eqpuls_bline */
-- /* eqpuls_eline */
-- .hso_begin = 0,
-- .hso_end = 0xc0,
-- .vso_begin = 0x1e,
-- .vso_end = 0x32,
-- .vso_bline = 0,
-- .vso_eline = 3,
-- .vso_eline_present = true,
-- /* sy_val */
-- /* sy2_val */
-- .max_lncnt = 0x4e1,
-- },
--};
--
--struct meson_hdmi_venc_dmt_mode {
-- struct drm_display_mode drm_mode;
-- union meson_hdmi_venc_mode *mode;
--} meson_hdmi_venc_dmt_modes[] = {
-- /* 640x480@60Hz */
-- {
-- { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
-- 752, 800, 0, 480, 490, 492, 525, 0,
-- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-- &meson_hdmi_encp_mode_640x480_60,
-- },
-- /* 800x600@60Hz */
-- {
-- { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
-- 968, 1056, 0, 600, 601, 605, 628, 0,
-- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-- &meson_hdmi_encp_mode_800x600_60,
-- },
-- /* 1024x768@60Hz */
-- {
-- { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024,
-- 1048, 1184, 1344, 0, 768, 771, 777, 806, 0,
-- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-- &meson_hdmi_encp_mode_1024x768_60,
-- },
-- /* 1152x864@75Hz */
-- {
-- { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152,
-- 1216, 1344, 1600, 0, 864, 865, 868, 900, 0,
-- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-- &meson_hdmi_encp_mode_1152x864_75,
-- },
-- /* 1280x1024@60Hz */
-- {
-- { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280,
-- 1328, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
-- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-- &meson_hdmi_encp_mode_1280x1024_60,
-- },
-- /* 1600x1200@60Hz */
-- {
-- { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600,
-- 1664, 1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
-- DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
-- &meson_hdmi_encp_mode_1600x1200_60,
-- },
-- /* 1920x1080@60Hz */
-- {
-- { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920,
-- 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
-- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
-- &meson_hdmi_encp_mode_1080p60
-- },
-- { }, /* sentinel */
--};
--
- struct meson_hdmi_venc_vic_mode {
- unsigned int vic;
- union meson_hdmi_venc_mode *mode;
-@@ -1044,17 +736,20 @@ static unsigned long modulo(unsigned long a, unsigned long b)
- return a;
- }
-
--bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
-+enum drm_mode_status
-+meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode)
- {
-- struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
-+ if (mode->flags & ~(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC |
-+ DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))
-+ return MODE_BAD;
-
-- while (vmode->mode) {
-- if (drm_mode_equal(&vmode->drm_mode, mode))
-- return true;
-- vmode++;
-- }
-+ if (mode->hdisplay < 640 || mode->hdisplay > 1920)
-+ return MODE_BAD_HVALUE;
-
-- return false;
-+ if (mode->vdisplay < 480 || mode->vdisplay > 1200)
-+ return MODE_BAD_VVALUE;
-+
-+ return MODE_OK;
- }
- EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_mode);
-
-@@ -1072,18 +767,29 @@ bool meson_venc_hdmi_supported_vic(int vic)
- }
- EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
-
--static union meson_hdmi_venc_mode
--*meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode)
-+void meson_venc_hdmi_get_dmt_vmode(const struct drm_display_mode *mode,
-+ union meson_hdmi_venc_mode *dmt_mode)
- {
-- struct meson_hdmi_venc_dmt_mode *vmode = meson_hdmi_venc_dmt_modes;
--
-- while (vmode->mode) {
-- if (drm_mode_equal(&vmode->drm_mode, mode))
-- return vmode->mode;
-- vmode++;
-- }
--
-- return NULL;
-+ memset(dmt_mode, 0, sizeof(*dmt_mode));
-+
-+ dmt_mode->encp.dvi_settings = 0x21;
-+ dmt_mode->encp.video_mode = 0x4040;
-+ dmt_mode->encp.video_mode_adv = 0x18;
-+ dmt_mode->encp.max_pxcnt = mode->htotal - 1;
-+ dmt_mode->encp.havon_begin = mode->htotal - mode->hsync_start;
-+ dmt_mode->encp.havon_end = dmt_mode->encp.havon_begin +
-+ mode->hdisplay - 1;
-+ dmt_mode->encp.vavon_bline = mode->vtotal - mode->vsync_start;
-+ dmt_mode->encp.vavon_eline = dmt_mode->encp.vavon_bline +
-+ mode->vdisplay - 1;
-+ dmt_mode->encp.hso_begin = 0;
-+ dmt_mode->encp.hso_end = mode->hsync_end - mode->hsync_start;
-+ dmt_mode->encp.vso_begin = 30;
-+ dmt_mode->encp.vso_end = 50;
-+ dmt_mode->encp.vso_bline = 0;
-+ dmt_mode->encp.vso_eline = mode->vsync_end - mode->vsync_start;
-+ dmt_mode->encp.vso_eline_present = true;
-+ dmt_mode->encp.max_lncnt = mode->vtotal - 1;
- }
-
- static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
-@@ -1120,6 +826,7 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
- struct drm_display_mode *mode)
- {
- union meson_hdmi_venc_mode *vmode = NULL;
-+ union meson_hdmi_venc_mode vmode_dmt;
- bool use_enci = false;
- bool venc_repeat = false;
- bool hdmi_repeat = false;
-@@ -1147,14 +854,18 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
- unsigned int sof_lines;
- unsigned int vsync_lines;
-
-- if (meson_venc_hdmi_supported_vic(vic))
-+ if (meson_venc_hdmi_supported_vic(vic)) {
- vmode = meson_venc_hdmi_get_vic_vmode(vic);
-- else
-- vmode = meson_venc_hdmi_get_dmt_vmode(mode);
-- if (!vmode) {
-- dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
-- DRM_MODE_FMT "\n", __func__, DRM_MODE_ARG(mode));
-- return;
-+ if (!vmode) {
-+ dev_err(priv->dev, "%s: Fatal Error, unsupported mode "
-+ DRM_MODE_FMT "\n", __func__,
-+ DRM_MODE_ARG(mode));
-+ return;
-+ }
-+ }
-+ else {
-+ meson_venc_hdmi_get_dmt_vmode(mode, &vmode_dmt);
-+ vmode = &vmode_dmt;
- }
-
- /* Use VENCI for 480i and 576i and double HDMI pixels */
-diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
-index 7c18a36..97eaebb 100644
---- a/drivers/gpu/drm/meson/meson_venc.h
-+++ b/drivers/gpu/drm/meson/meson_venc.h
-@@ -58,7 +58,8 @@ struct meson_cvbs_enci_mode {
- };
-
- /* HDMI Clock parameters */
--bool meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
-+enum drm_mode_status
-+meson_venc_hdmi_supported_mode(const struct drm_display_mode *mode);
- bool meson_venc_hdmi_supported_vic(int vic);
- bool meson_venc_hdmi_venc_repeat(int vic);
-
diff --git a/testing/linux-amlogic/0007-ASoC-meson-add-register-definitions.patch b/testing/linux-amlogic/0003-ASoC-meson-add-register-definitions.patch
index 0a13a427cc..cb4027a2c4 100644
--- a/testing/linux-amlogic/0007-ASoC-meson-add-register-definitions.patch
+++ b/testing/linux-amlogic/0003-ASoC-meson-add-register-definitions.patch
@@ -1,4 +1,4 @@
-From f6c0ce626b08f5ba85bd9bfe000044c4f9e7da24 Mon Sep 17 00:00:00 2001
+From dc1d93ea8dc61686364e2659c1ac1392681b64b4 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 12:00:10 +0200
Subject: [PATCH] ASoC: meson: add register definitions
@@ -6,6 +6,7 @@ Subject: [PATCH] ASoC: meson: add register definitions
Add the register definition for the AIU and AUDIN blocks
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
sound/soc/meson/aiu-regs.h | 182 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/meson/audin-regs.h | 148 +++++++++++++++++++++++++++++++++++
diff --git a/testing/linux-amlogic/0008-ASoC-meson-add-aiu-i2s-dma-support.patch b/testing/linux-amlogic/0004-ASoC-meson-add-aiu-i2s-dma-support.patch
index 1de0e444ad..900659845e 100644
--- a/testing/linux-amlogic/0008-ASoC-meson-add-aiu-i2s-dma-support.patch
+++ b/testing/linux-amlogic/0004-ASoC-meson-add-aiu-i2s-dma-support.patch
@@ -1,4 +1,4 @@
-From bb5102086db1579c1289440fa8aa184a70cb7c64 Mon Sep 17 00:00:00 2001
+From ef53207463b1ffa58dbc8b994cb470f35bf12420 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 12:14:40 +0200
Subject: [PATCH] ASoC: meson: add aiu i2s dma support
@@ -6,18 +6,19 @@ Subject: [PATCH] ASoC: meson: add aiu i2s dma support
Add support for the i2s output dma which is part of the AIU block
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
sound/soc/meson/Kconfig | 7 +
- sound/soc/meson/Makefile | 2 +
+ sound/soc/meson/Makefile | 4 +-
sound/soc/meson/aiu-i2s-dma.c | 370 ++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 379 insertions(+)
+ 3 files changed, 380 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/meson/aiu-i2s-dma.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
-index ca0e3e9..88fbfc2 100644
+index ed432d4..6e030b5 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
-@@ -7,3 +7,10 @@ menuconfig SND_SOC_MESON
+@@ -73,3 +73,10 @@ menuconfig SND_SOC_MESON
Say Y or M if you want to add support for codecs attached to
the Amlogic Meson SoCs Audio interfaces. You will also need to
select the audio interfaces to support below.
@@ -29,15 +30,20 @@ index ca0e3e9..88fbfc2 100644
+ Say Y or M if you want to add support for i2s dma driver for Amlogic
+ Meson SoCs.
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
-index 22028ab..273f275 100644
+index 768d7c4..5796007 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
-@@ -1,3 +1,5 @@
+@@ -21,5 +21,7 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o
+ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
+
snd-soc-meson-audio-core-objs := audio-core.o
+snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
- obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
-+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+-obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+\ No newline at end of file
++obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
++obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+\ No newline at end of file
diff --git a/sound/soc/meson/aiu-i2s-dma.c b/sound/soc/meson/aiu-i2s-dma.c
new file mode 100644
index 0000000..2684bd0
diff --git a/testing/linux-amlogic/0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch b/testing/linux-amlogic/0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch
deleted file mode 100644
index e2b3860f5a..0000000000
--- a/testing/linux-amlogic/0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 0cecf963b9d815699fe50b7a7ee4a93ece3ed834 Mon Sep 17 00:00:00 2001
-From: Jerome Brunet <jbrunet@baylibre.com>
-Date: Tue, 19 Jun 2018 18:14:49 +0200
-Subject: [PATCH] clk: meson: switch gxbb cts-amclk div to the generic divider
-
-clk-audio-divider was a (poor) attempt to use CCF rate propagation
-while making sure the PLL rate would be high enough to work with
-audio use cases. The result is far from optimal. We can do better
-by carefully choosing the PLL rates for the audio use cases.
-Doing so, we don't need to use clk-audio-divider anymore. The
-generic will do
-
-Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
----
- drivers/clk/meson/gxbb.c | 12 +++++-------
- 1 file changed, 5 insertions(+), 7 deletions(-)
-
-diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
-index 177fffb..69a58cb 100644
---- a/drivers/clk/meson/gxbb.c
-+++ b/drivers/clk/meson/gxbb.c
-@@ -982,17 +982,15 @@ static struct clk_regmap gxbb_cts_amclk_sel = {
- };
-
- static struct clk_regmap gxbb_cts_amclk_div = {
-- .data = &(struct meson_clk_audio_div_data){
-- .div = {
-- .reg_off = HHI_AUD_CLK_CNTL,
-- .shift = 0,
-- .width = 8,
-- },
-+ .data = &(struct clk_regmap_div_data) {
-+ .offset = HHI_AUD_CLK_CNTL,
-+ .shift = 0,
-+ .width = 8,
- .flags = CLK_DIVIDER_ROUND_CLOSEST,
- },
- .hw.init = &(struct clk_init_data){
- .name = "cts_amclk_div",
-- .ops = &meson_clk_audio_divider_ops,
-+ .ops = &clk_regmap_divider_ops,
- .parent_names = (const char *[]){ "cts_amclk_sel" },
- .num_parents = 1,
- .flags = CLK_SET_RATE_PARENT,
diff --git a/testing/linux-amlogic/0009-ASoC-meson-add-initial-i2s-dai-support.patch b/testing/linux-amlogic/0005-ASoC-meson-add-initial-i2s-dai-support.patch
index f3bac343f7..e1be6fab36 100644
--- a/testing/linux-amlogic/0009-ASoC-meson-add-initial-i2s-dai-support.patch
+++ b/testing/linux-amlogic/0005-ASoC-meson-add-initial-i2s-dai-support.patch
@@ -1,4 +1,4 @@
-From 6a5036e9f7dbd99023c6f9482fed3a747868b1c2 Mon Sep 17 00:00:00 2001
+From 9031b415030a316ec4ca513185e2d2c0fbb894c4 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 12:17:27 +0200
Subject: [PATCH] ASoC: meson: add initial i2s dai support
@@ -8,18 +8,19 @@ With this initial implementation, only playback is supported.
Capture will be part of furture work.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
sound/soc/meson/Kconfig | 2 +-
- sound/soc/meson/Makefile | 2 +
+ sound/soc/meson/Makefile | 4 +-
sound/soc/meson/i2s-dai.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 468 insertions(+), 1 deletion(-)
+ 3 files changed, 469 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/meson/i2s-dai.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
-index 88fbfc2..478f29a 100644
+index 6e030b5..5904e9e 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
-@@ -12,5 +12,5 @@ config SND_SOC_MESON_I2S
+@@ -78,5 +78,5 @@ config SND_SOC_MESON_I2S
tristate "Meson i2s interface"
depends on SND_SOC_MESON
help
@@ -27,17 +28,21 @@ index 88fbfc2..478f29a 100644
+ Say Y or M if you want to add support for i2s driver for Amlogic
Meson SoCs.
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
-index 273f275..ea06dde 100644
+index 5796007..b8641f9 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
-@@ -1,5 +1,7 @@
+@@ -22,6 +22,8 @@ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
+
snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
+snd-soc-meson-i2s-dai-objs := i2s-dai.o
- obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
- obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
-+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
+ obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+-obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+\ No newline at end of file
++obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
++obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
+\ No newline at end of file
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
new file mode 100644
index 0000000..1008af8
diff --git a/testing/linux-amlogic/0005-clk-meson-remove-unused-clk-audio-divider-driver.patch b/testing/linux-amlogic/0005-clk-meson-remove-unused-clk-audio-divider-driver.patch
deleted file mode 100644
index cd6da8cf57..0000000000
--- a/testing/linux-amlogic/0005-clk-meson-remove-unused-clk-audio-divider-driver.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From e87dd7b11611e4ac5279ba4ad4f1fea4d0900273 Mon Sep 17 00:00:00 2001
-From: Jerome Brunet <jbrunet@baylibre.com>
-Date: Tue, 19 Jun 2018 18:23:28 +0200
-Subject: [PATCH] clk: meson: remove unused clk-audio-divider driver
-
-Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
----
- drivers/clk/meson/Makefile | 2 +-
- drivers/clk/meson/clkc.h | 7 -------
- 2 files changed, 1 insertion(+), 8 deletions(-)
-
-diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
-index d0d13ae..e40fea9 100644
---- a/drivers/clk/meson/Makefile
-+++ b/drivers/clk/meson/Makefile
-@@ -2,7 +2,7 @@
- # Makefile for Meson specific clk
- #
-
--obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-audio-divider.o
-+obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o
- obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
- obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
- obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
-diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
-index 2fb0843..48db024 100644
---- a/drivers/clk/meson/clkc.h
-+++ b/drivers/clk/meson/clkc.h
-@@ -91,11 +91,6 @@ struct meson_clk_mpll_data {
-
- #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0)
-
--struct meson_clk_audio_div_data {
-- struct parm div;
-- u8 flags;
--};
--
- #define MESON_GATE(_name, _reg, _bit) \
- struct clk_regmap _name = { \
- .data = &(struct clk_regmap_gate_data){ \
-@@ -117,7 +112,5 @@ extern const struct clk_ops meson_clk_pll_ops;
- extern const struct clk_ops meson_clk_cpu_ops;
- extern const struct clk_ops meson_clk_mpll_ro_ops;
- extern const struct clk_ops meson_clk_mpll_ops;
--extern const struct clk_ops meson_clk_audio_divider_ro_ops;
--extern const struct clk_ops meson_clk_audio_divider_ops;
-
- #endif /* __CLKC_H */
diff --git a/testing/linux-amlogic/0010-ASoC-meson-add-aiu-spdif-dma-support.patch b/testing/linux-amlogic/0006-ASoC-meson-add-aiu-spdif-dma-support.patch
index 380f5d5b2c..31cef2e53d 100644
--- a/testing/linux-amlogic/0010-ASoC-meson-add-aiu-spdif-dma-support.patch
+++ b/testing/linux-amlogic/0006-ASoC-meson-add-aiu-spdif-dma-support.patch
@@ -1,4 +1,4 @@
-From 8dd5edaf984e4c8d6f7ca1e7709b3109cf7dd780 Mon Sep 17 00:00:00 2001
+From 32a55958cc2d89e2feee831ca4e6ceae8458e950 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 13:43:52 +0200
Subject: [PATCH] ASoC: meson: add aiu spdif dma support
@@ -6,18 +6,19 @@ Subject: [PATCH] ASoC: meson: add aiu spdif dma support
Add support for the spdif output dma which is part of the AIU block
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
sound/soc/meson/Kconfig | 7 +
- sound/soc/meson/Makefile | 2 +
+ sound/soc/meson/Makefile | 4 +-
sound/soc/meson/aiu-spdif-dma.c | 388 ++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 397 insertions(+)
+ 3 files changed, 398 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/meson/aiu-spdif-dma.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
-index 478f29a..3fb93b9 100644
+index 5904e9e..712303f 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
-@@ -14,3 +14,10 @@ config SND_SOC_MESON_I2S
+@@ -80,3 +80,10 @@ config SND_SOC_MESON_I2S
help
Say Y or M if you want to add support for i2s driver for Amlogic
Meson SoCs.
@@ -29,19 +30,23 @@ index 478f29a..3fb93b9 100644
+ Say Y or M if you want to add support for spdif dma driver for Amlogic
+ Meson SoCs.
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
-index ea06dde..cef9a9d 100644
+index b8641f9..dc5164a7 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
-@@ -1,7 +1,9 @@
+@@ -22,8 +22,10 @@ obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o
+
snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
+snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
snd-soc-meson-i2s-dai-objs := i2s-dai.o
- obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
- obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
- obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
-+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
+ obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+ obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+-obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
+\ No newline at end of file
++obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
++obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
+\ No newline at end of file
diff --git a/sound/soc/meson/aiu-spdif-dma.c b/sound/soc/meson/aiu-spdif-dma.c
new file mode 100644
index 0000000..81c3b85
diff --git a/testing/linux-amlogic/0011-ASoC-meson-add-initial-spdif-dai-support.patch b/testing/linux-amlogic/0007-ASoC-meson-add-initial-spdif-dai-support.patch
index 3d36f4b064..c60779b465 100644
--- a/testing/linux-amlogic/0011-ASoC-meson-add-initial-spdif-dai-support.patch
+++ b/testing/linux-amlogic/0007-ASoC-meson-add-initial-spdif-dai-support.patch
@@ -1,4 +1,4 @@
-From e635299f76dc27b97a768f2a044d04c1917b9ad1 Mon Sep 17 00:00:00 2001
+From 67e2a1601f80648f5c318728218b788c51081fa3 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 13:46:03 +0200
Subject: [PATCH] ASoC: meson: add initial spdif dai support
@@ -9,18 +9,19 @@ from the spdif dma is supported. Future work will add compressed
support, pcm playback from i2s dma and capture.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
sound/soc/meson/Kconfig | 3 +-
- sound/soc/meson/Makefile | 2 +
+ sound/soc/meson/Makefile | 4 +-
sound/soc/meson/spdif-dai.c | 374 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 378 insertions(+), 1 deletion(-)
+ 3 files changed, 379 insertions(+), 2 deletions(-)
create mode 100644 sound/soc/meson/spdif-dai.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
-index 3fb93b9..301d3a3 100644
+index 712303f..bc3d6f2 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
-@@ -18,6 +18,7 @@ config SND_SOC_MESON_I2S
+@@ -84,6 +84,7 @@ config SND_SOC_MESON_I2S
config SND_SOC_MESON_SPDIF
tristate "Meson spdif interface"
depends on SND_SOC_MESON
@@ -30,20 +31,23 @@ index 3fb93b9..301d3a3 100644
+ Say Y or M if you want to add support for spdif driver for Amlogic
Meson SoCs.
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
-index cef9a9d..bc4391c 100644
+index dc5164a7..44f79d8 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
-@@ -2,8 +2,10 @@ snd-soc-meson-audio-core-objs := audio-core.o
+@@ -24,8 +24,10 @@ snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
snd-soc-meson-i2s-dai-objs := i2s-dai.o
+snd-soc-meson-spdif-dai-objs := spdif-dai.o
- obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
- obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
- obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
- obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
-+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-spdif-dai.o
+ obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+ obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+ obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
+-obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
+\ No newline at end of file
++obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
++obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-spdif-dai.o
+\ No newline at end of file
diff --git a/sound/soc/meson/spdif-dai.c b/sound/soc/meson/spdif-dai.c
new file mode 100644
index 0000000..e763000
diff --git a/testing/linux-amlogic/0012-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch b/testing/linux-amlogic/0008-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
index ff2035ecc8..2f8854bf36 100644
--- a/testing/linux-amlogic/0012-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
+++ b/testing/linux-amlogic/0008-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
@@ -1,4 +1,4 @@
-From 5ddca63ac5c5d81c6d6a6745670a3f136970eaef Mon Sep 17 00:00:00 2001
+From 93621178cb2f756c8ca8901801c2ce914ac7dc6b Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 31 Mar 2017 15:55:03 +0200
Subject: [PATCH] ARM64: defconfig: enable audio support for meson SoCs as
@@ -8,22 +8,22 @@ Add audio support for meson SoCs. This includes the audio core
driver and the i2s and spdif output interfaces
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
- arch/arm64/configs/defconfig | 4 ++++
- 1 file changed, 4 insertions(+)
+ arch/arm64/configs/defconfig | 3 +++
+ 1 file changed, 3 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
-index 2584605..ae1f774 100644
+index ab1cb51..a4bf54b 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
-@@ -451,6 +451,10 @@ CONFIG_SOUND=y
+@@ -464,6 +464,9 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_SOC_MESON=m
+CONFIG_SND_SOC_MESON_I2S=m
+CONFIG_SND_SOC_MESON_SPDIF=m
-+CONFIG_SND_SOC_RCAR=y
- CONFIG_SND_SOC_SAMSUNG=y
- CONFIG_SND_SOC_RCAR=m
- CONFIG_SND_SOC_AK4613=m
+ CONFIG_SND_SOC_ROCKCHIP=m
+ CONFIG_SND_SOC_ROCKCHIP_I2S=m
+ CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
diff --git a/testing/linux-amlogic/0008-drm-meson-Add-HDMI-1.4-4k-modes.patch b/testing/linux-amlogic/0008-drm-meson-Add-HDMI-1.4-4k-modes.patch
new file mode 100644
index 0000000000..194ba6e2de
--- /dev/null
+++ b/testing/linux-amlogic/0008-drm-meson-Add-HDMI-1.4-4k-modes.patch
@@ -0,0 +1,165 @@
+From 24b38ca3bd2579d4bac18f57526c93bc63354959 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Fri, 20 Jul 2018 15:29:18 +0200
+Subject: [PATCH] drm/meson: Add HDMI 1.4 4k modes
+
+Add the timings for the HDMI 1.4 4K modes support :
+- 3840x2160@30
+- 3840x2160@25
+- 3840x2160@24
+
+Since the 297000Hz pixel clock is already managed and the modes are
+compatible with the HDMI 1.4 current HDMI PHY+Controller support, only
+the missing timings values needs to be added.
+
+---
+ drivers/gpu/drm/meson/meson_venc.c | 129 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 129 insertions(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
+index 14aac66..d68ccbf 100644
+--- a/drivers/gpu/drm/meson/meson_venc.c
++++ b/drivers/gpu/drm/meson/meson_venc.c
+@@ -698,6 +698,132 @@ union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
+ },
+ };
+
++union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p24 = {
++ .encp = {
++ .dvi_settings = 0x1,
++ .video_mode = 0x4040,
++ .video_mode_adv = 0x8,
++ /* video_sync_mode */
++ /* video_yc_dly */
++ /* video_rgb_ctrl */
++ .video_filt_ctrl = 0x1000,
++ .video_filt_ctrl_present = true,
++ /* video_ofld_voav_ofst */
++ .yfp1_htime = 140,
++ .yfp2_htime = 140+3840,
++ .max_pxcnt = 3840+1660-1,
++ .hspuls_begin = 2156+1920,
++ .hspuls_end = 44,
++ .hspuls_switch = 44,
++ .vspuls_begin = 140,
++ .vspuls_end = 2059+1920,
++ .vspuls_bline = 0,
++ .vspuls_eline = 4,
++ .havon_begin = 148,
++ .havon_end = 3987,
++ .vavon_bline = 89,
++ .vavon_eline = 2248,
++ /* eqpuls_begin */
++ /* eqpuls_end */
++ /* eqpuls_bline */
++ /* eqpuls_eline */
++ .hso_begin = 44,
++ .hso_end = 2156+1920,
++ .vso_begin = 2100+1920,
++ .vso_end = 2164+1920,
++ .vso_bline = 51,
++ .vso_eline = 53,
++ .vso_eline_present = true,
++ /* sy_val */
++ /* sy2_val */
++ .max_lncnt = 2249,
++ },
++};
++
++union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p25 = {
++ .encp = {
++ .dvi_settings = 0x1,
++ .video_mode = 0x4040,
++ .video_mode_adv = 0x8,
++ /* video_sync_mode */
++ /* video_yc_dly */
++ /* video_rgb_ctrl */
++ .video_filt_ctrl = 0x1000,
++ .video_filt_ctrl_present = true,
++ /* video_ofld_voav_ofst */
++ .yfp1_htime = 140,
++ .yfp2_htime = 140+3840,
++ .max_pxcnt = 3840+1440-1,
++ .hspuls_begin = 2156+1920,
++ .hspuls_end = 44,
++ .hspuls_switch = 44,
++ .vspuls_begin = 140,
++ .vspuls_end = 2059+1920,
++ .vspuls_bline = 0,
++ .vspuls_eline = 4,
++ .havon_begin = 148,
++ .havon_end = 3987,
++ .vavon_bline = 89,
++ .vavon_eline = 2248,
++ /* eqpuls_begin */
++ /* eqpuls_end */
++ /* eqpuls_bline */
++ /* eqpuls_eline */
++ .hso_begin = 44,
++ .hso_end = 2156+1920,
++ .vso_begin = 2100+1920,
++ .vso_end = 2164+1920,
++ .vso_bline = 51,
++ .vso_eline = 53,
++ .vso_eline_present = true,
++ /* sy_val */
++ /* sy2_val */
++ .max_lncnt = 2249,
++ },
++};
++
++union meson_hdmi_venc_mode meson_hdmi_encp_mode_2160p30 = {
++ .encp = {
++ .dvi_settings = 0x1,
++ .video_mode = 0x4040,
++ .video_mode_adv = 0x8,
++ /* video_sync_mode */
++ /* video_yc_dly */
++ /* video_rgb_ctrl */
++ .video_filt_ctrl = 0x1000,
++ .video_filt_ctrl_present = true,
++ /* video_ofld_voav_ofst */
++ .yfp1_htime = 140,
++ .yfp2_htime = 140+3840,
++ .max_pxcnt = 3840+560-1,
++ .hspuls_begin = 2156+1920,
++ .hspuls_end = 44,
++ .hspuls_switch = 44,
++ .vspuls_begin = 140,
++ .vspuls_end = 2059+1920,
++ .vspuls_bline = 0,
++ .vspuls_eline = 4,
++ .havon_begin = 148,
++ .havon_end = 3987,
++ .vavon_bline = 89,
++ .vavon_eline = 2248,
++ /* eqpuls_begin */
++ /* eqpuls_end */
++ /* eqpuls_bline */
++ /* eqpuls_eline */
++ .hso_begin = 44,
++ .hso_end = 2156+1920,
++ .vso_begin = 2100+1920,
++ .vso_end = 2164+1920,
++ .vso_bline = 51,
++ .vso_eline = 53,
++ .vso_eline_present = true,
++ /* sy_val */
++ /* sy2_val */
++ .max_lncnt = 2249,
++ },
++};
++
+ struct meson_hdmi_venc_vic_mode {
+ unsigned int vic;
+ union meson_hdmi_venc_mode *mode;
+@@ -718,6 +844,9 @@ struct meson_hdmi_venc_vic_mode {
+ { 34, &meson_hdmi_encp_mode_1080p30 },
+ { 31, &meson_hdmi_encp_mode_1080p50 },
+ { 16, &meson_hdmi_encp_mode_1080p60 },
++ { 93, &meson_hdmi_encp_mode_2160p24 },
++ { 94, &meson_hdmi_encp_mode_2160p25 },
++ { 95, &meson_hdmi_encp_mode_2160p30 },
+ { 0, NULL}, /* sentinel */
+ };
+
diff --git a/testing/linux-amlogic/0013-ARM64-dts-meson-gx-add-audio-controller-nodes.patch b/testing/linux-amlogic/0009-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
index f58d3ef3ca..f16edd0d1b 100644
--- a/testing/linux-amlogic/0013-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
+++ b/testing/linux-amlogic/0009-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
@@ -1,4 +1,4 @@
-From f4d7ad156ad2253d5ec3e79ea36309e27b8fabc7 Mon Sep 17 00:00:00 2001
+From 7ecd280bd317cff3c608b32b2a185929b2ec17ca Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:19:04 +0200
Subject: [PATCH] ARM64: dts: meson-gx: add audio controller nodes
@@ -11,6 +11,7 @@ Audio on this SoC family is still a work in progress. More nodes are likely
to be added later on (pcm DAIs, input DMAs, etc ...)
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 35 ++++++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 39 +++++++++++++++++++++++++++++
diff --git a/testing/linux-amlogic/0009-drm-meson-Use-drm_fbdev_generic_setup.patch b/testing/linux-amlogic/0009-drm-meson-Use-drm_fbdev_generic_setup.patch
new file mode 100644
index 0000000000..fc3511a111
--- /dev/null
+++ b/testing/linux-amlogic/0009-drm-meson-Use-drm_fbdev_generic_setup.patch
@@ -0,0 +1,100 @@
+From a753ec94679503680fcf86ffad3f3d3eb817c6b9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
+Date: Sat, 8 Sep 2018 15:46:33 +0200
+Subject: [PATCH] drm/meson: Use drm_fbdev_generic_setup()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The CMA helper is already using the drm_fb_helper_generic_probe part of
+the generic fbdev emulation. This patch makes full use of the generic
+fbdev emulation by using its drm_client callbacks. This means that
+drm_mode_config_funcs->output_poll_changed and drm_driver->lastclose are
+now handled by the emulation code. Additionally fbdev unregister happens
+automatically on drm_dev_unregister().
+
+The drm_fbdev_generic_setup() call is put after drm_dev_register() in the
+driver. This is done to highlight the fact that fbdev emulation is an
+internal client that makes use of the driver, it is not part of the
+driver as such. If fbdev setup fails, an error is printed, but the driver
+succeeds probing.
+
+Cc: Neil Armstrong <narmstrong@baylibre.com>
+Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
+
+---
+ drivers/gpu/drm/meson/meson_drv.c | 19 ++-----------------
+ drivers/gpu/drm/meson/meson_drv.h | 1 -
+ 2 files changed, 2 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
+index b55e03d..3997e3e 100644
+--- a/drivers/gpu/drm/meson/meson_drv.c
++++ b/drivers/gpu/drm/meson/meson_drv.c
+@@ -69,15 +69,7 @@
+ * - Powering Up HDMI controller and PHY
+ */
+
+-static void meson_fb_output_poll_changed(struct drm_device *dev)
+-{
+- struct meson_drm *priv = dev->dev_private;
+-
+- drm_fbdev_cma_hotplug_event(priv->fbdev);
+-}
+-
+ static const struct drm_mode_config_funcs meson_mode_config_funcs = {
+- .output_poll_changed = meson_fb_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+ .fb_create = drm_gem_fb_create,
+@@ -314,13 +306,6 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+
+ drm_mode_config_reset(drm);
+
+- priv->fbdev = drm_fbdev_cma_init(drm, 32,
+- drm->mode_config.num_connector);
+- if (IS_ERR(priv->fbdev)) {
+- ret = PTR_ERR(priv->fbdev);
+- goto free_drm;
+- }
+-
+ drm_kms_helper_poll_init(drm);
+
+ platform_set_drvdata(pdev, priv);
+@@ -329,6 +314,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ if (ret)
+ goto free_drm;
+
++ drm_fbdev_generic_setup(drm, 32);
++
+ return 0;
+
+ free_drm:
+@@ -345,7 +332,6 @@ static int meson_drv_bind(struct device *dev)
+ static void meson_drv_unbind(struct device *dev)
+ {
+ struct drm_device *drm = dev_get_drvdata(dev);
+- struct meson_drm *priv = drm->dev_private;
+
+ if (priv->canvas) {
+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
+@@ -356,7 +342,6 @@ static void meson_drv_unbind(struct device *dev)
+
+ drm_dev_unregister(drm);
+ drm_kms_helper_poll_fini(drm);
+- drm_fbdev_cma_fini(priv->fbdev);
+ drm_mode_config_cleanup(drm);
+ drm_dev_put(drm);
+
+diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
+index a955354..4dccf4c 100644
+--- a/drivers/gpu/drm/meson/meson_drv.h
++++ b/drivers/gpu/drm/meson/meson_drv.h
+@@ -40,7 +40,6 @@ struct meson_drm {
+
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+- struct drm_fbdev_cma *fbdev;
+ struct drm_plane *primary_plane;
+ struct drm_plane *overlay_plane;
+
diff --git a/testing/linux-amlogic/0010-fixup-drm-meson-Use-optional-canvas-provider.patch b/testing/linux-amlogic/0010-fixup-drm-meson-Use-optional-canvas-provider.patch
new file mode 100644
index 0000000000..9ea9352c9b
--- /dev/null
+++ b/testing/linux-amlogic/0010-fixup-drm-meson-Use-optional-canvas-provider.patch
@@ -0,0 +1,21 @@
+From 07145ad0791209d3782eca4800406e7028e40a24 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:24:43 +0100
+Subject: [PATCH] fixup! drm/meson: Use optional canvas provider
+
+---
+ drivers/gpu/drm/meson/meson_drv.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
+index 3997e3e..3ee4d4a4e 100644
+--- a/drivers/gpu/drm/meson/meson_drv.c
++++ b/drivers/gpu/drm/meson/meson_drv.c
+@@ -332,6 +332,7 @@ static int meson_drv_bind(struct device *dev)
+ static void meson_drv_unbind(struct device *dev)
+ {
+ struct drm_device *drm = dev_get_drvdata(dev);
++ struct meson_drm *priv = drm->dev_private;
+
+ if (priv->canvas) {
+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
diff --git a/testing/linux-amlogic/0014-snd-meson-activate-HDMI-audio-path.patch b/testing/linux-amlogic/0010-snd-meson-activate-HDMI-audio-path.patch
index 26dedf3d20..8a3ea861f2 100644
--- a/testing/linux-amlogic/0014-snd-meson-activate-HDMI-audio-path.patch
+++ b/testing/linux-amlogic/0010-snd-meson-activate-HDMI-audio-path.patch
@@ -1,9 +1,10 @@
-From 69d2f200d91fbd48e2388a8c5346f10d889a2928 Mon Sep 17 00:00:00 2001
+From c89e4a9d376b72bb00c1c71795b86fe81914a3ea Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 7 Jul 2017 17:39:21 +0200
Subject: [PATCH] snd: meson: activate HDMI audio path
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
---
sound/soc/meson/i2s-dai.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/testing/linux-amlogic/0015-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch b/testing/linux-amlogic/0011-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
index cb88ebaf11..25c5a7f968 100644
--- a/testing/linux-amlogic/0015-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
+++ b/testing/linux-amlogic/0011-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
@@ -1,9 +1,10 @@
-From 223d7ef1a49981c597094e8519e150108cba9ef9 Mon Sep 17 00:00:00 2001
+From d46542e83265b476b32b94729e609a9a7767deac Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Tue, 14 Feb 2017 19:18:04 +0100
Subject: [PATCH] drm/meson: select dw-hdmi i2s audio for meson hdmi
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
drivers/gpu/drm/meson/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/testing/linux-amlogic/0016-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch b/testing/linux-amlogic/0012-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
index a5e4fab7a5..0b84218aa9 100644
--- a/testing/linux-amlogic/0016-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
+++ b/testing/linux-amlogic/0012-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
@@ -1,9 +1,10 @@
-From 00ce6fbb804c6aaecd3bde8f2978d091fbc0546c Mon Sep 17 00:00:00 2001
+From 0eb1a7bb3fd9e1ff2f368bb20490c7a032fc96e6 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Wed, 20 Sep 2017 18:01:26 +0200
Subject: [PATCH] ARM64: dts: meson-gx: add sound-dai-cells to HDMI node
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
+
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 +
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 1 +
diff --git a/testing/linux-amlogic/0012-drm-meson-add-support-for-1080p25-mode.patch b/testing/linux-amlogic/0012-drm-meson-add-support-for-1080p25-mode.patch
new file mode 100644
index 0000000000..bd267a5c03
--- /dev/null
+++ b/testing/linux-amlogic/0012-drm-meson-add-support-for-1080p25-mode.patch
@@ -0,0 +1,21 @@
+From 1f929f36f48f0f957f6c73cec309235243bd42f9 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Mon, 12 Nov 2018 16:10:31 +0100
+Subject: [PATCH] drm/meson: add support for 1080p25 mode
+
+---
+ drivers/gpu/drm/meson/meson_venc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
+index d68ccbf..0fbe525 100644
+--- a/drivers/gpu/drm/meson/meson_venc.c
++++ b/drivers/gpu/drm/meson/meson_venc.c
+@@ -841,6 +841,7 @@ struct meson_hdmi_venc_vic_mode {
+ { 5, &meson_hdmi_encp_mode_1080i60 },
+ { 20, &meson_hdmi_encp_mode_1080i50 },
+ { 32, &meson_hdmi_encp_mode_1080p24 },
++ { 33, &meson_hdmi_encp_mode_1080p50 },
+ { 34, &meson_hdmi_encp_mode_1080p30 },
+ { 31, &meson_hdmi_encp_mode_1080p50 },
+ { 16, &meson_hdmi_encp_mode_1080p60 },
diff --git a/testing/linux-amlogic/0017-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch b/testing/linux-amlogic/0013-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
index e02abbfe21..3ad65fc473 100644
--- a/testing/linux-amlogic/0017-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
+++ b/testing/linux-amlogic/0013-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
@@ -1,4 +1,4 @@
-From 2df1a3a93bc1ce2d04fa0f0743c9c30195c7057a Mon Sep 17 00:00:00 2001
+From f0417a0c309fb02a5896abb868a52a1a3e23d610 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Wed, 20 Sep 2017 18:10:08 +0200
Subject: [PATCH] ARM64: dts: meson: activate hdmi audio HDMI enabled boards
@@ -11,6 +11,7 @@ the audio I expect to see merged
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
---
.../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 45 ++++++++++++++++++++++
.../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 45 ++++++++++++++++++++++
@@ -27,10 +28,10 @@ Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
12 files changed, 540 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
-index 88e712e..319512e 100644
+index 765247b..fb9ad6f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
-@@ -95,6 +95,39 @@
+@@ -102,6 +102,39 @@
};
};
};
@@ -70,7 +71,7 @@ index 88e712e..319512e 100644
};
&cec_AO {
-@@ -104,6 +137,14 @@
+@@ -111,6 +144,14 @@
hdmi-phandle = <&hdmi_tx>;
};
@@ -85,7 +86,7 @@ index 88e712e..319512e 100644
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
-@@ -126,6 +167,10 @@
+@@ -133,6 +174,10 @@
};
};
@@ -719,7 +720,7 @@ index 5896e8a..f8c66a7 100644
status = "okay";
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
-index 0868da4..ea71261 100644
+index 313f88f..4fbfa5a 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
@@ -85,6 +85,39 @@
@@ -777,7 +778,7 @@ index 0868da4..ea71261 100644
&cpu0 {
#cooling-cells = <2>;
};
-@@ -255,6 +296,10 @@
+@@ -279,6 +320,10 @@
};
};
diff --git a/testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch b/testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch
new file mode 100644
index 0000000000..832af82c2a
--- /dev/null
+++ b/testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch
@@ -0,0 +1,147 @@
+From 2ffa6ba6e67706f195b1938c5f7e8a385252bd8e Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 14 Nov 2018 16:48:50 +0100
+Subject: [PATCH] drm/bridge: dw-hdmi: Add SCDC and TMDS Scrambling support
+
+Add support for SCDC Setup for TMDS Clock > 3.4GHz and enable TMDS
+Scrambling when supported or mandatory.
+
+This patch also adds an helper to setup the control bit to support
+the hight TMDS Bit Period/TMDS Clock-Period Ratio as required with
+TMDS Clock > 3.4GHz for HDMI2.0 3840x2160@60/50 modes.
+
+These changes were based on work done by Huicong Xu <xhc@rock-chips.com>
+and Nickey Yang <nickey.yang@rock-chips.com> to support HDMI2.0 modes
+on the Rockchip 4.4 BSP kernel at [1]
+
+[1] https://github.com/rockchip-linux/kernel/tree/release-4.4
+
+Cc: Nickey Yang <nickey.yang@rock-chips.com>
+Cc: Huicong Xu <xhc@rock-chips.com>
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 45 ++++++++++++++++++++++++++++---
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 1 +
+ include/drm/bridge/dw_hdmi.h | 1 +
+ 3 files changed, 44 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+index 1fc1270..2a30d83 100644
+--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+@@ -28,6 +28,7 @@
+ #include <drm/drm_crtc_helper.h>
+ #include <drm/drm_edid.h>
+ #include <drm/drm_encoder_slave.h>
++#include <drm/drm_scdc_helper.h>
+ #include <drm/bridge/dw_hdmi.h>
+
+ #include <uapi/linux/media-bus-format.h>
+@@ -1026,6 +1027,20 @@ void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+ }
+ EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
+
++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
++{
++ unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
++
++ /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
++ if (hdmi->connector.display_info.hdmi.scdc.supported) {
++ if (mtmdsclock > 340000000)
++ drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 1);
++ else
++ drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, 0);
++ }
++}
++EXPORT_SYMBOL_GPL(dw_hdmi_set_high_tmds_clock_ratio);
++
+ static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
+ {
+ hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
+@@ -1351,11 +1366,12 @@ static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
+
+ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ {
++ bool is_hdmi2_sink = hdmi->connector.display_info.hdmi.scdc.supported;
+ struct hdmi_avi_infoframe frame;
+ u8 val;
+
+ /* Initialise info frame from DRM mode */
+- drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, false);
++ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
+
+ if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
+ frame.colorspace = HDMI_COLORSPACE_YUV444;
+@@ -1514,7 +1530,8 @@ static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
+ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ const struct drm_display_mode *mode)
+ {
+- u8 inv_val;
++ u8 inv_val, bytes;
++ struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
+ struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+ int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+ unsigned int vdisplay;
+@@ -1524,7 +1541,9 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+ /* Set up HDMI_FC_INVIDCONF */
+- inv_val = (hdmi->hdmi_data.hdcp_enable ?
++ inv_val = (hdmi->hdmi_data.hdcp_enable ||
++ vmode->mpixelclock > 340000000 ||
++ hdmi_info->scdc.scrambling.low_rates ?
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+@@ -1573,6 +1592,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ vsync_len /= 2;
+ }
+
++ /* Scrambling Control */
++ if (hdmi_info->scdc.supported) {
++ if (vmode->mpixelclock > 340000000 ||
++ hdmi_info->scdc.scrambling.low_rates) {
++ drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
++ &bytes);
++ drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION,
++ bytes);
++ drm_scdc_set_scrambling(&hdmi->i2c->adap, 1);
++ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
++ HDMI_MC_SWRSTZ);
++ hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL);
++ } else {
++ hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL);
++ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ,
++ HDMI_MC_SWRSTZ);
++ drm_scdc_set_scrambling(&hdmi->i2c->adap, 0);
++ }
++ }
++
+ /* Set up horizontal active pixel width */
+ hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+ hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+index 9d90eb9..3f3c616 100644
+--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+@@ -255,6 +255,7 @@
+ #define HDMI_FC_MASK2 0x10DA
+ #define HDMI_FC_POL2 0x10DB
+ #define HDMI_FC_PRCONF 0x10E0
++#define HDMI_FC_SCRAMBLER_CTRL 0x10E1
+
+ #define HDMI_FC_GMD_STAT 0x1100
+ #define HDMI_FC_GMD_EN 0x1101
+diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
+index ccb5aa8..d7cc5d0 100644
+--- a/include/drm/bridge/dw_hdmi.h
++++ b/include/drm/bridge/dw_hdmi.h
+@@ -156,6 +156,7 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense);
+ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
+ void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
+ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
++void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi);
+
+ /* PHY configuration */
+ void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
diff --git a/testing/linux-amlogic/0018-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch b/testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
index fbff6c8d89..702f0c7141 100644
--- a/testing/linux-amlogic/0018-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
+++ b/testing/linux-amlogic/0014-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
@@ -1,16 +1,17 @@
-From e282ad866be628951a95d297207c9a5580f4101d Mon Sep 17 00:00:00 2001
+From 68854b3c7771ad5754ad46d42f45f626ca87b4ac Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Mon, 2 Jul 2018 12:21:55 +0200
Subject: [PATCH] drm: bridge: dw-hdmi: Use AUTO CTS setup mode when non-AHB
audio
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++++++++++++++++-----------
1 file changed, 26 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
-index 3c136f2b..a68ffbb 100644
+index 5971976..1fc1270 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -430,8 +430,12 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
diff --git a/testing/linux-amlogic/0015-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch b/testing/linux-amlogic/0015-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
new file mode 100644
index 0000000000..7dc23b5b47
--- /dev/null
+++ b/testing/linux-amlogic/0015-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
@@ -0,0 +1,61 @@
+From 40bfd476f6bb44f9bf88bbbc0bd4cfd9591bedc9 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 28 Feb 2018 16:07:18 +0100
+Subject: [PATCH] drm/meson: Call drm_crtc_vblank_on / drm_crtc_vblank_off
+
+Make sure that the CRTC code will call the enable/disable_vblank hooks.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_crtc.c | 4 ++++
+ drivers/gpu/drm/meson/meson_venc.c | 3 +++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index 0552020..7c0bdc8 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -102,6 +102,8 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+ priv->io_base + _REG(VPP_MISC));
+
+ priv->viu.osd1_enabled = true;
++
++ drm_crtc_vblank_on(crtc);
+ }
+
+ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+@@ -110,6 +112,8 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+ struct meson_drm *priv = meson_crtc->priv;
+
++ drm_crtc_vblank_off(crtc);
++
+ priv->viu.osd1_enabled = false;
+ priv->viu.osd1_commit = false;
+
+diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
+index 514245e..14aac66 100644
+--- a/drivers/gpu/drm/meson/meson_venc.c
++++ b/drivers/gpu/drm/meson/meson_venc.c
+@@ -71,6 +71,7 @@
+ */
+
+ /* HHI Registers */
++#define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */
+ #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
+ #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
+ #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */
+@@ -1529,10 +1530,12 @@ unsigned int meson_venci_get_field(struct meson_drm *priv)
+ void meson_venc_enable_vsync(struct meson_drm *priv)
+ {
+ writel_relaxed(2, priv->io_base + _REG(VENC_INTCTRL));
++ regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), BIT(25));
+ }
+
+ void meson_venc_disable_vsync(struct meson_drm *priv)
+ {
++ regmap_update_bits(priv->hhi, HHI_GCLK_MPEG2, BIT(25), 0);
+ writel_relaxed(0, priv->io_base + _REG(VENC_INTCTRL));
+ }
+
diff --git a/testing/linux-amlogic/0015-drm-meson-add-HDMI-div40-TMDS-mode.patch b/testing/linux-amlogic/0015-drm-meson-add-HDMI-div40-TMDS-mode.patch
new file mode 100644
index 0000000000..3af3749c72
--- /dev/null
+++ b/testing/linux-amlogic/0015-drm-meson-add-HDMI-div40-TMDS-mode.patch
@@ -0,0 +1,69 @@
+From cd02f4b3e7ad491111dbd6e1eccf3db9bbc1bc81 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Mon, 12 Nov 2018 16:08:13 +0100
+Subject: [PATCH] drm/meson: add HDMI div40 TMDS mode
+
+Add support for TMDS Clock > 3.4GHz for HDMI2.0 display modes.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_dw_hdmi.c | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+index d8c5cc3..118c49e 100644
+--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+@@ -365,7 +365,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+ unsigned int wr_clk =
+ readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
+
+- DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
++ DRM_DEBUG_DRIVER("%d:\"%s\" div%d\n", mode->base.id, mode->name,
++ mode->clock > 340000 ? 40 : 10);
+
+ /* Enable clocks */
+ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
+@@ -385,9 +386,17 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+ /* Enable normal output to PHY */
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
+
+- /* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
+- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
+- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
++ /* TMDS pattern setup (TOFIX Handle the YUV420 case) */
++ if (mode->clock > 340000) {
++ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
++ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
++ 0x03ff03ff);
++ } else {
++ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01,
++ 0x001f001f);
++ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
++ 0x001f001f);
++ }
+
+ /* Load TMDS pattern */
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
+@@ -413,6 +422,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+ /* Disable clock, fifo, fifo_wr */
+ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
+
++ dw_hdmi_set_high_tmds_clock_ratio(hdmi);
++
+ msleep(100);
+
+ /* Reset PHY 3 times in a row */
+@@ -562,6 +573,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ mode->vdisplay, mode->vsync_start,
+ mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+
++ /* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
++ if (mode->clock > 340000 &&
++ connector->display_info.max_tmds_clock < 340000)
++ return MODE_BAD;
++
+ /* Check against non-VIC supported modes */
+ if (!vic) {
+ status = meson_venc_hdmi_supported_mode(mode);
diff --git a/testing/linux-amlogic/0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch b/testing/linux-amlogic/0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch
new file mode 100644
index 0000000000..4a860acdbc
--- /dev/null
+++ b/testing/linux-amlogic/0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch
@@ -0,0 +1,28 @@
+From b48d4a78b2c3dd2db65ac391be3e12e323b6759e Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Mon, 12 Nov 2018 16:10:07 +0100
+Subject: [PATCH] drm/meson: add support for HDMI2.0 2160p modes
+
+Now we support the TMDS Clock > 3.4GHz and support the SCDC Control
+operation in the DW-HDMI Controller, we can enable support for the
+HDMI2.0 3840x2160@60/50 RGB444 display modes.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_venc.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
+index 0fbe525..1bcd642 100644
+--- a/drivers/gpu/drm/meson/meson_venc.c
++++ b/drivers/gpu/drm/meson/meson_venc.c
+@@ -848,6 +848,8 @@ struct meson_hdmi_venc_vic_mode {
+ { 93, &meson_hdmi_encp_mode_2160p24 },
+ { 94, &meson_hdmi_encp_mode_2160p25 },
+ { 95, &meson_hdmi_encp_mode_2160p30 },
++ { 96, &meson_hdmi_encp_mode_2160p25 },
++ { 97, &meson_hdmi_encp_mode_2160p30 },
+ { 0, NULL}, /* sentinel */
+ };
+
diff --git a/testing/linux-amlogic/0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch b/testing/linux-amlogic/0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch
new file mode 100644
index 0000000000..9c36ea2b48
--- /dev/null
+++ b/testing/linux-amlogic/0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch
@@ -0,0 +1,198 @@
+From 3e7f3ec3de8753faefdeb02ed6d00cc580e6ad52 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 14 Nov 2018 17:19:36 +0100
+Subject: [PATCH] drm/bridge: dw-hdmi: add support for YUV420 output
+
+In order to support the HDMI2.0 YUV420 display modes, this patch
+adds support for the YUV420 TMDS Clock divided by 2 and the controller
+passthrough mode.
+
+This patch is based on work from Zheng Yang <zhengyang@rock-chips.com> in
+the Rockchip Linux 4.4 BSP at [1]
+
+[1] https://github.com/rockchip-linux/kernel/tree/release-4.4
+
+Cc: Zheng Yang <zhengyang@rock-chips.com>
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 63 ++++++++++++++++++++++++-------
+ 1 file changed, 50 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+index 2a30d83..c3e4ed1 100644
+--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+@@ -94,6 +94,7 @@ struct hdmi_vmode {
+ unsigned int mpixelclock;
+ unsigned int mpixelrepetitioninput;
+ unsigned int mpixelrepetitionoutput;
++ unsigned int mtmdsclock;
+ };
+
+ struct hdmi_data_info {
+@@ -549,7 +550,7 @@ static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
+ static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
+ {
+ mutex_lock(&hdmi->audio_mutex);
+- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
++ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
+ hdmi->sample_rate);
+ mutex_unlock(&hdmi->audio_mutex);
+ }
+@@ -558,7 +559,7 @@ void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate)
+ {
+ mutex_lock(&hdmi->audio_mutex);
+ hdmi->sample_rate = rate;
+- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock,
++ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mtmdsclock,
+ hdmi->sample_rate);
+ mutex_unlock(&hdmi->audio_mutex);
+ }
+@@ -659,6 +660,20 @@ static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
+ }
+ }
+
++static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
++{
++ switch (bus_format) {
++ case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
++ case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
++ case MEDIA_BUS_FMT_UYYVYY12_0_5X36:
++ case MEDIA_BUS_FMT_UYYVYY16_0_5X48:
++ return true;
++
++ default:
++ return false;
++ }
++}
++
+ static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
+ {
+ switch (bus_format) {
+@@ -888,7 +903,8 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
+ u8 val, vp_conf;
+
+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format) ||
+- hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format)) {
++ hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format) ||
++ hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
+ switch (hdmi_bus_fmt_color_depth(
+ hdmi->hdmi_data.enc_out_bus_format)) {
+ case 8:
+@@ -1029,7 +1045,7 @@ EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
+
+ void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi)
+ {
+- unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mpixelclock;
++ unsigned long mtmdsclock = hdmi->hdmi_data.video_mode.mtmdsclock;
+
+ /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */
+ if (hdmi->connector.display_info.hdmi.scdc.supported) {
+@@ -1370,6 +1386,9 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ struct hdmi_avi_infoframe frame;
+ u8 val;
+
++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
++ is_hdmi2_sink = true;
++
+ /* Initialise info frame from DRM mode */
+ drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2_sink);
+
+@@ -1377,6 +1396,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ frame.colorspace = HDMI_COLORSPACE_YUV444;
+ else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
+ frame.colorspace = HDMI_COLORSPACE_YUV422;
++ else if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
++ frame.colorspace = HDMI_COLORSPACE_YUV420;
+ else
+ frame.colorspace = HDMI_COLORSPACE_RGB;
+
+@@ -1534,15 +1555,18 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ struct drm_hdmi_info *hdmi_info = &hdmi->connector.display_info.hdmi;
+ struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+ int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+- unsigned int vdisplay;
++ unsigned int vdisplay, hdisplay;
+
+- vmode->mpixelclock = mode->clock * 1000;
++ vmode->mtmdsclock = vmode->mpixelclock = mode->clock * 1000;
+
+ dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format))
++ vmode->mtmdsclock /= 2;
++
+ /* Set up HDMI_FC_INVIDCONF */
+ inv_val = (hdmi->hdmi_data.hdcp_enable ||
+- vmode->mpixelclock > 340000000 ||
++ vmode->mtmdsclock > 340000000 ||
+ hdmi_info->scdc.scrambling.low_rates ?
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+@@ -1576,6 +1600,22 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+
+ hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
++ hdisplay = mode->hdisplay;
++ hblank = mode->htotal - mode->hdisplay;
++ h_de_hs = mode->hsync_start - mode->hdisplay;
++ hsync_len = mode->hsync_end - mode->hsync_start;
++
++ /*
++ * When we're setting a YCbCr420 mode, we need
++ * to adjust the horizontal timing to suit.
++ */
++ if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format)) {
++ hdisplay /= 2;
++ hblank /= 2;
++ h_de_hs /= 2;
++ hsync_len /= 2;
++ }
++
+ vdisplay = mode->vdisplay;
+ vblank = mode->vtotal - mode->vdisplay;
+ v_de_vs = mode->vsync_start - mode->vdisplay;
+@@ -1594,7 +1634,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+
+ /* Scrambling Control */
+ if (hdmi_info->scdc.supported) {
+- if (vmode->mpixelclock > 340000000 ||
++ if (vmode->mtmdsclock > 340000000 ||
+ hdmi_info->scdc.scrambling.low_rates) {
+ drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION,
+ &bytes);
+@@ -1613,15 +1653,14 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ }
+
+ /* Set up horizontal active pixel width */
+- hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+- hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
++ hdmi_writeb(hdmi, hdisplay >> 8, HDMI_FC_INHACTV1);
++ hdmi_writeb(hdmi, hdisplay, HDMI_FC_INHACTV0);
+
+ /* Set up vertical active lines */
+ hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1);
+ hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0);
+
+ /* Set up horizontal blanking pixel region width */
+- hblank = mode->htotal - mode->hdisplay;
+ hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+ hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+@@ -1629,7 +1668,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+ /* Set up HSYNC active edge delay width (in pixel clks) */
+- h_de_hs = mode->hsync_start - mode->hdisplay;
+ hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+ hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+@@ -1637,7 +1675,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+ /* Set up HSYNC active pulse width (in pixel clks) */
+- hsync_len = mode->hsync_end - mode->hsync_start;
+ hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+ hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
diff --git a/testing/linux-amlogic/0017-soc-amlogic-add-meson-canvas-driver.patch b/testing/linux-amlogic/0017-soc-amlogic-add-meson-canvas-driver.patch
new file mode 100644
index 0000000000..4bb5731f30
--- /dev/null
+++ b/testing/linux-amlogic/0017-soc-amlogic-add-meson-canvas-driver.patch
@@ -0,0 +1,314 @@
+From 47756c823298bef3895fa2837c4b3e97062e9842 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+Date: Fri, 20 Apr 2018 13:17:07 +0200
+Subject: [PATCH] soc: amlogic: add meson-canvas driver
+
+Amlogic SoCs have a repository of 256 canvas which they use to
+describe pixel buffers.
+
+They contain metadata like width, height, block mode, endianness [..]
+
+Many IPs within those SoCs like vdec/vpu rely on those canvas to read/write
+pixels.
+
+Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
+Tested-by: Neil Armstrong <narmstrong@baylibre.com>
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ drivers/soc/amlogic/Kconfig | 7 ++
+ drivers/soc/amlogic/Makefile | 1 +
+ drivers/soc/amlogic/meson-canvas.c | 185 +++++++++++++++++++++++++++++++
+ include/linux/soc/amlogic/meson-canvas.h | 65 +++++++++++
+ 4 files changed, 258 insertions(+)
+ create mode 100644 drivers/soc/amlogic/meson-canvas.c
+ create mode 100644 include/linux/soc/amlogic/meson-canvas.h
+
+diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
+index b04f6e4..2f282b4 100644
+--- a/drivers/soc/amlogic/Kconfig
++++ b/drivers/soc/amlogic/Kconfig
+@@ -1,5 +1,12 @@
+ menu "Amlogic SoC drivers"
+
++config MESON_CANVAS
++ tristate "Amlogic Meson Canvas driver"
++ depends on ARCH_MESON || COMPILE_TEST
++ default n
++ help
++ Say yes to support the canvas IP for Amlogic SoCs.
++
+ config MESON_GX_SOCINFO
+ bool "Amlogic Meson GX SoC Information driver"
+ depends on ARCH_MESON || COMPILE_TEST
+diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
+index 8fa3218..0ab16d3 100644
+--- a/drivers/soc/amlogic/Makefile
++++ b/drivers/soc/amlogic/Makefile
+@@ -1,3 +1,4 @@
++obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
+ obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
+ obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
+ obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
+diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
+new file mode 100644
+index 0000000..fce33ca
+--- /dev/null
++++ b/drivers/soc/amlogic/meson-canvas.c
+@@ -0,0 +1,185 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
++ * Copyright (C) 2014 Endless Mobile
++ */
++
++#include <linux/kernel.h>
++#include <linux/mfd/syscon.h>
++#include <linux/module.h>
++#include <linux/regmap.h>
++#include <linux/soc/amlogic/meson-canvas.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/io.h>
++
++#define NUM_CANVAS 256
++
++/* DMC Registers */
++#define DMC_CAV_LUT_DATAL 0x00
++ #define CANVAS_WIDTH_LBIT 29
++ #define CANVAS_WIDTH_LWID 3
++#define DMC_CAV_LUT_DATAH 0x04
++ #define CANVAS_WIDTH_HBIT 0
++ #define CANVAS_HEIGHT_BIT 9
++ #define CANVAS_WRAP_BIT 22
++ #define CANVAS_BLKMODE_BIT 24
++ #define CANVAS_ENDIAN_BIT 26
++#define DMC_CAV_LUT_ADDR 0x08
++ #define CANVAS_LUT_WR_EN BIT(9)
++ #define CANVAS_LUT_RD_EN BIT(8)
++
++struct meson_canvas {
++ struct device *dev;
++ void __iomem *reg_base;
++ spinlock_t lock; /* canvas device lock */
++ u8 used[NUM_CANVAS];
++};
++
++static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
++{
++ writel_relaxed(val, canvas->reg_base + reg);
++}
++
++static u32 canvas_read(struct meson_canvas *canvas, u32 reg)
++{
++ return readl_relaxed(canvas->reg_base + reg);
++}
++
++struct meson_canvas *meson_canvas_get(struct device *dev)
++{
++ struct device_node *canvas_node;
++ struct platform_device *canvas_pdev;
++
++ canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
++ if (!canvas_node)
++ return ERR_PTR(-ENODEV);
++
++ canvas_pdev = of_find_device_by_node(canvas_node);
++ if (!canvas_pdev)
++ return ERR_PTR(-EPROBE_DEFER);
++
++ return dev_get_drvdata(&canvas_pdev->dev);
++}
++EXPORT_SYMBOL_GPL(meson_canvas_get);
++
++int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
++ u32 addr, u32 stride, u32 height,
++ unsigned int wrap,
++ unsigned int blkmode,
++ unsigned int endian)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&canvas->lock, flags);
++ if (!canvas->used[canvas_index]) {
++ dev_err(canvas->dev,
++ "Trying to setup non allocated canvas %u\n",
++ canvas_index);
++ spin_unlock_irqrestore(&canvas->lock, flags);
++ return -EINVAL;
++ }
++
++ canvas_write(canvas, DMC_CAV_LUT_DATAL,
++ ((addr + 7) >> 3) |
++ (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
++
++ canvas_write(canvas, DMC_CAV_LUT_DATAH,
++ ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
++ CANVAS_WIDTH_HBIT) |
++ (height << CANVAS_HEIGHT_BIT) |
++ (wrap << CANVAS_WRAP_BIT) |
++ (blkmode << CANVAS_BLKMODE_BIT) |
++ (endian << CANVAS_ENDIAN_BIT));
++
++ canvas_write(canvas, DMC_CAV_LUT_ADDR,
++ CANVAS_LUT_WR_EN | canvas_index);
++
++ /* Force a read-back to make sure everything is flushed. */
++ canvas_read(canvas, DMC_CAV_LUT_DATAH);
++ spin_unlock_irqrestore(&canvas->lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(meson_canvas_config);
++
++int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index)
++{
++ int i;
++ unsigned long flags;
++
++ spin_lock_irqsave(&canvas->lock, flags);
++ for (i = 0; i < NUM_CANVAS; ++i) {
++ if (!canvas->used[i]) {
++ canvas->used[i] = 1;
++ spin_unlock_irqrestore(&canvas->lock, flags);
++ *canvas_index = i;
++ return 0;
++ }
++ }
++ spin_unlock_irqrestore(&canvas->lock, flags);
++
++ dev_err(canvas->dev, "No more canvas available\n");
++ return -ENODEV;
++}
++EXPORT_SYMBOL_GPL(meson_canvas_alloc);
++
++int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&canvas->lock, flags);
++ if (!canvas->used[canvas_index]) {
++ dev_err(canvas->dev,
++ "Trying to free unused canvas %u\n", canvas_index);
++ spin_unlock_irqrestore(&canvas->lock, flags);
++ return -EINVAL;
++ }
++ canvas->used[canvas_index] = 0;
++ spin_unlock_irqrestore(&canvas->lock, flags);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(meson_canvas_free);
++
++static int meson_canvas_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ struct meson_canvas *canvas;
++ struct device *dev = &pdev->dev;
++
++ canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL);
++ if (!canvas)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ canvas->reg_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(canvas->reg_base))
++ return PTR_ERR(canvas->reg_base);
++
++ canvas->dev = dev;
++ spin_lock_init(&canvas->lock);
++ dev_set_drvdata(dev, canvas);
++
++ return 0;
++}
++
++static const struct of_device_id canvas_dt_match[] = {
++ { .compatible = "amlogic,canvas" },
++ {}
++};
++MODULE_DEVICE_TABLE(of, canvas_dt_match);
++
++static struct platform_driver meson_canvas_driver = {
++ .probe = meson_canvas_probe,
++ .driver = {
++ .name = "amlogic-canvas",
++ .of_match_table = canvas_dt_match,
++ },
++};
++module_platform_driver(meson_canvas_driver);
++
++MODULE_DESCRIPTION("Amlogic Canvas driver");
++MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/soc/amlogic/meson-canvas.h b/include/linux/soc/amlogic/meson-canvas.h
+new file mode 100644
+index 0000000..b4dde2f
+--- /dev/null
++++ b/include/linux/soc/amlogic/meson-canvas.h
+@@ -0,0 +1,65 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ */
++#ifndef __SOC_MESON_CANVAS_H
++#define __SOC_MESON_CANVAS_H
++
++#include <linux/kernel.h>
++
++#define MESON_CANVAS_WRAP_NONE 0x00
++#define MESON_CANVAS_WRAP_X 0x01
++#define MESON_CANVAS_WRAP_Y 0x02
++
++#define MESON_CANVAS_BLKMODE_LINEAR 0x00
++#define MESON_CANVAS_BLKMODE_32x32 0x01
++#define MESON_CANVAS_BLKMODE_64x64 0x02
++
++#define MESON_CANVAS_ENDIAN_SWAP16 0x1
++#define MESON_CANVAS_ENDIAN_SWAP32 0x3
++#define MESON_CANVAS_ENDIAN_SWAP64 0x7
++#define MESON_CANVAS_ENDIAN_SWAP128 0xf
++
++struct meson_canvas;
++
++/**
++ * meson_canvas_get() - get a canvas provider instance
++ *
++ * @dev: consumer device pointer
++ */
++struct meson_canvas *meson_canvas_get(struct device *dev);
++
++/**
++ * meson_canvas_alloc() - take ownership of a canvas
++ *
++ * @canvas: canvas provider instance retrieved from meson_canvas_get()
++ * @canvas_index: will be filled with the canvas ID
++ */
++int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index);
++
++/**
++ * meson_canvas_free() - remove ownership from a canvas
++ *
++ * @canvas: canvas provider instance retrieved from meson_canvas_get()
++ * @canvas_index: canvas ID that was obtained via meson_canvas_alloc()
++ */
++int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index);
++
++/**
++ * meson_canvas_config() - configure a canvas
++ *
++ * @canvas: canvas provider instance retrieved from meson_canvas_get()
++ * @canvas_index: canvas ID that was obtained via meson_canvas_alloc()
++ * @addr: physical address to the pixel buffer
++ * @stride: width of the buffer
++ * @height: height of the buffer
++ * @wrap: undocumented
++ * @blkmode: block mode (linear, 32x32, 64x64)
++ * @endian: byte swapping (swap16, swap32, swap64, swap128)
++ */
++int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
++ u32 addr, u32 stride, u32 height,
++ unsigned int wrap, unsigned int blkmode,
++ unsigned int endian);
++
++#endif
diff --git a/testing/linux-amlogic/0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch b/testing/linux-amlogic/0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
new file mode 100644
index 0000000000..b09c7c8488
--- /dev/null
+++ b/testing/linux-amlogic/0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
@@ -0,0 +1,39 @@
+From b2b84d801a2e8145b2a08e0d310682fc5e88b0ad Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
+Date: Fri, 20 Apr 2018 16:09:09 +0200
+Subject: [PATCH] ARM64: dts: meson-gx: add dmcbus and canvas nodes.
+
+DMC is a small memory region with various registers,
+including the ones needed for the canvas module.
+
+Reviewed-by: Jerome Brunet <jbrunet@baylibre.com>
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+index 6b64b63..fb64354 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+@@ -458,6 +458,19 @@
+ };
+ };
+
++ dmcbus: bus@c8838000 {
++ compatible = "simple-bus";
++ reg = <0x0 0xc8838000 0x0 0x400>;
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges = <0x0 0x0 0x0 0xc8838000 0x0 0x400>;
++
++ canvas: video-lut@48 {
++ compatible = "amlogic,canvas";
++ reg = <0x0 0x48 0x0 0x14>;
++ };
++ };
++
+ hiubus: bus@c883c000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc883c000 0x0 0x2000>;
diff --git a/testing/linux-amlogic/0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch b/testing/linux-amlogic/0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch
new file mode 100644
index 0000000000..bc86f57989
--- /dev/null
+++ b/testing/linux-amlogic/0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch
@@ -0,0 +1,102 @@
+From 2dcf2d31652207dfe20d7606804ca3b763b7f094 Mon Sep 17 00:00:00 2001
+From: Zheng Yang <zhengyang@rock-chips.com>
+Date: Tue, 27 Jun 2017 16:22:01 +0800
+Subject: [PATCH] drm/bridge: dw-hdmi: support dynamically get input/out color
+ info
+
+To get input/output bus_format/enc_format dynamically, this patch
+introduce following funstion in plat_data:
+ - get_input_bus_format
+ - get_output_bus_format
+ - get_enc_in_encoding
+ - get_enc_out_encoding
+
+Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++++++-------
+ include/drm/bridge/dw_hdmi.h | 5 +++++
+ 2 files changed, 26 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+index c3e4ed1..6473df3 100644
+--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+@@ -1774,6 +1774,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
+ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ {
+ int ret;
++ void *data = hdmi->plat_data->phy_data;
+
+ hdmi_disable_overflow_interrupts(hdmi);
+
+@@ -1785,10 +1786,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+ }
+
+- if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+- (hdmi->vic == 21) || (hdmi->vic == 22) ||
+- (hdmi->vic == 2) || (hdmi->vic == 3) ||
+- (hdmi->vic == 17) || (hdmi->vic == 18))
++ if (hdmi->plat_data->get_enc_out_encoding)
++ hdmi->hdmi_data.enc_out_encoding =
++ hdmi->plat_data->get_enc_out_encoding(data);
++ else if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
++ (hdmi->vic == 21) || (hdmi->vic == 22) ||
++ (hdmi->vic == 2) || (hdmi->vic == 3) ||
++ (hdmi->vic == 17) || (hdmi->vic == 18))
+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
+ else
+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
+@@ -1797,21 +1801,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+ hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+ /* TOFIX: Get input format from plat data or fallback to RGB888 */
+- if (hdmi->plat_data->input_bus_format)
++ if (hdmi->plat_data->get_input_bus_format)
++ hdmi->hdmi_data.enc_in_bus_format =
++ hdmi->plat_data->get_input_bus_format(data);
++ else if (hdmi->plat_data->input_bus_format)
+ hdmi->hdmi_data.enc_in_bus_format =
+ hdmi->plat_data->input_bus_format;
+ else
+ hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ /* TOFIX: Get input encoding from plat data or fallback to none */
+- if (hdmi->plat_data->input_bus_encoding)
++ if (hdmi->plat_data->get_enc_in_encoding)
++ hdmi->hdmi_data.enc_in_encoding =
++ hdmi->plat_data->get_enc_in_encoding(data);
++ else if (hdmi->plat_data->input_bus_encoding)
+ hdmi->hdmi_data.enc_in_encoding =
+ hdmi->plat_data->input_bus_encoding;
+ else
+ hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
+
+ /* TOFIX: Default to RGB888 output format */
+- hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
++ if (hdmi->plat_data->get_output_bus_format)
++ hdmi->hdmi_data.enc_out_bus_format =
++ hdmi->plat_data->get_output_bus_format(data);
++ else
++ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ hdmi->hdmi_data.pix_repet_factor = 0;
+ hdmi->hdmi_data.hdcp_enable = 0;
+diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
+index d7cc5d0..27f9cce 100644
+--- a/include/drm/bridge/dw_hdmi.h
++++ b/include/drm/bridge/dw_hdmi.h
+@@ -141,6 +141,11 @@ struct dw_hdmi_plat_data {
+ int (*configure_phy)(struct dw_hdmi *hdmi,
+ const struct dw_hdmi_plat_data *pdata,
+ unsigned long mpixelclock);
++
++ unsigned long (*get_input_bus_format)(void *data);
++ unsigned long (*get_output_bus_format)(void *data);
++ unsigned long (*get_enc_in_encoding)(void *data);
++ unsigned long (*get_enc_out_encoding)(void *data);
+ };
+
+ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
diff --git a/testing/linux-amlogic/0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch b/testing/linux-amlogic/0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch
new file mode 100644
index 0000000000..54939c84e9
--- /dev/null
+++ b/testing/linux-amlogic/0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch
@@ -0,0 +1,46 @@
+From 94d815707144fb76f2e6f718a864f10a8d3f6306 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 14 Nov 2018 17:39:46 +0100
+Subject: [PATCH] drm/bridge: dw-hdmi: allow ycbcr420 modes for >= 0x200a
+
+Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support
+for these modes in the connector if the platform supports them.
+We limit these modes to DW-HDMI IP version >= 0x200a which
+are designed to support HDMI2.0 display modes.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++
+ include/drm/bridge/dw_hdmi.h | 1 +
+ 2 files changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+index 6473df3..d10277f 100644
+--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+@@ -2575,6 +2575,12 @@ __dw_hdmi_probe(struct platform_device *pdev,
+ if (hdmi->phy.ops->setup_hpd)
+ hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
+
++ if (hdmi->version >= 0x200a)
++ hdmi->connector.ycbcr_420_allowed =
++ hdmi->plat_data->ycbcr_420_allowed;
++ else
++ hdmi->connector.ycbcr_420_allowed = false;
++
+ memset(&pdevinfo, 0, sizeof(pdevinfo));
+ pdevinfo.parent = dev;
+ pdevinfo.id = PLATFORM_DEVID_AUTO;
+diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
+index 27f9cce..c04f497a 100644
+--- a/include/drm/bridge/dw_hdmi.h
++++ b/include/drm/bridge/dw_hdmi.h
+@@ -128,6 +128,7 @@ struct dw_hdmi_plat_data {
+ const struct drm_display_mode *mode);
+ unsigned long input_bus_format;
+ unsigned long input_bus_encoding;
++ bool ycbcr_420_allowed;
+
+ /* Vendor PHY support */
+ const struct dw_hdmi_phy_ops *phy_ops;
diff --git a/testing/linux-amlogic/0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch b/testing/linux-amlogic/0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
deleted file mode 100644
index 314ff482b8..0000000000
--- a/testing/linux-amlogic/0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 4a3a6d04d4996ff0a0acc8405fdd0b0347a62138 Mon Sep 17 00:00:00 2001
-From: Neil Armstrong <narmstrong@baylibre.com>
-Date: Wed, 28 Feb 2018 16:07:18 +0100
-Subject: [PATCH] drm/meson: Call drm_crtc_vblank_on / drm_crtc_vblank_off
-
-Make sure that the CRTC code will call the enable/disable_vblank hooks.
-
-Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
----
- drivers/gpu/drm/meson/meson_crtc.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
-index 0552020..4dd0df0 100644
---- a/drivers/gpu/drm/meson/meson_crtc.c
-+++ b/drivers/gpu/drm/meson/meson_crtc.c
-@@ -102,6 +102,8 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
- priv->io_base + _REG(VPP_MISC));
-
- priv->viu.osd1_enabled = true;
-+
-+ drm_crtc_vblank_on(crtc);
- }
-
- static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
-@@ -110,6 +112,10 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
- struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
- struct meson_drm *priv = meson_crtc->priv;
-
-+ DRM_DEBUG_DRIVER("\n");
-+
-+ drm_crtc_vblank_off(crtc);
-+
- priv->viu.osd1_enabled = false;
- priv->viu.osd1_commit = false;
-
diff --git a/testing/linux-amlogic/0020-drm-meson-Add-YUV420-output-support.patch b/testing/linux-amlogic/0020-drm-meson-Add-YUV420-output-support.patch
new file mode 100644
index 0000000000..ab69cd67c9
--- /dev/null
+++ b/testing/linux-amlogic/0020-drm-meson-Add-YUV420-output-support.patch
@@ -0,0 +1,582 @@
+From fb1abdc9ba8015b1a5c2a6c53ffc08fa0676db04 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Thu, 15 Nov 2018 16:41:23 +0100
+Subject: [PATCH] drm/meson: Add YUV420 output support
+
+This patch adds support for the YUV420 output from the Amlogic Meson SoCs
+Video Processing Unit to the HDMI Controller.
+
+The YUV420 is obtained by generating a YUV444 pixel stream like
+the classic HDMI display modes, but then the Video Encoder output
+can be configured to down-sample the YUV444 pixel stream to a YUV420
+stream.
+In addition if pixel stream down-sampling, the Y Cb Cr components must
+also be mapped differently to align with the HDMI2.0 specifications.
+
+This mode needs a different clock generation scheme since the TMDS PHY
+clock must match the 10x ration with the YUV420 pixel clock, but
+the video encoder must run at 2x the pixel clock.
+
+This patch adds the TMDS PHY clock value in all the video clock setup
+in order to better support these specific uses cases and switch
+to the Common Clock framework for clocks handling in the future.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_dw_hdmi.c | 108 +++++++++++++++++++++++++++-----
+ drivers/gpu/drm/meson/meson_vclk.c | 95 +++++++++++++++++++++-------
+ drivers/gpu/drm/meson/meson_vclk.h | 7 ++-
+ drivers/gpu/drm/meson/meson_venc.c | 6 +-
+ drivers/gpu/drm/meson/meson_venc.h | 11 ++++
+ drivers/gpu/drm/meson/meson_venc_cvbs.c | 3 +-
+ 6 files changed, 184 insertions(+), 46 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+index 118c49e..0b9ecbf 100644
+--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+@@ -141,6 +141,8 @@ struct meson_dw_hdmi {
+ struct regulator *hdmi_supply;
+ u32 irq_stat;
+ struct dw_hdmi *hdmi;
++ unsigned long input_bus_format;
++ unsigned long output_bus_format;
+ };
+ #define encoder_to_meson_dw_hdmi(x) \
+ container_of(x, struct meson_dw_hdmi, encoder)
+@@ -323,25 +325,36 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
+ {
+ struct meson_drm *priv = dw_hdmi->priv;
+ int vic = drm_match_cea_mode(mode);
++ unsigned int phy_freq;
+ unsigned int vclk_freq;
+ unsigned int venc_freq;
+ unsigned int hdmi_freq;
+
+ vclk_freq = mode->clock;
+
++ /* For 420, pixel clock is half unlike venc clock */
++ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
++ vclk_freq /= 2;
++
++ /* TMDS clock is pixel_clock * 10 */
++ phy_freq = vclk_freq * 10;
++
+ if (!vic) {
+- meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, vclk_freq,
+- vclk_freq, vclk_freq, false);
++ meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq,
++ vclk_freq, vclk_freq, vclk_freq, false);
+ return;
+ }
+
++ /* 480i/576i needs global pixel doubling */
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ vclk_freq *= 2;
+
+ venc_freq = vclk_freq;
+ hdmi_freq = vclk_freq;
+
+- if (meson_venc_hdmi_venc_repeat(vic))
++ /* VENC double pixels for 1080i, 720p and YUV420 modes */
++ if (meson_venc_hdmi_venc_repeat(vic) ||
++ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
+ venc_freq *= 2;
+
+ vclk_freq = max(venc_freq, hdmi_freq);
+@@ -349,11 +362,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ venc_freq /= 2;
+
+- DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
+- vclk_freq, venc_freq, hdmi_freq,
++ DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n",
++ phy_freq, vclk_freq, venc_freq, hdmi_freq,
+ priv->venc.hdmi_use_enci);
+
+- meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
++ meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq,
+ venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
+ }
+
+@@ -387,7 +400,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
+
+ /* TMDS pattern setup (TOFIX Handle the YUV420 case) */
+- if (mode->clock > 340000) {
++ if (mode->clock > 340000 &&
++ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_YUV8_1X24) {
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0);
+ dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23,
+ 0x03ff03ff);
+@@ -560,6 +574,8 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+ {
+ struct meson_drm *priv = connector->dev->dev_private;
++ bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported;
++ unsigned int phy_freq;
+ unsigned int vclk_freq;
+ unsigned int venc_freq;
+ unsigned int hdmi_freq;
+@@ -573,9 +589,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ mode->vdisplay, mode->vsync_start,
+ mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+
+- /* If sink max TMDS clock < 340MHz, we reject the HDMI2.0 modes */
++ /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */
+ if (mode->clock > 340000 &&
+- connector->display_info.max_tmds_clock < 340000)
++ connector->display_info.max_tmds_clock < 340000 &&
++ !drm_mode_is_420_only(&connector->display_info, mode) &&
++ !drm_mode_is_420_also(&connector->display_info, mode))
+ return MODE_BAD;
+
+ /* Check against non-VIC supported modes */
+@@ -591,6 +609,15 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+
+ vclk_freq = mode->clock;
+
++ /* For 420, pixel clock is half unlike venc clock */
++ if (drm_mode_is_420_only(&connector->display_info, mode) ||
++ (!is_hdmi2_sink &&
++ drm_mode_is_420_also(&connector->display_info, mode)))
++ vclk_freq /= 2;
++
++ /* TMDS clock is pixel_clock * 10 */
++ phy_freq = vclk_freq * 10;
++
+ /* 480i/576i needs global pixel doubling */
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ vclk_freq *= 2;
+@@ -598,8 +625,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ venc_freq = vclk_freq;
+ hdmi_freq = vclk_freq;
+
+- /* VENC double pixels for 1080i and 720p modes */
+- if (meson_venc_hdmi_venc_repeat(vic))
++ /* VENC double pixels for 1080i, 720p and YUV420 modes */
++ if (meson_venc_hdmi_venc_repeat(vic) ||
++ drm_mode_is_420_only(&connector->display_info, mode) ||
++ (!is_hdmi2_sink &&
++ drm_mode_is_420_also(&connector->display_info, mode)))
+ venc_freq *= 2;
+
+ vclk_freq = max(venc_freq, hdmi_freq);
+@@ -607,10 +637,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+ venc_freq /= 2;
+
+- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
+- vclk_freq, venc_freq, hdmi_freq);
++ dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
++ __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
+
+- return meson_vclk_vic_supported_freq(vclk_freq);
++ return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
+ }
+
+ /* Encoder */
+@@ -628,6 +658,21 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+ {
++ struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
++ struct drm_display_info *info = &conn_state->connector->display_info;
++ struct drm_display_mode *mode = &crtc_state->mode;
++ bool is_hdmi2_sink =
++ conn_state->connector->display_info.hdmi.scdc.supported;
++
++ if (drm_mode_is_420_only(info, mode) ||
++ (!is_hdmi2_sink && drm_mode_is_420_also(info, mode))) {
++ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
++ } else {
++ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
++ }
++
+ return 0;
+ }
+
+@@ -665,18 +710,30 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+ struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+ struct meson_drm *priv = dw_hdmi->priv;
+ int vic = drm_match_cea_mode(mode);
++ unsigned int ycrcb_map = MESON_VENC_MAP_CB_Y_CR;
++ bool yuv420_mode = false;
+
+ DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
+ mode->base.id, mode->name, vic);
+
++ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) {
++ ycrcb_map = MESON_VENC_MAP_CR_Y_CB;
++ yuv420_mode = true;
++ }
++
+ /* VENC + VENC-DVI Mode setup */
+- meson_venc_hdmi_mode_set(priv, vic, mode);
++ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode);
+
+ /* VCLK Set clock */
+ dw_hdmi_set_vclk(dw_hdmi, mode);
+
+- /* Setup YUV444 to HDMI-TX, no 10bit diphering */
+- writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
++ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24)
++ /* Setup YUV420 to HDMI-TX, no 10bit diphering */
++ writel_relaxed(2 | (2 << 2),
++ priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
++ else
++ /* Setup YUV444 to HDMI-TX, no 10bit diphering */
++ writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+ }
+
+ static const struct drm_encoder_helper_funcs
+@@ -714,6 +771,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = {
+ .max_register = 0x10000,
+ };
+
++static unsigned long meson_dw_hdmi_get_in_bus_format(void *data)
++{
++ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
++
++ return dw_hdmi->input_bus_format;
++}
++
++static unsigned long meson_dw_hdmi_get_out_bus_format(void *data)
++{
++ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
++
++ return dw_hdmi->output_bus_format;
++}
++
+ static bool meson_hdmi_connector_is_available(struct device *dev)
+ {
+ struct device_node *ep, *remote;
+@@ -890,6 +961,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
+ dw_plat_data->phy_data = meson_dw_hdmi;
+ dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
+ dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
++ dw_plat_data->get_input_bus_format = meson_dw_hdmi_get_in_bus_format;
++ dw_plat_data->get_output_bus_format = meson_dw_hdmi_get_out_bus_format;
++ dw_plat_data->ycbcr_420_allowed = true;
+
+ platform_set_drvdata(pdev, meson_dw_hdmi);
+
+diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
+index 5accceb..27c9c5e 100644
+--- a/drivers/gpu/drm/meson/meson_vclk.c
++++ b/drivers/gpu/drm/meson/meson_vclk.c
+@@ -337,12 +337,17 @@ enum {
+ /* 2970 /1 /1 /1 /5 /2 => /1 /1 */
+ MESON_VCLK_HDMI_297000,
+ /* 5940 /1 /1 /2 /5 /1 => /1 /1 */
+- MESON_VCLK_HDMI_594000
++ MESON_VCLK_HDMI_594000,
++/* 2970 /1 /1 /1 /5 /1 => /1 /2 */
++ MESON_VCLK_HDMI_594000_YUV420,
+ };
+
+ struct meson_vclk_params {
++ unsigned int pll_freq;
++ unsigned int phy_freq;
++ unsigned int vclk_freq;
++ unsigned int venc_freq;
+ unsigned int pixel_freq;
+- unsigned int pll_base_freq;
+ unsigned int pll_od1;
+ unsigned int pll_od2;
+ unsigned int pll_od3;
+@@ -350,8 +355,11 @@ struct meson_vclk_params {
+ unsigned int vclk_div;
+ } params[] = {
+ [MESON_VCLK_HDMI_ENCI_54000] = {
++ .pll_freq = 4320000,
++ .phy_freq = 270000,
++ .vclk_freq = 54000,
++ .venc_freq = 54000,
+ .pixel_freq = 54000,
+- .pll_base_freq = 4320000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+ .pll_od3 = 1,
+@@ -359,8 +367,11 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_DDR_54000] = {
+- .pixel_freq = 54000,
+- .pll_base_freq = 4320000,
++ .pll_freq = 4320000,
++ .phy_freq = 270000,
++ .vclk_freq = 54000,
++ .venc_freq = 54000,
++ .pixel_freq = 27000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+ .pll_od3 = 1,
+@@ -368,8 +379,11 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_DDR_148500] = {
+- .pixel_freq = 148500,
+- .pll_base_freq = 2970000,
++ .pll_freq = 2970000,
++ .phy_freq = 742500,
++ .vclk_freq = 148500,
++ .venc_freq = 148500,
++ .pixel_freq = 74250,
+ .pll_od1 = 4,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+@@ -377,8 +391,11 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_74250] = {
++ .pll_freq = 2970000,
++ .phy_freq = 742500,
++ .vclk_freq = 74250,
++ .venc_freq = 74250,
+ .pixel_freq = 74250,
+- .pll_base_freq = 2970000,
+ .pll_od1 = 2,
+ .pll_od2 = 2,
+ .pll_od3 = 2,
+@@ -386,8 +403,11 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_148500] = {
++ .pll_freq = 2970000,
++ .phy_freq = 1485000,
++ .vclk_freq = 148500,
++ .venc_freq = 148500,
+ .pixel_freq = 148500,
+- .pll_base_freq = 2970000,
+ .pll_od1 = 1,
+ .pll_od2 = 2,
+ .pll_od3 = 2,
+@@ -395,8 +415,11 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_297000] = {
++ .pll_freq = 2970000,
++ .phy_freq = 2970000,
++ .venc_freq = 297000,
++ .vclk_freq = 297000,
+ .pixel_freq = 297000,
+- .pll_base_freq = 2970000,
+ .pll_od1 = 1,
+ .pll_od2 = 1,
+ .pll_od3 = 1,
+@@ -404,14 +427,29 @@ struct meson_vclk_params {
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_594000] = {
++ .pll_freq = 5940000,
++ .phy_freq = 5940000,
++ .venc_freq = 594000,
++ .vclk_freq = 594000,
+ .pixel_freq = 594000,
+- .pll_base_freq = 5940000,
+ .pll_od1 = 1,
+ .pll_od2 = 1,
+ .pll_od3 = 2,
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 1,
+ },
++ [MESON_VCLK_HDMI_594000_YUV420] = {
++ .pll_freq = 2970000,
++ .phy_freq = 2970000,
++ .venc_freq = 594000,
++ .vclk_freq = 594000,
++ .pixel_freq = 297000,
++ .pll_od1 = 1,
++ .pll_od2 = 1,
++ .pll_od3 = 1,
++ .vid_pll_div = VID_PLL_DIV_5,
++ .vclk_div = 1,
++ },
+ { /* sentinel */ },
+ };
+
+@@ -616,6 +654,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
+ unsigned int od, m, frac, od1, od2, od3;
+
+ if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) {
++ /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */
+ od3 = 1;
+ if (od < 4) {
+ od1 = 2;
+@@ -638,21 +677,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
+ }
+
+ enum drm_mode_status
+-meson_vclk_vic_supported_freq(unsigned int freq)
++meson_vclk_vic_supported_freq(unsigned int phy_freq,
++ unsigned int vclk_freq)
+ {
+ int i;
+
+- DRM_DEBUG_DRIVER("freq = %d\n", freq);
++ DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
++ phy_freq, vclk_freq);
+
+ for (i = 0 ; params[i].pixel_freq ; ++i) {
+ DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
+ i, params[i].pixel_freq,
+ FREQ_1000_1001(params[i].pixel_freq));
++ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n",
++ i, params[i].phy_freq,
++ FREQ_1000_1001(params[i].phy_freq/10)*10);
+ /* Match strict frequency */
+- if (freq == params[i].pixel_freq)
++ if (phy_freq == params[i].phy_freq &&
++ vclk_freq == params[i].vclk_freq)
+ return MODE_OK;
+ /* Match 1000/1001 variant */
+- if (freq == FREQ_1000_1001(params[i].pixel_freq))
++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) &&
++ vclk_freq == FREQ_1000_1001(params[i].vclk_freq))
+ return MODE_OK;
+ }
+
+@@ -666,7 +712,7 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
+ unsigned int hdmi_tx_div, unsigned int venc_div,
+ bool hdmi_use_enci, bool vic_alternate_clock)
+ {
+- unsigned int m, frac;
++ unsigned int m = 0, frac = 0;
+
+ /* Set HDMI-TX sys clock */
+ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+@@ -863,8 +909,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
+ }
+
+ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+- unsigned int vclk_freq, unsigned int venc_freq,
+- unsigned int dac_freq, bool hdmi_use_enci)
++ unsigned int phy_freq, unsigned int vclk_freq,
++ unsigned int venc_freq, unsigned int dac_freq,
++ bool hdmi_use_enci)
+ {
+ bool vic_alternate_clock = false;
+ unsigned int freq;
+@@ -883,7 +930,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ * - venc_div = 1
+ * - encp encoder
+ */
+- meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
++ meson_vclk_set(priv, phy_freq, 0, 0, 0,
+ VID_PLL_DIV_5, 2, 1, 1, false, false);
+ return;
+ }
+@@ -905,9 +952,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ }
+
+ for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
+- if (vclk_freq == params[freq].pixel_freq ||
+- vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
+- if (vclk_freq != params[freq].pixel_freq)
++ if ((phy_freq == params[freq].phy_freq ||
++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) &&
++ (vclk_freq == params[freq].vclk_freq ||
++ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) {
++ if (vclk_freq != params[freq].vclk_freq)
+ vic_alternate_clock = true;
+ else
+ vic_alternate_clock = false;
+@@ -936,7 +985,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ return;
+ }
+
+- meson_vclk_set(priv, params[freq].pll_base_freq,
++ meson_vclk_set(priv, params[freq].pll_freq,
+ params[freq].pll_od1, params[freq].pll_od2,
+ params[freq].pll_od3, params[freq].vid_pll_div,
+ params[freq].vclk_div, hdmi_tx_div, venc_div,
+diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
+index 4bd8752..c4d19dd 100644
+--- a/drivers/gpu/drm/meson/meson_vclk.h
++++ b/drivers/gpu/drm/meson/meson_vclk.h
+@@ -33,10 +33,11 @@ enum {
+ enum drm_mode_status
+ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
+ enum drm_mode_status
+-meson_vclk_vic_supported_freq(unsigned int freq);
++meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
+
+ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+- unsigned int vclk_freq, unsigned int venc_freq,
+- unsigned int dac_freq, bool hdmi_use_enci);
++ unsigned int phy_freq, unsigned int vclk_freq,
++ unsigned int venc_freq, unsigned int dac_freq,
++ bool hdmi_use_enci);
+
+ #endif /* __MESON_VCLK_H */
+diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
+index 1bcd642..ab72ddd 100644
+--- a/drivers/gpu/drm/meson/meson_venc.c
++++ b/drivers/gpu/drm/meson/meson_venc.c
+@@ -956,6 +956,8 @@ bool meson_venc_hdmi_venc_repeat(int vic)
+ EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
+
+ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
++ unsigned int ycrcb_map,
++ bool yuv420_mode,
+ struct drm_display_mode *mode)
+ {
+ union meson_hdmi_venc_mode *vmode = NULL;
+@@ -1505,8 +1507,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
+ writel_relaxed((use_enci ? 1 : 2) |
+ (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) |
+ (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) |
+- 4 << 5 |
+- (venc_repeat ? 1 << 8 : 0) |
++ (ycrcb_map << 5) |
++ (venc_repeat || yuv420_mode ? 1 << 8 : 0) |
+ (hdmi_repeat ? 1 << 12 : 0),
+ priv->io_base + _REG(VPU_HDMI_SETTING));
+
+diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
+index 97eaebb..5580bf3 100644
+--- a/drivers/gpu/drm/meson/meson_venc.h
++++ b/drivers/gpu/drm/meson/meson_venc.h
+@@ -33,6 +33,15 @@ enum {
+ MESON_VENC_MODE_HDMI,
+ };
+
++enum {
++ MESON_VENC_MAP_CR_Y_CB = 0,
++ MESON_VENC_MAP_Y_CB_CR,
++ MESON_VENC_MAP_Y_CR_CB,
++ MESON_VENC_MAP_CB_CR_Y,
++ MESON_VENC_MAP_CB_Y_CR,
++ MESON_VENC_MAP_CR_CB_Y,
++};
++
+ struct meson_cvbs_enci_mode {
+ unsigned int mode_tag;
+ unsigned int hso_begin; /* HSO begin position */
+@@ -70,6 +79,8 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
+ void meson_venci_cvbs_mode_set(struct meson_drm *priv,
+ struct meson_cvbs_enci_mode *mode);
+ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
++ unsigned int ycrcb_map,
++ bool yuv420_mode,
+ struct drm_display_mode *mode);
+ unsigned int meson_venci_get_field(struct meson_drm *priv);
+
+diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
+index f7945ba..38a1117 100644
+--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
++++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
+@@ -207,7 +207,8 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
+ /* Setup 27MHz vclk2 for ENCI and VDAC */
+ meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
+ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+- MESON_VCLK_CVBS, true);
++ MESON_VCLK_CVBS, MESON_VCLK_CVBS,
++ true);
+ break;
+ }
+ }
diff --git a/testing/linux-amlogic/0020-drm-meson-Use-optional-canvas-provider.patch b/testing/linux-amlogic/0020-drm-meson-Use-optional-canvas-provider.patch
new file mode 100644
index 0000000000..3988b69855
--- /dev/null
+++ b/testing/linux-amlogic/0020-drm-meson-Use-optional-canvas-provider.patch
@@ -0,0 +1,172 @@
+From 21a926d5d6a2973c1a1665482accac7548c1a67d Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Mon, 15 Oct 2018 14:37:18 +0200
+Subject: [PATCH] drm/meson: Use optional canvas provider
+
+This is the first step into converting the meson/drm driver to use
+the canvas module.
+
+If a canvas provider node is detected in DT, use it. Otherwise,
+fall back to what is currently being done.
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/Kconfig | 1 +
+ drivers/gpu/drm/meson/meson_crtc.c | 14 +++++++----
+ drivers/gpu/drm/meson/meson_drv.c | 46 +++++++++++++++++++++++--------------
+ drivers/gpu/drm/meson/meson_drv.h | 4 ++++
+ drivers/gpu/drm/meson/meson_plane.c | 8 ++++++-
+ 5 files changed, 51 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
+index 02d400b..8929058 100644
+--- a/drivers/gpu/drm/meson/Kconfig
++++ b/drivers/gpu/drm/meson/Kconfig
+@@ -7,6 +7,7 @@ config DRM_MESON
+ select DRM_GEM_CMA_HELPER
+ select VIDEOMODE_HELPERS
+ select REGMAP_MMIO
++ select MESON_CANVAS
+
+ config DRM_MESON_DW_HDMI
+ tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index 7c0bdc8..8744244 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -197,10 +197,16 @@ void meson_crtc_irq(struct meson_drm *priv)
+ } else
+ meson_vpp_disable_interlace_vscaler_osd1(priv);
+
+- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
+- priv->viu.osd1_addr, priv->viu.osd1_stride,
+- priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
+- MESON_CANVAS_BLKMODE_LINEAR);
++ if (priv->canvas)
++ meson_canvas_config(priv->canvas, priv->canvas_id_osd1,
++ priv->viu.osd1_addr, priv->viu.osd1_stride,
++ priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR, 0);
++ else
++ meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
++ priv->viu.osd1_addr, priv->viu.osd1_stride,
++ priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR);
+
+ /* Enable OSD1 */
+ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
+diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
+index d344312..b39c38c 100644
+--- a/drivers/gpu/drm/meson/meson_drv.c
++++ b/drivers/gpu/drm/meson/meson_drv.c
+@@ -216,24 +216,33 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ goto free_drm;
+ }
+
+- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
+- if (!res) {
+- ret = -EINVAL;
+- goto free_drm;
+- }
+- /* Simply ioremap since it may be a shared register zone */
+- regs = devm_ioremap(dev, res->start, resource_size(res));
+- if (!regs) {
+- ret = -EADDRNOTAVAIL;
+- goto free_drm;
+- }
++ priv->canvas = meson_canvas_get(dev);
++ if (!IS_ERR(priv->canvas)) {
++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
++ if (ret)
++ goto free_drm;
++ } else {
++ priv->canvas = NULL;
+
+- priv->dmc = devm_regmap_init_mmio(dev, regs,
+- &meson_regmap_config);
+- if (IS_ERR(priv->dmc)) {
+- dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
+- ret = PTR_ERR(priv->dmc);
+- goto free_drm;
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
++ if (!res) {
++ ret = -EINVAL;
++ goto free_drm;
++ }
++ /* Simply ioremap since it may be a shared register zone */
++ regs = devm_ioremap(dev, res->start, resource_size(res));
++ if (!regs) {
++ ret = -EADDRNOTAVAIL;
++ goto free_drm;
++ }
++
++ priv->dmc = devm_regmap_init_mmio(dev, regs,
++ &meson_regmap_config);
++ if (IS_ERR(priv->dmc)) {
++ dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
++ ret = PTR_ERR(priv->dmc);
++ goto free_drm;
++ }
+ }
+
+ priv->vsync_irq = platform_get_irq(pdev, 0);
+@@ -315,6 +324,9 @@ static void meson_drv_unbind(struct device *dev)
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct meson_drm *priv = drm->dev_private;
+
++ if (priv->canvas)
++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
++
+ drm_dev_unregister(drm);
+ drm_kms_helper_poll_fini(drm);
+ drm_fbdev_cma_fini(priv->fbdev);
+diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
+index 8450d6ac..728d0ca 100644
+--- a/drivers/gpu/drm/meson/meson_drv.h
++++ b/drivers/gpu/drm/meson/meson_drv.h
+@@ -22,6 +22,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/regmap.h>
+ #include <linux/of.h>
++#include <linux/soc/amlogic/meson-canvas.h>
+ #include <drm/drmP.h>
+
+ struct meson_drm {
+@@ -31,6 +32,9 @@ struct meson_drm {
+ struct regmap *dmc;
+ int vsync_irq;
+
++ struct meson_canvas *canvas;
++ u8 canvas_id_osd1;
++
+ struct drm_device *drm;
+ struct drm_crtc *crtc;
+ struct drm_fbdev_cma *fbdev;
+diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
+index 12c80df..51bec8e 100644
+--- a/drivers/gpu/drm/meson/meson_plane.c
++++ b/drivers/gpu/drm/meson/meson_plane.c
+@@ -90,6 +90,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ .y2 = state->crtc_y + state->crtc_h,
+ };
+ unsigned long flags;
++ u8 canvas_id_osd1;
+
+ /*
+ * Update Coordinates
+@@ -104,8 +105,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ (0xFF << OSD_GLOBAL_ALPHA_SHIFT) |
+ OSD_BLK0_ENABLE;
+
++ if (priv->canvas)
++ canvas_id_osd1 = priv->canvas_id_osd1;
++ else
++ canvas_id_osd1 = MESON_CANVAS_ID_OSD1;
++
+ /* Set up BLK0 to point to the right canvas */
+- priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
++ priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) |
+ OSD_ENDIANNESS_LE);
+
+ /* On GXBB, Use the old non-HDR RGB2YUV converter */
diff --git a/testing/linux-amlogic/0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch b/testing/linux-amlogic/0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch
deleted file mode 100644
index 81569fc4d3..0000000000
--- a/testing/linux-amlogic/0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 830bb1ab9ee8999566a4d98086590ac824cdeb4e Mon Sep 17 00:00:00 2001
-From: Neil Armstrong <narmstrong@baylibre.com>
-Date: Tue, 10 Jul 2018 15:00:45 +0200
-Subject: [PATCH] media: platform: meson-ao-cec: make busy TX warning silent
-
-Switch to dev_dbg for the busy TX message to avoid having a flood of:
-[ 228.064570] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
-[ 230.368489] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
-[ 234.208655] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
-[ 236.512558] meson-ao-cec c8100100.cec: meson_ao_cec_transmit: busy TX: aborting
-
-This message is only a debug hint and not an error.
-
-Fixes: 7ec2c0f72cb1 ("media: platform: Add Amlogic Meson AO CEC Controller driver")
-Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
----
- drivers/media/platform/meson/ao-cec.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c
-index 8040a62..cd4be38 100644
---- a/drivers/media/platform/meson/ao-cec.c
-+++ b/drivers/media/platform/meson/ao-cec.c
-@@ -524,7 +524,7 @@ static int meson_ao_cec_transmit(struct cec_adapter *adap, u8 attempts,
- return ret;
-
- if (reg == TX_BUSY) {
-- dev_err(&ao_cec->pdev->dev, "%s: busy TX: aborting\n",
-+ dev_dbg(&ao_cec->pdev->dev, "%s: busy TX: aborting\n",
- __func__);
- meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT, &ret);
- }
diff --git a/testing/linux-amlogic/0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch b/testing/linux-amlogic/0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch
new file mode 100644
index 0000000000..fa25f46426
--- /dev/null
+++ b/testing/linux-amlogic/0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch
@@ -0,0 +1,25 @@
+From 7d3414ae548dd7d6e7caad845322b0dedcf05cb1 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Mon, 15 Oct 2018 14:38:24 +0200
+Subject: [PATCH] arm64: dts: meson-gx: Add canvas provider node to the vpu
+
+Allows the vpu driver to optionally use a canvas provider node.
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+index fb64354..5012607 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+@@ -540,6 +540,7 @@
+ interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
+ #address-cells = <1>;
+ #size-cells = <0>;
++ amlogic,canvas = <&canvas>;
+
+ /* CVBS VDAC output port */
+ cvbs_vdac_port: port@0 {
diff --git a/testing/linux-amlogic/0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch b/testing/linux-amlogic/0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch
new file mode 100644
index 0000000000..50aa112db2
--- /dev/null
+++ b/testing/linux-amlogic/0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch
@@ -0,0 +1,31 @@
+From c9cf1e80259276c3da76bc03ab0aaa9dfac481ae Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Sun, 18 Nov 2018 14:06:11 +0100
+Subject: [PATCH] drm/meson: Output in YUV444 if sink supports it
+
+With the YUV420 handling, we can no dynamically setup the HDMI output
+pixel format depending on the mode and connector info.
+So now, we can output in YUV444, which is the native video pipeline
+format, directly the the HDMI Sink it it's supported, without
+involving the HDMI Controller CSC.
+
+---
+ drivers/gpu/drm/meson/meson_dw_hdmi.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+index 0b9ecbf..6df124c 100644
+--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+@@ -670,7 +670,10 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+ } else {
+ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
+- dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
++ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
++ else
++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+ }
+
+ return 0;
diff --git a/testing/linux-amlogic/0021-soc-amlogic-add-meson-canvas-driver.patch b/testing/linux-amlogic/0021-soc-amlogic-add-meson-canvas-driver.patch
deleted file mode 100644
index 226a7961a1..0000000000
--- a/testing/linux-amlogic/0021-soc-amlogic-add-meson-canvas-driver.patch
+++ /dev/null
@@ -1,280 +0,0 @@
-From 8d7247813f02cad15a67980c2631d9ee37d7b76b Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Wed, 1 Aug 2018 20:51:25 +0200
-Subject: [PATCH] soc: amlogic: add meson-canvas driver
-
-Amlogic SoCs have a repository of 256 canvas which they use to
-describe pixel buffers.
-
-They contain metadata like width, height, block mode, endianness [..]
-
-Many IPs within those SoCs like vdec/vpu rely on those canvas to read/write
-pixels.
-
-Signed-off-by: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
----
- drivers/soc/amlogic/Kconfig | 7 ++
- drivers/soc/amlogic/Makefile | 1 +
- drivers/soc/amlogic/meson-canvas.c | 182 +++++++++++++++++++++++++++++++
- include/linux/soc/amlogic/meson-canvas.h | 37 +++++++
- 4 files changed, 227 insertions(+)
- create mode 100644 drivers/soc/amlogic/meson-canvas.c
- create mode 100644 include/linux/soc/amlogic/meson-canvas.h
-
-diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
-index b04f6e4..5bd0498 100644
---- a/drivers/soc/amlogic/Kconfig
-+++ b/drivers/soc/amlogic/Kconfig
-@@ -1,5 +1,12 @@
- menu "Amlogic SoC drivers"
-
-+config MESON_CANVAS
-+ bool "Amlogic Meson Canvas driver"
-+ depends on ARCH_MESON || COMPILE_TEST
-+ default ARCH_MESON
-+ help
-+ Say yes to support the canvas IP within Amlogic Meson Soc family.
-+
- config MESON_GX_SOCINFO
- bool "Amlogic Meson GX SoC Information driver"
- depends on ARCH_MESON || COMPILE_TEST
-diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
-index 8fa3218..0ab16d3 100644
---- a/drivers/soc/amlogic/Makefile
-+++ b/drivers/soc/amlogic/Makefile
-@@ -1,3 +1,4 @@
-+obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
- obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
- obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
- obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
-diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
-new file mode 100644
-index 0000000..671eb89
---- /dev/null
-+++ b/drivers/soc/amlogic/meson-canvas.c
-@@ -0,0 +1,182 @@
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan
-+ * Copyright (C) 2016 BayLibre, SAS
-+ * Author: Neil Armstrong <narmstrong@baylibre.com>
-+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
-+ * Copyright (C) 2014 Endless Mobile
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of the
-+ * License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/of_address.h>
-+#include <linux/platform_device.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/regmap.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/soc/amlogic/meson-canvas.h>
-+#include <asm/io.h>
-+
-+#define NUM_CANVAS 256
-+
-+/* DMC Registers */
-+#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */
-+ #define CANVAS_WIDTH_LBIT 29
-+ #define CANVAS_WIDTH_LWID 3
-+#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */
-+ #define CANVAS_WIDTH_HBIT 0
-+ #define CANVAS_HEIGHT_BIT 9
-+ #define CANVAS_BLKMODE_BIT 24
-+#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
-+ #define CANVAS_LUT_WR_EN (0x2 << 8)
-+ #define CANVAS_LUT_RD_EN (0x1 << 8)
-+
-+struct meson_canvas {
-+ struct device *dev;
-+ struct regmap *regmap_dmc;
-+ struct mutex lock;
-+ u8 used[NUM_CANVAS];
-+};
-+
-+static struct meson_canvas canvas = { 0 };
-+
-+static int meson_canvas_setup(uint8_t canvas_index, uint32_t addr,
-+ uint32_t stride, uint32_t height,
-+ unsigned int wrap,
-+ unsigned int blkmode,
-+ unsigned int endian)
-+{
-+ struct regmap *regmap = canvas.regmap_dmc;
-+ u32 val;
-+
-+ mutex_lock(&canvas.lock);
-+
-+ if (!canvas.used[canvas_index]) {
-+ dev_err(canvas.dev,
-+ "Trying to setup non allocated canvas %u\n",
-+ canvas_index);
-+ mutex_unlock(&canvas.lock);
-+ return -EINVAL;
-+ }
-+
-+ regmap_write(regmap, DMC_CAV_LUT_DATAL,
-+ ((addr + 7) >> 3) |
-+ (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
-+
-+ regmap_write(regmap, DMC_CAV_LUT_DATAH,
-+ ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
-+ CANVAS_WIDTH_HBIT) |
-+ (height << CANVAS_HEIGHT_BIT) |
-+ (wrap << 22) |
-+ (blkmode << CANVAS_BLKMODE_BIT) |
-+ (endian << 26));
-+
-+ regmap_write(regmap, DMC_CAV_LUT_ADDR,
-+ CANVAS_LUT_WR_EN | canvas_index);
-+
-+ /* Force a read-back to make sure everything is flushed. */
-+ regmap_read(regmap, DMC_CAV_LUT_DATAH, &val);
-+ mutex_unlock(&canvas.lock);
-+
-+ return 0;
-+}
-+
-+static int meson_canvas_alloc(uint8_t *canvas_index)
-+{
-+ int i;
-+
-+ mutex_lock(&canvas.lock);
-+ for (i = 0; i < NUM_CANVAS; ++i) {
-+ if (!canvas.used[i]) {
-+ canvas.used[i] = 1;
-+ mutex_unlock(&canvas.lock);
-+ *canvas_index = i;
-+ return 0;
-+ }
-+ }
-+ mutex_unlock(&canvas.lock);
-+ dev_err(canvas.dev, "No more canvas available\n");
-+
-+ return -ENODEV;
-+}
-+
-+static int meson_canvas_free(uint8_t canvas_index)
-+{
-+ mutex_lock(&canvas.lock);
-+ if (!canvas.used[canvas_index]) {
-+ dev_err(canvas.dev,
-+ "Trying to free unused canvas %u\n", canvas_index);
-+ mutex_unlock(&canvas.lock);
-+ return -EINVAL;
-+ }
-+ canvas.used[canvas_index] = 0;
-+ mutex_unlock(&canvas.lock);
-+
-+ return 0;
-+}
-+
-+static struct meson_canvas_platform_data canvas_platform_data = {
-+ .alloc = meson_canvas_alloc,
-+ .free = meson_canvas_free,
-+ .setup = meson_canvas_setup,
-+};
-+
-+static int meson_canvas_probe(struct platform_device *pdev)
-+{
-+ struct regmap *regmap_dmc;
-+ struct device *dev;
-+
-+ dev = &pdev->dev;
-+
-+ regmap_dmc = syscon_node_to_regmap(of_get_parent(dev->of_node));
-+ if (IS_ERR(regmap_dmc)) {
-+ dev_err(&pdev->dev, "failed to get DMC regmap\n");
-+ return PTR_ERR(regmap_dmc);
-+ }
-+
-+ canvas.dev = dev;
-+ canvas.regmap_dmc = regmap_dmc;
-+ mutex_init(&canvas.lock);
-+
-+ dev->platform_data = &canvas_platform_data;
-+
-+ return 0;
-+}
-+
-+static int meson_canvas_remove(struct platform_device *pdev)
-+{
-+ mutex_destroy(&canvas.lock);
-+ return 0;
-+}
-+
-+static const struct of_device_id canvas_dt_match[] = {
-+ { .compatible = "amlogic,meson-canvas" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, canvas_dt_match);
-+
-+static struct platform_driver meson_canvas_driver = {
-+ .probe = meson_canvas_probe,
-+ .remove = meson_canvas_remove,
-+ .driver = {
-+ .name = "meson-canvas",
-+ .of_match_table = canvas_dt_match,
-+ },
-+};
-+module_platform_driver(meson_canvas_driver);
-+
-+MODULE_ALIAS("platform:meson-canvas");
-+MODULE_DESCRIPTION("AMLogic Meson Canvas driver");
-+MODULE_AUTHOR("Maxime Jourdan <maxi.jourdan@wanadoo.fr>");
-+MODULE_LICENSE("GPL v2");
-diff --git a/include/linux/soc/amlogic/meson-canvas.h b/include/linux/soc/amlogic/meson-canvas.h
-new file mode 100644
-index 0000000..af9e241
---- /dev/null
-+++ b/include/linux/soc/amlogic/meson-canvas.h
-@@ -0,0 +1,37 @@
-+/*
-+ * Copyright (c) 2018 Maxime Jourdan
-+ * Author: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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 MESON_CANVAS_H
-+#define MESON_CANVAS_H
-+
-+#include <linux/kernel.h>
-+
-+#define MESON_CANVAS_WRAP_NONE 0x00
-+#define MESON_CANVAS_WRAP_X 0x01
-+#define MESON_CANVAS_WRAP_Y 0x02
-+
-+#define MESON_CANVAS_BLKMODE_LINEAR 0x00
-+#define MESON_CANVAS_BLKMODE_32x32 0x01
-+#define MESON_CANVAS_BLKMODE_64x64 0x02
-+
-+struct meson_canvas_platform_data {
-+ int (*alloc)(uint8_t *canvas_index);
-+ int (*free) (uint8_t canvas_index);
-+ int (*setup)(uint8_t canvas_index, uint32_t addr,
-+ uint32_t stride, uint32_t height,
-+ unsigned int wrap,
-+ unsigned int blkmode,
-+ unsigned int endian);
-+};
-+
-+#endif
diff --git a/testing/linux-amlogic/0022-drm-meson-Fixes-for-drm_crtc_vblank_on-off-support.patch b/testing/linux-amlogic/0022-drm-meson-Fixes-for-drm_crtc_vblank_on-off-support.patch
new file mode 100644
index 0000000000..a17be6bc38
--- /dev/null
+++ b/testing/linux-amlogic/0022-drm-meson-Fixes-for-drm_crtc_vblank_on-off-support.patch
@@ -0,0 +1,130 @@
+From 5a258bd31dab2dad8afcced8a7a85fa92e04edab Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 28 Feb 2018 16:07:18 +0100
+Subject: [PATCH] drm/meson: Fixes for drm_crtc_vblank_on/off support
+
+Since Linux 4.17, calls to drm_crtc_vblank_on/off are mandatory, and we get
+a warning when ctrc is disabled :
+ driver forgot to call drm_crtc_vblank_off()
+
+But, the vsync IRQ was not totally disabled due the transient hardware
+state, thus adding proper IRQ masking from the HHI system control registers.
+
+The last change fixes a race condition introduced by calling the added
+drm_crtc_vblank_on/off when an HPD event occurs from the HDMI connector,
+triggering a WARN_ON() in the _atomic_bebin() callback when the CRTC
+is disabled, thus also triggering a WARN_ON() in drm_vblank_put() :
+
+WARNING: CPU: 0 PID: 1185 at drivers/gpu/drm/meson/meson_crtc.c:157 meson_crtc_atomic_begin+0x78/0x80
+[...]
+Call trace:
+ meson_crtc_atomic_begin+0x78/0x80
+ drm_atomic_helper_commit_planes+0x140/0x218
+ drm_atomic_helper_commit_tail+0x38/0x80
+ commit_tail+0x7c/0x80
+ drm_atomic_helper_commit+0xdc/0x150
+ drm_atomic_commit+0x54/0x60
+ restore_fbdev_mode_atomic+0x198/0x238
+ restore_fbdev_mode+0x6c/0x1c0
+ drm_fb_helper_restore_fbdev_mode_unlocked+0x7c/0xf0
+ drm_fb_helper_set_par+0x34/0x60
+ drm_fb_helper_hotplug_event.part.28+0xb8/0xc8
+ drm_fbdev_client_hotplug+0xa4/0xe0
+ drm_client_dev_hotplug+0x90/0xe0
+ drm_kms_helper_hotplug_event+0x3c/0x48
+ drm_helper_hpd_irq_event+0x134/0x168
+ dw_hdmi_top_thread_irq+0x3c/0x50
+[...]
+WARNING: CPU: 0 PID: 1185 at drivers/gpu/drm/drm_vblank.c:1026 drm_vblank_put+0xb4/0xc8
+[...]
+ Call trace:
+ drm_vblank_put+0xb4/0xc8
+ drm_crtc_vblank_put+0x24/0x30
+ drm_atomic_helper_wait_for_vblanks.part.9+0x130/0x2b8
+ drm_atomic_helper_commit_tail+0x68/0x80
+[...]
+
+The issue is the vblank need to be enabled in any occurence of :
+- atomic_enable()
+- atomic_begin() and state->enable == true, which was not the case
+
+Moving the CRTC enable code to a common function and calling in one
+of these occurence solves this race condition and makes sure vblank
+is enabled in each call to _atomic_begin() from the HPD event leading
+to drm_atomic_helper_commit_planes().
+
+To Summarize :
+- Make sure that the CRTC code will calls the drm_crtc_vblank_on/off
+- *Really* mask the Vsync IRQ
+- Initialize and enable vblank at the first _atomic_begin()/_atomic_enable()
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_crtc.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index 6099997..f8e260b 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -46,6 +46,7 @@ struct meson_crtc {
+ struct drm_crtc base;
+ struct drm_pending_vblank_event *event;
+ struct meson_drm *priv;
++ bool enabled;
+ };
+ #define to_meson_crtc(x) container_of(x, struct meson_crtc, base)
+
+@@ -81,8 +82,7 @@ static const struct drm_crtc_funcs meson_crtc_funcs = {
+
+ };
+
+-static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+- struct drm_crtc_state *old_state)
++static void meson_crtc_enable(struct drm_crtc *crtc)
+ {
+ struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+ struct drm_crtc_state *crtc_state = crtc->state;
+@@ -106,6 +106,22 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
+ priv->io_base + _REG(VPP_MISC));
+
++ drm_crtc_vblank_on(crtc);
++
++ meson_crtc->enabled = true;
++}
++
++static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
++ struct drm_crtc_state *old_state)
++{
++ struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
++ struct meson_drm *priv = meson_crtc->priv;
++
++ DRM_DEBUG_DRIVER("\n");
++
++ if (!meson_crtc->enabled)
++ meson_crtc_enable(crtc);
++
+ priv->viu.osd1_enabled = true;
+
+ drm_crtc_vblank_on(crtc);
+@@ -139,6 +155,8 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+
+ crtc->state->event = NULL;
+ }
++
++ meson_crtc->enabled = false;
+ }
+
+ static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
+@@ -147,6 +165,9 @@ static void meson_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
+ unsigned long flags;
+
++ if (crtc->state->enable && !meson_crtc->enabled)
++ meson_crtc_enable(crtc);
++
+ if (crtc->state->event) {
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
diff --git a/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch b/testing/linux-amlogic/0022-drm-meson-Support-Overlay-plane-for-video-rendering.patch
index 6102e1cdc3..704b26c878 100644
--- a/testing/linux-amlogic/0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
+++ b/testing/linux-amlogic/0022-drm-meson-Support-Overlay-plane-for-video-rendering.patch
@@ -1,40 +1,122 @@
-From 5d0ab03232cdda74b9eb4ce283e98aa60c40b0c9 Mon Sep 17 00:00:00 2001
+From cfcbd82639be569a7ef6f71e991d7506b5e372ab Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 2 Aug 2018 10:00:01 +0200
-Subject: [PATCH] [WIP] drm/meson: Support Overlay plane for video rendering
+Subject: [PATCH] drm/meson: Support Overlay plane for video rendering
The Amlogic Meson GX SoCs support an Overlay plane behind the primary
-plan for video rendering.
-This Overlay plane support various YUV layouts and a non-alpha RGB32
-layout.
+plane for video rendering.
+
+This Overlay plane support various YUV layouts :
+- YUYV
+- NV12 / NV21
+- YUV444 / 422 / 420 / 411 / 410
+
+The scaler supports a wide range of scaling ratios, but for simplicity,
+plane atomic check limits the scaling from x5 to /5 in vertical and
+horizontal scaling.
+
+The z-order is fixed and always behind the primary plane and cannot be changed.
+
+The scaling parameter algorithm was taken from the Amlogic vendor kernel
+code and rewritten to match the atomic universal plane requirements.
+
+The video rendering using this overlay plane support has been tested using
+the new Kodi DRM-KMS Prime rendering path along the in-review V4L2 Mem2Mem
+Hardware Video Decoder up to 3840x2160 NV12 frames on various display modes.
+
---
drivers/gpu/drm/meson/Makefile | 2 +-
- drivers/gpu/drm/meson/meson_crtc.c | 170 ++++++++-
- drivers/gpu/drm/meson/meson_drv.c | 14 +
+ drivers/gpu/drm/meson/meson_canvas.c | 7 +-
+ drivers/gpu/drm/meson/meson_canvas.h | 11 +-
+ drivers/gpu/drm/meson/meson_crtc.c | 216 +++++++++++-
+ drivers/gpu/drm/meson/meson_drv.c | 29 +-
drivers/gpu/drm/meson/meson_drv.h | 52 +++
- drivers/gpu/drm/meson/meson_overlay.c | 595 ++++++++++++++++++++++++++++++++
+ drivers/gpu/drm/meson/meson_overlay.c | 586 ++++++++++++++++++++++++++++++++
drivers/gpu/drm/meson/meson_overlay.h | 14 +
drivers/gpu/drm/meson/meson_registers.h | 3 +
drivers/gpu/drm/meson/meson_viu.c | 15 +
drivers/gpu/drm/meson/meson_vpp.c | 44 ++-
- drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 8 +-
- 10 files changed, 910 insertions(+), 7 deletions(-)
+ 11 files changed, 971 insertions(+), 8 deletions(-)
create mode 100644 drivers/gpu/drm/meson/meson_overlay.c
create mode 100644 drivers/gpu/drm/meson/meson_overlay.h
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
-index bd67429..d4ea82f 100644
+index c5c4cc3..7709f2f 100644
--- a/drivers/gpu/drm/meson/Makefile
+++ b/drivers/gpu/drm/meson/Makefile
@@ -1,5 +1,5 @@
meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
--meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o
-+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o
+-meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
++meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o
obj-$(CONFIG_DRM_MESON) += meson-drm.o
obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
+diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c
+index 08f6073..5de11aa 100644
+--- a/drivers/gpu/drm/meson/meson_canvas.c
++++ b/drivers/gpu/drm/meson/meson_canvas.c
+@@ -39,6 +39,7 @@
+ #define CANVAS_WIDTH_HBIT 0
+ #define CANVAS_HEIGHT_BIT 9
+ #define CANVAS_BLKMODE_BIT 24
++#define CANVAS_ENDIAN_BIT 26
+ #define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
+ #define CANVAS_LUT_WR_EN (0x2 << 8)
+ #define CANVAS_LUT_RD_EN (0x1 << 8)
+@@ -47,7 +48,8 @@ void meson_canvas_setup(struct meson_drm *priv,
+ uint32_t canvas_index, uint32_t addr,
+ uint32_t stride, uint32_t height,
+ unsigned int wrap,
+- unsigned int blkmode)
++ unsigned int blkmode,
++ unsigned int endian)
+ {
+ unsigned int val;
+
+@@ -60,7 +62,8 @@ void meson_canvas_setup(struct meson_drm *priv,
+ CANVAS_WIDTH_HBIT) |
+ (height << CANVAS_HEIGHT_BIT) |
+ (wrap << 22) |
+- (blkmode << CANVAS_BLKMODE_BIT));
++ (blkmode << CANVAS_BLKMODE_BIT) |
++ (endian << CANVAS_ENDIAN_BIT));
+
+ regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
+ CANVAS_LUT_WR_EN | canvas_index);
+diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h
+index af1759d..85dbf26 100644
+--- a/drivers/gpu/drm/meson/meson_canvas.h
++++ b/drivers/gpu/drm/meson/meson_canvas.h
+@@ -23,6 +23,9 @@
+ #define __MESON_CANVAS_H
+
+ #define MESON_CANVAS_ID_OSD1 0x4e
++#define MESON_CANVAS_ID_VD1_0 0x60
++#define MESON_CANVAS_ID_VD1_1 0x61
++#define MESON_CANVAS_ID_VD1_2 0x62
+
+ /* Canvas configuration. */
+ #define MESON_CANVAS_WRAP_NONE 0x00
+@@ -33,10 +36,16 @@
+ #define MESON_CANVAS_BLKMODE_32x32 0x01
+ #define MESON_CANVAS_BLKMODE_64x64 0x02
+
++#define MESON_CANVAS_ENDIAN_SWAP16 0x1
++#define MESON_CANVAS_ENDIAN_SWAP32 0x3
++#define MESON_CANVAS_ENDIAN_SWAP64 0x7
++#define MESON_CANVAS_ENDIAN_SWAP128 0xf
++
+ void meson_canvas_setup(struct meson_drm *priv,
+ uint32_t canvas_index, uint32_t addr,
+ uint32_t stride, uint32_t height,
+ unsigned int wrap,
+- unsigned int blkmode);
++ unsigned int blkmode,
++ unsigned int endian);
+
+ #endif /* __MESON_CANVAS_H */
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
-index 7c8ad06..90c826b 100644
+index 8744244..1d9d22c 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -25,6 +25,7 @@
@@ -45,7 +127,7 @@ index 7c8ad06..90c826b 100644
#include <drm/drmP.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-@@ -97,6 +98,10 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
+@@ -98,6 +99,10 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
writel(crtc_state->mode.hdisplay,
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
@@ -56,7 +138,12 @@ index 7c8ad06..90c826b 100644
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
priv->io_base + _REG(VPP_MISC));
-@@ -118,8 +123,12 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+@@ -114,11 +119,17 @@ static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
+
+ drm_crtc_vblank_off(crtc);
+
++ DRM_DEBUG_DRIVER("\n");
++
priv->viu.osd1_enabled = false;
priv->viu.osd1_commit = false;
@@ -70,7 +157,7 @@ index 7c8ad06..90c826b 100644
priv->io_base + _REG(VPP_MISC));
if (crtc->state->event && !crtc->state->active) {
-@@ -154,6 +163,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
+@@ -153,6 +164,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
struct meson_drm *priv = meson_crtc->priv;
priv->viu.osd1_commit = true;
@@ -78,7 +165,16 @@ index 7c8ad06..90c826b 100644
}
static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
-@@ -210,6 +220,164 @@ void meson_crtc_irq(struct meson_drm *priv)
+@@ -206,7 +218,7 @@ void meson_crtc_irq(struct meson_drm *priv)
+ meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
+ priv->viu.osd1_addr, priv->viu.osd1_stride,
+ priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
+- MESON_CANVAS_BLKMODE_LINEAR);
++ MESON_CANVAS_BLKMODE_LINEAR, 0);
+
+ /* Enable OSD1 */
+ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
+@@ -215,6 +227,206 @@ void meson_crtc_irq(struct meson_drm *priv)
priv->viu.osd1_commit = false;
}
@@ -87,20 +183,61 @@ index 7c8ad06..90c826b 100644
+
+ switch (priv->viu.vd1_planes) {
+ case 3:
-+ priv->canvas_ops->setup(priv->canvas_id_vd1_2,
-+ priv->viu.vd1_addr2, priv->viu.vd1_stride2,
-+ priv->viu.vd1_height2, MESON_CANVAS_WRAP_NONE,
-+ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ if (priv->canvas)
++ meson_canvas_config(priv->canvas,
++ priv->canvas_id_vd1_2,
++ priv->viu.vd1_addr2,
++ priv->viu.vd1_stride2,
++ priv->viu.vd1_height2,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++ else
++ meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2,
++ priv->viu.vd1_addr2,
++ priv->viu.vd1_stride2,
++ priv->viu.vd1_height2,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++ /* fallthrough */
+ case 2:
-+ priv->canvas_ops->setup(priv->canvas_id_vd1_1,
-+ priv->viu.vd1_addr1, priv->viu.vd1_stride1,
-+ priv->viu.vd1_height1, MESON_CANVAS_WRAP_NONE,
-+ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ if (priv->canvas)
++ meson_canvas_config(priv->canvas,
++ priv->canvas_id_vd1_1,
++ priv->viu.vd1_addr1,
++ priv->viu.vd1_stride1,
++ priv->viu.vd1_height1,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++ else
++ meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1,
++ priv->viu.vd1_addr2,
++ priv->viu.vd1_stride2,
++ priv->viu.vd1_height2,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++ /* fallthrough */
+ case 1:
-+ priv->canvas_ops->setup(priv->canvas_id_vd1_0,
-+ priv->viu.vd1_addr0, priv->viu.vd1_stride0,
-+ priv->viu.vd1_height0, MESON_CANVAS_WRAP_NONE,
-+ MESON_CANVAS_BLKMODE_LINEAR, 7);
++ if (priv->canvas)
++ meson_canvas_config(priv->canvas,
++ priv->canvas_id_vd1_0,
++ priv->viu.vd1_addr0,
++ priv->viu.vd1_stride0,
++ priv->viu.vd1_height0,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++ else
++ meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0,
++ priv->viu.vd1_addr2,
++ priv->viu.vd1_stride2,
++ priv->viu.vd1_height2,
++ MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
+ };
+
+ writel_relaxed(priv->viu.vd1_if0_gen_reg,
@@ -192,13 +329,13 @@ index 7c8ad06..90c826b 100644
+ writel_relaxed(priv->viu.vpp_pic_in_height,
+ priv->io_base + _REG(VPP_PIC_IN_HEIGHT));
+ writel_relaxed(priv->viu.vpp_postblend_vd1_h_start_end,
-+ priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END));
++ priv->io_base + _REG(VPP_POSTBLEND_VD1_H_START_END));
+ writel_relaxed(priv->viu.vpp_blend_vd2_h_start_end,
-+ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
++ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END));
+ writel_relaxed(priv->viu.vpp_postblend_vd1_v_start_end,
-+ priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END));
++ priv->io_base + _REG(VPP_POSTBLEND_VD1_V_START_END));
+ writel_relaxed(priv->viu.vpp_blend_vd2_v_start_end,
-+ priv->io_base + _REG(VPP_BLEND_VD2_V_START_END));
++ priv->io_base + _REG(VPP_BLEND_VD2_V_START_END));
+ writel_relaxed(priv->viu.vpp_hsc_region12_startp,
+ priv->io_base + _REG(VPP_HSC_REGION12_STARTP));
+ writel_relaxed(priv->viu.vpp_hsc_region34_startp,
@@ -208,9 +345,9 @@ index 7c8ad06..90c826b 100644
+ writel_relaxed(priv->viu.vpp_hsc_start_phase_step,
+ priv->io_base + _REG(VPP_HSC_START_PHASE_STEP));
+ writel_relaxed(priv->viu.vpp_hsc_region1_phase_slope,
-+ priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE));
++ priv->io_base + _REG(VPP_HSC_REGION1_PHASE_SLOPE));
+ writel_relaxed(priv->viu.vpp_hsc_region3_phase_slope,
-+ priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE));
++ priv->io_base + _REG(VPP_HSC_REGION3_PHASE_SLOPE));
+ writel_relaxed(priv->viu.vpp_line_in_length,
+ priv->io_base + _REG(VPP_LINE_IN_LENGTH));
+ writel_relaxed(priv->viu.vpp_preblend_h_size,
@@ -229,12 +366,13 @@ index 7c8ad06..90c826b 100644
+ priv->io_base + _REG(VPP_VSC_PHASE_CTRL));
+ writel_relaxed(priv->viu.vpp_hsc_phase_ctrl,
+ priv->io_base + _REG(VPP_HSC_PHASE_CTRL));
-+ writel_relaxed(0x00000042,
-+ priv->io_base + _REG(VPP_SCALE_COEF_IDX));
++ writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX));
+
+ /* Enable VD1 */
-+ writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | VPP_COLOR_MNG_ENABLE,
-+ VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | VPP_COLOR_MNG_ENABLE,
++ writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
++ VPP_COLOR_MNG_ENABLE,
++ VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND |
++ VPP_COLOR_MNG_ENABLE,
+ priv->io_base + _REG(VPP_MISC));
+
+ priv->viu.vd1_commit = false;
@@ -244,10 +382,10 @@ index 7c8ad06..90c826b 100644
spin_lock_irqsave(&priv->drm->event_lock, flags);
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
-index de46833..2a002cc 100644
+index b39c38c..b55e03d 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
-@@ -42,6 +42,7 @@
+@@ -41,6 +41,7 @@
#include "meson_drv.h"
#include "meson_plane.h"
@@ -255,23 +393,32 @@ index de46833..2a002cc 100644
#include "meson_crtc.h"
#include "meson_venc_cvbs.h"
-@@ -241,6 +242,15 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
- ret = priv->canvas_ops->alloc(&priv->canvas_id_osd1);
- if (ret)
- goto free_drm;
-+ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_0);
-+ if (ret)
-+ goto free_drm;
-+ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_1);
-+ if (ret)
-+ goto free_drm;
-+ ret = priv->canvas_ops->alloc(&priv->canvas_id_vd1_2);
-+ if (ret)
-+ goto free_drm;
-
- priv->vsync_irq = platform_get_irq(pdev, 0);
+@@ -221,6 +222,24 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1);
+ if (ret)
+ goto free_drm;
++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0);
++ if (ret) {
++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
++ goto free_drm;
++ }
++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1);
++ if (ret) {
++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
++ goto free_drm;
++ }
++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2);
++ if (ret) {
++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
++ goto free_drm;
++ }
+ } else {
+ priv->canvas = NULL;
-@@ -278,6 +288,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
+@@ -281,6 +300,10 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret)
goto free_drm;
@@ -282,17 +429,31 @@ index de46833..2a002cc 100644
ret = meson_crtc_create(priv);
if (ret)
goto free_drm;
+@@ -324,8 +347,12 @@ static void meson_drv_unbind(struct device *dev)
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct meson_drm *priv = drm->dev_private;
+
+- if (priv->canvas)
++ if (priv->canvas) {
+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1);
++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_2);
++ }
+
+ drm_dev_unregister(drm);
+ drm_kms_helper_poll_fini(drm);
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
-index dfea959..e9305d7 100644
+index 728d0ca..c971557 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
-@@ -33,11 +33,15 @@ struct meson_drm {
+@@ -34,11 +34,15 @@ struct meson_drm {
- struct meson_canvas_platform_data *canvas_ops;
- uint8_t canvas_id_osd1;
-+ uint8_t canvas_id_vd1_0;
-+ uint8_t canvas_id_vd1_1;
-+ uint8_t canvas_id_vd1_2;
+ struct meson_canvas *canvas;
+ u8 canvas_id_osd1;
++ u8 canvas_id_vd1_0;
++ u8 canvas_id_vd1_1;
++ u8 canvas_id_vd1_2;
struct drm_device *drm;
struct drm_crtc *crtc;
@@ -302,7 +463,7 @@ index dfea959..e9305d7 100644
/* Components Data */
struct {
-@@ -49,6 +53,54 @@ struct meson_drm {
+@@ -50,6 +54,54 @@ struct meson_drm {
uint32_t osd1_addr;
uint32_t osd1_stride;
uint32_t osd1_height;
@@ -359,10 +520,10 @@ index dfea959..e9305d7 100644
struct {
diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c
new file mode 100644
-index 0000000..ea7261a
+index 0000000..9aebc5e
--- /dev/null
+++ b/drivers/gpu/drm/meson/meson_overlay.c
-@@ -0,0 +1,595 @@
+@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 BayLibre, SAS
@@ -386,6 +547,7 @@ index 0000000..ea7261a
+#include "meson_overlay.h"
+#include "meson_vpp.h"
+#include "meson_viu.h"
++#include "meson_canvas.h"
+#include "meson_registers.h"
+
+/* VD1_IF0_GEN_REG */
@@ -452,7 +614,7 @@ index 0000000..ea7261a
+#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
+
+static int meson_overlay_atomic_check(struct drm_plane *plane,
-+ struct drm_plane_state *state)
++ struct drm_plane_state *state)
+{
+ struct drm_crtc_state *crtc_state;
+
@@ -475,20 +637,19 @@ index 0000000..ea7261a
+ return value >> 16;
+}
+
-+static const uint8_t skip_tab[6] = {0x24, 0x04, 0x68, 0x48, 0x28, 0x08};
++static const uint8_t skip_tab[6] = {
++ 0x24, 0x04, 0x68, 0x48, 0x28, 0x08,
++};
+
-+static void meson_overlay_get_vertical_phase(unsigned ratio_y,
-+ int *phase,
-+ int *repeat,
-+ bool interlace)
++static void meson_overlay_get_vertical_phase(unsigned int ratio_y, int *phase,
++ int *repeat, bool interlace)
+{
+ int offset_in = 0;
+ int offset_out = 0;
+ int repeat_skip = 0;
+
-+ if (!interlace && ratio_y > (1 << 18)) {
++ if (!interlace && ratio_y > (1 << 18))
+ offset_out = (1 * ratio_y) >> 10;
-+ }
+
+ while ((offset_in + (4 << 8)) <= offset_out) {
+ repeat_skip++;
@@ -512,19 +673,19 @@ index 0000000..ea7261a
+ struct drm_plane *plane,
+ bool interlace_mode)
+{
-+ struct drm_plane_state *state = plane->state;
+ struct drm_crtc_state *crtc_state = priv->crtc->state;
+ int video_top, video_left, video_width, video_height;
-+ unsigned int crop_top, crop_left;
-+ unsigned int crtc_height, crtc_width;
++ struct drm_plane_state *state = plane->state;
+ unsigned int vd_start_lines, vd_end_lines;
+ unsigned int hd_start_lines, hd_end_lines;
++ unsigned int crtc_height, crtc_width;
+ unsigned int vsc_startp, vsc_endp;
+ unsigned int hsc_startp, hsc_endp;
-+ unsigned int ratio_x, ratio_y;
-+ unsigned int w_in, h_in;
++ unsigned int crop_top, crop_left;
+ int vphase, vphase_repeat_skip;
++ unsigned int ratio_x, ratio_y;
+ int temp_height, temp_width;
++ unsigned int w_in, h_in;
+ int temp, start, end;
+
+ if (!crtc_state) {
@@ -546,19 +707,15 @@ index 0000000..ea7261a
+ video_height = state->crtc_h;
+
+ DRM_DEBUG("crtc_width %d crtc_height %d interlace %d\n",
-+ crtc_width, crtc_height, interlace_mode);
++ crtc_width, crtc_height, interlace_mode);
+ DRM_DEBUG("w_in %d h_in %d crop_top %d crop_left %d\n",
-+ w_in, h_in, crop_top, crop_left);
++ w_in, h_in, crop_top, crop_left);
+ DRM_DEBUG("video top %d left %d width %d height %d\n",
-+ video_top, video_left, video_width, video_height);
++ video_top, video_left, video_width, video_height);
+
+ ratio_x = (w_in << 18) / video_width;
+ ratio_y = (h_in << 18) / video_height;
+
-+ /* TOFIX Interlace output */
-+ if (interlace_mode)
-+ ratio_y <<= 1;
-+
+ if (ratio_x * video_width < (w_in << 18))
+ ratio_x++;
+
@@ -571,7 +728,7 @@ index 0000000..ea7261a
+
+ /* Vertical */
+
-+ start = video_top + video_height / 2 - ((h_in << 17) / ratio_x);
++ start = video_top + video_height / 2 - ((h_in << 17) / ratio_y);
+ end = (h_in << 18) / ratio_y + start - 1;
+
+ if (video_top < 0 && start < 0)
@@ -582,11 +739,13 @@ index 0000000..ea7261a
+ vd_start_lines = 0;
+
+ if (video_top < 0)
-+ temp_height = min_t(unsigned int, (video_top + video_height - 1),
-+ (crtc_height - 1));
++ temp_height = min_t(unsigned int,
++ video_top + video_height - 1,
++ crtc_height - 1);
+ else
-+ temp_height = min_t(unsigned int, (video_top + video_height - 1),
-+ (crtc_height - 1)) - video_top + 1;
++ temp_height = min_t(unsigned int,
++ video_top + video_height - 1,
++ crtc_height - 1) - video_top + 1;
+
+ temp = vd_start_lines + (temp_height * ratio_y >> 18);
+ vd_end_lines = (temp <= (h_in - 1)) ? temp : (h_in - 1);
@@ -594,6 +753,11 @@ index 0000000..ea7261a
+ vd_start_lines += crop_left;
+ vd_end_lines += crop_left;
+
++ /*
++ * TOFIX: Input frames are handled and scaled like progressive frames,
++ * proper handling of interlaced field input frames need to be figured
++ * out using the proper framebuffer flags set by userspace.
++ */
+ if (interlace_mode) {
+ start >>= 1;
+ end >>= 1;
@@ -621,21 +785,21 @@ index 0000000..ea7261a
+ hd_start_lines = 0;
+
+ if (video_left < 0)
-+ temp_width = min_t(unsigned int, (video_left + video_width - 1),
-+ (crtc_width - 1));
++ temp_width = min_t(unsigned int,
++ video_left + video_width - 1,
++ crtc_width - 1);
+ else
-+ temp_width = min_t(unsigned int, (video_left + video_width - 1),
-+ (crtc_width - 1)) - video_left + 1;
++ temp_width = min_t(unsigned int,
++ video_left + video_width - 1,
++ crtc_width - 1) - video_left + 1;
+
+ temp = hd_start_lines + (temp_width * ratio_x >> 18);
+ hd_end_lines = (temp <= (w_in - 1)) ? temp : (w_in - 1);
+
+ priv->viu.vpp_line_in_length = hd_end_lines - hd_start_lines + 1;
-+ hsc_startp = max_t(int, start,
-+ max_t(int, 0, video_left));
-+ hsc_endp = min_t(int, end,
-+ min_t(int, crtc_width - 1,
-+ video_left + video_width - 1));
++ hsc_startp = max_t(int, start, max_t(int, 0, video_left));
++ hsc_endp = min_t(int, end, min_t(int, crtc_width - 1,
++ video_left + video_width - 1));
+
+ hd_start_lines += crop_top;
+ hd_end_lines += crop_top;
@@ -654,8 +818,9 @@ index 0000000..ea7261a
+ priv->viu.vd1_if0_chroma_x0 = VD_X_START(hd_start_lines >> 1) |
+ VD_X_END(hd_end_lines >> 1);
+
-+ priv->viu.viu_vd1_fmt_w = VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
-+ VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
++ priv->viu.viu_vd1_fmt_w =
++ VD_H_WIDTH(hd_end_lines - hd_start_lines + 1) |
++ VD_V_WIDTH(hd_end_lines/2 - hd_start_lines/2 + 1);
+
+ priv->viu.vd1_if0_luma_y0 = VD_Y_START(vd_start_lines) |
+ VD_Y_END(vd_end_lines);
@@ -671,7 +836,8 @@ index 0000000..ea7261a
+ VD_H_END(hd_end_lines);
+ priv->viu.vpp_hsc_region12_startp = VD_REGION13_END(0) |
+ VD_REGION24_START(hsc_startp);
-+ priv->viu.vpp_hsc_region34_startp = VD_REGION13_END(hsc_startp) |
++ priv->viu.vpp_hsc_region34_startp =
++ VD_REGION13_END(hsc_startp) |
+ VD_REGION24_START(hsc_endp - hsc_startp);
+ priv->viu.vpp_hsc_region4_endp = hsc_endp - hsc_startp;
+ priv->viu.vpp_hsc_start_phase_step = ratio_x << 6;
@@ -690,8 +856,8 @@ index 0000000..ea7261a
+
+ priv->viu.vpp_vsc_region12_startp = 0;
+ priv->viu.vpp_vsc_region34_startp =
-+ VD_REGION13_END(vsc_endp - vsc_startp) |
-+ VD_REGION24_START(vsc_endp - vsc_startp);
++ VD_REGION13_END(vsc_endp - vsc_startp) |
++ VD_REGION24_START(vsc_endp - vsc_startp);
+ priv->viu.vpp_vsc_region4_endp = vsc_endp - vsc_startp;
+ priv->viu.vpp_vsc_start_phase_step = ratio_y << 6;
+}
@@ -709,14 +875,15 @@ index 0000000..ea7261a
+
+ DRM_DEBUG_DRIVER("\n");
+
++ /* Fallback is canvas provider is not available */
++ if (!priv->canvas) {
++ priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0;
++ priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1;
++ priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2;
++ }
++
+ interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
-+ /*
-+ * Update Coordinates
-+ * Update Formats
-+ * Update Buffer
-+ * Enable Plane
-+ */
+ spin_lock_irqsave(&priv->drm->event_lock, flags);
+
+ priv->viu.vd1_if0_gen_reg = VD_URGENT_CHROMA |
@@ -728,17 +895,9 @@ index 0000000..ea7261a
+ /* Setup scaler params */
+ meson_overlay_setup_scaler_params(priv, plane, interlace_mode);
+
-+ //VD1_IF0_CANVAS1=0
-+ //VD1_IF0_CHROMA_X1=0
-+ //VD1_IF0_CHROMA_Y1=0
+ priv->viu.vd1_if0_repeat_loop = 0;
+ priv->viu.vd1_if0_luma0_rpt_pat = interlace_mode ? 8 : 0;
+ priv->viu.vd1_if0_chroma0_rpt_pat = interlace_mode ? 8 : 0;
-+ //VD1_IF0_LUMA1_RPT_PAT=0
-+ //VD1_IF0_CHROMA1_RPT_PAT=0
-+ //VD1_IF0_LUMA_PSEL=0
-+ //VD1_IF0_CHROMA_PSEL=0
-+ //VD1_IF0_DUMMY_PIXEL=?
+ priv->viu.vd1_range_map_y = 0;
+ priv->viu.vd1_range_map_cb = 0;
+ priv->viu.vd1_range_map_cr = 0;
@@ -748,15 +907,7 @@ index 0000000..ea7261a
+ priv->viu.viu_vd1_fmt_ctrl = 0;
+
+ switch (fb->format->format) {
-+ case DRM_FORMAT_RGB888:
-+ /* TOFIX enable RGB2YUV somewhere ! */
-+ priv->viu.vd1_if0_gen_reg |= VD_DEMUX_MODE_RGB |
-+ VD_BYTES_PER_PIXEL(2);
-+ priv->viu.vd1_if0_canvas0 =
-+ CANVAS_ADDR2(priv->canvas_id_vd1_0) |
-+ CANVAS_ADDR1(priv->canvas_id_vd1_0) |
-+ CANVAS_ADDR0(priv->canvas_id_vd1_0);
-+ break;
++ /* TOFIX DRM_FORMAT_RGB888 should be supported */
+ case DRM_FORMAT_YUYV:
+ priv->viu.vd1_if0_gen_reg |= VD_BYTES_PER_PIXEL(1);
+ priv->viu.vd1_if0_canvas0 =
@@ -854,6 +1005,7 @@ index 0000000..ea7261a
+ priv->viu.vd1_addr2,
+ priv->viu.vd1_stride2,
+ priv->viu.vd1_height2);
++ /* fallthrough */
+ case 2:
+ gem = drm_fb_cma_get_gem_obj(fb, 1);
+ priv->viu.vd1_addr1 = gem->paddr + fb->offsets[1];
@@ -865,6 +1017,7 @@ index 0000000..ea7261a
+ priv->viu.vd1_addr1,
+ priv->viu.vd1_stride1,
+ priv->viu.vd1_height1);
++ /* fallthrough */
+ case 1:
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+ priv->viu.vd1_addr0 = gem->paddr + fb->offsets[0];
@@ -917,7 +1070,6 @@ index 0000000..ea7261a
+};
+
+static const uint32_t supported_drm_formats[] = {
-+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
@@ -960,11 +1112,11 @@ index 0000000..ea7261a
+}
diff --git a/drivers/gpu/drm/meson/meson_overlay.h b/drivers/gpu/drm/meson/meson_overlay.h
new file mode 100644
-index 0000000..0fd63da
+index 0000000..dae24f5
--- /dev/null
+++ b/drivers/gpu/drm/meson/meson_overlay.h
@@ -0,0 +1,14 @@
-+// SPDX-License-Identifier: GPL-2.0+
++/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
@@ -1007,10 +1159,10 @@ index bca8714..5c7e02c 100644
#define VPP_FIFO_STATUS 0x1d28
#define VPP_SMOKE_CTRL 0x1d29
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
-index 5b48c4c..a423e7a 100644
+index 6bcfa52..2dffb98 100644
--- a/drivers/gpu/drm/meson/meson_viu.c
+++ b/drivers/gpu/drm/meson/meson_viu.c
-@@ -328,6 +328,21 @@ void meson_viu_init(struct meson_drm *priv)
+@@ -329,6 +329,21 @@ void meson_viu_init(struct meson_drm *priv)
0xff << OSD_REPLACE_SHIFT,
priv->io_base + _REG(VIU_OSD2_CTRL_STAT2));
@@ -1104,38 +1256,3 @@ index 27356f8..5dc24a9 100644
+ meson_vpp_write_vd_scaling_filter_coefs(priv, vpp_filter_coefs_bicubic,
+ true);
}
-diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
-index 6289965..05421d0 100644
---- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
-+++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c
-@@ -54,12 +54,12 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
- /* Power Down Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-- 0x2 << i, 0x3 << i);
-+ 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-- 0x2 << i, 0x3 << i);
-+ 0x3 << i, 0x3 << i);
- udelay(5);
- }
- for (i = 8; i < 16; i++) {
-@@ -108,13 +108,13 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
- /* Power Up Memories */
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-- 0x2 << i, 0);
-+ 0x3 << i, 0);
- udelay(5);
- }
-
- for (i = 0; i < 32; i += 2) {
- regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-- 0x2 << i, 0);
-+ 0x3 << i, 0);
- udelay(5);
- }
-
diff --git a/testing/linux-amlogic/0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch b/testing/linux-amlogic/0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch
deleted file mode 100644
index 6d449e3f9b..0000000000
--- a/testing/linux-amlogic/0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From c50c3a3d2cb0d563757a8b8b1a3e52acdf68910e Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Wed, 1 Aug 2018 20:51:26 +0200
-Subject: [PATCH] dt-bindings: soc: amlogic: add meson-canvas documentation
-
-DT bindings doc for amlogic,meson-canvas
-
-Signed-off-by: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
----
- .../bindings/soc/amlogic/amlogic,meson-canvas.txt | 36 ++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-canvas.txt
-
-diff --git a/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-canvas.txt b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-canvas.txt
-new file mode 100644
-index 0000000..96e1437
---- /dev/null
-+++ b/Documentation/devicetree/bindings/soc/amlogic/amlogic,meson-canvas.txt
-@@ -0,0 +1,36 @@
-+Amlogic Meson Canvas
-+================================
-+
-+A canvas is a collection of metadata that describes a pixel buffer.
-+Those metadata include: width, height, phyaddr, wrapping, block mode
-+and endianness.
-+
-+Many IPs within Amlogic SoCs rely on canvas indexes to read/write pixel data
-+rather than use the phy addresses directly. For instance, this is the case for
-+the video decoders and the display.
-+
-+Amlogic SoCs have 256 canvas.
-+
-+Device Tree Bindings:
-+---------------------
-+
-+Canvas Provider
-+--------------------------
-+
-+Required properties:
-+- compatible: "amlogic,meson-canvas"
-+
-+Parent node should have the following properties :
-+- compatible: "amlogic,meson-gx-dmc-sysctrl", "syscon", "simple-mfd"
-+- reg: base address and size of the DMC system control register space.
-+
-+Example:
-+
-+sysctrl_DMC: system-controller@0 {
-+ compatible = "amlogic,meson-gx-dmc-sysctrl", "syscon", "simple-mfd";
-+ reg = <0x0 0x0 0x0 0x1000>;
-+
-+ canvas: canvas-provider@0 {
-+ compatible = "amlogic,meson-canvas";
-+ };
-+};
diff --git a/testing/linux-amlogic/0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch b/testing/linux-amlogic/0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
deleted file mode 100644
index 6e97663fc1..0000000000
--- a/testing/linux-amlogic/0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 2c6aee7a14a22d1d042dc7ddafe72c44a4da501f Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Wed, 1 Aug 2018 20:51:27 +0200
-Subject: [PATCH] ARM64: dts: meson-gx: add dmcbus and canvas nodes.
-
-Wrap the canvas node in a syscon node.
-
-Signed-off-by: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
----
- arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 17 +++++++++++++++++
- 1 file changed, 17 insertions(+)
-
-diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-index 6b64b63..25e195f 100644
---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-@@ -458,6 +458,23 @@
- };
- };
-
-+ dmcbus: bus@c8838000 {
-+ compatible = "simple-bus";
-+ reg = <0x0 0xc8838000 0x0 0x1000>;
-+ #address-cells = <2>;
-+ #size-cells = <2>;
-+ ranges = <0x0 0x0 0x0 0xc8838000 0x0 0x1000>;
-+
-+ sysctrl_DMC: system-controller@0 {
-+ compatible = "amlogic,meson-gx-dmc-sysctrl", "syscon", "simple-mfd";
-+ reg = <0x0 0x0 0x0 0x1000>;
-+
-+ canvas: canvas-provider@0 {
-+ compatible = "amlogic,meson-canvas";
-+ };
-+ };
-+ };
-+
- hiubus: bus@c883c000 {
- compatible = "simple-bus";
- reg = <0x0 0xc883c000 0x0 0x2000>;
diff --git a/testing/linux-amlogic/0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch b/testing/linux-amlogic/0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch
new file mode 100644
index 0000000000..23d0bc366f
--- /dev/null
+++ b/testing/linux-amlogic/0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch
@@ -0,0 +1,124 @@
+From 90c2e40067b0591a1419472da186463f3f84613b Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Thu, 22 Nov 2018 17:27:20 +0100
+Subject: [PATCH] drm/meson: Fix an Alpha Primary Plane bug on Meson GXL/GXM
+ SoCs
+
+On the Amlogic GXL & GXM SoCs, a bug occurs in the OSD1 plane when
+alpha is used where the alpha is not aligned with the pixel content.
+
+The woraround Amlogic implemented is the reset the OSD1 plane hardware
+block each time the plane is updated, solving the issue.
+
+In the reset, we still need to save the content of 2 registers which
+depends on the status of the plane, in addition to reload the scaler
+conversion matrix in the same time.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_crtc.c | 1 +
+ drivers/gpu/drm/meson/meson_plane.c | 12 ++++++++++++
+ drivers/gpu/drm/meson/meson_viu.c | 27 +++++++++++++++++++++++++++
+ drivers/gpu/drm/meson/meson_viu.h | 1 +
+ 4 files changed, 41 insertions(+)
+
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index f8e260b..5312cce 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -202,6 +202,7 @@ void meson_crtc_irq(struct meson_drm *priv)
+
+ /* Update the OSD registers */
+ if (priv->viu.osd1_enabled && priv->viu.osd1_commit) {
++
+ writel_relaxed(priv->viu.osd1_ctrl_stat,
+ priv->io_base + _REG(VIU_OSD1_CTRL_STAT));
+ writel_relaxed(priv->viu.osd1_blk0_cfg[0],
+diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
+index 12a47b4..8372288 100644
+--- a/drivers/gpu/drm/meson/meson_plane.c
++++ b/drivers/gpu/drm/meson/meson_plane.c
+@@ -79,6 +79,7 @@
+ struct meson_plane {
+ struct drm_plane base;
+ struct meson_drm *priv;
++ bool enabled;
+ };
+ #define to_meson_plane(x) container_of(x, struct meson_plane, base)
+
+@@ -303,6 +304,15 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ priv->viu.osd1_stride = fb->pitches[0];
+ priv->viu.osd1_height = fb->height;
+
++ if (!meson_plane->enabled) {
++ /* Reset OSD1 at updates on GXL+ SoCs */
++ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
++ meson_viu_reset(priv);
++
++ meson_plane->enabled = true;
++ }
++
+ spin_unlock_irqrestore(&priv->drm->event_lock, flags);
+ }
+
+@@ -316,6 +326,8 @@ static void meson_plane_atomic_disable(struct drm_plane *plane,
+ writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0,
+ priv->io_base + _REG(VPP_MISC));
+
++ meson_plane->enabled = false;
++
+ }
+
+ static const struct drm_plane_helper_funcs meson_plane_helper_funcs = {
+diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
+index 2dffb98..a41dd6c 100644
+--- a/drivers/gpu/drm/meson/meson_viu.c
++++ b/drivers/gpu/drm/meson/meson_viu.c
+@@ -296,6 +296,33 @@ static void meson_viu_load_matrix(struct meson_drm *priv)
+ true);
+ }
+
++/* VIU OSD1 Reset as workaround for GXL+ Alpha OSD Bug */
++void meson_viu_reset(struct meson_drm *priv)
++{
++ uint32_t osd1_fifo_ctrl_stat, osd1_ctrl_stat2;
++
++ /* Save these 2 registers state */
++ osd1_fifo_ctrl_stat = readl_relaxed(
++ priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
++ osd1_ctrl_stat2 = readl_relaxed(
++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
++
++ /* Reset OSD1 */
++ writel_bits_relaxed(BIT(0), BIT(0),
++ priv->io_base + _REG(VIU_SW_RESET));
++ writel_bits_relaxed(BIT(0), 0,
++ priv->io_base + _REG(VIU_SW_RESET));
++
++ /* Rewrite these registers state lost in the reset */
++ writel_relaxed(osd1_fifo_ctrl_stat,
++ priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT));
++ writel_relaxed(osd1_ctrl_stat2,
++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2));
++
++ /* Reload the conversion matrix */
++ meson_viu_load_matrix(priv);
++}
++
+ void meson_viu_init(struct meson_drm *priv)
+ {
+ uint32_t reg;
+diff --git a/drivers/gpu/drm/meson/meson_viu.h b/drivers/gpu/drm/meson/meson_viu.h
+index 073b191..e4a6e2f 100644
+--- a/drivers/gpu/drm/meson/meson_viu.h
++++ b/drivers/gpu/drm/meson/meson_viu.h
+@@ -59,6 +59,7 @@
+ #define OSD_REPLACE_EN BIT(14)
+ #define OSD_REPLACE_SHIFT 6
+
++void meson_viu_reset(struct meson_drm *priv);
+ void meson_viu_init(struct meson_drm *priv);
+
+ #endif /* __MESON_VIU_H */
diff --git a/testing/linux-amlogic/0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch b/testing/linux-amlogic/0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch
new file mode 100644
index 0000000000..54b356de64
--- /dev/null
+++ b/testing/linux-amlogic/0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch
@@ -0,0 +1,198 @@
+From b92e7773bdb2d5c86091cbb2d03cc55ec6365115 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Mon, 29 Oct 2018 17:04:05 +0100
+Subject: [PATCH] drm/meson: move OSD scaler management into plane atomic
+ update
+
+In preparation to support the Primary Plane scaling, move the basic
+OSD Interlace-Only scaler setup code into the primary plane atomic
+update callback and handle the vsync scaler update like the overlay
+plane scaling registers update.
+
+---
+ drivers/gpu/drm/meson/meson_crtc.c | 35 ++++++++++++++++------------
+ drivers/gpu/drm/meson/meson_drv.h | 10 ++++++++
+ drivers/gpu/drm/meson/meson_plane.c | 39 ++++++++++++++++++++++++++++++-
+ drivers/gpu/drm/meson/meson_vpp.c | 46 -------------------------------------
+ 4 files changed, 68 insertions(+), 62 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
+index 1d9d22c..6099997 100644
+--- a/drivers/gpu/drm/meson/meson_crtc.c
++++ b/drivers/gpu/drm/meson/meson_crtc.c
+@@ -193,21 +193,26 @@ void meson_crtc_irq(struct meson_drm *priv)
+ priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W3));
+ writel_relaxed(priv->viu.osd1_blk0_cfg[4],
+ priv->io_base + _REG(VIU_OSD1_BLK0_CFG_W4));
+-
+- /* If output is interlace, make use of the Scaler */
+- if (priv->viu.osd1_interlace) {
+- struct drm_plane *plane = priv->primary_plane;
+- struct drm_plane_state *state = plane->state;
+- struct drm_rect dest = {
+- .x1 = state->crtc_x,
+- .y1 = state->crtc_y,
+- .x2 = state->crtc_x + state->crtc_w,
+- .y2 = state->crtc_y + state->crtc_h,
+- };
+-
+- meson_vpp_setup_interlace_vscaler_osd1(priv, &dest);
+- } else
+- meson_vpp_disable_interlace_vscaler_osd1(priv);
++ writel_relaxed(priv->viu.osd_sc_ctrl0,
++ priv->io_base + _REG(VPP_OSD_SC_CTRL0));
++ writel_relaxed(priv->viu.osd_sc_i_wh_m1,
++ priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
++ writel_relaxed(priv->viu.osd_sc_o_h_start_end,
++ priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
++ writel_relaxed(priv->viu.osd_sc_o_v_start_end,
++ priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
++ writel_relaxed(priv->viu.osd_sc_v_ini_phase,
++ priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
++ writel_relaxed(priv->viu.osd_sc_v_phase_step,
++ priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
++ writel_relaxed(priv->viu.osd_sc_h_ini_phase,
++ priv->io_base + _REG(VPP_OSD_HSC_INI_PHASE));
++ writel_relaxed(priv->viu.osd_sc_h_phase_step,
++ priv->io_base + _REG(VPP_OSD_HSC_PHASE_STEP));
++ writel_relaxed(priv->viu.osd_sc_h_ctrl0,
++ priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
++ writel_relaxed(priv->viu.osd_sc_v_ctrl0,
++ priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+
+ if (priv->canvas)
+ meson_canvas_config(priv->canvas, priv->canvas_id_osd1,
+diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
+index c971557..a955354 100644
+--- a/drivers/gpu/drm/meson/meson_drv.h
++++ b/drivers/gpu/drm/meson/meson_drv.h
+@@ -54,6 +54,16 @@ struct meson_drm {
+ uint32_t osd1_addr;
+ uint32_t osd1_stride;
+ uint32_t osd1_height;
++ uint32_t osd_sc_ctrl0;
++ uint32_t osd_sc_i_wh_m1;
++ uint32_t osd_sc_o_h_start_end;
++ uint32_t osd_sc_o_v_start_end;
++ uint32_t osd_sc_v_ini_phase;
++ uint32_t osd_sc_v_phase_step;
++ uint32_t osd_sc_h_ini_phase;
++ uint32_t osd_sc_h_phase_step;
++ uint32_t osd_sc_h_ctrl0;
++ uint32_t osd_sc_v_ctrl0;
+
+ bool vd1_enabled;
+ bool vd1_commit;
+diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
+index 51bec8e..f915a79 100644
+--- a/drivers/gpu/drm/meson/meson_plane.c
++++ b/drivers/gpu/drm/meson/meson_plane.c
+@@ -143,13 +143,50 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ break;
+ };
+
++ /*
++ * When the output is interlaced, the OSD must switch between
++ * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
++ * at each vsync.
++ * But the vertical scaler can provide such funtionnality if
++ * is configured for 2:1 scaling with interlace options enabled.
++ */
+ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
+ priv->viu.osd1_interlace = true;
+
+ dest.y1 /= 2;
+ dest.y2 /= 2;
+- } else
++
++ priv->viu.osd_sc_ctrl0 = BIT(3)| /* Enable scaler */
++ BIT(2); /* Select OSD1 */
++
++ /* 2:1 scaling */
++ priv->viu.osd_sc_i_wh_m1 = ((drm_rect_width(&dest) - 1) << 16) |
++ (drm_rect_height(&dest) - 1);
++ priv->viu.osd_sc_o_h_start_end = (dest.x1 << 16) | dest.x2;
++ priv->viu.osd_sc_o_v_start_end = (dest.y1 << 16) | dest.y2;
++
++ /* 2:1 vertical scaling values */
++ priv->viu.osd_sc_v_ini_phase = BIT(16);
++ priv->viu.osd_sc_v_phase_step = BIT(25);
++ priv->viu.osd_sc_v_ctrl0 =
++ (4 << 0) | /* osd_vsc_bank_length */
++ (4 << 3) | /* osd_vsc_top_ini_rcv_num0 */
++ (1 << 8) | /* osd_vsc_top_rpt_p0_num0 */
++ (6 << 11) | /* osd_vsc_bot_ini_rcv_num0 */
++ (2 << 16) | /* osd_vsc_bot_rpt_p0_num0 */
++ BIT(23) | /* osd_prog_interlace */
++ BIT(24); /* Enable vertical scaler */
++
++ /* No horizontal scaling */
++ priv->viu.osd_sc_h_ini_phase = 0;
++ priv->viu.osd_sc_h_phase_step = 0;
++ priv->viu.osd_sc_h_ctrl0 = 0;
++ } else {
+ priv->viu.osd1_interlace = false;
++ priv->viu.osd_sc_ctrl0 = 0;
++ priv->viu.osd_sc_h_ctrl0 = 0;
++ priv->viu.osd_sc_v_ctrl0 = 0;
++ }
+
+ /*
+ * The format of these registers is (x2 << 16 | x1),
+diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c
+index 5dc24a9..f9efb43 100644
+--- a/drivers/gpu/drm/meson/meson_vpp.c
++++ b/drivers/gpu/drm/meson/meson_vpp.c
+@@ -51,52 +51,6 @@ void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux)
+ writel(mux, priv->io_base + _REG(VPU_VIU_VENC_MUX_CTRL));
+ }
+
+-/*
+- * When the output is interlaced, the OSD must switch between
+- * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
+- * at each vsync.
+- * But the vertical scaler can provide such funtionnality if
+- * is configured for 2:1 scaling with interlace options enabled.
+- */
+-void meson_vpp_setup_interlace_vscaler_osd1(struct meson_drm *priv,
+- struct drm_rect *input)
+-{
+- writel_relaxed(BIT(3) /* Enable scaler */ |
+- BIT(2), /* Select OSD1 */
+- priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+-
+- writel_relaxed(((drm_rect_width(input) - 1) << 16) |
+- (drm_rect_height(input) - 1),
+- priv->io_base + _REG(VPP_OSD_SCI_WH_M1));
+- /* 2:1 scaling */
+- writel_relaxed(((input->x1) << 16) | (input->x2),
+- priv->io_base + _REG(VPP_OSD_SCO_H_START_END));
+- writel_relaxed(((input->y1 >> 1) << 16) | (input->y2 >> 1),
+- priv->io_base + _REG(VPP_OSD_SCO_V_START_END));
+-
+- /* 2:1 scaling values */
+- writel_relaxed(BIT(16), priv->io_base + _REG(VPP_OSD_VSC_INI_PHASE));
+- writel_relaxed(BIT(25), priv->io_base + _REG(VPP_OSD_VSC_PHASE_STEP));
+-
+- writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+-
+- writel_relaxed((4 << 0) /* osd_vsc_bank_length */ |
+- (4 << 3) /* osd_vsc_top_ini_rcv_num0 */ |
+- (1 << 8) /* osd_vsc_top_rpt_p0_num0 */ |
+- (6 << 11) /* osd_vsc_bot_ini_rcv_num0 */ |
+- (2 << 16) /* osd_vsc_bot_rpt_p0_num0 */ |
+- BIT(23) /* osd_prog_interlace */ |
+- BIT(24), /* Enable vertical scaler */
+- priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+-}
+-
+-void meson_vpp_disable_interlace_vscaler_osd1(struct meson_drm *priv)
+-{
+- writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0));
+- writel_relaxed(0, priv->io_base + _REG(VPP_OSD_VSC_CTRL0));
+- writel_relaxed(0, priv->io_base + _REG(VPP_OSD_HSC_CTRL0));
+-}
+-
+ static unsigned int vpp_filter_coefs_4point_bspline[] = {
+ 0x15561500, 0x14561600, 0x13561700, 0x12561800,
+ 0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
diff --git a/testing/linux-amlogic/0024-drm-meson-Add-primary-plane-scaling.patch b/testing/linux-amlogic/0024-drm-meson-Add-primary-plane-scaling.patch
new file mode 100644
index 0000000000..472355a105
--- /dev/null
+++ b/testing/linux-amlogic/0024-drm-meson-Add-primary-plane-scaling.patch
@@ -0,0 +1,285 @@
+From 7489078416fdb581625f99ec87b828c2e22794ee Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Tue, 30 Oct 2018 14:29:10 +0100
+Subject: [PATCH] drm/meson: Add primary plane scaling
+
+This patch adds support for the Primary Plane scaling.
+
+On the Amlogic GX SoCs, the primary plane is used as On-Screen-Display
+layer on top of video, and it's needed to keep the OSD layer to a lower
+size as the physical display size to :
+- lower the memory bandwidth
+- lower the OSD rendering
+- lower the memory usage
+
+This use-case is used when setting the display mode to 3840x2160 and the
+OSD layer is rendered using the GPU. In this case, the GXBB & GXL cannot
+work on more than 2000x2000 buffer, thus needing the OSD layer to be kept
+at 1920x1080 and upscaled to 3840x2160 in hardware.
+
+The primary plane atomic check still allow 1:1 scaling, allowing native
+3840x2160 if needed by user-space applications.
+
+---
+ drivers/gpu/drm/meson/meson_plane.c | 186 +++++++++++++++++++++++++++---------
+ 1 file changed, 141 insertions(+), 45 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
+index f915a79..12a47b4 100644
+--- a/drivers/gpu/drm/meson/meson_plane.c
++++ b/drivers/gpu/drm/meson/meson_plane.c
+@@ -24,6 +24,7 @@
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mutex.h>
++#include <linux/bitfield.h>
+ #include <linux/platform_device.h>
+ #include <drm/drmP.h>
+ #include <drm/drm_atomic.h>
+@@ -39,12 +40,50 @@
+ #include "meson_canvas.h"
+ #include "meson_registers.h"
+
++/* OSD_SCI_WH_M1 */
++#define SCI_WH_M1_W(w) FIELD_PREP(GENMASK(28, 16), w)
++#define SCI_WH_M1_H(h) FIELD_PREP(GENMASK(12, 0), h)
++
++/* OSD_SCO_H_START_END */
++/* OSD_SCO_V_START_END */
++#define SCO_HV_START(start) FIELD_PREP(GENMASK(27, 16), start)
++#define SCO_HV_END(end) FIELD_PREP(GENMASK(11, 0), end)
++
++/* OSD_SC_CTRL0 */
++#define SC_CTRL0_PATH_EN BIT(3)
++#define SC_CTRL0_SEL_OSD1 BIT(2)
++
++/* OSD_VSC_CTRL0 */
++#define VSC_BANK_LEN(value) FIELD_PREP(GENMASK(2, 0), value)
++#define VSC_TOP_INI_RCV_NUM(value) FIELD_PREP(GENMASK(6, 3), value)
++#define VSC_TOP_RPT_L0_NUM(value) FIELD_PREP(GENMASK(9, 8), value)
++#define VSC_BOT_INI_RCV_NUM(value) FIELD_PREP(GENMASK(14, 11), value)
++#define VSC_BOT_RPT_L0_NUM(value) FIELD_PREP(GENMASK(17, 16), value)
++#define VSC_PROG_INTERLACE BIT(23)
++#define VSC_VERTICAL_SCALER_EN BIT(24)
++
++/* OSD_VSC_INI_PHASE */
++#define VSC_INI_PHASE_BOT(bottom) FIELD_PREP(GENMASK(31, 16), bottom)
++#define VSC_INI_PHASE_TOP(top) FIELD_PREP(GENMASK(15, 0), top)
++
++/* OSD_HSC_CTRL0 */
++#define HSC_BANK_LENGTH(value) FIELD_PREP(GENMASK(2, 0), value)
++#define HSC_INI_RCV_NUM0(value) FIELD_PREP(GENMASK(6, 3), value)
++#define HSC_RPT_P0_NUM0(value) FIELD_PREP(GENMASK(9, 8), value)
++#define HSC_HORIZ_SCALER_EN BIT(22)
++
++/* VPP_OSD_VSC_PHASE_STEP */
++/* VPP_OSD_HSC_PHASE_STEP */
++#define SC_PHASE_STEP(value) FIELD_PREP(GENMASK(27, 0), value)
++
+ struct meson_plane {
+ struct drm_plane base;
+ struct meson_drm *priv;
+ };
+ #define to_meson_plane(x) container_of(x, struct meson_plane, base)
+
++#define FRAC_16_16(mult, div) (((mult) << 16) / (div))
++
+ static int meson_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+ {
+@@ -57,10 +96,15 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
++ /*
++ * Only allow :
++ * - Upscaling up to 5x, vertical and horizontal
++ * - Final coordinates must match crtc size
++ */
+ return drm_atomic_helper_check_plane_state(state, crtc_state,
++ FRAC_16_16(1, 5),
+ DRM_PLANE_HELPER_NO_SCALING,
+- DRM_PLANE_HELPER_NO_SCALING,
+- true, true);
++ false, true);
+ }
+
+ /* Takes a fixed 16.16 number and converts it to integer. */
+@@ -74,22 +118,19 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ {
+ struct meson_plane *meson_plane = to_meson_plane(plane);
+ struct drm_plane_state *state = plane->state;
+- struct drm_framebuffer *fb = state->fb;
++ struct drm_rect dest = drm_plane_state_dest(state);
+ struct meson_drm *priv = meson_plane->priv;
++ struct drm_framebuffer *fb = state->fb;
+ struct drm_gem_cma_object *gem;
+- struct drm_rect src = {
+- .x1 = (state->src_x),
+- .y1 = (state->src_y),
+- .x2 = (state->src_x + state->src_w),
+- .y2 = (state->src_y + state->src_h),
+- };
+- struct drm_rect dest = {
+- .x1 = state->crtc_x,
+- .y1 = state->crtc_y,
+- .x2 = state->crtc_x + state->crtc_w,
+- .y2 = state->crtc_y + state->crtc_h,
+- };
+ unsigned long flags;
++ int vsc_ini_rcv_num, vsc_ini_rpt_p0_num;
++ int vsc_bot_rcv_num, vsc_bot_rpt_p0_num;
++ int hsc_ini_rcv_num, hsc_ini_rpt_p0_num;
++ int hf_phase_step, vf_phase_step;
++ int src_w, src_h, dst_w, dst_h;
++ int bot_ini_phase;
++ int hf_bank_len;
++ int vf_bank_len;
+ u8 canvas_id_osd1;
+
+ /*
+@@ -143,6 +184,27 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ break;
+ };
+
++ /* Default scaler parameters */
++ vsc_bot_rcv_num = 0;
++ vsc_bot_rpt_p0_num = 0;
++ hf_bank_len = 4;
++ vf_bank_len = 4;
++
++ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
++ vsc_bot_rcv_num = 6;
++ vsc_bot_rpt_p0_num = 2;
++ }
++
++ hsc_ini_rcv_num = hf_bank_len;
++ vsc_ini_rcv_num = vf_bank_len;
++ hsc_ini_rpt_p0_num = (hf_bank_len / 2) - 1;
++ vsc_ini_rpt_p0_num = (vf_bank_len / 2) - 1;
++
++ src_w = fixed16_to_int(state->src_w);
++ src_h = fixed16_to_int(state->src_h);
++ dst_w = state->crtc_w;
++ dst_h = state->crtc_h;
++
+ /*
+ * When the output is interlaced, the OSD must switch between
+ * each field using the INTERLACE_SEL_ODD (0) of VIU_OSD1_BLK0_CFG_W0
+@@ -151,41 +213,73 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ * is configured for 2:1 scaling with interlace options enabled.
+ */
+ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) {
+- priv->viu.osd1_interlace = true;
+-
+ dest.y1 /= 2;
+ dest.y2 /= 2;
++ dst_h /= 2;
++ }
+
+- priv->viu.osd_sc_ctrl0 = BIT(3)| /* Enable scaler */
+- BIT(2); /* Select OSD1 */
++ hf_phase_step = ((src_w << 18) / dst_w) << 6;
++ vf_phase_step = (src_h << 20) / dst_h;
+
+- /* 2:1 scaling */
+- priv->viu.osd_sc_i_wh_m1 = ((drm_rect_width(&dest) - 1) << 16) |
+- (drm_rect_height(&dest) - 1);
+- priv->viu.osd_sc_o_h_start_end = (dest.x1 << 16) | dest.x2;
+- priv->viu.osd_sc_o_v_start_end = (dest.y1 << 16) | dest.y2;
++ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
++ bot_ini_phase = ((vf_phase_step / 2) >> 4);
++ else
++ bot_ini_phase = 0;
++
++ vf_phase_step = (vf_phase_step << 4);
++
++ /* In interlaced mode, scaler is always active */
++ if (src_h != dst_h || src_w != dst_w) {
++ priv->viu.osd_sc_i_wh_m1 = SCI_WH_M1_W(src_w - 1) |
++ SCI_WH_M1_H(src_h - 1);
++ priv->viu.osd_sc_o_h_start_end = SCO_HV_START(dest.x1) |
++ SCO_HV_END(dest.x2 - 1);
++ priv->viu.osd_sc_o_v_start_end = SCO_HV_START(dest.y1) |
++ SCO_HV_END(dest.y2 - 1);
++ /* Enable OSD Scaler */
++ priv->viu.osd_sc_ctrl0 = SC_CTRL0_PATH_EN | SC_CTRL0_SEL_OSD1;
++ } else {
++ priv->viu.osd_sc_i_wh_m1 = 0;
++ priv->viu.osd_sc_o_h_start_end = 0;
++ priv->viu.osd_sc_o_v_start_end = 0;
++ priv->viu.osd_sc_ctrl0 = 0;
++ }
+
+- /* 2:1 vertical scaling values */
+- priv->viu.osd_sc_v_ini_phase = BIT(16);
+- priv->viu.osd_sc_v_phase_step = BIT(25);
++ /* In interlaced mode, vertical scaler is always active */
++ if (src_h != dst_h) {
+ priv->viu.osd_sc_v_ctrl0 =
+- (4 << 0) | /* osd_vsc_bank_length */
+- (4 << 3) | /* osd_vsc_top_ini_rcv_num0 */
+- (1 << 8) | /* osd_vsc_top_rpt_p0_num0 */
+- (6 << 11) | /* osd_vsc_bot_ini_rcv_num0 */
+- (2 << 16) | /* osd_vsc_bot_rpt_p0_num0 */
+- BIT(23) | /* osd_prog_interlace */
+- BIT(24); /* Enable vertical scaler */
+-
+- /* No horizontal scaling */
++ VSC_BANK_LEN(vf_bank_len) |
++ VSC_TOP_INI_RCV_NUM(vsc_ini_rcv_num) |
++ VSC_TOP_RPT_L0_NUM(vsc_ini_rpt_p0_num) |
++ VSC_VERTICAL_SCALER_EN;
++
++ if (state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
++ priv->viu.osd_sc_v_ctrl0 |=
++ VSC_BOT_INI_RCV_NUM(vsc_bot_rcv_num) |
++ VSC_BOT_RPT_L0_NUM(vsc_bot_rpt_p0_num) |
++ VSC_PROG_INTERLACE;
++
++ priv->viu.osd_sc_v_phase_step = SC_PHASE_STEP(vf_phase_step);
++ priv->viu.osd_sc_v_ini_phase = VSC_INI_PHASE_BOT(bot_ini_phase);
++ } else {
++ priv->viu.osd_sc_v_ctrl0 = 0;
++ priv->viu.osd_sc_v_phase_step = 0;
++ priv->viu.osd_sc_v_ini_phase = 0;
++ }
++
++ /* Horizontal scaler is only used if width does not match */
++ if (src_w != dst_w) {
++ priv->viu.osd_sc_h_ctrl0 =
++ HSC_BANK_LENGTH(hf_bank_len) |
++ HSC_INI_RCV_NUM0(hsc_ini_rcv_num) |
++ HSC_RPT_P0_NUM0(hsc_ini_rpt_p0_num) |
++ HSC_HORIZ_SCALER_EN;
++ priv->viu.osd_sc_h_phase_step = SC_PHASE_STEP(hf_phase_step);
+ priv->viu.osd_sc_h_ini_phase = 0;
+- priv->viu.osd_sc_h_phase_step = 0;
+- priv->viu.osd_sc_h_ctrl0 = 0;
+ } else {
+- priv->viu.osd1_interlace = false;
+- priv->viu.osd_sc_ctrl0 = 0;
+ priv->viu.osd_sc_h_ctrl0 = 0;
+- priv->viu.osd_sc_v_ctrl0 = 0;
++ priv->viu.osd_sc_h_phase_step = 0;
++ priv->viu.osd_sc_h_ini_phase = 0;
+ }
+
+ /*
+@@ -193,10 +287,12 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
+ * where x2 is exclusive.
+ * e.g. +30x1920 would be (1919 << 16) | 30
+ */
+- priv->viu.osd1_blk0_cfg[1] = ((fixed16_to_int(src.x2) - 1) << 16) |
+- fixed16_to_int(src.x1);
+- priv->viu.osd1_blk0_cfg[2] = ((fixed16_to_int(src.y2) - 1) << 16) |
+- fixed16_to_int(src.y1);
++ priv->viu.osd1_blk0_cfg[1] =
++ ((fixed16_to_int(state->src.x2) - 1) << 16) |
++ fixed16_to_int(state->src.x1);
++ priv->viu.osd1_blk0_cfg[2] =
++ ((fixed16_to_int(state->src.y2) - 1) << 16) |
++ fixed16_to_int(state->src.y1);
+ priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1;
+ priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1;
+
diff --git a/testing/linux-amlogic/0024-drm-meson-convert-to-the-new-canvas-module.patch b/testing/linux-amlogic/0024-drm-meson-convert-to-the-new-canvas-module.patch
deleted file mode 100644
index dc8fdcb181..0000000000
--- a/testing/linux-amlogic/0024-drm-meson-convert-to-the-new-canvas-module.patch
+++ /dev/null
@@ -1,399 +0,0 @@
-From c71ba17b0625595a2c0268cb76b7032694550fb3 Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Wed, 1 Aug 2018 20:51:28 +0200
-Subject: [PATCH] drm/meson: convert to the new canvas module
-
-This removes the meson_canvas files within the meson/drm layer
-and makes use of the new canvas module that is referenced in the dts.
-
-Canvases can be used by different IPs and modules, and it is as such
-preferable to rely on a module that can safely dispatch canvases on
-demand.
-
-Signed-off-by: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
----
- .../bindings/display/amlogic,meson-vpu.txt | 9 +--
- arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 7 ++-
- drivers/gpu/drm/meson/Kconfig | 1 +
- drivers/gpu/drm/meson/Makefile | 2 +-
- drivers/gpu/drm/meson/meson_canvas.c | 70 ----------------------
- drivers/gpu/drm/meson/meson_canvas.h | 42 -------------
- drivers/gpu/drm/meson/meson_crtc.c | 5 +-
- drivers/gpu/drm/meson/meson_drv.c | 35 ++++++-----
- drivers/gpu/drm/meson/meson_drv.h | 5 +-
- drivers/gpu/drm/meson/meson_plane.c | 3 +-
- drivers/gpu/drm/meson/meson_viu.c | 1 -
- 11 files changed, 39 insertions(+), 141 deletions(-)
- delete mode 100644 drivers/gpu/drm/meson/meson_canvas.c
- delete mode 100644 drivers/gpu/drm/meson/meson_canvas.h
-
-diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
-index 057b813..60b6e13 100644
---- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
-+++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
-@@ -60,9 +60,9 @@ Required properties:
- - reg: base address and size of he following memory-mapped regions :
- - vpu
- - hhi
-- - dmc
- - reg-names: should contain the names of the previous memory regions
- - interrupts: should contain the VENC Vsync interrupt number
-+- amlogic,canvas: should point to a meson canvas provider node
-
- Optional properties:
- - power-domains: Optional phandle to associated power domain as described in
-@@ -98,13 +98,14 @@ tv-connector {
- vpu: vpu@d0100000 {
- compatible = "amlogic,meson-gxbb-vpu";
- reg = <0x0 0xd0100000 0x0 0x100000>,
-- <0x0 0xc883c000 0x0 0x1000>,
-- <0x0 0xc8838000 0x0 0x1000>;
-- reg-names = "vpu", "hhi", "dmc";
-+ <0x0 0xc883c000 0x0 0x1000>;
-+ reg-names = "vpu", "hhi";
- interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
- #address-cells = <1>;
- #size-cells = <0>;
-
-+ amlogic,canvas = <&canvas>;
-+
- /* CVBS VDAC output port */
- port@0 {
- reg = <0>;
-diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-index 25e195f..7296b4f 100644
---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-@@ -538,13 +538,14 @@
- vpu: vpu@d0100000 {
- compatible = "amlogic,meson-gx-vpu";
- reg = <0x0 0xd0100000 0x0 0x100000>,
-- <0x0 0xc883c000 0x0 0x1000>,
-- <0x0 0xc8838000 0x0 0x1000>;
-- reg-names = "vpu", "hhi", "dmc";
-+ <0x0 0xc883c000 0x0 0x1000>;
-+ reg-names = "vpu", "hhi";
- interrupts = <GIC_SPI 3 IRQ_TYPE_EDGE_RISING>;
- #address-cells = <1>;
- #size-cells = <0>;
-
-+ amlogic,canvas = <&canvas>;
-+
- /* CVBS VDAC output port */
- cvbs_vdac_port: port@0 {
- reg = <0>;
-diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
-index 02d400b..8929058 100644
---- a/drivers/gpu/drm/meson/Kconfig
-+++ b/drivers/gpu/drm/meson/Kconfig
-@@ -7,6 +7,7 @@ config DRM_MESON
- select DRM_GEM_CMA_HELPER
- select VIDEOMODE_HELPERS
- select REGMAP_MMIO
-+ select MESON_CANVAS
-
- config DRM_MESON_DW_HDMI
- tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
-diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
-index c5c4cc3..bd67429 100644
---- a/drivers/gpu/drm/meson/Makefile
-+++ b/drivers/gpu/drm/meson/Makefile
-@@ -1,5 +1,5 @@
- meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
--meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
-+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o
-
- obj-$(CONFIG_DRM_MESON) += meson-drm.o
- obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
-diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c
-deleted file mode 100644
-index 08f6073..0000000
---- a/drivers/gpu/drm/meson/meson_canvas.c
-+++ /dev/null
-@@ -1,70 +0,0 @@
--/*
-- * Copyright (C) 2016 BayLibre, SAS
-- * Author: Neil Armstrong <narmstrong@baylibre.com>
-- * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
-- * Copyright (C) 2014 Endless Mobile
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License as
-- * published by the Free Software Foundation; either version 2 of the
-- * License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful, but
-- * WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, see <http://www.gnu.org/licenses/>.
-- */
--
--#include <linux/kernel.h>
--#include <linux/module.h>
--#include "meson_drv.h"
--#include "meson_canvas.h"
--#include "meson_registers.h"
--
--/**
-- * DOC: Canvas
-- *
-- * CANVAS is a memory zone where physical memory frames information
-- * are stored for the VIU to scanout.
-- */
--
--/* DMC Registers */
--#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */
--#define CANVAS_WIDTH_LBIT 29
--#define CANVAS_WIDTH_LWID 3
--#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */
--#define CANVAS_WIDTH_HBIT 0
--#define CANVAS_HEIGHT_BIT 9
--#define CANVAS_BLKMODE_BIT 24
--#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
--#define CANVAS_LUT_WR_EN (0x2 << 8)
--#define CANVAS_LUT_RD_EN (0x1 << 8)
--
--void meson_canvas_setup(struct meson_drm *priv,
-- uint32_t canvas_index, uint32_t addr,
-- uint32_t stride, uint32_t height,
-- unsigned int wrap,
-- unsigned int blkmode)
--{
-- unsigned int val;
--
-- regmap_write(priv->dmc, DMC_CAV_LUT_DATAL,
-- (((addr + 7) >> 3)) |
-- (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
--
-- regmap_write(priv->dmc, DMC_CAV_LUT_DATAH,
-- ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
-- CANVAS_WIDTH_HBIT) |
-- (height << CANVAS_HEIGHT_BIT) |
-- (wrap << 22) |
-- (blkmode << CANVAS_BLKMODE_BIT));
--
-- regmap_write(priv->dmc, DMC_CAV_LUT_ADDR,
-- CANVAS_LUT_WR_EN | canvas_index);
--
-- /* Force a read-back to make sure everything is flushed. */
-- regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val);
--}
-diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h
-deleted file mode 100644
-index af1759d..0000000
---- a/drivers/gpu/drm/meson/meson_canvas.h
-+++ /dev/null
-@@ -1,42 +0,0 @@
--/*
-- * Copyright (C) 2016 BayLibre, SAS
-- * Author: Neil Armstrong <narmstrong@baylibre.com>
-- * Copyright (C) 2014 Endless Mobile
-- *
-- * This program is free software; you can redistribute it and/or
-- * modify it under the terms of the GNU General Public License as
-- * published by the Free Software Foundation; either version 2 of the
-- * License, or (at your option) any later version.
-- *
-- * This program is distributed in the hope that it will be useful, but
-- * WITHOUT ANY WARRANTY; without even the implied warranty of
-- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- * General Public License for more details.
-- *
-- * You should have received a copy of the GNU General Public License
-- * along with this program; if not, see <http://www.gnu.org/licenses/>.
-- */
--
--/* Canvas LUT Memory */
--
--#ifndef __MESON_CANVAS_H
--#define __MESON_CANVAS_H
--
--#define MESON_CANVAS_ID_OSD1 0x4e
--
--/* Canvas configuration. */
--#define MESON_CANVAS_WRAP_NONE 0x00
--#define MESON_CANVAS_WRAP_X 0x01
--#define MESON_CANVAS_WRAP_Y 0x02
--
--#define MESON_CANVAS_BLKMODE_LINEAR 0x00
--#define MESON_CANVAS_BLKMODE_32x32 0x01
--#define MESON_CANVAS_BLKMODE_64x64 0x02
--
--void meson_canvas_setup(struct meson_drm *priv,
-- uint32_t canvas_index, uint32_t addr,
-- uint32_t stride, uint32_t height,
-- unsigned int wrap,
-- unsigned int blkmode);
--
--#endif /* __MESON_CANVAS_H */
-diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
-index 4dd0df0..7c8ad06 100644
---- a/drivers/gpu/drm/meson/meson_crtc.c
-+++ b/drivers/gpu/drm/meson/meson_crtc.c
-@@ -36,7 +36,6 @@
- #include "meson_venc.h"
- #include "meson_vpp.h"
- #include "meson_viu.h"
--#include "meson_canvas.h"
- #include "meson_registers.h"
-
- /* CRTC definition */
-@@ -199,10 +198,10 @@ void meson_crtc_irq(struct meson_drm *priv)
- } else
- meson_vpp_disable_interlace_vscaler_osd1(priv);
-
-- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
-+ priv->canvas_ops->setup(priv->canvas_id_osd1,
- priv->viu.osd1_addr, priv->viu.osd1_stride,
- priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
-- MESON_CANVAS_BLKMODE_LINEAR);
-+ MESON_CANVAS_BLKMODE_LINEAR, 0);
-
- /* Enable OSD1 */
- writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
-diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
-index d344312..de46833 100644
---- a/drivers/gpu/drm/meson/meson_drv.c
-+++ b/drivers/gpu/drm/meson/meson_drv.c
-@@ -26,6 +26,7 @@
- #include <linux/platform_device.h>
- #include <linux/component.h>
- #include <linux/of_graph.h>
-+#include <linux/of_platform.h>
-
- #include <drm/drmP.h>
- #include <drm/drm_atomic.h>
-@@ -47,7 +48,6 @@
- #include "meson_vpp.h"
- #include "meson_viu.h"
- #include "meson_venc.h"
--#include "meson_canvas.h"
- #include "meson_registers.h"
-
- #define DRIVER_NAME "meson"
-@@ -165,6 +165,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
- struct meson_drm *priv;
- struct drm_device *drm;
- struct resource *res;
-+ struct device_node *canvas;
-+ struct platform_device *canvas_pdev;
- void __iomem *regs;
- int ret;
-
-@@ -211,31 +213,35 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
- priv->hhi = devm_regmap_init_mmio(dev, regs,
- &meson_regmap_config);
- if (IS_ERR(priv->hhi)) {
-- dev_err(&pdev->dev, "Couldn't create the HHI regmap\n");
-+ dev_err(dev, "Couldn't create the HHI regmap\n");
- ret = PTR_ERR(priv->hhi);
- goto free_drm;
- }
-
-- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
-- if (!res) {
-- ret = -EINVAL;
-+ canvas = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
-+ if (!canvas) {
-+ ret = -ENODEV;
- goto free_drm;
- }
-- /* Simply ioremap since it may be a shared register zone */
-- regs = devm_ioremap(dev, res->start, resource_size(res));
-- if (!regs) {
-- ret = -EADDRNOTAVAIL;
-+
-+ canvas_pdev = of_find_device_by_node(canvas);
-+ if (!canvas_pdev) {
-+ dev_err(dev, "Unable to find canvas pdev\n");
-+ ret = -ENODEV;
- goto free_drm;
- }
-
-- priv->dmc = devm_regmap_init_mmio(dev, regs,
-- &meson_regmap_config);
-- if (IS_ERR(priv->dmc)) {
-- dev_err(&pdev->dev, "Couldn't create the DMC regmap\n");
-- ret = PTR_ERR(priv->dmc);
-+ priv->canvas_ops = dev_get_platdata(&canvas_pdev->dev);
-+ if (!priv->canvas_ops) {
-+ dev_err(dev, "canvas pdata structure NULL\n");
-+ ret = -EINVAL;
- goto free_drm;
- }
-
-+ ret = priv->canvas_ops->alloc(&priv->canvas_id_osd1);
-+ if (ret)
-+ goto free_drm;
-+
- priv->vsync_irq = platform_get_irq(pdev, 0);
-
- ret = drm_vblank_init(drm, 1);
-@@ -315,6 +321,7 @@ static void meson_drv_unbind(struct device *dev)
- struct drm_device *drm = dev_get_drvdata(dev);
- struct meson_drm *priv = drm->dev_private;
-
-+ priv->canvas_ops->free(priv->canvas_id_osd1);
- drm_dev_unregister(drm);
- drm_kms_helper_poll_fini(drm);
- drm_fbdev_cma_fini(priv->fbdev);
-diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
-index 8450d6ac..dfea959 100644
---- a/drivers/gpu/drm/meson/meson_drv.h
-+++ b/drivers/gpu/drm/meson/meson_drv.h
-@@ -22,15 +22,18 @@
- #include <linux/platform_device.h>
- #include <linux/regmap.h>
- #include <linux/of.h>
-+#include <linux/soc/amlogic/meson-canvas.h>
- #include <drm/drmP.h>
-
- struct meson_drm {
- struct device *dev;
- void __iomem *io_base;
- struct regmap *hhi;
-- struct regmap *dmc;
- int vsync_irq;
-
-+ struct meson_canvas_platform_data *canvas_ops;
-+ uint8_t canvas_id_osd1;
-+
- struct drm_device *drm;
- struct drm_crtc *crtc;
- struct drm_fbdev_cma *fbdev;
-diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c
-index 12c80df..8745f92 100644
---- a/drivers/gpu/drm/meson/meson_plane.c
-+++ b/drivers/gpu/drm/meson/meson_plane.c
-@@ -36,7 +36,6 @@
- #include "meson_plane.h"
- #include "meson_vpp.h"
- #include "meson_viu.h"
--#include "meson_canvas.h"
- #include "meson_registers.h"
-
- struct meson_plane {
-@@ -105,7 +104,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
- OSD_BLK0_ENABLE;
-
- /* Set up BLK0 to point to the right canvas */
-- priv->viu.osd1_blk0_cfg[0] = ((MESON_CANVAS_ID_OSD1 << OSD_CANVAS_SEL) |
-+ priv->viu.osd1_blk0_cfg[0] = ((priv->canvas_id_osd1 << OSD_CANVAS_SEL) |
- OSD_ENDIANNESS_LE);
-
- /* On GXBB, Use the old non-HDR RGB2YUV converter */
-diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
-index 6bcfa52..5b48c4c 100644
---- a/drivers/gpu/drm/meson/meson_viu.c
-+++ b/drivers/gpu/drm/meson/meson_viu.c
-@@ -25,7 +25,6 @@
- #include "meson_viu.h"
- #include "meson_vpp.h"
- #include "meson_venc.h"
--#include "meson_canvas.h"
- #include "meson_registers.h"
-
- /**
diff --git a/testing/linux-amlogic/0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch b/testing/linux-amlogic/0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch
deleted file mode 100644
index 5967c19a07..0000000000
--- a/testing/linux-amlogic/0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch
+++ /dev/null
@@ -1,5906 +0,0 @@
-From ec4b3da71229c2ba3f56b62cfcab4b2d18eda4eb Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Thu, 26 Jul 2018 21:35:52 +0200
-Subject: [PATCH] media: meson: add v4l2 m2m video decoder driver
-
-Amlogic SoCs feature a powerful video decoder unit able to
-decode many formats, with a performance of usually up to 4k60.
-
-This is a driver for this IP that is based around the v4l2 m2m framework.
-
-It features decoding for:
-- MPEG 1/2/4, H.264, MJPEG, (partial) HEVC 8-bit
-
-Even though they are supported in hardware, it doesn't leverage support for:
-- HEVC 10-bit, VP9, VC1 (all those are in TODOs)
-
-The code was made in such a way to allow easy inclusion of those formats in the future.
-Supported SoCs are: GXBB (S905), GXL (S905X/W/D), GXM (S912)
-
-Specifically, two of the vdec units are enabled within this driver:
-
-- VDEC_1: can decode MPEG 1/2/4, H.264, MJPEG
-- VDEC_HEVC: can decode HEVC
-
-There is also a hardware bitstream parser (ESPARSER) that is handled here.
----
- drivers/media/platform/Kconfig | 10 +
- drivers/media/platform/meson/Makefile | 1 +
- drivers/media/platform/meson/vdec/Makefile | 7 +
- drivers/media/platform/meson/vdec/canvas.c | 69 +
- drivers/media/platform/meson/vdec/canvas.h | 42 +
- drivers/media/platform/meson/vdec/codec_h264.c | 376 ++++++
- drivers/media/platform/meson/vdec/codec_h264.h | 13 +
- drivers/media/platform/meson/vdec/codec_helpers.c | 45 +
- drivers/media/platform/meson/vdec/codec_helpers.h | 8 +
- drivers/media/platform/meson/vdec/codec_hevc.c | 1383 +++++++++++++++++++++
- drivers/media/platform/meson/vdec/codec_hevc.h | 13 +
- drivers/media/platform/meson/vdec/codec_mjpeg.c | 203 +++
- drivers/media/platform/meson/vdec/codec_mjpeg.h | 13 +
- drivers/media/platform/meson/vdec/codec_mpeg12.c | 183 +++
- drivers/media/platform/meson/vdec/codec_mpeg12.h | 13 +
- drivers/media/platform/meson/vdec/codec_mpeg4.c | 213 ++++
- drivers/media/platform/meson/vdec/codec_mpeg4.h | 13 +
- drivers/media/platform/meson/vdec/esparser.c | 320 +++++
- drivers/media/platform/meson/vdec/esparser.h | 16 +
- drivers/media/platform/meson/vdec/hevc_regs.h | 742 +++++++++++
- drivers/media/platform/meson/vdec/vdec.c | 1009 +++++++++++++++
- drivers/media/platform/meson/vdec/vdec.h | 152 +++
- drivers/media/platform/meson/vdec/vdec_1.c | 266 ++++
- drivers/media/platform/meson/vdec/vdec_1.h | 13 +
- drivers/media/platform/meson/vdec/vdec_hevc.c | 188 +++
- drivers/media/platform/meson/vdec/vdec_hevc.h | 22 +
- drivers/media/platform/meson/vdec/vdec_platform.c | 273 ++++
- drivers/media/platform/meson/vdec/vdec_platform.h | 29 +
- 28 files changed, 5635 insertions(+)
- create mode 100644 drivers/media/platform/meson/vdec/Makefile
- create mode 100644 drivers/media/platform/meson/vdec/canvas.c
- create mode 100644 drivers/media/platform/meson/vdec/canvas.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_h264.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_h264.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_helpers.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_helpers.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.h
- create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.c
- create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.h
- create mode 100644 drivers/media/platform/meson/vdec/esparser.c
- create mode 100644 drivers/media/platform/meson/vdec/esparser.h
- create mode 100644 drivers/media/platform/meson/vdec/hevc_regs.h
- create mode 100644 drivers/media/platform/meson/vdec/vdec.c
- create mode 100644 drivers/media/platform/meson/vdec/vdec.h
- create mode 100644 drivers/media/platform/meson/vdec/vdec_1.c
- create mode 100644 drivers/media/platform/meson/vdec/vdec_1.h
- create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.c
- create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.h
- create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.c
- create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.h
-
-diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
-index 2728376..42d600b 100644
---- a/drivers/media/platform/Kconfig
-+++ b/drivers/media/platform/Kconfig
-@@ -482,6 +482,16 @@ config VIDEO_QCOM_VENUS
- on various Qualcomm SoCs.
- To compile this driver as a module choose m here.
-
-+config VIDEO_AML_MESON_VDEC
-+ tristate "AMLogic video decoder driver"
-+ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
-+ depends on (ARCH_MESON) || COMPILE_TEST
-+ select VIDEOBUF2_DMA_CONTIG
-+ select V4L2_MEM2MEM_DEV
-+ ---help---
-+ Support for the video decoder found in gxbb/gxl/gxm chips.
-+ Can decode MPEG 1/2/4, H.264, MJPEG, HEVC 8-bit.
-+
- endif # V4L_MEM2MEM_DRIVERS
-
- # TI VIDEO PORT Helper Modules
-diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile
-index 597beb8..5c935c2 100644
---- a/drivers/media/platform/meson/Makefile
-+++ b/drivers/media/platform/meson/Makefile
-@@ -1 +1,2 @@
- obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o
-+obj-$(CONFIG_VIDEO_AML_MESON_VDEC) += vdec/
-diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
-new file mode 100644
-index 0000000..9f506bc
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/Makefile
-@@ -0,0 +1,7 @@
-+# SPDX-License-Identifier: GPL-2.0
-+# Makefile for AMLogic meson video decoder driver
-+
-+meson-vdec-objs += vdec.o vdec_1.o vdec_hevc.o esparser.o canvas.o codec_helpers.o codec_mpeg12.o codec_h264.o codec_hevc.o vdec_platform.o codec_mpeg4.o codec_mjpeg.o
-+
-+obj-$(CONFIG_VIDEO_AML_MESON_VDEC) += meson-vdec.o
-+
-diff --git a/drivers/media/platform/meson/vdec/canvas.c b/drivers/media/platform/meson/vdec/canvas.c
-new file mode 100644
-index 0000000..92a8cf7
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/canvas.c
-@@ -0,0 +1,69 @@
-+/*
-+ * Copyright (C) 2016 BayLibre, SAS
-+ * Author: Neil Armstrong <narmstrong@baylibre.com>
-+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
-+ * Copyright (C) 2014 Endless Mobile
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of the
-+ * License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <asm/io.h>
-+#include "canvas.h"
-+
-+/* XXX: There is already a canvas implementation in the DRM subsystem but it's
-+ * tied to it. This one is almost entirely copied from it.
-+ * We should have a generic canvas provider for meson.
-+ */
-+
-+/**
-+ * DOC: Canvas
-+ *
-+ * CANVAS is a memory zone where physical memory frames information
-+ * are stored for the VIU to scanout.
-+ */
-+
-+/* DMC Registers */
-+#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */
-+#define CANVAS_WIDTH_LBIT 29
-+#define CANVAS_WIDTH_LWID 3
-+#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */
-+#define CANVAS_WIDTH_HBIT 0
-+#define CANVAS_HEIGHT_BIT 9
-+#define CANVAS_BLKMODE_BIT 24
-+#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */
-+#define CANVAS_LUT_WR_EN (0x2 << 8)
-+#define CANVAS_LUT_RD_EN (0x1 << 8)
-+
-+void vdec_canvas_setup(void __iomem *dmc_base,
-+ uint32_t canvas_index, uint32_t addr,
-+ uint32_t stride, uint32_t height,
-+ unsigned int wrap,
-+ unsigned int blkmode)
-+{
-+ writel_relaxed((((addr + 7) >> 3)) |
-+ (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT), dmc_base + DMC_CAV_LUT_DATAL);
-+
-+ writel_relaxed(((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
-+ CANVAS_WIDTH_HBIT) |
-+ (height << CANVAS_HEIGHT_BIT) |
-+ (wrap << 22) |
-+ (blkmode << CANVAS_BLKMODE_BIT) | (7 << 26), dmc_base + DMC_CAV_LUT_DATAH);
-+
-+ writel_relaxed(CANVAS_LUT_WR_EN | canvas_index, dmc_base + DMC_CAV_LUT_ADDR);
-+
-+ /* Force a read-back to make sure everything is flushed. */
-+ readl_relaxed(dmc_base + DMC_CAV_LUT_DATAH);
-+}
-diff --git a/drivers/media/platform/meson/vdec/canvas.h b/drivers/media/platform/meson/vdec/canvas.h
-new file mode 100644
-index 0000000..b8b5409
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/canvas.h
-@@ -0,0 +1,42 @@
-+/*
-+ * Copyright (C) 2016 BayLibre, SAS
-+ * Author: Neil Armstrong <narmstrong@baylibre.com>
-+ * Copyright (C) 2014 Endless Mobile
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License as
-+ * published by the Free Software Foundation; either version 2 of the
-+ * License, or (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful, but
-+ * WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
-+ */
-+
-+/* Canvas LUT Memory */
-+
-+#ifndef __MESON_CANVAS_H
-+#define __MESON_CANVAS_H
-+
-+#define MESON_CANVAS_ID_OSD1 0x4e
-+
-+/* Canvas configuration. */
-+#define MESON_CANVAS_WRAP_NONE 0x00
-+#define MESON_CANVAS_WRAP_X 0x01
-+#define MESON_CANVAS_WRAP_Y 0x02
-+
-+#define MESON_CANVAS_BLKMODE_LINEAR 0x00
-+#define MESON_CANVAS_BLKMODE_32x32 0x01
-+#define MESON_CANVAS_BLKMODE_64x64 0x02
-+
-+void vdec_canvas_setup(void __iomem *dmc_base,
-+ uint32_t canvas_index, uint32_t addr,
-+ uint32_t stride, uint32_t height,
-+ unsigned int wrap,
-+ unsigned int blkmode);
-+
-+#endif /* __MESON_CANVAS_H */
-diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c
-new file mode 100644
-index 0000000..97621cd
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_h264.c
-@@ -0,0 +1,376 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_h264.h"
-+#include "codec_helpers.h"
-+#include "canvas.h"
-+
-+#define SIZE_EXT_FW (SZ_1K * 20)
-+#define SIZE_WORKSPACE 0x1ee000
-+#define SIZE_SEI (SZ_1K * 8)
-+
-+/* Offset added by the firmware which must be substracted
-+ * from the workspace paddr
-+ */
-+#define DEF_BUF_START_ADDR 0x1000000
-+
-+/* DOS registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define LMEM_DMA_CTRL 0x0d40
-+
-+#define PSCALE_CTRL 0x2444
-+
-+#define MDEC_PIC_DC_CTRL 0x2638
-+#define ANC0_CANVAS_ADDR 0x2640
-+#define MDEC_PIC_DC_THRESH 0x26e0
-+
-+#define AV_SCRATCH_0 0x2700
-+#define AV_SCRATCH_1 0x2704
-+#define AV_SCRATCH_2 0x2708
-+#define AV_SCRATCH_3 0x270c
-+#define AV_SCRATCH_4 0x2710
-+#define AV_SCRATCH_5 0x2714
-+#define AV_SCRATCH_6 0x2718
-+#define AV_SCRATCH_7 0x271c
-+#define AV_SCRATCH_8 0x2720
-+#define AV_SCRATCH_9 0x2724
-+#define AV_SCRATCH_D 0x2734
-+#define AV_SCRATCH_F 0x273c
-+#define AV_SCRATCH_G 0x2740
-+#define AV_SCRATCH_H 0x2744
-+#define AV_SCRATCH_I 0x2748
-+#define AV_SCRATCH_J 0x274c
-+ #define SEI_DATA_READY BIT(15)
-+
-+#define POWER_CTL_VLD 0x3020
-+
-+#define DCAC_DMA_CTRL 0x3848
-+
-+#define DOS_SW_RESET0 0xfc00
-+
-+struct codec_h264 {
-+ /* H.264 decoder requires an extended firmware loaded in contiguous RAM */
-+ void *ext_fw_vaddr;
-+ dma_addr_t ext_fw_paddr;
-+
-+ /* Buffer for the H.264 Workspace */
-+ void *workspace_vaddr;
-+ dma_addr_t workspace_paddr;
-+
-+ /* Buffer for the H.264 references MV */
-+ void *ref_vaddr;
-+ dma_addr_t ref_paddr;
-+ u32 ref_size;
-+
-+ /* Buffer for parsed SEI data ; > M8 ? */
-+ void *sei_vaddr;
-+ dma_addr_t sei_paddr;
-+
-+ /* Housekeeping thread for recycling buffers into the hardware */
-+ struct task_struct *buffers_thread;
-+};
-+
-+static void codec_h264_recycle_first(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct vdec_buffer *tmp;
-+
-+ tmp = list_first_entry(&sess->bufs_recycle, struct vdec_buffer, list);
-+
-+ /* Tell the decoder he can recycle this buffer.
-+ * AV_SCRATCH_8 serves the same purpose.
-+ */
-+ if (!readl_relaxed(core->dos_base + AV_SCRATCH_7))
-+ writel_relaxed(tmp->index + 1, core->dos_base + AV_SCRATCH_7);
-+ else
-+ writel_relaxed(tmp->index + 1, core->dos_base + AV_SCRATCH_8);
-+
-+ dev_dbg(core->dev, "Buffer %d recycled\n", tmp->index);
-+
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+}
-+
-+static int codec_h264_buffers_thread(void *data)
-+{
-+ struct vdec_session *sess = data;
-+ struct vdec_core *core = sess->core;
-+
-+ while (!kthread_should_stop()) {
-+ mutex_lock(&sess->bufs_recycle_lock);
-+ while (!list_empty(&sess->bufs_recycle) &&
-+ (!readl_relaxed(core->dos_base + AV_SCRATCH_7) ||
-+ !readl_relaxed(core->dos_base + AV_SCRATCH_8)))
-+ {
-+ codec_h264_recycle_first(sess);
-+ }
-+ mutex_unlock(&sess->bufs_recycle_lock);
-+
-+ usleep_range(5000, 10000);
-+ }
-+
-+ return 0;
-+}
-+
-+static int codec_h264_start(struct vdec_session *sess) {
-+ u32 workspace_offset;
-+ struct vdec_core *core = sess->core;
-+ struct codec_h264 *h264 = sess->priv;
-+
-+ /* Allocate some memory for the H.264 decoder's state */
-+ h264->workspace_vaddr =
-+ dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &h264->workspace_paddr, GFP_KERNEL);
-+ if (!h264->workspace_vaddr) {
-+ dev_err(core->dev, "Failed to request H.264 Workspace\n");
-+ return -ENOMEM;
-+ }
-+
-+ /* Allocate some memory for the H.264 SEI dump */
-+ h264->sei_vaddr =
-+ dma_alloc_coherent(core->dev, SIZE_SEI, &h264->sei_paddr, GFP_KERNEL);
-+ if (!h264->sei_vaddr) {
-+ dev_err(core->dev, "Failed to request H.264 SEI\n");
-+ return -ENOMEM;
-+ }
-+
-+ while (readl_relaxed(core->dos_base + DCAC_DMA_CTRL) & 0x8000) { }
-+ while (readl_relaxed(core->dos_base + LMEM_DMA_CTRL) & 0x8000) { }
-+
-+ writel_relaxed((1<<7) | (1<<6) | (1<<4), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed((1<<7) | (1<<6) | (1<<4), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed((1<<9) | (1<<8), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + POWER_CTL_VLD) | (1 << 9) | (1 << 6), core->dos_base + POWER_CTL_VLD);
-+
-+ writel_relaxed(0, core->dos_base + PSCALE_CTRL);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_0);
-+
-+ workspace_offset = h264->workspace_paddr - DEF_BUF_START_ADDR;
-+ writel_relaxed(workspace_offset, core->dos_base + AV_SCRATCH_1);
-+ writel_relaxed(h264->ext_fw_paddr, core->dos_base + AV_SCRATCH_G);
-+ writel_relaxed(h264->sei_paddr - workspace_offset, core->dos_base + AV_SCRATCH_I);
-+
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_7);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_8);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_9);
-+
-+ /* Enable "error correction", don't know what it means */
-+ writel_relaxed((readl_relaxed(core->dos_base + AV_SCRATCH_F) & 0xffffffc3) | (1 << 4), core->dos_base + AV_SCRATCH_F);
-+
-+ /* Enable IRQ */
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_MASK);
-+
-+ /* Enable 2-plane output */
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) | (1 << 17), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ writel_relaxed(0x404038aa, core->dos_base + MDEC_PIC_DC_THRESH);
-+
-+ writel_relaxed((1<<12)|(1<<11), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ h264->buffers_thread = kthread_run(codec_h264_buffers_thread, sess, "buffers_done");
-+
-+ return 0;
-+}
-+
-+static int codec_h264_stop(struct vdec_session *sess)
-+{
-+ struct codec_h264 *h264 = sess->priv;
-+ struct vdec_core *core = sess->core;
-+
-+ kthread_stop(h264->buffers_thread);
-+
-+ if (h264->ext_fw_vaddr)
-+ dma_free_coherent(core->dev, SIZE_EXT_FW, h264->ext_fw_vaddr, h264->ext_fw_paddr);
-+
-+ if (h264->workspace_vaddr)
-+ dma_free_coherent(core->dev, SIZE_WORKSPACE, h264->workspace_vaddr, h264->workspace_paddr);
-+
-+ if (h264->ref_vaddr)
-+ dma_free_coherent(core->dev, h264->ref_size, h264->ref_vaddr, h264->ref_paddr);
-+
-+ if (h264->sei_vaddr)
-+ dma_free_coherent(core->dev, SIZE_SEI, h264->sei_vaddr, h264->sei_paddr);
-+
-+ kfree(h264);
-+ sess->priv = 0;
-+
-+ return 0;
-+}
-+
-+static int codec_h264_load_extended_firmware(struct vdec_session *sess, const u8 *data, u32 len)
-+{
-+ struct codec_h264 *h264;
-+ struct vdec_core *core = sess->core;
-+
-+ h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
-+ if (!h264)
-+ return -ENOMEM;
-+
-+ sess->priv = h264;
-+
-+ if (len != SIZE_EXT_FW)
-+ return -EINVAL;
-+
-+ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW, &h264->ext_fw_paddr, GFP_KERNEL);
-+ if (!h264->ext_fw_vaddr) {
-+ dev_err(core->dev, "Couldn't allocate memory for H.264 extended firmware\n");
-+ return -ENOMEM;
-+ }
-+
-+ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
-+
-+ return 0;
-+}
-+
-+/* Configure the H.264 decoder when the esparser finished parsing
-+ * the first buffer.
-+ */
-+static void codec_h264_set_param(struct vdec_session *sess) {
-+ u32 max_reference_size;
-+ u32 parsed_info, mb_width, mb_height, mb_total;
-+ u32 mb_mv_byte;
-+ u32 actual_dpb_size = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
-+ u32 max_dpb_size = 4;
-+ struct vdec_core *core = sess->core;
-+ struct codec_h264 *h264 = sess->priv;
-+
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_7);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_8);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_9);
-+
-+ parsed_info = readl_relaxed(core->dos_base + AV_SCRATCH_1);
-+
-+ /* Total number of 16x16 macroblocks */
-+ mb_total = (parsed_info >> 8) & 0xffff;
-+
-+ /* Size of Motion Vector per macroblock ? */
-+ mb_mv_byte = (parsed_info & 0x80000000) ? 24 : 96;
-+
-+ /* Number of macroblocks per line */
-+ mb_width = parsed_info & 0xff;
-+
-+ /* Number of macroblock lines */
-+ mb_height = mb_total / mb_width;
-+
-+ max_reference_size = (parsed_info >> 24) & 0x7f;
-+
-+ /* Align to a multiple of 4 macroblocks */
-+ mb_width = (mb_width + 3) & 0xfffffffc;
-+ mb_height = (mb_height + 3) & 0xfffffffc;
-+ mb_total = mb_width * mb_height;
-+
-+ codec_helper_set_canvases(sess, core->dos_base + ANC0_CANVAS_ADDR);
-+
-+ if (max_reference_size >= max_dpb_size)
-+ max_dpb_size = max_reference_size;
-+
-+ max_reference_size++;
-+
-+ h264->ref_size = mb_total * mb_mv_byte * max_reference_size;
-+ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size, &h264->ref_paddr, GFP_ATOMIC);
-+
-+ /* Address to store the references' MVs ? */
-+ writel_relaxed(h264->ref_paddr, core->dos_base + AV_SCRATCH_1);
-+
-+ /* End of ref MV */
-+ writel_relaxed(h264->ref_paddr + h264->ref_size, core->dos_base + AV_SCRATCH_4);
-+
-+ writel_relaxed((max_reference_size << 24) | (actual_dpb_size << 16) | (max_dpb_size << 8), core->dos_base + AV_SCRATCH_0);
-+}
-+
-+static void codec_h264_frames_ready(struct vdec_session *sess, u32 status)
-+{
-+ struct vdec_core *core = sess->core;
-+ int error_count;
-+ int error;
-+ int num_frames;
-+ int frame_status;
-+ unsigned int buffer_index;
-+ int i;
-+
-+ error_count = readl_relaxed(core->dos_base + AV_SCRATCH_D);
-+ num_frames = (status >> 8) & 0xff;
-+ if (error_count) {
-+ dev_warn(core->dev,
-+ "decoder error(s) happened, count %d\n", error_count);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_D);
-+ }
-+
-+ for (i = 0; i < num_frames; i++) {
-+ frame_status = readl_relaxed(core->dos_base + AV_SCRATCH_1 + i*4);
-+ buffer_index = frame_status & 0x1f;
-+ error = frame_status & 0x200;
-+
-+ /* A buffer decode error means it was decoded,
-+ * but part of the picture will have artifacts.
-+ * Typical reason is a temporarily corrupted bitstream
-+ */
-+ if (error)
-+ dev_dbg(core->dev, "Buffer %d decode error: %08X\n",
-+ buffer_index, error);
-+
-+ vdec_dst_buf_done_idx(sess, buffer_index);
-+ }
-+}
-+
-+static irqreturn_t codec_h264_threaded_isr(struct vdec_session *sess)
-+{
-+ u32 status;
-+ u8 cmd;
-+ struct vdec_core *core = sess->core;
-+
-+ status = readl_relaxed(core->dos_base + AV_SCRATCH_0);
-+ cmd = status & 0xff;
-+
-+ if (cmd == 1) {
-+ codec_h264_set_param(sess);
-+ } else if (cmd == 2) {
-+ codec_h264_frames_ready(sess, status);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_0);
-+ } else if (cmd != 0) {
-+ dev_warn(core->dev, "Unexpected cmd: %08X\n", cmd);
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_0);
-+ }
-+
-+ /* Decoder has some SEI data for us ; ignore */
-+ if (readl_relaxed(core->dos_base + AV_SCRATCH_J) & SEI_DATA_READY)
-+ writel_relaxed(0, core->dos_base + AV_SCRATCH_J);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t codec_h264_isr(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+
-+ return IRQ_WAKE_THREAD;
-+}
-+
-+struct vdec_codec_ops codec_h264_ops = {
-+ .start = codec_h264_start,
-+ .stop = codec_h264_stop,
-+ .load_extended_firmware = codec_h264_load_extended_firmware,
-+ .isr = codec_h264_isr,
-+ .threaded_isr = codec_h264_threaded_isr,
-+ .notify_dst_buffer = vdec_queue_recycle,
-+};
-+
-diff --git a/drivers/media/platform/meson/vdec/codec_h264.h b/drivers/media/platform/meson/vdec/codec_h264.h
-new file mode 100644
-index 0000000..1a15913
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_h264.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CODEC_H264_H_
-+#define __MESON_VDEC_CODEC_H264_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_codec_ops codec_h264_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_helpers.c b/drivers/media/platform/meson/vdec/codec_helpers.c
-new file mode 100644
-index 0000000..9906433
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_helpers.c
-@@ -0,0 +1,45 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_helpers.h"
-+#include "canvas.h"
-+
-+void codec_helper_set_canvases(struct vdec_session *sess, void *reg_base)
-+{
-+ struct vdec_core *core = sess->core;
-+ u32 width = ALIGN(sess->width, 64);
-+ u32 height = ALIGN(sess->height, 64);
-+ struct v4l2_m2m_buffer *buf;
-+
-+ /* Setup NV12 canvases for Decoded Picture Buffer (dpb)
-+ * Map them to the user buffers' planes
-+ */
-+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
-+ u32 buf_idx = buf->vb.vb2_buf.index;
-+ u32 cnv_y_idx = 128 + buf_idx * 2;
-+ u32 cnv_uv_idx = cnv_y_idx + 1;
-+ dma_addr_t buf_y_paddr =
-+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
-+ dma_addr_t buf_uv_paddr =
-+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
-+
-+ /* Y plane */
-+ vdec_canvas_setup(core->dmc_base, cnv_y_idx, buf_y_paddr,
-+ width, height, MESON_CANVAS_WRAP_NONE,
-+ MESON_CANVAS_BLKMODE_LINEAR);
-+
-+ /* U/V plane */
-+ vdec_canvas_setup(core->dmc_base, cnv_uv_idx, buf_uv_paddr,
-+ width, height / 2, MESON_CANVAS_WRAP_NONE,
-+ MESON_CANVAS_BLKMODE_LINEAR);
-+
-+ writel_relaxed(((cnv_uv_idx) << 16) |
-+ ((cnv_uv_idx) << 8) |
-+ (cnv_y_idx), reg_base + buf_idx * 4);
-+ }
-+}
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_helpers.h b/drivers/media/platform/meson/vdec/codec_helpers.h
-new file mode 100644
-index 0000000..0a778ba
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_helpers.h
-@@ -0,0 +1,8 @@
-+#ifndef __MESON_VDEC_CODEC_HELPERS_H_
-+#define __MESON_VDEC_CODEC_HELPERS_H_
-+
-+#include "vdec.h"
-+
-+void codec_helper_set_canvases(struct vdec_session *sess, void *reg_base);
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c
-new file mode 100644
-index 0000000..cf3e80a
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_hevc.c
-@@ -0,0 +1,1383 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_hevc.h"
-+#include "canvas.h"
-+#include "hevc_regs.h"
-+
-+/* DOS registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define DOS_SW_RESET3 0xfcd0
-+
-+/* HEVC reg mapping */
-+#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0
-+ #define HEVC_ACTION_DONE 0xff
-+#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1
-+#define HEVC_DECODE_INFO HEVC_ASSIST_SCRATCH_1
-+#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2
-+#define HEVC_VPS_BUFFER HEVC_ASSIST_SCRATCH_3
-+#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4
-+#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5
-+#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6
-+#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7
-+#define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7
-+#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8
-+#define HEVC_sao_mem_unit HEVC_ASSIST_SCRATCH_9
-+#define HEVC_SAO_ABV HEVC_ASSIST_SCRATCH_A
-+#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B
-+#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C
-+#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D
-+#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E
-+#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F
-+#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F
-+#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G
-+#define HEVC_DECODE_MODE2 HEVC_ASSIST_SCRATCH_H
-+#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I
-+#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J
-+ #define DECODE_MODE_SINGLE 0
-+#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K
-+#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L
-+#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_M
-+#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N
-+
-+#define HEVCD_MPP_ANC2AXI_TBL_DATA (0x3464 * 4)
-+
-+#define HEVC_CM_BODY_START_ADDR (0x3626 * 4)
-+#define HEVC_CM_BODY_LENGTH (0x3627 * 4)
-+#define HEVC_CM_HEADER_LENGTH (0x3629 * 4)
-+#define HEVC_CM_HEADER_OFFSET (0x362b * 4)
-+
-+#define AMRISC_MAIN_REQ 0x04
-+
-+/* HEVC Constants */
-+#define MAX_REF_PIC_NUM 24
-+#define MAX_REF_ACTIVE 16
-+#define MPRED_MV_BUF_SIZE 0x120000
-+#define MAX_TILE_COL_NUM 10
-+#define MAX_TILE_ROW_NUM 20
-+#define MAX_SLICE_NUM 800
-+#define INVALID_POC 0x80000000
-+
-+/* HEVC Workspace layout */
-+#define IPP_OFFSET 0x00
-+#define SAO_ABV_OFFSET (IPP_OFFSET + 0x4000)
-+#define SAO_VB_OFFSET (SAO_ABV_OFFSET + 0x30000)
-+#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + 0x30000)
-+#define VPS_OFFSET (SH_TM_RPS_OFFSET + 0x800)
-+#define SPS_OFFSET (VPS_OFFSET + 0x800)
-+#define PPS_OFFSET (SPS_OFFSET + 0x800)
-+#define SAO_UP_OFFSET (PPS_OFFSET + 0x2000)
-+#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + 0x800)
-+#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + 0x800)
-+#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + 0x800)
-+#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + 0x8000)
-+#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + 0x20000)
-+#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + 0x40000)
-+#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + 0x5000)
-+#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + 0x8000)
-+#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM)
-+#define LMEM_OFFSET (RPM_OFFSET + 0x100)
-+
-+/* ISR decode status */
-+#define HEVC_DEC_IDLE 0x0
-+#define HEVC_NAL_UNIT_VPS 0x1
-+#define HEVC_NAL_UNIT_SPS 0x2
-+#define HEVC_NAL_UNIT_PPS 0x3
-+#define HEVC_NAL_UNIT_CODED_SLICE_SEGMENT 0x4
-+#define HEVC_CODED_SLICE_SEGMENT_DAT 0x5
-+#define HEVC_SLICE_DECODING 0x6
-+#define HEVC_NAL_UNIT_SEI 0x7
-+#define HEVC_SLICE_SEGMENT_DONE 0x8
-+#define HEVC_NAL_SEARCH_DONE 0x9
-+#define HEVC_DECPIC_DATA_DONE 0xa
-+#define HEVC_DECPIC_DATA_ERROR 0xb
-+#define HEVC_SEI_DAT 0xc
-+#define HEVC_SEI_DAT_DONE 0xd
-+
-+/* RPM misc_flag0 */
-+#define PCM_LOOP_FILTER_DISABLED_FLAG_BIT 0
-+#define PCM_ENABLE_FLAG_BIT 1
-+#define LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT 2
-+#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 3
-+#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT 4
-+#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 5
-+#define DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT 6
-+#define SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 7
-+#define SLICE_SAO_LUMA_FLAG_BIT 8
-+#define SLICE_SAO_CHROMA_FLAG_BIT 9
-+#define SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 10
-+
-+/* Buffer sizes */
-+#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + 0xA00, 64 * SZ_1K)
-+#define SIZE_AUX (SZ_1K * 16)
-+#define SIZE_FRAME_MMU (0x1200 * 4)
-+#define RPM_SIZE 0x80
-+#define RPS_USED_BIT 14
-+
-+#define PARSER_CMD_SKIP_CFG_0 0x0000090b
-+#define PARSER_CMD_SKIP_CFG_1 0x1b14140f
-+#define PARSER_CMD_SKIP_CFG_2 0x001b1910
-+static const uint16_t parser_cmd[] = {
-+ 0x0401, 0x8401, 0x0800, 0x0402,
-+ 0x9002, 0x1423, 0x8CC3, 0x1423,
-+ 0x8804, 0x9825, 0x0800, 0x04FE,
-+ 0x8406, 0x8411, 0x1800, 0x8408,
-+ 0x8409, 0x8C2A, 0x9C2B, 0x1C00,
-+ 0x840F, 0x8407, 0x8000, 0x8408,
-+ 0x2000, 0xA800, 0x8410, 0x04DE,
-+ 0x840C, 0x840D, 0xAC00, 0xA000,
-+ 0x08C0, 0x08E0, 0xA40E, 0xFC00,
-+ 0x7C00
-+};
-+
-+/* Data received from the HW in this form, do not rearrange */
-+union rpm_param {
-+ struct {
-+ uint16_t data[RPM_SIZE];
-+ } l;
-+ struct {
-+ uint16_t CUR_RPS[MAX_REF_ACTIVE];
-+ uint16_t num_ref_idx_l0_active;
-+ uint16_t num_ref_idx_l1_active;
-+ uint16_t slice_type;
-+ uint16_t slice_temporal_mvp_enable_flag;
-+ uint16_t dependent_slice_segment_flag;
-+ uint16_t slice_segment_address;
-+ uint16_t num_title_rows_minus1;
-+ uint16_t pic_width_in_luma_samples;
-+ uint16_t pic_height_in_luma_samples;
-+ uint16_t log2_min_coding_block_size_minus3;
-+ uint16_t log2_diff_max_min_coding_block_size;
-+ uint16_t log2_max_pic_order_cnt_lsb_minus4;
-+ uint16_t POClsb;
-+ uint16_t collocated_from_l0_flag;
-+ uint16_t collocated_ref_idx;
-+ uint16_t log2_parallel_merge_level;
-+ uint16_t five_minus_max_num_merge_cand;
-+ uint16_t sps_num_reorder_pics_0;
-+ uint16_t modification_flag;
-+ uint16_t tiles_flags;
-+ uint16_t num_tile_columns_minus1;
-+ uint16_t num_tile_rows_minus1;
-+ uint16_t tile_width[8];
-+ uint16_t tile_height[8];
-+ uint16_t misc_flag0;
-+ uint16_t pps_beta_offset_div2;
-+ uint16_t pps_tc_offset_div2;
-+ uint16_t slice_beta_offset_div2;
-+ uint16_t slice_tc_offset_div2;
-+ uint16_t pps_cb_qp_offset;
-+ uint16_t pps_cr_qp_offset;
-+ uint16_t first_slice_segment_in_pic_flag;
-+ uint16_t m_temporalId;
-+ uint16_t m_nalUnitType;
-+ uint16_t vui_num_units_in_tick_hi;
-+ uint16_t vui_num_units_in_tick_lo;
-+ uint16_t vui_time_scale_hi;
-+ uint16_t vui_time_scale_lo;
-+ uint16_t bit_depth;
-+ uint16_t profile_etc;
-+ uint16_t sei_frame_field_info;
-+ uint16_t video_signal_type;
-+ uint16_t modification_list[0x20];
-+ uint16_t conformance_window_flag;
-+ uint16_t conf_win_left_offset;
-+ uint16_t conf_win_right_offset;
-+ uint16_t conf_win_top_offset;
-+ uint16_t conf_win_bottom_offset;
-+ uint16_t chroma_format_idc;
-+ uint16_t color_description;
-+ uint16_t aspect_ratio_idc;
-+ uint16_t sar_width;
-+ uint16_t sar_height;
-+ } p;
-+};
-+
-+enum nal_unit_type {
-+ NAL_UNIT_CODED_SLICE_BLA = 16,
-+ NAL_UNIT_CODED_SLICE_BLANT = 17,
-+ NAL_UNIT_CODED_SLICE_BLA_N_LP = 18,
-+ NAL_UNIT_CODED_SLICE_IDR = 19,
-+ NAL_UNIT_CODED_SLICE_IDR_N_LP = 20,
-+};
-+
-+enum slice_type {
-+ B_SLICE = 0,
-+ P_SLICE = 1,
-+ I_SLICE = 2,
-+};
-+
-+/* Refers to a frame being decoded */
-+struct hevc_frame {
-+ struct list_head list;
-+ struct vb2_v4l2_buffer *vbuf;
-+ u32 poc;
-+
-+ int referenced;
-+ u32 num_reorder_pic;
-+
-+ u32 cur_slice_idx;
-+ u32 cur_slice_type;
-+
-+ /* 2 lists (L0/L1) ; 800 slices ; 16 refs */
-+ u32 ref_poc_list[2][MAX_SLICE_NUM][16];
-+ u32 ref_num[2];
-+};
-+
-+struct hevc_tile {
-+ int width;
-+ int height;
-+ int start_cu_x;
-+ int start_cu_y;
-+
-+ dma_addr_t sao_vb_start_addr;
-+ dma_addr_t sao_abv_start_addr;
-+};
-+
-+struct codec_hevc {
-+ /* Current decoding status provided by the ISR */
-+ u32 dec_status;
-+
-+ /* Buffer for the HEVC Workspace */
-+ void *workspace_vaddr;
-+ dma_addr_t workspace_paddr;
-+
-+ /* AUX buffer */
-+ void *aux_vaddr;
-+ dma_addr_t aux_paddr;
-+
-+ /* Frame MMU buffer (>= GXL) ; unused for now */
-+ void *frame_mmu_vaddr;
-+ dma_addr_t frame_mmu_paddr;
-+
-+ /* Contains many information parsed from the bitstream */
-+ union rpm_param rpm_param;
-+
-+ /* Information computed from the RPM */
-+ u32 lcu_size; // Largest Coding Unit
-+ u32 lcu_x_num;
-+ u32 lcu_y_num;
-+ u32 lcu_total;
-+
-+ /* Current Frame being handled */
-+ struct hevc_frame *cur_frame;
-+ u32 curr_poc;
-+ /* Collocated Reference Picture */
-+ struct hevc_frame *col_frame;
-+ u32 col_poc;
-+
-+ /* All ref frames used by the HW at a given time */
-+ struct list_head ref_frames_list;
-+ u32 frames_num;
-+
-+ /* Resolution reported by the hardware */
-+ u32 width;
-+ u32 height;
-+
-+ u32 iPrevTid0POC;
-+ u32 slice_segment_addr;
-+ u32 slice_addr;
-+ u32 ldc_flag;
-+
-+ /* Tiles */
-+ u32 num_tile_col;
-+ u32 num_tile_row;
-+ struct hevc_tile m_tile[MAX_TILE_ROW_NUM][MAX_TILE_COL_NUM];
-+ u32 tile_start_lcu_x;
-+ u32 tile_start_lcu_y;
-+ u32 tile_width_lcu;
-+ u32 tile_height_lcu;
-+};
-+
-+static u32 codec_hevc_num_pending_bufs(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc;
-+ u32 ret;
-+
-+ mutex_lock(&sess->codec_lock);
-+ hevc = sess->priv;
-+ if (!hevc) {
-+ mutex_unlock(&sess->codec_lock);
-+ return 0;
-+ }
-+
-+ ret = hevc->frames_num;
-+ mutex_unlock(&sess->codec_lock);
-+
-+ return ret;
-+}
-+
-+/* Update the L0 and L1 reference lists for a given frame */
-+static void codec_hevc_update_frame_refs(struct vdec_session *sess, struct hevc_frame *frame)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *params = &hevc->rpm_param;
-+ int i;
-+ int num_neg = 0;
-+ int num_pos = 0;
-+ int total_num;
-+ int num_ref_idx_l0_active =
-+ (params->p.num_ref_idx_l0_active > MAX_REF_ACTIVE) ?
-+ MAX_REF_ACTIVE : params->p.num_ref_idx_l0_active;
-+ int num_ref_idx_l1_active =
-+ (params->p.num_ref_idx_l1_active > MAX_REF_ACTIVE) ?
-+ MAX_REF_ACTIVE : params->p.num_ref_idx_l1_active;
-+ int ref_picset0[16] = { 0 };
-+ int ref_picset1[16] = { 0 };
-+
-+ for (i = 0; i < 16; i++) {
-+ frame->ref_poc_list[0][frame->cur_slice_idx][i] = 0;
-+ frame->ref_poc_list[1][frame->cur_slice_idx][i] = 0;
-+ }
-+
-+ for (i = 0; i < 16; i++) {
-+ u16 cur_rps = params->p.CUR_RPS[i];
-+ int delt = cur_rps & ((1 << (RPS_USED_BIT - 1)) - 1);
-+
-+ if (cur_rps & 0x8000)
-+ break;
-+
-+ if (!((cur_rps >> RPS_USED_BIT) & 1))
-+ continue;
-+
-+ if ((cur_rps >> (RPS_USED_BIT - 1)) & 1) {
-+ ref_picset0[num_neg] =
-+ frame->poc - ((1 << (RPS_USED_BIT - 1)) - delt);
-+ num_neg++;
-+ } else {
-+ ref_picset1[num_pos] = frame->poc + delt;
-+ num_pos++;
-+ }
-+ }
-+
-+ total_num = num_neg + num_pos;
-+
-+ if (total_num <= 0)
-+ goto end;
-+
-+ for (i = 0; i < num_ref_idx_l0_active; i++) {
-+ int cIdx;
-+ if (params->p.modification_flag & 0x1)
-+ cIdx = params->p.modification_list[i];
-+ else
-+ cIdx = i % total_num;
-+
-+ frame->ref_poc_list[0][frame->cur_slice_idx][i] =
-+ cIdx >= num_neg ? ref_picset1[cIdx - num_neg] :
-+ ref_picset0[cIdx];
-+ }
-+
-+ if (params->p.slice_type != B_SLICE)
-+ goto end;
-+
-+ if (params->p.modification_flag & 0x2) {
-+ for (i = 0; i < num_ref_idx_l1_active; i++) {
-+ int cIdx;
-+ if (params->p.modification_flag & 0x1)
-+ cIdx =
-+ params->p.modification_list[num_ref_idx_l0_active + i];
-+ else
-+ cIdx = params->p.modification_list[i];
-+
-+ frame->ref_poc_list[1][frame->cur_slice_idx][i] =
-+ (cIdx >= num_pos) ? ref_picset0[cIdx - num_pos]
-+ : ref_picset1[cIdx];
-+ }
-+ } else {
-+ for (i = 0; i < num_ref_idx_l1_active; i++) {
-+ int cIdx = i % total_num;
-+ frame->ref_poc_list[1][frame->cur_slice_idx][i] =
-+ cIdx >= num_pos ? ref_picset0[cIdx - num_pos] :
-+ ref_picset1[cIdx];
-+ }
-+ }
-+
-+end:
-+ frame->ref_num[0] = num_ref_idx_l0_active;
-+ frame->ref_num[1] = num_ref_idx_l1_active;
-+
-+ dev_dbg(sess->core->dev,
-+ "Frame %u; slice %u; slice_type %u; num_l0 %u; num_l1 %u\n",
-+ frame->poc, frame->cur_slice_idx, params->p.slice_type,
-+ frame->ref_num[0], frame->ref_num[1]);
-+}
-+
-+static void codec_hevc_update_ldc_flag(struct codec_hevc *hevc)
-+{
-+ struct hevc_frame *frame = hevc->cur_frame;
-+ u32 slice_type = frame->cur_slice_type;
-+ int i;
-+
-+ hevc->ldc_flag = 0;
-+
-+ if (slice_type == I_SLICE)
-+ return;
-+
-+ hevc->ldc_flag = 1;
-+ for (i = 0; (i < frame->ref_num[0]) && hevc->ldc_flag; i++) {
-+ if (frame->ref_poc_list[0][frame->cur_slice_idx][i] > frame->poc) {
-+ hevc->ldc_flag = 0;
-+ break;
-+ }
-+ }
-+
-+ if (slice_type == P_SLICE)
-+ return;
-+
-+ for (i = 0; (i < frame->ref_num[1]) && hevc->ldc_flag; i++) {
-+ if (frame->ref_poc_list[1][frame->cur_slice_idx][i] > frame->poc) {
-+ hevc->ldc_flag = 0;
-+ break;
-+ }
-+ }
-+}
-+
-+/* Tag "old" frames that are no longer referenced */
-+static void codec_hevc_update_referenced(struct codec_hevc *hevc)
-+{
-+ union rpm_param *param = &hevc->rpm_param;
-+ struct hevc_frame *frame;
-+ int i;
-+ u32 curr_poc = hevc->curr_poc;
-+
-+ list_for_each_entry(frame, &hevc->ref_frames_list, list) {
-+ int is_referenced = 0;
-+ u32 poc_tmp;
-+
-+ if (!frame->referenced)
-+ continue;
-+
-+ for (i = 0; i < MAX_REF_ACTIVE; i++) {
-+ int delt;
-+ if (param->p.CUR_RPS[i] & 0x8000)
-+ break;
-+
-+ delt = param->p.CUR_RPS[i] & ((1 << (RPS_USED_BIT - 1)) - 1);
-+ if (param->p.CUR_RPS[i] & (1 << (RPS_USED_BIT - 1))) {
-+ poc_tmp = curr_poc - ((1 << (RPS_USED_BIT - 1)) - delt);
-+ } else
-+ poc_tmp = curr_poc + delt;
-+ if (poc_tmp == frame->poc) {
-+ is_referenced = 1;
-+ break;
-+ }
-+ }
-+
-+ frame->referenced = is_referenced;
-+ }
-+}
-+
-+static struct hevc_frame *codec_hevc_get_lowest_poc_frame(struct codec_hevc *hevc)
-+{
-+ struct hevc_frame *tmp, *ret = NULL;
-+ u32 poc = INT_MAX;
-+
-+ list_for_each_entry(tmp, &hevc->ref_frames_list, list) {
-+ if (tmp->poc < poc) {
-+ ret = tmp;
-+ poc = tmp->poc;
-+ }
-+ }
-+
-+ return ret;
-+}
-+
-+/* Try to output as many frames as possible */
-+static void codec_hevc_output_frames(struct vdec_session *sess)
-+{
-+ struct hevc_frame *tmp;
-+ struct codec_hevc *hevc = sess->priv;
-+
-+ while ((tmp = codec_hevc_get_lowest_poc_frame(hevc))) {
-+ if (tmp->referenced || tmp->num_reorder_pic >= hevc->frames_num)
-+ break;
-+
-+ dev_dbg(sess->core->dev, "DONE frame poc %u; vbuf %u\n",
-+ tmp->poc, tmp->vbuf->vb2_buf.index);
-+ vdec_dst_buf_done(sess, tmp->vbuf);
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ hevc->frames_num--;
-+ }
-+}
-+
-+/* Configure part of the IP responsible for frame buffer decompression */
-+static void codec_hevc_setup_decode_head(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ /* TODO */
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_DECOMP_CTL1);
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_DECOMP_CTL2);
-+ writel_relaxed(0, core->dos_base + HEVC_CM_BODY_LENGTH);
-+ writel_relaxed(0, core->dos_base + HEVC_CM_HEADER_OFFSET);
-+ writel_relaxed(0, core->dos_base + HEVC_CM_HEADER_LENGTH);
-+}
-+
-+static void codec_hevc_setup_buffers_gxbb(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct v4l2_m2m_buffer *buf;
-+ u32 buf_size = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
-+ dma_addr_t buf_y_paddr = 0;
-+ dma_addr_t buf_uv_paddr = 0;
-+ u32 idx = 0;
-+ u32 val;
-+ int i;
-+
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR);
-+
-+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
-+ idx = buf->vb.vb2_buf.index;
-+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
-+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
-+
-+ val = buf_y_paddr | ((idx * 2) << 8) | 1;
-+ writel_relaxed(val, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR);
-+ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1;
-+ writel_relaxed(val, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR);
-+ }
-+
-+ val = buf_y_paddr | ((idx * 2) << 8) | 1;
-+ /* Fill the remaining unused slots with the last buffer's Y addr */
-+ for (i = buf_size; i < MAX_REF_PIC_NUM; ++i)
-+ writel_relaxed(val, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR);
-+
-+ writel_relaxed(1, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR);
-+ writel_relaxed(1, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ for (i = 0; i < 32; ++i)
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+}
-+
-+static void codec_hevc_setup_buffers_gxl(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct v4l2_m2m_buffer *buf;
-+ u32 buf_size = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
-+ dma_addr_t buf_y_paddr = 0;
-+ dma_addr_t buf_uv_paddr = 0;
-+ int i;
-+
-+ writel_relaxed((1 << 2) | (1 << 1), core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR);
-+
-+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
-+ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
-+ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
-+
-+ writel_relaxed(buf_y_paddr >> 5, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_DATA);
-+ writel_relaxed(buf_uv_paddr >> 5, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_DATA);
-+ }
-+
-+ /* Fill the remaining unused slots with the last buffer's Y addr */
-+ for (i = buf_size; i < MAX_REF_PIC_NUM; ++i) {
-+ writel_relaxed(buf_y_paddr >> 5, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_DATA);
-+ //writel_relaxed(buf_uv_paddr >> 5, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_DATA);
-+ }
-+
-+ writel_relaxed(1, core->dos_base + HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR);
-+ writel_relaxed(1, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ for (i = 0; i < 32; ++i)
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+}
-+
-+static int codec_hevc_setup_workspace(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+
-+ /* Allocate some memory for the HEVC decoder's state */
-+ hevc->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &hevc->workspace_paddr, GFP_KERNEL);
-+ if (!hevc->workspace_vaddr) {
-+ dev_err(core->dev, "Failed to allocate HEVC Workspace\n");
-+ return -ENOMEM;
-+ }
-+
-+ writel_relaxed(hevc->workspace_paddr + IPP_OFFSET, core->dos_base + HEVCD_IPP_LINEBUFF_BASE);
-+ writel_relaxed(hevc->workspace_paddr + RPM_OFFSET, core->dos_base + HEVC_RPM_BUFFER);
-+ writel_relaxed(hevc->workspace_paddr + SH_TM_RPS_OFFSET, core->dos_base + HEVC_SHORT_TERM_RPS);
-+ writel_relaxed(hevc->workspace_paddr + VPS_OFFSET, core->dos_base + HEVC_VPS_BUFFER);
-+ writel_relaxed(hevc->workspace_paddr + SPS_OFFSET, core->dos_base + HEVC_SPS_BUFFER);
-+ writel_relaxed(hevc->workspace_paddr + PPS_OFFSET, core->dos_base + HEVC_PPS_BUFFER);
-+ writel_relaxed(hevc->workspace_paddr + SAO_UP_OFFSET, core->dos_base + HEVC_SAO_UP);
-+
-+ /* MMU */
-+ //writel_relaxed(hevc->frame_mmu_paddr, core->dos_base + H265_MMU_MAP_BUFFER);
-+ /* No MMU */
-+ writel_relaxed(hevc->workspace_paddr + SWAP_BUF_OFFSET, core->dos_base + HEVC_STREAM_SWAP_BUFFER);
-+
-+ writel_relaxed(hevc->workspace_paddr + SWAP_BUF2_OFFSET, core->dos_base + HEVC_STREAM_SWAP_BUFFER2);
-+ writel_relaxed(hevc->workspace_paddr + SCALELUT_OFFSET, core->dos_base + HEVC_SCALELUT);
-+ writel_relaxed(hevc->workspace_paddr + DBLK_PARA_OFFSET, core->dos_base + HEVC_DBLK_CFG4);
-+ writel_relaxed(hevc->workspace_paddr + DBLK_DATA_OFFSET, core->dos_base + HEVC_DBLK_CFG5);
-+
-+ return 0;
-+}
-+
-+static int codec_hevc_start(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc;
-+ int ret;
-+ int i;
-+
-+ hevc = kzalloc(sizeof(*hevc), GFP_KERNEL);
-+ if (!hevc)
-+ return -ENOMEM;
-+
-+ sess->priv = hevc;
-+ INIT_LIST_HEAD(&hevc->ref_frames_list);
-+ hevc->curr_poc = INVALID_POC;
-+
-+ ret = codec_hevc_setup_workspace(sess);
-+ if (ret)
-+ goto free_hevc;
-+
-+ writel_relaxed(0x5a5a55aa, core->dos_base + HEVC_PARSER_VERSION);
-+ writel_relaxed((1 << 14), core->dos_base + DOS_SW_RESET3);
-+ writel_relaxed(0, core->dos_base + HEVC_CABAC_CONTROL);
-+ writel_relaxed(0, core->dos_base + HEVC_PARSER_CORE_CONTROL);
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_STREAM_CONTROL) | 1, core->dos_base + HEVC_STREAM_CONTROL);
-+ writel_relaxed(0x00000100, core->dos_base + HEVC_SHIFT_STARTCODE);
-+ writel_relaxed(0x00000300, core->dos_base + HEVC_SHIFT_EMULATECODE);
-+ writel_relaxed((readl_relaxed(core->dos_base + HEVC_PARSER_INT_CONTROL) & 0x03ffffff) |
-+ (3 << 29) | (2 << 26) | (1 << 24) | (1 << 22) | (1 << 7) | (1 << 4) | 1, core->dos_base + HEVC_PARSER_INT_CONTROL);
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_SHIFT_STATUS) | (1 << 1) | 1, core->dos_base + HEVC_SHIFT_STATUS);
-+ writel_relaxed((3 << 6) | (2 << 4) | (2 << 1) | 1, core->dos_base + HEVC_SHIFT_CONTROL);
-+ writel_relaxed(1, core->dos_base + HEVC_CABAC_CONTROL);
-+ writel_relaxed(1, core->dos_base + HEVC_PARSER_CORE_CONTROL);
-+ writel_relaxed(0, core->dos_base + HEVC_DEC_STATUS_REG);
-+
-+ writel_relaxed(0, core->dos_base + HEVC_IQIT_SCALELUT_WR_ADDR);
-+ for (i = 0; i < 1024; ++i)
-+ writel_relaxed(0, core->dos_base + HEVC_IQIT_SCALELUT_DATA);
-+
-+ writel_relaxed(0, core->dos_base + HEVC_DECODE_SIZE);
-+
-+ writel_relaxed((1 << 16), core->dos_base + HEVC_PARSER_CMD_WRITE);
-+ for (i = 0; i < ARRAY_SIZE(parser_cmd); ++i)
-+ writel_relaxed(parser_cmd[i], core->dos_base + HEVC_PARSER_CMD_WRITE);
-+
-+ writel_relaxed(PARSER_CMD_SKIP_CFG_0, core->dos_base + HEVC_PARSER_CMD_SKIP_0);
-+ writel_relaxed(PARSER_CMD_SKIP_CFG_1, core->dos_base + HEVC_PARSER_CMD_SKIP_1);
-+ writel_relaxed(PARSER_CMD_SKIP_CFG_2, core->dos_base + HEVC_PARSER_CMD_SKIP_2);
-+ writel_relaxed((1 << 5) | (1 << 2) | 1, core->dos_base + HEVC_PARSER_IF_CONTROL);
-+
-+ writel_relaxed(1, core->dos_base + HEVCD_IPP_TOP_CNTL);
-+ writel_relaxed((1 << 1), core->dos_base + HEVCD_IPP_TOP_CNTL);
-+
-+ /* Enable 2-plane reference read mode for MC */
-+ if (sess->fmt_cap->pixfmt == V4L2_PIX_FMT_NV12M)
-+ writel_relaxed(1 << 31, core->dos_base + HEVCD_MPP_DECOMP_CTL1);
-+
-+ writel_relaxed(1, core->dos_base + HEVC_WAIT_FLAG);
-+
-+ /* clear mailbox interrupt */
-+ writel_relaxed(1, core->dos_base + HEVC_ASSIST_MBOX1_CLR_REG);
-+ /* enable mailbox interrupt */
-+ writel_relaxed(1, core->dos_base + HEVC_ASSIST_MBOX1_MASK);
-+ /* disable PSCALE for hardware sharing */
-+ writel_relaxed(0, core->dos_base + HEVC_PSCALE_CTRL);
-+ /* Let the uCode do all the parsing */
-+ writel_relaxed(0xc, core->dos_base + NAL_SEARCH_CTL);
-+
-+ writel_relaxed(0, core->dos_base + DECODE_STOP_POS);
-+ writel_relaxed(DECODE_MODE_SINGLE, core->dos_base + HEVC_DECODE_MODE);
-+ writel_relaxed(0, core->dos_base + HEVC_DECODE_MODE2);
-+
-+ /* AUX buffers */
-+ hevc->aux_vaddr = dma_alloc_coherent(core->dev, SIZE_AUX, &hevc->aux_paddr, GFP_KERNEL);
-+ if (!hevc->aux_vaddr) {
-+ dev_err(core->dev, "Failed to request HEVC AUX\n");
-+ ret = -ENOMEM;
-+ goto free_hevc;
-+ }
-+
-+ writel_relaxed(hevc->aux_paddr, core->dos_base + HEVC_AUX_ADR);
-+ writel_relaxed((((SIZE_AUX) >> 4) << 16) | 0, core->dos_base + HEVC_AUX_DATA_SIZE);
-+
-+ if (core->platform->revision == VDEC_REVISION_GXBB)
-+ codec_hevc_setup_buffers_gxbb(sess);
-+ else
-+ codec_hevc_setup_buffers_gxl(sess);
-+
-+ if (sess->fmt_cap->pixfmt != V4L2_PIX_FMT_NV12M)
-+ codec_hevc_setup_decode_head(sess);
-+
-+ return 0;
-+
-+free_hevc:
-+ kfree(hevc);
-+ return ret;
-+}
-+
-+static void codec_hevc_flush_output(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ struct hevc_frame *tmp, *n;
-+
-+ list_for_each_entry_safe(tmp, n, &hevc->ref_frames_list, list) {
-+ vdec_dst_buf_done(sess, tmp->vbuf);
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ hevc->frames_num--;
-+ }
-+}
-+
-+static int codec_hevc_stop(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ struct vdec_core *core = sess->core;
-+
-+ mutex_lock(&sess->codec_lock);
-+ codec_hevc_flush_output(sess);
-+
-+ if (hevc->workspace_vaddr) {
-+ dma_free_coherent(core->dev, SIZE_WORKSPACE,
-+ hevc->workspace_vaddr,
-+ hevc->workspace_paddr);
-+ hevc->workspace_vaddr = 0;
-+ }
-+
-+ if (hevc->frame_mmu_vaddr) {
-+ dma_free_coherent(core->dev, SIZE_FRAME_MMU,
-+ hevc->frame_mmu_vaddr,
-+ hevc->frame_mmu_paddr);
-+ hevc->frame_mmu_vaddr = 0;
-+ }
-+
-+ if (hevc->aux_vaddr) {
-+ dma_free_coherent(core->dev, SIZE_AUX,
-+ hevc->aux_vaddr, hevc->aux_paddr);
-+ hevc->aux_vaddr = 0;
-+ }
-+
-+ kfree(hevc);
-+ sess->priv = 0;
-+ mutex_unlock(&sess->codec_lock);
-+
-+ return 0;
-+}
-+
-+static void codec_hevc_update_tiles(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ struct vdec_core *core = sess->core;
-+ u32 sao_mem_unit = (hevc->lcu_size == 16 ? 9 : hevc->lcu_size == 32 ? 14 : 24) << 4;
-+ u32 pic_height_cu = (hevc->height + hevc->lcu_size - 1) / hevc->lcu_size;
-+ u32 pic_width_cu = (hevc->width + hevc->lcu_size - 1) / hevc->lcu_size;
-+ u32 sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu;
-+ u32 tiles_flags = hevc->rpm_param.p.tiles_flags;
-+
-+ if (tiles_flags & 1) {
-+ /* TODO; The samples I'm using have tiles_flags == 0 */
-+ return;
-+ }
-+
-+ hevc->num_tile_col = 1;
-+ hevc->num_tile_row = 1;
-+ hevc->m_tile[0][0].width = pic_width_cu;
-+ hevc->m_tile[0][0].height = pic_height_cu;
-+ hevc->m_tile[0][0].start_cu_x = 0;
-+ hevc->m_tile[0][0].start_cu_y = 0;
-+ hevc->m_tile[0][0].sao_vb_start_addr = hevc->workspace_paddr + SAO_VB_OFFSET;
-+ hevc->m_tile[0][0].sao_abv_start_addr = hevc->workspace_paddr + SAO_ABV_OFFSET;
-+
-+ hevc->tile_start_lcu_x = 0;
-+ hevc->tile_start_lcu_y = 0;
-+ hevc->tile_width_lcu = pic_width_cu;
-+ hevc->tile_height_lcu = pic_height_cu;
-+
-+ writel_relaxed(sao_mem_unit, core->dos_base + HEVC_sao_mem_unit);
-+ writel_relaxed(hevc->workspace_paddr + SAO_ABV_OFFSET, core->dos_base + HEVC_SAO_ABV);
-+ writel_relaxed(sao_vb_size, core->dos_base + HEVC_sao_vb_size);
-+ writel_relaxed(hevc->workspace_paddr + SAO_VB_OFFSET, core->dos_base + HEVC_SAO_VB);
-+}
-+
-+static struct hevc_frame * codec_hevc_get_frame_by_poc(struct codec_hevc *hevc, u32 poc)
-+{
-+ struct hevc_frame *tmp;
-+
-+ list_for_each_entry(tmp, &hevc->ref_frames_list, list) {
-+ if (tmp->poc == poc)
-+ return tmp;
-+ }
-+
-+ return NULL;
-+}
-+
-+static struct hevc_frame * codec_hevc_prepare_new_frame(struct vdec_session *sess)
-+{
-+ struct vb2_v4l2_buffer *vbuf;
-+ struct hevc_frame *new_frame = NULL;
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *params = &hevc->rpm_param;
-+
-+ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx);
-+ if (!vbuf) {
-+ dev_warn(sess->core->dev, "Couldn't remove dst buf\n");
-+ return NULL;
-+ }
-+
-+ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL);
-+ if (!new_frame)
-+ return NULL;
-+
-+ new_frame->vbuf = vbuf;
-+ new_frame->referenced = 1;
-+ new_frame->poc = hevc->curr_poc;
-+ new_frame->cur_slice_type = params->p.slice_type;
-+ new_frame->num_reorder_pic = params->p.sps_num_reorder_pics_0;
-+
-+ list_add_tail(&new_frame->list, &hevc->ref_frames_list);
-+ hevc->frames_num++;
-+
-+ return new_frame;
-+}
-+
-+static void codec_hevc_set_sao(struct vdec_session *sess, struct hevc_frame *frame)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *param = &hevc->rpm_param;
-+ dma_addr_t buf_y_paddr = vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0);
-+ dma_addr_t buf_u_v_paddr = vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 1);
-+ u32 misc_flag0 = param->p.misc_flag0;
-+ u32 slice_deblocking_filter_disabled_flag;
-+ u32 val, val_2;
-+
-+ val = (readl_relaxed(core->dos_base + HEVC_SAO_CTRL0) & ~0xf) | ilog2(hevc->lcu_size);
-+ writel_relaxed(val, core->dos_base + HEVC_SAO_CTRL0);
-+
-+ writel_relaxed(hevc->width | (hevc->height << 16), core->dos_base + HEVC_SAO_PIC_SIZE);
-+ writel_relaxed((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16, core->dos_base + HEVC_SAO_PIC_SIZE_LCU);
-+
-+ writel_relaxed(buf_y_paddr, core->dos_base + HEVC_SAO_Y_START_ADDR);
-+ writel_relaxed(vdec_get_output_size(sess), core->dos_base + HEVC_SAO_Y_LENGTH);
-+ writel_relaxed(buf_u_v_paddr, core->dos_base + HEVC_SAO_C_START_ADDR);
-+ writel_relaxed((vdec_get_output_size(sess) / 2), core->dos_base + HEVC_SAO_C_LENGTH);
-+
-+ writel_relaxed(buf_y_paddr, core->dos_base + HEVC_SAO_Y_WPTR);
-+ writel_relaxed(buf_u_v_paddr, core->dos_base + HEVC_SAO_C_WPTR);
-+
-+ if (frame->cur_slice_idx == 0) {
-+ writel_relaxed(hevc->width | (hevc->height << 16), core->dos_base + HEVC_DBLK_CFG2);
-+
-+ val = 0;
-+ if ((misc_flag0 >> PCM_ENABLE_FLAG_BIT) & 0x1)
-+ val |= ((misc_flag0 >> PCM_LOOP_FILTER_DISABLED_FLAG_BIT) & 0x1) << 3;
-+
-+ val |= (param->p.pps_cb_qp_offset & 0x1f) << 4;
-+ val |= (param->p.pps_cr_qp_offset & 0x1f) << 9;
-+ val |= (hevc->lcu_size == 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2);
-+ writel_relaxed(val, core->dos_base + HEVC_DBLK_CFG1);
-+ }
-+
-+ val = readl_relaxed(core->dos_base + HEVC_SAO_CTRL1) & ~0x3ff3;
-+ if (sess->fmt_cap->pixfmt == V4L2_PIX_FMT_NV12M)
-+ val |= 0xff0 | /* Set endianness for 2-bytes swaps (nv12) */
-+ 0x1; /* disable cm compression */
-+ else
-+ val |= 0x3000 | /* 64x32 block mode */
-+ 0x880 | /* 64-bit Big Endian */
-+ 0x2; /* Disable double write */
-+
-+ writel_relaxed(val, core->dos_base + HEVC_SAO_CTRL1);
-+
-+ /* set them all 0 for H265_NV21 (no down-scale) */
-+ val = readl_relaxed(core->dos_base + HEVC_SAO_CTRL5) & ~0xff0000;
-+ writel_relaxed(val, core->dos_base + HEVC_SAO_CTRL5);
-+
-+ val = readl_relaxed(core->dos_base + HEVCD_IPP_AXIIF_CONFIG) & ~0x30;
-+ val |= 0xf;
-+ if (sess->fmt_cap->pixfmt != V4L2_PIX_FMT_NV12M)
-+ val |= 0x30; /* 64x32 block mode */
-+
-+ writel_relaxed(val, core->dos_base + HEVCD_IPP_AXIIF_CONFIG);
-+
-+ val = 0;
-+ val_2 = readl_relaxed(core->dos_base + HEVC_SAO_CTRL0);
-+ val_2 &= (~0x300);
-+
-+ /* TODO: handle tiles here if enabled */
-+ slice_deblocking_filter_disabled_flag = (misc_flag0 >>
-+ SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1;
-+ if ((misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT))
-+ && (misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT))) {
-+ val |= slice_deblocking_filter_disabled_flag << 2;
-+
-+ if (!slice_deblocking_filter_disabled_flag) {
-+ val |= (param->p.slice_beta_offset_div2 & 0xf) << 3;
-+ val |= (param->p.slice_tc_offset_div2 & 0xf) << 7;
-+ }
-+ } else {
-+ val |=
-+ ((misc_flag0 >>
-+ PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1) << 2;
-+
-+ if (((misc_flag0 >> PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) &
-+ 0x1) == 0) {
-+ val |= (param->p.pps_beta_offset_div2 & 0xf) << 3;
-+ val |= (param->p.pps_tc_offset_div2 & 0xf) << 7;
-+ }
-+ }
-+ if ((misc_flag0 & (1 << PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT))
-+ && ((misc_flag0 & (1 << SLICE_SAO_LUMA_FLAG_BIT))
-+ || (misc_flag0 & (1 << SLICE_SAO_CHROMA_FLAG_BIT))
-+ || (!slice_deblocking_filter_disabled_flag))) {
-+ val |=
-+ ((misc_flag0 >>
-+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
-+ & 0x1) << 1;
-+ val_2 |=
-+ ((misc_flag0 >>
-+ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
-+ & 0x1) << 9;
-+ } else {
-+ val |=
-+ ((misc_flag0 >>
-+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
-+ & 0x1) << 1;
-+ val_2 |=
-+ ((misc_flag0 >>
-+ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)
-+ & 0x1) << 9;
-+ }
-+
-+ writel_relaxed(val, core->dos_base + HEVC_DBLK_CFG9);
-+ writel_relaxed(val_2, core->dos_base + HEVC_SAO_CTRL0);
-+}
-+
-+static dma_addr_t codec_hevc_get_frame_mv_paddr(struct codec_hevc *hevc, struct hevc_frame *frame)
-+{
-+ return hevc->workspace_paddr + MPRED_MV_OFFSET +
-+ (frame->vbuf->vb2_buf.index * MPRED_MV_BUF_SIZE);
-+}
-+
-+/* Update the necessary information for motion prediction with the current slice */
-+static void codec_hevc_set_mpred(struct vdec_session *sess, struct hevc_frame *frame, struct hevc_frame *col_frame)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *param = &hevc->rpm_param;
-+ u32 *ref_num = frame->ref_num;
-+ u32 *ref_poc_l0 = frame->ref_poc_list[0][frame->cur_slice_idx];
-+ u32 *ref_poc_l1 = frame->ref_poc_list[1][frame->cur_slice_idx];
-+ u32 lcu_size_log2 = ilog2(hevc->lcu_size);
-+ u32 mv_mem_unit = lcu_size_log2 == 6 ? 0x200 : lcu_size_log2 == 5 ? 0x80 : 0x20;
-+ u32 slice_segment_address = param->p.slice_segment_address;
-+ u32 max_num_merge_cand = 5 - param->p.five_minus_max_num_merge_cand;
-+ u32 plevel = param->p.log2_parallel_merge_level;
-+ u32 col_from_l0_flag = param->p.collocated_from_l0_flag;
-+ u32 tmvp_flag = param->p.slice_temporal_mvp_enable_flag;
-+ u32 is_next_slice_segment = param->p.dependent_slice_segment_flag ? 1 : 0;
-+ u32 slice_type = param->p.slice_type;
-+ dma_addr_t col_mv_rd_start_addr, col_mv_rd_ptr, col_mv_rd_end_addr;
-+ dma_addr_t mpred_mv_wr_ptr;
-+ u32 mv_rd_en = 1;
-+ u32 val;
-+ int i;
-+
-+ val = readl_relaxed(core->dos_base + HEVC_MPRED_CURR_LCU);
-+
-+ col_mv_rd_start_addr = codec_hevc_get_frame_mv_paddr(hevc, col_frame);
-+ mpred_mv_wr_ptr = codec_hevc_get_frame_mv_paddr(hevc, frame) + (hevc->slice_addr * mv_mem_unit);
-+ col_mv_rd_ptr = col_mv_rd_start_addr + (hevc->slice_addr * mv_mem_unit);
-+ col_mv_rd_end_addr = col_mv_rd_start_addr + ((hevc->lcu_x_num * hevc->lcu_y_num) * mv_mem_unit);
-+
-+ writel_relaxed(codec_hevc_get_frame_mv_paddr(hevc, frame), core->dos_base + HEVC_MPRED_MV_WR_START_ADDR);
-+ writel_relaxed(col_mv_rd_start_addr, core->dos_base + HEVC_MPRED_MV_RD_START_ADDR);
-+
-+ val = ((hevc->lcu_x_num - hevc->tile_width_lcu) * mv_mem_unit);
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_MV_WR_ROW_JUMP);
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_MV_RD_ROW_JUMP);
-+
-+ if (slice_type == I_SLICE)
-+ mv_rd_en = 0;
-+
-+ val = slice_type |
-+ 1 << 2 | // new pic
-+ 1 << 3 | // new tile
-+ is_next_slice_segment << 4 |
-+ tmvp_flag << 5 |
-+ hevc->ldc_flag << 6 |
-+ col_from_l0_flag << 7 |
-+ 1 << 9 |
-+ 1 << 10 |
-+ mv_rd_en << 11 |
-+ 1 << 13 |
-+ lcu_size_log2 << 16 |
-+ 3 << 20 | plevel << 24;
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_CTRL0);
-+
-+ val = max_num_merge_cand | 2 << 4 | 3 << 8 | 5 << 12 | 36 << 16;
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_CTRL1);
-+
-+ writel_relaxed(hevc->width | (hevc->height << 16), core->dos_base + HEVC_MPRED_PIC_SIZE);
-+
-+ val = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16);
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_PIC_SIZE_LCU);
-+ val = (hevc->tile_start_lcu_x | hevc->tile_start_lcu_y << 16);
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_TILE_START);
-+ val = (hevc->tile_width_lcu | hevc->tile_height_lcu << 16);
-+ writel_relaxed(val, core->dos_base + HEVC_MPRED_TILE_SIZE_LCU);
-+
-+ writel_relaxed((ref_num[1] << 8) | ref_num[0], core->dos_base + HEVC_MPRED_REF_NUM);
-+ writel_relaxed((1 << ref_num[0]) - 1, core->dos_base + HEVC_MPRED_REF_EN_L0);
-+ writel_relaxed((1 << ref_num[1]) - 1, core->dos_base + HEVC_MPRED_REF_EN_L1);
-+
-+ writel_relaxed(hevc->curr_poc, core->dos_base + HEVC_MPRED_CUR_POC);
-+ writel_relaxed(hevc->col_poc, core->dos_base + HEVC_MPRED_COL_POC);
-+
-+ for (i = 0; i < MAX_REF_ACTIVE; ++i) {
-+ writel_relaxed(ref_poc_l0[i], core->dos_base + HEVC_MPRED_L0_REF00_POC + i * 4);
-+ writel_relaxed(ref_poc_l1[i], core->dos_base + HEVC_MPRED_L1_REF00_POC + i * 4);
-+ }
-+
-+ if (slice_segment_address == 0) {
-+ writel_relaxed(hevc->workspace_paddr + MPRED_ABV_OFFSET, core->dos_base + HEVC_MPRED_ABV_START_ADDR);
-+ writel_relaxed(mpred_mv_wr_ptr, core->dos_base + HEVC_MPRED_MV_WPTR);
-+ writel_relaxed(col_mv_rd_start_addr, core->dos_base + HEVC_MPRED_MV_RPTR);
-+ } else {
-+ writel_relaxed(col_mv_rd_ptr, core->dos_base + HEVC_MPRED_MV_RPTR);
-+ }
-+
-+ writel_relaxed(col_mv_rd_end_addr, core->dos_base + HEVC_MPRED_MV_RD_END_ADDR);
-+}
-+
-+/* motion compensation reference cache controller */
-+static void codec_hevc_set_mcrcc(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+ u32 val, val_2;
-+ int l0_cnt = hevc->cur_frame->ref_num[0];
-+ int l1_cnt = hevc->cur_frame->ref_num[1];
-+
-+ /* reset mcrcc */
-+ writel_relaxed(0x02, core->dos_base + HEVCD_MCRCC_CTL1);
-+
-+ if (hevc->cur_frame->cur_slice_type == I_SLICE) {
-+ /* remove reset -- disables clock */
-+ writel_relaxed(0, core->dos_base + HEVCD_MCRCC_CTL1);
-+ return;
-+ }
-+
-+ if (hevc->cur_frame->cur_slice_type == P_SLICE) {
-+ writel_relaxed(1 << 1, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ val = readl_relaxed(core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ val &= 0xffff;
-+ val |= (val << 16);
-+ writel_relaxed(val, core->dos_base + HEVCD_MCRCC_CTL2);
-+
-+ if (l0_cnt == 1) {
-+ writel_relaxed(val, core->dos_base + HEVCD_MCRCC_CTL3);
-+ } else {
-+ val = readl_relaxed(core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ val &= 0xffff;
-+ val |= (val << 16);
-+ writel_relaxed(val, core->dos_base + HEVCD_MCRCC_CTL3);
-+ }
-+ } else { /* B_SLICE */
-+ writel_relaxed(0, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ val = readl_relaxed(core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ val &= 0xffff;
-+ val |= (val << 16);
-+ writel_relaxed(val, core->dos_base + HEVCD_MCRCC_CTL2);
-+
-+ writel_relaxed((16 << 8) | (1 << 1), core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ val_2 = readl_relaxed(core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ val_2 &= 0xffff;
-+ val_2 |= (val_2 << 16);
-+ if (val == val_2 && l1_cnt > 1) {
-+ val_2 = readl_relaxed(core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ val_2 &= 0xffff;
-+ val_2 |= (val_2 << 16);
-+ }
-+ writel_relaxed(val, core->dos_base + HEVCD_MCRCC_CTL3);
-+ }
-+
-+ /* enable mcrcc progressive-mode */
-+ writel_relaxed(0xff0, core->dos_base + HEVCD_MCRCC_CTL1);
-+}
-+
-+static void codec_hevc_set_ref_list(struct vdec_session *sess,
-+ u32 ref_num, u32 *ref_poc_list)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ struct hevc_frame *ref_frame;
-+ struct vdec_core *core = sess->core;
-+ int i;
-+ u32 ref_frame_id;
-+
-+ for (i = 0; i < ref_num; i++) {
-+ ref_frame = codec_hevc_get_frame_by_poc(hevc, ref_poc_list[i]);
-+
-+ if (!ref_frame) {
-+ dev_warn(core->dev, "Couldn't find ref. frame %u\n",
-+ ref_poc_list[i]);
-+ continue;
-+ }
-+
-+ ref_frame_id = ref_frame->vbuf->vb2_buf.index * 2;
-+ dev_dbg(core->dev, "Programming ref poc %u\n", ref_poc_list[i]);
-+
-+ writel_relaxed(((ref_frame_id + 1) << 16) |
-+ ((ref_frame_id + 1) << 8) |
-+ ref_frame_id,
-+ core->dos_base + HEVCD_MPP_ANC_CANVAS_DATA_ADDR);
-+ }
-+}
-+
-+static void codec_hevc_set_mc(struct vdec_session *sess, struct hevc_frame *frame)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ if (frame->cur_slice_type == I_SLICE)
-+ return;
-+
-+ writel_relaxed(1, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ codec_hevc_set_ref_list(sess, frame->ref_num[0],
-+ frame->ref_poc_list[0][frame->cur_slice_idx]);
-+
-+ if (frame->cur_slice_type == P_SLICE)
-+ return;
-+
-+ writel_relaxed((16 << 8) | 1, core->dos_base + HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR);
-+ codec_hevc_set_ref_list(sess, frame->ref_num[1],
-+ frame->ref_poc_list[1][frame->cur_slice_idx]);
-+}
-+
-+static void codec_hevc_update_col_frame(struct codec_hevc *hevc)
-+{
-+ struct hevc_frame *cur_frame = hevc->cur_frame;
-+ union rpm_param *param = &hevc->rpm_param;
-+ u32 list_no = 0;
-+ u32 col_ref = param->p.collocated_ref_idx;
-+ u32 col_from_l0 = param->p.collocated_from_l0_flag;
-+
-+ if (cur_frame->cur_slice_type == B_SLICE)
-+ list_no = 1 - col_from_l0;
-+
-+ if (col_ref >= cur_frame->ref_num[list_no])
-+ hevc->col_poc = INVALID_POC;
-+ else
-+ hevc->col_poc = cur_frame->ref_poc_list[list_no][cur_frame->cur_slice_idx][col_ref];
-+
-+ if (cur_frame->cur_slice_type == I_SLICE)
-+ goto end;
-+
-+ if (hevc->col_poc != INVALID_POC)
-+ hevc->col_frame = codec_hevc_get_frame_by_poc(hevc, hevc->col_poc);
-+ else
-+ hevc->col_frame = hevc->cur_frame;
-+
-+end:
-+ if (!hevc->col_frame)
-+ hevc->col_frame = hevc->cur_frame;
-+}
-+
-+static void codec_hevc_update_pocs(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *param = &hevc->rpm_param;
-+ u32 nal_unit_type = param->p.m_nalUnitType;
-+ u32 temporal_id = param->p.m_temporalId & 0x7;
-+ int iMaxPOClsb = 1 << (param->p.log2_max_pic_order_cnt_lsb_minus4 + 4);
-+ int iPrevPOClsb;
-+ int iPrevPOCmsb;
-+ int iPOCmsb;
-+ int iPOClsb = param->p.POClsb;
-+
-+ if (nal_unit_type == NAL_UNIT_CODED_SLICE_IDR ||
-+ nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) {
-+ hevc->curr_poc = 0;
-+ if ((temporal_id - 1) == 0)
-+ hevc->iPrevTid0POC = hevc->curr_poc;
-+
-+ return;
-+ }
-+
-+ iPrevPOClsb = hevc->iPrevTid0POC % iMaxPOClsb;
-+ iPrevPOCmsb = hevc->iPrevTid0POC - iPrevPOClsb;
-+
-+ if ((iPOClsb < iPrevPOClsb) && ((iPrevPOClsb - iPOClsb) >= (iMaxPOClsb / 2)))
-+ iPOCmsb = iPrevPOCmsb + iMaxPOClsb;
-+ else if ((iPOClsb > iPrevPOClsb) && ((iPOClsb - iPrevPOClsb) > (iMaxPOClsb / 2)))
-+ iPOCmsb = iPrevPOCmsb - iMaxPOClsb;
-+ else
-+ iPOCmsb = iPrevPOCmsb;
-+
-+ if (nal_unit_type == NAL_UNIT_CODED_SLICE_BLA ||
-+ nal_unit_type == NAL_UNIT_CODED_SLICE_BLANT ||
-+ nal_unit_type == NAL_UNIT_CODED_SLICE_BLA_N_LP)
-+ iPOCmsb = 0;
-+
-+ hevc->curr_poc = (iPOCmsb + iPOClsb);
-+ if ((temporal_id - 1) == 0)
-+ hevc->iPrevTid0POC = hevc->curr_poc;
-+}
-+
-+static int codec_hevc_process_segment_header(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *param = &hevc->rpm_param;
-+ u32 slice_segment_address = param->p.slice_segment_address;
-+
-+ if (param->p.first_slice_segment_in_pic_flag == 0) {
-+ hevc->slice_segment_addr = param->p.slice_segment_address;
-+ if (!param->p.dependent_slice_segment_flag)
-+ hevc->slice_addr = hevc->slice_segment_addr;
-+ } else {
-+ hevc->slice_segment_addr = 0;
-+ hevc->slice_addr = 0;
-+ }
-+
-+ codec_hevc_update_pocs(sess);
-+
-+ /* First slice: new frame */
-+ if (slice_segment_address == 0) {
-+ codec_hevc_update_referenced(hevc);
-+ codec_hevc_output_frames(sess);
-+
-+ hevc->cur_frame = codec_hevc_prepare_new_frame(sess);
-+ if (!hevc->cur_frame) {
-+ dev_err(sess->core->dev_dec,
-+ "No destination buffer available\n");
-+ return -1;
-+ }
-+
-+ codec_hevc_update_tiles(sess);
-+ } else {
-+ hevc->cur_frame->cur_slice_idx++;
-+ }
-+
-+ return 0;
-+}
-+
-+static int codec_hevc_process_rpm(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+ union rpm_param *rpm_param = &hevc->rpm_param;
-+ u32 lcu_x_num_div, lcu_y_num_div;
-+
-+ if (rpm_param->p.bit_depth &&
-+ sess->fmt_cap->pixfmt == V4L2_PIX_FMT_NV12M) {
-+ dev_err(sess->core->dev_dec,
-+ "V4L2_PIX_FMT_NV12M is only compatible with HEVC 8-bit\n");
-+ return -EINVAL;
-+ }
-+
-+ hevc->width = rpm_param->p.pic_width_in_luma_samples;
-+ hevc->height = rpm_param->p.pic_height_in_luma_samples;
-+
-+ /*if (hevc->width != sess->width ||
-+ hevc->height != sess->height) {
-+ dev_err(sess->core->dev_dec,
-+ "Size mismatch: bitstream %ux%u ; driver %ux%u\n",
-+ hevc->width, hevc->height,
-+ sess->width, sess->height);
-+ return -EINVAL;
-+ }*/
-+
-+ hevc->lcu_size = 1 << (rpm_param->p.log2_min_coding_block_size_minus3 +
-+ 3 + rpm_param->p.log2_diff_max_min_coding_block_size);
-+
-+ lcu_x_num_div = (hevc->width / hevc->lcu_size);
-+ lcu_y_num_div = (hevc->height / hevc->lcu_size);
-+ hevc->lcu_x_num = ((hevc->width % hevc->lcu_size) == 0) ? lcu_x_num_div : lcu_x_num_div + 1;
-+ hevc->lcu_y_num = ((hevc->height % hevc->lcu_size) == 0) ? lcu_y_num_div : lcu_y_num_div + 1;
-+ hevc->lcu_total = hevc->lcu_x_num * hevc->lcu_y_num;
-+
-+ dev_dbg(core->dev, "lcu_size = %u ; lcu_x_num = %u; lcu_y_num = %u",
-+ hevc->lcu_size, hevc->lcu_x_num, hevc->lcu_y_num);
-+
-+ return 0;
-+}
-+
-+/* The RPM section within the workspace contains
-+ * many information regarding the parsed bitstream
-+ */
-+static void codec_hevc_fetch_rpm(struct vdec_session *sess)
-+{
-+ struct codec_hevc *hevc = sess->priv;
-+ u16 *rpm_vaddr = hevc->workspace_vaddr + RPM_OFFSET;
-+ int i, j;
-+
-+ for (i = 0; i < RPM_SIZE; i += 4)
-+ for (j = 0; j < 4; j++)
-+ hevc->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j];
-+}
-+
-+static irqreturn_t codec_hevc_threaded_isr(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc;
-+
-+ mutex_lock(&sess->codec_lock);
-+ hevc = sess->priv;
-+ if (!hevc)
-+ goto unlock;
-+
-+ if (hevc->dec_status != HEVC_SLICE_SEGMENT_DONE) {
-+ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n",
-+ hevc->dec_status);
-+ vdec_abort(sess);
-+ goto unlock;
-+ }
-+
-+ codec_hevc_fetch_rpm(sess);
-+ if (codec_hevc_process_rpm(sess)) {
-+ vdec_abort(sess);
-+ goto unlock;
-+ }
-+
-+ if (codec_hevc_process_segment_header(sess)) {
-+ vdec_abort(sess);
-+ goto unlock;
-+ }
-+
-+ codec_hevc_update_frame_refs(sess, hevc->cur_frame);
-+ codec_hevc_update_col_frame(hevc);
-+ codec_hevc_update_ldc_flag(hevc);
-+ codec_hevc_set_mc(sess, hevc->cur_frame);
-+ codec_hevc_set_mcrcc(sess);
-+ codec_hevc_set_mpred(sess, hevc->cur_frame, hevc->col_frame);
-+ codec_hevc_set_sao(sess, hevc->cur_frame);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_WAIT_FLAG) | 2, core->dos_base + HEVC_WAIT_FLAG);
-+ writel_relaxed(HEVC_CODED_SLICE_SEGMENT_DAT, core->dos_base + HEVC_DEC_STATUS_REG);
-+
-+ /* Interrupt the firmware's processor */
-+ writel_relaxed(AMRISC_MAIN_REQ, core->dos_base + HEVC_MCPU_INTR_REQ);
-+
-+unlock:
-+ mutex_unlock(&sess->codec_lock);
-+ return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t codec_hevc_isr(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_hevc *hevc = sess->priv;
-+
-+ hevc->dec_status = readl_relaxed(core->dos_base + HEVC_DEC_STATUS_REG);
-+
-+ return IRQ_WAKE_THREAD;
-+}
-+
-+struct vdec_codec_ops codec_hevc_ops = {
-+ .start = codec_hevc_start,
-+ .stop = codec_hevc_stop,
-+ .isr = codec_hevc_isr,
-+ .threaded_isr = codec_hevc_threaded_isr,
-+ .num_pending_bufs = codec_hevc_num_pending_bufs,
-+};
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_hevc.h b/drivers/media/platform/meson/vdec/codec_hevc.h
-new file mode 100644
-index 0000000..1cf009b
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_hevc.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CODEC_HEVC_H_
-+#define __MESON_VDEC_CODEC_HEVC_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_codec_ops codec_hevc_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c
-new file mode 100644
-index 0000000..57b56d7
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c
-@@ -0,0 +1,203 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_mjpeg.h"
-+#include "codec_helpers.h"
-+
-+/* DOS registers */
-+#define VDEC_ASSIST_AMR1_INT8 0x00b4
-+
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define MCPU_INTR_MSK 0x0c10
-+
-+#define PSCALE_RST 0x2440
-+#define PSCALE_CTRL 0x2444
-+#define PSCALE_BMEM_ADDR 0x247c
-+#define PSCALE_BMEM_DAT 0x2480
-+
-+#define MDEC_PIC_DC_CTRL 0x2638
-+
-+#define AV_SCRATCH_0 0x2700
-+#define AV_SCRATCH_1 0x2704
-+#define MREG_DECODE_PARAM 0x2708
-+#define AV_SCRATCH_4 0x2710
-+#define MREG_TO_AMRISC 0x2720
-+#define MREG_FROM_AMRISC 0x2724
-+
-+#define DOS_SW_RESET0 0xfc00
-+
-+struct codec_mjpeg {
-+ /* Housekeeping thread for marking buffers to DONE
-+ * and recycling them into the hardware
-+ */
-+ struct task_struct *buffers_thread;
-+};
-+
-+static int codec_mjpeg_buffers_thread(void *data)
-+{
-+ struct vdec_buffer *tmp;
-+ struct vdec_session *sess = data;
-+ struct vdec_core *core = sess->core;;
-+
-+ while (!kthread_should_stop()) {
-+ mutex_lock(&sess->bufs_recycle_lock);
-+ while (!list_empty(&sess->bufs_recycle) &&
-+ !readl_relaxed(core->dos_base + MREG_TO_AMRISC))
-+ {
-+ tmp = list_first_entry(&sess->bufs_recycle, struct vdec_buffer, list);
-+
-+ /* Tell the decoder he can recycle this buffer */
-+ writel_relaxed(tmp->index + 1, core->dos_base + MREG_TO_AMRISC);
-+
-+ dev_dbg(core->dev, "Buffer %d recycled\n", tmp->index);
-+
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ }
-+ mutex_unlock(&sess->bufs_recycle_lock);
-+
-+ usleep_range(5000, 10000);
-+ }
-+
-+ return 0;
-+}
-+
-+/* 4 point triangle */
-+static const uint32_t filt_coef[] = {
-+ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
-+ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
-+ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
-+ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
-+ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
-+ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
-+ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
-+ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
-+ 0x10303010
-+};
-+
-+static void codec_mjpeg_init_scaler(struct vdec_core *core)
-+{
-+ int i;
-+
-+ /* PSCALE cbus bmem enable */
-+ writel_relaxed(0xc000, core->dos_base + PSCALE_CTRL);
-+
-+ writel_relaxed(0, core->dos_base + PSCALE_BMEM_ADDR);
-+ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) {
-+ writel_relaxed(0, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(filt_coef[i], core->dos_base + PSCALE_BMEM_DAT);
-+ }
-+
-+ writel_relaxed(74, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x0008, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(0x60000000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed(82, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x0008, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(0x60000000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed(78, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x0008, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(0x60000000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed(86, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x0008, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(0x60000000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed(73, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x10000, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(81, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x10000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed(77, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x10000, core->dos_base + PSCALE_BMEM_DAT);
-+ writel_relaxed(85, core->dos_base + PSCALE_BMEM_ADDR);
-+ writel_relaxed(0x10000, core->dos_base + PSCALE_BMEM_DAT);
-+
-+ writel_relaxed((1 << 10), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed(0x7, core->dos_base + PSCALE_RST);
-+ writel_relaxed(0, core->dos_base + PSCALE_RST);
-+}
-+
-+static int codec_mjpeg_start(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct codec_mjpeg *mjpeg = sess->priv;
-+
-+ mjpeg = kzalloc(sizeof(*mjpeg), GFP_KERNEL);
-+ if (!mjpeg)
-+ return -ENOMEM;
-+
-+ sess->priv = mjpeg;
-+
-+ writel_relaxed((1 << 7) | (1 << 6), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed(12, core->dos_base + AV_SCRATCH_0);
-+ writel_relaxed(0x031a, core->dos_base + AV_SCRATCH_1);
-+
-+ codec_helper_set_canvases(sess, core->dos_base + AV_SCRATCH_4);
-+ codec_mjpeg_init_scaler(core);
-+
-+ writel_relaxed(0, core->dos_base + MREG_TO_AMRISC);
-+ writel_relaxed(0, core->dos_base + MREG_FROM_AMRISC);
-+ writel_relaxed(0xffff, core->dos_base + MCPU_INTR_MSK);
-+ writel_relaxed((sess->height << 4) | 0x8000, core->dos_base + MREG_DECODE_PARAM);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_MASK);
-+ writel_relaxed(8, core->dos_base + VDEC_ASSIST_AMR1_INT8);
-+
-+ /* Enable 2-plane output */
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) | (1 << 17), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ mjpeg->buffers_thread = kthread_run(codec_mjpeg_buffers_thread, sess, "buffers_done");
-+
-+ return 0;
-+}
-+
-+static int codec_mjpeg_stop(struct vdec_session *sess)
-+{
-+ struct codec_mjpeg *mjpeg = sess->priv;
-+
-+ kthread_stop(mjpeg->buffers_thread);
-+
-+ kfree(mjpeg);
-+ sess->priv = 0;
-+
-+ return 0;
-+}
-+
-+static irqreturn_t codec_mjpeg_isr(struct vdec_session *sess)
-+{
-+ u32 reg;
-+ u32 buffer_index;
-+ struct vdec_core *core = sess->core;
-+
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+
-+ reg = readl_relaxed(core->dos_base + MREG_FROM_AMRISC);
-+ if (!(reg & 0x7))
-+ return IRQ_HANDLED;
-+
-+ buffer_index = ((reg & 0x7) - 1) & 3;
-+ vdec_dst_buf_done_idx(sess, buffer_index);
-+
-+ writel_relaxed(0, core->dos_base + MREG_FROM_AMRISC);
-+ return IRQ_HANDLED;
-+}
-+
-+struct vdec_codec_ops codec_mjpeg_ops = {
-+ .start = codec_mjpeg_start,
-+ .stop = codec_mjpeg_stop,
-+ .isr = codec_mjpeg_isr,
-+ .notify_dst_buffer = vdec_queue_recycle,
-+};
-diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h
-new file mode 100644
-index 0000000..1164c61
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CODEC_MJPEG_H_
-+#define __MESON_VDEC_CODEC_MJPEG_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_codec_ops codec_mjpeg_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.c b/drivers/media/platform/meson/vdec/codec_mpeg12.c
-new file mode 100644
-index 0000000..8682adc
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mpeg12.c
-@@ -0,0 +1,183 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_mpeg12.h"
-+#include "codec_helpers.h"
-+
-+#define SIZE_WORKSPACE (2 * SZ_64K)
-+#define SIZE_CCBUF (5 * SZ_1K)
-+
-+/* DOS registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define PSCALE_CTRL 0x2444
-+
-+#define MDEC_PIC_DC_CTRL 0x2638
-+
-+#define AV_SCRATCH_0 0x2700
-+#define MREG_SEQ_INFO 0x2710
-+#define MREG_PIC_INFO 0x2714
-+#define MREG_PIC_WIDTH 0x2718
-+#define MREG_PIC_HEIGHT 0x271c
-+#define MREG_BUFFERIN 0x2720
-+#define MREG_BUFFEROUT 0x2724
-+#define MREG_CMD 0x2728
-+#define MREG_CO_MV_START 0x272c
-+#define MREG_ERROR_COUNT 0x2730
-+#define MREG_FRAME_OFFSET 0x2734
-+#define MREG_WAIT_BUFFER 0x2738
-+#define MREG_FATAL_ERROR 0x273c
-+
-+#define MPEG1_2_REG 0x3004
-+#define PIC_HEAD_INFO 0x300c
-+#define POWER_CTL_VLD 0x3020
-+#define M4_CONTROL_REG 0x30a4
-+
-+#define DOS_SW_RESET0 0xfc00
-+
-+struct codec_mpeg12 {
-+ /* Buffer for the MPEG1/2 Workspace */
-+ void *workspace_vaddr;
-+ dma_addr_t workspace_paddr;
-+
-+ /* Housekeeping thread for recycling buffers into the hardware */
-+ struct task_struct *buffers_thread;
-+};
-+
-+static int codec_mpeg12_buffers_thread(void *data)
-+{
-+ struct vdec_buffer *tmp;
-+ struct vdec_session *sess = data;
-+ struct vdec_core *core = sess->core;;
-+
-+ while (!kthread_should_stop()) {
-+ mutex_lock(&sess->bufs_recycle_lock);
-+ while (!list_empty(&sess->bufs_recycle) &&
-+ !readl_relaxed(core->dos_base + MREG_BUFFERIN))
-+ {
-+ tmp = list_first_entry(&sess->bufs_recycle, struct vdec_buffer, list);
-+
-+ /* Tell the decoder he can recycle this buffer */
-+ writel_relaxed(tmp->index + 1, core->dos_base + MREG_BUFFERIN);
-+
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ }
-+ mutex_unlock(&sess->bufs_recycle_lock);
-+
-+ usleep_range(5000, 10000);
-+ }
-+
-+ return 0;
-+}
-+
-+static int codec_mpeg12_start(struct vdec_session *sess) {
-+ struct vdec_core *core = sess->core;
-+ struct codec_mpeg12 *mpeg12 = sess->priv;
-+ int ret;
-+
-+ mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL);
-+ if (!mpeg12)
-+ return -ENOMEM;
-+
-+ sess->priv = mpeg12;
-+
-+ /* Allocate some memory for the MPEG1/2 decoder's state */
-+ mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &mpeg12->workspace_paddr, GFP_KERNEL);
-+ if (!mpeg12->workspace_vaddr) {
-+ dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n");
-+ ret = -ENOMEM;
-+ goto free_mpeg12;
-+ }
-+
-+ writel_relaxed((1<<9) | (1<<8) | (1<<7) | (1<<6) | (1<<4), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed((1 << 4), core->dos_base + POWER_CTL_VLD);
-+
-+ codec_helper_set_canvases(sess, core->dos_base + AV_SCRATCH_0);
-+ writel_relaxed(mpeg12->workspace_paddr + SIZE_CCBUF, core->dos_base + MREG_CO_MV_START);
-+
-+ writel_relaxed(0, core->dos_base + MPEG1_2_REG);
-+ writel_relaxed(0, core->dos_base + PSCALE_CTRL);
-+ writel_relaxed(0x380, core->dos_base + PIC_HEAD_INFO);
-+ writel_relaxed(0, core->dos_base + M4_CONTROL_REG);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+ writel_relaxed(0, core->dos_base + MREG_BUFFERIN);
-+ writel_relaxed(0, core->dos_base + MREG_BUFFEROUT);
-+ writel_relaxed((sess->width << 16) | sess->height, core->dos_base + MREG_CMD);
-+ writel_relaxed(0, core->dos_base + MREG_ERROR_COUNT);
-+ writel_relaxed(0, core->dos_base + MREG_FATAL_ERROR);
-+ writel_relaxed(0, core->dos_base + MREG_WAIT_BUFFER);
-+
-+ /* Enable NV21 */
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) | (1 << 17), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ mpeg12->buffers_thread = kthread_run(codec_mpeg12_buffers_thread, sess, "buffers_done");
-+
-+ return 0;
-+
-+free_mpeg12:
-+ kfree(mpeg12);
-+ return ret;
-+}
-+
-+static int codec_mpeg12_stop(struct vdec_session *sess)
-+{
-+ struct codec_mpeg12 *mpeg12 = sess->priv;
-+ struct vdec_core *core = sess->core;
-+
-+ kthread_stop(mpeg12->buffers_thread);
-+
-+ if (mpeg12->workspace_vaddr) {
-+ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr, mpeg12->workspace_paddr);
-+ mpeg12->workspace_vaddr = 0;
-+ }
-+
-+ kfree(mpeg12);
-+ sess->priv = 0;
-+
-+ return 0;
-+}
-+
-+static irqreturn_t codec_mpeg12_isr(struct vdec_session *sess)
-+{
-+ u32 reg;
-+ u32 buffer_index;
-+ struct vdec_core *core = sess->core;
-+
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+
-+ reg = readl_relaxed(core->dos_base + MREG_FATAL_ERROR);
-+ if (reg == 1)
-+ dev_err(core->dev, "MPEG12 fatal error\n");
-+
-+ reg = readl_relaxed(core->dos_base + MREG_BUFFEROUT);
-+ if (!reg)
-+ return IRQ_HANDLED;
-+
-+ if ((reg >> 16) & 0xfe)
-+ goto end;
-+
-+ buffer_index = ((reg & 0xf) - 1) & 7;
-+ vdec_dst_buf_done_idx(sess, buffer_index);
-+
-+end:
-+ writel_relaxed(0, core->dos_base + MREG_BUFFEROUT);
-+ return IRQ_HANDLED;
-+}
-+
-+struct vdec_codec_ops codec_mpeg12_ops = {
-+ .start = codec_mpeg12_start,
-+ .stop = codec_mpeg12_stop,
-+ .isr = codec_mpeg12_isr,
-+ .notify_dst_buffer = vdec_queue_recycle,
-+};
-+
-diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.h b/drivers/media/platform/meson/vdec/codec_mpeg12.h
-new file mode 100644
-index 0000000..7dc37ad
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mpeg12.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CODEC_MPEG12_H_
-+#define __MESON_VDEC_CODEC_MPEG12_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_codec_ops codec_mpeg12_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c
-new file mode 100644
-index 0000000..739b97e
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c
-@@ -0,0 +1,213 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <media/v4l2-mem2mem.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "codec_mpeg4.h"
-+#include "codec_helpers.h"
-+#include "canvas.h"
-+
-+#define SIZE_WORKSPACE (1 * SZ_1M)
-+#define DCAC_BUFF_START_IP 0x02b00000
-+
-+/* DOS registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define PSCALE_CTRL 0x2444
-+
-+#define MDEC_PIC_DC_CTRL 0x2638
-+#define MDEC_PIC_DC_THRESH 0x26e0
-+
-+#define AV_SCRATCH_0 0x2700
-+#define MP4_PIC_RATIO 0x2714
-+#define MP4_RATE 0x270c
-+#define AV_SCRATCH_4 0x2710
-+#define MP4_ERR_COUNT 0x2718
-+#define MP4_PIC_WH 0x271c
-+#define MREG_BUFFERIN 0x2720
-+#define MREG_BUFFEROUT 0x2724
-+#define MP4_NOT_CODED_CNT 0x2728
-+#define MP4_VOP_TIME_INC 0x272c
-+#define MP4_OFFSET_REG 0x2730
-+#define MP4_SYS_RATE 0x2738
-+#define MEM_OFFSET_REG 0x273c
-+#define AV_SCRATCH_G 0x2740
-+#define MREG_FATAL_ERROR 0x2754
-+
-+#define DOS_SW_RESET0 0xfc00
-+
-+struct codec_mpeg4 {
-+ /* Buffer for the MPEG1/2 Workspace */
-+ void *workspace_vaddr;
-+ dma_addr_t workspace_paddr;
-+
-+ /* Housekeeping thread for recycling buffers into the hardware */
-+ struct task_struct *buffers_thread;
-+};
-+
-+static int codec_mpeg4_buffers_thread(void *data)
-+{
-+ struct vdec_buffer *tmp;
-+ struct vdec_session *sess = data;
-+ struct vdec_core *core = sess->core;;
-+
-+ while (!kthread_should_stop()) {
-+ mutex_lock(&sess->bufs_recycle_lock);
-+ while (!list_empty(&sess->bufs_recycle) &&
-+ !readl_relaxed(core->dos_base + MREG_BUFFERIN))
-+ {
-+ tmp = list_first_entry(&sess->bufs_recycle, struct vdec_buffer, list);
-+
-+ /* Tell the decoder he can recycle this buffer */
-+ writel_relaxed(~(1 << tmp->index), core->dos_base + MREG_BUFFERIN);
-+
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ }
-+ mutex_unlock(&sess->bufs_recycle_lock);
-+
-+ usleep_range(5000, 10000);
-+ }
-+
-+ return 0;
-+}
-+
-+/* The MPEG4 canvas regs are not contiguous,
-+ * handle it specifically instead of using the helper
-+ * AV_SCRATCH_0 - AV_SCRATCH_3 ; AV_SCRATCH_G - AV_SCRATCH_J
-+ */
-+void codec_mpeg4_set_canvases(struct vdec_session *sess) {
-+ struct v4l2_m2m_buffer *buf;
-+ struct vdec_core *core = sess->core;
-+ void *current_reg = core->dos_base + AV_SCRATCH_0;
-+ u32 width = ALIGN(sess->width, 64);
-+ u32 height = ALIGN(sess->height, 64);
-+
-+ /* Setup NV12 canvases for Decoded Picture Buffer (dpb)
-+ * Map them to the user buffers' planes
-+ */
-+ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
-+ u32 buf_idx = buf->vb.vb2_buf.index;
-+ u32 cnv_y_idx = buf_idx * 2;
-+ u32 cnv_uv_idx = buf_idx * 2 + 1;
-+ dma_addr_t buf_y_paddr =
-+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
-+ dma_addr_t buf_uv_paddr =
-+ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
-+
-+ /* Y plane */
-+ vdec_canvas_setup(core->dmc_base, cnv_y_idx, buf_y_paddr, width, height, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR);
-+
-+ /* U/V plane */
-+ vdec_canvas_setup(core->dmc_base, cnv_uv_idx, buf_uv_paddr, width, height / 2, MESON_CANVAS_WRAP_NONE, MESON_CANVAS_BLKMODE_LINEAR);
-+
-+ writel_relaxed(((cnv_uv_idx) << 16) |
-+ ((cnv_uv_idx) << 8) |
-+ (cnv_y_idx), current_reg);
-+
-+ current_reg += 4;
-+ if (current_reg == core->dos_base + AV_SCRATCH_4)
-+ current_reg = core->dos_base + AV_SCRATCH_G;
-+ }
-+}
-+
-+static int codec_mpeg4_start(struct vdec_session *sess) {
-+ struct vdec_core *core = sess->core;
-+ struct codec_mpeg4 *mpeg4 = sess->priv;
-+ int ret;
-+
-+ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL);
-+ if (!mpeg4)
-+ return -ENOMEM;
-+
-+ sess->priv = mpeg4;
-+
-+ /* Allocate some memory for the MPEG4 decoder's state */
-+ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, &mpeg4->workspace_paddr, GFP_KERNEL);
-+ if (!mpeg4->workspace_vaddr) {
-+ dev_err(core->dev, "Failed to request MPEG4 Workspace\n");
-+ ret = -ENOMEM;
-+ goto free_mpeg4;
-+ }
-+
-+ writel_relaxed((1<<7) | (1<<6), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ codec_mpeg4_set_canvases(sess);
-+
-+ writel_relaxed(mpeg4->workspace_paddr - DCAC_BUFF_START_IP, core->dos_base + MEM_OFFSET_REG);
-+ writel_relaxed(0, core->dos_base + PSCALE_CTRL);
-+ writel_relaxed(0, core->dos_base + MP4_NOT_CODED_CNT);
-+ writel_relaxed(0, core->dos_base + MREG_BUFFERIN);
-+ writel_relaxed(0, core->dos_base + MREG_BUFFEROUT);
-+ writel_relaxed(0, core->dos_base + MREG_FATAL_ERROR);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_MASK);
-+ writel_relaxed(0x404038aa, core->dos_base + MDEC_PIC_DC_THRESH);
-+
-+ /* Enable NV21 */
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) | (1 << 17), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ mpeg4->buffers_thread = kthread_run(codec_mpeg4_buffers_thread, sess, "buffers_done");
-+
-+ return 0;
-+
-+free_mpeg4:
-+ kfree(mpeg4);
-+ return ret;
-+}
-+
-+static int codec_mpeg4_stop(struct vdec_session *sess)
-+{
-+ struct codec_mpeg4 *mpeg4 = sess->priv;
-+ struct vdec_core *core = sess->core;
-+
-+ kthread_stop(mpeg4->buffers_thread);
-+
-+ if (mpeg4->workspace_vaddr) {
-+ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg4->workspace_vaddr, mpeg4->workspace_paddr);
-+ mpeg4->workspace_vaddr = 0;
-+ }
-+
-+ kfree(mpeg4);
-+ sess->priv = 0;
-+
-+ return 0;
-+}
-+
-+static irqreturn_t codec_mpeg4_isr(struct vdec_session *sess)
-+{
-+ u32 reg;
-+ u32 buffer_index;
-+ struct vdec_core *core = sess->core;
-+
-+ reg = readl_relaxed(core->dos_base + MREG_FATAL_ERROR);
-+ if (reg == 1)
-+ dev_err(core->dev, "mpeg4 fatal error\n");
-+
-+ reg = readl_relaxed(core->dos_base + MREG_BUFFEROUT);
-+ if (reg) {
-+ readl_relaxed(core->dos_base + MP4_NOT_CODED_CNT);
-+ readl_relaxed(core->dos_base + MP4_VOP_TIME_INC);
-+ buffer_index = reg & 0x7;
-+ vdec_dst_buf_done_idx(sess, buffer_index);
-+ writel_relaxed(0, core->dos_base + MREG_BUFFEROUT);
-+ }
-+
-+ writel_relaxed(1, core->dos_base + ASSIST_MBOX1_CLR_REG);
-+
-+ return IRQ_HANDLED;
-+}
-+
-+struct vdec_codec_ops codec_mpeg4_ops = {
-+ .start = codec_mpeg4_start,
-+ .stop = codec_mpeg4_stop,
-+ .isr = codec_mpeg4_isr,
-+ .notify_dst_buffer = vdec_queue_recycle,
-+};
-+
-diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.h b/drivers/media/platform/meson/vdec/codec_mpeg4.h
-new file mode 100644
-index 0000000..a30ceed
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/codec_mpeg4.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CODEC_MPEG4_H_
-+#define __MESON_VDEC_CODEC_MPEG4_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_codec_ops codec_mpeg4_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c
-new file mode 100644
-index 0000000..400d6d5
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/esparser.c
-@@ -0,0 +1,320 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <linux/init.h>
-+#include <linux/ioctl.h>
-+#include <linux/list.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/reset.h>
-+#include <media/videobuf2-dma-contig.h>
-+#include <media/v4l2-mem2mem.h>
-+
-+#include "esparser.h"
-+
-+/* PARSER REGS (CBUS) */
-+#define PARSER_CONTROL 0x00
-+ #define ES_PACK_SIZE_BIT 8
-+ #define ES_WRITE BIT(5)
-+ #define ES_SEARCH BIT(1)
-+ #define ES_PARSER_START BIT(0)
-+#define PARSER_FETCH_ADDR 0x4
-+#define PARSER_FETCH_CMD 0x8
-+#define PARSER_CONFIG 0x14
-+ #define PS_CFG_MAX_FETCH_CYCLE_BIT 0
-+ #define PS_CFG_STARTCODE_WID_24_BIT 10
-+ #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
-+ #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
-+#define PFIFO_WR_PTR 0x18
-+#define PFIFO_RD_PTR 0x1c
-+#define PARSER_SEARCH_PATTERN 0x24
-+ #define ES_START_CODE_PATTERN 0x00000100
-+#define PARSER_SEARCH_MASK 0x28
-+ #define ES_START_CODE_MASK 0xffffff00
-+ #define FETCH_ENDIAN_BIT 27
-+#define PARSER_INT_ENABLE 0x2c
-+ #define PARSER_INT_HOST_EN_BIT 8
-+#define PARSER_INT_STATUS 0x30
-+ #define PARSER_INTSTAT_SC_FOUND 1
-+#define PARSER_ES_CONTROL 0x5c
-+#define PARSER_VIDEO_START_PTR 0x80
-+#define PARSER_VIDEO_END_PTR 0x84
-+#define PARSER_VIDEO_HOLE 0x90
-+
-+/* STBUF regs */
-+#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120
-+ #define MEM_BUFCTRL_MANUAL BIT(1)
-+
-+#define SEARCH_PATTERN_LEN 512
-+
-+static DECLARE_WAIT_QUEUE_HEAD(wq);
-+static int search_done;
-+
-+/* Buffer to send to the ESPARSER to signal End Of Stream.
-+ * Credits to Endless Mobile.
-+ */
-+#define EOS_TAIL_BUF_SIZE 1024
-+static const u8 eos_tail_data[] = {
-+ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7,
-+ 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63,
-+ 0x6f, 0x72, 0x65, 0x20, 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37,
-+ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, 0x50, 0x45,
-+ 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20,
-+ 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30,
-+ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
-+ 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36,
-+ 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
-+ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
-+ 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e,
-+ 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20,
-+ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x36, 0x20, 0x70,
-+ 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69,
-+ 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e,
-+ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d,
-+ 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64,
-+ 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a,
-+ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61,
-+ 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68,
-+ 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63,
-+ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66, 0x66, 0x3d, 0x30, 0x20,
-+ 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74,
-+ 0x3d, 0x32, 0x35, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d,
-+ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, 0x34, 0x30, 0x20, 0x72,
-+ 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69, 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30,
-+ 0x20, 0x72, 0x61, 0x74, 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f,
-+ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, 0x6e, 0x3d, 0x31, 0x30,
-+ 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35, 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70,
-+ 0x3d, 0x34, 0x20, 0x69, 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
-+ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
-+ 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20, 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06,
-+ 0x51, 0xe2, 0x44, 0xd4, 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01,
-+ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6, 0x57, 0xae, 0x49, 0x30,
-+ 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4, 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb,
-+ 0xd6, 0xbe, 0x5c, 0xd7, 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09,
-+ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66, 0xba, 0x9b, 0x82, 0x29,
-+ 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b
-+};
-+
-+static irqreturn_t esparser_isr(int irq, void *dev)
-+{
-+ int int_status;
-+ struct vdec_core *core = dev;
-+
-+ int_status = readl_relaxed(core->esparser_base + PARSER_INT_STATUS);
-+ writel_relaxed(int_status, core->esparser_base + PARSER_INT_STATUS);
-+
-+ dev_dbg(core->dev, "esparser_isr, status = %08X\n", int_status);
-+
-+ if (int_status & PARSER_INTSTAT_SC_FOUND) {
-+ writel_relaxed(0, core->esparser_base + PFIFO_RD_PTR);
-+ writel_relaxed(0, core->esparser_base + PFIFO_WR_PTR);
-+ search_done = 1;
-+ wake_up_interruptible(&wq);
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/* Add a start code at the end of the buffer
-+ * to trigger the esparser interrupt
-+ */
-+static void esparser_append_start_code(struct vb2_buffer *vb)
-+{
-+ u8 *vaddr = vb2_plane_vaddr(vb, 0) + vb2_get_plane_payload(vb, 0);
-+
-+ vaddr[0] = 0x00;
-+ vaddr[1] = 0x00;
-+ vaddr[2] = 0x01;
-+ vaddr[3] = 0xff;
-+}
-+
-+static int
-+esparser_write_data(struct vdec_core *core, dma_addr_t addr, u32 size)
-+{
-+ writel_relaxed(0, core->esparser_base + PFIFO_RD_PTR);
-+ writel_relaxed(0, core->esparser_base + PFIFO_WR_PTR);
-+ writel_relaxed(ES_WRITE | ES_PARSER_START | ES_SEARCH | (size << ES_PACK_SIZE_BIT), core->esparser_base + PARSER_CONTROL);
-+
-+ writel_relaxed(addr, core->esparser_base + PARSER_FETCH_ADDR);
-+ writel_relaxed((7 << FETCH_ENDIAN_BIT) | (size + 512), core->esparser_base + PARSER_FETCH_CMD);
-+ search_done = 0;
-+
-+ return wait_event_interruptible_timeout(wq, search_done != 0, HZ/5);
-+}
-+
-+static u32 esparser_vififo_get_free_space(struct vdec_session *sess)
-+{
-+ u32 vififo_usage;
-+ struct vdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
-+ struct vdec_core *core = sess->core;
-+
-+ vififo_usage = vdec_ops->vififo_level(sess);
-+ vififo_usage += readl_relaxed(core->esparser_base + PARSER_VIDEO_HOLE);
-+ vififo_usage += (6 * SZ_1K);
-+
-+ if (vififo_usage > sess->vififo_size) {
-+ dev_warn(sess->core->dev,
-+ "VIFIFO usage (%u) > VIFIFO size (%u)\n",
-+ vififo_usage, sess->vififo_size);
-+ return 0;
-+ }
-+
-+ return sess->vififo_size - vififo_usage;
-+}
-+
-+int esparser_queue_eos(struct vdec_session *sess)
-+{
-+ struct device *dev = sess->core->dev;
-+ struct vdec_core *core = sess->core;
-+ void *eos_vaddr;
-+ dma_addr_t eos_paddr;
-+ int ret;
-+
-+ eos_vaddr = dma_alloc_coherent(dev, EOS_TAIL_BUF_SIZE + 512, &eos_paddr, GFP_KERNEL);
-+ if (!eos_vaddr)
-+ return -ENOMEM;
-+
-+ sess->should_stop = 1;
-+
-+ memcpy(eos_vaddr, eos_tail_data, sizeof(eos_tail_data));
-+ ret = esparser_write_data(core, eos_paddr, EOS_TAIL_BUF_SIZE);
-+ dma_free_coherent(dev, EOS_TAIL_BUF_SIZE + 512,
-+ eos_vaddr, eos_paddr);
-+
-+ return ret;
-+}
-+
-+static int esparser_queue(struct vdec_session *sess, struct vb2_v4l2_buffer *vbuf)
-+{
-+ int ret;
-+ struct vb2_buffer *vb = &vbuf->vb2_buf;
-+ struct vdec_core *core = sess->core;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+ u32 num_dst_bufs = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
-+ u32 payload_size = vb2_get_plane_payload(vb, 0);
-+ dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
-+
-+ if (!payload_size) {
-+ esparser_queue_eos(sess);
-+ return 0;
-+ }
-+
-+ if (codec_ops->num_pending_bufs)
-+ num_dst_bufs += codec_ops->num_pending_bufs(sess);
-+
-+ if (esparser_vififo_get_free_space(sess) < payload_size ||
-+ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
-+ return -EAGAIN;
-+
-+ v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
-+ vdec_add_ts_reorder(sess, vb->timestamp);
-+
-+ esparser_append_start_code(vb);
-+ ret = esparser_write_data(core, phy, payload_size);
-+
-+ if (ret > 0) {
-+ vbuf->flags = 0;
-+ vbuf->field = V4L2_FIELD_NONE;
-+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
-+ } else if (ret <= 0) {
-+ printk("ESPARSER input parsing error\n");
-+ vdec_remove_ts(sess, vb->timestamp);
-+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
-+ writel_relaxed(0, core->esparser_base + PARSER_FETCH_CMD);
-+ }
-+
-+ if (vbuf->flags & V4L2_BUF_FLAG_LAST)
-+ esparser_queue_eos(sess);
-+
-+ return 0;
-+}
-+
-+void esparser_queue_all_src(struct work_struct *work)
-+{
-+ struct v4l2_m2m_buffer *buf, *n;
-+ struct vdec_session *sess =
-+ container_of(work, struct vdec_session, esparser_queue_work);
-+
-+ mutex_lock(&sess->lock);
-+ v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) {
-+ if (esparser_queue(sess, &buf->vb) < 0)
-+ break;
-+
-+ atomic_inc(&sess->esparser_queued_bufs);
-+ }
-+ mutex_unlock(&sess->lock);
-+}
-+
-+int esparser_power_up(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct vdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
-+
-+ reset_control_reset(core->esparser_reset);
-+ writel_relaxed((10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
-+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
-+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT),
-+ core->esparser_base + PARSER_CONFIG);
-+
-+ writel_relaxed(0, core->esparser_base + PFIFO_RD_PTR);
-+ writel_relaxed(0, core->esparser_base + PFIFO_WR_PTR);
-+
-+ writel_relaxed(ES_START_CODE_PATTERN, core->esparser_base + PARSER_SEARCH_PATTERN);
-+ writel_relaxed(ES_START_CODE_MASK, core->esparser_base + PARSER_SEARCH_MASK);
-+
-+ writel_relaxed((10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
-+ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
-+ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) |
-+ (2 << PS_CFG_STARTCODE_WID_24_BIT),
-+ core->esparser_base + PARSER_CONFIG);
-+
-+ writel_relaxed((ES_SEARCH | ES_PARSER_START), core->esparser_base + PARSER_CONTROL);
-+
-+ writel_relaxed(sess->vififo_paddr, core->esparser_base + PARSER_VIDEO_START_PTR);
-+ writel_relaxed(sess->vififo_paddr + sess->vififo_size - 8, core->esparser_base + PARSER_VIDEO_END_PTR);
-+ writel_relaxed(readl_relaxed(core->esparser_base + PARSER_ES_CONTROL) & ~1, core->esparser_base + PARSER_ES_CONTROL);
-+
-+ if (vdec_ops->conf_esparser)
-+ vdec_ops->conf_esparser(sess);
-+
-+ writel_relaxed(0xffff, core->esparser_base + PARSER_INT_STATUS);
-+ writel_relaxed(1 << PARSER_INT_HOST_EN_BIT, core->esparser_base + PARSER_INT_ENABLE);
-+
-+ return 0;
-+}
-+
-+int esparser_init(struct platform_device *pdev, struct vdec_core *core)
-+{
-+ struct device *dev = &pdev->dev;
-+ int ret;
-+ int irq;
-+
-+ /* TODO: name the IRQs */
-+ irq = platform_get_irq(pdev, 1);
-+ if (irq < 0) {
-+ dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n");
-+ return irq;
-+ }
-+
-+ printk("Requesting IRQ %d\n", irq);
-+
-+ ret = devm_request_irq(dev, irq, esparser_isr,
-+ IRQF_SHARED,
-+ "esparserirq", core);
-+ if (ret) {
-+ dev_err(dev, "Failed requesting ESPARSER IRQ\n");
-+ return ret;
-+ }
-+
-+ core->esparser_reset = devm_reset_control_get_exclusive(dev,
-+ "esparser");
-+ if (IS_ERR(core->esparser_reset)) {
-+ dev_err(dev, "Failed to get esparser_reset\n");
-+ return PTR_ERR(core->esparser_reset);
-+ }
-+
-+ return 0;
-+}
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/esparser.h b/drivers/media/platform/meson/vdec/esparser.h
-new file mode 100644
-index 0000000..f9c8b31
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/esparser.h
-@@ -0,0 +1,16 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_ESPARSER_H_
-+#define __MESON_VDEC_ESPARSER_H_
-+
-+#include "vdec.h"
-+
-+int esparser_init(struct platform_device *pdev, struct vdec_core *core);
-+int esparser_power_up(struct vdec_session *sess);
-+int esparser_queue_eos(struct vdec_session *sess);
-+void esparser_queue_all_src(struct work_struct *work);
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h
-new file mode 100644
-index 0000000..ae9b38e
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/hevc_regs.h
-@@ -0,0 +1,742 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
-+ */
-+
-+#ifndef HEVC_REGS_HEADERS__
-+#define HEVC_REGS_HEADERS__
-+/*add from M8M2*/
-+#define HEVC_ASSIST_AFIFO_CTRL (0x3001 * 4)
-+#define HEVC_ASSIST_AFIFO_CTRL1 (0x3002 * 4)
-+#define HEVC_ASSIST_GCLK_EN (0x3003 * 4)
-+#define HEVC_ASSIST_SW_RESET (0x3004 * 4)
-+#define HEVC_ASSIST_AMR1_INT0 (0x3025 * 4)
-+#define HEVC_ASSIST_AMR1_INT1 (0x3026 * 4)
-+#define HEVC_ASSIST_AMR1_INT2 (0x3027 * 4)
-+#define HEVC_ASSIST_AMR1_INT3 (0x3028 * 4)
-+#define HEVC_ASSIST_AMR1_INT4 (0x3029 * 4)
-+#define HEVC_ASSIST_AMR1_INT5 (0x302a * 4)
-+#define HEVC_ASSIST_AMR1_INT6 (0x302b * 4)
-+#define HEVC_ASSIST_AMR1_INT7 (0x302c * 4)
-+#define HEVC_ASSIST_AMR1_INT8 (0x302d * 4)
-+#define HEVC_ASSIST_AMR1_INT9 (0x302e * 4)
-+#define HEVC_ASSIST_AMR1_INTA (0x302f * 4)
-+#define HEVC_ASSIST_AMR1_INTB (0x3030 * 4)
-+#define HEVC_ASSIST_AMR1_INTC (0x3031 * 4)
-+#define HEVC_ASSIST_AMR1_INTD (0x3032 * 4)
-+#define HEVC_ASSIST_AMR1_INTE (0x3033 * 4)
-+#define HEVC_ASSIST_AMR1_INTF (0x3034 * 4)
-+#define HEVC_ASSIST_AMR2_INT0 (0x3035 * 4)
-+#define HEVC_ASSIST_AMR2_INT1 (0x3036 * 4)
-+#define HEVC_ASSIST_AMR2_INT2 (0x3037 * 4)
-+#define HEVC_ASSIST_AMR2_INT3 (0x3038 * 4)
-+#define HEVC_ASSIST_AMR2_INT4 (0x3039 * 4)
-+#define HEVC_ASSIST_AMR2_INT5 (0x303a * 4)
-+#define HEVC_ASSIST_AMR2_INT6 (0x303b * 4)
-+#define HEVC_ASSIST_AMR2_INT7 (0x303c * 4)
-+#define HEVC_ASSIST_AMR2_INT8 (0x303d * 4)
-+#define HEVC_ASSIST_AMR2_INT9 (0x303e * 4)
-+#define HEVC_ASSIST_AMR2_INTA (0x303f * 4)
-+#define HEVC_ASSIST_AMR2_INTB (0x3040 * 4)
-+#define HEVC_ASSIST_AMR2_INTC (0x3041 * 4)
-+#define HEVC_ASSIST_AMR2_INTD (0x3042 * 4)
-+#define HEVC_ASSIST_AMR2_INTE (0x3043 * 4)
-+#define HEVC_ASSIST_AMR2_INTF (0x3044 * 4)
-+#define HEVC_ASSIST_MBX_SSEL (0x3045 * 4)
-+#define HEVC_ASSIST_TIMER0_LO (0x3060 * 4)
-+#define HEVC_ASSIST_TIMER0_HI (0x3061 * 4)
-+#define HEVC_ASSIST_TIMER1_LO (0x3062 * 4)
-+#define HEVC_ASSIST_TIMER1_HI (0x3063 * 4)
-+#define HEVC_ASSIST_DMA_INT (0x3064 * 4)
-+#define HEVC_ASSIST_DMA_INT_MSK (0x3065 * 4)
-+#define HEVC_ASSIST_DMA_INT2 (0x3066 * 4)
-+#define HEVC_ASSIST_DMA_INT_MSK2 (0x3067 * 4)
-+#define HEVC_ASSIST_MBOX0_IRQ_REG (0x3070 * 4)
-+#define HEVC_ASSIST_MBOX0_CLR_REG (0x3071 * 4)
-+#define HEVC_ASSIST_MBOX0_MASK (0x3072 * 4)
-+#define HEVC_ASSIST_MBOX0_FIQ_SEL (0x3073 * 4)
-+#define HEVC_ASSIST_MBOX1_IRQ_REG (0x3074 * 4)
-+#define HEVC_ASSIST_MBOX1_CLR_REG (0x3075 * 4)
-+#define HEVC_ASSIST_MBOX1_MASK (0x3076 * 4)
-+#define HEVC_ASSIST_MBOX1_FIQ_SEL (0x3077 * 4)
-+#define HEVC_ASSIST_MBOX2_IRQ_REG (0x3078 * 4)
-+#define HEVC_ASSIST_MBOX2_CLR_REG (0x3079 * 4)
-+#define HEVC_ASSIST_MBOX2_MASK (0x307a * 4)
-+#define HEVC_ASSIST_MBOX2_FIQ_SEL (0x307b * 4)
-+#define HEVC_ASSIST_AXI_CTRL (0x307c * 4)
-+#define HEVC_ASSIST_AXI_STATUS (0x307d * 4)
-+#define HEVC_ASSIST_SCRATCH_0 (0x30c0 * 4)
-+#define HEVC_ASSIST_SCRATCH_1 (0x30c1 * 4)
-+#define HEVC_ASSIST_SCRATCH_2 (0x30c2 * 4)
-+#define HEVC_ASSIST_SCRATCH_3 (0x30c3 * 4)
-+#define HEVC_ASSIST_SCRATCH_4 (0x30c4 * 4)
-+#define HEVC_ASSIST_SCRATCH_5 (0x30c5 * 4)
-+#define HEVC_ASSIST_SCRATCH_6 (0x30c6 * 4)
-+#define HEVC_ASSIST_SCRATCH_7 (0x30c7 * 4)
-+#define HEVC_ASSIST_SCRATCH_8 (0x30c8 * 4)
-+#define HEVC_ASSIST_SCRATCH_9 (0x30c9 * 4)
-+#define HEVC_ASSIST_SCRATCH_A (0x30ca * 4)
-+#define HEVC_ASSIST_SCRATCH_B (0x30cb * 4)
-+#define HEVC_ASSIST_SCRATCH_C (0x30cc * 4)
-+#define HEVC_ASSIST_SCRATCH_D (0x30cd * 4)
-+#define HEVC_ASSIST_SCRATCH_E (0x30ce * 4)
-+#define HEVC_ASSIST_SCRATCH_F (0x30cf * 4)
-+#define HEVC_ASSIST_SCRATCH_G (0x30d0 * 4)
-+#define HEVC_ASSIST_SCRATCH_H (0x30d1 * 4)
-+#define HEVC_ASSIST_SCRATCH_I (0x30d2 * 4)
-+#define HEVC_ASSIST_SCRATCH_J (0x30d3 * 4)
-+#define HEVC_ASSIST_SCRATCH_K (0x30d4 * 4)
-+#define HEVC_ASSIST_SCRATCH_L (0x30d5 * 4)
-+#define HEVC_ASSIST_SCRATCH_M (0x30d6 * 4)
-+#define HEVC_ASSIST_SCRATCH_N (0x30d7 * 4)
-+#define HEVC_PARSER_VERSION (0x3100 * 4)
-+#define HEVC_STREAM_CONTROL (0x3101 * 4)
-+#define HEVC_STREAM_START_ADDR (0x3102 * 4)
-+#define HEVC_STREAM_END_ADDR (0x3103 * 4)
-+#define HEVC_STREAM_WR_PTR (0x3104 * 4)
-+#define HEVC_STREAM_RD_PTR (0x3105 * 4)
-+#define HEVC_STREAM_LEVEL (0x3106 * 4)
-+#define HEVC_STREAM_FIFO_CTL (0x3107 * 4)
-+#define HEVC_SHIFT_CONTROL (0x3108 * 4)
-+#define HEVC_SHIFT_STARTCODE (0x3109 * 4)
-+#define HEVC_SHIFT_EMULATECODE (0x310a * 4)
-+#define HEVC_SHIFT_STATUS (0x310b * 4)
-+#define HEVC_SHIFTED_DATA (0x310c * 4)
-+#define HEVC_SHIFT_BYTE_COUNT (0x310d * 4)
-+#define HEVC_SHIFT_COMMAND (0x310e * 4)
-+#define HEVC_ELEMENT_RESULT (0x310f * 4)
-+#define HEVC_CABAC_CONTROL (0x3110 * 4)
-+#define HEVC_PARSER_SLICE_INFO (0x3111 * 4)
-+#define HEVC_PARSER_CMD_WRITE (0x3112 * 4)
-+#define HEVC_PARSER_CORE_CONTROL (0x3113 * 4)
-+#define HEVC_PARSER_CMD_FETCH (0x3114 * 4)
-+#define HEVC_PARSER_CMD_STATUS (0x3115 * 4)
-+#define HEVC_PARSER_LCU_INFO (0x3116 * 4)
-+#define HEVC_PARSER_HEADER_INFO (0x3117 * 4)
-+#define HEVC_PARSER_RESULT_0 (0x3118 * 4)
-+#define HEVC_PARSER_RESULT_1 (0x3119 * 4)
-+#define HEVC_PARSER_RESULT_2 (0x311a * 4)
-+#define HEVC_PARSER_RESULT_3 (0x311b * 4)
-+#define HEVC_CABAC_TOP_INFO (0x311c * 4)
-+#define HEVC_CABAC_TOP_INFO_2 (0x311d * 4)
-+#define HEVC_CABAC_LEFT_INFO (0x311e * 4)
-+#define HEVC_CABAC_LEFT_INFO_2 (0x311f * 4)
-+#define HEVC_PARSER_INT_CONTROL (0x3120 * 4)
-+#define HEVC_PARSER_INT_STATUS (0x3121 * 4)
-+#define HEVC_PARSER_IF_CONTROL (0x3122 * 4)
-+#define HEVC_PARSER_PICTURE_SIZE (0x3123 * 4)
-+#define HEVC_PARSER_LCU_START (0x3124 * 4)
-+#define HEVC_PARSER_HEADER_INFO2 (0x3125 * 4)
-+#define HEVC_PARSER_QUANT_READ (0x3126 * 4)
-+#define HEVC_PARSER_RESERVED_27 (0x3127 * 4)
-+#define HEVC_PARSER_CMD_SKIP_0 (0x3128 * 4)
-+#define HEVC_PARSER_CMD_SKIP_1 (0x3129 * 4)
-+#define HEVC_PARSER_CMD_SKIP_2 (0x312a * 4)
-+#define HEVC_PARSER_MANUAL_CMD (0x312b * 4)
-+#define HEVC_PARSER_MEM_RD_ADDR (0x312c * 4)
-+#define HEVC_PARSER_MEM_WR_ADDR (0x312d * 4)
-+#define HEVC_PARSER_MEM_RW_DATA (0x312e * 4)
-+#define HEVC_SAO_IF_STATUS (0x3130 * 4)
-+#define HEVC_SAO_IF_DATA_Y (0x3131 * 4)
-+#define HEVC_SAO_IF_DATA_U (0x3132 * 4)
-+#define HEVC_SAO_IF_DATA_V (0x3133 * 4)
-+#define HEVC_STREAM_SWAP_ADDR (0x3134 * 4)
-+#define HEVC_STREAM_SWAP_CTRL (0x3135 * 4)
-+#define HEVC_IQIT_IF_WAIT_CNT (0x3136 * 4)
-+#define HEVC_MPRED_IF_WAIT_CNT (0x3137 * 4)
-+#define HEVC_SAO_IF_WAIT_CNT (0x3138 * 4)
-+#define HEVC_PARSER_DEBUG_IDX (0x313e * 4)
-+#define HEVC_PARSER_DEBUG_DAT (0x313f * 4)
-+#define HEVC_MPRED_VERSION (0x3200 * 4)
-+#define HEVC_MPRED_CTRL0 (0x3201 * 4)
-+#define HEVC_MPRED_CTRL1 (0x3202 * 4)
-+#define HEVC_MPRED_INT_EN (0x3203 * 4)
-+#define HEVC_MPRED_INT_STATUS (0x3204 * 4)
-+#define HEVC_MPRED_PIC_SIZE (0x3205 * 4)
-+#define HEVC_MPRED_PIC_SIZE_LCU (0x3206 * 4)
-+#define HEVC_MPRED_TILE_START (0x3207 * 4)
-+#define HEVC_MPRED_TILE_SIZE_LCU (0x3208 * 4)
-+#define HEVC_MPRED_REF_NUM (0x3209 * 4)
-+#define HEVC_MPRED_LT_REF (0x320a * 4)
-+#define HEVC_MPRED_LT_COLREF (0x320b * 4)
-+#define HEVC_MPRED_REF_EN_L0 (0x320c * 4)
-+#define HEVC_MPRED_REF_EN_L1 (0x320d * 4)
-+#define HEVC_MPRED_COLREF_EN_L0 (0x320e * 4)
-+#define HEVC_MPRED_COLREF_EN_L1 (0x320f * 4)
-+#define HEVC_MPRED_AXI_WCTRL (0x3210 * 4)
-+#define HEVC_MPRED_AXI_RCTRL (0x3211 * 4)
-+#define HEVC_MPRED_ABV_START_ADDR (0x3212 * 4)
-+#define HEVC_MPRED_MV_WR_START_ADDR (0x3213 * 4)
-+#define HEVC_MPRED_MV_RD_START_ADDR (0x3214 * 4)
-+#define HEVC_MPRED_MV_WPTR (0x3215 * 4)
-+#define HEVC_MPRED_MV_RPTR (0x3216 * 4)
-+#define HEVC_MPRED_MV_WR_ROW_JUMP (0x3217 * 4)
-+#define HEVC_MPRED_MV_RD_ROW_JUMP (0x3218 * 4)
-+#define HEVC_MPRED_CURR_LCU (0x3219 * 4)
-+#define HEVC_MPRED_ABV_WPTR (0x321a * 4)
-+#define HEVC_MPRED_ABV_RPTR (0x321b * 4)
-+#define HEVC_MPRED_CTRL2 (0x321c * 4)
-+#define HEVC_MPRED_CTRL3 (0x321d * 4)
-+#define HEVC_MPRED_MV_WLCUY (0x321e * 4)
-+#define HEVC_MPRED_MV_RLCUY (0x321f * 4)
-+#define HEVC_MPRED_L0_REF00_POC (0x3220 * 4)
-+#define HEVC_MPRED_L0_REF01_POC (0x3221 * 4)
-+#define HEVC_MPRED_L0_REF02_POC (0x3222 * 4)
-+#define HEVC_MPRED_L0_REF03_POC (0x3223 * 4)
-+#define HEVC_MPRED_L0_REF04_POC (0x3224 * 4)
-+#define HEVC_MPRED_L0_REF05_POC (0x3225 * 4)
-+#define HEVC_MPRED_L0_REF06_POC (0x3226 * 4)
-+#define HEVC_MPRED_L0_REF07_POC (0x3227 * 4)
-+#define HEVC_MPRED_L0_REF08_POC (0x3228 * 4)
-+#define HEVC_MPRED_L0_REF09_POC (0x3229 * 4)
-+#define HEVC_MPRED_L0_REF10_POC (0x322a * 4)
-+#define HEVC_MPRED_L0_REF11_POC (0x322b * 4)
-+#define HEVC_MPRED_L0_REF12_POC (0x322c * 4)
-+#define HEVC_MPRED_L0_REF13_POC (0x322d * 4)
-+#define HEVC_MPRED_L0_REF14_POC (0x322e * 4)
-+#define HEVC_MPRED_L0_REF15_POC (0x322f * 4)
-+#define HEVC_MPRED_L1_REF00_POC (0x3230 * 4)
-+#define HEVC_MPRED_L1_REF01_POC (0x3231 * 4)
-+#define HEVC_MPRED_L1_REF02_POC (0x3232 * 4)
-+#define HEVC_MPRED_L1_REF03_POC (0x3233 * 4)
-+#define HEVC_MPRED_L1_REF04_POC (0x3234 * 4)
-+#define HEVC_MPRED_L1_REF05_POC (0x3235 * 4)
-+#define HEVC_MPRED_L1_REF06_POC (0x3236 * 4)
-+#define HEVC_MPRED_L1_REF07_POC (0x3237 * 4)
-+#define HEVC_MPRED_L1_REF08_POC (0x3238 * 4)
-+#define HEVC_MPRED_L1_REF09_POC (0x3239 * 4)
-+#define HEVC_MPRED_L1_REF10_POC (0x323a * 4)
-+#define HEVC_MPRED_L1_REF11_POC (0x323b * 4)
-+#define HEVC_MPRED_L1_REF12_POC (0x323c * 4)
-+#define HEVC_MPRED_L1_REF13_POC (0x323d * 4)
-+#define HEVC_MPRED_L1_REF14_POC (0x323e * 4)
-+#define HEVC_MPRED_L1_REF15_POC (0x323f * 4)
-+#define HEVC_MPRED_PIC_SIZE_EXT (0x3240 * 4)
-+#define HEVC_MPRED_DBG_MODE0 (0x3241 * 4)
-+#define HEVC_MPRED_DBG_MODE1 (0x3242 * 4)
-+#define HEVC_MPRED_DBG2_MODE (0x3243 * 4)
-+#define HEVC_MPRED_IMP_CMD0 (0x3244 * 4)
-+#define HEVC_MPRED_IMP_CMD1 (0x3245 * 4)
-+#define HEVC_MPRED_IMP_CMD2 (0x3246 * 4)
-+#define HEVC_MPRED_IMP_CMD3 (0x3247 * 4)
-+#define HEVC_MPRED_DBG2_DATA_0 (0x3248 * 4)
-+#define HEVC_MPRED_DBG2_DATA_1 (0x3249 * 4)
-+#define HEVC_MPRED_DBG2_DATA_2 (0x324a * 4)
-+#define HEVC_MPRED_DBG2_DATA_3 (0x324b * 4)
-+#define HEVC_MPRED_DBG_DATA_0 (0x3250 * 4)
-+#define HEVC_MPRED_DBG_DATA_1 (0x3251 * 4)
-+#define HEVC_MPRED_DBG_DATA_2 (0x3252 * 4)
-+#define HEVC_MPRED_DBG_DATA_3 (0x3253 * 4)
-+#define HEVC_MPRED_DBG_DATA_4 (0x3254 * 4)
-+#define HEVC_MPRED_DBG_DATA_5 (0x3255 * 4)
-+#define HEVC_MPRED_DBG_DATA_6 (0x3256 * 4)
-+#define HEVC_MPRED_DBG_DATA_7 (0x3257 * 4)
-+#define HEVC_MPRED_CUR_POC (0x3260 * 4)
-+#define HEVC_MPRED_COL_POC (0x3261 * 4)
-+#define HEVC_MPRED_MV_RD_END_ADDR (0x3262 * 4)
-+#define HEVCD_IPP_TOP_CNTL (0x3400 * 4)
-+#define HEVCD_IPP_TOP_STATUS (0x3401 * 4)
-+#define HEVCD_IPP_TOP_FRMCONFIG (0x3402 * 4)
-+#define HEVCD_IPP_TOP_TILECONFIG1 (0x3403 * 4)
-+#define HEVCD_IPP_TOP_TILECONFIG2 (0x3404 * 4)
-+#define HEVCD_IPP_TOP_TILECONFIG3 (0x3405 * 4)
-+#define HEVCD_IPP_TOP_LCUCONFIG (0x3406 * 4)
-+#define HEVCD_IPP_TOP_FRMCTL (0x3407 * 4)
-+#define HEVCD_IPP_CONFIG (0x3408 * 4)
-+#define HEVCD_IPP_LINEBUFF_BASE (0x3409 * 4)
-+#define HEVCD_IPP_INTR_MASK (0x340a * 4)
-+#define HEVCD_IPP_AXIIF_CONFIG (0x340b * 4)
-+#define HEVCD_IPP_BITDEPTH_CONFIG (0x340c * 4)
-+#define HEVCD_IPP_SWMPREDIF_CONFIG (0x3410 * 4)
-+#define HEVCD_IPP_SWMPREDIF_STATUS (0x3411 * 4)
-+#define HEVCD_IPP_SWMPREDIF_CTBINFO (0x3412 * 4)
-+#define HEVCD_IPP_SWMPREDIF_PUINFO0 (0x3413 * 4)
-+#define HEVCD_IPP_SWMPREDIF_PUINFO1 (0x3414 * 4)
-+#define HEVCD_IPP_SWMPREDIF_PUINFO2 (0x3415 * 4)
-+#define HEVCD_IPP_SWMPREDIF_PUINFO3 (0x3416 * 4)
-+#define HEVCD_IPP_DYNCLKGATE_CONFIG (0x3420 * 4)
-+#define HEVCD_IPP_DYNCLKGATE_STATUS (0x3421 * 4)
-+#define HEVCD_IPP_DBG_SEL (0x3430 * 4)
-+#define HEVCD_IPP_DBG_DATA (0x3431 * 4)
-+#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR (0x3460 * 4)
-+#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR (0x3461 * 4)
-+#define HEVCD_MPP_ANC2AXI_TBL_WDATA_ADDR (0x3462 * 4)
-+#define HEVCD_MPP_ANC2AXI_TBL_RDATA_ADDR (0x3463 * 4)
-+#define HEVCD_MPP_WEIGHTPRED_CNTL_ADDR (0x347b * 4)
-+#define HEVCD_MPP_L0_WEIGHT_FLAG_ADDR (0x347c * 4)
-+#define HEVCD_MPP_L1_WEIGHT_FLAG_ADDR (0x347d * 4)
-+#define HEVCD_MPP_YLOG2WGHTDENOM_ADDR (0x347e * 4)
-+#define HEVCD_MPP_DELTACLOG2WGHTDENOM_ADDR (0x347f * 4)
-+#define HEVCD_MPP_WEIGHT_ADDR (0x3480 * 4)
-+#define HEVCD_MPP_WEIGHT_DATA (0x3481 * 4)
-+#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR (0x34c0 * 4)
-+#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR (0x34c1 * 4)
-+#define HEVCD_MPP_DECOMP_CTL1 (0x34c2 * 4)
-+#define HEVCD_MPP_DECOMP_CTL2 (0x34c3 * 4)
-+#define HEVCD_MCRCC_CTL1 (0x34f0 * 4)
-+#define HEVCD_MCRCC_CTL2 (0x34f1 * 4)
-+#define HEVCD_MCRCC_CTL3 (0x34f2 * 4)
-+#define HEVCD_MCRCC_PERFMON_CTL (0x34f3 * 4)
-+#define HEVCD_MCRCC_PERFMON_DATA (0x34f4 * 4)
-+#define HEVC_DBLK_CFG0 (0x3500 * 4)
-+#define HEVC_DBLK_CFG1 (0x3501 * 4)
-+#define HEVC_DBLK_CFG2 (0x3502 * 4)
-+#define HEVC_DBLK_CFG3 (0x3503 * 4)
-+#define HEVC_DBLK_CFG4 (0x3504 * 4)
-+#define HEVC_DBLK_CFG5 (0x3505 * 4)
-+#define HEVC_DBLK_CFG6 (0x3506 * 4)
-+#define HEVC_DBLK_CFG7 (0x3507 * 4)
-+#define HEVC_DBLK_CFG8 (0x3508 * 4)
-+#define HEVC_DBLK_CFG9 (0x3509 * 4)
-+#define HEVC_DBLK_CFGA (0x350a * 4)
-+#define HEVC_DBLK_STS0 (0x350b * 4)
-+#define HEVC_DBLK_STS1 (0x350c * 4)
-+#define HEVC_SAO_VERSION (0x3600 * 4)
-+#define HEVC_SAO_CTRL0 (0x3601 * 4)
-+#define HEVC_SAO_CTRL1 (0x3602 * 4)
-+#define HEVC_SAO_INT_EN (0x3603 * 4)
-+#define HEVC_SAO_INT_STATUS (0x3604 * 4)
-+#define HEVC_SAO_PIC_SIZE (0x3605 * 4)
-+#define HEVC_SAO_PIC_SIZE_LCU (0x3606 * 4)
-+#define HEVC_SAO_TILE_START (0x3607 * 4)
-+#define HEVC_SAO_TILE_SIZE_LCU (0x3608 * 4)
-+#define HEVC_SAO_AXI_WCTRL (0x3609 * 4)
-+#define HEVC_SAO_AXI_RCTRL (0x360a * 4)
-+#define HEVC_SAO_Y_START_ADDR (0x360b * 4)
-+#define HEVC_SAO_Y_LENGTH (0x360c * 4)
-+#define HEVC_SAO_C_START_ADDR (0x360d * 4)
-+#define HEVC_SAO_C_LENGTH (0x360e * 4)
-+#define HEVC_SAO_Y_WPTR (0x360f * 4)
-+#define HEVC_SAO_C_WPTR (0x3610 * 4)
-+#define HEVC_SAO_ABV_START_ADDR (0x3611 * 4)
-+#define HEVC_SAO_VB_WR_START_ADDR (0x3612 * 4)
-+#define HEVC_SAO_VB_RD_START_ADDR (0x3613 * 4)
-+#define HEVC_SAO_ABV_WPTR (0x3614 * 4)
-+#define HEVC_SAO_ABV_RPTR (0x3615 * 4)
-+#define HEVC_SAO_VB_WPTR (0x3616 * 4)
-+#define HEVC_SAO_VB_RPTR (0x3617 * 4)
-+#define HEVC_SAO_DBG_MODE0 (0x361e * 4)
-+#define HEVC_SAO_DBG_MODE1 (0x361f * 4)
-+#define HEVC_SAO_CTRL2 (0x3620 * 4)
-+#define HEVC_SAO_CTRL3 (0x3621 * 4)
-+#define HEVC_SAO_CTRL4 (0x3622 * 4)
-+#define HEVC_SAO_CTRL5 (0x3623 * 4)
-+#define HEVC_SAO_CTRL6 (0x3624 * 4)
-+#define HEVC_SAO_CTRL7 (0x3625 * 4)
-+#define HEVC_SAO_DBG_DATA_0 (0x3630 * 4)
-+#define HEVC_SAO_DBG_DATA_1 (0x3631 * 4)
-+#define HEVC_SAO_DBG_DATA_2 (0x3632 * 4)
-+#define HEVC_SAO_DBG_DATA_3 (0x3633 * 4)
-+#define HEVC_SAO_DBG_DATA_4 (0x3634 * 4)
-+#define HEVC_SAO_DBG_DATA_5 (0x3635 * 4)
-+#define HEVC_SAO_DBG_DATA_6 (0x3636 * 4)
-+#define HEVC_SAO_DBG_DATA_7 (0x3637 * 4)
-+#define HEVC_IQIT_CLK_RST_CTRL (0x3700 * 4)
-+#define HEVC_IQIT_DEQUANT_CTRL (0x3701 * 4)
-+#define HEVC_IQIT_SCALELUT_WR_ADDR (0x3702 * 4)
-+#define HEVC_IQIT_SCALELUT_RD_ADDR (0x3703 * 4)
-+#define HEVC_IQIT_SCALELUT_DATA (0x3704 * 4)
-+#define HEVC_IQIT_SCALELUT_IDX_4 (0x3705 * 4)
-+#define HEVC_IQIT_SCALELUT_IDX_8 (0x3706 * 4)
-+#define HEVC_IQIT_SCALELUT_IDX_16_32 (0x3707 * 4)
-+#define HEVC_IQIT_STAT_GEN0 (0x3708 * 4)
-+#define HEVC_QP_WRITE (0x3709 * 4)
-+#define HEVC_IQIT_STAT_GEN1 (0x370a * 4)
-+/**/
-+
-+/*add from M8M2*/
-+#define HEVC_MC_CTRL_REG (0x3900 * 4)
-+#define HEVC_MC_MB_INFO (0x3901 * 4)
-+#define HEVC_MC_PIC_INFO (0x3902 * 4)
-+#define HEVC_MC_HALF_PEL_ONE (0x3903 * 4)
-+#define HEVC_MC_HALF_PEL_TWO (0x3904 * 4)
-+#define HEVC_POWER_CTL_MC (0x3905 * 4)
-+#define HEVC_MC_CMD (0x3906 * 4)
-+#define HEVC_MC_CTRL0 (0x3907 * 4)
-+#define HEVC_MC_PIC_W_H (0x3908 * 4)
-+#define HEVC_MC_STATUS0 (0x3909 * 4)
-+#define HEVC_MC_STATUS1 (0x390a * 4)
-+#define HEVC_MC_CTRL1 (0x390b * 4)
-+#define HEVC_MC_MIX_RATIO0 (0x390c * 4)
-+#define HEVC_MC_MIX_RATIO1 (0x390d * 4)
-+#define HEVC_MC_DP_MB_XY (0x390e * 4)
-+#define HEVC_MC_OM_MB_XY (0x390f * 4)
-+#define HEVC_PSCALE_RST (0x3910 * 4)
-+#define HEVC_PSCALE_CTRL (0x3911 * 4)
-+#define HEVC_PSCALE_PICI_W (0x3912 * 4)
-+#define HEVC_PSCALE_PICI_H (0x3913 * 4)
-+#define HEVC_PSCALE_PICO_W (0x3914 * 4)
-+#define HEVC_PSCALE_PICO_H (0x3915 * 4)
-+#define HEVC_PSCALE_PICO_START_X (0x3916 * 4)
-+#define HEVC_PSCALE_PICO_START_Y (0x3917 * 4)
-+#define HEVC_PSCALE_DUMMY (0x3918 * 4)
-+#define HEVC_PSCALE_FILT0_COEF0 (0x3919 * 4)
-+#define HEVC_PSCALE_FILT0_COEF1 (0x391a * 4)
-+#define HEVC_PSCALE_CMD_CTRL (0x391b * 4)
-+#define HEVC_PSCALE_CMD_BLK_X (0x391c * 4)
-+#define HEVC_PSCALE_CMD_BLK_Y (0x391d * 4)
-+#define HEVC_PSCALE_STATUS (0x391e * 4)
-+#define HEVC_PSCALE_BMEM_ADDR (0x391f * 4)
-+#define HEVC_PSCALE_BMEM_DAT (0x3920 * 4)
-+#define HEVC_PSCALE_DRAM_BUF_CTRL (0x3921 * 4)
-+#define HEVC_PSCALE_MCMD_CTRL (0x3922 * 4)
-+#define HEVC_PSCALE_MCMD_XSIZE (0x3923 * 4)
-+#define HEVC_PSCALE_MCMD_YSIZE (0x3924 * 4)
-+#define HEVC_PSCALE_RBUF_START_BLKX (0x3925 * 4)
-+#define HEVC_PSCALE_RBUF_START_BLKY (0x3926 * 4)
-+#define HEVC_PSCALE_PICO_SHIFT_XY (0x3928 * 4)
-+#define HEVC_PSCALE_CTRL1 (0x3929 * 4)
-+#define HEVC_PSCALE_SRCKEY_CTRL0 (0x392a * 4)
-+#define HEVC_PSCALE_SRCKEY_CTRL1 (0x392b * 4)
-+#define HEVC_PSCALE_CANVAS_RD_ADDR (0x392c * 4)
-+#define HEVC_PSCALE_CANVAS_WR_ADDR (0x392d * 4)
-+#define HEVC_PSCALE_CTRL2 (0x392e * 4)
-+#define HEVC_HDEC_MC_OMEM_AUTO (0x3930 * 4)
-+#define HEVC_HDEC_MC_MBRIGHT_IDX (0x3931 * 4)
-+#define HEVC_HDEC_MC_MBRIGHT_RD (0x3932 * 4)
-+#define HEVC_MC_MPORT_CTRL (0x3940 * 4)
-+#define HEVC_MC_MPORT_DAT (0x3941 * 4)
-+#define HEVC_MC_WT_PRED_CTRL (0x3942 * 4)
-+#define HEVC_MC_MBBOT_ST_EVEN_ADDR (0x3944 * 4)
-+#define HEVC_MC_MBBOT_ST_ODD_ADDR (0x3945 * 4)
-+#define HEVC_MC_DPDN_MB_XY (0x3946 * 4)
-+#define HEVC_MC_OMDN_MB_XY (0x3947 * 4)
-+#define HEVC_MC_HCMDBUF_H (0x3948 * 4)
-+#define HEVC_MC_HCMDBUF_L (0x3949 * 4)
-+#define HEVC_MC_HCMD_H (0x394a * 4)
-+#define HEVC_MC_HCMD_L (0x394b * 4)
-+#define HEVC_MC_IDCT_DAT (0x394c * 4)
-+#define HEVC_MC_CTRL_GCLK_CTRL (0x394d * 4)
-+#define HEVC_MC_OTHER_GCLK_CTRL (0x394e * 4)
-+#define HEVC_MC_CTRL2 (0x394f * 4)
-+#define HEVC_MDEC_PIC_DC_CTRL (0x398e * 4)
-+#define HEVC_MDEC_PIC_DC_STATUS (0x398f * 4)
-+#define HEVC_ANC0_CANVAS_ADDR (0x3990 * 4)
-+#define HEVC_ANC1_CANVAS_ADDR (0x3991 * 4)
-+#define HEVC_ANC2_CANVAS_ADDR (0x3992 * 4)
-+#define HEVC_ANC3_CANVAS_ADDR (0x3993 * 4)
-+#define HEVC_ANC4_CANVAS_ADDR (0x3994 * 4)
-+#define HEVC_ANC5_CANVAS_ADDR (0x3995 * 4)
-+#define HEVC_ANC6_CANVAS_ADDR (0x3996 * 4)
-+#define HEVC_ANC7_CANVAS_ADDR (0x3997 * 4)
-+#define HEVC_ANC8_CANVAS_ADDR (0x3998 * 4)
-+#define HEVC_ANC9_CANVAS_ADDR (0x3999 * 4)
-+#define HEVC_ANC10_CANVAS_ADDR (0x399a * 4)
-+#define HEVC_ANC11_CANVAS_ADDR (0x399b * 4)
-+#define HEVC_ANC12_CANVAS_ADDR (0x399c * 4)
-+#define HEVC_ANC13_CANVAS_ADDR (0x399d * 4)
-+#define HEVC_ANC14_CANVAS_ADDR (0x399e * 4)
-+#define HEVC_ANC15_CANVAS_ADDR (0x399f * 4)
-+#define HEVC_ANC16_CANVAS_ADDR (0x39a0 * 4)
-+#define HEVC_ANC17_CANVAS_ADDR (0x39a1 * 4)
-+#define HEVC_ANC18_CANVAS_ADDR (0x39a2 * 4)
-+#define HEVC_ANC19_CANVAS_ADDR (0x39a3 * 4)
-+#define HEVC_ANC20_CANVAS_ADDR (0x39a4 * 4)
-+#define HEVC_ANC21_CANVAS_ADDR (0x39a5 * 4)
-+#define HEVC_ANC22_CANVAS_ADDR (0x39a6 * 4)
-+#define HEVC_ANC23_CANVAS_ADDR (0x39a7 * 4)
-+#define HEVC_ANC24_CANVAS_ADDR (0x39a8 * 4)
-+#define HEVC_ANC25_CANVAS_ADDR (0x39a9 * 4)
-+#define HEVC_ANC26_CANVAS_ADDR (0x39aa * 4)
-+#define HEVC_ANC27_CANVAS_ADDR (0x39ab * 4)
-+#define HEVC_ANC28_CANVAS_ADDR (0x39ac * 4)
-+#define HEVC_ANC29_CANVAS_ADDR (0x39ad * 4)
-+#define HEVC_ANC30_CANVAS_ADDR (0x39ae * 4)
-+#define HEVC_ANC31_CANVAS_ADDR (0x39af * 4)
-+#define HEVC_DBKR_CANVAS_ADDR (0x39b0 * 4)
-+#define HEVC_DBKW_CANVAS_ADDR (0x39b1 * 4)
-+#define HEVC_REC_CANVAS_ADDR (0x39b2 * 4)
-+#define HEVC_CURR_CANVAS_CTRL (0x39b3 * 4)
-+#define HEVC_MDEC_PIC_DC_THRESH (0x39b8 * 4)
-+#define HEVC_MDEC_PICR_BUF_STATUS (0x39b9 * 4)
-+#define HEVC_MDEC_PICW_BUF_STATUS (0x39ba * 4)
-+#define HEVC_MCW_DBLK_WRRSP_CNT (0x39bb * 4)
-+#define HEVC_MC_MBBOT_WRRSP_CNT (0x39bc * 4)
-+#define HEVC_MDEC_PICW_BUF2_STATUS (0x39bd * 4)
-+#define HEVC_WRRSP_FIFO_PICW_DBK (0x39be * 4)
-+#define HEVC_WRRSP_FIFO_PICW_MC (0x39bf * 4)
-+#define HEVC_AV_SCRATCH_0 (0x39c0 * 4)
-+#define HEVC_AV_SCRATCH_1 (0x39c1 * 4)
-+#define HEVC_AV_SCRATCH_2 (0x39c2 * 4)
-+#define HEVC_AV_SCRATCH_3 (0x39c3 * 4)
-+#define HEVC_AV_SCRATCH_4 (0x39c4 * 4)
-+#define HEVC_AV_SCRATCH_5 (0x39c5 * 4)
-+#define HEVC_AV_SCRATCH_6 (0x39c6 * 4)
-+#define HEVC_AV_SCRATCH_7 (0x39c7 * 4)
-+#define HEVC_AV_SCRATCH_8 (0x39c8 * 4)
-+#define HEVC_AV_SCRATCH_9 (0x39c9 * 4)
-+#define HEVC_AV_SCRATCH_A (0x39ca * 4)
-+#define HEVC_AV_SCRATCH_B (0x39cb * 4)
-+#define HEVC_AV_SCRATCH_C (0x39cc * 4)
-+#define HEVC_AV_SCRATCH_D (0x39cd * 4)
-+#define HEVC_AV_SCRATCH_E (0x39ce * 4)
-+#define HEVC_AV_SCRATCH_F (0x39cf * 4)
-+#define HEVC_AV_SCRATCH_G (0x39d0 * 4)
-+#define HEVC_AV_SCRATCH_H (0x39d1 * 4)
-+#define HEVC_AV_SCRATCH_I (0x39d2 * 4)
-+#define HEVC_AV_SCRATCH_J (0x39d3 * 4)
-+#define HEVC_AV_SCRATCH_K (0x39d4 * 4)
-+#define HEVC_AV_SCRATCH_L (0x39d5 * 4)
-+#define HEVC_AV_SCRATCH_M (0x39d6 * 4)
-+#define HEVC_AV_SCRATCH_N (0x39d7 * 4)
-+#define HEVC_WRRSP_CO_MB (0x39d8 * 4)
-+#define HEVC_WRRSP_DCAC (0x39d9 * 4)
-+#define HEVC_WRRSP_VLD (0x39da * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG0 (0x39db * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG1 (0x39dc * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG2 (0x39dd * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG3 (0x39de * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG4 (0x39df * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG5 (0x39e0 * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG6 (0x39e1 * 4)
-+#define HEVC_MDEC_DOUBLEW_CFG7 (0x39e2 * 4)
-+#define HEVC_MDEC_DOUBLEW_STATUS (0x39e3 * 4)
-+#define HEVC_DBLK_RST (0x3950 * 4)
-+#define HEVC_DBLK_CTRL (0x3951 * 4)
-+#define HEVC_DBLK_MB_WID_HEIGHT (0x3952 * 4)
-+#define HEVC_DBLK_STATUS (0x3953 * 4)
-+#define HEVC_DBLK_CMD_CTRL (0x3954 * 4)
-+#define HEVC_DBLK_MB_XY (0x3955 * 4)
-+#define HEVC_DBLK_QP (0x3956 * 4)
-+#define HEVC_DBLK_Y_BHFILT (0x3957 * 4)
-+#define HEVC_DBLK_Y_BHFILT_HIGH (0x3958 * 4)
-+#define HEVC_DBLK_Y_BVFILT (0x3959 * 4)
-+#define HEVC_DBLK_CB_BFILT (0x395a * 4)
-+#define HEVC_DBLK_CR_BFILT (0x395b * 4)
-+#define HEVC_DBLK_Y_HFILT (0x395c * 4)
-+#define HEVC_DBLK_Y_HFILT_HIGH (0x395d * 4)
-+#define HEVC_DBLK_Y_VFILT (0x395e * 4)
-+#define HEVC_DBLK_CB_FILT (0x395f * 4)
-+#define HEVC_DBLK_CR_FILT (0x3960 * 4)
-+#define HEVC_DBLK_BETAX_QP_SEL (0x3961 * 4)
-+#define HEVC_DBLK_CLIP_CTRL0 (0x3962 * 4)
-+#define HEVC_DBLK_CLIP_CTRL1 (0x3963 * 4)
-+#define HEVC_DBLK_CLIP_CTRL2 (0x3964 * 4)
-+#define HEVC_DBLK_CLIP_CTRL3 (0x3965 * 4)
-+#define HEVC_DBLK_CLIP_CTRL4 (0x3966 * 4)
-+#define HEVC_DBLK_CLIP_CTRL5 (0x3967 * 4)
-+#define HEVC_DBLK_CLIP_CTRL6 (0x3968 * 4)
-+#define HEVC_DBLK_CLIP_CTRL7 (0x3969 * 4)
-+#define HEVC_DBLK_CLIP_CTRL8 (0x396a * 4)
-+#define HEVC_DBLK_STATUS1 (0x396b * 4)
-+#define HEVC_DBLK_GCLK_FREE (0x396c * 4)
-+#define HEVC_DBLK_GCLK_OFF (0x396d * 4)
-+#define HEVC_DBLK_AVSFLAGS (0x396e * 4)
-+#define HEVC_DBLK_CBPY (0x3970 * 4)
-+#define HEVC_DBLK_CBPY_ADJ (0x3971 * 4)
-+#define HEVC_DBLK_CBPC (0x3972 * 4)
-+#define HEVC_DBLK_CBPC_ADJ (0x3973 * 4)
-+#define HEVC_DBLK_VHMVD (0x3974 * 4)
-+#define HEVC_DBLK_STRONG (0x3975 * 4)
-+#define HEVC_DBLK_RV8_QUANT (0x3976 * 4)
-+#define HEVC_DBLK_CBUS_HCMD2 (0x3977 * 4)
-+#define HEVC_DBLK_CBUS_HCMD1 (0x3978 * 4)
-+#define HEVC_DBLK_CBUS_HCMD0 (0x3979 * 4)
-+#define HEVC_DBLK_VLD_HCMD2 (0x397a * 4)
-+#define HEVC_DBLK_VLD_HCMD1 (0x397b * 4)
-+#define HEVC_DBLK_VLD_HCMD0 (0x397c * 4)
-+#define HEVC_DBLK_OST_YBASE (0x397d * 4)
-+#define HEVC_DBLK_OST_CBCRDIFF (0x397e * 4)
-+#define HEVC_DBLK_CTRL1 (0x397f * 4)
-+#define HEVC_MCRCC_CTL1 (0x3980 * 4)
-+#define HEVC_MCRCC_CTL2 (0x3981 * 4)
-+#define HEVC_MCRCC_CTL3 (0x3982 * 4)
-+#define HEVC_GCLK_EN (0x3983 * 4)
-+#define HEVC_MDEC_SW_RESET (0x3984 * 4)
-+
-+/*add from M8M2*/
-+#define HEVC_VLD_STATUS_CTRL (0x3c00 * 4)
-+#define HEVC_MPEG1_2_REG (0x3c01 * 4)
-+#define HEVC_F_CODE_REG (0x3c02 * 4)
-+#define HEVC_PIC_HEAD_INFO (0x3c03 * 4)
-+#define HEVC_SLICE_VER_POS_PIC_TYPE (0x3c04 * 4)
-+#define HEVC_QP_VALUE_REG (0x3c05 * 4)
-+#define HEVC_MBA_INC (0x3c06 * 4)
-+#define HEVC_MB_MOTION_MODE (0x3c07 * 4)
-+#define HEVC_POWER_CTL_VLD (0x3c08 * 4)
-+#define HEVC_MB_WIDTH (0x3c09 * 4)
-+#define HEVC_SLICE_QP (0x3c0a * 4)
-+#define HEVC_PRE_START_CODE (0x3c0b * 4)
-+#define HEVC_SLICE_START_BYTE_01 (0x3c0c * 4)
-+#define HEVC_SLICE_START_BYTE_23 (0x3c0d * 4)
-+#define HEVC_RESYNC_MARKER_LENGTH (0x3c0e * 4)
-+#define HEVC_DECODER_BUFFER_INFO (0x3c0f * 4)
-+#define HEVC_FST_FOR_MV_X (0x3c10 * 4)
-+#define HEVC_FST_FOR_MV_Y (0x3c11 * 4)
-+#define HEVC_SCD_FOR_MV_X (0x3c12 * 4)
-+#define HEVC_SCD_FOR_MV_Y (0x3c13 * 4)
-+#define HEVC_FST_BAK_MV_X (0x3c14 * 4)
-+#define HEVC_FST_BAK_MV_Y (0x3c15 * 4)
-+#define HEVC_SCD_BAK_MV_X (0x3c16 * 4)
-+#define HEVC_SCD_BAK_MV_Y (0x3c17 * 4)
-+#define HEVC_VLD_DECODE_CONTROL (0x3c18 * 4)
-+#define HEVC_VLD_REVERVED_19 (0x3c19 * 4)
-+#define HEVC_VIFF_BIT_CNT (0x3c1a * 4)
-+#define HEVC_BYTE_ALIGN_PEAK_HI (0x3c1b * 4)
-+#define HEVC_BYTE_ALIGN_PEAK_LO (0x3c1c * 4)
-+#define HEVC_NEXT_ALIGN_PEAK (0x3c1d * 4)
-+#define HEVC_VC1_CONTROL_REG (0x3c1e * 4)
-+#define HEVC_PMV1_X (0x3c20 * 4)
-+#define HEVC_PMV1_Y (0x3c21 * 4)
-+#define HEVC_PMV2_X (0x3c22 * 4)
-+#define HEVC_PMV2_Y (0x3c23 * 4)
-+#define HEVC_PMV3_X (0x3c24 * 4)
-+#define HEVC_PMV3_Y (0x3c25 * 4)
-+#define HEVC_PMV4_X (0x3c26 * 4)
-+#define HEVC_PMV4_Y (0x3c27 * 4)
-+#define HEVC_M4_TABLE_SELECT (0x3c28 * 4)
-+#define HEVC_M4_CONTROL_REG (0x3c29 * 4)
-+#define HEVC_BLOCK_NUM (0x3c2a * 4)
-+#define HEVC_PATTERN_CODE (0x3c2b * 4)
-+#define HEVC_MB_INFO (0x3c2c * 4)
-+#define HEVC_VLD_DC_PRED (0x3c2d * 4)
-+#define HEVC_VLD_ERROR_MASK (0x3c2e * 4)
-+#define HEVC_VLD_DC_PRED_C (0x3c2f * 4)
-+#define HEVC_LAST_SLICE_MV_ADDR (0x3c30 * 4)
-+#define HEVC_LAST_MVX (0x3c31 * 4)
-+#define HEVC_LAST_MVY (0x3c32 * 4)
-+#define HEVC_VLD_C38 (0x3c38 * 4)
-+#define HEVC_VLD_C39 (0x3c39 * 4)
-+#define HEVC_VLD_STATUS (0x3c3a * 4)
-+#define HEVC_VLD_SHIFT_STATUS (0x3c3b * 4)
-+#define HEVC_VOFF_STATUS (0x3c3c * 4)
-+#define HEVC_VLD_C3D (0x3c3d * 4)
-+#define HEVC_VLD_DBG_INDEX (0x3c3e * 4)
-+#define HEVC_VLD_DBG_DATA (0x3c3f * 4)
-+#define HEVC_VLD_MEM_VIFIFO_START_PTR (0x3c40 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_CURR_PTR (0x3c41 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_END_PTR (0x3c42 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_BYTES_AVAIL (0x3c43 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_CONTROL (0x3c44 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_WP (0x3c45 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_RP (0x3c46 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_LEVEL (0x3c47 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_BUF_CNTL (0x3c48 * 4)
-+#define HEVC_VLD_TIME_STAMP_CNTL (0x3c49 * 4)
-+#define HEVC_VLD_TIME_STAMP_SYNC_0 (0x3c4a * 4)
-+#define HEVC_VLD_TIME_STAMP_SYNC_1 (0x3c4b * 4)
-+#define HEVC_VLD_TIME_STAMP_0 (0x3c4c * 4)
-+#define HEVC_VLD_TIME_STAMP_1 (0x3c4d * 4)
-+#define HEVC_VLD_TIME_STAMP_2 (0x3c4e * 4)
-+#define HEVC_VLD_TIME_STAMP_3 (0x3c4f * 4)
-+#define HEVC_VLD_TIME_STAMP_LENGTH (0x3c50 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_WRAP_COUNT (0x3c51 * 4)
-+#define HEVC_VLD_MEM_VIFIFO_MEM_CTL (0x3c52 * 4)
-+#define HEVC_VLD_MEM_VBUF_RD_PTR (0x3c53 * 4)
-+#define HEVC_VLD_MEM_VBUF2_RD_PTR (0x3c54 * 4)
-+#define HEVC_VLD_MEM_SWAP_ADDR (0x3c55 * 4)
-+#define HEVC_VLD_MEM_SWAP_CTL (0x3c56 * 4)
-+/**/
-+
-+/*add from M8M2*/
-+#define HEVC_VCOP_CTRL_REG (0x3e00 * 4)
-+#define HEVC_QP_CTRL_REG (0x3e01 * 4)
-+#define HEVC_INTRA_QUANT_MATRIX (0x3e02 * 4)
-+#define HEVC_NON_I_QUANT_MATRIX (0x3e03 * 4)
-+#define HEVC_DC_SCALER (0x3e04 * 4)
-+#define HEVC_DC_AC_CTRL (0x3e05 * 4)
-+#define HEVC_DC_AC_SCALE_MUL (0x3e06 * 4)
-+#define HEVC_DC_AC_SCALE_DIV (0x3e07 * 4)
-+#define HEVC_POWER_CTL_IQIDCT (0x3e08 * 4)
-+#define HEVC_RV_AI_Y_X (0x3e09 * 4)
-+#define HEVC_RV_AI_U_X (0x3e0a * 4)
-+#define HEVC_RV_AI_V_X (0x3e0b * 4)
-+#define HEVC_RV_AI_MB_COUNT (0x3e0c * 4)
-+#define HEVC_NEXT_INTRA_DMA_ADDRESS (0x3e0d * 4)
-+#define HEVC_IQIDCT_CONTROL (0x3e0e * 4)
-+#define HEVC_IQIDCT_DEBUG_INFO_0 (0x3e0f * 4)
-+#define HEVC_DEBLK_CMD (0x3e10 * 4)
-+#define HEVC_IQIDCT_DEBUG_IDCT (0x3e11 * 4)
-+#define HEVC_DCAC_DMA_CTRL (0x3e12 * 4)
-+#define HEVC_DCAC_DMA_ADDRESS (0x3e13 * 4)
-+#define HEVC_DCAC_CPU_ADDRESS (0x3e14 * 4)
-+#define HEVC_DCAC_CPU_DATA (0x3e15 * 4)
-+#define HEVC_DCAC_MB_COUNT (0x3e16 * 4)
-+#define HEVC_IQ_QUANT (0x3e17 * 4)
-+#define HEVC_VC1_BITPLANE_CTL (0x3e18 * 4)
-+
-+
-+/*add from M8M2*/
-+#define HEVC_MSP (0x3300 * 4)
-+#define HEVC_MPSR (0x3301 * 4)
-+#define HEVC_MINT_VEC_BASE (0x3302 * 4)
-+#define HEVC_MCPU_INTR_GRP (0x3303 * 4)
-+#define HEVC_MCPU_INTR_MSK (0x3304 * 4)
-+#define HEVC_MCPU_INTR_REQ (0x3305 * 4)
-+#define HEVC_MPC_P (0x3306 * 4)
-+#define HEVC_MPC_D (0x3307 * 4)
-+#define HEVC_MPC_E (0x3308 * 4)
-+#define HEVC_MPC_W (0x3309 * 4)
-+#define HEVC_MINDEX0_REG (0x330a * 4)
-+#define HEVC_MINDEX1_REG (0x330b * 4)
-+#define HEVC_MINDEX2_REG (0x330c * 4)
-+#define HEVC_MINDEX3_REG (0x330d * 4)
-+#define HEVC_MINDEX4_REG (0x330e * 4)
-+#define HEVC_MINDEX5_REG (0x330f * 4)
-+#define HEVC_MINDEX6_REG (0x3310 * 4)
-+#define HEVC_MINDEX7_REG (0x3311 * 4)
-+#define HEVC_MMIN_REG (0x3312 * 4)
-+#define HEVC_MMAX_REG (0x3313 * 4)
-+#define HEVC_MBREAK0_REG (0x3314 * 4)
-+#define HEVC_MBREAK1_REG (0x3315 * 4)
-+#define HEVC_MBREAK2_REG (0x3316 * 4)
-+#define HEVC_MBREAK3_REG (0x3317 * 4)
-+#define HEVC_MBREAK_TYPE (0x3318 * 4)
-+#define HEVC_MBREAK_CTRL (0x3319 * 4)
-+#define HEVC_MBREAK_STAUTS (0x331a * 4)
-+#define HEVC_MDB_ADDR_REG (0x331b * 4)
-+#define HEVC_MDB_DATA_REG (0x331c * 4)
-+#define HEVC_MDB_CTRL (0x331d * 4)
-+#define HEVC_MSFTINT0 (0x331e * 4)
-+#define HEVC_MSFTINT1 (0x331f * 4)
-+#define HEVC_CSP (0x3320 * 4)
-+#define HEVC_CPSR (0x3321 * 4)
-+#define HEVC_CINT_VEC_BASE (0x3322 * 4)
-+#define HEVC_CCPU_INTR_GRP (0x3323 * 4)
-+#define HEVC_CCPU_INTR_MSK (0x3324 * 4)
-+#define HEVC_CCPU_INTR_REQ (0x3325 * 4)
-+#define HEVC_CPC_P (0x3326 * 4)
-+#define HEVC_CPC_D (0x3327 * 4)
-+#define HEVC_CPC_E (0x3328 * 4)
-+#define HEVC_CPC_W (0x3329 * 4)
-+#define HEVC_CINDEX0_REG (0x332a * 4)
-+#define HEVC_CINDEX1_REG (0x332b * 4)
-+#define HEVC_CINDEX2_REG (0x332c * 4)
-+#define HEVC_CINDEX3_REG (0x332d * 4)
-+#define HEVC_CINDEX4_REG (0x332e * 4)
-+#define HEVC_CINDEX5_REG (0x332f * 4)
-+#define HEVC_CINDEX6_REG (0x3330 * 4)
-+#define HEVC_CINDEX7_REG (0x3331 * 4)
-+#define HEVC_CMIN_REG (0x3332 * 4)
-+#define HEVC_CMAX_REG (0x3333 * 4)
-+#define HEVC_CBREAK0_REG (0x3334 * 4)
-+#define HEVC_CBREAK1_REG (0x3335 * 4)
-+#define HEVC_CBREAK2_REG (0x3336 * 4)
-+#define HEVC_CBREAK3_REG (0x3337 * 4)
-+#define HEVC_CBREAK_TYPE (0x3338 * 4)
-+#define HEVC_CBREAK_CTRL (0x3339 * 4)
-+#define HEVC_CBREAK_STAUTS (0x333a * 4)
-+#define HEVC_CDB_ADDR_REG (0x333b * 4)
-+#define HEVC_CDB_DATA_REG (0x333c * 4)
-+#define HEVC_CDB_CTRL (0x333d * 4)
-+#define HEVC_CSFTINT0 (0x333e * 4)
-+#define HEVC_CSFTINT1 (0x333f * 4)
-+#define HEVC_IMEM_DMA_CTRL (0x3340 * 4)
-+#define HEVC_IMEM_DMA_ADR (0x3341 * 4)
-+#define HEVC_IMEM_DMA_COUNT (0x3342 * 4)
-+#define HEVC_WRRSP_IMEM (0x3343 * 4)
-+#define HEVC_LMEM_DMA_CTRL (0x3350 * 4)
-+#define HEVC_LMEM_DMA_ADR (0x3351 * 4)
-+#define HEVC_LMEM_DMA_COUNT (0x3352 * 4)
-+#define HEVC_WRRSP_LMEM (0x3353 * 4)
-+#define HEVC_MAC_CTRL1 (0x3360 * 4)
-+#define HEVC_ACC0REG1 (0x3361 * 4)
-+#define HEVC_ACC1REG1 (0x3362 * 4)
-+#define HEVC_MAC_CTRL2 (0x3370 * 4)
-+#define HEVC_ACC0REG2 (0x3371 * 4)
-+#define HEVC_ACC1REG2 (0x3372 * 4)
-+#define HEVC_CPU_TRACE (0x3380 * 4)
-+/**/
-+
-+#endif
-+
-diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c
-new file mode 100644
-index 0000000..b8b1edf
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec.c
-@@ -0,0 +1,1009 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#define DEBUG
-+
-+#include <linux/of_device.h>
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/slab.h>
-+#include <media/v4l2-ioctl.h>
-+#include <media/v4l2-event.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-mem2mem.h>
-+#include <media/v4l2-dev.h>
-+#include <media/videobuf2-dma-contig.h>
-+
-+#include "vdec.h"
-+#include "esparser.h"
-+#include "canvas.h"
-+
-+#include "vdec_1.h"
-+
-+/* 16 MiB for parsed bitstream swap exchange */
-+#define SIZE_VIFIFO (16 * SZ_1M)
-+
-+void vdec_abort(struct vdec_session *sess)
-+{
-+ printk("Aborting decoding session!\n");
-+ vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
-+ vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
-+}
-+
-+static u32 get_output_size(u32 width, u32 height)
-+{
-+ return ALIGN(width * height, 64 * SZ_1K);
-+}
-+
-+u32 vdec_get_output_size(struct vdec_session *sess)
-+{
-+ return get_output_size(sess->width, sess->height);
-+}
-+
-+static int vdec_poweron(struct vdec_session *sess)
-+{
-+ int ret;
-+ struct vdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
-+
-+ ret = clk_prepare_enable(sess->core->dos_parser_clk);
-+ if (ret)
-+ return ret;
-+
-+ ret = clk_prepare_enable(sess->core->dos_clk);
-+ if (ret)
-+ goto disable_dos_parser;
-+
-+ ret = vdec_ops->start(sess);
-+ if (ret)
-+ goto disable_dos;
-+
-+ esparser_power_up(sess);
-+
-+ return 0;
-+
-+disable_dos:
-+ clk_disable_unprepare(sess->core->dos_clk);
-+disable_dos_parser:
-+ clk_disable_unprepare(sess->core->dos_parser_clk);
-+
-+ return ret;
-+}
-+
-+static void vdec_poweroff(struct vdec_session *sess) {
-+ struct vdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
-+
-+ vdec_ops->stop(sess);
-+ clk_disable_unprepare(sess->core->dos_clk);
-+ clk_disable_unprepare(sess->core->dos_parser_clk);
-+}
-+
-+void vdec_queue_recycle(struct vdec_session *sess, struct vb2_buffer *vb)
-+{
-+ struct vdec_buffer *new_buf;
-+
-+ new_buf = kmalloc(sizeof(struct vdec_buffer), GFP_KERNEL);
-+ new_buf->index = vb->index;
-+
-+ mutex_lock(&sess->bufs_recycle_lock);
-+ list_add_tail(&new_buf->list, &sess->bufs_recycle);
-+ mutex_unlock(&sess->bufs_recycle_lock);
-+}
-+
-+void vdec_m2m_device_run(void *priv)
-+{
-+ struct vdec_session *sess = priv;
-+ schedule_work(&sess->esparser_queue_work);
-+}
-+
-+void vdec_m2m_job_abort(void *priv)
-+{
-+ struct vdec_session *sess = priv;
-+ v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx);
-+}
-+
-+static const struct v4l2_m2m_ops vdec_m2m_ops = {
-+ .device_run = vdec_m2m_device_run,
-+ .job_abort = vdec_m2m_job_abort,
-+};
-+
-+static int vdec_queue_setup(struct vb2_queue *q,
-+ unsigned int *num_buffers, unsigned int *num_planes,
-+ unsigned int sizes[], struct device *alloc_devs[])
-+{
-+ struct vdec_session *sess = vb2_get_drv_priv(q);
-+ const struct vdec_format *fmt_out = sess->fmt_out;
-+ const struct vdec_format *fmt_cap = sess->fmt_cap;
-+
-+ switch (q->type) {
-+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
-+ sizes[0] = vdec_get_output_size(sess);
-+ sess->num_input_bufs = *num_buffers;
-+ *num_planes = fmt_out->num_planes;
-+ break;
-+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
-+ sizes[0] = vdec_get_output_size(sess);
-+ sizes[1] = vdec_get_output_size(sess) / 2;
-+ *num_planes = fmt_cap->num_planes;
-+ *num_buffers = min(max(*num_buffers, fmt_out->min_buffers), fmt_out->max_buffers);
-+ sess->num_output_bufs = *num_buffers;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ return 0;
-+}
-+
-+static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
-+{
-+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
-+ struct vdec_session *sess = vb2_get_drv_priv(vb->vb2_queue);
-+ struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+
-+ mutex_lock(&sess->lock);
-+ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
-+
-+ if (!(sess->streamon_out & sess->streamon_cap))
-+ goto unlock;
-+
-+ if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-+ schedule_work(&sess->esparser_queue_work);
-+ } else if (codec_ops->notify_dst_buffer)
-+ codec_ops->notify_dst_buffer(sess, vb);
-+
-+unlock:
-+ mutex_unlock(&sess->lock);
-+}
-+
-+static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
-+{
-+ struct vdec_session *sess = vb2_get_drv_priv(q);
-+ struct vb2_v4l2_buffer *buf;
-+ int ret;
-+
-+ mutex_lock(&sess->lock);
-+
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-+ sess->streamon_out = 1;
-+ else
-+ sess->streamon_cap = 1;
-+
-+ if (!(sess->streamon_out & sess->streamon_cap)) {
-+ mutex_unlock(&sess->lock);
-+ return 0;
-+ }
-+
-+ sess->vififo_size = SIZE_VIFIFO;
-+ sess->vififo_vaddr = dma_alloc_coherent(sess->core->dev, sess->vififo_size, &sess->vififo_paddr, GFP_KERNEL);
-+ if (!sess->vififo_vaddr) {
-+ printk("Failed to request VIFIFO buffer\n");
-+ ret = -ENOMEM;
-+ goto bufs_done;
-+ }
-+
-+ sess->should_stop = 0;
-+ ret = vdec_poweron(sess);
-+ if (ret)
-+ goto vififo_free;
-+
-+ sess->sequence_cap = 0;
-+ mutex_unlock(&sess->lock);
-+
-+ return 0;
-+
-+vififo_free:
-+ dma_free_coherent(sess->core->dev, sess->vififo_size, sess->vififo_vaddr, sess->vififo_paddr);
-+bufs_done:
-+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
-+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
-+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
-+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-+ sess->streamon_out = 0;
-+ else
-+ sess->streamon_cap = 0;
-+ mutex_unlock(&sess->lock);
-+ return ret;
-+}
-+
-+void vdec_stop_streaming(struct vb2_queue *q)
-+{
-+ struct vdec_session *sess = vb2_get_drv_priv(q);
-+ struct vb2_v4l2_buffer *buf;
-+
-+ mutex_lock(&sess->lock);
-+
-+ if (sess->streamon_out & sess->streamon_cap) {
-+ vdec_poweroff(sess);
-+ dma_free_coherent(sess->core->dev, sess->vififo_size, sess->vififo_vaddr, sess->vififo_paddr);
-+ INIT_LIST_HEAD(&sess->bufs);
-+ INIT_LIST_HEAD(&sess->bufs_recycle);
-+ }
-+
-+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-+ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
-+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
-+
-+ sess->streamon_out = 0;
-+ } else {
-+ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
-+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
-+
-+ sess->streamon_cap = 0;
-+ }
-+
-+ mutex_unlock(&sess->lock);
-+}
-+
-+static const struct vb2_ops vdec_vb2_ops = {
-+ .queue_setup = vdec_queue_setup,
-+ .start_streaming = vdec_start_streaming,
-+ .stop_streaming = vdec_stop_streaming,
-+ .buf_queue = vdec_vb2_buf_queue,
-+};
-+
-+static int
-+vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
-+{
-+ strlcpy(cap->driver, "meson-vdec", sizeof(cap->driver));
-+ strlcpy(cap->card, "AMLogic Video Decoder", sizeof(cap->card));
-+ strlcpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info));
-+
-+ return 0;
-+}
-+
-+static const struct vdec_format *
-+find_format(const struct vdec_format *fmts, u32 size, u32 pixfmt, u32 type)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < size; i++) {
-+ if (fmts[i].pixfmt == pixfmt)
-+ break;
-+ }
-+
-+ if (i == size || fmts[i].type != type)
-+ return NULL;
-+
-+ return &fmts[i];
-+}
-+
-+static const struct vdec_format *
-+find_format_by_index(const struct vdec_format *fmts, u32 size, u32 index, u32 type)
-+{
-+ unsigned int i, k = 0;
-+
-+ if (index > size)
-+ return NULL;
-+
-+ for (i = 0; i < size; i++) {
-+ if (fmts[i].type != type)
-+ continue;
-+ if (k == index)
-+ break;
-+ k++;
-+ }
-+
-+ if (i == size)
-+ return NULL;
-+
-+ return &fmts[i];
-+}
-+
-+static const struct vdec_format *
-+vdec_try_fmt_common(const struct vdec_format *fmts, u32 size, struct v4l2_format *f)
-+{
-+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
-+ struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
-+ const struct vdec_format *fmt;
-+
-+ memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
-+ memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
-+
-+ fmt = find_format(fmts, size, pixmp->pixelformat, f->type);
-+ if (!fmt) {
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-+ pixmp->pixelformat = V4L2_PIX_FMT_NV12M;
-+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-+ pixmp->pixelformat = V4L2_PIX_FMT_H264;
-+ else
-+ return NULL;
-+
-+ fmt = find_format(fmts, size, pixmp->pixelformat, f->type);
-+ pixmp->width = 1280;
-+ pixmp->height = 720;
-+ }
-+
-+ pixmp->width = clamp(pixmp->width, (u32)256, (u32)3840);
-+ pixmp->height = clamp(pixmp->height, (u32)144, (u32)2160);
-+
-+ if (pixmp->field == V4L2_FIELD_ANY)
-+ pixmp->field = V4L2_FIELD_NONE;
-+
-+ pixmp->num_planes = fmt->num_planes;
-+ pixmp->flags = 0;
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-+ memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
-+ pfmt[0].sizeimage = get_output_size(pixmp->width, pixmp->height);
-+ pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
-+
-+ pfmt[1].sizeimage = get_output_size(pixmp->width, pixmp->height) / 2;
-+ pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
-+ } else {
-+ pfmt[0].sizeimage = get_output_size(pixmp->width, pixmp->height);
-+ pfmt[0].bytesperline = 0;
-+ }
-+
-+
-+ return fmt;
-+}
-+
-+static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct vdec_session *sess = container_of(file->private_data, struct vdec_session, fh);
-+
-+ vdec_try_fmt_common(sess->core->platform->formats,
-+ sess->core->platform->num_formats, f);
-+
-+ return 0;
-+}
-+
-+static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct vdec_session *sess = container_of(file->private_data, struct vdec_session, fh);
-+ const struct vdec_format *fmt = NULL;
-+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-+ fmt = sess->fmt_cap;
-+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-+ fmt = sess->fmt_out;
-+
-+ pixmp->pixelformat = fmt->pixfmt;
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-+ pixmp->width = sess->width;
-+ pixmp->height = sess->height;
-+ pixmp->colorspace = sess->colorspace;
-+ pixmp->ycbcr_enc = sess->ycbcr_enc;
-+ pixmp->quantization = sess->quantization;
-+ pixmp->xfer_func = sess->xfer_func;
-+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-+ pixmp->width = sess->width;
-+ pixmp->height = sess->height;
-+ }
-+
-+ vdec_try_fmt_common(sess->core->platform->formats, sess->core->platform->num_formats, f);
-+
-+ return 0;
-+}
-+
-+static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
-+{
-+ struct vdec_session *sess = container_of(file->private_data, struct vdec_session, fh);
-+ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
-+ const struct vdec_format *formats = sess->core->platform->formats;
-+ u32 num_formats = sess->core->platform->num_formats;
-+ const struct vdec_format *fmt;
-+ struct v4l2_pix_format_mplane orig_pixmp;
-+ struct v4l2_format format;
-+ u32 pixfmt_out = 0, pixfmt_cap = 0;
-+
-+ orig_pixmp = *pixmp;
-+
-+ fmt = vdec_try_fmt_common(formats, num_formats, f);
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-+ pixfmt_out = pixmp->pixelformat;
-+ pixfmt_cap = sess->fmt_cap->pixfmt;
-+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-+ pixfmt_cap = pixmp->pixelformat;
-+ pixfmt_out = sess->fmt_out->pixfmt;
-+ }
-+
-+ memset(&format, 0, sizeof(format));
-+
-+ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+ format.fmt.pix_mp.pixelformat = pixfmt_out;
-+ format.fmt.pix_mp.width = orig_pixmp.width;
-+ format.fmt.pix_mp.height = orig_pixmp.height;
-+ vdec_try_fmt_common(formats, num_formats, &format);
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-+ sess->width = format.fmt.pix_mp.width;
-+ sess->height = format.fmt.pix_mp.height;
-+ sess->colorspace = pixmp->colorspace;
-+ sess->ycbcr_enc = pixmp->ycbcr_enc;
-+ sess->quantization = pixmp->quantization;
-+ sess->xfer_func = pixmp->xfer_func;
-+ }
-+
-+ memset(&format, 0, sizeof(format));
-+
-+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-+ format.fmt.pix_mp.pixelformat = pixfmt_cap;
-+ format.fmt.pix_mp.width = orig_pixmp.width;
-+ format.fmt.pix_mp.height = orig_pixmp.height;
-+ vdec_try_fmt_common(formats, num_formats, &format);
-+
-+ sess->width = format.fmt.pix_mp.width;
-+ sess->height = format.fmt.pix_mp.height;
-+
-+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
-+ sess->fmt_out = fmt;
-+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-+ sess->fmt_cap = fmt;
-+
-+ return 0;
-+}
-+
-+static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
-+{
-+ struct vdec_session *sess =
-+ container_of(file->private_data, struct vdec_session, fh);
-+ const struct vdec_platform *platform = sess->core->platform;
-+ const struct vdec_format *fmt;
-+
-+ memset(f->reserved, 0, sizeof(f->reserved));
-+
-+ fmt = find_format_by_index(platform->formats, platform->num_formats,
-+ f->index, f->type);
-+ if (!fmt)
-+ return -EINVAL;
-+
-+ f->pixelformat = fmt->pixfmt;
-+
-+ return 0;
-+}
-+
-+static int vdec_enum_framesizes(struct file *file, void *fh,
-+ struct v4l2_frmsizeenum *fsize)
-+{
-+ struct vdec_session *sess =
-+ container_of(file->private_data, struct vdec_session, fh);
-+ const struct vdec_format *formats = sess->core->platform->formats;
-+ u32 num_formats = sess->core->platform->num_formats;
-+ const struct vdec_format *fmt;
-+
-+ fmt = find_format(formats, num_formats, fsize->pixel_format,
-+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-+ if (!fmt) {
-+ fmt = find_format(formats, num_formats, fsize->pixel_format,
-+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-+ if (!fmt)
-+ return -EINVAL;
-+ }
-+
-+ if (fsize->index)
-+ return -EINVAL;
-+
-+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-+
-+ /* TODO: Store these constants in vdec_format */
-+ fsize->stepwise.min_width = 256;
-+ fsize->stepwise.max_width = 3840;
-+ fsize->stepwise.step_width = 1;
-+ fsize->stepwise.min_height = 144;
-+ fsize->stepwise.max_height = 2160;
-+ fsize->stepwise.step_height = 1;
-+
-+ return 0;
-+}
-+
-+static int
-+vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
-+{
-+ switch (cmd->cmd) {
-+ case V4L2_DEC_CMD_STOP:
-+ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
-+ return -EINVAL;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
-+{
-+ struct vdec_session *sess =
-+ container_of(file->private_data, struct vdec_session, fh);
-+ int ret;
-+
-+ ret = vdec_try_decoder_cmd(file, fh, cmd);
-+ if (ret)
-+ return ret;
-+
-+ mutex_lock(&sess->lock);
-+
-+ if (!(sess->streamon_out & sess->streamon_cap))
-+ goto unlock;
-+
-+ esparser_queue_eos(sess);
-+
-+unlock:
-+ mutex_unlock(&sess->lock);
-+ return ret;
-+}
-+
-+static int vdec_subscribe_event(struct v4l2_fh *fh,
-+ const struct v4l2_event_subscription *sub)
-+{
-+ switch (sub->type) {
-+ case V4L2_EVENT_EOS:
-+ return v4l2_event_subscribe(fh, sub, 2, NULL);
-+ default:
-+ return -EINVAL;
-+ }
-+}
-+
-+static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
-+ .vidioc_querycap = vdec_querycap,
-+ .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt,
-+ .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt,
-+ .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt,
-+ .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt,
-+ .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt,
-+ .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt,
-+ .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt,
-+ .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt,
-+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
-+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
-+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
-+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
-+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
-+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
-+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
-+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
-+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
-+ .vidioc_enum_framesizes = vdec_enum_framesizes,
-+ .vidioc_subscribe_event = vdec_subscribe_event,
-+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-+ .vidioc_try_decoder_cmd = vdec_try_decoder_cmd,
-+ .vidioc_decoder_cmd = vdec_decoder_cmd,
-+};
-+
-+static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
-+ struct vb2_queue *dst_vq)
-+{
-+ struct vdec_session *sess = priv;
-+ int ret;
-+
-+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
-+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
-+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-+ src_vq->ops = &vdec_vb2_ops;
-+ src_vq->mem_ops = &vb2_dma_contig_memops;
-+ src_vq->drv_priv = sess;
-+ src_vq->buf_struct_size = sizeof(struct dummy_buf);
-+ src_vq->allow_zero_bytesused = 1;
-+ src_vq->min_buffers_needed = 1;
-+ src_vq->dev = sess->core->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->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
-+ dst_vq->ops = &vdec_vb2_ops;
-+ dst_vq->mem_ops = &vb2_dma_contig_memops;
-+ dst_vq->drv_priv = sess;
-+ dst_vq->buf_struct_size = sizeof(struct dummy_buf);
-+ dst_vq->allow_zero_bytesused = 1;
-+ dst_vq->min_buffers_needed = 1;
-+ dst_vq->dev = sess->core->dev;
-+ ret = vb2_queue_init(dst_vq);
-+ if (ret) {
-+ vb2_queue_release(src_vq);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int vdec_open(struct file *file)
-+{
-+ struct vdec_core *core = video_drvdata(file);
-+ struct device *dev = core->dev;
-+ const struct vdec_format *formats = core->platform->formats;
-+ struct vdec_session *sess;
-+ int ret;
-+
-+ mutex_lock(&core->lock);
-+ if (core->cur_sess) {
-+ mutex_unlock(&core->lock);
-+ return -EBUSY;
-+ }
-+
-+ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
-+ if (!sess) {
-+ mutex_unlock(&core->lock);
-+ return -ENOMEM;
-+ }
-+
-+ core->cur_sess = sess;
-+ mutex_unlock(&core->lock);
-+
-+ sess->core = core;
-+ sess->fmt_cap = &formats[0];
-+ sess->fmt_out = &formats[1];
-+ sess->width = 1280;
-+ sess->height = 720;
-+ INIT_LIST_HEAD(&sess->bufs);
-+ INIT_LIST_HEAD(&sess->bufs_recycle);
-+ INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src);
-+ spin_lock_init(&sess->bufs_spinlock);
-+ mutex_init(&sess->lock);
-+ mutex_init(&sess->codec_lock);
-+ mutex_init(&sess->bufs_recycle_lock);
-+
-+ sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
-+ if (IS_ERR(sess->m2m_dev)) {
-+ dev_err(dev, "Fail to v4l2_m2m_init\n");
-+ ret = PTR_ERR(sess->m2m_dev);
-+ goto err_free_sess;
-+ }
-+
-+ sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init);
-+ if (IS_ERR(sess->m2m_ctx)) {
-+ dev_err(dev, "Fail to v4l2_m2m_ctx_init\n");
-+ ret = PTR_ERR(sess->m2m_ctx);
-+ goto err_m2m_release;
-+ }
-+
-+ v4l2_fh_init(&sess->fh, core->vdev_dec);
-+ v4l2_fh_add(&sess->fh);
-+ sess->fh.m2m_ctx = sess->m2m_ctx;
-+ file->private_data = &sess->fh;
-+
-+ return 0;
-+
-+err_m2m_release:
-+ v4l2_m2m_release(sess->m2m_dev);
-+err_free_sess:
-+ kfree(sess);
-+ return ret;
-+}
-+
-+static int vdec_close(struct file *file)
-+{
-+ struct vdec_session *sess =
-+ container_of(file->private_data, struct vdec_session, fh);
-+ struct vdec_core *core = sess->core;
-+
-+ v4l2_m2m_ctx_release(sess->m2m_ctx);
-+ v4l2_m2m_release(sess->m2m_dev);
-+ v4l2_fh_del(&sess->fh);
-+ v4l2_fh_exit(&sess->fh);
-+ mutex_destroy(&sess->lock);
-+
-+ kfree(sess);
-+ core->cur_sess = NULL;
-+
-+ return 0;
-+}
-+
-+void vdec_dst_buf_done(struct vdec_session *sess, struct vb2_v4l2_buffer *vbuf)
-+{
-+ unsigned long flags;
-+ struct vdec_buffer *tmp;
-+ struct device *dev = sess->core->dev_dec;
-+
-+ spin_lock_irqsave(&sess->bufs_spinlock, flags);
-+ if (list_empty(&sess->bufs)) {
-+ dev_err(dev, "Buffer %u done but list is empty\n",
-+ vbuf->vb2_buf.index);
-+
-+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
-+ vdec_abort(sess);
-+ goto unlock;
-+ }
-+
-+ tmp = list_first_entry(&sess->bufs, struct vdec_buffer, list);
-+
-+ vbuf->vb2_buf.planes[0].bytesused = vdec_get_output_size(sess);
-+ vbuf->vb2_buf.planes[1].bytesused = vdec_get_output_size(sess) / 2;
-+ vbuf->vb2_buf.timestamp = tmp->timestamp;
-+ vbuf->sequence = sess->sequence_cap++;
-+
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+
-+ if (sess->should_stop && list_empty(&sess->bufs)) {
-+ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
-+ v4l2_event_queue_fh(&sess->fh, &ev);
-+ vbuf->flags |= V4L2_BUF_FLAG_LAST;
-+ }
-+
-+ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
-+
-+unlock:
-+ spin_unlock_irqrestore(&sess->bufs_spinlock, flags);
-+
-+ atomic_dec(&sess->esparser_queued_bufs);
-+ /* Buffer done probably means the vififo got freed */
-+ schedule_work(&sess->esparser_queue_work);
-+}
-+
-+static void vdec_rm_first_ts(struct vdec_session *sess)
-+{
-+ unsigned long flags;
-+ struct vdec_buffer *tmp;
-+ struct device *dev = sess->core->dev_dec;
-+
-+ spin_lock_irqsave(&sess->bufs_spinlock, flags);
-+ if (list_empty(&sess->bufs)) {
-+ dev_err(dev, "Can't rm first timestamp: list empty\n");
-+ goto unlock;
-+ }
-+
-+ tmp = list_first_entry(&sess->bufs, struct vdec_buffer, list);
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+
-+unlock:
-+ spin_unlock_irqrestore(&sess->bufs_spinlock, flags);
-+}
-+
-+void vdec_dst_buf_done_idx(struct vdec_session *sess, u32 buf_idx)
-+{
-+ struct vb2_v4l2_buffer *vbuf;
-+ struct device *dev = sess->core->dev_dec;
-+
-+ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx);
-+ if (!vbuf) {
-+ dev_err(dev, "Buffer %u done but it doesn't exist in m2m_ctx\n",
-+ buf_idx);
-+ atomic_dec(&sess->esparser_queued_bufs);
-+ vdec_rm_first_ts(sess);
-+ return;
-+ }
-+
-+ vdec_dst_buf_done(sess, vbuf);
-+}
-+
-+/* Userspace will often queue timestamps that are not
-+ * in chronological order. Rearrange them here.
-+ */
-+void vdec_add_ts_reorder(struct vdec_session *sess, u64 ts)
-+{
-+ struct vdec_buffer *new_buf, *tmp;
-+ unsigned long flags;
-+
-+ new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL);
-+ new_buf->timestamp = ts;
-+ new_buf->index = -1;
-+
-+ spin_lock_irqsave(&sess->bufs_spinlock, flags);
-+ if (list_empty(&sess->bufs))
-+ goto add_core;
-+
-+ list_for_each_entry(tmp, &sess->bufs, list) {
-+ if (ts < tmp->timestamp) {
-+ list_add_tail(&new_buf->list, &tmp->list);
-+ goto unlock;
-+ }
-+ }
-+
-+add_core:
-+ list_add_tail(&new_buf->list, &sess->bufs);
-+unlock:
-+ spin_unlock_irqrestore(&sess->bufs_spinlock, flags);
-+}
-+
-+void vdec_remove_ts(struct vdec_session *sess, u64 ts)
-+{
-+ struct vdec_buffer *tmp;
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&sess->bufs_spinlock, flags);
-+ list_for_each_entry(tmp, &sess->bufs, list) {
-+ if (tmp->timestamp == ts) {
-+ list_del(&tmp->list);
-+ kfree(tmp);
-+ goto unlock;
-+ }
-+ }
-+ dev_warn(sess->core->dev_dec,
-+ "Couldn't remove buffer with timestamp %llu from list\n", ts);
-+
-+unlock:
-+ spin_unlock_irqrestore(&sess->bufs_spinlock, flags);
-+}
-+
-+static const struct v4l2_file_operations vdec_fops = {
-+ .owner = THIS_MODULE,
-+ .open = vdec_open,
-+ .release = vdec_close,
-+ .unlocked_ioctl = video_ioctl2,
-+ .poll = v4l2_m2m_fop_poll,
-+ .mmap = v4l2_m2m_fop_mmap,
-+#ifdef CONFIG_COMPAT
-+ .compat_ioctl32 = v4l2_compat_ioctl32,
-+#endif
-+};
-+
-+static irqreturn_t vdec_isr(int irq, void *data)
-+{
-+ struct vdec_core *core = data;
-+ struct vdec_session *sess = core->cur_sess;
-+
-+ return sess->fmt_out->codec_ops->isr(sess);
-+}
-+
-+static irqreturn_t vdec_threaded_isr(int irq, void *data)
-+{
-+ struct vdec_core *core = data;
-+ struct vdec_session *sess = core->cur_sess;
-+
-+ return sess->fmt_out->codec_ops->threaded_isr(sess);
-+}
-+
-+static const struct of_device_id vdec_dt_match[] = {
-+ { .compatible = "amlogic,meson-gxbb-vdec",
-+ .data = &vdec_platform_gxbb },
-+ { .compatible = "amlogic,meson-gxm-vdec",
-+ .data = &vdec_platform_gxm },
-+ { .compatible = "amlogic,meson-gxl-vdec",
-+ .data = &vdec_platform_gxl },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, vdec_dt_match);
-+
-+static int vdec_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ struct video_device *vdev;
-+ struct vdec_core *core;
-+ struct resource *r;
-+ const struct of_device_id *of_id;
-+ int irq;
-+ int ret;
-+
-+ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
-+ if (!core) {
-+ dev_err(dev, "No memory for devm_kzalloc\n");
-+ return -ENOMEM;
-+ }
-+
-+ core->dev = dev;
-+ platform_set_drvdata(pdev, core);
-+
-+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos");
-+ core->dos_base = devm_ioremap_resource(dev, r);
-+ if (IS_ERR(core->dos_base)) {
-+ dev_err(dev, "Couldn't remap DOS memory\n");
-+ return PTR_ERR(core->dos_base);
-+ }
-+
-+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser");
-+ core->esparser_base = devm_ioremap_resource(dev, r);
-+ if (IS_ERR(core->esparser_base)) {
-+ dev_err(dev, "Couldn't remap ESPARSER memory\n");
-+ return PTR_ERR(core->esparser_base);
-+ }
-+
-+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc");
-+ core->dmc_base = devm_ioremap(dev, r->start, resource_size(r));
-+ if (IS_ERR(core->dmc_base)) {
-+ dev_err(dev, "Couldn't remap DMC memory\n");
-+ return PTR_ERR(core->dmc_base);
-+ }
-+
-+ core->regmap_ao = syscon_regmap_lookup_by_phandle(dev->of_node,
-+ "amlogic,ao-sysctrl");
-+ if (IS_ERR(core->regmap_ao)) {
-+ dev_err(dev, "Couldn't regmap AO sysctrl\n");
-+ return PTR_ERR(core->regmap_ao);
-+ }
-+
-+ core->dos_parser_clk = devm_clk_get(dev, "dos_parser");
-+ if (IS_ERR(core->dos_parser_clk)) {
-+ dev_err(dev, "dos_parser clock request failed\n");
-+ return PTR_ERR(core->dos_parser_clk);
-+ }
-+
-+ core->dos_clk = devm_clk_get(dev, "dos");
-+ if (IS_ERR(core->dos_clk)) {
-+ dev_err(dev, "dos clock request failed\n");
-+ return PTR_ERR(core->dos_clk);
-+ }
-+
-+ core->vdec_1_clk = devm_clk_get(dev, "vdec_1");
-+ if (IS_ERR(core->vdec_1_clk)) {
-+ dev_err(dev, "vdec_1 clock request failed\n");
-+ return PTR_ERR(core->vdec_1_clk);
-+ }
-+
-+ core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc");
-+ if (IS_ERR(core->vdec_hevc_clk)) {
-+ dev_err(dev, "vdec_hevc clock request failed\n");
-+ return PTR_ERR(core->vdec_hevc_clk);
-+ }
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq < 0)
-+ return irq;
-+
-+ ret = devm_request_threaded_irq(core->dev, irq, vdec_isr,
-+ vdec_threaded_isr, IRQF_ONESHOT, "vdec", core);
-+ if (ret)
-+ return ret;
-+
-+ ret = esparser_init(pdev, core);
-+ if (ret)
-+ return ret;
-+
-+ ret = v4l2_device_register(dev, &core->v4l2_dev);
-+ if (ret) {
-+ dev_err(dev, "Couldn't register v4l2 device\n");
-+ return -ENOMEM;
-+ }
-+
-+ vdev = video_device_alloc();
-+ if (!vdev) {
-+ ret = -ENOMEM;
-+ goto err_vdev_release;
-+ }
-+
-+ strlcpy(vdev->name, "meson-video-decoder", sizeof(vdev->name));
-+ vdev->release = video_device_release;
-+ vdev->fops = &vdec_fops;
-+ vdev->ioctl_ops = &vdec_ioctl_ops;
-+ vdev->vfl_dir = VFL_DIR_M2M;
-+ vdev->v4l2_dev = &core->v4l2_dev;
-+ vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
-+
-+ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
-+ if (ret) {
-+ dev_err(dev, "Failed registering video device\n");
-+ goto err_vdev_release;
-+ }
-+
-+ of_id = of_match_node(vdec_dt_match, dev->of_node);
-+ core->platform = of_id->data;
-+ core->vdev_dec = vdev;
-+ core->dev_dec = dev;
-+ mutex_init(&core->lock);
-+
-+ video_set_drvdata(vdev, core);
-+
-+ return 0;
-+
-+err_vdev_release:
-+ video_device_release(vdev);
-+ return ret;
-+}
-+
-+static int vdec_remove(struct platform_device *pdev)
-+{
-+ struct vdec_core *core = platform_get_drvdata(pdev);
-+
-+ video_unregister_device(core->vdev_dec);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver meson_vdec_driver = {
-+ .probe = vdec_probe,
-+ .remove = vdec_remove,
-+ .driver = {
-+ .name = "meson-vdec",
-+ .of_match_table = vdec_dt_match,
-+ },
-+};
-+module_platform_driver(meson_vdec_driver);
-+
-+MODULE_ALIAS("platform:meson-video-decoder");
-+MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM");
-+MODULE_AUTHOR("Maxime Jourdan <maxi.jourdan@wanadoo.fr>");
-+MODULE_LICENSE("GPL v2");
-diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h
-new file mode 100644
-index 0000000..b97d6b2
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec.h
-@@ -0,0 +1,152 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_CORE_H_
-+#define __MESON_VDEC_CORE_H_
-+
-+#include <linux/regmap.h>
-+#include <linux/list.h>
-+#include <media/videobuf2-v4l2.h>
-+#include <media/v4l2-ctrls.h>
-+#include <media/v4l2-device.h>
-+
-+#include "vdec_platform.h"
-+
-+#define REG_BUF_SIZE 21
-+
-+struct dummy_buf {
-+ struct vb2_v4l2_buffer vb;
-+ struct list_head list;
-+};
-+
-+struct vdec_buffer {
-+ struct list_head list;
-+ s32 index;
-+ u64 timestamp;
-+};
-+
-+struct vdec_session;
-+
-+struct vdec_core {
-+ void __iomem *dos_base;
-+ void __iomem *esparser_base;
-+ void __iomem *dmc_base;
-+ struct regmap *regmap_ao;
-+
-+ struct device *dev;
-+ struct device *dev_dec;
-+ const struct vdec_platform *platform;
-+
-+ struct clk *dos_parser_clk;
-+ struct clk *dos_clk;
-+ struct clk *vdec_1_clk;
-+ struct clk *vdec_hevc_clk;
-+
-+ struct reset_control *esparser_reset;
-+
-+ struct video_device *vdev_dec;
-+ struct v4l2_device v4l2_dev;
-+
-+ struct vdec_session *cur_sess;
-+ struct mutex lock;
-+};
-+
-+/* Describes one of the VDECS (VDEC_1, VDEC_2, VDEC_HCODEC, VDEC_HEVC) */
-+struct vdec_ops {
-+ int (*start)(struct vdec_session *sess);
-+ int (*stop)(struct vdec_session *sess);
-+ void (*conf_esparser)(struct vdec_session *sess);
-+ u32 (*vififo_level)(struct vdec_session *sess);
-+};
-+
-+/* Describes one of the compression standard supported (H.264, HEVC..) */
-+struct vdec_codec_ops {
-+ int (*start)(struct vdec_session *sess);
-+ int (*stop)(struct vdec_session *sess);
-+ int (*load_extended_firmware)(struct vdec_session *sess, const u8 *data, u32 len);
-+ u32 (*num_pending_bufs)(struct vdec_session *sess);
-+ void (*notify_dst_buffer)(struct vdec_session *sess, struct vb2_buffer *vb);
-+ irqreturn_t (*isr)(struct vdec_session *sess);
-+ irqreturn_t (*threaded_isr)(struct vdec_session *sess);
-+};
-+
-+/* Describes one of the format that can be decoded/encoded */
-+struct vdec_format {
-+ u32 pixfmt;
-+ u32 num_planes;
-+ u32 type;
-+ u32 min_buffers;
-+ u32 max_buffers;
-+
-+ struct vdec_ops *vdec_ops;
-+ struct vdec_codec_ops *codec_ops;
-+
-+ char *firmware_path;
-+};
-+
-+struct vdec_session {
-+ struct vdec_core *core;
-+
-+ struct v4l2_fh fh;
-+ struct v4l2_m2m_dev *m2m_dev;
-+ struct v4l2_m2m_ctx *m2m_ctx;
-+ struct mutex lock;
-+ struct mutex codec_lock;
-+
-+ const struct vdec_format *fmt_out;
-+ const struct vdec_format *fmt_cap;
-+ u32 width;
-+ u32 height;
-+ u32 colorspace;
-+ u8 ycbcr_enc;
-+ u8 quantization;
-+ u8 xfer_func;
-+
-+ u32 num_input_bufs;
-+ u32 num_output_bufs;
-+
-+ /* Number of buffers currently queued into ESPARSER */
-+ atomic_t esparser_queued_bufs;
-+
-+ /* Work for the ESPARSER to process src buffers */
-+ struct work_struct esparser_queue_work;
-+
-+ /* Whether capture/output streaming are on */
-+ unsigned int streamon_cap, streamon_out;
-+
-+ /* Capture sequence counter */
-+ unsigned int sequence_cap;
-+
-+ /* Whether userspace signaled EOS via command, empty buffer or
-+ * V4L2_BUF_FLAG_LAST
-+ */
-+ unsigned int should_stop;
-+
-+ /* Big contiguous area for the VIFIFO */
-+ void *vififo_vaddr;
-+ dma_addr_t vififo_paddr;
-+ u32 vififo_size;
-+
-+ /* Buffers that need to be recycled by the HW */
-+ struct list_head bufs_recycle;
-+ struct mutex bufs_recycle_lock;
-+
-+ /* Buffers queued into the HW */
-+ struct list_head bufs;
-+ spinlock_t bufs_spinlock;
-+
-+ /* Codec private data */
-+ void *priv;
-+};
-+
-+u32 vdec_get_output_size(struct vdec_session *sess);
-+void vdec_dst_buf_done_idx(struct vdec_session *sess, u32 buf_idx);
-+void vdec_dst_buf_done(struct vdec_session *sess, struct vb2_v4l2_buffer *vbuf);
-+void vdec_add_ts_reorder(struct vdec_session *sess, u64 ts);
-+void vdec_remove_ts(struct vdec_session *sess, u64 ts);
-+void vdec_queue_recycle(struct vdec_session *sess, struct vb2_buffer *vb);
-+void vdec_abort(struct vdec_session *sess);
-+
-+#endif
-diff --git a/drivers/media/platform/meson/vdec/vdec_1.c b/drivers/media/platform/meson/vdec/vdec_1.c
-new file mode 100644
-index 0000000..e6593a6
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_1.c
-@@ -0,0 +1,266 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <linux/firmware.h>
-+#include <linux/clk.h>
-+
-+#include "vdec_1.h"
-+
-+/* AO Registers */
-+#define AO_RTI_GEN_PWR_SLEEP0 0xe8
-+#define AO_RTI_GEN_PWR_ISO0 0xec
-+ #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2))
-+
-+/* DOS Registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define MPSR 0x0c04
-+#define CPSR 0x0c84
-+
-+#define IMEM_DMA_CTRL 0x0d00
-+#define IMEM_DMA_ADR 0x0d04
-+#define IMEM_DMA_COUNT 0x0d08
-+#define LMEM_DMA_CTRL 0x0d40
-+
-+#define MC_STATUS0 0x2424
-+#define MC_CTRL1 0x242c
-+
-+#define DBLK_CTRL 0x2544
-+#define DBLK_STATUS 0x254c
-+
-+#define GCLK_EN 0x260c
-+#define MDEC_PIC_DC_CTRL 0x2638
-+#define MDEC_PIC_DC_STATUS 0x263c
-+
-+#define DCAC_DMA_CTRL 0x3848
-+
-+#define DOS_SW_RESET0 0xfc00
-+#define DOS_GCLK_EN0 0xfc04
-+#define DOS_GEN_CTRL0 0xfc08
-+#define DOS_MEM_PD_VDEC 0xfcc0
-+#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00
-+
-+/* Stream Buffer (stbuf) regs (DOS) */
-+#define POWER_CTL_VLD 0x3020
-+#define VLD_MEM_VIFIFO_START_PTR 0x3100
-+#define VLD_MEM_VIFIFO_CURR_PTR 0x3104
-+#define VLD_MEM_VIFIFO_END_PTR 0x3108
-+#define VLD_MEM_VIFIFO_CONTROL 0x3110
-+ #define MEM_FIFO_CNT_BIT 16
-+ #define MEM_FILL_ON_LEVEL BIT(10)
-+ #define MEM_CTRL_EMPTY_EN BIT(2)
-+ #define MEM_CTRL_FILL_EN BIT(1)
-+#define VLD_MEM_VIFIFO_WP 0x3114
-+#define VLD_MEM_VIFIFO_RP 0x3118
-+#define VLD_MEM_VIFIFO_LEVEL 0x311c
-+#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120
-+ #define MEM_BUFCTRL_MANUAL BIT(1)
-+#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144
-+
-+#define MC_SIZE (4096 * 4)
-+
-+static int vdec_1_load_firmware(struct vdec_session *sess, const char* fwname)
-+{
-+ const struct firmware *fw;
-+ struct vdec_core *core = sess->core;
-+ struct device *dev = core->dev_dec;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+ static void *mc_addr;
-+ static dma_addr_t mc_addr_map;
-+ int ret;
-+ u32 i = 1000;
-+
-+ ret = request_firmware(&fw, fwname, dev);
-+ if (ret < 0)
-+ return -EINVAL;
-+
-+ if (fw->size < MC_SIZE) {
-+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
-+ fw->size, MC_SIZE);
-+ ret = -EINVAL;
-+ goto release_firmware;
-+ }
-+
-+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, GFP_KERNEL);
-+ if (!mc_addr) {
-+ dev_err(dev, "Failed allocating memory for firmware loading\n");
-+ ret = -ENOMEM;
-+ goto release_firmware;
-+ }
-+
-+ memcpy(mc_addr, fw->data, MC_SIZE);
-+
-+ writel_relaxed(0, core->dos_base + MPSR);
-+ writel_relaxed(0, core->dos_base + CPSR);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) & ~(1<<31), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ writel_relaxed(mc_addr_map, core->dos_base + IMEM_DMA_ADR);
-+ writel_relaxed(MC_SIZE / 4, core->dos_base + IMEM_DMA_COUNT);
-+ writel_relaxed((0x8000 | (7 << 16)), core->dos_base + IMEM_DMA_CTRL);
-+
-+ while (--i && readl(core->dos_base + IMEM_DMA_CTRL) & 0x8000) { }
-+
-+ if (i == 0) {
-+ dev_err(dev, "Firmware load fail (DMA hang?)\n");
-+ ret = -EINVAL;
-+ goto free_mc;
-+ }
-+
-+ if (codec_ops->load_extended_firmware)
-+ codec_ops->load_extended_firmware(sess, fw->data + MC_SIZE, fw->size - MC_SIZE);
-+
-+free_mc:
-+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
-+release_firmware:
-+ release_firmware(fw);
-+ return ret;
-+}
-+
-+int vdec_1_stbuf_power_up(struct vdec_session *sess) {
-+ struct vdec_core *core = sess->core;
-+
-+ writel_relaxed(0, core->dos_base + VLD_MEM_VIFIFO_CONTROL);
-+ writel_relaxed(0, core->dos_base + VLD_MEM_VIFIFO_WRAP_COUNT);
-+ writel_relaxed(1 << 4, core->dos_base + POWER_CTL_VLD);
-+
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + VLD_MEM_VIFIFO_START_PTR);
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + VLD_MEM_VIFIFO_CURR_PTR);
-+ writel_relaxed(sess->vififo_paddr + sess->vififo_size - 8, core->dos_base + VLD_MEM_VIFIFO_END_PTR);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_CONTROL) | 1, core->dos_base + VLD_MEM_VIFIFO_CONTROL);
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_CONTROL) & ~1, core->dos_base + VLD_MEM_VIFIFO_CONTROL);
-+
-+ writel_relaxed(MEM_BUFCTRL_MANUAL, core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL);
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + VLD_MEM_VIFIFO_WP);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL) | 1, core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL);
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL) & ~1, core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_CONTROL) | (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL | MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN, core->dos_base + VLD_MEM_VIFIFO_CONTROL);
-+
-+ return 0;
-+}
-+
-+static void vdec_1_conf_esparser(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ /* VDEC_1 specific ESPARSER stuff */
-+ writel_relaxed(0, core->dos_base + DOS_GEN_CTRL0); // set vififo_vbuf_rp_sel=>vdec
-+ writel_relaxed(1, core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL);
-+ writel_relaxed(readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL) & ~1, core->dos_base + VLD_MEM_VIFIFO_BUF_CNTL);
-+}
-+
-+static u32 vdec_1_vififo_level(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ return readl_relaxed(core->dos_base + VLD_MEM_VIFIFO_LEVEL);
-+}
-+
-+static int vdec_1_start(struct vdec_session *sess)
-+{
-+ int ret;
-+ struct vdec_core *core = sess->core;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+
-+ clk_set_rate(core->vdec_1_clk, 666666666);
-+ ret = clk_prepare_enable(core->vdec_1_clk);
-+ if (ret)
-+ return ret;
-+
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
-+ GEN_PWR_VDEC_1, 0);
-+ udelay(10);
-+
-+ /* Reset VDEC1 */
-+ writel_relaxed(0xfffffffc, core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0x00000000, core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed(0x3ff, core->dos_base + DOS_GCLK_EN0);
-+
-+ /* VDEC Memories */
-+ writel_relaxed(0x00000000, core->dos_base + DOS_MEM_PD_VDEC);
-+ /* Remove VDEC1 Isolation */
-+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0x00000000);
-+ /* Reset DOS top registers */
-+ writel_relaxed(0x00000000, core->dos_base + DOS_VDEC_MCRCC_STALL_CTRL);
-+
-+ writel_relaxed(0x3ff, core->dos_base + GCLK_EN);
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) & ~(1<<31), core->dos_base + MDEC_PIC_DC_CTRL);
-+
-+ vdec_1_stbuf_power_up(sess);
-+
-+ ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path);
-+ if (ret) {
-+ clk_disable_unprepare(core->vdec_1_clk);
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
-+ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1);
-+ return ret;
-+ }
-+
-+ codec_ops->start(sess);
-+
-+ /* Enable firmware processor */
-+ writel_relaxed(1, core->dos_base + MPSR);
-+
-+ /* Let the firmware settle */
-+ udelay(10);
-+
-+ return 0;
-+}
-+
-+static int vdec_1_stop(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+
-+ writel_relaxed(0, core->dos_base + MPSR);
-+ writel_relaxed(0, core->dos_base + CPSR);
-+
-+ codec_ops->stop(sess);
-+
-+ while (readl_relaxed(core->dos_base + IMEM_DMA_CTRL) & 0x8000) { }
-+
-+ writel_relaxed((1<<12)|(1<<11), core->dos_base + DOS_SW_RESET0);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET0);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET0);
-+
-+ writel_relaxed(0, core->dos_base + ASSIST_MBOX1_MASK);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) | 1, core->dos_base + MDEC_PIC_DC_CTRL);
-+ writel_relaxed(readl_relaxed(core->dos_base + MDEC_PIC_DC_CTRL) & ~1, core->dos_base + MDEC_PIC_DC_CTRL);
-+ readl_relaxed(core->dos_base + MDEC_PIC_DC_STATUS);
-+
-+ writel_relaxed(3, core->dos_base + DBLK_CTRL);
-+ writel_relaxed(0, core->dos_base + DBLK_CTRL);
-+ readl_relaxed(core->dos_base + DBLK_STATUS);
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + MC_CTRL1) | 0x9, core->dos_base + MC_CTRL1);
-+ writel_relaxed(readl_relaxed(core->dos_base + MC_CTRL1) & ~0x9, core->dos_base + MC_CTRL1);
-+ readl_relaxed(core->dos_base + MC_STATUS0);
-+
-+ while (readl_relaxed(core->dos_base + DCAC_DMA_CTRL) & 0x8000) { }
-+
-+ /* enable vdec1 isolation */
-+ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0);
-+ /* power off vdec1 memories */
-+ writel(0xffffffffUL, core->dos_base + DOS_MEM_PD_VDEC);
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
-+ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1);
-+
-+ clk_disable_unprepare(core->vdec_1_clk);
-+
-+ return 0;
-+}
-+
-+struct vdec_ops vdec_1_ops = {
-+ .start = vdec_1_start,
-+ .stop = vdec_1_stop,
-+ .conf_esparser = vdec_1_conf_esparser,
-+ .vififo_level = vdec_1_vififo_level,
-+};
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/vdec_1.h b/drivers/media/platform/meson/vdec/vdec_1.h
-new file mode 100644
-index 0000000..b6c8b41
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_1.h
-@@ -0,0 +1,13 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_VDEC_1_H_
-+#define __MESON_VDEC_VDEC_1_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_ops vdec_1_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c
-new file mode 100644
-index 0000000..4f6e056
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_hevc.c
-@@ -0,0 +1,188 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include <linux/firmware.h>
-+#include <linux/clk.h>
-+
-+#include "vdec_1.h"
-+#include "hevc_regs.h"
-+
-+/* AO Registers */
-+#define AO_RTI_GEN_PWR_SLEEP0 0xe8
-+#define AO_RTI_GEN_PWR_ISO0 0xec
-+ #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6))
-+
-+/* DOS Registers */
-+#define ASSIST_MBOX1_CLR_REG 0x01d4
-+#define ASSIST_MBOX1_MASK 0x01d8
-+
-+#define DOS_GEN_CTRL0 0xfc08
-+#define DOS_SW_RESET3 0xfcd0
-+#define DOS_MEM_PD_HEVC 0xfccc
-+#define DOS_GCLK_EN3 0xfcd4
-+
-+#define MC_SIZE (4096 * 4)
-+
-+static int vdec_hevc_load_firmware(struct vdec_session *sess, const char* fwname)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct device *dev = core->dev_dec;
-+ const struct firmware *fw;
-+ static void *mc_addr;
-+ static dma_addr_t mc_addr_map;
-+ int ret;
-+ u32 i = 100;
-+
-+ ret = request_firmware(&fw, fwname, dev);
-+ if (ret < 0) {
-+ dev_err(dev, "Unable to request firmware %s\n", fwname);
-+ return ret;
-+ }
-+
-+ if (fw->size < MC_SIZE) {
-+ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
-+ fw->size, MC_SIZE);
-+ ret = -EINVAL;
-+ goto release_firmware;
-+ }
-+
-+ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, GFP_KERNEL);
-+ if (!mc_addr) {
-+ dev_err(dev, "Failed allocating memory for firmware loading\n");
-+ ret = -ENOMEM;
-+ goto release_firmware;
-+ }
-+
-+ memcpy(mc_addr, fw->data, MC_SIZE);
-+
-+ writel_relaxed(0, core->dos_base + HEVC_MPSR);
-+ writel_relaxed(0, core->dos_base + HEVC_CPSR);
-+
-+ writel_relaxed(mc_addr_map, core->dos_base + HEVC_IMEM_DMA_ADR);
-+ writel_relaxed(MC_SIZE / 4, core->dos_base + HEVC_IMEM_DMA_COUNT);
-+ writel_relaxed((0x8000 | (7 << 16)), core->dos_base + HEVC_IMEM_DMA_CTRL);
-+
-+ while (--i && readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000) { }
-+
-+ if (i == 0) {
-+ dev_err(dev, "Firmware load fail (DMA hang?)\n");
-+ ret = -ENODEV;
-+ }
-+
-+ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
-+release_firmware:
-+ release_firmware(fw);
-+ return ret;
-+}
-+
-+static void vdec_hevc_stbuf_init(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_STREAM_CONTROL) & ~1, core->dos_base + HEVC_STREAM_CONTROL);
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + HEVC_STREAM_START_ADDR);
-+ writel_relaxed(sess->vififo_paddr + sess->vififo_size, core->dos_base + HEVC_STREAM_END_ADDR);
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + HEVC_STREAM_RD_PTR);
-+ writel_relaxed(sess->vififo_paddr, core->dos_base + HEVC_STREAM_WR_PTR);
-+}
-+
-+/* VDEC_HEVC specific ESPARSER configuration */
-+static void vdec_hevc_conf_esparser(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+
-+ /* set vififo_vbuf_rp_sel=>vdec_hevc */
-+ writel_relaxed(3 << 1, core->dos_base + DOS_GEN_CTRL0);
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_STREAM_CONTROL) | (1 << 3), core->dos_base + HEVC_STREAM_CONTROL);
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_STREAM_CONTROL) | 1, core->dos_base + HEVC_STREAM_CONTROL);
-+ writel_relaxed(readl_relaxed(core->dos_base + HEVC_STREAM_FIFO_CTL) | (1 << 29), core->dos_base + HEVC_STREAM_FIFO_CTL);
-+}
-+
-+static u32 vdec_hevc_vififo_level(struct vdec_session *sess)
-+{
-+ return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL);
-+}
-+
-+static int vdec_hevc_stop(struct vdec_session *sess)
-+{
-+ struct vdec_core *core = sess->core;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+
-+ /* Disable interrupt */
-+ writel_relaxed(0, core->dos_base + HEVC_ASSIST_MBOX1_MASK);
-+ /* Disable firmware processor */
-+ writel_relaxed(0, core->dos_base + HEVC_MPSR);
-+
-+ codec_ops->stop(sess);
-+
-+ /* Enable VDEC_HEVC Isolation */
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0xc00);
-+
-+ /* VDEC_HEVC Memories */
-+ writel_relaxed(0xffffffffUL, core->dos_base + DOS_MEM_PD_HEVC);
-+
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
-+ GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC);
-+
-+ clk_disable_unprepare(core->vdec_hevc_clk);
-+
-+ return 0;
-+}
-+
-+static int vdec_hevc_start(struct vdec_session *sess)
-+{
-+ int ret;
-+ struct vdec_core *core = sess->core;
-+ struct vdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
-+
-+ clk_set_rate(core->vdec_hevc_clk, 666666666);
-+ ret = clk_prepare_enable(core->vdec_hevc_clk);
-+ if (ret)
-+ return ret;
-+
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
-+ GEN_PWR_VDEC_HEVC, 0);
-+ udelay(10);
-+
-+ /* Reset VDEC_HEVC*/
-+ writel_relaxed(0xffffffff, core->dos_base + DOS_SW_RESET3);
-+ writel_relaxed(0x00000000, core->dos_base + DOS_SW_RESET3);
-+
-+ writel_relaxed(0xffffffff, core->dos_base + DOS_GCLK_EN3);
-+
-+ /* VDEC_HEVC Memories */
-+ writel_relaxed(0x00000000, core->dos_base + DOS_MEM_PD_HEVC);
-+
-+ /* Remove VDEC_HEVC Isolation */
-+ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0);
-+
-+ writel_relaxed(0xffffffff, core->dos_base + DOS_SW_RESET3);
-+ writel_relaxed(0x00000000, core->dos_base + DOS_SW_RESET3);
-+
-+ vdec_hevc_stbuf_init(sess);
-+
-+ ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path);
-+ if (ret) {
-+ vdec_hevc_stop(sess);
-+ return ret;
-+ }
-+
-+ codec_ops->start(sess);
-+
-+ writel_relaxed((1<<12)|(1<<11), core->dos_base + DOS_SW_RESET3);
-+ writel_relaxed(0, core->dos_base + DOS_SW_RESET3);
-+ readl_relaxed(core->dos_base + DOS_SW_RESET3);
-+
-+ writel_relaxed(1, core->dos_base + HEVC_MPSR);
-+
-+ return 0;
-+}
-+
-+struct vdec_ops vdec_hevc_ops = {
-+ .start = vdec_hevc_start,
-+ .stop = vdec_hevc_stop,
-+ .conf_esparser = vdec_hevc_conf_esparser,
-+ .vififo_level = vdec_hevc_vififo_level,
-+};
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.h b/drivers/media/platform/meson/vdec/vdec_hevc.h
-new file mode 100644
-index 0000000..a90529c
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_hevc.h
-@@ -0,0 +1,22 @@
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * 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 __MESON_VDEC_VDEC_HEVC_H_
-+#define __MESON_VDEC_VDEC_HEVC_H_
-+
-+#include "vdec.h"
-+
-+extern struct vdec_ops vdec_hevc_ops;
-+
-+#endif
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
-new file mode 100644
-index 0000000..92b7e45
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_platform.c
-@@ -0,0 +1,273 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#include "vdec_platform.h"
-+#include "vdec.h"
-+
-+#include "vdec_1.h"
-+#include "vdec_hevc.h"
-+#include "codec_mpeg12.h"
-+#include "codec_mpeg4.h"
-+#include "codec_mjpeg.h"
-+#include "codec_h264.h"
-+#include "codec_hevc.h"
-+
-+static const struct vdec_format vdec_formats_gxbb[] = {
-+ {
-+ .pixfmt = V4L2_PIX_FMT_NV12M,
-+ .num_planes = 2,
-+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H264,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 32,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_h264_ops,
-+ .firmware_path = "meson/gxbb/vh264_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_HEVC,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 24,
-+ .vdec_ops = &vdec_hevc_ops,
-+ .codec_ops = &codec_hevc_ops,
-+ .firmware_path = "meson/gx/vh265_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG1,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG2,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG4,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H263,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/h263_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_XVID,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MJPEG,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 4,
-+ .max_buffers = 4,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mjpeg_ops,
-+ .firmware_path = "meson/gx/vmjpeg_mc",
-+ },
-+};
-+
-+static const struct vdec_format vdec_formats_gxl[] = {
-+ {
-+ .pixfmt = V4L2_PIX_FMT_NV12M,
-+ .num_planes = 2,
-+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H264,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 32,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_h264_ops,
-+ .firmware_path = "meson/gxl/vh264_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_HEVC,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 24,
-+ .vdec_ops = &vdec_hevc_ops,
-+ .codec_ops = &codec_hevc_ops,
-+ .firmware_path = "meson/gx/vh265_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG1,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG2,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG4,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H263,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/h263_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_XVID,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MJPEG,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 4,
-+ .max_buffers = 4,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mjpeg_ops,
-+ .firmware_path = "meson/gx/vmjpeg_mc",
-+ },
-+};
-+
-+static const struct vdec_format vdec_formats_gxm[] = {
-+ {
-+ .pixfmt = V4L2_PIX_FMT_NV12M,
-+ .num_planes = 2,
-+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H264,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 32,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_h264_ops,
-+ .firmware_path = "meson/gxm/vh264_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_HEVC,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 16,
-+ .max_buffers = 24,
-+ .vdec_ops = &vdec_hevc_ops,
-+ .codec_ops = &codec_hevc_ops,
-+ .firmware_path = "meson/gx/vh265_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG1,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG2,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg12_ops,
-+ .firmware_path = "meson/gx/vmpeg12_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MPEG4,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_H263,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/h263_mc",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_XVID,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 8,
-+ .max_buffers = 8,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mpeg4_ops,
-+ .firmware_path = "meson/gx/vmpeg4_mc_5",
-+ }, {
-+ .pixfmt = V4L2_PIX_FMT_MJPEG,
-+ .num_planes = 1,
-+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
-+ .min_buffers = 4,
-+ .max_buffers = 4,
-+ .vdec_ops = &vdec_1_ops,
-+ .codec_ops = &codec_mjpeg_ops,
-+ .firmware_path = "meson/gx/vmjpeg_mc",
-+ },
-+};
-+
-+const struct vdec_platform vdec_platform_gxbb = {
-+ .formats = vdec_formats_gxbb,
-+ .num_formats = ARRAY_SIZE(vdec_formats_gxbb),
-+ .revision = VDEC_REVISION_GXBB,
-+};
-+
-+const struct vdec_platform vdec_platform_gxl = {
-+ .formats = vdec_formats_gxl,
-+ .num_formats = ARRAY_SIZE(vdec_formats_gxl),
-+ .revision = VDEC_REVISION_GXL,
-+};
-+
-+const struct vdec_platform vdec_platform_gxm = {
-+ .formats = vdec_formats_gxm,
-+ .num_formats = ARRAY_SIZE(vdec_formats_gxm),
-+ .revision = VDEC_REVISION_GXM,
-+};
-\ No newline at end of file
-diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h
-new file mode 100644
-index 0000000..d19fad3
---- /dev/null
-+++ b/drivers/media/platform/meson/vdec/vdec_platform.h
-@@ -0,0 +1,29 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-+ */
-+
-+#ifndef __MESON_VDEC_PLATFORM_H_
-+#define __MESON_VDEC_PLATFORM_H_
-+
-+#include "vdec.h"
-+
-+struct vdec_format;
-+
-+enum vdec_revision {
-+ VDEC_REVISION_GXBB,
-+ VDEC_REVISION_GXL,
-+ VDEC_REVISION_GXM,
-+};
-+
-+struct vdec_platform {
-+ const struct vdec_format *formats;
-+ const u32 num_formats;
-+ enum vdec_revision revision;
-+};
-+
-+extern const struct vdec_platform vdec_platform_gxbb;
-+extern const struct vdec_platform vdec_platform_gxm;
-+extern const struct vdec_platform vdec_platform_gxl;
-+
-+#endif
-\ No newline at end of file
diff --git a/testing/linux-amlogic/0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch b/testing/linux-amlogic/0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch
new file mode 100644
index 0000000000..d07847edac
--- /dev/null
+++ b/testing/linux-amlogic/0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch
@@ -0,0 +1,55 @@
+From 90af79faeb239f3a32974d99a2b58d4ce37cd0c1 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:34:47 +0100
+Subject: [PATCH] pinctrl: meson-gxl: remove invalid GPIOX tsin_a pins
+
+The GPIOX tsin_a pins wrongly uses the SDCard pinctrl bits, this
+patch completely removes these pins entries until we find out what
+are the correct bits and registers to be used instead.
+
+Fixes: 5a6ae9b80139 ("pinctrl: meson-gxl: add tsin_a pins")
+
+---
+ drivers/pinctrl/meson/pinctrl-meson-gxl.c | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+index 158f618..0c0a501 100644
+--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
++++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+@@ -239,13 +239,9 @@ static const unsigned int eth_link_led_pins[] = { GPIOZ_14 };
+ static const unsigned int eth_act_led_pins[] = { GPIOZ_15 };
+
+ static const unsigned int tsin_a_d0_pins[] = { GPIODV_0 };
+-static const unsigned int tsin_a_d0_x_pins[] = { GPIOX_10 };
+ static const unsigned int tsin_a_clk_pins[] = { GPIODV_8 };
+-static const unsigned int tsin_a_clk_x_pins[] = { GPIOX_11 };
+ static const unsigned int tsin_a_sop_pins[] = { GPIODV_9 };
+-static const unsigned int tsin_a_sop_x_pins[] = { GPIOX_8 };
+ static const unsigned int tsin_a_d_valid_pins[] = { GPIODV_10 };
+-static const unsigned int tsin_a_d_valid_x_pins[] = { GPIOX_9 };
+ static const unsigned int tsin_a_fail_pins[] = { GPIODV_11 };
+ static const unsigned int tsin_a_dp_pins[] = {
+ GPIODV_1, GPIODV_2, GPIODV_3, GPIODV_4, GPIODV_5, GPIODV_6, GPIODV_7,
+@@ -432,10 +428,6 @@ static struct meson_pmx_group meson_gxl_periphs_groups[] = {
+ GROUP(spi_miso, 5, 2),
+ GROUP(spi_ss0, 5, 1),
+ GROUP(spi_sclk, 5, 0),
+- GROUP(tsin_a_sop_x, 6, 3),
+- GROUP(tsin_a_d_valid_x, 6, 2),
+- GROUP(tsin_a_d0_x, 6, 1),
+- GROUP(tsin_a_clk_x, 6, 0),
+
+ /* Bank Z */
+ GROUP(eth_mdio, 4, 23),
+@@ -698,8 +690,8 @@ static const char * const eth_led_groups[] = {
+ };
+
+ static const char * const tsin_a_groups[] = {
+- "tsin_a_clk", "tsin_a_clk_x", "tsin_a_sop", "tsin_a_sop_x",
+- "tsin_a_d_valid", "tsin_a_d_valid_x", "tsin_a_d0", "tsin_a_d0_x",
++ "tsin_a_clk", "tsin_a_sop",
++ "tsin_a_d_valid", "tsin_a_d0",
+ "tsin_a_dp", "tsin_a_fail",
+ };
+
diff --git a/testing/linux-amlogic/0027-ARM64-dts-meson-gx-add-vdec-entry.patch b/testing/linux-amlogic/0027-ARM64-dts-meson-gx-add-vdec-entry.patch
deleted file mode 100644
index b5cfc9c3bf..0000000000
--- a/testing/linux-amlogic/0027-ARM64-dts-meson-gx-add-vdec-entry.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 862bb56b65dccfa92e29d58f006f7bd22f68186e Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Thu, 26 Jul 2018 21:51:54 +0200
-Subject: [PATCH] ARM64: dts: meson-gx: add vdec entry
-
-Add the video decoder dts entry
----
- arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-index 7296b4f..739dc49 100644
---- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
-@@ -535,6 +535,20 @@
- };
- };
-
-+ vdec: video-decoder@0xd0050000 {
-+ compatible = "amlogic,meson-gx-vdec";
-+ reg = <0x0 0xc8820000 0x0 0x10000
-+ 0x0 0xc110a580 0x0 0xe4
-+ 0x0 0xc8838000 0x0 0x60>;
-+ reg-names = "dos", "esparser", "dmc";
-+
-+ interrupts = <GIC_SPI 44 IRQ_TYPE_EDGE_RISING
-+ GIC_SPI 32 IRQ_TYPE_EDGE_RISING>;
-+ interrupt-names = "vdec", "esparser";
-+
-+ amlogic,ao-sysctrl = <&sysctrl_AO>;
-+ };
-+
- vpu: vpu@d0100000 {
- compatible = "amlogic,meson-gx-vpu";
- reg = <0x0 0xd0100000 0x0 0x100000>,
diff --git a/testing/linux-amlogic/0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch b/testing/linux-amlogic/0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch
new file mode 100644
index 0000000000..f1ee60638e
--- /dev/null
+++ b/testing/linux-amlogic/0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch
@@ -0,0 +1,79 @@
+From 6c4496753e3bea38dd4b42266c8402d048bde635 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Thu, 8 Nov 2018 14:24:38 +0100
+Subject: [PATCH] arm64: dts: meson-gx: Add hdmi_5v regulator as hdmi tx supply
+
+The hdmi_5v regulator must be enabled to provide power to the physical HDMI
+PHY and enables the HDMI 5V presence loopback for the monitor.
+
+Fixes: b409f625a6d5 ("ARM64: dts: meson-gx: Add HDMI_5V regulator on selected boards")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 1 +
+ arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 1 +
+ arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 1 +
+ arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts | 1 +
+ arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 1 +
+ 5 files changed, 5 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+index fb9ad6f..774f8af 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+@@ -166,6 +166,7 @@
+ status = "okay";
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+ pinctrl-names = "default";
++ hdmi-supply = <&hdmi_5v>;
+ };
+
+ &hdmi_tx_tmds_port {
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+index f053595..e5ef9b0 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+@@ -119,6 +119,7 @@
+ status = "okay";
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+ pinctrl-names = "default";
++ hdmi-supply = <&hdmi_5v>;
+ };
+
+ &hdmi_tx_tmds_port {
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
+index f56969e..ca0228e 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
+@@ -200,6 +200,7 @@
+ status = "okay";
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+ pinctrl-names = "default";
++ hdmi-supply = <&hdmi_5v>;
+ };
+
+ &hdmi_tx_tmds_port {
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
+index f8c66a7..29c9837 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
+@@ -96,6 +96,7 @@
+ status = "okay";
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+ pinctrl-names = "default";
++ hdmi-supply = <&hdmi_5v>;
+ };
+
+ &hdmi_tx_tmds_port {
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
+index 4fbfa5a..fe8e726 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts
+@@ -312,6 +312,7 @@
+ status = "okay";
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+ pinctrl-names = "default";
++ hdmi-supply = <&hdmi_5v>;
+ };
+
+ &hdmi_tx_tmds_port {
diff --git a/testing/linux-amlogic/0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch b/testing/linux-amlogic/0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch
new file mode 100644
index 0000000000..ca8d27efb3
--- /dev/null
+++ b/testing/linux-amlogic/0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch
@@ -0,0 +1,38 @@
+From a0d84363005399bb41b3eee556aa813a129bbcdf Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:45:47 +0100
+Subject: [PATCH] arm64: dts: meson-gxl-libretech-cc: fix GPIO lines names
+
+The gpio line names were set in the pinctrl node instead of the gpio node,
+at the time it was merged, it worked, but was obviously wrong.
+This patch moves the properties to the gpio nodes.
+
+Fixes: 47884c5c746e ("ARM64: dts: meson-gxl-libretech-cc: Add GPIO lines names")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
+index ca0228e..bb2a8c7 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
+@@ -209,7 +209,7 @@
+ };
+ };
+
+-&pinctrl_aobus {
++&gpio_ao {
+ gpio-line-names = "UART TX",
+ "UART RX",
+ "Blue LED",
+@@ -224,7 +224,7 @@
+ "7J1 Header Pin15";
+ };
+
+-&pinctrl_periphs {
++&gpio {
+ gpio-line-names = /* Bank GPIOZ */
+ "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "",
diff --git a/testing/linux-amlogic/0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch b/testing/linux-amlogic/0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch
new file mode 100644
index 0000000000..4ee05f01f1
--- /dev/null
+++ b/testing/linux-amlogic/0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch
@@ -0,0 +1,38 @@
+From 29cf4c3c228fd4cea4f46db9fa5e9386b3e794e6 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:45:48 +0100
+Subject: [PATCH] arm64: dts: meson-gxbb-nanopi-k2: fix GPIO lines names
+
+The gpio line names were set in the pinctrl node instead of the gpio node,
+at the time it was merged, it worked, but was obviously wrong.
+This patch moves the properties to the gpio nodes.
+
+Fixes: 12ada0513d7a ("ARM64: dts: meson-gxbb-nanopi-k2: Add GPIO lines names")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
+index 5b10de9..8ea5ed5 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
+@@ -236,7 +236,7 @@
+ pinctrl-names = "default";
+ };
+
+-&pinctrl_aobus {
++&gpio_ao {
+ gpio-line-names = "UART TX", "UART RX", "Power Control", "Power Key In",
+ "VCCK En", "CON1 Header Pin31",
+ "I2S Header Pin6", "IR In", "I2S Header Pin7",
+@@ -246,7 +246,7 @@
+ "";
+ };
+
+-&pinctrl_periphs {
++&gpio {
+ gpio-line-names = /* Bank GPIOZ */
+ "Eth MDIO", "Eth MDC", "Eth RGMII RX Clk",
+ "Eth RX DV", "Eth RX D0", "Eth RX D1", "Eth RX D2",
diff --git a/testing/linux-amlogic/0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch b/testing/linux-amlogic/0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch
new file mode 100644
index 0000000000..57e37258f5
--- /dev/null
+++ b/testing/linux-amlogic/0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch
@@ -0,0 +1,38 @@
+From fe156961d17219329389eee52306a731b8151b49 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:45:49 +0100
+Subject: [PATCH] arm64: dts: meson-gxbb-odroidc2: fix GPIO lines names
+
+The gpio line names were set in the pinctrl node instead of the gpio node,
+at the time it was merged, it worked, but was obviously wrong.
+This patch moves the properties to the gpio nodes.
+
+Fixes: b03c7d6438bb ("ARM64: dts: meson-gxbb-odroidc2: Add GPIO lines names")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+index 3da3309..73cc801 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+@@ -232,7 +232,7 @@
+ pinctrl-names = "default";
+ };
+
+-&pinctrl_aobus {
++&gpio_ao {
+ gpio-line-names = "UART TX", "UART RX", "VCCK En", "TF 3V3/1V8 En",
+ "USB HUB nRESET", "USB OTG Power En",
+ "J7 Header Pin2", "IR In", "J7 Header Pin4",
+@@ -242,7 +242,7 @@
+ "";
+ };
+
+-&pinctrl_periphs {
++&gpio {
+ gpio-line-names = /* Bank GPIOZ */
+ "Eth MDIO", "Eth MDC", "Eth RGMII RX Clk",
+ "Eth RX DV", "Eth RX D0", "Eth RX D1", "Eth RX D2",
diff --git a/testing/linux-amlogic/0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch b/testing/linux-amlogic/0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch
new file mode 100644
index 0000000000..3e686149e6
--- /dev/null
+++ b/testing/linux-amlogic/0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch
@@ -0,0 +1,38 @@
+From 06df453970ccfbd1affb8ecd6ea50808fa132774 Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Wed, 7 Nov 2018 11:45:50 +0100
+Subject: [PATCH] arm64: dts: meson-gxl-khadas-vim: fix GPIO lines names
+
+The gpio line names were set in the pinctrl node instead of the gpio node,
+at the time it was merged, it worked, but was obviously wrong.
+This patch moves the properties to the gpio nodes.
+
+Fixes: 60795933b709 ("ARM64: dts: meson-gxl-khadas-vim: Add GPIO lines names")
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+index e5ef9b0..1a4b3f3 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
+@@ -158,7 +158,7 @@
+ linux,rc-map-name = "rc-geekbox";
+ };
+
+-&pinctrl_aobus {
++&gpio_ao {
+ gpio-line-names = "UART TX",
+ "UART RX",
+ "Power Key In",
+@@ -173,7 +173,7 @@
+ "";
+ };
+
+-&pinctrl_periphs {
++&gpio {
+ gpio-line-names = /* Bank GPIOZ */
+ "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "",
diff --git a/testing/linux-amlogic/0032-drm-meson-Add-support-for-VIC-alternate-timings.patch b/testing/linux-amlogic/0032-drm-meson-Add-support-for-VIC-alternate-timings.patch
new file mode 100644
index 0000000000..42673f4bc2
--- /dev/null
+++ b/testing/linux-amlogic/0032-drm-meson-Add-support-for-VIC-alternate-timings.patch
@@ -0,0 +1,328 @@
+From 96c3cc9c6943cb27ee519cafe17cb563c3fcc28d Mon Sep 17 00:00:00 2001
+From: Neil Armstrong <narmstrong@baylibre.com>
+Date: Tue, 6 Nov 2018 11:54:35 +0100
+Subject: [PATCH] drm/meson: Add support for VIC alternate timings
+
+This change is an attempt to handle the alternate clock for the CEA mode.
+60Hz vs. 59.94Hz, 30Hz vs 29.97Hz or 24Hz vs 23.97Hz on the Amlogic Meson SoC
+DRM Driver pixel clock generation.
+
+The actual clock generation will be moved to the Common Clock framework once
+all the video clock are handled by the Amlogic Meson SoC clock driver,
+then these alternate timings will be handled in the same time in a cleaner
+fashion.
+
+Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
+
+---
+ drivers/gpu/drm/meson/meson_dw_hdmi.c | 12 +---
+ drivers/gpu/drm/meson/meson_vclk.c | 127 +++++++++++++++++++++++-----------
+ drivers/gpu/drm/meson/meson_vclk.h | 2 +
+ 3 files changed, 89 insertions(+), 52 deletions(-)
+
+diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+index df7247c..d8c5cc3 100644
+--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
+@@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
+ dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
+ vclk_freq, venc_freq, hdmi_freq);
+
+- /* Finally filter by configurable vclk frequencies for VIC modes */
+- switch (vclk_freq) {
+- case 54000:
+- case 74250:
+- case 148500:
+- case 297000:
+- case 594000:
+- return MODE_OK;
+- }
+-
+- return MODE_CLOCK_RANGE;
++ return meson_vclk_vic_supported_freq(vclk_freq);
+ }
+
+ /* Encoder */
+diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
+index ae54732..5accceb 100644
+--- a/drivers/gpu/drm/meson/meson_vclk.c
++++ b/drivers/gpu/drm/meson/meson_vclk.c
+@@ -117,6 +117,8 @@
+ #define HDMI_PLL_RESET BIT(28)
+ #define HDMI_PLL_LOCK BIT(31)
+
++#define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001)
++
+ /* VID PLL Dividers */
+ enum {
+ VID_PLL_DIV_1 = 0,
+@@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
+ enum {
+ /* PLL O1 O2 O3 VP DV EN TX */
+ /* 4320 /4 /4 /1 /5 /1 => /2 /2 */
+- MESON_VCLK_HDMI_ENCI_54000 = 1,
++ MESON_VCLK_HDMI_ENCI_54000 = 0,
+ /* 4320 /4 /4 /1 /5 /1 => /1 /2 */
+ MESON_VCLK_HDMI_DDR_54000,
+ /* 2970 /4 /1 /1 /5 /1 => /1 /2 */
+@@ -339,6 +341,7 @@ enum {
+ };
+
+ struct meson_vclk_params {
++ unsigned int pixel_freq;
+ unsigned int pll_base_freq;
+ unsigned int pll_od1;
+ unsigned int pll_od2;
+@@ -347,6 +350,7 @@ struct meson_vclk_params {
+ unsigned int vclk_div;
+ } params[] = {
+ [MESON_VCLK_HDMI_ENCI_54000] = {
++ .pixel_freq = 54000,
+ .pll_base_freq = 4320000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+@@ -355,6 +359,7 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_DDR_54000] = {
++ .pixel_freq = 54000,
+ .pll_base_freq = 4320000,
+ .pll_od1 = 4,
+ .pll_od2 = 4,
+@@ -363,6 +368,7 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_DDR_148500] = {
++ .pixel_freq = 148500,
+ .pll_base_freq = 2970000,
+ .pll_od1 = 4,
+ .pll_od2 = 1,
+@@ -371,6 +377,7 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_74250] = {
++ .pixel_freq = 74250,
+ .pll_base_freq = 2970000,
+ .pll_od1 = 2,
+ .pll_od2 = 2,
+@@ -379,6 +386,7 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_148500] = {
++ .pixel_freq = 148500,
+ .pll_base_freq = 2970000,
+ .pll_od1 = 1,
+ .pll_od2 = 2,
+@@ -387,6 +395,7 @@ struct meson_vclk_params {
+ .vclk_div = 1,
+ },
+ [MESON_VCLK_HDMI_297000] = {
++ .pixel_freq = 297000,
+ .pll_base_freq = 2970000,
+ .pll_od1 = 1,
+ .pll_od2 = 1,
+@@ -395,6 +404,7 @@ struct meson_vclk_params {
+ .vclk_div = 2,
+ },
+ [MESON_VCLK_HDMI_594000] = {
++ .pixel_freq = 594000,
+ .pll_base_freq = 5940000,
+ .pll_od1 = 1,
+ .pll_od2 = 1,
+@@ -402,6 +412,7 @@ struct meson_vclk_params {
+ .vid_pll_div = VID_PLL_DIV_5,
+ .vclk_div = 1,
+ },
++ { /* sentinel */ },
+ };
+
+ static inline unsigned int pll_od_to_reg(unsigned int od)
+@@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
+ pll_freq);
+ }
+
++enum drm_mode_status
++meson_vclk_vic_supported_freq(unsigned int freq)
++{
++ int i;
++
++ DRM_DEBUG_DRIVER("freq = %d\n", freq);
++
++ for (i = 0 ; params[i].pixel_freq ; ++i) {
++ DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
++ i, params[i].pixel_freq,
++ FREQ_1000_1001(params[i].pixel_freq));
++ /* Match strict frequency */
++ if (freq == params[i].pixel_freq)
++ return MODE_OK;
++ /* Match 1000/1001 variant */
++ if (freq == FREQ_1000_1001(params[i].pixel_freq))
++ return MODE_OK;
++ }
++
++ return MODE_CLOCK_RANGE;
++}
++EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq);
++
+ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
+ unsigned int od1, unsigned int od2, unsigned int od3,
+ unsigned int vid_pll_div, unsigned int vclk_div,
+ unsigned int hdmi_tx_div, unsigned int venc_div,
+- bool hdmi_use_enci)
++ bool hdmi_use_enci, bool vic_alternate_clock)
+ {
++ unsigned int m, frac;
++
+ /* Set HDMI-TX sys clock */
+ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+ CTS_HDMI_SYS_SEL_MASK, 0);
+@@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
+ switch (pll_base_freq) {
+ case 2970000:
+- meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
+- od1, od2, od3);
++ m = 0x3d;
++ frac = vic_alternate_clock ? 0xd02 : 0xe00;
+ break;
+ case 4320000:
+- meson_hdmi_pll_set_params(priv, 0x5a, 0,
+- od1, od2, od3);
++ m = vic_alternate_clock ? 0x59 : 0x5a;
++ frac = vic_alternate_clock ? 0xe8f : 0;
+ break;
+ case 5940000:
+- meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
+- od1, od2, od3);
++ m = 0x7b;
++ frac = vic_alternate_clock ? 0xa05 : 0xc00;
+ break;
+ }
++
++ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
+ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
+ switch (pll_base_freq) {
+ case 2970000:
+- meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
+- od1, od2, od3);
++ m = 0x7b;
++ frac = vic_alternate_clock ? 0x281 : 0x300;
+ break;
+ case 4320000:
+- meson_hdmi_pll_set_params(priv, 0xb4, 0,
+- od1, od2, od3);
++ m = vic_alternate_clock ? 0xb3 : 0xb4;
++ frac = vic_alternate_clock ? 0x347 : 0;
+ break;
+ case 5940000:
+- meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
+- od1, od2, od3);
++ m = 0xf7;
++ frac = vic_alternate_clock ? 0x102 : 0x200;
+ break;
+ }
++
++ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
+ }
+
+ /* Setup vid_pll divider */
+@@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ unsigned int vclk_freq, unsigned int venc_freq,
+ unsigned int dac_freq, bool hdmi_use_enci)
+ {
++ bool vic_alternate_clock = false;
+ unsigned int freq;
+ unsigned int hdmi_tx_div;
+ unsigned int venc_div;
+@@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ * - encp encoder
+ */
+ meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
+- VID_PLL_DIV_5, 2, 1, 1, false);
++ VID_PLL_DIV_5, 2, 1, 1, false, false);
+ return;
+ }
+
+@@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ return;
+ }
+
+- switch (vclk_freq) {
+- case 54000:
+- if (hdmi_use_enci)
+- freq = MESON_VCLK_HDMI_ENCI_54000;
+- else
+- freq = MESON_VCLK_HDMI_DDR_54000;
+- break;
+- case 74250:
+- freq = MESON_VCLK_HDMI_74250;
+- break;
+- case 148500:
+- if (dac_freq != 148500)
+- freq = MESON_VCLK_HDMI_DDR_148500;
+- else
+- freq = MESON_VCLK_HDMI_148500;
+- break;
+- case 297000:
+- freq = MESON_VCLK_HDMI_297000;
+- break;
+- case 594000:
+- freq = MESON_VCLK_HDMI_594000;
+- break;
+- default:
+- pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
+- vclk_freq);
++ for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
++ if (vclk_freq == params[freq].pixel_freq ||
++ vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
++ if (vclk_freq != params[freq].pixel_freq)
++ vic_alternate_clock = true;
++ else
++ vic_alternate_clock = false;
++
++ if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
++ !hdmi_use_enci)
++ continue;
++
++ if (freq == MESON_VCLK_HDMI_DDR_54000 &&
++ hdmi_use_enci)
++ continue;
++
++ if (freq == MESON_VCLK_HDMI_DDR_148500 &&
++ dac_freq == vclk_freq)
++ continue;
++
++ if (freq == MESON_VCLK_HDMI_148500 &&
++ dac_freq != vclk_freq)
++ continue;
++ break;
++ }
++ }
++
++ if (!params[freq].pixel_freq) {
++ pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
+ return;
+ }
+
+@@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ params[freq].pll_od1, params[freq].pll_od2,
+ params[freq].pll_od3, params[freq].vid_pll_div,
+ params[freq].vclk_div, hdmi_tx_div, venc_div,
+- hdmi_use_enci);
++ hdmi_use_enci, vic_alternate_clock);
+ }
+ EXPORT_SYMBOL_GPL(meson_vclk_setup);
+diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
+index 869fa3a..4bd8752 100644
+--- a/drivers/gpu/drm/meson/meson_vclk.h
++++ b/drivers/gpu/drm/meson/meson_vclk.h
+@@ -32,6 +32,8 @@ enum {
+
+ enum drm_mode_status
+ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
++enum drm_mode_status
++meson_vclk_vic_supported_freq(unsigned int freq);
+
+ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
+ unsigned int vclk_freq, unsigned int venc_freq,
diff --git a/testing/linux-amlogic/0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch b/testing/linux-amlogic/0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch
new file mode 100644
index 0000000000..3604a6e456
--- /dev/null
+++ b/testing/linux-amlogic/0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch
@@ -0,0 +1,2969 @@
+From 2c28b1d1f1487bf4aecb36986c2d7b73eb8ac94d Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 29 Aug 2018 15:17:22 +0200
+Subject: [PATCH] media: meson: add v4l2 m2m video decoder driver
+
+Amlogic SoCs feature a powerful video decoder unit able to
+decode many formats, with a performance of usually up to 4k60.
+
+This is a driver for this IP that is based around the v4l2 m2m framework.
+
+It features decoding for:
+- MPEG 1
+- MPEG 2
+
+Supported SoCs are: GXBB (S905), GXL (S905X/W/D), GXM (S912)
+
+There is also a hardware bitstream parser (ESPARSER) that is handled here.
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ drivers/media/platform/Kconfig | 10 +
+ drivers/media/platform/meson/Makefile | 1 +
+ drivers/media/platform/meson/vdec/Makefile | 8 +
+ drivers/media/platform/meson/vdec/codec_mpeg12.c | 209 +++++
+ drivers/media/platform/meson/vdec/codec_mpeg12.h | 14 +
+ drivers/media/platform/meson/vdec/dos_regs.h | 98 ++
+ drivers/media/platform/meson/vdec/esparser.c | 322 +++++++
+ drivers/media/platform/meson/vdec/esparser.h | 32 +
+ drivers/media/platform/meson/vdec/vdec.c | 1034 +++++++++++++++++++++
+ drivers/media/platform/meson/vdec/vdec.h | 251 +++++
+ drivers/media/platform/meson/vdec/vdec_1.c | 231 +++++
+ drivers/media/platform/meson/vdec/vdec_1.h | 14 +
+ drivers/media/platform/meson/vdec/vdec_helpers.c | 412 ++++++++
+ drivers/media/platform/meson/vdec/vdec_helpers.h | 48 +
+ drivers/media/platform/meson/vdec/vdec_platform.c | 101 ++
+ drivers/media/platform/meson/vdec/vdec_platform.h | 30 +
+ 16 files changed, 2815 insertions(+)
+ create mode 100644 drivers/media/platform/meson/vdec/Makefile
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.c
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.h
+ create mode 100644 drivers/media/platform/meson/vdec/dos_regs.h
+ create mode 100644 drivers/media/platform/meson/vdec/esparser.c
+ create mode 100644 drivers/media/platform/meson/vdec/esparser.h
+ create mode 100644 drivers/media/platform/meson/vdec/vdec.c
+ create mode 100644 drivers/media/platform/meson/vdec/vdec.h
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_1.c
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_1.h
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.c
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.h
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.c
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.h
+
+diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
+index 54fe90a..6bffb0c 100644
+--- a/drivers/media/platform/Kconfig
++++ b/drivers/media/platform/Kconfig
+@@ -482,6 +482,16 @@ config VIDEO_QCOM_VENUS
+ on various Qualcomm SoCs.
+ To compile this driver as a module choose m here.
+
++config VIDEO_MESON_VDEC
++ tristate "Amlogic video decoder driver"
++ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
++ depends on ARCH_MESON || COMPILE_TEST
++ select VIDEOBUF2_DMA_CONTIG
++ select V4L2_MEM2MEM_DEV
++ select MESON_CANVAS
++ help
++ Support for the video decoder found in gxbb/gxl/gxm chips.
++
+ endif # V4L_MEM2MEM_DRIVERS
+
+ # TI VIDEO PORT Helper Modules
+diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile
+index 597beb8..f7c6e10 100644
+--- a/drivers/media/platform/meson/Makefile
++++ b/drivers/media/platform/meson/Makefile
+@@ -1 +1,2 @@
+ obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o
++obj-$(CONFIG_VIDEO_MESON_VDEC) += vdec/
+diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
+new file mode 100644
+index 0000000..6bea129
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/Makefile
+@@ -0,0 +1,8 @@
++# SPDX-License-Identifier: GPL-2.0
++# Makefile for Amlogic meson video decoder driver
++
++meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
++meson-vdec-objs += vdec_1.o
++meson-vdec-objs += codec_mpeg12.o
++
++obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
+diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.c b/drivers/media/platform/meson/vdec/codec_mpeg12.c
+new file mode 100644
+index 0000000..1bd6fb7
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mpeg12.c
+@@ -0,0 +1,209 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#include <media/v4l2-mem2mem.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec_helpers.h"
++#include "dos_regs.h"
++
++#define SIZE_WORKSPACE SZ_128K
++/* Offset substracted by the firmware from the workspace paddr */
++#define WORKSPACE_OFFSET (5 * SZ_1K)
++
++/* map firmware registers to known MPEG1/2 functions */
++#define MREG_SEQ_INFO AV_SCRATCH_4
++ #define MPEG2_SEQ_DAR_MASK GENMASK(3, 0)
++ #define MPEG2_DAR_4_3 2
++ #define MPEG2_DAR_16_9 3
++ #define MPEG2_DAR_221_100 4
++#define MREG_PIC_INFO AV_SCRATCH_5
++#define MREG_PIC_WIDTH AV_SCRATCH_6
++#define MREG_PIC_HEIGHT AV_SCRATCH_7
++#define MREG_BUFFERIN AV_SCRATCH_8
++#define MREG_BUFFEROUT AV_SCRATCH_9
++#define MREG_CMD AV_SCRATCH_A
++#define MREG_CO_MV_START AV_SCRATCH_B
++#define MREG_ERROR_COUNT AV_SCRATCH_C
++#define MREG_FRAME_OFFSET AV_SCRATCH_D
++#define MREG_WAIT_BUFFER AV_SCRATCH_E
++#define MREG_FATAL_ERROR AV_SCRATCH_F
++
++#define PICINFO_PROG 0x00008000
++#define PICINFO_TOP_FIRST 0x00002000
++
++struct codec_mpeg12 {
++ /* Buffer for the MPEG1/2 Workspace */
++ void *workspace_vaddr;
++ dma_addr_t workspace_paddr;
++};
++
++static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 };
++
++static const u8 *codec_mpeg12_eos_sequence(u32 *len)
++{
++ *len = ARRAY_SIZE(eos_sequence);
++ return eos_sequence;
++}
++
++static int codec_mpeg12_can_recycle(struct amvdec_core *core)
++{
++ return !amvdec_read_dos(core, MREG_BUFFERIN);
++}
++
++static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx)
++{
++ amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1);
++}
++
++static int codec_mpeg12_start(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ struct codec_mpeg12 *mpeg12 = sess->priv;
++ int ret;
++
++ mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL);
++ if (!mpeg12)
++ return -ENOMEM;
++
++ /* Allocate some memory for the MPEG1/2 decoder's state */
++ mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
++ &mpeg12->workspace_paddr,
++ GFP_KERNEL);
++ if (!mpeg12->workspace_vaddr) {
++ dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n");
++ ret = -ENOMEM;
++ goto free_mpeg12;
++ }
++
++ ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 },
++ (u32[]){ 8, 0 });
++ if (ret)
++ goto free_workspace;
++
++ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4));
++ amvdec_write_dos(core, MREG_CO_MV_START,
++ mpeg12->workspace_paddr + WORKSPACE_OFFSET);
++
++ amvdec_write_dos(core, MPEG1_2_REG, 0);
++ amvdec_write_dos(core, PSCALE_CTRL, 0);
++ amvdec_write_dos(core, PIC_HEAD_INFO, 0x380);
++ amvdec_write_dos(core, M4_CONTROL_REG, 0);
++ amvdec_write_dos(core, MREG_BUFFERIN, 0);
++ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
++ amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height);
++ amvdec_write_dos(core, MREG_ERROR_COUNT, 0);
++ amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
++ amvdec_write_dos(core, MREG_WAIT_BUFFER, 0);
++
++ sess->keyframe_found = 1;
++ sess->priv = mpeg12;
++
++ return 0;
++
++free_workspace:
++ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr,
++ mpeg12->workspace_paddr);
++free_mpeg12:
++ kfree(mpeg12);
++
++ return ret;
++}
++
++static int codec_mpeg12_stop(struct amvdec_session *sess)
++{
++ struct codec_mpeg12 *mpeg12 = sess->priv;
++ struct amvdec_core *core = sess->core;
++
++ if (mpeg12->workspace_vaddr)
++ dma_free_coherent(core->dev, SIZE_WORKSPACE,
++ mpeg12->workspace_vaddr,
++ mpeg12->workspace_paddr);
++
++ return 0;
++}
++
++static void codec_mpeg12_update_dar(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO);
++ u32 ar = seq & MPEG2_SEQ_DAR_MASK;
++
++ switch (ar) {
++ case MPEG2_DAR_4_3:
++ amvdec_set_par_from_dar(sess, 4, 3);
++ break;
++ case MPEG2_DAR_16_9:
++ amvdec_set_par_from_dar(sess, 16, 9);
++ break;
++ case MPEG2_DAR_221_100:
++ amvdec_set_par_from_dar(sess, 221, 100);
++ break;
++ default:
++ sess->pixelaspect.numerator = 1;
++ sess->pixelaspect.denominator = 1;
++ break;
++ };
++}
++
++static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 reg;
++ u32 pic_info;
++ u32 is_progressive;
++ u32 buffer_index;
++ u32 field = V4L2_FIELD_NONE;
++ u32 offset;
++
++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
++ reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
++ if (reg == 1) {
++ dev_err(core->dev, "MPEG1/2 fatal error\n");
++ amvdec_abort(sess);
++ return IRQ_HANDLED;
++ }
++
++ reg = amvdec_read_dos(core, MREG_BUFFEROUT);
++ if (!reg)
++ return IRQ_HANDLED;
++
++ /* Unclear what this means */
++ if ((reg & GENMASK(23, 17)) == GENMASK(23, 17))
++ goto end;
++
++ pic_info = amvdec_read_dos(core, MREG_PIC_INFO);
++ is_progressive = pic_info & PICINFO_PROG;
++
++ if (!is_progressive)
++ field = (pic_info & PICINFO_TOP_FIRST) ?
++ V4L2_FIELD_INTERLACED_TB :
++ V4L2_FIELD_INTERLACED_BT;
++
++ codec_mpeg12_update_dar(sess);
++ buffer_index = ((reg & 0xf) - 1) & 7;
++ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET);
++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
++
++end:
++ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess)
++{
++ return IRQ_WAKE_THREAD;
++}
++
++struct amvdec_codec_ops codec_mpeg12_ops = {
++ .start = codec_mpeg12_start,
++ .stop = codec_mpeg12_stop,
++ .isr = codec_mpeg12_isr,
++ .threaded_isr = codec_mpeg12_threaded_isr,
++ .can_recycle = codec_mpeg12_can_recycle,
++ .recycle = codec_mpeg12_recycle,
++ .eos_sequence = codec_mpeg12_eos_sequence,
++};
+diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.h b/drivers/media/platform/meson/vdec/codec_mpeg12.h
+new file mode 100644
+index 0000000..43cab5f
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mpeg12.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_CODEC_MPEG12_H_
++#define __MESON_VDEC_CODEC_MPEG12_H_
++
++#include "vdec.h"
++
++extern struct amvdec_codec_ops codec_mpeg12_ops;
++
++#endif
+diff --git a/drivers/media/platform/meson/vdec/dos_regs.h b/drivers/media/platform/meson/vdec/dos_regs.h
+new file mode 100644
+index 0000000..abd8105
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/dos_regs.h
+@@ -0,0 +1,98 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_DOS_REGS_H_
++#define __MESON_VDEC_DOS_REGS_H_
++
++/* DOS registers */
++#define VDEC_ASSIST_AMR1_INT8 0x00b4
++
++#define ASSIST_MBOX1_CLR_REG 0x01d4
++#define ASSIST_MBOX1_MASK 0x01d8
++
++#define MPSR 0x0c04
++#define MCPU_INTR_MSK 0x0c10
++#define CPSR 0x0c84
++
++#define IMEM_DMA_CTRL 0x0d00
++#define IMEM_DMA_ADR 0x0d04
++#define IMEM_DMA_COUNT 0x0d08
++#define LMEM_DMA_CTRL 0x0d40
++
++#define MC_STATUS0 0x2424
++#define MC_CTRL1 0x242c
++
++#define PSCALE_RST 0x2440
++#define PSCALE_CTRL 0x2444
++#define PSCALE_BMEM_ADDR 0x247c
++#define PSCALE_BMEM_DAT 0x2480
++
++#define DBLK_CTRL 0x2544
++#define DBLK_STATUS 0x254c
++
++#define GCLK_EN 0x260c
++#define MDEC_PIC_DC_CTRL 0x2638
++#define MDEC_PIC_DC_STATUS 0x263c
++#define ANC0_CANVAS_ADDR 0x2640
++#define MDEC_PIC_DC_THRESH 0x26e0
++
++/* Firmware interface registers */
++#define AV_SCRATCH_0 0x2700
++#define AV_SCRATCH_1 0x2704
++#define AV_SCRATCH_2 0x2708
++#define AV_SCRATCH_3 0x270c
++#define AV_SCRATCH_4 0x2710
++#define AV_SCRATCH_5 0x2714
++#define AV_SCRATCH_6 0x2718
++#define AV_SCRATCH_7 0x271c
++#define AV_SCRATCH_8 0x2720
++#define AV_SCRATCH_9 0x2724
++#define AV_SCRATCH_A 0x2728
++#define AV_SCRATCH_B 0x272c
++#define AV_SCRATCH_C 0x2730
++#define AV_SCRATCH_D 0x2734
++#define AV_SCRATCH_E 0x2738
++#define AV_SCRATCH_F 0x273c
++#define AV_SCRATCH_G 0x2740
++#define AV_SCRATCH_H 0x2744
++#define AV_SCRATCH_I 0x2748
++#define AV_SCRATCH_J 0x274c
++#define AV_SCRATCH_K 0x2750
++#define AV_SCRATCH_L 0x2754
++
++#define MPEG1_2_REG 0x3004
++#define PIC_HEAD_INFO 0x300c
++#define POWER_CTL_VLD 0x3020
++#define M4_CONTROL_REG 0x30a4
++
++/* Stream Buffer (stbuf) regs */
++#define VLD_MEM_VIFIFO_START_PTR 0x3100
++#define VLD_MEM_VIFIFO_CURR_PTR 0x3104
++#define VLD_MEM_VIFIFO_END_PTR 0x3108
++#define VLD_MEM_VIFIFO_CONTROL 0x3110
++ #define MEM_FIFO_CNT_BIT 16
++ #define MEM_FILL_ON_LEVEL BIT(10)
++ #define MEM_CTRL_EMPTY_EN BIT(2)
++ #define MEM_CTRL_FILL_EN BIT(1)
++#define VLD_MEM_VIFIFO_WP 0x3114
++#define VLD_MEM_VIFIFO_RP 0x3118
++#define VLD_MEM_VIFIFO_LEVEL 0x311c
++#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120
++ #define MEM_BUFCTRL_MANUAL BIT(1)
++#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144
++
++#define DCAC_DMA_CTRL 0x3848
++
++#define DOS_SW_RESET0 0xfc00
++#define DOS_GCLK_EN0 0xfc04
++#define DOS_GEN_CTRL0 0xfc08
++#define DOS_MEM_PD_VDEC 0xfcc0
++#define DOS_MEM_PD_HEVC 0xfccc
++#define DOS_SW_RESET3 0xfcd0
++#define DOS_GCLK_EN3 0xfcd4
++#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00
++
++#endif
+diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c
+new file mode 100644
+index 0000000..9498812
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/esparser.c
+@@ -0,0 +1,322 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ *
++ * The Elementary Stream Parser is a HW bitstream parser.
++ * It reads bitstream buffers and feeds them to the VIFIFO
++ */
++
++#include <linux/init.h>
++#include <linux/ioctl.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/reset.h>
++#include <media/videobuf2-dma-contig.h>
++#include <media/v4l2-mem2mem.h>
++
++#include "dos_regs.h"
++#include "esparser.h"
++#include "vdec_helpers.h"
++
++/* PARSER REGS (CBUS) */
++#define PARSER_CONTROL 0x00
++ #define ES_PACK_SIZE_BIT 8
++ #define ES_WRITE BIT(5)
++ #define ES_SEARCH BIT(1)
++ #define ES_PARSER_START BIT(0)
++#define PARSER_FETCH_ADDR 0x4
++#define PARSER_FETCH_CMD 0x8
++#define PARSER_CONFIG 0x14
++ #define PS_CFG_MAX_FETCH_CYCLE_BIT 0
++ #define PS_CFG_STARTCODE_WID_24_BIT 10
++ #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12
++ #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16
++#define PFIFO_WR_PTR 0x18
++#define PFIFO_RD_PTR 0x1c
++#define PARSER_SEARCH_PATTERN 0x24
++ #define ES_START_CODE_PATTERN 0x00000100
++#define PARSER_SEARCH_MASK 0x28
++ #define ES_START_CODE_MASK 0xffffff00
++ #define FETCH_ENDIAN_BIT 27
++#define PARSER_INT_ENABLE 0x2c
++ #define PARSER_INT_HOST_EN_BIT 8
++#define PARSER_INT_STATUS 0x30
++ #define PARSER_INTSTAT_SC_FOUND 1
++#define PARSER_ES_CONTROL 0x5c
++#define PARSER_VIDEO_START_PTR 0x80
++#define PARSER_VIDEO_END_PTR 0x84
++#define PARSER_VIDEO_WP 0x88
++#define PARSER_VIDEO_HOLE 0x90
++
++#define SEARCH_PATTERN_LEN 512
++
++static DECLARE_WAIT_QUEUE_HEAD(wq);
++static int search_done;
++
++static irqreturn_t esparser_isr(int irq, void *dev)
++{
++ int int_status;
++ struct amvdec_core *core = dev;
++
++ int_status = amvdec_read_parser(core, PARSER_INT_STATUS);
++ amvdec_write_parser(core, PARSER_INT_STATUS, int_status);
++
++ if (int_status & PARSER_INTSTAT_SC_FOUND) {
++ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
++ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
++ search_done = 1;
++ wake_up_interruptible(&wq);
++ }
++
++ return IRQ_HANDLED;
++}
++
++/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger
++ * ISRs.
++ * Also append a start code 000001ff at the end to trigger
++ * the ESPARSER interrupt.
++ */
++static u32 esparser_pad_start_code(struct vb2_buffer *vb)
++{
++ u32 payload_size = vb2_get_plane_payload(vb, 0);
++ u32 pad_size = 0;
++ u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size;
++
++ if (payload_size < ESPARSER_MIN_PACKET_SIZE) {
++ pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size;
++ memset(vaddr, 0, pad_size);
++ }
++
++ memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN);
++ vaddr[pad_size] = 0x00;
++ vaddr[pad_size + 1] = 0x00;
++ vaddr[pad_size + 2] = 0x01;
++ vaddr[pad_size + 3] = 0xff;
++
++ return pad_size;
++}
++
++static int
++esparser_write_data(struct amvdec_core *core, dma_addr_t addr, u32 size)
++{
++ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
++ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
++ amvdec_write_parser(core, PARSER_CONTROL,
++ ES_WRITE |
++ ES_PARSER_START |
++ ES_SEARCH |
++ (size << ES_PACK_SIZE_BIT));
++
++ amvdec_write_parser(core, PARSER_FETCH_ADDR, addr);
++ amvdec_write_parser(core, PARSER_FETCH_CMD,
++ (7 << FETCH_ENDIAN_BIT) |
++ (size + SEARCH_PATTERN_LEN));
++
++ search_done = 0;
++ return wait_event_interruptible_timeout(wq, search_done, (HZ / 5));
++}
++
++static u32 esparser_vififo_get_free_space(struct amvdec_session *sess)
++{
++ u32 vififo_usage;
++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
++ struct amvdec_core *core = sess->core;
++
++ vififo_usage = vdec_ops->vififo_level(sess);
++ vififo_usage += amvdec_read_parser(core, PARSER_VIDEO_HOLE);
++ vififo_usage += (6 * SZ_1K); // 6 KiB internal fifo
++
++ if (vififo_usage > sess->vififo_size) {
++ dev_warn(sess->core->dev,
++ "VIFIFO usage (%u) > VIFIFO size (%u)\n",
++ vififo_usage, sess->vififo_size);
++ return 0;
++ }
++
++ return sess->vififo_size - vififo_usage;
++}
++
++int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len)
++{
++ struct device *dev = core->dev;
++ void *eos_vaddr;
++ dma_addr_t eos_paddr;
++ int ret;
++
++ eos_vaddr = dma_alloc_coherent(dev,
++ len + SEARCH_PATTERN_LEN,
++ &eos_paddr, GFP_KERNEL);
++ if (!eos_vaddr)
++ return -ENOMEM;
++
++ memset(eos_vaddr, 0, len + SEARCH_PATTERN_LEN);
++ memcpy(eos_vaddr, data, len);
++ ret = esparser_write_data(core, eos_paddr, len);
++ dma_free_coherent(dev, len + SEARCH_PATTERN_LEN,
++ eos_vaddr, eos_paddr);
++
++ return ret;
++}
++
++static u32 esparser_get_offset(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 offset = amvdec_read_parser(core, PARSER_VIDEO_WP) -
++ sess->vififo_paddr;
++
++ if (offset < sess->last_offset)
++ sess->wrap_count++;
++
++ sess->last_offset = offset;
++ offset += (sess->wrap_count * sess->vififo_size);
++
++ return offset;
++}
++
++static int
++esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf)
++{
++ int ret;
++ struct vb2_buffer *vb = &vbuf->vb2_buf;
++ struct amvdec_core *core = sess->core;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++ u32 num_dst_bufs = 0;
++ u32 payload_size = vb2_get_plane_payload(vb, 0);
++ dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0);
++ u32 offset;
++ u32 pad_size;
++
++ if (codec_ops->num_pending_bufs)
++ num_dst_bufs = codec_ops->num_pending_bufs(sess);
++
++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx);
++
++ if (esparser_vififo_get_free_space(sess) < payload_size ||
++ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs)
++ return -EAGAIN;
++
++ v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf);
++
++ offset = esparser_get_offset(sess);
++
++ amvdec_add_ts_reorder(sess, vb->timestamp, offset);
++ dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n",
++ vb->timestamp, payload_size, offset);
++
++ pad_size = esparser_pad_start_code(vb);
++ ret = esparser_write_data(core, phy, payload_size + pad_size);
++
++ if (ret <= 0) {
++ dev_warn(core->dev, "esparser: input parsing error\n");
++ amvdec_remove_ts(sess, vb->timestamp);
++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
++ amvdec_write_parser(core, PARSER_FETCH_CMD, 0);
++
++ return 0;
++ }
++
++ /* We need to wait until we parse the first keyframe.
++ * All buffers prior to the first keyframe must be dropped.
++ */
++ if (!sess->keyframe_found)
++ usleep_range(1000, 2000);
++
++ if (sess->keyframe_found)
++ atomic_inc(&sess->esparser_queued_bufs);
++ else
++ amvdec_remove_ts(sess, vb->timestamp);
++
++ vbuf->flags = 0;
++ vbuf->field = V4L2_FIELD_NONE;
++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
++
++ return 0;
++}
++
++void esparser_queue_all_src(struct work_struct *work)
++{
++ struct v4l2_m2m_buffer *buf, *n;
++ struct amvdec_session *sess =
++ container_of(work, struct amvdec_session, esparser_queue_work);
++
++ mutex_lock(&sess->lock);
++ v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) {
++ if (esparser_queue(sess, &buf->vb) < 0)
++ break;
++ }
++ mutex_unlock(&sess->lock);
++}
++
++int esparser_power_up(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
++
++ reset_control_reset(core->esparser_reset);
++ amvdec_write_parser(core, PARSER_CONFIG,
++ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
++ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
++ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT));
++
++ amvdec_write_parser(core, PFIFO_RD_PTR, 0);
++ amvdec_write_parser(core, PFIFO_WR_PTR, 0);
++
++ amvdec_write_parser(core, PARSER_SEARCH_PATTERN,
++ ES_START_CODE_PATTERN);
++ amvdec_write_parser(core, PARSER_SEARCH_MASK, ES_START_CODE_MASK);
++
++ amvdec_write_parser(core, PARSER_CONFIG,
++ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) |
++ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) |
++ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) |
++ (2 << PS_CFG_STARTCODE_WID_24_BIT));
++
++ amvdec_write_parser(core, PARSER_CONTROL,
++ (ES_SEARCH | ES_PARSER_START));
++
++ amvdec_write_parser(core, PARSER_VIDEO_START_PTR, sess->vififo_paddr);
++ amvdec_write_parser(core, PARSER_VIDEO_END_PTR,
++ sess->vififo_paddr + sess->vififo_size - 8);
++ amvdec_write_parser(core, PARSER_ES_CONTROL,
++ amvdec_read_parser(core, PARSER_ES_CONTROL) & ~1);
++
++ if (vdec_ops->conf_esparser)
++ vdec_ops->conf_esparser(sess);
++
++ amvdec_write_parser(core, PARSER_INT_STATUS, 0xffff);
++ amvdec_write_parser(core, PARSER_INT_ENABLE,
++ BIT(PARSER_INT_HOST_EN_BIT));
++
++ return 0;
++}
++
++int esparser_init(struct platform_device *pdev, struct amvdec_core *core)
++{
++ struct device *dev = &pdev->dev;
++ int ret;
++ int irq;
++
++ irq = platform_get_irq_byname(pdev, "esparser");
++ if (irq < 0) {
++ dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n");
++ return irq;
++ }
++
++ ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED,
++ "esparserirq", core);
++ if (ret) {
++ dev_err(dev, "Failed requesting ESPARSER IRQ\n");
++ return ret;
++ }
++
++ core->esparser_reset =
++ devm_reset_control_get_exclusive(dev, "esparser");
++ if (IS_ERR(core->esparser_reset)) {
++ dev_err(dev, "Failed to get esparser_reset\n");
++ return PTR_ERR(core->esparser_reset);
++ }
++
++ return 0;
++}
+diff --git a/drivers/media/platform/meson/vdec/esparser.h b/drivers/media/platform/meson/vdec/esparser.h
+new file mode 100644
+index 0000000..ff51fe7
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/esparser.h
+@@ -0,0 +1,32 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_ESPARSER_H_
++#define __MESON_VDEC_ESPARSER_H_
++
++#include <linux/platform_device.h>
++
++#include "vdec.h"
++
++int esparser_init(struct platform_device *pdev, struct amvdec_core *core);
++int esparser_power_up(struct amvdec_session *sess);
++
++/**
++ * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER
++ *
++ * @core vdec core struct
++ */
++int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len);
++
++/**
++ * esparser_queue_all_src() - work handler that writes as many src buffers
++ * as possible to the ESPARSER
++ */
++void esparser_queue_all_src(struct work_struct *work);
++
++#define ESPARSER_MIN_PACKET_SIZE SZ_4K
++
++#endif
+diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c
+new file mode 100644
+index 0000000..d8db52c
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec.c
+@@ -0,0 +1,1034 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#include <linux/of_device.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mfd/syscon.h>
++#include <linux/slab.h>
++#include <media/v4l2-ioctl.h>
++#include <media/v4l2-event.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-mem2mem.h>
++#include <media/v4l2-dev.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec.h"
++#include "esparser.h"
++#include "vdec_helpers.h"
++
++struct dummy_buf {
++ struct vb2_v4l2_buffer vb;
++ struct list_head list;
++};
++
++/* 16 MiB for parsed bitstream swap exchange */
++#define SIZE_VIFIFO SZ_16M
++
++static u32 get_output_size(u32 width, u32 height)
++{
++ return ALIGN(width * height, SZ_64K);
++}
++
++u32 amvdec_get_output_size(struct amvdec_session *sess)
++{
++ return get_output_size(sess->width, sess->height);
++}
++EXPORT_SYMBOL_GPL(amvdec_get_output_size);
++
++static int vdec_codec_needs_recycle(struct amvdec_session *sess)
++{
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++
++ return codec_ops->can_recycle && codec_ops->recycle;
++}
++
++static int vdec_recycle_thread(void *data)
++{
++ struct amvdec_session *sess = data;
++ struct amvdec_core *core = sess->core;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++ struct amvdec_buffer *tmp, *n;
++
++ while (!kthread_should_stop()) {
++ mutex_lock(&sess->bufs_recycle_lock);
++ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) {
++ if (!codec_ops->can_recycle(core))
++ break;
++
++ codec_ops->recycle(core, tmp->vb->index);
++ list_del(&tmp->list);
++ kfree(tmp);
++ }
++ mutex_unlock(&sess->bufs_recycle_lock);
++
++ usleep_range(5000, 10000);
++ }
++
++ return 0;
++}
++
++static int vdec_poweron(struct amvdec_session *sess)
++{
++ int ret;
++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
++
++ ret = clk_prepare_enable(sess->core->dos_parser_clk);
++ if (ret)
++ return ret;
++
++ ret = clk_prepare_enable(sess->core->dos_clk);
++ if (ret)
++ goto disable_dos_parser;
++
++ ret = vdec_ops->start(sess);
++ if (ret)
++ goto disable_dos;
++
++ esparser_power_up(sess);
++
++ return 0;
++
++disable_dos:
++ clk_disable_unprepare(sess->core->dos_clk);
++disable_dos_parser:
++ clk_disable_unprepare(sess->core->dos_parser_clk);
++
++ return ret;
++}
++
++static void vdec_wait_inactive(struct amvdec_session *sess)
++{
++ /* We consider 50ms with no IRQ to be inactive. */
++ while (time_is_after_jiffies64(sess->last_irq_jiffies +
++ msecs_to_jiffies(50)))
++ msleep(25);
++}
++
++static void vdec_poweroff(struct amvdec_session *sess)
++{
++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++
++ vdec_wait_inactive(sess);
++ if (codec_ops->drain)
++ codec_ops->drain(sess);
++
++ vdec_ops->stop(sess);
++ clk_disable_unprepare(sess->core->dos_clk);
++ clk_disable_unprepare(sess->core->dos_parser_clk);
++}
++
++static void
++vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb)
++{
++ struct amvdec_buffer *new_buf;
++
++ new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL);
++ new_buf->vb = vb;
++
++ mutex_lock(&sess->bufs_recycle_lock);
++ list_add_tail(&new_buf->list, &sess->bufs_recycle);
++ mutex_unlock(&sess->bufs_recycle_lock);
++}
++
++static void vdec_m2m_device_run(void *priv)
++{
++ struct amvdec_session *sess = priv;
++
++ schedule_work(&sess->esparser_queue_work);
++}
++
++static void vdec_m2m_job_abort(void *priv)
++{
++ struct amvdec_session *sess = priv;
++
++ v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx);
++}
++
++static const struct v4l2_m2m_ops vdec_m2m_ops = {
++ .device_run = vdec_m2m_device_run,
++ .job_abort = vdec_m2m_job_abort,
++};
++
++static int vdec_queue_setup(struct vb2_queue *q,
++ unsigned int *num_buffers, unsigned int *num_planes,
++ unsigned int sizes[], struct device *alloc_devs[])
++{
++ struct amvdec_session *sess = vb2_get_drv_priv(q);
++ const struct amvdec_format *fmt_out = sess->fmt_out;
++ u32 output_size = amvdec_get_output_size(sess);
++ u32 buffers_total;
++
++ if (*num_planes) {
++ switch (q->type) {
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
++ if (*num_planes != 1 || sizes[0] < output_size)
++ return -EINVAL;
++ break;
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
++ switch (sess->pixfmt_cap) {
++ case V4L2_PIX_FMT_NV12M:
++ if (*num_planes != 2 ||
++ sizes[0] < output_size ||
++ sizes[1] < output_size / 2)
++ return -EINVAL;
++ break;
++ case V4L2_PIX_FMT_YUV420M:
++ if (*num_planes != 3 ||
++ sizes[0] < output_size ||
++ sizes[1] < output_size / 4 ||
++ sizes[2] < output_size / 4)
++ return -EINVAL;
++ break;
++ default:
++ return -EINVAL;
++ }
++ break;
++ }
++
++ return 0;
++ }
++
++ switch (q->type) {
++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
++ sizes[0] = amvdec_get_output_size(sess);
++ *num_planes = 1;
++ break;
++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
++ switch (sess->pixfmt_cap) {
++ case V4L2_PIX_FMT_NV12M:
++ sizes[0] = output_size;
++ sizes[1] = output_size / 2;
++ *num_planes = 2;
++ break;
++ case V4L2_PIX_FMT_YUV420M:
++ sizes[0] = output_size;
++ sizes[1] = output_size / 4;
++ sizes[2] = output_size / 4;
++ *num_planes = 3;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ buffers_total = q->num_buffers + *num_buffers;
++
++ if (buffers_total < fmt_out->min_buffers)
++ *num_buffers = fmt_out->min_buffers - q->num_buffers;
++ if (buffers_total > fmt_out->max_buffers)
++ *num_buffers = fmt_out->max_buffers - q->num_buffers;
++
++ /* We need to program the complete CAPTURE buffer list
++ * in registers during start_streaming, and the firmwares
++ * are free to choose any of them to write frames to. As such,
++ * we need all of them to be queued into the driver
++ */
++ q->min_buffers_needed = q->num_buffers + *num_buffers;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
++{
++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
++ struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue);
++ struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx;
++
++ v4l2_m2m_buf_queue(m2m_ctx, vbuf);
++
++ if (!sess->streamon_out || !sess->streamon_cap)
++ return;
++
++ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
++ vdec_codec_needs_recycle(sess))
++ vdec_queue_recycle(sess, vb);
++
++ schedule_work(&sess->esparser_queue_work);
++}
++
++static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
++{
++ struct amvdec_session *sess = vb2_get_drv_priv(q);
++ struct amvdec_core *core = sess->core;
++ struct vb2_v4l2_buffer *buf;
++ int ret;
++
++ if (core->cur_sess && core->cur_sess != sess) {
++ ret = -EBUSY;
++ goto bufs_done;
++ }
++
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
++ sess->streamon_out = 1;
++ else
++ sess->streamon_cap = 1;
++
++ if (!sess->streamon_out || !sess->streamon_cap)
++ return 0;
++
++ sess->vififo_size = SIZE_VIFIFO;
++ sess->vififo_vaddr =
++ dma_alloc_coherent(sess->core->dev, sess->vififo_size,
++ &sess->vififo_paddr, GFP_KERNEL);
++ if (!sess->vififo_vaddr) {
++ dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n");
++ ret = -ENOMEM;
++ goto bufs_done;
++ }
++
++ sess->should_stop = 0;
++ sess->keyframe_found = 0;
++ sess->last_offset = 0;
++ sess->wrap_count = 0;
++ sess->pixelaspect.numerator = 1;
++ sess->pixelaspect.denominator = 1;
++ atomic_set(&sess->esparser_queued_bufs, 0);
++
++ ret = vdec_poweron(sess);
++ if (ret)
++ goto vififo_free;
++
++ sess->sequence_cap = 0;
++ if (vdec_codec_needs_recycle(sess))
++ sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
++ "vdec_recycle");
++
++ core->cur_sess = sess;
++
++ return 0;
++
++vififo_free:
++ dma_free_coherent(sess->core->dev, sess->vififo_size,
++ sess->vififo_vaddr, sess->vififo_paddr);
++bufs_done:
++ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
++ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
++
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
++ sess->streamon_out = 0;
++ else
++ sess->streamon_cap = 0;
++
++ return ret;
++}
++
++static void vdec_free_canvas(struct amvdec_session *sess)
++{
++ int i;
++
++ for (i = 0; i < sess->canvas_num; ++i)
++ meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]);
++
++ sess->canvas_num = 0;
++}
++
++static void vdec_reset_timestamps(struct amvdec_session *sess)
++{
++ struct amvdec_timestamp *tmp, *n;
++
++ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
++ list_del(&tmp->list);
++ kfree(tmp);
++ }
++}
++
++static void vdec_reset_bufs_recycle(struct amvdec_session *sess)
++{
++ struct amvdec_buffer *tmp, *n;
++
++ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) {
++ list_del(&tmp->list);
++ kfree(tmp);
++ }
++}
++
++static void vdec_stop_streaming(struct vb2_queue *q)
++{
++ struct amvdec_session *sess = vb2_get_drv_priv(q);
++ struct amvdec_core *core = sess->core;
++ struct vb2_v4l2_buffer *buf;
++
++ if (sess->streamon_out && sess->streamon_cap) {
++ if (vdec_codec_needs_recycle(sess))
++ kthread_stop(sess->recycle_thread);
++
++ vdec_poweroff(sess);
++ vdec_free_canvas(sess);
++ dma_free_coherent(sess->core->dev, sess->vififo_size,
++ sess->vififo_vaddr, sess->vififo_paddr);
++ vdec_reset_timestamps(sess);
++ vdec_reset_bufs_recycle(sess);
++ kfree(sess->priv);
++ sess->priv = NULL;
++ core->cur_sess = NULL;
++ }
++
++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx)))
++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
++
++ sess->streamon_out = 0;
++ } else {
++ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx)))
++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
++
++ sess->streamon_cap = 0;
++ }
++}
++
++static const struct vb2_ops vdec_vb2_ops = {
++ .queue_setup = vdec_queue_setup,
++ .start_streaming = vdec_start_streaming,
++ .stop_streaming = vdec_stop_streaming,
++ .buf_queue = vdec_vb2_buf_queue,
++ .wait_prepare = vb2_ops_wait_prepare,
++ .wait_finish = vb2_ops_wait_finish,
++};
++
++static int
++vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
++{
++ strscpy(cap->driver, "meson-vdec", sizeof(cap->driver));
++ strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card));
++ strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info));
++
++ return 0;
++}
++
++static const struct amvdec_format *
++find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt)
++{
++ unsigned int i;
++
++ for (i = 0; i < size; i++) {
++ if (fmts[i].pixfmt == pixfmt)
++ return &fmts[i];
++ }
++
++ return NULL;
++}
++
++static unsigned int
++vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap)
++{
++ int i;
++
++ for (i = 0; fmt_out->pixfmts_cap[i]; i++)
++ if (fmt_out->pixfmts_cap[i] == pixfmt_cap)
++ return 1;
++
++ return 0;
++}
++
++static const struct amvdec_format *
++vdec_try_fmt_common(struct amvdec_session *sess, u32 size,
++ struct v4l2_format *f)
++{
++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
++ struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
++ const struct amvdec_format *fmts = sess->core->platform->formats;
++ const struct amvdec_format *fmt_out;
++
++ memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
++ memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ fmt_out = find_format(fmts, size, pixmp->pixelformat);
++ if (!fmt_out) {
++ pixmp->pixelformat = V4L2_PIX_FMT_MPEG2;
++ fmt_out = find_format(fmts, size, pixmp->pixelformat);
++ }
++
++ pfmt[0].sizeimage =
++ get_output_size(pixmp->width, pixmp->height);
++ pfmt[0].bytesperline = 0;
++ pixmp->num_planes = 1;
++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
++ fmt_out = sess->fmt_out;
++ if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat))
++ pixmp->pixelformat = fmt_out->pixfmts_cap[0];
++
++ memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved));
++ if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) {
++ pfmt[0].sizeimage =
++ get_output_size(pixmp->width, pixmp->height);
++ pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
++
++ pfmt[1].sizeimage =
++ get_output_size(pixmp->width, pixmp->height) / 2;
++ pfmt[1].bytesperline = ALIGN(pixmp->width, 64);
++ pixmp->num_planes = 2;
++ } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) {
++ pfmt[0].sizeimage =
++ get_output_size(pixmp->width, pixmp->height);
++ pfmt[0].bytesperline = ALIGN(pixmp->width, 64);
++
++ pfmt[1].sizeimage =
++ get_output_size(pixmp->width, pixmp->height) / 4;
++ pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2;
++
++ pfmt[2].sizeimage =
++ get_output_size(pixmp->width, pixmp->height) / 4;
++ pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2;
++ pixmp->num_planes = 3;
++ }
++ } else {
++ return NULL;
++ }
++
++ pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width);
++ pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height);
++
++ if (pixmp->field == V4L2_FIELD_ANY)
++ pixmp->field = V4L2_FIELD_NONE;
++
++ return fmt_out;
++}
++
++static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++
++ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f);
++
++ return 0;
++}
++
++static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
++ pixmp->pixelformat = sess->pixfmt_cap;
++ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
++ pixmp->pixelformat = sess->fmt_out->pixfmt;
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
++ pixmp->width = sess->width;
++ pixmp->height = sess->height;
++ pixmp->colorspace = sess->colorspace;
++ pixmp->ycbcr_enc = sess->ycbcr_enc;
++ pixmp->quantization = sess->quantization;
++ pixmp->xfer_func = sess->xfer_func;
++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ pixmp->width = sess->width;
++ pixmp->height = sess->height;
++ }
++
++ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f);
++
++ return 0;
++}
++
++static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
++ u32 num_formats = sess->core->platform->num_formats;
++ const struct amvdec_format *fmt_out;
++ struct v4l2_pix_format_mplane orig_pixmp;
++ struct v4l2_format format;
++ u32 pixfmt_out = 0, pixfmt_cap = 0;
++
++ orig_pixmp = *pixmp;
++
++ fmt_out = vdec_try_fmt_common(sess, num_formats, f);
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ pixfmt_out = pixmp->pixelformat;
++ pixfmt_cap = sess->pixfmt_cap;
++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
++ pixfmt_cap = pixmp->pixelformat;
++ pixfmt_out = sess->fmt_out->pixfmt;
++ }
++
++ memset(&format, 0, sizeof(format));
++
++ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
++ format.fmt.pix_mp.pixelformat = pixfmt_out;
++ format.fmt.pix_mp.width = orig_pixmp.width;
++ format.fmt.pix_mp.height = orig_pixmp.height;
++ vdec_try_fmt_common(sess, num_formats, &format);
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ sess->width = format.fmt.pix_mp.width;
++ sess->height = format.fmt.pix_mp.height;
++ sess->colorspace = pixmp->colorspace;
++ sess->ycbcr_enc = pixmp->ycbcr_enc;
++ sess->quantization = pixmp->quantization;
++ sess->xfer_func = pixmp->xfer_func;
++ }
++
++ memset(&format, 0, sizeof(format));
++
++ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
++ format.fmt.pix_mp.pixelformat = pixfmt_cap;
++ format.fmt.pix_mp.width = orig_pixmp.width;
++ format.fmt.pix_mp.height = orig_pixmp.height;
++ vdec_try_fmt_common(sess, num_formats, &format);
++
++ sess->width = format.fmt.pix_mp.width;
++ sess->height = format.fmt.pix_mp.height;
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
++ sess->fmt_out = fmt_out;
++ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
++ sess->pixfmt_cap = format.fmt.pix_mp.pixelformat;
++
++ return 0;
++}
++
++static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++ const struct vdec_platform *platform = sess->core->platform;
++ const struct amvdec_format *fmt_out;
++
++ memset(f->reserved, 0, sizeof(f->reserved));
++
++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
++ if (f->index >= platform->num_formats)
++ return -EINVAL;
++
++ fmt_out = &platform->formats[f->index];
++ f->pixelformat = fmt_out->pixfmt;
++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
++ fmt_out = sess->fmt_out;
++ if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index])
++ return -EINVAL;
++
++ f->pixelformat = fmt_out->pixfmts_cap[f->index];
++ } else {
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int vdec_enum_framesizes(struct file *file, void *fh,
++ struct v4l2_frmsizeenum *fsize)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++ const struct amvdec_format *formats = sess->core->platform->formats;
++ const struct amvdec_format *fmt;
++ u32 num_formats = sess->core->platform->num_formats;
++
++ fmt = find_format(formats, num_formats, fsize->pixel_format);
++ if (!fmt || fsize->index)
++ return -EINVAL;
++
++ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
++
++ fsize->stepwise.min_width = 256;
++ fsize->stepwise.max_width = fmt->max_width;
++ fsize->stepwise.step_width = 1;
++ fsize->stepwise.min_height = 144;
++ fsize->stepwise.max_height = fmt->max_height;
++ fsize->stepwise.step_height = 1;
++
++ return 0;
++}
++
++static int
++vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
++{
++ switch (cmd->cmd) {
++ case V4L2_DEC_CMD_STOP:
++ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
++ return -EINVAL;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int
++vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++ struct device *dev = sess->core->dev;
++ int ret;
++
++ ret = vdec_try_decoder_cmd(file, fh, cmd);
++ if (ret)
++ return ret;
++
++ if (!(sess->streamon_out & sess->streamon_cap))
++ return 0;
++
++ dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n");
++ sess->should_stop = 1;
++
++ vdec_wait_inactive(sess);
++
++ if (codec_ops->drain) {
++ codec_ops->drain(sess);
++ } else if (codec_ops->eos_sequence) {
++ u32 len;
++ const u8 *data = codec_ops->eos_sequence(&len);
++
++ esparser_queue_eos(sess->core, data, len);
++ }
++
++ return ret;
++}
++
++static int vdec_subscribe_event(struct v4l2_fh *fh,
++ const struct v4l2_event_subscription *sub)
++{
++ switch (sub->type) {
++ case V4L2_EVENT_EOS:
++ return v4l2_event_subscribe(fh, sub, 2, NULL);
++ default:
++ return -EINVAL;
++ }
++}
++
++static int vdec_cropcap(struct file *file, void *fh,
++ struct v4l2_cropcap *crop)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++
++ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
++ return -EINVAL;
++
++ crop->pixelaspect = sess->pixelaspect;
++ return 0;
++}
++
++static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
++ .vidioc_querycap = vdec_querycap,
++ .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt,
++ .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt,
++ .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt,
++ .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt,
++ .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt,
++ .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt,
++ .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt,
++ .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt,
++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
++ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
++ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
++ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
++ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
++ .vidioc_enum_framesizes = vdec_enum_framesizes,
++ .vidioc_subscribe_event = vdec_subscribe_event,
++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
++ .vidioc_try_decoder_cmd = vdec_try_decoder_cmd,
++ .vidioc_decoder_cmd = vdec_decoder_cmd,
++ .vidioc_cropcap = vdec_cropcap,
++};
++
++static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
++ struct vb2_queue *dst_vq)
++{
++ struct amvdec_session *sess = priv;
++ int ret;
++
++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
++ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
++ src_vq->ops = &vdec_vb2_ops;
++ src_vq->mem_ops = &vb2_dma_contig_memops;
++ src_vq->drv_priv = sess;
++ src_vq->buf_struct_size = sizeof(struct dummy_buf);
++ src_vq->min_buffers_needed = 1;
++ src_vq->dev = sess->core->dev;
++ src_vq->lock = &sess->lock;
++ 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->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
++ dst_vq->ops = &vdec_vb2_ops;
++ dst_vq->mem_ops = &vb2_dma_contig_memops;
++ dst_vq->drv_priv = sess;
++ dst_vq->buf_struct_size = sizeof(struct dummy_buf);
++ dst_vq->min_buffers_needed = 1;
++ dst_vq->dev = sess->core->dev;
++ dst_vq->lock = &sess->lock;
++ ret = vb2_queue_init(dst_vq);
++ if (ret) {
++ vb2_queue_release(src_vq);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int vdec_open(struct file *file)
++{
++ struct amvdec_core *core = video_drvdata(file);
++ struct device *dev = core->dev;
++ const struct amvdec_format *formats = core->platform->formats;
++ struct amvdec_session *sess;
++ int ret;
++
++ sess = kzalloc(sizeof(*sess), GFP_KERNEL);
++ if (!sess)
++ return -ENOMEM;
++
++ sess->core = core;
++
++ sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
++ if (IS_ERR(sess->m2m_dev)) {
++ dev_err(dev, "Fail to v4l2_m2m_init\n");
++ ret = PTR_ERR(sess->m2m_dev);
++ goto err_free_sess;
++ }
++
++ sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init);
++ if (IS_ERR(sess->m2m_ctx)) {
++ dev_err(dev, "Fail to v4l2_m2m_ctx_init\n");
++ ret = PTR_ERR(sess->m2m_ctx);
++ goto err_m2m_release;
++ }
++
++ sess->pixfmt_cap = formats[0].pixfmts_cap[0];
++ sess->fmt_out = &formats[0];
++ sess->width = 1280;
++ sess->height = 720;
++ sess->pixelaspect.numerator = 1;
++ sess->pixelaspect.denominator = 1;
++
++ INIT_LIST_HEAD(&sess->timestamps);
++ INIT_LIST_HEAD(&sess->bufs_recycle);
++ INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src);
++ mutex_init(&sess->lock);
++ mutex_init(&sess->bufs_recycle_lock);
++ spin_lock_init(&sess->ts_spinlock);
++
++ v4l2_fh_init(&sess->fh, core->vdev_dec);
++ v4l2_fh_add(&sess->fh);
++ sess->fh.m2m_ctx = sess->m2m_ctx;
++ file->private_data = &sess->fh;
++
++ return 0;
++
++err_m2m_release:
++ v4l2_m2m_release(sess->m2m_dev);
++err_free_sess:
++ kfree(sess);
++ return ret;
++}
++
++static int vdec_close(struct file *file)
++{
++ struct amvdec_session *sess =
++ container_of(file->private_data, struct amvdec_session, fh);
++
++ v4l2_m2m_ctx_release(sess->m2m_ctx);
++ v4l2_m2m_release(sess->m2m_dev);
++ v4l2_fh_del(&sess->fh);
++ v4l2_fh_exit(&sess->fh);
++
++ mutex_destroy(&sess->lock);
++ mutex_destroy(&sess->bufs_recycle_lock);
++
++ kfree(sess);
++
++ return 0;
++}
++
++static const struct v4l2_file_operations vdec_fops = {
++ .owner = THIS_MODULE,
++ .open = vdec_open,
++ .release = vdec_close,
++ .unlocked_ioctl = video_ioctl2,
++ .poll = v4l2_m2m_fop_poll,
++ .mmap = v4l2_m2m_fop_mmap,
++};
++
++static irqreturn_t vdec_isr(int irq, void *data)
++{
++ struct amvdec_core *core = data;
++ struct amvdec_session *sess = core->cur_sess;
++
++ sess->last_irq_jiffies = get_jiffies_64();
++
++ return sess->fmt_out->codec_ops->isr(sess);
++}
++
++static irqreturn_t vdec_threaded_isr(int irq, void *data)
++{
++ struct amvdec_core *core = data;
++ struct amvdec_session *sess = core->cur_sess;
++
++ return sess->fmt_out->codec_ops->threaded_isr(sess);
++}
++
++static const struct of_device_id vdec_dt_match[] = {
++ { .compatible = "amlogic,gxbb-vdec",
++ .data = &vdec_platform_gxbb },
++ { .compatible = "amlogic,gxm-vdec",
++ .data = &vdec_platform_gxm },
++ { .compatible = "amlogic,gxl-vdec",
++ .data = &vdec_platform_gxl },
++ {}
++};
++MODULE_DEVICE_TABLE(of, vdec_dt_match);
++
++static int vdec_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct video_device *vdev;
++ struct amvdec_core *core;
++ struct resource *r;
++ const struct of_device_id *of_id;
++ int irq;
++ int ret;
++
++ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
++ if (!core)
++ return -ENOMEM;
++
++ core->dev = dev;
++ platform_set_drvdata(pdev, core);
++
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos");
++ core->dos_base = devm_ioremap_resource(dev, r);
++ if (IS_ERR(core->dos_base)) {
++ dev_err(dev, "Couldn't remap DOS memory\n");
++ return PTR_ERR(core->dos_base);
++ }
++
++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser");
++ core->esparser_base = devm_ioremap_resource(dev, r);
++ if (IS_ERR(core->esparser_base)) {
++ dev_err(dev, "Couldn't remap ESPARSER memory\n");
++ return PTR_ERR(core->esparser_base);
++ }
++
++ core->regmap_ao = syscon_regmap_lookup_by_phandle(dev->of_node,
++ "amlogic,ao-sysctrl");
++ if (IS_ERR(core->regmap_ao)) {
++ dev_err(dev, "Couldn't regmap AO sysctrl\n");
++ return PTR_ERR(core->regmap_ao);
++ }
++
++ core->canvas = meson_canvas_get(dev);
++ if (!core->canvas)
++ return PTR_ERR(core->canvas);
++
++ core->dos_parser_clk = devm_clk_get(dev, "dos_parser");
++ if (IS_ERR(core->dos_parser_clk))
++ return -EPROBE_DEFER;
++
++ core->dos_clk = devm_clk_get(dev, "dos");
++ if (IS_ERR(core->dos_clk))
++ return -EPROBE_DEFER;
++
++ core->vdec_1_clk = devm_clk_get(dev, "vdec_1");
++ if (IS_ERR(core->vdec_1_clk))
++ return -EPROBE_DEFER;
++
++ core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc");
++ if (IS_ERR(core->vdec_hevc_clk))
++ return -EPROBE_DEFER;
++
++ irq = platform_get_irq_byname(pdev, "vdec");
++ if (irq < 0)
++ return irq;
++
++ ret = devm_request_threaded_irq(core->dev, irq, vdec_isr,
++ vdec_threaded_isr, IRQF_ONESHOT,
++ "vdec", core);
++ if (ret)
++ return ret;
++
++ ret = esparser_init(pdev, core);
++ if (ret)
++ return ret;
++
++ ret = v4l2_device_register(dev, &core->v4l2_dev);
++ if (ret) {
++ dev_err(dev, "Couldn't register v4l2 device\n");
++ return -ENOMEM;
++ }
++
++ vdev = video_device_alloc();
++ if (!vdev) {
++ ret = -ENOMEM;
++ goto err_vdev_release;
++ }
++
++ of_id = of_match_node(vdec_dt_match, dev->of_node);
++ core->platform = of_id->data;
++ core->vdev_dec = vdev;
++ core->dev_dec = dev;
++ mutex_init(&core->lock);
++
++ strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name));
++ vdev->release = video_device_release;
++ vdev->fops = &vdec_fops;
++ vdev->ioctl_ops = &vdec_ioctl_ops;
++ vdev->vfl_dir = VFL_DIR_M2M;
++ vdev->v4l2_dev = &core->v4l2_dev;
++ vdev->lock = &core->lock;
++ vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
++
++ video_set_drvdata(vdev, core);
++
++ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
++ if (ret) {
++ dev_err(dev, "Failed registering video device\n");
++ goto err_vdev_release;
++ }
++
++ return 0;
++
++err_vdev_release:
++ video_device_release(vdev);
++ return ret;
++}
++
++static int vdec_remove(struct platform_device *pdev)
++{
++ struct amvdec_core *core = platform_get_drvdata(pdev);
++
++ video_unregister_device(core->vdev_dec);
++
++ return 0;
++}
++
++static struct platform_driver meson_vdec_driver = {
++ .probe = vdec_probe,
++ .remove = vdec_remove,
++ .driver = {
++ .name = "meson-vdec",
++ .of_match_table = vdec_dt_match,
++ },
++};
++module_platform_driver(meson_vdec_driver);
++
++MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM");
++MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h
+new file mode 100644
+index 0000000..4e8c3f1
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec.h
+@@ -0,0 +1,251 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_CORE_H_
++#define __MESON_VDEC_CORE_H_
++
++#include <linux/regmap.h>
++#include <linux/list.h>
++#include <media/videobuf2-v4l2.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-device.h>
++#include <linux/soc/amlogic/meson-canvas.h>
++
++#include "vdec_platform.h"
++
++/* 32 buffers in 3-plane YUV420 */
++#define MAX_CANVAS (32 * 3)
++
++struct amvdec_buffer {
++ struct list_head list;
++ struct vb2_buffer *vb;
++};
++
++/**
++ * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset
++ *
++ * @list: used to make lists out of this struct
++ * @ts: timestamp
++ * @offset: offset in the VIFIFO where the associated packet was written
++ */
++struct amvdec_timestamp {
++ struct list_head list;
++ u64 ts;
++ u32 offset;
++};
++
++struct amvdec_session;
++
++/**
++ * struct amvdec_core - device parameters, singleton
++ *
++ * @dos_base: DOS memory base address
++ * @esparser_base: PARSER memory base address
++ * @regmap_ao: regmap for the AO bus
++ * @dev: core device
++ * @dev_dec: decoder device
++ * @platform: platform-specific data
++ * @canvas: canvas provider reference
++ * @dos_parser_clk: DOS_PARSER clock
++ * @dos_clk: DOS clock
++ * @vdec_1_clk: VDEC_1 clock
++ * @vdec_hevc_clk: VDEC_HEVC clock
++ * @esparser_reset: RESET for the PARSER
++ * @vdec_dec: video device for the decoder
++ * @v4l2_dev: v4l2 device
++ * @cur_sess: current decoding session
++ * @lock: lock for this structure
++ */
++struct amvdec_core {
++ void __iomem *dos_base;
++ void __iomem *esparser_base;
++ struct regmap *regmap_ao;
++
++ struct device *dev;
++ struct device *dev_dec;
++ const struct vdec_platform *platform;
++
++ struct meson_canvas *canvas;
++
++ struct clk *dos_parser_clk;
++ struct clk *dos_clk;
++ struct clk *vdec_1_clk;
++ struct clk *vdec_hevc_clk;
++
++ struct reset_control *esparser_reset;
++
++ struct video_device *vdev_dec;
++ struct v4l2_device v4l2_dev;
++
++ struct amvdec_session *cur_sess;
++ struct mutex lock;
++};
++
++/**
++ * struct amvdec_ops - vdec operations
++ *
++ * @start: mandatory call when the vdec needs to initialize
++ * @stop: mandatory call when the vdec needs to stop
++ * @conf_esparser: mandatory call to let the vdec configure the ESPARSER
++ * @vififo_level: mandatory call to get the current amount of data
++ * in the VIFIFO
++ * @use_offsets: mandatory call. Returns 1 if the VDEC supports vififo offsets
++ */
++struct amvdec_ops {
++ int (*start)(struct amvdec_session *sess);
++ int (*stop)(struct amvdec_session *sess);
++ void (*conf_esparser)(struct amvdec_session *sess);
++ u32 (*vififo_level)(struct amvdec_session *sess);
++};
++
++/**
++ * struct amvdec_codec_ops - codec operations
++ *
++ * @start: mandatory call when the codec needs to initialize
++ * @stop: mandatory call when the codec needs to stop
++ * @load_extended_firmware: optional call to load additional firmware bits
++ * @num_pending_bufs: optional call to get the number of dst buffers on hold
++ * @can_recycle: optional call to know if the codec is ready to recycle
++ * a dst buffer
++ * @recycle: optional call to tell the codec to recycle a dst buffer. Must go
++ * in pair with @can_recycle
++ * @drain: optional call if the codec has a custom way of draining
++ * @eos_sequence: optional call to get an end sequence to send to esparser
++ * for flush. Mutually exclusive with @drain.
++ * @isr: mandatory call when the ISR triggers
++ * @threaded_isr: mandatory call for the threaded ISR
++ */
++struct amvdec_codec_ops {
++ int (*start)(struct amvdec_session *sess);
++ int (*stop)(struct amvdec_session *sess);
++ int (*load_extended_firmware)(struct amvdec_session *sess,
++ const u8 *data, u32 len);
++ u32 (*num_pending_bufs)(struct amvdec_session *sess);
++ int (*can_recycle)(struct amvdec_core *core);
++ void (*recycle)(struct amvdec_core *core, u32 buf_idx);
++ void (*drain)(struct amvdec_session *sess);
++ const u8 * (*eos_sequence)(u32 *len);
++ irqreturn_t (*isr)(struct amvdec_session *sess);
++ irqreturn_t (*threaded_isr)(struct amvdec_session *sess);
++};
++
++/**
++ * struct amvdec_format - describes one of the OUTPUT (src) format supported
++ *
++ * @pixfmt: V4L2 pixel format
++ * @min_buffers: minimum amount of CAPTURE (dst) buffers
++ * @max_buffers: maximum amount of CAPTURE (dst) buffers
++ * @max_width: maximum picture width supported
++ * @max_height: maximum picture height supported
++ * @vdec_ops: the VDEC operations that support this format
++ * @codec_ops: the codec operations that support this format
++ * @firmware_path: Path to the firmware that supports this format
++ * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt
++ */
++struct amvdec_format {
++ u32 pixfmt;
++ u32 min_buffers;
++ u32 max_buffers;
++ u32 max_width;
++ u32 max_height;
++
++ struct amvdec_ops *vdec_ops;
++ struct amvdec_codec_ops *codec_ops;
++
++ char *firmware_path;
++ u32 pixfmts_cap[4];
++};
++
++/**
++ * struct amvdec_session - decoding session parameters
++ *
++ * @core: reference to the vdec core struct
++ * @fh: v4l2 file handle
++ * @m2m_dev: v4l2 m2m device
++ * @m2m_ctx: v4l2 m2m context
++ * @lock: session lock
++ * @fmt_out: vdec pixel format for the OUTPUT queue
++ * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue
++ * @width: current picture width
++ * @height: current picture height
++ * @colorspace: current colorspace
++ * @ycbcr_enc: current ycbcr_enc
++ * @quantization: current quantization
++ * @xfer_func: current transfer function
++ * @pixelaspect: Pixel Aspect Ratio reported by the decoder
++ * @esparser_queued_bufs: number of buffers currently queued into ESPARSER
++ * @esparser_queue_work: work struct for the ESPARSER to process src buffers
++ * @streamon_cap: stream on flag for capture queue
++ * @streamon_out: stream on flag for output queue
++ * @sequence_cap: capture sequence counter
++ * @should_stop: flag set if userspace signaled EOS via command
++ * or empty buffer
++ * @keyframe_found: flag set once a keyframe has been parsed
++ * @canvas_alloc: array of all the canvas IDs allocated
++ * @canvas_num: number of canvas IDs allocated
++ * @vififo_vaddr: virtual address for the VIFIFO
++ * @vififo_paddr: physical address for the VIFIFO
++ * @vififo_size: size of the VIFIFO dma alloc
++ * @bufs_recycle: list of buffers that need to be recycled
++ * @bufs_recycle_lock: lock for the bufs_recycle list
++ * @recycle_thread: task struct for the recycling thread
++ * @timestamps: chronological list of src timestamps
++ * @ts_spinlock: spinlock for the timestamps list
++ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ
++ * @priv: codec private data
++ */
++struct amvdec_session {
++ struct amvdec_core *core;
++
++ struct v4l2_fh fh;
++ struct v4l2_m2m_dev *m2m_dev;
++ struct v4l2_m2m_ctx *m2m_ctx;
++ struct mutex lock;
++
++ const struct amvdec_format *fmt_out;
++ u32 pixfmt_cap;
++
++ u32 width;
++ u32 height;
++ u32 colorspace;
++ u8 ycbcr_enc;
++ u8 quantization;
++ u8 xfer_func;
++
++ struct v4l2_fract pixelaspect;
++
++ atomic_t esparser_queued_bufs;
++ struct work_struct esparser_queue_work;
++
++ unsigned int streamon_cap, streamon_out;
++ unsigned int sequence_cap;
++ unsigned int should_stop;
++ unsigned int keyframe_found;
++
++ u8 canvas_alloc[MAX_CANVAS];
++ u32 canvas_num;
++
++ void *vififo_vaddr;
++ dma_addr_t vififo_paddr;
++ u32 vififo_size;
++
++ struct list_head bufs_recycle;
++ struct mutex bufs_recycle_lock;
++ struct task_struct *recycle_thread;
++
++ struct list_head timestamps;
++ spinlock_t ts_spinlock;
++
++ u64 last_irq_jiffies;
++ u32 last_offset;
++ u32 wrap_count;
++
++ void *priv;
++};
++
++u32 amvdec_get_output_size(struct amvdec_session *sess);
++
++#endif
+diff --git a/drivers/media/platform/meson/vdec/vdec_1.c b/drivers/media/platform/meson/vdec/vdec_1.c
+new file mode 100644
+index 0000000..88b8bed
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_1.c
+@@ -0,0 +1,231 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ *
++ * VDEC_1 is a video decoding block that allows decoding of
++ * MPEG 1/2/4, H.263, H.264, MJPEG, VC1
++ */
++
++#include <linux/firmware.h>
++#include <linux/clk.h>
++
++#include "vdec_1.h"
++#include "vdec_helpers.h"
++#include "dos_regs.h"
++
++/* AO Registers */
++#define AO_RTI_GEN_PWR_SLEEP0 0xe8
++#define AO_RTI_GEN_PWR_ISO0 0xec
++ #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2))
++
++#define MC_SIZE (4096 * 4)
++
++static int
++vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname)
++{
++ const struct firmware *fw;
++ struct amvdec_core *core = sess->core;
++ struct device *dev = core->dev_dec;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++ static void *mc_addr;
++ static dma_addr_t mc_addr_map;
++ int ret;
++ u32 i = 1000;
++
++ ret = request_firmware(&fw, fwname, dev);
++ if (ret < 0)
++ return -EINVAL;
++
++ if (fw->size < MC_SIZE) {
++ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n",
++ fw->size, MC_SIZE);
++ ret = -EINVAL;
++ goto release_firmware;
++ }
++
++ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE,
++ &mc_addr_map, GFP_KERNEL);
++ if (!mc_addr) {
++ dev_err(dev,
++ "Failed allocating memory for firmware loading\n");
++ ret = -ENOMEM;
++ goto release_firmware;
++ }
++
++ memcpy(mc_addr, fw->data, MC_SIZE);
++
++ amvdec_write_dos(core, MPSR, 0);
++ amvdec_write_dos(core, CPSR, 0);
++
++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31));
++
++ amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map);
++ amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4);
++ amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16)));
++
++ while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000) { }
++
++ if (i == 0) {
++ dev_err(dev, "Firmware load fail (DMA hang?)\n");
++ ret = -EINVAL;
++ goto free_mc;
++ }
++
++ if (codec_ops->load_extended_firmware)
++ ret = codec_ops->load_extended_firmware(sess,
++ fw->data + MC_SIZE,
++ fw->size - MC_SIZE);
++
++free_mc:
++ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map);
++release_firmware:
++ release_firmware(fw);
++ return ret;
++}
++
++int vdec_1_stbuf_power_up(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0);
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0);
++ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4));
++
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr);
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr);
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR,
++ sess->vififo_paddr + sess->vififo_size - 8);
++
++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1);
++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1);
++
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL);
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr);
++
++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
++
++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL,
++ (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL |
++ MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN);
++
++ return 0;
++}
++
++static void vdec_1_conf_esparser(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++
++ /* VDEC_1 specific ESPARSER stuff */
++ amvdec_write_dos(core, DOS_GEN_CTRL0, 0);
++ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1);
++}
++
++static u32 vdec_1_vififo_level(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++
++ return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL);
++}
++
++static int vdec_1_stop(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++
++ amvdec_write_dos(core, MPSR, 0);
++ amvdec_write_dos(core, CPSR, 0);
++ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0);
++
++ amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11));
++ amvdec_write_dos(core, DOS_SW_RESET0, 0);
++ amvdec_read_dos(core, DOS_SW_RESET0);
++
++ /* enable vdec1 isolation */
++ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0);
++ /* power off vdec1 memories */
++ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff);
++ /* power off vdec1 */
++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
++ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1);
++
++ clk_disable_unprepare(core->vdec_1_clk);
++
++ if (sess->priv)
++ codec_ops->stop(sess);
++
++ return 0;
++}
++
++static int vdec_1_start(struct amvdec_session *sess)
++{
++ int ret;
++ struct amvdec_core *core = sess->core;
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
++
++ /* Configure the vdec clk to the maximum available */
++ clk_set_rate(core->vdec_1_clk, 666666666);
++ ret = clk_prepare_enable(core->vdec_1_clk);
++ if (ret)
++ return ret;
++
++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
++ GEN_PWR_VDEC_1, 0);
++ udelay(10);
++
++ /* Reset VDEC1 */
++ amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc);
++ amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000);
++
++ amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff);
++
++ /* enable VDEC Memories */
++ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0);
++ /* Remove VDEC1 Isolation */
++ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0);
++ /* Reset DOS top registers */
++ amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0);
++
++ amvdec_write_dos(core, GCLK_EN, 0x3ff);
++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31));
++
++ vdec_1_stbuf_power_up(sess);
++
++ ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path);
++ if (ret)
++ goto stop;
++
++ ret = codec_ops->start(sess);
++ if (ret)
++ goto stop;
++
++ /* Enable IRQ */
++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
++ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1);
++
++ /* Enable 2-plane output */
++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M)
++ amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17));
++ else
++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17));
++
++ /* Enable firmware processor */
++ amvdec_write_dos(core, MPSR, 1);
++ /* Let the firmware settle */
++ udelay(10);
++
++ return 0;
++
++stop:
++ vdec_1_stop(sess);
++ return ret;
++}
++
++struct amvdec_ops vdec_1_ops = {
++ .start = vdec_1_start,
++ .stop = vdec_1_stop,
++ .conf_esparser = vdec_1_conf_esparser,
++ .vififo_level = vdec_1_vififo_level,
++};
+diff --git a/drivers/media/platform/meson/vdec/vdec_1.h b/drivers/media/platform/meson/vdec/vdec_1.h
+new file mode 100644
+index 0000000..042d930
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_1.h
+@@ -0,0 +1,14 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_VDEC_1_H_
++#define __MESON_VDEC_VDEC_1_H_
++
++#include "vdec.h"
++
++extern struct amvdec_ops vdec_1_ops;
++
++#endif
+diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c
+new file mode 100644
+index 0000000..02090c5
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c
+@@ -0,0 +1,412 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#include <linux/gcd.h>
++#include <media/v4l2-mem2mem.h>
++#include <media/v4l2-event.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec_helpers.h"
++
++#define NUM_CANVAS_NV12 2
++#define NUM_CANVAS_YUV420 3
++
++u32 amvdec_read_dos(struct amvdec_core *core, u32 reg)
++{
++ return readl_relaxed(core->dos_base + reg);
++}
++EXPORT_SYMBOL_GPL(amvdec_read_dos);
++
++void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val)
++{
++ writel_relaxed(val, core->dos_base + reg);
++}
++EXPORT_SYMBOL_GPL(amvdec_write_dos);
++
++void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
++{
++ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val);
++}
++EXPORT_SYMBOL_GPL(amvdec_write_dos_bits);
++
++void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val)
++{
++ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val);
++}
++EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits);
++
++u32 amvdec_read_parser(struct amvdec_core *core, u32 reg)
++{
++ return readl_relaxed(core->esparser_base + reg);
++}
++EXPORT_SYMBOL_GPL(amvdec_read_parser);
++
++void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val)
++{
++ writel_relaxed(val, core->esparser_base + reg);
++}
++EXPORT_SYMBOL_GPL(amvdec_write_parser);
++
++static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id)
++{
++ int ret;
++
++ if (sess->canvas_num >= MAX_CANVAS) {
++ dev_err(sess->core->dev, "Reached max number of canvas\n");
++ return -ENOMEM;
++ }
++
++ ret = meson_canvas_alloc(sess->core->canvas, canvas_id);
++ if (ret)
++ return ret;
++
++ sess->canvas_alloc[sess->canvas_num++] = *canvas_id;
++ return 0;
++}
++
++static int set_canvas_yuv420m(struct amvdec_session *sess,
++ struct vb2_buffer *vb, u32 width,
++ u32 height, u32 reg)
++{
++ struct amvdec_core *core = sess->core;
++ u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */
++ dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */
++ int ret, i;
++
++ for (i = 0; i < NUM_CANVAS_YUV420; ++i) {
++ ret = canvas_alloc(sess, &canvas_id[i]);
++ if (ret)
++ return ret;
++
++ buf_paddr[i] =
++ vb2_dma_contig_plane_dma_addr(vb, i);
++ }
++
++ /* Y plane */
++ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
++ width, height, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++
++ /* U plane */
++ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
++ width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++
++ /* V plane */
++ meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2],
++ width / 2, height / 2, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++
++ amvdec_write_dos(core, reg,
++ ((canvas_id[2]) << 16) |
++ ((canvas_id[1]) << 8) |
++ (canvas_id[0]));
++
++ return 0;
++}
++
++static int set_canvas_nv12m(struct amvdec_session *sess,
++ struct vb2_buffer *vb, u32 width,
++ u32 height, u32 reg)
++{
++ struct amvdec_core *core = sess->core;
++ u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */
++ dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */
++ int ret, i;
++
++ for (i = 0; i < NUM_CANVAS_NV12; ++i) {
++ ret = canvas_alloc(sess, &canvas_id[i]);
++ if (ret)
++ return ret;
++
++ buf_paddr[i] =
++ vb2_dma_contig_plane_dma_addr(vb, i);
++ }
++
++ /* Y plane */
++ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0],
++ width, height, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++
++ /* U/V plane */
++ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1],
++ width, height / 2, MESON_CANVAS_WRAP_NONE,
++ MESON_CANVAS_BLKMODE_LINEAR,
++ MESON_CANVAS_ENDIAN_SWAP64);
++
++ amvdec_write_dos(core, reg,
++ ((canvas_id[1]) << 16) |
++ ((canvas_id[1]) << 8) |
++ (canvas_id[0]));
++
++ return 0;
++}
++
++int amvdec_set_canvases(struct amvdec_session *sess,
++ u32 reg_base[], u32 reg_num[])
++{
++ struct v4l2_m2m_buffer *buf;
++ u32 pixfmt = sess->pixfmt_cap;
++ u32 width = ALIGN(sess->width, 64);
++ u32 height = ALIGN(sess->height, 64);
++ u32 reg_cur = reg_base[0];
++ u32 reg_num_cur = 0;
++ u32 reg_base_cur = 0;
++ int ret;
++
++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
++ if (!reg_base[reg_base_cur])
++ return -EINVAL;
++
++ reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4;
++
++ switch (pixfmt) {
++ case V4L2_PIX_FMT_NV12M:
++ ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width,
++ height, reg_cur);
++ if (ret)
++ return ret;
++ break;
++ case V4L2_PIX_FMT_YUV420M:
++ ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width,
++ height, reg_cur);
++ if (ret)
++ return ret;
++ break;
++ default:
++ dev_err(sess->core->dev, "Unsupported pixfmt %08X\n",
++ pixfmt);
++ return -EINVAL;
++ };
++
++ reg_num_cur++;
++ if (reg_num_cur >= reg_num[reg_base_cur]) {
++ reg_base_cur++;
++ reg_num_cur = 0;
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(amvdec_set_canvases);
++
++void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset)
++{
++ struct amvdec_timestamp *new_ts, *tmp;
++ unsigned long flags;
++
++ new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL);
++ new_ts->ts = ts;
++ new_ts->offset = offset;
++
++ spin_lock_irqsave(&sess->ts_spinlock, flags);
++
++ if (list_empty(&sess->timestamps))
++ goto add_tail;
++
++ list_for_each_entry(tmp, &sess->timestamps, list) {
++ if (ts <= tmp->ts) {
++ list_add_tail(&new_ts->list, &tmp->list);
++ goto unlock;
++ }
++ }
++
++add_tail:
++ list_add_tail(&new_ts->list, &sess->timestamps);
++unlock:
++ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
++}
++EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder);
++
++void amvdec_remove_ts(struct amvdec_session *sess, u64 ts)
++{
++ struct amvdec_timestamp *tmp;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sess->ts_spinlock, flags);
++ list_for_each_entry(tmp, &sess->timestamps, list) {
++ if (tmp->ts == ts) {
++ list_del(&tmp->list);
++ kfree(tmp);
++ goto unlock;
++ }
++ }
++ dev_warn(sess->core->dev_dec,
++ "Couldn't remove buffer with timestamp %llu from list\n", ts);
++
++unlock:
++ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
++}
++EXPORT_SYMBOL_GPL(amvdec_remove_ts);
++
++static void dst_buf_done(struct amvdec_session *sess,
++ struct vb2_v4l2_buffer *vbuf,
++ u32 field,
++ u64 timestamp)
++{
++ struct device *dev = sess->core->dev_dec;
++ u32 output_size = amvdec_get_output_size(sess);
++
++ switch (sess->pixfmt_cap) {
++ case V4L2_PIX_FMT_NV12M:
++ vbuf->vb2_buf.planes[0].bytesused = output_size;
++ vbuf->vb2_buf.planes[1].bytesused = output_size / 2;
++ break;
++ case V4L2_PIX_FMT_YUV420M:
++ vbuf->vb2_buf.planes[0].bytesused = output_size;
++ vbuf->vb2_buf.planes[1].bytesused = output_size / 4;
++ vbuf->vb2_buf.planes[2].bytesused = output_size / 4;
++ break;
++ }
++
++ vbuf->vb2_buf.timestamp = timestamp;
++ vbuf->sequence = sess->sequence_cap++;
++
++ if (sess->should_stop &&
++ atomic_read(&sess->esparser_queued_bufs) <= 2) {
++ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
++
++ dev_dbg(dev, "Signaling EOS\n");
++ v4l2_event_queue_fh(&sess->fh, &ev);
++ vbuf->flags |= V4L2_BUF_FLAG_LAST;
++ } else if (sess->should_stop)
++ dev_dbg(dev, "should_stop, %u bufs remain\n",
++ atomic_read(&sess->esparser_queued_bufs));
++
++ dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index);
++ vbuf->field = field;
++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
++
++ /* Buffer done probably means the vififo got freed */
++ schedule_work(&sess->esparser_queue_work);
++}
++
++void amvdec_dst_buf_done(struct amvdec_session *sess,
++ struct vb2_v4l2_buffer *vbuf, u32 field)
++{
++ struct device *dev = sess->core->dev_dec;
++ struct amvdec_timestamp *tmp;
++ struct list_head *timestamps = &sess->timestamps;
++ u64 timestamp;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sess->ts_spinlock, flags);
++ if (list_empty(timestamps)) {
++ dev_err(dev, "Buffer %u done but list is empty\n",
++ vbuf->vb2_buf.index);
++
++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
++ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
++ return;
++ }
++
++ tmp = list_first_entry(timestamps, struct amvdec_timestamp, list);
++ timestamp = tmp->ts;
++ list_del(&tmp->list);
++ kfree(tmp);
++ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
++
++ dst_buf_done(sess, vbuf, field, timestamp);
++ atomic_dec(&sess->esparser_queued_bufs);
++}
++EXPORT_SYMBOL_GPL(amvdec_dst_buf_done);
++
++static void amvdec_dst_buf_done_offset(struct amvdec_session *sess,
++ struct vb2_v4l2_buffer *vbuf,
++ u32 offset,
++ u32 field)
++{
++ struct device *dev = sess->core->dev_dec;
++ struct amvdec_timestamp *match = NULL;
++ struct amvdec_timestamp *tmp, *n;
++ u64 timestamp = 0;
++ unsigned long flags;
++
++ spin_lock_irqsave(&sess->ts_spinlock, flags);
++
++ /* Look for our vififo offset to get the corresponding timestamp. */
++ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) {
++ s64 delta = (s64)offset - tmp->offset;
++
++ /* Offsets reported by codecs usually differ slightly,
++ * so we need some wiggle room.
++ * 4KiB being the minimum packet size, there is no risk here.
++ */
++ if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) {
++ match = tmp;
++ break;
++ }
++
++ /* Delete any timestamp entry that appears before our target
++ * (not all src packets/timestamps lead to a frame)
++ */
++ if (delta > 0 || delta < -1 * (s32)sess->vififo_size) {
++ atomic_dec(&sess->esparser_queued_bufs);
++ list_del(&tmp->list);
++ kfree(tmp);
++ }
++ }
++
++ if (!match) {
++ dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n",
++ vbuf->vb2_buf.index, offset);
++ } else {
++ timestamp = match->ts;
++ list_del(&match->list);
++ kfree(match);
++ }
++ spin_unlock_irqrestore(&sess->ts_spinlock, flags);
++
++ dst_buf_done(sess, vbuf, field, timestamp);
++ if (match)
++ atomic_dec(&sess->esparser_queued_bufs);
++}
++
++void amvdec_dst_buf_done_idx(struct amvdec_session *sess,
++ u32 buf_idx, u32 offset, u32 field)
++{
++ struct vb2_v4l2_buffer *vbuf;
++ struct device *dev = sess->core->dev_dec;
++
++ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx);
++ if (!vbuf) {
++ dev_err(dev,
++ "Buffer %u done but it doesn't exist in m2m_ctx\n",
++ buf_idx);
++ return;
++ }
++
++ if (offset != -1)
++ amvdec_dst_buf_done_offset(sess, vbuf, offset, field);
++ else
++ amvdec_dst_buf_done(sess, vbuf, field);
++}
++EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx);
++
++void amvdec_set_par_from_dar(struct amvdec_session *sess,
++ u32 dar_num, u32 dar_den)
++{
++ u32 div;
++
++ sess->pixelaspect.numerator = sess->height * dar_num;
++ sess->pixelaspect.denominator = sess->width * dar_den;
++ div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator);
++ sess->pixelaspect.numerator /= div;
++ sess->pixelaspect.denominator /= div;
++}
++EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
++
++void amvdec_abort(struct amvdec_session *sess)
++{
++ dev_info(sess->core->dev, "Aborting decoding session!\n");
++ vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q);
++ vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q);
++}
++EXPORT_SYMBOL_GPL(amvdec_abort);
+diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h
+new file mode 100644
+index 0000000..b9250a8
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_helpers.h
+@@ -0,0 +1,48 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_HELPERS_H_
++#define __MESON_VDEC_HELPERS_H_
++
++#include "vdec.h"
++
++/**
++ * amvdec_set_canvases() - Map VB2 buffers to canvases
++ *
++ * @sess: current session
++ * @reg_base: Registry bases of where to write the canvas indexes
++ * @reg_num: number of contiguous registers after each reg_base (including it)
++ */
++int amvdec_set_canvases(struct amvdec_session *sess,
++ u32 reg_base[], u32 reg_num[]);
++
++u32 amvdec_read_dos(struct amvdec_core *core, u32 reg);
++void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val);
++void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
++void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val);
++u32 amvdec_read_parser(struct amvdec_core *core, u32 reg);
++void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val);
++
++void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx,
++ u32 offset, u32 field);
++void amvdec_dst_buf_done(struct amvdec_session *sess,
++ struct vb2_v4l2_buffer *vbuf, u32 field);
++
++/**
++ * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order
++ *
++ * @sess: current session
++ * @ts: timestamp to add
++ * @offset: offset in the VIFIFO where the associated packet was written
++ */
++void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset);
++void amvdec_remove_ts(struct amvdec_session *sess, u64 ts);
++
++void amvdec_set_par_from_dar(struct amvdec_session *sess,
++ u32 dar_num, u32 dar_den);
++
++void amvdec_abort(struct amvdec_session *sess);
++#endif
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
+new file mode 100644
+index 0000000..46eeb74
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_platform.c
+@@ -0,0 +1,101 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#include "vdec_platform.h"
++#include "vdec.h"
++
++#include "vdec_1.h"
++#include "codec_mpeg12.h"
++
++static const struct amvdec_format vdec_formats_gxbb[] = {
++ {
++ .pixfmt = V4L2_PIX_FMT_MPEG1,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_MPEG2,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ },
++};
++
++static const struct amvdec_format vdec_formats_gxl[] = {
++ {
++ .pixfmt = V4L2_PIX_FMT_MPEG1,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_MPEG2,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ },
++};
++
++static const struct amvdec_format vdec_formats_gxm[] = {
++ {
++ .pixfmt = V4L2_PIX_FMT_MPEG1,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_MPEG2,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg12_ops,
++ .firmware_path = "meson/gx/vmpeg12_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ },
++};
++
++const struct vdec_platform vdec_platform_gxbb = {
++ .formats = vdec_formats_gxbb,
++ .num_formats = ARRAY_SIZE(vdec_formats_gxbb),
++ .revision = VDEC_REVISION_GXBB,
++};
++
++const struct vdec_platform vdec_platform_gxl = {
++ .formats = vdec_formats_gxl,
++ .num_formats = ARRAY_SIZE(vdec_formats_gxl),
++ .revision = VDEC_REVISION_GXL,
++};
++
++const struct vdec_platform vdec_platform_gxm = {
++ .formats = vdec_formats_gxm,
++ .num_formats = ARRAY_SIZE(vdec_formats_gxm),
++ .revision = VDEC_REVISION_GXM,
++};
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h
+new file mode 100644
+index 0000000..f602532
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_platform.h
+@@ -0,0 +1,30 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 BayLibre, SAS
++ * Author: Maxime Jourdan <mjourdan@baylibre.com>
++ */
++
++#ifndef __MESON_VDEC_PLATFORM_H_
++#define __MESON_VDEC_PLATFORM_H_
++
++#include "vdec.h"
++
++struct amvdec_format;
++
++enum vdec_revision {
++ VDEC_REVISION_GXBB,
++ VDEC_REVISION_GXL,
++ VDEC_REVISION_GXM,
++};
++
++struct vdec_platform {
++ const struct amvdec_format *formats;
++ const u32 num_formats;
++ enum vdec_revision revision;
++};
++
++extern const struct vdec_platform vdec_platform_gxbb;
++extern const struct vdec_platform vdec_platform_gxm;
++extern const struct vdec_platform vdec_platform_gxl;
++
++#endif
diff --git a/testing/linux-amlogic/0034-MAINTAINERS-Add-meson-video-decoder.patch b/testing/linux-amlogic/0034-MAINTAINERS-Add-meson-video-decoder.patch
new file mode 100644
index 0000000000..76a6a3826b
--- /dev/null
+++ b/testing/linux-amlogic/0034-MAINTAINERS-Add-meson-video-decoder.patch
@@ -0,0 +1,32 @@
+From a4089c61b05e61349ff10539fc20ee480d44b303 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Tue, 4 Sep 2018 10:07:08 +0200
+Subject: [PATCH] MAINTAINERS: Add meson video decoder
+
+Add an entry for the meson video decoder for amlogic SoCs.
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ MAINTAINERS | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 9e9b19e..ede389b 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -9520,6 +9520,14 @@ F: drivers/media/platform/meson/ao-cec.c
+ F: Documentation/devicetree/bindings/media/meson-ao-cec.txt
+ T: git git://linuxtv.org/media_tree.git
+
++MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS
++M: Maxime Jourdan <mjourdan@baylibre.com>
++L: linux-media@lists.freedesktop.org
++L: linux-amlogic@lists.infradead.org
++S: Supported
++F: drivers/media/platform/meson/vdec/
++T: git git://linuxtv.org/media_tree.git
++
+ MICROBLAZE ARCHITECTURE
+ M: Michal Simek <monstr@monstr.eu>
+ W: http://www.monstr.eu/fdt/
diff --git a/testing/linux-amlogic/0035-arm64-dts-meson-gx-add-vdec-entry.patch b/testing/linux-amlogic/0035-arm64-dts-meson-gx-add-vdec-entry.patch
new file mode 100644
index 0000000000..4b1f168f7e
--- /dev/null
+++ b/testing/linux-amlogic/0035-arm64-dts-meson-gx-add-vdec-entry.patch
@@ -0,0 +1,38 @@
+From 771e9830bdd1361594a874ded57fe497f443d7dd Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 29 Aug 2018 15:24:02 +0200
+Subject: [PATCH] arm64: dts: meson-gx: add vdec entry
+
+Add the video decoder dts entry
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+index 5012607..5d2820e 100644
+--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+@@ -445,6 +445,20 @@
+ };
+ };
+
++ vdec: video-decoder@c8820000 {
++ compatible = "amlogic,gx-vdec";
++ reg = <0x0 0xc8820000 0x0 0x10000>,
++ <0x0 0xc110a580 0x0 0xe4>;
++ reg-names = "dos", "esparser";
++
++ interrupts = <GIC_SPI 44 IRQ_TYPE_EDGE_RISING>,
++ <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>;
++ interrupt-names = "vdec", "esparser";
++
++ amlogic,ao-sysctrl = <&sysctrl_AO>;
++ amlogic,canvas = <&canvas>;
++ };
++
+ periphs: periphs@c8834000 {
+ compatible = "simple-bus";
+ reg = <0x0 0xc8834000 0x0 0x2000>;
diff --git a/testing/linux-amlogic/0001-ARM64-dts-meson-add-vdec-entries.patch b/testing/linux-amlogic/0036-arm64-dts-meson-add-vdec-entries.patch
index 861623ad33..0770272005 100644
--- a/testing/linux-amlogic/0001-ARM64-dts-meson-add-vdec-entries.patch
+++ b/testing/linux-amlogic/0036-arm64-dts-meson-add-vdec-entries.patch
@@ -1,47 +1,56 @@
-From f7fd519b2188e86d212234cf3f2c8606917afd0a Mon Sep 17 00:00:00 2001
-From: Maxime Jourdan <maxi.jourdan@wanadoo.fr>
-Date: Thu, 26 Jul 2018 23:30:30 +0200
-Subject: [PATCH] ARM64: dts: meson: add vdec entries
+From 75863ab0baf29e4b0212a34f9ab7ef2763a38824 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 29 Aug 2018 15:24:22 +0200
+Subject: [PATCH] arm64: dts: meson: add vdec entries
This enables the video decoder for gxbb, gxl and gxm chips
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
---
- arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 7 +++++++
- arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 7 +++++++
- arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++
- 3 files changed, 18 insertions(+)
+ arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 10 ++++++++++
+ arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 10 ++++++++++
+ arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++
+ 3 files changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
-index 2a4d506..c34ecca 100644
+index 2a4d506..96145e4 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
-@@ -814,3 +814,10 @@
+@@ -814,3 +814,13 @@
power-domains = <&pwrc_vpu>;
};
+&vdec {
-+ compatible = "amlogic,meson-gxbb-vdec";
-+ clocks = <&clkc CLKID_DOS_PARSER>, <&clkc CLKID_DOS>, <&clkc CLKID_VDEC_1>, <&clkc CLKID_VDEC_HEVC>;
++ compatible = "amlogic,gxbb-vdec";
++ clocks = <&clkc CLKID_DOS_PARSER>,
++ <&clkc CLKID_DOS>,
++ <&clkc CLKID_VDEC_1>,
++ <&clkc CLKID_VDEC_HEVC>;
+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc";
+ resets = <&reset RESET_PARSER>;
+ reset-names = "esparser";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
-index 9f4b618..7b95db8 100644
+index 9f4b618..6ca93ae 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
-@@ -814,3 +814,10 @@
+@@ -814,3 +814,13 @@
power-domains = <&pwrc_vpu>;
};
+&vdec {
-+ compatible = "amlogic,meson-gxl-vdec";
-+ clocks = <&clkc CLKID_DOS_PARSER>, <&clkc CLKID_DOS>, <&clkc CLKID_VDEC_1>, <&clkc CLKID_VDEC_HEVC>;
++ compatible = "amlogic,gxl-vdec";
++ clocks = <&clkc CLKID_DOS_PARSER>,
++ <&clkc CLKID_DOS>,
++ <&clkc CLKID_VDEC_1>,
++ <&clkc CLKID_VDEC_HEVC>;
+ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc";
+ resets = <&reset RESET_PARSER>;
+ reset-names = "esparser";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
-index 247888d..4ce7b12 100644
+index 247888d..2f35649 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
@@ -117,3 +117,7 @@
@@ -50,5 +59,5 @@ index 247888d..4ce7b12 100644
};
+
+&vdec {
-+ compatible = "amlogic,meson-gxm-vdec";
++ compatible = "amlogic,gxm-vdec";
+};
diff --git a/testing/linux-amlogic/0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch b/testing/linux-amlogic/0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch
new file mode 100644
index 0000000000..3c120117b1
--- /dev/null
+++ b/testing/linux-amlogic/0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch
@@ -0,0 +1,153 @@
+From e36802c6297adb0c560f3a6c1672546eb380c458 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 10 Oct 2018 17:22:27 +0200
+Subject: [PATCH] meson: vdec: introduce controls and
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE
+
+---
+ drivers/media/platform/meson/vdec/Makefile | 2 +-
+ drivers/media/platform/meson/vdec/vdec.c | 7 ++++
+ drivers/media/platform/meson/vdec/vdec.h | 2 ++
+ drivers/media/platform/meson/vdec/vdec_ctrls.c | 45 ++++++++++++++++++++++++++
+ drivers/media/platform/meson/vdec/vdec_ctrls.h | 8 +++++
+ 5 files changed, 63 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.c
+ create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.h
+
+diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
+index 6bea129..eba8608 100644
+--- a/drivers/media/platform/meson/vdec/Makefile
++++ b/drivers/media/platform/meson/vdec/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ # Makefile for Amlogic meson video decoder driver
+
+-meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o
++meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o
+ meson-vdec-objs += vdec_1.o
+ meson-vdec-objs += codec_mpeg12.o
+
+diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c
+index d8db52c..1c5d3e9 100644
+--- a/drivers/media/platform/meson/vdec/vdec.c
++++ b/drivers/media/platform/meson/vdec/vdec.c
+@@ -21,6 +21,7 @@
+ #include "vdec.h"
+ #include "esparser.h"
+ #include "vdec_helpers.h"
++#include "vdec_ctrls.h"
+
+ struct dummy_buf {
+ struct vb2_v4l2_buffer vb;
+@@ -290,6 +291,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+ sess->keyframe_found = 0;
+ sess->last_offset = 0;
+ sess->wrap_count = 0;
++ sess->dpb_size = 0;
+ sess->pixelaspect.numerator = 1;
+ sess->pixelaspect.denominator = 1;
+ atomic_set(&sess->esparser_queued_bufs, 0);
+@@ -812,6 +814,10 @@ static int vdec_open(struct file *file)
+ goto err_m2m_release;
+ }
+
++ ret = amvdec_init_ctrls(&sess->ctrl_handler);
++ if (ret)
++ goto err_m2m_release;
++
+ sess->pixfmt_cap = formats[0].pixfmts_cap[0];
+ sess->fmt_out = &formats[0];
+ sess->width = 1280;
+@@ -827,6 +833,7 @@ static int vdec_open(struct file *file)
+ spin_lock_init(&sess->ts_spinlock);
+
+ v4l2_fh_init(&sess->fh, core->vdev_dec);
++ sess->fh.ctrl_handler = &sess->ctrl_handler;
+ v4l2_fh_add(&sess->fh);
+ sess->fh.m2m_ctx = sess->m2m_ctx;
+ file->private_data = &sess->fh;
+diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h
+index 4e8c3f1..6be7de2 100644
+--- a/drivers/media/platform/meson/vdec/vdec.h
++++ b/drivers/media/platform/meson/vdec/vdec.h
+@@ -203,6 +203,7 @@ struct amvdec_session {
+ struct v4l2_fh fh;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
++ struct v4l2_ctrl_handler ctrl_handler;
+ struct mutex lock;
+
+ const struct amvdec_format *fmt_out;
+@@ -242,6 +243,7 @@ struct amvdec_session {
+ u64 last_irq_jiffies;
+ u32 last_offset;
+ u32 wrap_count;
++ u32 dpb_size;
+
+ void *priv;
+ };
+diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.c b/drivers/media/platform/meson/vdec/vdec_ctrls.c
+new file mode 100644
+index 0000000..cd6dd6d
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_ctrls.c
+@@ -0,0 +1,45 @@
++#include "vdec_ctrls.h"
++
++static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
++{
++ struct amvdec_session *sess =
++ container_of(ctrl->handler, struct amvdec_session, ctrl_handler);
++
++ switch (ctrl->id) {
++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
++ ctrl->val = sess->dpb_size;
++ break;
++ default:
++ return -EINVAL;
++ };
++
++ return 0;
++}
++
++static const struct v4l2_ctrl_ops vdec_ctrl_ops = {
++ .g_volatile_ctrl = vdec_op_g_volatile_ctrl,
++};
++
++int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler)
++{
++ int ret;
++ struct v4l2_ctrl *ctrl;
++
++ ret = v4l2_ctrl_handler_init(ctrl_handler, 1);
++ if (ret)
++ return ret;
++
++ ctrl = v4l2_ctrl_new_std(ctrl_handler, &vdec_ctrl_ops,
++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1);
++ if (ctrl)
++ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
++
++ ret = ctrl_handler->error;
++ if (ret) {
++ v4l2_ctrl_handler_free(ctrl_handler);
++ return ret;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(amvdec_init_ctrls);
+diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.h b/drivers/media/platform/meson/vdec/vdec_ctrls.h
+new file mode 100644
+index 0000000..4bcc5e6
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/vdec_ctrls.h
+@@ -0,0 +1,8 @@
++#ifndef __MESON_VDEC_CTRLS_H_
++#define __MESON_VDEC_CTRLS_H_
++
++#include "vdec.h"
++
++int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler);
++
++#endif
diff --git a/testing/linux-amlogic/0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch b/testing/linux-amlogic/0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch
new file mode 100644
index 0000000000..7229bb2ec6
--- /dev/null
+++ b/testing/linux-amlogic/0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch
@@ -0,0 +1,49 @@
+From 80f9e75b2fce22552fdf56ade990f3f98567e29e Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Thu, 4 Oct 2018 15:37:39 +0200
+Subject: [PATCH] media: videodev2: add V4L2_FMT_FLAG_NO_SOURCE_CHANGE
+
+When a v4l2 driver exposes V4L2_EVENT_SOURCE_CHANGE, some (usually
+OUTPUT) formats may not be able to trigger this event.
+
+Add a enum_fmt format flag to tag those specific formats.
+
+Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
+
+---
+ Documentation/media/uapi/v4l/vidioc-enum-fmt.rst | 5 +++++
+ include/uapi/linux/videodev2.h | 5 +++--
+ 2 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst
+index 019c513..e0040b3 100644
+--- a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst
++++ b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst
+@@ -116,6 +116,11 @@ one until ``EINVAL`` is returned.
+ - This format is not native to the device but emulated through
+ software (usually libv4l2), where possible try to use a native
+ format instead for better performance.
++ * - ``V4L2_FMT_FLAG_NO_SOURCE_CHANGE``
++ - 0x0004
++ - The event ``V4L2_EVENT_SOURCE_CHANGE`` is not supported
++ for this format.
++
+
+
+ Return Value
+diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
+index 1aae2e4..f44bdef 100644
+--- a/include/uapi/linux/videodev2.h
++++ b/include/uapi/linux/videodev2.h
+@@ -733,8 +733,9 @@ struct v4l2_fmtdesc {
+ __u32 reserved[4];
+ };
+
+-#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+-#define V4L2_FMT_FLAG_EMULATED 0x0002
++#define V4L2_FMT_FLAG_COMPRESSED 0x0001
++#define V4L2_FMT_FLAG_EMULATED 0x0002
++#define V4L2_FMT_FLAG_NO_SOURCE_CHANGE 0x0004
+
+ /* Frame Size and frame rate enumeration */
+ /*
diff --git a/testing/linux-amlogic/0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch b/testing/linux-amlogic/0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch
new file mode 100644
index 0000000000..4a29d88391
--- /dev/null
+++ b/testing/linux-amlogic/0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch
@@ -0,0 +1,270 @@
+From 4ba289cf4940b6b8ddf1e332fc7248a27f54cfc8 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 10 Oct 2018 15:44:56 +0200
+Subject: [PATCH] meson: vdec: allow subscribing to V4L2_EVENT_SOURCE_CHANGE
+
+Flag MPEG1/MPEG2 as NO_SOURCE_CHANGE.
+
+---
+ drivers/media/platform/meson/vdec/vdec.c | 20 ++++++++++++++--
+ drivers/media/platform/meson/vdec/vdec.h | 13 +++++++++++
+ drivers/media/platform/meson/vdec/vdec_helpers.c | 28 +++++++++++++++++++++++
+ drivers/media/platform/meson/vdec/vdec_helpers.h | 1 +
+ drivers/media/platform/meson/vdec/vdec_platform.c | 6 +++++
+ 5 files changed, 66 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c
+index 1c5d3e9..ca64045 100644
+--- a/drivers/media/platform/meson/vdec/vdec.c
++++ b/drivers/media/platform/meson/vdec/vdec.c
+@@ -230,7 +230,8 @@ static int vdec_queue_setup(struct vb2_queue *q,
+ * are free to choose any of them to write frames to. As such,
+ * we need all of them to be queued into the driver
+ */
+- q->min_buffers_needed = q->num_buffers + *num_buffers;
++ sess->num_dst_bufs = q->num_buffers + *num_buffers;
++ q->min_buffers_needed = sess->num_dst_bufs;
+ break;
+ default:
+ return -EINVAL;
+@@ -260,6 +261,7 @@ static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
+ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+ {
+ struct amvdec_session *sess = vb2_get_drv_priv(q);
++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
+ struct amvdec_core *core = sess->core;
+ struct vb2_v4l2_buffer *buf;
+ int ret;
+@@ -277,6 +279,13 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+ if (!sess->streamon_out || !sess->streamon_cap)
+ return 0;
+
++ if (sess->status == STATUS_NEEDS_RESUME &&
++ q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
++ codec_ops->resume(sess);
++ sess->status = STATUS_RUNNING;
++ return 0;
++ }
++
+ sess->vififo_size = SIZE_VIFIFO;
+ sess->vififo_vaddr =
+ dma_alloc_coherent(sess->core->dev, sess->vififo_size,
+@@ -305,6 +314,7 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+ sess->recycle_thread = kthread_run(vdec_recycle_thread, sess,
+ "vdec_recycle");
+
++ sess->status = STATUS_RUNNING;
+ core->cur_sess = sess;
+
+ return 0;
+@@ -362,7 +372,9 @@ static void vdec_stop_streaming(struct vb2_queue *q)
+ struct amvdec_core *core = sess->core;
+ struct vb2_v4l2_buffer *buf;
+
+- if (sess->streamon_out && sess->streamon_cap) {
++ if (sess->status == STATUS_RUNNING ||
++ (sess->status == STATUS_NEEDS_RESUME &&
++ (!sess->streamon_out || !sess->streamon_cap))) {
+ if (vdec_codec_needs_recycle(sess))
+ kthread_stop(sess->recycle_thread);
+
+@@ -375,6 +387,7 @@ static void vdec_stop_streaming(struct vb2_queue *q)
+ kfree(sess->priv);
+ sess->priv = NULL;
+ core->cur_sess = NULL;
++ sess->status = STATUS_STOPPED;
+ }
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+@@ -611,6 +624,7 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+
+ fmt_out = &platform->formats[f->index];
+ f->pixelformat = fmt_out->pixfmt;
++ f->flags = fmt_out->flags;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt_out = sess->fmt_out;
+ if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index])
+@@ -703,6 +717,8 @@ static int vdec_subscribe_event(struct v4l2_fh *fh,
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 2, NULL);
++ case V4L2_EVENT_SOURCE_CHANGE:
++ return v4l2_src_change_event_subscribe(fh, sub);
+ default:
+ return -EINVAL;
+ }
+diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h
+index 6be7de2..8f8ce62 100644
+--- a/drivers/media/platform/meson/vdec/vdec.h
++++ b/drivers/media/platform/meson/vdec/vdec.h
+@@ -101,6 +101,7 @@ struct amvdec_ops {
+ u32 (*vififo_level)(struct amvdec_session *sess);
+ };
+
++
+ /**
+ * struct amvdec_codec_ops - codec operations
+ *
+@@ -127,6 +128,7 @@ struct amvdec_codec_ops {
+ int (*can_recycle)(struct amvdec_core *core);
+ void (*recycle)(struct amvdec_core *core, u32 buf_idx);
+ void (*drain)(struct amvdec_session *sess);
++ void (*resume)(struct amvdec_session *sess);
+ const u8 * (*eos_sequence)(u32 *len);
+ irqreturn_t (*isr)(struct amvdec_session *sess);
+ irqreturn_t (*threaded_isr)(struct amvdec_session *sess);
+@@ -140,6 +142,7 @@ struct amvdec_codec_ops {
+ * @max_buffers: maximum amount of CAPTURE (dst) buffers
+ * @max_width: maximum picture width supported
+ * @max_height: maximum picture height supported
++ * @flags: enum flags associated with this pixfmt
+ * @vdec_ops: the VDEC operations that support this format
+ * @codec_ops: the codec operations that support this format
+ * @firmware_path: Path to the firmware that supports this format
+@@ -151,6 +154,7 @@ struct amvdec_format {
+ u32 max_buffers;
+ u32 max_width;
+ u32 max_height;
++ u32 flags;
+
+ struct amvdec_ops *vdec_ops;
+ struct amvdec_codec_ops *codec_ops;
+@@ -159,6 +163,12 @@ struct amvdec_format {
+ u32 pixfmts_cap[4];
+ };
+
++enum amvdec_status {
++ STATUS_STOPPED,
++ STATUS_RUNNING,
++ STATUS_NEEDS_RESUME,
++};
++
+ /**
+ * struct amvdec_session - decoding session parameters
+ *
+@@ -195,6 +205,7 @@ struct amvdec_format {
+ * @timestamps: chronological list of src timestamps
+ * @ts_spinlock: spinlock for the timestamps list
+ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ
++ * @status: current decoding status
+ * @priv: codec private data
+ */
+ struct amvdec_session {
+@@ -225,6 +236,7 @@ struct amvdec_session {
+ unsigned int sequence_cap;
+ unsigned int should_stop;
+ unsigned int keyframe_found;
++ unsigned int num_dst_bufs;
+
+ u8 canvas_alloc[MAX_CANVAS];
+ u32 canvas_num;
+@@ -245,6 +257,7 @@ struct amvdec_session {
+ u32 wrap_count;
+ u32 dpb_size;
+
++ enum amvdec_status status;
+ void *priv;
+ };
+
+diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c
+index 02090c5..b982b28 100644
+--- a/drivers/media/platform/meson/vdec/vdec_helpers.c
++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c
+@@ -403,6 +403,34 @@ void amvdec_set_par_from_dar(struct amvdec_session *sess,
+ }
+ EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar);
+
++void amvdec_src_change(struct amvdec_session *sess, u32 width, u32 height, u32 dpb_size)
++{
++ static const struct v4l2_event ev = {
++ .type = V4L2_EVENT_SOURCE_CHANGE,
++ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
++
++ sess->dpb_size = dpb_size;
++
++ /* Check if the capture queue is already configured well for our
++ * usecase. If so, keep decoding with it and do not send the event
++ */
++ if (sess->width == width &&
++ sess->height == height &&
++ dpb_size <= sess->num_dst_bufs) {
++ sess->fmt_out->codec_ops->resume(sess);
++ return;
++ }
++
++ sess->width = width;
++ sess->height = height;
++ sess->status = STATUS_NEEDS_RESUME;
++
++ dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n",
++ width, height, dpb_size);
++ v4l2_event_queue_fh(&sess->fh, &ev);
++}
++EXPORT_SYMBOL_GPL(amvdec_src_change);
++
+ void amvdec_abort(struct amvdec_session *sess)
+ {
+ dev_info(sess->core->dev, "Aborting decoding session!\n");
+diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h
+index b9250a8..060799b 100644
+--- a/drivers/media/platform/meson/vdec/vdec_helpers.h
++++ b/drivers/media/platform/meson/vdec/vdec_helpers.h
+@@ -44,5 +44,6 @@ void amvdec_remove_ts(struct amvdec_session *sess, u64 ts);
+ void amvdec_set_par_from_dar(struct amvdec_session *sess,
+ u32 dar_num, u32 dar_den);
+
++void amvdec_src_change(struct amvdec_session *sess, u32 width, u32 height, u32 dpb_size);
+ void amvdec_abort(struct amvdec_session *sess);
+ #endif
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
+index 46eeb74..291f1ee 100644
+--- a/drivers/media/platform/meson/vdec/vdec_platform.c
++++ b/drivers/media/platform/meson/vdec/vdec_platform.c
+@@ -17,6 +17,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
+@@ -27,6 +28,7 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
+@@ -41,6 +43,7 @@ static const struct amvdec_format vdec_formats_gxl[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
+@@ -51,6 +54,7 @@ static const struct amvdec_format vdec_formats_gxl[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
+@@ -65,6 +69,7 @@ static const struct amvdec_format vdec_formats_gxm[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
+@@ -75,6 +80,7 @@ static const struct amvdec_format vdec_formats_gxm[] = {
+ .max_buffers = 8,
+ .max_width = 1920,
+ .max_height = 1080,
++ .flags = V4L2_FMT_FLAG_NO_SOURCE_CHANGE,
+ .vdec_ops = &vdec_1_ops,
+ .codec_ops = &codec_mpeg12_ops,
+ .firmware_path = "meson/gx/vmpeg12_mc",
diff --git a/testing/linux-amlogic/0040-media-meson-vdec-add-H.264-decoding-support.patch b/testing/linux-amlogic/0040-media-meson-vdec-add-H.264-decoding-support.patch
new file mode 100644
index 0000000000..aa66ec743e
--- /dev/null
+++ b/testing/linux-amlogic/0040-media-meson-vdec-add-H.264-decoding-support.patch
@@ -0,0 +1,591 @@
+From a41f52edc3681c11517c4d7ceb374f3189ea3310 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 29 Aug 2018 15:42:56 +0200
+Subject: [PATCH] media: meson: vdec: add H.264 decoding support
+
+Add support for V4L2_PIX_FMT_H264
+
+---
+ drivers/media/platform/meson/vdec/Makefile | 2 +-
+ drivers/media/platform/meson/vdec/codec_h264.c | 478 ++++++++++++++++++++++
+ drivers/media/platform/meson/vdec/codec_h264.h | 13 +
+ drivers/media/platform/meson/vdec/vdec_platform.c | 31 ++
+ 4 files changed, 523 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/media/platform/meson/vdec/codec_h264.c
+ create mode 100644 drivers/media/platform/meson/vdec/codec_h264.h
+
+diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
+index eba8608..01dc960 100644
+--- a/drivers/media/platform/meson/vdec/Makefile
++++ b/drivers/media/platform/meson/vdec/Makefile
+@@ -3,6 +3,6 @@
+
+ meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o
+ meson-vdec-objs += vdec_1.o
+-meson-vdec-objs += codec_mpeg12.o
++meson-vdec-objs += codec_mpeg12.o codec_h264.o
+
+ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
+diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c
+new file mode 100644
+index 0000000..6ac0115
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_h264.c
+@@ -0,0 +1,478 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#include <media/v4l2-mem2mem.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec_helpers.h"
++#include "dos_regs.h"
++
++#define SIZE_EXT_FW (20 * SZ_1K)
++#define SIZE_WORKSPACE 0x1ee000
++#define SIZE_SEI (8 * SZ_1K)
++
++/* Offset added by the firmware which must be substracted
++ * from the workspace phyaddr
++ */
++#define WORKSPACE_BUF_OFFSET 0x1000000
++
++/* ISR status */
++#define CMD_MASK GENMASK(7, 0)
++#define CMD_SRC_CHANGE 1
++#define CMD_FRAMES_READY 2
++#define CMD_FATAL_ERROR 6
++#define CMD_BAD_WIDTH 7
++#define CMD_BAD_HEIGHT 8
++
++#define SEI_DATA_READY BIT(15)
++
++/* Picture type */
++#define PIC_TOP_BOT 5
++#define PIC_BOT_TOP 6
++
++/* Size of Motion Vector per macroblock */
++#define MB_MV_SIZE 96
++
++/* Frame status data */
++#define PIC_STRUCT_BIT 5
++#define PIC_STRUCT_MASK GENMASK(2, 0)
++#define BUF_IDX_MASK GENMASK(4, 0)
++#define ERROR_FLAG BIT(9)
++#define OFFSET_BIT 16
++#define OFFSET_MASK GENMASK(15, 0)
++
++/* Bitstream parsed data */
++#define MB_TOTAL_BIT 8
++#define MB_TOTAL_MASK GENMASK(15, 0)
++#define MB_WIDTH_MASK GENMASK(7, 0)
++#define MAX_REF_BIT 24
++#define MAX_REF_MASK GENMASK(6, 0)
++#define AR_IDC_BIT 16
++#define AR_IDC_MASK GENMASK(7, 0)
++#define AR_PRESENT_FLAG BIT(0)
++#define AR_EXTEND 0xff
++
++/* Buffer to send to the ESPARSER to signal End Of Stream for H.264.
++ * This is a 16x16 encoded picture that will trigger drain firmware-side.
++ * There is no known alternative.
++ */
++static const u8 eos_sequence[SZ_1K] = {
++ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd,
++ 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef,
++ 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20,
++ 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37,
++ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34,
++ 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20,
++ 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79,
++ 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30,
++ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
++ 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e,
++ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74,
++ 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
++ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65,
++ 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d,
++ 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73,
++ 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20,
++ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65,
++ 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e,
++ 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f,
++ 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e,
++ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61,
++ 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
++ 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30,
++ 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a,
++ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68,
++ 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73,
++ 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64,
++ 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63,
++ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66,
++ 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d,
++ 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
++ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d,
++ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d,
++ 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69,
++ 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74,
++ 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f,
++ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69,
++ 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35,
++ 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69,
++ 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30,
++ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80,
++ 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20,
++ 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4,
++ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01,
++ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6,
++ 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4,
++ 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7,
++ 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09,
++ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66,
++ 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b
++};
++
++static const u8 *codec_h264_eos_sequence(u32 *len)
++{
++ *len = ARRAY_SIZE(eos_sequence);
++ return eos_sequence;
++}
++
++struct codec_h264 {
++ /* H.264 decoder requires an extended firmware */
++ void *ext_fw_vaddr;
++ dma_addr_t ext_fw_paddr;
++
++ /* Buffer for the H.264 Workspace */
++ void *workspace_vaddr;
++ dma_addr_t workspace_paddr;
++
++ /* Buffer for the H.264 references MV */
++ void *ref_vaddr;
++ dma_addr_t ref_paddr;
++ u32 ref_size;
++
++ /* Buffer for parsed SEI data */
++ void *sei_vaddr;
++ dma_addr_t sei_paddr;
++
++ u32 mb_width;
++ u32 mb_height;
++ u32 max_refs;
++};
++
++static int codec_h264_can_recycle(struct amvdec_core *core)
++{
++ return !amvdec_read_dos(core, AV_SCRATCH_7) ||
++ !amvdec_read_dos(core, AV_SCRATCH_8);
++}
++
++static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx)
++{
++ /* Tell the decoder he can recycle this buffer.
++ * AV_SCRATCH_8 serves the same purpose.
++ */
++ if (!amvdec_read_dos(core, AV_SCRATCH_7))
++ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1);
++ else
++ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1);
++}
++
++static int codec_h264_start(struct amvdec_session *sess) {
++ u32 workspace_offset;
++ struct amvdec_core *core = sess->core;
++ struct codec_h264 *h264 = sess->priv;
++
++ /* Allocate some memory for the H.264 decoder's state */
++ h264->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
++ &h264->workspace_paddr, GFP_KERNEL);
++ if (!h264->workspace_vaddr) {
++ dev_err(core->dev, "Failed to alloc H.264 Workspace\n");
++ return -ENOMEM;
++ }
++
++ /* Allocate some memory for the H.264 SEI dump */
++ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI,
++ &h264->sei_paddr, GFP_KERNEL);
++ if (!h264->sei_vaddr) {
++ dev_err(core->dev, "Failed to alloc H.264 SEI\n");
++ return -ENOMEM;
++ }
++
++ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6));
++
++ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET;
++ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset);
++ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr);
++ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - workspace_offset);
++
++ /* Enable "error correction" */
++ amvdec_write_dos(core, AV_SCRATCH_F,
++ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) |
++ BIT(4) | BIT(7));
++
++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
++
++ return 0;
++}
++
++static int codec_h264_stop(struct amvdec_session *sess)
++{
++ struct codec_h264 *h264 = sess->priv;
++ struct amvdec_core *core = sess->core;
++
++ if (h264->ext_fw_vaddr)
++ dma_free_coherent(core->dev, SIZE_EXT_FW,
++ h264->ext_fw_vaddr, h264->ext_fw_paddr);
++
++ if (h264->workspace_vaddr)
++ dma_free_coherent(core->dev, SIZE_WORKSPACE,
++ h264->workspace_vaddr, h264->workspace_paddr);
++
++ if (h264->ref_vaddr)
++ dma_free_coherent(core->dev, h264->ref_size,
++ h264->ref_vaddr, h264->ref_paddr);
++
++ if (h264->sei_vaddr)
++ dma_free_coherent(core->dev, SIZE_SEI,
++ h264->sei_vaddr, h264->sei_paddr);
++
++ return 0;
++}
++
++static int codec_h264_load_extended_firmware(struct amvdec_session *sess,
++ const u8 *data, u32 len)
++{
++ struct codec_h264 *h264;
++ struct amvdec_core *core = sess->core;
++
++ if (len < SIZE_EXT_FW)
++ return -EINVAL;
++
++ h264 = kzalloc(sizeof(*h264), GFP_KERNEL);
++ if (!h264)
++ return -ENOMEM;
++
++ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW,
++ &h264->ext_fw_paddr, GFP_KERNEL);
++ if (!h264->ext_fw_vaddr) {
++ dev_err(core->dev, "Failed to alloc H.264 extended fw\n");
++ kfree(h264);
++ return -ENOMEM;
++ }
++
++ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW);
++ sess->priv = h264;
++
++ return 0;
++}
++
++static const struct v4l2_fract par_table[] = {
++ { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 },
++ { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 },
++ { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 },
++ { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 },
++ { 2, 1 }
++};
++
++static void codec_h264_set_par(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2);
++ u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK;
++
++ if (!(seq_info & AR_PRESENT_FLAG))
++ return;
++
++ if (ar_idc == AR_EXTEND) {
++ u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3);
++ sess->pixelaspect.numerator = ar_info & 0xffff;
++ sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff;
++ return;
++ }
++
++ if (ar_idc >= ARRAY_SIZE(par_table))
++ return;
++
++ sess->pixelaspect = par_table[ar_idc];
++}
++
++static void codec_h264_resume(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ struct codec_h264 *h264 = sess->priv;
++ u32 mb_width, mb_height, mb_total;
++
++ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 },
++ (u32[]){ 24, 0 });
++
++ dev_dbg(core->dev,
++ "max_refs = %u; actual_dpb_size = %u\n",
++ h264->max_refs, sess->num_dst_bufs);
++
++ /* Align to a multiple of 4 macroblocks */
++ mb_width = ALIGN(h264->mb_width, 4);
++ mb_height = ALIGN(h264->mb_height, 4);
++ mb_total = mb_width * mb_height;
++
++ h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs;
++ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size,
++ &h264->ref_paddr, GFP_KERNEL);
++ if (!h264->ref_vaddr) {
++ dev_err(core->dev, "Failed to alloc refs (%u)\n",
++ h264->ref_size);
++ amvdec_abort(sess);
++ return;
++ }
++
++ /* Address to store the references' MVs */
++ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr);
++ /* End of ref MV */
++ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size);
++
++ amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) |
++ (sess->num_dst_bufs << 16) |
++ ((h264->max_refs - 1) << 8));
++}
++
++/* Configure the H.264 decoder when the parser detected a parameter set change
++ */
++static void codec_h264_src_change(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ struct codec_h264 *h264 = sess->priv;
++ u32 parsed_info, mb_total;
++ u32 crop_infor, crop_bottom, crop_right;
++ u32 frame_width, frame_height;
++
++ sess->keyframe_found = 1;
++
++ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1);
++
++ /* Total number of 16x16 macroblocks */
++ mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK;
++ /* Number of macroblocks per line */
++ h264->mb_width = parsed_info & MB_WIDTH_MASK;
++ /* Number of macroblock lines */
++ h264->mb_height = mb_total / h264->mb_width;
++
++ h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1;
++
++ crop_infor = amvdec_read_dos(core, AV_SCRATCH_6);
++ crop_bottom = (crop_infor & 0xff);
++ crop_right = (crop_infor >> 16) & 0xff;
++
++ frame_width = h264->mb_width * 16 - crop_right;
++ frame_height = h264->mb_height * 16 - crop_bottom;
++
++ dev_info(core->dev, "frame: %ux%u; crop: %u %u\n",
++ frame_width, frame_height, crop_right, crop_bottom);
++
++ codec_h264_set_par(sess);
++ amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5);
++}
++
++/**
++ * The offset is split in half in 2 different registers
++ */
++static u32 get_offset_msb(struct amvdec_core *core, int frame_num)
++{
++ int take_msb = frame_num % 2;
++ int reg_offset = (frame_num / 2) * 4;
++ u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset);
++
++ if (take_msb)
++ return offset_msb & 0xffff0000;
++
++ return (offset_msb & 0x0000ffff) << 16;
++}
++
++static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status)
++{
++ struct amvdec_core *core = sess->core;
++ int error_count;
++ int num_frames;
++ int i;
++
++ error_count = amvdec_read_dos(core, AV_SCRATCH_D);
++ num_frames = (status >> 8) & 0xff;
++ if (error_count) {
++ dev_warn(core->dev,
++ "decoder error(s) happened, count %d\n", error_count);
++ amvdec_write_dos(core, AV_SCRATCH_D, 0);
++ }
++
++ for (i = 0; i < num_frames; i++) {
++ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4);
++ u32 buffer_index = frame_status & BUF_IDX_MASK;
++ u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) &
++ PIC_STRUCT_MASK;
++ u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK;
++ u32 field = V4L2_FIELD_NONE;
++
++ /* A buffer decode error means it was decoded,
++ * but part of the picture will have artifacts.
++ * Typical reason is a temporarily corrupted bitstream
++ */
++ if (frame_status & ERROR_FLAG)
++ dev_dbg(core->dev, "Buffer %d decode error\n",
++ buffer_index);
++
++ if (pic_struct == PIC_TOP_BOT)
++ field = V4L2_FIELD_INTERLACED_TB;
++ else if (pic_struct == PIC_BOT_TOP)
++ field = V4L2_FIELD_INTERLACED_BT;
++
++ offset |= get_offset_msb(core, i);
++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
++ }
++}
++
++static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 status;
++ u32 size;
++ u8 cmd;
++
++ status = amvdec_read_dos(core, AV_SCRATCH_0);
++ cmd = status & CMD_MASK;
++
++ switch (cmd) {
++ case CMD_SRC_CHANGE:
++ codec_h264_src_change(sess);
++ break;
++ case CMD_FRAMES_READY:
++ codec_h264_frames_ready(sess, status);
++ break;
++ case CMD_FATAL_ERROR:
++ dev_err(core->dev, "H.264 decoder fatal error\n");
++ goto abort;
++ case CMD_BAD_WIDTH:
++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
++ dev_err(core->dev, "Unsupported video width: %u\n", size);
++ goto abort;
++ case CMD_BAD_HEIGHT:
++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16;
++ dev_err(core->dev, "Unsupported video height: %u\n", size);
++ goto abort;
++ case 0: /* Unused but not worth printing for */
++ case 9:
++ break;
++ default:
++ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd);
++ break;
++ }
++
++ if (cmd && cmd != CMD_SRC_CHANGE)
++ amvdec_write_dos(core, AV_SCRATCH_0, 0);
++
++ /* Decoder has some SEI data for us ; ignore */
++ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY)
++ amvdec_write_dos(core, AV_SCRATCH_J, 0);
++
++ return IRQ_HANDLED;
++abort:
++ amvdec_abort(sess);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t codec_h264_isr(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++
++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
++
++ return IRQ_WAKE_THREAD;
++}
++
++struct amvdec_codec_ops codec_h264_ops = {
++ .start = codec_h264_start,
++ .stop = codec_h264_stop,
++ .load_extended_firmware = codec_h264_load_extended_firmware,
++ .isr = codec_h264_isr,
++ .threaded_isr = codec_h264_threaded_isr,
++ .can_recycle = codec_h264_can_recycle,
++ .recycle = codec_h264_recycle,
++ .eos_sequence = codec_h264_eos_sequence,
++ .resume = codec_h264_resume,
++};
+diff --git a/drivers/media/platform/meson/vdec/codec_h264.h b/drivers/media/platform/meson/vdec/codec_h264.h
+new file mode 100644
+index 0000000..7a15976
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_h264.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#ifndef __MESON_VDEC_CODEC_H264_H_
++#define __MESON_VDEC_CODEC_H264_H_
++
++#include "vdec.h"
++
++extern struct amvdec_codec_ops codec_h264_ops;
++
++#endif
+\ No newline at end of file
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
+index 291f1ee..baecf59 100644
+--- a/drivers/media/platform/meson/vdec/vdec_platform.c
++++ b/drivers/media/platform/meson/vdec/vdec_platform.c
+@@ -9,9 +9,20 @@
+
+ #include "vdec_1.h"
+ #include "codec_mpeg12.h"
++#include "codec_h264.h"
+
+ static const struct amvdec_format vdec_formats_gxbb[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_H264,
++ .min_buffers = 2,
++ .max_buffers = 24,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_h264_ops,
++ .firmware_path = "meson/gxbb/vh264_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
+@@ -38,6 +49,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
+
+ static const struct amvdec_format vdec_formats_gxl[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_H264,
++ .min_buffers = 2,
++ .max_buffers = 24,
++ .max_width = 3840,
++ .max_height = 2160,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_h264_ops,
++ .firmware_path = "meson/gxl/vh264_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
+@@ -64,6 +85,16 @@ static const struct amvdec_format vdec_formats_gxl[] = {
+
+ static const struct amvdec_format vdec_formats_gxm[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_H264,
++ .min_buffers = 2,
++ .max_buffers = 24,
++ .max_width = 3840,
++ .max_height = 2160,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_h264_ops,
++ .firmware_path = "meson/gxm/vh264_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG1,
+ .min_buffers = 8,
+ .max_buffers = 8,
diff --git a/testing/linux-amlogic/0041-media-meson-vdec-add-MPEG4-decoding-support.patch b/testing/linux-amlogic/0041-media-meson-vdec-add-MPEG4-decoding-support.patch
new file mode 100644
index 0000000000..01fd5ae030
--- /dev/null
+++ b/testing/linux-amlogic/0041-media-meson-vdec-add-MPEG4-decoding-support.patch
@@ -0,0 +1,313 @@
+From e222a1cf4bd62745407a9404565d76b8a5770f12 Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Wed, 29 Aug 2018 16:01:55 +0200
+Subject: [PATCH] media: meson: vdec: add MPEG4 decoding support
+
+Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and
+V4L2_PIX_FMT_H.263
+
+---
+ drivers/media/platform/meson/vdec/Makefile | 2 +-
+ drivers/media/platform/meson/vdec/codec_mpeg4.c | 139 ++++++++++++++++++++++
+ drivers/media/platform/meson/vdec/codec_mpeg4.h | 13 ++
+ drivers/media/platform/meson/vdec/vdec_platform.c | 91 ++++++++++++++
+ 4 files changed, 244 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.c
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.h
+
+diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
+index 01dc960..bb7a134 100644
+--- a/drivers/media/platform/meson/vdec/Makefile
++++ b/drivers/media/platform/meson/vdec/Makefile
+@@ -3,6 +3,6 @@
+
+ meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o
+ meson-vdec-objs += vdec_1.o
+-meson-vdec-objs += codec_mpeg12.o codec_h264.o
++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o
+
+ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
+diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c
+new file mode 100644
+index 0000000..1d574e5
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c
+@@ -0,0 +1,139 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#include <media/v4l2-mem2mem.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec_helpers.h"
++#include "dos_regs.h"
++
++#define SIZE_WORKSPACE SZ_1M
++/* Offset added by firmware, to substract from workspace paddr */
++#define DCAC_BUFF_START_IP 0x02b00000
++
++/* map firmware registers to known MPEG4 functions */
++#define MREG_BUFFERIN AV_SCRATCH_8
++#define MREG_BUFFEROUT AV_SCRATCH_9
++#define MP4_NOT_CODED_CNT AV_SCRATCH_A
++#define MP4_OFFSET_REG AV_SCRATCH_C
++#define MEM_OFFSET_REG AV_SCRATCH_F
++#define MREG_FATAL_ERROR AV_SCRATCH_L
++
++#define BUF_IDX_MASK GENMASK(2, 0)
++#define INTERLACE_FLAG BIT(7)
++#define TOP_FIELD_FIRST_FLAG BIT(6)
++
++struct codec_mpeg4 {
++ /* Buffer for the MPEG4 Workspace */
++ void *workspace_vaddr;
++ dma_addr_t workspace_paddr;
++};
++
++static int codec_mpeg4_can_recycle(struct amvdec_core *core)
++{
++ return !amvdec_read_dos(core, MREG_BUFFERIN);
++}
++
++static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx)
++{
++ amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx));
++}
++
++static int codec_mpeg4_start(struct amvdec_session *sess) {
++ struct amvdec_core *core = sess->core;
++ struct codec_mpeg4 *mpeg4 = sess->priv;
++ int ret;
++
++ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL);
++ if (!mpeg4)
++ return -ENOMEM;
++
++ /* Allocate some memory for the MPEG4 decoder's state */
++ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
++ &mpeg4->workspace_paddr,
++ GFP_KERNEL);
++ if (!mpeg4->workspace_vaddr) {
++ dev_err(core->dev, "Failed to request MPEG4 Workspace\n");
++ ret = -ENOMEM;
++ goto free_mpeg4;
++ }
++
++ /* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */
++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 },
++ (u32[]){ 4, 4, 0 });
++
++ amvdec_write_dos(core, MEM_OFFSET_REG,
++ mpeg4->workspace_paddr - DCAC_BUFF_START_IP);
++ amvdec_write_dos(core, PSCALE_CTRL, 0);
++ amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0);
++ amvdec_write_dos(core, MREG_BUFFERIN, 0);
++ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
++ amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa);
++
++ sess->keyframe_found = 1;
++ sess->priv = mpeg4;
++
++ return 0;
++
++free_mpeg4:
++ kfree(mpeg4);
++ return ret;
++}
++
++static int codec_mpeg4_stop(struct amvdec_session *sess)
++{
++ struct codec_mpeg4 *mpeg4 = sess->priv;
++ struct amvdec_core *core = sess->core;
++
++ if (mpeg4->workspace_vaddr) {
++ dma_free_coherent(core->dev, SIZE_WORKSPACE,
++ mpeg4->workspace_vaddr,
++ mpeg4->workspace_paddr);
++ mpeg4->workspace_vaddr = 0;
++ }
++
++ return 0;
++}
++
++static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 reg;
++ u32 buffer_index;
++ u32 field = V4L2_FIELD_NONE;
++
++ reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
++ if (reg == 1) {
++ dev_err(core->dev, "mpeg4 fatal error\n");
++ amvdec_abort(sess);
++ return IRQ_HANDLED;
++ }
++
++ reg = amvdec_read_dos(core, MREG_BUFFEROUT);
++ if (!reg)
++ goto end;
++
++ buffer_index = reg & BUF_IDX_MASK;
++ if (reg & INTERLACE_FLAG)
++ field = (reg & TOP_FIELD_FIRST_FLAG) ?
++ V4L2_FIELD_INTERLACED_TB :
++ V4L2_FIELD_INTERLACED_BT;
++
++ amvdec_dst_buf_done_idx(sess, buffer_index, -1, field);
++ amvdec_write_dos(core, MREG_BUFFEROUT, 0);
++
++end:
++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
++ return IRQ_HANDLED;
++}
++
++struct amvdec_codec_ops codec_mpeg4_ops = {
++ .start = codec_mpeg4_start,
++ .stop = codec_mpeg4_stop,
++ .isr = codec_mpeg4_isr,
++ .can_recycle = codec_mpeg4_can_recycle,
++ .recycle = codec_mpeg4_recycle,
++};
+diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.h b/drivers/media/platform/meson/vdec/codec_mpeg4.h
+new file mode 100644
+index 0000000..b91b26413
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mpeg4.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#ifndef __MESON_VDEC_CODEC_MPEG4_H_
++#define __MESON_VDEC_CODEC_MPEG4_H_
++
++#include "vdec.h"
++
++extern struct amvdec_codec_ops codec_mpeg4_ops;
++
++#endif
+\ No newline at end of file
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
+index baecf59..80b43fd 100644
+--- a/drivers/media/platform/meson/vdec/vdec_platform.c
++++ b/drivers/media/platform/meson/vdec/vdec_platform.c
+@@ -10,9 +10,40 @@
+ #include "vdec_1.h"
+ #include "codec_mpeg12.h"
+ #include "codec_h264.h"
++#include "codec_mpeg4.h"
+
+ static const struct amvdec_format vdec_formats_gxbb[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MPEG4,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_H263,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/h263_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_XVID,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_H264,
+ .min_buffers = 2,
+ .max_buffers = 24,
+@@ -49,6 +80,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
+
+ static const struct amvdec_format vdec_formats_gxl[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MPEG4,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_H263,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/h263_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_XVID,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_H264,
+ .min_buffers = 2,
+ .max_buffers = 24,
+@@ -85,6 +146,36 @@ static const struct amvdec_format vdec_formats_gxl[] = {
+
+ static const struct amvdec_format vdec_formats_gxm[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MPEG4,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_H263,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/h263_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
++ .pixfmt = V4L2_PIX_FMT_XVID,
++ .min_buffers = 8,
++ .max_buffers = 8,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mpeg4_ops,
++ .firmware_path = "meson/gx/vmpeg4_mc_5",
++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_H264,
+ .min_buffers = 2,
+ .max_buffers = 24,
diff --git a/testing/linux-amlogic/0042-media-meson-vdec-add-MJPEG-decoding-support.patch b/testing/linux-amlogic/0042-media-meson-vdec-add-MJPEG-decoding-support.patch
new file mode 100644
index 0000000000..b72f817fe6
--- /dev/null
+++ b/testing/linux-amlogic/0042-media-meson-vdec-add-MJPEG-decoding-support.patch
@@ -0,0 +1,253 @@
+From 9a662159440cf5e0f55275ef63588e35c91c581e Mon Sep 17 00:00:00 2001
+From: Maxime Jourdan <mjourdan@baylibre.com>
+Date: Sun, 21 Oct 2018 15:14:27 +0200
+Subject: [PATCH] media: meson: vdec: add MJPEG decoding support
+
+Add support for V4L2_PIX_FMT_MJPEG
+
+---
+ drivers/media/platform/meson/vdec/Makefile | 2 +-
+ drivers/media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++++++
+ drivers/media/platform/meson/vdec/codec_mjpeg.h | 13 ++
+ drivers/media/platform/meson/vdec/vdec_platform.c | 31 +++++
+ 4 files changed, 185 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c
+ create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h
+
+diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile
+index bb7a134..acf07f3 100644
+--- a/drivers/media/platform/meson/vdec/Makefile
++++ b/drivers/media/platform/meson/vdec/Makefile
+@@ -3,6 +3,6 @@
+
+ meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o
+ meson-vdec-objs += vdec_1.o
+-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o
++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o
+
+ obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o
+diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c
+new file mode 100644
+index 0000000..abea9e3
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c
+@@ -0,0 +1,140 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#include <media/v4l2-mem2mem.h>
++#include <media/videobuf2-dma-contig.h>
++
++#include "vdec_helpers.h"
++#include "dos_regs.h"
++
++/* map FW registers to known MJPEG functions */
++#define MREG_DECODE_PARAM AV_SCRATCH_2
++#define MREG_TO_AMRISC AV_SCRATCH_8
++#define MREG_FROM_AMRISC AV_SCRATCH_9
++#define MREG_FRAME_OFFSET AV_SCRATCH_A
++
++static int codec_mjpeg_can_recycle(struct amvdec_core *core)
++{
++ return !amvdec_read_dos(core, MREG_TO_AMRISC);
++}
++
++static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx)
++{
++ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1);
++}
++
++/* 4 point triangle */
++static const uint32_t filt_coef[] = {
++ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
++ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
++ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
++ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
++ 0x18382808, 0x18382808, 0x17372909, 0x17372909,
++ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
++ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
++ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
++ 0x10303010
++};
++
++static void codec_mjpeg_init_scaler(struct amvdec_core *core)
++{
++ int i;
++
++ /* PSCALE cbus bmem enable */
++ amvdec_write_dos(core, PSCALE_CTRL, 0xc000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0);
++ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) {
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]);
++ }
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
++
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85);
++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000);
++
++ amvdec_write_dos(core, PSCALE_RST, 0x7);
++ amvdec_write_dos(core, PSCALE_RST, 0);
++}
++
++static int codec_mjpeg_start(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++
++ amvdec_write_dos(core, AV_SCRATCH_0, 12);
++ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a);
++
++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 },
++ (u32[]){ 4, 0 });
++ codec_mjpeg_init_scaler(core);
++
++ amvdec_write_dos(core, MREG_TO_AMRISC, 0);
++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
++ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff);
++ amvdec_write_dos(core, MREG_DECODE_PARAM,
++ (sess->height << 4) | 0x8000);
++ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8);
++
++ /* Intra-only codec */
++ sess->keyframe_found = 1;
++
++ return 0;
++}
++
++static int codec_mjpeg_stop(struct amvdec_session *sess)
++{
++ return 0;
++}
++
++static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess)
++{
++ struct amvdec_core *core = sess->core;
++ u32 reg;
++ u32 buffer_index;
++ u32 offset;
++
++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
++
++ reg = amvdec_read_dos(core, MREG_FROM_AMRISC);
++ if (!(reg & 0x7))
++ return IRQ_HANDLED;
++
++ buffer_index = ((reg & 0x7) - 1) & 3;
++ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET);
++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, V4L2_FIELD_NONE);
++
++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0);
++ return IRQ_HANDLED;
++}
++
++struct amvdec_codec_ops codec_mjpeg_ops = {
++ .start = codec_mjpeg_start,
++ .stop = codec_mjpeg_stop,
++ .isr = codec_mjpeg_isr,
++ .can_recycle = codec_mjpeg_can_recycle,
++ .recycle = codec_mjpeg_recycle,
++};
+diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h
+new file mode 100644
+index 0000000..cc1cf73
+--- /dev/null
++++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h
+@@ -0,0 +1,13 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr>
++ */
++
++#ifndef __MESON_VDEC_CODEC_MJPEG_H_
++#define __MESON_VDEC_CODEC_MJPEG_H_
++
++#include "vdec.h"
++
++extern struct amvdec_codec_ops codec_mjpeg_ops;
++
++#endif
+\ No newline at end of file
+diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c
+index 80b43fd..61def15 100644
+--- a/drivers/media/platform/meson/vdec/vdec_platform.c
++++ b/drivers/media/platform/meson/vdec/vdec_platform.c
+@@ -11,9 +11,20 @@
+ #include "codec_mpeg12.h"
+ #include "codec_h264.h"
+ #include "codec_mpeg4.h"
++#include "codec_mjpeg.h"
+
+ static const struct amvdec_format vdec_formats_gxbb[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MJPEG,
++ .min_buffers = 4,
++ .max_buffers = 4,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mjpeg_ops,
++ .firmware_path = "meson/gx/vmjpeg_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
+ .min_buffers = 8,
+ .max_buffers = 8,
+@@ -80,6 +91,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = {
+
+ static const struct amvdec_format vdec_formats_gxl[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MJPEG,
++ .min_buffers = 4,
++ .max_buffers = 4,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mjpeg_ops,
++ .firmware_path = "meson/gx/vmjpeg_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
+ .min_buffers = 8,
+ .max_buffers = 8,
+@@ -146,6 +167,16 @@ static const struct amvdec_format vdec_formats_gxl[] = {
+
+ static const struct amvdec_format vdec_formats_gxm[] = {
+ {
++ .pixfmt = V4L2_PIX_FMT_MJPEG,
++ .min_buffers = 4,
++ .max_buffers = 4,
++ .max_width = 1920,
++ .max_height = 1080,
++ .vdec_ops = &vdec_1_ops,
++ .codec_ops = &codec_mjpeg_ops,
++ .firmware_path = "meson/gx/vmjpeg_mc",
++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 },
++ }, {
+ .pixfmt = V4L2_PIX_FMT_MPEG4,
+ .min_buffers = 8,
+ .max_buffers = 8,
diff --git a/testing/linux-amlogic/0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch b/testing/linux-amlogic/0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch
new file mode 100644
index 0000000000..33671060cc
--- /dev/null
+++ b/testing/linux-amlogic/0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch
@@ -0,0 +1,42 @@
+From 6b98d7c6cd508cfb4a2d4a1e87e192ffcabeda9e Mon Sep 17 00:00:00 2001
+From: Christian Hewitt <christianshewitt@gmail.com>
+Date: Sat, 13 Oct 2018 14:04:46 +0400
+Subject: [PATCH] clk: meson-gxbb: set fclk_div3 as CLK_IS_CRITICAL
+
+On the Khadas VIM2 (GXM) and LePotato (GXL) board there are problems
+with reboot; e.g. a ~60 second delay between issuing reboot and the
+board power cycling (and in some OS configurations reboot will fail
+and require manual power cycling).
+
+Similar to 'commit c987ac6f1f088663b6dad39281071aeb31d450a8 ("clk:
+meson-gxbb: set fclk_div2 as CLK_IS_CRITICAL")' the SCPI Cortex-M4
+Co-Processor seems to depend on FCLK_DIV3 being operational.
+
+Bisect gives 'commit 05f814402d6174369b3b29832cbb5eb5ed287059 ("clk:
+meson: add fdiv clock gates") between 4.16 and 4.16-rc1 as the first
+bad commit. This added support for the missing clock gates before the
+fixed PLL fixed dividers (FCLK_DIVx) and the clock framework which
+disabled all the unused fixed dividers, thus it disabled a critical
+clock path for the SCPI Co-Processor.
+
+This change simply sets the FCLK_DIV3 gate as critical to ensure
+nothing can disable it.
+
+Signed-off-by: Christian Hewitt <christianshewitt@gmail.com>
+
+---
+ drivers/clk/meson/gxbb.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
+index 6628ffa..01f7615 100644
+--- a/drivers/clk/meson/gxbb.c
++++ b/drivers/clk/meson/gxbb.c
+@@ -513,6 +513,7 @@ static struct clk_fixed_factor gxbb_fclk_div3_div = {
+ .ops = &clk_fixed_factor_ops,
+ .parent_names = (const char *[]){ "fixed_pll" },
+ .num_parents = 1,
++ .flags = CLK_IS_CRITICAL,
+ },
+ };
+
diff --git a/testing/linux-amlogic/APKBUILD b/testing/linux-amlogic/APKBUILD
index 2c7bbc3ff7..ec8ccb65f9 100644
--- a/testing/linux-amlogic/APKBUILD
+++ b/testing/linux-amlogic/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: He Yangxuan <yangxuan8282@gmail.com>
pkgname=linux-amlogic
-pkgver=4.18.14
+pkgver=4.19.8
case $pkgver in
*.*.*) _kernver=${pkgver%.*};;
*.*) _kernver=${pkgver};;
@@ -9,7 +9,7 @@ esac
pkgrel=0
pkgdesc="Linux kernel for Amlogic"
url=https://github.com/torvalds/linux
-_commit=e7d199e92956587695510d147c8de795f944cec9
+_commit=178574b66509c9ff7df4ad26c84a8884567e93b4
depends="mkinitfs"
_depends_dev="perl gmp-dev elfutils-dev bash"
makedepends="$_depends_dev sed installkernel bc linux-headers linux-firmware openssl-dev bison flex"
@@ -17,40 +17,63 @@ options="!strip !check"
source="$url/archive/${_commit}.tar.gz
config-changes-amlogic.aarch64
defconfig
- 0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch
- 0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch
- 0003-ARM64-defconfig-enable-CEC-support.patch
- 0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch
- 0005-clk-meson-remove-unused-clk-audio-divider-driver.patch
- 0006-ASoC-meson-add-meson-audio-core-driver.patch
- 0007-ASoC-meson-add-register-definitions.patch
- 0008-ASoC-meson-add-aiu-i2s-dma-support.patch
- 0009-ASoC-meson-add-initial-i2s-dai-support.patch
- 0010-ASoC-meson-add-aiu-spdif-dma-support.patch
- 0011-ASoC-meson-add-initial-spdif-dai-support.patch
- 0012-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
- 0013-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
- 0014-snd-meson-activate-HDMI-audio-path.patch
- 0015-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
- 0016-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
- 0017-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
- 0018-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
- 0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
- 0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch
- 0021-soc-amlogic-add-meson-canvas-driver.patch
- 0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch
- 0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
- 0024-drm-meson-convert-to-the-new-canvas-module.patch
- 0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
- 0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch
- 0027-ARM64-dts-meson-gx-add-vdec-entry.patch
- 0001-libretech-cc-disable-CVBS-connector.patch
- 0001-ARM64-dts-meson-add-vdec-entries.patch
+ 0001-ARM64-defconfig-enable-CEC-support.patch
+ 0002-ASoC-meson-add-meson-audio-core-driver.patch
+ 0003-ASoC-meson-add-register-definitions.patch
+ 0004-ASoC-meson-add-aiu-i2s-dma-support.patch
+ 0005-ASoC-meson-add-initial-i2s-dai-support.patch
+ 0006-ASoC-meson-add-aiu-spdif-dma-support.patch
+ 0007-ASoC-meson-add-initial-spdif-dai-support.patch
+ 0008-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
+ 0009-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
+ 0010-snd-meson-activate-HDMI-audio-path.patch
+ 0011-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
+ 0012-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
+ 0013-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
+ 0014-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
+ 0017-soc-amlogic-add-meson-canvas-driver.patch
+ 0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
+ 0020-drm-meson-Use-optional-canvas-provider.patch
+ 0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch
+ 0022-drm-meson-Support-Overlay-plane-for-video-rendering.patch
+ 0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch
+ 0024-drm-meson-Add-primary-plane-scaling.patch
+ 0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch
+ 0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch
+ 0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch
+ 0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch
+ 0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch
+ 0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch
+ 0032-drm-meson-Add-support-for-VIC-alternate-timings.patch
+ 0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch
+ 0034-MAINTAINERS-Add-meson-video-decoder.patch
+ 0035-arm64-dts-meson-gx-add-vdec-entry.patch
+ 0036-arm64-dts-meson-add-vdec-entries.patch
+ 0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch
+ 0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch
+ 0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch
+ 0040-media-meson-vdec-add-H.264-decoding-support.patch
+ 0041-media-meson-vdec-add-MPEG4-decoding-support.patch
+ 0042-media-meson-vdec-add-MJPEG-decoding-support.patch
+ 0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch
+ 0008-drm-meson-Add-HDMI-1.4-4k-modes.patch
+ 0009-drm-meson-Use-drm_fbdev_generic_setup.patch
+ 0010-fixup-drm-meson-Use-optional-canvas-provider.patch
+ 0012-drm-meson-add-support-for-1080p25-mode.patch
+ 0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch
+ 0015-drm-meson-add-HDMI-div40-TMDS-mode.patch
+ 0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch
+ 0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch
+ 0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch
+ 0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch
+ 0020-drm-meson-Add-YUV420-output-support.patch
+ 0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch
+ 0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch
+ 0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch
+ 0001-drm-meson-fix-max-mode_config-height-width.patch
add-phicomm-n1.patch
bt-btbcm.patch
- brcmfmac-Disable-power-management.patch
- offset.patch
- off_error_text_offset.patch
+ text_offset.patch
"
subpackages=""
arch="aarch64"
@@ -274,40 +297,63 @@ _dev() {
"$subpkgdir"/lib/modules/${_abi_release}/build
}
-sha512sums="b65dc14801b987b4d8ca786aa6571da12fd929ab147ed2f71f366b32313cd72d3047830e502b3fe51f9f1f3963d46b7f5b45ed937a4bdfee14dc216b32de2d3a e7d199e92956587695510d147c8de795f944cec9.tar.gz
+sha512sums="642e3de14702d3034f9108c7b6661294722f4cf455b9167c349111642586d9a48732070e46092e7084f3ffbc26f01bae50f8da52eeceb7cf0f40e1441f9d895e 178574b66509c9ff7df4ad26c84a8884567e93b4.tar.gz
7186849193386fc06caab6db9ebf3d5b7efe2511f1c3836bb70d713340eb69b1f123f8372f15ee7f8dd61eeff5ce772b35db8557133ef64a2a1a5ca9e7cd30c9 config-changes-amlogic.aarch64
2784f8c05c1c66f2bff73d0cdd415781e6529f269223607c18302803125092e7cb6c94083146deecc3226672f7f4754246cc62808f9384f697782ec55786883d defconfig
-94f944448156e435030d84d787d1489cdab4a6733b1fd27cd4ecd1284337d2b3e68bb3f74b3268a4cac01587e96019d4ad2a354c59d1422b6caae3f97849717f 0001-ARM64-dts-meson-gxbb-nanopi-k2-Add-HDMI-CEC-and-CVBS.patch
-997fee925f07735e635fdd2d2474500ca5a81a80a7817c079174e2508eec223264c97b79cfc057d6b4e428c4d9392405f79befd242dc9b21e020f544ffd84c9d 0002-drm-meson-Make-DMT-timings-parameters-and-pixel-cloc.patch
-3294e40073360e9f6daf3360022a8443bdab960ba0f261e5858e36e7b838af0304888eef9992ef93f67a5dc97f0a26c46f08da1c2f32ca1fe01b9754f55ae975 0003-ARM64-defconfig-enable-CEC-support.patch
-02c5a7b99be3a180eb40716735ced4ba5f9da1897cb9132c3376b660ba1c005df60b9da1ad7808f53027b7d37b89ef007c71aa2fdfd5ad77be4425886348c3b2 0004-clk-meson-switch-gxbb-cts-amclk-div-to-the-generic-d.patch
-8d4d3bead45b420b0920eb4eb77fc938c2bcb64a3304d5690432aec7a235f348deba4246b737742901102f256313ab34f95caa8932184099ed20baaf23913f6f 0005-clk-meson-remove-unused-clk-audio-divider-driver.patch
-7057d93953fe9bb83415ac82fe63bacc64161f295e1340dc8b56330a74655c44e9f7feb621f12b74e7d92497115abd918e7b087bc0ece7d0322e384fbd5acd95 0006-ASoC-meson-add-meson-audio-core-driver.patch
-42ba176a6198fae2146f871dc469fb94b40382ff966b167f976d5e28375f4849bda6141b01e786d37cf14ca71ba159ee0a0316ec477150040517cebf0f638334 0007-ASoC-meson-add-register-definitions.patch
-720c21f11514edba0164ecfe260b8d2409ccea5eaaf4d98013e42a7e4f160fbe30d6a25fd94ae1fae115742fff298ebab1a079ac1f54ae0dc39cfb5567eb693c 0008-ASoC-meson-add-aiu-i2s-dma-support.patch
-19d3afeae370201d513c98137bd3833ec3bb8fbd43dee5a391a6e4926a31b381746725e3abdc907a2f24f72ae6757687083d0b99ba1e27a34d90e0f06e506573 0009-ASoC-meson-add-initial-i2s-dai-support.patch
-d9da5fc3cf9d6942aa995c06e6c22bfeac89add9dc7d0dd4f58cb4d8e07ceb3679d8af1dd68ba1510bc964cc6303cdf38954b7364ccd9bf22de4c379f12cfbe3 0010-ASoC-meson-add-aiu-spdif-dma-support.patch
-9cbab78248da16985ac64c3ee58652df36ae3a8313d7723a168ed36cb23c6d488dd21a603b09ac2fc7ee88aaa4d248c49768821af065f627e8bad671a961a58a 0011-ASoC-meson-add-initial-spdif-dai-support.patch
-f7e1b85b59f4347918b626fd373cb23bc5ede17f52f7c8d0f29d6f80a22d28966060c7842363393505b8c059b11ee15297e3b429976a7e6e5f0189a14223a480 0012-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
-52a9eaaf61daa1923ed91a20fc7088d532060d180755c257122b6d897a07812249fefe6f5cd568551b9b8656071be3f2f6922f34d691003d8146bb5307e7522b 0013-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
-5c31a60457ccc4e6fc1c6f005b9c70583a03797cd56cca3e9799d2717312fd8610ec13cd7d83eadd134379788e9655b4e95b90462076adf10ff39b71dc7c9a10 0014-snd-meson-activate-HDMI-audio-path.patch
-afd396bd828a87fb001956ce7369ac8c34e51a684f7be486995463cf4d912a39b242b51af7f3a841b6ecb42ab7e4366c5f9d163992ccaf370fedd842f7a4b2c6 0015-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
-b6ac2f340d57cd0514a8fbd54f3d17942e794f20bfe3402c64a98fdf7cca7ab487cc2bac884436324eda21482bebbdfe7633bd9f9708bc84adb720161a555b89 0016-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
-b55f9b3370d1c7b75c52f8f75f12a5033402d3a7f0f5be591cd6268b280a39959464570c8868e94586034f48a90f50ac17e414b191e12f7725175dca6fee2a1f 0017-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
-5814fcf935365b7975ae21f416122a341cef4e54dc8556a03882915d908586e42ec966b18ab5abb85b1533a1c494eeebbb237df3a4ebde28f15449bab66fa421 0018-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
-95da882661e07c40d726797b570b2407c94862278a2148f8ff1d3ce7ffe00ba6f83d1f06be77a1fbc59c5f1f5620c1346bd565903b49e5d657e8d143eb247af8 0019-drm-meson-Call-drm_crtc_vblank_on-drm_crtc_vblank_of.patch
-8371d3c08ba0029e7c29a5171eb53ba175c0909f1a90a17967f2ca68c1d9a2dbc49a39d1102a62470d237a50a99307b7475a4ba243a0a0d6881684705f428e2b 0020-media-platform-meson-ao-cec-make-busy-TX-warning-sil.patch
-896a8ba7c44744e067d3d5216d28df241c6796f1aff01b9648ea2e54e5798f25436328cdb173f00de2f998903ae01b3785a37ed07aea576ccada4590925de10f 0021-soc-amlogic-add-meson-canvas-driver.patch
-ad723a68e02b2d4fd708fab3b61aba3ad888b25de9d5e73f3f00dc81bf778d1b59061aa25b840bc790903a8dc9ce180da5aca6312c9f7c8b724a18c80866e174 0022-dt-bindings-soc-amlogic-add-meson-canvas-documentati.patch
-0854014aaf150468b14a739649e1461fa66450d168f3f430756bcf6d2e34158be922824d2eb62fd867e5ac28340ef120fb13504183984da7a4bd3a6fe59724b8 0023-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
-f01e6fd7a319c75c85803e1deb1681772385640fd10ef4a24b164af6e708d0d29e8118bf2be12a82e6587587a87a6b5b7331bd160c32ae9e3d5f4c1a4e62ce79 0024-drm-meson-convert-to-the-new-canvas-module.patch
-783a1c4c0deb352b699faa5f572d38737c1c67983a84822b900a984e9aec521f7a762d6f139d5ce7546503af4a76fd2b604ef79a2aef5105d23fc33919fa13de 0025-WIP-drm-meson-Support-Overlay-plane-for-video-render.patch
-34b404bbb4b1e2c3ae1c9fba8e297ed48d382d59208bb00340a5e9f2a86ef0f12d0fc6f347a68915cffc141e19bd4b086a1bbdc440b4bd8a1edef5a7fb79c46e 0026-media-meson-add-v4l2-m2m-video-decoder-driver.patch
-608bb5d25c94e9d8e0a1ea9d9fc2eb4436870d72e39f9446322dbdc62a5b7a3fd07d735613a425e1853cf9dd3e61fc860f4310858f9cfbea62a3ba69378b653c 0027-ARM64-dts-meson-gx-add-vdec-entry.patch
-0ab00106ab3a15ef884d0d08c4e947037007a4af7b03fc204346e9487f1f8841140dead1f6b8704b74f7fd955deaaa58cc7ce81c42a847bcdc5c13aac627f3e4 0001-libretech-cc-disable-CVBS-connector.patch
-7715e9c35072f60856d5ab6940874f053cd5e64f09ae97c79eef98bf0856f3a27643dae1154eec787c94a8c7c84b39c580324540db37d9bf2cf70b2bfa66595a 0001-ARM64-dts-meson-add-vdec-entries.patch
-6262ecd89164edcfc58ef7d50c0b027a2263e6e78f51f033b611734a8e8db0436e1b132aee65546717dd5c79635ef38c9be11cffd7808491687494df9fdcb08e add-phicomm-n1.patch
+09e8d284608ac0e86db8b36bdefdb17c8ad8e9b3bdf443ee5a687f1591d88d26cffef1a36919b0547acef49394d903ff8067d46f75b55eccadec415971bf0b34 0001-ARM64-defconfig-enable-CEC-support.patch
+55d3e84c4e01b94a3bf256a980bd23a8d02c3ea7f4103d350400eb28cc31336bb35f9404ee34ba80f7d3d7427d73ed4ee75119a916ae0e88d911bb83b0303229 0002-ASoC-meson-add-meson-audio-core-driver.patch
+b5a65140612b011f22d4bfbb4ab41a4c0fe07bab43f8033195a42b02c5d74c69c7fbc2b186f8d6ff08ed7b66ccbfd9d8d7945f81812ae5021b1d37154acdb12f 0003-ASoC-meson-add-register-definitions.patch
+441b0385e88bb7ddb324363536413e6538d4b0367181ae5ceada806a8efe3d1b5daa643bd3ab99db6fa7a2d5ea0944a15a63672fa26bfc7850959ce2d7238aa1 0004-ASoC-meson-add-aiu-i2s-dma-support.patch
+4615d01a2548ce5057446ff32c52bca1cea189fc74d902ea22dc90e73c2eb21ef5b4b58c6a4ebbdf3c6cad5bac483dabdee025438ebc0bdf1b4368af0fce1b87 0005-ASoC-meson-add-initial-i2s-dai-support.patch
+d1dc1d99393a885776144dea27c0789d9e7968de1164bc85b07cc8d444cdcc898ce2f7ff1f9515ae2424789cbb76b84a8ed56008c1880fef60be79000bf55452 0006-ASoC-meson-add-aiu-spdif-dma-support.patch
+b101c64312509738b078732f73b265fa81bb94806bb39524e85d171949505dc0548fc3ece498cca6586b8ca4af08b271b6c02f028040f8cf16ec5eee94ddafa1 0007-ASoC-meson-add-initial-spdif-dai-support.patch
+98fd62a02fa76a957d15da9456c85def94a790429c3357b4b06a63d4224b624ffe763410ffdbc09ff560ba0a17a5299b722e2c9cefbb4a59455cfbe7379850b3 0008-ARM64-defconfig-enable-audio-support-for-meson-SoCs-.patch
+a286d6ecb284f505ebd29c04c5e95b1e7ba1a4a3c5ffb17580c2387ab78360cba7be6806772a058be8326f7a299f59c84051ed022b2c99372412d935f12f7c6a 0009-ARM64-dts-meson-gx-add-audio-controller-nodes.patch
+e84ab2a28d08570590ad06219e1a99a8cc47a589d4170f5ff1bf6eeb1b50c1e4e21857a5633495d2271ae702b9bfdc8aa76bb56d572b236d54a4ec08566f13d6 0010-snd-meson-activate-HDMI-audio-path.patch
+35962172f6c2682f0e3ba438ca9e62ddd679a0cd665e6bc6208167a753877a02a1d4db8d78b230de44ab494016cf9d47f0e61d31121cb0b8b676b689f1258f71 0011-drm-meson-select-dw-hdmi-i2s-audio-for-meson-hdmi.patch
+db2c10c9e4b58e7f0b72a0b8b81ef39544d0e14ef5814dda4d6d5d98d181c9c0f5993ac0e6bc98ea8c79b5d22a3c4eb38793ddb22e7e2553f4643027767a597e 0012-ARM64-dts-meson-gx-add-sound-dai-cells-to-HDMI-node.patch
+4f0073aa0a4ed1297b00817bb6cad704362c32fda284780e7a73505dab8e3cfdec5eb851fccdf7e6bf16c1788bc0f8f6ca58b0898adacca678f46ca940aa493a 0013-ARM64-dts-meson-activate-hdmi-audio-HDMI-enabled-boa.patch
+998c39cf37d2258582d6d60a7e6a702601430645b01c971c162bb219684e363fd11d0572cefb15f00551fe6bc95d97d1c101e6f36b1ae015083edeb5742b3df3 0014-drm-bridge-dw-hdmi-Use-AUTO-CTS-setup-mode-when-non-.patch
+03c2649558bedc2bf34f0e139db489d6891bda6041384d0023cf700be31d1fb1f983c8bc7d58754acd0a57986432b0330996c82f7dc7fd4a6044589725fc4c9c 0017-soc-amlogic-add-meson-canvas-driver.patch
+7c1e84356a62a175326f56e71e6984aa4a00ab4b50ac09cce8a078890f2c2ac700d53c53b1229e8dbfb82f36bac32b3082ccdf91a8f92545148bd705784b38e4 0018-ARM64-dts-meson-gx-add-dmcbus-and-canvas-nodes.patch
+f2a94fde352734e1de54f10703d792c62c95ae4b68c2c0ce9eb78fded934084fab4b999c930f7228982044052e5b331cce60cf72dcc1f181bcc88eaf68116bb8 0020-drm-meson-Use-optional-canvas-provider.patch
+635410e2f6476ee1f1114d31c06f997d5997e117d857ef67f7acb456b52941a4b4aa0cdd94ce9788a017a07d75143d783e900e03eac009d030c90fbe95798003 0021-arm64-dts-meson-gx-Add-canvas-provider-node-to-the-v.patch
+df666c95cc1d0dc4c9dd93f79778c5880afd89c320a0edb22dc3f017388cd2df88806aae4c7cde4c412e6643fcd1a8df4c6f15b41b0b0e6b020eced9cedf8d9a 0022-drm-meson-Support-Overlay-plane-for-video-rendering.patch
+8e3f62fc50c8478951f8a2e6c5d8c8f38f56ed4d68f9c0fb55c23c46d3ae2182e8a6e5f23171aac08867da4bb16d7c98741a80a3ae6a3acfc41568350be59a57 0023-drm-meson-move-OSD-scaler-management-into-plane-atom.patch
+63c41b6db1386530339bd3b6d87849bb38a8d51ec8fcd0bf3c1bcb77c567c589e069dee02f066030f608288fd510e3af244ff45b346e0addc31614867daab334 0024-drm-meson-Add-primary-plane-scaling.patch
+64682336c72ac1e505e19e4a099bb2c6f8ba6e8df2ed3b149e355c50b27a29337ac1de7768dd0fd3274bda4fe2f6cc53d068d8a1e6325d27c42e372a0324cbd2 0026-pinctrl-meson-gxl-remove-invalid-GPIOX-tsin_a-pins.patch
+332aa83ae3c581b81dae9b37df047fa5e553b0c31790713395ab562aa03ac32fbf909ab6372aba22d06cb82c509efef68af90aeaf66ca5cf70c0861c69039139 0027-arm64-dts-meson-gx-Add-hdmi_5v-regulator-as-hdmi-tx-.patch
+0cb8ed9fb52cfdcfac8dbbab5b08f4b5fe1b8716655fe77f37ff1ee39355fac89314dd318856582c62dce1fd56232b4a2725c60a2d07ef15efba86160eb093f0 0028-arm64-dts-meson-gxl-libretech-cc-fix-GPIO-lines-name.patch
+f4d251863ac20a95642a60f7c6c51694d36a12f745864fccbb6513b2e53fb0039fa316f4bcd245abe306d2d0aeb0037498f9e21333ab1d84e58fb5d287632093 0029-arm64-dts-meson-gxbb-nanopi-k2-fix-GPIO-lines-names.patch
+c481cde9a8bf2609b99e1a7a94bdfead78afe8665347dfffcde8747b8e2817356123e0e44b71de4c5b85224aa20c3c63d5ce3f44e49e3969f0ea28f4df94dc62 0030-arm64-dts-meson-gxbb-odroidc2-fix-GPIO-lines-names.patch
+768d954c5580b68e999bf3ed051219187c96de88f27be54e52242687f2ef505c0616dabbc5bee42fdc6d20d53d973f2e64ef4809649fb2e666d8727ed314f3fd 0031-arm64-dts-meson-gxl-khadas-vim-fix-GPIO-lines-names.patch
+e23b9303036d736a3f9abed22712848da514f6388de66b3029bde551a85b7d42d1506ee960a539457c8dd7d8b6c07e80919ca0714a9435bdcaa85ca2e201d69f 0032-drm-meson-Add-support-for-VIC-alternate-timings.patch
+671da78856f524f7e491e35dcb2764acb6ff0e99eee4df6c9e9538dc321c6c2e4481fd8c39daa2cb32d23d38c96823e5ab04db0342b2daabd5d1b7efdb0d6288 0033-media-meson-add-v4l2-m2m-video-decoder-driver.patch
+8d13b4e5c503a196b29263a85d3bc2d9cd1b95d186e6347532b8ae7efc35c93ed72d3f9c4a7ff12b5c2186b3f7d3b35247858e66a96382ba3a2630db35cdf794 0034-MAINTAINERS-Add-meson-video-decoder.patch
+c1817a1b59a4a38f7a0689c1e2603398f538d9270a93b40e2ce3e9633b71943beb385206d802673b18f244fb5d9a6c9b2e0498d7803432cf98750843fb91ce5f 0035-arm64-dts-meson-gx-add-vdec-entry.patch
+bdd5bd9e4203e3e7bd6412b2068963e22a974316b8ee1a707933808f1ec03ab43aa174804e7fd21f2f7062dc25226e4f2047a863366f132d8687d098a203c6d1 0036-arm64-dts-meson-add-vdec-entries.patch
+9c3b9170bbc5fbf3331052e5a99864b76cee6c2c50629f22d33d6e0b01de164e34db4a57c3864e6cb10ff9486999842c9d5f5d38bcb65ef98ccca34c3a6366be 0037-meson-vdec-introduce-controls-and-V4L2_CID_MIN_BUFFE.patch
+6bd52ae9872d79b5b2199d23bbef6f73b7530c54df702edf0ce040ba799c60265d199f75fcd4301587100fe60a6d43988bdffdfcb6f98be0c0d8a79f27d206bf 0038-media-videodev2-add-V4L2_FMT_FLAG_NO_SOURCE_CHANGE.patch
+516113c435158775f85a3904e5941bcfe641428cfce1945722a2ab8f7897a8493dca634f3527fa4d8fb0433635efcd48353a2feadee94e3467057ce4ff966964 0039-meson-vdec-allow-subscribing-to-V4L2_EVENT_SOURCE_CH.patch
+0332979243ae7c182006050c3c2b34c9035ce9f3b084659ec0c3fd39c6772d42c0f5420628150113d2d149d8b1a2481d42650aae08ac054d25cf19178ba64ebc 0040-media-meson-vdec-add-H.264-decoding-support.patch
+d696a4a726801786e65fcb69f70c5271a982b2d494a8036d7d8a3e201f910d0e1dc411283128b3460bf2371cb43817d760c0de866cfc22a985f1ff052b98cbff 0041-media-meson-vdec-add-MPEG4-decoding-support.patch
+1381cbabd3e040d6e14c1f270904b2c41c6758f2757c3871d1a09d41ab4ce8f85cde95ed1cc989fe59addfa3eae6246f7cc25b63f213f9b28cc73ec86a1c3deb 0042-media-meson-vdec-add-MJPEG-decoding-support.patch
+36281f344133b7f4130d69685b1802524a597e110e792f0cae43991eb3a15282d77779cca8033679b943660cd23c9da54c62178b99999e91dc8581052cb53945 0043-clk-meson-gxbb-set-fclk_div3-as-CLK_IS_CRITICAL.patch
+ddcb198b0e052975764dfaf140763247e80632eee5f49e3316dc4f1b6220da80fdca0dc32ec618b27fb0487b3ff0676f2a2ed07d5cecfad350bafba0b79ddfed 0008-drm-meson-Add-HDMI-1.4-4k-modes.patch
+a58680d93e56fbc95e9e255b79822fcb7960d1f58dbf819dda729b21b61949f42ac58454a6403e77b0d12708613425f331531de700a74c18b262f1336849d5a1 0009-drm-meson-Use-drm_fbdev_generic_setup.patch
+b103daed449e59ce1d73e929c694f042e461241ef9d09592828414ab04a9c7ce07c16f636461d8bc5ba49650b9f584a861d5bd4267e90899b8bd72ec113bee4e 0010-fixup-drm-meson-Use-optional-canvas-provider.patch
+5e25559535d0a1529c8b5e31e9dab82c0d41f70e515a2ca4ed614177e127c0933cc1d54566ef6f063b19dbd19f3b1d67cb51ad4d8a87877140cf166c5969a6f0 0012-drm-meson-add-support-for-1080p25-mode.patch
+8de5c1f61e8467504f96db3c615658f40bb217d57a1a0c03b505cd8e310961dce38a191cd40ccecd48ed204fac1c3d3facb371e07ff590b8683afc4420e7f303 0014-drm-bridge-dw-hdmi-Add-SCDC-and-TMDS-Scrambling-supp.patch
+8fe6432a889ee13081185eeb8602ea48465b7d858f0b573f5a5c4d35e6ed76edc47f697b0c1729a31e9a319e0712bb0eaa111077d86570d2954dcbe6fceb7b60 0015-drm-meson-add-HDMI-div40-TMDS-mode.patch
+358f064f42c9e21afeccb867c062fc18484f91ed7805752edaf74492774962c16348099de004ce130134610f8c5d076fd715ca0de3eb30d0abd23f90236c6a7b 0016-drm-meson-add-support-for-HDMI2.0-2160p-modes.patch
+9bd13d763a007ffb9d0e9f9f4c9b5018752c010a39780e467d463153cc79a32774120d7af83496ba706b971dd3bd9bb600fad4795b3c0796e22eb42b23374a90 0017-drm-bridge-dw-hdmi-add-support-for-YUV420-output.patch
+f15dd5116fe7464009ade33a9c6d305a7720767e1b31acbf7653cd9d2f83b428e734712739e8bb4cfd04407640187f5528f80d7e8b89992a75f2316b6f8513c6 0018-drm-bridge-dw-hdmi-support-dynamically-get-input-out.patch
+2399c1c95455f2e4d0d03d2c84cf454251b7c8a151da555e7665bede91b7b62f96391efac3ca9a5b90761e105409bd033f348e25bc163a439a2ff7efd82e2184 0019-drm-bridge-dw-hdmi-allow-ycbcr420-modes-for-0x200a.patch
+26eb2b101ab563558649f38a5102773b2d79eeb39cf04a3f8d512361beed70ad585825233716acb58853887bc863ba76ce87f6eaf6d8c5c22e4caa99a5ce294a 0020-drm-meson-Add-YUV420-output-support.patch
+fac806a77816f655354499ab597974659e5d6dc74d04ac74cd81bacd6a264ac13ab33bc230a2c233d98d6e3b0342f329c2af0c6359d9ae8b6b456add06809822 0021-drm-meson-Output-in-YUV444-if-sink-supports-it.patch
+e365ba0479201f1c4fb08f872447f2496d4c8d75c8e3f632eeb3f7091e56d0659d4b6f580d384183e0e9c80ccf659b1704ecbaca88b66ca34c78c250c0f55a29 0023-drm-meson-Fix-an-Alpha-Primary-Plane-bug-on-Meson-GX.patch
+0aca4ad6af15ea8f8e2e8a05aa3c5a16e1a909ee0f80cb1f64e0ee027a7050b0bbd5815520e146f96641b92e5d39688677de39d4294be6a25ea1a2e519df257b 0001-arm64-dts-meson-Fix-IRQ-trigger-type-for-macirq.patch
+613d619e86883d83d53d045ed589d91c74a9f2031de953d2f3e4cdf374ae32841a69b28abfd0d8314a5739f51fbd3ab02c7f8baf4c5060db725d21f7a677db7f 0001-drm-meson-fix-max-mode_config-height-width.patch
+ea41c0b63d8890cf5db69a37ead0fb9863299a344cee2d3606cc8c049405a563e139dceb6c908abc57b5b545d3daee16f7b9c6f7f1284cb9cf676ff5830d5c96 add-phicomm-n1.patch
dcc02a2e35e530490f18dd1f7e304aebd7c268ed8a46971d94e9da7dfd65b287002e6b921e46db5ce118177c9ab79fbe3640565cb2df19809b6eff514122fb43 bt-btbcm.patch
-007075ca40915f20c6c8f5e04825c3433a52621deb689a9a690a3fcc618ca9629bc089a1a2ad5141fc47a8aa0aabb302ecf75e81ef8cae466e978074156231ac brcmfmac-Disable-power-management.patch
-cb2ec80ae38c4cc46ea2a4ca6d157498632f8154ef6a1dedb898c70593c812743a69a4c0d36a4e146a71c588e30e9f9b2feb415e00166850c2cf79797048b032 offset.patch
-e5d214788f9a28d79a9ef135fbed3b3c87982941788ca74d31d919534d1627c1265b268982f67de6c14b331d1a38938b4c2772f17b3db3bddd3983f919fe73ca off_error_text_offset.patch"
+298ded76cf87f08c9357505e9dd7582d886a5e59111eee81ecb136b2dd1f3f404899a32029696038cb2299760568b2b0345c92dfd961591b28ec2964460f09b1 text_offset.patch"
diff --git a/testing/linux-amlogic/add-phicomm-n1.patch b/testing/linux-amlogic/add-phicomm-n1.patch
index 2140d8d828..3c3b16e32c 100644
--- a/testing/linux-amlogic/add-phicomm-n1.patch
+++ b/testing/linux-amlogic/add-phicomm-n1.patch
@@ -1,5 +1,5 @@
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
-index 34dd0e9..773f415 100644
+index a97c0e2..ebd96da 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -17,6 +17,7 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-nexbox-a95x.dtb
@@ -7,9 +7,9 @@ index 34dd0e9..773f415 100644
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-phicomm-n1.dtb
- dtb-$(CONFIG_ARCH_MESON) += meson-gxm-khadas-vim2.dtb
- dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb
- dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb
+ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb
+ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb
+ dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-phicomm-n1.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-phicomm-n1.dts
new file mode 100644
index 0000000..7903dad
diff --git a/testing/linux-amlogic/brcmfmac-Disable-power-management.patch b/testing/linux-amlogic/brcmfmac-Disable-power-management.patch
deleted file mode 100644
index 17629f8e0c..0000000000
--- a/testing/linux-amlogic/brcmfmac-Disable-power-management.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-index b6122aa..e2098ad 100644
---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2697,6 +2697,8 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev,
- * preference in cfg struct to apply this to
- * FW later while initializing the dongle
- */
-+ pr_info("power management disabled\n");
-+ enabled = false;
- cfg->pwr_save = enabled;
- if (!check_vif_up(ifp->vif)) {
-
diff --git a/testing/linux-amlogic/off_error_text_offset.patch b/testing/linux-amlogic/off_error_text_offset.patch
deleted file mode 100644
index a5069502b6..0000000000
--- a/testing/linux-amlogic/off_error_text_offset.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
-index b085306..68edc91 100644
---- a/arch/arm64/kernel/head.S
-+++ b/arch/arm64/kernel/head.S
-@@ -51,7 +51,7 @@
- #elif (PAGE_OFFSET & 0x1fffff) != 0
- #error PAGE_OFFSET must be at least 2MB aligned
- #elif TEXT_OFFSET > 0x1fffff
--#error TEXT_OFFSET must be less than 2MB
-+//#error TEXT_OFFSET must be less than 2MB
- #endif
-
- /*
diff --git a/testing/linux-amlogic/offset.patch b/testing/linux-amlogic/offset.patch
deleted file mode 100644
index 644b65ee4a..0000000000
--- a/testing/linux-amlogic/offset.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
-index e7101b1..deabd29 100644
---- a/arch/arm64/Makefile
-+++ b/arch/arm64/Makefile
-@@ -87,7 +87,7 @@ TEXT_OFFSET := $(shell awk "BEGIN {srand(); printf \"0x%06x\n\", \
- int(2 * 1024 * 1024 / (2 ^ $(CONFIG_ARM64_PAGE_SHIFT)) * \
- rand()) * (2 ^ $(CONFIG_ARM64_PAGE_SHIFT))}")
- else
--TEXT_OFFSET := 0x00080000
-+TEXT_OFFSET := 0x01080000
- endif
-
- # KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
diff --git a/testing/linux-amlogic/text_offset.patch b/testing/linux-amlogic/text_offset.patch
new file mode 100644
index 0000000000..fff476e656
--- /dev/null
+++ b/testing/linux-amlogic/text_offset.patch
@@ -0,0 +1,26 @@
+diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
+index 106039d..651d990 100644
+--- a/arch/arm64/Makefile
++++ b/arch/arm64/Makefile
+@@ -88,7 +88,7 @@ TEXT_OFFSET := $(shell awk "BEGIN {srand(); printf \"0x%06x\n\", \
+ int(2 * 1024 * 1024 / (2 ^ $(CONFIG_ARM64_PAGE_SHIFT)) * \
+ rand()) * (2 ^ $(CONFIG_ARM64_PAGE_SHIFT))}")
+ else
+-TEXT_OFFSET := 0x00080000
++TEXT_OFFSET := 0x01080000
+ endif
+
+ # KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index b085306..68edc91 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -51,7 +51,7 @@
+ #elif (PAGE_OFFSET & 0x1fffff) != 0
+ #error PAGE_OFFSET must be at least 2MB aligned
+ #elif TEXT_OFFSET > 0x1fffff
+-#error TEXT_OFFSET must be less than 2MB
++//#error TEXT_OFFSET must be less than 2MB
+ #endif
+
+ /*