sunxi a523: add support for PCIe, SPI Flash and Iommu (#9280)

This commit is contained in:
Marvin Wewer 2026-01-31 06:52:26 +01:00 committed by GitHub
parent e05e27bc6f
commit 6afba3a119
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 10368 additions and 3 deletions

View File

@ -579,6 +579,7 @@ CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_PCIE_DW_PLAT_HOST=y
CONFIG_PCIE_SUN55I_RC=y
CONFIG_UEVENT_HELPER=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@ -603,7 +604,7 @@ CONFIG_MTD_CMDLINE_PARTS=m
CONFIG_MTD_BLOCK=y
CONFIG_MTD_OOPS=m
CONFIG_MTD_PARTITIONED_MASTER=y
CONFIG_MTD_SPI_NOR=m
CONFIG_MTD_SPI_NOR=y
CONFIG_OF_OVERLAY=y
CONFIG_BLK_DEV_PCIESSD_MTIP32XX=m
CONFIG_ZRAM=m
@ -1137,11 +1138,13 @@ CONFIG_I2C_SLAVE_EEPROM=m
CONFIG_I3C=m
CONFIG_DW_I3C_MASTER=m
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_DESIGNWARE=m
CONFIG_SPI_DW_DMA=y
CONFIG_SPI_DW_PCI=m
CONFIG_SPI_DW_MMIO=m
CONFIG_SPI_GPIO=m
CONFIG_SPI_GPIO=y
CONFIG_SPI_PL022=y
CONFIG_SPI_SUN4I=y
CONFIG_SPI_SUN6I=y
CONFIG_SPI_MUX=m
@ -2223,6 +2226,7 @@ CONFIG_ARM_SMMU_V3=m
CONFIG_ARM_SMMU_V3_SVA=y
CONFIG_IOMMUFD=m
CONFIG_SUN50I_IOMMU=y
CONFIG_SUN55I_IOMMU=y
CONFIG_REMOTEPROC=y
CONFIG_REMOTEPROC_CDEV=y
CONFIG_SUN50I_H6_PRCM_PPU=m
@ -2644,6 +2648,7 @@ CONFIG_PHY_CAN_TRANSCEIVER=m
CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_SUN9I_USB=y
CONFIG_PHY_SUN50I_USB3=y
CONFIG_AW_INNO_COMBOPHY=y
CONFIG_ARM_CCI_PMU=y
# CONFIG_ARM_CCI400_PMU is not set
# CONFIG_ARM_CCI5xx_PMU is not set

View File

@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sun, 11 Jan 2026 12:11:10 +0000
Subject: arm64: dts: allwinner: a527-cubie-a5e: enable PCIe/USB-C combophy
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
---
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 58 ++++++++++
1 file changed, 58 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
index 111111111111..222222222222 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
@@ -76,6 +76,39 @@ reg_usb_vbus: vbus {
gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
enable-active-high;
};
+
+ reg_pcie_vcc3v3: regulator-pcie-vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-enable-ramp-delay = <1000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&r_pio 0 11 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ gma340_oe: gma340-oe {
+ compatible = "regulator-fixed";
+ regulator-name = "gma340-oe";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&pio 1 7 GPIO_ACTIVE_LOW>;
+ };
+
+ gma340_pcie: gma340-pcie {
+ compatible = "regulator-fixed";
+ regulator-name = "gma340-pcie";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&pio 1 6 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
&ehci0 {
@@ -434,3 +467,28 @@ w25q128: flash@0 {
status = "okay";
};
};
+
+/* PCIE and USB Switch */
+&combophy {
+ resets = <&ccu RST_BUS_PCIE_USB3>;
+ phy_use_sel = <0>; /* 0:PCIE; 1:USB3 */
+ status = "okay";
+};
+
+&pcie {
+ reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;
+ wake-gpios = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ num-lanes = <1>;
+ clk-freq-100M;
+ pcie3v3-supply = <&reg_pcie_vcc3v3>;
+ status = "okay";
+};
+
+&usbc1 {
+ device_type = "usbc1";
+ usb_regulator_io = "nocare";
+ usb_wakeup_suspend = <1>;
+ wakeup-source;
+ status = "okay";
+};
+
--
Armbian

View File

@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Mon, 5 Jan 2026 21:41:18 +0000
Subject: arm64: dts: allwinner: sun55i-a523: add iommu and PCIe/USB-C nodes
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi | 84 ++++++++++
1 file changed, 84 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index 111111111111..222222222222 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -12,6 +12,7 @@
#include <dt-bindings/power/allwinner,sun55i-a523-ppu.h>
#include <dt-bindings/power/allwinner,sun55i-a523-pck-600.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/phy/phy.h>
/ {
interrupt-parent = <&gic>;
@@ -113,6 +114,17 @@ timer {
<GIC_PPI 10 IRQ_TYPE_LEVEL_HIGH>;
};
+ iommu: iommu@2010000 {
+ compatible = "allwinner,sun55i-a523-iommu";
+ reg = <0x0 0x02010000 0x0 0x1000>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "iommu-irq";
+ clocks = <&ccu CLK_IOMMU>;
+ clock-names = "iommu";
+ /* clock-frequency = <24000000>; */
+ #iommu-cells = <2>;
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -844,6 +856,78 @@ gmac1_mtl_tx_setup: tx-queues-config {
};
};
+usbc1: usbc1@11 {
+ device_type = "usbc1";
+ reg = <0x11 0x1000>;
+ usb_regulator_io = "nocare";
+ usb_wakeup_suspend = <0>;
+ status = "disabled";
+};
+
+combophy: phy@4f00000 {
+ compatible = "allwinner,inno-combphy";
+ reg = <0x04f00000 0x80000>, /* Sub-System Application Registers */
+ <0x04f80000 0x80000>; /* Combo INNO PHY Registers */
+ reg-names = "phy-ctl", "phy-clk";
+ power-domains = <&pck600 PD_PCIE>;
+ phy_refclk_sel = <0>; /* 0:internal clk; 1:external clk */
+ clocks = <&ccu CLK_USB3_REF>, <&ccu CLK_PLL_PERIPH0_200M>;
+ clock-names = "phyclk_ref","refclk_par";
+ resets = <&ccu RST_BUS_PCIE_USB3>;
+ reset-names = "phy_rst";
+ #phy-cells = <1>;
+ status = "disabled";
+};
+
+pcie: pcie@4800000 {
+ compatible = "allwinner,sunxi-pcie-v210-rc";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xff>;
+ reg = <0x04800000 0x480000>;
+ reg-names = "dbi";
+ device_type = "pci";
+ ranges = <0x00000800 0 0x20000000 0x20000000 0 0x01000000
+ 0x81000000 0 0x21000000 0x21000000 0 0x01000000
+ 0x82000000 0 0x22000000 0x22000000 0 0x0e000000>;
+ num-lanes = <1>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ phy-names = "pcie-phy";
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "msi", "sii", "edma-w0", "edma-w1", "edma-w2", "edma-w3",
+ "edma-r0", "edma-r1", "edma-r2", "edma-r3";
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc 0>,
+ <0 0 0 2 &pcie_intc 1>,
+ <0 0 0 3 &pcie_intc 2>,
+ <0 0 0 4 &pcie_intc 3>;
+ num-edma = <4>;
+ max-link-speed = <2>;
+ num-ib-windows = <8>;
+ num-ob-windows = <8>;
+ linux,pci-domain = <0>;
+ power-domains = <&pck600 PD_PCIE>;
+ clocks = <&osc24M>, <&ccu CLK_PCIE_AUX>;
+ clock-names = "hosc", "pclk_aux";
+ status = "disabled";
+
+ pcie_intc: legacy-interrupt-controller {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ };
+};
+
ppu: power-controller@7001400 {
compatible = "allwinner,sun55i-a523-ppu";
reg = <0x07001400 0x400>;
--
Armbian

View File

@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Tue, 6 Jan 2026 13:46:53 +0000
Subject: arm64: dts: allwinner: t527-orangepi-4a: enable PCIe combophy
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts | 15 ++++++++++
1 file changed, 15 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
index 111111111111..222222222222 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
@@ -442,6 +442,21 @@ bluetooth {
};
};
+&combophy {
+ resets = <&ccu RST_BUS_PCIE_USB3>;
+ phy_use_sel = <0>;
+ status = "okay";
+};
+
+&pcie {
+ reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;
+ wake-gpios = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ num-lanes = <2>;
+ clk-freq-100M;
+ pcie3v3-supply = <&reg_pcie_vcc3v3>;
+ status = "okay";
+};
+
&usb_otg {
/*
* The OTG controller is connected to one of the type-A ports.
--
Armbian

View File

@ -0,0 +1,64 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Tue, 9 Dec 2025 16:43:16 +0000
Subject: clk: sunxi-ng: add A523 USB3 ref clock and reset
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 13 +++++++++-
include/dt-bindings/clock/sun55i-a523-ccu.h | 1 +
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
index 111111111111..222222222222 100644
--- a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
+++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c
@@ -1186,6 +1186,15 @@ static SUNXI_CCU_MUX_DATA_WITH_GATE(fanout2_clk, "fanout2", fanout_parents,
BIT(23), /* gate */
0);
+static const struct clk_parent_data usb3_ref_parents[] = { { .fw_name = "hosc" }, { .hw = &pll_periph0_200M_clk.hw }, { .hw = &pll_periph1_200M_clk.hw } };
+static SUNXI_CCU_M_DATA_WITH_MUX_GATE(usb3_ref_clk, "usb3-ref",
+ usb3_ref_parents, 0x0A84,
+ 0, 5, /* M */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+
/*
* Contains all clocks that are controlled by a hardware register. They
* have a (sunxi) .common member, which needs to be initialised by the common
@@ -1354,6 +1363,7 @@ static struct ccu_common *sun55i_a523_ccu_clks[] = {
&fanout0_clk.common,
&fanout1_clk.common,
&fanout2_clk.common,
+ &usb3_ref_clk.common,
};
static struct clk_hw_onecell_data sun55i_a523_hw_clks = {
@@ -1538,8 +1548,9 @@ static struct clk_hw_onecell_data sun55i_a523_hw_clks = {
[CLK_FANOUT1] = &fanout1_clk.common.hw,
[CLK_FANOUT2] = &fanout2_clk.common.hw,
[CLK_NPU] = &npu_clk.common.hw,
+ [CLK_USB3_REF] = &usb3_ref_clk.common.hw,
},
- .num = CLK_NPU + 1,
+ .num = CLK_USB3_REF + 1,
};
static struct ccu_reset_map sun55i_a523_ccu_resets[] = {
diff --git a/include/dt-bindings/clock/sun55i-a523-ccu.h b/include/dt-bindings/clock/sun55i-a523-ccu.h
index 111111111111..222222222222 100644
--- a/include/dt-bindings/clock/sun55i-a523-ccu.h
+++ b/include/dt-bindings/clock/sun55i-a523-ccu.h
@@ -186,5 +186,6 @@
#define CLK_FANOUT1 177
#define CLK_FANOUT2 178
#define CLK_NPU 179
+#define CLK_USB3_REF 180
#endif /* _DT_BINDINGS_CLK_SUN55I_A523_CCU_H_ */
--
Armbian

View File

@ -2,10 +2,14 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@kernel.org>
Date: Sun, 21 Dec 2025 11:05:52 +0000
Subject: arm64: allwinner: a523: Support SPI controllers
Original patch by Chen-Yu Tsai.
Modified by [Marvin Wewer <mwewer37@proton.me>]: Added SPI support for Radxa Cubie A5E
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
drivers/spi/spi-sun6i.c
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
https://patchwork.kernel.org/project/linux-arm-kernel/cover/20251221110513.1850535-1-wens@kernel.org/
@ -13,9 +17,10 @@ Signed-off-by: Chen-Yu Tsai <wens@kernel.org>
---
Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml | 4 +
arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi | 94 ++++++++++
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 13 ++
arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts | 15 ++
drivers/spi/spi-sun6i.c | 11 +-
4 files changed, 120 insertions(+), 4 deletions(-)
5 files changed, 133 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml b/Documentation/devicetree/bindings/spi/allwinner,sun6i-a31-spi.yaml
index 111111111111..222222222222 100644
@ -158,6 +163,27 @@ index 111111111111..222222222222 100644
mcu_ccu: clock-controller@7102000 {
compatible = "allwinner,sun55i-a523-mcu-ccu";
reg = <0x7102000 0x200>;
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
index 111111111111..222222222222 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
@@ -421,3 +421,16 @@ &usbphy {
usb1_vbus-supply = <&reg_usb_vbus>;
status = "okay";
};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pc_pins>, <&spi0_cs0_pc_pin>;
+ status = "okay";
+ w25q128: flash@0 {
+ compatible = "winbond,w25q128fw", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <24000000>;
+ vcc-supply = <&reg_cldo1>;
+ status = "okay";
+ };
+};
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
index 111111111111..222222222222 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts

View File

@ -550,3 +550,10 @@
patches.armbian/drv-usb-gadget-composite-rename-serial-manufacturer.patch
patches.armbian/drv-video-st7796s-fb-tft-driver.patch
patches.armbian/include-uapi-drm_fourcc-add-ARM-tiled-format-modifier.patch
patches.armbian/drv-clk-sunxi-ng-fix-clock-handling-for-ccu-sun55i-a523.patch
patches.armbian/drv-pci-sunxi-enable-pcie-support.patch
patches.armbian/drv-phy-allwinner-add-pcie-usb3-driver.patch
patches.armbian/drv-iommu-sunxi-add-iommu-driver.patch
patches.armbian/arm64-dts-sun55i-t527-orangepi-4a-enable-pcie-combophy.patch
patches.armbian/arm64-dts-sun55i-a527-cubie-a5e-enable-usbc-pcie-combophy.patch
patches.armbian/arm64-dts-sun55i-dtsi-add-iommu-usbc-pcie-combophy-nodes.patch

View File

@ -0,0 +1,127 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Thu, 23 Oct 2025 13:30:29 +0000
Subject: spi: sunxi: Add support for Allwinner A523 SPI controllers
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
drivers/spi/spi-sunxi.c | 44 ++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c
index 111111111111..222222222222 100644
--- a/drivers/spi/spi-sunxi.c
+++ b/drivers/spi/spi-sunxi.c
@@ -82,10 +82,12 @@ DECLARE_GLOBAL_DATA_PTR;
#endif
#define SUN4I_SPI_MIN_RATE 3000
#define SUN4I_SPI_DEFAULT_RATE 1000000
#define SUN4I_SPI_TIMEOUT_MS 1000
+#define SUN55I_BUF_STA_REG 0x400
+
#define SPI_REG(priv, reg) ((priv)->base + \
(priv)->variant->regs[reg])
#define SPI_BIT(priv, bit) ((priv)->variant->bits[bit])
#define SPI_CS(priv, cs) (((cs) << SPI_BIT(priv, SPI_TCR_CS_SEL)) & \
SPI_BIT(priv, SPI_TCR_CS_MASK))
@@ -128,10 +130,11 @@ struct sun4i_spi_variant {
const u32 *bits;
u32 fifo_depth;
bool has_soft_reset;
bool has_burst_ctl;
bool has_clk_ctl;
+ bool has_bsr;
};
struct sun4i_spi_plat {
struct sun4i_spi_variant *variant;
u32 base;
@@ -364,10 +367,25 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen,
/* Reset FIFOs */
setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) |
SPI_BIT(priv, SPI_FCR_TF_RST));
+ if (priv->variant->has_bsr) {
+ u32 reg;
+ int ret;
+
+ ret = readl_poll_timeout(SPI_REG(priv, SPI_FCR), reg,
+ !(reg & (SPI_BIT(priv, SPI_FCR_RF_RST) |
+ SPI_BIT(priv, SPI_FCR_TF_RST))),
+ SUN4I_SPI_TIMEOUT_MS * 1000);
+ if (ret) {
+ printf("ERROR: sun4i_spi: FIFO reset timeout\n");
+ sun4i_spi_set_cs(bus, slave_plat->cs[0], false);
+ return ret;
+ }
+ }
+
while (len) {
/* Setup the transfer now... */
nbytes = min(len, (priv->variant->fifo_depth - 1));
/* Setup the counters */
@@ -517,10 +535,23 @@ static const unsigned long sun6i_spi_regs[] = {
[SPI_BCTL] = SUN6I_BURST_CTL_REG,
[SPI_TXD] = SUN6I_TXDATA_REG,
[SPI_RXD] = SUN6I_RXDATA_REG,
};
+static const unsigned long sun55i_spi_regs[] = {
+ [SPI_GCR] = SUN6I_GBL_CTL_REG,
+ [SPI_TCR] = SUN6I_TFR_CTL_REG,
+ [SPI_FCR] = SUN6I_FIFO_CTL_REG,
+ [SPI_FSR] = SUN55I_BUF_STA_REG,
+ [SPI_CCR] = SUN6I_CLK_CTL_REG,
+ [SPI_BC] = SUN6I_BURST_CNT_REG,
+ [SPI_TC] = SUN6I_XMIT_CNT_REG,
+ [SPI_BCTL] = SUN6I_BURST_CTL_REG,
+ [SPI_TXD] = SUN6I_TXDATA_REG,
+ [SPI_RXD] = SUN6I_RXDATA_REG,
+};
+
static const u32 sun6i_spi_bits[] = {
[SPI_GCR_TP] = BIT(7),
[SPI_GCR_SRST] = BIT(31),
[SPI_TCR_CPHA] = BIT(0),
[SPI_TCR_CPOL] = BIT(1),
@@ -568,10 +599,19 @@ static const struct sun4i_spi_variant sun50i_r329_spi_variant = {
.fifo_depth = 64,
.has_soft_reset = true,
.has_burst_ctl = true,
};
+static const struct sun4i_spi_variant sun55i_a523_spi_variant = {
+ .regs = sun55i_spi_regs,
+ .bits = sun6i_spi_bits,
+ .fifo_depth = 64,
+ .has_soft_reset = true,
+ .has_burst_ctl = true,
+ .has_bsr = true,
+};
+
static const struct udevice_id sun4i_spi_ids[] = {
{
.compatible = "allwinner,sun4i-a10-spi",
.data = (ulong)&sun4i_a10_spi_variant,
},
@@ -585,10 +625,14 @@ static const struct udevice_id sun4i_spi_ids[] = {
},
{
.compatible = "allwinner,sun50i-r329-spi",
.data = (ulong)&sun50i_r329_spi_variant,
},
+ {
+ .compatible = "allwinner,sun55i-a523-spi",
+ .data = (ulong)&sun55i_a523_spi_variant,
+ },
{ /* sentinel */ }
};
U_BOOT_DRIVER(sun4i_spi) = {
.name = "sun4i_spi",
--
Armbian

View File

@ -0,0 +1,236 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Mon, 10 Nov 2025 22:10:36 +0000
Subject: Add Allwinner A523 support for SPL SPI controllers
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
arch/arm/mach-sunxi/spl_spi_sunxi.c | 107 ++++++----
1 file changed, 68 insertions(+), 39 deletions(-)
diff --git a/arch/arm/mach-sunxi/spl_spi_sunxi.c b/arch/arm/mach-sunxi/spl_spi_sunxi.c
index 111111111111..222222222222 100644
--- a/arch/arm/mach-sunxi/spl_spi_sunxi.c
+++ b/arch/arm/mach-sunxi/spl_spi_sunxi.c
@@ -99,35 +99,44 @@
#define SPI0_CLK_DIV_BY_2 0x1000
#define SPI0_CLK_DIV_BY_4 0x1001
#define SPI0_CLK_DIV_BY_32 0x100f
+#define SUN55I_BUF_STA_REG 0x400
+
/*****************************************************************************/
/*
* Allwinner A10/A20 SoCs were using pins PC0,PC1,PC2,PC23 for booting
* from SPI Flash, everything else is using pins PC0,PC1,PC2,PC3.
* The H6 uses PC0, PC2, PC3, PC5, the H616 PC0, PC2, PC3, PC4.
*/
static void spi0_pinmux_setup(unsigned int pin_function)
{
+ if (IS_ENABLED(CONFIG_MACH_SUN55I_A523)) {
+ sunxi_gpio_set_cfgpin(SUNXI_GPC(12), pin_function);
+ }
+
/* All chips use PC2. And all chips use PC0, except R528/T113 */
- if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+ if (!IS_ENABLED(CONFIG_MACH_SUN8I_R528) &&
+ !IS_ENABLED(CONFIG_MACH_SUN55I_A523))
sunxi_gpio_set_cfgpin(SUNXI_GPC(0), pin_function);
sunxi_gpio_set_cfgpin(SUNXI_GPC(2), pin_function);
/* All chips except H6/H616/R528/T113 use PC1. */
if (!IS_ENABLED(CONFIG_SUN50I_GEN_H6) &&
- !IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+ !IS_ENABLED(CONFIG_MACH_SUN8I_R528) &&
+ !IS_ENABLED(CONFIG_MACH_SUN55I_A523))
sunxi_gpio_set_cfgpin(SUNXI_GPC(1), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN50I_H6) ||
IS_ENABLED(CONFIG_MACH_SUN8I_R528))
sunxi_gpio_set_cfgpin(SUNXI_GPC(5), pin_function);
if (IS_ENABLED(CONFIG_MACH_SUN50I_H616) ||
- IS_ENABLED(CONFIG_MACH_SUN8I_R528))
+ IS_ENABLED(CONFIG_MACH_SUN8I_R528) ||
+ IS_ENABLED(CONFIG_MACH_SUN55I_A523))
sunxi_gpio_set_cfgpin(SUNXI_GPC(4), pin_function);
/* Older generations use PC23 for CS, newer ones use PC3. */
if (IS_ENABLED(CONFIG_MACH_SUN4I) || IS_ENABLED(CONFIG_MACH_SUN7I) ||
IS_ENABLED(CONFIG_MACH_SUN8I_R40))
@@ -142,10 +151,15 @@ static bool is_sun6i_gen_spi(void)
IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
IS_ENABLED(CONFIG_SUNXI_GEN_NCAT2) ||
IS_ENABLED(CONFIG_MACH_SUN8I_V3S);
}
+static bool is_sun55i_gen_spi(void)
+{
+ return IS_ENABLED(CONFIG_MACH_SUN55I_A523);
+}
+
static uintptr_t spi0_base_address(void)
{
if (IS_ENABLED(CONFIG_MACH_SUN8I_R40))
return 0x01C05000;
@@ -225,11 +239,11 @@ static void spi0_enable_clock(void)
static void spi0_disable_clock(void)
{
uintptr_t base = spi0_base_address();
/* Disable the SPI0 controller */
- if (is_sun6i_gen_spi())
+ if (is_sun6i_gen_spi() || is_sun55i_gen_spi())
clrbits_le32(base + SUN6I_SPI0_GCR, SUN6I_CTL_MASTER |
SUN6I_CTL_ENABLE);
else
clrbits_le32(base + SUN4I_SPI0_CTL, SUN4I_CTL_MASTER |
SUN4I_CTL_ENABLE);
@@ -255,11 +269,12 @@ static void spi0_disable_clock(void)
static void spi0_init(void)
{
unsigned int pin_function = SUNXI_GPC_SPI0;
if (IS_ENABLED(CONFIG_MACH_SUN50I) ||
- IS_ENABLED(CONFIG_SUN50I_GEN_H6))
+ IS_ENABLED(CONFIG_SUN50I_GEN_H6) ||
+ IS_ENABLED(CONFIG_MACH_SUN55I_A523))
pin_function = SUN50I_GPC_SPI0;
else if (IS_ENABLED(CONFIG_MACH_SUNIV) ||
IS_ENABLED(CONFIG_MACH_SUN8I_R528))
pin_function = SUNIV_GPC_SPI0;
@@ -270,11 +285,12 @@ static void spi0_init(void)
static void spi0_deinit(void)
{
/* New SoCs can disable pins, older could only set them as input */
unsigned int pin_function = SUNXI_GPIO_INPUT;
- if (is_sun6i_gen_spi())
+ if (is_sun6i_gen_spi() ||
+ is_sun55i_gen_spi())
pin_function = SUNXI_GPIO_DISABLE;
spi0_disable_clock();
spi0_pinmux_setup(pin_function);
}
@@ -282,46 +298,49 @@ static void spi0_deinit(void)
/*****************************************************************************/
#define SPI_READ_MAX_SIZE 60 /* FIFO size, minus 4 bytes of the header */
static void sunxi_spi0_read_data(u8 *buf, u32 addr, u32 bufsize,
- ulong spi_ctl_reg,
- ulong spi_ctl_xch_bitmask,
- ulong spi_fifo_reg,
- ulong spi_tx_reg,
- ulong spi_rx_reg,
- ulong spi_bc_reg,
- ulong spi_tc_reg,
- ulong spi_bcc_reg)
+ ulong spi_ctl_reg,
+ ulong spi_ctl_xch_bitmask,
+ ulong spi_fifo_reg,
+ ulong spi_tx_reg,
+ ulong spi_rx_reg,
+ ulong spi_bc_reg,
+ ulong spi_tc_reg,
+ ulong spi_bcc_reg)
{
- writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
- writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */
- if (spi_bcc_reg)
- writel(4, spi_bcc_reg); /* SUN6I also needs this */
-
- /* Send the Read Data Bytes (03h) command header */
- writeb(0x03, spi_tx_reg);
- writeb((u8)(addr >> 16), spi_tx_reg);
- writeb((u8)(addr >> 8), spi_tx_reg);
- writeb((u8)(addr), spi_tx_reg);
-
- /* Start the data transfer */
- setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
-
- /* Wait until everything is received in the RX FIFO */
- while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize)
- ;
+ writel(4 + bufsize, spi_bc_reg); /* Burst counter (total bytes) */
+ writel(4, spi_tc_reg); /* Transfer counter (bytes to send) */
+ if (spi_bcc_reg)
+ writel(4, spi_bcc_reg); /* SUN6I also needs this */
+
+ /* Send the Read Data Bytes (03h) command header */
+ writeb(0x03, spi_tx_reg);
+ writeb((u8)(addr >> 16), spi_tx_reg);
+ writeb((u8)(addr >> 8), spi_tx_reg);
+ writeb((u8)(addr), spi_tx_reg);
+
+ /* Start the data transfer */
+ setbits_le32(spi_ctl_reg, spi_ctl_xch_bitmask);
+
+ /* Wait until everything is received in the RX FIFO */
+#if IS_ENABLED(CONFIG_MACH_SUN55I_A523)
+ while ((readl(spi_fifo_reg) & 0xFF) < 4 + bufsize);
+#else
+ while ((readl(spi_fifo_reg) & 0x7F) < 4 + bufsize);
+#endif
- /* Skip 4 bytes */
- readl(spi_rx_reg);
+ /* Skip 4 bytes */
+ readl(spi_rx_reg);
- /* Read the data */
- while (bufsize-- > 0)
- *buf++ = readb(spi_rx_reg);
+ /* Read the data */
+ while (bufsize-- > 0)
+ *buf++ = readb(spi_rx_reg);
- /* tSHSL time is up to 100 ns in various SPI flash datasheets */
- udelay(1);
+ /* tSHSL time is up to 100 ns in various SPI flash datasheets */
+ udelay(1);
}
static void spi0_read_data(void *buf, u32 addr, u32 len)
{
u8 *buf8 = buf;
@@ -331,20 +350,30 @@ static void spi0_read_data(void *buf, u32 addr, u32 len)
while (len > 0) {
chunk_len = len;
if (chunk_len > SPI_READ_MAX_SIZE)
chunk_len = SPI_READ_MAX_SIZE;
- if (is_sun6i_gen_spi()) {
+ if (is_sun6i_gen_spi() && !is_sun55i_gen_spi()) {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN6I_SPI0_TCR,
SUN6I_TCR_XCH,
base + SUN6I_SPI0_FIFO_STA,
base + SUN6I_SPI0_TXD,
base + SUN6I_SPI0_RXD,
base + SUN6I_SPI0_MBC,
base + SUN6I_SPI0_MTC,
base + SUN6I_SPI0_BCC);
+ } else if (is_sun55i_gen_spi()) {
+ sunxi_spi0_read_data(buf8, addr, chunk_len,
+ base + SUN6I_SPI0_TCR,
+ SUN6I_TCR_XCH,
+ base + SUN55I_BUF_STA_REG,
+ base + SUN6I_SPI0_TXD,
+ base + SUN6I_SPI0_RXD,
+ base + SUN6I_SPI0_MBC,
+ base + SUN6I_SPI0_MTC,
+ base + SUN6I_SPI0_BCC);
} else {
sunxi_spi0_read_data(buf8, addr, chunk_len,
base + SUN4I_SPI0_CTL,
SUN4I_CTL_XCH,
base + SUN4I_SPI0_FIFO_STA,
--
Armbian

View File

@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sun, 16 Nov 2025 13:44:00 +0000
Subject: Add NVME boot target support to sunxi-common.h
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
include/configs/sunxi-common.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 111111111111..222222222222 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -206,10 +206,16 @@
#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na)
#else
#define BOOT_TARGET_DEVICES_DHCP(func)
#endif
+#ifdef CONFIG_CMD_NVME
+#define BOOT_TARGET_DEVICES_NVME(func) func(NVME, nvme, 0)
+#else
+#define BOOT_TARGET_DEVICES_NVME(func)
+#endif
+
/* FEL boot support, auto-execute boot.scr if a script address was provided */
#define BOOTENV_DEV_FEL(devtypeu, devtypel, instance) \
"bootcmd_fel=" \
"if test -n ${fel_booted} && test -n ${fel_scriptaddr}; then " \
"echo '(FEL boot)'; " \
@@ -218,10 +224,11 @@
#define BOOTENV_DEV_NAME_FEL(devtypeu, devtypel, instance) \
"fel "
#define BOOT_TARGET_DEVICES(func) \
func(FEL, fel, na) \
+ BOOT_TARGET_DEVICES_NVME(func) \
BOOT_TARGET_DEVICES_MMC(func) \
BOOT_TARGET_DEVICES_SCSI(func) \
BOOT_TARGET_DEVICES_USB(func) \
BOOT_TARGET_DEVICES_PXE(func) \
BOOT_TARGET_DEVICES_DHCP(func)
--
Armbian

View File

@ -0,0 +1,141 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sat, 25 Oct 2025 16:50:43 +0000
Subject: arm64: dts: allwinner: sun55i-a527-cubie-a5e: Enable SPI0 and PCIe with ComboPHY
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts | 84 ++++++++++
1 file changed, 84 insertions(+)
diff --git a/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts b/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts
index 111111111111..222222222222 100644
--- a/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/dts/upstream/src/arm64/allwinner/sun55i-a527-cubie-a5e.dts
@@ -43,10 +43,34 @@
regulator-max-microvolt = <5000000>;
vin-supply = <&reg_vcc5v>;
gpio = <&r_pio 0 8 GPIO_ACTIVE_HIGH>; /* PL8 */
enable-active-high;
};
+
+ reg_pcie_vcc3v3: regulator-pcie-vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "pcie-pwren";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&r_pio 0 11 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie_pwren_pins>;
+ };
+
+ reg_vcc_3v3: vcc-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ };
};
&ehci0 {
status = "okay";
};
@@ -102,10 +126,34 @@
vcc-pg-supply = <&reg_bldo1>;
vcc-ph-supply = <&reg_cldo3>; /* via VCC-IO */
vcc-pi-supply = <&reg_cldo3>;
vcc-pj-supply = <&reg_cldo4>;
vcc-pk-supply = <&reg_cldo1>;
+
+ pcie0_pins_ph: pcie0-ph {
+ pins = "PH19";
+ function = "pcie0";
+ allwinner,pinmux = <6>;
+ drive-strength = <20>;
+ bias-pull-up;
+ power-source = <3300>;
+ };
+
+ spi0_pins: spi0-pins {
+ pins = "PC2","PC4", "PC12";
+ allwinner,pinmux = <4>;
+ function = "spi0";
+ drive-strength = <10>;
+ };
+
+ spi0_cs_pin: spi0-cs0-pin {
+ pins = "PC3";
+ allwinner,pinmux = <4>;
+ function = "spi0";
+ drive-strength = <10>;
+ bias-pull-up; /* cs, hold, wp should be pulled up */
+ };
};
&r_i2c0 {
status = "okay";
@@ -280,18 +328,53 @@
* Specifying the supply would create a circular dependency.
*
* vcc-pl-supply = <&reg_aldo3>;
*/
vcc-pm-supply = <&reg_aldo3>;
+
+ pcie_pwren_pins: pcie-pwren-pins {
+ allwinner,pins = "PL11";
+ function = "gpio_out";
+ allwinner,pinmux = <1>;
+ drive-strength = <10>;
+ bias-disable; //bias-pull-up; or bias-pull-down;
+ };
};
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pb_pins>;
status = "okay";
};
+&combophy {
+ select3v3-supply = <&reg_vcc_3v3>;
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-0 = <&spi0_pins>, <&spi0_cs_pin>;
+ pinctrl-names = "default";
+ status = "okay";
+ w25q128: flash@0 {
+ compatible = "winbond,w25q128fw", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <24000000>;
+ vcc-supply = <&reg_cldo1>;
+ status = "okay";
+ };
+};
+
+&pcie {
+ reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;
+ wake-gpios = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ num-lanes = <1>;
+ slot-3v3-supply = <&reg_pcie_vcc3v3>;
+ switch-sel-gpios = <&pio 1 6 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
&usb_otg {
/*
* The USB-C port is the primary power supply, so in this configuration
* relies on the other end of the USB cable to supply the VBUS power.
* So use this port in peripheral mode.
--
Armbian

View File

@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sun, 4 Jan 2026 21:16:16 +0000
Subject: arm64: dts: allwinner: sun55i-t527-orangepi-4a: Enable SPI0 and PCIe with ComboPHY
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
dts/upstream/src/arm64/allwinner/sun55i-t527-orangepi-4a.dts | 38 ++++++++--
1 file changed, 38 insertions(+)
diff --git a/dts/upstream/src/arm64/allwinner/sun55i-t527-orangepi-4a.dts b/dts/upstream/src/arm64/allwinner/sun55i-t527-orangepi-4a.dts
index 111111111111..222222222222 100644
--- a/dts/upstream/src/arm64/allwinner/sun55i-t527-orangepi-4a.dts
+++ b/dts/upstream/src/arm64/allwinner/sun55i-t527-orangepi-4a.dts
@@ -152,10 +152,22 @@
vcc-pg-supply = <&reg_bldo1>;
vcc-ph-supply = <&reg_cldo3>; /* via VCC-IO */
vcc-pi-supply = <&reg_cldo3>;
vcc-pj-supply = <&reg_cldo1>;
vcc-pk-supply = <&reg_cldo1>;
+
+ spi0_pc_pins: spi0-pc-pins {
+ pins = "PC2", "PC4", "PC12";
+ function = "spi0";
+ allwinner,pinmux = <4>;
+ };
+
+ spi0_cs0_pc_pin: spi0-cs0-pc-pin {
+ pins = "PC3";
+ function = "spi0";
+ allwinner,pinmux = <4>;
+ };
};
&r_i2c0 {
status = "okay";
@@ -368,10 +390,36 @@
host-wakeup-gpios = <&r_pio 1 4 GPIO_ACTIVE_HIGH>; /* PM4 */
shutdown-gpios = <&r_pio 1 2 GPIO_ACTIVE_HIGH>; /* PM2 */
};
};
+&combophy {
+ select3v3-supply = <&reg_cldo3>;
+ status = "okay";
+};
+
+&spi0 {
+ pinctrl-0 = <&spi0_pc_pins>, <&spi0_cs0_pc_pin>;
+ pinctrl-names = "default";
+ status = "okay";
+ xm25qu128c: flash@0 {
+ compatible = "xmc,xm25qu128c", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ vcc-supply = <&reg_cldo1>;
+ status = "okay";
+ };
+};
+
+&pcie {
+ reset-gpios = <&pio 7 11 GPIO_ACTIVE_HIGH>;
+ wake-gpios = <&pio 7 12 GPIO_ACTIVE_HIGH>;
+ num-lanes = <2>;
+ slot-3v3-supply = <&reg_pcie_vcc3v3>;
+ status = "okay";
+};
+
&usb_otg {
/*
* The OTG controller is connected to one of the type-A ports.
* There is a regulator, controlled by a GPIO, to provide VBUS power
* to the port, and a VBUSDET GPIO, to detect externally provided
@@ -386,5 +414,6 @@
usb0_vbus-supply = <&reg_otg_vbus>;
usb0_vbus_det-gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
usb1_vbus-supply = <&reg_usb_vbus>;
status = "okay";
};
+
--
Armbian

View File

@ -0,0 +1,114 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Thu, 23 Oct 2025 09:10:08 +0000
Subject: arm64: dts: allwinner: sun55i-a523: Add SPI0, PCIe and Combophy nodes
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi | 66 ++++++++++
1 file changed, 66 insertions(+)
diff --git a/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi b/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi
index 111111111111..222222222222 100644
--- a/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi
+++ b/dts/upstream/src/arm64/allwinner/sun55i-a523.dtsi
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
// Copyright (C) 2023-2024 Arm Ltd.
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/phy/phy.h>
#include <dt-bindings/clock/sun6i-rtc.h>
#include <dt-bindings/clock/sun55i-a523-ccu.h>
#include <dt-bindings/clock/sun55i-a523-r-ccu.h>
#include <dt-bindings/reset/sun55i-a523-ccu.h>
#include <dt-bindings/reset/sun55i-a523-r-ccu.h>
@@ -607,10 +608,38 @@
clocks = <&r_ccu CLK_BUS_R_PPU1>;
resets = <&r_ccu RST_BUS_R_PPU1>;
#power-domain-cells = <1>;
};
+ dma:dma-controller@3002000 {
+ compatible = "allwinner,sun50i-h6-dma";
+ reg = <0x03002000 0x1000>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_DMA>, <&ccu CLK_MBUS_DMA>;
+ clock-names = "bus", "mbus";
+ dma-channels = <8>;
+ dma-requests = <54>;
+ resets = <&ccu RST_BUS_DMA>;
+ #dma-cells = <1>;
+ status = "okay";
+ };
+
+ spi0: spi@4025000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "allwinner,sun55i-a523-spi";
+ device_type = "spi0";
+ reg = <0x04025000 0x1000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_SPI0>, <&ccu CLK_SPI0>;
+ clock-names = "ahb", "mod";
+ resets = <&ccu RST_BUS_SPI0>;
+ dmas = <&dma 22>, <&dma 22>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
r_ccu: clock-controller@7010000 {
compatible = "allwinner,sun55i-a523-r-ccu";
reg = <0x7010000 0x250>;
clocks = <&osc24M>,
<&rtc CLK_OSC32K>,
@@ -624,10 +653,46 @@
"pll-audio";
#clock-cells = <1>;
#reset-cells = <1>;
};
+ combophy: phy@4f00000 {
+ compatible = "allwinner,inno-combphy";
+ reg = <0x04f00000 0x80000>, /* Sub-System Application Registers */
+ <0x04f80000 0x80000>; /* Combo INNO PHY Registers */
+ reg-names = "phy-ctl", "phy-clk";
+ #phy-cells = <1>;
+ clocks = <&ccu CLK_USB3_REF>, <&ccu CLK_PLL_PERIPH0_200M>;
+ clock-names = "phyclk_ref","refclk_par";
+ resets = <&ccu RST_BUS_PCIE_USB3>;
+ reset-names = "phy_rst";
+ };
+
+ pcie: pcie@4800000 {
+ compatible = "allwinner,sun55i-pcie-v210-rc";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ bus-range = <0x0 0xff>;
+ reg = <0x04800000 0x480000>;
+ reg-names = "dbi";
+ device_type = "pci";
+ ranges = <0x00000800 0 0x20000000 0x20000000 0 0x01000000
+ 0x81000000 0 0x21000000 0x21000000 0 0x01000000
+ 0x82000000 0 0x22000000 0x22000000 0 0x0e000000>;
+ phys = <&combophy PHY_TYPE_PCIE>;
+ phy-names = "pcie-phy";
+ #interrupt-cells = <1>;
+ num-edma = <4>;
+ max-link-speed = <2>;
+ num-ib-windows = <8>;
+ num-ob-windows = <8>;
+ linux,pci-domain = <0>;
+ clocks = <&osc24M>, <&ccu CLK_PCIE_AUX>;
+ clock-names = "hosc", "pclk_aux";
+ power-domains = <&pck600 PD_PCIE>;
+ };
+
nmi_intc: interrupt-controller@7010320 {
compatible = "allwinner,sun55i-a523-nmi";
reg = <0x07010320 0xc>;
interrupt-controller;
#interrupt-cells = <2>;
--
Armbian

View File

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sat, 25 Oct 2025 10:54:53 +0000
Subject: clk: sunxi: Add USB3 and PCIe clock gates and reset for A523
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
drivers/clk/sunxi/clk_a523.c | 3 +++
dts/upstream/include/dt-bindings/clock/sun55i-a523-ccu.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/clk/sunxi/clk_a523.c b/drivers/clk/sunxi/clk_a523.c
index 111111111111..222222222222 100644
--- a/drivers/clk/sunxi/clk_a523.c
+++ b/drivers/clk/sunxi/clk_a523.c
@@ -44,10 +44,12 @@ static struct ccu_clk_gate a523_gates[] = {
[CLK_BUS_OHCI0] = GATE(0xa8c, BIT(0)),
[CLK_BUS_OHCI1] = GATE(0xa8c, BIT(1)),
[CLK_BUS_EHCI0] = GATE(0xa8c, BIT(4)),
[CLK_BUS_EHCI1] = GATE(0xa8c, BIT(5)),
[CLK_BUS_OTG] = GATE(0xa8c, BIT(8)),
+ [CLK_USB3_REF] = GATE(0x0A84, BIT(31)),
+ [CLK_PCIE_AUX] = GATE(0xaa0, BIT(31)),
};
static struct ccu_reset a523_resets[] = {
[RST_BUS_MMC0] = RESET(0x84c, BIT(16)),
[RST_BUS_MMC1] = RESET(0x84c, BIT(17)),
@@ -73,10 +75,11 @@ static struct ccu_reset a523_resets[] = {
[RST_BUS_OHCI0] = RESET(0xa8c, BIT(16)),
[RST_BUS_OHCI1] = RESET(0xa8c, BIT(17)),
[RST_BUS_EHCI0] = RESET(0xa8c, BIT(20)),
[RST_BUS_EHCI1] = RESET(0xa8c, BIT(21)),
[RST_BUS_OTG] = RESET(0xa8c, BIT(24)),
+ [RST_BUS_PCIE_USB3] = RESET(0xaac, BIT(24)),
};
const struct ccu_desc a523_ccu_desc = {
.gates = a523_gates,
.resets = a523_resets,
diff --git a/dts/upstream/include/dt-bindings/clock/sun55i-a523-ccu.h b/dts/upstream/include/dt-bindings/clock/sun55i-a523-ccu.h
index 111111111111..222222222222 100644
--- a/dts/upstream/include/dt-bindings/clock/sun55i-a523-ccu.h
+++ b/dts/upstream/include/dt-bindings/clock/sun55i-a523-ccu.h
@@ -183,7 +183,8 @@
#define CLK_FANOUT_27M 174
#define CLK_FANOUT_PCLK 175
#define CLK_FANOUT0 176
#define CLK_FANOUT1 177
#define CLK_FANOUT2 178
+#define CLK_USB3_REF 179
#endif /* _DT_BINDINGS_CLK_SUN55I_A523_CCU_H_ */
--
Armbian

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Mon, 12 Jan 2026 13:45:24 +0000
Subject: Enable PCIe, NVMe, SPI and additional commands in orangepi_4a_defconfig
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
configs/orangepi_4a_defconfig | 20 ++++++++++
1 file changed, 20 insertions(+)
diff --git a/configs/orangepi_4a_defconfig b/configs/orangepi_4a_defconfig
index 111111111111..222222222222 100644
--- a/configs/orangepi_4a_defconfig
+++ b/configs/orangepi_4a_defconfig
@@ -28,5 +28,25 @@ CONFIG_AXP717_POWER=y
CONFIG_AXP_I2C_ADDRESS=0x35
CONFIG_AXP_DCDC2_VOLT=920
CONFIG_AXP_DCDC3_VOLT=1160
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
+CONFIG_PHY_SUN55I_PCIE_USB3=y
+CONFIG_PCI=y
+CONFIG_PCIE_SUN55I_RC=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_NVME=y
+CONFIG_NVME_PCI=y
+CONFIG_SPI_SUNXI=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_CAT=y
+CONFIG_BLKMAP=y
+CONFIG_MTD=y
+CONFIG_SPI=y
+CONFIG_CMD_SF=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_BOOTDEV_SPI_FLASH=y
+CONFIG_CMD_BOOTDEV=y
+CONFIG_SPL_SPI_SUNXI=y
--
Armbian

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sun, 19 Oct 2025 11:39:07 +0200
Subject: Enable PCIe, NVMe, SPI and GPIO support in radxa-cubie-a5e_defconfig
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
configs/radxa-cubie-a5e_defconfig | 55 ++++++++++
1 file changed, 55 insertions(+)
diff --git a/configs/radxa-cubie-a5e_defconfig b/configs/radxa-cubie-a5e_defconfig
index 111111111111..222222222222 100644
--- a/configs/radxa-cubie-a5e_defconfig
+++ b/configs/radxa-cubie-a5e_defconfig
@@ -28,5 +28,25 @@ CONFIG_REGULATOR_AXP=y
CONFIG_AXP717_POWER=y
CONFIG_AXP_DCDC2_VOLT=920
CONFIG_AXP_DCDC3_VOLT=1100
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
+CONFIG_PHY_SUN55I_PCIE_USB3=y
+CONFIG_PCI=y
+CONFIG_PCIE_SUN55I_RC=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_NVME=y
+CONFIG_NVME_PCI=y
+CONFIG_SPI_SUNXI=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_PART=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_LSBLK=y
+CONFIG_CMD_CAT=y
+CONFIG_BLKMAP=y
+CONFIG_MTD=y
+CONFIG_SPI=y
+CONFIG_CMD_SF=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_BOOTDEV_SPI_FLASH=y
+CONFIG_CMD_BOOTDEV=y
+CONFIG_SPL_SPI_SUNXI=y
--
Armbian

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,712 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marvin Wewer <mwewer37@proton.me>
Date: Sat, 25 Oct 2025 20:32:35 +0000
Subject: phy: allwinner: Add SUN55I INNO combo PHY driver for PCIe/USB3
Signed-off-by: Marvin Wewer <mwewer37@proton.me>
---
drivers/phy/allwinner/Kconfig | 8 +
drivers/phy/allwinner/Makefile | 1 +
drivers/phy/allwinner/phy-sun55i-pcie-usb3.c | 661 ++++++++++
3 files changed, 670 insertions(+)
diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig
index 111111111111..222222222222 100644
--- a/drivers/phy/allwinner/Kconfig
+++ b/drivers/phy/allwinner/Kconfig
@@ -31,5 +31,13 @@ config PHY_SUN50I_USB3
depends on ARCH_SUNXI
select PHY
help
Enable this to support the USB3 transceiver that is part of
Allwinner sun50i SoCs.
+
+config PHY_SUN55I_PCIE_USB3
+ tristate "Allwinner SUN55I INNO COMBO PHY Driver"
+ depends on ARCH_SUNXI
+ select PHY
+ help
+ Enable this to support the Allwinner sun55i PCIe/USB3.0 combo PHY
+ with INNOSILICON IP block.
diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile
index 111111111111..222222222222 100644
--- a/drivers/phy/allwinner/Makefile
+++ b/drivers/phy/allwinner/Makefile
@@ -3,5 +3,6 @@
# Copyright (C) 2016 Amarula Solutions
#
obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o
+obj-$(CONFIG_PHY_SUN55I_PCIE_USB3) += phy-sun55i-pcie-usb3.o
\ No newline at end of file
diff --git a/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c b/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c
new file mode 100644
index 000000000000..111111111111
--- /dev/null
+++ b/drivers/phy/allwinner/phy-sun55i-pcie-usb3.c
@@ -0,0 +1,661 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner PIPE USB3.0 PCIE Combo Phy driver
+ *
+ * Copyright(c) 2020 - 2024 Allwinner Technology Co.,Ltd. All rights reserved.
+ *
+ * sun55i-inno-combophy.c: chenhuaqiang <chenhuaqiang@allwinnertech.com>
+ */
+
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <log.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/lists.h>
+#include <dt-bindings/phy/phy.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+#include <power-domain.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+#include <reset.h>
+
+
+#define sun55i_COMBOPHY_CTL_BASE 0x04f00000
+#define sun55i_COMBOPHY_CLK_BASE 0x04f80000
+
+/* PCIE USB3 Sub-System Registers */
+/* Sub-System Version Reset Register */
+#define PCIE_USB3_SYS_VER 0x00
+
+/* PHY CLK Gating Control Register */
+#define PCIE_REF_CLK_GATING 31
+
+/* CCMU Base Address */
+#define SUNXI_CCMU_BASE 0x02001000
+#define SUNXI_CCM_BASE (SUNXI_CCMU_BASE)
+
+/* Sub-System PCIE Bus Gating Reset Register */
+#define PCIE_BRG_REG_RST 16
+#define PCIE_BGR_REG (SUNXI_CCM_BASE + 0x0aac)
+
+/* Sub-System PCIE Bus Gating Reset Register */
+#define PCIE_COMBO_PHY_BGR 0x04
+#define PCIE_SLV_ACLK_EN BIT(18)
+#define PCIE_ACLK_EN BIT(17)
+#define PCIE_HCLK_EN BIT(16)
+#define PCIE_PERSTN BIT(1)
+#define PCIE_PW_UP_RSTN BIT(0)
+
+/* Sub-System USB3 Bus Gating Reset Register */
+#define USB3_COMBO_PHY_BGR 0x08
+#define USB3_ACLK_EN BIT(17)
+#define USB3_HCLK_EN BIT(16)
+#define USB3_U2_PHY_RSTN BIT(4)
+#define USB3_U2_PHY_MUX_EN BIT(3)
+#define USB3_U2_PHY_MUX_SEL BIT(0)
+#define USB3_RESETN BIT(0)
+
+/* Sub-System PCIE PHY Control Register */
+#define PCIE_COMBO_PHY_CTL 0x10
+#define PHY_USE_SEL BIT(31) /* 0:PCIE; 1:USB3 */
+#define PHY_CLK_SEL BIT(30) /* 0:internal clk; 1:external clk */
+#define PHY_BIST_EN BIT(16)
+#define PHY_PIPE_SW BIT(9)
+#define PHY_PIPE_SEL BIT(8) /* 0:rstn by PCIE or USB3; 1:rstn by PHY_PIPE_SW */
+#define PHY_PIPE_CLK_INVERT BIT(4)
+#define PHY_FPGA_SYS_RSTN BIT(1) /* for FPGA */
+#define PHY_RSTN BIT(0)
+
+/* PHY CLK Registers (offset from sun55i_COMBOPHY_CLK_BASE) */
+#define PCIE_REF_CLK_REG_PCIE_REF_CLK_GATING_CLEAR_MASK 0x80000000
+
+/* Registers */
+#define COMBO_REG_SYSVER(comb_base_addr) ((comb_base_addr) \
+ + PCIE_USB3_SYS_VER)
+#define COMBO_REG_PCIEBGR(comb_base_addr) ((comb_base_addr) \
+ + PCIE_COMBO_PHY_BGR)
+#define COMBO_REG_USB3BGR(comb_base_addr) ((comb_base_addr) \
+ + USB3_COMBO_PHY_BGR)
+#define COMBO_REG_PHYCTRL(comb_base_addr) ((comb_base_addr) \
+ + PCIE_COMBO_PHY_CTL)
+
+/* Sub-System Version Number */
+#define COMBO_VERSION_01 (0x10000)
+#define COMBO_VERSION_ANY (0x0)
+
+enum phy_use_sel {
+ PHY_USE_BY_PCIE = 0, /* PHY used by PCIE */
+ PHY_USE_BY_USB3, /* PHY used by USB3 */
+ PHY_USE_BY_PCIE_USB3_U2,/* PHY used by PCIE & USB3_U2 */
+};
+
+enum phy_refclk_sel {
+ INTER_SIG_REF_CLK = 0, /* PHY use internal single end reference clock */
+ EXTER_DIF_REF_CLK, /* PHY use external single end reference clock */
+};
+
+struct sun55i_combophy_of_data {
+ bool has_cfg_clk;
+ bool has_slv_clk;
+ bool has_phy_mbus_clk;
+ bool has_phy_ahb_clk;
+ bool has_pcie_axi_clk;
+ bool has_u2_phy_mux;
+ bool need_noppu_rst;
+ bool has_u3_phy_data_quirk;
+ bool need_optimize_jitter;
+};
+
+struct sun55i_combphy {
+ struct device *dev;
+ struct phy *phy;
+ void __iomem *phy_ctl; /* parse dts, control the phy mode, reset and power */
+ void __iomem *phy_clk; /* parse dts, set the phy clock */
+
+ struct reset_ctl reset;
+ struct reset_ctl noppu_reset;
+
+ struct clk *phyclk_ref;
+ struct clk *refclk_par;
+ struct clk *phyclk_cfg;
+ struct clk *cfgclk_par;
+ struct clk *phy_mclk;
+ struct clk *phy_hclk;
+ struct clk *phy_axi;
+ struct clk *phy_axi_par;
+ __u8 mode;
+ __u32 vernum; /* version number */
+ enum phy_use_sel user;
+ enum phy_refclk_sel ref;
+ const struct sun55i_combophy_of_data *drvdata;
+
+ struct udevice *select3v3_supply;
+ bool initialized;
+};
+
+static void sun55i_combphy_usb3_phy_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(combphy->phy_clk + 0x1418);
+ tmp = GENMASK(17, 16);
+ if (enable) {
+ val &= ~tmp;
+ val |= BIT(25);
+ } else {
+ val |= tmp;
+ val &= ~BIT(25);
+ }
+ writel(val, combphy->phy_clk + 0x1418);
+
+ /* reg_rx_eq_bypass[3]=1, rx_ctle_res_cal_bypass */
+ val = readl(combphy->phy_clk + 0x0674);
+ if (enable)
+ val |= BIT(3);
+ else
+ val &= ~BIT(3);
+ writel(val, combphy->phy_clk + 0x0674);
+
+ /* rx_ctle_res_cal=0xf, 0x4->0xf */
+ val = readl(combphy->phy_clk + 0x0704);
+ tmp = GENMASK(9, 8) | BIT(11);
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, combphy->phy_clk + 0x0704);
+
+ /* CDR_div_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0400);
+ if (enable)
+ val |= BIT(4);
+ else
+ val &= ~BIT(4);
+ writel(val, combphy->phy_clk + 0x0400);
+
+ /* CDR_div1_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0404);
+ tmp = GENMASK(3, 0) | BIT(5);
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, combphy->phy_clk + 0x0404);
+
+ /* CDR_div3_fin_gain1 */
+ val = readl(combphy->phy_clk + 0x0408);
+ if (enable)
+ val |= BIT(5);
+ else
+ val &= ~BIT(5);
+ writel(val, combphy->phy_clk + 0x0408);
+
+ val = readl(combphy->phy_clk + 0x109c);
+ if (enable)
+ val |= BIT(1);
+ else
+ val &= ~BIT(1);
+ writel(val, combphy->phy_clk + 0x109c);
+
+ /* balance parm configure */
+ if (combphy->drvdata->has_u3_phy_data_quirk) {
+ val = readl(combphy->phy_clk + 0x0804);
+ if (enable)
+ val |= (0x6<<4);
+ else
+ val &= ~(0xf<<4);
+ writel(val, combphy->phy_clk + 0x0804);
+ }
+
+ /* SSC configure */
+ val = readl(combphy->phy_clk + 0x107c);
+ tmp = 0x3f << 12;
+ val = val & (~tmp);
+ val |= ((0x1 << 12) & tmp); /* div_N */
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1020);
+ tmp = 0x1f << 0;
+ val = val & (~tmp);
+ val |= ((0x6 << 0) & tmp); /* modulation freq div */
+ writel(val, combphy->phy_clk + 0x1020);
+
+ val = readl(combphy->phy_clk + 0x1034);
+ tmp = 0x7f << 16;
+ val = val & (~tmp);
+ val |= ((0x9 << 16) & tmp); /* spread[6:0], 400*9=4410ppm ssc */
+ writel(val, combphy->phy_clk + 0x1034);
+
+ val = readl(combphy->phy_clk + 0x101c);
+ tmp = 0x1 << 27;
+ val = val & (~tmp);
+ val |= ((0x1 << 27) & tmp); /* choose downspread */
+
+ tmp = 0x1 << 28;
+ val = val & (~tmp);
+ if (enable)
+ val |= ((0x0 << 28) & tmp); /* don't disable ssc = 0 */
+ else
+ val |= ((0x1 << 28) & tmp); /* don't enable ssc = 1 */
+ writel(val, combphy->phy_clk + 0x101c);
+
+#ifdef SUN55i_INNO_COMMBOPHY_DEBUG
+ /* TX Eye configure bypass_en */
+ val = readl(combphy->phy_clk + 0x0ddc);
+ if (enable)
+ val |= BIT(4); /* 0x0ddc[4]=1 */
+ else
+ val &= ~BIT(4);
+ writel(val, combphy->phy_clk + 0x0ddc);
+
+ /* Leg_cur[6:0] - 7'd84 */
+ val = readl(combphy->phy_clk + 0x0ddc);
+ val |= ((0x54 & BIT(6)) >> 3); /* 0x0ddc[3] */
+ writel(val, combphy->phy_clk + 0x0ddc);
+
+ val = readl(combphy->phy_clk + 0x0de0);
+ val |= ((0x54 & GENMASK(5, 0)) << 2); /* 0x0de0[7:2] */
+ writel(val, combphy->phy_clk + 0x0de0);
+
+ /* Leg_curb[5:0] - 6'd18 */
+ val = readl(combphy->phy_clk + 0x0de4);
+ val |= ((0x12 & GENMASK(5, 1)) >> 1); /* 0x0de4[4:0] */
+ writel(val, combphy->phy_clk + 0x0de4);
+
+ val = readl(combphy->phy_clk + 0x0de8);
+ val |= ((0x12 & BIT(0)) << 7); /* 0x0de8[7] */
+ writel(val, combphy->phy_clk + 0x0de8);
+
+ /* Exswing_isel */
+ val = readl(combphy->phy_clk + 0x0028);
+ val |= (0x4 << 28); /* 0x28[30:28] */
+ writel(val, combphy->phy_clk + 0x0028);
+
+ /* Exswing_en */
+ val = readl(combphy->phy_clk + 0x0028);
+ if (enable)
+ val |= BIT(31); /* 0x28[31]=1 */
+ else
+ val &= ~BIT(31);
+ writel(val, combphy->phy_clk + 0x0028);
+#endif
+}
+
+static int sun55i_combphy_usb3_init(struct sun55i_combphy *combphy)
+{
+ sun55i_combphy_usb3_phy_set(combphy, true);
+
+ return 0;
+}
+
+// static int sun55i_combphy_usb3_exit(struct sun55i_combphy *combphy)
+// {
+// sun55i_combphy_usb3_phy_set(combphy, false);
+
+// return 0;
+// }
+
+static void sun55i_combphy_pcie_phy_enable(struct sun55i_combphy *combphy)
+{
+ u32 val;
+
+ /* set the phy:
+ * bit(18): slv aclk enable
+ * bit(17): aclk enable
+ * bit(16): hclk enbale
+ * bit(1) : pcie_presetn
+ * bit(0) : pcie_power_up_rstn
+ */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_BGR);
+ val &= (~(0x03<<0));
+ val &= (~(0x03<<16));
+ val |= (0x03<<0);
+ if (combphy->drvdata->has_slv_clk)
+ val |= (0x07<<16);
+ else
+ val |= (0x03<<16);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_BGR);
+
+
+ /* select phy mode, phy assert */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_USE_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+ /* phy De-assert */
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_CLK_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ val |= PHY_RSTN;
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+ val = readl(combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+ val &= (~PHY_CLK_SEL);
+ val &= (~(0x03<<8));
+ val &= (~PHY_FPGA_SYS_RSTN);
+ val &= (~PHY_RSTN);
+ val |= PHY_RSTN;
+ val |= (PHY_FPGA_SYS_RSTN);
+ writel(val, combphy->phy_ctl + PCIE_COMBO_PHY_CTL);
+
+}
+
+static void sun55i_combphy_pcie_phy_100M(struct sun55i_combphy *combphy)
+{
+ u32 val;
+
+ val = readl(combphy->phy_clk + 0x1004);
+ val &= ~(0x3<<3);
+ val &= ~(0x1<<0);
+ val |= (0x1<<0);
+ val |= (0x1<<2);
+ val |= (0x1<<4);
+ writel(val, combphy->phy_clk + 0x1004);
+
+ val = readl(combphy->phy_clk + 0x1018);
+ val &= ~(0x3<<4);
+ val |= (0x3<<4);
+ writel(val, combphy->phy_clk + 0x1018);
+
+ val = readl(combphy->phy_clk + 0x101c);
+ val &= ~(0x0fffffff);
+ writel(val, combphy->phy_clk + 0x101c);
+
+ /* if need optimize jitter parm*/
+ if (combphy->drvdata->need_optimize_jitter) {
+ val = readl(combphy->phy_clk + 0x107c);
+ val &= ~(0x3ffff);
+ val |= (0x4<<12);
+ val |= 0x64;
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1030);
+ val &= ~(0x3<<20);
+ writel(val, combphy->phy_clk + 0x1030);
+
+ val = readl(combphy->phy_clk + 0x1050);
+ val &= ~(0x7<<0);
+ val &= ~(0x7<<5);
+ val &= ~(0x3<<3);
+ val |= (0x3<<3);
+ writel(val, combphy->phy_clk + 0x1050);
+ } else {
+ val = readl(combphy->phy_clk + 0x107c);
+ val &= ~(0x3ffff);
+ val |= (0x2<<12);
+ val |= 0x32;
+ writel(val, combphy->phy_clk + 0x107c);
+
+ val = readl(combphy->phy_clk + 0x1030);
+ val &= ~(0x3<<20);
+ writel(val, combphy->phy_clk + 0x1030);
+
+ val = readl(combphy->phy_clk + 0x1050);
+ val &= ~(0x7<<5);
+ val |= (0x1<<5);
+ writel(val, combphy->phy_clk + 0x1050);
+ }
+
+ val = readl(combphy->phy_clk + 0x1054);
+ val &= ~(0x7<<5);
+ val |= (0x1<<5);
+ writel(val, combphy->phy_clk + 0x1054);
+
+ val = readl(combphy->phy_clk + 0x0804);
+ val &= ~(0xf<<4);
+ val |= (0xc<<4);
+ writel(val, combphy->phy_clk + 0x0804);
+
+ val = readl(combphy->phy_clk + 0x109c);
+ val &= ~(0x3<<8);
+ val |= (0x1<<1);
+ writel(val, combphy->phy_clk + 0x109c);
+
+ writel(0x80540a0a, combphy->phy_clk + 0x1418);
+}
+
+static int sun55i_combphy_pcie_init(struct sun55i_combphy *combphy)
+{
+ sun55i_combphy_pcie_phy_100M(combphy);
+
+ sun55i_combphy_pcie_phy_enable(combphy);
+
+ return 0;
+}
+
+static int sun55i_combphy_set_mode(struct sun55i_combphy *combphy)
+{
+ switch (combphy->mode) {
+ case PHY_TYPE_PCIE:
+ sun55i_combphy_pcie_init(combphy);
+ break;
+ case PHY_TYPE_USB3:
+ if (combphy->user == PHY_USE_BY_PCIE_USB3_U2) {
+ sun55i_combphy_pcie_init(combphy);
+ } else if (combphy->user == PHY_USE_BY_USB3) {
+ sun55i_combphy_usb3_init(combphy);
+ }
+ break;
+ default:
+ printf("incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void combo_phy_mode_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val;
+
+ val = readl(COMBO_REG_PHYCTRL(combphy->phy_ctl));
+
+ /* Set PHY_USE_SEL based on user (default: clear for PCIE/PCIE_USB3_U2, set for USB3) */
+ val &= ~PHY_USE_SEL; /* Default: clear (PCIE mode) */
+ if (combphy->user == PHY_USE_BY_USB3)
+ val |= PHY_USE_SEL;
+
+ /* Set PHY_CLK_SEL based on ref (default: clear for internal, set for external) */
+ val &= ~PHY_CLK_SEL; /* Default: clear (internal clock) */
+ if (combphy->ref == EXTER_DIF_REF_CLK)
+ val |= PHY_CLK_SEL;
+
+ /* Set or clear PHY_RSTN based on enable */
+ if (enable)
+ val |= PHY_RSTN;
+ else
+ val &= ~PHY_RSTN;
+
+ writel(val, COMBO_REG_PHYCTRL(combphy->phy_ctl));
+}
+
+/* PCIE USB3 Sub-system Application */
+static void combo_pcie_clk_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(COMBO_REG_PCIEBGR(combphy->phy_ctl));
+ if (combphy->drvdata->has_slv_clk)
+ tmp = PCIE_SLV_ACLK_EN | PCIE_ACLK_EN | PCIE_HCLK_EN | PCIE_PERSTN | PCIE_PW_UP_RSTN;
+ else
+ tmp = PCIE_ACLK_EN | PCIE_HCLK_EN | PCIE_PERSTN | PCIE_PW_UP_RSTN;
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, COMBO_REG_PCIEBGR(combphy->phy_ctl));
+}
+
+static void combo_usb3_clk_set(struct sun55i_combphy *combphy, bool enable)
+{
+ u32 val, tmp = 0;
+
+ val = readl(COMBO_REG_USB3BGR(combphy->phy_ctl));
+ if (combphy->drvdata->has_u2_phy_mux)
+ tmp = USB3_ACLK_EN | USB3_HCLK_EN | USB3_U2_PHY_MUX_SEL | USB3_U2_PHY_RSTN | USB3_U2_PHY_MUX_EN;
+ else
+ tmp = USB3_ACLK_EN | USB3_HCLK_EN | USB3_RESETN;
+ if (enable)
+ val |= tmp;
+ else
+ val &= ~tmp;
+ writel(val, COMBO_REG_USB3BGR(combphy->phy_ctl));
+}
+
+static u32 combo_sysver_get(struct sun55i_combphy *combphy)
+{
+ u32 reg;
+
+ reg = readl(COMBO_REG_SYSVER(combphy->phy_ctl));
+
+ return reg;
+}
+
+static void pcie_usb3_sub_system_enable(struct sun55i_combphy *combphy)
+{
+ combo_phy_mode_set(combphy, true);
+
+ if (combphy->user == PHY_USE_BY_PCIE)
+ combo_pcie_clk_set(combphy, true);
+ else if (combphy->user == PHY_USE_BY_USB3)
+ combo_usb3_clk_set(combphy, true);
+ else if (combphy->user == PHY_USE_BY_PCIE_USB3_U2) {
+ combo_pcie_clk_set(combphy, true);
+ combo_usb3_clk_set(combphy, true);
+ }
+
+ combphy->vernum = combo_sysver_get(combphy);
+}
+
+static int pcie_usb3_sub_system_init(void *phy)
+{
+ struct sun55i_combphy *combphy = (struct sun55i_combphy *)(phy);
+ unsigned long reg_value = 0;
+
+ if (combphy->initialized)
+ return 0;
+
+ reg_value = readl(PCIE_BGR_REG);
+ reg_value |= (1 << PCIE_BRG_REG_RST);
+ writel(reg_value, PCIE_BGR_REG);
+
+ reg_value = readl(0x2001a84);
+ reg_value |= (1 << PCIE_REF_CLK_GATING);
+ //reg_value = 0x81000001;
+ writel(reg_value, 0x2001a84);
+
+ pcie_usb3_sub_system_enable(combphy);
+
+ combphy->initialized = true;
+
+ return 0;
+}
+
+int sun55i_combphy_init(struct phy *phy)
+{
+ struct sun55i_combphy *combphy = dev_get_priv(phy->dev);
+ int ret;
+
+ if (!combphy) {
+ printf("PHY drvdata not set!\n");
+ return -EIO;
+ }
+
+ if (combphy->select3v3_supply) {
+ ret = regulator_set_enable_if_allowed(combphy->select3v3_supply, true);
+ if (ret && ret != -EALREADY) {
+ printf("PHY: Failed to enable 3.3V supply: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = reset_deassert(&combphy->reset);
+ if (ret) {
+ printf("PHY: Failed to deassert reset: %d\n", ret);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ ret = pcie_usb3_sub_system_init(combphy);
+ if (ret) {
+ printf("PHY: failed to init sub system\n");
+ reset_assert(&combphy->reset);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ ret = sun55i_combphy_set_mode(combphy);
+ if (ret) {
+ printf("PHY: invalid number of arguments\n");
+ reset_assert(&combphy->reset);
+ regulator_set_enable(combphy->select3v3_supply, false);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct sun55i_combophy_of_data sun55i_inno_v1_of_data = {
+ .has_cfg_clk = false,
+};
+
+static int sun55i_inno_phy_probe(struct udevice *dev)
+{
+ struct sun55i_combphy *combphy = dev_get_priv(dev);
+ int ret;
+
+ combphy->phy_ctl = dev_read_addr_name_ptr(dev, "phy-ctl");
+ if (!combphy->phy_ctl)
+ return -ENODEV;
+
+ combphy->phy_clk = dev_read_addr_name_ptr(dev, "phy-clk");
+ if (!combphy->phy_clk)
+ return -ENODEV;
+
+ ret = reset_get_by_index(dev, 0, &combphy->reset);
+ if (ret)
+ return ret;
+
+ ret = device_get_supply_regulator(dev, "select3v3-supply", &combphy->select3v3_supply);
+ if (ret)
+ return ret;
+
+ combphy->drvdata = (const struct sun55i_combophy_of_data *)dev_get_driver_data(dev);
+ combphy->user = PHY_USE_BY_PCIE;
+ combphy->mode = PHY_TYPE_PCIE;
+ combphy->ref = EXTER_DIF_REF_CLK;
+
+ return 0;
+}
+
+static const struct phy_ops sun55i_inno_phy_ops = {
+ .init = sun55i_combphy_init,
+};
+
+static const struct udevice_id sun55i_inno_phy_of_match_table[] = {
+ {
+ .compatible = "allwinner,inno-combphy",
+ .data = (ulong)&sun55i_inno_v1_of_data,
+ },
+};
+
+U_BOOT_DRIVER(sun55i_inno_combophy) = {
+ .name = "sun55i_inno_combophy",
+ .id = UCLASS_PHY,
+ .of_match = sun55i_inno_phy_of_match_table,
+ .ops = &sun55i_inno_phy_ops,
+ .probe = sun55i_inno_phy_probe,
+ .priv_auto = sizeof(struct sun55i_combphy),
+};
--
Armbian