mirror of
https://github.com/linux-sunxi/meta-sunxi.git
synced 2024-11-08 06:18:22 +01:00
add kernel patches for orangepi-3lts for 6.1 6.5 kernels(KMETA)
This commit is contained in:
parent
96453886e2
commit
0437a1df6b
@ -44,7 +44,8 @@ S = "${WORKDIR}/linux-${PV}"
|
||||
KRELEASE = "${@d.getVar('PV', True).split('.')[0]}"
|
||||
|
||||
SRC_URI = "https://www.kernel.org/pub/linux/kernel/v${KRELEASE}.x/linux-${PV}.tar.xz \
|
||||
file://defconfig \
|
||||
file://defconfig \
|
||||
file://sunxi-kmeta;type=kmeta;name=sunxi-kmeta;destsuffix=sunxi-kmeta \
|
||||
"
|
||||
|
||||
# append patches for kernels before 6.5 and after based on version
|
||||
|
@ -0,0 +1,142 @@
|
||||
From 91b69779e0875e58d8973b2938a1cc4b7a1c455b Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Karlman <jonas@kwiboo.se>
|
||||
Date: Sun, 25 Mar 2018 22:17:06 +0200
|
||||
Subject: [PATCH 22/44] ASoC: hdmi-codec: fix channel allocation
|
||||
|
||||
---
|
||||
sound/soc/codecs/hdmi-codec.c | 113 ++++++++++++++++------------------
|
||||
1 file changed, 52 insertions(+), 61 deletions(-)
|
||||
|
||||
--- a/sound/soc/codecs/hdmi-codec.c
|
||||
+++ b/sound/soc/codecs/hdmi-codec.c
|
||||
@@ -194,78 +194,69 @@ static const struct snd_pcm_chmap_elem h
|
||||
*/
|
||||
static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = {
|
||||
{ .ca_id = 0x00, .n_ch = 2,
|
||||
- .mask = FL | FR},
|
||||
- /* 2.1 */
|
||||
- { .ca_id = 0x01, .n_ch = 4,
|
||||
- .mask = FL | FR | LFE},
|
||||
- /* Dolby Surround */
|
||||
+ .mask = FL | FR },
|
||||
+ { .ca_id = 0x03, .n_ch = 4,
|
||||
+ .mask = FL | FR | LFE | FC },
|
||||
{ .ca_id = 0x02, .n_ch = 4,
|
||||
.mask = FL | FR | FC },
|
||||
- /* surround51 */
|
||||
+ { .ca_id = 0x01, .n_ch = 4,
|
||||
+ .mask = FL | FR | LFE },
|
||||
{ .ca_id = 0x0b, .n_ch = 6,
|
||||
- .mask = FL | FR | LFE | FC | RL | RR},
|
||||
- /* surround40 */
|
||||
- { .ca_id = 0x08, .n_ch = 6,
|
||||
- .mask = FL | FR | RL | RR },
|
||||
- /* surround41 */
|
||||
- { .ca_id = 0x09, .n_ch = 6,
|
||||
- .mask = FL | FR | LFE | RL | RR },
|
||||
- /* surround50 */
|
||||
+ .mask = FL | FR | LFE | FC | RL | RR },
|
||||
{ .ca_id = 0x0a, .n_ch = 6,
|
||||
.mask = FL | FR | FC | RL | RR },
|
||||
- /* 6.1 */
|
||||
- { .ca_id = 0x0f, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FC | RL | RR | RC },
|
||||
- /* surround71 */
|
||||
+ { .ca_id = 0x09, .n_ch = 6,
|
||||
+ .mask = FL | FR | LFE | RL | RR },
|
||||
+ { .ca_id = 0x08, .n_ch = 6,
|
||||
+ .mask = FL | FR | RL | RR },
|
||||
+ { .ca_id = 0x07, .n_ch = 6,
|
||||
+ .mask = FL | FR | LFE | FC | RC },
|
||||
+ { .ca_id = 0x06, .n_ch = 6,
|
||||
+ .mask = FL | FR | FC | RC },
|
||||
+ { .ca_id = 0x05, .n_ch = 6,
|
||||
+ .mask = FL | FR | LFE | RC },
|
||||
+ { .ca_id = 0x04, .n_ch = 6,
|
||||
+ .mask = FL | FR | RC },
|
||||
{ .ca_id = 0x13, .n_ch = 8,
|
||||
.mask = FL | FR | LFE | FC | RL | RR | RLC | RRC },
|
||||
- /* others */
|
||||
- { .ca_id = 0x03, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FC },
|
||||
- { .ca_id = 0x04, .n_ch = 8,
|
||||
- .mask = FL | FR | RC},
|
||||
- { .ca_id = 0x05, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RC },
|
||||
- { .ca_id = 0x06, .n_ch = 8,
|
||||
- .mask = FL | FR | FC | RC },
|
||||
- { .ca_id = 0x07, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FC | RC },
|
||||
- { .ca_id = 0x0c, .n_ch = 8,
|
||||
- .mask = FL | FR | RC | RL | RR },
|
||||
- { .ca_id = 0x0d, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RL | RR | RC },
|
||||
- { .ca_id = 0x0e, .n_ch = 8,
|
||||
- .mask = FL | FR | FC | RL | RR | RC },
|
||||
- { .ca_id = 0x10, .n_ch = 8,
|
||||
- .mask = FL | FR | RL | RR | RLC | RRC },
|
||||
- { .ca_id = 0x11, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RL | RR | RLC | RRC },
|
||||
+ { .ca_id = 0x1f, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
|
||||
{ .ca_id = 0x12, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RL | RR | RLC | RRC },
|
||||
- { .ca_id = 0x14, .n_ch = 8,
|
||||
- .mask = FL | FR | FLC | FRC },
|
||||
- { .ca_id = 0x15, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FLC | FRC },
|
||||
- { .ca_id = 0x16, .n_ch = 8,
|
||||
- .mask = FL | FR | FC | FLC | FRC },
|
||||
- { .ca_id = 0x17, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FC | FLC | FRC },
|
||||
- { .ca_id = 0x18, .n_ch = 8,
|
||||
- .mask = FL | FR | RC | FLC | FRC },
|
||||
- { .ca_id = 0x19, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RC | FLC | FRC },
|
||||
- { .ca_id = 0x1a, .n_ch = 8,
|
||||
- .mask = FL | FR | RC | FC | FLC | FRC },
|
||||
- { .ca_id = 0x1b, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RC | FC | FLC | FRC },
|
||||
- { .ca_id = 0x1c, .n_ch = 8,
|
||||
- .mask = FL | FR | RL | RR | FLC | FRC },
|
||||
- { .ca_id = 0x1d, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | RL | RR | FLC | FRC },
|
||||
{ .ca_id = 0x1e, .n_ch = 8,
|
||||
.mask = FL | FR | FC | RL | RR | FLC | FRC },
|
||||
- { .ca_id = 0x1f, .n_ch = 8,
|
||||
- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC },
|
||||
+ { .ca_id = 0x11, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | RL | RR | RLC | RRC },
|
||||
+ { .ca_id = 0x1d, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | RL | RR | FLC | FRC },
|
||||
+ { .ca_id = 0x10, .n_ch = 8,
|
||||
+ .mask = FL | FR | RL | RR | RLC | RRC },
|
||||
+ { .ca_id = 0x1c, .n_ch = 8,
|
||||
+ .mask = FL | FR | RL | RR | FLC | FRC },
|
||||
+ { .ca_id = 0x0f, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | FC | RL | RR | RC },
|
||||
+ { .ca_id = 0x1b, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | RC | FC | FLC | FRC },
|
||||
+ { .ca_id = 0x0e, .n_ch = 8,
|
||||
+ .mask = FL | FR | FC | RL | RR | RC },
|
||||
+ { .ca_id = 0x1a, .n_ch = 8,
|
||||
+ .mask = FL | FR | RC | FC | FLC | FRC },
|
||||
+ { .ca_id = 0x0d, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | RL | RR | RC },
|
||||
+ { .ca_id = 0x19, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | RC | FLC | FRC },
|
||||
+ { .ca_id = 0x0c, .n_ch = 8,
|
||||
+ .mask = FL | FR | RC | RL | RR },
|
||||
+ { .ca_id = 0x18, .n_ch = 8,
|
||||
+ .mask = FL | FR | RC | FLC | FRC },
|
||||
+ { .ca_id = 0x17, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | FC | FLC | FRC },
|
||||
+ { .ca_id = 0x16, .n_ch = 8,
|
||||
+ .mask = FL | FR | FC | FLC | FRC },
|
||||
+ { .ca_id = 0x15, .n_ch = 8,
|
||||
+ .mask = FL | FR | LFE | FLC | FRC },
|
||||
+ { .ca_id = 0x14, .n_ch = 8,
|
||||
+ .mask = FL | FR | FLC | FRC },
|
||||
};
|
||||
|
||||
struct hdmi_codec_priv {
|
@ -0,0 +1,53 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Sat, 16 Jan 2021 10:58:14 +0100
|
||||
Subject: [PATCH] HACK: h6: Add HDMI sound card
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 20 +++++++++++++++++++-
|
||||
1 file changed, 19 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -108,6 +108,24 @@
|
||||
(GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
|
||||
};
|
||||
|
||||
+ sound_hdmi: sound {
|
||||
+ compatible = "simple-audio-card";
|
||||
+ simple-audio-card,format = "i2s";
|
||||
+ simple-audio-card,name = "allwinner-hdmi";
|
||||
+ simple-audio-card,mclk-fs = <128>;
|
||||
+ simple-audio-card,frame-inversion;
|
||||
+
|
||||
+ simple-audio-card,codec {
|
||||
+ sound-dai = <&hdmi>;
|
||||
+ };
|
||||
+
|
||||
+ simple-audio-card,cpu {
|
||||
+ sound-dai = <&i2s1>;
|
||||
+ dai-tdm-slot-num = <2>;
|
||||
+ dai-tdm-slot-width = <32>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
soc {
|
||||
compatible = "simple-bus";
|
||||
#address-cells = <1>;
|
||||
@@ -664,7 +682,6 @@
|
||||
dmas = <&dma 4>, <&dma 4>;
|
||||
resets = <&ccu RST_BUS_I2S1>;
|
||||
dma-names = "rx", "tx";
|
||||
- status = "disabled";
|
||||
};
|
||||
|
||||
spdif: spdif@5093000 {
|
||||
@@ -801,6 +818,7 @@
|
||||
};
|
||||
|
||||
hdmi: hdmi@6000000 {
|
||||
+ #sound-dai-cells = <0>;
|
||||
compatible = "allwinner,sun50i-h6-dw-hdmi";
|
||||
reg = <0x06000000 0x10000>;
|
||||
reg-io-width = <1>;
|
@ -0,0 +1,52 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sat, 2 Jan 2021 15:52:27 -0600
|
||||
Subject: [PATCH] Input: axp20x-pek - allow wakeup after shutdown
|
||||
|
||||
While the AXP20x PMIC handles the power button itself after shutting
|
||||
down, it is not always possible to use the PMIC's built-in shutdown
|
||||
feature, such as when other wakeup sources are needed (for example, an
|
||||
IR remote or wake-on-LAN) that require firmware support. In that case,
|
||||
the PMIC remains on, but suspended, until the board is powered back on.
|
||||
|
||||
During this "fake" off state, IRQ configuration is similar to system
|
||||
sleep, where enable_irq_wake() must be call on an IRQ for it to be
|
||||
wakeup capable. Run the suspend callback to arm the power button IRQs
|
||||
during the shutdown process, so the power button works in this state.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
drivers/input/misc/axp20x-pek.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/input/misc/axp20x-pek.c
|
||||
+++ b/drivers/input/misc/axp20x-pek.c
|
||||
@@ -354,7 +354,7 @@ static int axp20x_pek_probe(struct platf
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int __maybe_unused axp20x_pek_suspend(struct device *dev)
|
||||
+static int axp20x_pek_suspend(struct device *dev)
|
||||
{
|
||||
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
|
||||
|
||||
@@ -413,6 +413,11 @@ static const struct dev_pm_ops axp20x_pe
|
||||
#endif
|
||||
};
|
||||
|
||||
+static void axp20x_pek_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+ axp20x_pek_suspend(&pdev->dev);
|
||||
+}
|
||||
+
|
||||
static const struct platform_device_id axp_pek_id_match[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
@@ -428,6 +433,7 @@ MODULE_DEVICE_TABLE(platform, axp_pek_id
|
||||
|
||||
static struct platform_driver axp20x_pek_driver = {
|
||||
.probe = axp20x_pek_probe,
|
||||
+ .shutdown = axp20x_pek_shutdown,
|
||||
.id_table = axp_pek_id_match,
|
||||
.driver = {
|
||||
.name = "axp20x-pek",
|
@ -0,0 +1,36 @@
|
||||
From dbf607d6716dd0a314d734cfd9423601d6c5a99d Mon Sep 17 00:00:00 2001
|
||||
From: OpenEmbedded <oe.patch@oe>
|
||||
Date: Wed, 6 Dec 2023 18:01:24 +0100
|
||||
Subject: [PATCH] Input: axp20x-pek - allow wakeup after shutdown
|
||||
|
||||
---
|
||||
drivers/input/misc/axp20x-pek.c | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
|
||||
index 4581606a2..7217dc6ed 100644
|
||||
--- a/drivers/input/misc/axp20x-pek.c
|
||||
+++ b/drivers/input/misc/axp20x-pek.c
|
||||
@@ -393,6 +393,11 @@ static const struct dev_pm_ops axp20x_pek_pm_ops = {
|
||||
.resume_noirq = pm_sleep_ptr(axp20x_pek_resume_noirq),
|
||||
};
|
||||
|
||||
+static void axp20x_pek_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+ axp20x_pek_suspend(&pdev->dev);
|
||||
+}
|
||||
+
|
||||
static const struct platform_device_id axp_pek_id_match[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
@@ -408,6 +413,7 @@ MODULE_DEVICE_TABLE(platform, axp_pek_id_match);
|
||||
|
||||
static struct platform_driver axp20x_pek_driver = {
|
||||
.probe = axp20x_pek_probe,
|
||||
+ .shutdown = axp20x_pek_shutdown,
|
||||
.id_table = axp_pek_id_match,
|
||||
.driver = {
|
||||
.name = "axp20x-pek",
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,393 @@
|
||||
From 20d3d43d9daa82d5fa1e937e17b975974572d189 Mon Sep 17 00:00:00 2001
|
||||
From: Juliano Dorigão <jdorigao@gmail.com>
|
||||
Date: Fri, 3 Mar 2023 16:12:03 -0400
|
||||
Subject: [PATCH] OrangePi 3 LTS support
|
||||
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/Makefile | 1 +
|
||||
.../allwinner/sun50i-h6-orangepi-3-lts.dts | 361 ++++++++++++++++++
|
||||
2 files changed, 362 insertions(+)
|
||||
create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile
|
||||
index 6a96494a2..ace8159a6 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/Makefile
|
||||
+++ b/arch/arm64/boot/dts/allwinner/Makefile
|
||||
@@ -32,6 +32,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h5-orangepi-zero-plus2.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-beelink-gs1.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-3.dtb
|
||||
+dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-3-lts.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-lite2.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-orangepi-one-plus.dtb
|
||||
dtb-$(CONFIG_ARCH_SUNXI) += sun50i-h6-pine-h64.dtb
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
new file mode 100644
|
||||
index 000000000..67f38b8a1
|
||||
--- /dev/null
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
@@ -0,0 +1,361 @@
|
||||
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
+// Copyright (C) 2023 Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
+// Based on sun50i-h6-orangepi-3.dts, which is:
|
||||
+// Copyright (C) 2019 Ondřej Jirman <megous@megous.com>
|
||||
+
|
||||
+/dts-v1/;
|
||||
+
|
||||
+#include "sun50i-h6.dtsi"
|
||||
+#include "sun50i-h6-cpu-opp.dtsi"
|
||||
+
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
+/ {
|
||||
+ model = "OrangePi 3 LTS";
|
||||
+ compatible = "xunlong,orangepi-3-lts", "allwinner,sun50i-h6";
|
||||
+
|
||||
+ aliases {
|
||||
+ ethernet0 = &emac;
|
||||
+ serial0 = &uart0;
|
||||
+ };
|
||||
+
|
||||
+ chosen {
|
||||
+ stdout-path = "serial0:115200n8";
|
||||
+ };
|
||||
+
|
||||
+ connector {
|
||||
+ compatible = "hdmi-connector";
|
||||
+ ddc-en-gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>; /* PH2 */
|
||||
+ type = "a";
|
||||
+
|
||||
+ port {
|
||||
+ hdmi_con_in: endpoint {
|
||||
+ remote-endpoint = <&hdmi_out_con>;
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ ext_osc32k: ext_osc32k_clk {
|
||||
+ #clock-cells = <0>;
|
||||
+ compatible = "fixed-clock";
|
||||
+ clock-frequency = <32768>;
|
||||
+ clock-output-names = "ext_osc32k";
|
||||
+ };
|
||||
+
|
||||
+ leds {
|
||||
+ compatible = "gpio-leds";
|
||||
+
|
||||
+ led-0 {
|
||||
+ label = "orangepi:red:power";
|
||||
+ gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
|
||||
+ };
|
||||
+
|
||||
+ led-1 {
|
||||
+ label = "orangepi:green:status";
|
||||
+ gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
|
||||
+ default-state = "on";
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
+ reg_vcc5v: vcc5v {
|
||||
+ /* board wide 5V supply directly from the DC jack */
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "vcc-5v";
|
||||
+ regulator-min-microvolt = <5000000>;
|
||||
+ regulator-max-microvolt = <5000000>;
|
||||
+ regulator-always-on;
|
||||
+ };
|
||||
+
|
||||
+ reg_gmac_3v3: gmac-3v3 {
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "gmac-3v3";
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ startup-delay-us = <150000>;
|
||||
+ enable-active-high;
|
||||
+ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
|
||||
+ };
|
||||
+
|
||||
+ reg_vcc33_wifi: vcc33-wifi {
|
||||
+ /* Always on 3.3V regulator for WiFi and BT */
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "vcc33-wifi";
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ enable-active-high;
|
||||
+ gpio = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
|
||||
+ };
|
||||
+
|
||||
+ reg_vcc_wifi_io: vcc-wifi-io {
|
||||
+ /* Always on 1.8V/300mA regulator for WiFi and BT IO */
|
||||
+ compatible = "regulator-fixed";
|
||||
+ regulator-name = "vcc-wifi-io";
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ regulator-always-on;
|
||||
+ vin-supply = <®_vcc33_wifi>;
|
||||
+ };
|
||||
+
|
||||
+ wifi_pwrseq: wifi-pwrseq {
|
||||
+ compatible = "mmc-pwrseq-simple";
|
||||
+ clocks = <&rtc 1>;
|
||||
+ clock-names = "ext_clock";
|
||||
+ reset-gpios = <&r_pio 1 3 GPIO_ACTIVE_LOW>; /* PM3 */
|
||||
+ post-power-on-delay-ms = <200>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&cpu0 {
|
||||
+ cpu-supply = <®_dcdca>;
|
||||
+};
|
||||
+
|
||||
+&de {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&dwc3 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ehci0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ehci3 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&emac {
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&ext_rgmii_pins>;
|
||||
+ phy-mode = "rgmii";
|
||||
+ phy-handle = <&ext_rgmii_phy>;
|
||||
+ phy-supply = <®_gmac_3v3>;
|
||||
+ allwinner,rx-delay-ps = <1500>;
|
||||
+ allwinner,tx-delay-ps = <700>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&gpu {
|
||||
+ mali-supply = <®_dcdcc>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&hdmi {
|
||||
+ hvcc-supply = <®_bldo2>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&hdmi_out {
|
||||
+ hdmi_out_con: endpoint {
|
||||
+ remote-endpoint = <&hdmi_con_in>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&mdio {
|
||||
+ ext_rgmii_phy: ethernet-phy@1 {
|
||||
+ compatible = "ethernet-phy-ieee802.3-c22";
|
||||
+ reg = <1>;
|
||||
+
|
||||
+ reset-gpios = <&pio 3 14 GPIO_ACTIVE_LOW>; /* PD14 */
|
||||
+ reset-assert-us = <15000>;
|
||||
+ reset-deassert-us = <40000>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&mmc0 {
|
||||
+ vmmc-supply = <®_cldo1>;
|
||||
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
|
||||
+ bus-width = <4>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&mmc1 {
|
||||
+ vmmc-supply = <®_vcc33_wifi>;
|
||||
+ vqmmc-supply = <®_vcc_wifi_io>;
|
||||
+ mmc-pwrseq = <&wifi_pwrseq>;
|
||||
+ bus-width = <4>;
|
||||
+ non-removable;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&mmc2 {
|
||||
+ vmmc-supply = <®_cldo1>;
|
||||
+ vqmmc-supply = <®_bldo2>;
|
||||
+ cap-mmc-hw-reset;
|
||||
+ non-removable;
|
||||
+ bus-width = <8>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ohci0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&ohci3 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&pio {
|
||||
+ vcc-pc-supply = <®_bldo2>;
|
||||
+ vcc-pd-supply = <®_cldo1>;
|
||||
+ vcc-pg-supply = <®_bldo3>;
|
||||
+};
|
||||
+
|
||||
+&r_ir {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&r_rsb {
|
||||
+ clock-frequency = <100000>;
|
||||
+ status = "okay";
|
||||
+
|
||||
+ axp805: pmic@745 {
|
||||
+ compatible = "x-powers,axp805", "x-powers,axp806";
|
||||
+ reg = <0x745>;
|
||||
+ interrupt-parent = <&r_intc>;
|
||||
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ interrupt-controller;
|
||||
+ #interrupt-cells = <1>;
|
||||
+ x-powers,self-working-mode;
|
||||
+ vina-supply = <®_vcc5v>;
|
||||
+ vinb-supply = <®_vcc5v>;
|
||||
+ vinc-supply = <®_vcc5v>;
|
||||
+ vind-supply = <®_vcc5v>;
|
||||
+ vine-supply = <®_vcc5v>;
|
||||
+ aldoin-supply = <®_vcc5v>;
|
||||
+ bldoin-supply = <®_vcc5v>;
|
||||
+ cldoin-supply = <®_vcc5v>;
|
||||
+
|
||||
+ regulators {
|
||||
+ reg_aldo1: aldo1 {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ regulator-name = "vcc-pl-led-ir";
|
||||
+ };
|
||||
+
|
||||
+ reg_aldo2: aldo2 {
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ regulator-name = "vcc33-audio-tv-ephy-mac";
|
||||
+ };
|
||||
+
|
||||
+ /* ALDO3 is shorted to CLDO1 */
|
||||
+ reg_aldo3: aldo3 {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-1";
|
||||
+ };
|
||||
+
|
||||
+ reg_bldo1: bldo1 {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ regulator-name = "vcc18-dram-bias-pll";
|
||||
+ };
|
||||
+
|
||||
+ reg_bldo2: bldo2 {
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ regulator-name = "vcc-efuse-pcie-hdmi-pc";
|
||||
+ };
|
||||
+
|
||||
+ reg_bldo3: bldo3 {
|
||||
+ regulator-min-microvolt = <1800000>;
|
||||
+ regulator-max-microvolt = <1800000>;
|
||||
+ regulator-name = "vcc-pm-pg-dcxoio-wifi";
|
||||
+ };
|
||||
+
|
||||
+ bldo4 {
|
||||
+ /* unused */
|
||||
+ };
|
||||
+
|
||||
+ reg_cldo1: cldo1 {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <3300000>;
|
||||
+ regulator-max-microvolt = <3300000>;
|
||||
+ regulator-name = "vcc33-io-pd-emmc-sd-usb-uart-2";
|
||||
+ };
|
||||
+
|
||||
+ cldo2 {
|
||||
+ /* unused */
|
||||
+ };
|
||||
+
|
||||
+ cldo3 {
|
||||
+ /* unused */
|
||||
+ };
|
||||
+
|
||||
+ reg_dcdca: dcdca {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <800000>;
|
||||
+ regulator-max-microvolt = <1160000>;
|
||||
+ regulator-ramp-delay = <2500>;
|
||||
+ regulator-name = "vdd-cpu";
|
||||
+ };
|
||||
+
|
||||
+ reg_dcdcc: dcdcc {
|
||||
+ regulator-enable-ramp-delay = <32000>;
|
||||
+ regulator-min-microvolt = <810000>;
|
||||
+ regulator-max-microvolt = <1080000>;
|
||||
+ regulator-ramp-delay = <2500>;
|
||||
+ regulator-name = "vdd-gpu";
|
||||
+ };
|
||||
+
|
||||
+ reg_dcdcd: dcdcd {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <980000>;
|
||||
+ regulator-max-microvolt = <980000>;
|
||||
+ regulator-name = "vdd-sys";
|
||||
+ };
|
||||
+
|
||||
+ reg_dcdce: dcdce {
|
||||
+ regulator-always-on;
|
||||
+ regulator-min-microvolt = <1200000>;
|
||||
+ regulator-max-microvolt = <1200000>;
|
||||
+ regulator-name = "vcc-dram";
|
||||
+ };
|
||||
+
|
||||
+ sw {
|
||||
+ /* unused */
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&pwm {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&r_ir {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&rtc {
|
||||
+ clocks = <&ext_osc32k>;
|
||||
+};
|
||||
+
|
||||
+/delete-node/ &spi0;
|
||||
+
|
||||
+&uart0 {
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&uart0_ph_pins>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&usb2otg {
|
||||
+ dr_mode = "host";
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&usb2phy {
|
||||
+ usb0_id_det-gpios = <&pio 2 15 GPIO_ACTIVE_HIGH>; /* PC15 */
|
||||
+ usb0_vbus-supply = <®_vcc5v>;
|
||||
+ usb3_vbus-supply = <®_vcc5v>;
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&usb3phy {
|
||||
+ status = "okay";
|
||||
+};
|
||||
--
|
||||
2.39.2
|
||||
|
@ -0,0 +1,49 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Mon, 30 Dec 2019 12:39:31 -0600
|
||||
Subject: [PATCH] Revert "clk: qcom: Support 'protected-clocks' property"
|
||||
|
||||
Now that protected-clocks is handled in the clk core, this
|
||||
driver-specific implementation is redundant.
|
||||
|
||||
This reverts commit b181b3b801da8893c8eb706e448dd5111b02de60.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
drivers/clk/qcom/common.c | 18 ------------------
|
||||
1 file changed, 18 deletions(-)
|
||||
|
||||
--- a/drivers/clk/qcom/common.c
|
||||
+++ b/drivers/clk/qcom/common.c
|
||||
@@ -194,22 +194,6 @@ int qcom_cc_register_sleep_clk(struct de
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
|
||||
|
||||
-/* Drop 'protected-clocks' from the list of clocks to register */
|
||||
-static void qcom_cc_drop_protected(struct device *dev, struct qcom_cc *cc)
|
||||
-{
|
||||
- struct device_node *np = dev->of_node;
|
||||
- struct property *prop;
|
||||
- const __be32 *p;
|
||||
- u32 i;
|
||||
-
|
||||
- of_property_for_each_u32(np, "protected-clocks", prop, p, i) {
|
||||
- if (i >= cc->num_rclks)
|
||||
- continue;
|
||||
-
|
||||
- cc->rclks[i] = NULL;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
static struct clk_hw *qcom_cc_clk_hw_get(struct of_phandle_args *clkspec,
|
||||
void *data)
|
||||
{
|
||||
@@ -272,8 +256,6 @@ int qcom_cc_really_probe(struct platform
|
||||
cc->rclks = rclks;
|
||||
cc->num_rclks = num_clks;
|
||||
|
||||
- qcom_cc_drop_protected(dev, cc);
|
||||
-
|
||||
for (i = 0; i < num_clk_hws; i++) {
|
||||
ret = devm_clk_hw_register(dev, clk_hws[i]);
|
||||
if (ret)
|
@ -0,0 +1,67 @@
|
||||
From ba3b30a80ac2c388d48c58fbee242466d51fbfd8 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sun, 6 Dec 2020 11:15:34 -0600
|
||||
Subject: [PATCH 177/389] arm64: dts: allwinner: Enforce consistent MMC
|
||||
numbering
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 6 ++++++
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi | 6 ++++++
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 6 ++++++
|
||||
3 files changed, 18 insertions(+)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
index 77b5349f6087..9e0e17179839 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
|
||||
@@ -18,6 +18,12 @@ / {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
+ aliases {
|
||||
+ mmc0 = &mmc0;
|
||||
+ mmc1 = &mmc1;
|
||||
+ mmc2 = &mmc2;
|
||||
+ };
|
||||
+
|
||||
chosen {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
index a56fae761a1f..2159fa336d75 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h5.dtsi
|
||||
@@ -6,6 +6,12 @@
|
||||
#include <dt-bindings/thermal/thermal.h>
|
||||
|
||||
/ {
|
||||
+ aliases {
|
||||
+ mmc0 = &mmc0;
|
||||
+ mmc1 = &mmc1;
|
||||
+ mmc2 = &mmc2;
|
||||
+ };
|
||||
+
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
index ca1d287a0a01..3feac99556f3 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -17,6 +17,12 @@ / {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
+ aliases {
|
||||
+ mmc0 = &mmc0;
|
||||
+ mmc1 = &mmc1;
|
||||
+ mmc2 = &mmc2;
|
||||
+ };
|
||||
+
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
--
|
||||
2.35.3
|
||||
|
@ -0,0 +1,110 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Fri, 16 Aug 2019 16:40:20 +0200
|
||||
Subject: [PATCH] arm64: dts: allwinner: h6: Add AC200 EPHY related nodes
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 56 ++++++++++++++++++++
|
||||
1 file changed, 56 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -16,6 +16,16 @@
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
+ ac200_pwm_clk: ac200_clk {
|
||||
+ compatible = "pwm-clock";
|
||||
+ #clock-cells = <0>;
|
||||
+ clock-frequency = <24000000>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&pwm1_pin>;
|
||||
+ pwms = <&pwm 1 42 0>;
|
||||
+ status = "disabled";
|
||||
+ };
|
||||
+
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
@@ -319,6 +329,10 @@
|
||||
cpu_speed_grade: cpu-speed-grade@1c {
|
||||
reg = <0x1c 0x4>;
|
||||
};
|
||||
+
|
||||
+ ephy_calib: ephy_calib@2c {
|
||||
+ reg = <0x2c 0x2>;
|
||||
+ };
|
||||
};
|
||||
|
||||
timer@3009000 {
|
||||
@@ -373,6 +387,13 @@
|
||||
drive-strength = <40>;
|
||||
};
|
||||
|
||||
+ ext_rmii_pins: rmii_pins {
|
||||
+ pins = "PA0", "PA1", "PA2", "PA3", "PA4",
|
||||
+ "PA5", "PA6", "PA7", "PA8", "PA9";
|
||||
+ function = "emac";
|
||||
+ drive-strength = <40>;
|
||||
+ };
|
||||
+
|
||||
hdmi_pins: hdmi-pins {
|
||||
pins = "PH8", "PH9", "PH10";
|
||||
function = "hdmi";
|
||||
@@ -393,6 +414,11 @@
|
||||
function = "i2c2";
|
||||
};
|
||||
|
||||
+ i2c3_pins: i2c3-pins {
|
||||
+ pins = "PB17", "PB18";
|
||||
+ function = "i2c3";
|
||||
+ };
|
||||
+
|
||||
mmc0_pins: mmc0-pins {
|
||||
pins = "PF0", "PF1", "PF2", "PF3",
|
||||
"PF4", "PF5";
|
||||
@@ -419,6 +445,11 @@
|
||||
bias-pull-up;
|
||||
};
|
||||
|
||||
+ pwm1_pin: pwm1-pin {
|
||||
+ pins = "PB19";
|
||||
+ function = "pwm1";
|
||||
+ };
|
||||
+
|
||||
/omit-if-no-ref/
|
||||
spi0_pins: spi0-pins {
|
||||
pins = "PC0", "PC2", "PC3";
|
||||
@@ -652,6 +683,31 @@
|
||||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
+ i2c3: i2c@5002c00 {
|
||||
+ compatible = "allwinner,sun6i-a31-i2c";
|
||||
+ reg = <0x05002c00 0x400>;
|
||||
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ clocks = <&ccu CLK_BUS_I2C3>;
|
||||
+ resets = <&ccu RST_BUS_I2C3>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&i2c3_pins>;
|
||||
+ status = "disabled";
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <0>;
|
||||
+
|
||||
+ ac200: mfd@10 {
|
||||
+ compatible = "x-powers,ac200";
|
||||
+ reg = <0x10>;
|
||||
+ clocks = <&ac200_pwm_clk>;
|
||||
+
|
||||
+ ac200_ephy: phy {
|
||||
+ compatible = "x-powers,ac200-ephy";
|
||||
+ nvmem-cells = <&ephy_calib>;
|
||||
+ nvmem-cell-names = "ephy_calib";
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
emac: ethernet@5020000 {
|
||||
compatible = "allwinner,sun50i-h6-emac",
|
||||
"allwinner,sun50i-a64-emac";
|
@ -0,0 +1,46 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sat, 14 Dec 2019 20:54:40 -0600
|
||||
Subject: [PATCH] arm64: dts: allwinner: h6: Add SCPI protocol
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 20 ++++++++++++++++++++
|
||||
1 file changed, 20 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -88,6 +88,13 @@
|
||||
method = "smc";
|
||||
};
|
||||
|
||||
+ scpi_protocol: scpi {
|
||||
+ compatible = "arm,scpi";
|
||||
+ mboxes = <&msgbox 2>, <&msgbox 3>;
|
||||
+ mbox-names = "tx", "rx";
|
||||
+ shmem = <&scpi_sram>;
|
||||
+ };
|
||||
+
|
||||
timer {
|
||||
compatible = "arm,armv8-timer";
|
||||
arm,no-tick-in-suspend;
|
||||
@@ -196,6 +203,19 @@
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
+ sram_a2: sram@100000 {
|
||||
+ compatible = "mmio-sram";
|
||||
+ reg = <0x00100000 0x18000>;
|
||||
+ #address-cells = <1>;
|
||||
+ #size-cells = <1>;
|
||||
+ ranges = <0 0x00100000 0x18000>;
|
||||
+
|
||||
+ scpi_sram: scpi-sram@17c00 {
|
||||
+ compatible = "arm,scp-shmem";
|
||||
+ reg = <0x17c00 0x200>;
|
||||
+ };
|
||||
+ };
|
||||
+
|
||||
sram_c: sram@28000 {
|
||||
compatible = "mmio-sram";
|
||||
reg = <0x00028000 0x1e000>;
|
@ -0,0 +1,26 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Wed, 12 Oct 2022 23:01:04 +0200
|
||||
Subject: [PATCH] arm64: dts: allwinner: h6: Fix Cedrus IOMMU, again
|
||||
|
||||
Cedrus actually uses two IOMMU channels. Add the second one.
|
||||
|
||||
Fixes: 62a8ccf3a248 ("arm64: dts: allwinner: h6: Fix Cedrus IOMMU usage")
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
index e897559d9a89..436cc2a02d1a 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -172,7 +172,7 @@ video-codec@1c0e000 {
|
||||
resets = <&ccu RST_BUS_VE>;
|
||||
interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
|
||||
allwinner,sram = <&ve_sram 1>;
|
||||
- iommus = <&iommu 3>;
|
||||
+ iommus = <&iommu 1>, <&iommu 3>;
|
||||
};
|
||||
|
||||
gpu: gpu@1800000 {
|
@ -0,0 +1,31 @@
|
||||
From c009b3b707bbde30fa6ff49ca3075160524ea7b9 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Tue, 26 May 2020 20:08:27 +0200
|
||||
Subject: [PATCH 41/44] arm64: dts: h6 deinterlace
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
|
||||
@@ -160,6 +160,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ deinterlace: deinterlace@1420000 {
|
||||
+ compatible = "allwinner,sun50i-h6-deinterlace";
|
||||
+ reg = <0x01420000 0x2000>;
|
||||
+ clocks = <&ccu CLK_BUS_DEINTERLACE>,
|
||||
+ <&ccu CLK_DEINTERLACE>,
|
||||
+ <&ccu CLK_MBUS_DEINTERLACE>;
|
||||
+ clock-names = "bus", "mod", "ram";
|
||||
+ resets = <&ccu RST_BUS_DEINTERLACE>;
|
||||
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
|
||||
+ iommus = <&iommu 2>;
|
||||
+ };
|
||||
+
|
||||
video-codec@1c0e000 {
|
||||
compatible = "allwinner,sun50i-h6-video-engine";
|
||||
reg = <0x01c0e000 0x2000>;
|
@ -0,0 +1,197 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sun, 29 Dec 2019 20:23:28 -0600
|
||||
Subject: [PATCH] clk: Implement protected-clocks for all OF clock providers
|
||||
|
||||
This is a generic implementation of the "protected-clocks" property from
|
||||
the common clock binding. It allows firmware to inform the OS about
|
||||
clocks that must not be disabled while the OS is running.
|
||||
|
||||
This implementation comes with some caveats:
|
||||
|
||||
1) Clocks that have CLK_IS_CRITICAL in their init data are prepared/
|
||||
enabled before they are attached to the clock tree. protected-clocks are
|
||||
only protected once the clock provider is added, which is generally
|
||||
after all of the clocks it provides have been registered. This leaves a
|
||||
window of opportunity where something could disable or modify the clock,
|
||||
such as a driver running on another CPU, or the clock core itself. There
|
||||
is a comment to this effect in __clk_core_init():
|
||||
|
||||
/*
|
||||
* Enable CLK_IS_CRITICAL clocks so newly added critical clocks
|
||||
* don't get accidentally disabled when walking the orphan tree and
|
||||
* reparenting clocks
|
||||
*/
|
||||
|
||||
Similarly, these clocks will be enabled after they are first reparented,
|
||||
unlike other CLK_IS_CRITICAL clocks. See the comment in
|
||||
clk_core_reparent_orphans_nolock():
|
||||
|
||||
/*
|
||||
* We need to use __clk_set_parent_before() and _after() to
|
||||
* to properly migrate any prepare/enable count of the orphan
|
||||
* clock. This is important for CLK_IS_CRITICAL clocks, which
|
||||
* are enabled during init but might not have a parent yet.
|
||||
*/
|
||||
|
||||
Ideally we could detect protected clocks before they are reparented, but
|
||||
there are two problems with that:
|
||||
|
||||
a) From the clock core's perspective, hw->init is const.
|
||||
|
||||
b) The clock core doesn't see the device_node until __clk_register is
|
||||
called on the first clock.
|
||||
|
||||
So the only "race-free" way to detect protected-clocks is to do it in
|
||||
the middle of __clk_register, between when core->flags is initialized
|
||||
and calling __clk_core_init(). That requires scanning the device tree
|
||||
again for each clock, which is part of why I didn't do it that way.
|
||||
|
||||
2) __clk_protect needs to be idempotent, for two reasons:
|
||||
|
||||
a) Clocks with CLK_IS_CRITICAL in their init data are already
|
||||
prepared/enabled, and we don't want to prepare/enable them again.
|
||||
|
||||
b) of_clk_set_defaults() is called twice for (at least some) clock
|
||||
controllers registered with CLK_OF_DECLARE. It is called first in
|
||||
of_clk_add_provider()/of_clk_add_hw_provider() inside clk_init_cb,
|
||||
and again afterward in of_clk_init(). The second call in
|
||||
of_clk_init() may be unnecessary, but verifying that would require
|
||||
auditing all users of CLK_OF_DECLARE to ensure they called one of
|
||||
the of_clk_add{,_hw}_provider functions.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
drivers/clk/clk-conf.c | 54 ++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/clk/clk.c | 31 ++++++++++++++++++++++++
|
||||
drivers/clk/clk.h | 2 ++
|
||||
3 files changed, 87 insertions(+)
|
||||
|
||||
--- a/drivers/clk/clk-conf.c
|
||||
+++ b/drivers/clk/clk-conf.c
|
||||
@@ -11,6 +11,54 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
+#include "clk.h"
|
||||
+
|
||||
+static int __set_clk_flags(struct device_node *node)
|
||||
+{
|
||||
+ struct of_phandle_args clkspec;
|
||||
+ struct property *prop;
|
||||
+ int i, index = 0, rc;
|
||||
+ const __be32 *cur;
|
||||
+ struct clk *clk;
|
||||
+ u32 nr_cells;
|
||||
+
|
||||
+ rc = of_property_read_u32(node, "#clock-cells", &nr_cells);
|
||||
+ if (rc < 0) {
|
||||
+ pr_err("clk: missing #clock-cells property on %pOF\n", node);
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ clkspec.np = node;
|
||||
+ clkspec.args_count = nr_cells;
|
||||
+
|
||||
+ of_property_for_each_u32(node, "protected-clocks", prop, cur, clkspec.args[0]) {
|
||||
+ /* read the remainder of the clock specifier */
|
||||
+ for (i = 1; i < nr_cells; ++i) {
|
||||
+ cur = of_prop_next_u32(prop, cur, &clkspec.args[i]);
|
||||
+ if (!cur) {
|
||||
+ pr_err("clk: invalid value of protected-clocks"
|
||||
+ " property at %pOF\n", node);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+ clk = of_clk_get_from_provider(&clkspec);
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
+ pr_err("clk: couldn't get protected clock"
|
||||
+ " %u for %pOF\n", index, node);
|
||||
+ return PTR_ERR(clk);
|
||||
+ }
|
||||
+
|
||||
+ rc = __clk_protect(clk);
|
||||
+ if (rc < 0)
|
||||
+ pr_warn("clk: failed to protect %s: %d\n",
|
||||
+ __clk_get_name(clk), rc);
|
||||
+ clk_put(clk);
|
||||
+ index++;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int __set_clk_parents(struct device_node *node, bool clk_supplier)
|
||||
{
|
||||
struct of_phandle_args clkspec;
|
||||
@@ -135,6 +183,12 @@ int of_clk_set_defaults(struct device_no
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
+ if (clk_supplier) {
|
||||
+ rc = __set_clk_flags(node);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
rc = __set_clk_parents(node, clk_supplier);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
--- a/drivers/clk/clk.c
|
||||
+++ b/drivers/clk/clk.c
|
||||
@@ -4271,6 +4271,37 @@ struct clk *devm_clk_hw_get_clk(struct d
|
||||
EXPORT_SYMBOL_GPL(devm_clk_hw_get_clk);
|
||||
|
||||
/*
|
||||
+ * clk-conf helpers
|
||||
+ */
|
||||
+
|
||||
+int __clk_protect(struct clk *clk)
|
||||
+{
|
||||
+ struct clk_core *core = clk->core;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ clk_prepare_lock();
|
||||
+
|
||||
+ /*
|
||||
+ * If CLK_IS_CRITICAL was set in the clock's init data, then
|
||||
+ * the clock was already prepared/enabled when it was added.
|
||||
+ */
|
||||
+ if (core->flags & CLK_IS_CRITICAL)
|
||||
+ goto out;
|
||||
+
|
||||
+ core->flags |= CLK_IS_CRITICAL;
|
||||
+ ret = clk_core_prepare(core);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = clk_core_enable_lock(core);
|
||||
+
|
||||
+out:
|
||||
+ clk_prepare_unlock();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* clkdev helpers
|
||||
*/
|
||||
|
||||
--- a/drivers/clk/clk.h
|
||||
+++ b/drivers/clk/clk.h
|
||||
@@ -24,6 +24,7 @@ struct clk_hw *clk_find_hw(const char *d
|
||||
#ifdef CONFIG_COMMON_CLK
|
||||
struct clk *clk_hw_create_clk(struct device *dev, struct clk_hw *hw,
|
||||
const char *dev_id, const char *con_id);
|
||||
+int __clk_protect(struct clk *clk);
|
||||
void __clk_put(struct clk *clk);
|
||||
#else
|
||||
/* All these casts to avoid ifdefs in clkdev... */
|
||||
@@ -33,6 +34,7 @@ clk_hw_create_clk(struct device *dev, st
|
||||
{
|
||||
return (struct clk *)hw;
|
||||
}
|
||||
+static inline int __clk_protect(struct clk *clk) { return 0; }
|
||||
static inline void __clk_put(struct clk *clk) { }
|
||||
|
||||
#endif
|
@ -0,0 +1,122 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Tue, 5 Mar 2019 22:02:41 -0600
|
||||
Subject: [PATCH] firmware: arm_scpi: Support unidirectional mailbox channels
|
||||
|
||||
Some mailbox controllers have only unidirectional channels, so we need a
|
||||
pair of them for each SCPI channel. If a mbox-names property is present,
|
||||
look for "rx" and "tx" mbox channels; otherwise, the existing behavior
|
||||
is preserved, and a single mbox channel is used for each SCPI channel.
|
||||
|
||||
Note that since the mailbox framework only supports a single phandle
|
||||
with each name (mbox_request_channel_byname always returns the first
|
||||
one), this new mode only supports a single SCPI channel.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
drivers/firmware/arm_scpi.c | 58 +++++++++++++++++++++++++++++--------
|
||||
1 file changed, 46 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/firmware/arm_scpi.c
|
||||
+++ b/drivers/firmware/arm_scpi.c
|
||||
@@ -231,7 +231,8 @@ struct scpi_xfer {
|
||||
|
||||
struct scpi_chan {
|
||||
struct mbox_client cl;
|
||||
- struct mbox_chan *chan;
|
||||
+ struct mbox_chan *rx_chan;
|
||||
+ struct mbox_chan *tx_chan;
|
||||
void __iomem *tx_payload;
|
||||
void __iomem *rx_payload;
|
||||
struct list_head rx_pending;
|
||||
@@ -505,7 +506,7 @@ static int scpi_send_message(u8 idx, voi
|
||||
msg->rx_len = rx_len;
|
||||
reinit_completion(&msg->done);
|
||||
|
||||
- ret = mbox_send_message(scpi_chan->chan, msg);
|
||||
+ ret = mbox_send_message(scpi_chan->tx_chan, msg);
|
||||
if (ret < 0 || !rx_buf)
|
||||
goto out;
|
||||
|
||||
@@ -856,8 +857,13 @@ static void scpi_free_channels(void *dat
|
||||
struct scpi_drvinfo *info = data;
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < info->num_chans; i++)
|
||||
- mbox_free_channel(info->channels[i].chan);
|
||||
+ for (i = 0; i < info->num_chans; i++) {
|
||||
+ struct scpi_chan *pchan = &info->channels[i];
|
||||
+
|
||||
+ if (pchan->tx_chan != pchan->rx_chan)
|
||||
+ mbox_free_channel(pchan->tx_chan);
|
||||
+ mbox_free_channel(pchan->rx_chan);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int scpi_remove(struct platform_device *pdev)
|
||||
@@ -913,6 +919,7 @@ static int scpi_probe(struct platform_de
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct scpi_drvinfo *scpi_drvinfo;
|
||||
+ bool use_mbox_names = false;
|
||||
|
||||
scpi_drvinfo = devm_kzalloc(dev, sizeof(*scpi_drvinfo), GFP_KERNEL);
|
||||
if (!scpi_drvinfo)
|
||||
@@ -926,6 +933,14 @@ static int scpi_probe(struct platform_de
|
||||
dev_err(dev, "no mboxes property in '%pOF'\n", np);
|
||||
return -ENODEV;
|
||||
}
|
||||
+ if (of_get_property(dev->of_node, "mbox-names", NULL)) {
|
||||
+ use_mbox_names = true;
|
||||
+ if (count != 2) {
|
||||
+ dev_err(dev, "need exactly 2 mboxes with mbox-names\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ count /= 2;
|
||||
+ }
|
||||
|
||||
scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
|
||||
GFP_KERNEL);
|
||||
@@ -974,15 +989,34 @@ static int scpi_probe(struct platform_de
|
||||
mutex_init(&pchan->xfers_lock);
|
||||
|
||||
ret = scpi_alloc_xfer_list(dev, pchan);
|
||||
- if (!ret) {
|
||||
- pchan->chan = mbox_request_channel(cl, idx);
|
||||
- if (!IS_ERR(pchan->chan))
|
||||
- continue;
|
||||
- ret = PTR_ERR(pchan->chan);
|
||||
- if (ret != -EPROBE_DEFER)
|
||||
- dev_err(dev, "failed to get channel%d err %d\n",
|
||||
- idx, ret);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (use_mbox_names) {
|
||||
+ pchan->rx_chan = mbox_request_channel_byname(cl, "rx");
|
||||
+ if (IS_ERR(pchan->rx_chan)) {
|
||||
+ ret = PTR_ERR(pchan->rx_chan);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ pchan->tx_chan = mbox_request_channel_byname(cl, "tx");
|
||||
+ if (IS_ERR(pchan->rx_chan)) {
|
||||
+ ret = PTR_ERR(pchan->tx_chan);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ } else {
|
||||
+ pchan->rx_chan = mbox_request_channel(cl, idx);
|
||||
+ if (IS_ERR(pchan->rx_chan)) {
|
||||
+ ret = PTR_ERR(pchan->rx_chan);
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ pchan->tx_chan = pchan->rx_chan;
|
||||
}
|
||||
+ continue;
|
||||
+
|
||||
+fail:
|
||||
+ if (ret != -EPROBE_DEFER)
|
||||
+ dev_err(dev, "failed to get channel%d err %d\n",
|
||||
+ idx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
From 791849a059cce08f238491b8cae1c3d452edcda5 Mon Sep 17 00:00:00 2001
|
||||
From: OpenEmbedded <oe.patch@oe>
|
||||
Date: Wed, 6 Dec 2023 00:37:25 +0100
|
||||
Subject: [PATCH 1/2] fix orange pi 3lts rtc on faulty boards"
|
||||
|
||||
---
|
||||
arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
index 67f38b8a1..e3337c6f2 100644
|
||||
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
|
||||
@@ -331,10 +331,10 @@ &pwm {
|
||||
&r_ir {
|
||||
status = "okay";
|
||||
};
|
||||
-
|
||||
+/*
|
||||
&rtc {
|
||||
clocks = <&ext_osc32k>;
|
||||
-};
|
||||
+};*/
|
||||
|
||||
/delete-node/ &spi0;
|
||||
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,3 @@
|
||||
# Optional patch for 3 lts that deactivates external 32Khz crystals and fallback to internal clock
|
||||
# This fix rtc problems at the cost of clock accuracy on faulty boards
|
||||
patch fix-orange-pi-3lts-rtc-on-faulty-boards.patch
|
@ -0,0 +1,107 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Fri, 14 Oct 2022 20:15:43 +0200
|
||||
Subject: [PATCH] iommu/sun50i: Allow page sizes multiple of 4096
|
||||
|
||||
While peripheral supports only 4K page sizes, we can easily emulate
|
||||
support for bigger page sizes, up to 1M. This is done by making multiple
|
||||
entries in map function or clearing multiple entries in unmap.
|
||||
|
||||
This considerably lowers overhead.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/iommu/sun50i-iommu.c | 44 +++++++++++++++++++++---------------
|
||||
1 file changed, 26 insertions(+), 18 deletions(-)
|
||||
|
||||
diff --git a/drivers/iommu/sun50i-iommu.c b/drivers/iommu/sun50i-iommu.c
|
||||
index d7c5e9b1a087..9944266c4f58 100644
|
||||
--- a/drivers/iommu/sun50i-iommu.c
|
||||
+++ b/drivers/iommu/sun50i-iommu.c
|
||||
@@ -593,10 +593,12 @@ static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova,
|
||||
{
|
||||
struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain);
|
||||
struct sun50i_iommu *iommu = sun50i_domain->iommu;
|
||||
- u32 pte_index;
|
||||
+ u32 pte_index, pages, i;
|
||||
u32 *page_table, *pte_addr;
|
||||
int ret = 0;
|
||||
|
||||
+ pages = size / SPAGE_SIZE;
|
||||
+
|
||||
page_table = sun50i_dte_get_page_table(sun50i_domain, iova, gfp);
|
||||
if (IS_ERR(page_table)) {
|
||||
ret = PTR_ERR(page_table);
|
||||
@@ -604,18 +606,21 @@ static int sun50i_iommu_map(struct iommu_domain *domain, unsigned long iova,
|
||||
}
|
||||
|
||||
pte_index = sun50i_iova_get_pte_index(iova);
|
||||
- pte_addr = &page_table[pte_index];
|
||||
- if (unlikely(sun50i_pte_is_page_valid(*pte_addr))) {
|
||||
- phys_addr_t page_phys = sun50i_pte_get_page_address(*pte_addr);
|
||||
- dev_err(iommu->dev,
|
||||
- "iova %pad already mapped to %pa cannot remap to %pa prot: %#x\n",
|
||||
- &iova, &page_phys, &paddr, prot);
|
||||
- ret = -EBUSY;
|
||||
- goto out;
|
||||
+ for (i = 0; i < pages; i++) {
|
||||
+ pte_addr = &page_table[pte_index + i];
|
||||
+ if (unlikely(sun50i_pte_is_page_valid(*pte_addr))) {
|
||||
+ phys_addr_t page_phys = sun50i_pte_get_page_address(*pte_addr);
|
||||
+ dev_err(iommu->dev,
|
||||
+ "iova %pad already mapped to %pa cannot remap to %pa prot: %#x\n",
|
||||
+ &iova, &page_phys, &paddr, prot);
|
||||
+ ret = -EBUSY;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ *pte_addr = sun50i_mk_pte(paddr, prot);
|
||||
+ paddr += SPAGE_SIZE;
|
||||
}
|
||||
|
||||
- *pte_addr = sun50i_mk_pte(paddr, prot);
|
||||
- sun50i_table_flush(sun50i_domain, pte_addr, 1);
|
||||
+ sun50i_table_flush(sun50i_domain, &page_table[pte_index], pages);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
@@ -626,8 +631,10 @@ static size_t sun50i_iommu_unmap(struct iommu_domain *domain, unsigned long iova
|
||||
{
|
||||
struct sun50i_iommu_domain *sun50i_domain = to_sun50i_domain(domain);
|
||||
phys_addr_t pt_phys;
|
||||
+ u32 dte, pages, i;
|
||||
u32 *pte_addr;
|
||||
- u32 dte;
|
||||
+
|
||||
+ pages = size / SPAGE_SIZE;
|
||||
|
||||
dte = sun50i_domain->dt[sun50i_iova_get_dte_index(iova)];
|
||||
if (!sun50i_dte_is_pt_valid(dte))
|
||||
@@ -636,13 +643,14 @@ static size_t sun50i_iommu_unmap(struct iommu_domain *domain, unsigned long iova
|
||||
pt_phys = sun50i_dte_get_pt_address(dte);
|
||||
pte_addr = (u32 *)phys_to_virt(pt_phys) + sun50i_iova_get_pte_index(iova);
|
||||
|
||||
- if (!sun50i_pte_is_page_valid(*pte_addr))
|
||||
- return 0;
|
||||
+ for (i = 0; i < pages; i++)
|
||||
+ if (!sun50i_pte_is_page_valid(pte_addr[i]))
|
||||
+ return 0;
|
||||
|
||||
- memset(pte_addr, 0, sizeof(*pte_addr));
|
||||
- sun50i_table_flush(sun50i_domain, pte_addr, 1);
|
||||
+ memset(pte_addr, 0, sizeof(*pte_addr) * pages);
|
||||
+ sun50i_table_flush(sun50i_domain, pte_addr, pages);
|
||||
|
||||
- return SZ_4K;
|
||||
+ return size;
|
||||
}
|
||||
|
||||
static phys_addr_t sun50i_iommu_iova_to_phys(struct iommu_domain *domain,
|
||||
@@ -828,7 +836,7 @@ static int sun50i_iommu_of_xlate(struct device *dev,
|
||||
}
|
||||
|
||||
static const struct iommu_ops sun50i_iommu_ops = {
|
||||
- .pgsize_bitmap = SZ_4K,
|
||||
+ .pgsize_bitmap = 0x1ff000,
|
||||
.device_group = sun50i_iommu_device_group,
|
||||
.domain_alloc = sun50i_iommu_domain_alloc,
|
||||
.of_xlate = sun50i_iommu_of_xlate,
|
@ -0,0 +1,406 @@
|
||||
From 59adceb6f34521c0f1a229f20ee9961269daa539 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Fri, 16 Aug 2019 16:38:21 +0200
|
||||
Subject: [PATCH 38/44] mfd: Add support for AC200
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
drivers/mfd/Kconfig | 9 ++
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/ac200.c | 150 +++++++++++++++++++++++++++
|
||||
include/linux/mfd/ac200.h | 209 ++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 369 insertions(+)
|
||||
create mode 100644 drivers/mfd/ac200.c
|
||||
create mode 100644 include/linux/mfd/ac200.h
|
||||
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -178,6 +178,15 @@ config MFD_AC100
|
||||
This driver include only the core APIs. You have to select individual
|
||||
components like codecs or RTC under the corresponding menus.
|
||||
|
||||
+config MFD_AC200
|
||||
+ tristate "X-Powers AC200"
|
||||
+ select MFD_CORE
|
||||
+ depends on I2C
|
||||
+ help
|
||||
+ If you say Y here you get support for the X-Powers AC200 IC.
|
||||
+ This driver include only the core APIs. You have to select individual
|
||||
+ components like Ethernet PHY or RTC under the corresponding menus.
|
||||
+
|
||||
config MFD_AXP20X
|
||||
tristate
|
||||
select MFD_CORE
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -142,6 +142,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-s
|
||||
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
|
||||
|
||||
obj-$(CONFIG_MFD_AC100) += ac100.o
|
||||
+obj-$(CONFIG_MFD_AC200) += ac200.o
|
||||
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
|
||||
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
|
||||
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/ac200.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * MFD core driver for X-Powers' AC200 IC
|
||||
+ *
|
||||
+ * The AC200 is a chip which is co-packaged with Allwinner H6 SoC and
|
||||
+ * includes analog audio codec, analog TV encoder, ethernet PHY, eFuse
|
||||
+ * and RTC.
|
||||
+ *
|
||||
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
+ *
|
||||
+ * Based on AC100 driver with following copyrights:
|
||||
+ * Copyright (2016) Chen-Yu Tsai
|
||||
+ */
|
||||
+
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/mfd/ac200.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+
|
||||
+static const struct regmap_range_cfg ac200_range_cfg[] = {
|
||||
+ {
|
||||
+ .range_min = AC200_SYS_VERSION,
|
||||
+ .range_max = AC200_IC_CHARA1,
|
||||
+ .selector_reg = AC200_TWI_REG_ADDR_H,
|
||||
+ .selector_mask = 0xff,
|
||||
+ .selector_shift = 0,
|
||||
+ .window_start = 0,
|
||||
+ .window_len = 256,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config ac200_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 16,
|
||||
+ .ranges = ac200_range_cfg,
|
||||
+ .num_ranges = ARRAY_SIZE(ac200_range_cfg),
|
||||
+ .max_register = AC200_IC_CHARA1,
|
||||
+};
|
||||
+
|
||||
+static struct mfd_cell ac200_cells[] = {
|
||||
+ {
|
||||
+ .name = "ac200-codec",
|
||||
+ .of_compatible = "x-powers,ac200-codec",
|
||||
+ }, {
|
||||
+ .name = "ac200-efuse",
|
||||
+ .of_compatible = "x-powers,ac200-efuse",
|
||||
+ }, {
|
||||
+ .name = "ac200-ephy",
|
||||
+ .of_compatible = "x-powers,ac200-ephy",
|
||||
+ }, {
|
||||
+ .name = "ac200-rtc",
|
||||
+ .of_compatible = "x-powers,ac200-rtc",
|
||||
+ }, {
|
||||
+ .name = "ac200-tve",
|
||||
+ .of_compatible = "x-powers,ac200-tve",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int ac200_i2c_probe(struct i2c_client *i2c,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct device *dev = &i2c->dev;
|
||||
+ struct ac200_dev *ac200;
|
||||
+ int ret;
|
||||
+
|
||||
+ ac200 = devm_kzalloc(dev, sizeof(*ac200), GFP_KERNEL);
|
||||
+ if (!ac200)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ i2c_set_clientdata(i2c, ac200);
|
||||
+
|
||||
+ ac200->clk = devm_clk_get(dev, NULL);
|
||||
+ if (IS_ERR(ac200->clk)) {
|
||||
+ ret = PTR_ERR(ac200->clk);
|
||||
+ dev_err(dev, "Can't obtain the clock: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ac200->regmap = devm_regmap_init_i2c(i2c, &ac200_regmap_config);
|
||||
+ if (IS_ERR(ac200->regmap)) {
|
||||
+ ret = PTR_ERR(ac200->regmap);
|
||||
+ dev_err(dev, "Regmap init failed: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = clk_prepare_enable(ac200->clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL, 0);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL, 1);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ac200_cells,
|
||||
+ ARRAY_SIZE(ac200_cells), NULL, 0, NULL);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to add MFD devices: %d\n", ret);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ clk_disable_unprepare(ac200->clk);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+void ac200_i2c_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ struct ac200_dev *ac200 = i2c_get_clientdata(i2c);
|
||||
+
|
||||
+ regmap_write(ac200->regmap, AC200_SYS_CONTROL, 0);
|
||||
+
|
||||
+ clk_disable_unprepare(ac200->clk);
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id ac200_ids[] = {
|
||||
+ { "ac200", },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, ac200_ids);
|
||||
+
|
||||
+static const struct of_device_id ac200_of_match[] = {
|
||||
+ { .compatible = "x-powers,ac200" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ac200_of_match);
|
||||
+
|
||||
+static struct i2c_driver ac200_i2c_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "ac200",
|
||||
+ .of_match_table = of_match_ptr(ac200_of_match),
|
||||
+ },
|
||||
+ .probe = ac200_i2c_probe,
|
||||
+ .remove = ac200_i2c_remove,
|
||||
+ .id_table = ac200_ids,
|
||||
+};
|
||||
+module_i2c_driver(ac200_i2c_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("MFD core driver for AC200");
|
||||
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/ac200.h
|
||||
@@ -0,0 +1,209 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/*
|
||||
+ * AC200 register list
|
||||
+ *
|
||||
+ * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_MFD_AC200_H
|
||||
+#define __LINUX_MFD_AC200_H
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+/* interface registers (can be accessed from any page) */
|
||||
+#define AC200_TWI_CHANGE_TO_RSB 0x3E
|
||||
+#define AC200_TWI_PAD_DELAY 0xC4
|
||||
+#define AC200_TWI_REG_ADDR_H 0xFE
|
||||
+
|
||||
+/* General registers */
|
||||
+#define AC200_SYS_VERSION 0x0000
|
||||
+#define AC200_SYS_CONTROL 0x0002
|
||||
+#define AC200_SYS_IRQ_ENABLE 0x0004
|
||||
+#define AC200_SYS_IRQ_STATUS 0x0006
|
||||
+#define AC200_SYS_CLK_CTL 0x0008
|
||||
+#define AC200_SYS_DLDO_OSC_CTL 0x000A
|
||||
+#define AC200_SYS_PLL_CTL0 0x000C
|
||||
+#define AC200_SYS_PLL_CTL1 0x000E
|
||||
+#define AC200_SYS_AUDIO_CTL0 0x0010
|
||||
+#define AC200_SYS_AUDIO_CTL1 0x0012
|
||||
+#define AC200_SYS_EPHY_CTL0 0x0014
|
||||
+#define AC200_SYS_EPHY_CTL1 0x0016
|
||||
+#define AC200_SYS_TVE_CTL0 0x0018
|
||||
+#define AC200_SYS_TVE_CTL1 0x001A
|
||||
+
|
||||
+/* Audio Codec registers */
|
||||
+#define AC200_AC_SYS_CLK_CTL 0x2000
|
||||
+#define AC200_SYS_MOD_RST 0x2002
|
||||
+#define AC200_SYS_SAMP_CTL 0x2004
|
||||
+#define AC200_I2S_CTL 0x2100
|
||||
+#define AC200_I2S_CLK 0x2102
|
||||
+#define AC200_I2S_FMT0 0x2104
|
||||
+#define AC200_I2S_FMT1 0x2108
|
||||
+#define AC200_I2S_MIX_SRC 0x2114
|
||||
+#define AC200_I2S_MIX_GAIN 0x2116
|
||||
+#define AC200_I2S_DACDAT_DVC 0x2118
|
||||
+#define AC200_I2S_ADCDAT_DVC 0x211A
|
||||
+#define AC200_AC_DAC_DPC 0x2200
|
||||
+#define AC200_AC_DAC_MIX_SRC 0x2202
|
||||
+#define AC200_AC_DAC_MIX_GAIN 0x2204
|
||||
+#define AC200_DACA_OMIXER_CTRL 0x2220
|
||||
+#define AC200_OMIXER_SR 0x2222
|
||||
+#define AC200_LINEOUT_CTRL 0x2224
|
||||
+#define AC200_AC_ADC_DPC 0x2300
|
||||
+#define AC200_MBIAS_CTRL 0x2310
|
||||
+#define AC200_ADC_MIC_CTRL 0x2320
|
||||
+#define AC200_ADCMIXER_SR 0x2322
|
||||
+#define AC200_ANALOG_TUNING0 0x232A
|
||||
+#define AC200_ANALOG_TUNING1 0x232C
|
||||
+#define AC200_AC_AGC_SEL 0x2480
|
||||
+#define AC200_ADC_DAPLCTRL 0x2500
|
||||
+#define AC200_ADC_DAPRCTRL 0x2502
|
||||
+#define AC200_ADC_DAPLSTA 0x2504
|
||||
+#define AC200_ADC_DAPRSTA 0x2506
|
||||
+#define AC200_ADC_DAPLTL 0x2508
|
||||
+#define AC200_ADC_DAPRTL 0x250A
|
||||
+#define AC200_ADC_DAPLHAC 0x250C
|
||||
+#define AC200_ADC_DAPLLAC 0x250E
|
||||
+#define AC200_ADC_DAPRHAC 0x2510
|
||||
+#define AC200_ADC_DAPRLAC 0x2512
|
||||
+#define AC200_ADC_DAPLDT 0x2514
|
||||
+#define AC200_ADC_DAPLAT 0x2516
|
||||
+#define AC200_ADC_DAPRDT 0x2518
|
||||
+#define AC200_ADC_DAPRAT 0x251A
|
||||
+#define AC200_ADC_DAPNTH 0x251C
|
||||
+#define AC200_ADC_DAPLHNAC 0x251E
|
||||
+#define AC200_ADC_DAPLLNAC 0x2520
|
||||
+#define AC200_ADC_DAPRHNAC 0x2522
|
||||
+#define AC200_ADC_DAPRLNAC 0x2524
|
||||
+#define AC200_AC_DAPHHPFC 0x2526
|
||||
+#define AC200_AC_DAPLHPFC 0x2528
|
||||
+#define AC200_AC_DAPOPT 0x252A
|
||||
+#define AC200_AC_DAC_DAPCTRL 0x3000
|
||||
+#define AC200_AC_DRC_HHPFC 0x3002
|
||||
+#define AC200_AC_DRC_LHPFC 0x3004
|
||||
+#define AC200_AC_DRC_CTRL 0x3006
|
||||
+#define AC200_AC_DRC_LPFHAT 0x3008
|
||||
+#define AC200_AC_DRC_LPFLAT 0x300A
|
||||
+#define AC200_AC_DRC_RPFHAT 0x300C
|
||||
+#define AC200_AC_DRC_RPFLAT 0x300E
|
||||
+#define AC200_AC_DRC_LPFHRT 0x3010
|
||||
+#define AC200_AC_DRC_LPFLRT 0x3012
|
||||
+#define AC200_AC_DRC_RPFHRT 0x3014
|
||||
+#define AC200_AC_DRC_RPFLRT 0x3016
|
||||
+#define AC200_AC_DRC_LRMSHAT 0x3018
|
||||
+#define AC200_AC_DRC_LRMSLAT 0x301A
|
||||
+#define AC200_AC_DRC_RRMSHAT 0x301C
|
||||
+#define AC200_AC_DRC_RRMSLAT 0x301E
|
||||
+#define AC200_AC_DRC_HCT 0x3020
|
||||
+#define AC200_AC_DRC_LCT 0x3022
|
||||
+#define AC200_AC_DRC_HKC 0x3024
|
||||
+#define AC200_AC_DRC_LKC 0x3026
|
||||
+#define AC200_AC_DRC_HOPC 0x3028
|
||||
+#define AC200_AC_DRC_LOPC 0x302A
|
||||
+#define AC200_AC_DRC_HLT 0x302C
|
||||
+#define AC200_AC_DRC_LLT 0x302E
|
||||
+#define AC200_AC_DRC_HKI 0x3030
|
||||
+#define AC200_AC_DRC_LKI 0x3032
|
||||
+#define AC200_AC_DRC_HOPL 0x3034
|
||||
+#define AC200_AC_DRC_LOPL 0x3036
|
||||
+#define AC200_AC_DRC_HET 0x3038
|
||||
+#define AC200_AC_DRC_LET 0x303A
|
||||
+#define AC200_AC_DRC_HKE 0x303C
|
||||
+#define AC200_AC_DRC_LKE 0x303E
|
||||
+#define AC200_AC_DRC_HOPE 0x3040
|
||||
+#define AC200_AC_DRC_LOPE 0x3042
|
||||
+#define AC200_AC_DRC_HKN 0x3044
|
||||
+#define AC200_AC_DRC_LKN 0x3046
|
||||
+#define AC200_AC_DRC_SFHAT 0x3048
|
||||
+#define AC200_AC_DRC_SFLAT 0x304A
|
||||
+#define AC200_AC_DRC_SFHRT 0x304C
|
||||
+#define AC200_AC_DRC_SFLRT 0x304E
|
||||
+#define AC200_AC_DRC_MXGHS 0x3050
|
||||
+#define AC200_AC_DRC_MXGLS 0x3052
|
||||
+#define AC200_AC_DRC_MNGHS 0x3054
|
||||
+#define AC200_AC_DRC_MNGLS 0x3056
|
||||
+#define AC200_AC_DRC_EPSHC 0x3058
|
||||
+#define AC200_AC_DRC_EPSLC 0x305A
|
||||
+#define AC200_AC_DRC_HPFHGAIN 0x305E
|
||||
+#define AC200_AC_DRC_HPFLGAIN 0x3060
|
||||
+#define AC200_AC_DRC_BISTCR 0x3100
|
||||
+#define AC200_AC_DRC_BISTST 0x3102
|
||||
+
|
||||
+/* TVE registers */
|
||||
+#define AC200_TVE_CTL0 0x4000
|
||||
+#define AC200_TVE_CTL1 0x4002
|
||||
+#define AC200_TVE_MOD0 0x4004
|
||||
+#define AC200_TVE_MOD1 0x4006
|
||||
+#define AC200_TVE_DAC_CFG0 0x4008
|
||||
+#define AC200_TVE_DAC_CFG1 0x400A
|
||||
+#define AC200_TVE_YC_DELAY 0x400C
|
||||
+#define AC200_TVE_YC_FILTER 0x400E
|
||||
+#define AC200_TVE_BURST_FRQ0 0x4010
|
||||
+#define AC200_TVE_BURST_FRQ1 0x4012
|
||||
+#define AC200_TVE_FRONT_PORCH 0x4014
|
||||
+#define AC200_TVE_BACK_PORCH 0x4016
|
||||
+#define AC200_TVE_TOTAL_LINE 0x401C
|
||||
+#define AC200_TVE_FIRST_ACTIVE 0x401E
|
||||
+#define AC200_TVE_BLACK_LEVEL 0x4020
|
||||
+#define AC200_TVE_BLANK_LEVEL 0x4022
|
||||
+#define AC200_TVE_PLUG_EN 0x4030
|
||||
+#define AC200_TVE_PLUG_IRQ_EN 0x4032
|
||||
+#define AC200_TVE_PLUG_IRQ_STA 0x4034
|
||||
+#define AC200_TVE_PLUG_STA 0x4038
|
||||
+#define AC200_TVE_PLUG_DEBOUNCE 0x4040
|
||||
+#define AC200_TVE_DAC_TEST 0x4042
|
||||
+#define AC200_TVE_PLUG_PULSE_LEVEL 0x40F4
|
||||
+#define AC200_TVE_PLUG_PULSE_START 0x40F8
|
||||
+#define AC200_TVE_PLUG_PULSE_PERIOD 0x40FA
|
||||
+#define AC200_TVE_IF_CTL 0x5000
|
||||
+#define AC200_TVE_IF_TIM0 0x5008
|
||||
+#define AC200_TVE_IF_TIM1 0x500A
|
||||
+#define AC200_TVE_IF_TIM2 0x500C
|
||||
+#define AC200_TVE_IF_TIM3 0x500E
|
||||
+#define AC200_TVE_IF_SYNC0 0x5010
|
||||
+#define AC200_TVE_IF_SYNC1 0x5012
|
||||
+#define AC200_TVE_IF_SYNC2 0x5014
|
||||
+#define AC200_TVE_IF_TIM4 0x5016
|
||||
+#define AC200_TVE_IF_STATUS 0x5018
|
||||
+
|
||||
+/* EPHY registers */
|
||||
+#define AC200_EPHY_CTL 0x6000
|
||||
+#define AC200_EPHY_BIST 0x6002
|
||||
+
|
||||
+/* eFuse registers (0x8000 - 0x9FFF, layout unknown) */
|
||||
+
|
||||
+/* RTC registers */
|
||||
+#define AC200_LOSC_CTRL0 0xA000
|
||||
+#define AC200_LOSC_CTRL1 0xA002
|
||||
+#define AC200_LOSC_AUTO_SWT_STA 0xA004
|
||||
+#define AC200_INTOSC_CLK_PRESCAL 0xA008
|
||||
+#define AC200_RTC_YY_MM_DD0 0xA010
|
||||
+#define AC200_RTC_YY_MM_DD1 0xA012
|
||||
+#define AC200_RTC_HH_MM_SS0 0xA014
|
||||
+#define AC200_RTC_HH_MM_SS1 0xA016
|
||||
+#define AC200_ALARM0_CUR_VLU0 0xA024
|
||||
+#define AC200_ALARM0_CUR_VLU1 0xA026
|
||||
+#define AC200_ALARM0_ENABLE 0xA028
|
||||
+#define AC200_ALARM0_IRQ_EN 0xA02C
|
||||
+#define AC200_ALARM0_IRQ_STA 0xA030
|
||||
+#define AC200_ALARM1_WK_HH_MM_SS0 0xA040
|
||||
+#define AC200_ALARM1_WK_HH_MM_SS1 0xA042
|
||||
+#define AC200_ALARM1_ENABLE 0xA044
|
||||
+#define AC200_ALARM1_IRQ_EN 0xA048
|
||||
+#define AC200_ALARM1_IRQ_STA 0xA04C
|
||||
+#define AC200_ALARM_CONFIG 0xA050
|
||||
+#define AC200_LOSC_OUT_GATING 0xA060
|
||||
+#define AC200_GP_DATA(x) (0xA100 + (x) * 2)
|
||||
+#define AC200_RTC_DEB 0xA170
|
||||
+#define AC200_GPL_HOLD_OUTPUT 0xA180
|
||||
+#define AC200_VDD_RTC 0xA190
|
||||
+#define AC200_IC_CHARA0 0xA1F0
|
||||
+#define AC200_IC_CHARA1 0xA1F2
|
||||
+
|
||||
+struct ac200_dev {
|
||||
+ struct clk *clk;
|
||||
+ struct regmap *regmap;
|
||||
+};
|
||||
+
|
||||
+#endif /* __LINUX_MFD_AC200_H */
|
@ -0,0 +1,374 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andre Przywara <andre.przywara@arm.com>
|
||||
Date: Mon, 13 Jun 2022 17:37:19 +0100
|
||||
Subject: mfd: Add support for X-Powers AC200 EPHY syscon
|
||||
|
||||
The X-Powers AC200 mixed signal chip contains a 100Mbit/s Ethernet PHY.
|
||||
While the PHY is using the standard MDIO and MII/RMII interfaces to
|
||||
the MAC, there are some registers in the AC200 that need to be setup to
|
||||
make the PHY functional:
|
||||
- The MDIO PHY address needs to set.
|
||||
- The LED polarity needs to be configured.
|
||||
- The MII interface mode needs to be set (MII or RMII).
|
||||
- There is a reset line that controls the PHY operation.
|
||||
- There is a clock gate that blocks or forwards the AC200's internal clock
|
||||
to the PHY.
|
||||
|
||||
This driver here takes care of those setup needs, but does not cover the
|
||||
actual PHY operation. Once the PHY is set up and enabled, it behaves like
|
||||
a standard MDIO/MII controlled PHY, and can be driven by the IEEE802.3-C22
|
||||
driver.
|
||||
|
||||
To some degree those parameters mimic the typical wired setup of a
|
||||
physical PHY chip: the LED polarity, MII interface mode and PHY address
|
||||
are typically configued via connecting certain pins. We use the
|
||||
devicetree to learn those parameters, which depend on the board setup.
|
||||
|
||||
This driver is a child of the AC200 MFD parent device, and uses its
|
||||
regmap and input clock. It also provides a reset and clock controller,
|
||||
which the actual PHY device (node) needs to refer to. This ensures that
|
||||
this PHY control device is initialised before the PHY is expected to work.
|
||||
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
drivers/phy/allwinner/Kconfig | 9 +
|
||||
drivers/phy/allwinner/Makefile | 1 +
|
||||
drivers/phy/allwinner/ac200-ephy-ctl.c | 301 ++++++++++
|
||||
3 files changed, 311 insertions(+)
|
||||
|
||||
diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
|
||||
index e93a53139460..d3614169de5c 100644
|
||||
--- a/drivers/phy/allwinner/Kconfig
|
||||
+++ b/drivers/phy/allwinner/Kconfig
|
||||
@@ -58,3 +58,12 @@ config PHY_SUN50I_USB3
|
||||
part of Allwinner H6 SoC.
|
||||
|
||||
This driver controls each individual USB 2+3 host PHY combo.
|
||||
+
|
||||
+config AC200_PHY_CTL
|
||||
+ tristate "X-Power AC200 PHY control driver"
|
||||
+ depends on MFD_AC200
|
||||
+ depends on RESET_CONTROLLER
|
||||
+ help
|
||||
+ Enable this to support the Ethernet PHY operation of the AC200
|
||||
+ mixed signal chip. This driver just enables and configures the
|
||||
+ PHY, the PHY itself is supported by a standard driver.
|
||||
diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile
|
||||
index bd74901a1255..0eecec7a908a 100644
|
||||
--- a/drivers/phy/allwinner/Makefile
|
||||
+++ b/drivers/phy/allwinner/Makefile
|
||||
@@ -3,3 +3,4 @@ obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
|
||||
obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o
|
||||
obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o
|
||||
obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o
|
||||
+obj-$(CONFIG_AC200_PHY_CTL) += ac200-ephy-ctl.o
|
||||
diff --git a/drivers/phy/allwinner/ac200-ephy-ctl.c b/drivers/phy/allwinner/ac200-ephy-ctl.c
|
||||
new file mode 100644
|
||||
index 000000000000..8efeaf18e42c
|
||||
--- /dev/null
|
||||
+++ b/drivers/phy/allwinner/ac200-ephy-ctl.c
|
||||
@@ -0,0 +1,301 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/**
|
||||
+ * syscon driver to control and configure AC200 Ethernet PHY
|
||||
+ * Copyright (c) 2022 Arm Ltd.
|
||||
+ *
|
||||
+ * TODO's and questions:
|
||||
+ * =========================
|
||||
+ * - This driver is something like a syscon driver, as it controls various
|
||||
+ * bits and registers that effect other devices (the actual PHY). It's
|
||||
+ * unclear where it should live, though:
|
||||
+ * - it could be integrated into the MFD driver, but this looks messy
|
||||
+ * - it could live at the current location (drivers/phy/allwinner), but that
|
||||
+ * sounds wrong
|
||||
+ * - it could be a separate file, but in drivers/mfd
|
||||
+ * - anything else
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <dt-bindings/gpio/gpio.h>
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/clk-provider.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/nvmem-consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_net.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/reset-controller.h>
|
||||
+
|
||||
+/* macros for system ephy control 0 register */
|
||||
+#define AC200_SYS_EPHY_CTL0 0x0014
|
||||
+#define AC200_EPHY_RESET_INVALID BIT(0)
|
||||
+#define AC200_EPHY_SYSCLK_GATING 1
|
||||
+
|
||||
+/* macros for system ephy control 1 register */
|
||||
+#define AC200_SYS_EPHY_CTL1 0x0016
|
||||
+#define AC200_EPHY_E_EPHY_MII_IO_EN BIT(0)
|
||||
+#define AC200_EPHY_E_LNK_LED_IO_EN BIT(1)
|
||||
+#define AC200_EPHY_E_SPD_LED_IO_EN BIT(2)
|
||||
+#define AC200_EPHY_E_DPX_LED_IO_EN BIT(3)
|
||||
+
|
||||
+/* macros for ephy control register */
|
||||
+#define AC200_EPHY_CTL 0x6000
|
||||
+#define AC200_EPHY_SHUTDOWN BIT(0)
|
||||
+#define AC200_EPHY_LED_POL BIT(1)
|
||||
+#define AC200_EPHY_CLK_SEL BIT(2)
|
||||
+#define AC200_EPHY_ADDR(x) (((x) & 0x1F) << 4)
|
||||
+#define AC200_EPHY_XMII_SEL BIT(11)
|
||||
+#define AC200_EPHY_CALIB(x) (((x) & 0xF) << 12)
|
||||
+
|
||||
+struct ac200_ephy_ctl_dev {
|
||||
+ struct reset_controller_dev rcdev;
|
||||
+ struct clk_hw *gate_clk;
|
||||
+ struct regmap *regmap;
|
||||
+};
|
||||
+
|
||||
+static struct ac200_ephy_ctl_dev *to_phy_dev(struct reset_controller_dev *rcdev)
|
||||
+{
|
||||
+ return container_of(rcdev, struct ac200_ephy_ctl_dev, rcdev);
|
||||
+}
|
||||
+
|
||||
+static int ephy_ctl_reset(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
+{
|
||||
+ struct ac200_ephy_ctl_dev *ac200 = to_phy_dev(rcdev);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_clear_bits(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* This is going via I2C, so there is plenty of built-in delay. */
|
||||
+ return regmap_set_bits(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID);
|
||||
+}
|
||||
+
|
||||
+static int ephy_ctl_assert(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
+{
|
||||
+ struct ac200_ephy_ctl_dev *ac200 = to_phy_dev(rcdev);
|
||||
+
|
||||
+ return regmap_clear_bits(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID);
|
||||
+}
|
||||
+
|
||||
+static int ephy_ctl_deassert(struct reset_controller_dev *rcdev,
|
||||
+ unsigned long id)
|
||||
+{
|
||||
+ struct ac200_ephy_ctl_dev *ac200 = to_phy_dev(rcdev);
|
||||
+
|
||||
+ return regmap_set_bits(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID);
|
||||
+}
|
||||
+
|
||||
+static int ephy_ctl_status(struct reset_controller_dev *rcdev, unsigned long id)
|
||||
+{
|
||||
+ struct ac200_ephy_ctl_dev *ac200 = to_phy_dev(rcdev);
|
||||
+
|
||||
+ return regmap_test_bits(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID);
|
||||
+}
|
||||
+
|
||||
+static int ephy_ctl_reset_of_xlate(struct reset_controller_dev *rcdev,
|
||||
+ const struct of_phandle_args *reset_spec)
|
||||
+{
|
||||
+ if (WARN_ON(reset_spec->args_count != 0))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+const struct reset_control_ops ephy_ctl_reset_ops = {
|
||||
+ .assert = ephy_ctl_assert,
|
||||
+ .deassert = ephy_ctl_deassert,
|
||||
+ .reset = ephy_ctl_reset,
|
||||
+ .status = ephy_ctl_status,
|
||||
+};
|
||||
+
|
||||
+static void ac200_ephy_ctl_disable(struct ac200_ephy_ctl_dev *priv)
|
||||
+{
|
||||
+ regmap_write(priv->regmap, AC200_EPHY_CTL, AC200_EPHY_SHUTDOWN);
|
||||
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1, 0);
|
||||
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0, 0);
|
||||
+}
|
||||
+
|
||||
+static int ac200_ephy_ctl_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct reset_controller_dev *rcdev;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct ac200_ephy_ctl_dev *priv;
|
||||
+ struct nvmem_cell *calcell;
|
||||
+ const char *parent_name;
|
||||
+ phy_interface_t phy_if;
|
||||
+ u16 *caldata, ephy_ctl;
|
||||
+ struct clk *clk;
|
||||
+ size_t callen;
|
||||
+ u32 value;
|
||||
+ int ret;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ priv->regmap = dev_get_regmap(dev->parent, NULL);
|
||||
+ if (!priv->regmap)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ calcell = devm_nvmem_cell_get(dev, "calibration");
|
||||
+ if (IS_ERR(calcell))
|
||||
+ return dev_err_probe(dev, PTR_ERR(calcell),
|
||||
+ "Unable to find calibration data!\n");
|
||||
+
|
||||
+ caldata = nvmem_cell_read(calcell, &callen);
|
||||
+ if (IS_ERR(caldata)) {
|
||||
+ dev_err(dev, "Unable to read calibration data!\n");
|
||||
+ return PTR_ERR(caldata);
|
||||
+ }
|
||||
+
|
||||
+ if (callen != 2) {
|
||||
+ dev_err(dev, "Calibration data length must be 2 bytes!\n");
|
||||
+ kfree(caldata);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ ephy_ctl = AC200_EPHY_CALIB(*caldata + 3);
|
||||
+ kfree(caldata);
|
||||
+
|
||||
+ ret = of_get_phy_mode(dev->of_node, &phy_if);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to read PHY connection mode\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ switch (phy_if) {
|
||||
+ case PHY_INTERFACE_MODE_MII:
|
||||
+ break;
|
||||
+ case PHY_INTERFACE_MODE_RMII:
|
||||
+ ephy_ctl |= AC200_EPHY_XMII_SEL;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(dev, "Illegal PHY connection mode (%d), only RMII or MII supported\n",
|
||||
+ phy_if);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ ret = of_property_read_u32(dev->of_node, "x-powers,led-polarity",
|
||||
+ &value);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to read LED polarity setting\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (value == GPIO_ACTIVE_LOW)
|
||||
+ ephy_ctl |= AC200_EPHY_LED_POL;
|
||||
+
|
||||
+ ret = of_property_read_u32(dev->of_node, "phy-address", &value);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to read PHY address value\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ephy_ctl |= AC200_EPHY_ADDR(value);
|
||||
+
|
||||
+ clk = clk_get(dev->parent, NULL);
|
||||
+ if (IS_ERR(clk))
|
||||
+ return dev_err_probe(dev, PTR_ERR(clk),
|
||||
+ "Unable to obtain the clock\n");
|
||||
+
|
||||
+ if (clk_get_rate(clk) == 24000000)
|
||||
+ ephy_ctl |= AC200_EPHY_CLK_SEL;
|
||||
+
|
||||
+ clk_put(clk);
|
||||
+
|
||||
+ /* Assert reset and gate clock, to disable PHY for now */
|
||||
+ ret = regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0, 0);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1,
|
||||
+ AC200_EPHY_E_EPHY_MII_IO_EN |
|
||||
+ AC200_EPHY_E_LNK_LED_IO_EN |
|
||||
+ AC200_EPHY_E_SPD_LED_IO_EN |
|
||||
+ AC200_EPHY_E_DPX_LED_IO_EN);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(priv->regmap, AC200_EPHY_CTL, ephy_ctl);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ rcdev = &priv->rcdev;
|
||||
+ rcdev->owner = dev->driver->owner;
|
||||
+ rcdev->nr_resets = 1;
|
||||
+ rcdev->ops = &ephy_ctl_reset_ops;
|
||||
+ rcdev->of_node = dev->of_node;
|
||||
+ rcdev->of_reset_n_cells = 0;
|
||||
+ rcdev->of_xlate = ephy_ctl_reset_of_xlate;
|
||||
+
|
||||
+ ret = devm_reset_controller_register(dev, rcdev);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to register reset controller: %d\n", ret);
|
||||
+ goto err_disable_ephy;
|
||||
+ }
|
||||
+
|
||||
+ parent_name = of_clk_get_parent_name(dev->parent->of_node, 0);
|
||||
+ priv->gate_clk = devm_clk_hw_register_regmap_gate(dev,
|
||||
+ "ac200-ephy-ctl-gate", parent_name, 0,
|
||||
+ priv->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_SYSCLK_GATING, 0);
|
||||
+ if (IS_ERR(priv->gate_clk)) {
|
||||
+ ret = PTR_ERR(priv->gate_clk);
|
||||
+ dev_err(dev, "Unable to register gate clock: %d\n", ret);
|
||||
+ goto err_disable_ephy;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
+ priv->gate_clk);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to register clock provider: %d\n", ret);
|
||||
+ goto err_disable_ephy;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_disable_ephy:
|
||||
+ ac200_ephy_ctl_disable(priv);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int ac200_ephy_ctl_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ac200_ephy_ctl_dev *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ ac200_ephy_ctl_disable(priv);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id ac200_ephy_ctl_match[] = {
|
||||
+ { .compatible = "x-powers,ac200-ephy-ctl" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ac200_ephy_ctl_match);
|
||||
+
|
||||
+static struct platform_driver ac200_ephy_ctl_driver = {
|
||||
+ .probe = ac200_ephy_ctl_probe,
|
||||
+ .remove = ac200_ephy_ctl_remove,
|
||||
+ .driver = {
|
||||
+ .name = "ac200-ephy-ctl",
|
||||
+ .of_match_table = ac200_ephy_ctl_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(ac200_ephy_ctl_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Andre Przywara <andre.przywara@arm.com>");
|
||||
+MODULE_DESCRIPTION("AC200 Ethernet PHY control driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--
|
||||
Armbian
|
||||
|
@ -0,0 +1,265 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Fri, 16 Aug 2019 16:38:21 +0200
|
||||
Subject: mfd: Add support for X-Powers AC200
|
||||
|
||||
The X-Powers AC200 is a mixed signal multi-purpose chip, which provides
|
||||
audio DAC/ADCs, a CVBS video encoder, a 100Mbit/s Ethernet PHY and a
|
||||
real-time clock. Its control registers can be accessed via I2C or
|
||||
Allwinner's RSB bus.
|
||||
Beside this chip being used on some older boards (for instance the Remix
|
||||
Mini PC), it is quite wide spread due to its die being co-packaged on the
|
||||
Allwinner H6 and H616 SoCs, which use its audio, video and PHY
|
||||
functionality.
|
||||
|
||||
Aside from the RTC, the other functions do not need constant
|
||||
hand-holding via the I2C registers, but rather need to be configured and
|
||||
enabled only once.
|
||||
|
||||
We model the control side of this chip using the MFD subsystem. This
|
||||
driver here just provides the parent device for the various subfunctions,
|
||||
and takes care of enabling clocks and reset, but also provides the regmap,
|
||||
which the respective child drivers will use.
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
|
||||
---
|
||||
drivers/mfd/Kconfig | 12 +
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/ac200.c | 190 ++++++++++
|
||||
3 files changed, 203 insertions(+)
|
||||
|
||||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
|
||||
index f6b519eaaa71..39fef6420fe5 100644
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -191,6 +191,18 @@ config MFD_AC100
|
||||
This driver include only the core APIs. You have to select individual
|
||||
components like codecs or RTC under the corresponding menus.
|
||||
|
||||
+config MFD_AC200
|
||||
+ tristate "X-Powers AC200"
|
||||
+ select MFD_CORE
|
||||
+ select REGMAP_I2C
|
||||
+ depends on COMMON_CLK
|
||||
+ depends on I2C
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ If you say Y here you get support for the X-Powers AC200 IC.
|
||||
+ This driver include only the core APIs. You have to select individual
|
||||
+ components like Ethernet PHY or codec under the corresponding menus.
|
||||
+
|
||||
config MFD_AXP20X
|
||||
tristate
|
||||
select MFD_CORE
|
||||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
|
||||
index f3d1f1dc73b5..e2ba77bd1d51 100644
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -137,6 +137,7 @@ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
|
||||
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
|
||||
|
||||
obj-$(CONFIG_MFD_AC100) += ac100.o
|
||||
+obj-$(CONFIG_MFD_AC200) += ac200.o
|
||||
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
|
||||
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
|
||||
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
|
||||
diff --git a/drivers/mfd/ac200.c b/drivers/mfd/ac200.c
|
||||
new file mode 100644
|
||||
index 000000000000..ad28c380c880
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/ac200.c
|
||||
@@ -0,0 +1,190 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * MFD core driver for X-Powers' AC200 IC
|
||||
+ *
|
||||
+ * The AC200 is a chip which is co-packaged with Allwinner H6 SoC and
|
||||
+ * includes analog audio codec, analog TV encoder, ethernet PHY, eFuse
|
||||
+ * and RTC.
|
||||
+ *
|
||||
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
+ *
|
||||
+ * Based on AC100 driver with following copyrights:
|
||||
+ * Copyright (2016) Chen-Yu Tsai
|
||||
+ */
|
||||
+
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/nvmem-consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+struct ac200_dev {
|
||||
+ struct clk *clk;
|
||||
+ struct regmap *regmap;
|
||||
+};
|
||||
+
|
||||
+#define AC200_SYS_CONTROL 0x0002
|
||||
+#define AC200_SYS_BG_CTL 0x0050
|
||||
+
|
||||
+/* interface register (can be accessed from any page) */
|
||||
+#define AC200_TWI_REG_ADDR_H 0xFE
|
||||
+
|
||||
+#define AC200_MAX_REG 0xA1F2
|
||||
+
|
||||
+static const struct regmap_range_cfg ac200_range_cfg[] = {
|
||||
+ {
|
||||
+ .range_max = AC200_MAX_REG,
|
||||
+ .selector_reg = AC200_TWI_REG_ADDR_H,
|
||||
+ .selector_mask = 0xff,
|
||||
+ .selector_shift = 0,
|
||||
+ .window_start = 0,
|
||||
+ .window_len = 256,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_config ac200_regmap_config = {
|
||||
+ .name = "AC200",
|
||||
+ .reg_bits = 8,
|
||||
+ .reg_stride = 2,
|
||||
+ .val_bits = 16,
|
||||
+ .ranges = ac200_range_cfg,
|
||||
+ .num_ranges = ARRAY_SIZE(ac200_range_cfg),
|
||||
+ .max_register = AC200_MAX_REG,
|
||||
+};
|
||||
+
|
||||
+static struct mfd_cell ac200_cells[] = {
|
||||
+ {
|
||||
+ .name = "ac200-codec",
|
||||
+ .of_compatible = "x-powers,ac200-codec",
|
||||
+ }, {
|
||||
+ .name = "ac200-ephy-ctl",
|
||||
+ .of_compatible = "x-powers,ac200-ephy-ctl",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int ac200_i2c_probe(struct i2c_client *i2c)
|
||||
+{
|
||||
+ struct device *dev = &i2c->dev;
|
||||
+ struct nvmem_cell *bgcell;
|
||||
+ struct ac200_dev *ac200;
|
||||
+ u16 *bgdata, bgval;
|
||||
+ size_t bglen;
|
||||
+ int ret;
|
||||
+
|
||||
+ ac200 = devm_kzalloc(dev, sizeof(*ac200), GFP_KERNEL);
|
||||
+ if (!ac200)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ i2c_set_clientdata(i2c, ac200);
|
||||
+
|
||||
+ ac200->clk = devm_clk_get(dev, NULL);
|
||||
+ if (IS_ERR(ac200->clk))
|
||||
+ return dev_err_probe(dev, PTR_ERR(ac200->clk),
|
||||
+ "Can't obtain the clock\n");
|
||||
+
|
||||
+ ac200->regmap = devm_regmap_init_i2c(i2c, &ac200_regmap_config);
|
||||
+ if (IS_ERR(ac200->regmap)) {
|
||||
+ ret = PTR_ERR(ac200->regmap);
|
||||
+ dev_err(dev, "Regmap init failed: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ bgcell = devm_nvmem_cell_get(dev, "bandgap");
|
||||
+ if (IS_ERR(bgcell))
|
||||
+ return dev_err_probe(dev, PTR_ERR(bgcell),
|
||||
+ "Unable to find bandgap data!\n");
|
||||
+
|
||||
+ bgdata = nvmem_cell_read(bgcell, &bglen);
|
||||
+ if (IS_ERR(bgdata)) {
|
||||
+ dev_err(dev, "Unable to read bandgap data!\n");
|
||||
+ return PTR_ERR(bgdata);
|
||||
+ }
|
||||
+
|
||||
+ if (bglen != 2) {
|
||||
+ dev_err(dev, "Invalid nvmem bandgap length!\n");
|
||||
+ kfree(bgdata);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ bgval = *bgdata;
|
||||
+ kfree(bgdata);
|
||||
+
|
||||
+ ret = clk_prepare_enable(ac200->clk);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * There is no documentation on how long we have to wait before
|
||||
+ * executing first operation. Vendor driver sleeps for 40 ms.
|
||||
+ */
|
||||
+ msleep(40);
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL, 0);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_CONTROL, 1);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+
|
||||
+ if (bgval) {
|
||||
+ /* bandgap register is not documented */
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_BG_CTL,
|
||||
+ 0x8280 | bgval);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, ac200_cells,
|
||||
+ ARRAY_SIZE(ac200_cells), NULL, 0, NULL);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to add MFD devices: %d\n", ret);
|
||||
+ goto err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ clk_disable_unprepare(ac200->clk);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void ac200_i2c_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ struct ac200_dev *ac200 = i2c_get_clientdata(i2c);
|
||||
+
|
||||
+ regmap_write(ac200->regmap, AC200_SYS_CONTROL, 0);
|
||||
+
|
||||
+ clk_disable_unprepare(ac200->clk);
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id ac200_ids[] = {
|
||||
+ { "ac200", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, ac200_ids);
|
||||
+
|
||||
+static const struct of_device_id ac200_of_match[] = {
|
||||
+ { .compatible = "x-powers,ac200" },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ac200_of_match);
|
||||
+
|
||||
+static struct i2c_driver ac200_i2c_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "ac200",
|
||||
+ .of_match_table = of_match_ptr(ac200_of_match),
|
||||
+ },
|
||||
+ .probe = ac200_i2c_probe,
|
||||
+ .remove = ac200_i2c_remove,
|
||||
+ .id_table = ac200_ids,
|
||||
+};
|
||||
+module_i2c_driver(ac200_i2c_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("MFD core driver for AC200");
|
||||
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@gmail.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--
|
||||
Armbian
|
||||
|
@ -0,0 +1,60 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez?=
|
||||
<alejandro.gonzalez.correo@gmail.com>
|
||||
Date: Sun, 25 Aug 2019 17:05:58 +0200
|
||||
Subject: [PATCH] mmc: sunxi: fix unusuable eMMC on some H6 boards by disabling
|
||||
DDR
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Some Allwinner H6 boards have timing problems when dealing with
|
||||
DDR-capable eMMC cards. These boards include the Pine H64 and Tanix TX6.
|
||||
|
||||
These timing problems result in out of sync communication between the
|
||||
driver and the eMMC, which renders the memory unsuable for every
|
||||
operation but some basic commmands, like reading the status register.
|
||||
|
||||
The cause of these timing problems is not yet well known, but they go
|
||||
away by disabling DDR mode operation in the driver. Like on some H5
|
||||
boards, it might be that the traces are not precise enough to support
|
||||
these speeds. However, Jernej Skrabec compared the BSP driver with this
|
||||
driver, and found that the BSP driver configures pinctrl to operate at
|
||||
1.8 V when entering DDR mode (although 3.3 V operation is supported), while
|
||||
the mainline kernel lacks any mechanism to switch voltages dynamically.
|
||||
Finally, other possible cause might be some timing parameter that is
|
||||
different on the H6 with respect to other SoCs.
|
||||
|
||||
Therefore, as this fix works reliably, the kernel lacks the required
|
||||
dynamic pinctrl control for now and a slow eMMC is better than a not
|
||||
working eMMC, just disable DDR operation for now on H6-compatible
|
||||
devices.
|
||||
|
||||
Signed-off-by: Alejandro González <alejandro.gonzalez.correo@gmail.com>
|
||||
---
|
||||
drivers/mmc/host/sunxi-mmc.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mmc/host/sunxi-mmc.c
|
||||
+++ b/drivers/mmc/host/sunxi-mmc.c
|
||||
@@ -1421,14 +1421,17 @@ static int sunxi_mmc_probe(struct platfo
|
||||
|
||||
/*
|
||||
* Some H5 devices do not have signal traces precise enough to
|
||||
- * use HS DDR mode for their eMMC chips.
|
||||
+ * use HS DDR mode for their eMMC chips. Other H6 devices operate
|
||||
+ * unreliably on HS DDR mode, too.
|
||||
*
|
||||
* We still enable HS DDR modes for all the other controller
|
||||
- * variants that support them.
|
||||
+ * variants that support them properly.
|
||||
*/
|
||||
if ((host->cfg->clk_delays || host->use_new_timings) &&
|
||||
!of_device_is_compatible(pdev->dev.of_node,
|
||||
- "allwinner,sun50i-h5-emmc"))
|
||||
+ "allwinner,sun50i-h5-emmc") &&
|
||||
+ !of_device_is_compatible(pdev->dev.of_node,
|
||||
+ "allwinner,sun50i-h6-emmc"))
|
||||
mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_3_3V_DDR;
|
||||
|
||||
ret = mmc_of_parse(mmc);
|
@ -0,0 +1,276 @@
|
||||
From cbf68fb141747879e2e6c43584c1e1e3b4d77683 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
Date: Fri, 16 Aug 2019 16:38:57 +0200
|
||||
Subject: [PATCH 39/44] net: phy: Add support for AC200 EPHY
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 7 ++
|
||||
drivers/net/phy/Makefile | 1 +
|
||||
drivers/net/phy/ac200.c | 234 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 242 insertions(+)
|
||||
create mode 100644 drivers/net/phy/ac200.c
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -63,6 +63,13 @@ config SFP
|
||||
|
||||
comment "MII PHY device drivers"
|
||||
|
||||
+config AC200_PHY
|
||||
+ tristate "AC200 EPHY"
|
||||
+ depends on NVMEM
|
||||
+ depends on OF
|
||||
+ help
|
||||
+ Fast ethernet PHY as found in X-Powers AC200 multi-function device.
|
||||
+
|
||||
config AMD_PHY
|
||||
tristate "AMD PHYs"
|
||||
help
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -30,6 +30,7 @@ obj-$(CONFIG_SFP) += sfp.o
|
||||
sfp-obj-$(CONFIG_SFP) += sfp-bus.o
|
||||
obj-y += $(sfp-obj-y) $(sfp-obj-m)
|
||||
|
||||
+obj-$(CONFIG_AC200_PHY) += ac200.o
|
||||
obj-$(CONFIG_ADIN_PHY) += adin.o
|
||||
obj-$(CONFIG_AMD_PHY) += amd.o
|
||||
aquantia-objs += aquantia_main.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/phy/ac200.c
|
||||
@@ -0,0 +1,234 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/**
|
||||
+ * Driver for AC200 Ethernet PHY
|
||||
+ *
|
||||
+ * Copyright (c) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mfd/ac200.h>
|
||||
+#include <linux/nvmem-consumer.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#define AC200_EPHY_ID 0x00441400
|
||||
+#define AC200_EPHY_ID_MASK 0x0ffffff0
|
||||
+
|
||||
+/* macros for system ephy control 0 register */
|
||||
+#define AC200_EPHY_RESET_INVALID BIT(0)
|
||||
+#define AC200_EPHY_SYSCLK_GATING BIT(1)
|
||||
+
|
||||
+/* macros for system ephy control 1 register */
|
||||
+#define AC200_EPHY_E_EPHY_MII_IO_EN BIT(0)
|
||||
+#define AC200_EPHY_E_LNK_LED_IO_EN BIT(1)
|
||||
+#define AC200_EPHY_E_SPD_LED_IO_EN BIT(2)
|
||||
+#define AC200_EPHY_E_DPX_LED_IO_EN BIT(3)
|
||||
+
|
||||
+/* macros for ephy control register */
|
||||
+#define AC200_EPHY_SHUTDOWN BIT(0)
|
||||
+#define AC200_EPHY_LED_POL BIT(1)
|
||||
+#define AC200_EPHY_CLK_SEL BIT(2)
|
||||
+#define AC200_EPHY_ADDR(x) (((x) & 0x1F) << 4)
|
||||
+#define AC200_EPHY_XMII_SEL BIT(11)
|
||||
+#define AC200_EPHY_CALIB(x) (((x) & 0xF) << 12)
|
||||
+
|
||||
+struct ac200_ephy_dev {
|
||||
+ struct phy_driver *ephy;
|
||||
+ struct regmap *regmap;
|
||||
+};
|
||||
+
|
||||
+static char *ac200_phy_name = "AC200 EPHY";
|
||||
+
|
||||
+static void disable_intelligent_ieee(struct phy_device *phydev)
|
||||
+{
|
||||
+ unsigned int value;
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0100); /* switch to page 1 */
|
||||
+ value = phy_read(phydev, 0x17);
|
||||
+ value &= ~BIT(3); /* disable IEEE */
|
||||
+ phy_write(phydev, 0x17, value);
|
||||
+ phy_write(phydev, 0x1f, 0x0000); /* switch to page 0 */
|
||||
+}
|
||||
+
|
||||
+static void disable_802_3az_ieee(struct phy_device *phydev)
|
||||
+{
|
||||
+ unsigned int value;
|
||||
+
|
||||
+ phy_write(phydev, 0xd, 0x7);
|
||||
+ phy_write(phydev, 0xe, 0x3c);
|
||||
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
|
||||
+ value = phy_read(phydev, 0xe);
|
||||
+ value &= ~BIT(1);
|
||||
+ phy_write(phydev, 0xd, 0x7);
|
||||
+ phy_write(phydev, 0xe, 0x3c);
|
||||
+ phy_write(phydev, 0xd, BIT(14) | 0x7);
|
||||
+ phy_write(phydev, 0xe, value);
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0200); /* switch to page 2 */
|
||||
+ phy_write(phydev, 0x18, 0x0000);
|
||||
+}
|
||||
+
|
||||
+static int ac200_ephy_config_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ const struct ac200_ephy_dev *priv = phydev->drv->driver_data;
|
||||
+ unsigned int value;
|
||||
+ int ret;
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0100); /* Switch to Page 1 */
|
||||
+ phy_write(phydev, 0x12, 0x4824); /* Disable APS */
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0200); /* Switch to Page 2 */
|
||||
+ phy_write(phydev, 0x18, 0x0000); /* PHYAFE TRX optimization */
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0600); /* Switch to Page 6 */
|
||||
+ phy_write(phydev, 0x14, 0x708f); /* PHYAFE TX optimization */
|
||||
+ phy_write(phydev, 0x13, 0xF000); /* PHYAFE RX optimization */
|
||||
+ phy_write(phydev, 0x15, 0x1530);
|
||||
+
|
||||
+ phy_write(phydev, 0x1f, 0x0800); /* Switch to Page 6 */
|
||||
+ phy_write(phydev, 0x18, 0x00bc); /* PHYAFE TRX optimization */
|
||||
+
|
||||
+ disable_intelligent_ieee(phydev); /* Disable Intelligent IEEE */
|
||||
+ disable_802_3az_ieee(phydev); /* Disable 802.3az IEEE */
|
||||
+ phy_write(phydev, 0x1f, 0x0000); /* Switch to Page 0 */
|
||||
+
|
||||
+ value = (phydev->interface == PHY_INTERFACE_MODE_RMII) ?
|
||||
+ AC200_EPHY_XMII_SEL : 0;
|
||||
+ ret = regmap_update_bits(priv->regmap, AC200_EPHY_CTL,
|
||||
+ AC200_EPHY_XMII_SEL, value);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* FIXME: This is probably H6 specific */
|
||||
+ value = phy_read(phydev, 0x13);
|
||||
+ value |= BIT(12);
|
||||
+ phy_write(phydev, 0x13, value);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct mdio_device_id __maybe_unused ac200_ephy_phy_tbl[] = {
|
||||
+ { AC200_EPHY_ID, AC200_EPHY_ID_MASK },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(mdio, ac200_ephy_phy_tbl);
|
||||
+
|
||||
+static int ac200_ephy_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ac200_dev *ac200 = dev_get_drvdata(pdev->dev.parent);
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct ac200_ephy_dev *priv;
|
||||
+ struct nvmem_cell *calcell;
|
||||
+ struct phy_driver *ephy;
|
||||
+ u16 *caldata, calib;
|
||||
+ size_t callen;
|
||||
+ int ret;
|
||||
+
|
||||
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ephy = devm_kzalloc(dev, sizeof(*ephy), GFP_KERNEL);
|
||||
+ if (!ephy)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ calcell = devm_nvmem_cell_get(dev, "ephy_calib");
|
||||
+ if (IS_ERR(calcell)) {
|
||||
+ dev_err(dev, "Unable to find calibration data!\n");
|
||||
+ return PTR_ERR(calcell);
|
||||
+ }
|
||||
+
|
||||
+ caldata = nvmem_cell_read(calcell, &callen);
|
||||
+ if (IS_ERR(caldata)) {
|
||||
+ dev_err(dev, "Unable to read calibration data!\n");
|
||||
+ return PTR_ERR(caldata);
|
||||
+ }
|
||||
+
|
||||
+ if (callen != 2) {
|
||||
+ dev_err(dev, "Calibration data has wrong length: 2 != %lu\n",
|
||||
+ callen);
|
||||
+ kfree(caldata);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ calib = *caldata + 3;
|
||||
+ kfree(caldata);
|
||||
+
|
||||
+ ephy->phy_id = AC200_EPHY_ID;
|
||||
+ ephy->phy_id_mask = AC200_EPHY_ID_MASK;
|
||||
+ ephy->name = ac200_phy_name;
|
||||
+ ephy->driver_data = priv;
|
||||
+ ephy->soft_reset = genphy_soft_reset;
|
||||
+ ephy->config_init = ac200_ephy_config_init;
|
||||
+ ephy->suspend = genphy_suspend;
|
||||
+ ephy->resume = genphy_resume;
|
||||
+
|
||||
+ priv->ephy = ephy;
|
||||
+ priv->regmap = ac200->regmap;
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL0,
|
||||
+ AC200_EPHY_RESET_INVALID |
|
||||
+ AC200_EPHY_SYSCLK_GATING);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_SYS_EPHY_CTL1,
|
||||
+ AC200_EPHY_E_EPHY_MII_IO_EN |
|
||||
+ AC200_EPHY_E_LNK_LED_IO_EN |
|
||||
+ AC200_EPHY_E_SPD_LED_IO_EN |
|
||||
+ AC200_EPHY_E_DPX_LED_IO_EN);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = regmap_write(ac200->regmap, AC200_EPHY_CTL,
|
||||
+ AC200_EPHY_LED_POL |
|
||||
+ AC200_EPHY_CLK_SEL |
|
||||
+ AC200_EPHY_ADDR(1) |
|
||||
+ AC200_EPHY_CALIB(calib));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = phy_driver_register(priv->ephy, THIS_MODULE);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Unable to register phy\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int ac200_ephy_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct ac200_ephy_dev *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ phy_driver_unregister(priv->ephy);
|
||||
+
|
||||
+ regmap_write(priv->regmap, AC200_EPHY_CTL, AC200_EPHY_SHUTDOWN);
|
||||
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL1, 0);
|
||||
+ regmap_write(priv->regmap, AC200_SYS_EPHY_CTL0, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id ac200_ephy_match[] = {
|
||||
+ { .compatible = "x-powers,ac200-ephy" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, ac200_ephy_match);
|
||||
+
|
||||
+static struct platform_driver ac200_ephy_driver = {
|
||||
+ .probe = ac200_ephy_probe,
|
||||
+ .remove = ac200_ephy_remove,
|
||||
+ .driver = {
|
||||
+ .name = "ac200-ephy",
|
||||
+ .of_match_table = ac200_ephy_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(ac200_ephy_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
|
||||
+MODULE_DESCRIPTION("AC200 Ethernet PHY driver");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,8 @@
|
||||
# K metadata for orangepi lts
|
||||
# version 6.1
|
||||
|
||||
patch Input-axp20x-pek-allow-wakeup-after-shutdown-6_1.patch
|
||||
patch mfd-Add-support-for-AC200.patch
|
||||
patch net-phy-Add-support-for-AC200-EPHY.patch
|
||||
|
||||
include orange-pi-3lts-common.scc
|
@ -0,0 +1,8 @@
|
||||
# K metadata for orangepi lts
|
||||
# version 6.5
|
||||
|
||||
patch Input-axp20x-pek-allow-wakeup-after-shutdown-6_5.patch
|
||||
patch mfd-Add-support-for-X-Powers-AC200-EPHY-syscon.patch
|
||||
patch mfd-Add-support-for-X-Powers-AC200.patch
|
||||
|
||||
include orange-pi-3lts-common.scc
|
@ -0,0 +1,20 @@
|
||||
# Kmeta common
|
||||
#
|
||||
|
||||
patch clk-Implement-protected-clocks-for-all-OF-clock-prov.patch
|
||||
patch Revert-clk-qcom-Support-protected-clocks-property.patch
|
||||
patch rtc-sun6i-Allow-RTC-wakeup-after-shutdown.patch
|
||||
patch firmware-arm_scpi-Support-unidirectional-mailbox-cha.patch
|
||||
patch arm64-dts-allwinner-h6-Add-SCPI-protocol.patch
|
||||
patch ASoC-hdmi-codec-fix-channel-allocation.patch
|
||||
patch arm64-dts-h6-deinterlace.patch
|
||||
patch HACK-h6-Add-HDMI-sound-card.patch
|
||||
patch arm64-dts-allwinner-h6-Add-AC200-EPHY-related-nodes.patch
|
||||
patch mmc-sunxi-fix-unusuable-eMMC-on-some-H6-boards-by-di.patch
|
||||
patch wip-fix-H6-4k-60.patch
|
||||
patch arm64-dts-allwinner-h6-Fix-Cedrus-IOMMU-again.patch
|
||||
patch iommu-sun50i-Allow-page-sizes-multiple-of-4096.patch
|
||||
patch OrangePi-3-LTS-support.patch
|
||||
patch arm64-dts-allwinner-Enforce-consistent-MMC-numbering.patch
|
||||
|
||||
kconf harware orange-pi-3lts.cfg
|
@ -0,0 +1,5 @@
|
||||
CONFIG_NVMEM_SUNXI_SID=y
|
||||
CONFIG_INIT_STACK_NONE=y
|
||||
CONFIG_PHY_SUN50I_USB3=y
|
||||
CONFIG_AC200_PHY=m
|
||||
CONFIG_MFD_AC200=m
|
@ -0,0 +1,62 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Holland <samuel@sholland.org>
|
||||
Date: Sat, 2 Jan 2021 15:52:27 -0600
|
||||
Subject: [PATCH] rtc: sun6i: Allow RTC wakeup after shutdown
|
||||
|
||||
Only IRQs that have enable_irq_wake() called on them can wake the system
|
||||
from sleep or after it has been shut down. Currently, the RTC alarm can
|
||||
only wake the system from sleep. Run the suspend callback to arm the IRQ
|
||||
during the shutdown process, so the RTC alarm also works after shutdown.
|
||||
|
||||
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
||||
---
|
||||
drivers/rtc/rtc-sun6i.c | 10 +++++++---
|
||||
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/rtc/rtc-sun6i.c
|
||||
+++ b/drivers/rtc/rtc-sun6i.c
|
||||
@@ -641,7 +641,6 @@ static const struct rtc_class_ops sun6i_
|
||||
.alarm_irq_enable = sun6i_rtc_alarm_irq_enable
|
||||
};
|
||||
|
||||
-#ifdef CONFIG_PM_SLEEP
|
||||
/* Enable IRQ wake on suspend, to wake up from RTC. */
|
||||
static int sun6i_rtc_suspend(struct device *dev)
|
||||
{
|
||||
@@ -654,7 +653,7 @@ static int sun6i_rtc_suspend(struct devi
|
||||
}
|
||||
|
||||
/* Disable IRQ wake on resume. */
|
||||
-static int sun6i_rtc_resume(struct device *dev)
|
||||
+static int __maybe_unused sun6i_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
|
||||
@@ -663,7 +662,6 @@ static int sun6i_rtc_resume(struct devic
|
||||
|
||||
return 0;
|
||||
}
|
||||
-#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(sun6i_rtc_pm_ops,
|
||||
sun6i_rtc_suspend, sun6i_rtc_resume);
|
||||
@@ -735,6 +733,11 @@ static int sun6i_rtc_probe(struct platfo
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void sun6i_rtc_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+ sun6i_rtc_suspend(&pdev->dev);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* As far as RTC functionality goes, all models are the same. The
|
||||
* datasheets claim that different models have different number of
|
||||
@@ -755,6 +758,7 @@ MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids
|
||||
|
||||
static struct platform_driver sun6i_rtc_driver = {
|
||||
.probe = sun6i_rtc_probe,
|
||||
+ .shutdown = sun6i_rtc_shutdown,
|
||||
.driver = {
|
||||
.name = "sun6i-rtc",
|
||||
.of_match_table = sun6i_rtc_dt_ids,
|
@ -0,0 +1,75 @@
|
||||
From edc858b1d62ce5ffd8b8d10cc62425af15d48a91 Mon Sep 17 00:00:00 2001
|
||||
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
Date: Wed, 8 Dec 2021 20:42:45 +0100
|
||||
Subject: [PATCH] wip: fix H6 4k@60
|
||||
|
||||
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
|
||||
---
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 7 +++++++
|
||||
drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 4 ++++
|
||||
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 2 +-
|
||||
3 files changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
index f08d0fded61f..bcd839a3ce80 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
|
||||
@@ -1488,6 +1488,8 @@ static int hdmi_phy_configure_dwc_hdmi_3d_tx(struct dw_hdmi *hdmi,
|
||||
/* Override and disable clock termination. */
|
||||
dw_hdmi_phy_i2c_write(hdmi, HDMI_3D_TX_PHY_CKCALCTRL_OVERRIDE,
|
||||
HDMI_3D_TX_PHY_CKCALCTRL);
|
||||
+ if (mpixelclock == 594000000)
|
||||
+ dw_hdmi_phy_i2c_write(hdmi, 0x8006, HDMI_3D_TX_PHY_MSM_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2166,6 +2168,8 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
|
||||
hdmi->hdmi_data.hdcp_enable = 0;
|
||||
hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
|
||||
|
||||
+ hdmi_writeb(hdmi, HDMI_FC_GCP_SET_AVMUTE, HDMI_FC_GCP);
|
||||
+
|
||||
/* HDMI Initialization Step B.1 */
|
||||
hdmi_av_composer(hdmi, &connector->display_info, mode);
|
||||
|
||||
@@ -2205,6 +2209,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
|
||||
hdmi_video_sample(hdmi);
|
||||
hdmi_tx_hdcp_config(hdmi);
|
||||
|
||||
+ msleep(100);
|
||||
+ hdmi_writeb(hdmi, HDMI_FC_GCP_CLEAR_AVMUTE, HDMI_FC_GCP);
|
||||
+
|
||||
dw_hdmi_clear_overflow(hdmi);
|
||||
|
||||
return 0;
|
||||
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
|
||||
index 1999db05bc3b..05182418efbb 100644
|
||||
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
|
||||
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h
|
||||
@@ -842,6 +842,10 @@ enum {
|
||||
HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
|
||||
HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
|
||||
|
||||
+/* HDMI_FC_GCP */
|
||||
+ HDMI_FC_GCP_SET_AVMUTE = 0x2,
|
||||
+ HDMI_FC_GCP_CLEAR_AVMUTE = 0x1,
|
||||
+
|
||||
/* FC_DBGFORCE field values */
|
||||
HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
|
||||
HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
|
||||
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
index b64d93da651d..b70bc9de761f 100644
|
||||
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
|
||||
@@ -90,7 +90,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
|
||||
},
|
||||
}, {
|
||||
594000000, {
|
||||
- { 0x1a40, 0x0003 },
|
||||
+ { 0x1a7c, 0x0003 },
|
||||
{ 0x3b4c, 0x0003 },
|
||||
{ 0x5a64, 0x0003 },
|
||||
},
|
||||
--
|
||||
2.34.1
|
||||
|
@ -21,3 +21,5 @@ SRC_URI:append:orange-pi-zero2 = " \
|
||||
file://0011-dts-add-usb-to-h616.patch \
|
||||
file://0012-dts-orange-pi-zero2.patch \
|
||||
"
|
||||
KERNEL_FEATURES:append:orange-pi-3lts = " bsp/orange-pi-3lts/orange-pi-3lts-6_1.scc bsp/uwe5622/uwe5622-6_1.scc"
|
||||
|
||||
|
@ -4,5 +4,9 @@ DESCRIPTION = "Mainline Longterm Linux kernel"
|
||||
|
||||
LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"
|
||||
|
||||
# Board Specific features
|
||||
KERNEL_FEATURES:prepend:orange-pi-3lts = " bsp/orange-pi-3lts/orange-pi-3lts-6_5.scc bsp/uwe5622/uwe5622-6_5.scc"
|
||||
|
||||
|
||||
SRC_URI[sha256sum] = "2ee24af9282b80923b2da56b70aad7df2e8ee4e3f076452e05ba66be2059b519"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user