mirror of
https://github.com/Fishwaldo/build.git
synced 2025-07-23 21:39:02 +00:00
Lepotato. Added NEXT, added patches from C2 NEXT, au, config update, removed deprecated patches, ...
This commit is contained in:
parent
38a7bcf8c2
commit
2c59bb9934
66 changed files with 50058 additions and 8 deletions
|
@ -0,0 +1,51 @@
|
|||
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 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 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 @@
|
||||
compatible = "mmc-pwrseq-emmc";
|
||||
reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
+
|
||||
+ hdmi-connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_connector_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&scpi_clocks {
|
||||
@@ -309,3 +320,15 @@
|
||||
vmmc-supply = <&vcc3v3>;
|
||||
vqmmc-supply = <&vcc1v8>;
|
||||
};
|
||||
+
|
||||
+&hdmi_tx {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx_tmds_port {
|
||||
+ hdmi_tx_tmds_out: endpoint {
|
||||
+ remote-endpoint = <&hdmi_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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 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(+)
|
||||
|
||||
diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
|
||||
index 3ce51d8..02d400b 100644
|
||||
--- a/drivers/gpu/drm/meson/Kconfig
|
||||
+++ b/drivers/gpu/drm/meson/Kconfig
|
||||
@@ -13,3 +13,4 @@ config DRM_MESON_DW_HDMI
|
||||
depends on DRM_MESON
|
||||
default y if DRM_MESON
|
||||
select DRM_DW_HDMI
|
||||
+ select DRM_DW_HDMI_I2S_AUDIO
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
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 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 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,
|
||||
/* nshift factor = 0 */
|
||||
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
|
||||
|
||||
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ /* Use Auto CTS mode with CTS is unknown */
|
||||
+ if (cts)
|
||||
+ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
+ else
|
||||
+ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3);
|
||||
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
||||
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
|
||||
|
||||
@@ -491,24 +495,31 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
|
||||
{
|
||||
unsigned long ftdms = pixel_clk;
|
||||
unsigned int n, cts;
|
||||
+ u8 config3;
|
||||
u64 tmp;
|
||||
|
||||
n = hdmi_compute_n(sample_rate, pixel_clk);
|
||||
|
||||
- /*
|
||||
- * Compute the CTS value from the N value. Note that CTS and N
|
||||
- * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
- * note that our TDMS clock is not fully accurate; it is accurate
|
||||
- * to kHz. This can introduce an unnecessary remainder in the
|
||||
- * calculation below, so we don't try to warn about that.
|
||||
- */
|
||||
- tmp = (u64)ftdms * n;
|
||||
- do_div(tmp, 128 * sample_rate);
|
||||
- cts = tmp;
|
||||
-
|
||||
- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
- n, cts);
|
||||
+ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID);
|
||||
+
|
||||
+ if (config3 & HDMI_CONFIG3_AHBAUDDMA) {
|
||||
+ /*
|
||||
+ * Compute the CTS value from the N value. Note that CTS and N
|
||||
+ * can be up to 20 bits in total, so we need 64-bit math. Also
|
||||
+ * note that our TDMS clock is not fully accurate; it is
|
||||
+ * accurate to kHz. This can introduce an unnecessary remainder
|
||||
+ * in the calculation below, so we don't try to warn about that.
|
||||
+ */
|
||||
+ tmp = (u64)ftdms * n;
|
||||
+ do_div(tmp, 128 * sample_rate);
|
||||
+ cts = tmp;
|
||||
+
|
||||
+ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n",
|
||||
+ __func__, sample_rate,
|
||||
+ ftdms / 1000000, (ftdms / 1000) % 1000,
|
||||
+ n, cts);
|
||||
+ } else
|
||||
+ cts = 0;
|
||||
|
||||
spin_lock_irq(&hdmi->audio_lock);
|
||||
hdmi->audio_n = n;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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>;
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
status = "okay";
|
||||
pinctrl-0 = <ð_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";
|
||||
+};
|
||||
+
|
||||
ðmac {
|
||||
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 */
|
||||
ðmac {
|
||||
pinctrl-0 = <ð_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
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
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"
|
||||
|
||||
@@ -175,6 +175,7 @@ struct dw_hdmi {
|
||||
|
||||
unsigned int reg_shift;
|
||||
struct regmap *regm;
|
||||
+ struct cec_notifier *cec_notifier;
|
||||
void (*enable_audio)(struct dw_hdmi *hdmi);
|
||||
void (*disable_audio)(struct dw_hdmi *hdmi);
|
||||
};
|
||||
@@ -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
|
||||
|
|
@ -0,0 +1,725 @@
|
|||
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
|
||||
@@ -85,4 +85,6 @@ obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/
|
||||
|
||||
obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/
|
||||
|
||||
+obj-y += meson/
|
||||
+
|
||||
obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
From 45ed0fea98d308d6cae17be657dd01d5ee729d87 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
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 | 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..67391e6
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-regs.h
|
||||
@@ -0,0 +1,182 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _AIU_REGS_H_
|
||||
+#define _AIU_REGS_H_
|
||||
+
|
||||
+#define AIU_958_BPF 0x000
|
||||
+#define AIU_958_BRST 0x004
|
||||
+#define AIU_958_LENGTH 0x008
|
||||
+#define AIU_958_PADDSIZE 0x00C
|
||||
+#define AIU_958_MISC 0x010
|
||||
+#define AIU_958_FORCE_LEFT 0x014 /* Unknown */
|
||||
+#define AIU_958_DISCARD_NUM 0x018
|
||||
+#define AIU_958_DCU_FF_CTRL 0x01C
|
||||
+#define AIU_958_CHSTAT_L0 0x020
|
||||
+#define AIU_958_CHSTAT_L1 0x024
|
||||
+#define AIU_958_CTRL 0x028
|
||||
+#define AIU_958_RPT 0x02C
|
||||
+#define AIU_I2S_MUTE_SWAP 0x030
|
||||
+#define AIU_I2S_SOURCE_DESC 0x034
|
||||
+#define AIU_I2S_MED_CTRL 0x038
|
||||
+#define AIU_I2S_MED_THRESH 0x03C
|
||||
+#define AIU_I2S_DAC_CFG 0x040
|
||||
+#define AIU_I2S_SYNC 0x044 /* Unknown */
|
||||
+#define AIU_I2S_MISC 0x048
|
||||
+#define AIU_I2S_OUT_CFG 0x04C
|
||||
+#define AIU_I2S_FF_CTRL 0x050 /* Unknown */
|
||||
+#define AIU_RST_SOFT 0x054
|
||||
+#define AIU_CLK_CTRL 0x058
|
||||
+#define AIU_MIX_ADCCFG 0x05C
|
||||
+#define AIU_MIX_CTRL 0x060
|
||||
+#define AIU_CLK_CTRL_MORE 0x064
|
||||
+#define AIU_958_POP 0x068
|
||||
+#define AIU_MIX_GAIN 0x06C
|
||||
+#define AIU_958_SYNWORD1 0x070
|
||||
+#define AIU_958_SYNWORD2 0x074
|
||||
+#define AIU_958_SYNWORD3 0x078
|
||||
+#define AIU_958_SYNWORD1_MASK 0x07C
|
||||
+#define AIU_958_SYNWORD2_MASK 0x080
|
||||
+#define AIU_958_SYNWORD3_MASK 0x084
|
||||
+#define AIU_958_FFRDOUT_THD 0x088
|
||||
+#define AIU_958_LENGTH_PER_PAUSE 0x08C
|
||||
+#define AIU_958_PAUSE_NUM 0x090
|
||||
+#define AIU_958_PAUSE_PAYLOAD 0x094
|
||||
+#define AIU_958_AUTO_PAUSE 0x098
|
||||
+#define AIU_958_PAUSE_PD_LENGTH 0x09C
|
||||
+#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0
|
||||
+#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL 0x0A8
|
||||
+#define AIU_CODEC_CLK_DATA_CTRL 0x0AC
|
||||
+#define AIU_ACODEC_CTRL 0x0B0
|
||||
+#define AIU_958_CHSTAT_R0 0x0C0
|
||||
+#define AIU_958_CHSTAT_R1 0x0C4
|
||||
+#define AIU_958_VALID_CTRL 0x0C8
|
||||
+#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */
|
||||
+#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */
|
||||
+#define AIU_AIFIFO2_CTRL 0x100
|
||||
+#define AIU_AIFIFO2_STATUS 0x104
|
||||
+#define AIU_AIFIFO2_GBIT 0x108
|
||||
+#define AIU_AIFIFO2_CLB 0x10C
|
||||
+#define AIU_CRC_CTRL 0x110
|
||||
+#define AIU_CRC_STATUS 0x114
|
||||
+#define AIU_CRC_SHIFT_REG 0x118
|
||||
+#define AIU_CRC_IREG 0x11C
|
||||
+#define AIU_CRC_CAL_REG1 0x120
|
||||
+#define AIU_CRC_CAL_REG0 0x124
|
||||
+#define AIU_CRC_POLY_COEF1 0x128
|
||||
+#define AIU_CRC_POLY_COEF0 0x12C
|
||||
+#define AIU_CRC_BIT_SIZE1 0x130
|
||||
+#define AIU_CRC_BIT_SIZE0 0x134
|
||||
+#define AIU_CRC_BIT_CNT1 0x138
|
||||
+#define AIU_CRC_BIT_CNT0 0x13C
|
||||
+#define AIU_AMCLK_GATE_HI 0x140
|
||||
+#define AIU_AMCLK_GATE_LO 0x144
|
||||
+#define AIU_AMCLK_MSR 0x148
|
||||
+#define AIU_AUDAC_CTRL0 0x14C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA0 0x154 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA1 0x158 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA2 0x15C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA3 0x160 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA4 0x164 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA5 0x168 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA6 0x16C /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA7 0x170 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */
|
||||
+#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */
|
||||
+#define AIU_MEM_I2S_START_PTR 0x180
|
||||
+#define AIU_MEM_I2S_RD_PTR 0x184
|
||||
+#define AIU_MEM_I2S_END_PTR 0x188
|
||||
+#define AIU_MEM_I2S_MASKS 0x18C
|
||||
+#define AIU_MEM_I2S_CONTROL 0x190
|
||||
+#define AIU_MEM_IEC958_START_PTR 0x194
|
||||
+#define AIU_MEM_IEC958_RD_PTR 0x198
|
||||
+#define AIU_MEM_IEC958_END_PTR 0x19C
|
||||
+#define AIU_MEM_IEC958_MASKS 0x1A0
|
||||
+#define AIU_MEM_IEC958_CONTROL 0x1A4
|
||||
+#define AIU_MEM_AIFIFO2_START_PTR 0x1A8
|
||||
+#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC
|
||||
+#define AIU_MEM_AIFIFO2_END_PTR 0x1B0
|
||||
+#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4
|
||||
+#define AIU_MEM_AIFIFO2_CONTROL 0x1B8
|
||||
+#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC
|
||||
+#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0
|
||||
+#define AIU_MEM_AIFIFO2_LEVEL 0x1C4
|
||||
+#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8
|
||||
+#define AIU_MEM_I2S_MAN_WP 0x1CC
|
||||
+#define AIU_MEM_I2S_MAN_RP 0x1D0
|
||||
+#define AIU_MEM_I2S_LEVEL 0x1D4
|
||||
+#define AIU_MEM_I2S_BUF_CNTL 0x1D8
|
||||
+#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC
|
||||
+#define AIU_MEM_I2S_MEM_CTL 0x1E0
|
||||
+#define AIU_MEM_IEC958_MEM_CTL 0x1E4
|
||||
+#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8
|
||||
+#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC
|
||||
+#define AIU_MEM_IEC958_MAN_WP 0x1F0
|
||||
+#define AIU_MEM_IEC958_MAN_RP 0x1F4
|
||||
+#define AIU_MEM_IEC958_LEVEL 0x1F8
|
||||
+#define AIU_MEM_IEC958_BUF_CNTL 0x1FC
|
||||
+#define AIU_AIFIFO_CTRL 0x200
|
||||
+#define AIU_AIFIFO_STATUS 0x204
|
||||
+#define AIU_AIFIFO_GBIT 0x208
|
||||
+#define AIU_AIFIFO_CLB 0x20C
|
||||
+#define AIU_MEM_AIFIFO_START_PTR 0x210
|
||||
+#define AIU_MEM_AIFIFO_CURR_PTR 0x214
|
||||
+#define AIU_MEM_AIFIFO_END_PTR 0x218
|
||||
+#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C
|
||||
+#define AIU_MEM_AIFIFO_CONTROL 0x220
|
||||
+#define AIU_MEM_AIFIFO_MAN_WP 0x224
|
||||
+#define AIU_MEM_AIFIFO_MAN_RP 0x228
|
||||
+#define AIU_MEM_AIFIFO_LEVEL 0x22C
|
||||
+#define AIU_MEM_AIFIFO_BUF_CNTL 0x230
|
||||
+#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234
|
||||
+#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238
|
||||
+#define AIU_MEM_AIFIFO_MEM_CTL 0x23C
|
||||
+#define AIFIFO_TIME_STAMP_CNTL 0x240
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_0 0x244
|
||||
+#define AIFIFO_TIME_STAMP_SYNC_1 0x248
|
||||
+#define AIFIFO_TIME_STAMP_0 0x24C
|
||||
+#define AIFIFO_TIME_STAMP_1 0x250
|
||||
+#define AIFIFO_TIME_STAMP_2 0x254
|
||||
+#define AIFIFO_TIME_STAMP_3 0x258
|
||||
+#define AIFIFO_TIME_STAMP_LENGTH 0x25C
|
||||
+#define AIFIFO2_TIME_STAMP_CNTL 0x260
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_0 0x264
|
||||
+#define AIFIFO2_TIME_STAMP_SYNC_1 0x268
|
||||
+#define AIFIFO2_TIME_STAMP_0 0x26C
|
||||
+#define AIFIFO2_TIME_STAMP_1 0x270
|
||||
+#define AIFIFO2_TIME_STAMP_2 0x274
|
||||
+#define AIFIFO2_TIME_STAMP_3 0x278
|
||||
+#define AIFIFO2_TIME_STAMP_LENGTH 0x27C
|
||||
+#define IEC958_TIME_STAMP_CNTL 0x280
|
||||
+#define IEC958_TIME_STAMP_SYNC_0 0x284
|
||||
+#define IEC958_TIME_STAMP_SYNC_1 0x288
|
||||
+#define IEC958_TIME_STAMP_0 0x28C
|
||||
+#define IEC958_TIME_STAMP_1 0x290
|
||||
+#define IEC958_TIME_STAMP_2 0x294
|
||||
+#define IEC958_TIME_STAMP_3 0x298
|
||||
+#define IEC958_TIME_STAMP_LENGTH 0x29C
|
||||
+#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0
|
||||
+#define AIU_I2S_CBUS_DDR_CNTL 0x2A4
|
||||
+#define AIU_I2S_CBUS_DDR_WDATA 0x2A8
|
||||
+#define AIU_I2S_CBUS_DDR_ADDR 0x2AC
|
||||
+
|
||||
+#endif /* _AIU_REGS_H_ */
|
||||
diff --git a/sound/soc/meson/audin-regs.h b/sound/soc/meson/audin-regs.h
|
||||
new file mode 100644
|
||||
index 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
|
||||
|
|
@ -0,0 +1,417 @@
|
|||
From 98fd2d06e53a52a033317864b317549e6f3e9245 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 30 Mar 2017 12:14:40 +0200
|
||||
Subject: [PATCH 29/79] ASoC: meson: add aiu i2s dma support
|
||||
|
||||
Add support for the i2s output dma which is part of the AIU block
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/Kconfig | 7 +
|
||||
sound/soc/meson/Makefile | 2 +
|
||||
sound/soc/meson/aiu-i2s-dma.c | 367 ++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 376 insertions(+)
|
||||
create mode 100644 sound/soc/meson/aiu-i2s-dma.c
|
||||
|
||||
diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig
|
||||
index 216c850..ad31a11 100644
|
||||
--- a/sound/soc/meson/Kconfig
|
||||
+++ b/sound/soc/meson/Kconfig
|
||||
@@ -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_SOC_MESON_I2S
|
||||
+ tristate "Meson i2s interface"
|
||||
+ depends on SND_SOC_MESON
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for i2s dma driver for Amlogic
|
||||
+ Meson SoCs.
|
||||
diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile
|
||||
index 22028ab..273f275 100644
|
||||
--- a/sound/soc/meson/Makefile
|
||||
+++ b/sound/soc/meson/Makefile
|
||||
@@ -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..bab950d
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/meson/aiu-i2s-dma.c
|
||||
@@ -0,0 +1,367 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2017 BayLibre, SAS
|
||||
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
|
||||
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <sound/pcm_params.h>
|
||||
+#include <sound/soc.h>
|
||||
+
|
||||
+#include "aiu-regs.h"
|
||||
+#include "audio-core.h"
|
||||
+
|
||||
+#define DRV_NAME "meson-aiu-i2s-dma"
|
||||
+
|
||||
+struct aiu_i2s_dma {
|
||||
+ struct meson_audio_core_data *core;
|
||||
+ struct clk *fast;
|
||||
+ int irq;
|
||||
+};
|
||||
+
|
||||
+#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_INIT BIT(0)
|
||||
+#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1)
|
||||
+#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2)
|
||||
+#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
|
||||
+#define AIU_MEM_I2S_CONTROL_BUSY BIT(7)
|
||||
+#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8)
|
||||
+#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16)
|
||||
+#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0)
|
||||
+#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0)
|
||||
+#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0)
|
||||
+#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1)
|
||||
+
|
||||
+/*
|
||||
+ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory
|
||||
+ * layout expected depends on the mode of operation.
|
||||
+ *
|
||||
+ * - Normal mode: The channels are expected to be packed in 32 bytes groups
|
||||
+ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing
|
||||
+ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the
|
||||
+ * channels read by the DMA. This is very flexible but the unsual memory layout
|
||||
+ * makes it less easy to deal with. The burst size is 32 bytes times the number
|
||||
+ * of channels read.
|
||||
+ *
|
||||
+ * - Split mode:
|
||||
+ * Classical channel interleaved frame organisation. In this mode,
|
||||
+ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and
|
||||
+ * the burst size is fixed to 256 bytes. The input can be either 2 or 8
|
||||
+ * channels.
|
||||
+ *
|
||||
+ * The following driver implements the split mode.
|
||||
+ */
|
||||
+
|
||||
+#define AIU_I2S_DMA_BURST 256
|
||||
+
|
||||
+static struct snd_pcm_hardware aiu_i2s_dma_hw = {
|
||||
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID |
|
||||
+ SNDRV_PCM_INFO_PAUSE),
|
||||
+
|
||||
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE),
|
||||
+
|
||||
+ /*
|
||||
+ * TODO: The DMA can change the endianness, the msb position
|
||||
+ * and deal with unsigned - support this later on
|
||||
+ */
|
||||
+
|
||||
+ .rate_min = 8000,
|
||||
+ .rate_max = 192000,
|
||||
+ .channels_min = 2,
|
||||
+ .channels_max = 8,
|
||||
+ .period_bytes_min = AIU_I2S_DMA_BURST,
|
||||
+ .period_bytes_max = AIU_I2S_DMA_BURST * 65535,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = UINT_MAX,
|
||||
+ .buffer_bytes_max = 1 * 1024 * 1024,
|
||||
+ .fifo_size = 0,
|
||||
+};
|
||||
+
|
||||
+static struct aiu_i2s_dma *aiu_i2s_dma_priv(struct snd_pcm_substream *s)
|
||||
+{
|
||||
+ struct snd_soc_pcm_runtime *rtd = s->private_data;
|
||||
+
|
||||
+ return snd_soc_platform_get_drvdata(rtd->platform);
|
||||
+}
|
||||
+
|
||||
+static snd_pcm_uframes_t
|
||||
+aiu_i2s_dma_pointer(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ unsigned int addr;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR,
|
||||
+ &addr);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr);
|
||||
+}
|
||||
+
|
||||
+static void __dma_enable(struct aiu_i2s_dma *priv, bool enable)
|
||||
+{
|
||||
+ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN |
|
||||
+ AIU_MEM_I2S_CONTROL_EMPTY_EN);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask,
|
||||
+ enable ? en_mask : 0);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case SNDRV_PCM_TRIGGER_START:
|
||||
+ case SNDRV_PCM_TRIGGER_RESUME:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
+ __dma_enable(priv, true);
|
||||
+ break;
|
||||
+ case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
+ case SNDRV_PCM_TRIGGER_STOP:
|
||||
+ __dma_enable(priv, false);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __dma_init_mem(struct aiu_i2s_dma *priv)
|
||||
+{
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_INIT,
|
||||
+ 0);
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL,
|
||||
+ AIU_MEM_I2S_BUF_CNTL_INIT,
|
||||
+ 0);
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_prepare(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ __dma_init_mem(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream,
|
||||
+ struct snd_pcm_hw_params *params)
|
||||
+{
|
||||
+ struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+ u32 burst_num, mem_ctl;
|
||||
+ dma_addr_t end_ptr;
|
||||
+
|
||||
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Setup memory layout */
|
||||
+ if (params_physical_width(params) == 16)
|
||||
+ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT;
|
||||
+ else
|
||||
+ mem_ctl = 0;
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL,
|
||||
+ AIU_MEM_I2S_CONTROL_MODE_16BIT,
|
||||
+ mem_ctl);
|
||||
+
|
||||
+ /* Initialize memory pointers */
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr);
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr);
|
||||
+
|
||||
+ /* The end pointer is the address of the last valid block */
|
||||
+ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr);
|
||||
+
|
||||
+ /* Memory masks */
|
||||
+ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST;
|
||||
+ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS,
|
||||
+ AIU_MEM_I2S_MASKS_CH_RD(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_CH_MEM(0xff) |
|
||||
+ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ return snd_pcm_lib_free_pages(substream);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static irqreturn_t aiu_i2s_dma_irq_block(int irq, void *dev_id)
|
||||
+{
|
||||
+ struct snd_pcm_substream *playback = dev_id;
|
||||
+
|
||||
+ snd_pcm_period_elapsed(playback);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_open(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+ int ret;
|
||||
+
|
||||
+ snd_soc_set_runtime_hwparams(substream, &aiu_i2s_dma_hw);
|
||||
+
|
||||
+ /*
|
||||
+ * Make sure the buffer and period size are multiple of the DMA burst
|
||||
+ * size
|
||||
+ */
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
||||
+ AIU_I2S_DMA_BURST);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Request the I2S DDR irq */
|
||||
+ ret = request_irq(priv->irq, aiu_i2s_dma_irq_block, 0,
|
||||
+ DRV_NAME, substream);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Power up the i2s fast domain - can't write the registers w/o it */
|
||||
+ ret = clk_prepare_enable(priv->fast);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Make sure the dma is initially disabled */
|
||||
+ __dma_enable(priv, false);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int aiu_i2s_dma_close(struct snd_pcm_substream *substream)
|
||||
+{
|
||||
+ struct aiu_i2s_dma *priv = aiu_i2s_dma_priv(substream);
|
||||
+
|
||||
+ clk_disable_unprepare(priv->fast);
|
||||
+ free_irq(priv->irq, substream);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct snd_pcm_ops aiu_i2s_dma_ops = {
|
||||
+ .open = aiu_i2s_dma_open,
|
||||
+ .close = aiu_i2s_dma_close,
|
||||
+ .ioctl = snd_pcm_lib_ioctl,
|
||||
+ .hw_params = aiu_i2s_dma_hw_params,
|
||||
+ .hw_free = aiu_i2s_dma_hw_free,
|
||||
+ .prepare = aiu_i2s_dma_prepare,
|
||||
+ .pointer = aiu_i2s_dma_pointer,
|
||||
+ .trigger = aiu_i2s_dma_trigger,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ struct snd_card *card = rtd->card->snd_card;
|
||||
+ size_t size = aiu_i2s_dma_hw.buffer_bytes_max;
|
||||
+
|
||||
+ return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
|
||||
+ SNDRV_DMA_TYPE_DEV,
|
||||
+ card->dev, size, size);
|
||||
+}
|
||||
+
|
||||
+struct snd_soc_platform_driver aiu_i2s_platform = {
|
||||
+ .ops = &aiu_i2s_dma_ops,
|
||||
+ .pcm_new = aiu_i2s_dma_new,
|
||||
+};
|
||||
+
|
||||
+static int aiu_i2s_dma_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct aiu_i2s_dma *priv;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ priv->core = dev_get_drvdata(dev->parent);
|
||||
+
|
||||
+ priv->fast = devm_clk_get(dev, "fast");
|
||||
+ if (IS_ERR(priv->fast)) {
|
||||
+ if (PTR_ERR(priv->fast) != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "Can't get i2s fast domain clock\n");
|
||||
+ return PTR_ERR(priv->fast);
|
||||
+ }
|
||||
+
|
||||
+ priv->irq = platform_get_irq(pdev, 0);
|
||||
+ if (priv->irq <= 0) {
|
||||
+ dev_err(dev, "Can't get i2s ddr irq\n");
|
||||
+ return priv->irq;
|
||||
+ }
|
||||
+
|
||||
+ return snd_soc_register_platform(dev, &aiu_i2s_platform);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id aiu_i2s_dma_of_match[] = {
|
||||
+ { .compatible = "amlogic,meson-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxbb-aiu-i2s-dma", },
|
||||
+ { .compatible = "amlogic,meson-gxl-aiu-i2s-dma", },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, aiu_i2s_dma_of_match);
|
||||
+
|
||||
+static struct platform_driver aiu_i2s_dma_pdrv = {
|
||||
+ .probe = aiu_i2s_dma_probe,
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .of_match_table = aiu_i2s_dma_of_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(aiu_i2s_dma_pdrv);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Meson AIU i2s DMA ASoC Driver");
|
||||
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 = <&>;
|
||||
+ 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,462 @@
|
|||
From ae5671893c76164ddbc7b9b0f6ea4361a121090f Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 20 Mar 2017 16:48:17 +0100
|
||||
Subject: [PATCH 50/79] clk: add support for clock protection
|
||||
|
||||
The patch adds clk_protect and clk_unprotect to the CCF API. These
|
||||
functions allow a consumer to inform the system that the rate of clock is
|
||||
critical to for its operations and it can't tolerate other consumers
|
||||
changing the rate or introducing glitches while the clock is protected.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 205 +++++++++++++++++++++++++++++++++++++++++--
|
||||
include/linux/clk-provider.h | 1 +
|
||||
include/linux/clk.h | 29 ++++++
|
||||
3 files changed, 229 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 163cb98..d688b8f 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -60,6 +60,7 @@ struct clk_core {
|
||||
bool orphan;
|
||||
unsigned int enable_count;
|
||||
unsigned int prepare_count;
|
||||
+ unsigned int protect_count;
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
unsigned long accuracy;
|
||||
@@ -84,6 +85,7 @@ struct clk {
|
||||
const char *con_id;
|
||||
unsigned long min_rate;
|
||||
unsigned long max_rate;
|
||||
+ unsigned long protect_count;
|
||||
struct hlist_node clks_node;
|
||||
};
|
||||
|
||||
@@ -148,6 +150,11 @@ static void clk_enable_unlock(unsigned long flags)
|
||||
spin_unlock_irqrestore(&enable_lock, flags);
|
||||
}
|
||||
|
||||
+static bool clk_core_rate_is_protected(struct clk_core *core)
|
||||
+{
|
||||
+ return core->protect_count;
|
||||
+}
|
||||
+
|
||||
static bool clk_core_is_prepared(struct clk_core *core)
|
||||
{
|
||||
/*
|
||||
@@ -328,6 +335,11 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
|
||||
return clk_core_is_prepared(hw->core);
|
||||
}
|
||||
|
||||
+bool clk_hw_rate_is_protected(const struct clk_hw *hw)
|
||||
+{
|
||||
+ return clk_core_rate_is_protected(hw->core);
|
||||
+}
|
||||
+
|
||||
bool clk_hw_is_enabled(const struct clk_hw *hw)
|
||||
{
|
||||
return clk_core_is_enabled(hw->core);
|
||||
@@ -466,6 +478,102 @@ int __clk_mux_determine_rate_closest(struct clk_hw *hw,
|
||||
|
||||
/*** clk api ***/
|
||||
|
||||
+static void clk_core_rate_unprotect(struct clk_core *core)
|
||||
+{
|
||||
+ lockdep_assert_held(&prepare_lock);
|
||||
+
|
||||
+ if (!core)
|
||||
+ return;
|
||||
+
|
||||
+ if (WARN_ON(core->protect_count == 0))
|
||||
+ return;
|
||||
+
|
||||
+ if (--core->protect_count > 0)
|
||||
+ return;
|
||||
+
|
||||
+ clk_core_rate_unprotect(core->parent);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * clk_rate_unprotect - unprotect the rate of a clock source
|
||||
+ * @clk: the clk being unprotected
|
||||
+ *
|
||||
+ * clk_unprotect completes a critical section during which the clock
|
||||
+ * consumer cannot tolerate any change to the clock rate. If no other clock
|
||||
+ * consumers have protected clocks in the parent chain, then calls to this
|
||||
+ * function will allow the clocks in the parent chain to change rates
|
||||
+ * freely.
|
||||
+ *
|
||||
+ * Unlike the clk_set_rate_range method, which allows the rate to change
|
||||
+ * within a given range, protected clocks cannot have their rate changed,
|
||||
+ * either directly or indirectly due to changes further up the parent chain
|
||||
+ * of clocks.
|
||||
+ *
|
||||
+ * Calls to clk_unprotect must be balanced with calls to clk_protect. Calls
|
||||
+ * to this function may sleep, and do not return error status.
|
||||
+ */
|
||||
+void clk_rate_unprotect(struct clk *clk)
|
||||
+{
|
||||
+ if (!clk)
|
||||
+ return;
|
||||
+
|
||||
+ clk_prepare_lock();
|
||||
+
|
||||
+ /*
|
||||
+ * if there is something wrong with this consumer protect count, stop
|
||||
+ * here before messing with the provider
|
||||
+ */
|
||||
+ if (WARN_ON(clk->protect_count <= 0))
|
||||
+ goto out;
|
||||
+
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+ clk->protect_count--;
|
||||
+out:
|
||||
+ clk_prepare_unlock();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_rate_unprotect);
|
||||
+
|
||||
+static void clk_core_rate_protect(struct clk_core *core)
|
||||
+{
|
||||
+ lockdep_assert_held(&prepare_lock);
|
||||
+
|
||||
+ if (!core)
|
||||
+ return;
|
||||
+
|
||||
+ if (core->protect_count == 0)
|
||||
+ clk_core_rate_protect(core->parent);
|
||||
+
|
||||
+ core->protect_count++;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * clk_rate_protect - protect a clock source
|
||||
+ * @clk: the clk being protected
|
||||
+ *
|
||||
+ * clk_protect begins a critical section during which the clock consumer
|
||||
+ * cannot tolerate any change to the clock rate. This results in all clocks
|
||||
+ * up the parent chain to also be rate-protected.
|
||||
+ *
|
||||
+ * Unlike the clk_set_rate_range method, which allows the rate to change
|
||||
+ * within a given range, protected clocks cannot have their rate changed,
|
||||
+ * either directly or indirectly due to changes further up the parent chain
|
||||
+ * of clocks.
|
||||
+ *
|
||||
+ * Calls to clk_protect should be balanced with calls to clk_unprotect.
|
||||
+ * Calls to this function may sleep, and do not return error status.
|
||||
+ */
|
||||
+void clk_rate_protect(struct clk *clk)
|
||||
+{
|
||||
+ if (!clk)
|
||||
+ return;
|
||||
+
|
||||
+ clk_prepare_lock();
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+ clk->protect_count++;
|
||||
+ clk_prepare_unlock();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_rate_protect);
|
||||
+
|
||||
static void clk_core_unprepare(struct clk_core *core)
|
||||
{
|
||||
lockdep_assert_held(&prepare_lock);
|
||||
@@ -838,7 +946,15 @@ static int clk_core_determine_round(struct clk_core *core,
|
||||
{
|
||||
long rate;
|
||||
|
||||
- if (core->ops->determine_rate) {
|
||||
+ /*
|
||||
+ * At this point, core protection will be disabled if
|
||||
+ * - if the provider is not protected at all
|
||||
+ * - if the calling consumer is the only one protecting the
|
||||
+ * provider (and only once)
|
||||
+ */
|
||||
+ if (clk_core_rate_is_protected(core)) {
|
||||
+ req->rate = core->rate;
|
||||
+ } else 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,
|
||||
@@ -944,10 +1060,17 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
|
||||
req.rate = rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(clk->core, &req);
|
||||
+
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
clk_prepare_unlock();
|
||||
|
||||
if (ret)
|
||||
@@ -1575,15 +1698,24 @@ static unsigned long clk_core_req_round_rate_nolock(struct clk_core *core,
|
||||
{
|
||||
int ret;
|
||||
struct clk_rate_request req;
|
||||
+ unsigned int cnt = core->protect_count;
|
||||
|
||||
if (!core)
|
||||
return 0;
|
||||
|
||||
+ /* simulate what the rate would be if it could be freely set */
|
||||
+ while (core->protect_count)
|
||||
+ clk_core_rate_unprotect(core);
|
||||
+
|
||||
clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
|
||||
req.rate = req_rate;
|
||||
|
||||
ret = clk_core_round_rate_nolock(core, &req);
|
||||
|
||||
+ /* restore the protection */
|
||||
+ while (core->protect_count < cnt)
|
||||
+ clk_core_rate_protect(core);
|
||||
+
|
||||
return ret ? 0 : req.rate;
|
||||
}
|
||||
|
||||
@@ -1602,6 +1734,10 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
if (rate == clk_core_get_rate_nolock(core))
|
||||
return 0;
|
||||
|
||||
+ /* fail on a direct rate set of a protected provider */
|
||||
+ if (clk_core_rate_is_protected(core))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
|
||||
return -EBUSY;
|
||||
|
||||
@@ -1658,8 +1794,14 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
/* prevent racing with updates to the clock topology */
|
||||
clk_prepare_lock();
|
||||
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
ret = clk_core_set_rate_nolock(clk->core, rate);
|
||||
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -1690,12 +1832,18 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
if (min != clk->min_rate || max != clk->max_rate) {
|
||||
clk->min_rate = min;
|
||||
clk->max_rate = max;
|
||||
ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
|
||||
}
|
||||
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -1837,6 +1985,9 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
|
||||
if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
|
||||
return -EBUSY;
|
||||
|
||||
+ if (clk_core_rate_is_protected(core))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
/* try finding the new parent index */
|
||||
if (parent) {
|
||||
p_index = clk_fetch_parent_index(core, parent);
|
||||
@@ -1894,8 +2045,16 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
return 0;
|
||||
|
||||
clk_prepare_lock();
|
||||
+
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
ret = clk_core_set_parent_nolock(clk->core,
|
||||
parent ? parent->core : NULL);
|
||||
+
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -1909,6 +2068,9 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees)
|
||||
if (!core)
|
||||
return 0;
|
||||
|
||||
+ if (clk_core_rate_is_protected(core))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
trace_clk_set_phase(core, degrees);
|
||||
|
||||
if (core->ops->set_phase)
|
||||
@@ -1952,7 +2114,15 @@ int clk_set_phase(struct clk *clk, int degrees)
|
||||
degrees += 360;
|
||||
|
||||
clk_prepare_lock();
|
||||
+
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
ret = clk_core_set_phase_nolock(clk->core, degrees);
|
||||
+
|
||||
+ if (clk->protect_count)
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+
|
||||
clk_prepare_unlock();
|
||||
|
||||
return ret;
|
||||
@@ -2039,11 +2209,12 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
- seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
|
||||
+ seq_printf(s, "%*s%-*s %11d %12d %12d %11lu %10lu %-3d\n",
|
||||
level * 3 + 1, "",
|
||||
30 - level * 3, c->name,
|
||||
- c->enable_count, c->prepare_count, clk_core_get_rate(c),
|
||||
- clk_core_get_accuracy(c), clk_core_get_phase(c));
|
||||
+ c->enable_count, c->prepare_count, c->protect_count,
|
||||
+ clk_core_get_rate(c), clk_core_get_accuracy(c),
|
||||
+ clk_core_get_phase(c));
|
||||
}
|
||||
|
||||
static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
|
||||
@@ -2065,8 +2236,8 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = (struct hlist_head **)s->private;
|
||||
|
||||
- seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
|
||||
- seq_puts(s, "----------------------------------------------------------------------------------------\n");
|
||||
+ seq_puts(s, " clock enable_cnt prepare_cnt protect_cnt rate accuracy phase\n");
|
||||
+ seq_puts(s, "----------------------------------------------------------------------------------------------------\n");
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
@@ -2101,6 +2272,7 @@ static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
|
||||
seq_printf(s, "\"%s\": { ", c->name);
|
||||
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
|
||||
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
|
||||
+ seq_printf(s, "\"protect_count\": %d,", c->protect_count);
|
||||
seq_printf(s, "\"rate\": %lu,", clk_core_get_rate(c));
|
||||
seq_printf(s, "\"accuracy\": %lu,", clk_core_get_accuracy(c));
|
||||
seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
|
||||
@@ -2231,6 +2403,11 @@ static int clk_debug_create_one(struct clk_core *core, struct dentry *pdentry)
|
||||
if (!d)
|
||||
goto err_out;
|
||||
|
||||
+ d = debugfs_create_u32("clk_protect_count", S_IRUGO, core->dentry,
|
||||
+ (u32 *)&core->protect_count);
|
||||
+ if (!d)
|
||||
+ goto err_out;
|
||||
+
|
||||
d = debugfs_create_u32("clk_notifier_count", S_IRUGO, core->dentry,
|
||||
(u32 *)&core->notifier_count);
|
||||
if (!d)
|
||||
@@ -2794,6 +2971,11 @@ void clk_unregister(struct clk *clk)
|
||||
if (clk->core->prepare_count)
|
||||
pr_warn("%s: unregistering prepared clock: %s\n",
|
||||
__func__, clk->core->name);
|
||||
+
|
||||
+ if (clk->core->protect_count)
|
||||
+ pr_warn("%s: unregistering protected clock: %s\n",
|
||||
+ __func__, clk->core->name);
|
||||
+
|
||||
kref_put(&clk->core->ref, __clk_release);
|
||||
unlock:
|
||||
clk_prepare_unlock();
|
||||
@@ -2952,6 +3134,17 @@ void __clk_put(struct clk *clk)
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
+ /*
|
||||
+ * Before calling clk_put, all calls to clk_rate_protect from a given
|
||||
+ * user must be balanced with calls to clk_rate_unprotect and by that
|
||||
+ * same user
|
||||
+ */
|
||||
+ WARN_ON(clk->protect_count);
|
||||
+
|
||||
+ /* We voiced our concern, let's sanitize the situation */
|
||||
+ for (; clk->protect_count; clk->protect_count--)
|
||||
+ clk_core_rate_unprotect(clk->core);
|
||||
+
|
||||
hlist_del(&clk->clks_node);
|
||||
if (clk->min_rate > clk->core->req_rate ||
|
||||
clk->max_rate < clk->core->req_rate)
|
||||
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
|
||||
index a428aec..ebd7df5 100644
|
||||
--- a/include/linux/clk-provider.h
|
||||
+++ b/include/linux/clk-provider.h
|
||||
@@ -739,6 +739,7 @@ struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw,
|
||||
unsigned long __clk_get_flags(struct clk *clk);
|
||||
unsigned long clk_hw_get_flags(const struct clk_hw *hw);
|
||||
bool clk_hw_is_prepared(const struct clk_hw *hw);
|
||||
+bool clk_hw_rate_is_protected(const struct clk_hw *hw);
|
||||
bool clk_hw_is_enabled(const struct clk_hw *hw);
|
||||
bool __clk_is_enabled(struct clk *clk);
|
||||
struct clk *__clk_lookup(const char *name);
|
||||
diff --git a/include/linux/clk.h b/include/linux/clk.h
|
||||
index 024cd07..85d73e0 100644
|
||||
--- a/include/linux/clk.h
|
||||
+++ b/include/linux/clk.h
|
||||
@@ -265,6 +265,30 @@ static inline void clk_unprepare(struct clk *clk)
|
||||
*/
|
||||
struct clk *devm_get_clk_from_child(struct device *dev,
|
||||
struct device_node *np, const char *con_id);
|
||||
+/**
|
||||
+ * clk_rate_protect - inform the system when the clock rate must be protected.
|
||||
+ * @clk: clock source
|
||||
+ *
|
||||
+ * This function informs the system that the consumer protecting the clock
|
||||
+ * depends on the rate of the clock source and can't tolerate any glitches
|
||||
+ * introduced by further clock rate change or re-parenting of the clock source.
|
||||
+ *
|
||||
+ * Must not be called from within atomic context.
|
||||
+ */
|
||||
+void clk_rate_protect(struct clk *clk);
|
||||
+
|
||||
+/**
|
||||
+ * clk_rate_unprotect - release the protection of the clock source.
|
||||
+ * @clk: clock source
|
||||
+ *
|
||||
+ * This function informs the system that the consumer previously protecting the
|
||||
+ * clock rate can now deal with other consumer altering the clock source rate
|
||||
+ *
|
||||
+ * The caller must balance the number of rate_protect and rate_unprotect calls.
|
||||
+ *
|
||||
+ * Must not be called from within atomic context.
|
||||
+ */
|
||||
+void clk_rate_unprotect(struct clk *clk);
|
||||
|
||||
/**
|
||||
* clk_enable - inform the system when the clock source should be running.
|
||||
@@ -460,6 +484,11 @@ static inline void clk_put(struct clk *clk) {}
|
||||
|
||||
static inline void devm_clk_put(struct device *dev, struct clk *clk) {}
|
||||
|
||||
+
|
||||
+static inline void clk_protect(struct clk *clk) {}
|
||||
+
|
||||
+static inline void clk_unprotect(struct clk *clk) {}
|
||||
+
|
||||
static inline int clk_enable(struct clk *clk)
|
||||
{
|
||||
return 0;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
From 88cb11f99ca3a209274faa0da15ac27bcda99959 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 18 May 2017 13:42:12 +0200
|
||||
Subject: [PATCH 51/79] clk: add clk_set_rate_protect
|
||||
|
||||
clk_set_rate_protect is a combination of clk_set_rate and clk_rate_protect
|
||||
within a critical section. In case where several protecting consumers
|
||||
compete to set the rate of the same provider, it provides a way to make
|
||||
sure that at least one of them will be satisfied before the resource is
|
||||
locked.
|
||||
|
||||
This is to avoid the unlikely situation where several consumers protect a
|
||||
clock provider and none actually get a rate it can work with.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/clk.h | 14 ++++++++++++++
|
||||
2 files changed, 59 insertions(+)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index d688b8f..d91236e 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -1809,6 +1809,51 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
EXPORT_SYMBOL_GPL(clk_set_rate);
|
||||
|
||||
/**
|
||||
+ * clk_set_rate_protect - specify a new rate and protect it
|
||||
+ * @clk: the clk whose rate is being changed
|
||||
+ * @rate: the new rate for clk
|
||||
+ *
|
||||
+ * This is a combination of clk_set_rate and clk_rate_protect within
|
||||
+ * a critical section
|
||||
+ *
|
||||
+ * This can be used initially to ensure that at least 1 consumers is
|
||||
+ * statisfied when several protecting consummers are competing for the
|
||||
+ * same clock provider.
|
||||
+ *
|
||||
+ * The protection is not applied if setting the rate failed.
|
||||
+ *
|
||||
+ * Returns 0 on success, -EERROR otherwise.
|
||||
+ */
|
||||
+int clk_set_rate_protect(struct clk *clk, unsigned long rate)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!clk)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* prevent racing with updates to the clock topology */
|
||||
+ clk_prepare_lock();
|
||||
+
|
||||
+ /*
|
||||
+ * The temporary protection removal is not here, on purpose
|
||||
+ * This function is meant to be used in instead of clk_rate_protect,
|
||||
+ * so before the consumer code path protect the clock provider
|
||||
+ */
|
||||
+
|
||||
+ ret = clk_core_set_rate_nolock(clk->core, rate);
|
||||
+
|
||||
+ if (!ret) {
|
||||
+ clk_core_rate_protect(clk->core);
|
||||
+ clk->protect_count++;
|
||||
+ }
|
||||
+
|
||||
+ clk_prepare_unlock();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(clk_set_rate_protect);
|
||||
+
|
||||
+/**
|
||||
* clk_set_rate_range - set a rate range for a clock source
|
||||
* @clk: clock source
|
||||
* @min: desired minimum clock rate in Hz, inclusive
|
||||
diff --git a/include/linux/clk.h b/include/linux/clk.h
|
||||
index 85d73e0..d3c299d 100644
|
||||
--- a/include/linux/clk.h
|
||||
+++ b/include/linux/clk.h
|
||||
@@ -388,6 +388,15 @@ struct clk *devm_get_clk_from_child(struct device *dev,
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate);
|
||||
|
||||
/**
|
||||
+ * clk_set_rate_protect - set and protect the clock rate for a clock source
|
||||
+ * @clk: clock source
|
||||
+ * @rate: desired clock rate in Hz
|
||||
+ *
|
||||
+ * Returns success (0) or negative errno.
|
||||
+ */
|
||||
+int clk_set_rate_protect(struct clk *clk, unsigned long rate);
|
||||
+
|
||||
+/**
|
||||
* clk_has_parent - check if a clock is a possible parent for another
|
||||
* @clk: clock source
|
||||
* @parent: parent clock source
|
||||
@@ -506,6 +515,11 @@ static inline int clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static inline int clk_set_rate_protect(struct clk *clk, unsigned long rate)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline long clk_round_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
return 0;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From fe7933da09cfadd75af72256a1d11f41ea5e46f0 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Mon, 20 Mar 2017 15:02:19 +0100
|
||||
Subject: [PATCH 52/79] clk: rollback set_rate_range changes on failure
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index d91236e..253f1d3 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -1864,6 +1864,7 @@ int clk_set_rate_protect(struct clk *clk, unsigned long rate)
|
||||
int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
{
|
||||
int ret = 0;
|
||||
+ unsigned int old_min, old_max;
|
||||
|
||||
if (!clk)
|
||||
return 0;
|
||||
@@ -1881,9 +1882,16 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
|
||||
clk_core_rate_unprotect(clk->core);
|
||||
|
||||
if (min != clk->min_rate || max != clk->max_rate) {
|
||||
+ old_min = clk->min_rate;
|
||||
+ old_max = clk->max_rate;
|
||||
clk->min_rate = min;
|
||||
clk->max_rate = max;
|
||||
ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
|
||||
+ if (ret) {
|
||||
+ /* undo changes */
|
||||
+ clk->min_rate = old_min;
|
||||
+ clk->max_rate = old_max;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (clk->protect_count)
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
From 29c6ab33e59640b8e09619be779091efc5953dc5 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 21 Mar 2017 19:24:35 +0100
|
||||
Subject: [PATCH 53/79] clk: cosmetic changes to clk_summary debugfs entry
|
||||
|
||||
clk_summary debugfs entry was already well over the traditional 80
|
||||
characters per line limit but it grew even larger with the addition of
|
||||
clock protection.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 253f1d3..8d57e13 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -2262,7 +2262,7 @@ static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
- seq_printf(s, "%*s%-*s %11d %12d %12d %11lu %10lu %-3d\n",
|
||||
+ seq_printf(s, "%*s%-*s %7d %8d %8d %11lu %10lu %-3d\n",
|
||||
level * 3 + 1, "",
|
||||
30 - level * 3, c->name,
|
||||
c->enable_count, c->prepare_count, c->protect_count,
|
||||
@@ -2289,8 +2289,9 @@ static int clk_summary_show(struct seq_file *s, void *data)
|
||||
struct clk_core *c;
|
||||
struct hlist_head **lists = (struct hlist_head **)s->private;
|
||||
|
||||
- seq_puts(s, " clock enable_cnt prepare_cnt protect_cnt rate accuracy phase\n");
|
||||
- seq_puts(s, "----------------------------------------------------------------------------------------------------\n");
|
||||
+ seq_puts(s, " enable prepare protect \n");
|
||||
+ seq_puts(s, " clock count count count rate accuracy phase\n");
|
||||
+ seq_puts(s, "----------------------------------------------------------------------------------------\n");
|
||||
|
||||
clk_prepare_lock();
|
||||
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 71696c295bdbc1624d6204c01070518cba0451b5 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Tue, 21 Mar 2017 16:03:55 +0100
|
||||
Subject: [PATCH 54/79] clk: fix incorrect usage of ENOSYS
|
||||
|
||||
ENOSYS is special and should only be used for incorrect syscall number.
|
||||
It does not seem to be the case here.
|
||||
|
||||
Reported by checkpatch.pl while working on clock protection.
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 8d57e13..5d54595 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -2032,7 +2032,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core,
|
||||
|
||||
/* verify ops for for multi-parent clks */
|
||||
if ((core->num_parents > 1) && (!core->ops->set_parent))
|
||||
- return -ENOSYS;
|
||||
+ return -EPERM;
|
||||
|
||||
/* check that we are allowed to re-parent if the clock is in use */
|
||||
if ((core->flags & CLK_SET_PARENT_GATE) && core->prepare_count)
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
From 62400daae8f31d68035f4c8e3ead19962b9ecde9 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 18 May 2017 15:36:38 +0200
|
||||
Subject: [PATCH 55/79] clk: fix CLK_SET_RATE_GATE with clock rate protection
|
||||
|
||||
Using clock rate protection, we can now enforce CLK_SET_RATE_GATE along the
|
||||
clock tree
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
drivers/clk/clk.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
|
||||
index 5d54595..971f39d 100644
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -587,6 +587,9 @@ static void clk_core_unprepare(struct clk_core *core)
|
||||
if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL))
|
||||
return;
|
||||
|
||||
+ if (core->flags & CLK_SET_RATE_GATE)
|
||||
+ clk_core_rate_unprotect(core);
|
||||
+
|
||||
if (--core->prepare_count > 0)
|
||||
return;
|
||||
|
||||
@@ -657,6 +660,14 @@ static int clk_core_prepare(struct clk_core *core)
|
||||
|
||||
core->prepare_count++;
|
||||
|
||||
+ /*
|
||||
+ * CLK_SET_RATE_GATE is a special case of clock protection
|
||||
+ * Instead of a consumer protection, the provider is protecting
|
||||
+ * itself when prepared
|
||||
+ */
|
||||
+ if (core->flags & CLK_SET_RATE_GATE)
|
||||
+ clk_core_rate_protect(core);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1738,9 +1749,6 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
if (clk_core_rate_is_protected(core))
|
||||
return -EBUSY;
|
||||
|
||||
- if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
|
||||
- return -EBUSY;
|
||||
-
|
||||
/* calculate new rates and get the topmost changed clock */
|
||||
top = clk_calc_new_rates(core, req_rate);
|
||||
if (!top)
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
From 73fcf1ce438f0952253ceee84e8a99510332a064 Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Thu, 23 Mar 2017 12:00:17 +0100
|
||||
Subject: [PATCH 56/79] ASoC: meson: protect dai output clock rates
|
||||
|
||||
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/i2s-dai.c | 4 ++++
|
||||
sound/soc/meson/spdif-dai.c | 4 ++++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
index 1008af8..d698aa0 100644
|
||||
--- a/sound/soc/meson/i2s-dai.c
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -351,6 +351,9 @@ static int meson_i2s_dai_startup(struct snd_pcm_substream *substream,
|
||||
AIU_I2S_SOURCE_DESC_MODE_SPLIT,
|
||||
AIU_I2S_SOURCE_DESC_MODE_SPLIT);
|
||||
|
||||
+ /* We can't tolerate glitches or rate change on this clock */
|
||||
+ clk_rate_protect(priv->mclk);
|
||||
+
|
||||
return 0;
|
||||
|
||||
out_bclks:
|
||||
@@ -368,6 +371,7 @@ static void meson_i2s_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct meson_i2s_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
+ clk_rate_unprotect(priv->mclk);
|
||||
clk_disable_unprepare(priv->bclks);
|
||||
clk_disable_unprepare(priv->mclk);
|
||||
clk_disable_unprepare(priv->iface);
|
||||
diff --git a/sound/soc/meson/spdif-dai.c b/sound/soc/meson/spdif-dai.c
|
||||
index e763000..1d27f19 100644
|
||||
--- a/sound/soc/meson/spdif-dai.c
|
||||
+++ b/sound/soc/meson/spdif-dai.c
|
||||
@@ -253,6 +253,9 @@ static int meson_spdif_dai_startup(struct snd_pcm_substream *substream,
|
||||
AIU_MEM_IEC958_CONTROL_MODE_LINEAR,
|
||||
AIU_MEM_IEC958_CONTROL_MODE_LINEAR);
|
||||
|
||||
+ /* We can't tolerate glitches or rate change on this clock */
|
||||
+ clk_rate_protect(priv->mclk);
|
||||
+
|
||||
return 0;
|
||||
|
||||
out_mclk:
|
||||
@@ -268,6 +271,7 @@ static void meson_spdif_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct meson_spdif_dai *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
+ clk_rate_unprotect(priv->mclk);
|
||||
clk_disable_unprepare(priv->iface);
|
||||
clk_disable_unprepare(priv->mclk);
|
||||
clk_disable_unprepare(priv->fast);
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
From a1619e301a0bdc1c90d505c740aeada54d229eaf Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:38:21 +0200
|
||||
Subject: [PATCH 57/79] snd: meson: add hdmi control bits
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/i2s-dai.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
index d698aa0..271bc14 100644
|
||||
--- a/sound/soc/meson/i2s-dai.c
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -56,8 +56,19 @@ struct meson_i2s_dai {
|
||||
#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0)
|
||||
#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6)
|
||||
+#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0)
|
||||
#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4)
|
||||
+#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4)
|
||||
#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0)
|
||||
#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0)
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
From 967a58cb6eeb223553058ea15083d755df70b5ec Mon Sep 17 00:00:00 2001
|
||||
From: Jerome Brunet <jbrunet@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:39:21 +0200
|
||||
Subject: [PATCH 58/79] snd: meson: activate HDMI audio path
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
sound/soc/meson/i2s-dai.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/sound/soc/meson/i2s-dai.c b/sound/soc/meson/i2s-dai.c
|
||||
index 271bc14..85a5023 100644
|
||||
--- a/sound/soc/meson/i2s-dai.c
|
||||
+++ b/sound/soc/meson/i2s-dai.c
|
||||
@@ -232,6 +232,17 @@ static int meson_i2s_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /* Quick and dirty hack for HDMI */
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK,
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S |
|
||||
+ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S);
|
||||
+
|
||||
+ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK,
|
||||
+ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
From 47ca3bb9f820024cc182e0f46db659e59e3f6318 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:47:31 +0200
|
||||
Subject: [PATCH 59/79] ARM64: dts: meson-gx: Switch p20x and p230 to HDMI
|
||||
output only
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi | 47 +---------------------
|
||||
.../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 25 ++++++------
|
||||
2 files changed, 14 insertions(+), 58 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
index 88e3713..4ff313a 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
|
||||
@@ -153,31 +153,10 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
- amp: analog-amplifier {
|
||||
- compatible = "dioo,dio2125";
|
||||
- enable-gpios = <&gpio GPIOH_3 0>;
|
||||
- status = "okay";
|
||||
- };
|
||||
-
|
||||
- spdif_out: spdif-out {
|
||||
- #sound-dai-cells = <0>;
|
||||
- compatible = "linux,spdif-dit";
|
||||
- status = "okay";
|
||||
- };
|
||||
-
|
||||
soc {
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "meson-gxbb-p20x";
|
||||
- simple-audio-card,aux-devs = <&>;
|
||||
- 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 {
|
||||
@@ -196,21 +175,7 @@
|
||||
};
|
||||
|
||||
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>;
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -352,19 +317,9 @@
|
||||
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";
|
||||
-};
|
||||
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 5da5206..f95978c 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
|
||||
@@ -85,28 +85,28 @@
|
||||
regulator-max-microvolt = <1800000>;
|
||||
};
|
||||
|
||||
- spdif_out: spdif-out {
|
||||
- #sound-dai-cells = <0>;
|
||||
- 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 {
|
||||
+ /* RCA Output */
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
plat {
|
||||
- sound-dai = <&aiu_spdif_dma>;
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
};
|
||||
|
||||
cpu {
|
||||
- sound-dai = <&spdif_dai>;
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
};
|
||||
|
||||
codec {
|
||||
- sound-dai = <&spdif_out>;
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -156,12 +156,13 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
-&aiu_spdif_dma {
|
||||
+&aiu_i2s_dma {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
-&spdif_dai {
|
||||
- pinctrl-0 = <&spdif_out_h_pins>;
|
||||
+&i2s_dai {
|
||||
+ pinctrl-0 = <&i2s_am_clk_pins>, <&i2s_out_ao_clk_pins>,
|
||||
+ <&i2s_out_lr_clk_pins>, <&i2s_out_ch01_pins>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
From 2836b35f50d8027974c9fc9d258911243f4815e9 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:47:47 +0200
|
||||
Subject: [PATCH 60/79] ARM64: dts: meson-gxbb-odroic2: Add HDMI audio output
|
||||
nodes
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 42 ++++++++++++++++++++++
|
||||
1 file changed, 42 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 0066b1a..6c09bf7 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -146,6 +146,33 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ soc {
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gxbb-odroidc2";
|
||||
+ status = "okay";
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&scpi_clocks {
|
||||
@@ -332,3 +359,18 @@
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_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";
|
||||
+};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
From 48620a0b478fbf467f86b7bf019e6a53a8eed08e Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 17:49:19 +0200
|
||||
Subject: [PATCH 61/79] ARM64: dts: meson: add sound-dai-cells to HDMI node
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 +
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 3 ++-
|
||||
2 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index 92d2b91..dc0eb44 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -710,4 +710,5 @@
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
clock-names = "isfr", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index de0a26b..1e65b0f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -660,5 +660,6 @@
|
||||
clocks = <&clkc CLKID_HDMI_PCLK>,
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_GCLK_VENCI_INT0>;
|
||||
- clock-names = "isfr", "iahb", "venci";
|
||||
+ clock-names = "isfr", "iahb", "venci", "iahb", "venci";
|
||||
+ #sound-dai-cells = <0>;
|
||||
};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
From b2e9388561f99c5ac8abc8de8b282f755fa43376 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Fri, 7 Jul 2017 18:08:36 +0200
|
||||
Subject: [PATCH 65/79] Add CEC support for Odroid-C2
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index 6c09bf7..b4f21d1 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -348,6 +348,13 @@
|
||||
vqmmc-supply = <&vcc1v8>;
|
||||
};
|
||||
|
||||
+&cec_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&ao_cec_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-phandle = <&hdmi_tx>;
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
From 13df956e16be2e1a645f01ba589c4a9af25fc5cf Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 8 Jun 2017 17:21:44 +0200
|
||||
Subject: [PATCH 67/79] ARM64: dts: meson-gxl-s905d-p230: Add HDMI nodes
|
||||
|
||||
Add HDMI nodes for the Amlogic P230 board.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gxl-s905d-p230.dts | 24 ++++++++++++++++++++++
|
||||
1 file changed, 24 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 f95978c..5aed4e6 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts
|
||||
@@ -111,6 +111,17 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ hdmi-connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_connector_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -147,6 +158,19 @@
|
||||
};
|
||||
};
|
||||
|
||||
+
|
||||
+&hdmi_tx {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx_tmds_port {
|
||||
+ hdmi_tx_tmds_out: endpoint {
|
||||
+ remote-endpoint = <&hdmi_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&saradc {
|
||||
status = "okay";
|
||||
vref-supply = <&vddio_ao18>;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
From 4fc4090651c1d5450283935e4b0e674bd36abeb7 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 8 Jun 2017 17:23:46 +0200
|
||||
Subject: [PATCH 69/79] ARM64: dts: meson-gxl-s905x-p212: Add HDMI and CVBS
|
||||
nodes
|
||||
|
||||
Add HDMI and CVBS nodes for the Amlogic P212 reference board.
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 23 ++++++++++++++++++++++
|
||||
1 file changed, 23 insertions(+)
|
||||
|
||||
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 99a01ff..6e2bf85 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts
|
||||
@@ -58,6 +58,17 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
+
|
||||
+ hdmi-connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_connector_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_tx_tmds_out>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
};
|
||||
|
||||
&cec_AO {
|
||||
@@ -73,6 +84,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&hdmi_tx {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+};
|
||||
+
|
||||
+&hdmi_tx_tmds_port {
|
||||
+ hdmi_tx_tmds_out: endpoint {
|
||||
+ remote-endpoint = <&hdmi_connector_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
/* This UART is brought out to the DB9 connector */
|
||||
&uart_AO {
|
||||
status = "okay";
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
From 41c79ce5a32601b5853f97a0186fbc2406d14f06 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Mon, 10 Jul 2017 12:24:14 +0200
|
||||
Subject: [PATCH 70/79] ARM64: dts: meson-gx: Add CEC support for Wetek Play2
|
||||
and Khadas Vim
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts | 6 ++++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 7 +++++++
|
||||
2 files changed, 13 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
|
||||
index e76ac31..f7144fd 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts
|
||||
@@ -108,6 +108,12 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&cec_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&ao_cec_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-phandle = <&hdmi_tx>;
|
||||
+};
|
||||
|
||||
&cvbs_vdac_port {
|
||||
cvbs_vdac_out: endpoint {
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
index a133ed8..da12721 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts
|
||||
@@ -67,6 +67,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&cec_AO {
|
||||
+ status = "okay";
|
||||
+ pinctrl-0 = <&ao_cec_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ hdmi-phandle = <&hdmi_tx>;
|
||||
+};
|
||||
+
|
||||
&hdmi_tx {
|
||||
status = "okay";
|
||||
pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
From 40979f4df1a3bbe110b3fe2ace1524dc559ad4e8 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Thu, 12 Jan 2017 01:38:26 +0100
|
||||
Subject: [PATCH 71/79] ARM64: dts: meson-gxbb: allow child devices on the USB
|
||||
controller
|
||||
|
||||
Add the size and adress cells to the USB controllers to allow specifying
|
||||
child devices (for example the USB hub on the Odroid-C2 which must be
|
||||
taken out of reset to work).
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
index dc0eb44..912c4dc 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
|
||||
@@ -73,6 +73,8 @@
|
||||
|
||||
usb0: usb@c9000000 {
|
||||
compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x0 0xc9000000 0x0 0x40000>;
|
||||
interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc CLKID_USB0_DDR_BRIDGE>;
|
||||
@@ -85,6 +87,8 @@
|
||||
|
||||
usb1: usb@c9100000 {
|
||||
compatible = "amlogic,meson-gxbb-usb", "snps,dwc2";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
reg = <0x0 0xc9100000 0x0 0x40000>;
|
||||
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clkc CLKID_USB1_DDR_BRIDGE>;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
From ce69e6bd727706aacc7fd5fa3d79b92c552fad79 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Thu, 12 Jan 2017 01:39:20 +0100
|
||||
Subject: [PATCH 72/79] ARM64: dts: meson-gxbb-odroidc2: take USB hub out of
|
||||
reset
|
||||
|
||||
This takes the USB hub out of reset, otherwise the hub is not working.
|
||||
|
||||
Fixes: 5a0803bd5ae ("ARM64: dts: meson-gxbb-odroidc2: Enable USB Nodes")
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
index b4f21d1..e5e5300 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts
|
||||
@@ -303,6 +303,13 @@
|
||||
|
||||
&usb1 {
|
||||
status = "okay";
|
||||
+
|
||||
+ hub@1 {
|
||||
+ compatible = "usb5e3,610";
|
||||
+ reg = <1>;
|
||||
+ reset-gpios = <&gpio GPIOAO_4 GPIO_ACTIVE_LOW>;
|
||||
+ reset-duration-us = <3000>;
|
||||
+ };
|
||||
};
|
||||
|
||||
&saradc {
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
From 6006726ba262f50d61f3a001cc87fbc82dd8318a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sun, 20 Nov 2016 00:23:52 +0100
|
||||
Subject: [PATCH 73/79] ARM64: dts: meson-gxl: add USB host support
|
||||
|
||||
This adds USB host support to the Meson GXL SoC. A dwc3 controller is
|
||||
used for host-mode, while a dwc2 controller is used for device-mode only.
|
||||
The dwc3 controller's internal roothub has two USB2 ports enabled but no
|
||||
USB3 port. Each of the ports is supplied by a separate PHY. The USB pins
|
||||
are connected to the SoC's USBHOST_A and USBOTG_B pins.
|
||||
Due to the way the roothub works internally the USB PHYs are left
|
||||
enabled. When the dwc3 controller is disabled the PHY is never powered on
|
||||
so it does not draw any extra power. However, when the dwc3 host
|
||||
controller is enabled then all PHYs also have to be enabled, otherwise
|
||||
USB devices will not be detected (regardless of whether they are plugged
|
||||
into an enabled port or not). This means that only the dwc3 controller
|
||||
has to be enabled on boards with USB support (instead of requiring all
|
||||
boards to enable the PHYs additionally with the chance of forgetting to
|
||||
enable one and breaking all other ports with that as well).
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 50 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 50 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
index 1e65b0f..c33c29f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
|
||||
@@ -49,6 +49,56 @@
|
||||
|
||||
/ {
|
||||
compatible = "amlogic,meson-gxl";
|
||||
+
|
||||
+ soc {
|
||||
+
|
||||
+ usb0: usb@c9000000 {
|
||||
+ compatible = "snps,dwc3";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reg = <0x0 0xc9000000 0x0 0x100000>;
|
||||
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ dr_mode = "host";
|
||||
+ maximum-speed = "high-speed";
|
||||
+ snps,dis_u2_susphy_quirk;
|
||||
+ status = "disabled";
|
||||
+
|
||||
+ dwc3_roothub: roothub@0 {
|
||||
+ compatible = "usb1d6b,3", "usb1d6b,2";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reg = <0>;
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ phys = <&usb2_phy0>;
|
||||
+ phy-names = "usb2-phy";
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ phys = <&usb2_phy1>;
|
||||
+ phy-names = "usb2-phy";
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&apb {
|
||||
+ usb2_phy0: phy@78000 {
|
||||
+ compatible = "amlogic,meson-gxl-usb2-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0x0 0x78000 0x0 0x20>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+
|
||||
+ usb2_phy1: phy@78020 {
|
||||
+ compatible = "amlogic,meson-gxl-usb2-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0x0 0x78020 0x0 0x20>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
};
|
||||
|
||||
ðmac {
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
From c6b2bca6dbd55fbdd2c5cdf3d214c982a215e6a7 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Sat, 26 Nov 2016 00:17:22 +0100
|
||||
Subject: [PATCH 74/79] ARM64: dts: meson-gxm: add GXM specific USB host
|
||||
configuration
|
||||
|
||||
The USB configuration on GXM is slightly different than on GXL. The dwc3
|
||||
controller's internal hub has three USB2 ports (instead of 2 on GXL)
|
||||
along with a dedicated USB2 PHY for this port. However, it seems that
|
||||
there are no pins on GXM which would allow connecting the third port to
|
||||
a physical USB port.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 17 +++++++++++++++++
|
||||
1 file changed, 17 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
index fe451cc..4089f04 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
|
||||
@@ -117,6 +117,23 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&apb {
|
||||
+ usb2_phy2: phy@78040 {
|
||||
+ compatible = "amlogic,meson-gxl-usb2-phy";
|
||||
+ #phy-cells = <0>;
|
||||
+ reg = <0x0 0x78040 0x0 0x20>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&dwc3_roothub {
|
||||
+ port@3 {
|
||||
+ reg = <3>;
|
||||
+ phys = <&usb2_phy2>;
|
||||
+ phy-names = "usb2-phy";
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
&saradc {
|
||||
compatible = "amlogic,meson-gxm-saradc", "amlogic,meson-saradc";
|
||||
};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,293 @@
|
|||
From acfe799c4e00a726cdb0bbd37aaaa123070ed59e Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Tue, 10 Jan 2017 18:59:43 +0100
|
||||
Subject: [PATCH 75/79] usb: host: add a generic platform USB roothub driver
|
||||
|
||||
Many SoC platforms have separate devices for the USB PHY which are
|
||||
registered through the generic PHY framework. These PHYs have to be
|
||||
enabled to make the USB controller actually work. They also have to be
|
||||
disabled again on shutdown/suspend.
|
||||
|
||||
Currently (at least) the following HCI platform drivers are using custom
|
||||
code to obtain all PHYs via devicetree for the roothub/controller and
|
||||
disable/enable them when required:
|
||||
- ehci-platform.c has ehci_platform_power_{on,off}
|
||||
- xhci-mtk.c has xhci_mtk_phy_{init,exit,power_on,power_off}
|
||||
- ohci-platform.c has ohci_platform_power_{on,off}
|
||||
|
||||
These drivers are not using the generic devicetree USB device bindings
|
||||
yet which were only introduced recently (documentation is available in
|
||||
devicetree/bindings/usb/usb-device.txt).
|
||||
With this new driver the usb2-phy and usb3-phy can be specified directly
|
||||
in the child-node of the corresponding port of the roothub via
|
||||
devicetree. This can be extended by not just parsing PHYs (some of the
|
||||
other drivers listed above are for example also parsing a list of clocks
|
||||
as well) when required.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../devicetree/bindings/usb/usb-roothub.txt | 46 +++++++
|
||||
drivers/usb/host/Kconfig | 3 +
|
||||
drivers/usb/host/Makefile | 2 +
|
||||
drivers/usb/host/platform-roothub.c | 146 +++++++++++++++++++++
|
||||
drivers/usb/host/platform-roothub.h | 14 ++
|
||||
5 files changed, 211 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
create mode 100644 drivers/usb/host/platform-roothub.c
|
||||
create mode 100644 drivers/usb/host/platform-roothub.h
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/usb/usb-roothub.txt b/Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
new file mode 100644
|
||||
index 0000000..23b24b6
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-roothub.txt
|
||||
@@ -0,0 +1,46 @@
|
||||
+Generic USB root-hub Properties
|
||||
+
|
||||
+similar to the USB device bindings (documented in usb-device.txt from the
|
||||
+current directory) this provides support for configuring the root-hub.
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: should be at least one of "usb1d6b,3", "usb1d6b,2"
|
||||
+- reg: must be 0.
|
||||
+- address-cells: must be 1
|
||||
+- size-cells: must be 0
|
||||
+
|
||||
+Required sub-nodes:
|
||||
+a sub-node per actual USB port is required. each sub-node supports the
|
||||
+following properties:
|
||||
+ Required properties:
|
||||
+ - reg: the port number on the root-hub (mandatory)
|
||||
+ Optional properties:
|
||||
+ - phys: optional, from the *Generic PHY* bindings (mandatory needed
|
||||
+ when phy-names is given)
|
||||
+ - phy-names: optional, from the *Generic PHY* bindings; supported names
|
||||
+ are "usb2-phy" or "usb3-phy"
|
||||
+
|
||||
+Example:
|
||||
+ &usb1 {
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ roothub@0 {
|
||||
+ compatible = "usb1d6b,3", "usb1d6b,2";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+ reg = <0>;
|
||||
+
|
||||
+ port@1 {
|
||||
+ reg = <1>;
|
||||
+ usb-phy = <&usb2_phy1>, <&usb3_phy1>;
|
||||
+ phy-names = "usb2-phy", "usb3-phy";
|
||||
+ };
|
||||
+
|
||||
+ port@2 {
|
||||
+ reg = <2>;
|
||||
+ usb-phy = <&usb2_phy2>, <&usb3_phy2>;
|
||||
+ phy-names = "usb2-phy", "usb3-phy";
|
||||
+ };
|
||||
+ };
|
||||
+ }
|
||||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
|
||||
index ababb91..3f450e0 100644
|
||||
--- a/drivers/usb/host/Kconfig
|
||||
+++ b/drivers/usb/host/Kconfig
|
||||
@@ -797,6 +797,9 @@ config USB_HCD_SSB
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+config USB_PLATFORM_ROOTHUB
|
||||
+ bool
|
||||
+
|
||||
config USB_HCD_TEST_MODE
|
||||
bool "HCD test mode support"
|
||||
---help---
|
||||
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
|
||||
index c77b0a3..93f0dd2 100644
|
||||
--- a/drivers/usb/host/Makefile
|
||||
+++ b/drivers/usb/host/Makefile
|
||||
@@ -29,6 +29,8 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
obj-$(CONFIG_USB_PCI) += pci-quirks.o
|
||||
|
||||
+obj-$(CONFIG_USB_PLATFORM_ROOTHUB) += platform-roothub.o
|
||||
+
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
||||
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
|
||||
diff --git a/drivers/usb/host/platform-roothub.c b/drivers/usb/host/platform-roothub.c
|
||||
new file mode 100644
|
||||
index 0000000..84837e4
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/host/platform-roothub.c
|
||||
@@ -0,0 +1,146 @@
|
||||
+/*
|
||||
+ * platform roothub driver - a virtual PHY device which passes all phy_*
|
||||
+ * function calls to multiple (actual) PHY devices. This is comes handy when
|
||||
+ * initializing all PHYs on a root-hub (to keep them all in the same state).
|
||||
+ *
|
||||
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ * 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/device.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/usb/of.h>
|
||||
+
|
||||
+#include "platform-roothub.h"
|
||||
+
|
||||
+#define ROOTHUB_PORTNUM 0
|
||||
+
|
||||
+struct platform_roothub {
|
||||
+ struct phy *phy;
|
||||
+ struct list_head list;
|
||||
+};
|
||||
+
|
||||
+static struct platform_roothub *platform_roothub_alloc(struct device *dev)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+
|
||||
+ roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
|
||||
+ if (!roothub_entry)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ INIT_LIST_HEAD(&roothub_entry->list);
|
||||
+
|
||||
+ return roothub_entry;
|
||||
+}
|
||||
+
|
||||
+static int platform_roothub_add_phy(struct device *dev,
|
||||
+ struct device_node *port_np,
|
||||
+ const char *con_id, struct list_head *list)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+ struct phy *phy = devm_of_phy_get(dev, port_np, con_id);
|
||||
+
|
||||
+ if (IS_ERR_OR_NULL(phy)) {
|
||||
+ if (!phy || PTR_ERR(phy) == -ENODEV)
|
||||
+ return 0;
|
||||
+ else
|
||||
+ return PTR_ERR(phy);
|
||||
+ }
|
||||
+
|
||||
+ roothub_entry = platform_roothub_alloc(dev);
|
||||
+ if (IS_ERR(roothub_entry))
|
||||
+ return PTR_ERR(roothub_entry);
|
||||
+
|
||||
+ roothub_entry->phy = phy;
|
||||
+
|
||||
+ list_add_tail(&roothub_entry->list, list);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct platform_roothub *platform_roothub_init(struct device *dev)
|
||||
+{
|
||||
+ struct device_node *roothub_np, *port_np;
|
||||
+ struct platform_roothub *plat_roothub;
|
||||
+ int err;
|
||||
+
|
||||
+ roothub_np = usb_of_get_child_node(dev->of_node, ROOTHUB_PORTNUM);
|
||||
+ if (!of_device_is_available(roothub_np))
|
||||
+ return NULL;
|
||||
+
|
||||
+ plat_roothub = platform_roothub_alloc(dev);
|
||||
+ if (IS_ERR(plat_roothub))
|
||||
+ return plat_roothub;
|
||||
+
|
||||
+ for_each_available_child_of_node(roothub_np, port_np) {
|
||||
+ err = platform_roothub_add_phy(dev, port_np, "usb2-phy",
|
||||
+ &plat_roothub->list);
|
||||
+ if (err)
|
||||
+ return ERR_PTR(err);
|
||||
+
|
||||
+ err = platform_roothub_add_phy(dev, port_np, "usb3-phy",
|
||||
+ &plat_roothub->list);
|
||||
+ if (err)
|
||||
+ return ERR_PTR(err);
|
||||
+ }
|
||||
+
|
||||
+ return plat_roothub;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_init);
|
||||
+
|
||||
+int platform_roothub_power_on(struct platform_roothub *plat_roothub)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+ struct list_head *head;
|
||||
+ int err;
|
||||
+
|
||||
+ if (!plat_roothub)
|
||||
+ return 0;
|
||||
+
|
||||
+ head = &plat_roothub->list;
|
||||
+
|
||||
+ list_for_each_entry(roothub_entry, head, list) {
|
||||
+ err = phy_init(roothub_entry->phy);
|
||||
+ if (err)
|
||||
+ goto err_out;
|
||||
+
|
||||
+ err = phy_power_on(roothub_entry->phy);
|
||||
+ if (err) {
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ goto err_out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_out:
|
||||
+ list_for_each_entry_continue_reverse(roothub_entry, head, list) {
|
||||
+ phy_power_off(roothub_entry->phy);
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_power_on);
|
||||
+
|
||||
+void platform_roothub_power_off(struct platform_roothub *plat_roothub)
|
||||
+{
|
||||
+ struct platform_roothub *roothub_entry;
|
||||
+
|
||||
+ if (!plat_roothub)
|
||||
+ return;
|
||||
+
|
||||
+ list_for_each_entry_reverse(roothub_entry, &plat_roothub->list, list) {
|
||||
+ phy_power_off(roothub_entry->phy);
|
||||
+ phy_exit(roothub_entry->phy);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(platform_roothub_power_off);
|
||||
diff --git a/drivers/usb/host/platform-roothub.h b/drivers/usb/host/platform-roothub.h
|
||||
new file mode 100644
|
||||
index 0000000..bde0bf2
|
||||
--- /dev/null
|
||||
+++ b/drivers/usb/host/platform-roothub.h
|
||||
@@ -0,0 +1,14 @@
|
||||
+#ifndef USB_HOST_PLATFORM_ROOTHUB_H
|
||||
+#define USB_HOST_PLATFORM_ROOTHUB_H
|
||||
+
|
||||
+struct phy;
|
||||
+struct device_node;
|
||||
+
|
||||
+struct platform_roothub;
|
||||
+
|
||||
+struct platform_roothub *platform_roothub_init(struct device *dev);
|
||||
+
|
||||
+int platform_roothub_power_on(struct platform_roothub *plat_roothub);
|
||||
+void platform_roothub_power_off(struct platform_roothub *plat_roothub);
|
||||
+
|
||||
+#endif /* USB_HOST_PLATFORM_ROOTHUB_H */
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
From 9dfd5d48fbcd31b12825e81d532aca76c2b769f8 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Date: Wed, 11 Jan 2017 11:34:59 +0100
|
||||
Subject: [PATCH 76/79] usb: host: xhci: plat: integrate the platform-roothub
|
||||
|
||||
This enables the platform-roothub for the xhci-plat driver. This allows
|
||||
specifying a PHY for each port via devicetree. All PHYs will then be
|
||||
enabled/disabled by the platform-roothub driver.
|
||||
|
||||
One example where this is required is the Amlogic GXL and GXM SoCs:
|
||||
They are using a dwc3 USB controller with up to three ports enabled on
|
||||
the internal roothub. Using only the top-level "phy" properties does not
|
||||
work here since one can only specify one "usb2-phy" and one "usb3-phy",
|
||||
while actually at least two "usb2-phy" have to be specified.
|
||||
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
Documentation/devicetree/bindings/usb/usb-xhci.txt | 7 ++++++
|
||||
drivers/usb/host/Kconfig | 1 +
|
||||
drivers/usb/host/xhci-plat.c | 26 +++++++++++++++++++++-
|
||||
drivers/usb/host/xhci.h | 3 +++
|
||||
4 files changed, 36 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
|
||||
index 2d80b60..31b4f68 100644
|
||||
--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
|
||||
+++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
|
||||
@@ -29,6 +29,13 @@ Optional properties:
|
||||
- usb3-lpm-capable: determines if platform is USB3 LPM capable
|
||||
- quirk-broken-port-ped: set if the controller has broken port disable mechanism
|
||||
|
||||
+sub-nodes:
|
||||
+- optionally there can be a node for the root-hub, see usb-roothub.txt in the
|
||||
+ current directory
|
||||
+- one or more nodes with reg 1-31 for each port to which a device is connected.
|
||||
+ See usb-device.txt in the current directory for more information.
|
||||
+
|
||||
+
|
||||
Example:
|
||||
usb@f0931000 {
|
||||
compatible = "generic-xhci";
|
||||
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
|
||||
index 3f450e0..d6279d7 100644
|
||||
--- a/drivers/usb/host/Kconfig
|
||||
+++ b/drivers/usb/host/Kconfig
|
||||
@@ -36,6 +36,7 @@ config USB_XHCI_PCI
|
||||
config USB_XHCI_PLATFORM
|
||||
tristate "Generic xHCI driver for a platform device"
|
||||
select USB_XHCI_RCAR if ARCH_RENESAS
|
||||
+ select USB_PLATFORM_ROOTHUB
|
||||
---help---
|
||||
Adds an xHCI host driver for a generic platform device, which
|
||||
provides a memory space and an irq.
|
||||
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
|
||||
index c04144b..4de20b5 100644
|
||||
--- a/drivers/usb/host/xhci-plat.c
|
||||
+++ b/drivers/usb/host/xhci-plat.c
|
||||
@@ -285,10 +285,20 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
||||
goto put_usb3_hcd;
|
||||
}
|
||||
|
||||
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
+ xhci->platform_roothub = platform_roothub_init(sysdev);
|
||||
+ if (IS_ERR(xhci->platform_roothub)) {
|
||||
+ ret = PTR_ERR(xhci->platform_roothub);
|
||||
+ goto disable_clk;
|
||||
+ }
|
||||
+
|
||||
+ ret = platform_roothub_power_on(xhci->platform_roothub);
|
||||
if (ret)
|
||||
goto disable_usb_phy;
|
||||
|
||||
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||
+ if (ret)
|
||||
+ goto disable_platform_roothub;
|
||||
+
|
||||
if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
|
||||
xhci->shared_hcd->can_do_streams = 1;
|
||||
|
||||
@@ -311,6 +321,9 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
||||
dealloc_usb2_hcd:
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
+disable_platform_roothub:
|
||||
+ platform_roothub_power_off(xhci->platform_roothub);
|
||||
+
|
||||
disable_usb_phy:
|
||||
usb_phy_shutdown(hcd->usb_phy);
|
||||
|
||||
@@ -342,6 +355,8 @@ static int xhci_plat_remove(struct platform_device *dev)
|
||||
usb_remove_hcd(xhci->shared_hcd);
|
||||
usb_phy_shutdown(hcd->usb_phy);
|
||||
|
||||
+ platform_roothub_power_off(xhci->platform_roothub);
|
||||
+
|
||||
usb_remove_hcd(hcd);
|
||||
usb_put_hcd(xhci->shared_hcd);
|
||||
|
||||
@@ -374,6 +389,11 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
|
||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
||||
clk_disable_unprepare(xhci->clk);
|
||||
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ platform_roothub_power_off(xhci->platform_roothub);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -386,6 +406,10 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
|
||||
if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
|
||||
clk_prepare_enable(xhci->clk);
|
||||
|
||||
+ ret = platform_roothub_power_on(xhci->platform_roothub);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
ret = xhci_priv_resume_quirk(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
|
||||
index 73a28a9..7f3d15e 100644
|
||||
--- a/drivers/usb/host/xhci.h
|
||||
+++ b/drivers/usb/host/xhci.h
|
||||
@@ -34,6 +34,8 @@
|
||||
#include "xhci-ext-caps.h"
|
||||
#include "pci-quirks.h"
|
||||
|
||||
+#include "platform-roothub.h"
|
||||
+
|
||||
/* xHCI PCI Configuration Registers */
|
||||
#define XHCI_SBRN_OFFSET (0x60)
|
||||
|
||||
@@ -1725,6 +1727,7 @@ struct xhci_hcd {
|
||||
int msix_count;
|
||||
/* optional clock */
|
||||
struct clk *clk;
|
||||
+ struct platform_roothub *platform_roothub;
|
||||
/* data structures */
|
||||
struct xhci_device_context_array *dcbaa;
|
||||
struct xhci_ring *cmd_ring;
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
From 7079f88717e54f9ea48c1cbfba09b53cc8b9aefd Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 13 Jul 2017 15:02:33 +0200
|
||||
Subject: [PATCH 77/79] ARM64: dts: meson-gx: Enable USB on GXL and GXM boards
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 4 ++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts | 4 ++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi | 4 ++++
|
||||
arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 4 ++++
|
||||
4 files changed, 16 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 54718ee..bf49f6f 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
|
||||
@@ -234,3 +234,7 @@
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
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 55ec11a..19bb39b 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
|
||||
@@ -249,3 +249,7 @@
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
index f3eea8e..a07c34d 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
@@ -171,3 +171,7 @@
|
||||
pinctrl-0 = <&uart_ao_a_pins>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
+
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
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 3a327dd..1b7038d 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
|
||||
@@ -215,3 +215,7 @@
|
||||
remote-endpoint = <&hdmi_connector_in>;
|
||||
};
|
||||
};
|
||||
+
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
From 8718f9cf5d8df7fd800d4f7692eb1982cfa88a17 Mon Sep 17 00:00:00 2001
|
||||
From: Neil Armstrong <narmstrong@baylibre.com>
|
||||
Date: Thu, 13 Jul 2017 15:08:22 +0200
|
||||
Subject: [PATCH 78/79] ARM64: dts: meson-gxl: Enable HDMI audio on p212 based
|
||||
boards
|
||||
|
||||
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
|
||||
---
|
||||
.../boot/dts/amlogic/meson-gxl-s905x-p212.dtsi | 41 ++++++++++++++++++++++
|
||||
1 file changed, 41 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
index a07c34d..1372ea2 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dtsi
|
||||
@@ -74,6 +74,47 @@
|
||||
clocks = <&wifi32k>;
|
||||
clock-names = "ext_clock";
|
||||
};
|
||||
+
|
||||
+ soc {
|
||||
+ sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,name = "meson-gxl";
|
||||
+
|
||||
+ simple-audio-card,dai-link@0 {
|
||||
+ format = "i2s";
|
||||
+ mclk-fs = <256>;
|
||||
+ bitclock-master = <&i2s_dai>;
|
||||
+ frame-master = <&i2s_dai>;
|
||||
+
|
||||
+ plat {
|
||||
+ sound-dai = <&aiu_i2s_dma>;
|
||||
+ };
|
||||
+
|
||||
+ cpu {
|
||||
+ sound-dai = <&i2s_dai>;
|
||||
+ };
|
||||
+
|
||||
+ codec {
|
||||
+ sound-dai = <&hdmi_tx>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&audio {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&aiu_i2s_dma {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&i2s_dai {
|
||||
+ pinctrl-0 = <&i2s_am_clk_pins>, <&i2s_out_ao_clk_pins>,
|
||||
+ <&i2s_out_lr_clk_pins>, <&i2s_out_ch01_pins>;
|
||||
+ pinctrl-names = "default";
|
||||
+ status = "okay";
|
||||
};
|
||||
|
||||
ðmac {
|
||||
--
|
||||
1.9.1
|
||||
|
|
@ -48,11 +48,14 @@ diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
|
|||
index f8047b4..bea10c6 100644
|
||||
--- a/drivers/phy/Makefile
|
||||
+++ b/drivers/phy/Makefile
|
||||
@@ -64,3 +64,4 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
|
||||
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
|
||||
@@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_MESON) += amlogic/
|
||||
obj-$(CONFIG_ARCH_RENESAS) += renesas/
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
|
||||
obj-y += broadcom/ \
|
||||
hisilicon/ \
|
||||
marvell/ \
|
||||
diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
|
||||
new file mode 100644
|
||||
index 0000000..f5fbd3c
|
28
patch/kernel/meson64-next/1005_USB_Adjust_for_4.13.patch
Normal file
28
patch/kernel/meson64-next/1005_USB_Adjust_for_4.13.patch
Normal file
|
@ -0,0 +1,28 @@
|
|||
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
index 3f0d83b..7590383 100644
|
||||
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts
|
||||
@@ -129,6 +129,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
+&usb0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
/* SD card */
|
||||
&sd_emmc_b {
|
||||
status = "okay";
|
||||
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
|
||||
index f252201..10b2165 100644
|
||||
--- a/drivers/phy/Makefile
|
||||
+++ b/drivers/phy/Makefile
|
||||
@@ -7,7 +7,7 @@ obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
|
||||
obj-$(CONFIG_PHY_MT65XX_USB3) += phy-mt65xx-usb3.o
|
||||
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
|
||||
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
|
||||
-
|
||||
+obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += allwinner/
|
||||
obj-$(CONFIG_ARCH_MESON) += amlogic/
|
||||
obj-$(CONFIG_ARCH_RENESAS) += renesas/
|
|
@ -0,0 +1,15 @@
|
|||
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
|
||||
old mode 100644
|
||||
new mode 100755
|
||||
index 3216e09..21bce28
|
||||
--- a/arch/arm64/mm/dma-mapping.c
|
||||
+++ b/arch/arm64/mm/dma-mapping.c
|
||||
@@ -44,7 +44,7 @@ static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot,
|
||||
|
||||
static struct gen_pool *atomic_pool;
|
||||
|
||||
-#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
|
||||
+#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_2M
|
||||
static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
|
||||
|
||||
static int __init early_coherent_pool(char *p)
|
36479
patch/kernel/meson64-next/aufs4.12.patch
Normal file
36479
patch/kernel/meson64-next/aufs4.12.patch
Normal file
File diff suppressed because it is too large
Load diff
11
patch/kernel/meson64-next/bash_to_afterinstall.patch
Normal file
11
patch/kernel/meson64-next/bash_to_afterinstall.patch
Normal file
|
@ -0,0 +1,11 @@
|
|||
--- a/scripts/package/builddeb
|
||||
+++ b/scripts/package/builddeb
|
||||
@@ -218,7 +218,7 @@
|
||||
for script in postinst postrm preinst prerm ; do
|
||||
mkdir -p "$tmpdir$debhookdir/$script.d"
|
||||
cat <<EOF > "$tmpdir/DEBIAN/$script"
|
||||
-#!/bin/sh
|
||||
+#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
|
||||
index 807c9cd..9b9435f 100755
|
||||
--- a/scripts/package/builddeb
|
||||
+++ b/scripts/package/builddeb
|
||||
@@ -29,6 +29,28 @@ create_package() {
|
||||
# in case we are in a restrictive umask environment like 0077
|
||||
chmod -R a+rX "$pdir"
|
||||
|
||||
+ # Create preinstall and post install script to remove dtb
|
||||
+ if [[ "$1" == *dtb* ]]; then
|
||||
+ echo "if [ -d /boot/dtb-$version ]; then mv /boot/dtb-$version /boot/dtb-$version.old; fi" >> $pdir/DEBIAN/preinst
|
||||
+ echo "if [ -d /boot/dtb.old ]; then rm -rf /boot/dtb.old; fi" >> $pdir/DEBIAN/preinst
|
||||
+ echo "if [ -d /dtb ]; then mv /dtb /dtb.old; fi" >> $pdir/DEBIAN/preinst
|
||||
+ echo "if [ -d /boot/dtb ]; then mv /boot/dtb /boot/dtb.old; fi" >> $pdir/DEBIAN/preinst
|
||||
+ echo "exit 0" >> $pdir/DEBIAN/preinst
|
||||
+ chmod 775 $pdir/DEBIAN/preinst
|
||||
+ #
|
||||
+ echo "if [ -d /boot/dtb-$version.old ]; then rm -rf /boot/dtb-$version.old; fi" >> $pdir/DEBIAN/postinst
|
||||
+ echo "ln -sf dtb-$version /boot/dtb > /dev/null 2>&1 || mv /boot/dtb-$version /boot/dtb" >> $pdir/DEBIAN/postinst
|
||||
+ echo "exit 0" >> $pdir/DEBIAN/postinst
|
||||
+ chmod 775 $pdir/DEBIAN/postinst
|
||||
+ fi
|
||||
+
|
||||
+ # Create postinstall script for headers
|
||||
+ if [[ "$1" == *headers* ]]; then
|
||||
+ echo "cd /usr/src/linux-headers-$version; echo \"Compiling headers - please wait ...\"; make -s scripts >/dev/null 2>&1" >> $pdir/DEBIAN/postinst
|
||||
+ echo "exit 0" >> $pdir/DEBIAN/postinst
|
||||
+ chmod 775 $pdir/DEBIAN/postinst
|
||||
+ fi
|
||||
+
|
||||
# Create the package
|
||||
dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch}" -p$pname -P"$pdir"
|
||||
dpkg --build "$pdir" ..
|
||||
@@ -95,11 +117,13 @@ tmpdir="$objtree/debian/tmp"
|
||||
fwdir="$objtree/debian/fwtmp"
|
||||
kernel_headers_dir="$objtree/debian/hdrtmp"
|
||||
libc_headers_dir="$objtree/debian/headertmp"
|
||||
+dtb_dir="$objtree/debian/dtbtmp"
|
||||
dbg_dir="$objtree/debian/dbgtmp"
|
||||
-packagename=linux-image-$version
|
||||
-fwpackagename=linux-firmware-image-$version
|
||||
-kernel_headers_packagename=linux-headers-$version
|
||||
-libc_headers_packagename=linux-libc-dev
|
||||
+packagename=linux-image-next"$LOCALVERSION"
|
||||
+fwpackagename=linux-firmware-image-next"$LOCALVERSION"
|
||||
+kernel_headers_packagename=linux-headers-next"$LOCALVERSION"
|
||||
+dtb_packagename=linux-dtb-next"$LOCALVERSION"
|
||||
+libc_headers_packagename=linux-libc-next"$LOCALVERSION"
|
||||
dbg_packagename=$packagename-dbg
|
||||
debarch=
|
||||
forcearch=
|
||||
@@ -126,7 +150,9 @@ esac
|
||||
BUILD_DEBUG="$(grep -s '^CONFIG_DEBUG_INFO=y' $KCONFIG_CONFIG || true)"
|
||||
|
||||
# Setup the directory structure
|
||||
-rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir" $objtree/debian/files
|
||||
+rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir" "$dtb_dir" $objtree/debian/files
|
||||
+mkdir -m 755 -p "$dtb_dir/DEBIAN"
|
||||
+mkdir -p "$dtb_dir/boot/dtb-$version" "$dtb_dir/usr/share/doc/$dtb_packagename"
|
||||
mkdir -m 755 -p "$tmpdir/DEBIAN"
|
||||
mkdir -p "$tmpdir/lib" "$tmpdir/boot"
|
||||
mkdir -p "$fwdir/lib/firmware/$version/"
|
||||
@@ -180,6 +206,11 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
+if grep -q '^CONFIG_OF=y' $KCONFIG_CONFIG ; then
|
||||
+ #mkdir -p "$tmpdir/boot/dtb"
|
||||
+ INSTALL_DTBS_PATH="$dtb_dir/boot/dtb-$version" $MAKE KBUILD_SRC= dtbs_install
|
||||
+fi
|
||||
+
|
||||
if [ "$ARCH" != "um" ]; then
|
||||
$MAKE headers_check KBUILD_SRC=
|
||||
$MAKE headers_install KBUILD_SRC= INSTALL_HDR_PATH="$libc_headers_dir/usr"
|
||||
@@ -192,7 +223,7 @@ fi
|
||||
# so do we; recent versions of dracut and initramfs-tools will obey this.
|
||||
debhookdir=${KDEB_HOOKDIR:-/etc/kernel}
|
||||
if grep -q '^CONFIG_BLK_DEV_INITRD=y' $KCONFIG_CONFIG; then
|
||||
- want_initrd=Yes
|
||||
+ want_initrd=Yes
|
||||
else
|
||||
want_initrd=No
|
||||
fi
|
||||
@@ -204,9 +235,11 @@ for script in postinst postrm preinst prerm ; do
|
||||
set -e
|
||||
|
||||
# Pass maintainer script parameters to hook scripts
|
||||
+
|
||||
export DEB_MAINT_PARAMS="\$*"
|
||||
|
||||
# Tell initramfs builder whether it's wanted
|
||||
+
|
||||
export INITRD=$want_initrd
|
||||
|
||||
test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d
|
||||
@@ -215,6 +248,55 @@ EOF
|
||||
chmod 755 "$tmpdir/DEBIAN/$script"
|
||||
done
|
||||
|
||||
+##
|
||||
+## Create sym link to kernel image
|
||||
+##
|
||||
+sed -e "s/set -e//g" -i $tmpdir/DEBIAN/postinst
|
||||
+sed -e "s/exit 0//g" -i $tmpdir/DEBIAN/postinst
|
||||
+cat >> $tmpdir/DEBIAN/postinst <<EOT
|
||||
+if [ "\$(grep nand /proc/partitions)" != "" ] && [ "\$(grep mmc /proc/partitions)" = "" ]; then
|
||||
+mkimage -A arm -O linux -T kernel -C none -a "0x40008000" -e "0x40008000" -n "Linux kernel" -d /$installed_image_path /boot/uImage > /dev/null 2>&1
|
||||
+cp /boot/uImage /tmp/uImage
|
||||
+sync
|
||||
+mountpoint -q /boot || mount /boot
|
||||
+cp /tmp/uImage /boot/uImage
|
||||
+rm -f /$installed_image_path
|
||||
+else
|
||||
+ln -sf $(basename $installed_image_path) /boot/zImage > /dev/null 2>&1 || mv /$installed_image_path /boot/zImage
|
||||
+fi
|
||||
+touch /boot/.next
|
||||
+exit 0
|
||||
+EOT
|
||||
+##
|
||||
+## FAT install workaround
|
||||
+##
|
||||
+sed -e "s/set -e//g" -i $tmpdir/DEBIAN/preinst
|
||||
+sed -e "s/exit 0//g" -i $tmpdir/DEBIAN/preinst
|
||||
+cat >> $tmpdir/DEBIAN/preinst <<EOT
|
||||
+# exit if we are running chroot
|
||||
+if [ "\$(stat -c %d:%i /)" != "\$(stat -c %d:%i /proc/1/root/.)" ]; then exit 0; fi
|
||||
+
|
||||
+check_and_unmount (){
|
||||
+boot_device=\$(mountpoint -d /boot)
|
||||
+
|
||||
+for file in /dev/* ; do
|
||||
+ CURRENT_DEVICE=\$(printf "%d:%d" \$(stat --printf="0x%t 0x%T" \$file))
|
||||
+ if [[ "\$CURRENT_DEVICE" = "\$boot_device" ]]; then
|
||||
+ boot_partition=\$file
|
||||
+ break;
|
||||
+ fi
|
||||
+done
|
||||
+
|
||||
+bootfstype=\$(blkid -s TYPE -o value \$boot_partition)
|
||||
+if [ "\$bootfstype" = "vfat" ]; then
|
||||
+umount /boot;
|
||||
+rm -f /boot/System.map* /boot/config* /boot/vmlinuz* /boot/zImage /boot/uImage
|
||||
+fi
|
||||
+}
|
||||
+mountpoint -q /boot && check_and_unmount
|
||||
+EOT
|
||||
+echo "exit 0" >> $tmpdir/DEBIAN/preinst
|
||||
+
|
||||
# Try to determine maintainer and email values
|
||||
if [ -n "$DEBEMAIL" ]; then
|
||||
email=$DEBEMAIL
|
||||
@@ -329,12 +411,20 @@ if grep -q '^CONFIG_GCC_PLUGINS=y' $KCONFIG_CONFIG ; then
|
||||
fi
|
||||
destdir=$kernel_headers_dir/usr/src/linux-headers-$version
|
||||
mkdir -p "$destdir"
|
||||
+######################## headers patch
|
||||
+ZACNI=$(pwd)
|
||||
+cd $destdir
|
||||
+patch -p1 < /tmp/headers-debian-byteshift.patch
|
||||
+cd $ZACNI
|
||||
+######################## headers patch
|
||||
(cd $srctree; tar -c -f - -T -) < "$objtree/debian/hdrsrcfiles" | (cd $destdir; tar -xf -)
|
||||
(cd $objtree; tar -c -f - -T -) < "$objtree/debian/hdrobjfiles" | (cd $destdir; tar -xf -)
|
||||
(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be
|
||||
ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
|
||||
rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
|
||||
|
||||
+(cd "$destdir"; make M=scripts clean)
|
||||
+
|
||||
cat <<EOF >> debian/control
|
||||
|
||||
Package: $kernel_headers_packagename
|
||||
@@ -363,6 +453,16 @@ fi
|
||||
|
||||
cat <<EOF >> debian/control
|
||||
|
||||
+Package: $dtb_packagename
|
||||
+Architecture: any
|
||||
+Description: Linux DTB, version $version
|
||||
+ This package contains device blobs from the Linux kernel, version $version.
|
||||
+EOF
|
||||
+
|
||||
+create_package "$dtb_packagename" "$dtb_dir"
|
||||
+
|
||||
+cat <<EOF >> debian/control
|
||||
+
|
||||
Package: $libc_headers_packagename
|
||||
Section: devel
|
||||
Provides: linux-kernel-headers
|
||||
@@ -374,7 +474,7 @@ EOF
|
||||
|
||||
if [ "$ARCH" != "um" ]; then
|
||||
create_package "$kernel_headers_packagename" "$kernel_headers_dir"
|
||||
- create_package "$libc_headers_packagename" "$libc_headers_dir"
|
||||
+# create_package "$libc_headers_packagename" "$libc_headers_dir"
|
||||
fi
|
||||
|
||||
create_package "$packagename" "$tmpdir"
|
14
patch/kernel/meson64-next/packaging-4.x-meson64.patch
Normal file
14
patch/kernel/meson64-next/packaging-4.x-meson64.patch
Normal file
|
@ -0,0 +1,14 @@
|
|||
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
|
||||
index 750d70e..8fc16c9 100755
|
||||
--- a/scripts/package/builddeb
|
||||
+++ b/scripts/package/builddeb
|
||||
@@ -267,7 +267,8 @@ mountpoint -q /boot || mount /boot
|
||||
cp /tmp/uImage /boot/uImage
|
||||
rm -f /$installed_image_path
|
||||
else
|
||||
-ln -sf $(basename $installed_image_path) /boot/zImage > /dev/null 2>&1 || mv /$installed_image_path /boot/zImage
|
||||
+rm -f /boot/zImage;gunzip -c /boot/$(basename $installed_image_path) > /boot/xImage
|
||||
+mkimage -A arm64 -O linux -T kernel -C none -a 0x1080000 -e 0x1080000 -n "Linux kernel" -d /boot/xImage /boot/uImage; rm -f /boot/xImage
|
||||
fi
|
||||
touch /boot/.next
|
||||
exit 0
|
Loading…
Add table
Add a link
Reference in a new issue