mirror of
https://github.com/home-assistant/operating-system.git
synced 2025-07-24 13:36:31 +00:00
Fix Kernel For odroid XU4/C2 (#510)
This commit is contained in:
parent
308fccd7b1
commit
30aa775450
@ -6,7 +6,7 @@
|
||||
| Open Virtual Applicance | 4.19.88 |
|
||||
| Raspberry Pi | 4.19.88 |
|
||||
| Tinker Board | 4.19.88 |
|
||||
| Odroid-C2 | 4.19.88 |
|
||||
| Odroid-XU4 | 4.19.88 |
|
||||
| Odroid-C2 | 4.19.72 |
|
||||
| Odroid-XU4 | 4.19.72 |
|
||||
| Orangepi-Prime | 4.19.88 |
|
||||
| Intel NUC | 4.19.88 |
|
||||
|
@ -1,50 +0,0 @@
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi
|
||||
index b160bd1084de..fffd55787981 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 ed336c7a98a7..44c5c51ff1fa 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -467,7 +467,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/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 00f7be6d83f7..2e1cd5e3a246 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -143,7 +143,6 @@
|
||||
interrupt-parent = <&gpio_intc>;
|
||||
/* MAC_INTR on GPIOZ_15 */
|
||||
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||
- eee-broken-1000t;
|
||||
};
|
||||
};
|
||||
};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
index 70325b273bd2..ec09bb5792b7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
@@ -142,7 +142,6 @@
|
||||
eth_phy0: ethernet-phy@0 {
|
||||
/* Realtek RTL8211F (0x001cc916) */
|
||||
reg = <0>;
|
||||
- eee-broken-1000t;
|
||||
};
|
||||
};
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
|
||||
index d0ae8c5315048..3ccf2c5be034c 100755
|
||||
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
|
||||
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
|
||||
@@ -402,7 +402,7 @@
|
||||
samsung,dw-mshc-sdr-timing = <0 4>;
|
||||
samsung,dw-mshc-ddr-timing = <0 2>;
|
||||
samsung,dw-mshc-hs400-timing = <0 2>;
|
||||
- samsung,read-strobe-delay = <90>;
|
||||
+ samsung,read-strobe-delay = <150>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8 &sd0_cd &sd0_rclk>;
|
||||
bus-width = <8>;
|
2
buildroot-external/board/hardkernel/patches/README.md
Normal file
2
buildroot-external/board/hardkernel/patches/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# Kernel
|
||||
https://github.com/akuster/meta-odroid
|
@ -0,0 +1,47 @@
|
||||
From 6763c7964e9cb28e21497eee0032be053461bba5 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 13 Nov 2017 12:09:40 +0100
|
||||
Subject: [PATCH 01/53] ARM64: defconfig: enable CEC support
|
||||
|
||||
Turn on CONFIG_CEC_SUPPORT and CONFIG_CEC_PLATFORM_DRIVERS
|
||||
Turn on CONFIG_VIDEO_MESON_AO_CEC as module
|
||||
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 db8d364f8476..ab1cb51319e7 100644
|
||||
--- a/arch/arm64/configs/defconfig
|
||||
+++ b/arch/arm64/configs/defconfig
|
||||
@@ -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
|
||||
+CONFIG_MEDIA_CEC_SUPPORT=y
|
||||
CONFIG_MEDIA_CONTROLLER=y
|
||||
CONFIG_VIDEO_V4L2_SUBDEV_API=y
|
||||
# CONFIG_DVB_NET is not set
|
||||
@@ -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
|
||||
+CONFIG_CEC_PLATFORM_DRIVERS=y
|
||||
+CONFIG_VIDEO_MESON_AO_CEC=m
|
||||
CONFIG_DRM=m
|
||||
CONFIG_DRM_NOUVEAU=m
|
||||
CONFIG_DRM_EXYNOS=m
|
||||
@@ -444,6 +447,7 @@ CONFIG_DRM_RCAR_LVDS=m
|
||||
CONFIG_DRM_TEGRA=m
|
||||
CONFIG_DRM_PANEL_SIMPLE=m
|
||||
CONFIG_DRM_I2C_ADV7511=m
|
||||
+CONFIG_DRM_DW_HDMI_CEC=m
|
||||
CONFIG_DRM_VC4=m
|
||||
CONFIG_DRM_HISI_HIBMC=m
|
||||
CONFIG_DRM_HISI_KIRIN=m
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,72 @@
|
||||
From 7041ca0d550d3a9caed54857365cf504eaeea756 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Kuster <akuster@mvista.com>
|
||||
Date: Fri, 23 Mar 2018 09:02:44 -0700
|
||||
Subject: [PATCH] exynos5422-odroidhc1.dts: fix booting from mmc
|
||||
|
||||
Signed-off-by: Armin Kuster <akuster@mvista.com>
|
||||
---
|
||||
arch/arm/boot/dts/exynos5422-odroidhc1.dts | 37 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 37 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/boot/dts/exynos5422-odroidhc1.dts b/arch/arm/boot/dts/exynos5422-odroidhc1.dts
|
||||
index fb8e8ae..c7adecf 100644
|
||||
--- a/arch/arm/boot/dts/exynos5422-odroidhc1.dts
|
||||
+++ b/arch/arm/boot/dts/exynos5422-odroidhc1.dts
|
||||
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
+#include <dt-bindings/input/input.h>
|
||||
#include "exynos5422-odroid-core.dtsi"
|
||||
|
||||
/ {
|
||||
@@ -30,6 +31,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ emmc_pwrseq: pwrseq {
|
||||
+ pinctrl-0 = <&emmc_nrst_pin>;
|
||||
+ pinctrl-names = "default";
|
||||
+ compatible = "mmc-pwrseq-emmc";
|
||||
+ reset-gpios = <&gpd1 0 GPIO_ACTIVE_LOW>;
|
||||
+ };
|
||||
+
|
||||
+
|
||||
thermal-zones {
|
||||
cpu0_thermal: cpu0-thermal {
|
||||
thermal-sensors = <&tmu_cpu0 0>;
|
||||
@@ -211,3 +220,31 @@
|
||||
&usbdrd_dwc3_1 {
|
||||
dr_mode = "host";
|
||||
};
|
||||
+
|
||||
+&mmc_0 {
|
||||
+ status = "okay";
|
||||
+ mmc-pwrseq = <&emmc_pwrseq>;
|
||||
+ card-detect-delay = <200>;
|
||||
+ samsung,dw-mshc-ciu-div = <3>;
|
||||
+ samsung,dw-mshc-sdr-timing = <0 4>;
|
||||
+ samsung,dw-mshc-ddr-timing = <0 2>;
|
||||
+ samsung,dw-mshc-hs400-timing = <0 2>;
|
||||
+ samsung,read-strobe-delay = <90>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8 &sd0_cd &sd0_rclk>;
|
||||
+ bus-width = <8>;
|
||||
+ cap-mmc-highspeed;
|
||||
+ mmc-hs200-1_8v;
|
||||
+ mmc-hs400-1_8v;
|
||||
+ vmmc-supply = <&ldo18_reg>;
|
||||
+ vqmmc-supply = <&ldo3_reg>;
|
||||
+};
|
||||
+
|
||||
+&pinctrl_1 {
|
||||
+ emmc_nrst_pin: emmc-nrst {
|
||||
+ samsung,pins = "gpd1-0";
|
||||
+ samsung,pin-function = <EXYNOS_PIN_FUNC_INPUT>;
|
||||
+ samsung,pin-pud = <EXYNOS_PIN_PULL_NONE>;
|
||||
+ samsung,pin-drv = <EXYNOS5420_PIN_DRV_LV1>;
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
2.7.4
|
||||
|
@ -0,0 +1,290 @@
|
||||
From 6b2734923e6bf1d4bd98f918400e2c7a692a8db0 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 11:49:55 +0200
|
||||
Subject: [PATCH 02/53] ASoC: meson: add meson audio core driver
|
||||
|
||||
This patch adds support for the audio core driver for the Amlogic Meson SoC
|
||||
family. The purpose of this driver is to properly reset the audio block and
|
||||
provide register access for the different devices scattered in this address
|
||||
space. This includes output and input DMAs, pcm, i2s and spdif dai, card
|
||||
level routing, internal codec for the gxl variant
|
||||
|
||||
For more information, please refer to the section 5 of the public datasheet
|
||||
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/meson/Kconfig | 10 ++
|
||||
sound/soc/meson/Makefile | 4 +
|
||||
sound/soc/meson/audio-core.c | 190 +++++++++++++++++++++++++++++++++++
|
||||
sound/soc/meson/audio-core.h | 28 ++++++
|
||||
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/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 8af8bc358a90..ed432d488b74 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -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
|
||||
+ select MFD_CORE
|
||||
+ select REGMAP_MMIO
|
||||
+ help
|
||||
+ 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.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index c5e003b093db..768d7c414649 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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
|
||||
\ 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 000000000000..99993ec4a5cc
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audio-core.c
|
||||
@@ -0,0 +1,190 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/clk.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
+
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-audio-core"
|
||||
+
|
||||
+static const char * const acore_clock_names[] = { "aiu_top",
|
||||
+ "aiu_glue",
|
||||
+ "audin" };
|
||||
+
|
||||
+static int meson_acore_init_clocks(struct device *dev)
|
||||
+{
|
||||
+ struct clk *clock;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(acore_clock_names); i++) {
|
||||
+ clock = devm_clk_get(dev, acore_clock_names[i]);
|
||||
+ if (IS_ERR(clock)) {
|
||||
+ if (PTR_ERR(clock) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Failed to get %s clock\n",
|
||||
+ acore_clock_names[i]);
|
||||
+ return PTR_ERR(clock);
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(clock);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to enable %s clock\n",
|
||||
+ acore_clock_names[i]);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev,
|
||||
+ (void(*)(void *))clk_disable_unprepare,
|
||||
+ clock);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const char * const acore_reset_names[] = { "aiu",
|
||||
+ "audin" };
|
||||
+
|
||||
+static int meson_acore_init_resets(struct device *dev)
|
||||
+{
|
||||
+ struct reset_control *reset;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(acore_reset_names); i++) {
|
||||
+ reset = devm_reset_control_get_exclusive(dev,
|
||||
+ acore_reset_names[i]);
|
||||
+ if (IS_ERR(reset)) {
|
||||
+ if (PTR_ERR(reset) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Failed to get %s reset\n",
|
||||
+ acore_reset_names[i]);
|
||||
+ return PTR_ERR(reset);
|
||||
+ }
|
||||
+
|
||||
+ ret = reset_control_reset(reset);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to pulse %s reset\n",
|
||||
+ acore_reset_names[i]);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_config meson_acore_regmap_config = {
|
||||
+ .reg_bits = 32,
|
||||
+ .val_bits = 32,
|
||||
+ .reg_stride = 4,
|
||||
+};
|
||||
+
|
||||
+static const struct mfd_cell meson_acore_devs[] = {
|
||||
+ {
|
||||
+ .name = "meson-i2s-dai",
|
||||
+ .of_compatible = "amlogic,meson-i2s-dai",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-spdif-dai",
|
||||
+ .of_compatible = "amlogic,meson-spdif-dai",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-aiu-i2s-dma",
|
||||
+ .of_compatible = "amlogic,meson-aiu-i2s-dma",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "meson-aiu-spdif-dma",
|
||||
+ .of_compatible = "amlogic,meson-aiu-spdif-dma",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int meson_acore_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_audio_core_data *data;
|
||||
+ struct resource *res;
|
||||
+ void __iomem *regs;
|
||||
+ int ret;
|
||||
+
|
||||
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
+ if (!data)
|
||||
+ return -ENOMEM;
|
||||
+ platform_set_drvdata(pdev, data);
|
||||
+
|
||||
+ ret = meson_acore_init_clocks(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = meson_acore_init_resets(dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aiu");
|
||||
+ regs = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ data->aiu = devm_regmap_init_mmio(dev, regs,
|
||||
+ &meson_acore_regmap_config);
|
||||
+ if (IS_ERR(data->aiu)) {
|
||||
+ dev_err(dev, "Couldn't create the AIU regmap\n");
|
||||
+ return PTR_ERR(data->aiu);
|
||||
+ }
|
||||
+
|
||||
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audin");
|
||||
+ regs = devm_ioremap_resource(dev, res);
|
||||
+ if (IS_ERR(regs))
|
||||
+ return PTR_ERR(regs);
|
||||
+
|
||||
+ data->audin = devm_regmap_init_mmio(dev, regs,
|
||||
+ &meson_acore_regmap_config);
|
||||
+ if (IS_ERR(data->audin)) {
|
||||
+ dev_err(dev, "Couldn't create the AUDIN regmap\n");
|
||||
+ return PTR_ERR(data->audin);
|
||||
+ }
|
||||
+
|
||||
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, meson_acore_devs,
|
||||
+ ARRAY_SIZE(meson_acore_devs), NULL, 0,
|
||||
+ NULL);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_acore_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-audio-core", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-audio-core", },
|
||||
+ { .compatible = "amlogic,meson-gxl-audio-core", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_acore_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_acore_pdrv = {
|
||||
+ .probe = meson_acore_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_acore_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_acore_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson Audio Core Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
diff --git a/sound/soc/meson/audio-core.h b/sound/soc/meson/audio-core.h
|
||||
new file mode 100644
|
||||
index 000000000000..6e7a24cdc4a9
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audio-core.h
|
||||
@@ -0,0 +1,28 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _MESON_AUDIO_CORE_H_
|
||||
+#define _MESON_AUDIO_CORE_H_
|
||||
+
|
||||
+struct meson_audio_core_data {
|
||||
+ struct regmap *aiu;
|
||||
+ struct regmap *audin;
|
||||
+};
|
||||
+
|
||||
+#endif /* _MESON_AUDIO_CORE_H_ */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,360 @@
|
||||
From 0b2aabc632854e317544bb293cbc0c63e120ddfa Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:00:10 +0200
|
||||
Subject: [PATCH 03/53] 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 ++++++++++++++++++++++++++++
|
||||
2 files changed, 330 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-regs.h
|
||||
create mode 100644 sound/soc/meson/audin-regs.h
|
||||
|
||||
diff --git a/sound/soc/meson/aiu-regs.h b/sound/soc/meson/aiu-regs.h
|
||||
new file mode 100644
|
||||
index 000000000000..67391e64fe1c
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-regs.h
|
||||
@@ -0,0 +1,182 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _AIU_REGS_H_
|
||||
+#define _AIU_REGS_H_
|
||||
+
|
||||
+#define AIU_958_BPF 0x000
|
||||
+#define AIU_958_BRST 0x004
|
||||
+#define AIU_958_LENGTH 0x008
|
||||
+#define AIU_958_PADDSIZE 0x00C
|
||||
+#define AIU_958_MISC 0x010
|
||||
+#define AIU_958_FORCE_LEFT 0x014 /* Unknown */
|
||||
+#define AIU_958_DISCARD_NUM 0x018
|
||||
+#define AIU_958_DCU_FF_CTRL 0x01C
|
||||
+#define AIU_958_CHSTAT_L0 0x020
|
||||
+#define AIU_958_CHSTAT_L1 0x024
|
||||
+#define AIU_958_CTRL 0x028
|
||||
+#define AIU_958_RPT 0x02C
|
||||
+#define AIU_I2S_MUTE_SWAP 0x030
|
||||
+#define AIU_I2S_SOURCE_DESC 0x034
|
||||
+#define AIU_I2S_MED_CTRL 0x038
|
||||
+#define AIU_I2S_MED_THRESH 0x03C
|
||||
+#define AIU_I2S_DAC_CFG 0x040
|
||||
+#define AIU_I2S_SYNC 0x044 /* Unknown */
|
||||
+#define AIU_I2S_MISC 0x048
|
||||
+#define AIU_I2S_OUT_CFG 0x04C
|
||||
+#define AIU_I2S_FF_CTRL 0x050 /* Unknown */
|
||||
+#define AIU_RST_SOFT 0x054
|
||||
+#define AIU_CLK_CTRL 0x058
|
||||
+#define AIU_MIX_ADCCFG 0x05C
|
||||
+#define AIU_MIX_CTRL 0x060
|
||||
+#define AIU_CLK_CTRL_MORE 0x064
|
||||
+#define AIU_958_POP 0x068
|
||||
+#define AIU_MIX_GAIN 0x06C
|
||||
+#define AIU_958_SYNWORD1 0x070
|
||||
+#define AIU_958_SYNWORD2 0x074
|
||||
+#define AIU_958_SYNWORD3 0x078
|
||||
+#define AIU_958_SYNWORD1_MASK 0x07C
|
||||
+#define AIU_958_SYNWORD2_MASK 0x080
|
||||
+#define AIU_958_SYNWORD3_MASK 0x084
|
||||
+#define AIU_958_FFRDOUT_THD 0x088
|
||||
+#define AIU_958_LENGTH_PER_PAUSE 0x08C
|
||||
+#define AIU_958_PAUSE_NUM 0x090
|
||||
+#define AIU_958_PAUSE_PAYLOAD 0x094
|
||||
+#define AIU_958_AUTO_PAUSE 0x098
|
||||
+#define AIU_958_PAUSE_PD_LENGTH 0x09C
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0
|
||||
+#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL 0x0A8
|
||||
+#define AIU_CODEC_CLK_DATA_CTRL 0x0AC
|
||||
+#define AIU_ACODEC_CTRL 0x0B0
|
||||
+#define AIU_958_CHSTAT_R0 0x0C0
|
||||
+#define AIU_958_CHSTAT_R1 0x0C4
|
||||
+#define AIU_958_VALID_CTRL 0x0C8
|
||||
+#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */
|
||||
+#define AIU_AIFIFO2_CTRL 0x100
|
||||
+#define AIU_AIFIFO2_STATUS 0x104
|
||||
+#define AIU_AIFIFO2_GBIT 0x108
|
||||
+#define AIU_AIFIFO2_CLB 0x10C
|
||||
+#define AIU_CRC_CTRL 0x110
|
||||
+#define AIU_CRC_STATUS 0x114
|
||||
+#define AIU_CRC_SHIFT_REG 0x118
|
||||
+#define AIU_CRC_IREG 0x11C
|
||||
+#define AIU_CRC_CAL_REG1 0x120
|
||||
+#define AIU_CRC_CAL_REG0 0x124
|
||||
+#define AIU_CRC_POLY_COEF1 0x128
|
||||
+#define AIU_CRC_POLY_COEF0 0x12C
|
||||
+#define AIU_CRC_BIT_SIZE1 0x130
|
||||
+#define AIU_CRC_BIT_SIZE0 0x134
|
||||
+#define AIU_CRC_BIT_CNT1 0x138
|
||||
+#define AIU_CRC_BIT_CNT0 0x13C
|
||||
+#define AIU_AMCLK_GATE_HI 0x140
|
||||
+#define AIU_AMCLK_GATE_LO 0x144
|
||||
+#define AIU_AMCLK_MSR 0x148
|
||||
+#define AIU_AUDAC_CTRL0 0x14C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA0 0x154 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA1 0x158 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA2 0x15C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA3 0x160 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA4 0x164 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA5 0x168 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA6 0x16C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA7 0x170 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */
|
||||
+#define AIU_MEM_I2S_START_PTR 0x180
|
||||
+#define AIU_MEM_I2S_RD_PTR 0x184
|
||||
+#define AIU_MEM_I2S_END_PTR 0x188
|
||||
+#define AIU_MEM_I2S_MASKS 0x18C
|
||||
+#define AIU_MEM_I2S_CONTROL 0x190
|
||||
+#define AIU_MEM_IEC958_START_PTR 0x194
|
||||
+#define AIU_MEM_IEC958_RD_PTR 0x198
|
||||
+#define AIU_MEM_IEC958_END_PTR 0x19C
|
||||
+#define AIU_MEM_IEC958_MASKS 0x1A0
|
||||
+#define AIU_MEM_IEC958_CONTROL 0x1A4
|
||||
+#define AIU_MEM_AIFIFO2_START_PTR 0x1A8
|
||||
+#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC
|
||||
+#define AIU_MEM_AIFIFO2_END_PTR 0x1B0
|
||||
+#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4
|
||||
+#define AIU_MEM_AIFIFO2_CONTROL 0x1B8
|
||||
+#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC
|
||||
+#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0
|
||||
+#define AIU_MEM_AIFIFO2_LEVEL 0x1C4
|
||||
+#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8
|
||||
+#define AIU_MEM_I2S_MAN_WP 0x1CC
|
||||
+#define AIU_MEM_I2S_MAN_RP 0x1D0
|
||||
+#define AIU_MEM_I2S_LEVEL 0x1D4
|
||||
+#define AIU_MEM_I2S_BUF_CNTL 0x1D8
|
||||
+#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC
|
||||
+#define AIU_MEM_I2S_MEM_CTL 0x1E0
|
||||
+#define AIU_MEM_IEC958_MEM_CTL 0x1E4
|
||||
+#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8
|
||||
+#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC
|
||||
+#define AIU_MEM_IEC958_MAN_WP 0x1F0
|
||||
+#define AIU_MEM_IEC958_MAN_RP 0x1F4
|
||||
+#define AIU_MEM_IEC958_LEVEL 0x1F8
|
||||
+#define AIU_MEM_IEC958_BUF_CNTL 0x1FC
|
||||
+#define AIU_AIFIFO_CTRL 0x200
|
||||
+#define AIU_AIFIFO_STATUS 0x204
|
||||
+#define AIU_AIFIFO_GBIT 0x208
|
||||
+#define AIU_AIFIFO_CLB 0x20C
|
||||
+#define AIU_MEM_AIFIFO_START_PTR 0x210
|
||||
+#define AIU_MEM_AIFIFO_CURR_PTR 0x214
|
||||
+#define AIU_MEM_AIFIFO_END_PTR 0x218
|
||||
+#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C
|
||||
+#define AIU_MEM_AIFIFO_CONTROL 0x220
|
||||
+#define AIU_MEM_AIFIFO_MAN_WP 0x224
|
||||
+#define AIU_MEM_AIFIFO_MAN_RP 0x228
|
||||
+#define AIU_MEM_AIFIFO_LEVEL 0x22C
|
||||
+#define AIU_MEM_AIFIFO_BUF_CNTL 0x230
|
||||
+#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234
|
||||
+#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238
|
||||
+#define AIU_MEM_AIFIFO_MEM_CTL 0x23C
|
||||
+#define AIFIFO_TIME_STAMP_CNTL 0x240
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_0 0x244
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_1 0x248
|
||||
+#define AIFIFO_TIME_STAMP_0 0x24C
|
||||
+#define AIFIFO_TIME_STAMP_1 0x250
|
||||
+#define AIFIFO_TIME_STAMP_2 0x254
|
||||
+#define AIFIFO_TIME_STAMP_3 0x258
|
||||
+#define AIFIFO_TIME_STAMP_LENGTH 0x25C
|
||||
+#define AIFIFO2_TIME_STAMP_CNTL 0x260
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_0 0x264
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_1 0x268
|
||||
+#define AIFIFO2_TIME_STAMP_0 0x26C
|
||||
+#define AIFIFO2_TIME_STAMP_1 0x270
|
||||
+#define AIFIFO2_TIME_STAMP_2 0x274
|
||||
+#define AIFIFO2_TIME_STAMP_3 0x278
|
||||
+#define AIFIFO2_TIME_STAMP_LENGTH 0x27C
|
||||
+#define IEC958_TIME_STAMP_CNTL 0x280
|
||||
+#define IEC958_TIME_STAMP_SYNC_0 0x284
|
||||
+#define IEC958_TIME_STAMP_SYNC_1 0x288
|
||||
+#define IEC958_TIME_STAMP_0 0x28C
|
||||
+#define IEC958_TIME_STAMP_1 0x290
|
||||
+#define IEC958_TIME_STAMP_2 0x294
|
||||
+#define IEC958_TIME_STAMP_3 0x298
|
||||
+#define IEC958_TIME_STAMP_LENGTH 0x29C
|
||||
+#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0
|
||||
+#define AIU_I2S_CBUS_DDR_CNTL 0x2A4
|
||||
+#define AIU_I2S_CBUS_DDR_WDATA 0x2A8
|
||||
+#define AIU_I2S_CBUS_DDR_ADDR 0x2AC
|
||||
+
|
||||
+#endif /* _AIU_REGS_H_ */
|
||||
diff --git a/sound/soc/meson/audin-regs.h b/sound/soc/meson/audin-regs.h
|
||||
new file mode 100644
|
||||
index 000000000000..f224610e80e7
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/audin-regs.h
|
||||
@@ -0,0 +1,148 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _AUDIN_REGS_H_
|
||||
+#define _AUDIN_REGS_H_
|
||||
+
|
||||
+/*
|
||||
+ * Note :
|
||||
+ * Datasheet issue page 196
|
||||
+ * AUDIN_MUTE_VAL 0x35 => impossible: Already assigned to AUDIN_FIFO1_PTR
|
||||
+ * AUDIN_FIFO1_PTR is more likely to be correct here since surrounding registers
|
||||
+ * also deal with AUDIN_FIFO1
|
||||
+ *
|
||||
+ * Clarification needed from Amlogic
|
||||
+ */
|
||||
+
|
||||
+#define AUDIN_SPDIF_MODE 0x000
|
||||
+#define AUDIN_SPDIF_FS_CLK_RLTN 0x004
|
||||
+#define AUDIN_SPDIF_CHNL_STS_A 0x008
|
||||
+#define AUDIN_SPDIF_CHNL_STS_B 0x00C
|
||||
+#define AUDIN_SPDIF_MISC 0x010
|
||||
+#define AUDIN_SPDIF_NPCM_PCPD 0x014
|
||||
+#define AUDIN_SPDIF_END 0x03C /* Unknown */
|
||||
+#define AUDIN_I2SIN_CTRL 0x040
|
||||
+#define AUDIN_SOURCE_SEL 0x044
|
||||
+#define AUDIN_DECODE_FORMAT 0x048
|
||||
+#define AUDIN_DECODE_CONTROL_STATUS 0x04C
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_0 0x050
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_1 0x054
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_2 0x058
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_3 0x05C
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_4 0x060
|
||||
+#define AUDIN_DECODE_CHANNEL_STATUS_A_5 0x064
|
||||
+#define AUDIN_FIFO0_START 0x080
|
||||
+#define AUDIN_FIFO0_END 0x084
|
||||
+#define AUDIN_FIFO0_PTR 0x088
|
||||
+#define AUDIN_FIFO0_INTR 0x08C
|
||||
+#define AUDIN_FIFO0_RDPTR 0x090
|
||||
+#define AUDIN_FIFO0_CTRL 0x094
|
||||
+#define AUDIN_FIFO0_CTRL1 0x098
|
||||
+#define AUDIN_FIFO0_LVL0 0x09C
|
||||
+#define AUDIN_FIFO0_LVL1 0x0A0
|
||||
+#define AUDIN_FIFO0_LVL2 0x0A4
|
||||
+#define AUDIN_FIFO0_REQID 0x0C0
|
||||
+#define AUDIN_FIFO0_WRAP 0x0C4
|
||||
+#define AUDIN_FIFO1_START 0x0CC
|
||||
+#define AUDIN_FIFO1_END 0x0D0
|
||||
+#define AUDIN_FIFO1_PTR 0x0D4
|
||||
+#define AUDIN_FIFO1_INTR 0x0D8
|
||||
+#define AUDIN_FIFO1_RDPTR 0x0DC
|
||||
+#define AUDIN_FIFO1_CTRL 0x0E0
|
||||
+#define AUDIN_FIFO1_CTRL1 0x0E4
|
||||
+#define AUDIN_FIFO1_LVL0 0x100
|
||||
+#define AUDIN_FIFO1_LVL1 0x104
|
||||
+#define AUDIN_FIFO1_LVL2 0x108
|
||||
+#define AUDIN_FIFO1_REQID 0x10C
|
||||
+#define AUDIN_FIFO1_WRAP 0x110
|
||||
+#define AUDIN_FIFO2_START 0x114
|
||||
+#define AUDIN_FIFO2_END 0x118
|
||||
+#define AUDIN_FIFO2_PTR 0x11C
|
||||
+#define AUDIN_FIFO2_INTR 0x120
|
||||
+#define AUDIN_FIFO2_RDPTR 0x124
|
||||
+#define AUDIN_FIFO2_CTRL 0x128
|
||||
+#define AUDIN_FIFO2_CTRL1 0x12C
|
||||
+#define AUDIN_FIFO2_LVL0 0x130
|
||||
+#define AUDIN_FIFO2_LVL1 0x134
|
||||
+#define AUDIN_FIFO2_LVL2 0x138
|
||||
+#define AUDIN_FIFO2_REQID 0x13C
|
||||
+#define AUDIN_FIFO2_WRAP 0x140
|
||||
+#define AUDIN_INT_CTRL 0x144
|
||||
+#define AUDIN_FIFO_INT 0x148
|
||||
+#define PCMIN_CTRL0 0x180
|
||||
+#define PCMIN_CTRL1 0x184
|
||||
+#define PCMIN1_CTRL0 0x188
|
||||
+#define PCMIN1_CTRL1 0x18C
|
||||
+#define PCMOUT_CTRL0 0x1C0
|
||||
+#define PCMOUT_CTRL1 0x1C4
|
||||
+#define PCMOUT_CTRL2 0x1C8
|
||||
+#define PCMOUT_CTRL3 0x1CC
|
||||
+#define PCMOUT1_CTRL0 0x1D0
|
||||
+#define PCMOUT1_CTRL1 0x1D4
|
||||
+#define PCMOUT1_CTRL2 0x1D8
|
||||
+#define PCMOUT1_CTRL3 0x1DC
|
||||
+#define AUDOUT_CTRL 0x200
|
||||
+#define AUDOUT_CTRL1 0x204
|
||||
+#define AUDOUT_BUF0_STA 0x208
|
||||
+#define AUDOUT_BUF0_EDA 0x20C
|
||||
+#define AUDOUT_BUF0_WPTR 0x210
|
||||
+#define AUDOUT_BUF1_STA 0x214
|
||||
+#define AUDOUT_BUF1_EDA 0x218
|
||||
+#define AUDOUT_BUF1_WPTR 0x21C
|
||||
+#define AUDOUT_FIFO_RPTR 0x220
|
||||
+#define AUDOUT_INTR_PTR 0x224
|
||||
+#define AUDOUT_FIFO_STS 0x228
|
||||
+#define AUDOUT1_CTRL 0x240
|
||||
+#define AUDOUT1_CTRL1 0x244
|
||||
+#define AUDOUT1_BUF0_STA 0x248
|
||||
+#define AUDOUT1_BUF0_EDA 0x24C
|
||||
+#define AUDOUT1_BUF0_WPTR 0x250
|
||||
+#define AUDOUT1_BUF1_STA 0x254
|
||||
+#define AUDOUT1_BUF1_EDA 0x258
|
||||
+#define AUDOUT1_BUF1_WPTR 0x25C
|
||||
+#define AUDOUT1_FIFO_RPTR 0x260
|
||||
+#define AUDOUT1_INTR_PTR 0x264
|
||||
+#define AUDOUT1_FIFO_STS 0x268
|
||||
+#define AUDIN_HDMI_MEAS_CTRL 0x280
|
||||
+#define AUDIN_HDMI_MEAS_CYCLES_M1 0x284
|
||||
+#define AUDIN_HDMI_MEAS_INTR_MASKN 0x288
|
||||
+#define AUDIN_HDMI_MEAS_INTR_STAT 0x28C
|
||||
+#define AUDIN_HDMI_REF_CYCLES_STAT_0 0x290
|
||||
+#define AUDIN_HDMI_REF_CYCLES_STAT_1 0x294
|
||||
+#define AUDIN_HDMIRX_AFIFO_STAT 0x298
|
||||
+#define AUDIN_FIFO0_PIO_STS 0x2C0
|
||||
+#define AUDIN_FIFO0_PIO_RDL 0x2C4
|
||||
+#define AUDIN_FIFO0_PIO_RDH 0x2C8
|
||||
+#define AUDIN_FIFO1_PIO_STS 0x2CC
|
||||
+#define AUDIN_FIFO1_PIO_RDL 0x2D0
|
||||
+#define AUDIN_FIFO1_PIO_RDH 0x2D4
|
||||
+#define AUDIN_FIFO2_PIO_STS 0x2D8
|
||||
+#define AUDIN_FIFO2_PIO_RDL 0x2DC
|
||||
+#define AUDIN_FIFO2_PIO_RDH 0x2E0
|
||||
+#define AUDOUT_FIFO_PIO_STS 0x2E4
|
||||
+#define AUDOUT_FIFO_PIO_WRL 0x2E8
|
||||
+#define AUDOUT_FIFO_PIO_WRH 0x2EC
|
||||
+#define AUDOUT1_FIFO_PIO_STS 0x2F0 /* Unknown */
|
||||
+#define AUDOUT1_FIFO_PIO_WRL 0x2F4 /* Unknown */
|
||||
+#define AUDOUT1_FIFO_PIO_WRH 0x2F8 /* Unknown */
|
||||
+#define AUD_RESAMPLE_CTRL0 0x2FC
|
||||
+#define AUD_RESAMPLE_CTRL1 0x300
|
||||
+#define AUD_RESAMPLE_STATUS 0x304
|
||||
+
|
||||
+#endif /* _AUDIN_REGS_H_ */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,424 @@
|
||||
From 61d387ffa57865531ead1a33d63b1d53a99e808b Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:14:40 +0200
|
||||
Subject: [PATCH 04/53] 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 | 4 +-
|
||||
sound/soc/meson/aiu-i2s-dma.c | 370 ++++++++++++++++++++++++++++++++++
|
||||
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 ed432d488b74..6e030b5c7804 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -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.
|
||||
+
|
||||
+config SND_SOC_MESON_I2S
|
||||
+ tristate "Meson i2s interface"
|
||||
+ depends on SND_SOC_MESON
|
||||
+ help
|
||||
+ 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 768d7c414649..57960077aab2 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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
|
||||
\ 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 000000000000..2684bd0db19e
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-i2s-dma.c
|
||||
@@ -0,0 +1,370 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-aiu-i2s-dma"
|
||||
+
|
||||
+struct aiu_i2s_dma {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *fast;
|
||||
+ int irq;
|
||||
+};
|
||||
+
|
||||
+#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1)
|
||||
+#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2)
|
||||
+#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
|
||||
+#define AIU_MEM_I2S_CONTROL_BUSY BIT(7)
|
||||
+#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8)
|
||||
+#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0)
|
||||
+#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0)
|
||||
+#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1)
|
||||
+
|
||||
+/*
|
||||
+ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory
|
||||
+ * layout expected depends on the mode of operation.
|
||||
+ *
|
||||
+ * - Normal mode: The channels are expected to be packed in 32 bytes groups
|
||||
+ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing
|
||||
+ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the
|
||||
+ * channels read by the DMA. This is very flexible but the unsual memory layout
|
||||
+ * makes it less easy to deal with. The burst size is 32 bytes times the number
|
||||
+ * of channels read.
|
||||
+ *
|
||||
+ * - Split mode:
|
||||
+ * Classical channel interleaved frame organisation. In this mode,
|
||||
+ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and
|
||||
+ * the burst size is fixed to 256 bytes. The input can be either 2 or 8
|
||||
+ * channels.
|
||||
+ *
|
||||
+ * The following driver implements the split mode.
|
||||
+ */
|
||||
+
|
||||
+#define AIU_I2S_DMA_BURST 256
|
||||
+
|
||||
+static struct snd_pcm_hardware aiu_i2s_dma_hw = {
|
||||
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE),
|
||||
+
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE),
|
||||
+
|
||||
+ /*
|
||||
+ * TODO: The DMA can change the endianness, the msb position
|
||||
+ * and deal with unsigned - support this later on
|
||||
+ */
|
||||
+
|
||||
+ .rate_min = 8000,
|
||||
+ .rate_max = 192000,
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 8,
|
||||
+ .period_bytes_min = AIU_I2S_DMA_BURST,
|
||||
+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = UINT_MAX,
|
||||
+ .buffer_bytes_max = 1 * 1024 * 1024,
|
||||
+ .fifo_size = 0,
|
||||
+};
|
||||
+
|
||||
+static struct aiu_i2s_dma *aiu_i2s_dma_priv(struct snd_pcm_substream *s)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = s->private_data;
|
||||
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
+
|
||||
+ return snd_soc_component_get_drvdata(component);
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t
|
||||
+aiu_i2s_dma_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ unsigned int addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR,
|
||||
+ &addr);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
+}
|
||||
+
|
||||
+static void __dma_enable(struct aiu_i2s_dma *priv, bool enable)
|
||||
+{
|
||||
+ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN |
|
||||
+ AIU_MEM_I2S_CONTROL_EMPTY_EN);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask,
|
||||
+ enable ? en_mask : 0);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __dma_enable(priv, true);
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ __dma_enable(priv, false);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __dma_init_mem(struct aiu_i2s_dma *priv)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ 0);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ __dma_init_mem(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+ u32 burst_num, mem_ctl;
|
||||
+ dma_addr_t end_ptr;
|
||||
+
|
||||
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Setup memory layout */
|
||||
+ if (params_physical_width(params) == 16)
|
||||
+ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT;
|
||||
+ else
|
||||
+ mem_ctl = 0;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_MODE_16BIT,
|
||||
+ mem_ctl);
|
||||
+
|
||||
+ /* Initialize memory pointers */
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr);
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr);
|
||||
+
|
||||
+ /* The end pointer is the address of the last valid block */
|
||||
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr);
|
||||
+
|
||||
+ /* Memory masks */
|
||||
+ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS,
|
||||
+ AIU_MEM_I2S_MASKS_CH_RD(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_CH_MEM(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static irqreturn_t aiu_i2s_dma_irq_block(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct snd_pcm_substream *playback = dev_id;
|
||||
+
|
||||
+ snd_pcm_period_elapsed(playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_soc_set_runtime_hwparams(substream, &aiu_i2s_dma_hw);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the buffer and period size are multiple of the DMA burst
|
||||
+ * size
|
||||
+ */
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request the I2S DDR irq */
|
||||
+ ret = request_irq(priv->irq, aiu_i2s_dma_irq_block, 0,
|
||||
+ DRV_NAME, substream);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Power up the i2s fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Make sure the dma is initially disabled */
|
||||
+ __dma_enable(priv, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+ free_irq(priv->irq, substream);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_pcm_ops aiu_i2s_dma_ops = {
|
||||
+ .open = aiu_i2s_dma_open,
|
||||
+ .close = aiu_i2s_dma_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = aiu_i2s_dma_hw_params,
|
||||
+ .hw_free = aiu_i2s_dma_hw_free,
|
||||
+ .prepare = aiu_i2s_dma_prepare,
|
||||
+ .pointer = aiu_i2s_dma_pointer,
|
||||
+ .trigger = aiu_i2s_dma_trigger,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_card *card = rtd->card->snd_card;
|
||||
+ size_t size = aiu_i2s_dma_hw.buffer_bytes_max;
|
||||
+
|
||||
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
+ SNDRV_DMA_TYPE_DEV,
|
||||
+ card->dev, size, size);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_i2s_platform = {
|
||||
+ .ops = &aiu_i2s_dma_ops,
|
||||
+ .pcm_new = aiu_i2s_dma_new,
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct aiu_i2s_dma *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get i2s fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq <= 0) {
|
||||
+ dev_err(dev, "Can't get i2s ddr irq\n");
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &aiu_i2s_platform,
|
||||
+ NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id aiu_i2s_dma_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxl-aiu-i2s-dma", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, aiu_i2s_dma_of_match);
|
||||
+
|
||||
+static struct platform_driver aiu_i2s_dma_pdrv = {
|
||||
+ .probe = aiu_i2s_dma_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = aiu_i2s_dma_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(aiu_i2s_dma_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson AIU i2s DMA ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,518 @@
|
||||
From 91eb80de0a4425e8856484d6480b2e347ccfa83d Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:17:27 +0200
|
||||
Subject: [PATCH 05/53] ASoC: meson: add initial i2s dai support
|
||||
|
||||
Add support for the i2s dai found on Amlogic Meson SoC family.
|
||||
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 | 4 +-
|
||||
sound/soc/meson/i2s-dai.c | 465 ++++++++++++++++++++++++++++++++++++++
|
||||
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 6e030b5c7804..5904e9e50569 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -78,5 +78,5 @@ config SND_SOC_MESON_I2S
|
||||
tristate "Meson i2s interface"
|
||||
depends on SND_SOC_MESON
|
||||
help
|
||||
- Say Y or M if you want to add support for i2s dma driver for Amlogic
|
||||
+ 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 57960077aab2..b8641f9f7fc1 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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
|
||||
\ 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 000000000000..1008af8d3972
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -0,0 +1,465 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-i2s-dai"
|
||||
+
|
||||
+struct meson_i2s_dai {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *mclk;
|
||||
+ struct clk *bclks;
|
||||
+ struct clk *iface;
|
||||
+ struct clk *fast;
|
||||
+ bool bclks_idle;
|
||||
+};
|
||||
+
|
||||
+#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0)
|
||||
+#define AIU_CLK_CTRL_I2S_DIV_MASK GENMASK(3, 2)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_MASK BIT(6)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL (0 << 6)
|
||||
+#define AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED (1 << 6)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_MASK BIT(7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL (0 << 7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED (1 << 7)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_SKEW_MASK GENMASK(9, 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_LEFT_J (0 << 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_I2S (1 << 8)
|
||||
+#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8)
|
||||
+#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0)
|
||||
+#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0)
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0)
|
||||
+#define AIU_I2S_DAC_CFG_AOCLK_64 (3 << 0)
|
||||
+#define AIU_I2S_MISC_HOLD_EN BIT(2)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9)
|
||||
+#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11)
|
||||
+
|
||||
+static void __hold(struct meson_i2s_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC,
|
||||
+ AIU_I2S_MISC_HOLD_EN,
|
||||
+ enable ? AIU_I2S_MISC_HOLD_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __divider_enable(struct meson_i2s_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_I2S_DIV_EN,
|
||||
+ enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __playback_start(struct meson_i2s_dai *priv)
|
||||
+{
|
||||
+ __divider_enable(priv, true);
|
||||
+ __hold(priv, false);
|
||||
+}
|
||||
+
|
||||
+static void __playback_stop(struct meson_i2s_dai *priv, bool clk_force)
|
||||
+{
|
||||
+ __hold(priv, true);
|
||||
+ /* Disable the bit clks if necessary */
|
||||
+ if (clk_force || !priv->bclks_idle)
|
||||
+ __divider_enable(priv, false);
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ bool clk_force_stop = false;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __playback_start(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ clk_force_stop = true;
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ __playback_stop(priv, clk_force_stop);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int __bclks_set_rate(struct meson_i2s_dai *priv, unsigned int srate,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ unsigned int fs;
|
||||
+
|
||||
+ /* Get the oversampling factor */
|
||||
+ fs = DIV_ROUND_CLOSEST(clk_get_rate(priv->mclk), srate);
|
||||
+
|
||||
+ /*
|
||||
+ * This DAI is usually connected to the dw-hdmi which does not support
|
||||
+ * bclk being 32 * lrclk or 48 * lrclk
|
||||
+ * Restrict to blck = 64 * lrclk
|
||||
+ */
|
||||
+ if (fs % 64)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Set the divider between lrclk and bclk */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_DAC_CFG,
|
||||
+ AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK,
|
||||
+ AIU_I2S_DAC_CFG_AOCLK_64);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CODEC_DAC_LRCLK_CTRL,
|
||||
+ AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK,
|
||||
+ AIU_CODEC_DAC_LRCLK_CTRL_DIV(64));
|
||||
+
|
||||
+ /* Use CLK_MORE for the i2s divider */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_I2S_DIV_MASK,
|
||||
+ 0);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE,
|
||||
+ AIU_CLK_CTRL_MORE_I2S_DIV_MASK,
|
||||
+ AIU_CLK_CTRL_MORE_I2S_DIV(fs / 64));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_desc(struct meson_i2s_dai *priv, unsigned int width,
|
||||
+ unsigned int channels)
|
||||
+{
|
||||
+ u32 desc = 0;
|
||||
+
|
||||
+ switch (width) {
|
||||
+ case 24:
|
||||
+ /*
|
||||
+ * For some reason, 24 bits wide audio don't play well
|
||||
+ * if the 32 bits mode is not set
|
||||
+ */
|
||||
+ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_32BIT);
|
||||
+ break;
|
||||
+ case 16:
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (channels) {
|
||||
+ case 2: /* Nothing to do */
|
||||
+ break;
|
||||
+ case 8:
|
||||
+ /* TODO: Still requires testing ... */
|
||||
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_32BIT,
|
||||
+ desc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ unsigned int width = params_width(params);
|
||||
+ unsigned int channels = params_channels(params);
|
||||
+ unsigned int rate = params_rate(params);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __setup_desc(priv, width, channels);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable set to set i2s description\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __bclks_set_rate(priv, rate, width);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable set to the i2s clock rates\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ u32 val;
|
||||
+
|
||||
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* DAI output mode */
|
||||
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
+ case SND_SOC_DAIFMT_I2S:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_I2S;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_LEFT_J:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_LEFT_J;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_RIGHT_J:
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_RIGHT_J;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_ALRCLK_SKEW_MASK,
|
||||
+ val);
|
||||
+
|
||||
+ /* DAI clock polarity */
|
||||
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
+ case SND_SOC_DAIFMT_IB_IF:
|
||||
+ /* Invert both clocks */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_IB_NF:
|
||||
+ /* Invert bit clock */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_NB_IF:
|
||||
+ /* Invert frame clock */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_NB_NF:
|
||||
+ /* Normal clocks */
|
||||
+ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_ALRCLK_POLARITY_MASK |
|
||||
+ AIU_CLK_CTRL_AOCLK_POLARITY_MASK,
|
||||
+ val);
|
||||
+
|
||||
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
|
||||
+ case SND_SOC_DAIFMT_CONT:
|
||||
+ priv->bclks_idle = true;
|
||||
+ break;
|
||||
+ case SND_SOC_DAIFMT_GATED:
|
||||
+ priv->bclks_idle = false;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
||||
+ unsigned int freq, int dir)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ if (WARN_ON(clk_id != 0))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (dir == SND_SOC_CLOCK_IN)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = clk_set_rate(priv->mclk, freq);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Failed to set sysclk to %uHz", freq);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_i2s_dai_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Power up the i2s fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ goto out_clk_fast;
|
||||
+
|
||||
+ /* Make sure nothing gets out of the DAI yet */
|
||||
+ __hold(priv, true);
|
||||
+
|
||||
+ /* I2S encoder needs the mixer interface gate */
|
||||
+ ret = clk_prepare_enable(priv->iface);
|
||||
+ if (ret)
|
||||
+ goto out_clk_iface;
|
||||
+
|
||||
+ /* Enable the i2s master clock */
|
||||
+ ret = clk_prepare_enable(priv->mclk);
|
||||
+ if (ret)
|
||||
+ goto out_mclk;
|
||||
+
|
||||
+ /* Enable the bit clock gate */
|
||||
+ ret = clk_prepare_enable(priv->bclks);
|
||||
+ if (ret)
|
||||
+ goto out_bclks;
|
||||
+
|
||||
+ /* Make sure the interface expect a memory layout we can work with */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
|
||||
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_bclks:
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+out_mclk:
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+out_clk_iface:
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+out_clk_fast:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void meson_i2s_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->bclks);
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops meson_i2s_dai_ops = {
|
||||
+ .startup = meson_i2s_dai_startup,
|
||||
+ .shutdown = meson_i2s_dai_shutdown,
|
||||
+ .trigger = meson_i2s_dai_trigger,
|
||||
+ .hw_params = meson_i2s_dai_hw_params,
|
||||
+ .set_fmt = meson_i2s_dai_set_fmt,
|
||||
+ .set_sysclk = meson_i2s_dai_set_sysclk,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver meson_i2s_dai = {
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 8,
|
||||
+ .rates = SNDRV_PCM_RATE_8000_192000,
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE)
|
||||
+ },
|
||||
+ .ops = &meson_i2s_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver meson_i2s_dai_component = {
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int meson_i2s_dai_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_i2s_dai *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the i2s fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->iface = devm_clk_get(dev, "iface");
|
||||
+ if (IS_ERR(priv->iface)) {
|
||||
+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get i2s dai clock gate\n");
|
||||
+ return PTR_ERR(priv->iface);
|
||||
+ }
|
||||
+
|
||||
+ priv->bclks = devm_clk_get(dev, "bclks");
|
||||
+ if (IS_ERR(priv->bclks)) {
|
||||
+ if (PTR_ERR(priv->bclks) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get bit clocks gate\n");
|
||||
+ return PTR_ERR(priv->bclks);
|
||||
+ }
|
||||
+
|
||||
+ priv->mclk = devm_clk_get(dev, "mclk");
|
||||
+ if (IS_ERR(priv->mclk)) {
|
||||
+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "failed to get the i2s master clock\n");
|
||||
+ return PTR_ERR(priv->mclk);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &meson_i2s_dai_component,
|
||||
+ &meson_i2s_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_i2s_dai_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-i2s-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-i2s-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxl-i2s-dai", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_i2s_dai_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_i2s_dai_pdrv = {
|
||||
+ .probe = meson_i2s_dai_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_i2s_dai_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_i2s_dai_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson i2s DAI ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,445 @@
|
||||
From 99e6d5ba97d0615428f88850ee8366a9dc24168e Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 13:43:52 +0200
|
||||
Subject: [PATCH 06/53] 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 | 4 +-
|
||||
sound/soc/meson/aiu-spdif-dma.c | 388 ++++++++++++++++++++++++++++++++
|
||||
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 5904e9e50569..712303ff8970 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -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.
|
||||
+
|
||||
+config SND_SOC_MESON_SPDIF
|
||||
+ tristate "Meson spdif interface"
|
||||
+ depends on SND_SOC_MESON
|
||||
+ help
|
||||
+ 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 b8641f9f7fc1..dc5164a7e164 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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
|
||||
\ 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 000000000000..81c3b856fbf9
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-spdif-dma.c
|
||||
@@ -0,0 +1,388 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-aiu-spdif-dma"
|
||||
+
|
||||
+struct aiu_spdif_dma {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *fast;
|
||||
+ int irq;
|
||||
+};
|
||||
+
|
||||
+#define AIU_958_DCU_FF_CTRL_EN BIT(0)
|
||||
+#define AIU_958_DCU_FF_CTRL_AUTO_DISABLE BIT(1)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK GENMASK(3, 2)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2)
|
||||
+#define AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3)
|
||||
+#define AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4)
|
||||
+#define AIU_958_DCU_FF_CTRL_BYTE_SEEK BIT(5)
|
||||
+#define AIU_958_DCU_FF_CTRL_CONTINUE BIT(6)
|
||||
+#define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0)
|
||||
+#define AIU_MEM_IEC958_CONTROL_INIT BIT(0)
|
||||
+#define AIU_MEM_IEC958_CONTROL_FILL_EN BIT(1)
|
||||
+#define AIU_MEM_IEC958_CONTROL_EMPTY_EN BIT(2)
|
||||
+#define AIU_MEM_IEC958_CONTROL_ENDIAN_MASK GENMASK(5, 3)
|
||||
+#define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6)
|
||||
+#define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_MEM_MASK GENMASK(15, 8)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_MEM(ch) ((ch) << 8)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_RD_MASK GENMASK(7, 0)
|
||||
+#define AIU_MEM_IEC958_MASKS_CH_RD(ch) ((ch) << 0)
|
||||
+
|
||||
+#define AIU_SPDIF_DMA_BURST 8
|
||||
+#define AIU_SPDIF_BPF_MAX USHRT_MAX
|
||||
+
|
||||
+static struct snd_pcm_hardware aiu_spdif_dma_hw = {
|
||||
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE),
|
||||
+
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE),
|
||||
+
|
||||
+ .rates = (SNDRV_PCM_RATE_32000 |
|
||||
+ SNDRV_PCM_RATE_44100 |
|
||||
+ SNDRV_PCM_RATE_48000 |
|
||||
+ SNDRV_PCM_RATE_96000 |
|
||||
+ SNDRV_PCM_RATE_192000),
|
||||
+ /*
|
||||
+ * TODO: The DMA can change the endianness, the msb position
|
||||
+ * and deal with unsigned - support this later on
|
||||
+ */
|
||||
+
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .period_bytes_min = AIU_SPDIF_DMA_BURST,
|
||||
+ .period_bytes_max = AIU_SPDIF_BPF_MAX,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = UINT_MAX,
|
||||
+ .buffer_bytes_max = 1 * 1024 * 1024,
|
||||
+ .fifo_size = 0,
|
||||
+};
|
||||
+
|
||||
+static struct aiu_spdif_dma *aiu_spdif_dma_priv(struct snd_pcm_substream *s)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = s->private_data;
|
||||
+ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
|
||||
+
|
||||
+ return snd_soc_component_get_drvdata(component);
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t
|
||||
+aiu_spdif_dma_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ unsigned int addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->core->aiu, AIU_MEM_IEC958_RD_PTR,
|
||||
+ &addr);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
+}
|
||||
+
|
||||
+static void __dma_enable(struct aiu_spdif_dma *priv, bool enable)
|
||||
+{
|
||||
+ unsigned int en_mask = (AIU_MEM_IEC958_CONTROL_FILL_EN |
|
||||
+ AIU_MEM_IEC958_CONTROL_EMPTY_EN);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, en_mask,
|
||||
+ enable ? en_mask : 0);
|
||||
+}
|
||||
+
|
||||
+static void __dcu_fifo_enable(struct aiu_spdif_dma *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL,
|
||||
+ AIU_958_DCU_FF_CTRL_EN,
|
||||
+ enable ? AIU_958_DCU_FF_CTRL_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __dcu_fifo_enable(priv, true);
|
||||
+ __dma_enable(priv, true);
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ __dma_enable(priv, false);
|
||||
+ __dcu_fifo_enable(priv, false);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __dma_init_mem(struct aiu_spdif_dma *priv)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_INIT,
|
||||
+ 0);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL,
|
||||
+ AIU_MEM_IEC958_BUF_CNTL_INIT,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ __dma_init_mem(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_memory_layout(struct aiu_spdif_dma *priv,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ u32 mem_ctl = AIU_MEM_IEC958_CONTROL_RD_DDR;
|
||||
+
|
||||
+ if (width == 16)
|
||||
+ mem_ctl |= AIU_MEM_IEC958_CONTROL_MODE_16BIT;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_ENDIAN_MASK |
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_16BIT |
|
||||
+ AIU_MEM_IEC958_CONTROL_RD_DDR,
|
||||
+ mem_ctl);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ int ret;
|
||||
+ dma_addr_t end_ptr;
|
||||
+
|
||||
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = __setup_memory_layout(priv, params_physical_width(params));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Initialize memory pointers */
|
||||
+ regmap_write(priv->core->aiu,
|
||||
+ AIU_MEM_IEC958_START_PTR, runtime->dma_addr);
|
||||
+ regmap_write(priv->core->aiu,
|
||||
+ AIU_MEM_IEC958_RD_PTR, runtime->dma_addr);
|
||||
+
|
||||
+ /* The end pointer is the address of the last valid block */
|
||||
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_SPDIF_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_END_PTR, end_ptr);
|
||||
+
|
||||
+ /* Memory masks */
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_IEC958_MASKS,
|
||||
+ AIU_MEM_IEC958_MASKS_CH_RD(0xff) |
|
||||
+ AIU_MEM_IEC958_MASKS_CH_MEM(0xff));
|
||||
+
|
||||
+ /* Setup the number bytes read by the FIFO between each IRQ */
|
||||
+ regmap_write(priv->core->aiu, AIU_958_BPF, params_period_bytes(params));
|
||||
+
|
||||
+ /*
|
||||
+ * AUTO_DISABLE and SYNC_HEAD are enabled by default but
|
||||
+ * this should be disabled in PCM (uncompressed) mode
|
||||
+ */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL,
|
||||
+ AIU_958_DCU_FF_CTRL_AUTO_DISABLE |
|
||||
+ AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK |
|
||||
+ AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN,
|
||||
+ AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t aiu_spdif_dma_irq(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct snd_pcm_substream *playback = dev_id;
|
||||
+
|
||||
+ snd_pcm_period_elapsed(playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_soc_set_runtime_hwparams(substream, &aiu_spdif_dma_hw);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the buffer and period size are multiple of the DMA burst
|
||||
+ * size
|
||||
+ */
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
+ AIU_SPDIF_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
+ AIU_SPDIF_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request the SPDIF DDR irq */
|
||||
+ ret = request_irq(priv->irq, aiu_spdif_dma_irq, 0,
|
||||
+ DRV_NAME, substream);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Power up the spdif fast domain - can't write the register w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Make sure the dma is initially halted */
|
||||
+ __dma_enable(priv, false);
|
||||
+ __dcu_fifo_enable(priv, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_spdif_dma_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_spdif_dma *priv = aiu_spdif_dma_priv(substream);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+ free_irq(priv->irq, substream);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_pcm_ops aiu_spdif_dma_ops = {
|
||||
+ .open = aiu_spdif_dma_open,
|
||||
+ .close = aiu_spdif_dma_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = aiu_spdif_dma_hw_params,
|
||||
+ .hw_free = aiu_spdif_dma_hw_free,
|
||||
+ .prepare = aiu_spdif_dma_prepare,
|
||||
+ .pointer = aiu_spdif_dma_pointer,
|
||||
+ .trigger = aiu_spdif_dma_trigger,
|
||||
+};
|
||||
+
|
||||
+static int aiu_spdif_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_card *card = rtd->card->snd_card;
|
||||
+ size_t size = aiu_spdif_dma_hw.buffer_bytes_max;
|
||||
+
|
||||
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
+ SNDRV_DMA_TYPE_DEV,
|
||||
+ card->dev, size, size);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_component_driver aiu_spdif_platform = {
|
||||
+ .ops = &aiu_spdif_dma_ops,
|
||||
+ .pcm_new = aiu_spdif_dma_new,
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int aiu_spdif_dma_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct aiu_spdif_dma *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get spdif fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq <= 0) {
|
||||
+ dev_err(dev, "Can't get spdif ddr irq\n");
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &aiu_spdif_platform,
|
||||
+ NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id aiu_spdif_dma_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-aiu-spdif-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-aiu-spdif-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxl-aiu-spdif-dma", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, aiu_spdif_dma_of_match);
|
||||
+
|
||||
+static struct platform_driver aiu_spdif_dma_pdrv = {
|
||||
+ .probe = aiu_spdif_dma_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = aiu_spdif_dma_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(aiu_spdif_dma_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson AIU spdif DMA ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,432 @@
|
||||
From ecabfe253aab181bdc241cc7e16e857a3574e528 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 13:46:03 +0200
|
||||
Subject: [PATCH 07/53] ASoC: meson: add initial spdif dai support
|
||||
|
||||
Add support for the spdif dai found on Amlogic Meson SoC family.
|
||||
With this initial implementation, only uncompressed pcm playback
|
||||
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 | 4 +-
|
||||
sound/soc/meson/spdif-dai.c | 374 ++++++++++++++++++++++++++++++++++++
|
||||
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 712303ff8970..bc3d6f22ed88 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -84,6 +84,7 @@ config SND_SOC_MESON_I2S
|
||||
config SND_SOC_MESON_SPDIF
|
||||
tristate "Meson spdif interface"
|
||||
depends on SND_SOC_MESON
|
||||
+ select SND_PCM_IEC958
|
||||
help
|
||||
- Say Y or M if you want to add support for spdif dma driver for Amlogic
|
||||
+ 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 dc5164a7e164..44f79d8b91b7 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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
|
||||
\ 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 000000000000..e7630007c84b
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/spdif-dai.c
|
||||
@@ -0,0 +1,374 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * 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/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+#include <sound/soc-dai.h>
|
||||
+#include <sound/pcm_iec958.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-spdif-dai"
|
||||
+
|
||||
+struct meson_spdif_dai {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *iface;
|
||||
+ struct clk *fast;
|
||||
+ struct clk *mclk_i958;
|
||||
+ struct clk *mclk;
|
||||
+};
|
||||
+
|
||||
+#define AIU_CLK_CTRL_958_DIV_EN BIT(1)
|
||||
+#define AIU_CLK_CTRL_958_DIV_MASK GENMASK(5, 4)
|
||||
+#define AIU_CLK_CTRL_958_DIV_MORE BIT(12)
|
||||
+#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8)
|
||||
+#define AIU_958_CTRL_HOLD_EN BIT(0)
|
||||
+#define AIU_958_MISC_NON_PCM BIT(0)
|
||||
+#define AIU_958_MISC_MODE_16BITS BIT(1)
|
||||
+#define AIU_958_MISC_16BITS_ALIGN_MASK GENMASK(6, 5)
|
||||
+#define AIU_958_MISC_16BITS_ALIGN(val) ((val) << 5)
|
||||
+#define AIU_958_MISC_MODE_32BITS BIT(7)
|
||||
+#define AIU_958_MISC_32BITS_SHIFT_MASK GENMASK(10, 8)
|
||||
+#define AIU_958_MISC_32BITS_SHIFT(val) ((val) << 8)
|
||||
+#define AIU_958_MISC_U_FROM_STREAM BIT(12)
|
||||
+#define AIU_958_MISC_FORCE_LR BIT(13)
|
||||
+
|
||||
+#define AIU_CS_WORD_LEN 4
|
||||
+
|
||||
+static void __hold(struct meson_spdif_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_CTRL,
|
||||
+ AIU_958_CTRL_HOLD_EN,
|
||||
+ enable ? AIU_958_CTRL_HOLD_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __divider_enable(struct meson_spdif_dai *priv, bool enable)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_958_DIV_EN,
|
||||
+ enable ? AIU_CLK_CTRL_958_DIV_EN : 0);
|
||||
+}
|
||||
+
|
||||
+static void __playback_start(struct meson_spdif_dai *priv)
|
||||
+{
|
||||
+ __divider_enable(priv, true);
|
||||
+ __hold(priv, false);
|
||||
+}
|
||||
+
|
||||
+static void __playback_stop(struct meson_spdif_dai *priv)
|
||||
+{
|
||||
+ __hold(priv, true);
|
||||
+ __divider_enable(priv, false);
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __playback_start(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ __playback_stop(priv);
|
||||
+ return 0;
|
||||
+
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int __setup_spdif_clk(struct meson_spdif_dai *priv, unsigned int rate)
|
||||
+{
|
||||
+ unsigned int mrate;
|
||||
+
|
||||
+ /* Leave the internal divisor alone */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL,
|
||||
+ AIU_CLK_CTRL_958_DIV_MASK |
|
||||
+ AIU_CLK_CTRL_958_DIV_MORE,
|
||||
+ 0);
|
||||
+
|
||||
+ /* 2 * 32bits per subframe * 2 channels = 128 */
|
||||
+ mrate = rate * 128;
|
||||
+ return clk_set_rate(priv->mclk, mrate);
|
||||
+}
|
||||
+
|
||||
+static int __setup_cs_word(struct meson_spdif_dai *priv,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ u8 cs[AIU_CS_WORD_LEN];
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs,
|
||||
+ AIU_CS_WORD_LEN);
|
||||
+ if (ret < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* Write the 1st half word */
|
||||
+ val = cs[1] | cs[0] << 8;
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L0, val);
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R0, val);
|
||||
+
|
||||
+ /* Write the 2nd half word */
|
||||
+ val = cs[3] | cs[2] << 8;
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L1, val);
|
||||
+ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R1, val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __setup_pcm_fmt(struct meson_spdif_dai *priv,
|
||||
+ unsigned int width)
|
||||
+{
|
||||
+ u32 val = 0;
|
||||
+
|
||||
+ switch (width) {
|
||||
+ case 16:
|
||||
+ val |= AIU_958_MISC_MODE_16BITS;
|
||||
+ val |= AIU_958_MISC_16BITS_ALIGN(2);
|
||||
+ break;
|
||||
+ case 32:
|
||||
+ case 24:
|
||||
+ /*
|
||||
+ * Looks like this should only be set for 32bits mode, but the
|
||||
+ * vendor kernel sets it like this for 24bits as well, let's
|
||||
+ * try and see
|
||||
+ */
|
||||
+ val |= AIU_958_MISC_MODE_32BITS;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /* No idea what this actually does, copying the vendor kernel for now */
|
||||
+ val |= AIU_958_MISC_FORCE_LR;
|
||||
+ val |= AIU_958_MISC_U_FROM_STREAM;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_958_MISC,
|
||||
+ AIU_958_MISC_NON_PCM |
|
||||
+ AIU_958_MISC_MODE_16BITS |
|
||||
+ AIU_958_MISC_16BITS_ALIGN_MASK |
|
||||
+ AIU_958_MISC_MODE_32BITS |
|
||||
+ AIU_958_MISC_FORCE_LR,
|
||||
+ val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __setup_spdif_clk(priv, params_rate(params));
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the spdif clock\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __setup_cs_word(priv, params);
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the channel status word\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = __setup_pcm_fmt(priv, params_width(params));
|
||||
+ if (ret) {
|
||||
+ dev_err(dai->dev, "Unable to set the pcm format\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int meson_spdif_dai_startup(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Power up the spdif fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ goto out_clk_fast;
|
||||
+
|
||||
+ /* Make sure nothing gets out of the DAI yet*/
|
||||
+ __hold(priv, true);
|
||||
+
|
||||
+ ret = clk_set_parent(priv->mclk, priv->mclk_i958);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Enable the clock gate */
|
||||
+ ret = clk_prepare_enable(priv->iface);
|
||||
+ if (ret)
|
||||
+ goto out_clk_iface;
|
||||
+
|
||||
+ /* Enable the spdif clock */
|
||||
+ ret = clk_prepare_enable(priv->mclk);
|
||||
+ if (ret)
|
||||
+ goto out_mclk;
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the interface expect a memory layout we can work with
|
||||
+ * MEM prefixed register usually belong to the DMA, but when the spdif
|
||||
+ * DAI takes data from the i2s buffer, we need to make sure it works in
|
||||
+ * split mode and not the "normal mode" (channel samples packed in
|
||||
+ * 32 bytes groups)
|
||||
+ */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL,
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR,
|
||||
+ AIU_MEM_IEC958_CONTROL_MODE_LINEAR);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+out_mclk:
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+out_clk_iface:
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+out_clk_fast:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void meson_spdif_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
+ struct snd_soc_dai *dai)
|
||||
+{
|
||||
+ struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->iface);
|
||||
+ clk_disable_unprepare(priv->mclk);
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+}
|
||||
+
|
||||
+static const struct snd_soc_dai_ops meson_spdif_dai_ops = {
|
||||
+ .startup = meson_spdif_dai_startup,
|
||||
+ .shutdown = meson_spdif_dai_shutdown,
|
||||
+ .trigger = meson_spdif_dai_trigger,
|
||||
+ .hw_params = meson_spdif_dai_hw_params,
|
||||
+};
|
||||
+
|
||||
+static struct snd_soc_dai_driver meson_spdif_dai = {
|
||||
+ .playback = {
|
||||
+ .stream_name = "Playback",
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 2,
|
||||
+ .rates = (SNDRV_PCM_RATE_32000 |
|
||||
+ SNDRV_PCM_RATE_44100 |
|
||||
+ SNDRV_PCM_RATE_48000 |
|
||||
+ SNDRV_PCM_RATE_96000 |
|
||||
+ SNDRV_PCM_RATE_192000),
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE)
|
||||
+ },
|
||||
+ .ops = &meson_spdif_dai_ops,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_soc_component_driver meson_spdif_dai_component = {
|
||||
+ .name = DRV_NAME,
|
||||
+};
|
||||
+
|
||||
+static int meson_spdif_dai_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct meson_spdif_dai *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get spdif fast domain clockt\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->iface = devm_clk_get(dev, "iface");
|
||||
+ if (IS_ERR(priv->iface)) {
|
||||
+ if (PTR_ERR(priv->iface) != -EPROBE_DEFER)
|
||||
+ dev_err(dev,
|
||||
+ "Can't get the dai clock gate\n");
|
||||
+ return PTR_ERR(priv->iface);
|
||||
+ }
|
||||
+
|
||||
+ priv->mclk_i958 = devm_clk_get(dev, "mclk_i958");
|
||||
+ if (IS_ERR(priv->mclk_i958)) {
|
||||
+ if (PTR_ERR(priv->mclk_i958) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the spdif master clock\n");
|
||||
+ return PTR_ERR(priv->mclk_i958);
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * TODO: the spdif dai can also get its data from the i2s fifo.
|
||||
+ * For this use-case, the DAI driver will need to get the i2s master
|
||||
+ * clock in order to reparent the spdif clock from cts_mclk_i958 to
|
||||
+ * cts_amclk
|
||||
+ */
|
||||
+
|
||||
+ priv->mclk = devm_clk_get(dev, "mclk");
|
||||
+ if (IS_ERR(priv->mclk)) {
|
||||
+ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get the spdif input mux clock\n");
|
||||
+ return PTR_ERR(priv->mclk);
|
||||
+ }
|
||||
+
|
||||
+ return devm_snd_soc_register_component(dev, &meson_spdif_dai_component,
|
||||
+ &meson_spdif_dai, 1);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id meson_spdif_dai_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-spdif-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-spdif-dai", },
|
||||
+ { .compatible = "amlogic,meson-gxl-spdif-dai", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, meson_spdif_dai_of_match);
|
||||
+
|
||||
+static struct platform_driver meson_spdif_dai_pdrv = {
|
||||
+ .probe = meson_spdif_dai_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = meson_spdif_dai_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(meson_spdif_dai_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson spdif DAI ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,31 @@
|
||||
From eabd19b9bb8a62764dfd5290205cf7431e0329d6 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 31 Mar 2017 15:55:03 +0200
|
||||
Subject: [PATCH 08/53] ARM64: defconfig: enable audio support for meson SoCs
|
||||
as module
|
||||
|
||||
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 | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
|
||||
index ab1cb51319e7..a4bf54b3b50d 100644
|
||||
--- a/arch/arm64/configs/defconfig
|
||||
+++ b/arch/arm64/configs/defconfig
|
||||
@@ -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_ROCKCHIP=m
|
||||
CONFIG_SND_SOC_ROCKCHIP_I2S=m
|
||||
CONFIG_SND_SOC_ROCKCHIP_SPDIF=m
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,189 @@
|
||||
From 8615d90edac5487f8639c5e4df40312972d7b2c9 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 15:19:04 +0200
|
||||
Subject: [PATCH 09/53] ARM64: dts: meson-gx: add audio controller nodes
|
||||
|
||||
Add audio controller nodes for Amlogic meson gxbb and gxl.
|
||||
This includes the audio-core node, the i2s and spdif DAIs, i2s and spdif
|
||||
aiu DMAs.
|
||||
|
||||
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 +++++++++++++++++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 38 ++++++++++++++++++++
|
||||
3 files changed, 112 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
index b8dc4dbb391b..6b64b63f2a68 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
|
||||
@@ -203,6 +203,41 @@
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
+ audio: audio@5400 {
|
||||
+ compatible = "amlogic,meson-audio-core";
|
||||
+ reg = <0x0 0x5400 0x0 0x2ac>,
|
||||
+ <0x0 0xa000 0x0 0x304>;
|
||||
+ reg-names = "aiu", "audin";
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ aiu_i2s_dma: aiu_i2s_dma {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-aiu-i2s-dma";
|
||||
+ interrupts = <GIC_SPI 48 IRQ_TYPE_EDGE_RISING>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ aiu_spdif_dma: aiu_spdif_dma {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-aiu-spdif-dma";
|
||||
+ interrupts = <GIC_SPI 50 IRQ_TYPE_EDGE_RISING>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ i2s_dai: i2s_dai {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-i2s-dai";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ spdif_dai: spdif_dai {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ compatible = "amlogic,meson-spdif-dai";
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
+ };
|
||||
+
|
||||
uart_A: serial@84c0 {
|
||||
compatible = "amlogic,meson-gx-uart";
|
||||
reg = <0x0 0x84c0 0x0 0x18>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 98cbba6809ca..79132496691f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -659,6 +659,35 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ clocks = <&clkc CLKID_AIU>,
|
||||
+ <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_SPDIF>;
|
||||
+ clock-names = "aiu_top", "aiu_glue", "audin";
|
||||
+ resets = <&reset RESET_AIU>,
|
||||
+ <&reset RESET_AUDIN>;
|
||||
+ reset-names = "aiu", "audin";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&aiu_spdif_dma {
|
||||
+ clocks = <&clkc CLKID_IEC958>;
|
||||
+ clock-names = "fast";
|
||||
+
|
||||
+};
|
||||
+
|
||||
+&i2s_dai {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>;
|
||||
+ clock-names = "fast", "iface", "bclks", "mclk";
|
||||
+};
|
||||
+
|
||||
&pwrc_vpu {
|
||||
resets = <&reset RESET_VIU>,
|
||||
<&reset RESET_VENC>,
|
||||
@@ -741,6 +770,15 @@
|
||||
num-cs = <1>;
|
||||
};
|
||||
|
||||
+&spdif_dai {
|
||||
+ clocks = <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk";
|
||||
+};
|
||||
+
|
||||
&spifc {
|
||||
clocks = <&clkc CLKID_SPI>;
|
||||
};
|
||||
@@ -774,3 +812,4 @@
|
||||
compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index c87a80e9bcc6..20922cdc2c23 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -660,6 +660,34 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ clocks = <&clkc CLKID_AIU>,
|
||||
+ <&clkc CLKID_AIU_GLUE>,
|
||||
+ <&clkc CLKID_I2S_SPDIF>;
|
||||
+ clock-names = "aiu_top", "aiu_glue", "audin";
|
||||
+ resets = <&reset RESET_AIU>,
|
||||
+ <&reset RESET_AUDIN>;
|
||||
+ reset-names = "aiu", "audin";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&aiu_spdif_dma {
|
||||
+ clocks = <&clkc CLKID_IEC958>;
|
||||
+ clock-names = "fast";
|
||||
+};
|
||||
+
|
||||
+&i2s_dai {
|
||||
+ clocks = <&clkc CLKID_I2S_OUT>,
|
||||
+ <&clkc CLKID_MIXER_IFACE>,
|
||||
+ <&clkc CLKID_AOCLK_GATE>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>;
|
||||
+ clock-names = "fast", "iface", "bclks", "mclk";
|
||||
+};
|
||||
+
|
||||
&pwrc_vpu {
|
||||
resets = <&reset RESET_VIU>,
|
||||
<&reset RESET_VENC>,
|
||||
@@ -742,6 +770,15 @@
|
||||
num-cs = <1>;
|
||||
};
|
||||
|
||||
+&spdif_dai {
|
||||
+ clocks = <&clkc CLKID_IEC958>,
|
||||
+ <&clkc CLKID_IEC958_GATE>,
|
||||
+ <&clkc CLKID_CTS_MCLK_I958>,
|
||||
+ <&clkc CLKID_CTS_AMCLK>,
|
||||
+ <&clkc CLKID_CTS_I958>;
|
||||
+ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk";
|
||||
+};
|
||||
+
|
||||
&spifc {
|
||||
clocks = <&clkc CLKID_SPI>;
|
||||
};
|
||||
@@ -775,3 +812,4 @@
|
||||
compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
+
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,55 @@
|
||||
From 5608714afb7c71054a01e4ad208b3eaa044041d4 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:39:21 +0200
|
||||
Subject: [PATCH 10/53] 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/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
index 1008af8d3972..63fe098ecf82 100644
|
||||
--- a/sound/soc/meson/i2s-dai.c
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -56,8 +56,19 @@ struct meson_i2s_dai {
|
||||
#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4)
|
||||
#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0)
|
||||
@@ -221,6 +232,17 @@ static int meson_i2s_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /* Quick and dirty hack for HDMI */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,22 @@
|
||||
From 5b3d41b6ad8275d53b758d6d4b95441b53cd320b Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 14 Feb 2017 19:18:04 +0100
|
||||
Subject: [PATCH 11/53] 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/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
|
||||
index 3ce51d8dfe1c..02d400b8795c 100644
|
||||
--- a/drivers/gpu/drm/meson/Kconfig
|
||||
+++ b/drivers/gpu/drm/meson/Kconfig
|
||||
@@ -13,3 +13,4 @@ config DRM_MESON_DW_HDMI
|
||||
depends on DRM_MESON
|
||||
default y if DRM_MESON
|
||||
select DRM_DW_HDMI
|
||||
+ select DRM_DW_HDMI_I2S_AUDIO
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,38 @@
|
||||
From 461a8ba1e73d38b8cd8f8c931a8ae27676cdb085 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 20 Sep 2017 18:01:26 +0200
|
||||
Subject: [PATCH 12/53] 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 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 79132496691f..2a4d506bad4e 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -305,6 +305,7 @@
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
&sysctrl {
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index 20922cdc2c23..9f4b6185a61d 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -257,6 +257,7 @@
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
|
||||
&sysctrl {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,864 @@
|
||||
From dc4eb517f2800001f77bec852f8f688f0164e51b Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Wed, 20 Sep 2017 18:10:08 +0200
|
||||
Subject: [PATCH 13/53] ARM64: dts: meson: activate hdmi audio HDMI enabled
|
||||
boards
|
||||
|
||||
This patch activate audio over HDMI on selected boards
|
||||
|
||||
Please note that this audio support is based on WIP changes
|
||||
This should be considered as preview and it does not reflect
|
||||
the audio I expect to see merged
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 45 +++++++++++++++++++
|
||||
.../dts/amlogic/meson-gxbb-nexbox-a95x.dts | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-odroidc2.dts | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-p20x.dtsi | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxbb-wetek.dtsi | 45 +++++++++++++++++++
|
||||
.../amlogic/meson-gxl-s905x-khadas-vim.dts | 45 +++++++++++++++++++
|
||||
.../amlogic/meson-gxl-s905x-libretech-cc.dts | 45 +++++++++++++++++++
|
||||
.../amlogic/meson-gxl-s905x-nexbox-a95x.dts | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 45 +++++++++++++++++++
|
||||
.../dts/amlogic/meson-gxm-khadas-vim2.dts | 45 +++++++++++++++++++
|
||||
.../boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 45 +++++++++++++++++++
|
||||
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 765247bc4f24..fb9ad6faa745 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
@@ -102,6 +102,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -111,6 +144,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -133,6 +174,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
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 cbe99bd4e06d..5b10de9a0bad 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts
|
||||
@@ -88,6 +88,39 @@
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
vcc1v8: regulator-vcc1v8 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VCC1.8V";
|
||||
@@ -131,6 +164,14 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cec_AO {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&ao_cec_pins>;
|
||||
@@ -185,6 +226,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
index 4cf7f6e80c6a..ff87bdc7ddbf 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
|
||||
@@ -119,6 +119,39 @@
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
cvbs-connector {
|
||||
compatible = "composite-video-connector";
|
||||
|
||||
@@ -154,6 +187,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_rmii_pins>;
|
||||
@@ -190,6 +231,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 54954b314a45..3da33090b8fe 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -110,6 +110,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -119,6 +152,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_rgmii_pins>;
|
||||
@@ -181,6 +222,10 @@
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
index ce862266b9aa..84eb93b4229f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
@@ -113,6 +113,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -122,6 +155,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -140,6 +181,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
index 70325b273bd2..7d1f1726f29d 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi
|
||||
@@ -105,6 +105,47 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -159,6 +200,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
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 d32cf3846370..f053595ebdc4 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
|
||||
@@ -65,6 +65,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -74,6 +107,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
@@ -86,6 +127,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&i2c_A {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c_a_pins>;
|
||||
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 f63bceb88caa..f56969efffba 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
|
||||
@@ -84,6 +84,39 @@
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
vcc_3v3: regulator-vcc_3v3 {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "VCC_3V3";
|
||||
@@ -130,6 +163,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -151,6 +192,10 @@
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
index 6739697be1de..e3e777f665c0 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
|
||||
@@ -102,6 +102,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -111,6 +144,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -135,6 +176,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
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 5896e8a5d86b..f8c66a7972b3 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
@@ -32,6 +32,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -41,12 +74,24 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
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 313f88f8759e..4fbfa5a850cc 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 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
|
||||
@@ -205,6 +238,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cpu0 {
|
||||
#cooling-cells = <2>;
|
||||
};
|
||||
@@ -279,6 +320,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&i2c_A {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&i2c_a_pins>;
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
index f7a1cffab4a8..b9c5e6444daa 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
@@ -75,6 +75,39 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gx-audio";
|
||||
+
|
||||
+ assigned-clocks = <&clkc CLKID_MPLL2>,
|
||||
+ <&clkc CLKID_MPLL0>,
|
||||
+ <&clkc CLKID_MPLL1>;
|
||||
+ assigned-clock-parents = <0>, <0>, <0>;
|
||||
+ assigned-clock-rates = <294912000>,
|
||||
+ <270950400>,
|
||||
+ <393216000>;
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ /* HDMI Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -84,6 +117,14 @@
|
||||
hdmi-phandle = <&hdmi_tx>;
|
||||
};
|
||||
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
remote-endpoint = <&cvbs_connector_in>;
|
||||
@@ -129,6 +170,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&i2s_dai {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&ir {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&remote_input_ao_pins>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,78 @@
|
||||
From de9e307aca194c9918a3ace8d809c9f3b18000b9 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 2 Jul 2018 12:21:55 +0200
|
||||
Subject: [PATCH 14/53] 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 5971976284bf..1fc12708dbb5 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,
|
||||
/* nshift factor = 0 */
|
||||
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
|
||||
|
||||
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ /* Use Auto CTS mode with CTS is unknown */
|
||||
+ if (cts)
|
||||
+ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ else
|
||||
+ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3);
|
||||
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
||||
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
|
||||
|
||||
@@ -501,24 +505,31 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
|
||||
{
|
||||
unsigned long ftdms = pixel_clk;
|
||||
unsigned int n, cts;
|
||||
+ u8 config3;
|
||||
u64 tmp;
|
||||
|
||||
n = hdmi_compute_n(sample_rate, pixel_clk);
|
||||
|
||||
- /*
|
||||
- * Compute the CTS value from the N value. Note that CTS and N
|
||||
- * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
- * note that our TDMS clock is not fully accurate; it is accurate
|
||||
- * to kHz. This can introduce an unnecessary remainder in the
|
||||
- * calculation below, so we don't try to warn about that.
|
||||
- */
|
||||
- tmp = (u64)ftdms * n;
|
||||
- do_div(tmp, 128 * sample_rate);
|
||||
- cts = tmp;
|
||||
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
|
||||
|
||||
- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
- n, cts);
|
||||
+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
|
||||
+ /*
|
||||
+ * Compute the CTS value from the N value. Note that CTS and N
|
||||
+ * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
+ * note that our TDMS clock is not fully accurate; it is
|
||||
+ * accurate to kHz. This can introduce an unnecessary remainder
|
||||
+ * in the calculation below, so we don't try to warn about that.
|
||||
+ */
|
||||
+ tmp = (u64)ftdms * n;
|
||||
+ do_div(tmp, 128 * sample_rate);
|
||||
+ cts = tmp;
|
||||
+
|
||||
+ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
+ __func__, sample_rate,
|
||||
+ ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
+ n, cts);
|
||||
+ } else
|
||||
+ cts = 0;
|
||||
|
||||
spin_lock_irq(&hdmi->audio_lock);
|
||||
hdmi->audio_n = n;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,29 @@
|
||||
From ca4d7cc46fc5788da89609691ccb0b001bdbdc2d Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 28 Feb 2018 16:07:18 +0100
|
||||
Subject: [PATCH 15/53] 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 | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
index 709475d5cc30..2680be54a1d1 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -104,6 +104,8 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc,
|
||||
drm_crtc_vblank_on(crtc);
|
||||
|
||||
priv->viu.osd1_enabled = true;
|
||||
+
|
||||
+ drm_crtc_vblank_on(crtc);
|
||||
}
|
||||
|
||||
static void meson_crtc_atomic_disable(struct drm_crtc *crtc,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,316 @@
|
||||
From d28f2758958eff3be784b80eff63c144d342539b 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 16/53] 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 b04f6e4aedbc..2f282b472912 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 8fa321893928..0ab16d35ac36 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 000000000000..fce33ca76bb6
|
||||
--- /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 000000000000..b4dde2fbeb3f
|
||||
--- /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
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,41 @@
|
||||
From 83a293f5c56ec7cb763edba40c9cbf4f79ed6393 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 17/53] 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 6b64b63f2a68..fb6435431a94 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>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,174 @@
|
||||
From b1ef71bf75024008c4221e0415f84af57cd128ac Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Mon, 15 Oct 2018 14:37:18 +0200
|
||||
Subject: [PATCH 18/53] 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 02d400b8795c..892905825fea 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 2680be54a1d1..910b92def5d2 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -199,10 +199,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 588b3b0c8315..874c7a74a7c1 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_drv.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_drv.c
|
||||
@@ -220,24 +220,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);
|
||||
@@ -322,6 +331,9 @@ static void meson_drv_unbind(struct device *dev)
|
||||
struct meson_drm *priv = dev_get_drvdata(dev);
|
||||
struct drm_device *drm = priv->drm;
|
||||
|
||||
+ if (priv->canvas)
|
||||
+ meson_canvas_free(priv->canvas, priv->canvas_id_osd1);
|
||||
+
|
||||
drm_dev_unregister(drm);
|
||||
drm_irq_uninstall(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 8450d6ac8c9b..728d0ca33732 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 12c80dfcff59..51bec8e98a39 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 */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,28 @@
|
||||
From c16450ca851dbe9b7ad58464cea210610dd0433c Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Mon, 15 Oct 2018 14:38:24 +0200
|
||||
Subject: [PATCH 19/53] 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 fb6435431a94..5012607c95d2 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 {
|
||||
--
|
||||
2.17.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,200 @@
|
||||
From 1d7b86b1151ec8ad46c689138977c57053c99608 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 29 Oct 2018 17:04:05 +0100
|
||||
Subject: [PATCH 21/53] 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 b292e9aedf52..23df4abd95c9 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -195,21 +195,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 c971557d4a48..a955354711ce 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 51bec8e98a39..f915a79ae81c 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 5dc24a99e978..f9efb431e953 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,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,287 @@
|
||||
From 166c3c3d19c030becc0c403cb638560d3165ff14 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 30 Oct 2018 14:29:10 +0100
|
||||
Subject: [PATCH 22/53] 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 f915a79ae81c..12a47b4f65a5 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;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,57 @@
|
||||
From 47a84b0f881a1e52f95b4b31cf7ca01a88b469d4 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 7 Nov 2018 11:34:47 +0100
|
||||
Subject: [PATCH 23/53] 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 158f618f1695..0c0a5018102b 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",
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,82 @@
|
||||
From 0e580116d8afa1dcab823eb31ca415c4714bf48a Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 8 Nov 2018 14:24:38 +0100
|
||||
Subject: [PATCH 24/53] 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 fb9ad6faa745..774f8afd2c65 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 f053595ebdc4..e5ef9b0b91c1 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 f56969efffba..ca0228e0d585 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 f8c66a7972b3..29c9837bd7ea 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 4fbfa5a850cc..fe8e726a4210 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 {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,41 @@
|
||||
From 15611dee35c448dd0409a1e06a4f87f0dbf59876 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 7 Nov 2018 11:45:47 +0100
|
||||
Subject: [PATCH 25/53] 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 ca0228e0d585..bb2a8c750589 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 */
|
||||
"", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "",
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,40 @@
|
||||
From 706947bf855b187bbd8d8b5786b38e84e571ca9b Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 7 Nov 2018 11:45:48 +0100
|
||||
Subject: [PATCH 26/53] 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 5b10de9a0bad..8ea5ed5a1c62 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",
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,40 @@
|
||||
From 62b3002dc67232b0a8cc5f51a5df991a48f062c7 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 7 Nov 2018 11:45:49 +0100
|
||||
Subject: [PATCH 27/53] 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 3da33090b8fe..73cc80143c04 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",
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,40 @@
|
||||
From db194607c28989a307f60f2fd89a4996b6ae4f02 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 7 Nov 2018 11:45:50 +0100
|
||||
Subject: [PATCH 28/53] 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 e5ef9b0b91c1..1a4b3f3b8ace 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 */
|
||||
"", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "",
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,330 @@
|
||||
From b63cbf7b44a26e219c55da750662e1d0ae9f565b Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Tue, 6 Nov 2018 11:54:35 +0100
|
||||
Subject: [PATCH 29/53] 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 2cb2ad26d716..807111ebfdd9 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 ae5473257f72..5acccebd026d 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 869fa3a3073e..4bd8752da02a 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,
|
||||
--
|
||||
2.17.1
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
From c8482bffc8ced44e3e22f403413b23c7b20af1be Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Tue, 4 Sep 2018 10:07:08 +0200
|
||||
Subject: [PATCH 31/53] 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 11a59e82d92e..d2c0c0f8b406 100644
|
||||
--- a/MAINTAINERS
|
||||
+++ b/MAINTAINERS
|
||||
@@ -9526,6 +9526,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/
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,40 @@
|
||||
From 91e2dc23af4fb673e609a4fddf2b813ea3f833b8 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:24:02 +0200
|
||||
Subject: [PATCH 32/53] 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 5012607c95d2..5d2820ef9a88 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>;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,65 @@
|
||||
From f9f1d0b0b197f94502ea2a13a27d6d4534f8150f Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:24:22 +0200
|
||||
Subject: [PATCH 33/53] 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 | 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 2a4d506bad4e..96145e49ea44 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -814,3 +814,13 @@
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
|
||||
+&vdec {
|
||||
+ 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 9f4b6185a61d..6ca93ae1e496 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -814,3 +814,13 @@
|
||||
power-domains = <&pwrc_vpu>;
|
||||
};
|
||||
|
||||
+&vdec {
|
||||
+ 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 247888d68a3a..2f356495be5e 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
@@ -117,3 +117,7 @@
|
||||
&dwc3 {
|
||||
phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>;
|
||||
};
|
||||
+
|
||||
+&vdec {
|
||||
+ compatible = "amlogic,gxm-vdec";
|
||||
+};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,156 @@
|
||||
From c5ad2d518874fe080e249c2a11497064c28d9b1b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 10 Oct 2018 17:22:27 +0200
|
||||
Subject: [PATCH 34/53] 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 +
|
||||
.../media/platform/meson/vdec/vdec_ctrls.c | 45 +++++++++++++++++++
|
||||
.../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 6bea129084b7..eba86083aadb 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 d8db52c01fbe..1c5d3e912bee 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 4e8c3f1742ac..6be7de2849b6 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 000000000000..cd6dd6d87172
|
||||
--- /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 000000000000..4bcc5e68865c
|
||||
--- /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
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,51 @@
|
||||
From 2688d1304cbb41d4e2c8514ec2bdcd2b48f2f88a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Thu, 4 Oct 2018 15:37:39 +0200
|
||||
Subject: [PATCH 35/53] 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 019c513df217..e0040b36ac43 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 1aae2e4b8f10..f44bdef62d0b 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 */
|
||||
/*
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,273 @@
|
||||
From b1d313fb821e3a4196bb32c86c585b8be23d491a Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 10 Oct 2018 15:44:56 +0200
|
||||
Subject: [PATCH 36/53] 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 +++++++++
|
||||
.../media/platform/meson/vdec/vdec_helpers.c | 28 +++++++++++++++++++
|
||||
.../media/platform/meson/vdec/vdec_helpers.h | 1 +
|
||||
.../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 1c5d3e912bee..ca6404546eb8 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 6be7de2849b6..8f8ce629c698 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 02090c5b089e..b982b2869fd2 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 b9250a8157c4..060799b5e4d4 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 46eeb7426f54..291f1eeb27d9 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",
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,593 @@
|
||||
From fecc45672255e63d4e99b9eaf24ac00083a5d4b6 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 15:42:56 +0200
|
||||
Subject: [PATCH 37/53] media: meson: vdec: add H.264 decoding support
|
||||
|
||||
Add support for V4L2_PIX_FMT_H264
|
||||
---
|
||||
drivers/media/platform/meson/vdec/Makefile | 2 +-
|
||||
.../media/platform/meson/vdec/codec_h264.c | 478 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_h264.h | 13 +
|
||||
.../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 eba86083aadb..01dc9603abdd 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 000000000000..6ac0115afaa3
|
||||
--- /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 000000000000..7a1597611faf
|
||||
--- /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 291f1eeb27d9..baecf5921d56 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,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,315 @@
|
||||
From cbb607b67a4a169b94884436208b05062bd2f93b Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Wed, 29 Aug 2018 16:01:55 +0200
|
||||
Subject: [PATCH 38/53] 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 +-
|
||||
.../media/platform/meson/vdec/codec_mpeg4.c | 139 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_mpeg4.h | 13 ++
|
||||
.../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 01dc9603abdd..bb7a134e2728 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 000000000000..1d574e576112
|
||||
--- /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 000000000000..b91b26413185
|
||||
--- /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 baecf5921d56..80b43fd5d01f 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,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,255 @@
|
||||
From 1434c8fcc8ae00e748225ca4922c0d0b7bd15b02 Mon Sep 17 00:00:00 2001
|
||||
From: Maxime Jourdan <mjourdan@baylibre.com>
|
||||
Date: Sun, 21 Oct 2018 15:14:27 +0200
|
||||
Subject: [PATCH 39/53] media: meson: vdec: add MJPEG decoding support
|
||||
|
||||
Add support for V4L2_PIX_FMT_MJPEG
|
||||
---
|
||||
drivers/media/platform/meson/vdec/Makefile | 2 +-
|
||||
.../media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++
|
||||
.../media/platform/meson/vdec/codec_mjpeg.h | 13 ++
|
||||
.../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 bb7a134e2728..acf07f3c3dac 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 000000000000..abea9e3f944c
|
||||
--- /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 000000000000..cc1cf731050d
|
||||
--- /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 80b43fd5d01f..61def155a5fd 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,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,44 @@
|
||||
From 8bb24f445a3b532a06a1d5bde70daad0c4f3da4f Mon Sep 17 00:00:00 2001
|
||||
From: Christian Hewitt <christianshewitt@gmail.com>
|
||||
Date: Sat, 13 Oct 2018 14:04:46 +0400
|
||||
Subject: [PATCH 40/53] 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 4d4f6d842c31..a6fae1c00df3 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,
|
||||
},
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,167 @@
|
||||
From cb1d14ed8b5d2dc67b8d7769b5314fd5b9010f23 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 20 Jul 2018 15:29:18 +0200
|
||||
Subject: [PATCH 41/53] 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 7a3a6ed9f27b..0fbe525b94c8 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;
|
||||
@@ -719,6 +845,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 */
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,94 @@
|
||||
From 040f80b511f207308bbd7c177e148551cbd2c110 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 42/53] 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 | 18 ++----------------
|
||||
drivers/gpu/drm/meson/meson_drv.h | 1 -
|
||||
2 files changed, 2 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
|
||||
index 63bb2727b183..a13704ab5d11 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,
|
||||
@@ -319,13 +311,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);
|
||||
@@ -334,6 +319,8 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
|
||||
if (ret)
|
||||
goto uninstall_irq;
|
||||
|
||||
+ drm_fbdev_generic_setup(drm, 32);
|
||||
+
|
||||
return 0;
|
||||
|
||||
uninstall_irq:
|
||||
@@ -364,7 +351,6 @@ static void meson_drv_unbind(struct device *dev)
|
||||
drm_dev_unregister(drm);
|
||||
drm_irq_uninstall(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 a955354711ce..4dccf4cd042a 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;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,150 @@
|
||||
From 3514e950490879dcdd75c74196e26eab8f5b740d Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Nov 2018 16:48:50 +0100
|
||||
Subject: [PATCH 43/53] 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 1fc12708dbb5..2a30d8393477 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 9d90eb9c46e5..3f3c616eba97 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 ccb5aa8468e0..d7cc5d094270 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);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,71 @@
|
||||
From 9f4886b1df0a93a313bc8a238ca6f020fbe8ae90 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 12 Nov 2018 16:08:13 +0100
|
||||
Subject: [PATCH 44/53] 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 807111ebfdd9..b8775102b100 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);
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,30 @@
|
||||
From 954b1e933ad1dd534c3f5b01fde7b52a62b78973 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 12 Nov 2018 16:10:07 +0100
|
||||
Subject: [PATCH 45/53] 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 0fbe525b94c8..1bcd642b6e42 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 */
|
||||
};
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,200 @@
|
||||
From afdd89304db8f3e858ee32cefaf29ed0be12500e Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Nov 2018 17:19:36 +0100
|
||||
Subject: [PATCH 46/53] 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 2a30d8393477..c3e4ed1e2d1c 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);
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,104 @@
|
||||
From c65b7b6a68ad5ccae7e861f840f1b45d79396929 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 47/53] 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 c3e4ed1e2d1c..6473df3068ce 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 d7cc5d094270..27f9cce66b6a 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,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,48 @@
|
||||
From 725830ef41b23e35b282ecf78f682c0c131a0042 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Wed, 14 Nov 2018 17:39:46 +0100
|
||||
Subject: [PATCH 48/53] 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 6473df3068ce..d10277f9ef0b 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 27f9cce66b6a..c04f497a919b 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;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,584 @@
|
||||
From d27e2f1dac6e94f845d83725481adf9fc1c9bb21 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 15 Nov 2018 16:41:23 +0100
|
||||
Subject: [PATCH 49/53] 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 b8775102b100..83360f37d9ce 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
|
||||
@@ -715,6 +772,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = {
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
+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;
|
||||
@@ -891,6 +962,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 5acccebd026d..27c9c5ead234 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 4bd8752da02a..c4d19ddfcd79 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 1bcd642b6e42..ab72ddda242d 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 97eaebbfa0c4..5580bf38e381 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 f7945bae3b4a..38a1117b1183 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;
|
||||
}
|
||||
}
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,33 @@
|
||||
From 2b420ad1ebade69b262cb1cf36668134d7bd785c Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Sun, 18 Nov 2018 14:06:11 +0100
|
||||
Subject: [PATCH 50/53] 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 83360f37d9ce..1b7092ab1be8 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;
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,126 @@
|
||||
From fa6cb8f89a7f9387a0299f6b55bc0cd54233aefd Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 22 Nov 2018 17:27:20 +0100
|
||||
Subject: [PATCH 51/53] 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 23df4abd95c9..f13e5b6b7a50 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_crtc.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_crtc.c
|
||||
@@ -183,6 +183,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 12a47b4f65a5..837228847675 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 90d9ae3c2b81..366f7e523d15 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 073b1910bd1b..e4a6e2fba8fb 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 */
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,51 @@
|
||||
From 5e2e26abc73f9bfae1e5edbcdea7e53e9822f2fb Mon Sep 17 00:00:00 2001
|
||||
From: Carlo Caione <ccaione@baylibre.com>
|
||||
Date: Tue, 4 Dec 2018 16:04:46 +0000
|
||||
Subject: [PATCH 52/53] 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/arm64/boot/dts/amlogic/meson-axg.dtsi | 2 +-
|
||||
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
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";
|
||||
};
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,36 @@
|
||||
From 47a653adc82602d0d8b21065807164f87c89c82b Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 4 Oct 2018 10:42:43 +0200
|
||||
Subject: [PATCH 53/53] 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 a13704ab5d11..960b8b08756e 100644
|
||||
--- a/drivers/gpu/drm/meson/meson_drv.c
|
||||
+++ b/drivers/gpu/drm/meson/meson_drv.c
|
||||
@@ -267,8 +267,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;
|
||||
drm->mode_config.helper_private = &meson_mode_config_helpers;
|
||||
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,92 @@
|
||||
ARM: dts: exynos5420: add mali dt bindings and enable mali on Odroid XU3/4
|
||||
|
||||
Signed-off-by: memeka <mihailescu2m@gmail.com>
|
||||
|
||||
https://github.com/hardkernel/linux/commit/27f16b364e195daefdb8839344c02870ceaf48f2#diff-80dd4bb1cf404a3774bbe37bcfe945c2
|
||||
|
||||
Upstream-Status: Backport
|
||||
|
||||
Signed-off-by: Armin Kuster <akuster808@gmail.com>
|
||||
|
||||
Index: kernel-source/arch/arm/boot/dts/exynos5422-odroid-core.dtsi
|
||||
===================================================================
|
||||
--- kernel-source.orig/arch/arm/boot/dts/exynos5422-odroid-core.dtsi
|
||||
+++ kernel-source/arch/arm/boot/dts/exynos5422-odroid-core.dtsi
|
||||
@@ -417,6 +417,11 @@
|
||||
vtmu-supply = <&ldo7_reg>;
|
||||
};
|
||||
|
||||
+&mali {
|
||||
+ mali-supply = <&buck4_reg>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
&rtc {
|
||||
status = "okay";
|
||||
clocks = <&clock CLK_RTC>, <&s2mps11_osc S2MPS11_CLK_AP>;
|
||||
Index: kernel-source/arch/arm/boot/dts/exynos5420.dtsi
|
||||
===================================================================
|
||||
--- kernel-source.orig/arch/arm/boot/dts/exynos5420.dtsi
|
||||
+++ kernel-source/arch/arm/boot/dts/exynos5420.dtsi
|
||||
@@ -1317,6 +1317,61 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ mali: mali@11800000 {
|
||||
+ compatible = "samsung,exynos5422-mali", "arm,malit6xx", "arm,mali-midgard";
|
||||
+ reg = <0x11800000 0x5000>;
|
||||
+ interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ interrupt-names = "JOB", "MMU", "GPU";
|
||||
+
|
||||
+ clocks = <&clock CLK_FOUT_VPLL>, <&clock CLK_DOUT_ACLK_G3D>, <&clock CLK_G3D>;
|
||||
+ clock-names = "fout_vpll", "dout_aclk_g3d", "clk_mali";
|
||||
+
|
||||
+ operating-points-v2 = <&gpu_opp_table>;
|
||||
+
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ power_model@0 {
|
||||
+ compatible = "arm,mali-simple-power-model";
|
||||
+ static-coefficient = <2427750>;
|
||||
+ dynamic-coefficient = <4687>;
|
||||
+ ts = <20000 2000 (-20) 2>;
|
||||
+ thermal-zone = "gpu-thermal";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ gpu_opp_table: opp_table0 {
|
||||
+ compatible = "operating-points-v2";
|
||||
+
|
||||
+ opp@600000000 {
|
||||
+ opp-hz = /bits/ 64 <600000000>;
|
||||
+ opp-microvolt = <1150000>;
|
||||
+ };
|
||||
+ opp@543000000 {
|
||||
+ opp-hz = /bits/ 64 <543000000>;
|
||||
+ opp-microvolt = <1037500>;
|
||||
+ };
|
||||
+ opp@480000000 {
|
||||
+ opp-hz = /bits/ 64 <480000000>;
|
||||
+ opp-microvolt = <1000000>;
|
||||
+ };
|
||||
+ opp@420000000 {
|
||||
+ opp-hz = /bits/ 64 <420000000>;
|
||||
+ opp-microvolt = <962500>;
|
||||
+ };
|
||||
+ opp@350000000 {
|
||||
+ opp-hz = /bits/ 64 <350000000>;
|
||||
+ opp-microvolt = <912500>;
|
||||
+ };
|
||||
+ opp@266000000 {
|
||||
+ opp-hz = /bits/ 64 <266000000>;
|
||||
+ opp-microvolt = <862500>;
|
||||
+ };
|
||||
+ opp@177000000 {
|
||||
+ opp-hz = /bits/ 64 <177000000>;
|
||||
+ opp-microvolt = <812500>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
thermal-zones {
|
||||
cpu0_thermal: cpu0-thermal {
|
||||
thermal-sensors = <&tmu_cpu0>;
|
@ -2,7 +2,7 @@ BR2_aarch64=y
|
||||
BR2_DL_DIR="/cache/dl"
|
||||
BR2_CCACHE=y
|
||||
BR2_CCACHE_DIR="/cache/cc"
|
||||
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_HASSOS_PATH)/patches $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-c2/patches"
|
||||
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_HASSOS_PATH)/patches $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/patches"
|
||||
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
|
||||
BR2_GCC_VERSION_7_X=y
|
||||
BR2_TOOLCHAIN_BUILDROOT_CXX=y
|
||||
@ -19,7 +19,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-image.sh"
|
||||
BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-c2 $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-c2/hassos-hook.sh"
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.19.88"
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.19.72"
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="$(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-c2/kernel.config"
|
||||
BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_HASSOS_PATH)/kernel/hassos.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/docker.config $(BR2_EXTERNAL_HASSOS_PATH)/kernel/device-support.config"
|
||||
@ -77,7 +77,7 @@ BR2_TARGET_ROOTFS_SQUASHFS4_LZ4=y
|
||||
BR2_TARGET_UBOOT=y
|
||||
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2018.07"
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2019.10"
|
||||
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="odroid-c2"
|
||||
BR2_TARGET_UBOOT_CONFIG_FRAGMENT_FILES="$(BR2_EXTERNAL_HASSOS_PATH)/bootloader/uboot.config $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-c2/uboot.config"
|
||||
BR2_TARGET_UBOOT_BOOT_SCRIPT=y
|
||||
|
@ -3,7 +3,7 @@ BR2_cortex_a7=y
|
||||
BR2_DL_DIR="/cache/dl"
|
||||
BR2_CCACHE=y
|
||||
BR2_CCACHE_DIR="/cache/cc"
|
||||
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_HASSOS_PATH)/patches $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-xu4/patches"
|
||||
BR2_GLOBAL_PATCH_DIR="$(BR2_EXTERNAL_HASSOS_PATH)/patches $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/patches"
|
||||
BR2_TOOLCHAIN_BUILDROOT_GLIBC=y
|
||||
BR2_GCC_VERSION_7_X=y
|
||||
BR2_TOOLCHAIN_BUILDROOT_CXX=y
|
||||
@ -20,7 +20,7 @@ BR2_ROOTFS_POST_IMAGE_SCRIPT="$(BR2_EXTERNAL_HASSOS_PATH)/scripts/post-image.sh"
|
||||
BR2_ROOTFS_POST_SCRIPT_ARGS="$(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-xu4 $(BR2_EXTERNAL_HASSOS_PATH)/board/hardkernel/odroid-xu4/hassos-hook.sh"
|
||||
BR2_LINUX_KERNEL=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION=y
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.19.88"
|
||||
BR2_LINUX_KERNEL_CUSTOM_VERSION_VALUE="4.19.72"
|
||||
BR2_LINUX_KERNEL_DTS_SUPPORT=y
|
||||
BR2_LINUX_KERNEL_INTREE_DTS_NAME="exynos5422-odroidxu4"
|
||||
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
|
||||
@ -80,7 +80,7 @@ BR2_TARGET_ROOTFS_SQUASHFS4_LZ4=y
|
||||
BR2_TARGET_UBOOT=y
|
||||
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION=y
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2018.07"
|
||||
BR2_TARGET_UBOOT_CUSTOM_VERSION_VALUE="2019.10"
|
||||
BR2_TARGET_UBOOT_BOARD_DEFCONFIG="odroid-xu3"
|
||||
BR2_TARGET_UBOOT_NEEDS_DTC=y
|
||||
BR2_TARGET_UBOOT_FORMAT_DTB_BIN=y
|
||||
|
Loading…
x
Reference in New Issue
Block a user