[v2,2/2] arm64: dts: allwinner: h6: Add Orange Pi 3 LTS
Commit Message
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Add a device tree for the Orange Pi 3 LTS, an Allwinner H6 board with
2 GiB LPDDR3, 8 GiB eMMC, a Motorcomm YT8531C Gigabit Ethernet PHY,
AW859A wireless module, USB 2.0/3.0 host ports and HDMI.
Describe the board-specific Ethernet power and reset wiring, wireless
supplies, storage and regulators. Include the review corrections from
the original submission: oscillator naming, symbolic RTC clock ID,
regulator supply chaining, BLDO3 always-on and DCDCA/DCDCB polyphase
annotation. Describe the PM bank supply and use the green PL7 LED as
the power indicator.
Configure the RGMII delays in the PHY with zero MAC delays, as proposed
during the Ethernet review. This setup was exercised in U-Boot on the
board; Linux runtime testing remains to be performed.
Link: https://lore.kernel.org/linux-sunxi/20250413134318.66681-3-jernej.skrabec@gmail.com/
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Signed-off-by: Cristian Filipescu <filipescu.cristian@gmail.com>
---
arch/arm64/boot/dts/allwinner/Makefile | 1 +
.../dts/allwinner/sun50i-h6-orangepi-3-lts.dts | 362 +++++++++++++++++++++
2 files changed, 363 insertions(+)
Comments
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] arm64: dts: allwinner: per-PHY reset-gpios and c22 compatible break YT8531C
- [Medium] arm64: dts: allwinner: orangepi-3-lts: swapped LED default-state values
--
commit e75611867d87d079b20765ad9c1ddf5482d2d71a
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
arm64: dts: allwinner: h6: Add Orange Pi 3 LTS
This commit adds a device tree for the Allwinner H6-based Orange Pi 3 LTS
board, describing its regulators, storage, wireless module, LEDs, USB ports,
HDMI, and Motorcomm YT8531C Gigabit Ethernet PHY.
Link: https://lore.kernel.org/linux-sunxi/20250413134318.66681-3-jernej.skrabec@gmail.com/
> 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 0000000000000..e6aa0b2e17ebe
> --- /dev/null
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3-lts.dts
[ ... ]
> + leds {
> + compatible = "gpio-leds";
> +
> + led-0 {
> + function = LED_FUNCTION_STATUS;
> + color = <LED_COLOR_ID_RED>;
> + gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
> + default-state = "on";
> + };
> +
> + led-1 {
> + function = LED_FUNCTION_POWER;
> + color = <LED_COLOR_ID_GREEN>;
> + gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
> + default-state = "off";
> + };
> + };
[Severity: Medium]
The commit message notes that the green PL7 LED is used as the power
indicator. When gpio_led_probe() -> create_gpio_led() in
drivers/leds/leds-gpio.c parses the leds node, led-0 (red PL4,
LED_FUNCTION_STATUS) is turned on and led-1 (green PL7, LED_FUNCTION_POWER)
is turned off.
When the LED functions were swapped relative to sun50i-h6-orangepi-3.dts,
were the default-state values on led-0 and led-1 accidentally left unswapped?
> +
> + reg_gmac_3v3: gmac-3v3 {
> + compatible = "regulator-fixed";
> + regulator-name = "gmac-3v3";
> + vin-supply = <®_vcc5v>;
> + regulator-min-microvolt = <3300000>;
> + regulator-max-microvolt = <3300000>;
> + startup-delay-us = <150000>;
> + enable-active-high;
> + gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
> + };
[ ... ]
> +&mdio {
> + ext_rgmii_phy: ethernet-phy@1 {
> + compatible = "ethernet-phy-ieee802.3-c22";
> + reg = <1>;
> +
> + motorcomm,clk-out-frequency-hz = <125000000>;
> + rx-internal-delay-ps = <1950>;
> + tx-internal-delay-ps = <1950>;
> +
> + reset-gpios = <&pio 3 14 GPIO_ACTIVE_LOW>; /* PD14 */
> + reset-assert-us = <15000>;
> + reset-deassert-us = <100000>;
> + };
> +};
[Severity: High]
Will the YT8531C PHY fail to probe or lose its 125 MHz clock output with
compatible = "ethernet-phy-ieee802.3-c22" and reset-gpios placed on the
ethernet-phy@1 node?
First, during MDIO bus registration:
sun8i_dwmac_init()
regulator_enable(gmac->regulator) /* enables reg_gmac_3v3 (PD6) */
stmmac_mdio_register()
of_mdiobus_register()
__of_mdiobus_parse_phys()
fwnode_mdiobus_register_phy()
In drivers/net/mdio/fwnode_mdio.c:fwnode_mdiobus_register_phy():
is_c45 = fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45");
if (is_c45 || fwnode_get_phy_id(child, &phy_id))
phy = get_phy_device(bus, addr, is_c45);
else
phy = phy_device_create(bus, addr, phy_id, 0, NULL);
if (IS_ERR(phy)) {
rc = PTR_ERR(phy);
goto clean_mii_ts;
}
...
} else if (is_of_node(child)) {
rc = fwnode_mdiobus_phy_device_register(bus, phy, child, addr);
Because compatible is not "ethernet-phy-id4f51.e91b" (which is also required
by Documentation/devicetree/bindings/net/motorcomm,yt8xxx.yaml),
fwnode_get_phy_id() fails and get_phy_device() -> get_phy_c22_id() reads
MII_PHYSID1 and MII_PHYSID2 over MDIO before
fwnode_mdiobus_phy_device_register() -> phy_device_register() registers and
deasserts the per-PHY reset-gpios (PD14):
phy_device_register()
mdiobus_register_device()
mdio_device_register_reset()
phy_device_reset(phydev, 0)
If PD14 is low when the kernel boots (for example, when U-Boot has not
initialized Ethernet) or on driver rebind after phy_device_remove() asserts
reset, the PHY is still held in reset during get_phy_c22_id(), causing MDIO
reads to return 0xffff and PHY registration to fail with -ENODEV.
Second, because reset-gpios is attached to the PHY node rather than the MDIO
bus, bringing the network interface down calls:
stmmac_release()
phylink_disconnect_phy()
phy_disconnect()
phy_detach()
phy_device_reset(phydev, 1)
This asserts hardware reset on PD14, resetting YTPHY_SYNCE_CFG_REG back to
its 25 MHz default. When the interface is brought back up via stmmac_open()
-> stmmac_init_phy() -> phylink_fwnode_phy_connect() -> phy_attach_direct()
-> phy_init_hw(), PD14 is deasserted and yt8531_config_init() runs, but
motorcomm,clk-out-frequency-hz is only applied once in yt8531_probe() in
drivers/net/phy/motorcomm.c:
if (device_property_read_u32(dev, "motorcomm,clk-out-frequency-hz", &freq))
freq = YTPHY_DTS_OUTPUT_CLK_DIS;
...
return ytphy_modify_ext_with_lock(phydev, YTPHY_SYNCE_CFG_REG, mask,
val);
Should ethernet-phy@1 use compatible = "ethernet-phy-id4f51.e91b" (or move
the reset handling so the PHY is out of reset before ID reads and not hard
reset across interface down/up cycles)?
[ ... ]
@@ -41,6 +41,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
new file mode 100644
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2025 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 "sun50i-h6-gpu-opp.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
+
+/ {
+ model = "OrangePi 3 LTS";
+ compatible = "xunlong,orangepi-3-lts", "allwinner,sun50i-h6";
+
+ aliases {
+ ethernet0 = &emac;
+ ethernet1 = &aw859a;
+ 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 {
+ function = LED_FUNCTION_STATUS;
+ color = <LED_COLOR_ID_RED>;
+ gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+ default-state = "on";
+ };
+
+ led-1 {
+ function = LED_FUNCTION_POWER;
+ color = <LED_COLOR_ID_GREEN>;
+ gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+ default-state = "off";
+ };
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "gmac-3v3";
+ vin-supply = <®_vcc5v>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <150000>;
+ enable-active-high;
+ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */
+ };
+
+ 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_wifi_3v3: wifi-3v3 {
+ /* 3.3V regulator for WiFi and BT */
+ compatible = "regulator-fixed";
+ regulator-name = "wifi-3v3";
+ vin-supply = <®_vcc5v>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 7 GPIO_ACTIVE_HIGH>; /* PH7 */
+ };
+
+ wifi_pwrseq: wifi-pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&rtc CLK_OSC32K_FANOUT>;
+ 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-id";
+ phy-handle = <&ext_rgmii_phy>;
+ phy-supply = <®_gmac_3v3>;
+ allwinner,rx-delay-ps = <0>;
+ allwinner,tx-delay-ps = <0>;
+ 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>;
+
+ motorcomm,clk-out-frequency-hz = <125000000>;
+ rx-internal-delay-ps = <1950>;
+ tx-internal-delay-ps = <1950>;
+
+ reset-gpios = <&pio 3 14 GPIO_ACTIVE_LOW>; /* PD14 */
+ reset-assert-us = <15000>;
+ reset-deassert-us = <100000>;
+ };
+};
+
+&mmc0 {
+ vmmc-supply = <®_cldo1>;
+ cd-gpios = <&pio 5 6 GPIO_ACTIVE_LOW>; /* PF6 */
+ disable-wp;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&mmc1 {
+ vmmc-supply = <®_wifi_3v3>;
+ vqmmc-supply = <®_bldo3>;
+ mmc-pwrseq = <&wifi_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ aw859a: wifi@1 {
+ reg = <1>;
+ };
+};
+
+&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_pio {
+ vcc-pm-supply = <®_bldo3>;
+};
+
+&r_i2c {
+ status = "okay";
+
+ axp805: pmic@36 {
+ compatible = "x-powers,axp805", "x-powers,axp806";
+ reg = <0x36>;
+ 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-always-on;
+ 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 */
+ };
+
+ /* DCDCB is polyphased with DCDCA. */
+ 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 = <960000>;
+ regulator-max-microvolt = <960000>;
+ regulator-name = "vdd-sys";
+ };
+
+ reg_dcdce: dcdce {
+ regulator-always-on;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-name = "vcc-dram";
+ };
+
+ sw {
+ /* unused */
+ };
+ };
+ };
+};
+
+&rtc {
+ clocks = <&ext_osc32k>;
+};
+
+&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";
+};