Odroid C2 4.12 NEXT kernel patches, enable back kernel target

This commit is contained in:
Igor Pecovnik 2017-07-22 13:10:54 +02:00
parent e388aa9665
commit 7a08a679b8
170 changed files with 8508 additions and 22409 deletions

View file

@ -6,7 +6,7 @@ BOOTCONFIG="odroidc2_config"
MODULES="bonding"
MODULES_NEXT=""
#
KERNEL_TARGET="default,dev"
KERNEL_TARGET="default,next,dev"
CLI_TARGET="jessie,xenial:default"
DESKTOP_TARGET="xenial:default"

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@ case $BRANCH in
;;
next)
KERNELSOURCE=$MAINLINE_KERNEL_SOURCE
KERNELBRANCH='branch:linux-4.10.y'
KERNELBRANCH='branch:linux-4.12.y'
KERNELDIR=$MAINLINE_KERNEL_DIR
;;
dev)

View file

@ -1,32 +0,0 @@
From 86f0b91719a9d97095187af6ddaade3b34dc1257 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 16 Mar 2017 09:38:10 +0100
Subject: [PATCH 01/93] ARM64: dts: meson-gxbb: Add gpio-ranges
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index b353073..2be29a3 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -186,6 +186,7 @@
reg-names = "mux", "pull", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_aobus 0 0 14>;
};
uart_ao_a_pins: uart_ao_a {
@@ -279,6 +280,7 @@
reg-names = "mux", "pull", "pull-enable", "gpio";
gpio-controller;
#gpio-cells = <2>;
+ gpio-ranges = <&pinctrl_periphs 0 14 120>;
};
emmc_pins: emmc {
--
1.9.1

View file

@ -1,14 +1,15 @@
From d074af897d4547d239f93b55c7baa4cf47a9f535 Mon Sep 17 00:00:00 2001
From 8ede929172f118c43ef1664fe66b56dadff3310f Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 28 Feb 2017 15:22:54 +0100
Subject: [PATCH 57/93] Add HDMI support for Odroid-C2
Subject: [PATCH 01/79] Add HDMI support for Odroid-C2
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index 492ac35..ee77c3d 100644
index 54a9c6a..0066b1a 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -135,6 +135,17 @@
@ -29,7 +30,7 @@ index 492ac35..ee77c3d 100644
};
&scpi_clocks {
@@ -240,3 +251,15 @@
@@ -309,3 +320,15 @@
vmmc-supply = <&vcc3v3>;
vqmmc-supply = <&vcc1v8>;
};

View file

@ -1,9 +1,10 @@
From d3527920b1ab4959557bda86974b143228746ce9 Mon Sep 17 00:00:00 2001
From aa7bd7ebd01c4a7a1e7f1cdca431e5447313fefc Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Tue, 14 Feb 2017 19:18:04 +0100
Subject: [PATCH 88/93] drm/meson: select dw-hdmi i2s audio for meson hdmi
Subject: [PATCH 02/79] drm/meson: select dw-hdmi i2s audio for meson hdmi
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/gpu/drm/meson/Kconfig | 1 +
1 file changed, 1 insertion(+)

View file

@ -1,40 +0,0 @@
From be24356f2a4214a9efbb28441f58cfd91aefb4b4 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 16 Mar 2017 09:40:16 +0100
Subject: [PATCH 02/93] pinctrl: meson: use gpio-ranges from DT
---
drivers/pinctrl/meson/pinctrl-meson.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
index 620c231a..3372ce9 100644
--- a/drivers/pinctrl/meson/pinctrl-meson.c
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -557,22 +557,10 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc)
if (ret) {
dev_err(pc->dev, "can't add gpio chip %s\n",
pc->data->name);
- goto fail;
- }
-
- ret = gpiochip_add_pin_range(&pc->chip, dev_name(pc->dev),
- 0, pc->data->pin_base,
- pc->chip.ngpio);
- if (ret) {
- dev_err(pc->dev, "can't add pin range\n");
- goto fail;
+ return ret;
}
return 0;
-fail:
- gpiochip_remove(&pc->chip);
-
- return ret;
}
static struct regmap_config meson_regmap_config = {
--
1.9.1

View file

@ -1,32 +0,0 @@
From 58d7c939ec531f768b03b0be2a714805a6aac3cf Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 16 Mar 2017 09:40:48 +0100
Subject: [PATCH 03/93] ARM64: dts: meson-gxbb: Add USB Hub GPIO hog
---
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
index c59403a..492ac35 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
@@ -177,6 +177,15 @@
pinctrl-names = "default";
};
+&gpio_ao {
+ usb-hub {
+ gpio-hog;
+ gpios = <GPIOAO_4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "usb-hub-reset";
+ };
+};
+
&usb0_phy {
status = "okay";
phy-supply = <&usb_otg_pwr>;
--
1.9.1

View file

@ -1,15 +1,16 @@
From 4dc44c40b6a55b15c2ce5189ce6b9d328b8b4344 Mon Sep 17 00:00:00 2001
From 095d92c205f588fbeb207a124eb860ea57dd568a Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Mon, 27 Mar 2017 11:08:24 +0200
Subject: [PATCH 92/93] drm: bridge: dw-hdmi: Use AUTO CTS setup mode when
Subject: [PATCH 03/79] 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 | 43 +++++++++++++++++++------------
1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 910d579..ad8d62a 100644
index 4e1f54a..ee788ca 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -420,8 +420,12 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,

View file

@ -1,75 +0,0 @@
From cbe0dba01d39c008cff6460bfcb1366801b4a41c Mon Sep 17 00:00:00 2001
From: Xinliang Liu <xinliang.liu@linaro.org>
Date: Wed, 15 Feb 2017 17:19:08 +0100
Subject: [PATCH 04/93] drm/fb-helper: Add multi buffer support for cma fbdev
This patch add a config to support to create multi buffer for cma fbdev.
Such as double buffer and triple buffer.
Cma fbdev is convient to add a legency fbdev. And still many Android
devices use fbdev now and at least double buffer is needed for these
Android devices, so that a buffer flip can be operated. It will need
some time for Android device vendors to abondon legency fbdev. So multi
buffer for fbdev is needed.
Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
[s.christ@phytec.de: Picking patch from
https://lkml.org/lkml/2015/9/14/188]
Signed-off-by: Stefan Christ <s.christ@phytec.de>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/Kconfig | 9 +++++++++
drivers/gpu/drm/drm_fb_helper.c | 10 ++++++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index ebfe840..700c8b8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -84,6 +84,15 @@ config DRM_FBDEV_EMULATION
If in doubt, say "Y".
+config DRM_FBDEV_OVERALLOC
+ int "Overallocation of the fbdev buffer"
+ depends on DRM_FBDEV_EMULATION
+ default 100
+ help
+ Defines the fbdev buffer overallocation in percent. Default
+ is 100. Typical values for double buffering will be 200,
+ triple buffering 300.
+
config DRM_LOAD_EDID_FIRMWARE
bool "Allow to specify an EDID data set instead of probing for it"
depends on DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e934b54..c6de87a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -48,6 +48,12 @@
MODULE_PARM_DESC(fbdev_emulation,
"Enable legacy fbdev emulation [default=true]");
+static int drm_fbdev_overalloc = CONFIG_DRM_FBDEV_OVERALLOC;
+module_param(drm_fbdev_overalloc, int, 0444);
+MODULE_PARM_DESC(drm_fbdev_overalloc,
+ "Overallocation of the fbdev buffer (%) [default="
+ __MODULE_STRING(CONFIG_DRM_FBDEV_OVERALLOC) "]");
+
static LIST_HEAD(kernel_fb_helper_list);
static DEFINE_MUTEX(kernel_fb_helper_lock);
@@ -1573,6 +1579,10 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
sizes.fb_height = sizes.surface_height = 768;
}
+ /* Handle our overallocation */
+ sizes.surface_height *= drm_fbdev_overalloc;
+ sizes.surface_height /= 100;
+
/* push down into drivers */
ret = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
if (ret < 0)
--
1.9.1

View file

@ -0,0 +1,26 @@
From 4923e7dd3aa1d072bb63ee46bdfc59f82de89a9c Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 30 May 2017 16:45:06 +0200
Subject: [PATCH 04/79] dt-bindings: clock: gxbb-aoclk: Add CEC 32k clock
This patchadds the clock binding entry for the CEC 32K AO Clock.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
include/dt-bindings/clock/gxbb-aoclkc.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/dt-bindings/clock/gxbb-aoclkc.h b/include/dt-bindings/clock/gxbb-aoclkc.h
index 3175148..9d15e22 100644
--- a/include/dt-bindings/clock/gxbb-aoclkc.h
+++ b/include/dt-bindings/clock/gxbb-aoclkc.h
@@ -62,5 +62,6 @@
#define CLKID_AO_UART1 3
#define CLKID_AO_UART2 4
#define CLKID_AO_IR_BLASTER 5
+#define CLKID_AO_CEC_32K 6
#endif
--
1.9.1

View file

@ -0,0 +1,376 @@
From 7e59aa215674f39cebb870b68bc0dc54c73cd407 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 30 May 2017 16:45:28 +0200
Subject: [PATCH 05/79] clk: meson: gxbb-aoclk: Add CEC 32k clock
The CEC 32K AO Clock is a dual divider with dual counter to provide a more
precise 32768Hz clock for the CEC subsystem from the external xtal.
The AO clocks management registers are spread among the AO register space,
so this patch also adds management of these registers mappings then uses them
for the CEC 32K AO clock management.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/meson/Makefile | 2 +-
drivers/clk/meson/gxbb-aoclk-32k.c | 188 +++++++++++++++++++++++++++++++++++++
drivers/clk/meson/gxbb-aoclk.c | 59 ++++++++++--
drivers/clk/meson/gxbb-aoclk.h | 23 +++++
4 files changed, 265 insertions(+), 7 deletions(-)
create mode 100644 drivers/clk/meson/gxbb-aoclk-32k.c
create mode 100644 drivers/clk/meson/gxbb-aoclk.h
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 83b6d9d..e315057 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
-obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
+obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c
new file mode 100644
index 0000000..3c06413
--- /dev/null
+++ b/drivers/clk/meson/gxbb-aoclk-32k.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include "gxbb-aoclk.h"
+
+/*
+ * The AO Domain embeds a dual/divider to generate a more precise
+ * 32,768KHz clock for low-power suspend mode and CEC.
+ */
+
+#define AO_RTC_ALT_CLK_CNTL0 0x0
+#define AO_RTC_ALT_CLK_CNTL1 0x4
+#define AO_CRT_CLK_CNTL1 0x0
+#define AO_RTI_PWR_CNTL_REG0 0x4
+
+#define CLK_CNTL0_N1_MASK GENMASK(11, 0)
+#define CLK_CNTL0_N2_MASK GENMASK(23, 12)
+#define CLK_CNTL0_DUALDIV_EN BIT(28)
+#define CLK_CNTL0_OUT_GATE_EN BIT(30)
+#define CLK_CNTL0_IN_GATE_EN BIT(31)
+
+#define CLK_CNTL1_M1_MASK GENMASK(11, 0)
+#define CLK_CNTL1_M2_MASK GENMASK(23, 12)
+#define CLK_CNTL1_BYPASS_EN BIT(24)
+#define CLK_CNTL1_SELECT_OSC BIT(27)
+
+#define PWR_CNTL_ALT_32K_SEL GENMASK(13, 10)
+
+struct cec_32k_freq_table {
+ unsigned long parent_rate;
+ unsigned long target_rate;
+ bool dualdiv;
+ unsigned int n1;
+ unsigned int n2;
+ unsigned int m1;
+ unsigned int m2;
+};
+
+static const struct cec_32k_freq_table aoclk_cec_32k_table[] = {
+ [0] = {
+ .parent_rate = 24000000,
+ .target_rate = 32768,
+ .dualdiv = true,
+ .n1 = 733,
+ .n2 = 732,
+ .m1 = 8,
+ .m2 = 11,
+ },
+};
+
+/*
+ * If CLK_CNTL0_DUALDIV_EN == 0
+ * - will use N1 divider only
+ * If CLK_CNTL0_DUALDIV_EN == 1
+ * - hold M1 cycles of N1 divider then changes to N2
+ * - hold M2 cycles of N2 divider then changes to N1
+ * Then we can get more accurate division.
+ */
+static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
+ u32 reg0, reg1;
+
+ reg0 = readl_relaxed(cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+ reg1 = readl_relaxed(cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL1);
+
+ if (reg1 & CLK_CNTL1_BYPASS_EN)
+ return parent_rate;
+
+ if (reg0 & CLK_CNTL0_DUALDIV_EN) {
+ unsigned long n1, n2, m1, m2, f1, f2, p1, p2;
+
+ n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
+ n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1;
+
+ m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1;
+ m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1;
+
+ f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
+ f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
+
+ p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
+ p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
+
+ return DIV_ROUND_UP(100000000, p1 + p2);
+ }
+ else {
+ unsigned long n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
+
+ return DIV_ROUND_CLOSEST(parent_rate, n1);
+ }
+}
+
+static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate,
+ unsigned long prate)
+{
+ int i;
+
+ for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i)
+ if (aoclk_cec_32k_table[i].parent_rate == prate &&
+ aoclk_cec_32k_table[i].target_rate == rate)
+ return &aoclk_cec_32k_table[i];
+
+ return NULL;
+}
+
+static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
+ *prate);
+
+ /* If invalid return first one */
+ if (!freq)
+ return freq[0].target_rate;
+
+ return freq->target_rate;
+}
+
+static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
+ parent_rate);
+ struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
+ u32 reg = 0;
+
+ if (!freq)
+ return -EINVAL;
+
+ /* Disable clock */
+ reg = readl(cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+ reg &= ~(CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN);
+ writel(reg, cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+
+ if (freq->dualdiv)
+ reg = CLK_CNTL0_DUALDIV_EN |
+ FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1) |
+ FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1);
+ else
+ reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1);
+
+ writel_relaxed(reg, cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+
+ if (freq->dualdiv)
+ reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1) |
+ FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1);
+ else
+ reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1);
+
+ writel_relaxed(reg, cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL1);
+
+ /* Enable clock */
+ reg = readl(cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+ reg |= CLK_CNTL0_IN_GATE_EN;
+ writel(reg, cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+
+ udelay(200);
+
+ reg |= CLK_CNTL0_OUT_GATE_EN;
+ writel(reg, cec_32k->rtc_base + AO_RTC_ALT_CLK_CNTL0);
+
+ reg = readl(cec_32k->crt_base + AO_CRT_CLK_CNTL1);
+ reg |= CLK_CNTL1_SELECT_OSC; /* select cts_rtc_oscin_clk */
+ writel(reg, cec_32k->crt_base + AO_CRT_CLK_CNTL1);
+
+ /* Select 32k from XTAL */
+ regmap_write_bits(cec_32k->pwr_regmap,
+ AO_RTI_PWR_CNTL_REG0,
+ PWR_CNTL_ALT_32K_SEL,
+ FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4));
+
+ return 0;
+}
+
+const struct clk_ops meson_aoclk_cec_32k_ops = {
+ .recalc_rate = aoclk_cec_32k_recalc_rate,
+ .round_rate = aoclk_cec_32k_round_rate,
+ .set_rate = aoclk_cec_32k_set_rate,
+};
diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c
index b45c5fb..e47f021 100644
--- a/drivers/clk/meson/gxbb-aoclk.c
+++ b/drivers/clk/meson/gxbb-aoclk.c
@@ -56,9 +56,13 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <dt-bindings/clock/gxbb-aoclkc.h>
#include <dt-bindings/reset/gxbb-aoclkc.h>
+#include "gxbb-aoclk.h"
static DEFINE_SPINLOCK(gxbb_aoclk_lock);
@@ -104,6 +108,17 @@ static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
GXBB_AO_GATE(uart2, 5);
GXBB_AO_GATE(ir_blaster, 6);
+static struct aoclk_cec_32k cec_32k_ao = {
+ .lock = &gxbb_aoclk_lock,
+ .hw.init = &(struct clk_init_data) {
+ .name = "cec_32k_ao",
+ .ops = &meson_aoclk_cec_32k_ops,
+ .parent_names = (const char *[]){ "xtal" },
+ .num_parents = 1,
+ .flags = CLK_IGNORE_UNUSED,
+ },
+};
+
static unsigned int gxbb_aoclk_reset[] = {
[RESET_AO_REMOTE] = 16,
[RESET_AO_I2C_MASTER] = 18,
@@ -130,28 +145,52 @@ static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
[CLKID_AO_UART1] = &uart1_ao.hw,
[CLKID_AO_UART2] = &uart2_ao.hw,
[CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
+ [CLKID_AO_CEC_32K] = &cec_32k_ao.hw,
},
- .num = ARRAY_SIZE(gxbb_aoclk_gate),
+ .num = 7,
};
static int gxbb_aoclkc_probe(struct platform_device *pdev)
{
- struct resource *res;
+ struct gxbb_aoclk_reset_controller *rstc;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap_pwr;
+ void __iomem *base_crt;
+ void __iomem *base_rtc;
void __iomem *base;
+ struct resource *res;
int ret, clkid;
- struct device *dev = &pdev->dev;
- struct gxbb_aoclk_reset_controller *rstc;
rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
if (!rstc)
return -ENOMEM;
/* Generic clocks */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aoclk");
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
+ /* CRT base */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aocrt");
+ base_crt = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base_crt))
+ return PTR_ERR(base_crt);
+
+ /* RTC base */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aortc");
+ base_rtc = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base_rtc))
+ return PTR_ERR(base_rtc);
+
+ /* PWR regmap */
+ regmap_pwr = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "amlogic,pwr-ctrl");
+ if (IS_ERR(regmap_pwr)) {
+ dev_err(dev, "failed to get PWR regmap\n");
+ return -ENODEV;
+ }
+
/* Reset Controller */
rstc->base = base;
rstc->data = gxbb_aoclk_reset;
@@ -163,7 +202,7 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
/*
* Populate base address and register all clks
*/
- for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) {
+ for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) {
gxbb_aoclk_gate[clkid]->reg = base;
ret = devm_clk_hw_register(dev,
@@ -172,6 +211,14 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
return ret;
}
+ /* Specific clocks */
+ cec_32k_ao.crt_base = base_crt;
+ cec_32k_ao.rtc_base = base_rtc;
+ cec_32k_ao.pwr_regmap = regmap_pwr;
+ ret = devm_clk_hw_register(dev, &cec_32k_ao.hw);
+ if (ret)
+ return ret;
+
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
&gxbb_aoclk_onecell_data);
}
diff --git a/drivers/clk/meson/gxbb-aoclk.h b/drivers/clk/meson/gxbb-aoclk.h
new file mode 100644
index 0000000..5925a6b
--- /dev/null
+++ b/drivers/clk/meson/gxbb-aoclk.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2017 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __GXBB_AOCLKC_H
+#define __GXBB_AOCLKC_H
+
+struct aoclk_cec_32k {
+ struct clk_hw hw;
+ void __iomem *crt_base;
+ void __iomem *rtc_base;
+ struct regmap *pwr_regmap;
+ spinlock_t *lock;
+};
+
+#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw)
+
+extern const struct clk_ops meson_aoclk_cec_32k_ops;
+
+#endif /* __GXBB_AOCLKC_H */
--
1.9.1

View file

@ -1,135 +0,0 @@
From c48872078789c6911e47e1c74d2024407c4daa8d Mon Sep 17 00:00:00 2001
From: Stefan Christ <s.christ@phytec.de>
Date: Wed, 15 Feb 2017 17:19:09 +0100
Subject: [PATCH 05/93] drm/fb-helper: implement ioctl FBIO_WAITFORVSYNC
Implement legacy framebuffer ioctl FBIO_WAITFORVSYNC in the generic
framebuffer emulation driver. Legacy framebuffer users like non kms/drm
based OpenGL(ES)/EGL implementations may require the ioctl to
synchronize drawing or buffer flip for double buffering. It is tested on
the i.MX6.
Code is based on
https://github.com/Xilinx/linux-xlnx/blob/master/drivers/gpu/drm/xilinx/xilinx_drm_fb.c#L196
Signed-off-by: Stefan Christ <s.christ@phytec.de>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
drivers/gpu/drm/drm_fb_helper.c | 63 +++++++++++++++++++++++++++++++++++++++++
include/drm/drm_fb_helper.h | 12 +++++++-
2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index c6de87a..15ee964 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1240,6 +1240,69 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
EXPORT_SYMBOL(drm_fb_helper_setcmap);
/**
+ * drm_fb_helper_ioctl - legacy ioctl implementation
+ * @info: fbdev registered by the helper
+ * @cmd: ioctl command
+ * @arg: ioctl argument
+ *
+ * A helper to implement the standard fbdev ioctl. Only
+ * FBIO_WAITFORVSYNC is implemented for now.
+ */
+int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_mode_set *mode_set;
+ struct drm_crtc *crtc;
+ u32 karg;
+ int ret = 0;
+
+ mutex_lock(&dev->mode_config.mutex);
+ if (!drm_fb_helper_is_bound(fb_helper)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ if (get_user(karg, (__u32 __user *)arg)) {
+ ret = -EFAULT;
+ goto unlock;
+ }
+
+ if (karg >= fb_helper->crtc_count) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ mode_set = &fb_helper->crtc_info[karg].mode_set;
+ crtc = mode_set->crtc;
+
+ /*
+ * Only wait for a vblank event if the CRTC is
+ * enabled, otherwise just don't do anythintg,
+ * not even report an error.
+ */
+ ret = drm_crtc_vblank_get(crtc);
+ if (!ret) {
+ drm_crtc_wait_one_vblank(crtc);
+ drm_crtc_vblank_put(crtc);
+ }
+
+ ret = 0;
+ goto unlock;
+ default:
+ ret = -ENOTTY;
+ }
+
+unlock:
+ mutex_unlock(&dev->mode_config.mutex);
+ return ret;
+}
+EXPORT_SYMBOL(drm_fb_helper_ioctl);
+
+/**
* drm_fb_helper_check_var - implementation for ->fb_check_var
* @var: screeninfo to check
* @info: fbdev registered by the helper
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 975deed..2891888 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -230,7 +230,8 @@ struct drm_fb_helper {
.fb_blank = drm_fb_helper_blank, \
.fb_pan_display = drm_fb_helper_pan_display, \
.fb_debug_enter = drm_fb_helper_debug_enter, \
- .fb_debug_leave = drm_fb_helper_debug_leave
+ .fb_debug_leave = drm_fb_helper_debug_leave, \
+ .fb_ioctl = drm_fb_helper_ioctl
#ifdef CONFIG_DRM_FBDEV_EMULATION
void drm_fb_helper_prepare(struct drm_device *dev, struct drm_fb_helper *helper,
@@ -286,6 +287,9 @@ void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
+int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
@@ -377,6 +381,12 @@ static inline int drm_fb_helper_setcmap(struct fb_cmap *cmap,
return 0;
}
+static inline int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ return 0;
+}
+
static inline void drm_fb_helper_unlink_fbi(struct drm_fb_helper *fb_helper)
{
}
--
1.9.1

View file

@ -0,0 +1,45 @@
From 9fa0d1f1e56768773b58eb486bf59561b1cc6e18 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 23 Jun 2017 15:27:38 +0200
Subject: [PATCH 06/79] ARM64: dts: meson-gx: Add PWR and CRT/RTC nodes and
adresses
The AO 32KHz generation registers are split among multiple registers :
- The CRT Control
- The RTC Clock Control
- The AO Domain PWR Control
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 436b875..4fd2926 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -358,11 +358,20 @@
#size-cells = <2>;
ranges = <0x0 0x0 0x0 0xc8100000 0x0 0x100000>;
+ pwr_AO: power-control@00c {
+ compatible = "amlogic,gx-pwr-ctrl", "syscon";
+ reg = <0x0 0x0000c 0x0 0x8>;
+ };
+
clkc_AO: clock-controller@040 {
compatible = "amlogic,gx-aoclkc", "amlogic,gxbb-aoclkc";
- reg = <0x0 0x00040 0x0 0x4>;
+ reg = <0x0 0x00040 0x0 0x4>,
+ <0x0 0x00068 0x0 0x4>,
+ <0x0 0x00094 0x0 0x8>;
+ reg-names = "aoclk", "aocrt", "aortc";
#clock-cells = <1>;
#reset-cells = <1>;
+ amlogic,pwr-ctrl = <&pwr_AO>;
};
uart_AO: serial@4c0 {
--
1.9.1

View file

@ -1,24 +0,0 @@
From e0c4b1d6b1ac850cb22d574bb485b3cc2ed36903 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 28 Feb 2017 15:23:14 +0100
Subject: [PATCH 06/93] Disable DRM fbdev FBIO_WAITFORVSYNC to achieve full FPS
---
drivers/gpu/drm/drm_fb_helper.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 15ee964..7b739a8 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1266,6 +1266,7 @@ int drm_fb_helper_ioctl(struct fb_info *info, unsigned int cmd,
switch (cmd) {
case FBIO_WAITFORVSYNC:
+ goto unlock;
if (get_user(karg, (__u32 __user *)arg)) {
ret = -EFAULT;
goto unlock;
--
1.9.1

View file

@ -0,0 +1,208 @@
From abcaac146da294f437f1a8589b27aced142b4da5 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 30 May 2017 16:46:16 +0200
Subject: [PATCH 07/79] ARM64: dts: meson-gx: Add AO CEC nodes
This patch adds the AO CEC node in all the HDMI enabled boards DTS.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 6 ++++++
arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 6 ++++++
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts | 7 +++++++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 6 ++++++
arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 7 +++++++
10 files changed, 67 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 a84e276..54718ee 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
@@ -210,6 +210,13 @@
status = "okay";
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 4fd2926..8901eeb 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -374,6 +374,12 @@
amlogic,pwr-ctrl = <&pwr_AO>;
};
+ cec_AO: cec@100 {
+ compatible = "amlogic,meson-gx-ao-cec";
+ reg = <0x0 0x00100 0x0 0x14>;
+ interrupts = <GIC_SPI 199 IRQ_TYPE_EDGE_RISING>;
+ };
+
uart_AO: serial@4c0 {
compatible = "amlogic,meson-uart";
reg = <0x0 0x004c0 0x0 0x14>;
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 87198ea..9af807e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
@@ -171,6 +171,13 @@
pinctrl-names = "default";
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&ethmac {
status = "okay";
pinctrl-0 = <&eth_rmii_pins>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 3c6c0b7..3ed5c99 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -250,6 +250,13 @@
clock-names = "clkin0";
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 86105a6..d760d93 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -97,6 +97,12 @@
};
};
+
+&cec_AO {
+ clocks = <&clkc_AO CLKID_AO_CEC_32K>;
+ clock-names = "core";
+};
+
&ethmac {
clocks = <&clkc CLKID_ETH>,
<&clkc CLKID_FCLK_DIV2>,
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
index f9fbfda..49e19aa 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -86,6 +86,13 @@
};
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
/* P230 has exclusive choice between internal or external PHY */
&ethmac {
pinctrl-0 = <&eth_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 8873c05..55ec11a 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
@@ -225,6 +225,13 @@
clock-names = "clkin0";
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
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 db31e09..99a01ff 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
@@ -60,6 +60,13 @@
};
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index d8e096d..3a1ccf5 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -43,6 +43,7 @@
#include "meson-gx.dtsi"
#include <dt-bindings/clock/gxbb-clkc.h>
+#include <dt-bindings/clock/gxbb-aoclkc.h>
#include <dt-bindings/gpio/meson-gxl-gpio.h>
#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
@@ -564,6 +565,11 @@
compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
};
+&cec_AO {
+ clocks = <&clkc_AO CLKID_AO_CEC_32K>;
+ clock-names = "core";
+};
+
&hdmi_tx {
compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
resets = <&reset RESET_HDMITX_CAPB3>,
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 11b0bf4..3a327dd 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
@@ -191,6 +191,13 @@
};
};
+&cec_AO {
+ status = "okay";
+ pinctrl-0 = <&ao_cec_pins>;
+ pinctrl-names = "default";
+ hdmi-phandle = <&hdmi_tx>;
+};
+
&cvbs_vdac_port {
cvbs_vdac_out: endpoint {
remote-endpoint = <&cvbs_connector_in>;
--
1.9.1

View file

@ -1,442 +0,0 @@
From bc80d5294931d37c19ef76d0a1bb144ad51b66f9 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 1 Feb 2017 11:45:04 +0100
Subject: [PATCH 07/93] clk: meson-gxbb: Add MALI clocks and fix GP0 pll
support
The Mali is clocked by two identical clock paths behind a glitch free mux
to safely change frequency while running.
The optimal clock frequency is provided by the GP0 PLL, but unlike Meson8 the
GXBB GP0 PLL needs some tweaking and need some SoC specific values to be set
in order to setup the PLL.
Since these values will change for GXL and GXM, add an init table that will
be changed for GXL or GXM.
For the MALI clocks, introduce them as Composite clocks to simplify the
management.
To handle composite clocks, a gxbb_composite structure is added to dynamically
create the composite clock at probe and fill accordingly the DT table.
Finally the glitch free mux is added and other muxes and dividers are also
grouped in initialization tables.
---
drivers/clk/meson/clk-pll.c | 34 ++++--
drivers/clk/meson/clkc.h | 3 +
drivers/clk/meson/gxbb.c | 211 +++++++++++++++++++++++++++++++++-
drivers/clk/meson/gxbb.h | 7 +-
include/dt-bindings/clock/gxbb-clkc.h | 4 +
5 files changed, 245 insertions(+), 14 deletions(-)
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
index 4adc1e8..b5ff81b 100644
--- a/drivers/clk/meson/clk-pll.c
+++ b/drivers/clk/meson/clk-pll.c
@@ -132,6 +132,24 @@ static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll,
return -ETIMEDOUT;
}
+static void meson_clk_pll_init(struct meson_clk_pll *pll)
+{
+ if (pll->init_count && pll->init_regs && pll->init_data) {
+ unsigned int i;
+
+ for (i = 0; i < pll->init_count; ++i)
+ writel(pll->init_data[i], pll->init_regs[i]);
+ } else {
+ struct parm *p;
+ u32 reg;
+
+ /* PLL reset */
+ p = &pll->n;
+ reg = readl(pll->base + p->reg_off);
+ writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
+ }
+}
+
static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -151,19 +169,18 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
if (!rate_set)
return -EINVAL;
- /* PLL reset */
- p = &pll->n;
- reg = readl(pll->base + p->reg_off);
- writel(reg | MESON_PLL_RESET, pll->base + p->reg_off);
-
- reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
- writel(reg, pll->base + p->reg_off);
+ meson_clk_pll_init(pll);
p = &pll->m;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->m);
writel(reg, pll->base + p->reg_off);
+ p = &pll->n;
+ reg = readl(pll->base + p->reg_off);
+ reg = PARM_SET(p->width, p->shift, reg, rate_set->n);
+ writel(reg, pll->base + p->reg_off);
+
p = &pll->od;
reg = readl(pll->base + p->reg_off);
reg = PARM_SET(p->width, p->shift, reg, rate_set->od);
@@ -184,6 +201,9 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
p = &pll->n;
+ reg = readl(pll->base + p->reg_off);
+ writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off);
+
ret = meson_clk_pll_wait_lock(pll, p);
if (ret) {
pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
index 9bb70e7..22a6335 100644
--- a/drivers/clk/meson/clkc.h
+++ b/drivers/clk/meson/clkc.h
@@ -70,6 +70,9 @@ struct meson_clk_pll {
struct parm frac;
struct parm od;
struct parm od2;
+ void __iomem **init_regs;
+ u32 *init_data;
+ unsigned int init_count;
const struct pll_rate_table *rate_table;
unsigned int rate_count;
spinlock_t *lock;
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index 9d9af44..d1dac0f 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -352,6 +352,20 @@
},
};
+static void __iomem *gxbb_gp0_init_regs[] = {
+ (void *)HHI_GP0_PLL_CNTL,
+ (void *)HHI_GP0_PLL_CNTL2,
+ (void *)HHI_GP0_PLL_CNTL3,
+ (void *)HHI_GP0_PLL_CNTL4,
+};
+
+static u32 gxbb_gp0_init_data[] = {
+ 0x6a000228,
+ 0x69c80000,
+ 0x0a5590c4,
+ 0x0000500d,
+};
+
static struct meson_clk_pll gxbb_gp0_pll = {
.m = {
.reg_off = HHI_GP0_PLL_CNTL,
@@ -368,6 +382,9 @@
.shift = 16,
.width = 2,
},
+ .init_regs = gxbb_gp0_init_regs,
+ .init_data = gxbb_gp0_init_data,
+ .init_count = 4,
.rate_table = gp0_pll_rate_table,
.rate_count = ARRAY_SIZE(gp0_pll_rate_table),
.lock = &clk_lock,
@@ -550,6 +567,75 @@
},
};
+/* Mali Clock components */
+static u32 mux_table_mali_0_1[] = {0, 1, 2, 3, 4, 5, 6, 7};
+const char *gxbb_mali_0_1_parent_names[] = {
+ "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7",
+ "fclk_div4", "fclk_div3", "fclk_div5"
+};
+
+static struct clk_mux gxbb_mali_0_sel = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .mask = 0x3,
+ .shift = 9,
+ .table = mux_table_mali_0_1,
+ .lock = &clk_lock,
+};
+
+static struct clk_divider gxbb_mali_0_div = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .shift = 0,
+ .width = 7,
+ .lock = &clk_lock,
+};
+
+static struct clk_gate gxbb_mali_0_en = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .bit_idx = 8,
+ .lock = &clk_lock,
+};
+
+static struct clk_mux gxbb_mali_1_sel = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .mask = 0x3,
+ .shift = 25,
+ .table = mux_table_mali_0_1,
+ .lock = &clk_lock,
+};
+
+static struct clk_divider gxbb_mali_1_div = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .shift = 16,
+ .width = 7,
+ .lock = &clk_lock,
+};
+
+static struct clk_gate gxbb_mali_1_en = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .bit_idx = 24,
+ .lock = &clk_lock,
+};
+
+static u32 mux_table_mali[] = {0, 1};
+const char *gxbb_mali_parent_names[] = {
+ "mali_0", "mali_1"
+};
+
+static struct clk_mux gxbb_mali = {
+ .reg = (void *)HHI_MALI_CLK_CNTL,
+ .mask = 1,
+ .shift = 31,
+ .table = mux_table_mali,
+ .lock = &clk_lock,
+ .hw.init = &(struct clk_init_data){
+ .name = "mali",
+ .ops = &clk_mux_ops,
+ .parent_names = gxbb_mali_parent_names,
+ .num_parents = 2,
+ .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED),
+ },
+};
+
/* the mother of dragons^W gates */
static struct clk_gate gxbb_clk81 = {
.reg = (void *)HHI_MPEG_CLK_CNTL,
@@ -754,6 +840,9 @@
[CLKID_SD_EMMC_A] = &gxbb_emmc_a.hw,
[CLKID_SD_EMMC_B] = &gxbb_emmc_b.hw,
[CLKID_SD_EMMC_C] = &gxbb_emmc_c.hw,
+ [CLKID_MALI] = &gxbb_mali.hw,
+ /* This sentinel entry makes sure the table is large enough */
+ [NR_CLKS] = NULL, /* Sentinel */
},
.num = NR_CLKS,
};
@@ -856,6 +945,66 @@
&gxbb_emmc_a,
&gxbb_emmc_b,
&gxbb_emmc_c,
+ &gxbb_mali_0_en,
+ &gxbb_mali_1_en,
+};
+
+static struct clk_mux *gxbb_clk_muxes[] = {
+ &gxbb_mpeg_clk_sel,
+ &gxbb_mali_0_sel,
+ &gxbb_mali_1_sel,
+ &gxbb_mali,
+};
+
+static struct clk_divider *gxbb_clk_dividers[] = {
+ &gxbb_mpeg_clk_div,
+ &gxbb_mali_0_div,
+ &gxbb_mali_1_div,
+};
+
+struct gxbb_composite_clk {
+ unsigned int id;
+ const char *name;
+ const char * const *parent_names;
+ int num_parents;
+ struct clk_hw *mux_hw;
+ const struct clk_ops *mux_ops;
+ struct clk_hw *rate_hw;
+ const struct clk_ops *rate_ops;
+ struct clk_hw *gate_hw;
+ const struct clk_ops *gate_ops;
+ unsigned long flags;
+};
+
+/* Convenient table to register the composite clocks */
+
+static struct gxbb_composite_clk gxbb_composite_clks[] = {
+ {
+ .id = CLKID_MALI_0,
+ .name = "mali_0",
+ .parent_names = gxbb_mali_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(gxbb_mali_0_1_parent_names),
+ .mux_hw = &gxbb_mali_0_sel.hw,
+ .mux_ops = &clk_mux_ops,
+ .rate_hw = &gxbb_mali_0_div.hw,
+ .rate_ops = &clk_divider_ops,
+ .gate_hw = &gxbb_mali_0_en.hw,
+ .gate_ops = &clk_gate_ops,
+ .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED),
+ },
+ {
+ .id = CLKID_MALI_1,
+ .name = "mali_1",
+ .parent_names = gxbb_mali_0_1_parent_names,
+ .num_parents = ARRAY_SIZE(gxbb_mali_0_1_parent_names),
+ .mux_hw = &gxbb_mali_1_sel.hw,
+ .mux_ops = &clk_mux_ops,
+ .rate_hw = &gxbb_mali_1_div.hw,
+ .rate_ops = &clk_divider_ops,
+ .gate_hw = &gxbb_mali_1_en.hw,
+ .gate_ops = &clk_gate_ops,
+ .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED),
+ },
};
static int gxbb_clkc_probe(struct platform_device *pdev)
@@ -884,24 +1033,61 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
/* Populate the base address for CPU clk */
gxbb_cpu_clk.base = clk_base;
- /* Populate the base address for the MPEG clks */
- gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg;
- gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg;
+ /* Populate base address for muxes */
+ for (i = 0; i < ARRAY_SIZE(gxbb_clk_muxes); i++)
+ gxbb_clk_muxes[i]->reg = clk_base +
+ (u64)gxbb_clk_muxes[i]->reg;
+
+ /* Populate base address for dividers */
+ for (i = 0; i < ARRAY_SIZE(gxbb_clk_dividers); i++)
+ gxbb_clk_dividers[i]->reg = clk_base +
+ (u64)gxbb_clk_dividers[i]->reg;
/* Populate base address for gates */
for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++)
gxbb_clk_gates[i]->reg = clk_base +
(u64)gxbb_clk_gates[i]->reg;
+ /* Populate base for GP0 init table */
+ for (i = 0; i < ARRAY_SIZE(gxbb_gp0_init_regs); ++i)
+ gxbb_gp0_init_regs[i] = clk_base +
+ (u64)gxbb_gp0_init_regs[i];
+
/*
* register all clks
*/
for (clkid = 0; clkid < NR_CLKS; clkid++) {
+ if (!gxbb_hw_onecell_data.hws[clkid])
+ continue;
+
ret = devm_clk_hw_register(dev, gxbb_hw_onecell_data.hws[clkid]);
if (ret)
goto iounmap;
}
+ /* Register Composite Clocks */
+ for (i = 0 ; i < ARRAY_SIZE(gxbb_composite_clks); ++i) {
+ struct gxbb_composite_clk *comp = &gxbb_composite_clks[i];
+ struct clk_hw *hw;
+
+ hw = clk_hw_register_composite(dev, comp->name,
+ comp->parent_names,
+ comp->num_parents,
+ comp->mux_hw, comp->mux_ops,
+ comp->rate_hw, comp->rate_ops,
+ comp->gate_hw, comp->gate_ops,
+ comp->flags);
+ if (IS_ERR(hw)) {
+ ret = PTR_ERR(hw);
+
+ pr_err("%s: Failed to register composite clock %s\n",
+ __func__, comp->name);
+
+ goto unregister_composites;
+ }
+ gxbb_hw_onecell_data.hws[comp->id] = hw;
+ }
+
/*
* Register CPU clk notifier
*
@@ -922,11 +1108,26 @@ static int gxbb_clkc_probe(struct platform_device *pdev)
if (ret) {
pr_err("%s: failed to register clock notifier for cpu_clk\n",
__func__);
- goto iounmap;
+ goto unregister_composites;
}
- return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
&gxbb_hw_onecell_data);
+ if (!ret)
+ return ret;
+
+unregister_composites:
+ for (i = 0 ; i < ARRAY_SIZE(gxbb_composite_clks); ++i) {
+ struct gxbb_composite_clk *comp = &gxbb_composite_clks[i];
+ struct clk *clk;
+
+ if (gxbb_hw_onecell_data.hws[comp->id]) {
+ clk = gxbb_hw_onecell_data.hws[comp->id]->clk;
+ clk_unregister_composite(clk);
+ }
+
+ gxbb_hw_onecell_data.hws[comp->id] = NULL;
+ }
iounmap:
iounmap(clk_base);
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 0252939..f79ab57 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -177,7 +177,7 @@
/* CLKID_FCLK_DIV4 */
#define CLKID_FCLK_DIV5 7
#define CLKID_FCLK_DIV7 8
-#define CLKID_GP0_PLL 9
+/* CLKID_GP0_PLL */
#define CLKID_MPEG_SEL 10
#define CLKID_MPEG_DIV 11
/* CLKID_CLK81 */
@@ -265,8 +265,11 @@
/* CLKID_SD_EMMC_A */
/* CLKID_SD_EMMC_B */
/* CLKID_SD_EMMC_C */
+/* CLKID_MALI_0 */
+/* CLKID_MALI_1 */
+/* CLKID_MALI */
-#define NR_CLKS 97
+#define NR_CLKS 100
/* include the CLKIDs that have been made part of the stable DT binding */
#include <dt-bindings/clock/gxbb-clkc.h>
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index baade6f..7bbc1d0 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -10,6 +10,7 @@
#define CLKID_FCLK_DIV2 4
#define CLKID_FCLK_DIV3 5
#define CLKID_FCLK_DIV4 6
+#define CLKID_GP0_PLL 9
#define CLKID_CLK81 12
#define CLKID_MPLL2 15
#define CLKID_SPI 34
@@ -24,5 +25,8 @@
#define CLKID_SD_EMMC_A 94
#define CLKID_SD_EMMC_B 95
#define CLKID_SD_EMMC_C 96
+#define CLKID_MALI_0 97
+#define CLKID_MALI_1 98
+#define CLKID_MALI 99
#endif /* __GXBB_CLKC_H */
--
1.9.1

View file

@ -1,61 +0,0 @@
From 992ae3b904d0ace47dcf33f8cc117a17f1cff0c2 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 1 Feb 2017 11:45:40 +0100
Subject: [PATCH 08/93] ARM64: dts: meson-gxbb: Add Mali node
Add the Mali-450 MP3 node for GXBB.
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 37 +++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 2be29a3..bbb034d 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -476,6 +476,43 @@
};
};
+&apb {
+ mali: gpu@c0000 {
+ compatible = "amlogic,meson-gxbb-mali", "arm,mali-450";
+ reg = <0x0 0xc0000 0x0 0x40000>;
+ interrupts = <GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 161 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 162 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "gp", "gpmmu", "pp", "pmu",
+ "pp0", "ppmmu0", "pp1", "ppmmu1",
+ "pp2", "ppmmu2";
+ clocks = <&clkc CLKID_CLK81>, <&clkc CLKID_MALI>;
+ clock-names = "bus", "core";
+
+ /*
+ * Mali clocking is provided by two identical clock paths
+ * MALI_0 and MALI_1 muxed to a single clock by a glitch
+ * free mux to safely change frequency while running.
+ */
+ assigned-clocks = <&clkc CLKID_GP0_PLL>,
+ <&clkc CLKID_MALI_0>,
+ <&clkc CLKID_MALI>; /* Glitch free mux */
+ assigned-clock-parents = <0>, /* Do Nothing */
+ <&clkc CLKID_GP0_PLL>,
+ <&clkc CLKID_MALI_0>;
+ assigned-clock-rates = <744000000>,
+ <744000000>,
+ <0>; /* Do Nothing */
+ };
+};
+
&i2c_A {
clocks = <&clkc CLKID_I2C>;
};
--
1.9.1

View file

@ -0,0 +1,81 @@
From ab3f6488b7ea751456324f57d27179599c151136 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Fri, 4 Dec 2015 10:47:35 +0000
Subject: [PATCH 08/79] drm/bridge: dw_hdmi: add cec notifier support
Add CEC notifier support to the HDMI bridge driver, so that the CEC
part of the IP can receive its physical address.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index ee788ca..5eff1e5 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -33,6 +33,8 @@
#include <uapi/linux/media-bus-format.h>
#include <uapi/linux/videodev2.h>
+#include <media/cec-notifier.h>
+
#include "dw-hdmi.h"
#include "dw-hdmi-audio.h"
@@ -173,6 +175,8 @@ struct dw_hdmi {
unsigned int reg_shift;
struct regmap *regm;
+
+ struct cec_notifier *cec_notifier;
};
#define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -1881,6 +1885,7 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
drm_mode_connector_update_edid_property(connector, edid);
+ cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid);
ret = drm_add_edid_modes(connector, edid);
/* Store the ELD */
drm_edid_to_eld(connector, edid);
@@ -2077,6 +2082,10 @@ void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
dw_hdmi_update_phy_mask(hdmi);
}
mutex_unlock(&hdmi->mutex);
+
+ if (!rx_sense && !hpd)
+ cec_notifier_set_phys_addr(hdmi->cec_notifier,
+ CEC_PHYS_ADDR_INVALID);
}
void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
@@ -2376,6 +2385,12 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
if (ret)
goto err_iahb;
+ hdmi->cec_notifier = cec_notifier_get(dev);
+ if (!hdmi->cec_notifier) {
+ ret = -ENOMEM;
+ goto err_iahb;
+ }
+
/*
* To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
* N and cts values before enabling phy
@@ -2448,6 +2463,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
hdmi->ddc = NULL;
}
+ if (hdmi->cec_notifier)
+ cec_notifier_put(hdmi->cec_notifier);
+
clk_disable_unprepare(hdmi->iahb_clk);
err_isfr:
clk_disable_unprepare(hdmi->isfr_clk);
--
1.9.1

View file

@ -1,212 +0,0 @@
From d7efc514cff47e958849fa122bc81839541b3dba Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 18 Jan 2017 10:33:04 +0100
Subject: [PATCH 09/93] ARM64: dts: meson-gxbb: Add support for WeTek Hub and
Play
Adds support for the WeTek Hub and Play2 boards.
The Hub is an extremely small IPTv Set-Top-Box and the Play2 is a more
traditionnal Satellite or Terrestrial and IPTv Set-Top-Box.
Both are based on the p200 Reference Design and out-of-tree support is
based on OpenELEC kernel at [1].
[1] https://github.com/wetek-enigma/linux-amlogic
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/Makefile | 2 +
.../boot/dts/amlogic/meson-gxbb-wetek-hub.dts | 66 +++++++++++++++
.../boot/dts/amlogic/meson-gxbb-wetek-play2.dts | 94 ++++++++++++++++++++++
3 files changed, 162 insertions(+)
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts
create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile
index 0d7bfbf..cc2e2dd 100644
--- a/arch/arm64/boot/dts/amlogic/Makefile
+++ b/arch/arm64/boot/dts/amlogic/Makefile
@@ -5,6 +5,8 @@ dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-p201.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-pro.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-hub.dtb
+dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-play2.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb
dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts
new file mode 100644
index 0000000..56f8559
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016 BayLibre, Inc.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxbb-p20x.dtsi"
+
+/ {
+ compatible = "wetek,hub", "amlogic,meson-gxbb";
+ model = "WeTek Hub";
+
+ leds {
+ compatible = "gpio-leds";
+
+ system {
+ label = "wetek-play:system-status";
+ gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ panic-indicator;
+ };
+ };
+
+ cvbs-connector {
+ status = "disabled";
+ };
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
new file mode 100644
index 0000000..ea79fdd
--- /dev/null
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016 BayLibre, Inc.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "meson-gxbb-p20x.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "wetek,play2", "amlogic,meson-gxbb";
+ model = "WeTek Play 2";
+
+ leds {
+ compatible = "gpio-leds";
+
+ system {
+ label = "wetek-play:system-status";
+ gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ panic-indicator;
+ };
+
+ wifi {
+ label = "wetek-play:wifi-status";
+ gpios = <&gpio GPIODV_26 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ ethernet {
+ label = "wetek-play:ethernet-status";
+ gpios = <&gpio GPIODV_27 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <100>;
+
+ button@0 {
+ label = "reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio_ao GPIOAO_3 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&i2c_A {
+ status = "okay";
+ pinctrl-0 = <&i2c_a_pins>;
+ pinctrl-names = "default";
+};
--
1.9.1

View file

@ -0,0 +1,724 @@
From c3be57d7fef20314fffd81e74b70ea75e35a4d26 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 30 May 2017 15:50:21 +0200
Subject: [PATCH 09/79] platform: Add Amlogic Meson AO CEC Controller driver
The Amlogic SoC embeds a standalone CEC controller, this patch adds a driver
for such controller.
The controller does not need HPD to be active, and could support up to max
5 logical addresses, but only 1 is handled since the Suspend firmware can
make use of this unique logical address to wake up the device.
The Suspend firmware configuration will be added in an other patchset.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/media/platform/Kconfig | 11 +
drivers/media/platform/Makefile | 2 +
drivers/media/platform/meson/Makefile | 1 +
drivers/media/platform/meson/ao-cec.c | 653 ++++++++++++++++++++++++++++++++++
4 files changed, 667 insertions(+)
create mode 100644 drivers/media/platform/meson/Makefile
create mode 100644 drivers/media/platform/meson/ao-cec.c
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 041cb80..857e068 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -499,6 +499,17 @@ menuconfig CEC_PLATFORM_DRIVERS
if CEC_PLATFORM_DRIVERS
+config VIDEO_MESON_AO_CEC
+ tristate "Amlogic Meson AO CEC driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ select CEC_CORE
+ select CEC_NOTIFIER
+ ---help---
+ This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the
+ generic CEC framework interface.
+ CEC bus is present in the HDMI connector and enables communication
+ between compatible devices.
+
config VIDEO_SAMSUNG_S5P_CEC
tristate "Samsung S5P CEC driver"
depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 63303d6..db15c59 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -77,3 +77,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/
obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/
obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/
+
+obj-y += meson/
diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile
new file mode 100644
index 0000000..597beb8
--- /dev/null
+++ b/drivers/media/platform/meson/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o
diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c
new file mode 100644
index 0000000..26d7c3e8
--- /dev/null
+++ b/drivers/media/platform/meson/ao-cec.c
@@ -0,0 +1,653 @@
+/*
+ * Driver for Amlogic Meson AO CEC Controller
+ *
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved
+ * Copyright (C) 2017 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <media/cec.h>
+#include <media/cec-notifier.h>
+
+/* CEC Registers */
+
+/*
+ * [2:1] cntl_clk
+ * - 0 = Disable clk (Power-off mode)
+ * - 1 = Enable gated clock (Normal mode)
+ * - 2 = Enable free-run clk (Debug mode)
+ */
+#define CEC_GEN_CNTL_REG 0x00
+
+#define CEC_GEN_CNTL_RESET BIT(0)
+#define CEC_GEN_CNTL_CLK_DISABLE 0
+#define CEC_GEN_CNTL_CLK_ENABLE 1
+#define CEC_GEN_CNTL_CLK_ENABLE_DBG 2
+#define CEC_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1)
+
+/*
+ * [7:0] cec_reg_addr
+ * [15:8] cec_reg_wrdata
+ * [16] cec_reg_wr
+ * - 0 = Read
+ * - 1 = Write
+ * [23] bus free
+ * [31:24] cec_reg_rddata
+ */
+#define CEC_RW_REG 0x04
+
+#define CEC_RW_ADDR GENMASK(7, 0)
+#define CEC_RW_WR_DATA GENMASK(15, 8)
+#define CEC_RW_WRITE_EN BIT(16)
+#define CEC_RW_BUS_BUSY BIT(23)
+#define CEC_RW_RD_DATA GENMASK(31, 24)
+
+/*
+ * [1] tx intr
+ * [2] rx intr
+ */
+#define CEC_INTR_MASKN_REG 0x08
+#define CEC_INTR_CLR_REG 0x0c
+#define CEC_INTR_STAT_REG 0x10
+
+#define CEC_INTR_TX BIT(1)
+#define CEC_INTR_RX BIT(2)
+
+/* CEC Commands */
+
+#define CEC_TX_MSG_0_HEADER 0x00
+#define CEC_TX_MSG_1_OPCODE 0x01
+#define CEC_TX_MSG_2_OP1 0x02
+#define CEC_TX_MSG_3_OP2 0x03
+#define CEC_TX_MSG_4_OP3 0x04
+#define CEC_TX_MSG_5_OP4 0x05
+#define CEC_TX_MSG_6_OP5 0x06
+#define CEC_TX_MSG_7_OP6 0x07
+#define CEC_TX_MSG_8_OP7 0x08
+#define CEC_TX_MSG_9_OP8 0x09
+#define CEC_TX_MSG_A_OP9 0x0A
+#define CEC_TX_MSG_B_OP10 0x0B
+#define CEC_TX_MSG_C_OP11 0x0C
+#define CEC_TX_MSG_D_OP12 0x0D
+#define CEC_TX_MSG_E_OP13 0x0E
+#define CEC_TX_MSG_F_OP14 0x0F
+#define CEC_TX_MSG_LENGTH 0x10
+#define CEC_TX_MSG_CMD 0x11
+#define CEC_TX_WRITE_BUF 0x12
+#define CEC_TX_CLEAR_BUF 0x13
+#define CEC_RX_MSG_CMD 0x14
+#define CEC_RX_CLEAR_BUF 0x15
+#define CEC_LOGICAL_ADDR0 0x16
+#define CEC_LOGICAL_ADDR1 0x17
+#define CEC_LOGICAL_ADDR2 0x18
+#define CEC_LOGICAL_ADDR3 0x19
+#define CEC_LOGICAL_ADDR4 0x1A
+#define CEC_CLOCK_DIV_H 0x1B
+#define CEC_CLOCK_DIV_L 0x1C
+#define CEC_QUIESCENT_25MS_BIT7_0 0x20
+#define CEC_QUIESCENT_25MS_BIT11_8 0x21
+#define CEC_STARTBITMINL2H_3MS5_BIT7_0 0x22
+#define CEC_STARTBITMINL2H_3MS5_BIT8 0x23
+#define CEC_STARTBITMAXL2H_3MS9_BIT7_0 0x24
+#define CEC_STARTBITMAXL2H_3MS9_BIT8 0x25
+#define CEC_STARTBITMINH_0MS6_BIT7_0 0x26
+#define CEC_STARTBITMINH_0MS6_BIT8 0x27
+#define CEC_STARTBITMAXH_1MS0_BIT7_0 0x28
+#define CEC_STARTBITMAXH_1MS0_BIT8 0x29
+#define CEC_STARTBITMINTOT_4MS3_BIT7_0 0x2A
+#define CEC_STARTBITMINTOT_4MS3_BIT9_8 0x2B
+#define CEC_STARTBITMAXTOT_4MS7_BIT7_0 0x2C
+#define CEC_STARTBITMAXTOT_4MS7_BIT9_8 0x2D
+#define CEC_LOGIC1MINL2H_0MS4_BIT7_0 0x2E
+#define CEC_LOGIC1MINL2H_0MS4_BIT8 0x2F
+#define CEC_LOGIC1MAXL2H_0MS8_BIT7_0 0x30
+#define CEC_LOGIC1MAXL2H_0MS8_BIT8 0x31
+#define CEC_LOGIC0MINL2H_1MS3_BIT7_0 0x32
+#define CEC_LOGIC0MINL2H_1MS3_BIT8 0x33
+#define CEC_LOGIC0MAXL2H_1MS7_BIT7_0 0x34
+#define CEC_LOGIC0MAXL2H_1MS7_BIT8 0x35
+#define CEC_LOGICMINTOTAL_2MS05_BIT7_0 0x36
+#define CEC_LOGICMINTOTAL_2MS05_BIT9_8 0x37
+#define CEC_LOGICMAXHIGH_2MS8_BIT7_0 0x38
+#define CEC_LOGICMAXHIGH_2MS8_BIT8 0x39
+#define CEC_LOGICERRLOW_3MS4_BIT7_0 0x3A
+#define CEC_LOGICERRLOW_3MS4_BIT8 0x3B
+#define CEC_NOMSMPPOINT_1MS05 0x3C
+#define CEC_DELCNTR_LOGICERR 0x3E
+#define CEC_TXTIME_17MS_BIT7_0 0x40
+#define CEC_TXTIME_17MS_BIT10_8 0x41
+#define CEC_TXTIME_2BIT_BIT7_0 0x42
+#define CEC_TXTIME_2BIT_BIT10_8 0x43
+#define CEC_TXTIME_4BIT_BIT7_0 0x44
+#define CEC_TXTIME_4BIT_BIT10_8 0x45
+#define CEC_STARTBITNOML2H_3MS7_BIT7_0 0x46
+#define CEC_STARTBITNOML2H_3MS7_BIT8 0x47
+#define CEC_STARTBITNOMH_0MS8_BIT7_0 0x48
+#define CEC_STARTBITNOMH_0MS8_BIT8 0x49
+#define CEC_LOGIC1NOML2H_0MS6_BIT7_0 0x4A
+#define CEC_LOGIC1NOML2H_0MS6_BIT8 0x4B
+#define CEC_LOGIC0NOML2H_1MS5_BIT7_0 0x4C
+#define CEC_LOGIC0NOML2H_1MS5_BIT8 0x4D
+#define CEC_LOGIC1NOMH_1MS8_BIT7_0 0x4E
+#define CEC_LOGIC1NOMH_1MS8_BIT8 0x4F
+#define CEC_LOGIC0NOMH_0MS9_BIT7_0 0x50
+#define CEC_LOGIC0NOMH_0MS9_BIT8 0x51
+#define CEC_LOGICERRLOW_3MS6_BIT7_0 0x52
+#define CEC_LOGICERRLOW_3MS6_BIT8 0x53
+#define CEC_CHKCONTENTION_0MS1 0x54
+#define CEC_PREPARENXTBIT_0MS05_BIT7_0 0x56
+#define CEC_PREPARENXTBIT_0MS05_BIT8 0x57
+#define CEC_NOMSMPACKPOINT_0MS45 0x58
+#define CEC_ACK0NOML2H_1MS5_BIT7_0 0x5A
+#define CEC_ACK0NOML2H_1MS5_BIT8 0x5B
+#define CEC_BUGFIX_DISABLE_0 0x60
+#define CEC_BUGFIX_DISABLE_1 0x61
+#define CEC_RX_MSG_0_HEADER 0x80
+#define CEC_RX_MSG_1_OPCODE 0x81
+#define CEC_RX_MSG_2_OP1 0x82
+#define CEC_RX_MSG_3_OP2 0x83
+#define CEC_RX_MSG_4_OP3 0x84
+#define CEC_RX_MSG_5_OP4 0x85
+#define CEC_RX_MSG_6_OP5 0x86
+#define CEC_RX_MSG_7_OP6 0x87
+#define CEC_RX_MSG_8_OP7 0x88
+#define CEC_RX_MSG_9_OP8 0x89
+#define CEC_RX_MSG_A_OP9 0x8A
+#define CEC_RX_MSG_B_OP10 0x8B
+#define CEC_RX_MSG_C_OP11 0x8C
+#define CEC_RX_MSG_D_OP12 0x8D
+#define CEC_RX_MSG_E_OP13 0x8E
+#define CEC_RX_MSG_F_OP14 0x8F
+#define CEC_RX_MSG_LENGTH 0x90
+#define CEC_RX_MSG_STATUS 0x91
+#define CEC_RX_NUM_MSG 0x92
+#define CEC_TX_MSG_STATUS 0x93
+#define CEC_TX_NUM_MSG 0x94
+
+
+/* CEC_TX_MSG_CMD definition */
+#define TX_NO_OP 0 /* No transaction */
+#define TX_REQ_CURRENT 1 /* Transmit earliest message in buffer */
+#define TX_ABORT 2 /* Abort transmitting earliest message */
+#define TX_REQ_NEXT 3 /* Overwrite earliest msg, transmit next */
+
+/* tx_msg_status definition */
+#define TX_IDLE 0 /* No transaction */
+#define TX_BUSY 1 /* Transmitter is busy */
+#define TX_DONE 2 /* Message successfully transmitted */
+#define TX_ERROR 3 /* Message transmitted with error */
+
+/* rx_msg_cmd */
+#define RX_NO_OP 0 /* No transaction */
+#define RX_ACK_CURRENT 1 /* Read earliest message in buffer */
+#define RX_DISABLE 2 /* Disable receiving latest message */
+#define RX_ACK_NEXT 3 /* Clear earliest msg, read next */
+
+/* rx_msg_status */
+#define RX_IDLE 0 /* No transaction */
+#define RX_BUSY 1 /* Receiver is busy */
+#define RX_DONE 2 /* Message has been received successfully */
+#define RX_ERROR 3 /* Message has been received with error */
+
+/* RX_CLEAR_BUF options */
+#define CLEAR_START 1
+#define CLEAR_STOP 0
+
+/* CEC_LOGICAL_ADDRx options */
+#define LOGICAL_ADDR_MASK 0xf
+#define LOGICAL_ADDR_VALID BIT(4)
+#define LOGICAL_ADDR_DISABLE 0
+
+#define CEC_CLK_RATE 32768
+
+struct meson_ao_cec_device {
+ struct platform_device *pdev;
+ void __iomem *base;
+ struct clk *core;
+ spinlock_t cec_reg_lock;
+ struct cec_notifier *notify;
+ struct cec_adapter *adap;
+ struct cec_msg rx_msg;
+};
+
+#define writel_bits_relaxed(mask, val, addr) \
+ writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)
+
+static inline void meson_ao_cec_wait_busy(struct meson_ao_cec_device *ao_cec)
+{
+ while (readl_relaxed(ao_cec->base + CEC_RW_REG) &
+ CEC_RW_BUS_BUSY)
+ ;
+}
+
+static u8 meson_ao_cec_read(struct meson_ao_cec_device *ao_cec,
+ unsigned long address)
+{
+ unsigned long flags;
+ u32 reg = FIELD_PREP(CEC_RW_ADDR, address);
+ u8 data;
+
+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
+
+ meson_ao_cec_wait_busy(ao_cec);
+
+ writel_relaxed(reg, ao_cec->base + CEC_RW_REG);
+
+ meson_ao_cec_wait_busy(ao_cec);
+
+ data = FIELD_GET(CEC_RW_RD_DATA,
+ readl_relaxed(ao_cec->base + CEC_RW_REG));
+
+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
+
+ return data;
+}
+
+static void meson_ao_cec_write(struct meson_ao_cec_device *ao_cec,
+ unsigned long address, u8 data)
+{
+ unsigned long flags;
+ u32 reg = FIELD_PREP(CEC_RW_ADDR, address) |
+ FIELD_PREP(CEC_RW_WR_DATA, data) |
+ CEC_RW_WRITE_EN;
+
+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
+
+ meson_ao_cec_wait_busy(ao_cec);
+
+ writel_relaxed(reg, ao_cec->base + CEC_RW_REG);
+
+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
+}
+
+static inline void meson_ao_cec_irq_setup(struct meson_ao_cec_device *ao_cec,
+ bool enable)
+{
+ u32 cfg = CEC_INTR_TX | CEC_INTR_RX;
+
+ writel_bits_relaxed(cfg, enable ? cfg : 0,
+ ao_cec->base + CEC_INTR_MASKN_REG);
+}
+
+static inline void meson_ao_cec_clear(struct meson_ao_cec_device *ao_cec)
+{
+ meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_DISABLE);
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT);
+ meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 1);
+ meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 1);
+
+ udelay(100);
+
+ meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, 0);
+ meson_ao_cec_write(ao_cec, CEC_TX_CLEAR_BUF, 0);
+
+ udelay(100);
+
+ meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP);
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP);
+}
+
+static void meson_ao_cec_arbit_bit_time_set(struct meson_ao_cec_device *ao_cec,
+ unsigned int bit_set,
+ unsigned int time_set)
+{
+ switch (bit_set) {
+ case 3:
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT7_0,
+ time_set & 0xff);
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_4BIT_BIT10_8,
+ (time_set >> 8) & 0x7);
+ break;
+
+ case 5:
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT7_0,
+ time_set & 0xff);
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_2BIT_BIT10_8,
+ (time_set >> 8) & 0x7);
+ break;
+
+ case 7:
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT7_0,
+ time_set & 0xff);
+ meson_ao_cec_write(ao_cec, CEC_TXTIME_17MS_BIT10_8,
+ (time_set >> 8) & 0x7);
+ break;
+ }
+}
+
+static irqreturn_t meson_ao_cec_irq(int irq, void *data)
+{
+ struct meson_ao_cec_device *ao_cec = data;
+ u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG);
+
+ if (stat)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+static void meson_ao_cec_irq_tx(struct meson_ao_cec_device *ao_cec)
+{
+ unsigned long tx_status = 0;
+ u8 stat = meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS);
+
+ switch (stat) {
+ case TX_DONE:
+ tx_status = CEC_TX_STATUS_OK;
+ break;
+
+ case TX_BUSY:
+ tx_status = CEC_TX_STATUS_ARB_LOST;
+ break;
+
+ case TX_IDLE:
+ tx_status = CEC_TX_STATUS_LOW_DRIVE;
+ break;
+
+ case TX_ERROR:
+ default:
+ tx_status = CEC_TX_STATUS_NACK;
+ }
+
+ /* Clear Interruption */
+ writel_relaxed(CEC_INTR_TX, ao_cec->base + CEC_INTR_CLR_REG);
+
+ /* Stop TX */
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_NO_OP);
+
+ cec_transmit_attempt_done(ao_cec->adap, tx_status);
+}
+
+static void meson_ao_cec_irq_rx(struct meson_ao_cec_device *ao_cec)
+{
+ u8 stat = meson_ao_cec_read(ao_cec, CEC_RX_MSG_STATUS);
+ int i;
+
+ /* RX Error */
+ if (stat != RX_DONE ||
+ meson_ao_cec_read(ao_cec, CEC_RX_NUM_MSG) != 1)
+ goto rx_out;
+
+ ao_cec->rx_msg.len = meson_ao_cec_read(ao_cec, CEC_RX_MSG_LENGTH) + 1;
+ if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE)
+ ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE;
+
+ for (i = 0; i < ao_cec->rx_msg.len; i++)
+ ao_cec->rx_msg.msg[i] =
+ meson_ao_cec_read(ao_cec, CEC_RX_MSG_0_HEADER + i);
+
+ cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
+
+rx_out:
+ /* Clear Interruption */
+ writel_relaxed(CEC_INTR_RX, ao_cec->base + CEC_INTR_CLR_REG);
+
+ /* Ack RX message */
+ meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_ACK_CURRENT);
+ meson_ao_cec_write(ao_cec, CEC_RX_MSG_CMD, RX_NO_OP);
+
+ /* Clear RX buffer */
+ meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_START);
+ meson_ao_cec_write(ao_cec, CEC_RX_CLEAR_BUF, CLEAR_STOP);
+}
+
+static irqreturn_t meson_ao_cec_irq_thread(int irq, void *data)
+{
+ struct meson_ao_cec_device *ao_cec = data;
+ u32 stat = readl_relaxed(ao_cec->base + CEC_INTR_STAT_REG);
+
+ if (stat & CEC_INTR_TX)
+ meson_ao_cec_irq_tx(ao_cec);
+
+ meson_ao_cec_irq_rx(ao_cec);
+
+ return IRQ_HANDLED;
+}
+
+static int meson_ao_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+ struct meson_ao_cec_device *ao_cec = adap->priv;
+
+ meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0, LOGICAL_ADDR_DISABLE);
+
+ meson_ao_cec_clear(ao_cec);
+
+ if (logical_addr == CEC_LOG_ADDR_INVALID)
+ return 0;
+
+ meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0,
+ logical_addr & LOGICAL_ADDR_MASK);
+
+ udelay(100);
+
+ meson_ao_cec_write(ao_cec, CEC_LOGICAL_ADDR0,
+ (logical_addr & LOGICAL_ADDR_MASK) |
+ LOGICAL_ADDR_VALID);
+
+ return 0;
+}
+
+static int meson_ao_cec_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct meson_ao_cec_device *ao_cec = adap->priv;
+ u8 reg;
+ int i;
+
+ reg = meson_ao_cec_read(ao_cec, CEC_TX_MSG_STATUS);
+ if (reg == TX_BUSY) {
+ dev_err(&ao_cec->pdev->dev, "%s: busy TX\n", __func__);
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_ABORT);
+ }
+
+ for (i = 0; i < msg->len; i++)
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_0_HEADER + i,
+ msg->msg[i]);
+
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_LENGTH, msg->len - 1);
+ meson_ao_cec_write(ao_cec, CEC_TX_MSG_CMD, TX_REQ_CURRENT);
+
+ return 0;
+}
+
+static int meson_ao_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+ struct meson_ao_cec_device *ao_cec = adap->priv;
+
+ meson_ao_cec_irq_setup(ao_cec, false);
+
+ writel_bits_relaxed(CEC_GEN_CNTL_RESET, CEC_GEN_CNTL_RESET,
+ ao_cec->base + CEC_GEN_CNTL_REG);
+
+ if (!enable)
+ return 0;
+
+ /* Enable gated clock (Normal mode). */
+ writel_bits_relaxed(CEC_GEN_CNTL_CLK_CTRL_MASK,
+ FIELD_PREP(CEC_GEN_CNTL_CLK_CTRL_MASK,
+ CEC_GEN_CNTL_CLK_ENABLE),
+ ao_cec->base + CEC_GEN_CNTL_REG);
+
+ udelay(100);
+
+ /* Release Reset */
+ writel_bits_relaxed(CEC_GEN_CNTL_RESET, 0,
+ ao_cec->base + CEC_GEN_CNTL_REG);
+
+ /* Clear buffers */
+ meson_ao_cec_clear(ao_cec);
+
+ /* CEC arbitration 3/5/7 bit time set. */
+ meson_ao_cec_arbit_bit_time_set(ao_cec, 3, 0x118);
+ meson_ao_cec_arbit_bit_time_set(ao_cec, 5, 0x000);
+ meson_ao_cec_arbit_bit_time_set(ao_cec, 7, 0x2aa);
+
+ meson_ao_cec_irq_setup(ao_cec, true);
+
+ return 0;
+}
+
+static const struct cec_adap_ops meson_ao_cec_ops = {
+ .adap_enable = meson_ao_cec_adap_enable,
+ .adap_log_addr = meson_ao_cec_set_log_addr,
+ .adap_transmit = meson_ao_cec_transmit,
+};
+
+static int meson_ao_cec_probe(struct platform_device *pdev)
+{
+ struct meson_ao_cec_device *ao_cec;
+ struct platform_device *hdmi_dev;
+ struct device_node *np;
+ struct resource *res;
+ int ret, irq;
+
+ np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0);
+ if (!np) {
+ dev_err(&pdev->dev, "Failed to find hdmi node\n");
+ return -ENODEV;
+ }
+
+ hdmi_dev = of_find_device_by_node(np);
+ if (hdmi_dev == NULL)
+ return -EPROBE_DEFER;
+
+ ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
+ if (!ao_cec)
+ return -ENOMEM;
+
+ spin_lock_init(&ao_cec->cec_reg_lock);
+
+ ao_cec->notify = cec_notifier_get(&hdmi_dev->dev);
+ if (!ao_cec->notify)
+ return -ENOMEM;
+
+ ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec,
+ "meson_ao_cec",
+ CEC_CAP_LOG_ADDRS |
+ CEC_CAP_TRANSMIT |
+ CEC_CAP_RC,
+ 1); /* Use 1 for now */
+ if (IS_ERR(ao_cec->adap)) {
+ ret = PTR_ERR(ao_cec->adap);
+ goto out_probe_notify;
+ }
+
+ ao_cec->adap->owner = THIS_MODULE;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ao_cec->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ao_cec->base)) {
+ ret = PTR_ERR(ao_cec->base);
+ goto out_probe_adapter;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ meson_ao_cec_irq,
+ meson_ao_cec_irq_thread,
+ 0, NULL, ao_cec);
+ if (ret) {
+ dev_err(&pdev->dev, "irq request failed\n");
+ goto out_probe_adapter;
+ }
+
+ ao_cec->core = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(ao_cec->core)) {
+ dev_err(&pdev->dev, "core clock request failed\n");
+ ret = PTR_ERR(ao_cec->core);
+ goto out_probe_adapter;
+ }
+
+ ret = clk_prepare_enable(ao_cec->core);
+ if (ret) {
+ dev_err(&pdev->dev, "core clock enable failed\n");
+ goto out_probe_adapter;
+ }
+
+ ret = clk_set_rate(ao_cec->core, CEC_CLK_RATE);
+ if (ret) {
+ dev_err(&pdev->dev, "core clock set rate failed\n");
+ goto out_probe_clk;
+ }
+
+ device_reset_optional(&pdev->dev);
+
+ ao_cec->pdev = pdev;
+ platform_set_drvdata(pdev, ao_cec);
+
+ ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
+ if (ret < 0) {
+ cec_notifier_put(ao_cec->notify);
+ goto out_probe_clk;
+ }
+
+ /* Setup Hardware */
+ writel_relaxed(CEC_GEN_CNTL_RESET,
+ ao_cec->base + CEC_GEN_CNTL_REG);
+
+ cec_register_cec_notifier(ao_cec->adap, ao_cec->notify);
+
+ return 0;
+
+out_probe_clk:
+ clk_disable_unprepare(ao_cec->core);
+
+out_probe_adapter:
+ cec_delete_adapter(ao_cec->adap);
+
+out_probe_notify:
+ cec_notifier_put(ao_cec->notify);
+
+ dev_err(&pdev->dev, "CEC controller registration failed\n");
+
+ return ret;
+}
+
+static int meson_ao_cec_remove(struct platform_device *pdev)
+{
+ struct meson_ao_cec_device *ao_cec = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(ao_cec->core);
+
+ cec_unregister_adapter(ao_cec->adap);
+
+ cec_notifier_put(ao_cec->notify);
+
+ return 0;
+}
+
+static const struct of_device_id meson_ao_cec_of_match[] = {
+ { .compatible = "amlogic,meson-gx-ao-cec", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match);
+
+static struct platform_driver meson_ao_cec_driver = {
+ .probe = meson_ao_cec_probe,
+ .remove = meson_ao_cec_remove,
+ .driver = {
+ .name = "meson-ao-cec",
+ .of_match_table = of_match_ptr(meson_ao_cec_of_match),
+ },
+};
+
+module_platform_driver(meson_ao_cec_driver);
+
+MODULE_DESCRIPTION("Meson AO CEC Controller driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_LICENSE("GPL");
--
1.9.1

View file

@ -0,0 +1,40 @@
From 6fd7485ab55a72cd7bce9e4f69dc95a6fe06e685 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 24 May 2017 09:41:12 +0200
Subject: [PATCH 10/79] ARM64: dts: meson-gxbb: Add CEC pins nodes
Add the AO and EE domain CEC pins nodes for the Amlogic Meson GXBB SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index d760d93..daa49ae 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -255,6 +255,20 @@
function = "spdif_out_ao";
};
};
+
+ ao_cec_pins: ao_cec {
+ mux {
+ groups = "ao_cec";
+ function = "cec_ao";
+ };
+ };
+
+ ee_cec_pins: ee_cec {
+ mux {
+ groups = "ee_cec";
+ function = "cec_ao";
+ };
+ };
};
};
--
1.9.1

View file

@ -1,639 +0,0 @@
From b53f55423fe344ecdd5bc8b2437170013a0a46e4 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Mon, 28 Nov 2016 17:59:08 +0200
Subject: [PATCH 10/93] drm: bridge: Link encoder and bridge in core code
Instead of linking encoders and bridges in every driver (and getting it
wrong half of the time, as many drivers forget to set the drm_bridge
encoder pointer), do so in core code. The drm_bridge_attach() function
needs the encoder and optional previous bridge to perform that task,
update all the callers.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: Stefan Agner <stefan@agner.ch> # For DCU
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com> # For atmel-hlcdc
Acked-by: Vincent Abriou <vincent.abriou@st.com> # For STI
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com> # For sun4i
Acked-by: Xinliang Liu <z.liuxinliang@hisilicon.com> # For hisilicon
Acked-by: Jyri Sarha <jsarha@ti.com> # For tilcdc
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1481709550-29226-4-git-send-email-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/arc/arcpgu_hdmi.c | 5 +--
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
drivers/gpu/drm/imx/imx-ldb.c | 6 +--
drivers/gpu/drm/imx/parallel-display.c | 4 +-
drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
drivers/gpu/drm/sti/sti_dvo.c | 3 +-
drivers/gpu/drm/sti/sti_hda.c | 3 +-
drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
drivers/gpu/drm/tilcdc/tilcdc_external.c | 4 +-
include/drm/drm_bridge.h | 3 +-
25 files changed, 85 insertions(+), 110 deletions(-)
diff --git a/drivers/gpu/drm/arc/arcpgu_hdmi.c b/drivers/gpu/drm/arc/arcpgu_hdmi.c
index b69c66b..0ce7f39 100644
--- a/drivers/gpu/drm/arc/arcpgu_hdmi.c
+++ b/drivers/gpu/drm/arc/arcpgu_hdmi.c
@@ -47,10 +47,7 @@ int arcpgu_drm_hdmi_init(struct drm_device *drm, struct device_node *np)
return ret;
/* Link drm_bridge to encoder */
- bridge->encoder = encoder;
- encoder->bridge = bridge;
-
- ret = drm_bridge_attach(drm, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret)
drm_encoder_cleanup(encoder);
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 6119b50..e7799b6 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
of_node_put(np);
if (bridge) {
- output->encoder.bridge = bridge;
- bridge->encoder = &output->encoder;
- ret = drm_bridge_attach(dev, bridge);
+ ret = drm_bridge_attach(&output->encoder, bridge, NULL);
if (!ret)
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 18eefdc..dfae80f 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
dp->bridge = bridge;
- dp->encoder->bridge = bridge;
bridge->driver_private = dp;
- bridge->encoder = dp->encoder;
bridge->funcs = &analogix_dp_bridge_funcs;
- ret = drm_bridge_attach(drm_dev, bridge);
+ ret = drm_bridge_attach(dp->encoder, bridge, NULL);
if (ret) {
DRM_ERROR("failed to attach drm bridge\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 235ce7d..f5009ae 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
hdmi->bridge = bridge;
bridge->driver_private = hdmi;
bridge->funcs = &dw_hdmi_bridge_funcs;
- ret = drm_bridge_attach(drm, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return -EINVAL;
}
- encoder->bridge = bridge;
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b..850bd65 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
/**
* DOC: overview
@@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
EXPORT_SYMBOL(drm_bridge_remove);
/**
- * drm_bridge_attach - associate given bridge to our DRM device
+ * drm_bridge_attach - attach the bridge to an encoder's chain
*
- * @dev: DRM device
- * @bridge: bridge control structure
+ * @encoder: DRM encoder
+ * @bridge: bridge to attach
+ * @previous: previous bridge in the chain (optional)
*
- * Called by a kms driver to link one of our encoder/bridge to the given
- * bridge.
+ * Called by a kms driver to link the bridge to an encoder's chain. The previous
+ * argument specifies the previous bridge in the chain. If NULL, the bridge is
+ * linked directly at the encoder's output. Otherwise it is linked at the
+ * previous bridge's output.
*
- * Note that setting up links between the bridge and our encoder/bridge
- * objects needs to be handled by the kms driver itself.
+ * If non-NULL the previous bridge must be already attached by a call to this
+ * function.
*
* RETURNS:
* Zero on success, error code on failure
*/
-int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
+ struct drm_bridge *previous)
{
- if (!dev || !bridge)
+ int ret;
+
+ if (!encoder || !bridge)
+ return -EINVAL;
+
+ if (previous && (!previous->dev || previous->encoder != encoder))
return -EINVAL;
if (bridge->dev)
return -EBUSY;
- bridge->dev = dev;
+ bridge->dev = encoder->dev;
+ bridge->encoder = encoder;
+
+ if (bridge->funcs->attach) {
+ ret = bridge->funcs->attach(bridge);
+ if (ret < 0) {
+ bridge->dev = NULL;
+ bridge->encoder = NULL;
+ return ret;
+ }
+ }
- if (bridge->funcs->attach)
- return bridge->funcs->attach(bridge);
+ if (previous)
+ previous->next = bridge;
+ else
+ encoder->bridge = bridge;
return 0;
}
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 7bae08c..ba7be61 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -182,9 +182,7 @@ static void drm_simple_kms_plane_cleanup_fb(struct drm_plane *plane,
int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
struct drm_bridge *bridge)
{
- bridge->encoder = &pipe->encoder;
- pipe->encoder.bridge = bridge;
- return drm_bridge_attach(pipe->encoder.dev, bridge);
+ return drm_bridge_attach(&pipe->encoder, bridge, NULL);
}
EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 528229f..1ef0be3 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
struct drm_connector *connector)
{
struct exynos_dp_device *dp = to_dp(plat_data);
- struct drm_encoder *encoder = &dp->encoder;
int ret;
drm_connector_register(connector);
@@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
/* Pre-empt DP connector creation if there's a bridge */
if (dp->ptn_bridge) {
- bridge->next = dp->ptn_bridge;
- dp->ptn_bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
+ ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
if (ret) {
DRM_ERROR("Failed to attach bridge to drm\n");
bridge->next = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index e07cb1f..812e2ec 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
}
bridge = of_drm_find_bridge(dsi->bridge_node);
- if (bridge) {
- encoder->bridge = bridge;
- drm_bridge_attach(drm_dev, bridge);
- }
+ if (bridge)
+ drm_bridge_attach(encoder, bridge, NULL);
return mipi_dsi_host_register(&dsi->dsi_host);
}
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index 05a8ee1..c365145 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -160,10 +160,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
if (!bridge)
return -ENODEV;
- fsl_dev->encoder.bridge = bridge;
- bridge->encoder = &fsl_dev->encoder;
-
- return drm_bridge_attach(fsl_dev->drm, bridge);
+ return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
}
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index 998452a..1737e98 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
int ret;
/* associate the bridge to dsi encoder */
- encoder->bridge = bridge;
- bridge->encoder = encoder;
-
- ret = drm_bridge_attach(dev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
DRM_ERROR("failed to attach external bridge\n");
return ret;
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index 516d064..ec49ea3 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -454,10 +454,8 @@ static int imx_ldb_register(struct drm_device *drm,
DRM_MODE_ENCODER_LVDS, NULL);
if (imx_ldb_ch->bridge) {
- imx_ldb_ch->bridge->encoder = encoder;
-
- imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
- ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
+ ret = drm_bridge_attach(&imx_ldb_ch->encoder,
+ imx_ldb_ch->bridge, NULL);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return ret;
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 8582a83..51d9f73 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -191,9 +191,7 @@ static int imx_pd_register(struct drm_device *drm,
drm_panel_attach(imxpd->panel, &imxpd->connector);
if (imxpd->bridge) {
- imxpd->bridge->encoder = encoder;
- encoder->bridge = imxpd->bridge;
- ret = drm_bridge_attach(drm, imxpd->bridge);
+ ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
if (ret < 0) {
dev_err(imxpd->dev, "failed to attach bridge: %d\n",
ret);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 90fb831..3bd3bd6 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder;
+ struct drm_bridge *bridge;
void __iomem *regs;
struct device *dev;
struct clk *engine_clk;
@@ -620,8 +621,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
/* Currently DPI0 is fixed to be driven by OVL1 */
dpi->encoder.possible_crtcs = BIT(1);
- dpi->encoder.bridge->encoder = &dpi->encoder;
- ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
+ ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto err_cleanup;
@@ -718,9 +718,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
- dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
+ dpi->bridge = of_drm_find_bridge(bridge_node);
of_node_put(bridge_node);
- if (!dpi->encoder.bridge)
+ if (!dpi->bridge)
return -EPROBE_DEFER;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 2c42f90..dd71cbb 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -622,26 +622,6 @@ static int mtk_dsi_connector_get_modes(struct drm_connector *connector)
.get_modes = mtk_dsi_connector_get_modes,
};
-static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
- struct drm_encoder *encoder)
-{
- int ret;
-
- if (!bridge)
- return -ENOENT;
-
- encoder->bridge = bridge;
- bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, bridge);
- if (ret) {
- DRM_ERROR("Failed to attach bridge to drm\n");
- encoder->bridge = NULL;
- bridge->encoder = NULL;
- }
-
- return ret;
-}
-
static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
{
int ret;
@@ -692,8 +672,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
dsi->encoder.possible_crtcs = 1;
/* If there's a bridge, attach to it and let it create the connector */
- ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
+ ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
if (ret) {
+ DRM_ERROR("Failed to attach bridge to drm\n");
+
/* Otherwise create our own connector and attach to a panel */
ret = mtk_dsi_create_connector(drm, dsi);
if (ret)
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 0e8c4d9..c262512 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -149,6 +149,7 @@ struct hdmi_audio_param {
struct mtk_hdmi {
struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
struct drm_connector conn;
struct device *dev;
struct phy *phy;
@@ -1314,9 +1315,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
return ret;
}
- if (bridge->next) {
- bridge->next->encoder = bridge->encoder;
- ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
+ if (hdmi->next_bridge) {
+ ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ bridge);
if (ret) {
dev_err(hdmi->dev,
"Failed to attach external bridge: %d\n", ret);
@@ -1510,8 +1511,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
of_node_put(ep);
if (!of_device_is_compatible(remote, "hdmi-connector")) {
- hdmi->bridge.next = of_drm_find_bridge(remote);
- if (!hdmi->bridge.next) {
+ hdmi->next_bridge = of_drm_find_bridge(remote);
+ if (!hdmi->next_bridge) {
dev_err(dev, "Waiting for external bridge\n");
of_node_put(remote);
return -EPROBE_DEFER;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index c8d1f19..2bd8dad 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_bridge *bridge = NULL;
struct dsi_bridge *dsi_bridge;
+ struct drm_encoder *encoder;
int ret;
dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
@@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
dsi_bridge->id = id;
+ /*
+ * HACK: we may not know the external DSI bridge device's mode
+ * flags here. We'll get to know them only when the device
+ * attaches to the dsi host. For now, assume the bridge supports
+ * DSI video mode
+ */
+ encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
+
bridge = &dsi_bridge->base;
bridge->funcs = &dsi_mgr_bridge_funcs;
- ret = drm_bridge_attach(msm_dsi->dev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret)
goto fail;
@@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
/* link the internal dsi bridge to the external bridge */
- int_bridge->next = ext_bridge;
- /* set the external bridge's encoder as dsi's encoder */
- ext_bridge->encoder = encoder;
-
- drm_bridge_attach(dev, ext_bridge);
+ drm_bridge_attach(encoder, ext_bridge, int_bridge);
/*
* we need the drm_connector created by the external bridge
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
index 2bc73f82..931a5c9 100644
--- a/drivers/gpu/drm/msm/edp/edp_bridge.c
+++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
@@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
bridge = &edp_bridge->base;
bridge->funcs = &edp_bridge_funcs;
- ret = drm_bridge_attach(edp->dev, bridge);
+ ret = drm_bridge_attach(edp->encoder, bridge, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index bacbd5d..4e6d1bf 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
bridge = &hdmi_bridge->base;
bridge->funcs = &msm_hdmi_bridge_funcs;
- ret = drm_bridge_attach(hdmi->dev, bridge);
+ ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index f9515f5..c4c5d1ab 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
hdmienc->renc = renc;
/* Link the bridge to the encoder. */
- bridge->encoder = encoder;
- encoder->bridge = bridge;
-
- ret = drm_bridge_attach(rcdu->ddev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
drm_encoder_cleanup(encoder);
return ret;
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index e8c1ed0..411dc6e 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
return err;
}
- err = drm_bridge_attach(drm_dev, bridge);
+ err = drm_bridge_attach(encoder, bridge, NULL);
if (err) {
DRM_ERROR("Failed to attach bridge\n");
return err;
}
dvo->bridge = bridge;
- encoder->bridge = bridge;
connector->encoder = encoder;
dvo->encoder = encoder;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 96f336d..66d37d78 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -707,9 +707,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
bridge->driver_private = hda;
bridge->funcs = &sti_hda_bridge_funcs;
- drm_bridge_attach(drm_dev, bridge);
+ drm_bridge_attach(encoder, bridge, NULL);
- encoder->bridge = bridge;
connector->encoder = encoder;
drm_connector = (struct drm_connector *)connector;
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 376b076..f0af1ae 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
bridge->driver_private = hdmi;
bridge->funcs = &sti_hdmi_bridge_funcs;
- drm_bridge_attach(drm_dev, bridge);
+ drm_bridge_attach(encoder, bridge, NULL);
- encoder->bridge = bridge;
connector->encoder = encoder;
drm_connector = (struct drm_connector *)connector;
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index f5e86fe..757208f 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -208,6 +208,7 @@ int sun4i_rgb_init(struct drm_device *drm)
struct sun4i_drv *drv = drm->dev_private;
struct sun4i_tcon *tcon = drv->tcon;
struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
struct sun4i_rgb *rgb;
int ret;
@@ -218,8 +219,8 @@ int sun4i_rgb_init(struct drm_device *drm)
encoder = &rgb->encoder;
tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
- encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
- if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
+ bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
+ if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
return 0;
}
@@ -260,16 +261,12 @@ int sun4i_rgb_init(struct drm_device *drm)
}
}
- if (!IS_ERR(encoder->bridge)) {
- encoder->bridge->encoder = &rgb->encoder;
-
- ret = drm_bridge_attach(drm, encoder->bridge);
+ if (!IS_ERR(bridge)) {
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't attach our bridge\n");
goto err_cleanup_connector;
}
- } else {
- encoder->bridge = NULL;
}
return 0;
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_external.c b/drivers/gpu/drm/tilcdc/tilcdc_external.c
index c67d7cd..b0dd5e8 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_external.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_external.c
@@ -167,10 +167,8 @@ int tilcdc_attach_bridge(struct drm_device *ddev, struct drm_bridge *bridge)
int ret;
priv->external_encoder->possible_crtcs = BIT(0);
- priv->external_encoder->bridge = bridge;
- bridge->encoder = priv->external_encoder;
- ret = drm_bridge_attach(ddev, bridge);
+ ret = drm_bridge_attach(priv->external_encoder, bridge, NULL);
if (ret) {
dev_err(ddev->dev, "drm_bridge_attach() failed %d\n", ret);
return ret;
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6..94e5ee9 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -201,7 +201,8 @@ struct drm_bridge {
int drm_bridge_add(struct drm_bridge *bridge);
void drm_bridge_remove(struct drm_bridge *bridge);
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
-int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
+int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
+ struct drm_bridge *previous);
void drm_bridge_detach(struct drm_bridge *bridge);
bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
--
1.9.1

View file

@ -0,0 +1,40 @@
From 629ad838c870b17536666327dcedbd0f8762cae8 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 24 May 2017 09:41:48 +0200
Subject: [PATCH 11/79] ARM64: dts: meson-gxl: Add CEC pins nodes
Add the AO and EE domain CEC pins nodes for the Amlogic Meson GXL SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 3a1ccf5..15539f9 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -191,6 +191,20 @@
function = "spdif_out_ao";
};
};
+
+ ao_cec_pins: ao_cec {
+ mux {
+ groups = "ao_cec";
+ function = "cec_ao";
+ };
+ };
+
+ ee_cec_pins: ee_cec {
+ mux {
+ groups = "ee_cec";
+ function = "cec_ao";
+ };
+ };
};
};
--
1.9.1

View file

@ -1,48 +0,0 @@
From 4d69de06ed2934b45c0e6b2a5056ef2a7caa0b9a Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:51 +0200
Subject: [PATCH 11/93] drm: bridge: dw-hdmi: Merge __hdmi_phy_i2c_write and
hdmi_phy_i2c_write
The latter is just an int wrapper around the former void function that
unconditionally returns 0. As the return value is never checked, merge
the two functions into one.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-2-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f5009ae..a668550 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -868,7 +868,7 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
return true;
}
-static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
@@ -882,13 +882,6 @@ static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
-static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
- unsigned char addr)
-{
- __hdmi_phy_i2c_write(hdmi, data, addr);
- return 0;
-}
-
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
hdmi_mask_writeb(hdmi, !enable, HDMI_PHY_CONF0,
--
1.9.1

View file

@ -0,0 +1,41 @@
From 69c139fa21249718dfd9d6f14a7b374ae28c8215 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 24 May 2017 09:44:45 +0200
Subject: [PATCH 12/79] ARM64: dts: meson-gxl: Add Ethernet PHY LEDS pins nodes
The Amlogic Meson GXL SoCs embeds an 10/100 Ethernet PHY, this patchs adds
the Link and Activity LEDs signals pins nodes.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 15539f9..dc7c53f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -369,6 +369,20 @@
};
};
+ eth_link_led_pins: eth_link_led {
+ mux {
+ groups = "eth_link_led";
+ function = "eth_led";
+ };
+ };
+
+ eth_act_led_pins: eth_act_led {
+ mux {
+ groups = "eth_act_led";
+ function = "eth_led";
+ };
+ };
+
pwm_a_pins: pwm_a {
mux {
groups = "pwm_a";
--
1.9.1

View file

@ -1,121 +0,0 @@
From fefa6576d7b085c7712fdc2b5af10e61f3fa1841 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:52 +0200
Subject: [PATCH 12/93] drm: bridge: dw-hdmi: Remove unneeded arguments to
bind/unbind functions
The master argument isn't used. The data argument, a void pointer, is
used by the bind function only where it's cast to a drm_device pointer,
which can easily be obtained from the encoder argument instead. Remove
them.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-3-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 8 +++-----
drivers/gpu/drm/imx/dw_hdmi-imx.c | 4 ++--
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 4 ++--
include/drm/bridge/dw_hdmi.h | 5 ++---
4 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index a668550..f868946 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1854,12 +1854,10 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
return 0;
}
-int dw_hdmi_bind(struct device *dev, struct device *master,
- void *data, struct drm_encoder *encoder,
+int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
struct resource *iores, int irq,
const struct dw_hdmi_plat_data *plat_data)
{
- struct drm_device *drm = data;
struct device_node *np = dev->of_node;
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
@@ -1992,7 +1990,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
if (ret)
goto err_iahb;
- ret = dw_hdmi_register(drm, hdmi);
+ ret = dw_hdmi_register(encoder->dev, hdmi);
if (ret)
goto err_iahb;
@@ -2059,7 +2057,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
}
EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
+void dw_hdmi_unbind(struct device *dev)
{
struct dw_hdmi *hdmi = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index 359cd27..f796658 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -249,7 +249,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -264,7 +264,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
void *data)
{
- return dw_hdmi_unbind(dev, master, data);
+ return dw_hdmi_unbind(dev);
}
static const struct component_ops dw_hdmi_imx_ops = {
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 0665fb9..e8fb5c5 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -301,7 +301,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
@@ -316,7 +316,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
void *data)
{
- return dw_hdmi_unbind(dev, master, data);
+ return dw_hdmi_unbind(dev);
}
static const struct component_ops dw_hdmi_rockchip_ops = {
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bae79f3..11edda6 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -56,9 +56,8 @@ struct dw_hdmi_plat_data {
struct drm_display_mode *mode);
};
-void dw_hdmi_unbind(struct device *dev, struct device *master, void *data);
-int dw_hdmi_bind(struct device *dev, struct device *master,
- void *data, struct drm_encoder *encoder,
+void dw_hdmi_unbind(struct device *dev);
+int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
struct resource *iores, int irq,
const struct dw_hdmi_plat_data *plat_data);
--
1.9.1

View file

@ -0,0 +1,42 @@
From f620469d663615a805ca21169013ba79089e2339 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Mon, 22 May 2017 15:14:45 +0200
Subject: [PATCH 13/79] ARM64: dts: meson-gxbb: Add SPI pinctrl nodes
This patch adds the SPICC Controller pins nodes for Amlogic GXBB SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index daa49ae..1d4c861 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -310,6 +310,22 @@
};
};
+ spi_pins: spi {
+ mux {
+ groups = "spi_miso",
+ "spi_mosi",
+ "spi_sclk";
+ function = "spi";
+ };
+ };
+
+ spi_ss0_pins: spi-ss0 {
+ mux {
+ groups = "spi_ss0";
+ function = "spi";
+ };
+ };
+
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
--
1.9.1

View file

@ -1,55 +0,0 @@
From 4c8725b2de2a5b87850fb7cfa9d2ecf4499e05fb Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:53 +0200
Subject: [PATCH 13/93] drm: bridge: dw-hdmi: Remove unused function parameter
The 'prep' parameter passed to hdmi_phy_configure() is useless. It is
hardcoded as 0, and if set, simply prevents the configure function from
executing.
Remove it.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-4-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f868946..5f8044a 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -931,7 +931,7 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
+static int hdmi_phy_configure(struct dw_hdmi *hdmi,
unsigned char res, int cscon)
{
unsigned res_idx;
@@ -941,9 +941,6 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
- if (prep)
- return -EINVAL;
-
switch (res) {
case 0: /* color resolution 0 is 8 bit colour depth */
case 8:
@@ -1072,7 +1069,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */
- ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+ ret = hdmi_phy_configure(hdmi, 8, cscon);
if (ret)
return ret;
}
--
1.9.1

View file

@ -0,0 +1,42 @@
From d83151a6b97f039c3efa13d70d9697ef1fd887ac Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Mon, 22 May 2017 15:15:13 +0200
Subject: [PATCH 14/79] ARM64: dts: meson-gxl: Add SPI pinctrl nodes
This patch adds the SPICC Controller pins nodes for Amlogic GXL SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index dc7c53f..6584e46 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -246,6 +246,22 @@
};
};
+ spi_pins: spi {
+ mux {
+ groups = "spi_miso",
+ "spi_mosi",
+ "spi_sclk";
+ function = "spi";
+ };
+ };
+
+ spi_ss0_pins: spi-ss0 {
+ mux {
+ groups = "spi_ss0";
+ function = "spi";
+ };
+ };
+
sdcard_pins: sdcard {
mux {
groups = "sdcard_d0",
--
1.9.1

View file

@ -1,60 +0,0 @@
From 891854dbb712fe784cc0553c05bd05a8734d6a3e Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:54 +0200
Subject: [PATCH 14/93] drm: bridge: dw-hdmi: Embed drm_bridge in struct
dw_hdmi
The drm_bridge instance is always needed, there's no point in allocating
it separately.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-5-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 5f8044a..2c85b6c 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -116,7 +116,7 @@ struct dw_hdmi_i2c {
struct dw_hdmi {
struct drm_connector connector;
struct drm_encoder *encoder;
- struct drm_bridge *bridge;
+ struct drm_bridge bridge;
struct platform_device *audio;
enum dw_hdmi_devtype dev_type;
@@ -1806,7 +1806,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
- drm_helper_hpd_irq_event(hdmi->bridge->dev);
+ drm_helper_hpd_irq_event(hdmi->bridge.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
@@ -1819,16 +1819,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
{
struct drm_encoder *encoder = hdmi->encoder;
- struct drm_bridge *bridge;
+ struct drm_bridge *bridge = &hdmi->bridge;
int ret;
- bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
- if (!bridge) {
- DRM_ERROR("Failed to allocate drm bridge\n");
- return -ENOMEM;
- }
-
- hdmi->bridge = bridge;
bridge->driver_private = hdmi;
bridge->funcs = &dw_hdmi_bridge_funcs;
ret = drm_bridge_attach(encoder, bridge, NULL);
--
1.9.1

View file

@ -1,68 +0,0 @@
From 9fef18b9a29bb46c33bd724b1f66296b69fa65df Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:55 +0200
Subject: [PATCH 15/93] drm: bridge: dw-hdmi: Remove encoder field from struct
dw_hdmi
The field isn't needed, remove it.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-6-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 2c85b6c..ef10bb8 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -115,7 +115,6 @@ struct dw_hdmi_i2c {
struct dw_hdmi {
struct drm_connector connector;
- struct drm_encoder *encoder;
struct drm_bridge bridge;
struct platform_device *audio;
@@ -1816,9 +1815,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
+static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi)
{
- struct drm_encoder *encoder = hdmi->encoder;
struct drm_bridge *bridge = &hdmi->bridge;
int ret;
@@ -1835,7 +1833,7 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
drm_connector_helper_add(&hdmi->connector,
&dw_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector,
+ drm_connector_init(encoder->dev, &hdmi->connector,
&dw_hdmi_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
@@ -1867,7 +1865,6 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
hdmi->dev = dev;
hdmi->dev_type = plat_data->dev_type;
hdmi->sample_rate = 48000;
- hdmi->encoder = encoder;
hdmi->disabled = true;
hdmi->rxsense = true;
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
@@ -1980,7 +1977,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
if (ret)
goto err_iahb;
- ret = dw_hdmi_register(encoder->dev, hdmi);
+ ret = dw_hdmi_register(encoder, hdmi);
if (ret)
goto err_iahb;
--
1.9.1

View file

@ -0,0 +1,32 @@
From 0f14939959a72d4cec1ed3343af441fe930aedf7 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 17:57:34 +0200
Subject: [PATCH 15/79] pinctrl: meson-gxl: Fix typo in AO I2S pins
The AO I2S pins were incorrectly defined with the EE pin offset.
Cc: Jerome Brunet <jbrunet@baylibre.com>
Fixes: 2899adf0422 ("pinctrl: meson: gxl: add i2s output pins")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 998210e..0673115 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -271,8 +271,8 @@
static const unsigned int pwm_ao_b_pins[] = { PIN(GPIOAO_9, 0) };
static const unsigned int pwm_ao_b_6_pins[] = { PIN(GPIOAO_6, 0) };
-static const unsigned int i2s_out_ch23_ao_pins[] = { PIN(GPIOAO_8, EE_OFF) };
-static const unsigned int i2s_out_ch45_ao_pins[] = { PIN(GPIOAO_9, EE_OFF) };
+static const unsigned int i2s_out_ch23_ao_pins[] = { PIN(GPIOAO_8, 0) };
+static const unsigned int i2s_out_ch45_ao_pins[] = { PIN(GPIOAO_9, 0) };
static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, EE_OFF) };
static const unsigned int spdif_out_ao_9_pins[] = { PIN(GPIOAO_9, EE_OFF) };
--
1.9.1

View file

@ -1,35 +0,0 @@
From 259254dabd150067bf932e192dd9ed8b3d545755 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:56 +0200
Subject: [PATCH 16/93] drm: bridge: dw-hdmi: Don't forward HPD events to DRM
core before attach
Hotplug events should only be forwarded to the DRM core by the interrupt
handler when the bridge has been attached, otherwise the DRM device
pointer will be NULL, resulting in a crash.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-7-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ef10bb8..488dc1a 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1805,7 +1805,8 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
phy_int_pol & HDMI_PHY_HPD ? "plugin" : "plugout");
- drm_helper_hpd_irq_event(hdmi->bridge.dev);
+ if (hdmi->bridge.dev)
+ drm_helper_hpd_irq_event(hdmi->bridge.dev);
}
hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
--
1.9.1

View file

@ -0,0 +1,32 @@
From 846811f8445bb82b54aac0b102c3d29f278cb587 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 24 May 2017 09:35:13 +0200
Subject: [PATCH 16/79] pinctrl: meson-gxl: Fix typo in AO SPDIF pins
The AO SPDIF pins were incorrectly defined with the EE pin offset.
Cc: Jerome Brunet <jbrunet@baylibre.com>
Fixes: b840d649f9ec ("pinctrl: meson: gxl: add spdif output pins")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 0673115..c59e377 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -274,8 +274,8 @@
static const unsigned int i2s_out_ch23_ao_pins[] = { PIN(GPIOAO_8, 0) };
static const unsigned int i2s_out_ch45_ao_pins[] = { PIN(GPIOAO_9, 0) };
-static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, EE_OFF) };
-static const unsigned int spdif_out_ao_9_pins[] = { PIN(GPIOAO_9, EE_OFF) };
+static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, 0) };
+static const unsigned int spdif_out_ao_9_pins[] = { PIN(GPIOAO_9, 0) };
static struct meson_pmx_group meson_gxl_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
--
1.9.1

View file

@ -1,167 +0,0 @@
From 1de2e27b041a944da876ec10a530991d82dfd991 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:57 +0200
Subject: [PATCH 17/93] drm: bridge: dw-hdmi: Move IRQ and IO resource
allocation to common code
There's no need to duplicate identical code in multiple drivers (two at
the moment, one more to come soon). Move it to the dw-hdmi core where it
can be shared. If resource allocation ever becomes device-specific later
we'll always have the option of splitting it out again.
While it at pass the platform device to the bind function to avoid
having to cast struct device to struct platform_device.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-8-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 13 ++++++++++---
drivers/gpu/drm/imx/dw_hdmi-imx.c | 12 +-----------
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 12 +-----------
include/drm/bridge/dw_hdmi.h | 3 +--
4 files changed, 13 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 488dc1a..563cbec 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1843,14 +1843,16 @@ static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi)
return 0;
}
-int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
- struct resource *iores, int irq,
+int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
const struct dw_hdmi_plat_data *plat_data)
{
+ struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
struct dw_hdmi *hdmi;
+ struct resource *iores;
+ int irq;
int ret;
u32 val = 1;
u8 config0;
@@ -1903,6 +1905,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
dev_dbg(hdmi->dev, "no ddc property found\n");
}
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hdmi->regs = devm_ioremap_resource(dev, iores);
if (IS_ERR(hdmi->regs)) {
ret = PTR_ERR(hdmi->regs);
@@ -1945,6 +1948,10 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
initialize_hdmi_ih_mutes(hdmi);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ goto err_iahb;
+
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
@@ -2025,7 +2032,7 @@ int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
if (hdmi->i2c)
dw_hdmi_i2c_init(hdmi);
- dev_set_drvdata(dev, hdmi);
+ platform_set_drvdata(pdev, hdmi);
return 0;
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index f796658..f645275 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -207,8 +207,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct drm_encoder *encoder;
struct imx_hdmi *hdmi;
- struct resource *iores;
- int irq;
int ret;
if (!pdev->dev.of_node)
@@ -223,14 +221,6 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -ENXIO;
-
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
@@ -249,7 +239,7 @@ static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(pdev, encoder, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index e8fb5c5..a6d4a02 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -257,8 +257,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct drm_encoder *encoder;
struct rockchip_hdmi *hdmi;
- struct resource *iores;
- int irq;
int ret;
if (!pdev->dev.of_node)
@@ -273,14 +271,6 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
hdmi->dev = &pdev->dev;
encoder = &hdmi->encoder;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iores)
- return -ENXIO;
-
encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
/*
* If we failed to find the CRTC(s) which this encoder is
@@ -301,7 +291,7 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
- ret = dw_hdmi_bind(dev, encoder, iores, irq, plat_data);
+ ret = dw_hdmi_bind(pdev, encoder, plat_data);
/*
* If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 11edda6..94ff6ed 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -57,8 +57,7 @@ struct dw_hdmi_plat_data {
};
void dw_hdmi_unbind(struct device *dev);
-int dw_hdmi_bind(struct device *dev, struct drm_encoder *encoder,
- struct resource *iores, int irq,
+int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
const struct dw_hdmi_plat_data *plat_data);
void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate);
--
1.9.1

View file

@ -0,0 +1,57 @@
From b39031e8d8ba32cb03a500c82f2d9c05784a6747 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 17:56:18 +0200
Subject: [PATCH 17/79] pinctrl: meson-gxbb: Add CEC pins
Add the AO and EE domain CEC pins for the Amlogic Meson GXBB SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 9b00be1..114e690 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -290,6 +290,9 @@
static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, 0) };
static const unsigned int spdif_out_ao_13_pins[] = { PIN(GPIOAO_13, 0) };
+static const unsigned int ao_cec_pins[] = { PIN(GPIOAO_12, 0) };
+static const unsigned int ee_cec_pins[] = { PIN(GPIOAO_12, 0) };
+
static struct meson_pmx_group meson_gxbb_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
GPIO_GROUP(GPIOZ_1, EE_OFF),
@@ -551,6 +554,8 @@
GROUP(i2s_out_ch45_ao, 1, 1),
GROUP(spdif_out_ao_6, 0, 16),
GROUP(spdif_out_ao_13, 0, 4),
+ GROUP(ao_cec, 0, 15),
+ GROUP(ee_cec, 0, 14),
};
static const char * const gpio_periphs_groups[] = {
@@ -739,6 +744,10 @@
"spdif_out_ao_6", "spdif_out_ao_13",
};
+static const char * const cec_ao_groups[] = {
+ "ao_cec", "ee_cec",
+};
+
static struct meson_pmx_func meson_gxbb_periphs_functions[] = {
FUNCTION(gpio_periphs),
FUNCTION(emmc),
@@ -779,6 +788,7 @@
FUNCTION(pwm_ao_b),
FUNCTION(i2s_out_ao),
FUNCTION(spdif_out_ao),
+ FUNCTION(cec_ao),
};
static struct meson_bank meson_gxbb_periphs_banks[] = {
--
1.9.1

View file

@ -1,111 +0,0 @@
From 78e502a47988bfdb298e8416444c0f1f6e7e93a4 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:58 +0200
Subject: [PATCH 18/93] drm: bridge: dw-hdmi: Reorder functions to prepare for
next commit
The next commit will reference structures and functions in a way that
currently requires forward declarations. Reorder the functions to avoid
that. No functional change to the code is performed.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-9-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 72 ++++++++++++++++++++--------------------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 563cbec..92ce9e5 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1575,42 +1575,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
}
-static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
- struct drm_display_mode *orig_mode,
- struct drm_display_mode *mode)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-
- mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
- hdmi->disabled = true;
- dw_hdmi_update_power(hdmi);
- dw_hdmi_update_phy_mask(hdmi);
- mutex_unlock(&hdmi->mutex);
-}
-
-static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
-{
- struct dw_hdmi *hdmi = bridge->driver_private;
-
- mutex_lock(&hdmi->mutex);
- hdmi->disabled = false;
- dw_hdmi_update_power(hdmi);
- dw_hdmi_update_phy_mask(hdmi);
- mutex_unlock(&hdmi->mutex);
-}
-
static enum drm_connector_status
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
@@ -1703,6 +1667,42 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
.best_encoder = drm_atomic_helper_best_encoder,
};
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+
+ mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = true;
+ dw_hdmi_update_power(hdmi);
+ dw_hdmi_update_phy_mask(hdmi);
+ mutex_unlock(&hdmi->mutex);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ mutex_lock(&hdmi->mutex);
+ hdmi->disabled = false;
+ dw_hdmi_update_power(hdmi);
+ dw_hdmi_update_phy_mask(hdmi);
+ mutex_unlock(&hdmi->mutex);
+}
+
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
--
1.9.1

View file

@ -0,0 +1,57 @@
From 4f867c391de6437aeeb725bf5beab4f88366ef34 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 17:50:47 +0200
Subject: [PATCH 18/79] pinctrl: meson-gxl: Add CEC pins
Add the AO and EE domain CEC pins for the Amlogic Meson GXL SoCs.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index c59e377..da7f3e9 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -277,6 +277,9 @@
static const unsigned int spdif_out_ao_6_pins[] = { PIN(GPIOAO_6, 0) };
static const unsigned int spdif_out_ao_9_pins[] = { PIN(GPIOAO_9, 0) };
+static const unsigned int ao_cec_pins[] = { PIN(GPIOAO_8, 0) };
+static const unsigned int ee_cec_pins[] = { PIN(GPIOAO_8, 0) };
+
static struct meson_pmx_group meson_gxl_periphs_groups[] = {
GPIO_GROUP(GPIOZ_0, EE_OFF),
GPIO_GROUP(GPIOZ_1, EE_OFF),
@@ -518,6 +521,8 @@
GROUP(i2s_out_ch45_ao, 1, 1),
GROUP(spdif_out_ao_6, 0, 16),
GROUP(spdif_out_ao_9, 0, 4),
+ GROUP(ao_cec, 0, 15),
+ GROUP(ee_cec, 0, 14),
};
static const char * const gpio_periphs_groups[] = {
@@ -689,6 +694,10 @@
"spdif_out_ao_6", "spdif_out_ao_9",
};
+static const char * const cec_ao_groups[] = {
+ "ao_cec", "ee_cec",
+};
+
static struct meson_pmx_func meson_gxl_periphs_functions[] = {
FUNCTION(gpio_periphs),
FUNCTION(emmc),
@@ -726,6 +735,7 @@
FUNCTION(pwm_ao_b),
FUNCTION(i2s_out_ao),
FUNCTION(spdif_out_ao),
+ FUNCTION(cec_ao),
};
static struct meson_bank meson_gxl_periphs_banks[] = {
--
1.9.1

View file

@ -1,88 +0,0 @@
From 8b9fed5697ca5dad3197822eb34ae317f45a16a5 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:28:59 +0200
Subject: [PATCH 19/93] drm: bridge: dw-hdmi: Create connector in the bridge
attach operation
The DRM device is not guaranteed by the bridge API to be available
before the attach callback. The driver performs properly at the moment
as it doesn't use the drm_bridge_add() registration method. As this will
be changed later, move connector creation to attach time to ensure
compatibility with the API.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-10-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 92ce9e5..88cd40a 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1667,6 +1667,25 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
.best_encoder = drm_atomic_helper_best_encoder,
};
+static int dw_hdmi_bridge_attach(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_connector *connector = &hdmi->connector;
+
+ connector->interlace_allowed = 1;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs);
+
+ drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ return 0;
+}
+
static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *orig_mode,
struct drm_display_mode *mode)
@@ -1704,6 +1723,7 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
}
static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .attach = dw_hdmi_bridge_attach,
.enable = dw_hdmi_bridge_enable,
.disable = dw_hdmi_bridge_disable,
.mode_set = dw_hdmi_bridge_mode_set,
@@ -1829,17 +1849,6 @@ static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi)
return -EINVAL;
}
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_connector_helper_add(&hdmi->connector,
- &dw_hdmi_connector_helper_funcs);
-
- drm_connector_init(encoder->dev, &hdmi->connector,
- &dw_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
-
- drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
-
return 0;
}
@@ -1862,8 +1871,6 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
if (!hdmi)
return -ENOMEM;
- hdmi->connector.interlace_allowed = 1;
-
hdmi->plat_data = plat_data;
hdmi->dev = dev;
hdmi->dev_type = plat_data->dev_type;
--
1.9.1

View file

@ -0,0 +1,58 @@
From d68ddd72a278abaeeec0ebccd7146f50fce9a4af Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 17:53:43 +0200
Subject: [PATCH 19/79] pinctrl: meson-gxl: Add Ethernet PHY LEDS pins
The Amlogic Meson GXL SoCs embeds an 10/100 Ethernet PHY, this patchs enables
the Link and Activity LEDs signals.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index da7f3e9..7adc7c2 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -234,6 +234,9 @@
static const unsigned int spdif_out_h_pins[] = { PIN(GPIOH_4, EE_OFF) };
+static const unsigned int eth_link_led_pins[] = { PIN(GPIOZ_14, EE_OFF) };
+static const unsigned int eth_act_led_pins[] = { PIN(GPIOZ_15, EE_OFF) };
+
static const struct pinctrl_pin_desc meson_gxl_aobus_pins[] = {
MESON_PIN(GPIOAO_0, 0),
MESON_PIN(GPIOAO_1, 0),
@@ -428,6 +431,8 @@
GROUP(i2s_out_ch23_z, 3, 26),
GROUP(i2s_out_ch45_z, 3, 25),
GROUP(i2s_out_ch67_z, 3, 24),
+ GROUP(eth_link_led, 4, 25),
+ GROUP(eth_act_led, 4, 24),
/* Bank H */
GROUP(hdmi_hpd, 6, 31),
@@ -652,6 +657,10 @@
"spdif_out_h",
};
+static const char * const eth_led_groups[] = {
+ "eth_link_led", "eth_act_led",
+};
+
static const char * const gpio_aobus_groups[] = {
"GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3", "GPIOAO_4",
"GPIOAO_5", "GPIOAO_6", "GPIOAO_7", "GPIOAO_8", "GPIOAO_9",
@@ -722,6 +731,7 @@
FUNCTION(hdmi_i2c),
FUNCTION(i2s_out),
FUNCTION(spdif_out),
+ FUNCTION(eth_led),
};
static struct meson_pmx_func meson_gxl_aobus_functions[] = {
--
1.9.1

View file

@ -1,220 +0,0 @@
From 200c0b9edb6b1203d6db6391d940f69b6f56e1d6 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:00 +0200
Subject: [PATCH 20/93] drm: bridge: dw-hdmi: Implement DRM bridge registration
As an option for drivers not based on the component framework, register
the bridge with the DRM core with the DRM bridge API. Existing drivers
based on dw_hdmi_bind() and dw_hdmi_unbind() are not affected as those
functions are preserved with their current behaviour.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-11-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 112 ++++++++++++++++++++++++++++-----------
include/drm/bridge/dw_hdmi.h | 3 ++
2 files changed, 83 insertions(+), 32 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 88cd40a..107fea4 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1836,24 +1836,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int dw_hdmi_register(struct drm_encoder *encoder, struct dw_hdmi *hdmi)
-{
- struct drm_bridge *bridge = &hdmi->bridge;
- int ret;
-
- bridge->driver_private = hdmi;
- bridge->funcs = &dw_hdmi_bridge_funcs;
- ret = drm_bridge_attach(encoder, bridge, NULL);
- if (ret) {
- DRM_ERROR("Failed to initialize bridge with drm\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
- const struct dw_hdmi_plat_data *plat_data)
+static struct dw_hdmi *
+__dw_hdmi_probe(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
@@ -1869,7 +1854,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
hdmi->plat_data = plat_data;
hdmi->dev = dev;
@@ -1896,7 +1881,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
break;
default:
dev_err(dev, "reg-io-width must be 1 or 4\n");
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
@@ -1905,7 +1890,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
of_node_put(ddc_node);
if (!hdmi->ddc) {
dev_dbg(hdmi->dev, "failed to read ddc node\n");
- return -EPROBE_DEFER;
+ return ERR_PTR(-EPROBE_DEFER);
}
} else {
@@ -1956,8 +1941,10 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
initialize_hdmi_ih_mutes(hdmi);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
+ if (irq < 0) {
+ ret = irq;
goto err_iahb;
+ }
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
dw_hdmi_irq, IRQF_SHARED,
@@ -1988,11 +1975,11 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
HDMI_IH_PHY_STAT0);
- ret = dw_hdmi_fb_registered(hdmi);
- if (ret)
- goto err_iahb;
+ hdmi->bridge.driver_private = hdmi;
+ hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
+ hdmi->bridge.of_node = pdev->dev.of_node;
- ret = dw_hdmi_register(encoder, hdmi);
+ ret = dw_hdmi_fb_registered(hdmi);
if (ret)
goto err_iahb;
@@ -2041,7 +2028,7 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
platform_set_drvdata(pdev, hdmi);
- return 0;
+ return hdmi;
err_iahb:
if (hdmi->i2c) {
@@ -2055,14 +2042,11 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
err_res:
i2c_put_adapter(hdmi->ddc);
- return ret;
+ return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(dw_hdmi_bind);
-void dw_hdmi_unbind(struct device *dev)
+static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
{
- struct dw_hdmi *hdmi = dev_get_drvdata(dev);
-
if (hdmi->audio && !IS_ERR(hdmi->audio))
platform_device_unregister(hdmi->audio);
@@ -2077,6 +2061,70 @@ void dw_hdmi_unbind(struct device *dev)
else
i2c_put_adapter(hdmi->ddc);
}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int dw_hdmi_probe(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data)
+{
+ struct dw_hdmi *hdmi;
+ int ret;
+
+ hdmi = __dw_hdmi_probe(pdev, plat_data);
+ if (IS_ERR(hdmi))
+ return PTR_ERR(hdmi);
+
+ ret = drm_bridge_add(&hdmi->bridge);
+ if (ret < 0) {
+ __dw_hdmi_remove(hdmi);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_probe);
+
+void dw_hdmi_remove(struct platform_device *pdev)
+{
+ struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
+
+ drm_bridge_remove(&hdmi->bridge);
+
+ __dw_hdmi_remove(hdmi);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+ const struct dw_hdmi_plat_data *plat_data)
+{
+ struct dw_hdmi *hdmi;
+ int ret;
+
+ hdmi = __dw_hdmi_probe(pdev, plat_data);
+ if (IS_ERR(hdmi))
+ return PTR_ERR(hdmi);
+
+ ret = drm_bridge_attach(encoder, &hdmi->bridge, NULL);
+ if (ret) {
+ dw_hdmi_remove(pdev);
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
+
+void dw_hdmi_unbind(struct device *dev)
+{
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+ __dw_hdmi_remove(hdmi);
+}
EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 94ff6ed..3bb22a8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -56,6 +56,9 @@ struct dw_hdmi_plat_data {
struct drm_display_mode *mode);
};
+int dw_hdmi_probe(struct platform_device *pdev,
+ const struct dw_hdmi_plat_data *plat_data);
+void dw_hdmi_remove(struct platform_device *pdev);
void dw_hdmi_unbind(struct device *dev);
int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
const struct dw_hdmi_plat_data *plat_data);
--
1.9.1

View file

@ -0,0 +1,28 @@
From 20c88cc6c1c4d6fb3903be634b54fd0659f2e364 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 11:53:57 +0200
Subject: [PATCH 20/79] pinctrl: meson-gxl: Add missing GPIODV_18 pin entry
GPIODV_18 entry was missing in the original driver push.
Fixes: 0f15f500ff2c ("pinctrl: meson: Add GXL pinctrl definitions")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
index 7adc7c2..6a486cb 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c
@@ -89,6 +89,7 @@
MESON_PIN(GPIODV_15, EE_OFF),
MESON_PIN(GPIODV_16, EE_OFF),
MESON_PIN(GPIODV_17, EE_OFF),
+ MESON_PIN(GPIODV_18, EE_OFF),
MESON_PIN(GPIODV_19, EE_OFF),
MESON_PIN(GPIODV_20, EE_OFF),
MESON_PIN(GPIODV_21, EE_OFF),
--
1.9.1

View file

@ -1,83 +0,0 @@
From 8fb0058965b30a39f1e0e3820b96013cfbf6bfc6 Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:01 +0200
Subject: [PATCH 21/93] drm: bridge: dw-hdmi: Remove PHY configuration
resolution parameter
The current code hard codes the call of hdmi_phy_configure() to be 8bpp
and provides extraneous error checking to verify that this hardcoded
value is correct. Simplify the implementation by removing the argument.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-12-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 27 +++++----------------------
1 file changed, 5 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 107fea4..b4fb0bd 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -930,31 +930,14 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct dw_hdmi *hdmi,
- unsigned char res, int cscon)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
{
- unsigned res_idx;
u8 val, msec;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
- switch (res) {
- case 0: /* color resolution 0 is 8 bit colour depth */
- case 8:
- res_idx = DW_HDMI_RES_8;
- break;
- case 10:
- res_idx = DW_HDMI_RES_10;
- break;
- case 12:
- res_idx = DW_HDMI_RES_12;
- break;
- default:
- return -EINVAL;
- }
-
/* PLL/MPLL Cfg - always match on final entry */
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
if (hdmi->hdmi_data.video_mode.mpixelclock <=
@@ -1004,11 +987,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi,
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[res_idx].gmp, 0x15);
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, 0x15);
/* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[res_idx], 0x10);
+ hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], 0x10);
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
@@ -1068,7 +1051,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
dw_hdmi_phy_enable_powerdown(hdmi, true);
/* Enable CSC */
- ret = hdmi_phy_configure(hdmi, 8, cscon);
+ ret = hdmi_phy_configure(hdmi, cscon);
if (ret)
return ret;
}
--
1.9.1

View file

@ -0,0 +1,28 @@
From 8dc15df570ea27434fa31704ca2bf2684471c2b4 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Tue, 23 May 2017 16:03:44 +0200
Subject: [PATCH 21/79] pinctrl: meson-gxbb: Add missing GPIODV_18 pin entry
GPIODV_18 entry was missing in the original driver push.
Fixes: 468c234f9ed7 ("pinctrl: amlogic: Add support for Amlogic Meson GXBB SoC")
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 114e690..2ccd776 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -85,6 +85,7 @@
MESON_PIN(GPIODV_15, EE_OFF),
MESON_PIN(GPIODV_16, EE_OFF),
MESON_PIN(GPIODV_17, EE_OFF),
+ MESON_PIN(GPIODV_18, EE_OFF),
MESON_PIN(GPIODV_19, EE_OFF),
MESON_PIN(GPIODV_20, EE_OFF),
MESON_PIN(GPIODV_21, EE_OFF),
--
1.9.1

View file

@ -0,0 +1,104 @@
From 1c11d32e68aa3591701810fc88fb1ed0e12d730d Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hans.verkuil@cisco.com>
Date: Wed, 7 Jun 2017 11:46:08 -0300
Subject: [PATCH 22/79] cec: add cec_s_phys_addr_from_edid helper function
This function simplifies the integration of CEC in DRM drivers.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
Documentation/media/kapi/cec-core.rst | 8 ++++++++
drivers/media/cec/cec-adap.c | 14 ++++++++++++++
include/media/cec.h | 9 +++++++++
3 files changed, 31 insertions(+)
diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst
index 7a04c53..278b358 100644
--- a/Documentation/media/kapi/cec-core.rst
+++ b/Documentation/media/kapi/cec-core.rst
@@ -307,6 +307,14 @@ to another valid physical address, then this function will first set the
address to CEC_PHYS_ADDR_INVALID before enabling the new physical address.
.. c:function::
+ void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
+ const struct edid *edid);
+
+A helper function that extracts the physical address from the edid struct
+and calls cec_s_phys_addr() with that address, or CEC_PHYS_ADDR_INVALID
+if the EDID did not contain a physical address or edid was a NULL pointer.
+
+.. c:function::
int cec_s_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs *log_addrs, bool block);
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 9dfc798..8a4417f 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -28,6 +28,8 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <drm/drm_edid.h>
+
#include "cec-priv.h"
static void cec_fill_msg_report_features(struct cec_adapter *adap,
@@ -1404,6 +1406,18 @@ void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
}
EXPORT_SYMBOL_GPL(cec_s_phys_addr);
+void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
+ const struct edid *edid)
+{
+ u16 pa = CEC_PHYS_ADDR_INVALID;
+
+ if (edid && edid->extensions)
+ pa = cec_get_edid_phys_addr((const u8 *)edid,
+ EDID_LENGTH * (edid->extensions + 1), NULL);
+ cec_s_phys_addr(adap, pa, false);
+}
+EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid);
+
/*
* Called from either the ioctl or a driver to set the logical addresses.
*
diff --git a/include/media/cec.h b/include/media/cec.h
index 201f060..ae206e2 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -206,6 +206,8 @@ static inline bool cec_is_sink(const struct cec_adapter *adap)
#define cec_phys_addr_exp(pa) \
((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf
+struct edid;
+
#if IS_REACHABLE(CONFIG_CEC_CORE)
struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
void *priv, const char *name, u32 caps, u8 available_las);
@@ -217,6 +219,8 @@ int cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs,
bool block);
void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
bool block);
+void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
+ const struct edid *edid);
int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
bool block);
@@ -326,6 +330,11 @@ static inline void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr,
{
}
+static inline void cec_s_phys_addr_from_edid(struct cec_adapter *adap,
+ const struct edid *edid)
+{
+}
+
static inline u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
unsigned int *offset)
{
--
1.9.1

View file

@ -1,68 +0,0 @@
From c7604b72b3695ee449d16916aa474b23c53af425 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:02 +0200
Subject: [PATCH 22/93] drm: bridge: dw-hdmi: Rename CONF0 SPARECTRL bit to
SVSRET
The bit is documented in a Rockchip BSP as
#define m_SVSRET_SIG (1 << 5) /* depend on PHY_MHL_COMB0=1 */
This is confirmed by a Renesas platform, which uses a 2.0 DWC HDMI TX as
the RK3288. Rename the bit accordingly.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-13-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 8 ++++----
drivers/gpu/drm/bridge/dw-hdmi.h | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index b4fb0bd..06c252f 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -895,11 +895,11 @@ static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_ENTMDS_MASK);
}
-static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_SPARECTRL_OFFSET,
- HDMI_PHY_CONF0_SPARECTRL_MASK);
+ HDMI_PHY_CONF0_SVSRET_OFFSET,
+ HDMI_PHY_CONF0_SVSRET_MASK);
}
static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
@@ -1014,7 +1014,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
dw_hdmi_phy_gen2_pddq(hdmi, 0);
if (hdmi->dev_type == RK3288_HDMI)
- dw_hdmi_phy_enable_spare(hdmi, 1);
+ dw_hdmi_phy_enable_svsret(hdmi, 1);
/*Wait for PHY PLL lock */
msec = 5;
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index 55135bb..08235ae 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -847,8 +847,8 @@ enum {
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
- HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
- HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
+ HDMI_PHY_CONF0_SVSRET_MASK = 0x20,
+ HDMI_PHY_CONF0_SVSRET_OFFSET = 5,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
--
1.9.1

View file

@ -0,0 +1,40 @@
From f853954636579085c6c21bf7df08af2c44f77042 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hans.verkuil@cisco.com>
Date: Wed, 7 Jun 2017 11:46:09 -0300
Subject: [PATCH 23/79] cec: add cec_phys_addr_invalidate() helper function
Simplifies setting the physical address to CEC_PHYS_ADDR_INVALID.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Hans Verkuil <hansverk@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
include/media/cec.h | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/include/media/cec.h b/include/media/cec.h
index ae206e2..fc69588 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -360,4 +360,17 @@ static inline int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
#endif
+/**
+ * cec_phys_addr_invalidate() - set the physical address to INVALID
+ *
+ * @adap: the CEC adapter
+ *
+ * This is a simple helper function to invalidate the physical
+ * address.
+ */
+static inline void cec_phys_addr_invalidate(struct cec_adapter *adap)
+{
+ cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false);
+}
+
#endif /* _MEDIA_CEC_H */
--
1.9.1

View file

@ -1,95 +0,0 @@
From a2bdacb64471d710bb4bdbc70e27d276eaae6d00 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:03 +0200
Subject: [PATCH 23/93] drm: bridge: dw-hdmi: Reject invalid product IDs
The DWC HDMI TX can be recognized by the two product identification
registers. If the registers don't read as expect the IP will be very
different than what the driver has been designed for, or will be
misconfigured in a way that makes it non-operational (invalid memory
address, incorrect clocks, ...). We should reject this situation with an
error.
While this isn't critical for proper operation with supported IPs at the
moment, the driver will soon gain automatic device-specific handling
based on runtime device identification. This change makes it easier to
implement that without having to default to a random guess in case the
device can't be identified.
While at it print a readable version number in the device identification
message instead of raw register values.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-14-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 25 +++++++++++++++++++------
drivers/gpu/drm/bridge/dw-hdmi.h | 8 ++++++++
2 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 06c252f..1809247 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1832,6 +1832,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
int irq;
int ret;
u32 val = 1;
+ u16 version;
+ u8 prod_id0;
+ u8 prod_id1;
u8 config0;
u8 config1;
@@ -1914,12 +1917,22 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
}
/* Product and revision IDs */
- dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+ version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
+ | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
+ prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
+ prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
+
+ if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX ||
+ (prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) {
+ dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n",
+ version, prod_id0, prod_id1);
+ ret = -ENODEV;
+ goto err_iahb;
+ }
+
+ dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n",
+ version >> 12, version & 0xfff,
+ prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without");
initialize_hdmi_ih_mutes(hdmi);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index 08235ae..91d7fab 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -545,6 +545,14 @@
#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
enum {
+/* PRODUCT_ID0 field values */
+ HDMI_PRODUCT_ID0_HDMI_TX = 0xa0,
+
+/* PRODUCT_ID1 field values */
+ HDMI_PRODUCT_ID1_HDCP = 0xc0,
+ HDMI_PRODUCT_ID1_HDMI_RX = 0x02,
+ HDMI_PRODUCT_ID1_HDMI_TX = 0x01,
+
/* CONFIG0_ID field values */
HDMI_CONFIG0_I2S = 0x10,
--
1.9.1

View file

@ -0,0 +1,104 @@
From e7f6f1daa5b19c35fbf25d6f5501273023a41f72 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hverkuil@xs4all.nl>
Date: Wed, 7 Jun 2017 11:46:10 -0300
Subject: [PATCH 24/79] cec: add cec_transmit_attempt_done helper function
A simpler variant of cec_transmit_done to be used where the HW does
just a single attempt at a transmit. So if the status indicates an
error, then the corresponding error count will always be 1 and this
function figures that out based on the status argument.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
Documentation/media/kapi/cec-core.rst | 10 ++++++++++
drivers/media/cec/cec-adap.c | 26 ++++++++++++++++++++++++++
include/media/cec.h | 6 ++++++
3 files changed, 42 insertions(+)
diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst
index 278b358..8a65c69 100644
--- a/Documentation/media/kapi/cec-core.rst
+++ b/Documentation/media/kapi/cec-core.rst
@@ -194,6 +194,11 @@ When a transmit finished (successfully or otherwise):
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
+or:
+
+.. c:function::
+ void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status);
+
The status can be one of:
CEC_TX_STATUS_OK:
@@ -231,6 +236,11 @@ to 1, if the hardware does support retry then either set these counters to
0 if the hardware provides no feedback of which errors occurred and how many
times, or fill in the correct values as reported by the hardware.
+The cec_transmit_attempt_done() function is a helper for cases where the
+hardware never retries, so the transmit is always for just a single
+attempt. It will call cec_transmit_done() in turn, filling in 1 for the
+count argument corresponding to the status. Or all 0 if the status was OK.
+
When a CEC message was received:
.. c:function::
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 8a4417f..193cea1 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -546,6 +546,32 @@ void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
}
EXPORT_SYMBOL_GPL(cec_transmit_done);
+void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status)
+{
+ switch (status) {
+ case CEC_TX_STATUS_OK:
+ cec_transmit_done(adap, status, 0, 0, 0, 0);
+ return;
+ case CEC_TX_STATUS_ARB_LOST:
+ cec_transmit_done(adap, status, 1, 0, 0, 0);
+ return;
+ case CEC_TX_STATUS_NACK:
+ cec_transmit_done(adap, status, 0, 1, 0, 0);
+ return;
+ case CEC_TX_STATUS_LOW_DRIVE:
+ cec_transmit_done(adap, status, 0, 0, 1, 0);
+ return;
+ case CEC_TX_STATUS_ERROR:
+ cec_transmit_done(adap, status, 0, 0, 0, 1);
+ return;
+ default:
+ /* Should never happen */
+ WARN(1, "cec-%s: invalid status 0x%02x\n", adap->name, status);
+ return;
+ }
+}
+EXPORT_SYMBOL_GPL(cec_transmit_attempt_done);
+
/*
* Called when waiting for a reply times out.
*/
diff --git a/include/media/cec.h b/include/media/cec.h
index fc69588..23c1faa 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -227,6 +227,12 @@ int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg,
/* Called by the adapter */
void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt,
u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt);
+/*
+ * Simplified version of cec_transmit_done for hardware that doesn't retry
+ * failed transmits. So this is always just one attempt in which case
+ * the status is sufficient.
+ */
+void cec_transmit_attempt_done(struct cec_adapter *adap, u8 status);
void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
/**
--
1.9.1

View file

@ -1,62 +0,0 @@
From dce4baf82ad245b9fc6a6fe6945e484ac9f32fa4 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:04 +0200
Subject: [PATCH 24/93] drm: bridge: dw-hdmi: Detect AHB audio DMA using
correct register
Bit 0 in CONFIG1_ID tells whether the IP core uses an AHB slave
interface for control. The correct way to identify AHB audio DMA support
is through bit 1 in CONFIG3_ID.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-15-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 6 +++---
drivers/gpu/drm/bridge/dw-hdmi.h | 4 ++++
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 1809247..730a7558 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1836,7 +1836,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
u8 prod_id0;
u8 prod_id1;
u8 config0;
- u8 config1;
+ u8 config3;
hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
if (!hdmi)
@@ -1988,9 +1988,9 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
pdevinfo.id = PLATFORM_DEVID_AUTO;
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
- config1 = hdmi_readb(hdmi, HDMI_CONFIG1_ID);
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
- if (config1 & HDMI_CONFIG1_AHB) {
+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
struct dw_hdmi_audio_data audio;
audio.phys = iores->start;
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index 91d7fab..a4fd64a 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -559,6 +559,10 @@ enum {
/* CONFIG1_ID field values */
HDMI_CONFIG1_AHB = 0x01,
+/* CONFIG3_ID field values */
+ HDMI_CONFIG3_AHBAUDDMA = 0x02,
+ HDMI_CONFIG3_GPAUD = 0x01,
+
/* IH_FC_INT2 field values */
HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
--
1.9.1

View file

@ -0,0 +1,176 @@
From e4826bb782c7fca70e8c1b7cbe1bb726400399b5 Mon Sep 17 00:00:00 2001
From: Hans Verkuil <hans.verkuil@cisco.com>
Date: Wed, 7 Jun 2017 11:46:12 -0300
Subject: [PATCH 25/79] cec: add CEC_CAP_NEEDS_HPD
Add a new capability CEC_CAP_NEEDS_HPD. If this capability is set
then the hardware can only use CEC if the HDMI Hotplug Detect pin
is high. Such hardware cannot handle the corner case in the CEC specification
where it is possible to transmit messages even if no hotplug signal is
present (needed for some displays that turn off the HPD when in standby,
but still have CEC enabled).
Typically hardware that needs this capability have the HPD wired to the CEC
block, often to a 'power' or 'active' pin.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/media/cec/cec-adap.c | 20 ++++++++++++++------
drivers/media/cec/cec-api.c | 5 ++++-
drivers/media/cec/cec-core.c | 1 +
include/media/cec.h | 1 +
include/uapi/linux/cec.h | 2 ++
5 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
index 193cea1..ab82e84 100644
--- a/drivers/media/cec/cec-adap.c
+++ b/drivers/media/cec/cec-adap.c
@@ -368,6 +368,8 @@ int cec_thread_func(void *_adap)
* transmit should be canceled.
*/
err = wait_event_interruptible_timeout(adap->kthread_waitq,
+ (adap->needs_hpd &&
+ (!adap->is_configured && !adap->is_configuring)) ||
kthread_should_stop() ||
(!adap->transmitting &&
!list_empty(&adap->transmit_queue)),
@@ -383,7 +385,9 @@ int cec_thread_func(void *_adap)
mutex_lock(&adap->lock);
- if (kthread_should_stop()) {
+ if ((adap->needs_hpd &&
+ (!adap->is_configured && !adap->is_configuring)) ||
+ kthread_should_stop()) {
cec_flush(adap);
goto unlock;
}
@@ -675,7 +679,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
return -EINVAL;
}
if (!adap->is_configured && !adap->is_configuring) {
- if (msg->msg[0] != 0xf0) {
+ if (adap->needs_hpd || msg->msg[0] != 0xf0) {
dprintk(1, "%s: adapter is unconfigured\n", __func__);
return -ENONET;
}
@@ -1154,7 +1158,9 @@ static int cec_config_log_addr(struct cec_adapter *adap,
*/
static void cec_adap_unconfigure(struct cec_adapter *adap)
{
- WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
+ if (!adap->needs_hpd ||
+ adap->phys_addr != CEC_PHYS_ADDR_INVALID)
+ WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID));
adap->log_addrs.log_addr_mask = 0;
adap->is_configuring = false;
adap->is_configured = false;
@@ -1383,6 +1389,8 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (phys_addr == adap->phys_addr || adap->devnode.unregistered)
return;
+ dprintk(1, "new physical address %x.%x.%x.%x\n",
+ cec_phys_addr_exp(phys_addr));
if (phys_addr == CEC_PHYS_ADDR_INVALID ||
adap->phys_addr != CEC_PHYS_ADDR_INVALID) {
adap->phys_addr = CEC_PHYS_ADDR_INVALID;
@@ -1392,7 +1400,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (adap->monitor_all_cnt)
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
mutex_lock(&adap->devnode.lock);
- if (list_empty(&adap->devnode.fhs))
+ if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock);
if (phys_addr == CEC_PHYS_ADDR_INVALID)
@@ -1400,7 +1408,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
}
mutex_lock(&adap->devnode.lock);
- if (list_empty(&adap->devnode.fhs) &&
+ if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) &&
adap->ops->adap_enable(adap, true)) {
mutex_unlock(&adap->devnode.lock);
return;
@@ -1408,7 +1416,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
if (adap->monitor_all_cnt &&
call_op(adap, adap_monitor_all_enable, true)) {
- if (list_empty(&adap->devnode.fhs))
+ if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
WARN_ON(adap->ops->adap_enable(adap, false));
mutex_unlock(&adap->devnode.lock);
return;
diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c
index 999926f..f7eb4c5 100644
--- a/drivers/media/cec/cec-api.c
+++ b/drivers/media/cec/cec-api.c
@@ -202,7 +202,8 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh,
err = -EPERM;
else if (adap->is_configuring)
err = -ENONET;
- else if (!adap->is_configured && msg.msg[0] != 0xf0)
+ else if (!adap->is_configured &&
+ (adap->needs_hpd || msg.msg[0] != 0xf0))
err = -ENONET;
else if (cec_is_busy(adap, fh))
err = -EBUSY;
@@ -515,6 +516,7 @@ static int cec_open(struct inode *inode, struct file *filp)
mutex_lock(&devnode->lock);
if (list_empty(&devnode->fhs) &&
+ !adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
err = adap->ops->adap_enable(adap, true);
if (err) {
@@ -559,6 +561,7 @@ static int cec_release(struct inode *inode, struct file *filp)
mutex_lock(&devnode->lock);
list_del(&fh->list);
if (list_empty(&devnode->fhs) &&
+ !adap->needs_hpd &&
adap->phys_addr == CEC_PHYS_ADDR_INVALID) {
WARN_ON(adap->ops->adap_enable(adap, false));
}
diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c
index 2f87748..b516d59 100644
--- a/drivers/media/cec/cec-core.c
+++ b/drivers/media/cec/cec-core.c
@@ -230,6 +230,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
adap->capabilities = caps;
+ adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
adap->available_log_addrs = available_las;
adap->sequence = 0;
adap->ops = ops;
diff --git a/include/media/cec.h b/include/media/cec.h
index 23c1faa..56643b2 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -164,6 +164,7 @@ struct cec_adapter {
u8 available_log_addrs;
u16 phys_addr;
+ bool needs_hpd;
bool is_configuring;
bool is_configured;
u32 monitor_all_cnt;
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
index a0dfe27..44579a2 100644
--- a/include/uapi/linux/cec.h
+++ b/include/uapi/linux/cec.h
@@ -336,6 +336,8 @@ static inline int cec_is_unconfigured(__u16 log_addr_mask)
#define CEC_CAP_RC (1 << 4)
/* Hardware can monitor all messages, not just directed and broadcast. */
#define CEC_CAP_MONITOR_ALL (1 << 5)
+/* Hardware can use CEC only if the HDMI HPD pin is high. */
+#define CEC_CAP_NEEDS_HPD (1 << 6)
/**
* struct cec_caps - CEC capabilities structure.
--
1.9.1

View file

@ -1,123 +0,0 @@
From 3b3c8dc7038a16dfeb29388d6b5afbef869ebc2d Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:05 +0200
Subject: [PATCH 25/93] drm: bridge: dw-hdmi: Handle overflow workaround based
on device version
Use the device version queried at runtime instead of the device type
provided through platform data to handle the overflow workaround. This
will make support of other SoCs integrating the same HDMI TX controller
version easier.
Among the supported platforms only i.MX6DL and i.MX6Q have been
identified as needing the workaround. Disabling it on Rockchip RK3288
(which integrates a v2.00a controller) didn't produce any error or
artifact.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-16-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 46 ++++++++++++++++++++++++++++------------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 730a7558..f4faa14 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -117,8 +117,10 @@ struct dw_hdmi {
struct drm_connector connector;
struct drm_bridge bridge;
- struct platform_device *audio;
enum dw_hdmi_devtype dev_type;
+ unsigned int version;
+
+ struct platform_device *audio;
struct device *dev;
struct clk *isfr_clk;
struct clk *iahb_clk;
@@ -1323,19 +1325,38 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
/* Workaround to clear the overflow condition */
static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
{
- int count;
+ unsigned int count;
+ unsigned int i;
u8 val;
- /* TMDS software reset */
- hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+ /*
+ * Under some circumstances the Frame Composer arithmetic unit can miss
+ * an FC register write due to being busy processing the previous one.
+ * The issue can be worked around by issuing a TMDS software reset and
+ * then write one of the FC registers several times.
+ *
+ * The number of iterations matters and depends on the HDMI TX revision
+ * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
+ * i.MX6DL (v1.31a) have been identified as needing the workaround, with
+ * 4 and 1 iterations respectively.
+ */
- val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
- if (hdmi->dev_type == IMX6DL_HDMI) {
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+ switch (hdmi->version) {
+ case 0x130a:
+ count = 4;
+ break;
+ case 0x131a:
+ count = 1;
+ break;
+ default:
return;
}
- for (count = 0; count < 4; count++)
+ /* TMDS software reset */
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+ val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+ for (i = 0; i < count; i++)
hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
}
@@ -1832,7 +1853,6 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
int irq;
int ret;
u32 val = 1;
- u16 version;
u8 prod_id0;
u8 prod_id1;
u8 config0;
@@ -1917,21 +1937,21 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
}
/* Product and revision IDs */
- version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
- | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
+ hdmi->version = (hdmi_readb(hdmi, HDMI_DESIGN_ID) << 8)
+ | (hdmi_readb(hdmi, HDMI_REVISION_ID) << 0);
prod_id0 = hdmi_readb(hdmi, HDMI_PRODUCT_ID0);
prod_id1 = hdmi_readb(hdmi, HDMI_PRODUCT_ID1);
if (prod_id0 != HDMI_PRODUCT_ID0_HDMI_TX ||
(prod_id1 & ~HDMI_PRODUCT_ID1_HDCP) != HDMI_PRODUCT_ID1_HDMI_TX) {
dev_err(dev, "Unsupported HDMI controller (%04x:%02x:%02x)\n",
- version, prod_id0, prod_id1);
+ hdmi->version, prod_id0, prod_id1);
ret = -ENODEV;
goto err_iahb;
}
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n",
- version >> 12, version & 0xfff,
+ hdmi->version >> 12, hdmi->version & 0xfff,
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without");
initialize_hdmi_ih_mutes(hdmi);
--
1.9.1

View file

@ -1,149 +0,0 @@
From c69ce1e08f7d1eeb8de98544ecc1c1c12fe91408 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:06 +0200
Subject: [PATCH 26/93] drm: bridge: dw-hdmi: Detect PHY type at runtime
Detect the PHY type and use it to handle the PHY type-specific SVSRET
signal.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-17-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 68 ++++++++++++++++++++++++++++++++++++++--
include/drm/bridge/dw_hdmi.h | 10 ++++++
2 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index f4faa14..ef4f2f9 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -113,6 +113,12 @@ struct dw_hdmi_i2c {
bool is_regaddr;
};
+struct dw_hdmi_phy_data {
+ enum dw_hdmi_phy_type type;
+ const char *name;
+ bool has_svsret;
+};
+
struct dw_hdmi {
struct drm_connector connector;
struct drm_bridge bridge;
@@ -134,7 +140,9 @@ struct dw_hdmi {
u8 edid[HDMI_EDID_LEN];
bool cable_plugin;
+ const struct dw_hdmi_phy_data *phy;
bool phy_enabled;
+
struct drm_display_mode previous_mode;
struct i2c_adapter *ddc;
@@ -1015,7 +1023,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
- if (hdmi->dev_type == RK3288_HDMI)
+ /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */
+ if (hdmi->phy->has_svsret)
dw_hdmi_phy_enable_svsret(hdmi, 1);
/*Wait for PHY PLL lock */
@@ -1840,6 +1849,54 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static const struct dw_hdmi_phy_data dw_hdmi_phys[] = {
+ {
+ .type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
+ .name = "DWC HDMI TX PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
+ .name = "DWC MHL PHY + HEAC PHY",
+ .has_svsret = true,
+ }, {
+ .type = DW_HDMI_PHY_DWC_MHL_PHY,
+ .name = "DWC MHL PHY",
+ .has_svsret = true,
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
+ .name = "DWC HDMI 3D TX PHY + HEAC PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
+ .name = "DWC HDMI 3D TX PHY",
+ }, {
+ .type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
+ .name = "DWC HDMI 2.0 TX PHY",
+ .has_svsret = true,
+ }
+};
+
+static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
+{
+ unsigned int i;
+ u8 phy_type;
+
+ phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
+
+ for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
+ if (dw_hdmi_phys[i].type == phy_type) {
+ hdmi->phy = &dw_hdmi_phys[i];
+ return 0;
+ }
+ }
+
+ if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
+ dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
+ else
+ dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
+ phy_type);
+
+ return -ENODEV;
+}
+
static struct dw_hdmi *
__dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data)
@@ -1950,9 +2007,14 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
goto err_iahb;
}
- dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP\n",
+ ret = dw_hdmi_detect_phy(hdmi);
+ if (ret < 0)
+ goto err_iahb;
+
+ dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
hdmi->version >> 12, hdmi->version & 0xfff,
- prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without");
+ prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
+ hdmi->phy->name);
initialize_hdmi_ih_mutes(hdmi);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 3bb22a8..b080a17 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -27,6 +27,16 @@ enum dw_hdmi_devtype {
RK3288_HDMI,
};
+enum dw_hdmi_phy_type {
+ DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
+ DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
+ DW_HDMI_PHY_DWC_MHL_PHY = 0xc2,
+ DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC = 0xe2,
+ DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY = 0xf2,
+ DW_HDMI_PHY_DWC_HDMI20_TX_PHY = 0xf3,
+ DW_HDMI_PHY_VENDOR_PHY = 0xfe,
+};
+
struct dw_hdmi_mpll_config {
unsigned long mpixelclock;
struct {
--
1.9.1

View file

@ -0,0 +1,42 @@
From 5337b8bcf8f92396880e95094f639a343ef5453a Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:11:42 +0200
Subject: [PATCH 26/79] dt-bindings: clock: gxbb: expose audin clock gate
Expose the clock gate required to power AUDIN block
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/meson/gxbb.h | 2 +-
include/dt-bindings/clock/gxbb-clkc.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 93b8f07..5c24285 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -205,7 +205,7 @@
#define CLKID_HIU_IFACE 32
#define CLKID_ASSIST_MISC 33
/* CLKID_SPI */
-#define CLKID_I2S_SPDIF 35
+/* CLKID_I2S_SPDIF */
/* CLKID_ETH */
#define CLKID_DEMUX 37
/* CLKID_AIU_GLUE */
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 3190e30..ba8a9be 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -17,6 +17,7 @@
#define CLKID_SAR_ADC 23
#define CLKID_RNG0 25
#define CLKID_SPI 34
+#define CLKID_I2S_SPDIF 35
#define CLKID_ETH 36
#define CLKID_AIU_GLUE 38
#define CLKID_I2S_OUT 40
--
1.9.1

View file

@ -0,0 +1,312 @@
From d4b067ab4833a89ccbd6c67bf5245621794dbe73 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 11:49:55 +0200
Subject: [PATCH 27/79] 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>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/meson/Kconfig | 9 ++
sound/soc/meson/Makefile | 3 +
sound/soc/meson/audio-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++
sound/soc/meson/audio-core.h | 28 +++++++
6 files changed, 232 insertions(+)
create mode 100644 sound/soc/meson/Kconfig
create mode 100644 sound/soc/meson/Makefile
create mode 100644 sound/soc/meson/audio-core.c
create mode 100644 sound/soc/meson/audio-core.h
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index c0abad2..7db316f 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -55,6 +55,7 @@ source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
source "sound/soc/mediatek/Kconfig"
+source "sound/soc/meson/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 39c27a5..d9892c3 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mediatek/
+obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
new file mode 100644
index 0000000..216c850
--- /dev/null
+++ b/sound/soc/meson/Kconfig
@@ -0,0 +1,9 @@
+menuconfig SND_SOC_MESON
+ tristate "ASoC support for Amlogic Meson SoCs"
+ depends on ARCH_MESON || COMPILE_TEST
+ 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
new file mode 100644
index 0000000..22028ab
--- /dev/null
+++ b/sound/soc/meson/Makefile
@@ -0,0 +1,3 @@
+snd-soc-meson-audio-core-objs := audio-core.o
+
+obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
diff --git a/sound/soc/meson/audio-core.c b/sound/soc/meson/audio-core.c
new file mode 100644
index 0000000..99993ec
--- /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 0000000..6e7a24c
--- /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_ */
--
1.9.1

View file

@ -1,145 +0,0 @@
From d7ce5ad1e16494b6881a9b3e641f224f5d27597b Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:07 +0200
Subject: [PATCH 27/93] drm: bridge: dw-hdmi: Define and use macros for PHY
register addresses
Replace the hardcoded register address numerical values with macros to
clarify the code.
This change has been tested by comparing the assembly code before and
after the change.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-18-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 35 ++++++++++++---------
drivers/gpu/drm/bridge/dw-hdmi.h | 66 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 86 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ef4f2f9..6e605fd 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -997,21 +997,26 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp, 0x15);
-
- /* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0], 0x10);
-
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
- hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
-
- hdmi_phy_i2c_write(hdmi, phy_config->term, 0x19); /* TXTERM */
- hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr, 0x09); /* CKSYMTXCTRL */
- hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr, 0x0E); /* VLEVCTRL */
-
- /* REMOVE CLK TERM */
- hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
+ HDMI_3D_TX_PHY_CPCE_CTRL);
+ hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
+ HDMI_3D_TX_PHY_GMPCTRL);
+ hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
+ HDMI_3D_TX_PHY_CURRCTRL);
+
+ hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
+ hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
+ HDMI_3D_TX_PHY_MSM_CTRL);
+
+ hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
+ hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+ HDMI_3D_TX_PHY_CKSYMTXCTRL);
+ hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+ HDMI_3D_TX_PHY_VLEVCTRL);
+
+ /* Override and disable clock termination. */
+ hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
+ HDMI_3D_TX_PHY_CKCALCTRL);
dw_hdmi_phy_enable_powerdown(hdmi, false);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index a4fd64a..f3c149c 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -1085,4 +1085,70 @@ enum {
HDMI_I2CM_CTLINT_ARB_MASK = 0x4,
};
+/*
+ * HDMI 3D TX PHY registers
+ */
+#define HDMI_3D_TX_PHY_PWRCTRL 0x00
+#define HDMI_3D_TX_PHY_SERDIVCTRL 0x01
+#define HDMI_3D_TX_PHY_SERCKCTRL 0x02
+#define HDMI_3D_TX_PHY_SERCKKILLCTRL 0x03
+#define HDMI_3D_TX_PHY_TXRESCTRL 0x04
+#define HDMI_3D_TX_PHY_CKCALCTRL 0x05
+#define HDMI_3D_TX_PHY_CPCE_CTRL 0x06
+#define HDMI_3D_TX_PHY_TXCLKMEASCTRL 0x07
+#define HDMI_3D_TX_PHY_TXMEASCTRL 0x08
+#define HDMI_3D_TX_PHY_CKSYMTXCTRL 0x09
+#define HDMI_3D_TX_PHY_CMPSEQCTRL 0x0a
+#define HDMI_3D_TX_PHY_CMPPWRCTRL 0x0b
+#define HDMI_3D_TX_PHY_CMPMODECTRL 0x0c
+#define HDMI_3D_TX_PHY_MEASCTRL 0x0d
+#define HDMI_3D_TX_PHY_VLEVCTRL 0x0e
+#define HDMI_3D_TX_PHY_D2ACTRL 0x0f
+#define HDMI_3D_TX_PHY_CURRCTRL 0x10
+#define HDMI_3D_TX_PHY_DRVANACTRL 0x11
+#define HDMI_3D_TX_PHY_PLLMEASCTRL 0x12
+#define HDMI_3D_TX_PHY_PLLPHBYCTRL 0x13
+#define HDMI_3D_TX_PHY_GRP_CTRL 0x14
+#define HDMI_3D_TX_PHY_GMPCTRL 0x15
+#define HDMI_3D_TX_PHY_MPLLMEASCTRL 0x16
+#define HDMI_3D_TX_PHY_MSM_CTRL 0x17
+#define HDMI_3D_TX_PHY_SCRPB_STATUS 0x18
+#define HDMI_3D_TX_PHY_TXTERM 0x19
+#define HDMI_3D_TX_PHY_PTRPT_ENBL 0x1a
+#define HDMI_3D_TX_PHY_PATTERNGEN 0x1b
+#define HDMI_3D_TX_PHY_SDCAP_MODE 0x1c
+#define HDMI_3D_TX_PHY_SCOPEMODE 0x1d
+#define HDMI_3D_TX_PHY_DIGTXMODE 0x1e
+#define HDMI_3D_TX_PHY_STR_STATUS 0x1f
+#define HDMI_3D_TX_PHY_SCOPECNT0 0x20
+#define HDMI_3D_TX_PHY_SCOPECNT1 0x21
+#define HDMI_3D_TX_PHY_SCOPECNT2 0x22
+#define HDMI_3D_TX_PHY_SCOPECNTCLK 0x23
+#define HDMI_3D_TX_PHY_SCOPESAMPLE 0x24
+#define HDMI_3D_TX_PHY_SCOPECNTMSB01 0x25
+#define HDMI_3D_TX_PHY_SCOPECNTMSB2CK 0x26
+
+/* HDMI_3D_TX_PHY_CKCALCTRL values */
+#define HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE BIT(15)
+
+/* HDMI_3D_TX_PHY_MSM_CTRL values */
+#define HDMI_3D_TX_PHY_MSM_CTRL_MPLL_PH_SEL_CK BIT(13)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_CLK_REF_MPLL (0 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_OFF (1 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_PCLK (2 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK (3 << 1)
+#define HDMI_3D_TX_PHY_MSM_CTRL_SCOPE_CK_SEL BIT(0)
+
+/* HDMI_3D_TX_PHY_PTRPT_ENBL values */
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_OVERRIDE BIT(15)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT2 BIT(8)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT1 BIT(7)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_PG_SKIP_BIT0 BIT(6)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CK_REF_ENB BIT(5)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_RCAL_ENB BIT(4)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_CLK_ALIGN_ENB BIT(3)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_TX_READY BIT(2)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_CKO_WORD_ENB BIT(1)
+#define HDMI_3D_TX_PHY_PTRPT_ENBL_REFCLK_ENB BIT(0)
+
#endif /* __DW_HDMI_H__ */
--
1.9.1

View file

@ -1,20 +1,25 @@
From d8358b5a254018c6329d4da6fb215bcecdfbceae Mon Sep 17 00:00:00 2001
From 45ed0fea98d308d6cae17be657dd01d5ee729d87 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 19 Jan 2017 15:49:08 +0100
Subject: [PATCH 74/93] snd: meson: add aiu register definitions
Date: Thu, 30 Mar 2017 12:00:10 +0200
Subject: [PATCH 28/79] ASoC: meson: add register definitions
Add the register definition for the AIU and AUDIN blocks
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/meson/aiu-regs.h | 186 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 186 insertions(+)
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 0000000..3b1945c
index 0000000..67391e6
--- /dev/null
+++ b/sound/soc/meson/aiu-regs.h
@@ -0,0 +1,186 @@
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2017 BayLibre, SAS
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
@ -37,10 +42,6 @@ index 0000000..3b1945c
+#ifndef _AIU_REGS_H_
+#define _AIU_REGS_H_
+
+/* Base address of AIU within Cbus */
+#define AIU_CBUS_BASE 0x5400 /* REALLY USEFUL ??? */
+
+/* AIU Registers */
+#define AIU_958_BPF 0x000
+#define AIU_958_BRST 0x004
+#define AIU_958_LENGTH 0x008
@ -85,7 +86,7 @@ index 0000000..3b1945c
+#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 /* Unknown */
+#define AIU_ACODEC_CTRL 0x0B0
+#define AIU_958_CHSTAT_R0 0x0C0
+#define AIU_958_CHSTAT_R1 0x0C4
+#define AIU_958_VALID_CTRL 0x0C8
@ -201,6 +202,160 @@ index 0000000..3b1945c
+#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 0000000..f224610
--- /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_ */
--
1.9.1

View file

@ -1,59 +0,0 @@
From 9e151c1acfd889a938f6f49bb07b14c101fa56d5 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:08 +0200
Subject: [PATCH 28/93] drm: bridge: dw-hdmi: Fix the name of the PHY reset
macros
The PHY reset signal is controlled by bit PHYRSTZ in the MC_PHYRSTZ
register. The signal is active low on Gen1 PHYs and active high on Gen2
PHYs. The driver toggles the signal high then low, which is correct for
all currently supported platforms, but the register values macros are
incorrectly named. Replace them with a single macro named after the bit,
and add a comment to the source code to explain the behaviour.
The driver's behaviour isn't changed by this rename, the code will still
need to be fixed to support Gen1 PHYs.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-19-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 6 +++---
drivers/gpu/drm/bridge/dw-hdmi.h | 3 +--
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 6e605fd..93e8816 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -986,9 +986,9 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
/* gen2 pddq */
dw_hdmi_phy_gen2_pddq(hdmi, 1);
- /* PHY reset */
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+ /* PHY reset. The reset signal is active high on Gen2 PHYs. */
+ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+ hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index f3c149c..325b0b8 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -989,8 +989,7 @@ enum {
HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
/* MC_PHYRSTZ field values */
- HDMI_MC_PHYRSTZ_ASSERT = 0x0,
- HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+ HDMI_MC_PHYRSTZ_PHYRSTZ = 0x01,
/* MC_HEACPHY_RST field values */
HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
--
1.9.1

View file

@ -1,163 +1,50 @@
From 0a351cf435e75a028694a7d5782f2b46582b004d Mon Sep 17 00:00:00 2001
From 98fd2d06e53a52a033317864b317549e6f3e9245 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Sun, 12 Feb 2017 00:50:07 +0100
Subject: [PATCH 76/93] snd: soc: meson: support for aiu i2s dma
Date: Thu, 30 Mar 2017 12:14:40 +0200
Subject: [PATCH 29/79] ASoC: meson: add aiu i2s dma support
Initial support for meson aiu i2s dma
TO BE COMPLETED ...
Add support for the i2s output dma which is part of the AIU block
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/meson/Kconfig | 17 ++
sound/soc/meson/Kconfig | 7 +
sound/soc/meson/Makefile | 2 +
sound/soc/meson/aiu-common.c | 69 ++++++++
sound/soc/meson/aiu-i2s-dma.c | 400 ++++++++++++++++++++++++++++++++++++++++++
sound/soc/meson/aiu.h | 6 +
7 files changed, 496 insertions(+)
create mode 100644 sound/soc/meson/Kconfig
create mode 100644 sound/soc/meson/Makefile
create mode 100644 sound/soc/meson/aiu-common.c
sound/soc/meson/aiu-i2s-dma.c | 367 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 376 insertions(+)
create mode 100644 sound/soc/meson/aiu-i2s-dma.c
create mode 100644 sound/soc/meson/aiu.h
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 182d92e..58ed5cf 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -54,6 +54,7 @@ source "sound/soc/kirkwood/Kconfig"
source "sound/soc/img/Kconfig"
source "sound/soc/intel/Kconfig"
source "sound/soc/mediatek/Kconfig"
+source "sound/soc/meson/Kconfig"
source "sound/soc/mxs/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/qcom/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 9a30f21..fbe16ac 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += img/
obj-$(CONFIG_SND_SOC) += intel/
obj-$(CONFIG_SND_SOC) += mediatek/
+obj-$(CONFIG_SND_SOC) += meson/
obj-$(CONFIG_SND_SOC) += mxs/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
new file mode 100644
index 0000000..f2504c6
--- /dev/null
index 216c850..ad31a11 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -0,0 +1,17 @@
+menu "Amlogic SoC Audio Support"
+ depends on ARCH_MESON || COMPILE_TEST
@@ -7,3 +7,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_MESON_AIU_I2S_DMA
+ tristate "Meson I2S Output DMA Support"
+ select MFD_SYSCON
+ select SND_MESON_AIU_COMMON
+config SND_SOC_MESON_I2S
+ tristate "Meson i2s interface"
+ depends on SND_SOC_MESON
+ help
+ This adds ASoC driver the Amlogic Meson i2s DAI
+ If unsure select "N".
+
+endmenu
+
+config SND_MESON_AIU_COMMON
+ tristate
+ depends on ARCH_MESON
+ depends on REGMAP_MMIO
+ 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
new file mode 100644
index 0000000..b237894
--- /dev/null
index 22028ab..273f275 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_MESON_AIU_COMMON) += aiu-common.o
+obj-$(CONFIG_SND_MESON_AIU_I2S_DMA) += aiu-i2s-dma.o
diff --git a/sound/soc/meson/aiu-common.c b/sound/soc/meson/aiu-common.c
new file mode 100644
index 0000000..9beee94
--- /dev/null
+++ b/sound/soc/meson/aiu-common.c
@@ -0,0 +1,69 @@
+/*
+ * 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/module.h>
+#include <linux/platform_device.h>
+
+
+static const char* aiu_gate_names[] = { "aiu_top", "aiu_glue" };
+
+static int aiu_common_register_clk_gates(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk *gate;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(aiu_gate_names); i++) {
+ gate = devm_clk_get(dev, aiu_gate_names[i]);
+ if (IS_ERR(gate)) {
+ if (PTR_ERR(gate) != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get %s clock gate\n",
+ aiu_gate_names[i]);
+ return PTR_ERR(gate);
+ }
+
+ ret = clk_prepare_enable(gate);
+ if (ret) {
+ dev_err(dev, "failed to enable %s clock gate\n",
+ aiu_gate_names[i]);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int aiu_common_register(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = aiu_common_register_clk_gates(pdev);
+ if (ret)
+ return ret;
+
+ /* FIXME: We should also handle the AIU reset here */
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(aiu_common_register);
+
+MODULE_DESCRIPTION("Meson AIU common helper");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
@@ -1,3 +1,5 @@
snd-soc-meson-audio-core-objs := audio-core.o
+snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
diff --git a/sound/soc/meson/aiu-i2s-dma.c b/sound/soc/meson/aiu-i2s-dma.c
new file mode 100644
index 0000000..1e8886c
index 0000000..bab950d
--- /dev/null
+++ b/sound/soc/meson/aiu-i2s-dma.c
@@ -0,0 +1,400 @@
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2017 BayLibre, SAS
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
@ -177,8 +64,6 @@ index 0000000..1e8886c
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
@ -189,16 +74,14 @@ index 0000000..1e8886c
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "aiu.h"
+#include "aiu-regs.h"
+#include "audio-core.h"
+
+#define DRV_NAME "meson-aiu-i2s-dma"
+
+struct aiu_i2s_dma {
+ struct regmap* regmap;
+
+ struct clk* i2s_out;
+
+ struct meson_audio_core_data *core;
+ struct clk *fast;
+ int irq;
+};
+
@ -218,21 +101,17 @@ index 0000000..1e8886c
+#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)
+#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)
+
+/*
+ * 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 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.
+ * - 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,
@ -265,20 +144,20 @@ index 0000000..1e8886c
+ .channels_min = 2,
+ .channels_max = 8,
+ .period_bytes_min = AIU_I2S_DMA_BURST,
+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535, /* 8192, */
+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535,
+ .periods_min = 2,
+ .periods_max = UINT_MAX,
+ .buffer_bytes_max = 1* 1024 * 1024,
+ .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;
+
+ return snd_soc_platform_get_drvdata(rtd->platform);
+}
+
+
+static snd_pcm_uframes_t
+aiu_i2s_dma_pointer(struct snd_pcm_substream *substream)
+{
@ -287,7 +166,7 @@ index 0000000..1e8886c
+ unsigned int addr;
+ int ret;
+
+ ret = regmap_read(priv->regmap, AIU_MEM_I2S_RD_PTR,
+ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR,
+ &addr);
+ if (ret)
+ return 0;
@ -300,7 +179,7 @@ index 0000000..1e8886c
+ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN |
+ AIU_MEM_I2S_CONTROL_EMPTY_EN);
+
+ regmap_update_bits(priv->regmap, AIU_MEM_I2S_CONTROL, en_mask,
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask,
+ enable ? en_mask : 0);
+
+}
@ -329,17 +208,17 @@ index 0000000..1e8886c
+
+static void __dma_init_mem(struct aiu_i2s_dma *priv)
+{
+ regmap_update_bits(priv->regmap, AIU_MEM_I2S_CONTROL,
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
+ AIU_MEM_I2S_CONTROL_INIT,
+ AIU_MEM_I2S_CONTROL_INIT);
+ regmap_update_bits(priv->regmap, AIU_MEM_I2S_BUF_CNTL,
+ 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->regmap, AIU_MEM_I2S_CONTROL,
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
+ AIU_MEM_I2S_CONTROL_INIT,
+ 0);
+ regmap_update_bits(priv->regmap, AIU_MEM_I2S_BUF_CNTL,
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
+ AIU_MEM_I2S_BUF_CNTL_INIT,
+ 0);
+}
@ -359,7 +238,7 @@ index 0000000..1e8886c
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
+ int ret;
+ u32 burst_num, desc = 0, mem_ctl = 0;
+ u32 burst_num, mem_ctl;
+ dma_addr_t end_ptr;
+
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
@ -367,48 +246,26 @@ index 0000000..1e8886c
+ return ret;
+
+ /* Setup memory layout */
+ if (params_physical_width(params) == 16) {
+ mem_ctl |= AIU_MEM_I2S_CONTROL_MODE_16BIT;
+ } else {
+ desc |= AIU_I2S_SOURCE_DESC_MODE_24BIT;
+ desc |= AIU_I2S_SOURCE_DESC_MODE_32BIT;
+ }
+ if (params_physical_width(params) == 16)
+ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT;
+ else
+ mem_ctl = 0;
+
+ switch (params_channels(params)) {
+ case 2: /* Nothing to do */
+ break;
+ case 8:
+ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Enable split mode - samples interleaved */
+ desc |= AIU_I2S_SOURCE_DESC_MODE_SPLIT;
+
+ regmap_update_bits(priv->regmap, AIU_MEM_I2S_CONTROL,
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
+ AIU_MEM_I2S_CONTROL_MODE_16BIT,
+ mem_ctl);
+
+ regmap_update_bits(priv->regmap, AIU_I2S_SOURCE_DESC,
+ AIU_I2S_SOURCE_DESC_MODE_8CH |
+ AIU_I2S_SOURCE_DESC_MODE_24BIT |
+ AIU_I2S_SOURCE_DESC_MODE_32BIT |
+ AIU_I2S_SOURCE_DESC_MODE_SPLIT,
+ desc);
+
+ /* Initialize memory pointers */
+ regmap_write(priv->regmap, AIU_MEM_I2S_START_PTR, runtime->dma_addr);
+ regmap_write(priv->regmap, AIU_MEM_I2S_RD_PTR, runtime->dma_addr);
+ 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->regmap, AIU_MEM_I2S_END_PTR, end_ptr);
+ 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->regmap, AIU_MEM_I2S_MASKS,
+ 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));
@ -456,22 +313,26 @@ index 0000000..1e8886c
+
+ /* Request the I2S DDR irq */
+ ret = request_irq(priv->irq, aiu_i2s_dma_irq_block, 0,
+ "meson-aiu-i2s-block", substream);
+ DRV_NAME, substream);
+ if (ret)
+ return ret;
+
+ /* Enable the DDR to FIFO clock gate */
+ return clk_prepare_enable(priv->i2s_out);
+ /* 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);
+
+ /* First close the clock gate so the DMA is definitely halted */
+ clk_disable_unprepare(priv->i2s_out);
+
+ /* Free the irq */
+ clk_disable_unprepare(priv->fast);
+ free_irq(priv->irq, substream);
+
+ return 0;
@ -507,28 +368,19 @@ index 0000000..1e8886c
+{
+ struct device *dev = &pdev->dev;
+ struct aiu_i2s_dma *priv;
+ int ret;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if(!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);
+
+ ret = aiu_common_register(pdev);
+ if (ret)
+ return ret;
+
+ priv->regmap = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(dev, "failed to get our regmap\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ priv->i2s_out = devm_clk_get(dev, "i2s_out");
+ if (IS_ERR(priv->i2s_out)) {
+ if(PTR_ERR(priv->i2s_out) != -EPROBE_DEFER)
+ dev_err(dev, "Can't get i2s_out\n");
+ return PTR_ERR(priv->i2s_out);
+ 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);
@ -540,17 +392,19 @@ index 0000000..1e8886c
+ return snd_soc_register_platform(dev, &aiu_i2s_platform);
+}
+
+static const struct of_device_id aiu_i2s_dma_match[] = {
+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_match);
+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_match,
+ .of_match_table = aiu_i2s_dma_of_match,
+ },
+};
+module_platform_driver(aiu_i2s_dma_pdrv);
@ -558,18 +412,6 @@ index 0000000..1e8886c
+MODULE_DESCRIPTION("Meson AIU i2s DMA ASoC Driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/aiu.h b/sound/soc/meson/aiu.h
new file mode 100644
index 0000000..a9d1c58
--- /dev/null
+++ b/sound/soc/meson/aiu.h
@@ -0,0 +1,6 @@
+#ifndef _AIU_H_
+#define _AIU_H_
+
+int aiu_common_register(struct platform_device *pdev);
+
+#endif /* _AIU_H_ */
--
1.9.1

View file

@ -1,49 +0,0 @@
From 9faac4dec35ecb92a6eb348a0904b5484b89df72 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Tue, 17 Jan 2017 10:29:09 +0200
Subject: [PATCH 29/93] drm: bridge: dw-hdmi: Assert SVSRET before resetting
the PHY
According to the PHY IP core vendor, the SVSRET signal must be asserted
before resetting the PHY. Tests on RK3288 and R-Car Gen3 showed no
regression, the change should thus be safe.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170117082910.27023-20-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 93e8816..4fda071 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -986,6 +986,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
/* gen2 pddq */
dw_hdmi_phy_gen2_pddq(hdmi, 1);
+ /* Leave low power consumption mode by asserting SVSRET. */
+ if (hdmi->phy->has_svsret)
+ dw_hdmi_phy_enable_svsret(hdmi, 1);
+
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
@@ -1028,11 +1032,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
dw_hdmi_phy_gen2_txpwron(hdmi, 1);
dw_hdmi_phy_gen2_pddq(hdmi, 0);
- /* The DWC MHL and HDMI 2.0 PHYs need the SVSRET signal to be set. */
- if (hdmi->phy->has_svsret)
- dw_hdmi_phy_enable_svsret(hdmi, 1);
-
- /*Wait for PHY PLL lock */
+ /* Wait for PHY PLL lock */
msec = 5;
do {
val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
--
1.9.1

View file

@ -0,0 +1,515 @@
From e976fda45f89573b89d118ded17112aae8a0f8f5 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 12:17:27 +0200
Subject: [PATCH 30/79] 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>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/meson/Kconfig | 2 +-
sound/soc/meson/Makefile | 2 +
sound/soc/meson/i2s-dai.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 468 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/meson/i2s-dai.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index ad31a11..604c9e2 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -12,5 +12,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 273f275..ea06dde 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -1,5 +1,7 @@
snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
+snd-soc-meson-i2s-dai-objs := i2s-dai.o
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
+obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
new file mode 100644
index 0000000..1008af8
--- /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");
--
1.9.1

View file

@ -1,40 +0,0 @@
From e9b6ad390a468f272176a6ceb103d63a46094be4 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Mon, 23 Jan 2017 13:20:38 +0100
Subject: [PATCH 30/93] drm: bridge: dw-hdmi: fix building without CONFIG_OF
The of_node member in struct drm_bridge is hidden when CONFIG_OF
is disabled, causing a build error:
drivers/gpu/drm/bridge/dw-hdmi.c: In function '__dw_hdmi_probe':
drivers/gpu/drm/bridge/dw-hdmi.c:2063:14: error: 'struct drm_bridge' has no member named 'of_node'
We could fix this either using a Kconfig dependency on CONFIG_OF
or making the one line conditional. The latter gives us better
compile test coverage, so this is what I'm doing here.
Fixes: 69497eb9234e ("drm: bridge: dw-hdmi: Implement DRM bridge registration")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170123122312.3290934-1-arnd@arndb.de
---
drivers/gpu/drm/bridge/dw-hdmi.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 4fda071..9a9ec27 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -2060,7 +2060,9 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
hdmi->bridge.driver_private = hdmi;
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
+#ifdef CONFIG_OF
hdmi->bridge.of_node = pdev->dev.of_node;
+#endif
ret = dw_hdmi_fb_registered(hdmi);
if (ret)
--
1.9.1

View file

@ -0,0 +1,439 @@
From e3ad81320cb0d2282f7a31bceab130bf4105a711 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 13:43:52 +0200
Subject: [PATCH 31/79] 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>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/meson/Kconfig | 7 +
sound/soc/meson/Makefile | 2 +
sound/soc/meson/aiu-spdif-dma.c | 385 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 394 insertions(+)
create mode 100644 sound/soc/meson/aiu-spdif-dma.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 604c9e2..8af3258 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -14,3 +14,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 ea06dde..cef9a9d 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -1,7 +1,9 @@
snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
+snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
snd-soc-meson-i2s-dai-objs := i2s-dai.o
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
diff --git a/sound/soc/meson/aiu-spdif-dma.c b/sound/soc/meson/aiu-spdif-dma.c
new file mode 100644
index 0000000..e3ff74b
--- /dev/null
+++ b/sound/soc/meson/aiu-spdif-dma.c
@@ -0,0 +1,385 @@
+/*
+ * 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;
+
+ return snd_soc_platform_get_drvdata(rtd->platform);
+}
+
+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);
+}
+
+struct snd_soc_platform_driver aiu_spdif_platform = {
+ .ops = &aiu_spdif_dma_ops,
+ .pcm_new = aiu_spdif_dma_new,
+};
+
+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 snd_soc_register_platform(dev, &aiu_spdif_platform);
+}
+
+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");
--
1.9.1

View file

@ -1,57 +0,0 @@
From 1ab78b07672b5e80bff302b1f2fab863a3107f2e Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Fri, 3 Mar 2017 19:19:58 +0200
Subject: [PATCH 31/93] drm: bridge: dw-hdmi: Remove unused functions
Most of the hdmi_phy_test_*() functions are unused. Remove them.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Tested-by: Nickey Yang <nickey.yang@rock-chips.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-2-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 26 --------------------------
1 file changed, 26 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 9a9ec27..ce74963 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -837,32 +837,6 @@ static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
}
-static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
- HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
- HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
-}
-
-static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
-}
-
static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
{
u32 val;
--
1.9.1

View file

@ -0,0 +1,430 @@
From f526e3ef0f6b52f591d93f2a68f25dd6062b592c Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 13:46:03 +0200
Subject: [PATCH 32/79] 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>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
sound/soc/meson/Kconfig | 3 +-
sound/soc/meson/Makefile | 2 +
sound/soc/meson/spdif-dai.c | 374 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 378 insertions(+), 1 deletion(-)
create mode 100644 sound/soc/meson/spdif-dai.c
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
index 8af3258..92422e7 100644
--- a/sound/soc/meson/Kconfig
+++ b/sound/soc/meson/Kconfig
@@ -18,6 +18,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 cef9a9d..bc4391c 100644
--- a/sound/soc/meson/Makefile
+++ b/sound/soc/meson/Makefile
@@ -2,8 +2,10 @@ snd-soc-meson-audio-core-objs := audio-core.o
snd-soc-meson-aiu-i2s-dma-objs := aiu-i2s-dma.o
snd-soc-meson-aiu-spdif-dma-objs := aiu-spdif-dma.o
snd-soc-meson-i2s-dai-objs := i2s-dai.o
+snd-soc-meson-spdif-dai-objs := spdif-dai.o
obj-$(CONFIG_SND_SOC_MESON) += snd-soc-meson-audio-core.o
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-aiu-i2s-dma.o
obj-$(CONFIG_SND_SOC_MESON_I2S) += snd-soc-meson-i2s-dai.o
obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-aiu-spdif-dma.o
+obj-$(CONFIG_SND_SOC_MESON_SPDIF) += snd-soc-meson-spdif-dai.o
diff --git a/sound/soc/meson/spdif-dai.c b/sound/soc/meson/spdif-dai.c
new file mode 100644
index 0000000..e763000
--- /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");
--
1.9.1

View file

@ -1,85 +0,0 @@
From 83ea2ac12ecbd8d77aa2ac7c3effcdac8301ef26 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Fri, 3 Mar 2017 19:19:59 +0200
Subject: [PATCH 32/93] drm: bridge: dw-hdmi: Move CSC configuration out of PHY
code
The color space converter isn't part of the PHY, move its configuration
out of PHY code.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-3-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 25 ++++++++++---------------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ce74963..906583b 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -914,7 +914,7 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
-static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
+static int hdmi_phy_configure(struct dw_hdmi *hdmi)
{
u8 val, msec;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
@@ -946,14 +946,6 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
return -EINVAL;
}
- /* Enable csc path */
- if (cscon)
- val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
- else
- val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
-
- hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
-
/* gen2 tx power off */
dw_hdmi_phy_gen2_txpwron(hdmi, 0);
@@ -1028,10 +1020,6 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, int cscon)
static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
{
int i, ret;
- bool cscon;
-
- /*check csc whether needed activated in HDMI mode */
- cscon = hdmi->sink_is_hdmi && is_color_space_conversion(hdmi);
/* HDMI Phy spec says to do the phy initialization sequence twice */
for (i = 0; i < 2; i++) {
@@ -1040,8 +1028,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
dw_hdmi_phy_enable_tmds(hdmi, 0);
dw_hdmi_phy_enable_powerdown(hdmi, true);
- /* Enable CSC */
- ret = hdmi_phy_configure(hdmi, cscon);
+ ret = hdmi_phy_configure(hdmi);
if (ret)
return ret;
}
@@ -1303,6 +1290,14 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
}
+
+ /* Enable color space conversion if needed (for HDMI sinks only). */
+ if (hdmi->sink_is_hdmi && is_color_space_conversion(hdmi))
+ hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
+ HDMI_MC_FLOWCTRL);
+ else
+ hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS,
+ HDMI_MC_FLOWCTRL);
}
static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
--
1.9.1

View file

@ -0,0 +1,33 @@
From f0bd8f7b16c1d75d562e0731704e96efa6ea3966 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 31 Mar 2017 15:55:03 +0200
Subject: [PATCH 33/79] 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>
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 97c123e..cd4114f 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -365,6 +365,10 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_SOC_MESON=m
+CONFIG_SND_SOC_MESON_I2S=m
+CONFIG_SND_SOC_MESON_SPDIF=m
+CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_AK4613=y
--
1.9.1

View file

@ -1,37 +0,0 @@
From 63411a28c0aad6f7df41c8d835d479d45ca35101 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 3 Mar 2017 19:20:00 +0200
Subject: [PATCH 33/93] drm: bridge: dw-hdmi: Enable CSC even for DVI
If the input pixel format is not RGB, the CSC must be enabled in order to
provide valid pixel to DVI sinks.
This patch removes the hdmi only dependency on the CSC enabling.
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-4-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 906583b..d863b33 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1291,8 +1291,8 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
}
- /* Enable color space conversion if needed (for HDMI sinks only). */
- if (hdmi->sink_is_hdmi && is_color_space_conversion(hdmi))
+ /* Enable color space conversion if needed */
+ if (is_color_space_conversion(hdmi))
hdmi_writeb(hdmi, HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH,
HDMI_MC_FLOWCTRL);
else
--
1.9.1

View file

@ -0,0 +1,27 @@
From 25b66766a7ebe95b2f083f27a808997d8438842c Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 31 Mar 2017 15:52:11 +0200
Subject: [PATCH 34/79] ARM64: defconfig: enable CONFIG_SND_SOC_ES7134 as
module
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index cd4114f..21f519d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -372,6 +372,7 @@ CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_AK4613=y
+CONFIG_SND_SOC_ES7134=m
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
--
1.9.1

View file

@ -1,150 +0,0 @@
From 4910824c44da97e1e8f1b934e75d0d40aaabaddc Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Mon, 6 Mar 2017 01:35:39 +0200
Subject: [PATCH 34/93] drm: bridge: dw-hdmi: Fix the PHY power down sequence
The PHY requires us to wait for the PHY to switch to low power mode
after deasserting TXPWRON and before asserting PDDQ in the power down
sequence, otherwise power down will fail.
The PHY power down can be monitored though the TX_READY bit, available
through I2C in the PHY registers, or the TX_PHY_LOCK bit, available
through the HDMI TX registers. As the two are equivalent, let's pick the
easier solution of polling the TX_PHY_LOCK bit.
The power down code is currently duplicated in multiple places. To avoid
spreading multiple calls to a TX_PHY_LOCK poll function, we have to
refactor the power down code and group it all in a single function.
Tests showed that one poll iteration was enough for TX_PHY_LOCK to
become low, without requiring any additional delay. Retrying the read
five times with a 1ms to 2ms delay between each attempt should thus be
more than enough.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170305233539.11898-1-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 52 +++++++++++++++++++++++++++++++++-------
1 file changed, 43 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index d863b33..3a1cd4c 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -116,6 +116,7 @@ struct dw_hdmi_i2c {
struct dw_hdmi_phy_data {
enum dw_hdmi_phy_type type;
const char *name;
+ unsigned int gen;
bool has_svsret;
};
@@ -914,6 +915,40 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
+static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
+{
+ const struct dw_hdmi_phy_data *phy = hdmi->phy;
+ unsigned int i;
+ u16 val;
+
+ if (phy->gen == 1) {
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_powerdown(hdmi, true);
+ return;
+ }
+
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+ /*
+ * Wait for TX_PHY_LOCK to be deasserted to indicate that the PHY went
+ * to low power mode.
+ */
+ for (i = 0; i < 5; ++i) {
+ val = hdmi_readb(hdmi, HDMI_PHY_STAT0);
+ if (!(val & HDMI_PHY_TX_PHY_LOCK))
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (val & HDMI_PHY_TX_PHY_LOCK)
+ dev_warn(hdmi->dev, "PHY failed to power down\n");
+ else
+ dev_dbg(hdmi->dev, "PHY powered down in %u iterations\n", i);
+
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
+}
+
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
{
u8 val, msec;
@@ -946,11 +981,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
return -EINVAL;
}
- /* gen2 tx power off */
- dw_hdmi_phy_gen2_txpwron(hdmi, 0);
-
- /* gen2 pddq */
- dw_hdmi_phy_gen2_pddq(hdmi, 1);
+ dw_hdmi_phy_power_off(hdmi);
/* Leave low power consumption mode by asserting SVSRET. */
if (hdmi->phy->has_svsret)
@@ -1025,8 +1056,6 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
for (i = 0; i < 2; i++) {
dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
dw_hdmi_phy_sel_interface_control(hdmi, 0);
- dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_powerdown(hdmi, true);
ret = hdmi_phy_configure(hdmi);
if (ret)
@@ -1256,8 +1285,7 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
if (!hdmi->phy_enabled)
return;
- dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_powerdown(hdmi, true);
+ dw_hdmi_phy_power_off(hdmi);
hdmi->phy_enabled = false;
}
@@ -1827,23 +1855,29 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
.type = DW_HDMI_PHY_DWC_HDMI_TX_PHY,
.name = "DWC HDMI TX PHY",
+ .gen = 1,
}, {
.type = DW_HDMI_PHY_DWC_MHL_PHY_HEAC,
.name = "DWC MHL PHY + HEAC PHY",
+ .gen = 2,
.has_svsret = true,
}, {
.type = DW_HDMI_PHY_DWC_MHL_PHY,
.name = "DWC MHL PHY",
+ .gen = 2,
.has_svsret = true,
}, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
.name = "DWC HDMI 3D TX PHY + HEAC PHY",
+ .gen = 2,
}, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
.name = "DWC HDMI 3D TX PHY",
+ .gen = 2,
}, {
.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
.name = "DWC HDMI 2.0 TX PHY",
+ .gen = 2,
.has_svsret = true,
}
};
--
1.9.1

View file

@ -0,0 +1,27 @@
From e23a5c9ce63bcacd81a63ed7f5a3049138de9cb0 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 31 Mar 2017 15:50:39 +0200
Subject: [PATCH 35/79] ARM64: defconfig: enable CONFIG_SND_SOC_DIO2125 as
module
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 21f519d..6fe57e4 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -372,6 +372,7 @@ CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_AK4613=y
+CONFIG_SND_SOC_DIO2125=m
CONFIG_SND_SOC_ES7134=m
CONFIG_USB=y
CONFIG_USB_OTG=y
--
1.9.1

View file

@ -1,113 +0,0 @@
From be5d590fc7021d9fa4aa9acd528f72047e8fd82b Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Mon, 6 Mar 2017 01:35:57 +0200
Subject: [PATCH 35/93] drm: bridge: dw-hdmi: Fix the PHY power up sequence
When powering the PHY up we need to wait for the PLL to lock. This is
done by polling the TX_PHY_LOCK bit in the HDMI_PHY_STAT0 register
(interrupt-based wait could be implemented as well but is likely
overkill). The bit is asserted when the PLL locks, but the current code
incorrectly waits for the bit to be deasserted. Fix it, and while at it,
replace the udelay() with a sleep as the code never runs in
non-sleepable context.
To be consistent with the power down implementation move the poll loop
to the power off function.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170305233557.11945-1-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 65 +++++++++++++++++++++++-----------------
1 file changed, 37 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 3a1cd4c..c25eac8 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -949,9 +949,44 @@ static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
dw_hdmi_phy_gen2_pddq(hdmi, 1);
}
+static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
+{
+ const struct dw_hdmi_phy_data *phy = hdmi->phy;
+ unsigned int i;
+ u8 val;
+
+ if (phy->gen == 1) {
+ dw_hdmi_phy_enable_powerdown(hdmi, false);
+
+ /* Toggle TMDS enable. */
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
+ return 0;
+ }
+
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+ /* Wait for PHY PLL lock */
+ for (i = 0; i < 5; ++i) {
+ val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ if (val)
+ break;
+
+ usleep_range(1000, 2000);
+ }
+
+ if (!val) {
+ dev_err(hdmi->dev, "PHY PLL failed to lock\n");
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(hdmi->dev, "PHY PLL locked %u iterations\n", i);
+ return 0;
+}
+
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
{
- u8 val, msec;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
@@ -1019,33 +1054,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
HDMI_3D_TX_PHY_CKCALCTRL);
- dw_hdmi_phy_enable_powerdown(hdmi, false);
-
- /* toggle TMDS enable */
- dw_hdmi_phy_enable_tmds(hdmi, 0);
- dw_hdmi_phy_enable_tmds(hdmi, 1);
-
- /* gen2 tx power on */
- dw_hdmi_phy_gen2_txpwron(hdmi, 1);
- dw_hdmi_phy_gen2_pddq(hdmi, 0);
-
- /* Wait for PHY PLL lock */
- msec = 5;
- do {
- val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
- if (!val)
- break;
-
- if (msec == 0) {
- dev_err(hdmi->dev, "PHY PLL not locked\n");
- return -ETIMEDOUT;
- }
-
- udelay(1000);
- msec--;
- } while (1);
-
- return 0;
+ return dw_hdmi_phy_power_on(hdmi);
}
static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
--
1.9.1

View file

@ -0,0 +1,26 @@
From d2922cf55cc2d5a0cd32d4d7055bbb3b1dacd459 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 31 Mar 2017 15:53:05 +0200
Subject: [PATCH 36/79] ARM64: defconfig: enable CONFIG_SND_SOC_SPDIF as module
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 6fe57e4..5da1e44 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -374,6 +374,7 @@ CONFIG_SND_SOC_RCAR=y
CONFIG_SND_SOC_AK4613=y
CONFIG_SND_SOC_DIO2125=m
CONFIG_SND_SOC_ES7134=m
+CONFIG_SND_SOC_SPDIF=m
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
--
1.9.1

View file

@ -1,268 +0,0 @@
From 815a37cd2514fc9fac5913bdefad6fcbff35d743 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Mon, 6 Mar 2017 01:36:15 +0200
Subject: [PATCH 36/93] drm: bridge: dw-hdmi: Create PHY operations
The HDMI TX controller support different PHYs whose programming
interface can vary significantly, especially with vendor PHYs that are
not provided by Synopsys. To support them, create a PHY operation
structure that can be provided by the platform glue layer. The existing
PHY handling code (limited to Synopsys PHY support) is refactored into a
set of default PHY operations that are used automatically when the
platform glue doesn't provide its own operations.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170305233615.11993-1-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 95 ++++++++++++++++++++++++++++------------
include/drm/bridge/dw_hdmi.h | 18 +++++++-
2 files changed, 82 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index c25eac8..cb27038 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -141,8 +141,12 @@ struct dw_hdmi {
u8 edid[HDMI_EDID_LEN];
bool cable_plugin;
- const struct dw_hdmi_phy_data *phy;
- bool phy_enabled;
+ struct {
+ const struct dw_hdmi_phy_ops *ops;
+ const char *name;
+ void *data;
+ bool enabled;
+ } phy;
struct drm_display_mode previous_mode;
@@ -831,6 +835,10 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
HDMI_VP_CONF);
}
+/* -----------------------------------------------------------------------------
+ * Synopsys PHY Handling
+ */
+
static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
unsigned char bit)
{
@@ -917,7 +925,7 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
{
- const struct dw_hdmi_phy_data *phy = hdmi->phy;
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
unsigned int i;
u16 val;
@@ -951,7 +959,7 @@ static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
{
- const struct dw_hdmi_phy_data *phy = hdmi->phy;
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
unsigned int i;
u8 val;
@@ -987,6 +995,7 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
static int hdmi_phy_configure(struct dw_hdmi *hdmi)
{
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
@@ -1019,7 +1028,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
dw_hdmi_phy_power_off(hdmi);
/* Leave low power consumption mode by asserting SVSRET. */
- if (hdmi->phy->has_svsret)
+ if (phy->has_svsret)
dw_hdmi_phy_enable_svsret(hdmi, 1);
/* PHY reset. The reset signal is active high on Gen2 PHYs. */
@@ -1057,7 +1066,8 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
return dw_hdmi_phy_power_on(hdmi);
}
-static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+ struct drm_display_mode *mode)
{
int i, ret;
@@ -1071,10 +1081,31 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
return ret;
}
- hdmi->phy_enabled = true;
return 0;
}
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
+{
+ dw_hdmi_phy_power_off(hdmi);
+}
+
+static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
+ void *data)
+{
+ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
+ .init = dw_hdmi_phy_init,
+ .disable = dw_hdmi_phy_disable,
+ .read_hpd = dw_hdmi_phy_read_hpd,
+};
+
+/* -----------------------------------------------------------------------------
+ * HDMI TX Setup
+ */
+
static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
{
u8 de;
@@ -1289,16 +1320,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi,
hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
}
-static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
-{
- if (!hdmi->phy_enabled)
- return;
-
- dw_hdmi_phy_power_off(hdmi);
-
- hdmi->phy_enabled = false;
-}
-
/* HDMI Initialization Step B.4 */
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
@@ -1431,9 +1452,10 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_av_composer(hdmi, mode);
/* HDMI Initializateion Step B.2 */
- ret = dw_hdmi_phy_init(hdmi);
+ ret = hdmi->phy.ops->init(hdmi, hdmi->phy.data, &hdmi->previous_mode);
if (ret)
return ret;
+ hdmi->phy.enabled = true;
/* HDMI Initialization Step B.3 */
dw_hdmi_enable_video_path(hdmi);
@@ -1548,7 +1570,11 @@ static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
{
- dw_hdmi_phy_disable(hdmi);
+ if (hdmi->phy.enabled) {
+ hdmi->phy.ops->disable(hdmi, hdmi->phy.data);
+ hdmi->phy.enabled = false;
+ }
+
hdmi->bridge_is_on = false;
}
@@ -1611,8 +1637,7 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
dw_hdmi_update_phy_mask(hdmi);
mutex_unlock(&hdmi->mutex);
- return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
- connector_status_connected : connector_status_disconnected;
+ return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data);
}
static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1898,19 +1923,31 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
phy_type = hdmi_readb(hdmi, HDMI_CONFIG2_ID);
+ if (phy_type == DW_HDMI_PHY_VENDOR_PHY) {
+ /* Vendor PHYs require support from the glue layer. */
+ if (!hdmi->plat_data->phy_ops || !hdmi->plat_data->phy_name) {
+ dev_err(hdmi->dev,
+ "Vendor HDMI PHY not supported by glue layer\n");
+ return -ENODEV;
+ }
+
+ hdmi->phy.ops = hdmi->plat_data->phy_ops;
+ hdmi->phy.data = hdmi->plat_data->phy_data;
+ hdmi->phy.name = hdmi->plat_data->phy_name;
+ return 0;
+ }
+
+ /* Synopsys PHYs are handled internally. */
for (i = 0; i < ARRAY_SIZE(dw_hdmi_phys); ++i) {
if (dw_hdmi_phys[i].type == phy_type) {
- hdmi->phy = &dw_hdmi_phys[i];
+ hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops;
+ hdmi->phy.name = dw_hdmi_phys[i].name;
+ hdmi->phy.data = (void *)&dw_hdmi_phys[i];
return 0;
}
}
- if (phy_type == DW_HDMI_PHY_VENDOR_PHY)
- dev_err(hdmi->dev, "Unsupported vendor HDMI PHY\n");
- else
- dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n",
- phy_type);
-
+ dev_err(hdmi->dev, "Unsupported HDMI PHY type (%02x)\n", phy_type);
return -ENODEV;
}
@@ -2031,7 +2068,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
dev_info(dev, "Detected HDMI TX controller v%x.%03x %s HDCP (%s)\n",
hdmi->version >> 12, hdmi->version & 0xfff,
prod_id1 & HDMI_PRODUCT_ID1_HDCP ? "with" : "without",
- hdmi->phy->name);
+ hdmi->phy.name);
initialize_hdmi_ih_mutes(hdmi);
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index b080a17..0f583ca 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -57,13 +57,27 @@ struct dw_hdmi_phy_config {
u16 vlev_ctr; /* voltage level control */
};
+struct dw_hdmi_phy_ops {
+ int (*init)(struct dw_hdmi *hdmi, void *data,
+ struct drm_display_mode *mode);
+ void (*disable)(struct dw_hdmi *hdmi, void *data);
+ enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data);
+};
+
struct dw_hdmi_plat_data {
enum dw_hdmi_devtype dev_type;
+ enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+ struct drm_display_mode *mode);
+
+ /* Vendor PHY support */
+ const struct dw_hdmi_phy_ops *phy_ops;
+ const char *phy_name;
+ void *phy_data;
+
+ /* Synopsys PHY support */
const struct dw_hdmi_mpll_config *mpll_cfg;
const struct dw_hdmi_curr_ctrl *cur_ctr;
const struct dw_hdmi_phy_config *phy_config;
- enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
- struct drm_display_mode *mode);
};
int dw_hdmi_probe(struct platform_device *pdev,
--
1.9.1

View file

@ -0,0 +1,194 @@
From 76c374731322248f9e48241e0debdfed6d794a44 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:19:04 +0200
Subject: [PATCH 37/79] 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>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 35 ++++++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 38 +++++++++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 37 ++++++++++++++++++++++++++++
3 files changed, 110 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 8901eeb..2251881 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -224,6 +224,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-uart";
reg = <0x0 0x84c0 0x0 0x14>;
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 1d4c861..92d2b91 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -602,6 +602,27 @@
};
};
+&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";
+
+};
+
&i2c_A {
clocks = <&clkc CLKID_I2C>;
};
@@ -618,6 +639,14 @@
clocks = <&clkc CLKID_I2C>;
};
+&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";
+};
+
&saradc {
compatible = "amlogic,meson-gxbb-saradc", "amlogic,meson-saradc";
clocks = <&xtal>,
@@ -649,6 +678,15 @@
clock-names = "core", "clkin0", "clkin1";
};
+&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>;
};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index 6584e46..de0a26b 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -208,6 +208,26 @@
};
};
+&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";
+};
+
&periphs {
pinctrl_periphs: pinctrl@4b0 {
compatible = "amlogic,meson-gxl-periphs-pinctrl";
@@ -570,6 +590,14 @@
clocks = <&clkc CLKID_I2C>;
};
+&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";
+};
+
&saradc {
compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
clocks = <&xtal>,
@@ -601,6 +629,15 @@
clock-names = "core", "clkin0", "clkin1";
};
+&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>;
};
--
1.9.1

View file

@ -1,251 +0,0 @@
From 3fdd6b3e658373e45ecbe36093403a30bd309df5 Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Date: Fri, 3 Mar 2017 19:20:04 +0200
Subject: [PATCH 37/93] drm: bridge: dw-hdmi: Add support for custom PHY
configuration
The DWC HDMI TX controller interfaces with a companion PHY. While
Synopsys provides multiple standard PHYs, SoC vendors can also integrate
a custom PHY.
Modularize PHY configuration to support vendor PHYs through platform
data. The existing PHY configuration code was originally written to
support the DWC HDMI 3D TX PHY, and seems to be compatible with the DWC
MLP PHY. The HDMI 2.0 PHY will require a separate configuration
function.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-8-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 109 ++++++++++++++++++++++++++-------------
include/drm/bridge/dw_hdmi.h | 7 +++
2 files changed, 81 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index cb27038..b835d81 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -118,6 +118,9 @@ struct dw_hdmi_phy_data {
const char *name;
unsigned int gen;
bool has_svsret;
+ int (*configure)(struct dw_hdmi *hdmi,
+ const struct dw_hdmi_plat_data *pdata,
+ unsigned long mpixelclock);
};
struct dw_hdmi {
@@ -860,8 +863,8 @@ static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
return true;
}
-static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
- unsigned char addr)
+void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
{
hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
@@ -873,6 +876,7 @@ static void hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
HDMI_PHY_I2CM_OPERATION_ADDR);
hdmi_phy_wait_i2c_done(hdmi, 1000);
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_write);
static void dw_hdmi_phy_enable_powerdown(struct dw_hdmi *hdmi, bool enable)
{
@@ -993,37 +997,67 @@ static int dw_hdmi_phy_power_on(struct dw_hdmi *hdmi)
return 0;
}
-static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+/*
+ * PHY configuration function for the DWC HDMI 3D TX PHY. Based on the available
+ * information the DWC MHL PHY has the same register layout and is thus also
+ * supported by this function.
+ */
+static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
+ const struct dw_hdmi_plat_data *pdata,
+ unsigned long mpixelclock)
{
- const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
- const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg;
const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr;
const struct dw_hdmi_phy_config *phy_config = pdata->phy_config;
/* PLL/MPLL Cfg - always match on final entry */
for (; mpll_config->mpixelclock != ~0UL; mpll_config++)
- if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config->mpixelclock)
+ if (mpixelclock <= mpll_config->mpixelclock)
break;
for (; curr_ctrl->mpixelclock != ~0UL; curr_ctrl++)
- if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl->mpixelclock)
+ if (mpixelclock <= curr_ctrl->mpixelclock)
break;
for (; phy_config->mpixelclock != ~0UL; phy_config++)
- if (hdmi->hdmi_data.video_mode.mpixelclock <=
- phy_config->mpixelclock)
+ if (mpixelclock <= phy_config->mpixelclock)
break;
if (mpll_config->mpixelclock == ~0UL ||
curr_ctrl->mpixelclock == ~0UL ||
- phy_config->mpixelclock == ~0UL) {
- dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
+ phy_config->mpixelclock == ~0UL)
return -EINVAL;
- }
+
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
+ HDMI_3D_TX_PHY_CPCE_CTRL);
+ dw_hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
+ HDMI_3D_TX_PHY_GMPCTRL);
+ dw_hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
+ HDMI_3D_TX_PHY_CURRCTRL);
+
+ dw_hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
+ dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
+ HDMI_3D_TX_PHY_MSM_CTRL);
+
+ dw_hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
+ dw_hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
+ HDMI_3D_TX_PHY_CKSYMTXCTRL);
+ dw_hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
+ HDMI_3D_TX_PHY_VLEVCTRL);
+
+ /* Override and disable clock termination. */
+ dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
+ HDMI_3D_TX_PHY_CKCALCTRL);
+
+ return 0;
+}
+
+static int hdmi_phy_configure(struct dw_hdmi *hdmi)
+{
+ const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
+ const struct dw_hdmi_plat_data *pdata = hdmi->plat_data;
+ unsigned long mpixelclock = hdmi->hdmi_data.video_mode.mpixelclock;
+ int ret;
dw_hdmi_phy_power_off(hdmi);
@@ -1042,26 +1076,16 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
HDMI_PHY_I2CM_SLAVE_ADDR);
hdmi_phy_test_clear(hdmi, 0);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[0].cpce,
- HDMI_3D_TX_PHY_CPCE_CTRL);
- hdmi_phy_i2c_write(hdmi, mpll_config->res[0].gmp,
- HDMI_3D_TX_PHY_GMPCTRL);
- hdmi_phy_i2c_write(hdmi, curr_ctrl->curr[0],
- HDMI_3D_TX_PHY_CURRCTRL);
-
- hdmi_phy_i2c_write(hdmi, 0, HDMI_3D_TX_PHY_PLLPHBYCTRL);
- hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_MSM_CTRL_CKO_SEL_FB_CLK,
- HDMI_3D_TX_PHY_MSM_CTRL);
-
- hdmi_phy_i2c_write(hdmi, phy_config->term, HDMI_3D_TX_PHY_TXTERM);
- hdmi_phy_i2c_write(hdmi, phy_config->sym_ctr,
- HDMI_3D_TX_PHY_CKSYMTXCTRL);
- hdmi_phy_i2c_write(hdmi, phy_config->vlev_ctr,
- HDMI_3D_TX_PHY_VLEVCTRL);
-
- /* Override and disable clock termination. */
- hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
- HDMI_3D_TX_PHY_CKCALCTRL);
+ /* Write to the PHY as configured by the platform */
+ if (pdata->configure_phy)
+ ret = pdata->configure_phy(hdmi, pdata, mpixelclock);
+ else
+ ret = phy->configure(hdmi, pdata, mpixelclock);
+ if (ret) {
+ dev_err(hdmi->dev, "PHY configuration failed (clock %lu)\n",
+ mpixelclock);
+ return ret;
+ }
return dw_hdmi_phy_power_on(hdmi);
}
@@ -1895,24 +1919,31 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
.name = "DWC MHL PHY + HEAC PHY",
.gen = 2,
.has_svsret = true,
+ .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, {
.type = DW_HDMI_PHY_DWC_MHL_PHY,
.name = "DWC MHL PHY",
.gen = 2,
.has_svsret = true,
+ .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY_HEAC,
.name = "DWC HDMI 3D TX PHY + HEAC PHY",
.gen = 2,
+ .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, {
.type = DW_HDMI_PHY_DWC_HDMI_3D_TX_PHY,
.name = "DWC HDMI 3D TX PHY",
.gen = 2,
+ .configure = hdmi_phy_configure_dwc_hdmi_3d_tx,
}, {
.type = DW_HDMI_PHY_DWC_HDMI20_TX_PHY,
.name = "DWC HDMI 2.0 TX PHY",
.gen = 2,
.has_svsret = true,
+ }, {
+ .type = DW_HDMI_PHY_VENDOR_PHY,
+ .name = "Vendor PHY",
}
};
@@ -1943,6 +1974,14 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
hdmi->phy.ops = &dw_hdmi_synopsys_phy_ops;
hdmi->phy.name = dw_hdmi_phys[i].name;
hdmi->phy.data = (void *)&dw_hdmi_phys[i];
+
+ if (!dw_hdmi_phys[i].configure &&
+ !hdmi->plat_data->configure_phy) {
+ dev_err(hdmi->dev, "%s requires platform support\n",
+ hdmi->phy.name);
+ return -ENODEV;
+ }
+
return 0;
}
}
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 0f583ca..dd33025 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -78,6 +78,9 @@ struct dw_hdmi_plat_data {
const struct dw_hdmi_mpll_config *mpll_cfg;
const struct dw_hdmi_curr_ctrl *cur_ctr;
const struct dw_hdmi_phy_config *phy_config;
+ int (*configure_phy)(struct dw_hdmi *hdmi,
+ const struct dw_hdmi_plat_data *pdata,
+ unsigned long mpixelclock);
};
int dw_hdmi_probe(struct platform_device *pdev,
@@ -91,4 +94,8 @@ int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
+/* PHY configuration */
+void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+ unsigned char addr);
+
#endif /* __IMX_HDMI_H__ */
--
1.9.1

View file

@ -0,0 +1,34 @@
From fb22697ac3dfd363e9d51307d1bb168bd6cf1c41 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:28:24 +0200
Subject: [PATCH 38/79] ARM64: dts: meson-gxbb-p20x: add i2s codec node
Add the node for the i2s codec Everest 7134 found on the P20x reference
design
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 3ed5c99..07b0f21 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -146,6 +146,12 @@
};
};
};
+
+ i2s_codec: external-codec {
+ #sound-dai-cells = <0>;
+ compatible = "everest,es7134";
+ status = "okay";
+ };
};
/* This UART is brought out to the DB9 connector */
--
1.9.1

View file

@ -1,103 +0,0 @@
From c5bdf6120fed0d57d7e602abc01f0cbacf275737 Mon Sep 17 00:00:00 2001
From: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Date: Fri, 3 Mar 2017 19:20:05 +0200
Subject: [PATCH 38/93] drm: bridge: dw-hdmi: Remove device type from platform
data
The device type isn't used anymore now that workarounds and PHY-specific
operations are performed based on version information read at runtime.
Remove it.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-9-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 2 --
drivers/gpu/drm/imx/dw_hdmi-imx.c | 2 --
drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
include/drm/bridge/dw_hdmi.h | 7 -------
4 files changed, 12 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index b835d81..132c006 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -127,7 +127,6 @@ struct dw_hdmi {
struct drm_connector connector;
struct drm_bridge bridge;
- enum dw_hdmi_devtype dev_type;
unsigned int version;
struct platform_device *audio;
@@ -2014,7 +2013,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
hdmi->plat_data = plat_data;
hdmi->dev = dev;
- hdmi->dev_type = plat_data->dev_type;
hdmi->sample_rate = 48000;
hdmi->disabled = true;
hdmi->rxsense = true;
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
index f645275..f039641 100644
--- a/drivers/gpu/drm/imx/dw_hdmi-imx.c
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -175,7 +175,6 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config,
- .dev_type = IMX6Q_HDMI,
.mode_valid = imx6q_hdmi_mode_valid,
};
@@ -183,7 +182,6 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
.mpll_cfg = imx_mpll_cfg,
.cur_ctr = imx_cur_ctr,
.phy_config = imx_phy_config,
- .dev_type = IMX6DL_HDMI,
.mode_valid = imx6dl_hdmi_mode_valid,
};
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index a6d4a02..d538274 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -237,7 +237,6 @@ static void dw_hdmi_rockchip_encoder_enable(struct drm_encoder *encoder)
.mpll_cfg = rockchip_mpll_cfg,
.cur_ctr = rockchip_cur_ctr,
.phy_config = rockchip_phy_config,
- .dev_type = RK3288_HDMI,
};
static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index dd33025..545f04fa 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -21,12 +21,6 @@ enum {
DW_HDMI_RES_MAX,
};
-enum dw_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
- RK3288_HDMI,
-};
-
enum dw_hdmi_phy_type {
DW_HDMI_PHY_DWC_HDMI_TX_PHY = 0x00,
DW_HDMI_PHY_DWC_MHL_PHY_HEAC = 0xb2,
@@ -65,7 +59,6 @@ struct dw_hdmi_phy_ops {
};
struct dw_hdmi_plat_data {
- enum dw_hdmi_devtype dev_type;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
--
1.9.1

View file

@ -0,0 +1,34 @@
From c834ddb8c5ca2957b7adb99a2a864f1892884e5e Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:32:17 +0200
Subject: [PATCH 39/79] ARM64: dts: meson-gxbb-p20x: add analog amplifier node
Add the node for the analog sound amplifier Dioo 2125 found on the p20x
reference design
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 07b0f21..b9fc07c 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -152,6 +152,12 @@
compatible = "everest,es7134";
status = "okay";
};
+
+ amp: analog-amplifier {
+ compatible = "dioo,dio2125";
+ enable-gpios = <&gpio GPIOH_3 0>;
+ status = "okay";
+ };
};
/* This UART is brought out to the DB9 connector */
--
1.9.1

View file

@ -1,227 +0,0 @@
From bee2b64f57985618a1b824362c427eb469f41e06 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 3 Mar 2017 19:20:06 +0200
Subject: [PATCH 39/93] drm: bridge: dw-hdmi: Switch to regmap for register
access
The Synopsys Designware HDMI TX Controller does not enforce register
access on platforms instanciating it. The current driver supports two
different types of memory-mapped flat register access, but in order to
support the Amlogic Meson SoCs integration, and provide a more generic
way to handle all sorts of register mapping, switch the register access
to use the regmap infrastructure.
In the case of registers that are not flat memory-mapped or do not
conform to the current driver implementation, a regmap struct can be
given in the plat_data and be used at probe or bind.
Since the AHB audio driver is only available with direct memory access,
only allow the I2S audio driver to be registered is directly
memory-mapped.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tested-by: Neil Armstrong <narmstrong@baylibre.com>
Reviewed-by: Jose Abreu <Jose.Abreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20170303172007.26541-10-laurent.pinchart+renesas@ideasonboard.com
---
drivers/gpu/drm/bridge/dw-hdmi.c | 109 +++++++++++++++++++++------------------
include/drm/bridge/dw_hdmi.h | 1 +
2 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index 132c006..026a0dc 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -19,6 +19,7 @@
#include <linux/hdmi.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
+#include <linux/regmap.h>
#include <linux/spinlock.h>
#include <drm/drm_of.h>
@@ -171,8 +172,8 @@ struct dw_hdmi {
unsigned int audio_n;
bool audio_enable;
- void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
- u8 (*read)(struct dw_hdmi *hdmi, int offset);
+ unsigned int reg_shift;
+ struct regmap *regm;
};
#define HDMI_IH_PHY_STAT0_RX_SENSE \
@@ -183,42 +184,23 @@ struct dw_hdmi {
(HDMI_PHY_RX_SENSE0 | HDMI_PHY_RX_SENSE1 | \
HDMI_PHY_RX_SENSE2 | HDMI_PHY_RX_SENSE3)
-static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
-{
- writel(val, hdmi->regs + (offset << 2));
-}
-
-static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
-{
- return readl(hdmi->regs + (offset << 2));
-}
-
-static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
-{
- writeb(val, hdmi->regs + offset);
-}
-
-static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
-{
- return readb(hdmi->regs + offset);
-}
-
static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
{
- hdmi->write(hdmi, val, offset);
+ regmap_write(hdmi->regm, offset << hdmi->reg_shift, val);
}
static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
{
- return hdmi->read(hdmi, offset);
+ unsigned int val = 0;
+
+ regmap_read(hdmi->regm, offset << hdmi->reg_shift, &val);
+
+ return val;
}
static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
{
- u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
- val |= data & mask;
- hdmi_writeb(hdmi, val, reg);
+ regmap_update_bits(hdmi->regm, reg << hdmi->reg_shift, mask, data);
}
static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
@@ -1989,6 +1971,20 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
return -ENODEV;
}
+static const struct regmap_config hdmi_regmap_8bit_config = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .reg_stride = 1,
+ .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR,
+};
+
+static const struct regmap_config hdmi_regmap_32bit_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = HDMI_I2CM_FS_SCL_LCNT_0_ADDR << 2,
+};
+
static struct dw_hdmi *
__dw_hdmi_probe(struct platform_device *pdev,
const struct dw_hdmi_plat_data *plat_data)
@@ -1998,7 +1994,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
struct dw_hdmi *hdmi;
- struct resource *iores;
+ struct resource *iores = NULL;
int irq;
int ret;
u32 val = 1;
@@ -2022,22 +2018,6 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
mutex_init(&hdmi->audio_mutex);
spin_lock_init(&hdmi->audio_lock);
- of_property_read_u32(np, "reg-io-width", &val);
-
- switch (val) {
- case 4:
- hdmi->write = dw_hdmi_writel;
- hdmi->read = dw_hdmi_readl;
- break;
- case 1:
- hdmi->write = dw_hdmi_writeb;
- hdmi->read = dw_hdmi_readb;
- break;
- default:
- dev_err(dev, "reg-io-width must be 1 or 4\n");
- return ERR_PTR(-EINVAL);
- }
-
ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
if (ddc_node) {
hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node);
@@ -2051,11 +2031,38 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
dev_dbg(hdmi->dev, "no ddc property found\n");
}
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs)) {
- ret = PTR_ERR(hdmi->regs);
- goto err_res;
+ if (!plat_data->regm) {
+ const struct regmap_config *reg_config;
+
+ of_property_read_u32(np, "reg-io-width", &val);
+ switch (val) {
+ case 4:
+ reg_config = &hdmi_regmap_32bit_config;
+ hdmi->reg_shift = 2;
+ break;
+ case 1:
+ reg_config = &hdmi_regmap_8bit_config;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi->regs = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs)) {
+ ret = PTR_ERR(hdmi->regs);
+ goto err_res;
+ }
+
+ hdmi->regm = devm_regmap_init_mmio(dev, hdmi->regs, reg_config);
+ if (IS_ERR(hdmi->regm)) {
+ dev_err(dev, "Failed to configure regmap\n");
+ ret = PTR_ERR(hdmi->regm);
+ goto err_res;
+ }
+ } else {
+ hdmi->regm = plat_data->regm;
}
hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
@@ -2165,7 +2172,7 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
config0 = hdmi_readb(hdmi, HDMI_CONFIG0_ID);
config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
- if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
+ if (iores && config3 & HDMI_CONFIG3_AHBAUDDMA) {
struct dw_hdmi_audio_data audio;
audio.phys = iores->start;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 545f04fa..bcceee8 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -59,6 +59,7 @@ struct dw_hdmi_phy_ops {
};
struct dw_hdmi_plat_data {
+ struct regmap *regm;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
--
1.9.1

View file

@ -0,0 +1,33 @@
From 6f0475d8b6b9792d1aee758a1674aa77a6c4232e Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 17:49:00 +0200
Subject: [PATCH 40/79] ARM64: dts: meson-gxbb-p20x: add spdif codec node
Add spdif-dit node to the meson gxbb reference design
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index b9fc07c..c8559be 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -158,6 +158,12 @@
enable-gpios = <&gpio GPIOH_3 0>;
status = "okay";
};
+
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ status = "okay";
+ };
};
/* This UART is brought out to the DB9 connector */
--
1.9.1

View file

@ -0,0 +1,51 @@
From 9f335bad0a74dc58e5450260dbfaa59911dfaa31 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:40:20 +0200
Subject: [PATCH 41/79] ARM64: dts: meson-gxbb-p20x: add i2s and spdif output
interfaces
Add the necessary pins for the i2s and spdif audio interface output and
enable these interfaces
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 25 ++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index c8559be..d36f82b0 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -292,3 +292,28 @@
remote-endpoint = <&hdmi_connector_in>;
};
};
+
+&audio {
+ status = "okay";
+};
+
+&aiu_i2s_dma {
+ status = "okay";
+};
+
+&aiu_spdif_dma {
+ status = "okay";
+};
+
+&i2s_dai {
+ pinctrl-0 = <&i2s_am_clk_pins>, <&i2s_out_ao_clk_pins>,
+ <&i2s_out_lr_clk_pins>, <&i2s_out_ch01_ao_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&spdif_dai {
+ pinctrl-0 = <&spdif_out_ao_6_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
--
1.9.1

View file

@ -1,115 +0,0 @@
From 8d012e114e251f5427cb46851ce47e43b745e6c3 Mon Sep 17 00:00:00 2001
From: Nickey Yang <nickey.yang@rock-chips.com>
Date: Mon, 20 Mar 2017 10:57:31 +0800
Subject: [PATCH 41/93] drm/bridge: dw_hdmi: support i2c extended read mode
"I2C Master Interface Extended Read Mode" implements a segment
pointer-based read operation using the Special Register configuration.
This patch fix https://patchwork.kernel.org/patch/7098101/ mentioned
"The current implementation does not support "I2C Master Interface
Extended Read Mode" to read data addressed by non-zero segment
pointer, this means that if EDID has more than 1 extension blocks,
EDID reading operation won't succeed"
With this patch, dw-hdmi can read EDID data with 1/2/4 blocks.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Acked-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1489978651-16647-1-git-send-email-nickey.yang@rock-chips.com
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 38 +++++++++++++++++++------------
1 file changed, 24 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 026a0dc..0d112cf 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -33,6 +33,7 @@
#include "dw-hdmi.h"
#include "dw-hdmi-audio.h"
+#define DDC_SEGMENT_ADDR 0x30
#define HDMI_EDID_LEN 512
#define RGB 0
@@ -112,6 +113,7 @@ struct dw_hdmi_i2c {
u8 slave_reg;
bool is_regaddr;
+ bool is_segment;
};
struct dw_hdmi_phy_data {
@@ -247,8 +249,12 @@ static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
reinit_completion(&i2c->cmp);
hdmi_writeb(hdmi, i2c->slave_reg++, HDMI_I2CM_ADDRESS);
- hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
- HDMI_I2CM_OPERATION);
+ if (i2c->is_segment)
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ_EXT,
+ HDMI_I2CM_OPERATION);
+ else
+ hdmi_writeb(hdmi, HDMI_I2CM_OPERATION_READ,
+ HDMI_I2CM_OPERATION);
stat = wait_for_completion_timeout(&i2c->cmp, HZ / 10);
if (!stat)
@@ -260,6 +266,7 @@ static int dw_hdmi_i2c_read(struct dw_hdmi *hdmi,
*buf++ = hdmi_readb(hdmi, HDMI_I2CM_DATAI);
}
+ i2c->is_segment = false;
return 0;
}
@@ -309,12 +316,6 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
dev_dbg(hdmi->dev, "xfer: num: %d, addr: %#x\n", num, addr);
for (i = 0; i < num; i++) {
- if (msgs[i].addr != addr) {
- dev_warn(hdmi->dev,
- "unsupported transfer, changed slave address\n");
- return -EOPNOTSUPP;
- }
-
if (msgs[i].len == 0) {
dev_dbg(hdmi->dev,
"unsupported transfer %d/%d, no data\n",
@@ -334,15 +335,24 @@ static int dw_hdmi_i2c_xfer(struct i2c_adapter *adap,
/* Set slave device register address on transfer */
i2c->is_regaddr = false;
+ /* Set segment pointer for I2C extended read mode operation */
+ i2c->is_segment = false;
+
for (i = 0; i < num; i++) {
dev_dbg(hdmi->dev, "xfer: num: %d/%d, len: %d, flags: %#x\n",
i + 1, num, msgs[i].len, msgs[i].flags);
-
- if (msgs[i].flags & I2C_M_RD)
- ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf, msgs[i].len);
- else
- ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf, msgs[i].len);
-
+ if (msgs[i].addr == DDC_SEGMENT_ADDR && msgs[i].len == 1) {
+ i2c->is_segment = true;
+ hdmi_writeb(hdmi, DDC_SEGMENT_ADDR, HDMI_I2CM_SEGADDR);
+ hdmi_writeb(hdmi, *msgs[i].buf, HDMI_I2CM_SEGPTR);
+ } else {
+ if (msgs[i].flags & I2C_M_RD)
+ ret = dw_hdmi_i2c_read(hdmi, msgs[i].buf,
+ msgs[i].len);
+ else
+ ret = dw_hdmi_i2c_write(hdmi, msgs[i].buf,
+ msgs[i].len);
+ }
if (ret < 0)
break;
}
--
1.9.1

View file

@ -0,0 +1,33 @@
From bb66443e46eab9d08082e98b1c53c4ed9699e8b4 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 17:53:57 +0200
Subject: [PATCH 42/79] ARM64: dts: meson-gxl-p230: add spdif codec node
Add spdif-dit node to the meson gxl reference design
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
index 49e19aa..3837560 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -84,6 +84,12 @@
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
+
+ spdif_out: spdif-out {
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
+ status = "okay";
+ };
};
&cec_AO {
--
1.9.1

View file

@ -1,107 +0,0 @@
From 7feb88b4b876148c48911d2c9733fcab0e877cd9 Mon Sep 17 00:00:00 2001
From: Nickey Yang <nickey.yang@rock-chips.com>
Date: Tue, 21 Mar 2017 15:36:17 +0800
Subject: [PATCH 42/93] drm: bridge: dw-hdmi: add HDMI vendor specific
infoframe config
Vendor specific infoframe is mandatory for 4K2K resolution.
Without this, the HDMI protocol compliance fails.
Signed-off-by: Nickey Yang <nickey.yang@rock-chips.com>
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1490081777-2232-1-git-send-email-nickey.yang@rock-chips.com
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 53 +++++++++++++++++++++++++++++++
drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 4 +++
2 files changed, 57 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 0d112cf..af93f7a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1240,6 +1240,58 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
hdmi_writeb(hdmi, (frame.right_bar >> 8) & 0xff, HDMI_FC_AVISRB1);
}
+static void hdmi_config_vendor_specific_infoframe(struct dw_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ struct hdmi_vendor_infoframe frame;
+ u8 buffer[10];
+ ssize_t err;
+
+ err = drm_hdmi_vendor_infoframe_from_display_mode(&frame, mode);
+ if (err < 0)
+ /*
+ * Going into that statement does not means vendor infoframe
+ * fails. It just informed us that vendor infoframe is not
+ * needed for the selected mode. Only 4k or stereoscopic 3D
+ * mode requires vendor infoframe. So just simply return.
+ */
+ return;
+
+ err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer));
+ if (err < 0) {
+ dev_err(hdmi->dev, "Failed to pack vendor infoframe: %zd\n",
+ err);
+ return;
+ }
+ hdmi_mask_writeb(hdmi, 0, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET,
+ HDMI_FC_DATAUTO0_VSD_MASK);
+
+ /* Set the length of HDMI vendor specific InfoFrame payload */
+ hdmi_writeb(hdmi, buffer[2], HDMI_FC_VSDSIZE);
+
+ /* Set 24bit IEEE Registration Identifier */
+ hdmi_writeb(hdmi, buffer[4], HDMI_FC_VSDIEEEID0);
+ hdmi_writeb(hdmi, buffer[5], HDMI_FC_VSDIEEEID1);
+ hdmi_writeb(hdmi, buffer[6], HDMI_FC_VSDIEEEID2);
+
+ /* Set HDMI_Video_Format and HDMI_VIC/3D_Structure */
+ hdmi_writeb(hdmi, buffer[7], HDMI_FC_VSDPAYLOAD0);
+ hdmi_writeb(hdmi, buffer[8], HDMI_FC_VSDPAYLOAD1);
+
+ if (frame.s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+ hdmi_writeb(hdmi, buffer[9], HDMI_FC_VSDPAYLOAD2);
+
+ /* Packet frame interpolation */
+ hdmi_writeb(hdmi, 1, HDMI_FC_DATAUTO1);
+
+ /* Auto packets per frame and line spacing */
+ hdmi_writeb(hdmi, 0x11, HDMI_FC_DATAUTO2);
+
+ /* Configures the Frame Composer On RDRB mode */
+ hdmi_mask_writeb(hdmi, 1, HDMI_FC_DATAUTO0, HDMI_FC_DATAUTO0_VSD_OFFSET,
+ HDMI_FC_DATAUTO0_VSD_MASK);
+}
+
static void hdmi_av_composer(struct dw_hdmi *hdmi,
const struct drm_display_mode *mode)
{
@@ -1489,6 +1541,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* HDMI Initialization Step F - Configure AVI InfoFrame */
hdmi_config_AVI(hdmi, mode);
+ hdmi_config_vendor_specific_infoframe(hdmi, mode);
} else {
dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
index 325b0b8..c59f87e 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
@@ -854,6 +854,10 @@ enum {
HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+/* FC_DATAUTO0 field values */
+ HDMI_FC_DATAUTO0_VSD_MASK = 0x08,
+ HDMI_FC_DATAUTO0_VSD_OFFSET = 3,
+
/* PHY_CONF0 field values */
HDMI_PHY_CONF0_PDZ_MASK = 0x80,
HDMI_PHY_CONF0_PDZ_OFFSET = 7,
--
1.9.1

View file

@ -0,0 +1,38 @@
From 01ff36940e53cd410abec88ec2eb282c397a3a77 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 16:04:39 +0200
Subject: [PATCH 43/79] ARM64: dts: meson-gxl-p230: add spdif output interface
Add the necessary pin for the spdif audio interface output and enable it
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
index 3837560..770a332 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -130,3 +130,17 @@
status = "okay";
vref-supply = <&vddio_ao18>;
};
+
+&audio {
+ status = "okay";
+};
+
+&aiu_spdif_dma {
+ status = "okay";
+};
+
+&spdif_dai {
+ pinctrl-0 = <&spdif_out_h_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+};
--
1.9.1

View file

@ -1,106 +0,0 @@
From b880ce74954cefe49cfc101c684c4ce0b0063945 Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Date: Fri, 3 Mar 2017 14:14:56 +0200
Subject: [PATCH 43/93] drm: bridge: dw-hdmi: Extract PHY interrupt setup to a
function
In preparation for adding PHY operations to handle RX SENSE and HPD,
group all the PHY interrupt setup code in a single location and extract
it to a separate function.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 50 ++++++++++++++-----------------
1 file changed, 23 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index af93f7a..f82750a 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1559,7 +1559,7 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
}
/* Wait until we are registered to enable interrupts */
-static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
+static void dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
{
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
HDMI_PHY_I2CM_INT_ADDR);
@@ -1567,15 +1567,6 @@ static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
HDMI_PHY_I2CM_CTLINT_ADDR);
-
- /* enable cable hot plug irq */
- hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
-
- /* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
- HDMI_IH_PHY_STAT0);
-
- return 0;
}
static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
@@ -1693,6 +1684,26 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
}
+static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi)
+{
+ /*
+ * Configure the PHY RX SENSE and HPD interrupts polarities and clear
+ * any pending interrupt.
+ */
+ hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+ HDMI_IH_PHY_STAT0);
+
+ /* Enable cable hot plug irq. */
+ hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
+
+ /* Clear and unmute interrupts. */
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+ HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
+ HDMI_IH_MUTE_PHY_STAT0);
+}
+
static enum drm_connector_status
dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
{
@@ -2204,29 +2215,14 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
hdmi->ddc = NULL;
}
- /*
- * Configure registers related to HDMI interrupt
- * generation before registering IRQ.
- */
- hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
-
- /* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
- HDMI_IH_PHY_STAT0);
-
hdmi->bridge.driver_private = hdmi;
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
#ifdef CONFIG_OF
hdmi->bridge.of_node = pdev->dev.of_node;
#endif
- ret = dw_hdmi_fb_registered(hdmi);
- if (ret)
- goto err_iahb;
-
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
- HDMI_IH_MUTE_PHY_STAT0);
+ dw_hdmi_fb_registered(hdmi);
+ dw_hdmi_phy_setup_hpd(hdmi);
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.parent = dev;
--
1.9.1

View file

@ -0,0 +1,84 @@
From bb5cf409583f04045ea97c7a039cb0935bbd6bfc Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 15:53:47 +0200
Subject: [PATCH 44/79] WIP: ARM64: dts: meson-gxbb-p20x: add sound card
support
This commit add sound card support to the meson-gxbb-p20x
This patch is not intended to be merged upstream the architecture of
the sound card has not been determined yet. To handle the routing caps
of meson SoCs, we will probably have to make our own card.
This implementation using simple-card is provided for testing purpose only
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 51 ++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index d36f82b0..88e3713 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -164,6 +164,57 @@
compatible = "linux,spdif-dit";
status = "okay";
};
+
+ soc {
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "meson-gxbb-p20x";
+ simple-audio-card,aux-devs = <&amp>;
+ simple-audio-card,widgets =
+ "Line", "Analog Left Output",
+ "Line", "Analog Right Output";
+ simple-audio-card,routing =
+ "Analog Left Output", "OUTL",
+ "Analog Right Output", "OUTR",
+ "INL", "AOUTL",
+ "INR", "AOUTR";
+ status = "okay";
+
+ simple-audio-card,dai-link@0 {
+ /* RCA 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 = <&i2s_codec>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 {
+ plat {
+ sound-dai = <&aiu_spdif_dma>;
+ };
+
+ cpu {
+ sound-dai = <&spdif_dai>;
+ };
+
+ codec {
+ sound-dai = <&spdif_out>;
+ };
+ };
+ };
+ };
};
/* This UART is brought out to the DB9 connector */
--
1.9.1

View file

@ -1,551 +0,0 @@
From 61801956e33a13e4682a8b52978d8f3c5d7f99e3 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 13 Jan 2017 16:07:42 +0100
Subject: [PATCH 44/93] drm: bridge: dw-hdmi: Switch to V4L bus format and
encodings
Some display pipelines can only provide non-RBG input pixels to the HDMI TX
Controller, this patch takes the pixel format from the plat_data if provided.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 326 +++++++++++++++++++++---------
include/drm/bridge/dw_hdmi.h | 63 ++++++
2 files changed, 294 insertions(+), 95 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index f82750a..fcb0a27 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -30,18 +30,15 @@
#include <drm/drm_encoder_slave.h>
#include <drm/bridge/dw_hdmi.h>
+#include <uapi/linux/media-bus-format.h>
+#include <uapi/linux/videodev2.h>
+
#include "dw-hdmi.h"
#include "dw-hdmi-audio.h"
#define DDC_SEGMENT_ADDR 0x30
#define HDMI_EDID_LEN 512
-#define RGB 0
-#define YCBCR444 1
-#define YCBCR422_16BITS 2
-#define YCBCR422_8BITS 3
-#define XVYCC444 4
-
enum hdmi_datamap {
RGB444_8B = 0x01,
RGB444_10B = 0x03,
@@ -95,10 +92,10 @@ struct hdmi_vmode {
};
struct hdmi_data_info {
- unsigned int enc_in_format;
- unsigned int enc_out_format;
- unsigned int enc_color_depth;
- unsigned int colorimetry;
+ unsigned int enc_in_bus_format;
+ unsigned int enc_out_bus_format;
+ unsigned int enc_in_encoding;
+ unsigned int enc_out_encoding;
unsigned int pix_repet_factor;
unsigned int hdcp_enable;
struct hdmi_vmode video_mode;
@@ -567,6 +564,92 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi)
}
EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable);
+static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_RGB121212_1X36:
+ case MEDIA_BUS_FMT_RGB161616_1X48:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool hdmi_bus_fmt_is_yuv444(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_YUV12_1X36:
+ case MEDIA_BUS_FMT_YUV16_1X48:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool hdmi_bus_fmt_is_yuv422(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static bool hdmi_bus_fmt_is_yuv420(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_UYYVYY8_1X24:
+ case MEDIA_BUS_FMT_UYYVYY10_1X30:
+ case MEDIA_BUS_FMT_UYYVYY12_1X36:
+ case MEDIA_BUS_FMT_UYYVYY16_1X48:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
+{
+ switch (bus_format) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYYVYY8_1X24:
+ return 8;
+
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ case MEDIA_BUS_FMT_UYYVYY10_1X30:
+ return 10;
+
+ case MEDIA_BUS_FMT_RGB121212_1X36:
+ case MEDIA_BUS_FMT_YUV12_1X36:
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ case MEDIA_BUS_FMT_UYYVYY12_1X36:
+ return 12;
+
+ case MEDIA_BUS_FMT_RGB161616_1X48:
+ case MEDIA_BUS_FMT_YUV16_1X48:
+ case MEDIA_BUS_FMT_UYYVYY16_1X48:
+ return 16;
+
+ default:
+ return 0;
+ }
+}
+
/*
* this submodule is responsible for the video data synchronization.
* for example, for RGB 4:4:4 input, the data map is defined as
@@ -579,37 +662,49 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
int color_format = 0;
u8 val;
- if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x01;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x03;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x05;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
- color_format = 0x07;
- else
- return;
- } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x09;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x0B;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x0D;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
- color_format = 0x0F;
- else
- return;
- } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x16;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x14;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x12;
- else
- return;
+ switch (hdmi->hdmi_data.enc_in_bus_format) {
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ color_format = 0x01;
+ break;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ color_format = 0x03;
+ break;
+ case MEDIA_BUS_FMT_RGB121212_1X36:
+ color_format = 0x05;
+ break;
+ case MEDIA_BUS_FMT_RGB161616_1X48:
+ color_format = 0x07;
+ break;
+
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_UYYVYY8_1X24:
+ color_format = 0x09;
+ break;
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ case MEDIA_BUS_FMT_UYYVYY10_1X30:
+ color_format = 0x0B;
+ break;
+ case MEDIA_BUS_FMT_YUV12_1X36:
+ case MEDIA_BUS_FMT_UYYVYY12_1X36:
+ color_format = 0x0D;
+ break;
+ case MEDIA_BUS_FMT_YUV16_1X48:
+ case MEDIA_BUS_FMT_UYYVYY16_1X48:
+ color_format = 0x0F;
+ break;
+
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ color_format = 0x16;
+ break;
+ case MEDIA_BUS_FMT_UYVY10_1X20:
+ color_format = 0x14;
+ break;
+ case MEDIA_BUS_FMT_UYVY12_1X24:
+ color_format = 0x12;
+ break;
+
+ default:
+ return;
}
val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
@@ -632,26 +727,30 @@ static void hdmi_video_sample(struct dw_hdmi *hdmi)
static int is_color_space_conversion(struct dw_hdmi *hdmi)
{
- return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
+ return hdmi->hdmi_data.enc_in_bus_format != hdmi->hdmi_data.enc_out_bus_format;
}
static int is_color_space_decimation(struct dw_hdmi *hdmi)
{
- if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+ if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
return 0;
- if (hdmi->hdmi_data.enc_in_format == RGB ||
- hdmi->hdmi_data.enc_in_format == YCBCR444)
+
+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format) ||
+ hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_in_bus_format))
return 1;
+
return 0;
}
static int is_color_space_interpolation(struct dw_hdmi *hdmi)
{
- if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+ if (!hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_in_bus_format))
return 0;
- if (hdmi->hdmi_data.enc_out_format == RGB ||
- hdmi->hdmi_data.enc_out_format == YCBCR444)
+
+ 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))
return 1;
+
return 0;
}
@@ -662,15 +761,16 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
u32 csc_scale = 1;
if (is_color_space_conversion(hdmi)) {
- if (hdmi->hdmi_data.enc_out_format == RGB) {
- if (hdmi->hdmi_data.colorimetry ==
- HDMI_COLORIMETRY_ITU_601)
+ if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
+ if (hdmi->hdmi_data.enc_out_encoding ==
+ V4L2_YCBCR_ENC_601)
csc_coeff = &csc_coeff_rgb_out_eitu601;
else
csc_coeff = &csc_coeff_rgb_out_eitu709;
- } else if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.colorimetry ==
- HDMI_COLORIMETRY_ITU_601)
+ } else if (hdmi_bus_fmt_is_rgb(
+ hdmi->hdmi_data.enc_in_bus_format)) {
+ if (hdmi->hdmi_data.enc_out_encoding ==
+ V4L2_YCBCR_ENC_601)
csc_coeff = &csc_coeff_rgb_in_eitu601;
else
csc_coeff = &csc_coeff_rgb_in_eitu709;
@@ -708,16 +808,23 @@ static void hdmi_video_csc(struct dw_hdmi *hdmi)
else if (is_color_space_decimation(hdmi))
decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
- if (hdmi->hdmi_data.enc_color_depth == 8)
+ switch (hdmi_bus_fmt_color_depth(hdmi->hdmi_data.enc_out_bus_format)) {
+ case 8:
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
+ break;
+ case 10:
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
+ break;
+ case 12:
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
+ break;
+ case 16:
color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
- else
+ break;
+
+ default:
return;
+ }
/* Configure the CSC registers */
hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
@@ -740,32 +847,43 @@ static void hdmi_video_packetize(struct dw_hdmi *hdmi)
struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
u8 val, vp_conf;
- if (hdmi_data->enc_out_format == RGB ||
- hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth) {
- output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 8) {
+ 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)) {
+ switch (hdmi_bus_fmt_color_depth(
+ hdmi->hdmi_data.enc_out_bus_format)) {
+ case 8:
color_depth = 4;
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10) {
+ break;
+ case 10:
color_depth = 5;
- } else if (hdmi_data->enc_color_depth == 12) {
+ break;
+ case 12:
color_depth = 6;
- } else if (hdmi_data->enc_color_depth == 16) {
+ break;
+ case 16:
color_depth = 7;
- } else {
- return;
+ break;
+ default:
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
}
- } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
- if (!hdmi_data->enc_color_depth ||
- hdmi_data->enc_color_depth == 8)
+ } else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format)) {
+ switch (hdmi_bus_fmt_color_depth(
+ hdmi->hdmi_data.enc_out_bus_format)) {
+ case 0:
+ case 8:
remap_size = HDMI_VP_REMAP_YCC422_16bit;
- else if (hdmi_data->enc_color_depth == 10)
+ break;
+ case 10:
remap_size = HDMI_VP_REMAP_YCC422_20bit;
- else if (hdmi_data->enc_color_depth == 12)
+ break;
+ case 12:
remap_size = HDMI_VP_REMAP_YCC422_24bit;
- else
+ break;
+
+ default:
return;
+ }
output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
} else {
return;
@@ -1148,28 +1266,35 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
/* Initialise info frame from DRM mode */
drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
- if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+ if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
frame.colorspace = HDMI_COLORSPACE_YUV444;
- else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+ else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
frame.colorspace = HDMI_COLORSPACE_YUV422;
else
frame.colorspace = HDMI_COLORSPACE_RGB;
/* Set up colorimetry */
- if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
- frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
- if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
- frame.extended_colorimetry =
+ switch (hdmi->hdmi_data.enc_out_encoding) {
+ case V4L2_YCBCR_ENC_601:
+ if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV601)
+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+ else
+ frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+ frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
- else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
- frame.extended_colorimetry =
+ case V4L2_YCBCR_ENC_709:
+ if (hdmi->hdmi_data.enc_in_encoding == V4L2_YCBCR_ENC_XV709)
+ frame.colorimetry = HDMI_COLORIMETRY_EXTENDED;
+ else
+ frame.colorimetry = HDMI_COLORIMETRY_ITU_709;
+ frame.extended_colorimetry =
HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
- } else if (hdmi->hdmi_data.enc_out_format != RGB) {
- frame.colorimetry = hdmi->hdmi_data.colorimetry;
- frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
- } else { /* Carries no data */
- frame.colorimetry = HDMI_COLORIMETRY_NONE;
- frame.extended_colorimetry = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ break;
+ default: /* Carries no data */
+ frame.colorimetry = HDMI_COLORIMETRY_ITU_601;
+ frame.extended_colorimetry =
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ break;
}
frame.scan_mode = HDMI_SCAN_MODE_NONE;
@@ -1498,19 +1623,30 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
(hdmi->vic == 21) || (hdmi->vic == 22) ||
(hdmi->vic == 2) || (hdmi->vic == 3) ||
(hdmi->vic == 17) || (hdmi->vic == 18))
- hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601;
else
- hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
+ hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709;
hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
- /* TODO: Get input format from IPU (via FB driver interface) */
- hdmi->hdmi_data.enc_in_format = RGB;
+ /* TOFIX: Get input format from plat data or fallback to RGB888 */
+ if (hdmi->plat_data->input_bus_format >= 0)
+ 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 >= 0)
+ hdmi->hdmi_data.enc_in_encoding =
+ hdmi->plat_data->input_bus_encoding;
+ else
+ hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
- hdmi->hdmi_data.enc_out_format = RGB;
+ /* TOFIX: Default to RGB888 output format */
+ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24;
- hdmi->hdmi_data.enc_color_depth = 8;
hdmi->hdmi_data.pix_repet_factor = 0;
hdmi->hdmi_data.hdcp_enable = 0;
hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index bcceee8..0da74fb 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -14,6 +14,67 @@
struct dw_hdmi;
+/**
+ * DOC: Supported input formats and encodings
+ *
+ * Depending on the Hardware configuration of the Controller IP, it supports
+ * a subset of the following input formats and encodings on it's internal
+ * 48bit bus.
+ *
+ * +----------------------+---------------------------------+------------------------------+
+ * + Format Name + Format Code + Encodings +
+ * +----------------------+---------------------------------+------------------------------+
+ * + RGB 4:4:4 8bit + ``MEDIA_BUS_FMT_RGB888_1X24`` + ``V4L2_YCBCR_ENC_DEFAULT`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + RGB 4:4:4 10bits + ``MEDIA_BUS_FMT_RGB101010_1X30``+ ``V4L2_YCBCR_ENC_DEFAULT`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + RGB 4:4:4 12bits + ``MEDIA_BUS_FMT_RGB121212_1X36``+ ``V4L2_YCBCR_ENC_DEFAULT`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + RGB 4:4:4 16bits + ``MEDIA_BUS_FMT_RGB161616_1X48``+ ``V4L2_YCBCR_ENC_DEFAULT`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:4:4 8bit + ``MEDIA_BUS_FMT_YUV8_1X24`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV601`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:4:4 10bits + ``MEDIA_BUS_FMT_YUV10_1X30`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV601`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:4:4 12bits + ``MEDIA_BUS_FMT_YUV12_1X36`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV601`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:4:4 16bits + ``MEDIA_BUS_FMT_YUV16_1X48`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV601`` +
+ * + + + or ``V4L2_YCBCR_ENC_XV709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:2 8bit + ``MEDIA_BUS_FMT_UYVY8_1X16`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:2 10bits + ``MEDIA_BUS_FMT_UYVY10_1X20`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:2 12bits + ``MEDIA_BUS_FMT_UYVY12_1X24`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:0 8bit + ``MEDIA_BUS_FMT_UYYVYY8_1X24`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:0 10bits + ``MEDIA_BUS_FMT_UYYVYY10_1X30`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:0 12bits + ``MEDIA_BUS_FMT_UYYVYY12_1X36`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ * + YCbCr 4:2:0 16bits + ``MEDIA_BUS_FMT_UYYVYY16_1X48`` + ``V4L2_YCBCR_ENC_601`` +
+ * + + + or ``V4L2_YCBCR_ENC_709`` +
+ * +----------------------+---------------------------------+------------------------------+
+ */
+
enum {
DW_HDMI_RES_8,
DW_HDMI_RES_10,
@@ -62,6 +123,8 @@ struct dw_hdmi_plat_data {
struct regmap *regm;
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
struct drm_display_mode *mode);
+ unsigned long input_bus_format;
+ unsigned long input_bus_encoding;
/* Vendor PHY support */
const struct dw_hdmi_phy_ops *phy_ops;
--
1.9.1

View file

@ -0,0 +1,53 @@
From 24739afc3e8549f7361dd2ac7f8f5368f8fe0f79 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Thu, 30 Mar 2017 16:06:10 +0200
Subject: [PATCH 45/79] WIP: ARM64: dts: meson-gxl-p230: add sound card support
This commit add sound card support to the meson-gxbb-p230
his patch is not intended to be merged upstream. The architecture of
the sound card has not been determined yet. To handle the routing caps
of meson SoCs, we will probably have to make our own card.
This implementation using simple-card is provided for testing purpose only
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
index 770a332..5da5206 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
@@ -90,6 +90,27 @@
compatible = "linux,spdif-dit";
status = "okay";
};
+
+ soc {
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "meson-gxl-p230";
+
+ simple-audio-card,dai-link@0 {
+ plat {
+ sound-dai = <&aiu_spdif_dma>;
+ };
+
+ cpu {
+ sound-dai = <&spdif_dai>;
+ };
+
+ codec {
+ sound-dai = <&spdif_out>;
+ };
+ };
+ };
+ };
};
&cec_AO {
--
1.9.1

View file

@ -1,225 +0,0 @@
From 5c5f665a2f6a9a8248bf38356f0958772d6d4ef6 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Wed, 8 Feb 2017 12:29:19 +0100
Subject: [PATCH 45/93] drm: bridge: dw-hdmi: Move HPD handling to PHY
operations
The HDMI TX controller support HPD and RXSENSE signaling from the PHY
via it's STAT0 PHY interface, but some vendor PHYs can manage these
signals independently from the controller, thus these STAT0 handling
should be moved to PHY specific operations and become optional.
The existing STAT0 HPD and RXSENSE handling code is refactored into
a supplementaty set of default PHY operations that are used automatically
when the platform glue doesn't provide its own operations.
Reviewed-by: Jose Abreu <joabreu@synopsys.com>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 135 ++++++++++++++++++------------
include/drm/bridge/dw_hdmi.h | 5 ++
2 files changed, 86 insertions(+), 54 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index fcb0a27..910d579 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1229,10 +1229,46 @@ static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
connector_status_connected : connector_status_disconnected;
}
+static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
+ bool force, bool disabled, bool rxsense)
+{
+ u8 old_mask = hdmi->phy_mask;
+
+ if (force || disabled || !rxsense)
+ hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
+ else
+ hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE;
+
+ if (old_mask != hdmi->phy_mask)
+ hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
+}
+
+static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
+{
+ /*
+ * Configure the PHY RX SENSE and HPD interrupts polarities and clear
+ * any pending interrupt.
+ */
+ hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+ HDMI_IH_PHY_STAT0);
+
+ /* Enable cable hot plug irq. */
+ hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
+
+ /* Clear and unmute interrupts. */
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
+ HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
+ HDMI_IH_MUTE_PHY_STAT0);
+}
+
static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
.init = dw_hdmi_phy_init,
.disable = dw_hdmi_phy_disable,
.read_hpd = dw_hdmi_phy_read_hpd,
+ .update_hpd = dw_hdmi_phy_update_hpd,
+ .setup_hpd = dw_hdmi_phy_setup_hpd,
};
/* -----------------------------------------------------------------------------
@@ -1809,35 +1845,10 @@ static void dw_hdmi_update_power(struct dw_hdmi *hdmi)
*/
static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi)
{
- u8 old_mask = hdmi->phy_mask;
-
- if (hdmi->force || hdmi->disabled || !hdmi->rxsense)
- hdmi->phy_mask |= HDMI_PHY_RX_SENSE;
- else
- hdmi->phy_mask &= ~HDMI_PHY_RX_SENSE;
-
- if (old_mask != hdmi->phy_mask)
- hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
-}
-
-static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi)
-{
- /*
- * Configure the PHY RX SENSE and HPD interrupts polarities and clear
- * any pending interrupt.
- */
- hdmi_writeb(hdmi, HDMI_PHY_HPD | HDMI_PHY_RX_SENSE, HDMI_PHY_POL0);
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
- HDMI_IH_PHY_STAT0);
-
- /* Enable cable hot plug irq. */
- hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
-
- /* Clear and unmute interrupts. */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE,
- HDMI_IH_PHY_STAT0);
- hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
- HDMI_IH_MUTE_PHY_STAT0);
+ if (hdmi->phy.ops->update_hpd)
+ hdmi->phy.ops->update_hpd(hdmi, hdmi->phy.data,
+ hdmi->force, hdmi->disabled,
+ hdmi->rxsense);
}
static enum drm_connector_status
@@ -2029,6 +2040,41 @@ static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
return ret;
}
+void __dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense)
+{
+ mutex_lock(&hdmi->mutex);
+
+ if (!hdmi->disabled && !hdmi->force) {
+ /*
+ * If the RX sense status indicates we're disconnected,
+ * clear the software rxsense status.
+ */
+ if (!rx_sense)
+ hdmi->rxsense = false;
+
+ /*
+ * Only set the software rxsense status when both
+ * rxsense and hpd indicates we're connected.
+ * This avoids what seems to be bad behaviour in
+ * at least iMX6S versions of the phy.
+ */
+ if (hpd)
+ hdmi->rxsense = true;
+
+ dw_hdmi_update_power(hdmi);
+ dw_hdmi_update_phy_mask(hdmi);
+ }
+ mutex_unlock(&hdmi->mutex);
+}
+
+void dw_hdmi_setup_rx_sense(struct device *dev, bool hpd, bool rx_sense)
+{
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+ __dw_hdmi_setup_rx_sense(hdmi, hpd, rx_sense);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_setup_rx_sense);
+
static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
{
struct dw_hdmi *hdmi = dev_id;
@@ -2061,30 +2107,10 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
* ask the source to re-read the EDID.
*/
if (intr_stat &
- (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD)) {
- mutex_lock(&hdmi->mutex);
- if (!hdmi->disabled && !hdmi->force) {
- /*
- * If the RX sense status indicates we're disconnected,
- * clear the software rxsense status.
- */
- if (!(phy_stat & HDMI_PHY_RX_SENSE))
- hdmi->rxsense = false;
-
- /*
- * Only set the software rxsense status when both
- * rxsense and hpd indicates we're connected.
- * This avoids what seems to be bad behaviour in
- * at least iMX6S versions of the phy.
- */
- if (phy_stat & HDMI_PHY_HPD)
- hdmi->rxsense = true;
-
- dw_hdmi_update_power(hdmi);
- dw_hdmi_update_phy_mask(hdmi);
- }
- mutex_unlock(&hdmi->mutex);
- }
+ (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_IH_PHY_STAT0_HPD))
+ __dw_hdmi_setup_rx_sense(hdmi,
+ phy_stat & HDMI_PHY_HPD,
+ phy_stat & HDMI_PHY_RX_SENSE);
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
dev_dbg(hdmi->dev, "EVENT=%s\n",
@@ -2358,7 +2384,8 @@ static int dw_hdmi_detect_phy(struct dw_hdmi *hdmi)
#endif
dw_hdmi_fb_registered(hdmi);
- dw_hdmi_phy_setup_hpd(hdmi);
+ if (hdmi->phy.ops->setup_hpd)
+ hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
memset(&pdevinfo, 0, sizeof(pdevinfo));
pdevinfo.parent = dev;
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 0da74fb..0668ae1 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -117,6 +117,9 @@ struct dw_hdmi_phy_ops {
struct drm_display_mode *mode);
void (*disable)(struct dw_hdmi *hdmi, void *data);
enum drm_connector_status (*read_hpd)(struct dw_hdmi *hdmi, void *data);
+ void (*update_hpd)(struct dw_hdmi *hdmi, void *data,
+ bool force, bool disabled, bool rxsense);
+ void (*setup_hpd)(struct dw_hdmi *hdmi, void *data);
};
struct dw_hdmi_plat_data {
@@ -147,6 +150,8 @@ int dw_hdmi_probe(struct platform_device *pdev,
int dw_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
const struct dw_hdmi_plat_data *plat_data);
+void dw_hdmi_setup_rx_sense(struct device *dev, 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);
--
1.9.1

View file

@ -0,0 +1,120 @@
From 8fb6f1d768e64d2df3f4effdb90a953ba0080a76 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Mon, 20 Mar 2017 12:04:14 +0100
Subject: [PATCH 46/79] clk: take the prepare lock out of clk_core_set_parent
Rework set_parent core function so it can be called when the prepare lock
is already held by the caller.
This rework is done to ease the integration of the "protected" clock
functionality.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/clk.c | 39 ++++++++++++++++++---------------------
1 file changed, 18 insertions(+), 21 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index fc58c52..f5c3715 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1787,7 +1787,8 @@ bool clk_has_parent(struct clk *clk, struct clk *parent)
}
EXPORT_SYMBOL_GPL(clk_has_parent);
-static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
+static int clk_core_set_parent_nolock(struct clk_core *core,
+ struct clk_core *parent)
{
int ret = 0;
int p_index = 0;
@@ -1796,23 +1797,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
if (!core)
return 0;
- /* prevent racing with updates to the clock topology */
- clk_prepare_lock();
-
if (core->parent == parent)
- goto out;
+ return 0;
/* verify ops for for multi-parent clks */
- if ((core->num_parents > 1) && (!core->ops->set_parent)) {
- ret = -ENOSYS;
- goto out;
- }
+ if ((core->num_parents > 1) && (!core->ops->set_parent))
+ return -ENOSYS;
/* check that we are allowed to re-parent if the clock is in use */
- if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count) {
- ret = -EBUSY;
- goto out;
- }
+ if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
+ return -EBUSY;
/* try finding the new parent index */
if (parent) {
@@ -1820,8 +1814,7 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
if (p_index < 0) {
pr_debug("%s: clk %s can not be parent of clk %s\n",
__func__, parent->name, core->name);
- ret = p_index;
- goto out;
+ return p_index;
}
p_rate = parent->rate;
}
@@ -1831,7 +1824,7 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
/* abort if a driver objects */
if (ret & NOTIFY_STOP_MASK)
- goto out;
+ return ret;
/* do the re-parent */
ret = __clk_set_parent(core, parent, p_index);
@@ -1844,9 +1837,6 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
__clk_recalc_accuracies(core);
}
-out:
- clk_prepare_unlock();
-
return ret;
}
@@ -1869,10 +1859,17 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent)
*/
int clk_set_parent(struct clk *clk, struct clk *parent)
{
+ int ret;
+
if (!clk)
return 0;
- return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+ clk_prepare_lock();
+ ret = clk_core_set_parent_nolock(clk->core,
+ parent ? parent->core : NULL);
+ clk_prepare_unlock();
+
+ return ret;
}
EXPORT_SYMBOL_GPL(clk_set_parent);
@@ -2753,7 +2750,7 @@ void clk_unregister(struct clk *clk)
/* Reparent all children to the orphan list. */
hlist_for_each_entry_safe(child, t, &clk->core->children,
child_node)
- clk_core_set_parent(child, NULL);
+ clk_core_set_parent_nolock(child, NULL);
}
hlist_del_init(&clk->core->child_node);
--
1.9.1

View file

@ -1,30 +0,0 @@
From 050ccc8152e10f6d8ae44cf6772a78331d8df19e Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 2 Feb 2017 10:47:43 +0100
Subject: [PATCH 46/93] drm: meson: rename module name to meson-drm
The module is currently named "meson.ko" which can lead to some
confusion, this patches renames it "meson-drm.ko"
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1486028864-19622-2-git-send-email-narmstrong@baylibre.com
---
drivers/gpu/drm/meson/Makefile | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
index 2591978..92cf845 100644
--- a/drivers/gpu/drm/meson/Makefile
+++ b/drivers/gpu/drm/meson/Makefile
@@ -1,4 +1,4 @@
-meson-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
-meson-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
+meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
+meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
-obj-$(CONFIG_DRM_MESON) += meson.o
+obj-$(CONFIG_DRM_MESON) += meson-drm.o
--
1.9.1

View file

@ -0,0 +1,76 @@
From 12e852dedde5d635713d095df5e83cc3ac54c64a Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Mon, 20 Mar 2017 12:20:41 +0100
Subject: [PATCH 47/79] clk: add clk_core_set_phase_nolock function
Create a core function for set_phase, as it is done for set_rate and
set_parent.
This rework is done to ease the integration of "protected" clock
functionality.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/clk.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index f5c3715..dceaf0f 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1873,6 +1873,23 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
}
EXPORT_SYMBOL_GPL(clk_set_parent);
+static int clk_core_set_phase_nolock(struct clk_core *core, int degrees)
+{
+ int ret = -EINVAL;
+
+ if (!core)
+ return 0;
+
+ trace_clk_set_phase(core, degrees);
+
+ if (core->ops->set_phase)
+ ret = core->ops->set_phase(core->hw, degrees);
+
+ trace_clk_set_phase_complete(core, degrees);
+
+ return ret;
+}
+
/**
* clk_set_phase - adjust the phase shift of a clock signal
* @clk: clock signal source
@@ -1895,7 +1912,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
*/
int clk_set_phase(struct clk *clk, int degrees)
{
- int ret = -EINVAL;
+ int ret;
if (!clk)
return 0;
@@ -1906,17 +1923,7 @@ int clk_set_phase(struct clk *clk, int degrees)
degrees += 360;
clk_prepare_lock();
-
- trace_clk_set_phase(clk->core, degrees);
-
- if (clk->core->ops->set_phase)
- ret = clk->core->ops->set_phase(clk->core->hw, degrees);
-
- trace_clk_set_phase_complete(clk->core, degrees);
-
- if (!ret)
- clk->core->phase = degrees;
-
+ ret = clk_core_set_phase_nolock(clk->core, degrees);
clk_prepare_unlock();
return ret;
--
1.9.1

View file

@ -1,34 +0,0 @@
From e0f2204f17c247d5e9384d8a57835b480ff16115 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Thu, 2 Feb 2017 10:47:44 +0100
Subject: [PATCH 47/93] drm: meson: rename driver name to meson-drm
The platform driver name is currently "meson" which can lead to some
confusion, this patch renames it to "meson-drm" and removes the owner
attribute since is always added by __platform_driver_register called by the
module_platform_driver() macro.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Acked-by: Daniel Vetter <daniel@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1486028864-19622-3-git-send-email-narmstrong@baylibre.com
---
drivers/gpu/drm/meson/meson_drv.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index ff1f601..380bde7 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -329,8 +329,7 @@ static int meson_drv_remove(struct platform_device *pdev)
.probe = meson_drv_probe,
.remove = meson_drv_remove,
.driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
+ .name = "meson-drm",
.of_match_table = dt_match,
},
};
--
1.9.1

View file

@ -0,0 +1,146 @@
From c87711484070e9fb733330662a19f7fc1de9b368 Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Mon, 20 Mar 2017 14:35:47 +0100
Subject: [PATCH 48/79] clk: rework calls to round and determine rate callbacks
Rework the way the callbacks round_rate and determine_rate are called. The
goal is to do this at a single point and make it easier to add conditions
before calling them.
This rework is done to ease the integration of "protected" clock
functionality.
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/clk.c | 78 +++++++++++++++++++++++++++++++------------------------
1 file changed, 44 insertions(+), 34 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index dceaf0f..8cc4672 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -833,16 +833,34 @@ static int clk_disable_unused(void)
}
late_initcall_sync(clk_disable_unused);
-static int clk_core_round_rate_nolock(struct clk_core *core,
- struct clk_rate_request *req)
+static int clk_core_determine_round(struct clk_core *core,
+ struct clk_rate_request *req)
{
- struct clk_core *parent;
long rate;
- lockdep_assert_held(&prepare_lock);
+ if (core->ops->determine_rate) {
+ return core->ops->determine_rate(core->hw, req);
+ } else if (core->ops->round_rate) {
+ rate = core->ops->round_rate(core->hw, req->rate,
+ &req->best_parent_rate);
+ if (rate < 0)
+ return rate;
- if (!core)
- return 0;
+ req->rate = rate;
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void clk_core_init_rate_req(struct clk_core *core,
+ struct clk_rate_request *req)
+{
+ struct clk_core *parent;
+
+ if (WARN_ON(!core || !req))
+ return;
parent = core->parent;
if (parent) {
@@ -852,22 +870,24 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
req->best_parent_hw = NULL;
req->best_parent_rate = 0;
}
+}
- if (core->ops->determine_rate) {
- return core->ops->determine_rate(core->hw, req);
- } else if (core->ops->round_rate) {
- rate = core->ops->round_rate(core->hw, req->rate,
- &req->best_parent_rate);
- if (rate < 0)
- return rate;
+static int clk_core_round_rate_nolock(struct clk_core *core,
+ struct clk_rate_request *req)
+{
+ lockdep_assert_held(&prepare_lock);
- req->rate = rate;
- } else if (core->flags & CLK_SET_RATE_PARENT) {
- return clk_core_round_rate_nolock(parent, req);
- } else {
- req->rate = core->rate;
- }
+ if (!core)
+ return 0;
+
+ clk_core_init_rate_req(core, req);
+
+ if (core->ops->determine_rate || core->ops->round_rate)
+ return clk_core_determine_round(core, req);
+ else if (core->flags & CLK_SET_RATE_PARENT)
+ return clk_core_round_rate_nolock(core->parent, req);
+ req->rate = core->rate;
return 0;
}
@@ -1356,36 +1376,26 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
clk_core_get_boundaries(core, &min_rate, &max_rate);
/* find the closest rate and parent clk/rate */
- if (core->ops->determine_rate) {
+ if (core->ops->determine_rate || core->ops->round_rate) {
struct clk_rate_request req;
req.rate = rate;
req.min_rate = min_rate;
req.max_rate = max_rate;
- if (parent) {
- req.best_parent_hw = parent->hw;
- req.best_parent_rate = parent->rate;
- } else {
- req.best_parent_hw = NULL;
- req.best_parent_rate = 0;
- }
- ret = core->ops->determine_rate(core->hw, &req);
+ clk_core_init_rate_req(core, &req);
+
+ ret = clk_core_determine_round(core, &req);
if (ret < 0)
return NULL;
best_parent_rate = req.best_parent_rate;
new_rate = req.rate;
parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
- } else if (core->ops->round_rate) {
- ret = core->ops->round_rate(core->hw, rate,
- &best_parent_rate);
- if (ret < 0)
- return NULL;
- new_rate = ret;
if (new_rate < min_rate || new_rate > max_rate)
return NULL;
+
} else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) {
/* pass-through clock without adjustable parent */
core->new_rate = core->rate;
--
1.9.1

View file

@ -1,61 +0,0 @@
From 1f82a2baa3b5935ed41738f38cf486872aa8a9f7 Mon Sep 17 00:00:00 2001
From: Neil Armstrong <narmstrong@baylibre.com>
Date: Fri, 13 Jan 2017 15:57:10 +0100
Subject: [PATCH 48/93] drm/meson: Use crtc_state for hdisplay and fix atomic
flush/enable sync for vsync commit
Clean the crtc_enable by using the proper crtc_state instead of the state
of the primary plane state data.
Also fix the dependency to commit the plane changes even if enable is called
after the flush.
---
drivers/gpu/drm/meson/meson_crtc.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index 749770e..d4b114d 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -60,11 +60,18 @@ struct meson_crtc {
static void meson_crtc_enable(struct drm_crtc *crtc)
{
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
- struct drm_plane *plane = meson_crtc->priv->primary_plane;
+ struct drm_crtc_state *crtc_state = crtc->state;
struct meson_drm *priv = meson_crtc->priv;
+ DRM_DEBUG_DRIVER("\n");
+
+ if (!crtc_state) {
+ DRM_ERROR("Invalid crtc_state\n");
+ return;
+ }
+
/* Enable VPP Postblend */
- writel(plane->state->crtc_w,
+ writel(crtc_state->mode.hdisplay,
priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
@@ -79,6 +86,7 @@ static void meson_crtc_disable(struct drm_crtc *crtc)
struct meson_drm *priv = meson_crtc->priv;
priv->viu.osd1_enabled = false;
+ priv->viu.osd1_commit = false;
/* Disable VPP Postblend */
writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
@@ -115,8 +123,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
struct meson_drm *priv = meson_crtc->priv;
- if (priv->viu.osd1_enabled)
- priv->viu.osd1_commit = true;
+ priv->viu.osd1_commit = true;
}
static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
--
1.9.1

View file

@ -0,0 +1,77 @@
From 0e588289da294fb71f7873c2781758a7ba19dc7f Mon Sep 17 00:00:00 2001
From: Jerome Brunet <jbrunet@baylibre.com>
Date: Fri, 19 May 2017 11:44:22 +0200
Subject: [PATCH 49/79] clk: use round rate to bail out early in set_rate
The current implementation of clk_core_set_rate_nolock bails out early if
the requested rate is exactly the same as the one set. It should bail out
if the request would not result in rate a change. This important when rate
is not exactly what is requested, which is fairly common with PLLs.
Ex: provider able to give any rate with steps of 100Hz
- 1st consumer request 48000Hz and gets it.
- 2nd consumer request 48010Hz as well. If we were to perform the usual
mechanism, we would get 48000Hz as well. The clock would not change so
there is no point performing any checks to make sure the clock can change,
we know it won't.
This is important to prepare the addition of the clock protection mechanism
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
drivers/clk/clk.c | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 8cc4672..163cb98 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1570,15 +1570,34 @@ static void clk_change_rate(struct clk_core *core)
clk_change_rate(core->new_child);
}
+static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
+ unsigned long req_rate)
+{
+ int ret;
+ struct clk_rate_request req;
+
+ if (!core)
+ return 0;
+
+ clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
+ req.rate = req_rate;
+
+ ret = clk_core_round_rate_nolock(core, &req);
+
+ return ret ? 0 : req.rate;
+}
+
static int clk_core_set_rate_nolock(struct clk_core *core,
unsigned long req_rate)
{
struct clk_core *top, *fail_clk;
- unsigned long rate = req_rate;
+ unsigned long rate;
if (!core)
return 0;
+ rate = clk_core_req_round_rate_nolock(core, req_rate);
+
/* bail early if nothing to do */
if (rate == clk_core_get_rate_nolock(core))
return 0;
@@ -1587,7 +1606,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
return -EBUSY;
/* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(core, rate);
+ top = clk_calc_new_rates(core, req_rate);
if (!top)
return -EINVAL;
--
1.9.1

Some files were not shown because too many files have changed in this diff Show more