siflower: sf21: new subtarget for sf21a6826/sf21h8898
authorChuanhong Guo <gch981213@gmail.com>
Tue, 8 Oct 2024 06:18:27 +0000 (14:18 +0800)
committerChuanhong Guo <gch981213@gmail.com>
Wed, 5 Feb 2025 03:08:37 +0000 (11:08 +0800)
Siflower SF21A6826/SF21H8898 are a family of RISC-V SoCs with:

 * Quad-core T-Head C908 (1.125G for SF21A6826, 1.25G for SF21H8898)
 * DDR3/DDR4 memory controller
 * 1 QSGMII 4x1G
 * 1 SGMII/2500Base-X 2.5G
 * 1 additional RGMII on SF21H8898
 * Network offloading engine for L2 switching and L3 NAT
 * 2 PCIE Gen2 lanes, operating in either one PCIE Gen2x2 or two
   PCIE Gen2x1 mode
 * 1 USB2.0

Link: https://github.com/openwrt/openwrt/pull/17115
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
71 files changed:
target/linux/siflower/Makefile
target/linux/siflower/dts/sf21.dtsi [new file with mode: 0644]
target/linux/siflower/dts/sf21a6826.dtsi [new file with mode: 0644]
target/linux/siflower/dts/sf21h8898.dtsi [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/clk/siflower/Kconfig
target/linux/siflower/files-6.6/drivers/clk/siflower/Makefile
target/linux/siflower/files-6.6/drivers/clk/siflower/clk-sf19a2890.c
target/linux/siflower/files-6.6/drivers/clk/siflower/clk-sf21-topcrm.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/gpio/gpio-siflower.c
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Kconfig [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Makefile [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dma.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dpns.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/eth.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_debugfs.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-dma.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-ext.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.h [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/net/phy/siflower.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/pci/controller/dwc/pcie-sf21.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/phy/siflower/Kconfig
target/linux/siflower/files-6.6/drivers/phy/siflower/Makefile
target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-pcie.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-usb.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/reset/reset-sf21.c [new file with mode: 0644]
target/linux/siflower/files-6.6/drivers/spi/spi-sf21-qspi.c [new file with mode: 0644]
target/linux/siflower/files-6.6/include/dt-bindings/clock/siflower,sf21-topcrm.h [new file with mode: 0644]
target/linux/siflower/files-6.6/include/dt-bindings/pinctrl/siflower,sf21-iomux.h [new file with mode: 0644]
target/linux/siflower/files-6.6/include/dt-bindings/reset/siflower,sf21-reset.h [new file with mode: 0644]
target/linux/siflower/image/sf21.mk [new file with mode: 0644]
target/linux/siflower/modules.mk
target/linux/siflower/patches-6.6/001-mips-add-support-for-Siflower-SF19A2890.patch [deleted file]
target/linux/siflower/patches-6.6/001-net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/002-clk-add-drivers-for-sf19a2890.patch [deleted file]
target/linux/siflower/patches-6.6/002-net-phy-Optimize-phy-speed-mask-to-be-compatible-to-.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/003-net-phy-Add-driver-for-Motorcomm-yt8821-2.5G-etherne.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/003-reset-add-support-for-sf19a2890.patch [deleted file]
target/linux/siflower/patches-6.6/004-gpio-add-support-for-siflower-socs.patch [deleted file]
target/linux/siflower/patches-6.6/004-mips-add-support-for-Siflower-SF19A2890.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/005-clk-add-drivers-for-siflower-socs.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/005-pinctrl-add-driver-for-siflower-sf19a2890.patch [deleted file]
target/linux/siflower/patches-6.6/006-reset-add-support-for-sf19a2890.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/006-stmmac-add-support-for-sf19a2890.patch [deleted file]
target/linux/siflower/patches-6.6/007-gpio-add-support-for-siflower-socs.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/007-phy-add-support-for-SF19A2890-USB-PHY.patch [deleted file]
target/linux/siflower/patches-6.6/008-pinctrl-add-driver-for-siflower-sf19a2890.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/008-usb-dwc2-add-support-for-Siflower-SF19A2890.patch [deleted file]
target/linux/siflower/patches-6.6/009-stmmac-add-support-for-sf19a2890.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/009-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch [deleted file]
target/linux/siflower/patches-6.6/010-phy-add-support-for-Siflower-USB-PHYs.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/011-usb-dwc2-add-support-for-Siflower-SF19A2890.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/012-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/013-riscv-add-Siflower-RISC-V-SoC-family-Kconfig-support.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/014-riscv-add-an-option-for-efficient-unaligned-access.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/015-reset-add-support-for-sf21a6826-sf21h8898.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/016-spi-spi-mem-allow-gpio-cs-in-spi_mem_exec_op.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/017-spi-add-support-for-sf21-qspi.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/018-pci-dw-pcie-add-support-for-sf21-pcie.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/019-net-phy-add-support-for-Siflower-SF23P1211-SF23P1240.patch [new file with mode: 0644]
target/linux/siflower/patches-6.6/020-net-ethernet-add-support-for-Siflower-DPNS.patch [new file with mode: 0644]
target/linux/siflower/sf21/base-files/etc/board.d/02_network [new file with mode: 0644]
target/linux/siflower/sf21/base-files/lib/upgrade/platform.sh [new file with mode: 0644]
target/linux/siflower/sf21/config-6.6 [new file with mode: 0644]
target/linux/siflower/sf21/target.mk [new file with mode: 0644]

index d6cded021a699f3948f550039a08840d63e65e79..4e65ea091ca2eb42214b7cef74221cdeb1cf8914 100644 (file)
@@ -5,7 +5,7 @@ ARCH:=mipsel
 BOARD:=siflower
 BOARDNAME:=Siflower SoCs
 FEATURES:=squashfs usb usbgadget source-only
-SUBTARGETS:=sf19a2890
+SUBTARGETS:=sf19a2890 sf21
 
 KERNEL_PATCHVER:=6.6
 
diff --git a/target/linux/siflower/dts/sf21.dtsi b/target/linux/siflower/dts/sf21.dtsi
new file mode 100644 (file)
index 0000000..40d87ad
--- /dev/null
@@ -0,0 +1,862 @@
+/*
+ * Copyright 2023 SiFlower Corporation.
+ */
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/siflower,sf21-iomux.h>
+#include <dt-bindings/clock/siflower,sf21-topcrm.h>
+#include <dt-bindings/reset/siflower,sf21-reset.h>
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart1;
+       };
+
+
+       cpus: cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       riscv,isa = "rv64imafdc_svpbmt_zba_zbb_zbc_zbs_zicbom_zicbop_zicboz";
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c",
+                                               "sstc", "svinval", "svnapot", "svpbmt", "zba", "zbb", "zbc", "zbs", "zfh", "zicbom", "zicbop", "zicboz", "zicntr", "zicsr", "zifencei", "zihintpause", "zihpm";
+                       reg = <0>;
+                       i-cache-block-size = <64>;
+                       i-cache-size = <32768>;
+                       i-cache-sets = <128>;
+                       d-cache-block-size = <64>;
+                       d-cache-size = <32768>;
+                       d-cache-sets = <128>;
+                       riscv,cbom-block-size = <64>;
+                       riscv,cbop-block-size = <64>;
+                       riscv,cboz-block-size = <64>;
+                       clocks = <&topcrm CLK_CPU>;
+                       next-level-cache = <&l2_cache>;
+                       mmu-type = "riscv,sv39";
+
+                       cpu0_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+
+               cpu@1 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       riscv,isa = "rv64imafdc_svpbmt_zba_zbb_zbc_zbs_zicbom_zicbop_zicboz";
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c",
+                                               "sstc", "svinval", "svnapot", "svpbmt", "zba", "zbb", "zbc", "zbs", "zfh", "zicbom", "zicbop", "zicboz", "zicntr", "zicsr", "zifencei", "zihintpause", "zihpm";
+                       reg = <1>;
+                       i-cache-block-size = <64>;
+                       i-cache-size = <32768>;
+                       i-cache-sets = <128>;
+                       d-cache-block-size = <64>;
+                       d-cache-size = <32768>;
+                       d-cache-sets = <128>;
+                       riscv,cbom-block-size = <64>;
+                       riscv,cbop-block-size = <64>;
+                       riscv,cboz-block-size = <64>;
+                       clocks = <&topcrm CLK_CPU>;
+                       next-level-cache = <&l2_cache>;
+                       mmu-type = "riscv,sv39";
+
+                       cpu1_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+
+               cpu@2 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       riscv,isa = "rv64imafdc_svpbmt_zba_zbb_zbc_zbs_zicbom_zicbop_zicboz";
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c",
+                                               "sstc", "svinval", "svnapot", "svpbmt", "zba", "zbb", "zbc", "zbs", "zfh", "zicbom", "zicbop", "zicboz", "zicntr", "zicsr", "zifencei", "zihintpause", "zihpm";
+                       reg = <2>;
+                       i-cache-block-size = <64>;
+                       i-cache-size = <32768>;
+                       i-cache-sets = <128>;
+                       d-cache-block-size = <64>;
+                       d-cache-size = <32768>;
+                       d-cache-sets = <128>;
+                       riscv,cbom-block-size = <64>;
+                       riscv,cbop-block-size = <64>;
+                       riscv,cboz-block-size = <64>;
+                       clocks = <&topcrm CLK_CPU>;
+                       next-level-cache = <&l2_cache>;
+                       mmu-type = "riscv,sv39";
+
+                       cpu2_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+
+               cpu@3 {
+                       compatible = "riscv";
+                       device_type = "cpu";
+                       riscv,isa = "rv64imafdc_svpbmt_zba_zbb_zbc_zbs_zicbom_zicbop_zicboz";
+                       riscv,isa-base = "rv64i";
+                       riscv,isa-extensions = "i", "m", "a", "f", "d", "c",
+                                               "sstc", "svinval", "svnapot", "svpbmt", "zba", "zbb", "zbc", "zbs", "zfh", "zicbom", "zicbop", "zicboz", "zicntr", "zicsr", "zifencei", "zihintpause", "zihpm";
+                       reg = <3>;
+                       i-cache-block-size = <64>;
+                       i-cache-size = <32768>;
+                       i-cache-sets = <128>;
+                       d-cache-block-size = <64>;
+                       d-cache-size = <32768>;
+                       d-cache-sets = <128>;
+                       riscv,cbom-block-size = <64>;
+                       riscv,cbop-block-size = <64>;
+                       riscv,cboz-block-size = <64>;
+                       clocks = <&topcrm CLK_CPU>;
+                       next-level-cache = <&l2_cache>;
+                       mmu-type = "riscv,sv39";
+
+                       cpu3_intc: interrupt-controller {
+                               #interrupt-cells = <1>;
+                               compatible = "riscv,cpu-intc";
+                               interrupt-controller;
+                       };
+               };
+
+               l2_cache: l2-cache {
+                       compatible = "cache";
+                       cache-level = <2>;
+                       cache-block-size = <64>;
+                       cache-size = <262144>;
+                       cache-sets = <256>;
+                       cache-unified;
+               };
+       };
+
+       xin25m: xin25m {
+               compatible = "fixed-clock";
+               clock-output-names = "xin25m";
+               clock-frequency = <25000000>;
+               #clock-cells = <0>;
+       };
+
+       pmu {
+               compatible = "riscv,pmu";
+               riscv,event-to-mhpmevent =
+                       <0x00003 0x0 0x9b>, // L1 Dcache Access
+                       <0x00004 0x0 0x9c>, // L1 Dcache Miss
+                       <0x00005 0x0 0x36>, // Branch Instruction
+                       <0x00006 0x0 0x38>, // Branch Mispred
+                       <0x00008 0x0 0x27>, // Stalled Cycles Frontend
+                       <0x00009 0x0 0x28>, // Stalled Cycles Backend
+                       <0x10000 0x0 0x0c>, // L1-dcache load access
+                       <0x10001 0x0 0x0d>, // L1-dcache load miss
+                       <0x10002 0x0 0x0e>, // L1-dcache store access
+                       <0x10003 0x0 0x0f>, // L1-dcache store miss
+                       <0x10004 0x0 0xa2>, // Dcache Hit Caused by Prefetch
+                       <0x10005 0x0 0xa1>, // Dcache Refill Caused by Prefetch
+                       <0x10008 0x0 0x01>, // L1-icache Access
+                       <0x10009 0x0 0x02>, // L1-icache Miss
+                       <0x1000c 0x0 0x9e>, // Icache Prefetch
+                       <0x1000d 0x0 0xa0>, // Icache Prefetch Miss
+                       <0x10010 0x0 0xa5>, // L2 Access
+                       <0x10011 0x0 0xa6>, // L2 Miss
+                       <0x10019 0x0 0xa4>, // Load Dtlb Miss
+                       <0x1001b 0x0 0xa3>, // Store Dtlb Miss
+                       <0x10021 0x0 0x03>; // iTLB Miss
+               riscv,event-to-mhpmcounters =
+                       <0x00001 0x00001 0x00000001>, // cycles
+                       <0x00002 0x00002 0x00000004>, // instructions
+                       <0x00003 0x1ffff 0xfffffff8>; // others
+               riscv,raw-event-to-mhpmcounters =
+                       <0x0 0x0 0xffffffff 0xffffff00 0xfffffff8>;
+       };
+
+       timer: timer {
+               compatible = "riscv,timer";
+       };
+
+       reset: reset-controller {
+               compatible = "siflower,sf21-reset";
+               #reset-cells = <1>;
+               siflower,crm = <&topcrm>;
+       };
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <2>;
+               compatible = "simple-bus";
+               dma-noncoherent;
+               ranges;
+               interrupt-parent = <&plic>;
+
+               pcie0: pcie@00200000 {
+                       compatible = "siflower,sf21-pcie";
+                       status = "disabled";
+                       reg = <0x0 0x00000000 0x0 0x200000>,
+                             <0x0 0x00200000 0x0 0x100000>,
+                             <0x0 0x00300000 0x0 0x080000>,
+                             <0x0 0x00380000 0x0 0x080000>,
+                             <0x0 0xa0000000 0x0 0x080000>;
+                       reg-names = "dbi", "elbi", "atu", "dma", "config";
+                       clocks = <&topcrm CLK_SERDES_CSR>,
+                                <&topcrm CLK_PCIE_REFP>,
+                                <&topcrm CLK_PCIEPLL_FOUT3>;
+                       clock-names = "csr", "ref", "phy";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0xa0080000 0x0 0xa0080000 0x0 0x00080000 /* downstream I/O 256KB */
+                                 0x82000000 0x0 0xa0100000 0x0 0xa0100000 0x0 0x2ff00000>; /* non-prefetchable memory */
+                       siflower,ctlr-idx = <0>;
+                       num-viewport = <8>;
+                       interrupts = <124 IRQ_TYPE_LEVEL_HIGH>,
+                                       <160 IRQ_TYPE_LEVEL_HIGH>, <161 IRQ_TYPE_LEVEL_HIGH>, <162 IRQ_TYPE_LEVEL_HIGH>, <163 IRQ_TYPE_LEVEL_HIGH>, <164 IRQ_TYPE_LEVEL_HIGH>, <165 IRQ_TYPE_LEVEL_HIGH>, <166 IRQ_TYPE_LEVEL_HIGH>, <167 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "intr", "msi0", "msi1", "msi2", "msi3", "msi4", "msi5", "msi6", "msi7";
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0 0 0 1 &plic 151 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 2 &plic 150 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 3 &plic 149 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 4 &plic 148 IRQ_TYPE_EDGE_RISING>;
+                       siflower,pcie-sysm = <&pcie_phy>;
+                       phys = <&pcie_phy0>;
+                       linux,pci-domain = <0>;
+               };
+
+               pcie1: pcie@04200000 {
+                       compatible = "siflower,sf21-pcie";
+                       status = "disabled";
+                       reg = <0x0 0x04000000 0x0 0x200000>,
+                             <0x0 0x04200000 0x0 0x100000>,
+                             <0x0 0x04300000 0x0 0x080000>,
+                             <0x0 0x04380000 0x0 0x080000>,
+                             <0x0 0xd0000000 0x0 0x080000>;
+                       reg-names = "dbi", "elbi", "atu", "dma", "config";
+                       clocks = <&topcrm CLK_SERDES_CSR>,
+                                <&topcrm CLK_PCIE_REFP>,
+                                <&topcrm CLK_PCIEPLL_FOUT3>;
+                       clock-names = "csr", "ref", "phy";
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       bus-range = <0x0 0xff>;
+                       ranges = <0x81000000 0x0 0xd0080000 0x0 0xd0080000 0x0 0x00080000 /* downstream I/O 256KB */
+                                 0x82000000 0x0 0xd0100000 0x0 0xd0100000 0x0 0x2ff00000>; /* non-prefetchable memory */
+                       siflower,ctlr-idx = <1>;
+                       num-viewport = <8>;
+                       interrupts = <125 IRQ_TYPE_LEVEL_HIGH>,
+                                       <168 IRQ_TYPE_LEVEL_HIGH>, <169 IRQ_TYPE_LEVEL_HIGH>, <170 IRQ_TYPE_LEVEL_HIGH>, <171 IRQ_TYPE_LEVEL_HIGH>, <172 IRQ_TYPE_LEVEL_HIGH>, <173 IRQ_TYPE_LEVEL_HIGH>, <174 IRQ_TYPE_LEVEL_HIGH>, <175 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "intr", "msi0", "msi1", "msi2", "msi3", "msi4", "msi5", "msi6", "msi7";
+                       #interrupt-cells = <1>;
+                       interrupt-map-mask = <0 0 0 7>;
+                       interrupt-map = <0 0 0 1 &plic 159 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 2 &plic 158 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 3 &plic 157 IRQ_TYPE_EDGE_RISING>,
+                                       <0 0 0 4 &plic 156 IRQ_TYPE_EDGE_RISING>;
+                       siflower,pcie-sysm = <&pcie_phy>;
+                       phys = <&pcie_phy1>;
+                       linux,pci-domain = <1>;
+               };
+
+               topcrm: clock-controller@0ce00400 {
+                       compatible = "siflower,sf21-topcrm", "syscon";
+                       reg = <0x0 0x0ce00400 0x0 0x400>;
+                       clocks = <&xin25m>;
+                       clock-names = "xin25m";
+                       #clock-cells = <1>;
+               };
+
+               i2crst: reset-controller@0ce08400 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce08400 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,num-resets = <2>;
+               };
+
+               i2cclk: clock-controller@0ce08404 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce08404 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>, <&topcrm CLK_APB>;
+                       clock-output-names = "i2c0", "i2c1";
+                       #clock-cells = <1>;
+               };
+
+               spirst: reset-controller@0ce08800 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce08800 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,reset-masks = <0x3 0xc>;
+               };
+
+               spiclk: clock-controller@0ce08804 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce08804 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>, <&topcrm CLK_APB>, <&topcrm CLK_APB>,
+                                <&topcrm CLK_APB>;
+                       clock-output-names = "spi0_apb", "spi0_ssp", "spi1_apb",
+                                            "spi1_ssp";
+                       #clock-cells = <1>;
+               };
+
+               uartrst: reset-controller@0ce08c00 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce08c00 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,reset-masks = <0x11 0x22>;
+               };
+
+               uartclk: clock-controller@0ce08c04 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce08c04 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>, <&topcrm CLK_APB>,
+                                <&topcrm CLK_UART>, <&topcrm CLK_UART>;
+                       clock-output-names = "uart0_apb", "uart1_apb",
+                                            "uart0", "uart1";
+                       siflower,valid-gates = <0x33>;
+                       siflower,critical-gates = <0x22>;
+                       #clock-cells = <1>;
+               };
+
+               timerst: reset-controller@0ce09800 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce09800 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,reset-masks = <0x1>;
+               };
+
+               timerclk: clock-controller@0ce09804 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce09804 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>;
+                       clock-output-names = "timer";
+                       #clock-cells = <1>;
+               };
+
+               wdtrst: reset-controller@0ce09c00 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce09c00 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,reset-masks = <0x1>;
+               };
+
+               wdtclk: clock-controller@0ce09c04 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce09c04 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>;
+                       clock-output-names = "wdt";
+                       #clock-cells = <1>;
+               };
+
+               gpiorst: reset-controller@0ce0a000 {
+                       compatible = "siflower,sf19a2890-periph-reset";
+                       reg = <0x0 0x0ce0a000 0x0 0x4>;
+                       #reset-cells = <1>;
+                       siflower,reset-masks = <0x1>;
+               };
+
+               gpioclk: clock-controller@0ce0a004 {
+                       compatible = "siflower,sf19a2890-periph-clk";
+                       reg = <0x0 0x0ce0a004 0x0 0x4>;
+                       clocks = <&topcrm CLK_APB>;
+                       clock-output-names = "gpio";
+                       #clock-cells = <1>;
+               };
+
+               uart0: uart@c300000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x0 0xc300000 0x0 0x1000>;
+                       clocks = <&uartclk 2>, <&uartclk 0>;
+                       clock-names = "uartclk", "apb_pclk";
+                       resets = <&uartrst 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins>;
+                       interrupts = <43 IRQ_TYPE_LEVEL_HIGH>;
+                       current-speed = <115200>;
+                       status = "disabled";
+               };
+
+               uart1: uart@c301000 {
+                       compatible = "arm,pl011", "arm,primecell";
+                       reg = <0x0 0xc301000 0x0 0x1000>;
+                       clocks = <&uartclk 3>, <&uartclk 1>;
+                       clock-names = "uartclk", "apb_pclk";
+                       resets = <&uartrst 1>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart1_pins>;
+                       interrupts = <44 IRQ_TYPE_LEVEL_HIGH>;
+                       current-speed = <115200>;
+                       status = "disabled";
+               };
+
+               spi0: spi@c200000 {
+                       compatible = "siflower,sf21-qspi";
+                       reg = <0x0 0xc200000 0x0 0x1000>;
+                       clocks = <&spiclk 0>, <&spiclk 1>;
+                       clock-names = "apb_pclk", "sspclk";
+                       resets = <&spirst 0>;
+                       interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi0_pins>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               spi1: spi@c201000 {
+                       compatible = "siflower,sf21-qspi";
+                       reg = <0x0 0xc201000 0x0 0x1000>;
+                       clocks = <&spiclk 2>, <&spiclk 3>;
+                       clock-names = "apb_pclk", "sspclk";
+                       resets = <&spirst 1>;
+                       interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&spi1_pins>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               watchdog: watchdog@0c700000 {
+                       compatible = "snps,dw-wdt";
+                       reg = <0x0 0x0c700000 0x0 0x1000>;
+                       interrupts = <51 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&wdtclk 0>;
+                       resets = <&wdtrst 0>;
+               };
+
+               usb_phy: phy@0ce02400 {
+                       compatible = "siflower,sf21-usb-phy";
+                       reg = <0x0 0x0ce02400 0x0 0x14>;
+                       clocks = <&topcrm CLK_USBPHY>;
+                       clock-names = "usb_phy_clk";
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+
+               pcie_phy: phy@0d810000 {
+                       compatible = "siflower,sf21-pcie-phy", "syscon";
+                       reg = <0x0 0x0d810000 0x0 0x100>;
+                       clocks = <&topcrm CLK_PCIE_REFP>, <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "ref", "csr";
+                       siflower,topcrm = <&topcrm>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+
+                       pcie_phy0: phy@0 {
+                               reg = <0>;
+                               siflower,num-lanes = <1>;
+                               #phy-cells = <0>;
+                       };
+
+                       pcie_phy1: phy@1 {
+                               reg = <1>;
+                               siflower,num-lanes = <1>;
+                               #phy-cells = <0>;
+                       };
+               };
+
+               usb: usb@10000000 {
+                       compatible = "siflower,sf19a2890-usb";
+                       reg = <0x0 0x10000000 0x0 0x80000>;
+                       interrupts = <33 IRQ_TYPE_LEVEL_HIGH>;
+                       clocks = <&topcrm CLK_USB>;
+                       clock-names = "otg";
+                       resets = <&reset SF21_RESET_USB>;
+                       reset-names = "dwc2";
+                       dr_mode = "host";
+                       phys = <&usb_phy>;
+                       phy-names = "usb2-phy";
+                       g-rx-fifo-size = <512>;
+                       g-np-tx-fifo-size = <128>;
+                       g-tx-fifo-size = <128 128 128 128 128 128 128 128
+                               16  16  16  16  16  16  16>;
+                       status = "disabled";
+               };
+
+               iram: sram@1c000000 {
+                       compatible = "mmio-sram";
+                       reg = <0x0 0x1c000000 0x0 0x10000>;
+                       clocks = <&topcrm CLK_IRAM>;
+                       ranges;
+               };
+
+               xgmac0: ethernet@8000000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x8000000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "csr";
+                       pcs-handle = <&qsgmii_pcs 0>;
+                       phy-mode = "qsgmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac0_mdio_pins>;
+                       interrupts = <176 IRQ_TYPE_LEVEL_HIGH>, <20 IRQ_TYPE_LEVEL_HIGH>, <26 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+
+                       mdio0: mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
+               xgmac1: ethernet@8004000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x8004000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "csr";
+                       pcs-handle = <&qsgmii_pcs 1>;
+                       phy-mode = "qsgmii";
+                       interrupts = <1 IRQ_TYPE_LEVEL_HIGH>, <21 IRQ_TYPE_LEVEL_HIGH>, <27 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+               };
+
+               xgmac2: ethernet@8008000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x8008000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "csr";
+                       pcs-handle = <&qsgmii_pcs 2>;
+                       phy-mode = "qsgmii";
+                       interrupts = <2 IRQ_TYPE_LEVEL_HIGH>, <22 IRQ_TYPE_LEVEL_HIGH>, <28 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+               };
+
+               xgmac3: ethernet@800c000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x800c000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "csr";
+                       pcs-handle = <&qsgmii_pcs 3>;
+                       phy-mode = "qsgmii";
+                       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>, <23 IRQ_TYPE_LEVEL_HIGH>, <29 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+               };
+
+               xgmac4: ethernet@8010000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x8010000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "csr";
+                       pcs-handle = <&sgmii_pcs 0>;
+                       phy-mode = "2500base-x";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&mac4_mdio_pins>;
+                       interrupts = <4 IRQ_TYPE_LEVEL_HIGH>, <24 IRQ_TYPE_LEVEL_HIGH>, <30 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+
+                       mdio1: mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+               };
+
+               edma: dma-controller@8018000 {
+                       compatible = "siflower,sf21-xgmac-dma";
+                       reg = <0x0 0x8018000 0x0 0x4000>;
+                       #dma-cells = <0>;
+                       ethsys = <&ethsys>;
+                       iram = <&iram>;
+                       clocks = <&topcrm CLK_AXI>, <&topcrm CLK_NPU>, <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "axi", "npu", "csr";
+                       interrupts = <6 IRQ_TYPE_LEVEL_HIGH>, <9 IRQ_TYPE_LEVEL_HIGH>, <10 IRQ_TYPE_LEVEL_HIGH>, <11 IRQ_TYPE_LEVEL_HIGH>, <12 IRQ_TYPE_LEVEL_HIGH>, <13 IRQ_TYPE_LEVEL_HIGH>, <14 IRQ_TYPE_LEVEL_HIGH>, <15 IRQ_TYPE_LEVEL_HIGH>, <16 IRQ_TYPE_LEVEL_HIGH>, <17 IRQ_TYPE_LEVEL_HIGH>, <18 IRQ_TYPE_LEVEL_HIGH>, <19 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "tx0", "tx1", "tx2", "tx3", "tx4",
+                                         "rx0", "rx1", "rx2", "rx3", "rx4", "rxovf";
+                       status = "disabled";
+               };
+
+               qsgmii_pcs: xpcs@8800000 {
+                       compatible = "siflower,sf21-xpcs";
+                       reg = <0x0 0x8800000 0x0 0x800000>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_ETH_REF_P>, <&topcrm CLK_ETHTSU>, <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "ref", "eee", "csr";
+                       interrupts = <7 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
+               sgmii_pcs: xpcs@9000000 {
+                       compatible = "siflower,sf21-xpcs";
+                       reg = <0x0 0x9000000 0x0 0x800000>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_ETH_REF_P>, <&topcrm CLK_ETHTSU>, <&topcrm CLK_SERDES_CSR>;
+                       clock-names = "ref", "eee", "csr";
+                       interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+                       status = "disabled";
+               };
+
+               gpio: gpio@c800000 {
+                       compatible = "siflower,sf19a2890-gpio";
+                       reg = <0x0 0xc800000 0x0 0x100000>;
+
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       interrupts = <54 IRQ_TYPE_LEVEL_HIGH>, <55 IRQ_TYPE_LEVEL_HIGH>, <56 IRQ_TYPE_LEVEL_HIGH>, <57 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+                       clocks = <&gpioclk 0>;
+                       resets = <&gpiorst 0>;
+
+                       ngpios = <41>;
+                       gpio-ranges = <&iomux 0 0 41>;
+               };
+
+               i2c0: i2c@c100000 {
+                       compatible = "snps,designware-i2c";
+                       reg = <0x0 0xc100000 0x0 0x1000>;
+                       clocks = <&i2cclk 0>;
+                       clock-names = "ref";
+                       clock-frequency = <400000>;
+                       interrupts = <35 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names="default";
+                       pinctrl-0 = <&i2c0_pins>;
+                       resets = <&i2crst 0>;
+                       status = "disabled";
+               };
+
+               i2c1: i2c@c101000 {
+                       compatible = "snps,designware-i2c";
+                       reg = <0x0 0xc101000 0x0 0x1000>;
+                       clocks = <&i2cclk 1>;
+                       clock-frequency = <400000>;
+                       interrupts = <36 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&i2c1_pins>;
+                       status = "disabled";
+               };
+
+               ethsys: syscon@ce01800 {
+                       compatible = "siflower,ethsys", "syscon";
+                       reg = <0x0 0xce01800 0x0 0x800>;
+               };
+
+               dpns: dpns@11000000 {
+                       compatible = "siflower,sf21-dpns";
+                       reg = <0x0 0x11000000 0x0 0x1000000>;
+                       #address-cells = <1>;
+                       dma-ranges = <0 0x0 0 0x20000000 0 0x80000000>;
+                       interrupts = <65 IRQ_TYPE_EDGE_RISING>, <66 IRQ_TYPE_EDGE_RISING>, <67 IRQ_TYPE_EDGE_RISING>, <68 IRQ_TYPE_EDGE_RISING>, <69 IRQ_TYPE_EDGE_RISING>, <70 IRQ_TYPE_EDGE_RISING>, <71 IRQ_TYPE_EDGE_RISING>, <72 IRQ_TYPE_EDGE_RISING>,
+                                    <73 IRQ_TYPE_EDGE_RISING>, <74 IRQ_TYPE_EDGE_RISING>, <75 IRQ_TYPE_EDGE_RISING>, <76 IRQ_TYPE_EDGE_RISING>, <77 IRQ_TYPE_EDGE_RISING>, <78 IRQ_TYPE_EDGE_RISING>, <79 IRQ_TYPE_EDGE_RISING>, <80 IRQ_TYPE_EDGE_RISING>,
+                                    <81 IRQ_TYPE_EDGE_RISING>, <82 IRQ_TYPE_EDGE_RISING>, <83 IRQ_TYPE_EDGE_RISING>, <84 IRQ_TYPE_EDGE_RISING>, <85 IRQ_TYPE_LEVEL_HIGH>, <86 IRQ_TYPE_LEVEL_HIGH>, <87 IRQ_TYPE_EDGE_RISING>, <88 IRQ_TYPE_EDGE_RISING>,
+                                    <89 IRQ_TYPE_EDGE_RISING>, <90 IRQ_TYPE_EDGE_RISING>, <91 IRQ_TYPE_EDGE_RISING>, <92 IRQ_TYPE_EDGE_RISING>, <93 IRQ_TYPE_EDGE_RISING>, <94 IRQ_TYPE_EDGE_RISING>, <95 IRQ_TYPE_EDGE_RISING>, <96 IRQ_TYPE_EDGE_RISING>,
+                                    <97 IRQ_TYPE_EDGE_RISING>, <98 IRQ_TYPE_EDGE_RISING>, <99 IRQ_TYPE_EDGE_RISING>, <100 IRQ_TYPE_EDGE_RISING>, <101 IRQ_TYPE_EDGE_RISING>, <102 IRQ_TYPE_EDGE_RISING>, <103 IRQ_TYPE_EDGE_RISING>, <104 IRQ_TYPE_EDGE_RISING>,
+                                    <105 IRQ_TYPE_EDGE_RISING>, <106 IRQ_TYPE_EDGE_RISING>, <107 IRQ_TYPE_EDGE_RISING>, <108 IRQ_TYPE_EDGE_RISING>, <109 IRQ_TYPE_EDGE_RISING>, <110 IRQ_TYPE_EDGE_RISING>, <111 IRQ_TYPE_EDGE_RISING>, <112 IRQ_TYPE_EDGE_RISING>,
+                                    <113 IRQ_TYPE_EDGE_RISING>, <114 IRQ_TYPE_EDGE_RISING>, <115 IRQ_TYPE_EDGE_RISING>, <116 IRQ_TYPE_EDGE_RISING>, <117 IRQ_TYPE_EDGE_RISING>, <118 IRQ_TYPE_EDGE_RISING>, <119 IRQ_TYPE_EDGE_RISING>, <120 IRQ_TYPE_EDGE_RISING>,
+                                    <121 IRQ_TYPE_EDGE_RISING>, <122 IRQ_TYPE_EDGE_RISING>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_NPU>;
+                       resets = <&reset SF21_RESET_NPU>, <&reset SF21_RESET_NPU2DDR_ASYNCBRIDGE>;
+                       reset-names = "npu", "npu2ddr";
+                       siflower,edma = <&edma>;
+                       status = "disabled";
+               };
+
+               syscon@ce00000 {
+                       compatible = "siflower,brom-sysm";
+                       reg = <0x0 0xce00000 0x0 0x400>;
+                       #reset-cells = <1>;
+               };
+
+               syscon@ce00c00 {
+                       compatible = "siflower,cpu-sysm";
+                       reg = <0x0 0xce00c00 0x0 0x400>;
+               };
+
+               iomux: iomux@ce3c000 {
+                       compatible = "pinconf-single";
+                       reg = <0x0 0xce3c000 0x0 0xa4>;
+                       #pinctrl-cells = <1>;
+
+                       pinctrl-single,register-width = <32>;
+                       pinctrl-single,function-mask = <FUNC_MODE_MASK>;
+                       pinctrl-single,function-off = <0>;
+                       pinctrl-single,gpio-range = <&range 0 41 GPIO_MODE>;
+
+                       range: gpio-range {
+                               #pinctrl-single,gpio-range-cells = <3>;
+                       };
+
+                       clk_pins: clk_pins {
+                               pinctrl-single,pins = <
+                                       EXT_CLK_IN      FUNC_MODE0
+                                       CLK_OUT         FUNC_MODE0
+                               >;
+                       };
+
+                       spi0_pins: spi0_pins {
+                               pinctrl-single,pins = <
+                                       SPI0_TXD        FUNC_MODE0
+                                       SPI0_RXD        FUNC_MODE0
+                                       SPI0_CLK        FUNC_MODE0
+                                       SPI0_CSN        FUNC_MODE0
+                                       SPI0_HOLD       FUNC_MODE0
+                                       SPI0_WP         FUNC_MODE0
+                               >;
+                       };
+
+                       jtag_pins: jtag_pins {
+                               pinctrl-single,pins = <
+                                       JTAG_TDO        FUNC_MODE0
+                                       JTAG_TDI        FUNC_MODE0
+                                       JTAG_TMS        FUNC_MODE0
+                                       JTAG_TCK        FUNC_MODE0
+                                       JTAG_RST        FUNC_MODE0
+                               >;
+                       };
+
+                       uart0_pins: uart0_pins {
+                               pinctrl-single,pins = <
+                                       JTAG_TDO        FUNC_MODE1
+                                       JTAG_TDI        FUNC_MODE1
+                                       JTAG_TMS        FUNC_MODE1
+                                       JTAG_TCK        FUNC_MODE1
+                               >;
+                       };
+
+                       uart1_pins: uart1_pins {
+                               pinctrl-single,pins = <
+                                       UART1_TX        FUNC_MODE0
+                                       UART1_RX        FUNC_MODE0
+                               >;
+                       };
+
+                       uart1_full_pins: uart1_full_pins {
+                               pinctrl-single,pins = <
+                                       UART1_TX        FUNC_MODE0
+                                       UART1_RX        FUNC_MODE0
+                                       I2C0_DAT        FUNC_MODE1
+                                       I2C0_CLK        FUNC_MODE1
+                               >;
+                       };
+
+                       i2c0_pins: i2c0_pins {
+                               pinctrl-single,pins = <
+                                       I2C0_DAT        FUNC_MODE0
+                                       I2C0_CLK        FUNC_MODE0
+                               >;
+                       };
+
+                       perst_pins: perst_pins {
+                               pinctrl-single,pins = <
+                                       I2C0_DAT        FUNC_MODE2
+                                       I2C0_CLK        FUNC_MODE2
+                               >;
+                       };
+
+                       i2c1_pins: i2c1_pins {
+                               pinctrl-single,pins = <
+                                       I2C1_DAT        FUNC_MODE0
+                                       I2C1_CLK        FUNC_MODE0
+                               >;
+                       };
+
+                       rgmii_pins: rgmii_pins {
+                               pinctrl-single,pins = <
+                                       RGMII_GTX_CLK   FUNC_MODE0
+                                       RGMII_TXD0      FUNC_MODE0
+                                       RGMII_TXD1      FUNC_MODE0
+                                       RGMII_TXD2      FUNC_MODE0
+                                       RGMII_TXD3      FUNC_MODE0
+                                       RGMII_TXCTL     FUNC_MODE0
+                                       RGMII_RXCLK     FUNC_MODE0
+                                       RGMII_RXD0      FUNC_MODE0
+                                       RGMII_RXD1      FUNC_MODE0
+                                       RGMII_RXD2      FUNC_MODE0
+                                       RGMII_RXD3      FUNC_MODE0
+                                       RGMII_RXCTL     FUNC_MODE0
+                               >;
+                       };
+
+                       spi1_pins: spi1_pins {
+                               pinctrl-single,pins = <
+                                       RGMII_GTX_CLK   FUNC_MODE1
+                                       RGMII_TXCLK     FUNC_MODE1
+                                       RGMII_TXD0      FUNC_MODE1
+                                       RGMII_TXD1      FUNC_MODE1
+                                       RGMII_TXD2      FUNC_MODE1
+                                       RGMII_TXD3      FUNC_MODE1
+                               >;
+                       };
+
+                       mac0_mdio_pins: mac0_mdio_pins {
+                               pinctrl-single,pins = <
+                                       QSGMII_MDIO     FUNC_MODE0
+                                       QSGMII_MDC      FUNC_MODE0
+                               >;
+                       };
+
+                       mac4_mdio_pins: mac4_mdio_pins {
+                               pinctrl-single,pins = <
+                                       SXGMII_MDIO     FUNC_MODE0
+                                       SXGMII_MDC      FUNC_MODE0
+                               >;
+                       };
+               };
+
+               plic: interrupt-controller@108000000 {
+                       compatible = "thead,c900-plic";
+                       reg = <0x1 0x8000000 0x0 0x400000>, <0x0 0x0ce00c34 0x0 0x20>;
+                       interrupt-controller;
+                       interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>,
+                                             <&cpu1_intc 11>, <&cpu1_intc 9>,
+                                             <&cpu2_intc 11>, <&cpu2_intc 9>,
+                                             <&cpu3_intc 11>, <&cpu3_intc 9>;
+                       #interrupt-cells = <2>;
+                       riscv,ndev = <176>;
+               };
+
+               interrupt-controller@10c000000 {
+                       compatible = "thead,c900-aclint-mswi";
+                       reg = <0x1 0xc000000 0x0 0x4000>;
+                       interrupts-extended = <&cpu0_intc 3>, <&cpu1_intc 3>,
+                                             <&cpu2_intc 3>, <&cpu3_intc 3>;
+               };
+
+               timer@10c004000 {
+                       compatible = "thead,c900-aclint-mtimer";
+                       reg = <0x1 0xc00bff8 0x0 0x8>, <0x1 0xc004000 0x0 0x7ff8>;
+                       interrupts-extended = <&cpu0_intc 7>, <&cpu1_intc 7>,
+                                             <&cpu2_intc 7>, <&cpu3_intc 7>;
+               };
+
+               interrupt-controller@10c00c000 {
+                       compatible = "thead,c900-aclint-sswi";
+                       reg = <0x1 0xc00c000 0x0 0x1000>;
+                       interrupts-extended = <&cpu0_intc 1>, <&cpu1_intc 1>,
+                                             <&cpu2_intc 1>, <&cpu3_intc 1>;
+               };
+       };
+};
diff --git a/target/linux/siflower/dts/sf21a6826.dtsi b/target/linux/siflower/dts/sf21a6826.dtsi
new file mode 100644 (file)
index 0000000..bddf506
--- /dev/null
@@ -0,0 +1,23 @@
+#include "sf21.dtsi"
+/ {
+       compatible = "siflower,sf21a6826";
+};
+
+&cpus {
+       timebase-frequency = <1125000000>;
+};
+
+&topcrm {
+       assigned-clocks = <&topcrm CLK_CMNPLL_VCO>, <&topcrm CLK_PIC>, <&topcrm CLK_AXI>,
+               <&topcrm CLK_AHB>, <&topcrm CLK_APB>, <&topcrm CLK_UART>,
+               <&topcrm CLK_IRAM>, <&topcrm CLK_NPU>, <&topcrm CLK_ETHTSU>,
+               <&topcrm CLK_GMAC_BYP_REF>, <&topcrm CLK_USB>, <&topcrm CLK_USBPHY>,
+               <&topcrm CLK_SERDES_CSR>, <&topcrm CLK_CRYPT_CSR>, <&topcrm CLK_CRYPT_APP>,
+               <&topcrm CLK_IROM>;
+       assigned-clock-rates = <2250000000>, <562500000>, <375000000>,
+               <281250000>, <187500000>, <93750000>,
+               <562500000>, <562500000>, <93750000>,
+               <250000000>, <250000000>, <50000000>,
+               <93750000>, <75000000>, <375000000>,
+               <375000000>;
+};
diff --git a/target/linux/siflower/dts/sf21h8898.dtsi b/target/linux/siflower/dts/sf21h8898.dtsi
new file mode 100644 (file)
index 0000000..4e916f6
--- /dev/null
@@ -0,0 +1,39 @@
+#include "sf21.dtsi"
+/ {
+       compatible = "siflower,sf21h8898";
+       soc {
+               xgmac5: ethernet@8014000 {
+                       compatible = "siflower,sf21-xgmac";
+                       reg = <0x0 0x8014000 0x0 0x4000>;
+                       dmas = <&edma>;
+                       ethsys = <&ethsys>;
+                       clocks = <&topcrm CLK_SERDES_CSR>, <&topcrm CLK_GMAC_BYP_REF>;
+                       clock-names = "csr", "rgmii";
+                       phy-mode = "rgmii";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&rgmii_pins>;
+                       interrupts = <5 IRQ_TYPE_LEVEL_HIGH>, <25 IRQ_TYPE_LEVEL_HIGH>, <31 IRQ_TYPE_LEVEL_HIGH>;
+                       interrupt-names = "sbd", "lpi", "pmt";
+                       status = "disabled";
+               };
+       };
+};
+
+&cpus {
+       timebase-frequency = <1250000000>;
+};
+
+&topcrm {
+       assigned-clocks = <&topcrm CLK_CMNPLL_VCO>, <&topcrm CLK_PIC>, <&topcrm CLK_AXI>,
+               <&topcrm CLK_AHB>, <&topcrm CLK_APB>, <&topcrm CLK_UART>,
+               <&topcrm CLK_IRAM>, <&topcrm CLK_NPU>, <&topcrm CLK_ETHTSU>,
+               <&topcrm CLK_GMAC_BYP_REF>, <&topcrm CLK_USB>, <&topcrm CLK_USBPHY>,
+               <&topcrm CLK_SERDES_CSR>, <&topcrm CLK_CRYPT_CSR>, <&topcrm CLK_CRYPT_APP>,
+               <&topcrm CLK_IROM>;
+       assigned-clock-rates = <2500000000>, <416666666>, <416666666>,
+               <250000000>, <178571428>, <89285714>,
+               <416666666>, <416666666>, <89285714>,
+               <250000000>, <250000000>, <50000000>,
+               <89285714>, <73529411>, <312500000>,
+               <312500000>;
+};
index 8e1c5a8f269dfb7e3af4d3ba01bf2e503eddfa42..a8bd6b18b72dbd6851e2e6fc1941a1243976e781 100644 (file)
@@ -2,7 +2,7 @@
 
 menuconfig CLK_SIFLOWER
        bool "Siflower SoC driver support"
-       depends on MIPS || COMPILE_TEST
+       depends on MIPS || RISCV || COMPILE_TEST
        help
          SoC drivers for Siflower Linux-capable SoCs.
 
@@ -18,10 +18,18 @@ config CLK_SF19A2890
 
 config CLK_SF19A2890_PERIPH
        bool "Clock driver for Siflower SF19A2890 peripheral clock gates"
-       depends on MIPS || COMPILE_TEST
+       depends on MIPS || RISCV || COMPILE_TEST
        help
          Supports the clock gates for various peripherals in SF19A2890.
          If this kernel is meant to run on a Siflower SF19A2890 SoC,
          enable this driver.
 
+config CLK_SF21_TOPCRM
+       bool "Clock driver for Siflower SF21A6826/SF21H8898 Top Clock & Reset Module"
+       depends on RISCV || COMPILE_TEST
+       help
+         Supports the Top Clock & Reset Module IP block found in SF21A6826.
+         If this kernel is meant to run on a Siflower SF21A6826 SoC,
+         enable this driver.
+
 endif
index d03a72ee25642e75c8150e0c301f9484d4584348..c6e2ca64fa1973b583110cabfab69d00829437bc 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_CLK_SF19A2890) += clk-sf19a2890.o
 obj-$(CONFIG_CLK_SF19A2890_PERIPH) += clk-sf19a2890-periph.o
+obj-$(CONFIG_CLK_SF21_TOPCRM) += clk-sf21-topcrm.o
index 626fbe7b8e24aeca3a6bae1194762081bcadfc96..a8644156aadea381d11013f9916d5682ae111547 100644 (file)
@@ -1,3 +1,5 @@
+// SPDX-License-Identifier: GPL-2.0
+
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
diff --git a/target/linux/siflower/files-6.6/drivers/clk/siflower/clk-sf21-topcrm.c b/target/linux/siflower/files-6.6/drivers/clk/siflower/clk-sf21-topcrm.c
new file mode 100644 (file)
index 0000000..73ed9e9
--- /dev/null
@@ -0,0 +1,808 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/compiler.h>
+#include <linux/clk-provider.h>
+#include <linux/bitfield.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/rational.h>
+#include <linux/spinlock.h>
+#include <linux/bug.h>
+#include <dt-bindings/clock/siflower,sf21-topcrm.h>
+
+struct sf_clk_common {
+       void __iomem    *base;
+       spinlock_t      *lock;
+       struct clk_hw   hw;
+};
+
+#define SF_CLK_COMMON(_name, _parents, _op, _flags)                    \
+       {                                                               \
+               .hw.init = CLK_HW_INIT_PARENTS(_name, _parents,         \
+                                                   _op, _flags),       \
+       }
+
+static inline struct sf_clk_common *hw_to_sf_clk_common(struct clk_hw *hw)
+{
+       return container_of(hw, struct sf_clk_common, hw);
+}
+
+static inline u32 sf_readl(struct sf_clk_common *priv, u32 reg)
+{
+       return readl(priv->base + reg);
+}
+
+static inline void sf_writel(struct sf_clk_common *priv, u32 reg, u32 val)
+{
+       return writel(val, priv->base + reg);
+}
+
+static inline void sf_rmw(struct sf_clk_common *priv, u32 reg, u32 clr, u32 set)
+{
+       u32 val;
+
+       val = sf_readl(priv, reg);
+       val &= ~clr;
+       val |= set;
+       sf_writel(priv, reg, val);
+}
+
+#define PLL_CMN_CFG1           0x0
+#define  PLL_CMN_BYPASS                BIT(27)
+#define  PLL_CMN_PD            BIT(26)
+#define  PLL_CMN_FBDIV         GENMASK(25, 14)
+#define  PLL_CMN_FBDIV_BITS    (25 - 14 + 1)
+#define  PLL_CMN_POSTDIV_PD    BIT(13)
+#define  PLL_CMN_VCO_PD                BIT(12)
+#define  PLL_CMN_POSTDIV1      GENMASK(11, 9)
+#define  PLL_CMN_POSTDIV2      GENMASK(8, 6)
+#define  PLL_CMN_REFDIV                GENMASK(5, 0)
+#define  PLL_CMN_REFDIV_BITS   6
+
+#define PLL_CMN_LOCK           0xc8
+#define PLL_DDR_LOCK           0xcc
+#define PLL_PCIE_LOCK          0xd4
+
+#define CFG_LOAD               0x100
+#define  CFG_LOAD_PCIE_PLL     BIT(4)
+#define  CFG_LOAD_DDR_PLL      BIT(2)
+#define  CFG_LOAD_CMN_PLL      BIT(1)
+#define  CFG_LOAD_DIV          BIT(0)
+
+static unsigned long sf21_cmnpll_vco_recalc_rate(struct clk_hw *hw,
+                                                     unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       u32 cfg = sf_readl(priv, PLL_CMN_CFG1);
+       unsigned long refdiv = FIELD_GET(PLL_CMN_REFDIV, cfg);
+       unsigned long fbdiv = FIELD_GET(PLL_CMN_FBDIV, cfg);
+
+       return (parent_rate / refdiv) * fbdiv;
+}
+
+static long sf21_cmnpll_vco_round_rate(struct clk_hw *hw,
+                                           unsigned long rate,
+                                           unsigned long *parent_rate)
+{
+       unsigned long fbdiv, refdiv;
+
+       rational_best_approximation(rate, *parent_rate,
+                                   BIT(PLL_CMN_FBDIV_BITS) - 1,
+                                   BIT(PLL_CMN_REFDIV_BITS) - 1, &fbdiv,
+                                   &refdiv);
+       return (*parent_rate / refdiv) * fbdiv;
+}
+
+static int sf21_cmnpll_vco_set_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       unsigned long flags;
+       unsigned long fbdiv, refdiv;
+
+       rational_best_approximation(rate, parent_rate,
+                                   BIT(PLL_CMN_FBDIV_BITS) - 1,
+                                   BIT(PLL_CMN_REFDIV_BITS) - 1, &fbdiv,
+                                   &refdiv);
+
+       spin_lock_irqsave(priv->lock, flags);
+
+       sf_rmw(priv, PLL_CMN_CFG1, 0, PLL_CMN_BYPASS);
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_CMN_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+
+       sf_rmw(priv, PLL_CMN_CFG1, PLL_CMN_REFDIV | PLL_CMN_FBDIV | PLL_CMN_PD,
+              FIELD_PREP(PLL_CMN_REFDIV, refdiv) |
+                      FIELD_PREP(PLL_CMN_FBDIV, fbdiv));
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_CMN_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+
+       while (!(sf_readl(priv, PLL_CMN_LOCK) & 1))
+               cpu_relax();
+
+       sf_rmw(priv, PLL_CMN_CFG1, PLL_CMN_BYPASS, 0);
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_CMN_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+
+       spin_unlock_irqrestore(priv->lock, flags);
+       return 0;
+}
+
+static const struct clk_ops sf21_cmnpll_vco_ops = {
+       .recalc_rate = sf21_cmnpll_vco_recalc_rate,
+       .round_rate = sf21_cmnpll_vco_round_rate,
+       .set_rate = sf21_cmnpll_vco_set_rate,
+};
+
+static const char *const clk_pll_parents[] = { "xin25m" };
+
+static struct sf_clk_common cmnpll_vco = SF_CLK_COMMON(
+       "cmnpll_vco", clk_pll_parents, &sf21_cmnpll_vco_ops, 0);
+
+static unsigned long sf21_dualdiv_round_rate(
+       unsigned long rate, unsigned long parent_rate,
+       unsigned int range, unsigned int *diva, unsigned int *divb)
+{
+       unsigned int div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       unsigned int best_diff, da, db, cur_div, cur_diff;
+
+       if (div <= 1) {
+               *diva = 1;
+               *divb = 1;
+               return parent_rate;
+       }
+
+       best_diff = div - 1;
+       *diva = 1;
+       *divb = 1;
+
+       for (da = 1; da <= range; da++) {
+               db = DIV_ROUND_CLOSEST(div, da);
+               if (db > da)
+                       db = da;
+
+               cur_div = da * db;
+               if (div > cur_div)
+                       cur_diff = div - cur_div;
+               else
+                       cur_diff = cur_div - div;
+
+               if (cur_diff < best_diff) {
+                       best_diff = cur_diff;
+                       *diva = da;
+                       *divb = db;
+               }
+               if (cur_diff == 0)
+                       break;
+       }
+
+       return parent_rate / *diva / *divb;
+}
+
+static long sf21_cmnpll_postdiv_round_rate(struct clk_hw *hw,
+                                               unsigned long rate,
+                                               unsigned long *parent_rate)
+{
+       unsigned int diva, divb;
+
+       return sf21_dualdiv_round_rate(rate, *parent_rate, 7, &diva,
+                                           &divb);
+}
+
+static int sf21_cmnpll_postdiv_set_rate(struct clk_hw *hw,
+                                            unsigned long rate,
+                                            unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       unsigned int diva, divb;
+       unsigned long flags;
+
+       sf21_dualdiv_round_rate(rate, parent_rate, 7, &diva, &divb);
+
+       spin_lock_irqsave(priv->lock, flags);
+       sf_rmw(priv, PLL_CMN_CFG1, PLL_CMN_POSTDIV1 | PLL_CMN_POSTDIV2,
+              FIELD_PREP(PLL_CMN_POSTDIV1, diva) |
+                      FIELD_PREP(PLL_CMN_POSTDIV2, divb));
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_CMN_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(priv->lock, flags);
+       return 0;
+}
+
+static unsigned long
+sf21_cmnpll_postdiv_recalc_rate(struct clk_hw *hw,
+                                    unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       u32 cfg = sf_readl(priv, PLL_CMN_CFG1);
+       unsigned long div1 = FIELD_GET(PLL_CMN_POSTDIV1, cfg);
+       unsigned long div2 = FIELD_GET(PLL_CMN_POSTDIV2, cfg);
+
+       return parent_rate / div1 / div2;
+}
+
+static const struct clk_ops sf21_cmnpll_postdiv_ops = {
+       .recalc_rate = sf21_cmnpll_postdiv_recalc_rate,
+       .round_rate = sf21_cmnpll_postdiv_round_rate,
+       .set_rate = sf21_cmnpll_postdiv_set_rate,
+};
+
+static const char *const clk_cmnpll_postdiv_parents[] = { "cmnpll_vco" };
+
+static struct sf_clk_common cmnpll_postdiv =
+       SF_CLK_COMMON("cmnpll_postdiv", clk_cmnpll_postdiv_parents,
+                     &sf21_cmnpll_postdiv_ops, 0);
+
+#define PLL_DDR_CFG1           0x18
+#define  PLL_DDR_BYPASS                BIT(23)
+#define  PLL_DDR_PLLEN         BIT(22)
+#define  PLL_DDR_4PHASEEN      BIT(21)
+#define  PLL_DDR_POSTDIVEN     BIT(20)
+#define  PLL_DDR_DSMEN         BIT(19)
+#define  PLL_DDR_DACEN         BIT(18)
+#define  PLL_DDR_DSKEWCALBYP   BIT(17)
+#define  PLL_DDR_DSKEWCALCNT   GENMASK(16, 14)
+#define  PLL_DDR_DSKEWCALEN    BIT(13)
+#define  PLL_DDR_DSKEWCALIN    GENMASK(12, 1)
+#define  PLL_DDR_DSKEWFASTCAL  BIT(0)
+
+#define PLL_DDR_CFG2           0x1c
+#define  PLL_DDR_POSTDIV1      GENMASK(29, 27)
+#define  PLL_DDR_POSTDIV2      GENMASK(26, 24)
+#define  PLL_DDR_FRAC          GENMASK(23, 0)
+
+#define PLL_DDR_CFG3           0x20
+#define  PLL_DDR_FBDIV         GENMASK(17, 6)
+#define  PLL_DDR_REFDIV                GENMASK(5, 0)
+
+static unsigned long
+sf21_ddrpll_postdiv_recalc_rate(struct clk_hw *hw,
+                                    unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       u32 cfg2 = sf_readl(priv, PLL_DDR_CFG2);
+       u32 postdiv1 = FIELD_GET(PLL_DDR_POSTDIV1, cfg2);
+       u32 postdiv2 = FIELD_GET(PLL_DDR_POSTDIV2, cfg2);
+       u32 cfg3 = sf_readl(priv, PLL_DDR_CFG3);
+       u32 fbdiv = FIELD_GET(PLL_DDR_FBDIV, cfg3);
+       u32 refdiv = FIELD_GET(PLL_DDR_REFDIV, cfg3);
+
+       return (parent_rate / refdiv) * fbdiv / postdiv1 / postdiv2;
+}
+
+static const struct clk_ops sf21_ddrpll_postdiv_ops = {
+       .recalc_rate = sf21_ddrpll_postdiv_recalc_rate,
+};
+
+static struct sf_clk_common ddrpll_postdiv = SF_CLK_COMMON(
+       "ddrpll_postdiv", clk_pll_parents, &sf21_ddrpll_postdiv_ops, 0);
+
+#define PLL_PCIE_CFG1          0x4c
+#define  PLL_PCIE_PLLEN                BIT(31)
+#define  PLL_PCIE_POSTDIV0PRE  BIT(30)
+#define  PLL_PCIE_REFDIV       GENMASK(29, 24)
+#define  PLL_PCIE_FRAC         GENMASK(23, 0)
+
+#define PLL_PCIE_CFG2          0x50
+#define  PLL_PCIE_FOUTEN(i)    BIT(28 + (i))
+#define  PLL_PCIE_BYPASS(i)    BIT(24 + (i))
+#define  PLL_PCIE_PDIVA_OFFS(i)        (21 - 6 * (i))
+#define  PLL_PCIE_PDIVB_OFFS(i)        (18 - 6 * (i))
+#define  PLL_PCIE_PDIV_MASK    GENMASK(2, 0)
+
+#define PLL_PCIE_CFG3          0x54
+#define  PLL_PCIE_DSKEWFASTCAL BIT(31)
+#define  PLL_PCIE_DACEN                BIT(30)
+#define  PLL_PCIE_DSMEN                BIT(29)
+#define  PLL_PCIE_DSKEWCALEN   BIT(28)
+#define  PLL_PCIE_DSKEWCALBYP  BIT(27)
+#define  PLL_PCIE_DSKEWCALCNT  GENMASK(26, 24)
+#define  PLL_PCIE_DSKEWCALIN   GENMASK(23, 12)
+#define  PLL_PCIE_FBDIV                GENMASK(11, 0)
+
+static unsigned long
+sf21_pciepll_vco_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       u32 cfg1 = sf_readl(priv, PLL_PCIE_CFG1);
+       unsigned long refdiv = FIELD_GET(PLL_PCIE_REFDIV, cfg1);
+       u32 cfg3 = sf_readl(priv, PLL_PCIE_CFG3);
+       unsigned long fbdiv = FIELD_GET(PLL_PCIE_FBDIV, cfg3);
+
+       return (parent_rate / refdiv) * fbdiv / 4;
+}
+
+static int sf21_pciepll_vco_enable(struct clk_hw *hw)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(priv->lock, flags);
+       sf_rmw(priv, PLL_PCIE_CFG1, 0, PLL_PCIE_PLLEN);
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_PCIE_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+       while (!(sf_readl(priv, PLL_PCIE_LOCK)))
+               ;
+       spin_unlock_irqrestore(priv->lock, flags);
+       return 0;
+}
+
+static void sf21_pciepll_vco_disable(struct clk_hw *hw)
+{
+       struct sf_clk_common *priv = hw_to_sf_clk_common(hw);
+       unsigned long flags;
+
+       spin_lock_irqsave(priv->lock, flags);
+       sf_rmw(priv, PLL_PCIE_CFG1, PLL_PCIE_PLLEN, 0);
+       sf_writel(priv, CFG_LOAD, CFG_LOAD_PCIE_PLL);
+       sf_writel(priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(priv->lock, flags);
+}
+
+static const struct clk_ops sf21_pciepll_vco_ops = {
+       .enable = sf21_pciepll_vco_enable,
+       .disable = sf21_pciepll_vco_disable,
+       .recalc_rate = sf21_pciepll_vco_recalc_rate,
+};
+
+static struct sf_clk_common pciepll_vco =
+       SF_CLK_COMMON("pciepll_vco", clk_pll_parents,
+                     &sf21_pciepll_vco_ops, CLK_SET_RATE_GATE);
+
+struct sf21_pciepll_fout {
+       struct sf_clk_common common;
+       u8 index;
+};
+
+static int sf21_pciepll_fout_enable(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_pciepll_fout *priv =
+               container_of(cmn_priv, struct sf21_pciepll_fout, common);
+       unsigned long flags;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, PLL_PCIE_CFG2, 0, PLL_PCIE_FOUTEN(priv->index));
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_PCIE_PLL);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+       return 0;
+}
+
+static void sf21_pciepll_fout_disable(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_pciepll_fout *priv =
+               container_of(cmn_priv, struct sf21_pciepll_fout, common);
+       unsigned long flags;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, PLL_PCIE_CFG2, PLL_PCIE_FOUTEN(priv->index), 0);
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_PCIE_PLL);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+}
+
+static long sf21_pciepll_fout_round_rate(struct clk_hw *hw,
+                                             unsigned long rate,
+                                             unsigned long *parent_rate)
+{
+       unsigned int diva, divb;
+
+       return sf21_dualdiv_round_rate(rate, *parent_rate, 8, &diva,
+                                           &divb);
+}
+
+static int sf21_pciepll_fout_set_rate(struct clk_hw *hw,
+                                          unsigned long rate,
+                                          unsigned long parent_rate)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_pciepll_fout *priv =
+               container_of(cmn_priv, struct sf21_pciepll_fout, common);
+       unsigned int diva, divb;
+       unsigned long flags;
+
+       sf21_dualdiv_round_rate(rate, parent_rate, 8, &diva, &divb);
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, PLL_PCIE_CFG2,
+              (PLL_PCIE_PDIV_MASK << PLL_PCIE_PDIVA_OFFS(priv->index)) |
+                      (PLL_PCIE_PDIV_MASK << PLL_PCIE_PDIVB_OFFS(priv->index)),
+              ((diva - 1) << PLL_PCIE_PDIVA_OFFS(priv->index)) |
+                      ((divb - 1) << PLL_PCIE_PDIVB_OFFS(priv->index)));
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_PCIE_PLL);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+       return 0;
+}
+
+static unsigned long
+sf21_pciepll_fout_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_pciepll_fout *priv =
+               container_of(cmn_priv, struct sf21_pciepll_fout, common);
+       int idx = priv->index;
+       u32 cfg2 = sf_readl(cmn_priv, PLL_PCIE_CFG2);
+       ulong pdiva = (cfg2 >> PLL_PCIE_PDIVA_OFFS(idx)) & PLL_PCIE_PDIV_MASK;
+       ulong pdivb = (cfg2 >> PLL_PCIE_PDIVB_OFFS(idx)) & PLL_PCIE_PDIV_MASK;
+
+       return parent_rate / (pdiva + 1) / (pdivb + 1);
+}
+
+static const struct clk_ops sf21_pciepll_fout_ops = {
+       .enable = sf21_pciepll_fout_enable,
+       .disable = sf21_pciepll_fout_disable,
+       .recalc_rate = sf21_pciepll_fout_recalc_rate,
+       .round_rate = sf21_pciepll_fout_round_rate,
+       .set_rate = sf21_pciepll_fout_set_rate,
+};
+
+static const char * const clk_pciepll_fout_parents[] = { "pciepll_vco" };
+
+#define SF21_PCIEPLL_FOUT(_name, _idx, _flags)                 \
+       struct sf21_pciepll_fout _name = {                              \
+               .common = SF_CLK_COMMON(#_name,                         \
+                                       clk_pciepll_fout_parents,       \
+                                       &sf21_pciepll_fout_ops, \
+                                       _flags),                        \
+               .index = _idx,                                          \
+       }
+
+static SF21_PCIEPLL_FOUT(pciepll_fout0, 0, 0);
+static SF21_PCIEPLL_FOUT(pciepll_fout1, 1, 0);
+static SF21_PCIEPLL_FOUT(pciepll_fout2, 2, 0);
+static SF21_PCIEPLL_FOUT(pciepll_fout3, 3, 0);
+
+struct sf21_clk_muxdiv {
+       struct sf_clk_common common;
+       u16 mux;
+       u16 en;
+       u8 div_reg;
+       u8 div_offs;
+};
+
+#define CRM_CLK_SEL(_x)                ((_x) * 4 + 0x80)
+#define CRM_CLK_EN             0x8c
+#define CRM_CLK_DIV(_x)                ((_x) * 4 + 0x94)
+#define  CRM_CLK_DIV_MASK      GENMASK(7, 0)
+
+static unsigned long sf21_muxdiv_recalc_rate(struct clk_hw *hw,
+                                                 unsigned long parent_rate)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       ulong div_reg = CRM_CLK_DIV(priv->div_reg);
+       u16 div_offs = priv->div_offs;
+       u16 div_val = (sf_readl(cmn_priv, div_reg) >> div_offs) &
+                     CRM_CLK_DIV_MASK;
+       div_val += 1;
+       return parent_rate / div_val;
+}
+
+static int sf21_muxdiv_determine_rate(struct clk_hw *hw,
+                                          struct clk_rate_request *req)
+{
+       unsigned int div;
+
+       div = DIV_ROUND_CLOSEST(req->best_parent_rate, req->rate);
+       if (!div)
+               div = 1;
+       else if (div > CRM_CLK_DIV_MASK + 1)
+               div = CRM_CLK_DIV_MASK + 1;
+
+       req->rate = req->best_parent_rate / div;
+       return 0;
+}
+
+static int sf21_muxdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+                                    unsigned long parent_rate)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       ulong div_reg = CRM_CLK_DIV(priv->div_reg);
+       u16 div_offs = priv->div_offs;
+       unsigned long flags;
+       unsigned int div;
+
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       if (div < 1)
+               div = 1;
+       else if (div > CRM_CLK_DIV_MASK + 1)
+               div = CRM_CLK_DIV_MASK + 1;
+       div -= 1;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, div_reg, CRM_CLK_DIV_MASK << div_offs,
+              div << div_offs);
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_DIV);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+       return 0;
+}
+
+static int sf21_muxdiv_enable(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       unsigned long flags;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, CRM_CLK_EN, 0, BIT(priv->en));
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_DIV);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+       return 0;
+}
+
+static void sf21_muxdiv_disable(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       unsigned long flags;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       sf_rmw(cmn_priv, CRM_CLK_EN, BIT(priv->en), 0);
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_DIV);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+}
+
+static int sf21_muxdiv_is_enabled(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       u32 reg_val = sf_readl(cmn_priv, CRM_CLK_EN);
+
+       return reg_val & (BIT(priv->en)) ? 1 : 0;
+}
+
+static u8 sf21_muxdiv_get_parent(struct clk_hw *hw)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       ulong mux_reg = CRM_CLK_SEL(priv->mux / 32);
+       u16 mux_offs = priv->mux % 32;
+       u32 reg_val = sf_readl(cmn_priv, mux_reg);
+
+       return reg_val & BIT(mux_offs) ? 1 : 0;
+}
+
+static int sf21_muxdiv_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct sf_clk_common *cmn_priv = hw_to_sf_clk_common(hw);
+       struct sf21_clk_muxdiv *priv =
+               container_of(cmn_priv, struct sf21_clk_muxdiv, common);
+       ulong mux_reg = CRM_CLK_SEL(priv->mux / 32);
+       u16 mux_offs = priv->mux % 32;
+       unsigned long flags;
+
+       spin_lock_irqsave(cmn_priv->lock, flags);
+       if (index)
+               sf_rmw(cmn_priv, mux_reg, 0, BIT(mux_offs));
+       else
+               sf_rmw(cmn_priv, mux_reg, BIT(mux_offs), 0);
+
+       sf_writel(cmn_priv, CFG_LOAD, CFG_LOAD_DIV);
+       sf_writel(cmn_priv, CFG_LOAD, 0);
+       spin_unlock_irqrestore(cmn_priv->lock, flags);
+       return 0;
+}
+
+static const struct clk_ops sf21_clk_muxdiv_ops = {
+       .enable = sf21_muxdiv_enable,
+       .disable = sf21_muxdiv_disable,
+       .is_enabled = sf21_muxdiv_is_enabled,
+       .recalc_rate = sf21_muxdiv_recalc_rate,
+       .determine_rate = sf21_muxdiv_determine_rate,
+       .set_rate = sf21_muxdiv_set_rate,
+       .get_parent = sf21_muxdiv_get_parent,
+       .set_parent = sf21_muxdiv_set_parent,
+};
+
+#define SF21_MUXDIV(_name, _parents,                           \
+                        _mux, _div_reg, _div_offs, _en, _flags)        \
+       struct sf21_clk_muxdiv _name = {                                \
+               .common = SF_CLK_COMMON(#_name, _parents,               \
+                                       &sf21_clk_muxdiv_ops,   \
+                                       _flags),                        \
+               .mux = _mux,                                            \
+               .en = _en,                                              \
+               .div_reg = _div_reg,                                    \
+               .div_offs = _div_offs,                                  \
+       }
+
+static const char *const clk_periph_parents[] = { "cmnpll_postdiv",
+                                                 "ddrpll_postdiv" };
+static const char *const clk_ddr_parents[] = { "ddrpll_postdiv",
+                                              "cmnpll_postdiv" };
+static const char *const clk_gmac_usb_parents[] = { "cmnpll_vco",
+                                                   "ddrpll_postdiv" };
+
+static SF21_MUXDIV(muxdiv_cpu, clk_periph_parents, 1, 0, 0, 0, CLK_IGNORE_UNUSED);
+static SF21_MUXDIV(muxdiv_pic, clk_periph_parents, 3, 3, 16, 1, CLK_IGNORE_UNUSED);
+static SF21_MUXDIV(muxdiv_axi, clk_periph_parents, 5, 0, 8, 2, CLK_IS_CRITICAL);
+static SF21_MUXDIV(muxdiv_ahb, clk_periph_parents, 7, 0, 16, 3, CLK_IS_CRITICAL);
+static SF21_MUXDIV(muxdiv_apb, clk_periph_parents, 9, 0, 24, 4, CLK_IS_CRITICAL);
+static SF21_MUXDIV(muxdiv_uart, clk_periph_parents, 11, 1, 0, 5, 0);
+static SF21_MUXDIV(muxdiv_iram, clk_periph_parents, 13, 1, 8, 6, 0);
+static SF21_MUXDIV(muxdiv_npu, clk_periph_parents, 17, 1, 24, 8, 0);
+static SF21_MUXDIV(muxdiv_ddrphy, clk_ddr_parents, 19, 2, 0, 9, CLK_IS_CRITICAL);
+static SF21_MUXDIV(muxdiv_ddr_bypass, clk_ddr_parents, 21, 3, 0, 10, CLK_IS_CRITICAL);
+static SF21_MUXDIV(muxdiv_ethtsu, clk_periph_parents, 25, 2, 16, 12, 0);
+static SF21_MUXDIV(muxdiv_gmac_byp_ref, clk_gmac_usb_parents, 27, 2, 24, 13, 0);
+static SF21_MUXDIV(muxdiv_usb, clk_gmac_usb_parents, 33, 1, 16, 24, 0);
+static SF21_MUXDIV(muxdiv_usbphy, clk_gmac_usb_parents, 35, 2, 8, 25, 0);
+static SF21_MUXDIV(muxdiv_serdes_csr, clk_periph_parents, 47, 5, 0, 20, 0);
+static SF21_MUXDIV(muxdiv_crypt_csr, clk_periph_parents, 49, 5, 8, 21, 0);
+static SF21_MUXDIV(muxdiv_crypt_app, clk_periph_parents, 51, 5, 16, 22, 0);
+static SF21_MUXDIV(muxdiv_irom, clk_periph_parents, 53, 5, 24, 23, CLK_IS_CRITICAL);
+
+static int sf21_mux_determine_rate(struct clk_hw *hw,
+                                       struct clk_rate_request *req)
+{
+       req->rate = req->best_parent_rate;
+       return 0;
+}
+
+static const struct clk_ops sf21_clk_mux_ops = {
+       .get_parent = sf21_muxdiv_get_parent,
+       .set_parent = sf21_muxdiv_set_parent,
+       .determine_rate = sf21_mux_determine_rate,
+};
+
+#define SF21_MUX(_name, _parents, _mux, _flags)                        \
+       struct sf21_clk_muxdiv _name = {                                \
+               .common = SF_CLK_COMMON(#_name, _parents,               \
+                                       &sf21_clk_mux_ops,              \
+                                       _flags),                        \
+               .mux = _mux,                                            \
+               .en = 0,                                                \
+               .div_reg = 0,                                           \
+               .div_offs = 0,                                          \
+       }
+
+static const char * const clk_boot_parents[] = { "muxdiv_irom", "xin25m" };
+
+static SF21_MUX(mux_boot, clk_boot_parents, 30, CLK_IS_CRITICAL);
+
+static const struct clk_ops sf21_clk_div_ops = {
+       .recalc_rate = sf21_muxdiv_recalc_rate,
+       .determine_rate = sf21_muxdiv_determine_rate,
+       .set_rate = sf21_muxdiv_set_rate,
+};
+
+#define SF21_DIV(_name, _parents, _div_reg, _div_offs, _flags) \
+       struct sf21_clk_muxdiv _name = {                                \
+               .common = SF_CLK_COMMON(#_name, _parents,               \
+                                       &sf21_clk_div_ops,              \
+                                       _flags),                        \
+               .mux = 0,                                               \
+               .en = 0,                                                \
+               .div_reg = _div_reg,                                    \
+               .div_offs = _div_offs,                                  \
+       }
+
+static SF21_DIV(div_pvt, clk_pll_parents, 3, 8, 0);
+static SF21_DIV(div_pll_test, clk_pll_parents, 3, 24, 0);
+
+static const struct clk_ops sf21_clk_gate_ops = {
+       .enable = sf21_muxdiv_enable,
+       .disable = sf21_muxdiv_disable,
+       .is_enabled = sf21_muxdiv_is_enabled,
+};
+
+#define SF21_GATE(_name, _parents, _en, _flags)                        \
+       struct sf21_clk_muxdiv _name = {                                \
+               .common = SF_CLK_COMMON(#_name,                         \
+                                       _parents,                       \
+                                       &sf21_clk_gate_ops,     \
+                                       _flags),                        \
+               .mux = 0,                                               \
+               .en = _en,                                              \
+               .div_reg = 0,                                           \
+               .div_offs = 0,                                          \
+       }
+
+static const char * const clk_pcie_parents[] = { "pciepll_fout1" };
+
+static SF21_GATE(pcie_refclk_n, clk_pcie_parents, 15, 0);
+static SF21_GATE(pcie_refclk_p, clk_pcie_parents, 16, 0);
+
+static struct clk_hw_onecell_data sf21_hw_clks = {
+       .num = CLK_MAX,
+       .hws = {
+               [CLK_CMNPLL_VCO] = &cmnpll_vco.hw,
+               [CLK_CMNPLL_POSTDIV] = &cmnpll_postdiv.hw,
+               [CLK_DDRPLL_POSTDIV] = &ddrpll_postdiv.hw,
+               [CLK_PCIEPLL_VCO] = &pciepll_vco.hw,
+               [CLK_PCIEPLL_FOUT0] = &pciepll_fout0.common.hw,
+               [CLK_PCIEPLL_FOUT1] = &pciepll_fout1.common.hw,
+               [CLK_PCIEPLL_FOUT2] = &pciepll_fout2.common.hw,
+               [CLK_PCIEPLL_FOUT3] = &pciepll_fout3.common.hw,
+               [CLK_CPU] = &muxdiv_cpu.common.hw,
+               [CLK_PIC] = &muxdiv_pic.common.hw,
+               [CLK_AXI] = &muxdiv_axi.common.hw,
+               [CLK_AHB] = &muxdiv_ahb.common.hw,
+               [CLK_APB] = &muxdiv_apb.common.hw,
+               [CLK_UART] = &muxdiv_uart.common.hw,
+               [CLK_IRAM] = &muxdiv_iram.common.hw,
+               [CLK_NPU] = &muxdiv_npu.common.hw,
+               [CLK_DDRPHY_REF] = &muxdiv_ddrphy.common.hw,
+               [CLK_DDR_BYPASS] = &muxdiv_ddr_bypass.common.hw,
+               [CLK_ETHTSU] = &muxdiv_ethtsu.common.hw,
+               [CLK_GMAC_BYP_REF] = &muxdiv_gmac_byp_ref.common.hw,
+               [CLK_USB] = &muxdiv_usb.common.hw,
+               [CLK_USBPHY] = &muxdiv_usbphy.common.hw,
+               [CLK_SERDES_CSR] = &muxdiv_serdes_csr.common.hw,
+               [CLK_CRYPT_CSR] = &muxdiv_crypt_csr.common.hw,
+               [CLK_CRYPT_APP] = &muxdiv_crypt_app.common.hw,
+               [CLK_IROM] = &muxdiv_irom.common.hw,
+               [CLK_BOOT] = &mux_boot.common.hw,
+               [CLK_PVT] = &div_pvt.common.hw,
+               [CLK_PLL_TEST] = &div_pll_test.common.hw,
+               [CLK_PCIE_REFN] = &pcie_refclk_n.common.hw,
+               [CLK_PCIE_REFP] = &pcie_refclk_p.common.hw,
+       }
+};
+
+struct sf21_clk_ctrl {
+       void __iomem *base;
+       spinlock_t lock;
+};
+
+static void __init sf21_topcrm_init(struct device_node *node)
+{
+       struct sf21_clk_ctrl *ctrl;
+       int i, ret;
+
+       ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return;
+
+       ctrl->base = of_iomap(node, 0);
+       if (!ctrl->base) {
+               pr_err("failed to map resources.\n");
+               return;
+       }
+
+       spin_lock_init(&ctrl->lock);
+
+       for (i = 0; i < sf21_hw_clks.num; i++) {
+               struct clk_hw *hw = sf21_hw_clks.hws[i];
+               struct sf_clk_common *common;
+
+               if (!hw)
+                       continue;
+               common = hw_to_sf_clk_common(hw);
+               common->base = ctrl->base;
+               common->lock = &ctrl->lock;
+               ret = clk_hw_register(NULL, hw);
+               if (ret) {
+                       pr_err("Couldn't register clock %d\n", i);
+                       goto err;
+               }
+       }
+
+       ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
+                                    &sf21_hw_clks);
+       if (ret) {
+               pr_err("failed to add hw provider.\n");
+               goto err;
+       }
+       return;
+err:
+       iounmap(ctrl->base);
+}
+
+CLK_OF_DECLARE(sf21_topcrm, "siflower,sf21-topcrm", sf21_topcrm_init);
index 4253a84bf43580427e4ca8aca0d5f1a14b94ec18..f2e9d24f2b8e82fe588ef24a1396920af1320b6d 100644 (file)
@@ -336,6 +336,7 @@ static struct platform_driver sf_gpio_driver = {
        .remove         = sf_gpio_remove,
        .driver = {
                .name           = "siflower_gpio",
+               .owner          = THIS_MODULE,
                .of_match_table = sf_gpio_ids,
        },
 };
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Kconfig b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Kconfig
new file mode 100644 (file)
index 0000000..8699b20
--- /dev/null
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Siflower network device configuration
+#
+
+config NET_VENDOR_SIFLOWER
+       bool "Siflower Ethernet"
+       default y
+       depends on ARCH_SIFLOWER
+
+if NET_VENDOR_SIFLOWER
+
+config NET_SIFLOWER_ETH_DPNS
+       tristate "Siflower DPNS driver"
+       help
+         Support the Dataplane network subsystem of SiFlower SF21A6826/SF21H8898 SoC.
+
+config NET_SIFLOWER_ETH_XGMAC
+       tristate "Siflower Ethernet MAC driver"
+       depends on NET_SIFLOWER_ETH_DPNS
+       select MII
+       select PAGE_POOL
+       select PHYLINK
+       select NET_SIFLOWER_ETH_DMA
+        select NET_SIFLOWER_ETH_XPCS
+       help
+         Support the Ethernet controller of SiFlower SF21A6826/SF21H8898 SoC.
+
+config NET_SIFLOWER_ETH_DMA
+       tristate "Siflower Ethernet DMA driver"
+       depends on NET_SIFLOWER_ETH_DPNS
+       select PAGE_POOL
+       help
+         Support the Ethernet controller of SiFlower SF21A6826/SF21H8898 SoC.
+
+config NET_SIFLOWER_ETH_XPCS
+       tristate "Siflower Ethernet XPCS driver"
+       depends on NET_SIFLOWER_ETH_DPNS
+       select PAGE_POOL
+       help
+         Support the PCS block of SiFlower SF21A6826/SF21H8898 SoC.
+
+if NET_SIFLOWER_ETH_DMA
+
+config NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+       bool "Use internal SRAM for DMA descriptors"
+       select SRAM
+       help
+         Use internal SRAM instead of system memory for DMA descriptors.
+
+endif # NET_SIFLOWER_ETH_DMA
+
+endif # NET_VENDOR_SIFLOWER
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Makefile b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/Makefile
new file mode 100644 (file)
index 0000000..557edb5
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the siflower soc network device drivers.
+#
+
+sf_dpns-objs := sf_dpns.o sf_dpns_debugfs.o sf_dpns_tmu.o sf_dpns_se.o
+obj-$(CONFIG_NET_SIFLOWER_ETH_DPNS) += sf_dpns.o
+
+obj-$(CONFIG_NET_SIFLOWER_ETH_XGMAC) += sfxgmac.o
+obj-$(CONFIG_NET_SIFLOWER_ETH_DMA) += sfxgmac-dma.o
+obj-$(CONFIG_NET_SIFLOWER_ETH_XPCS) += sfxpcs.o
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dma.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dma.h
new file mode 100644 (file)
index 0000000..89fa320
--- /dev/null
@@ -0,0 +1,152 @@
+#ifndef _SFXGMAC_DMA_H
+#define _SFXGMAC_DMA_H
+
+#include <linux/clk.h>
+#include <linux/genalloc.h>
+#include <linux/if_vlan.h>
+#include <linux/mfd/syscon.h>
+#include <linux/netdevice.h>
+#include <linux/regmap.h>
+
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+#define DMA_TX_SIZE    512
+#define DMA_RX_SIZE    512
+#else
+#define DMA_TX_SIZE    2048
+#define DMA_RX_SIZE    2048
+#endif
+#define DPNS_HOST_PORT 6
+#define DPNS_MAX_PORT  27
+#define DMA_CH_MAX     4
+#define DMA_CH_DISABLE 4
+#define DMA_OVPORT_CH  4
+#define SZ_1_5K                0x00000600
+#define SZ_3K          0x00000C00
+
+/* Either 8 (64-bit) or 16 (128-bit), configured in RTL */
+#define DMA_DATAWIDTH  8
+
+/* extra header room for skb to wifi */
+#define NET_WIFI_HEADERROOM_EXTRA SKB_DATA_ALIGN(32)
+
+/* Padding at the beginning of the allocated buffer, passed into skb_reserve */
+#define BUF_PAD                (NET_SKB_PAD + NET_IP_ALIGN + NET_WIFI_HEADERROOM_EXTRA)
+
+/* RX Buffer size, calculated by MTU + eth header + double VLAN tag + FCS */
+#define BUF_SIZE(x)    ((x) + ETH_HLEN + VLAN_HLEN * 2 + ETH_FCS_LEN)
+
+/* RX Buffer alloc size, with padding and skb_shared_info, passed into
+ * page_pool_dev_alloc_frag */
+#define BUF_SIZE_ALLOC(x)      (SKB_DATA_ALIGN(BUF_SIZE(x) + BUF_PAD) + \
+                               SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
+/* RX Buffer size programmed into RBSZ field, must be multiple of datawidth */
+#define BUF_SIZE_ALIGN(x)      ALIGN(BUF_SIZE(x) + NET_IP_ALIGN, DMA_DATAWIDTH)
+
+/* Maximum value of the RBSZ field */
+#define BUF_SIZE_ALIGN_MAX     ALIGN_DOWN(FIELD_MAX(XGMAC_RBSZ), DMA_DATAWIDTH)
+
+/* TODO: use mtu in priv */
+#define BUF_SIZE_DEFAULT    SKB_MAX_HEAD(BUF_PAD)
+#define BUF_SIZE_DEFAULT_ALIGN  ALIGN(BUF_SIZE_DEFAULT, DMA_DATAWIDTH)
+
+/* skb handled by dpns flag */
+#define SF_DPNS_FLAG        47
+
+/* skb handled by dpns need to be forwarded */
+#define SF_CB_DPNS_FORWARD             22
+
+struct xgmac_dma_desc {
+       __le32 des0;
+       __le32 des1;
+       __le32 des2;
+       __le32 des3;
+};
+
+struct xgmac_skb_cb {
+       u8 id;
+       bool fastmode;
+};
+
+#define XGMAC_SKB_CB(skb)      ((struct xgmac_skb_cb *)(skb)->cb)
+
+struct xgmac_tx_info {
+       dma_addr_t buf;
+       bool map_as_page;
+       unsigned len;
+       bool last_segment;
+};
+
+struct xgmac_txq {
+       struct xgmac_dma_desc *dma_tx ____cacheline_aligned_in_smp;
+       struct sk_buff **tx_skbuff;
+       struct xgmac_tx_info *tx_skbuff_dma;
+       unsigned int cur_tx;
+       unsigned int dirty_tx;
+       dma_addr_t dma_tx_phy;
+       dma_addr_t tx_tail_addr;
+       spinlock_t lock;
+       struct napi_struct napi ____cacheline_aligned_in_smp;
+       u32 idx;
+       u32 irq;
+       bool is_busy;
+};
+
+struct xgmac_dma_rx_buffer {
+       struct page *page;
+       unsigned int offset;
+};
+
+struct xgmac_rxq {
+       struct xgmac_dma_desc *dma_rx ____cacheline_aligned_in_smp;
+       struct page_pool *page_pool;
+       struct xgmac_dma_rx_buffer *buf_pool;
+       unsigned int cur_rx;
+       unsigned int dirty_rx;
+       dma_addr_t dma_rx_phy;
+       dma_addr_t rx_tail_addr;
+       struct napi_struct napi ____cacheline_aligned_in_smp;
+       u32 idx;
+       u32 irq;
+};
+
+enum {
+       DMA_CLK_AXI,
+       DMA_CLK_NPU,
+       DMA_CLK_CSR,
+       DMA_NUM_CLKS
+};
+
+struct xgmac_dma_priv {
+       void __iomem            *ioaddr;
+       struct device           *dev;
+       struct clk_bulk_data    clks[DMA_NUM_CLKS];
+       struct net_device       napi_dev;
+       /* RX Queue */
+       struct xgmac_rxq        rxq[DMA_CH_MAX];
+
+       /* TX Queue */
+       struct xgmac_txq        txq[DMA_CH_MAX];
+
+       /* associated net devices (vports) */
+       struct net_device       *ndevs[DPNS_MAX_PORT];
+
+       struct regmap           *ethsys;
+       refcount_t              refcnt;
+       u32                     irq;
+       u8                      ifindex;
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+       struct gen_pool         *genpool;
+#endif
+       u16                     rx_alloc_size;
+       u16                     rx_buffer_size;
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_PAGE_POOL_STATS)
+       struct dentry           *dbgdir;
+#endif
+};
+
+netdev_tx_t xgmac_dma_xmit_fast(struct sk_buff *skb, struct net_device *dev);
+int xgmac_dma_open(struct xgmac_dma_priv *priv, struct net_device *dev, u8 id);
+int xgmac_dma_stop(struct xgmac_dma_priv *priv, struct net_device *dev, u8 id);
+
+#endif
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dpns.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/dpns.h
new file mode 100644 (file)
index 0000000..1db8139
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef __SF_DPNS_H__
+#define __SF_DPNS_H__
+#include <asm/mmio.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/reset.h>
+
+#define PKT_ERR_STG_CFG2               0x80038
+#define  ARP_REPLY_ERR_OP              GENMASK(18, 16)
+#define  ARP_REPLY_ERR_DROP            BIT(18)
+#define  ARP_REPLY_ERR_UP              BIT(17)
+#define  ARP_REPLY_ERR_FWD             BIT(16)
+#define  ARP_REQ_ERR_OP                        GENMASK(14, 12)
+#define  ARP_REQ_ERR_DROP              BIT(14)
+#define  ARP_REQ_ERR_UP                        BIT(13)
+#define  ARP_REQ_ERR_FWD               BIT(12)
+
+#define  PKT_ERR_ACTION_DROP           BIT(2)
+#define  PKT_ERR_ACTION_UP             BIT(1)
+#define  PKT_ERR_ACTION_FWD            BIT(0)
+
+#define NPU_MIB_BASE                   0x380000
+#define NPU_MIB(x)                     (NPU_MIB_BASE + (x) * 4)
+#define NPU_MIB_PKT_RCV_PORT(x)                (NPU_MIB_BASE + 0x2000 + (x) * 4)
+#define NPU_MIB_NCI_RD_DATA2           (NPU_MIB_BASE + 0x301c)
+#define NPU_MIB_NCI_RD_DATA3           (NPU_MIB_BASE + 0x3020)
+
+struct dpns_priv {
+       void __iomem *ioaddr;
+       struct clk *clk;
+       struct reset_control *npu_rst;
+       struct device *dev;
+       struct dentry *debugfs;
+};
+
+static inline u32 dpns_r32(struct dpns_priv *priv, unsigned reg)
+{
+       return readl(priv->ioaddr + reg);
+}
+
+static inline void dpns_w32(struct dpns_priv *priv, unsigned reg, u32 val)
+{
+       writel(val, priv->ioaddr + reg);
+}
+
+static inline void dpns_rmw(struct dpns_priv *priv, unsigned reg, u32 clr,
+                           u32 set)
+{
+       u32 val = dpns_r32(priv, reg);
+       val &= ~clr;
+       val |= set;
+       dpns_w32(priv, reg, val);
+}
+
+int dpns_se_init(struct dpns_priv *priv);
+int dpns_tmu_init(struct dpns_priv *priv);
+void sf_dpns_debugfs_init(struct dpns_priv *priv);
+
+#endif /* __SF_DPNS_H__ */
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/eth.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/eth.h
new file mode 100644 (file)
index 0000000..0a813d9
--- /dev/null
@@ -0,0 +1,782 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
+ * Copyright (c) 2022 SiFlower Ltd.
+ */
+#ifndef _SIFLOWER_ETH_H
+#define _SIFLOWER_ETH_H
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/netdevice.h>
+
+struct phylink_pcs *xpcs_port_get(struct platform_device *, unsigned int);
+void xpcs_port_put(struct platform_device *);
+
+#define reg_read(p, reg)               readl((p)->ioaddr + (reg))
+#define reg_write(p, reg, val)         writel(val, (p)->ioaddr + (reg))
+#define reg_rmw(p, reg, clear, set)                            \
+       do {                                                    \
+               void __iomem *ioaddr = (p)->ioaddr + (reg);     \
+               u32 val = readl(ioaddr);                \
+                                                               \
+               val &= ~(clear);                                \
+               val |= (set);                                   \
+               writel(val, ioaddr);                    \
+       } while (0)
+#define reg_set(p, reg, set)           reg_rmw(p, reg, 0, set)
+#define reg_clear(p, reg, clear)       reg_rmw(p, reg, clear, 0)
+
+#define priv_to_netdev(p) \
+       ((struct net_device*)((void*)(p) - ALIGN(sizeof(struct net_device), NETDEV_ALIGN)))
+
+#define offset_to_id(addr)     FIELD_GET(GENMASK(19, 14), addr)
+
+/* Maximum L2 frame size, including FCS */
+#define MAX_FRAME_SIZE         16383
+#define TSO_MAX_BUFF_SIZE      MAX_FRAME_SIZE
+
+/* Ethernet sysm defines */
+#define ETHSYS_MAC(n)          ((n) * 4)
+#define ETHSYS_PHY_INTF_SEL    GENMASK(17, 16)
+#define ETHSYS_PHY_INTF_RGMII   FIELD_PREP(ETHSYS_PHY_INTF_SEL, 1)
+#define ETHSYS_MAC5_CTRL        0xdc
+#define MAC5_PHY_INTF_SEL       GENMASK(17, 16)
+#define MAC5_RX_DELAY_EN        BIT(24)
+#define MAC5_RX_DELAY           GENMASK(23, 16)
+#define MAC5_TX_DELAY_EN        BIT(8)
+#define MAC5_TX_DELAY           GENMASK(7, 0)
+#define MAC5_DELAY_MASK         (MAC5_TX_DELAY_EN | MAC5_TX_DELAY | MAC5_RX_DELAY | MAC5_RX_DELAY_EN)
+#define MAC5_DELAY_STEP         49
+#define MAC5_DELAY_DEFAULT      (0x41 * MAC5_DELAY_STEP)
+#define ETHSYS_QSG_CTRL                0x6c
+#define ETHSYS_SG_CTRL         0x70
+#define ETHSYS_REF_RPT_EN      BIT(10)
+#define ETHSYS_RST          0x88
+#define ETHSYS_RST_MAC5            BIT(9)
+#define ETHSYS_RATIO_LOAD   0xec
+#define ETHSYS_NPU_BYPASS      0x8c
+#define ETHSYS_RX_QUEUE_ENABLE 0xb4
+#define ETHSYS_MRI_Q_MODE      GENMASK(31, 30)
+#define ETHSYS_MRI_OVPORT_MAX  GENMASK(21, 16)
+#define ETHSYS_MRI_OVPORT_MIN  GENMASK(13, 8)
+#define ETHSYS_MRI_Q_EN        0xb8
+#define ETHSYS_MRI_OVPORT_TOP_PRIO     GENMASK(5, 0)
+#define XGMAC_MTL_RXQ_DMA_MAP0 0x00001030
+#define ETHSYS_TX_DIS          0xd4
+#define ETHSYS_QS_SGMII_STATUS         0x128
+#define XGMAC_PORT_DH(n)      (BIT(12) >> ((n)*4))
+#define XGMAC_PORT_LINK(n)    (BIT(13)  >> ((n)*4))
+#define XGMAC_PORT0_SPD_MASK    GENMASK(3, 2)
+
+#define GMAC_HI_REG_AE         BIT(31)
+
+/* XGMAC Registers */
+#define XGMAC_TX_CONFIG                        0x00000000
+#define XGMAC_CONFIG_SS_OFF            29
+#define XGMAC_CONFIG_SS_MASK           GENMASK(31, 29)
+#define XGMAC_CONFIG_SS_10000          (0x0 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_2500_GMII      (0x2 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_1000_GMII      (0x3 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_100_MII                (0x4 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_5000           (0x5 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_2500           (0x6 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SS_10_MII         (0x7 << XGMAC_CONFIG_SS_OFF)
+#define XGMAC_CONFIG_SARC              GENMASK(22, 20)
+#define XGMAC_CONFIG_SARC_SHIFT                20
+#define XGMAC_CONFIG_JD                        BIT(16)
+#define XGMAC_CONFIG_IFP               BIT(11)
+enum inter_packet_gap {
+       XGMAC_CONTROL_IPG_88 = 0x00000100,
+       XGMAC_CONTROL_IPG_80 = 0x00000200,
+       XGMAC_CONTROL_IPG_72 = 0x00000300,
+       XGMAC_CONTROL_IPG_64 = 0x00000400,
+};
+#define XGMAC_CONFIG_TE                        BIT(0)
+#define XGMAC_CORE_INIT_TX             (XGMAC_CONTROL_IPG_88)
+#define XGMAC_RX_CONFIG                        0x00000004
+#define XGMAC_CONFIG_ARPEN             BIT(31)
+#define XGMAC_CONFIG_GPSL              GENMASK(29, 16)
+#define XGMAC_CONFIG_GPSL_SHIFT                16
+#define XGMAC_CONFIG_HDSMS             GENMASK(14, 12)
+#define XGMAC_CONFIG_HDSMS_SHIFT       12
+#define XGMAC_CONFIG_HDSMS_256         (0x2 << XGMAC_CONFIG_HDSMS_SHIFT)
+#define XGMAC_CONFIG_S2KP              BIT(11)
+#define XGMAC_CONFIG_LM                        BIT(10)
+#define XGMAC_CONFIG_IPC               BIT(9)
+#define XGMAC_CONFIG_JE                        BIT(8)
+#define XGMAC_CONFIG_WD                        BIT(7)
+#define XGMAC_CONFIG_GPSLCE            BIT(6)
+#define XGMAC_CONFIG_DCRCC             BIT(3)
+#define XGMAC_CONFIG_CST               BIT(2)
+#define XGMAC_CONFIG_ACS               BIT(1)
+#define XGMAC_CONFIG_RE                        BIT(0)
+#define XGMAC_CORE_INIT_RX             (XGMAC_CONFIG_ACS | XGMAC_CONFIG_CST |\
+                                       XGMAC_CONFIG_IPC)
+#define XGMAC_PACKET_FILTER            0x00000008
+#define XGMAC_FILTER_RA                        BIT(31)
+#define XGMAC_FILTER_IPFE              BIT(20)
+#define XGMAC_FILTER_VTFE              BIT(16)
+#define XGMAC_FILTER_HPF               BIT(10)
+#define XGMAC_FILTER_PCF               BIT(7)
+#define XGMAC_FILTER_PM                        BIT(4)
+#define XGMAC_FILTER_HMC               BIT(2)
+#define XGMAC_FILTER_PR                        BIT(0)
+#define XGMAC_WD_JB_TIMEOUT            0xc
+#define XGMAC_PJE                      BIT(24)
+#define XGMAC_JTO                      GENMASK(19, 16)
+#define XGMAC_PWE                      BIT(8)
+#define XGMAC_WTO                      GENMASK(3, 0)
+#define XGMAC_HASH_TABLE(x)            (0x00000010 + (x) * 4)
+#define XGMAC_MAX_HASH_TABLE           8
+#define XGMAC_VLAN_TAG                 0x00000050
+#define XGMAC_VLAN_EDVLP               BIT(26)
+#define XGMAC_VLAN_VTHM                        BIT(25)
+#define XGMAC_VLAN_DOVLTC              BIT(20)
+#define XGMAC_VLAN_ESVL                        BIT(18)
+#define XGMAC_VLAN_ETV                 BIT(16)
+#define XGMAC_VLAN_VID                 GENMASK(15, 0)
+#define XGMAC_VLAN_HASH_TABLE          0x00000058
+#define XGMAC_VLAN_INCL                        0x00000060
+#define XGMAC_VLAN_VLTI                        BIT(20)
+#define XGMAC_VLAN_CSVL                        BIT(19)
+#define XGMAC_VLAN_VLC                 GENMASK(17, 16)
+#define XGMAC_VLAN_VLC_SHIFT           16
+#define XGMAC_RXQ_CTRL0                        0x000000a0
+#define XGMAC_RXQEN(x)                 GENMASK((x) * 2 + 1, (x) * 2)
+#define XGMAC_RXQEN_SHIFT(x)           ((x) * 2)
+#define XGMAC_RXQ_CTRL1                        0x000000a4
+#define XGMAC_RQ                       GENMASK(7, 4)
+#define XGMAC_RQ_SHIFT                 4
+#define XGMAC_RXQ_CTRL2                        0x000000a8
+#define XGMAC_RXQ_CTRL3                        0x000000ac
+#define XGMAC_PSRQ(x)                  GENMASK((x) * 8 + 7, (x) * 8)
+#define XGMAC_PSRQ_SHIFT(x)            ((x) * 8)
+#define XGMAC_INT_STATUS               0x000000b0
+#define XGMAC_RGMII_LS                 BIT(27)
+#define XGMAC_RGMII_SPD                        GENMASK(26, 25)
+#define XGMAC_RGMII_DM                 BIT(24)
+#define XGMAC_LS                       GENMASK(25, 24)
+#define XGMAC_MMCRXIPIS                        BIT(11)
+#define XGMAC_MMCTXIS                  BIT(10)
+#define XGMAC_MMCRXIS                  BIT(9)
+#define XGMAC_MMCIS                    (XGMAC_MMCRXIPIS | XGMAC_MMCTXIS | XGMAC_MMCRXIS)
+#define XGMAC_LPIIS                    BIT(5)
+#define XGMAC_PMTIS                    BIT(4)
+#define XGMAC_SMI                      BIT(1)
+#define XGMAC_LSI                      BIT(0)
+#define XGMAC_INT_EN                   0x000000b4
+#define XGMAC_TSIE                     BIT(12)
+#define XGMAC_LPIIE                    BIT(5)
+#define XGMAC_PMTIE                    BIT(4)
+#define XGMAC_INT_DEFAULT_EN           (XGMAC_LPIIE | XGMAC_PMTIE)
+#define XGMAC_Qx_TX_FLOW_CTRL(x)       (0x00000070 + (x) * 4)
+#define XGMAC_PT                       GENMASK(31, 16)
+#define XGMAC_PT_SHIFT                 16
+#define XGMAC_TFE                      BIT(1)
+#define XGMAC_RX_FLOW_CTRL             0x00000090
+#define XGMAC_UP                       BIT(1)
+#define XGMAC_RFE                      BIT(0)
+#define XGMAC_PMT                      0x000000c0
+#define XGMAC_GLBLUCAST                        BIT(9)
+#define XGMAC_RWKPKTEN                 BIT(2)
+#define XGMAC_MGKPKTEN                 BIT(1)
+#define XGMAC_PWRDWN                   BIT(0)
+#define XGMAC_LPI_CTRL                 0x000000d0
+#define XGMAC_TXCGE                    BIT(21)
+#define XGMAC_LPIATE                   BIT(20)
+#define XGMAC_LPITXA                   BIT(19)
+#define XGMAC_PLS                      BIT(17)
+#define XGMAC_LPITXEN                  BIT(16)
+#define XGMAC_RLPIEX                   BIT(3)
+#define XGMAC_RLPIEN                   BIT(2)
+#define XGMAC_TLPIEX                   BIT(1)
+#define XGMAC_TLPIEN                   BIT(0)
+#define XGMAC_LPI_TIMER_CTRL           0x000000d4
+#define XGMAC_LPI_LST                  GENMASK(25, 16)
+#define XGMAC_LPI_LST_DEFAULT          1000
+#define XGMAC_LPI_TWT                  GENMASK(15, 0)
+#define XGMAC_LPI_TWT_DEFAULT          30
+#define XGMAC_LPI_AUTO_EN              0x000000d8
+#define XGMAC_LPI_AUTO_EN_MAX          0xffff8
+#define XGMAC_LPI_AUTO_EN_DEFAULT      10000
+#define XGMAC_LPI_1US                  0x000000dc
+#define XGMAC_VERSION                  0x00000110
+#define XGMAC_VERSION_USER             GENMASK(23, 16)
+#define XGMAC_VERSION_ID_MASK          GENMASK(15, 0)
+#define XGMAC_VERSION_ID               0x7631
+#define XGMAC_HW_FEATURE0              0x0000011c
+#define XGMAC_HWFEAT_SAVLANINS         BIT(27)
+#define XGMAC_HWFEAT_RXCOESEL          BIT(16)
+#define XGMAC_HWFEAT_TXCOESEL          BIT(14)
+#define XGMAC_HWFEAT_EEESEL            BIT(13)
+#define XGMAC_HWFEAT_TSSEL             BIT(12)
+#define XGMAC_HWFEAT_AVSEL             BIT(11)
+#define XGMAC_HWFEAT_RAVSEL            BIT(10)
+#define XGMAC_HWFEAT_ARPOFFSEL         BIT(9)
+#define XGMAC_HWFEAT_MMCSEL            BIT(8)
+#define XGMAC_HWFEAT_MGKSEL            BIT(7)
+#define XGMAC_HWFEAT_RWKSEL            BIT(6)
+#define XGMAC_HWFEAT_VLHASH            BIT(4)
+#define XGMAC_HWFEAT_GMIISEL           BIT(1)
+#define XGMAC_HW_FEATURE1              0x00000120
+#define XGMAC_HWFEAT_L3L4FNUM          GENMASK(30, 27)
+#define XGMAC_HWFEAT_HASHTBLSZ         GENMASK(25, 24)
+#define XGMAC_HWFEAT_RSSEN             BIT(20)
+#define XGMAC_HWFEAT_TSOEN             BIT(18)
+#define XGMAC_HWFEAT_SPHEN             BIT(17)
+#define XGMAC_HWFEAT_ADDR64            GENMASK(15, 14)
+#define XGMAC_HWFEAT_TXFIFOSIZE                GENMASK(10, 6)
+#define XGMAC_HWFEAT_RXFIFOSIZE                GENMASK(4, 0)
+#define XGMAC_HW_FEATURE2              0x00000124
+#define XGMAC_HWFEAT_PPSOUTNUM         GENMASK(26, 24)
+#define XGMAC_HWFEAT_TXCHCNT           GENMASK(21, 18)
+#define XGMAC_HWFEAT_RXCHCNT           GENMASK(15, 12)
+#define XGMAC_HWFEAT_TXQCNT            GENMASK(9, 6)
+#define XGMAC_HWFEAT_RXQCNT            GENMASK(3, 0)
+#define XGMAC_HW_FEATURE3              0x00000128
+#define XGMAC_HWFEAT_TBSSEL            BIT(27)
+#define XGMAC_HWFEAT_FPESEL            BIT(26)
+#define XGMAC_HWFEAT_ESTWID            GENMASK(24, 23)
+#define XGMAC_HWFEAT_ESTDEP            GENMASK(22, 20)
+#define XGMAC_HWFEAT_ESTSEL            BIT(19)
+#define XGMAC_HWFEAT_ASP               GENMASK(15, 14)
+#define XGMAC_HWFEAT_DVLAN             BIT(13)
+#define XGMAC_HWFEAT_FRPES             GENMASK(12, 11)
+#define XGMAC_HWFEAT_FRPPB             GENMASK(10, 9)
+#define XGMAC_HWFEAT_FRPSEL            BIT(3)
+#define XGMAC_MAC_EXT_CONFIG           0x00000140
+#define XGMAC_HD                       BIT(24)
+#define XGMAC_MAC_DPP_FSM_INT_STATUS   0x00000150
+#define XGMAC_MAC_FSM_CONTROL          0x00000158
+#define XGMAC_PRTYEN                   BIT(1)
+#define XGMAC_TMOUTEN                  BIT(0)
+#define XGMAC_FPE_CTRL_STS             0x00000280
+#define XGMAC_EFPE                     BIT(0)
+#define XGMAC_ADDRx_HIGH(x)            (0x00000300 + (x) * 0x8)
+#define XGMAC_ADDR_MAX                 32
+#define XGMAC_AE                       BIT(31)
+#define XGMAC_DCS                      GENMASK(19, 16)
+#define XGMAC_DCS_SHIFT                        16
+#define XGMAC_ADDRx_LOW(x)             (0x00000304 + (x) * 0x8)
+#define XGMAC_L3L4_ADDR_CTRL           0x00000c00
+#define XGMAC_IDDR                     GENMASK(15, 8)
+#define XGMAC_IDDR_SHIFT               8
+#define XGMAC_IDDR_FNUM                        4
+#define XGMAC_TT                       BIT(1)
+#define XGMAC_XB                       BIT(0)
+#define XGMAC_L3L4_DATA                        0x00000c04
+#define XGMAC_L3L4_CTRL                        0x0
+#define XGMAC_L4DPIM0                  BIT(21)
+#define XGMAC_L4DPM0                   BIT(20)
+#define XGMAC_L4SPIM0                  BIT(19)
+#define XGMAC_L4SPM0                   BIT(18)
+#define XGMAC_L4PEN0                   BIT(16)
+#define XGMAC_L3HDBM0                  GENMASK(15, 11)
+#define XGMAC_L3HSBM0                  GENMASK(10, 6)
+#define XGMAC_L3DAIM0                  BIT(5)
+#define XGMAC_L3DAM0                   BIT(4)
+#define XGMAC_L3SAIM0                  BIT(3)
+#define XGMAC_L3SAM0                   BIT(2)
+#define XGMAC_L3PEN0                   BIT(0)
+#define XGMAC_L4_ADDR                  0x1
+#define XGMAC_L4DP0                    GENMASK(31, 16)
+#define XGMAC_L4DP0_SHIFT              16
+#define XGMAC_L4SP0                    GENMASK(15, 0)
+#define XGMAC_L3_ADDR0                 0x4
+#define XGMAC_L3_ADDR1                 0x5
+#define XGMAC_L3_ADDR2                 0x6
+#define XGMAC_L3_ADDR3                 0x7
+#define XGMAC_ARP_ADDR                 0x00000c10
+#define XGMAC_RSS_CTRL                 0x00000c80
+#define XGMAC_UDP4TE                   BIT(3)
+#define XGMAC_TCP4TE                   BIT(2)
+#define XGMAC_IP2TE                    BIT(1)
+#define XGMAC_RSSE                     BIT(0)
+#define XGMAC_RSS_ADDR                 0x00000c88
+#define XGMAC_RSSIA_SHIFT              8
+#define XGMAC_ADDRT                    BIT(2)
+#define XGMAC_CT                       BIT(1)
+#define XGMAC_OB                       BIT(0)
+#define XGMAC_RSS_DATA                 0x00000c8c
+#define XGMAC_TIMESTAMP_STATUS         0x00000d20
+#define XGMAC_TXTSC                    BIT(15)
+#define XGMAC_TXTIMESTAMP_NSEC         0x00000d30
+#define XGMAC_TXTSSTSLO                        GENMASK(30, 0)
+#define XGMAC_TXTIMESTAMP_SEC          0x00000d34
+#define XGMAC_PPS_CONTROL              0x00000d70
+#define XGMAC_PPS_MAXIDX(x)            ((((x) + 1) * 8) - 1)
+#define XGMAC_PPS_MINIDX(x)            ((x) * 8)
+#define XGMAC_PPSx_MASK(x)             \
+       GENMASK(XGMAC_PPS_MAXIDX(x), XGMAC_PPS_MINIDX(x))
+#define XGMAC_TRGTMODSELx(x, val)      \
+       GENMASK(XGMAC_PPS_MAXIDX(x) - 1, XGMAC_PPS_MAXIDX(x) - 2) & \
+       ((val) << (XGMAC_PPS_MAXIDX(x) - 2))
+#define XGMAC_PPSCMDx(x, val)          \
+       GENMASK(XGMAC_PPS_MINIDX(x) + 3, XGMAC_PPS_MINIDX(x)) & \
+       ((val) << XGMAC_PPS_MINIDX(x))
+#define XGMAC_PPSCMD_START             0x2
+#define XGMAC_PPSCMD_STOP              0x5
+#define XGMAC_PPSEN0                   BIT(4)
+#define XGMAC_PPSx_TARGET_TIME_SEC(x)  (0x00000d80 + (x) * 0x10)
+#define XGMAC_PPSx_TARGET_TIME_NSEC(x) (0x00000d84 + (x) * 0x10)
+#define XGMAC_TRGTBUSY0                        BIT(31)
+#define XGMAC_PPSx_INTERVAL(x)         (0x00000d88 + (x) * 0x10)
+#define XGMAC_PPSx_WIDTH(x)            (0x00000d8c + (x) * 0x10)
+
+#define XGMAC_MDIO_ADDR                        0x00000200
+#define XGMAC_MDIO_DATA                        0x00000204
+#define XGMAC_MDIO_INT_STATUS          0x00000214
+#define XGMAC_MDIO_INT_EN              0x00000218
+#define XGMAC_MDIO_INT_EN_SINGLE       BIT(12)
+#define XGMAC_MDIO_C22P                        0x00000220
+
+/* MDIO defines */
+#define MII_GMAC_PA                    GENMASK(15, 11)
+#define MII_GMAC_RA                    GENMASK(10, 6)
+#define MII_GMAC_CR                    GENMASK(5, 2)
+#define MII_GMAC_WRITE                 BIT(1)
+#define MII_GMAC_BUSY                  BIT(0)
+#define MII_DATA_MASK                  GENMASK(15, 0)
+#define MII_XGMAC_DA                   GENMASK(25, 21)
+#define MII_XGMAC_PA                   GENMASK(20, 16)
+#define MII_XGMAC_RA                   GENMASK(15, 0)
+#define MII_XGMAC_BUSY                 BIT(22)
+#define MII_XGMAC_CR                   GENMASK(21, 19)
+#define MII_XGMAC_SADDR                        BIT(18)
+#define MII_XGMAC_CMD_SHIFT            16
+#define MII_XGMAC_WRITE                        (1 << MII_XGMAC_CMD_SHIFT)
+#define MII_XGMAC_READ                 (3 << MII_XGMAC_CMD_SHIFT)
+#define MII_XGMAC_PSE                  BIT(30)
+#define MII_XGMAC_CRS                  BIT(31)
+
+/* XGMAC MMC Registers */
+#define MMC_XGMAC_CONTROL              0x800
+#define MMC_XGMAC_CONTROL_RSTONRD      BIT(2)
+#define MMC_XGMAC_CONTROL_RESET                BIT(0)
+#define MMC_XGMAC_RX_INT_EN            0x80c
+#define MMC_XGMAC_TX_INT_EN            0x810
+
+#define MMC_XGMAC_TX_OCTET_GB          0x814
+#define MMC_XGMAC_TX_PKT_GB            0x81c
+#define MMC_XGMAC_TX_BROAD_PKT_G       0x824
+#define MMC_XGMAC_TX_MULTI_PKT_G       0x82c
+#define MMC_XGMAC_TX_64OCT_GB          0x834
+#define MMC_XGMAC_TX_65OCT_GB          0x83c
+#define MMC_XGMAC_TX_128OCT_GB         0x844
+#define MMC_XGMAC_TX_256OCT_GB         0x84c
+#define MMC_XGMAC_TX_512OCT_GB         0x854
+#define MMC_XGMAC_TX_1024OCT_GB                0x85c
+#define MMC_XGMAC_TX_UNI_PKT_GB                0x864
+#define MMC_XGMAC_TX_MULTI_PKT_GB      0x86c
+#define MMC_XGMAC_TX_BROAD_PKT_GB      0x874
+#define MMC_XGMAC_TX_UNDER             0x87c
+#define MMC_XGMAC_TX_OCTET_G           0x884
+#define MMC_XGMAC_TX_PKT_G             0x88c
+#define MMC_XGMAC_TX_PAUSE             0x894
+#define MMC_XGMAC_TX_VLAN_PKT_G                0x89c
+#define MMC_XGMAC_TX_LPI_USEC          0x8a4
+#define MMC_XGMAC_TX_LPI_TRAN          0x8a8
+
+#define MMC_XGMAC_RX_PKT_GB            0x900
+#define MMC_XGMAC_RX_OCTET_GB          0x908
+#define MMC_XGMAC_RX_OCTET_G           0x910
+#define MMC_XGMAC_RX_BROAD_PKT_G       0x918
+#define MMC_XGMAC_RX_MULTI_PKT_G       0x920
+#define MMC_XGMAC_RX_CRC_ERR           0x928
+#define MMC_XGMAC_RX_RUNT_ERR          0x930
+#define MMC_XGMAC_RX_JABBER_ERR                0x934
+#define MMC_XGMAC_RX_UNDER             0x938
+#define MMC_XGMAC_RX_OVER              0x93c
+#define MMC_XGMAC_RX_64OCT_GB          0x940
+#define MMC_XGMAC_RX_65OCT_GB          0x948
+#define MMC_XGMAC_RX_128OCT_GB         0x950
+#define MMC_XGMAC_RX_256OCT_GB         0x958
+#define MMC_XGMAC_RX_512OCT_GB         0x960
+#define MMC_XGMAC_RX_1024OCT_GB                0x968
+#define MMC_XGMAC_RX_UNI_PKT_G         0x970
+#define MMC_XGMAC_RX_LENGTH_ERR                0x978
+#define MMC_XGMAC_RX_RANGE             0x980
+#define MMC_XGMAC_RX_PAUSE             0x988
+#define MMC_XGMAC_RX_FIFOOVER_PKT      0x990
+#define MMC_XGMAC_RX_VLAN_PKT_GB       0x998
+#define MMC_XGMAC_RX_WATCHDOG_ERR      0x9a0
+#define MMC_XGMAC_RX_LPI_USEC          0x9a4
+#define MMC_XGMAC_RX_LPI_TRAN          0x9a8
+#define MMC_XGMAC_RX_DISCARD_PKT_GB    0x9ac
+#define MMC_XGMAC_RX_DISCARD_OCT_GB    0x9b4
+#define MMC_XGMAC_RX_ALIGN_ERR_PKT     0x9bc
+
+#define MMC_XGMAC_TX_SINGLE_COL_G      0xa40
+#define MMC_XGMAC_TX_MULTI_COL_G       0xa44
+#define MMC_XGMAC_TX_DEFER             0xa48
+#define MMC_XGMAC_TX_LATE_COL          0xa4c
+#define MMC_XGMAC_TX_EXCESSIVE_COL     0xa50
+#define MMC_XGMAC_TX_CARRIER           0xa54
+#define MMC_XGMAC_TX_EXCESSIVE_DEFER   0xa58
+
+#define MMC_XGMAC_RX_IPC_INTR_MASK     0xa5c
+
+#define MMC_XGMAC_RX_IPV4_PKT_G                0xa64
+#define MMC_XGMAC_RX_IPV4_HDRERR_PKT   0xa6c
+#define MMC_XGMAC_RX_IPV4_NOPAY_PKT    0xa74
+#define MMC_XGMAC_RX_IPV4_FRAG_PKT     0xa7c
+#define MMC_XGMAC_RX_IPV4_UDSBL_PKT    0xa84
+#define MMC_XGMAC_RX_IPV6_PKT_G                0xa8c
+#define MMC_XGMAC_RX_IPV6_HDRERR_PKT   0xa94
+#define MMC_XGMAC_RX_IPV6_NOPAY_PKT    0xa9c
+#define MMC_XGMAC_RX_UDP_PKT_G         0xaa4
+#define MMC_XGMAC_RX_UDP_ERR_PKT       0xaac
+#define MMC_XGMAC_RX_TCP_PKT_G         0xab4
+#define MMC_XGMAC_RX_TCP_ERR_PKT       0xabc
+#define MMC_XGMAC_RX_ICMP_PKT_G                0xac4
+#define MMC_XGMAC_RX_ICMP_ERR_PKT      0xacc
+#define MMC_XGMAC_RX_IPV4_OCTET_G      0xad4
+#define MMC_XGMAC_RX_IPV4_HDRERR_OCTET 0xadc
+#define MMC_XGMAC_RX_IPV4_NOPAY_OCTET  0xae4
+#define MMC_XGMAC_RX_IPV4_FRAG_OCTET   0xaec
+#define MMC_XGMAC_RX_IPV4_UDSBL_OCTET  0xaf4
+#define MMC_XGMAC_RX_IPV6_OCTET_G      0xafc
+#define MMC_XGMAC_RX_IPV6_HDRERR_OCTET 0xb04
+#define MMC_XGMAC_RX_IPV6_NOPAY_OCTET  0xb0c
+#define MMC_XGMAC_RX_UDP_OCTET_G       0xb14
+#define MMC_XGMAC_RX_UDP_ERR_OCTET     0xb1c
+#define MMC_XGMAC_RX_TCP_OCTET_G       0xb24
+#define MMC_XGMAC_RX_TCP_ERR_OCTET     0xb2c
+#define MMC_XGMAC_RX_ICMP_OCTET_G      0xb34
+#define MMC_XGMAC_RX_ICMP_ERR_OCTET    0xb3c
+
+/* MTL Registers */
+#define XGMAC_MTL_OPMODE               0x00001000
+#define XGMAC_FRPE                     BIT(15)
+#define XGMAC_ETSALG                   GENMASK(6, 5)
+#define XGMAC_WRR                      (0x0 << 5)
+#define XGMAC_WFQ                      (0x1 << 5)
+#define XGMAC_DWRR                     (0x2 << 5)
+#define XGMAC_RAA                      BIT(2)
+#define XGMAC_FTS                      BIT(1)
+#define XGMAC_MTL_INT_STATUS           0x00001020
+#define XGMAC_MTL_RXQ_DMA_MAP0         0x00001030
+#define XGMAC_MTL_RXQ_DMA_MAP1         0x00001034
+#define XGMAC_QxMDMACH(x)              GENMASK((x) * 8 + 7, (x) * 8)
+#define XGMAC_QxMDMACH_SHIFT(x)                ((x) * 8)
+#define XGMAC_QDDMACH                  BIT(7)
+#define XGMAC_TC_PRTY_MAP0             0x00001040
+#define XGMAC_TC_PRTY_MAP1             0x00001044
+#define XGMAC_PSTC(x)                  GENMASK((x) * 8 + 7, (x) * 8)
+#define XGMAC_PSTC_SHIFT(x)            ((x) * 8)
+#define XGMAC_MTL_EST_CONTROL          0x00001050
+#define XGMAC_PTOV                     GENMASK(31, 23)
+#define XGMAC_PTOV_SHIFT               23
+#define XGMAC_SSWL                     BIT(1)
+#define XGMAC_EEST                     BIT(0)
+#define XGMAC_MTL_EST_GCL_CONTROL      0x00001080
+#define XGMAC_BTR_LOW                  0x0
+#define XGMAC_BTR_HIGH                 0x1
+#define XGMAC_CTR_LOW                  0x2
+#define XGMAC_CTR_HIGH                 0x3
+#define XGMAC_TER                      0x4
+#define XGMAC_LLR                      0x5
+#define XGMAC_ADDR_SHIFT               8
+#define XGMAC_GCRR                     BIT(2)
+#define XGMAC_SRWO                     BIT(0)
+#define XGMAC_MTL_EST_GCL_DATA         0x00001084
+#define XGMAC_MTL_RXP_CONTROL_STATUS   0x000010a0
+#define XGMAC_RXPI                     BIT(31)
+#define XGMAC_NPE                      GENMASK(23, 16)
+#define XGMAC_NVE                      GENMASK(7, 0)
+#define XGMAC_MTL_RXP_IACC_CTRL_ST     0x000010b0
+#define XGMAC_STARTBUSY                        BIT(31)
+#define XGMAC_WRRDN                    BIT(16)
+#define XGMAC_ADDR                     GENMASK(9, 0)
+#define XGMAC_MTL_RXP_IACC_DATA                0x000010b4
+#define XGMAC_MTL_ECC_CONTROL          0x000010c0
+#define XGMAC_MTL_SAFETY_INT_STATUS    0x000010c4
+#define XGMAC_MEUIS                    BIT(1)
+#define XGMAC_MECIS                    BIT(0)
+#define XGMAC_MTL_ECC_INT_ENABLE       0x000010c8
+#define XGMAC_RPCEIE                   BIT(12)
+#define XGMAC_ECEIE                    BIT(8)
+#define XGMAC_RXCEIE                   BIT(4)
+#define XGMAC_TXCEIE                   BIT(0)
+#define XGMAC_MTL_ECC_INT_STATUS       0x000010cc
+#define XGMAC_MTL_TXQ_OPMODE(x)                (0x00001100 + 0x80 * (x))
+#define XGMAC_TQS                      GENMASK(25, 16)
+#define XGMAC_TQS_SHIFT                        16
+#define XGMAC_Q2TCMAP                  GENMASK(10, 8)
+#define XGMAC_Q2TCMAP_SHIFT            8
+#define XGMAC_TTC                      GENMASK(6, 4)
+#define XGMAC_TTC_SHIFT                        4
+#define XGMAC_TXQEN                    GENMASK(3, 2)
+#define XGMAC_TXQEN_SHIFT              2
+#define XGMAC_TSF                      BIT(1)
+#define XGMAC_FTQ                      BIT(0)
+#define XGMAC_MTL_TXQ_DEBUG(x)         (0x00001108 + 0x80 * (x))
+#define XGMAC_TRCPSTS                  BIT(5)
+#define XGMAC_TXQSTS                   BIT(4)
+#define XGMAC_TWCSTS                   BIT(3)
+#define XGMAC_TRCSTS                   GENMASK(2, 1)
+#define XGMAC_TCPAUSED                 BIT(0)
+#define XGMAC_MTL_TCx_ETS_CONTROL(x)   (0x00001110 + 0x80 * (x))
+#define XGMAC_MTL_TCx_QUANTUM_WEIGHT(x)        (0x00001118 + 0x80 * (x))
+#define XGMAC_MTL_TCx_SENDSLOPE(x)     (0x0000111c + 0x80 * (x))
+#define XGMAC_MTL_TCx_HICREDIT(x)      (0x00001120 + 0x80 * (x))
+#define XGMAC_MTL_TCx_LOCREDIT(x)      (0x00001124 + 0x80 * (x))
+#define XGMAC_CC                       BIT(3)
+#define XGMAC_TSA                      GENMASK(1, 0)
+#define XGMAC_SP                       (0x0 << 0)
+#define XGMAC_CBS                      (0x1 << 0)
+#define XGMAC_ETS                      (0x2 << 0)
+#define XGMAC_MTL_RXQ_OPMODE(x)                (0x00001140 + 0x80 * (x))
+#define XGMAC_RQS                      GENMASK(25, 16)
+#define XGMAC_RQS_SHIFT                        16
+#define XGMAC_EHFC                     BIT(7)
+#define XGMAC_RSF                      BIT(5)
+#define XGMAC_RTC                      GENMASK(1, 0)
+#define XGMAC_RTC_SHIFT                        0
+#define XGMAC_MTL_RXQ_OVF_CNT(x)               (0x00001144 + 0x80 * (x))
+#define XGMAC_MISCNTOVF                        BIT(31)
+#define XGMAC_MISPKTCNT                        GENMASK(26, 16)
+#define XGMAC_OVFCNTOVF                        BIT(15)
+#define XGMAC_OVFPKTCNT                        GENMASK(10, 0)
+#define XGMAC_MTL_RXQ_DEBUG(x)                 (0x00001148 + 0x80 * (x))
+#define XGMAC_PRXQ                             GENMASK(29, 16)
+#define XGMAC_RXQSTS                   GENMASK(5, 4)
+#define XGMAC_RRCSTS                   GENMASK(2, 1)
+#define XGMAC_RWCSTS                   BIT(0)
+#define XGMAC_MTL_RXQ_FLOW_CONTROL(x)  (0x00001150 + 0x80 * (x))
+#define XGMAC_RFD                      GENMASK(31, 17)
+#define XGMAC_RFD_SHIFT                        17
+#define XGMAC_RFA                      GENMASK(15, 1)
+#define XGMAC_RFA_SHIFT                        1
+#define XGMAC_MTL_QINTEN(x)            (0x00001170 + 0x80 * (x))
+#define XGMAC_RXOIE                    BIT(16)
+#define XGMAC_MTL_QINT_STATUS(x)       (0x00001174 + 0x80 * (x))
+#define XGMAC_RXOVFIS                  BIT(16)
+#define XGMAC_ABPSIS                   BIT(1)
+#define XGMAC_TXUNFIS                  BIT(0)
+#define XGMAC_MAC_REGSIZE              (XGMAC_MTL_QINT_STATUS(15) / 4)
+
+#define XGMAC_DMA_MODE                 0x00003000
+#define XGMAC_INTM                     GENMASK(13, 12)
+#define XGMAC_SWR                      BIT(0)
+#define XGMAC_DMA_SYSBUS_MODE          0x00003004
+#define XGMAC_WR_OSR_LMT               GENMASK(29, 24)
+#define XGMAC_WR_OSR_LMT_SHIFT         24
+#define XGMAC_RD_OSR_LMT               GENMASK(21, 16)
+#define XGMAC_RD_OSR_LMT_SHIFT         16
+#define XGMAC_EN_LPI                   BIT(15)
+#define XGMAC_LPI_XIT_PKT              BIT(14)
+#define XGMAC_AAL                      BIT(12)
+#define XGMAC_EAME                     BIT(11)
+#define XGMAC_BLEN                     GENMASK(7, 1)
+#define XGMAC_BLEN256                  BIT(7)
+#define XGMAC_BLEN128                  BIT(6)
+#define XGMAC_BLEN64                   BIT(5)
+#define XGMAC_BLEN32                   BIT(4)
+#define XGMAC_BLEN16                   BIT(3)
+#define XGMAC_BLEN8                    BIT(2)
+#define XGMAC_BLEN4                    BIT(1)
+#define XGMAC_UNDEF                    BIT(0)
+#define XGMAC_DMA_INT_STATUS           0x00003008
+#define XGMAC_MTLIS                    BIT(16)
+#define XGMAC_DMA_DEBUG_STATUS(x)      (0x00003020 + 4 * (x))
+#define XGMAC_DMA_DBG_STS3_RDAS                        BIT(0)
+#define XGMAC_DMA_DBG_STS1_TDAS                        BIT(0)
+#define XGMAC_TX_EDMA_CTRL             0x00003040
+#define XGMAC_TEDM                     GENMASK(31, 30)
+#define XGMAC_TDPS                     GENMASK(29, 0)
+#define XGMAC_RX_EDMA_CTRL             0x00003044
+#define XGMAC_REDM                     GENMASK(31, 30)
+#define XGMAC_RDPS                     GENMASK(29, 0)
+#define XGMAC_DMA_TBS_CTRL0            0x00003054
+#define XGMAC_DMA_TBS_CTRL1            0x00003058
+#define XGMAC_DMA_TBS_CTRL2            0x0000305c
+#define XGMAC_DMA_TBS_CTRL3            0x00003060
+#define XGMAC_FTOS                     GENMASK(31, 8)
+#define XGMAC_FTOV                     BIT(0)
+#define XGMAC_DEF_FTOS                 (XGMAC_FTOS | XGMAC_FTOV)
+#define XGMAC_DMA_SAFETY_INT_STATUS    0x00003064
+#define XGMAC_MCSIS                    BIT(31)
+#define XGMAC_MSUIS                    BIT(29)
+#define XGMAC_MSCIS                    BIT(28)
+#define XGMAC_DEUIS                    BIT(1)
+#define XGMAC_DECIS                    BIT(0)
+#define XGMAC_DMA_ECC_INT_ENABLE       0x00003068
+#define XGMAC_DCEIE                    BIT(1)
+#define XGMAC_TCEIE                    BIT(0)
+#define XGMAC_DMA_ECC_INT_STATUS       0x0000306c
+#define XGMAC_DMA_CH_CONTROL(x)                (0x00003100 + 0x80 * (x))
+#define XGMAC_SPH                      BIT(24)
+#define XGMAC_PBLx8                    BIT(16)
+#define XGMAC_DMA_CH_TX_CONTROL(x)     (0x00003104 + 0x80 * (x))
+#define XGMAC_EDSE                     BIT(28)
+#define XGMAC_TxPBL                    GENMASK(21, 16)
+#define XGMAC_TxPBL_SHIFT              16
+#define XGMAC_TSE                      BIT(12)
+#define XGMAC_OSP                      BIT(4)
+#define XGMAC_TXST                     BIT(0)
+#define XGMAC_DMA_CH_RX_CONTROL(x)     (0x00003108 + 0x80 * (x))
+#define XGMAC_RPF                      BIT(31)
+#define XGMAC_RxPBL                    GENMASK(21, 16)
+#define XGMAC_RxPBL_SHIFT              16
+#define XGMAC_RBSZ                     GENMASK(14, 1)
+#define XGMAC_RBSZ_SHIFT               1
+#define XGMAC_RXST                     BIT(0)
+#define XGMAC_DMA_CH_TxDESC_LADDR(x)   (0x00003114 + 0x80 * (x))
+#define XGMAC_DMA_CH_RxDESC_LADDR(x)   (0x0000311c + 0x80 * (x))
+#define XGMAC_DMA_CH_TxDESC_TAIL_LPTR(x)       (0x00003124 + 0x80 * (x))
+#define XGMAC_DMA_CH_RxDESC_TAIL_LPTR(x)       (0x0000312c + 0x80 * (x))
+#define XGMAC_DMA_CH_TxDESC_RING_LEN(x)                (0x00003130 + 0x80 * (x))
+#define XGMAC_DMA_CH_RxDESC_RING_LEN(x)                (0x00003134 + 0x80 * (x))
+#define XGMAC_OWRQ                     GENMASK(26, 24)
+#define XGMAC_DMA_CH_INT_EN(x)         (0x00003138 + 0x80 * (x))
+#define XGMAC_NIE                      BIT(15)
+#define XGMAC_AIE                      BIT(14)
+#define XGMAC_CDEE                     BIT(13)
+#define XGMAC_FBEE                     BIT(12)
+#define XGMAC_DDEE                     BIT(9)
+#define XGMAC_RSE                      BIT(8)
+#define XGMAC_RBUE                     BIT(7)
+#define XGMAC_RIE                      BIT(6)
+#define XGMAC_TBUE                     BIT(2)
+#define XGMAC_TXSE                     BIT(1)
+#define XGMAC_TIE                      BIT(0)
+#define XGMAC_DMA_INT_DEFAULT_EN       (XGMAC_DMA_INT_NORMAL_EN | \
+                               XGMAC_DMA_INT_ABNORMAL_EN)
+#define XGMAC_DMA_INT_NORMAL_EN                (XGMAC_NIE | XGMAC_TIE | XGMAC_RIE)
+#define XGMAC_DMA_INT_ABNORMAL_EN      (XGMAC_AIE | XGMAC_RBUE | XGMAC_CDEE | XGMAC_DDEE | XGMAC_FBEE)
+#define XGMAC_DMA_CH_Rx_WATCHDOG(x)    (0x0000313c + 0x80 * (x))
+#define XGMAC_PSEL                     BIT(31)
+#define XGMAC_RBCT                     GENMASK(25, 16)
+#define XGMAC_RWTU                     GENMASK(13, 12)
+#define XGMAC_RWT                      GENMASK(7, 0)
+#define XGMAC_DMA_CH_CUR_TxDESC_LADDR(x)       (0x00003144 + 0x80 * (x))
+#define XGMAC_DMA_CH_CUR_RxDESC_LADDR(x)       (0x0000314c + 0x80 * (x))
+#define XGMAC_DMA_CH_CUR_TxBUFF_LADDR(x)       (0x00003154 + 0x80 * (x))
+#define XGMAC_DMA_CH_CUR_RxBUFF_LADDR(x)       (0x0000315c + 0x80 * (x))
+#define XGMAC_DMA_CH_STATUS(x)         (0x00003160 + 0x80 * (x))
+#define XGMAC_NIS                      BIT(15)
+#define XGMAC_AIS                      BIT(14)
+#define XGMAC_CDE                      BIT(13)
+#define XGMAC_FBE                      BIT(12)
+#define XGMAC_DDE                      BIT(9)
+#define XGMAC_RPS                      BIT(8)
+#define XGMAC_RBU                      BIT(7)
+#define XGMAC_RI                       BIT(6)
+#define XGMAC_TBU                      BIT(2)
+#define XGMAC_TPS                      BIT(1)
+#define XGMAC_TI                       BIT(0)
+#define XGMAC_DMA_CH_DEBUG_STATUS(x)   (0x00003164 + 0x80 * (x))
+#define XGMAC_RDTS                     GENMASK(27, 19)
+#define XGMAC_RDFS                     GENMASK(18, 16)
+#define XGMAC_TDTS                     GENMASK(11, 8)
+#define XGMAC_TDRS                     GENMASK(7, 6)
+#define XGMAC_TDXS                     GENMASK(5, 3)
+#define XGMAC_TDFS                     GENMASK(2, 0)
+#define XGMAC_REGSIZE                  ((0x0000317c + (0x80 * 15)) / 4)
+
+#define XGMAC_DMA_STATUS_MSK_COMMON    (XGMAC_NIS | XGMAC_AIS | XGMAC_FBE)
+#define XGMAC_DMA_STATUS_MSK_RX                (XGMAC_RBU | XGMAC_RI | \
+                                        XGMAC_DMA_STATUS_MSK_COMMON)
+#define XGMAC_DMA_STATUS_MSK_TX                (XGMAC_TBU | XGMAC_TPS | XGMAC_TI | \
+                                        XGMAC_DMA_STATUS_MSK_COMMON)
+
+/* Descriptors */
+#define XGMAC_TDES0_LTV                        BIT(31)
+#define XGMAC_TDES0_LT                 GENMASK(7, 0)
+#define XGMAC_TDES1_LT                 GENMASK(31, 8)
+#define XGMAC_TDES2_IVT                        GENMASK(31, 16)
+#define XGMAC_TDES2_IVT_SHIFT          16
+#define XGMAC_TDES2_IOC                        BIT(31)
+#define XGMAC_TDES2_TTSE               BIT(30)
+#define XGMAC_TDES2_B2L                        GENMASK(29, 16)
+#define XGMAC_TDES2_B2L_SHIFT          16
+#define XGMAC_TDES2_VTIR               GENMASK(15, 14)
+#define XGMAC_TDES2_VTIR_SHIFT         14
+#define XGMAC_TDES2_B1L                        GENMASK(13, 0)
+#define XGMAC_TDES3_OWN                        BIT(31)
+#define XGMAC_TDES3_CTXT               BIT(30)
+#define XGMAC_TDES3_FD                 BIT(29)
+#define XGMAC_TDES3_LD                 BIT(28)
+#define XGMAC_TDES3_CPC                        GENMASK(27, 26)
+#define XGMAC_TDES3_CPC_SHIFT          26
+#define XGMAC_TDES3_TCMSSV             BIT(26)
+#define XGMAC_TDES3_SAIC               GENMASK(25, 23)
+#define XGMAC_TDES3_SAIC_SHIFT         23
+#define XGMAC_TDES3_TBSV               BIT(24)
+#define XGMAC_TDES3_THL                        GENMASK(22, 19)
+#define XGMAC_TDES3_THL_SHIFT          19
+#define XGMAC_TDES3_IVTIR              GENMASK(19, 18)
+#define XGMAC_TDES3_IVTIR_SHIFT                18
+#define XGMAC_TDES3_TSE                        BIT(18)
+#define XGMAC_TDES3_IVLTV              BIT(17)
+#define XGMAC_TDES3_CIC                        GENMASK(17, 16)
+#define XGMAC_TDES3_CIC_SHIFT          16
+#define XGMAC_TDES3_TPL                        GENMASK(17, 0)
+#define XGMAC_TDES3_VLTV               BIT(16)
+#define XGMAC_TDES3_VT                 GENMASK(15, 0)
+#define XGMAC_TDES3_FL                 GENMASK(14, 0)
+#define XGMAC_TDES3_PIDV               BIT(25)
+#define XGMAC_TDES0_QUEUE_ID   GENMASK(19, 17)
+#define XGMAC_TDES0_FAST_MODE  BIT(16)
+#define XGMAC_TDES0_OVPORT             GENMASK(12, 8)
+#define XGMAC_TDES0_IVPORT             GENMASK(4, 0)
+
+
+#define XGMAC_RDES0_IP_FRAG    GENMASK(31, 30)
+enum {
+       FRAG_NONE,
+       FRAG_FIRST,
+       FRAG_MIDDLE,
+       FRAG_LAST,
+};
+#define XGMAC_RDES0_L3_TYPE            GENMASK(29, 28)
+enum {
+       L3_TYPE_IPV4,
+       L3_TYPE_IPV6,
+       L3_TYPE_IPIP6,
+       L3_TYPE_UNKNOWN,
+};
+#define XGMAC_RDES0_L4_TYPE            GENMASK(27, 26)
+enum {
+       L4_TYPE_TCP,
+       L4_TYPE_UDP,
+       L4_TYPE_ICMP,
+       L4_TYPE_UNKNOWN,
+};
+#define XGMAC_RDES0_RPT_INDEX  GENMASK(25, 22)
+#define XGMAC_RDES0_STA_INDEX  GENMASK(21, 12)
+#define XGMAC_RDES0_OVPORT     GENMASK(11, 6)
+#define XGMAC_RDES0_IVPORT     GENMASK(5, 0)
+#define XGMAC_RDES2_DFRAG              BIT(31)
+#define XGMAC_RDES2_OVID               GENMASK(27, 16)
+#define XGMAC_RDES3_OWN                        BIT(31)
+#define XGMAC_RDES3_CTXT               BIT(30)
+#define XGMAC_RDES3_FD                 BIT(29)
+#define XGMAC_RDES3_LD                 BIT(28)
+#define XGMAC_RDES3_CDA                        BIT(27)
+#define XGMAC_RDES3_RSV                        BIT(26)
+#define XGMAC_RDES3_TCI_PRI            GENMASK(22, 20)
+#define XGMAC_RDES3_ET                 GENMASK(19, 16)
+#define XGMAC_RDES3_ES                 BIT(15)
+#define XGMAC_RDES3_PL                 GENMASK(13, 0)
+
+#define XGMAC_RDES0_SPORT      GENMASK(31, 16)
+#define XGMAC_RDES0_ETH_TYPE   GENMASK(15, 0)
+#define XGMAC_RDES1_UP_REASON   GENMASK(31, 24)
+#define XGMAC_RDES1_RXHASH      GENMASK(23, 8)
+#define XGMAC_RDES1_TNP        BIT(6)
+#define XGMAC_RDES1_DSCP        GENMASK(5, 0)
+#define XGMAC_RDES2_SMAC_0_31   GENMASK(31, 0)
+#define XGMAC_RDES3_SMAC_32_47  GENMASK(15, 0)
+#define XGMAC_RDES3_PKT_TYPE    GENMASK(17, 16)
+enum {
+       PKT_TYPE_UCAST,
+       PKT_TYPE_MCAST,
+       PKT_TYPE_UNKNOWN,
+       PKT_TYPE_BCAST,
+};
+#define XGMAC_RDES3_IOC                        BIT(30)
+
+#endif
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns.c
new file mode 100644 (file)
index 0000000..092c7d4
--- /dev/null
@@ -0,0 +1,77 @@
+#include "linux/delay.h"
+#include "linux/reset.h"
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include "dpns.h"
+
+
+
+static int dpns_probe(struct platform_device *pdev)
+{
+       struct dpns_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+       priv->dev = &pdev->dev;
+       priv->ioaddr = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->ioaddr))
+               return PTR_ERR(priv->ioaddr);
+
+       priv->clk = devm_clk_get_enabled(priv->dev, NULL);
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       priv->npu_rst = devm_reset_control_get_exclusive(priv->dev, "npu");
+       if (IS_ERR(priv->npu_rst))
+               return PTR_ERR(priv->npu_rst);
+
+       reset_control_assert(priv->npu_rst);
+       reset_control_deassert(priv->npu_rst);
+
+       ret = dpns_se_init(priv);
+       if (ret)
+               return dev_err_probe(priv->dev, ret, "failed to initialize SE.\n");
+
+       ret = dpns_tmu_init(priv);
+       if (ret)
+               return dev_err_probe(priv->dev, ret, "failed to initialize TMU.\n");
+
+       sf_dpns_debugfs_init(priv);
+       platform_set_drvdata(pdev, priv);
+       return 0;
+}
+
+static int dpns_remove(struct platform_device *pdev) {
+       struct dpns_priv *priv = platform_get_drvdata(pdev);
+       debugfs_remove_recursive(priv->debugfs);
+       reset_control_assert(priv->npu_rst);
+       return 0;
+}
+
+static const struct of_device_id dpns_match[] = {
+       { .compatible = "siflower,sf21-dpns" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dpns_match);
+
+static struct platform_driver dpns_driver = {
+       .probe  = dpns_probe,
+       .remove = dpns_remove,
+       .driver = {
+               .name           = "sfdpns",
+               .of_match_table = dpns_match,
+       },
+};
+module_platform_driver(dpns_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Qingfang Deng <qingfang.deng@siflower.com.cn>");
+MODULE_DESCRIPTION("NPU stub driver for SF21A6826/SF21H8898 SoC");
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_debugfs.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_debugfs.c
new file mode 100644 (file)
index 0000000..d45dc0a
--- /dev/null
@@ -0,0 +1,427 @@
+#include <linux/debugfs.h>
+#include "dpns.h"
+#include "dma.h"
+
+static const char * const sf21_dpns_mib_name[] = {
+       "pkt_rcv_drop_port0",
+       "pkt_rcv_drop_port1",
+       "pkt_rcv_drop_port2",
+       "pkt_rcv_drop_port3",
+       "pkt_rcv_drop_port4",
+       "pkt_rcv_drop_port5",
+       "pkt_rcv_drop_port6",
+       "pkt_rcv_drop_spl0",
+       "pkt_rcv_drop_spl1",
+       "pkt_rcv_drop_spl2",
+       "pkt_rcv_drop_spl3",
+       "pkt_rcv_drop_spl4",
+       "pkt_rcv_drop_spl5",
+       "pkt_rcv_drop_spl6",
+       "pkt_rcv_trans_cnt0",
+       "pkt_rcv_trans_cnt1",
+       "pkt_rcv_trans_cnt2",
+       "pkt_rcv_trans_cnt3",
+       "pkt_rcv_trans_cnt4",
+       "pkt_rcv_trans_cnt5",
+       "pkt_rcv_trans_cnt6",
+       "pkt_rcv_total0",
+       "pkt_rcv_total1",
+       "pkt_rcv_total2",
+       "pkt_rcv_total3",
+       "pkt_rcv_total4",
+       "pkt_rcv_total5",
+       "pkt_rcv_total6",
+       "pkt_rcv",
+       "udp",
+       "tcp",
+       "ipv4",
+       "ipv6",
+       "icmpv4",
+       "icmpv6",
+       "other_protocol",
+       "ipv4_sip_eq_dip",
+       "ipv4_icmp_frag",
+       "ipv4_icmp_ping_too_big",
+       "ipv4_udp_sp_eq_dp",
+       "ipv4_tcp_flagchk_err",
+       "ipv4_tcp_sq_eq_dp",
+       "ipv4_tcp_frag_off1",
+       "ipv4_tcp_syn_err",
+       "ipv4_tcp_xmas",
+       "ipv4_tcp_null",
+       "ipv4_tcp_too_short",
+       "ipv4_icmp4_redirect",
+       "ipv4_icmp_smurf",
+       "ipv6_sip_eq_dip",
+       "ipv6_icmp_frag",
+       "ipv6_icmp_ping_too_big",
+       "ipv6_udp_sp_eq_dp",
+       "ipv6_tcp_flagchk_err",
+       "ipv6_tcp_sq_eq_dp",
+       "ipv6_tcp_frag_off1",
+       "ipv6_tcp_syn_err",
+       "ipv6_tcp_xmas",
+       "ipv6_tcp_null",
+       "ipv6_tcp_too_short",
+       "ipv6_icmp4_redirect",
+       "ipv6_icmp_smurf",
+       "ipv4in6_pls",
+       "frame_ismc_pls",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       "arp_reply_err_fwd",
+       "arp_req_err_fwd",
+       "pkt_len_less_l2hd_err_fwd",
+       "pkt_len_less_60B_err_fwd",
+       "smac_is_mc_err_fwd",
+       "smac_is_bc_err_fwd",
+       "smac_eq_dmac_err_fwd",
+       "smac_eq_zero_err_fwd",
+       "dmac_eq_zero_err_fwd",
+       "dribble_err_fwd",
+       "runt_err_fwd",
+       "giant_frame_err_fwd",
+       "watchdog_err_fwd",
+       "gmii_err_fwd",
+       "dos_err_fwd",
+       "ttl_err_fwd",
+       "payload_chksum_err_fwd",
+       "ip_version_err_fwd",
+       "ip_hd_chksum_err_fwd",
+       "crc_err_fwd",
+       "pkt_len_err_fwd",
+       "arp_reply_err_up",
+       "arp_req_err_up",
+       "pkt_len_less_l2hd_err_up",
+       "pkt_len_less_60B_err_up",
+       "smac_is_mc_err_up",
+       "smac_is_bc_err_up",
+       "smac_eq_dmac_err_up",
+       "smac_eq_zero_err_up",
+       "dmac_eq_zero_err_up",
+       "dribble_err_up",
+       "runt_err_up",
+       "giant_frame_err_up",
+       "watchdog_err_up",
+       "gmii_err_up",
+       "dos_err_up",
+       "ttl_err_up",
+       "payload_chksum_err_up",
+       "ip_version_err_up",
+       "ip_hd_chksum_err_up",
+       "crc_err_up",
+       "pkt_len_err_up",
+       "arp_reply_err_drop",
+       "arp_req_err_drop",
+       "pkt_len_less_l2hd_err_drop",
+       "pkt_len_less_60B_err_drop",
+       "smac_is_mc_err_drop",
+       "smac_is_bc_err_drop",
+       "smac_eq_dmac_err_drop",
+       "smac_eq_zero_err_drop",
+       "dmac_eq_zero_err_drop",
+       "dribble_err_drop",
+       "runt_err_drop",
+       "giant_frame_err_drop",
+       "watchdog_err_drop",
+       "gmii_err_drop",
+       "dos_err_drop",
+       "ttl_err_drop",
+       "payload_chksum_err_drop",
+       "ip_version_err_drop",
+       "ip_hd_chksum_err_drop",
+       "crc_err_drop",
+       "pkt_len_err_drop",
+       "ivlan_vid_input_mf",
+       "ivlan_vid_pass_mf",
+       "ivlan_vid_port_based_srch",
+       "ivlan_vid_xlt_srch",
+       "ivlan_vid_vfp_srch",
+       "ivlan_vid_port_based_resp",
+       "ivlan_vid_xlt_resp",
+       "ivlan_vid_vfp_resp",
+       "ivlan_vid_port_based_hit",
+       "ivlan_vid_xlt_hit",
+       "ivlan_vid_vfp_hit",
+       "ivlan_vid_output_mf",
+       "ivlan_vid_port_based_pass",
+       "ivlan_vid_cp_drop",
+       "ivlan_vid_cp_up",
+       "ivlan_lkp_input_mf",
+       "ivlan_lkp_pass_mf",
+       "ivlan_lkp_srch",
+       "ivlan_lkp_resp",
+       "ivlan_lkp_hit",
+       "ivlan_lkp_output_mf",
+       "ivlan_lkp_cp_drop",
+       "ivlan_lkp_cp_up",
+       "l2_input_mf",
+       "l2_pass_mf",
+       "l2_flood_spl_srch_cnt",
+       "l2_da_srch",
+       "l2_sa_srch",
+       "l2_flood_spl_resp_cnt",
+       "l2_da_resp",
+       "l2_sa_resp",
+       "l2_flood_spl_cnt",
+       "l2_da_hit",
+       "l2_sa_hit",
+       "l2_output_mf",
+       "l2_cp_drop",
+       "l2_cp_up",
+       "l2_cp_fwd",
+       "l2_cp_up_fwd",
+       "nat_input_mf",
+       "nat_pass_mf",
+       "nat_srch",
+       "nat_resp",
+       "nat_hit",
+       "nat_output_mf",
+       "nat_v4_search",
+       "nat_dnat",
+       "nat_v4_hit",
+       "nat_dnat_hit",
+       "l3_input_mf",
+       "l3_pass_mf",
+       "l3_uc_srch",
+       "l3_mcsg_srch",
+       "l3_uc_resp",
+       "l3_mcsg_resp",
+       "l3_uc_hit",
+       "l3_mcsg_hit",
+       "l3_output_mf",
+       "l3_v6_mf",
+       "l3_mc",
+       "l3_v6_srch",
+       "l3_mc_srch",
+       "l3_v6_hit",
+       "l3_mc_hit",
+       "iacl_input_mf",
+       "iacl_pass_mf",
+       "iacl_srch",
+       "iacl_resp",
+       "iacl_hit",
+       "iacl_output_mf",
+       "iacl_v6",
+       "iacl_v6_srch",
+       "iacl_v6_hit",
+       "tmu_port0_phy_tran",
+       "tmu_port1_phy_tran",
+       "tmu_port2_phy_tran",
+       "tmu_port3_phy_tran",
+       "tmu_port4_phy_tran",
+       "tmu_port5_phy_tran",
+       "tmu_port6_phy_tran",
+       "tmu_port7_phy_tran",
+       "tmu_port8_phy_tran",
+       "tmu_port9_phy_tran",
+       "tmu_port10_phy_tran",
+       "tmu_port11_phy_tran",
+       "tmu_port12_phy_tran",
+       "tmu_port13_phy_tran",
+       "tmu_port14_phy_tran",
+       "tmu_port15_phy_tran",
+       "tmu_port16_phy_tran",
+       "tmu_port17_phy_tran",
+       "tmu_port18_phy_tran",
+       "tmu_port19_phy_tran",
+       "tmu_port20_phy_tran",
+       "tmu_port21_phy_tran",
+       "tmu_port22_phy_tran",
+       "tmu_port23_phy_tran",
+       "tmu_port24_phy_tran",
+       "tmu_port25_phy_tran",
+       "tmu_port26_phy_tran",
+       "tmu_port0_phy_drop_rclm",
+       "tmu_port1_phy_drop_rclm",
+       "tmu_port2_phy_drop_rclm",
+       "tmu_port3_phy_drop_rclm",
+       "tmu_port4_phy_drop_rclm",
+       "tmu_port5_phy_drop_rclm",
+       "tmu_port6_phy_drop_rclm",
+       "tmu_port7_phy_drop_rclm",
+       "tmu_port8_phy_drop_rclm",
+       "tmu_port9_phy_drop_rclm",
+       "tmu_port10_phy_drop_rclm",
+       "tmu_port11_phy_drop_rclm",
+       "tmu_port12_phy_drop_rclm",
+       "tmu_port13_phy_drop_rclm",
+       "tmu_port14_phy_drop_rclm",
+       "tmu_port15_phy_drop_rclm",
+       "tmu_port16_phy_drop_rclm",
+       "tmu_port17_phy_drop_rclm",
+       "tmu_port18_phy_drop_rclm",
+       "tmu_port19_phy_drop_rclm",
+       "tmu_port20_phy_drop_rclm",
+       "tmu_port21_phy_drop_rclm",
+       "tmu_port22_phy_drop_rclm",
+       "tmu_port23_phy_drop_rclm",
+       "tmu_port24_phy_drop_rclm",
+       "tmu_port25_phy_drop_rclm",
+       "tmu_port26_phy_drop_rclm",
+       "tmu_drop_bit_cnt",
+       "nat_cp_drop_cnt",
+       "nat_cp_up_cnt",
+       "nat_fwd_cnt",
+       "nat_cp_fwd_cnt",
+       "l3_cp_up_fwd_cnt",
+       "l3_cp_fwd_cnt",
+       "l3_cp_up_cnt",
+       "l3_drop_bit_cnt",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       "arp_intf_input_mf",
+       "arp_intf_pass_mf",
+       "arp_intf_intf_srch",
+       "arp_intf_arp_srch",
+       "arp_intf_intf_resp",
+       "arp_intf_arp_resp",
+       "arp_intf_intf_hit",
+       "arp_intf_arp_hit",
+       "arp_intf_output_mf",
+       "arp_intf_v6_mf",
+       "arp_intf_mc",
+       "arp_intf_v6_srch",
+       "arp_intf_mc_srch",
+       "arp_intf_v6_hit",
+       "arp_intf_mc_hit",
+       "evlan_lkp_input_mf",
+       "evlan_lkp_pass_mf",
+       "evlan_lkp_port_tpid_srch",
+       "evlan_lkp_tag_mem_srch",
+       "evlan_lkp_vlan_srch",
+       "evlan_lkp_port_tpid_resp",
+       "evlan_lkp_tag_mem_resp",
+       "evlan_lkp_vlan_resp",
+       "evlan_lkp_port_tpid_hit",
+       "evlan_lkp_tag_mem_hit",
+       "evlan_lkp_vlan_hit",
+       "evlan_lkp_output_mf",
+       "evlan_lkp_cp_drop",
+       "evlan_lkp_cp_up",
+       "evlan_lkp_cp_fwd",
+       "evlan_act_input_mf",
+       "evlan_act_pass_mf",
+       "evlan_act_srch",
+       "evlan_xlt_srch_cnt",
+       "evlan_act_resp",
+       "evlan_xlt_resp_hit",
+       NULL,
+       "evlan_xlt_hit_cnt",
+       "evlan_act_output_mf",
+       "evlan_act_cp_drop",
+       "evlan_act_cp_cpu",
+       "eacl_input_mf",
+       "eacl_pass_mf",
+       "eacl_srch",
+       "eacl_resp",
+       "eacl_hit",
+       "eacl_output_mf",
+       "eacl_v6",
+       "eacl_v6_srch",
+       "eacl_v6_hit",
+       "md2port_0_data_sof",
+       "md2port_0_data_eof",
+       "md2port_1_data_sof",
+       "md2port_1_data_eof",
+       "md2port_2_data_sof",
+       "md2port_2_data_eof",
+       "md2port_3_data_sof",
+       "md2port_3_data_eof",
+       "md2port_4_data_sof",
+       "md2port_4_data_eof",
+       "md2port_5_data_sof",
+       "md2port_5_data_eof",
+       "md2port_6_data_sof",
+       "md2port_6_data_eof",
+       "pkt_separate_free_cnt",
+       "pkt_whold_free_cnt",
+       "se2md_result_cnt",
+       "md2se_key_cnt",
+       "mem2md_data_cnt",
+       "md2mem_rd_cnt",
+       "modify_drop_cnt",
+       "mipp_cnt[0]",
+       "mipp_cnt[1]",
+       "ipv6_hdr_add",
+       "ipv6_hdr_del",
+       "otpid_replace",
+       "itpid_replace",
+       "ppp_hdr_add",
+       "ppp_hdr_del",
+       "avlan_replace",
+       "avlan_add",
+       "avlan_del",
+       "ovlan_replace",
+       "ovlan_add",
+       "ovlan_del",
+       "ivlan_replace",
+       "ivlan_add",
+       "ivlan_del",
+};
+
+static int
+sf_dpns_mib_show(struct seq_file *m, void *private)
+{
+       struct dpns_priv *priv = m->private;
+       u64 bytes;
+       u32 count;
+       int i;
+       seq_printf(m, "General MIBs:\n");
+       for (i = 0; i < ARRAY_SIZE(sf21_dpns_mib_name); i++) {
+               if (!sf21_dpns_mib_name[i])
+                       continue;
+               count = dpns_r32(priv, NPU_MIB(i));
+               seq_printf(m, "name:%-30s packets:%11u\n",
+                          sf21_dpns_mib_name[i], count);
+       }
+       seq_printf(m, "Port MIBs:\n");
+       for (i = 0; i < DPNS_MAX_PORT; i++) {
+               count = dpns_r32(priv, NPU_MIB_PKT_RCV_PORT(i));
+               bytes = dpns_r32(priv, NPU_MIB_NCI_RD_DATA2) |
+                       (u64)dpns_r32(priv, NPU_MIB_NCI_RD_DATA3) << 32;
+               seq_printf(m,
+                          "name:pkt_rcv_port%-18u packets:%11u bytes:%20llu\n",
+                          i, count, bytes);
+       }
+       return 0;
+}
+
+static int sf_dpns_mib_open(struct inode *inode, struct file *file)
+{
+       return single_open_size(file, sf_dpns_mib_show, inode->i_private,
+                               56 * (ARRAY_SIZE(sf21_dpns_mib_name) + 1) +
+                                       83 * (DPNS_MAX_PORT + 1));
+}
+
+static const struct file_operations sf_dpns_mib_fops = {               
+       .owner          = THIS_MODULE,  
+       .open           = sf_dpns_mib_open,     
+       .read           = seq_read,     
+       .llseek         = seq_lseek,    
+       .release        = single_release,       
+};
+
+void sf_dpns_debugfs_init(struct dpns_priv *priv)
+{
+       priv->debugfs = debugfs_create_dir(dev_name(priv->dev), NULL);
+       debugfs_create_file("mib", S_IRUSR, priv->debugfs, priv, &sf_dpns_mib_fops);
+}
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.c
new file mode 100644 (file)
index 0000000..2b5e13e
--- /dev/null
@@ -0,0 +1,50 @@
+#include "dpns.h"
+#include <linux/iopoll.h>
+#include <linux/bitfield.h>
+#include "sf_dpns_se.h"
+
+static int dpns_populate_table(struct dpns_priv *priv)
+{
+       void __iomem *ioaddr = priv->ioaddr;
+       int ret, i;
+       u32 reg;
+
+       dpns_rmw(priv, SE_CONFIG0, SE_IPSPL_ZERO_LIMIT,
+                SE_IPORT_TABLE_VALID);
+       dpns_w32(priv, SE_TB_WRDATA(0), 0xa0000);
+       for (i = 0; i < 6; i++) {
+               reg = SE_TB_OP_WR | FIELD_PREP(SE_TB_OP_REQ_ADDR, i) |
+                     FIELD_PREP(SE_TB_OP_REQ_ID, SE_TB_IPORT);
+               dpns_w32(priv, SE_TB_OP, reg);
+               ret = readl_poll_timeout(ioaddr + SE_TB_OP, reg,
+                                        !(reg & SE_TB_OP_BUSY), 0, 100);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int dpns_se_init(struct dpns_priv *priv) {
+       int ret;
+       u32 reg;
+
+       dpns_w32(priv, SE_CLR_RAM_CTRL, SE_CLR_RAM_ALL);
+       dpns_w32(priv, SE_TCAM_CLR, SE_TCAM_CLR);
+
+       ret = readl_poll_timeout(priv->ioaddr + SE_CLR_RAM_CTRL, reg, !reg, 0,
+                                1000);
+       if (ret)
+               return ret;
+       ret = readl_poll_timeout(priv->ioaddr + SE_TCAM_CLR, reg, !reg, 0,
+                                1000);
+       if (ret)
+               return ret;
+
+       /* Upload ARP packets which NPU considers invalid to host. */
+       dpns_rmw(priv, PKT_ERR_STG_CFG2, ARP_REQ_ERR_OP | ARP_REPLY_ERR_OP,
+                ARP_REQ_ERR_UP | ARP_REPLY_ERR_UP);
+
+       ret = dpns_populate_table(priv);
+       return ret;
+}
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_se.h
new file mode 100644 (file)
index 0000000..2e29092
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef __SF_DPNS_SE_H__
+#define __SF_DPNS_SE_H__
+#include "dpns.h"
+
+#define SE_INT_STATUS                  0x180000
+#define  SE_INT_EVACT_SCH_OVF          BIT(14)
+#define  SE_INT_L2_MF_SPL_OVF          BIT(13)
+#define  SE_INT_L2_MP_SCH_OVF          BIT(12)
+#define  SE_INT_MODIFY_OVF             BIT(11)
+#define  SE_INT_EVXLT_LKP_OVF          BIT(10)
+#define  SE_INT_EVLAN_LKP_OVF          BIT(9)
+#define  SE_INT_EVSCH_OVF              BIT(8)
+#define  SE_INT_MACSCH_OVF             BIT(7)
+#define  SE_INT_MSPLS_OVF              BIT(6)
+#define  SE_INT_MACSPL_LKP_OVF         BIT(5)
+#define  SE_INT_L2_LKP_BUF_OVF         BIT(4)
+#define  SE_INT_L2_LKP_SCH_OVF         BIT(3)
+#define  SE_INT_IVXLT_OVF              BIT(2)
+#define  SE_INT_IVLKP_OVF              BIT(1)
+#define  SE_INT_IVPSPL_LKP_OVF         BIT(0)
+
+#define SE_CLR_RAM_CTRL                        0x180004
+#define  SE_CLR_RAM_ALL                        GENMASK(20, 0)
+
+#define SE_CONFIG0                     0x180008
+#define  SE_L2_VID_ZERO_MODE           BIT(27)
+#define  SE_IPSPL_DIS_STEP             BIT(26)
+#define  SE_IPSPL_CMPT_LEN             GENMASK(25, 20)
+#define  SE_IPSPL_ZERO_LIMIT           BIT(19)
+#define  SE_IPSPL_CNT_MODE             GENMASK(18, 17)
+#define  SE_IVLKP_CFG_DISABLE          BIT(16)
+#define  SE_IVLKP_CFG_ENTR_MINUS1      GENMASK(15, 10)
+#define  SE_PORTBV_TABLE_VALID         BIT(9)
+#define  SE_IPORT_TABLE_VALID          BIT(8)
+#define  SE_IVXLT_CFG_DISABLE          BIT(7)
+#define  SE_IVXLT_CFG_ENTR_MINUS1      GENMASK(6, 1)
+#define  SE_IPSPL_MODE                 BIT(0)
+
+#define SE_CONFIG1                     0x18000c
+#define  SE_UNUC_SPL_CNT_MODE          BIT(30)
+#define  SE_L2_HASH_POLY_SEL(x)                GENMASK((x) * 3 + 2, (x) * 3)
+
+#define SE_CONFIG2                     0x180010
+#define  SE_EVACT_TABLE_VALID          BIT(31)
+#define  SE_EVXLT_CFG_DIS              BIT(30)
+#define  SE_EVXLT_CFG_ENTR_MINUS1      GENMASK(29, 24)
+#define  SE_L2_MFSPL_ZERO_LIMIT                BIT(23)
+#define  SE_L2_MFSPL_CNT_MODE          GENMASK(22, 21)
+#define  SE_MFSPL_MODE                 BIT(20)
+#define  SE_MACSPL_ZERO_LIMIT          BIT(19)
+#define  SE_MACSPL_CNT_MODE            GENMASK(18, 17)
+#define  SE_PTPID_TABLE_VALID          BIT(16)
+#define  SE_OTPID_TABLE_VALID          BIT(15)
+#define  SE_EVLKP_CFG_DIS_TB           BIT(14)
+#define  SE_EVLKP_CFG_ENTR_MINUS1      GENMASK(13, 8)
+#define  SE_INTF_TABLE_VALID           BIT(7)
+#define  SE_MAC_TABLE_VALID            BIT(6)
+#define  SE_MACSPL_MODE                        BIT(5)
+#define  SE_L2_AGE_CLR_AFTER_RD                BIT(4)
+#define  SE_L2_SEG_NUM_MINUS1          GENMASK(3, 0)
+
+#define SE_TB_OP                       0x18003c
+#define  SE_TB_OP_BUSY                 BIT(31)
+#define  SE_TB_OP_WR                   BIT(24)
+#define  SE_TB_OP_REQ_ID               GENMASK(21, 16)
+#define   SE_TB_IPORT                  1
+#define  SE_TB_OP_REQ_ADDR             GENMASK(15, 0)
+
+#define SE_TB_WRDATA(x)                        (0x180040 + 4 * (x))
+#define SE_TB_RDDATA(x)                        (0x180080 + 4 * (x))
+
+#define SE_TCAM_CLR                    0x190004
+#define  SE_TCAM_CLR_ALL               GENMASK(5, 0)
+#define  SE_TCAM_CLR_ACL_SPL           BIT(5)
+#define  SE_TCAM_CLR_BLK(x)            BIT(x)
+
+#endif
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.c
new file mode 100644 (file)
index 0000000..12548e3
--- /dev/null
@@ -0,0 +1,247 @@
+#include <linux/of_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include "dpns.h"
+#include "sf_dpns_tmu.h"
+
+static u32 tmu_rm32(struct dpns_priv *priv, u32 reg, u32 mask, u32 shift)
+{
+       u32 t;
+
+       t = dpns_r32(priv, reg);
+       t &= mask;
+       t >>= shift;
+
+       return t;
+}
+
+static void tmu_rmw32(struct dpns_priv *priv, u32 reg, u32 mask, u32 shift, u32 val)
+{
+       u32 t;
+
+       val <<= shift;
+       val &= mask;
+       t = dpns_r32(priv, reg);
+       t &= ~mask;
+       t |= val;
+       dpns_w32(priv, reg, t);
+}
+
+static int is_valid_port_idx(struct dpns_priv *priv, u32 port)
+{
+       if (port >= TMU_MAX_PORT_CNT)
+               return 0;
+
+       return 1;
+}
+
+static int is_valid_queue_idx(u32 q)
+{
+       if (q >= QUE_MAX_NUM_PER_PORT)
+               return 0;
+
+       return 1;
+}
+
+static int is_valid_sched_idx(struct dpns_priv *priv, u32 sched)
+{
+       if (sched >= QUE_SCH_NUM_PER_PORT)
+               return 0;
+
+       return 1;
+}
+
+static int is_valid_shaper_idx(struct dpns_priv *priv, u32 shaper)
+{
+       if (shaper >= QUE_SHAPER_NUM_PER_PORT)
+               return 0;
+
+       return 1;
+}
+
+static int tmu_port_writel(struct dpns_priv *priv, u32 port, u32 reg, u32 val)
+{
+       if (!is_valid_port_idx(priv, port))
+               return -EINVAL;
+
+       dpns_w32(priv, TMU_PORT_BASE(port) + reg, val);
+       return 0;
+}
+
+static int tmu_port_rm32(struct dpns_priv *priv, u32 port, u32 reg, u32 mask, u32 shift, u32 *val)
+{
+       if (!is_valid_port_idx(priv, port))
+               return -EINVAL;
+
+       *val = tmu_rm32(priv, TMU_PORT_BASE(port) + reg, mask, shift);
+       return 0;
+}
+
+static int tmu_port_rmw32(struct dpns_priv *priv, u32 port, u32 reg, u32 mask, u32 shift, u32 val)
+{
+       if (!is_valid_port_idx(priv, port))
+               return -EINVAL;
+
+       tmu_rmw32(priv, TMU_PORT_BASE(port) + reg, mask, shift, val);
+
+       return 0;
+}
+
+static int tmu_queue_writel(struct dpns_priv *priv, u32 port, u32 queue, u32 reg, u32 val)
+{
+       if (!is_valid_queue_idx(queue))
+               return -EINVAL;
+
+       return tmu_port_writel(priv, port, TMU_QUEUE_BASE(queue) + reg, val);
+}
+
+static int tmu_sched_writel(struct dpns_priv *priv, u32 port, u32 sched, u32 reg, u32 val)
+{
+       if (!is_valid_sched_idx(priv, sched))
+               return -EINVAL;
+
+       return tmu_port_writel(priv, port, TMU_SCHED_BASE(sched) + reg, val);
+}
+
+static int tmu_shaper_writel(struct dpns_priv *priv, u32 port, u32 shaper, u32 reg, u32 val)
+{
+       if (!is_valid_shaper_idx(priv, shaper))
+               return -EINVAL;
+
+       return tmu_port_writel(priv, port, TMU_SHAPER_BASE(shaper) + reg, val);
+}
+
+static int tmu_shaper_rmw32(struct dpns_priv *priv, u32 port, u32 shaper, u32 reg, u32 mask, u32 shift, u32 val)
+{
+       if (!is_valid_shaper_idx(priv, shaper))
+               return -EINVAL;
+
+       return tmu_port_rmw32(priv, port, TMU_SHAPER_BASE(shaper) + reg, mask, shift, val);
+}
+
+static int tdq_ctrl_is_configurable(struct dpns_priv *priv, u32 port)
+{
+       u32 val = 0;
+       int err;
+
+       if ((err = tmu_port_rm32(priv, port,
+                                TMU_TDQ_CTRL,
+                                TMU_TDQ_ALLOW_CFG,
+                                TMU_TDQ_ALLOW_CFG_SHIFT,
+                                &val))) {
+               return 0;
+       }
+
+       return val;
+}
+
+static void tmu_port_queue_cfg(struct dpns_priv *priv, u32 port)
+{
+       int comp;
+
+       for (comp = 0; comp < QUE_MAX_NUM_PER_PORT; comp++) {
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_CFG0, 0x00011f00);
+
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_CFG1, 0x00000000);
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_CFG2, 0x00000000);
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_STS0, 0x00000000);
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_STS1, 0x00000000);
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_STS2, 0x00000000);
+               tmu_queue_writel(priv, port, comp, TMU_PORT_QUEUE_CFG3, 0x000005ee);
+       }
+}
+
+static void tmu_port_sched_cfg(struct dpns_priv *priv, u32 port)
+{
+       int comp;
+       for (comp = 0; comp < QUE_SCH_NUM_PER_PORT; comp++) {
+               tmu_sched_writel(priv, port, comp, TMU_SCH_CTRL,      0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q0_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q1_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q2_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q3_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q4_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q5_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q6_WEIGHT, 0x00000000);
+               tmu_sched_writel(priv, port, comp, TMU_SCH_Q7_WEIGHT, 0x00000000);
+
+               switch (comp) {
+               case 0:
+                       tmu_sched_writel(priv, port, comp, TMU_SCH_QUEUE_ALLOC0, 0x03020100);
+                       tmu_sched_writel(priv, port, comp, TMU_SCH_QUEUE_ALLOC1, 0x08080808);
+                       break;
+
+               case 1:
+                       tmu_sched_writel(priv, port, comp, TMU_SCH_QUEUE_ALLOC0, 0x06050400);
+                       tmu_sched_writel(priv, port, comp, TMU_SCH_QUEUE_ALLOC1, 0x08080807);
+                       break;
+
+               default:
+                       break;
+               }
+
+               tmu_sched_writel(priv, port, comp, TMU_SCH_BIT_RATE, 0x00000000);
+
+               if (comp == 0)
+                       tmu_sched_writel(priv, port, comp, TMU_SCH0_POS, 0x00000000);
+       }
+}
+
+static void tmu_port_shaper_cfg(struct dpns_priv *priv, u32 port)
+{
+       int comp;
+       for (comp = 0; comp < QUE_SHAPER_NUM_PER_PORT; comp++) {
+               tmu_shaper_writel(priv, port, comp, TMU_SHP_CTRL,       0x00000000);
+               tmu_shaper_writel(priv, port, comp, TMU_SHP_WEIGHT,     0x00000000);
+               tmu_shaper_writel(priv, port, comp, TMU_SHP_CTRL2,      0x00000000);
+               tmu_shaper_writel(priv, port, comp, TMU_SHP_MIN_CREDIT, 0x0003ff00);
+               tmu_shaper_writel(priv, port, comp, TMU_SHP_MAX_CREDIT, 0x00000400);
+               tmu_shaper_rmw32(priv, port, comp, TMU_SHP_CTRL2, TMU_SHP_POS, TMU_SHP_POS_SHIFT, comp);
+       }
+}
+
+static void _tmu_reset(struct dpns_priv *priv, u32 port)
+{
+       tmu_port_queue_cfg(priv, port);
+       tmu_port_sched_cfg(priv, port);
+       tmu_port_shaper_cfg(priv, port);
+
+       // Cause tmu shaper rate limit not include pkt preamble(8byte)/IFG(12byte)/FCS(4Byte)
+       // so config 24 byte here
+       tmu_port_writel(priv, port, TMU_TDQ_IFG, 0x00000018);
+
+       if (tdq_ctrl_is_configurable(priv, port))
+               tmu_port_writel(priv, port, TMU_TDQ_CTRL, 0x0000002f);
+}
+
+static int tmu_reset(struct dpns_priv *priv)
+{
+       int port;
+
+       dpns_w32(priv, TMU_CTRL, 0x00000006);
+       dpns_w32(priv, TMU_LLM_FIFO_CTRL0, 0x07fe07ff);
+       dpns_w32(priv, TMU_LLM_FIFO_CTRL1, 0x00280024);
+
+       for (port = 0; port < TMU_MAX_PORT_CNT; port++) {
+               _tmu_reset(priv, port);
+       }
+
+       return 0;
+}
+
+int dpns_tmu_init(struct dpns_priv *priv)
+{
+       int err;
+
+       if ((err = tmu_reset(priv)) != 0)
+               return err;
+
+       return err;
+}
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sf_dpns_tmu.h
new file mode 100644 (file)
index 0000000..ae15d31
--- /dev/null
@@ -0,0 +1,315 @@
+#ifndef __SF_TMU_H__
+#define __SF_TMU_H__
+#include <linux/bitfield.h>
+// npu clk is 400MHz in mpw, will change to 600MHz in fullmask
+// TODO: should use mpw define to diff
+#define LIF_SHP_CLKDIV_DEF      (3)
+#define LIF_WEIGHT_MAX          (0x7ff)
+#define TMU_SHP_CLKDIV_DEF      (6)
+#define TMU_SHP_CLKDIV_MAX      (15)
+#define TMU_WEIGHT_MAX                 (256)
+#define TMU_SHP_INT_WGHT_MAX    ((TMU_SHP_WEIGHT_INT_MASK) >> TMU_SHP_WEIGHT_INT_SHIFT)
+#define TMU_SHP_FRAC_WGHT_MAX   ((TMU_SHP_WEIGHT_FRAC_MASK) >> TMU_SHP_WEIGHT_FRAC_SHIFT)
+
+#define TMU_VERSION_INFO               0x148000
+#define TMU_ID_SHIFT                   0
+#define TMU_ID                         GENMASK(15, 0)
+#define TMU_VERSION_SHIFT              16
+#define TMU_VERSION                    GENMASK(23, 16)
+#define TMU_REVISION_SHIFT             24
+#define TMU_REVISION                   GENMASK(31, 24)
+
+#define TMU_CTRL                       0x148004
+#define TMU_MF_IN_CNT_EN_SHIFT         1
+#define TMU_MF_IN_CNT_EN               BIT(1)
+#define TMU_MD_RDY_EN_SHIFT            2
+#define TMU_MD_RDY_EN                  BIT(2)
+#define TMU_DEBUG_SEL_SHIFT            3
+#define TMU_DEBUG_SEL                  GENMASK(8, 3)
+
+#define TMU_LLM_FIFO_CTRL0             0x148008
+#define TMU_LLM_FIFO_FULL_ASSERT_SHIFT 0
+#define TMU_LLM_FIFO_FULL_ASSERT       GENMASK(11, 0)
+#define TMU_LLM_FIFO_FULL_NEGATE_SHIFT 16
+#define TMU_LLM_FIFO_FULL_NEGATE       GENMASK(27, 16)
+
+#define TMU_LLM_FIFO_CTRL1             0x14800c
+#define TMU_LLM_FIFO_EMPTY_ASSERT_SHIFT        0
+#define TMU_LLM_FIFO_EMPTY_ASSERT      GENMASK(11, 0)
+#define TMU_LLM_FIFO_EMPTY_NEGATE_SHIFT        16
+#define TMU_LLM_FIFO_EMPTY_NEGATE      GENMASK(27, 16)
+
+#define TMU_RD_CLR_EN          0x2800c0
+#define TMU_BUF_THR0           0x2800d8
+
+/* 36 ports in registers */
+#define TMU_PORT0                      0x0000
+
+#define TMU_PORT_SZ                    0x2000
+#define TMU_PORT_CNT                   36
+#define TMU_PORT_CNT_V1                        10
+
+/* 8 queues for each port */
+#define TMU_PORT_QUEUE0                        0x100000
+
+#define TMU_PORT_QUEUE_SZ              0x20
+#define TMU_PORT_QUEUE_CNT             8
+
+#define TMU_PORT_QUEUE_CFG0            0x00
+/* 0x00: mix tail drop
+ * 0x01: tail drop (default)
+ * 0x02: WRED
+ * 0x03: buf count tail drop
+ */
+#define TMU_DROP_TYPE_SHIFT            0
+#define TMU_DROP_TYPE                  GENMASK(1, 0)
+#define TMU_QUEUE_MAX_SHIFT            8
+#define TMU_QUEUE_MAX                  GENMASK(18, 8)
+#define TMU_QUEUE_MIN_SHIFT            20
+#define TMU_QUEUE_MIN                  GENMASK(30, 20) // related to WRED
+
+#define TMU_QUEUE_MIX_TAIL_DROP                0x00
+#define TMU_QUEUE_TAIL_DROP            0x01
+#define TMU_QUEUE_WRED                 0x02
+#define TMU_QUEUE_BUF_CNT_TAIL_DROP    0x03
+
+/* drop probability of each stage in WRED */
+#define TMU_PORT_QUEUE_CFG1            0x04
+#define TMU_WRED_HW_PROB_STG0_SHIFT    0
+#define TMU_WRED_HW_PROB_STG0          GENMASK(4, 0)
+#define TMU_WRED_HW_PROB_STG1_SHIFT    5
+#define TMU_WRED_HW_PROB_STG1          GENMASK(9, 5)
+#define TMU_WRED_HW_PROB_STG2_SHIFT    10
+#define TMU_WRED_HW_PROB_STG2          GENMASK(14, 10)
+#define TMU_WRED_HW_PROB_STG3_SHIFT    15
+#define TMU_WRED_HW_PROB_STG3          GENMASK(19, 15)
+#define TMU_WRED_HW_PROB_STG4_SHIFT    20
+#define TMU_WRED_HW_PROB_STG4          GENMASK(24, 20)
+#define TMU_WRED_HW_PROB_STG5_SHIFT    25
+#define TMU_WRED_HW_PROB_STG5          GENMASK(29, 25)
+
+#define TMU_PORT_QUEUE_CFG2            0x08
+#define TMU_WRED_HW_PROB_STG6_SHIFT    0
+#define TMU_WRED_HW_PROB_STG6          GENMASK(4, 0)
+#define TMU_WRED_HW_PROB_STG7_SHIFT    5
+#define TMU_WRED_HW_PROB_STG7          GENMASK(9, 5)
+
+#define TMU_WRED_PROB_CNT              8
+
+/* RO */
+#define TMU_PORT_QUEUE_STS0            0x0c
+#define TMU_QUEUE_HEAD_PTR_SHIFT       0
+#define TMU_QUEUE_HEAD_PTR             GENMASK(10, 0)
+#define TMU_QUEUE_TAIL_PTR_SHIFT       16
+#define TMU_QUEUE_TAIL_PTR             GENMASK(26, 16)
+
+/* RO */
+#define TMU_PORT_QUEUE_STS1            0x10
+#define TMU_QUEUE_PKT_CNT_SHIFT                0
+#define TMU_QUEUE_PKT_CNT              GENMASK(11, 0)
+
+/* RO */
+#define TMU_PORT_QUEUE_STS2            0x14
+#define TMU_QUEUE_BUF_CNT_SHIFT                0
+#define TMU_QUEUE_BUF_CNT              GENMASK(11, 0)
+
+/* max buffer cell of queue */
+#define TMU_PORT_QUEUE_CFG3            0x18
+#define TMU_QUEUE_BUF_MAX_SHIFT                0
+#define TMU_QUEUE_BUF_MAX              GENMASK(11, 0)
+
+/* 2 schedulers (dequeuing) for each port */
+#define TMU_SCH0                       0x101000
+#define TMU_SCH1                       0x101040
+
+#define TMU_SCH_SZ                     0x40
+#define TMU_SCH_CNT                    2
+
+#define TMU_SCH_CTRL                   0x00
+#define TMU_SCH_ALGO_SHIFT             0
+#define TMU_SCH_ALGO                   GENMASK(6, 0)
+
+/* TMU_SCH_ALGO */
+#define TMU_SCH_PQ                     0x00
+#define TMU_SCH_WFQ                    0x01
+#define TMU_SCH_DWRR                   0x02
+#define TMU_SCH_RR                     0x03
+#define TMU_SCH_WRR                    0x04
+
+#define TMU_SCH_Q0_WEIGHT              0x10
+#define TMU_SCH_Q1_WEIGHT              0x14
+#define TMU_SCH_Q2_WEIGHT              0x18
+#define TMU_SCH_Q3_WEIGHT              0x1c
+#define TMU_SCH_Q4_WEIGHT              0x20
+#define TMU_SCH_Q5_WEIGHT              0x24
+#define TMU_SCH_Q6_WEIGHT              0x28
+#define TMU_SCH_Q7_WEIGHT              0x2c
+#define TMU_SCH_Q_WEIGHT_SZ            4
+
+#define TMU_SCH_Q_WEIGHT_CNT           8
+
+/* TMU_SCH_Qn_WEIGHT */
+#define TMU_SCH_QUEUE_WEIGHT_SHIFT     0
+#define TMU_SCH_QUEUE_WEIGHT           GENMASK(31, 0)
+
+/* port queue and scheduler selection */
+#define TMU_SCH_QUEUE_ALLOC0           0x30
+#define TMU_SCH_Q0_ALLOC_SHIFT         0
+#define TMU_SCH_Q0_ALLOC               GENMASK(3, 0)
+#define TMU_SCH_Q1_ALLOC_SHIFT         8
+#define TMU_SCH_Q1_ALLOC               GENMASK(11, 8)
+#define TMU_SCH_Q2_ALLOC_SHIFT         16
+#define TMU_SCH_Q2_ALLOC               GENMASK(19, 16)
+#define TMU_SCH_Q3_ALLOC_SHIFT         24
+#define TMU_SCH_Q3_ALLOC               GENMASK(27, 24)
+
+#define TMU_SCH_QUEUE_ALLOC1           0x34
+#define TMU_SCH_Q4_ALLOC_SHIFT         0
+#define TMU_SCH_Q4_ALLOC               GENMASK(3, 0)
+#define TMU_SCH_Q5_ALLOC_SHIFT         8
+#define TMU_SCH_Q5_ALLOC               GENMASK(11, 8)
+#define TMU_SCH_Q6_ALLOC_SHIFT         16
+#define TMU_SCH_Q6_ALLOC               GENMASK(19, 16)
+#define TMU_SCH_Q7_ALLOC_SHIFT         24
+#define TMU_SCH_Q7_ALLOC               GENMASK(27, 24)
+
+#define TMU_SCH_Q_ALLOC_CNT            8
+
+// schedule by pkt_len or pkt_cnt
+#define TMU_SCH_BIT_RATE               0x38
+#define TMU_SCH_BIT_RATE_SHIFT         0
+#define TMU_SCH_BIT_RATE_MASK          GENMASK(31, 0)
+#define TMU_SCH_BIT_RATE_PKT_LEN       0x00
+#define TMU_SCH_BIT_RATE_PKT_CNT       0x01
+
+// RW
+// SCH0 Only, to select how to connect to SCH1
+#define TMU_SCH0_POS                   0x3c
+#define TMU_SCH0_POS_SHIFT             0
+#define TMU_SCH0_POS_MASK              GENMASK(3, 0)
+
+/* 5 shapers for each port */
+#define TMU_SHP0                       0x101080
+
+#define TMU_SHP_SZ                     0x0020
+#define TMU_SHP_CNT                    6
+
+#define TMU_SHP_CTRL                   0x00
+#define TMU_SHP_EN_SHIFT               0
+#define TMU_SHP_EN                     BIT(0)
+#define TMU_SHP_CLK_DIV_SHIFT          1
+#define TMU_SHP_CLK_DIV                        GENMASK(31, 1)
+
+/* byte size of per token (credit) */
+#define TMU_SHP_WEIGHT                 0x04
+#define TMU_SHP_WEIGHT_FRAC_SHIFT      0
+#define TMU_SHP_WEIGHT_FRAC_MASK       GENMASK(11, 0)
+#define TMU_SHP_WEIGHT_INT_SHIFT        12
+#define TMU_SHP_WEIGHT_INT_MASK         GENMASK(19, 12)
+
+#define TMU_SHP_MAX_CREDIT             0x08
+#define TMU_SHP_MAX_CREDIT_SHIFT       10
+#define TMU_SHP_MAX_CREDIT_MASK                GENMASK(31, 10)
+
+// (fraction part num) = (register fraction part) / (2 ^ 12)
+#define TMU_SHP_FRAC_WEIGHT_2DBL(reg)   (((double)(reg)) / (1 << 12))
+#define TMU_SHP_DBL_2FRAC_WEIGHT(dbl)   (((double)(dbl)) * (1 << 12))
+
+#define TMU_SHP_CTRL2                  0x0c
+#define TMU_SHP_BIT_RATE_SHIFT         0
+#define TMU_SHP_BIT_RATE               BIT(0)
+#define TMU_SHP_POS_SHIFT              1
+#define TMU_SHP_POS                    GENMASK(5, 1)   // RW
+#define TMU_SHP_MODE_SHIFT             6
+#define TMU_SHP_MODE                   BIT(6)
+
+/* TMU_SHP_BIT_RATE */
+#define TMU_SHP_SCHED_PKT_LEN          0
+#define TMU_SHP_SCHED_PKT_CNT          1
+
+/* TMU_SHP_MODE */
+#define TMU_SHP_MODE_KEEP_CREDIT       0
+#define TMU_SHP_MODE_CLEAR_CREDIT      1
+
+#define TMU_SHP_MIN_CREDIT             0x10
+#define TMU_SHP_MIN_CREDIT_SHIFT       0
+#define TMU_SHP_MIN_CREDIT_MASK                GENMASK(21, 0)
+
+/* RO */
+#define TMU_SHP_STATUS                 0x14
+#define TMU_SHP_CURR_STATUS_SHIFT      0       // shaper is working or not
+#define TMU_SHP_CURR_STATUS            BIT(0)
+#define TMU_SHP_CREDIT_CNTR_SHIFT      1
+#define TMU_SHP_CREDIT_CNTR            GENMASK(23, 1)
+
+/* dequeue stage configs */
+#define TMU_TDQ                                0x101140
+
+/* effective only when TMU_SCH_BIT_RATE is PKT_LEN mode.
+ * ifg value can be used to adjust packet length of scheduler.
+ */
+#define TMU_TDQ_IFG                    (TMU_TDQ + 0x00)
+#define TMU_TDQ_IIF_CFG_SHIFT          0
+#define TMU_TDQ_IIF_CFG                        GENMASK(7, 0)
+
+#define TMU_TDQ_CTRL                   (TMU_TDQ + 0x04)
+#define TMU_SHP_CLK_CNT_EN_SHIFT       0
+#define TMU_SHP_CLK_CNT_EN             BIT(0)
+#define TMU_TDQ_HW_EN_SHIFT            1
+#define TMU_TDQ_HW_EN                  BIT(1)
+#define TMU_SCH0_EN_SHIFT              2
+#define TMU_SCH0_EN                    BIT(2)
+#define TMU_SCH1_EN_SHIFT              3
+#define TMU_SCH1_EN                    BIT(3)
+#define TMU_TDQ_ALLOW_CFG_SHIFT                4
+#define TMU_TDQ_ALLOW_CFG              BIT(4)  // RO, 1 = configurable
+#define TMU_PKT_LEFT_IGNORE_SHIFT      5
+#define TMU_PKT_LEFT_IGNORE            BIT(5)
+
+#define TMU_PORT_BASE(port)            (TMU_PORT0 + TMU_PORT_SZ * (port))
+#define TMU_QUEUE_BASE(q)              (TMU_PORT_QUEUE0 + TMU_PORT_QUEUE_SZ * (q))
+#define TMU_SCHED_BASE(sch)            (TMU_SCH0 + TMU_SCH_SZ * (sch))
+#define TMU_SHAPER_BASE(shp)           (TMU_SHP0 + TMU_SHP_SZ * (shp))
+
+
+
+#define TMU_MAX_PORT_CNT 10
+#define QUE_MAX_NUM_PER_PORT 8
+#define QUE_SHAPER_NUM_PER_PORT 6
+#define QUE_SCH_NUM_PER_PORT 2
+
+enum TMU_QUEUE_TYPE {
+       TMU_Q_MIX_TAIL_DROP = 0,
+       TMU_Q_TAIL_DROP,
+       TMU_Q_WRED,
+       TMU_Q_BUF_CNT_TAIL_DROP,
+       NUM_TMU_QUEUE_TYPES,
+};
+
+enum TMU_SCHED_ALG {
+       TMU_SCHED_PQ = 0,
+       TMU_SCHED_WFQ,
+       TMU_SCHED_DWRR,
+       TMU_SCHED_RR,
+       TMU_SCHED_WRR,
+       NUM_TMU_SCEHD_ALGS,
+};
+
+enum TMU_BITRATE_MODE {
+       TMU_BITRATE_PKTLEN = 0,
+       TMU_BITRATE_PKTCNT,
+       NUM_TMU_BITRATE_MODES,
+};
+
+static const u8 sched_q_weight_regs[] = {
+       TMU_SCH_Q0_WEIGHT,
+       TMU_SCH_Q1_WEIGHT,
+       TMU_SCH_Q2_WEIGHT,
+       TMU_SCH_Q3_WEIGHT,
+       TMU_SCH_Q4_WEIGHT,
+       TMU_SCH_Q5_WEIGHT,
+       TMU_SCH_Q6_WEIGHT,
+       TMU_SCH_Q7_WEIGHT,
+};
+
+#endif /* __SF_TMU_H__ */
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-dma.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-dma.c
new file mode 100644 (file)
index 0000000..3061b89
--- /dev/null
@@ -0,0 +1,1618 @@
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/dma-mapping.h>
+#include <linux/if_ether.h>
+#include <linux/of_platform.h>
+#include <linux/seq_file.h>
+#include <linux/tcp.h>
+#include <net/page_pool/helpers.h>
+
+#include "sfxgmac-ext.h"
+#include "dma.h"
+#include "eth.h"
+
+struct xgmac_dma_desc_rx {
+       struct xgmac_dma_desc norm;
+       struct xgmac_dma_desc ctxt;
+};
+
+static void xgmac_dma_set_tx_head_ptr(struct xgmac_dma_priv *priv,
+                                     dma_addr_t addr, u32 queue)
+{
+       reg_write(priv, XGMAC_DMA_CH_TxDESC_LADDR(queue), lower_32_bits(addr));
+}
+
+static void xgmac_dma_set_rx_head_ptr(struct xgmac_dma_priv *priv,
+                                     dma_addr_t addr, u32 queue)
+{
+       reg_write(priv, XGMAC_DMA_CH_RxDESC_LADDR(queue), lower_32_bits(addr));
+}
+
+static void xgmac_dma_set_tx_tail_ptr(struct xgmac_dma_priv *priv,
+                                     dma_addr_t addr, u32 queue)
+{
+       reg_write(priv, XGMAC_DMA_CH_TxDESC_TAIL_LPTR(queue), lower_32_bits(addr));
+}
+
+static void xgmac_dma_set_rx_tail_ptr(struct xgmac_dma_priv *priv,
+                                     dma_addr_t addr, u32 queue)
+{
+       reg_write(priv, XGMAC_DMA_CH_RxDESC_TAIL_LPTR(queue), lower_32_bits(addr));
+}
+
+static void xgmac_dma_set_tx_desc_addr(struct xgmac_dma_desc *p,
+                                      dma_addr_t addr)
+{
+       p->des0 = cpu_to_le32(lower_32_bits(addr));
+       p->des1 = 0;
+}
+
+static void xgmac_dma_set_rx_desc_addr(struct xgmac_dma_desc *p,
+                                      dma_addr_t addr)
+{
+       p->des0 = cpu_to_le32(lower_32_bits(addr));
+       p->des1 = 0;
+       p->des2 = 0;
+}
+
+static void xgmac_dma_set_rx_owner(struct xgmac_dma_desc *p, bool int_en)
+{
+       u32 val = XGMAC_RDES3_OWN;
+
+       if (int_en)
+               val |= XGMAC_RDES3_IOC;
+       p->des3 = cpu_to_le32(val);
+}
+
+static void xgmac_dma_init_rx_desc(struct xgmac_dma_desc *p,
+                                  dma_addr_t addr, bool int_en)
+{
+       xgmac_dma_set_rx_desc_addr(p, addr);
+       xgmac_dma_set_rx_owner(p, int_en);
+}
+
+static __always_inline void
+xgmac_dma_rx_coe_hash(const struct net_device *dev, struct sk_buff *skb,
+                     u32 rdes0, u32 rdes_ctx1)
+{
+       bool rxcoe, is_l3, is_l4, not_tunnel, not_frag;
+       u32 hash;
+       /* RX COE is only available if:
+        * 1. It's not an IP fragment
+        * 2. It's not a tunnel packet (4in6, PPPoE, etc.)
+        * 3. Its L4 protocol is known (TCP, UDP, or ICMP)
+        *
+        * If all of the above are true, mark the skb as
+        * CHECKSUM_UNNECESSARY
+        *
+        * Note: bit-wise ops are used to avoid branches
+        */
+       not_frag = FIELD_GET(XGMAC_RDES0_IP_FRAG, rdes0) == FRAG_NONE;
+       not_tunnel = FIELD_GET(XGMAC_RDES1_TNP, rdes_ctx1) != 1;
+       is_l3 = (FIELD_GET(XGMAC_RDES0_L3_TYPE, rdes0) == L3_TYPE_IPV4) |
+               (FIELD_GET(XGMAC_RDES0_L3_TYPE, rdes0) == L3_TYPE_IPV6);
+       is_l4 = FIELD_GET(XGMAC_RDES0_L4_TYPE, rdes0) != L4_TYPE_UNKNOWN;
+
+       rxcoe = !!(dev->features & NETIF_F_RXCSUM) & not_frag & not_tunnel & is_l3 & is_l4;
+
+       skb->ip_summed = rxcoe ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
+
+       /* Fill in skb->hash */
+       hash = FIELD_GET(XGMAC_RDES1_RXHASH, rdes_ctx1);
+       __skb_set_hash(skb, hash, false, is_l4);
+}
+
+static u32 xgmac_dma_tx_avail(struct xgmac_txq *txq)
+{
+       if (txq->dirty_tx > txq->cur_tx)
+               return txq->dirty_tx - txq->cur_tx - 1;
+       else
+               return DMA_TX_SIZE - txq->cur_tx + txq->dirty_tx - 1;
+}
+
+static void xgmac_dma_rx_refill(struct xgmac_dma_priv *priv,
+                               struct xgmac_rxq *rxq)
+{
+       u32 entry = rxq->dirty_rx;
+       u16 channel = rxq->idx;
+       s32 dirty;
+
+       if (rxq->dirty_rx <= rxq->cur_rx)
+               dirty = rxq->cur_rx - rxq->dirty_rx;
+       else
+               dirty = DMA_RX_SIZE - rxq->dirty_rx + rxq->cur_rx;
+
+       for (; dirty > 0; dirty -= 2) {
+               struct xgmac_dma_rx_buffer *buf = &rxq->buf_pool[entry];
+               struct xgmac_dma_desc *p = &rxq->dma_rx[entry];
+
+               if (likely(buf->page == NULL)) {
+                       buf->page = page_pool_dev_alloc_frag(rxq->page_pool,
+                                                            &buf->offset,
+                                                            priv->rx_alloc_size);
+                       if (unlikely(!buf->page))
+                               break;
+               }
+
+               xgmac_dma_init_rx_desc(p, page_pool_get_dma_addr(buf->page) + buf->offset + BUF_PAD, false);
+               /* No buffer space required by context descs */
+               xgmac_dma_init_rx_desc(p + 1, 0, false);
+
+               entry = (entry + 2) % DMA_RX_SIZE;
+       }
+
+       rxq->dirty_rx = entry;
+       rxq->rx_tail_addr = rxq->dirty_rx * sizeof(struct xgmac_dma_desc) +
+                           rxq->dma_rx_phy;
+
+       xgmac_dma_set_rx_tail_ptr(priv, rxq->rx_tail_addr, channel);
+}
+
+static int xgmac_dma_poll_rx(struct xgmac_rxq *rxq, int budget)
+{
+       struct xgmac_dma_priv *priv = container_of(rxq, struct xgmac_dma_priv,
+                                                  rxq[rxq->idx]);
+       unsigned int next_entry = rxq->cur_rx;
+       int count = 0;
+
+       for (; count < budget; count++) {
+               u32 len, rdes0, rdes2, rdes3, rdes_ctx0, rdes_ctx1, rdes_ctx2, rdes_ctx3, sta_index, rpt_index;
+               struct xgmac_dma_rx_buffer *buf;
+               register struct xgmac_dma_desc_rx rx;
+               struct net_device *netdev;
+               struct sk_buff *skb;
+               unsigned int entry;
+               u8 id, up_reason, vlan_pri, no_frag;
+               u16 ovid, sport, eth_type, dscp, pkt_type, tnp;
+               u64 smac;
+
+               entry = next_entry;
+               buf = &rxq->buf_pool[entry];
+
+               rx = __READ_ONCE(*(struct xgmac_dma_desc_rx *)&rxq->dma_rx[next_entry]);
+               /* check if owned by the DMA otherwise go ahead */
+               if (unlikely(le32_to_cpu(rx.ctxt.des3) & XGMAC_RDES3_OWN))
+                       break;
+
+               rxq->cur_rx = (entry + 2) % DMA_RX_SIZE;
+               next_entry = rxq->cur_rx;
+
+               rdes3 = le32_to_cpu(rx.norm.des3);
+               if (unlikely(!(rdes3 & XGMAC_RDES3_LD)))
+                       continue;
+
+               if (unlikely(rdes3 & XGMAC_RDES3_ES)) {
+                       pr_debug_ratelimited("error type: 0x%lx\n",
+                                       FIELD_GET(XGMAC_RDES3_ET, rdes3));
+                       continue;
+               }
+
+               rdes0 = le32_to_cpu(rx.norm.des0);
+               /* get ivport */
+               id = FIELD_GET(XGMAC_RDES0_IVPORT, rdes0);
+               netdev = priv->ndevs[id];
+               if (unlikely(!netdev))
+                       continue;
+
+               /* When memory is tight, the buf->addr may be empty */
+               if (unlikely(!buf->page))
+                       break;
+
+               len = FIELD_GET(XGMAC_RDES3_PL, rdes3);
+               dma_sync_single_for_cpu(priv->dev, page_pool_get_dma_addr(buf->page) + buf->offset + BUF_PAD, len, DMA_FROM_DEVICE);
+               prefetch(page_address(buf->page) + buf->offset + BUF_PAD);
+               skb = napi_build_skb(page_address(buf->page) + buf->offset, priv->rx_alloc_size);
+               if (unlikely(!skb))
+                       break;
+
+               buf->page = NULL;
+               skb_mark_for_recycle(skb);
+               skb_reserve(skb, BUF_PAD);
+               __skb_put(skb, len);
+
+               rdes2 = le32_to_cpu(rx.norm.des2);
+               ovid = FIELD_GET(XGMAC_RDES2_OVID, rdes2);
+               no_frag = FIELD_GET(XGMAC_RDES2_DFRAG, rdes2);
+               vlan_pri = FIELD_GET(XGMAC_RDES3_TCI_PRI, rdes3);
+               sta_index = FIELD_GET(XGMAC_RDES0_STA_INDEX, rdes0);
+               rpt_index = FIELD_GET(XGMAC_RDES0_RPT_INDEX, rdes0);
+
+               /* get the context descriptor */
+               rdes_ctx0 = le32_to_cpu(rx.ctxt.des0);
+               rdes_ctx1 = le32_to_cpu(rx.ctxt.des1);
+               rdes_ctx2 = le32_to_cpu(rx.ctxt.des2);
+               rdes_ctx3 = le32_to_cpu(rx.ctxt.des3);
+               sport = FIELD_GET(XGMAC_RDES0_SPORT, rdes_ctx0);
+               eth_type = FIELD_GET(XGMAC_RDES0_ETH_TYPE, rdes_ctx0);
+               dscp = FIELD_GET(XGMAC_RDES1_DSCP, rdes_ctx1);
+               tnp = FIELD_GET(XGMAC_RDES1_TNP, rdes_ctx1);
+               up_reason = FIELD_GET(XGMAC_RDES1_UP_REASON, rdes_ctx1);
+               smac = rdes_ctx2 | FIELD_GET(XGMAC_RDES3_SMAC_32_47, rdes_ctx3) << 32;
+               pkt_type = FIELD_GET(XGMAC_RDES3_PKT_TYPE, rdes_ctx3);
+               pr_debug_ratelimited("%s: up_reason:%02x sta_index:%u rpt_index:%u "
+                               "ovid:%u vlan_pri:%u no_frag:%u sport:%u eth_type:0x%x "
+                               "dscp:%u tnp:%u pkt_type:%u smac:%llx\n",
+                               netdev->name, up_reason, sta_index, rpt_index,
+                               ovid, vlan_pri, no_frag, sport, eth_type,
+                               dscp, tnp, pkt_type, smac);
+
+               xgmac_dma_rx_coe_hash(netdev, skb, rdes0, rdes_ctx1);
+
+               skb_record_rx_queue(skb, rxq->idx);
+               skb->protocol = eth_type_trans(skb, netdev);
+               napi_gro_receive(&rxq->napi, skb);
+       }
+
+       xgmac_dma_rx_refill(priv, rxq);
+
+       return count;
+}
+
+static int xgmac_dma_poll_tx(struct xgmac_txq *txq, int budget)
+{
+       struct xgmac_dma_priv *priv = container_of(txq, struct xgmac_dma_priv,
+                                                  txq[txq->idx]);
+       u32 bytes_compl[DPNS_HOST_PORT] = {}, pkts_compl[DPNS_HOST_PORT] = {};
+       u32 entry, count = 0, i;
+
+       spin_lock_bh(&txq->lock);
+
+       entry = txq->dirty_tx;
+       while (entry != txq->cur_tx && count < budget) {
+               struct xgmac_dma_desc *p = &txq->dma_tx[entry];
+               struct sk_buff *skb = txq->tx_skbuff[entry];
+               u32 tdes3 = le32_to_cpu(READ_ONCE(p->des3));
+
+               /* Check if the descriptor is owned by the DMA */
+               if (unlikely(tdes3 & XGMAC_TDES3_OWN))
+                       break;
+
+               /* Check if the descriptor is a context descriptor */
+               if (unlikely(tdes3 & XGMAC_TDES3_CTXT))
+                       goto next;
+
+               count++;
+               /* Make sure descriptor fields are read after reading
+                * the own bit.
+                */
+               dma_rmb();
+
+               if (likely(txq->tx_skbuff_dma[entry].buf)) {
+                       if (txq->tx_skbuff_dma[entry].map_as_page)
+                               dma_unmap_page(priv->dev,
+                                              txq->tx_skbuff_dma[entry].buf,
+                                              txq->tx_skbuff_dma[entry].len,
+                                              DMA_TO_DEVICE);
+                       else
+                               dma_unmap_single(priv->dev,
+                                                txq->tx_skbuff_dma[entry].buf,
+                                                txq->tx_skbuff_dma[entry].len,
+                                                DMA_TO_DEVICE);
+                       txq->tx_skbuff_dma[entry].buf = 0;
+                       txq->tx_skbuff_dma[entry].len = 0;
+                       txq->tx_skbuff_dma[entry].map_as_page = false;
+               }
+
+               txq->tx_skbuff_dma[entry].last_segment = false;
+
+               if (likely(skb)) {
+                       u8 id = XGMAC_SKB_CB(skb)->id;
+
+                       if (XGMAC_SKB_CB(skb)->fastmode) {
+                               pkts_compl[id]++;
+                               bytes_compl[id] += skb->len;
+                       }
+                       napi_consume_skb(skb, budget);
+                       txq->tx_skbuff[entry] = NULL;
+               }
+
+next:
+               entry = (entry + 1) % DMA_TX_SIZE;
+       }
+       txq->dirty_tx = entry;
+
+       for (i = 0; i < DPNS_HOST_PORT; i++) {
+               struct net_device *dev = priv->ndevs[i];
+               struct netdev_queue *queue;
+
+               if (!dev)
+                       continue;
+
+               queue = netdev_get_tx_queue(dev, txq->idx);
+               netdev_tx_completed_queue(queue, pkts_compl[i], bytes_compl[i]);
+
+               if (unlikely(netif_tx_queue_stopped(queue) &&
+                            xgmac_dma_tx_avail(txq) > DMA_TX_SIZE / 4))
+                       netif_tx_wake_queue(queue);
+       }
+
+       spin_unlock_bh(&txq->lock);
+
+       return count;
+}
+
+static int xgmac_dma_napi_rx(struct napi_struct *napi, int budget)
+{
+       struct xgmac_rxq *rxq = container_of(napi, struct xgmac_rxq, napi);
+       int work_done;
+
+       work_done = xgmac_dma_poll_rx(rxq, budget);
+       if (work_done < budget && napi_complete_done(napi, work_done))
+               enable_irq(rxq->irq);
+
+       return work_done;
+}
+
+static int xgmac_dma_napi_tx(struct napi_struct *napi, int budget)
+{
+       struct xgmac_txq *txq = container_of(napi, struct xgmac_txq, napi);
+       int work_done = xgmac_dma_poll_tx(txq, budget);
+
+       if (work_done < budget && napi_complete_done(napi, work_done))
+               enable_irq(txq->irq);
+
+       return work_done;
+}
+
+static irqreturn_t xgmac_dma_irq_misc(int irq, void *dev_id)
+{
+       struct xgmac_dma_priv *priv = dev_id;
+       u32 mtl_status = reg_read(priv, XGMAC_MTL_INT_STATUS);
+       u32 dma_status = reg_read(priv, XGMAC_DMA_INT_STATUS);
+       u32 i;
+
+       //dev_info(priv->dev, "irq %d mtl %#08x dma %#08x\n",
+       //              irq, mtl_status, dma_status);
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               if (BIT(i) & mtl_status) {
+                       u32 status = reg_read(priv, XGMAC_MTL_QINT_STATUS(i));
+
+                       if (status & XGMAC_RXOVFIS)
+                               pr_debug_ratelimited("RX queue %u overflow\n", i);
+
+                       /* Clear interrupts */
+                       reg_write(priv, XGMAC_MTL_QINT_STATUS(i), status);
+               }
+
+               if (BIT(i) & dma_status) {
+                       u32 status = reg_read(priv, XGMAC_DMA_CH_STATUS(i));
+                       status &= ~(XGMAC_TI | XGMAC_TBU | XGMAC_RI);
+
+                       /* ABNORMAL interrupts */
+                       if (unlikely(status & XGMAC_AIS)) {
+                               if (status & XGMAC_CDE)
+                                       dev_info(priv->dev, "Trigger queue %u CDE\n", i);
+
+                               if (status & XGMAC_DDE)
+                                       dev_info(priv->dev, "Trigger queue %u DDE\n", i);
+
+                               if (status & XGMAC_FBE) {
+                                       dev_info(priv->dev, "Trigger queue %u FBE\n", i);
+                                       /* TODO: restart TX */
+                               }
+
+                               if (status & XGMAC_RBU) {
+                                       pr_debug_ratelimited("Trigger queue %u RBU\n", i);
+                               }
+                       }
+
+                       reg_write(priv, XGMAC_DMA_CH_STATUS(i), status);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t xgmac_dma_irq_tx(int irq, void *dev_id)
+{
+       struct xgmac_txq *txq = dev_id;
+       struct xgmac_dma_priv *priv = container_of(txq, struct xgmac_dma_priv,
+                                                  txq[txq->idx]);
+       u16 channel = txq->idx;
+       u32 status = reg_read(priv, XGMAC_DMA_CH_STATUS(channel)) &
+               (XGMAC_TBU | XGMAC_TI);
+
+       if (unlikely(!status))
+               return IRQ_NONE;
+
+       /* Clear interrupts */
+       reg_write(priv, XGMAC_DMA_CH_STATUS(channel), status);
+
+       /* TX NORMAL interrupts */
+       if (likely(napi_schedule_prep(&txq->napi))) {
+               /* Disable TX interrupt */
+               disable_irq_nosync(irq);
+
+               /* Turn on polling */
+               __napi_schedule_irqoff(&txq->napi);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t xgmac_dma_irq_rx(int irq, void *dev_id)
+{
+       struct xgmac_rxq *rxq = dev_id;
+       struct xgmac_dma_priv *priv = container_of(rxq, struct xgmac_dma_priv,
+                                                  rxq[rxq->idx]);
+       u16 channel = rxq->idx;
+       u32 status = reg_read(priv, XGMAC_DMA_CH_STATUS(channel)) &
+               (XGMAC_RI);
+
+       if (unlikely(!status))
+               return IRQ_NONE;
+
+       /* Clear interrupts */
+       reg_write(priv, XGMAC_DMA_CH_STATUS(channel), status);
+
+       /* RX NORMAL interrupts */
+       if (likely(napi_schedule_prep(&rxq->napi))) {
+               /* Disable RX interrupt */
+               disable_irq_nosync(irq);
+
+               /* Turn on polling */
+               __napi_schedule_irqoff(&rxq->napi);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int xgmac_dma_soft_reset(struct xgmac_dma_priv *priv)
+{
+       unsigned long timeout = jiffies + HZ;
+
+       reg_write(priv, XGMAC_DMA_MODE, XGMAC_SWR);
+       do {
+               if (!(reg_read(priv, XGMAC_DMA_MODE) & XGMAC_SWR))
+                       return 0;
+
+               cond_resched();
+       } while (time_after(timeout, jiffies));
+
+       dev_err(priv->dev, "DMA reset timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int xgmac_dma_init(struct xgmac_dma_priv *priv)
+{
+       int ret;
+       u32 i;
+
+       /* DMA SW reset */
+       ret = xgmac_dma_soft_reset(priv);
+       if (ret)
+               return ret;
+
+       /* DMA Configuration */
+       /* Exclude per-channel interrupts from sbd_intr_o */
+       reg_write(priv, XGMAC_DMA_MODE, FIELD_PREP(XGMAC_INTM, 1));
+       reg_rmw(priv, XGMAC_DMA_SYSBUS_MODE,
+               XGMAC_RD_OSR_LMT | XGMAC_WR_OSR_LMT,
+               FIELD_PREP(XGMAC_RD_OSR_LMT, 31) | XGMAC_EN_LPI |
+               FIELD_PREP(XGMAC_WR_OSR_LMT, 31) | XGMAC_UNDEF);
+
+       reg_write(priv, XGMAC_TX_EDMA_CTRL, 1);
+       reg_write(priv, XGMAC_RX_EDMA_CTRL, 1);
+
+       /* enable rx_queue 0 1 2 3 */
+       regmap_write(priv->ethsys, ETHSYS_RX_QUEUE_ENABLE, 0xAA);
+
+       /* Use static RX Queue to DMA mapping
+        * queue 0 to channel 0
+        * queue 1 to channel 1
+        * queue 2 to channel 2
+        * queue 3 to chennel 3
+        * queue 4 to channel 4
+       */
+       reg_write(priv, XGMAC_MTL_RXQ_DMA_MAP0, 0x03020100);
+       reg_write(priv, XGMAC_MTL_RXQ_DMA_MAP1, 0x4);
+
+       /* DMA Channel Configuration
+        * TXQs share 8KB, RXQs share 16KB
+        *
+        * Configured queue size = 256B * (1 + (TQS or RQS field))
+        *
+        * The maximum limit of PBL is queue size / datawidth / 2
+        *
+        * TxPBL must be limited to 32 for Tx COE to work on 1500 MTU, see the
+        * comment in xgmac_dma_xmit() for detail.
+        */
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               /* set RxPBL to 16 beats for ddr schedule with 128bit (16*8) */
+               reg_rmw(priv, XGMAC_DMA_CH_RX_CONTROL(i), XGMAC_RxPBL,
+                       FIELD_PREP(XGMAC_RxPBL, 16));
+               /* set TxPBL to 16 beats for ddr schedule with 128bit (16*8) */
+               reg_rmw(priv, XGMAC_DMA_CH_TX_CONTROL(i), XGMAC_TxPBL,
+                       FIELD_PREP(XGMAC_TxPBL, 16) | XGMAC_TSE | XGMAC_OSP);
+
+               /* Enable TX queue, store-and-forward mode
+                * each queue size 2k bytes
+                */
+               reg_rmw(priv, XGMAC_MTL_TXQ_OPMODE(i), XGMAC_TQS | XGMAC_TXQEN,
+                       FIELD_PREP(XGMAC_TQS, 0x7) | XGMAC_TSF |
+                               FIELD_PREP(XGMAC_TXQEN, 0x2));
+
+               /* Enable RX queue
+                * each queue size 4k bytes
+                */
+               reg_write(priv, XGMAC_MTL_RXQ_OPMODE(i),
+                         FIELD_PREP(XGMAC_RQS, 0xf));
+       }
+
+       return 0;
+}
+
+static void xgmac_dma_free_rx_buffer(struct xgmac_dma_priv *priv, struct xgmac_rxq *rxq, u32 i)
+{
+       struct xgmac_dma_rx_buffer *buf = &rxq->buf_pool[i];
+
+       if (buf->page) {
+               page_pool_put_full_page(rxq->page_pool, buf->page, false);
+               buf->page = NULL;
+       }
+}
+
+static int xgmac_dma_init_rx_buffers(struct xgmac_dma_priv *priv, struct xgmac_rxq *rxq, u32 i,
+                                    struct xgmac_dma_desc *p, u16 rx_alloc_size)
+{
+       struct xgmac_dma_rx_buffer *buf = &rxq->buf_pool[i];
+
+       buf->page = page_pool_dev_alloc_frag(rxq->page_pool, &buf->offset, rx_alloc_size);
+       if (!buf->page)
+               return -ENOMEM;
+
+       xgmac_dma_init_rx_desc(p, page_pool_get_dma_addr(buf->page) + buf->offset + BUF_PAD, false);
+
+       return 0;
+}
+
+static int xgmac_dma_init_rx_rings(struct xgmac_dma_priv *priv)
+{
+       u32 queue, i;
+       int ret;
+
+       for (queue = 0; queue < DMA_CH_MAX; queue++) {
+               struct xgmac_rxq *rxq = &priv->rxq[queue];
+
+               for (i = 0; i < DMA_RX_SIZE; i += 2) {
+                       struct xgmac_dma_desc *p = &rxq->dma_rx[i];
+
+                       ret = xgmac_dma_init_rx_buffers(priv, rxq, i, p, priv->rx_alloc_size);
+                       if (ret)
+                               goto err_init_rx_buffers;
+                       /* No buffer space required by context descs */
+                       xgmac_dma_init_rx_desc(p + 1, 0, false);
+               }
+
+               rxq->cur_rx = 0;
+               rxq->dirty_rx = (unsigned int)(i - DMA_RX_SIZE);
+       }
+
+       return 0;
+
+err_init_rx_buffers:
+       while (queue >= 0) {
+               while (--i >= 0)
+                       xgmac_dma_free_rx_buffer(priv, &priv->rxq[queue], i);
+
+               if (queue == 0)
+                       break;
+
+               i = DMA_RX_SIZE;
+               queue--;
+       }
+
+       return ret;
+}
+
+static void xgmac_dma_init_tx_rings(struct xgmac_dma_priv *priv)
+{
+       u32 queue, i;
+
+       for (queue = 0; queue < DMA_CH_MAX; queue++) {
+               struct xgmac_txq *txq = &priv->txq[queue];
+
+               for (i = 0; i < DMA_TX_SIZE; i++) {
+                       struct xgmac_dma_desc *p = &txq->dma_tx[i];
+
+                       memset(p, 0, sizeof(*p));
+
+                       txq->tx_skbuff_dma[i].buf = 0;
+                       txq->tx_skbuff_dma[i].map_as_page = false;
+                       txq->tx_skbuff_dma[i].len = 0;
+                       txq->tx_skbuff_dma[i].last_segment = false;
+                       txq->tx_skbuff[i] = NULL;
+               }
+
+               txq->dirty_tx = 0;
+               txq->cur_tx = 0;
+       }
+}
+
+static void xgmac_dma_free_tx_buffer(struct xgmac_txq *txq, u32 i)
+{
+       struct xgmac_dma_priv *priv = container_of(txq, struct xgmac_dma_priv,
+                                                  txq[txq->idx]);
+
+       if (txq->tx_skbuff_dma[i].buf) {
+               if (txq->tx_skbuff_dma[i].map_as_page)
+                       dma_unmap_page(priv->dev,
+                                      txq->tx_skbuff_dma[i].buf,
+                                      txq->tx_skbuff_dma[i].len,
+                                      DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(priv->dev,
+                                        txq->tx_skbuff_dma[i].buf,
+                                        txq->tx_skbuff_dma[i].len,
+                                        DMA_TO_DEVICE);
+       }
+
+       if (txq->tx_skbuff[i]) {
+               dev_kfree_skb(txq->tx_skbuff[i]);
+               txq->tx_skbuff[i] = NULL;
+               txq->tx_skbuff_dma[i].buf = 0;
+               txq->tx_skbuff_dma[i].map_as_page = false;
+       }
+}
+
+static void xgmac_dma_free_rx_skbufs(struct xgmac_dma_priv *priv, struct xgmac_rxq *rxq)
+{
+       u32 i;
+
+       for (i = 0; i < DMA_RX_SIZE; i++)
+               xgmac_dma_free_rx_buffer(priv, rxq, i);
+}
+
+static void xgmac_dma_free_tx_skbufs(struct xgmac_txq *txq)
+{
+       u32 i;
+
+       for (i = 0; i < DMA_TX_SIZE; i++)
+               xgmac_dma_free_tx_buffer(txq, i);
+}
+
+static void xgmac_dma_free_rx_descs(struct xgmac_dma_priv *priv)
+{
+       u32 i;
+
+       /* Free RX queue resources */
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_rxq *rxq = &priv->rxq[i];
+
+               /* Release the DMA RX socket buffers */
+               xgmac_dma_free_rx_skbufs(priv, rxq);
+
+               /* Free DMA RX descs */
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+               gen_pool_free(priv->genpool, (uintptr_t)rxq->dma_rx,
+                             DMA_RX_SIZE * sizeof(*rxq->dma_rx));
+#else
+               dma_free_coherent(priv->dev, DMA_RX_SIZE * sizeof(*rxq->dma_rx),
+                                 (void *)rxq->dma_rx, rxq->dma_rx_phy);
+#endif
+
+               kfree(rxq->buf_pool);
+               if (rxq->page_pool)
+                       page_pool_destroy(rxq->page_pool);
+       }
+}
+
+static void xgmac_dma_free_tx_descs(struct xgmac_dma_priv *priv)
+{
+       u32 i;
+
+       /* Free TX queue resources */
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_txq *txq = &priv->txq[i];
+               spin_lock_bh(&txq->lock);
+               txq->is_busy = true;
+               spin_unlock_bh(&txq->lock);
+               /* Release the DMA TX socket buffers */
+               xgmac_dma_free_tx_skbufs(txq);
+
+               /* Free DMA TX descs */
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+               gen_pool_free(priv->genpool, (uintptr_t)txq->dma_tx,
+                             DMA_TX_SIZE * sizeof(*txq->dma_tx));
+#else
+               dma_free_coherent(priv->dev, DMA_TX_SIZE * sizeof(*txq->dma_tx),
+                                 txq->dma_tx, txq->dma_tx_phy);
+#endif
+               txq->dma_tx = NULL;
+               kfree(txq->tx_skbuff_dma);
+               txq->tx_skbuff_dma = NULL;
+               kfree(txq->tx_skbuff);
+               txq->tx_skbuff = NULL;
+
+               spin_lock_bh(&txq->lock);
+               txq->is_busy = false;
+               spin_unlock_bh(&txq->lock);
+       }
+}
+
+static int xgmac_dma_alloc_rx_descs(struct xgmac_dma_priv *priv)
+{
+       struct page_pool_params pp_params = {};
+       int ret = -ENOMEM;
+       u32 i;
+
+       pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV | PP_FLAG_PAGE_FRAG;
+       pp_params.pool_size = DMA_RX_SIZE;
+       pp_params.order = 0;
+       pp_params.max_len = PAGE_SIZE;
+       pp_params.nid = dev_to_node(priv->dev);
+       pp_params.dev = priv->dev;
+       pp_params.dma_dir = DMA_FROM_DEVICE;
+
+       /* RX queues buffers and DMA */
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_rxq *rxq = &priv->rxq[i];
+
+               rxq->page_pool = page_pool_create(&pp_params);
+               if (IS_ERR(rxq->page_pool)) {
+                       ret = PTR_ERR(rxq->page_pool);
+                       rxq->page_pool = NULL;
+                       goto err_dma;
+               }
+
+               rxq->buf_pool = kcalloc(DMA_RX_SIZE, sizeof(*rxq->buf_pool),
+                                       GFP_KERNEL);
+               if (!rxq->buf_pool)
+                       goto err_dma;
+
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+               rxq->dma_rx = gen_pool_dma_alloc(priv->genpool, DMA_RX_SIZE *
+                                                sizeof(*rxq->dma_rx),
+                                                &rxq->dma_rx_phy);
+#else
+               rxq->dma_rx = dma_alloc_coherent(priv->dev, DMA_RX_SIZE *
+                                                sizeof(*rxq->dma_rx),
+                                                &rxq->dma_rx_phy, GFP_KERNEL);
+#endif
+               if (!rxq->dma_rx)
+                       goto err_dma;
+       }
+
+       return 0;
+
+err_dma:
+       xgmac_dma_free_rx_descs(priv);
+       return ret;
+}
+
+static int xgmac_dma_alloc_tx_descs(struct xgmac_dma_priv *priv)
+{
+       int ret = -ENOMEM;
+       u32 i;
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_txq *txq = &priv->txq[i];
+
+               txq->tx_skbuff_dma = kcalloc(DMA_TX_SIZE,
+                                            sizeof(*txq->tx_skbuff_dma),
+                                            GFP_KERNEL);
+               if (!txq->tx_skbuff_dma)
+                       goto err_dma;
+
+               txq->tx_skbuff = kcalloc(DMA_TX_SIZE,
+                                        sizeof(struct sk_buff *),
+                                        GFP_KERNEL);
+               if (!txq->tx_skbuff)
+                       goto err_dma;
+
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+               txq->dma_tx = gen_pool_dma_zalloc(priv->genpool, DMA_TX_SIZE *
+                                                 sizeof(*txq->dma_tx),
+                                                 &txq->dma_tx_phy);
+#else
+               txq->dma_tx = dma_alloc_coherent(priv->dev, DMA_TX_SIZE *
+                                                sizeof(*txq->dma_tx),
+                                                &txq->dma_tx_phy, GFP_KERNEL);
+#endif
+               if (!txq->dma_tx)
+                       goto err_dma;
+       }
+
+       return 0;
+
+err_dma:
+       xgmac_dma_free_tx_descs(priv);
+       return ret;
+}
+
+static int xgmac_dma_enable(struct xgmac_dma_priv *priv)
+{
+       int ret;
+       u32 i;
+
+       ret = xgmac_dma_alloc_rx_descs(priv);
+       if (ret)
+               return ret;
+
+       ret = xgmac_dma_init_rx_rings(priv);
+       if (ret)
+               return ret;
+
+       ret = xgmac_dma_alloc_tx_descs(priv);
+       if (ret)
+               return ret;
+
+       xgmac_dma_init_tx_rings(priv);
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_rxq *rxq = &priv->rxq[i];
+               struct xgmac_txq *txq = &priv->txq[i];
+
+               /*
+                * Initiate the WDT with packet count of 32 to enable IRQ
+                * set watchdog timer 2048 * 100 * 2.5ns = 0.512ms
+                * */
+               reg_write(priv, XGMAC_DMA_CH_Rx_WATCHDOG(i),
+                         XGMAC_PSEL | FIELD_PREP(XGMAC_RBCT, 32) |
+                         FIELD_PREP(XGMAC_RWTU, 3) | FIELD_PREP(XGMAC_RWT, 100));
+
+               /* Set RX buffer size */
+               reg_rmw(priv, XGMAC_DMA_CH_RX_CONTROL(i), XGMAC_RBSZ,
+                       FIELD_PREP(XGMAC_RBSZ, priv->rx_buffer_size));
+
+               /* Set head pointer */
+               xgmac_dma_set_rx_head_ptr(priv, rxq->dma_rx_phy, i);
+               xgmac_dma_set_tx_head_ptr(priv, txq->dma_tx_phy, i);
+
+               /* Set tail pointer */
+               rxq->rx_tail_addr = DMA_RX_SIZE * sizeof(*rxq->dma_rx) +
+                                   rxq->dma_rx_phy;
+               txq->tx_tail_addr = txq->dma_tx_phy;
+               xgmac_dma_set_rx_tail_ptr(priv, rxq->rx_tail_addr, i);
+               xgmac_dma_set_tx_tail_ptr(priv, txq->tx_tail_addr, i);
+
+               /* Set ring length */
+               reg_write(priv, XGMAC_DMA_CH_RxDESC_RING_LEN(i),
+                         ((DMA_RX_SIZE - 1) | (FIELD_PREP(XGMAC_OWRQ, 7))));
+               reg_write(priv, XGMAC_DMA_CH_TxDESC_RING_LEN(i),
+                         DMA_TX_SIZE - 1);
+
+               /* Enable NAPI poll */
+               napi_enable(&rxq->napi);
+               napi_enable(&txq->napi);
+
+               /* Enable interrupt */
+               reg_write(priv, XGMAC_DMA_CH_INT_EN(i),
+                         XGMAC_DMA_INT_DEFAULT_EN);
+
+               /* Enable MTL RX overflow interrupt */
+               reg_write(priv, XGMAC_MTL_QINTEN(i), XGMAC_RXOIE);
+
+               /* Start DMA */
+               reg_set(priv, XGMAC_DMA_CH_RX_CONTROL(i), XGMAC_RXST);
+               reg_set(priv, XGMAC_DMA_CH_TX_CONTROL(i), XGMAC_TXST);
+       }
+
+       return 0;
+}
+
+static void xgmac_dma_disable(struct xgmac_dma_priv *priv)
+{
+       u32 i;
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct xgmac_rxq *rxq = &priv->rxq[i];
+               struct xgmac_txq *txq = &priv->txq[i];
+
+               /* Disable interrupts */
+               reg_write(priv, XGMAC_DMA_CH_INT_EN(i), 0);
+               reg_write(priv, XGMAC_MTL_QINTEN(i), 0);
+
+               /* Disable DMA transfer */
+               reg_clear(priv, XGMAC_DMA_CH_RX_CONTROL(i), XGMAC_RXST);
+               reg_clear(priv, XGMAC_DMA_CH_TX_CONTROL(i), XGMAC_TXST);
+
+               /* Disable NAPI poll */
+               napi_disable(&rxq->napi);
+               napi_disable(&txq->napi);
+
+               /* Clear all pending interrupts */
+               reg_write(priv, XGMAC_DMA_CH_STATUS(i), -1);
+               reg_write(priv, XGMAC_MTL_QINT_STATUS(i), -1);
+       }
+
+       /* Free resources */
+       xgmac_dma_free_rx_descs(priv);
+       xgmac_dma_free_tx_descs(priv);
+}
+
+static void xgmac_dma_stop_queue(struct xgmac_dma_priv *priv, int queue)
+{
+       int i;
+
+       for (i = 0; i < 6; i++) {
+               struct net_device *dev = priv->ndevs[i];
+
+               if (!dev)
+                       continue;
+
+               netif_tx_stop_queue(netdev_get_tx_queue(dev, queue));
+       }
+}
+
+static void xgmac_dma_tso_fill_desc(struct xgmac_txq *txq, dma_addr_t des,
+                                   unsigned int pay_len, bool last_segment)
+{
+       struct xgmac_dma_desc *desc;
+       int tmp_len = pay_len;
+       u32 entry;
+
+       /* 1. put every 2 16K-1 buffers into one desc */
+       while (tmp_len > TSO_MAX_BUFF_SIZE) {
+               bool ld = (last_segment && tmp_len <= TSO_MAX_BUFF_SIZE * 2);
+               entry = txq->cur_tx;
+               entry = (entry + 1) % DMA_TX_SIZE;
+               txq->cur_tx = entry;
+               desc = &txq->dma_tx[entry];
+
+               desc->des0 = cpu_to_le32(des);
+               desc->des1 = cpu_to_le32(des + TSO_MAX_BUFF_SIZE);
+               desc->des2 = cpu_to_le32((ld ? XGMAC_TDES2_IOC : 0) | XGMAC_TDES2_B1L |
+                                        FIELD_PREP(XGMAC_TDES2_B2L,
+                                                   min(tmp_len - TSO_MAX_BUFF_SIZE,
+                                                       TSO_MAX_BUFF_SIZE)));
+               desc->des3 = cpu_to_le32(XGMAC_TDES3_OWN |
+                                        (ld ? XGMAC_TDES3_LD : 0));
+
+               tmp_len -= TSO_MAX_BUFF_SIZE * 2;
+               des += TSO_MAX_BUFF_SIZE * 2;
+       }
+       /* 2. put the last buffer, if exists */
+       if (tmp_len > 0) {
+               entry = txq->cur_tx;
+               entry = (entry + 1) % DMA_TX_SIZE;
+               txq->cur_tx = entry;
+               desc = &txq->dma_tx[entry];
+
+               desc->des0 = cpu_to_le32(des);
+               desc->des1 = cpu_to_le32(0);
+               desc->des2 = cpu_to_le32((last_segment ? XGMAC_TDES2_IOC : 0) |
+                                        FIELD_PREP(XGMAC_TDES2_B1L, tmp_len));
+               desc->des3 = cpu_to_le32(XGMAC_TDES3_OWN |
+                                        (last_segment ? XGMAC_TDES3_LD : 0));
+       }
+}
+
+static netdev_tx_t xgmac_dma_tso_xmit(struct sk_buff *skb,
+                                     struct xgmac_dma_priv *priv)
+{
+       u16 queue = skb_get_queue_mapping(skb);
+       u16 channel = queue;
+       u32 size = (queue == DMA_CH_DISABLE) ? SZ_2K : SZ_1_5K;
+       struct xgmac_txq *txq = &priv->txq[queue];
+       struct xgmac_dma_desc *desc, *first, *ctxt;
+       struct xgmac_skb_cb *cb = XGMAC_SKB_CB(skb);
+       u8 nfrags = skb_shinfo(skb)->nr_frags;
+       struct net_device *dev = skb->dev;
+       u32 first_entry, entry, i, tdes0, pay_len;
+       u32 proto_hdr_len, hdr;
+       bool last_segment;
+       dma_addr_t des;
+       u16 mss;
+
+       hdr = tcp_hdrlen(skb);
+       proto_hdr_len = skb_transport_offset(skb) + hdr;
+       pay_len = skb_headlen(skb) - proto_hdr_len; /* no frags */
+
+       spin_lock(&txq->lock);
+       /* Desc availability based on threshold should be enough safe */
+       if (unlikely(xgmac_dma_tx_avail(txq) <
+                    max_t(u32, nfrags, (skb->len - proto_hdr_len) / TSO_MAX_BUFF_SIZE) + 2)) {
+               xgmac_dma_stop_queue(priv, queue);
+               pr_debug_ratelimited("%s: Tx Ring full when queue awake\n",
+                       __func__);
+               spin_unlock(&txq->lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       mss = skb_shinfo(skb)->gso_size;
+       /* The header length + MSS + TxPBL must be less than Tx Queue size */
+       mss = min_t(u16, mss, size - 16 - proto_hdr_len - 1);
+
+       entry = txq->cur_tx;
+       desc = &txq->dma_tx[entry];
+       ctxt = desc;
+       /* Prepare TX context descriptor */
+       tdes0 = XGMAC_TDES0_FAST_MODE |
+               FIELD_PREP(XGMAC_TDES0_OVPORT, cb->id) |
+               FIELD_PREP(XGMAC_TDES0_IVPORT, DPNS_HOST_PORT);
+       ctxt->des0 = cpu_to_le32(tdes0);
+       ctxt->des1 = 0;
+       ctxt->des2 = cpu_to_le32(mss);
+
+       entry = (entry + 1) % DMA_TX_SIZE;
+       txq->cur_tx = first_entry = entry;
+       desc = &txq->dma_tx[entry];
+       first = desc;
+
+       /* first descriptor: fill Headers on Buf1 */
+       last_segment = (nfrags == 0);
+       des = dma_map_single(priv->dev, skb->data, skb_headlen(skb),
+                            DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(priv->dev, des)))
+               goto drop;
+
+       txq->tx_skbuff_dma[first_entry].buf = des;
+       txq->tx_skbuff_dma[first_entry].len = skb_headlen(skb);
+       first->des0 = cpu_to_le32(des);
+
+       /* Fill start of payload in buff2 of first descriptor */
+       first->des1 = cpu_to_le32(pay_len ? des + proto_hdr_len : 0);
+       if (pay_len > TSO_MAX_BUFF_SIZE) {
+               /* Need more descs if the buffer size > 16383 */
+               pay_len -= TSO_MAX_BUFF_SIZE;
+               first->des2 =
+                       cpu_to_le32(FIELD_PREP(XGMAC_TDES2_B1L, proto_hdr_len) |
+                                   XGMAC_TDES2_B2L);
+               des += proto_hdr_len + TSO_MAX_BUFF_SIZE;
+       } else {
+               first->des2 =
+                       cpu_to_le32((last_segment ? XGMAC_TDES2_IOC : 0) |
+                                   FIELD_PREP(XGMAC_TDES2_B1L, proto_hdr_len) |
+                                   FIELD_PREP(XGMAC_TDES2_B2L, pay_len));
+               pay_len = 0;
+       }
+       first->des3 = cpu_to_le32(
+               XGMAC_TDES3_OWN | XGMAC_TDES3_FD |
+               (last_segment && !pay_len ? XGMAC_TDES3_LD : 0) |
+               FIELD_PREP(XGMAC_TDES3_THL, hdr / 4) | XGMAC_TDES3_TSE |
+               FIELD_PREP(XGMAC_TDES3_TPL, skb->len - proto_hdr_len));
+
+       /* Put the remaining headlen buffer */
+       xgmac_dma_tso_fill_desc(txq, des, pay_len, last_segment);
+       entry = txq->cur_tx;
+       /* Prepare fragments */
+       for (i = 0; i < nfrags; i++) {
+               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               des = skb_frag_dma_map(priv->dev, frag, 0, skb_frag_size(frag),
+                                      DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(priv->dev, des)))
+                       goto drop;
+
+               last_segment = (i == nfrags - 1);
+
+               xgmac_dma_tso_fill_desc(txq, des, skb_frag_size(frag), last_segment);
+               entry = txq->cur_tx;
+               txq->tx_skbuff_dma[entry].buf = des;
+               txq->tx_skbuff_dma[entry].len = skb_frag_size(frag);
+               txq->tx_skbuff_dma[entry].map_as_page = true;
+       }
+       txq->tx_skbuff_dma[entry].last_segment = true;
+       /* Only the last descriptor gets to point to the skb. */
+       txq->tx_skbuff[entry] = skb;
+
+       /* We've used all descriptors we need for this skb, however,
+        * advance cur_tx so that it references a fresh descriptor.
+        * ndo_start_xmit will fill this descriptor the next time it's
+        * called and xgmac_dma_poll_tx may clean up to this descriptor.
+        */
+       entry = (entry + 1) % DMA_TX_SIZE;
+       txq->cur_tx = entry;
+
+       if (unlikely(xgmac_dma_tx_avail(txq) <= (MAX_SKB_FRAGS + 1)))
+               xgmac_dma_stop_queue(priv, queue);
+
+       skb_tx_timestamp(skb);
+       ctxt->des3 = cpu_to_le32(XGMAC_TDES3_OWN | XGMAC_TDES3_CTXT |
+                                XGMAC_TDES3_TCMSSV | XGMAC_TDES3_PIDV);
+       dma_wmb();
+       netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len);
+       txq->tx_tail_addr = txq->dma_tx_phy + txq->cur_tx * sizeof(*desc);
+       xgmac_dma_set_tx_tail_ptr(priv, txq->tx_tail_addr, channel);
+       spin_unlock(&txq->lock);
+       return NETDEV_TX_OK;
+drop:
+       dev->stats.tx_dropped++;
+       spin_unlock(&txq->lock);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+
+netdev_tx_t xgmac_dma_xmit(struct sk_buff *skb, struct xgmac_dma_priv *priv)
+{
+       u16 queue = skb_get_queue_mapping(skb);
+       u16 channel = queue;
+       u32 size = (queue == DMA_CH_DISABLE) ? SZ_2K : SZ_1_5K;
+       struct xgmac_txq *txq = &priv->txq[queue];
+       u8 nfrags = skb_shinfo(skb)->nr_frags;
+       struct xgmac_dma_desc *desc, *first, *ctxt;
+       struct xgmac_skb_cb *cb = XGMAC_SKB_CB(skb);
+       struct net_device *dev = skb->dev;
+       u32 nopaged_len = skb_headlen(skb);
+       u32 first_entry, entry, i, tdes0, cic = 0;
+       bool last_segment;
+       dma_addr_t des;
+
+       if (skb_is_gso(skb) && skb_is_gso_tcp(skb))
+               return xgmac_dma_tso_xmit(skb, priv);
+
+       if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+               /* Tx COE only works with packets that are LESS THAN the
+                * following number of bytes in size:
+                * TXQ SIZE in bytes â€“ ((PBL + 5)*(DATAWIDTH in bytes))
+                *
+                * Thus for queue size of 2K, Tx COE of 1500 MTU works only if
+                * PBL <= 32.
+                */
+               const unsigned int txcoeovh = (16 + 5) * 8;
+
+               if (unlikely(skb->len >= size - txcoeovh)) {
+                       if (unlikely(skb_checksum_help(skb)))
+                               goto drop_kfree;
+               } else {
+                       cic = XGMAC_TDES3_CIC;
+               }
+       }
+
+       spin_lock(&txq->lock);
+       if (txq->is_busy || (NULL == txq->dma_tx) || (NULL == txq->tx_skbuff_dma) || (NULL == txq->tx_skbuff)) {
+               spin_unlock(&txq->lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       /* We need at least 2 + nfrags free TX descriptors to xmit a packet */
+       if (unlikely(xgmac_dma_tx_avail(txq) < nfrags + 2)) {
+               xgmac_dma_stop_queue(priv, queue);
+               pr_debug_ratelimited("%s: Tx Ring full when queue awake\n",
+                       __func__);
+               spin_unlock(&txq->lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       entry = txq->cur_tx;
+       desc = &txq->dma_tx[entry];
+       ctxt = desc;
+
+       /* Prepare TX context descriptor */
+       if (cb->fastmode)
+               tdes0 = XGMAC_TDES0_FAST_MODE |
+                       FIELD_PREP(XGMAC_TDES0_OVPORT, cb->id) |
+                       FIELD_PREP(XGMAC_TDES0_IVPORT, DPNS_HOST_PORT);
+       else
+               tdes0 = FIELD_PREP(XGMAC_TDES0_OVPORT, DPNS_HOST_PORT) |
+                       FIELD_PREP(XGMAC_TDES0_IVPORT, cb->id);
+
+       ctxt->des0 = cpu_to_le32(tdes0);
+       ctxt->des1 = 0;
+       ctxt->des2 = 0;
+
+       entry = (entry + 1) % DMA_TX_SIZE;
+       first_entry = entry;
+       desc = &txq->dma_tx[entry];
+       first = desc;
+
+       for (i = 0; i < nfrags; i++) {
+               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               u32 len = skb_frag_size(frag);
+
+               last_segment = (i == (nfrags - 1));
+               entry = (entry + 1) % DMA_TX_SIZE;
+               desc = &txq->dma_tx[entry];
+               des = skb_frag_dma_map(priv->dev, frag, 0, len, DMA_TO_DEVICE);
+               if (dma_mapping_error(priv->dev, des))
+                       goto drop;
+
+               txq->tx_skbuff_dma[entry].buf = des;
+
+               xgmac_dma_set_tx_desc_addr(desc, des);
+
+               txq->tx_skbuff_dma[entry].map_as_page = true;
+               txq->tx_skbuff_dma[entry].len = len;
+               txq->tx_skbuff_dma[entry].last_segment = last_segment;
+               /* Prepare the descriptor and set the own bit too */
+               desc->des2 = cpu_to_le32(FIELD_PREP(XGMAC_TDES2_B1L, len) |
+                                        (last_segment ? XGMAC_TDES2_IOC : 0));
+               desc->des3 = cpu_to_le32(XGMAC_TDES3_OWN | cic |
+                                        (last_segment ? XGMAC_TDES3_LD : 0) |
+                                        FIELD_PREP(XGMAC_TDES3_FL, skb->len));
+       }
+
+       /* Only the last descriptor gets to point to the skb. */
+       txq->tx_skbuff[entry] = skb;
+
+       /* We've used all descriptors we need for this skb, however,
+        * advance cur_tx so that it references a fresh descriptor.
+        * ndo_start_xmit will fill this descriptor the next time it's
+        * called and xgmac_dma_poll_tx may clean up to this descriptor.
+        */
+       entry = (entry + 1) % DMA_TX_SIZE;
+       txq->cur_tx = entry;
+
+       if (unlikely(xgmac_dma_tx_avail(txq) <= (MAX_SKB_FRAGS + 1)))
+               xgmac_dma_stop_queue(priv, queue);
+
+       skb_tx_timestamp(skb);
+
+       /* Ready to fill the first descriptor and set the OWN bit w/o any
+        * problems because all the descriptors are actually ready to be
+        * passed to the DMA engine.
+        */
+       last_segment = (nfrags == 0);
+       des = dma_map_single(priv->dev, skb->data, nopaged_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(priv->dev, des))
+               goto drop;
+
+       txq->tx_skbuff_dma[first_entry].buf = des;
+       txq->tx_skbuff_dma[first_entry].len = nopaged_len;
+       txq->tx_skbuff_dma[first_entry].last_segment = last_segment;
+       /* Prepare the first descriptor setting the OWN bit too */
+       xgmac_dma_set_tx_desc_addr(first, des);
+       first->des2 = cpu_to_le32(FIELD_PREP(XGMAC_TDES2_B1L, nopaged_len) |
+                                 (last_segment ? XGMAC_TDES2_IOC : 0));
+       first->des3 = cpu_to_le32(XGMAC_TDES3_OWN | XGMAC_TDES3_FD | cic |
+                                 (last_segment ? XGMAC_TDES3_LD : 0) |
+                                 FIELD_PREP(XGMAC_TDES3_FL, skb->len));
+
+       ctxt->des3 = cpu_to_le32(XGMAC_TDES3_OWN | XGMAC_TDES3_CTXT | XGMAC_TDES3_PIDV);
+       /* The descriptor must be set before tail poiner update and then barrier
+        * is needed to make sure that all is coherent before granting the
+        * DMA engine.
+        */
+       dma_wmb();
+
+       if (dev)
+               netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len);
+       txq->tx_tail_addr = txq->dma_tx_phy + txq->cur_tx * sizeof(*desc);
+       xgmac_dma_set_tx_tail_ptr(priv, txq->tx_tail_addr, channel);
+       spin_unlock(&txq->lock);
+       return NETDEV_TX_OK;
+
+drop:
+       if (dev)
+               dev->stats.tx_dropped++;
+       spin_unlock(&txq->lock);
+drop_kfree:
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+netdev_tx_t xgmac_dma_xmit_fast(struct sk_buff *skb, struct net_device *dev)
+{
+       struct gmac_common *priv = netdev_priv(dev);
+       struct xgmac_skb_cb *cb = XGMAC_SKB_CB(skb);
+       netdev_tx_t ret;
+
+       cb->id = priv->id;
+       cb->fastmode = true;
+
+       ret = xgmac_dma_xmit(skb, priv->dma);
+       if (unlikely(ret != NETDEV_TX_OK)) {
+               pr_debug_ratelimited("%s: Tx Ring full when queue awake\n",
+                       __func__);
+       }
+       return ret;
+}
+EXPORT_SYMBOL(xgmac_dma_xmit_fast);
+
+int xgmac_dma_open(struct xgmac_dma_priv *priv, struct net_device *dev, u8 id)
+{
+       if (id >= ARRAY_SIZE(priv->ndevs))
+               return -EINVAL;
+
+       if (priv->ndevs[id])
+               return -EBUSY;
+
+       priv->ndevs[id] = dev;
+
+       /* we run multiple netdevs on the same DMA ring so we only bring it
+        * up once
+        */
+       if (!refcount_read(&priv->refcnt)) {
+               int ret = xgmac_dma_enable(priv);
+               if (ret) {
+                       priv->ndevs[id] = NULL;
+                       return ret;
+               }
+
+               refcount_set(&priv->refcnt, 1);
+       } else {
+               refcount_inc(&priv->refcnt);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(xgmac_dma_open);
+
+int xgmac_dma_stop(struct xgmac_dma_priv *priv, struct net_device *dev, u8 id)
+{
+       if (id >= ARRAY_SIZE(priv->ndevs) || priv->ndevs[id] != dev)
+               return -EINVAL;
+
+       /* only shutdown DMA if this is the last user */
+       if (refcount_dec_and_test(&priv->refcnt))
+               xgmac_dma_disable(priv);
+
+       priv->ndevs[id] = NULL;
+
+       return 0;
+}
+EXPORT_SYMBOL(xgmac_dma_stop);
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_PAGE_POOL_STATS)
+static int xgmac_dma_stats_show(struct seq_file *m, void *v)
+{
+       struct xgmac_dma_priv *priv = m->private;
+       int i;
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               struct page_pool_stats stats = {};
+
+               page_pool_get_stats(priv->rxq[i].page_pool, &stats);
+               seq_printf(m, "RX alloc statistics:\n"
+                       "fast:\t%llu\n"
+                       "slow:\t%llu\n"
+                       "empty:\t%llu\n"
+                       "refill:\t%llu\n"
+                       "waive:\t%llu\n",
+                       stats.alloc_stats.fast, stats.alloc_stats.slow,
+                       stats.alloc_stats.empty, stats.alloc_stats.refill,
+                       stats.alloc_stats.waive);
+
+               seq_printf(m, "RX recycle statistics:\n"
+                       "cached:\t%llu\n"
+                       "cache_full:\t%llu\n"
+                       "ring:\t%llu\n"
+                       "ring_full:\t%llu\n"
+                       "released_refcnt:\t%llu\n",
+                       stats.recycle_stats.cached, stats.recycle_stats.cache_full,
+                       stats.recycle_stats.ring, stats.recycle_stats.ring_full,
+                       stats.recycle_stats.released_refcnt);
+       }
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(xgmac_dma_stats);
+#endif
+
+static int xgmac_dma_debug_show(struct seq_file *m, void *v)
+{
+       struct xgmac_dma_priv *priv = m->private;
+       int i, j;
+
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               j = (i == DMA_CH_DISABLE) ? DMA_OVPORT_CH : i;
+               spin_lock_bh(&(priv->txq[i].lock));
+               seq_printf(m, "txq %d curr:%d dirty:%d\n",
+                               i, priv->txq[i].cur_tx, priv->txq[i].dirty_tx);
+               seq_printf(m, "      MTL Opmode:0x%x debug:0x%x\n",
+                               reg_read(priv, XGMAC_MTL_TXQ_OPMODE(j)),
+                               reg_read(priv, XGMAC_MTL_TXQ_DEBUG(j)));
+               seq_printf(m, "rxq %d curr:%d dirty:%d\n",
+                               i, priv->rxq[i].cur_rx, priv->rxq[i].dirty_rx);
+               seq_printf(m, "      MTL Opmode:0x%x debug:0x%x\n",
+                               reg_read(priv, XGMAC_MTL_RXQ_OPMODE(j)),
+                               reg_read(priv, XGMAC_MTL_RXQ_DEBUG(j)));
+               spin_unlock_bh(&(priv->txq[i].lock));
+
+               seq_printf(m, "DMA channel %d status:0x%x debug sts:0x%x\n", j,
+                               reg_read(priv, XGMAC_DMA_CH_STATUS(j)),
+                               reg_read(priv, XGMAC_DMA_CH_DEBUG_STATUS(j)));
+               seq_printf(m, "              TxDesc HAddr:0x%x TAddr:0x%x\n",
+                               reg_read(priv, XGMAC_DMA_CH_TxDESC_LADDR(j)),
+                               reg_read(priv, XGMAC_DMA_CH_TxDESC_TAIL_LPTR(j)));
+               seq_printf(m, "                     Cur desAddr:0x%x bufAddr:0x%x\n",
+                               reg_read(priv, XGMAC_DMA_CH_CUR_TxDESC_LADDR(j)),
+                               reg_read(priv, XGMAC_DMA_CH_CUR_TxBUFF_LADDR(j)));
+               seq_printf(m, "              RxDesc HAddr:0x%x TAddr:0x%x\n",
+                               reg_read(priv, XGMAC_DMA_CH_RxDESC_LADDR(j)),
+                               reg_read(priv, XGMAC_DMA_CH_RxDESC_TAIL_LPTR(j)));
+               seq_printf(m, "                     Cur desAddr:0x%x bufAddr:0x%x\n",
+                               reg_read(priv, XGMAC_DMA_CH_CUR_RxDESC_LADDR(j)),
+                               reg_read(priv, XGMAC_DMA_CH_CUR_RxBUFF_LADDR(j)));
+       }
+
+       seq_printf(m, "DMA debug sts0:0x%x sts1:0x%x sts3:0x%x\n",
+                       reg_read(priv, XGMAC_DMA_DEBUG_STATUS(0)),
+                       reg_read(priv, XGMAC_DMA_DEBUG_STATUS(1)),
+                       reg_read(priv, XGMAC_DMA_DEBUG_STATUS(3)));
+       return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(xgmac_dma_debug);
+
+static int xgmac_dma_probe(struct platform_device *pdev)
+{
+       struct xgmac_dma_priv *priv;
+       const char *irq_name;
+       char buf[4];
+       int ret;
+       u32 i;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = &pdev->dev;
+       priv->ioaddr = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->ioaddr))
+               return PTR_ERR(priv->ioaddr);
+
+       /* Request all clocks at once */
+       priv->clks[DMA_CLK_AXI].id = "axi";
+       priv->clks[DMA_CLK_NPU].id = "npu";
+       priv->clks[DMA_CLK_CSR].id = "csr";
+       ret = devm_clk_bulk_get(&pdev->dev, DMA_NUM_CLKS, priv->clks);
+       if (ret)
+               return ret;
+
+#ifdef CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM
+       priv->genpool = of_gen_pool_get(pdev->dev.of_node, "iram", 0);
+       if (!priv->genpool)
+               return -ENODEV;
+#endif
+
+       priv->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                      "ethsys");
+       if (IS_ERR(priv->ethsys))
+               return PTR_ERR(priv->ethsys);
+
+       /* lif/hif reset and release reset*/
+       ret = regmap_clear_bits(priv->ethsys, ETHSYS_RST, BIT(7) | BIT(8));
+       if (ret)
+               return ret;
+
+       ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, BIT(7) | BIT(8));
+       if (ret)
+               return ret;
+
+       /* set the mapping mode 0
+        * hash random use queue 0-3
+        */
+       ret = regmap_write(priv->ethsys, ETHSYS_MRI_Q_EN, 0x003F003F);
+
+       /* we run multiple netdevs on the same DMA ring so we need a dummy
+        * device for NAPI to work
+        */
+       init_dummy_netdev(&priv->napi_dev);
+
+       /* DMA IRQ */
+       ret = platform_get_irq_byname(pdev, "sbd");
+       if (ret < 0)
+               return ret;
+
+       priv->irq = ret;
+       ret = devm_request_irq(&pdev->dev, ret, xgmac_dma_irq_misc, 0,
+                              "xgmac_dma_sbd", priv);
+       if (ret)
+               return ret;
+
+       irq_set_affinity_hint(priv->irq, cpumask_of(1));
+
+       /* TX IRQ */
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               snprintf(buf, sizeof(buf), "tx%u", i);
+               ret = platform_get_irq_byname(pdev, buf);
+               if (ret < 0)
+                       goto out_napi_del;
+
+               priv->txq[i].irq = ret;
+
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                         "xgmac_dma_txq%u", i);
+               if (!irq_name) {
+                       ret = -ENOMEM;
+                       goto out_napi_del;
+               }
+
+               ret = devm_request_irq(&pdev->dev, ret, xgmac_dma_irq_tx, 0,
+                                      irq_name, &priv->txq[i]);
+               if (ret)
+                       goto out_napi_del;
+
+               priv->txq[i].idx = i;
+               spin_lock_init(&priv->txq[i].lock);
+               netif_napi_add_tx_weight(&priv->napi_dev, &priv->txq[i].napi,
+                                 xgmac_dma_napi_tx, NAPI_POLL_WEIGHT);
+               irq_set_affinity_hint(priv->txq[i].irq, cpumask_of(i % NR_CPUS));
+       }
+
+       /* RX IRQ */
+#ifdef CONFIG_NET_SIFLOWER_ETH_RX_THREAD
+       strscpy(priv->napi_dev.name, KBUILD_MODNAME, IFNAMSIZ);
+       priv->napi_dev.threaded = 1;
+#endif
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               snprintf(buf, sizeof(buf), "rx%u", i);
+               ret = platform_get_irq_byname(pdev, buf);
+               if (ret < 0)
+                       goto out_napi_del;
+
+               priv->rxq[i].irq = ret;
+
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                         "xgmac_dma_rxq%u", i);
+               if (!irq_name) {
+                       ret = -ENOMEM;
+                       goto out_napi_del;
+               }
+
+               ret = devm_request_irq(&pdev->dev, ret, xgmac_dma_irq_rx, 0,
+                                      irq_name, &priv->rxq[i]);
+               if (ret)
+                       goto out_napi_del;
+
+               priv->rxq[i].idx = i;
+               netif_napi_add_weight(&priv->napi_dev, &priv->rxq[i].napi,
+                              xgmac_dma_napi_rx, NAPI_POLL_WEIGHT);
+               irq_set_affinity_hint(priv->rxq[i].irq, cpumask_of(i % NR_CPUS));
+       }
+
+       priv->rx_alloc_size = BUF_SIZE_ALLOC(ETH_DATA_LEN);
+       priv->rx_buffer_size = BUF_SIZE_ALIGN(ETH_DATA_LEN);
+       platform_set_drvdata(pdev, priv);
+       ret = clk_bulk_prepare_enable(DMA_NUM_CLKS, priv->clks);
+       if (ret)
+               goto out_napi_del;
+
+       ret = xgmac_dma_init(priv);
+       if (ret)
+               goto out_clk_disable;
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_PAGE_POOL_STATS)
+       priv->dbgdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+       if (IS_ERR(priv->dbgdir)) {
+               ret = PTR_ERR(priv->dbgdir);
+               goto out_clk_disable;
+       }
+       debugfs_create_file("rx_stats", 0444, priv->dbgdir, priv, &xgmac_dma_stats_fops);
+       debugfs_create_file("debug", 0444, priv->dbgdir, priv, &xgmac_dma_debug_fops);
+#endif
+
+       return ret;
+out_clk_disable:
+       clk_bulk_disable_unprepare(DMA_NUM_CLKS, priv->clks);
+out_napi_del:
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               irq_set_affinity_hint(priv->rxq[i].irq, NULL);
+               irq_set_affinity_hint(priv->txq[i].irq, NULL);
+               netif_napi_del(&priv->rxq[i].napi);
+               netif_napi_del(&priv->txq[i].napi);
+       }
+       return ret;
+}
+
+static void xgmac_dma_remove(struct platform_device *pdev)
+{
+       struct xgmac_dma_priv *priv = platform_get_drvdata(pdev);
+       int i;
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_PAGE_POOL_STATS)
+       debugfs_remove(priv->dbgdir);
+#endif
+       xgmac_dma_soft_reset(priv);
+       clk_bulk_disable_unprepare(DMA_NUM_CLKS, priv->clks);
+       for (i = 0; i < DMA_CH_MAX; i++) {
+               irq_set_affinity_hint(priv->rxq[i].irq, NULL);
+               irq_set_affinity_hint(priv->txq[i].irq, NULL);
+               netif_napi_del(&priv->rxq[i].napi);
+               netif_napi_del(&priv->txq[i].napi);
+       }
+}
+
+static const struct of_device_id xgmac_dma_match[] = {
+       { .compatible = "siflower,sf21-xgmac-dma" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgmac_dma_match);
+
+static struct platform_driver xgmac_dma_driver = {
+       .probe  = xgmac_dma_probe,
+       .remove_new     = xgmac_dma_remove,
+       .driver = {
+               .name           = "sfxgmac_dma",
+               .of_match_table = xgmac_dma_match,
+       },
+};
+module_platform_driver(xgmac_dma_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Qingfang Deng <qingfang.deng@siflower.com.cn>");
+MODULE_DESCRIPTION("Ethernet DMA driver for SF21A6826/SF21H8898 SoC");
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-ext.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac-ext.h
new file mode 100644 (file)
index 0000000..4524dad
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef __XGMAC_EXT_H_
+#define __XGMAC_EXT_H__
+
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/phylink.h>
+
+#define SF_GMAC_DUNMMY_ID 0xfa
+
+#define GMAC_COMMON_STRUCT                     \
+       void __iomem *ioaddr;                   \
+       struct device *dev;                     \
+       struct clk *csr_clk;                    \
+       struct xgmac_dma_priv *dma;             \
+       struct regmap *ethsys;                  \
+       struct phylink *phylink;                \
+       struct phylink_config phylink_config;   \
+       u8 id;                                  \
+       bool phy_supports_eee;                  \
+       bool tx_lpi_enabled;                    \
+       struct platform_device *pcs_dev;        \
+       void *dp_port;
+
+struct gmac_common {
+       GMAC_COMMON_STRUCT;
+};
+
+#endif
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxgmac.c
new file mode 100644 (file)
index 0000000..5eec4ff
--- /dev/null
@@ -0,0 +1,1324 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/etherdevice.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/of_platform.h>
+#include <linux/ethtool.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+
+#include "dma.h"
+#include "eth.h"
+#include "sfxgmac-ext.h"
+
+struct xgmac_mib_desc {
+       char name[ETH_GSTRING_LEN];
+       u16 offset;
+};
+#define MIB_DESC(n, o, s) { .name = (n), .offset = (o), }
+
+static const struct xgmac_mib_desc xgmac_mib[] = {
+       MIB_DESC("tx_bytes",    MMC_XGMAC_TX_OCTET_GB, 1),
+       MIB_DESC("tx_packets",  MMC_XGMAC_TX_PKT_GB, 1),
+       MIB_DESC("tx_broadcast_packets_good",   MMC_XGMAC_TX_BROAD_PKT_G, 1),
+       MIB_DESC("tx_multicast_packets_good",   MMC_XGMAC_TX_MULTI_PKT_G, 1),
+       MIB_DESC("tx_64_byte_packets",  MMC_XGMAC_TX_64OCT_GB, 1),
+       MIB_DESC("tx_65_to_127_byte_packets",   MMC_XGMAC_TX_65OCT_GB, 1),
+       MIB_DESC("tx_128_to_255_byte_packets",  MMC_XGMAC_TX_128OCT_GB, 1),
+       MIB_DESC("tx_256_to_511_byte_packets",  MMC_XGMAC_TX_256OCT_GB, 1),
+       MIB_DESC("tx_512_to_1023_byte_packets", MMC_XGMAC_TX_512OCT_GB, 1),
+       MIB_DESC("tx_1024_to_max_byte_packets", MMC_XGMAC_TX_1024OCT_GB, 1),
+       MIB_DESC("tx_unicast_packets",  MMC_XGMAC_TX_UNI_PKT_GB, 1),
+       MIB_DESC("tx_multicast_packets",        MMC_XGMAC_TX_MULTI_PKT_GB, 1),
+       MIB_DESC("tx_broadcast_packets",        MMC_XGMAC_TX_BROAD_PKT_GB, 1),
+       MIB_DESC("tx_underflow_errors", MMC_XGMAC_TX_UNDER, 1),
+       MIB_DESC("tx_bytes_good",       MMC_XGMAC_TX_OCTET_G, 1),
+       MIB_DESC("tx_packets_good",     MMC_XGMAC_TX_PKT_G, 1),
+       MIB_DESC("tx_pause_frames",     MMC_XGMAC_TX_PAUSE, 1),
+       MIB_DESC("tx_vlan_packets_good",        MMC_XGMAC_TX_VLAN_PKT_G, 1),
+       MIB_DESC("tx_lpi_usec", MMC_XGMAC_TX_LPI_USEC, 0),
+       MIB_DESC("tx_lpi_tran", MMC_XGMAC_TX_LPI_TRAN, 0),
+       MIB_DESC("rx_packets",  MMC_XGMAC_RX_PKT_GB, 1),
+       MIB_DESC("rx_bytes",    MMC_XGMAC_RX_OCTET_GB, 1),
+       MIB_DESC("rx_bytes_good",       MMC_XGMAC_RX_OCTET_G, 1),
+       MIB_DESC("rx_broadcast_packets_good",   MMC_XGMAC_RX_BROAD_PKT_G, 1),
+       MIB_DESC("rx_multicast_packets_good",   MMC_XGMAC_RX_MULTI_PKT_G, 1),
+       MIB_DESC("rx_crc_errors",       MMC_XGMAC_RX_CRC_ERR, 1),
+       MIB_DESC("rx_crc_errors_small_packets", MMC_XGMAC_RX_RUNT_ERR, 0),
+       MIB_DESC("rx_crc_errors_giant_packets", MMC_XGMAC_RX_JABBER_ERR, 0),
+       MIB_DESC("rx_undersize_packets_good",   MMC_XGMAC_RX_UNDER, 0),
+       MIB_DESC("rx_oversize_packets_good",    MMC_XGMAC_RX_OVER, 0),
+       MIB_DESC("rx_64_byte_packets",  MMC_XGMAC_RX_64OCT_GB, 1),
+       MIB_DESC("rx_65_to_127_byte_packets",   MMC_XGMAC_RX_65OCT_GB, 1),
+       MIB_DESC("rx_128_to_255_byte_packets",  MMC_XGMAC_RX_128OCT_GB, 1),
+       MIB_DESC("rx_256_to_511_byte_packets",  MMC_XGMAC_RX_256OCT_GB, 1),
+       MIB_DESC("rx_512_to_1023_byte_packets", MMC_XGMAC_RX_512OCT_GB, 1),
+       MIB_DESC("rx_1024_to_max_byte_packets", MMC_XGMAC_RX_1024OCT_GB, 1),
+       MIB_DESC("rx_unicast_packets_good",     MMC_XGMAC_RX_UNI_PKT_G, 1),
+       MIB_DESC("rx_length_errors",    MMC_XGMAC_RX_LENGTH_ERR, 1),
+       MIB_DESC("rx_out_of_range_errors",      MMC_XGMAC_RX_RANGE, 1),
+       MIB_DESC("rx_pause_frames",     MMC_XGMAC_RX_PAUSE, 1),
+       MIB_DESC("rx_fifo_overflow_errors",     MMC_XGMAC_RX_FIFOOVER_PKT, 1),
+       MIB_DESC("rx_vlan_packets",     MMC_XGMAC_RX_VLAN_PKT_GB, 1),
+       MIB_DESC("rx_watchdog_errors",  MMC_XGMAC_RX_WATCHDOG_ERR, 0),
+       MIB_DESC("rx_lpi_usec", MMC_XGMAC_RX_LPI_USEC, 0),
+       MIB_DESC("rx_lpi_tran", MMC_XGMAC_RX_LPI_TRAN, 0),
+       MIB_DESC("rx_discard_packets",  MMC_XGMAC_RX_DISCARD_PKT_GB, 1),
+       MIB_DESC("rx_discard_bytes",    MMC_XGMAC_RX_DISCARD_OCT_GB, 1),
+       MIB_DESC("rx_alignment_errors", MMC_XGMAC_RX_ALIGN_ERR_PKT, 0),
+       MIB_DESC("tx_single_collision_packets", MMC_XGMAC_TX_SINGLE_COL_G, 0),
+       MIB_DESC("tx_multiple_collision_packets",       MMC_XGMAC_TX_MULTI_COL_G, 0),
+       MIB_DESC("tx_deferred_packets", MMC_XGMAC_TX_DEFER, 0),
+       MIB_DESC("tx_late_collision_errors",    MMC_XGMAC_TX_LATE_COL, 0),
+       MIB_DESC("tx_excessive_collision_errors",       MMC_XGMAC_TX_EXCESSIVE_COL, 0),
+       MIB_DESC("tx_carrier_sense_errors",     MMC_XGMAC_TX_CARRIER, 0),
+       MIB_DESC("tx_excessive_deferral_errors",        MMC_XGMAC_TX_EXCESSIVE_DEFER, 0),
+       MIB_DESC("rx_ipv4_packets_good",        MMC_XGMAC_RX_IPV4_PKT_G, 1),
+       MIB_DESC("rx_ipv4_header_error_packets",        MMC_XGMAC_RX_IPV4_HDRERR_PKT, 1),
+       MIB_DESC("rx_ipv4_no_payload_packets",  MMC_XGMAC_RX_IPV4_NOPAY_PKT, 1),
+       MIB_DESC("rx_ipv4_fragment_packets",    MMC_XGMAC_RX_IPV4_FRAG_PKT, 1),
+       MIB_DESC("rx_ipv4_udp_sum_zero_packets",        MMC_XGMAC_RX_IPV4_UDSBL_PKT, 1),
+       MIB_DESC("rx_ipv6_packets_good",        MMC_XGMAC_RX_IPV6_PKT_G, 1),
+       MIB_DESC("rx_ipv6_header_error_packets",        MMC_XGMAC_RX_IPV6_HDRERR_PKT, 1),
+       MIB_DESC("rx_ipv6_no_payload_packets",  MMC_XGMAC_RX_IPV6_NOPAY_PKT, 1),
+       MIB_DESC("rx_udp_packets_good", MMC_XGMAC_RX_UDP_PKT_G, 1),
+       MIB_DESC("rx_udp_sum_error_packets",    MMC_XGMAC_RX_UDP_ERR_PKT, 1),
+       MIB_DESC("rx_tcp_packets_good", MMC_XGMAC_RX_TCP_PKT_G, 1),
+       MIB_DESC("rx_tcp_sum_error_packets",    MMC_XGMAC_RX_TCP_ERR_PKT, 1),
+       MIB_DESC("rx_icmp_packets_good",        MMC_XGMAC_RX_ICMP_PKT_G, 1),
+       MIB_DESC("rx_icmp_sum_error_packets",   MMC_XGMAC_RX_ICMP_ERR_PKT, 1),
+       MIB_DESC("rx_ipv4_bytes_good",  MMC_XGMAC_RX_IPV4_OCTET_G, 1),
+       MIB_DESC("rx_ipv4_header_error_bytes",  MMC_XGMAC_RX_IPV4_HDRERR_OCTET, 1),
+       MIB_DESC("rx_ipv4_no_payload_bytes",    MMC_XGMAC_RX_IPV4_NOPAY_OCTET, 1),
+       MIB_DESC("rx_ipv4_fragment_bytes",      MMC_XGMAC_RX_IPV4_FRAG_OCTET, 1),
+       MIB_DESC("rx_ipv4_udp_sum_zero_bytes",  MMC_XGMAC_RX_IPV4_UDSBL_OCTET, 1),
+       MIB_DESC("rx_ipv6_bytes_good",  MMC_XGMAC_RX_IPV6_OCTET_G, 1),
+       MIB_DESC("rx_ipv6_header_error_bytes",  MMC_XGMAC_RX_IPV6_HDRERR_OCTET, 1),
+       MIB_DESC("rx_ipv6_no_payload_bytes",    MMC_XGMAC_RX_IPV6_NOPAY_OCTET, 1),
+       MIB_DESC("rx_udp_bytes_good",   MMC_XGMAC_RX_UDP_OCTET_G, 1),
+       MIB_DESC("rx_udp_sum_error_bytes",      MMC_XGMAC_RX_UDP_ERR_OCTET, 1),
+       MIB_DESC("rx_tcp_bytes_good",   MMC_XGMAC_RX_TCP_OCTET_G, 1),
+       MIB_DESC("rx_tcp_sum_error_bytes",      MMC_XGMAC_RX_TCP_ERR_OCTET, 1),
+       MIB_DESC("rx_icmp_bytes_good",  MMC_XGMAC_RX_ICMP_OCTET_G, 1),
+       MIB_DESC("rx_icmp_sum_error_bytes",     MMC_XGMAC_RX_ICMP_ERR_OCTET, 1),
+};
+
+struct xgmac_priv {
+       GMAC_COMMON_STRUCT;
+       struct mii_bus *mii;
+       wait_queue_head_t mdio_wait;
+       spinlock_t stats_lock;
+       u32 mdio_ctrl;
+       int sbd_irq;
+       char irq_name[16];
+       u64 mib_cache[ARRAY_SIZE(xgmac_mib)];
+       struct phylink_pcs *pcs;
+};
+
+// Used by ndo_get_stats64, don't change this without changing xgmac_mib[]!
+enum {
+       STATS64_TX_PKT_GB = 1,
+       STATS64_TX_UNDER = 13,
+       STATS64_TX_OCTET_G = 14,
+       STATS64_TX_PKT_G = 15,
+       STATS64_RX_PKT_GB = 20,
+       STATS64_RX_OCTET_G = 22,
+       STATS64_RX_BROAD_PKT_G = 23,
+       STATS64_RX_MULTI_PKT_G = 24,
+       STATS64_RX_CRC_ERR = 25,
+       STATS64_RX_UNI_PKT_G = 36,
+       STATS64_RX_LENGTH_ERR = 37,
+       STATS64_RX_RANGE = 38,
+       STATS64_RX_FIFOOVER_PKT = 40,
+       STATS64_RX_ALIGN_ERR_PKT = 47,
+       STATS64_TX_SINGLE_COL_G = 48,
+       STATS64_TX_MULTI_COL_G = 49,
+       STATS64_TX_LATE_COL = 51,
+       STATS64_TX_EXCESSIVE_COL = 52,
+       STATS64_TX_CARRIER = 53,
+};
+
+// Sync MIB counters to software. Caller must hold stats_lock.
+static void xgmac_mib_sync(struct xgmac_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(xgmac_mib); i++)
+               priv->mib_cache[i] += reg_read(priv, xgmac_mib[i].offset);
+}
+
+static void xgmac_mib_irq_enable(struct xgmac_priv *priv)
+{
+       reg_write(priv, MMC_XGMAC_RX_INT_EN, ~0);
+       reg_write(priv, MMC_XGMAC_TX_INT_EN, ~0);
+       reg_write(priv, MMC_XGMAC_RX_IPC_INTR_MASK, 0);
+}
+
+static void xgmac_mib_irq_disable(struct xgmac_priv *priv)
+{
+       reg_write(priv, MMC_XGMAC_RX_INT_EN, 0);
+       reg_write(priv, MMC_XGMAC_TX_INT_EN, 0);
+       reg_write(priv, MMC_XGMAC_RX_IPC_INTR_MASK, ~0);
+}
+
+static void xgmac_mib_sync_begin(struct xgmac_priv *priv)
+{
+       xgmac_mib_irq_disable(priv);
+       spin_lock(&priv->stats_lock);
+}
+
+static void xgmac_mib_sync_end(struct xgmac_priv *priv)
+{
+       spin_unlock(&priv->stats_lock);
+       xgmac_mib_irq_enable(priv);
+}
+
+static int xgmac_mdio_wait(struct xgmac_priv *priv)
+{
+       unsigned long ret;
+       u32 val;
+
+       ret = wait_event_timeout(priv->mdio_wait,
+                                !((val = reg_read(priv, XGMAC_MDIO_DATA)) & MII_XGMAC_BUSY),
+                                HZ);
+       if (ret)
+               return FIELD_GET(MII_DATA_MASK, val);
+
+       return -ETIMEDOUT;
+}
+
+static int xgmac_mdio_read(struct mii_bus *bus, int addr, int regnum)
+{
+       struct xgmac_priv *priv = bus->priv;
+       u32 reg;
+       int ret;
+
+       ret = xgmac_mdio_wait(priv);
+       if (ret < 0)
+               return ret;
+
+       reg_set(priv, XGMAC_MDIO_C22P, BIT(addr));
+
+       reg = FIELD_PREP(MII_XGMAC_PA, addr) | FIELD_PREP(MII_XGMAC_RA, regnum);
+       reg_write(priv, XGMAC_MDIO_ADDR, reg);
+
+       reg = MII_XGMAC_BUSY | MII_XGMAC_READ | priv->mdio_ctrl;
+       reg_write(priv, XGMAC_MDIO_DATA, reg);
+
+       return xgmac_mdio_wait(priv);
+}
+
+static int xgmac_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
+{
+       struct xgmac_priv *priv = bus->priv;
+       u32 reg;
+       int ret;
+
+       ret = xgmac_mdio_wait(priv);
+       if (ret < 0)
+               return ret;
+
+       reg_set(priv, XGMAC_MDIO_C22P, BIT(addr));
+
+       reg = FIELD_PREP(MII_XGMAC_PA, addr) | FIELD_PREP(MII_XGMAC_RA, regnum);
+       reg_write(priv, XGMAC_MDIO_ADDR, reg);
+
+       reg = MII_XGMAC_BUSY | MII_XGMAC_WRITE | priv->mdio_ctrl |
+             FIELD_PREP(MII_DATA_MASK, val);
+       reg_write(priv, XGMAC_MDIO_DATA, reg);
+
+       ret = xgmac_mdio_wait(priv);
+       return ret < 0 ? ret : 0;
+}
+
+static int xgmac_mdio_read_c45(struct mii_bus *bus, int addr, int devnum, int regnum)
+{
+       struct xgmac_priv *priv = bus->priv;
+       u32 reg;
+       int ret;
+
+       ret = xgmac_mdio_wait(priv);
+       if (ret < 0)
+               return ret;
+
+       reg_clear(priv, XGMAC_MDIO_C22P, BIT(addr));
+
+       reg = FIELD_PREP(MII_XGMAC_PA, addr) | FIELD_PREP(MII_XGMAC_DA, devnum) |
+             FIELD_PREP(MII_XGMAC_RA, regnum);
+       reg_write(priv, XGMAC_MDIO_ADDR, reg);
+
+       reg = MII_XGMAC_BUSY | MII_XGMAC_READ | priv->mdio_ctrl;
+       reg_write(priv, XGMAC_MDIO_DATA, reg);
+
+       return xgmac_mdio_wait(priv);
+}
+
+static int xgmac_mdio_write_c45(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val)
+{
+       struct xgmac_priv *priv = bus->priv;
+       u32 reg;
+       int ret;
+
+       ret = xgmac_mdio_wait(priv);
+       if (ret < 0)
+               return ret;
+
+       reg_clear(priv, XGMAC_MDIO_C22P, BIT(addr));
+
+       reg = FIELD_PREP(MII_XGMAC_PA, addr) | FIELD_PREP(MII_XGMAC_DA, devnum) |
+             FIELD_PREP(MII_XGMAC_RA, regnum);
+       reg_write(priv, XGMAC_MDIO_ADDR, reg);
+
+       reg = MII_XGMAC_BUSY | MII_XGMAC_WRITE | priv->mdio_ctrl |
+             FIELD_PREP(MII_DATA_MASK, val);
+       reg_write(priv, XGMAC_MDIO_DATA, reg);
+
+       ret = xgmac_mdio_wait(priv);
+       return ret < 0 ? ret : 0;
+}
+
+static int xgmac_mdio_init(struct xgmac_priv *priv)
+{
+       struct device_node *mdio_node = NULL, *np = priv->dev->of_node;
+       u32 csr_freq = clk_get_rate(priv->csr_clk);
+       int ret = -ENOMEM;
+       u32 freq;
+
+       mdio_node = of_get_child_by_name(np, "mdio");
+       if (!mdio_node)
+               return 0;
+
+       if (of_property_read_bool(mdio_node, "suppress-preamble"))
+               priv->mdio_ctrl |= MII_XGMAC_PSE;
+
+       if (of_property_read_u32(mdio_node, "clock-frequency", &freq))
+               freq = 2500000;
+
+       if (freq > DIV_ROUND_UP(csr_freq, 4))
+               dev_warn(priv->dev,
+                        "MDC frequency %uHz too high, reducing to %uHz\n",
+                        freq, DIV_ROUND_UP(csr_freq, 4));
+       else if (freq < csr_freq / 202)
+               dev_warn(priv->dev,
+                        "MDC frequency %uHz too low, increasing to %uHz\n",
+                        freq, csr_freq / 202);
+
+       if (freq >= DIV_ROUND_UP(csr_freq, 4))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 0);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 6))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 1);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 8))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 2);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 10))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 3);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 12))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 4);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 14))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 5);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 16))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 6);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 18))
+               priv->mdio_ctrl |= MII_XGMAC_CRS | FIELD_PREP(MII_XGMAC_CR, 7);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 62))
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 0);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 102))
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 1);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 122))
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 2);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 142))
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 3);
+       else if (freq >= DIV_ROUND_UP(csr_freq, 162))
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 4);
+       else
+               priv->mdio_ctrl |= FIELD_PREP(MII_XGMAC_CR, 5);
+
+       priv->mii = devm_mdiobus_alloc(priv->dev);
+       if (!priv->mii)
+               goto cleanup;
+
+       priv->mii->name = "xgmac";
+       priv->mii->priv = priv;
+       priv->mii->read = xgmac_mdio_read;
+       priv->mii->write = xgmac_mdio_write;
+       priv->mii->read_c45 = xgmac_mdio_read_c45;
+       priv->mii->write_c45 = xgmac_mdio_write_c45;
+       snprintf(priv->mii->id, MII_BUS_ID_SIZE, "xgmac%u", priv->id);
+       init_waitqueue_head(&priv->mdio_wait);
+       reg_write(priv, XGMAC_MDIO_INT_EN, XGMAC_MDIO_INT_EN_SINGLE);
+
+       ret = devm_of_mdiobus_register(priv->dev, priv->mii, mdio_node);
+cleanup:
+       of_node_put(mdio_node);
+       return ret;
+}
+
+static irqreturn_t xgmac_irq(int irq, void *dev_id)
+{
+       struct xgmac_priv *priv = dev_id;
+       irqreturn_t ret = IRQ_NONE;
+       u32 status;
+
+       status = reg_read(priv, XGMAC_INT_STATUS);
+       if (status & XGMAC_MMCIS) {
+               if (spin_trylock(&priv->stats_lock)) {
+                       xgmac_mib_sync(priv);
+                       spin_unlock(&priv->stats_lock);
+               }
+               ret = IRQ_HANDLED;
+       }
+       if (status & XGMAC_SMI) {
+               reg_read(priv, XGMAC_MDIO_INT_STATUS);
+               wake_up(&priv->mdio_wait);
+               ret = IRQ_HANDLED;
+       }
+       /* LSI is set regardless of LSIE bit in XGMAC_INT_EN */
+       if (status & XGMAC_LSI && reg_read(priv, XGMAC_INT_EN) & XGMAC_LSI) {
+               phylink_mac_change(priv->phylink, status & XGMAC_RGMII_LS);
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static void xgmac_write_mac_addr(struct xgmac_priv *priv, const u8 *addr,
+                                u32 reg)
+{
+       u32 val;
+
+       /* For MAC Addr registers we have to set the Address Enable (AE)
+        * bit that has no effect on the High Reg 0 where the bit 31 (MO)
+        * is RO.
+        */
+       val = GMAC_HI_REG_AE | (addr[5] << 8) | addr[4];
+       reg_write(priv, XGMAC_ADDRx_HIGH(reg), val);
+       val = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       reg_write(priv, XGMAC_ADDRx_LOW(reg), val);
+}
+
+static int xgmac_open(struct net_device *dev)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       int ret;
+
+       ret = phylink_of_phy_connect(priv->phylink, priv->dev->of_node, 0);
+       if (ret)
+               return ret;
+
+       ret = xgmac_dma_open(priv->dma, dev, priv->id);
+       if (ret) {
+               phylink_disconnect_phy(priv->phylink);
+               return ret;
+       }
+
+       phylink_start(priv->phylink);
+       netif_tx_start_all_queues(dev);
+
+       return 0;
+}
+
+static int xgmac_stop(struct net_device *dev)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       phylink_stop(priv->phylink);
+       netif_tx_stop_all_queues(dev);
+       phylink_disconnect_phy(priv->phylink);
+
+       return xgmac_dma_stop(priv->dma, dev, priv->id);
+}
+
+static void xgmac_set_rx_mode(struct net_device *dev)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       unsigned int value = 0;
+       unsigned int perfect_addr_number = 4;
+
+       pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
+                netdev_mc_count(dev), netdev_uc_count(dev));
+
+       if (dev->flags & IFF_PROMISC) {
+               value = XGMAC_FILTER_PR;
+       } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
+               value = XGMAC_FILTER_PM;        /* pass all multi */
+       }
+
+       /* Handle multiple unicast addresses (perfect filtering) */
+       if (netdev_uc_count(dev) > perfect_addr_number)
+               /* Switch to promiscuous mode if more than unicast
+                * addresses are requested than supported by hardware.
+                */
+               value |= XGMAC_FILTER_PR;
+       else {
+               int reg = 1;
+               struct netdev_hw_addr *ha;
+
+               netdev_for_each_uc_addr(ha, dev) {
+                       xgmac_write_mac_addr(priv, ha->addr, reg);
+                       reg++;
+               }
+
+               while (reg <= perfect_addr_number) {
+                       reg_write(priv, XGMAC_ADDRx_HIGH(reg), 0);
+                       reg_write(priv, XGMAC_ADDRx_LOW(reg), 0);
+                       reg++;
+               }
+       }
+
+#ifdef FRAME_FILTER_DEBUG
+       /* Enable Receive all mode (to debug filtering_fail errors) */
+       value |= XGMAC_FILTER_RA;
+#endif
+       reg_write(priv, XGMAC_PACKET_FILTER, value);
+}
+
+static int xgmac_set_mac_address(struct net_device *dev, void *p)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       int ret;
+
+       ret = eth_mac_addr(dev, p);
+       if (ret)
+               return ret;
+
+       xgmac_write_mac_addr(priv, dev->dev_addr, 0);
+
+       return 0;
+}
+
+static int xgmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_mii_ioctl(priv->phylink, ifr, cmd);
+}
+
+static int xgmac_set_features(struct net_device *dev,
+                             netdev_features_t features)
+{
+       netdev_features_t diff = dev->features ^ features;
+       struct xgmac_priv *priv = netdev_priv(dev);
+       u32 ctrl = reg_read(priv, XGMAC_RX_CONFIG);
+
+       if (diff & NETIF_F_LOOPBACK) {
+               if (features & NETIF_F_LOOPBACK) {
+                       netdev_info(dev, "MAC internal loopback enabled\n");
+                       ctrl |= XGMAC_CONFIG_LM;
+               } else {
+                       netdev_info(dev, "MAC internal loopback disabled\n");
+                       ctrl &= ~XGMAC_CONFIG_LM;
+               }
+       }
+
+       if (diff & NETIF_F_RXFCS) {
+               if (features & NETIF_F_RXFCS) {
+                       netdev_info(dev, "MAC FCS stripping disabled\n");
+                       ctrl &= ~(XGMAC_CONFIG_ACS | XGMAC_CONFIG_CST);
+               } else {
+                       netdev_info(dev, "MAC FCS stripping enabled\n");
+                       ctrl |= XGMAC_CONFIG_ACS | XGMAC_CONFIG_CST;
+               }
+       }
+
+       if (diff & NETIF_F_RXCSUM) {
+               if (features & NETIF_F_RXCSUM) {
+                       netdev_info(dev, "MAC Rx checksum offload enabled\n");
+                       ctrl |= XGMAC_CONFIG_IPC;
+               } else {
+                       netdev_info(dev, "MAC Rx checksum offload disabled\n");
+                       ctrl &= ~XGMAC_CONFIG_IPC;
+               }
+       }
+
+       if (diff & NETIF_F_RXALL) {
+               u32 rff = reg_read(priv, XGMAC_PACKET_FILTER);
+
+               if (features & NETIF_F_RXALL) {
+                       ctrl |= XGMAC_CONFIG_DCRCC;
+                       rff |= XGMAC_FILTER_RA;
+               } else {
+                       ctrl &= ~XGMAC_CONFIG_DCRCC;
+                       rff &= ~XGMAC_FILTER_RA;
+               }
+               reg_write(priv, XGMAC_PACKET_FILTER, rff);
+       }
+       reg_write(priv, XGMAC_RX_CONFIG, ctrl);
+
+       return 0;
+}
+
+static int xgmac_get_phys_port_id(struct net_device *dev,
+                                         struct netdev_phys_item_id *ppid)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       ppid->id[0] = priv->id;
+       ppid->id_len = 1;
+
+       return 0;
+}
+
+static int xgmac_get_port_parent_id(struct net_device *dev,
+                                         struct netdev_phys_item_id *ppid)
+{
+       ppid->id[0] = SF_GMAC_DUNMMY_ID;
+       ppid->id_len = 1;
+
+       return 0;
+}
+
+static void xgmac_neigh_destroy(struct net_device *dev,
+                                     struct neighbour *n)
+{
+       // struct xgmac_priv *priv = netdev_priv(dev);
+
+       /** TODO: call dpns->ops->port_neigh_destroy(dp_port, n); */
+       return;
+}
+static void xgmac_get_stats64(struct net_device *dev,
+                             struct rtnl_link_stats64 *stats)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       const u64 *mib;
+
+       // Compile-time check in case someone changes the order
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_PKT_GB].offset != MMC_XGMAC_TX_PKT_GB);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_UNDER].offset != MMC_XGMAC_TX_UNDER);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_OCTET_G].offset != MMC_XGMAC_TX_OCTET_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_PKT_G].offset != MMC_XGMAC_TX_PKT_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_PKT_GB].offset != MMC_XGMAC_RX_PKT_GB);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_OCTET_G].offset != MMC_XGMAC_RX_OCTET_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_BROAD_PKT_G].offset != MMC_XGMAC_RX_BROAD_PKT_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_MULTI_PKT_G].offset != MMC_XGMAC_RX_MULTI_PKT_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_CRC_ERR].offset != MMC_XGMAC_RX_CRC_ERR);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_UNI_PKT_G].offset != MMC_XGMAC_RX_UNI_PKT_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_LENGTH_ERR].offset != MMC_XGMAC_RX_LENGTH_ERR);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_RANGE].offset != MMC_XGMAC_RX_RANGE);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_FIFOOVER_PKT].offset != MMC_XGMAC_RX_FIFOOVER_PKT);
+       BUILD_BUG_ON(xgmac_mib[STATS64_RX_ALIGN_ERR_PKT].offset != MMC_XGMAC_RX_ALIGN_ERR_PKT);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_SINGLE_COL_G].offset != MMC_XGMAC_TX_SINGLE_COL_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_MULTI_COL_G].offset != MMC_XGMAC_TX_MULTI_COL_G);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_LATE_COL].offset != MMC_XGMAC_TX_LATE_COL);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_EXCESSIVE_COL].offset != MMC_XGMAC_TX_EXCESSIVE_COL);
+       BUILD_BUG_ON(xgmac_mib[STATS64_TX_CARRIER].offset != MMC_XGMAC_TX_CARRIER);
+
+       xgmac_mib_sync_begin(priv);
+       xgmac_mib_sync(priv);
+       mib = priv->mib_cache;
+       stats->rx_packets = mib[STATS64_RX_BROAD_PKT_G] +
+                           mib[STATS64_RX_MULTI_PKT_G] +
+                           mib[STATS64_RX_UNI_PKT_G];
+       stats->tx_packets = mib[STATS64_TX_PKT_G];
+       stats->rx_bytes = mib[STATS64_RX_OCTET_G];
+       stats->tx_bytes = mib[STATS64_TX_OCTET_G];
+       stats->rx_errors = mib[STATS64_RX_PKT_GB] - stats->rx_packets;
+       stats->tx_errors = mib[STATS64_TX_PKT_GB] - stats->tx_packets;
+       stats->multicast = mib[STATS64_RX_BROAD_PKT_G] +
+                          mib[STATS64_RX_MULTI_PKT_G];
+       stats->collisions = mib[STATS64_TX_SINGLE_COL_G] +
+                           mib[STATS64_TX_MULTI_COL_G];
+       stats->rx_length_errors = mib[STATS64_RX_LENGTH_ERR] +
+                                 mib[STATS64_RX_RANGE];
+       stats->rx_over_errors = mib[STATS64_RX_FIFOOVER_PKT];
+       stats->rx_crc_errors = mib[STATS64_RX_CRC_ERR];
+       stats->rx_frame_errors = mib[STATS64_RX_ALIGN_ERR_PKT];
+       stats->tx_aborted_errors = mib[STATS64_TX_EXCESSIVE_COL];
+       stats->tx_carrier_errors = mib[STATS64_TX_CARRIER];
+       stats->tx_fifo_errors = mib[STATS64_TX_UNDER];
+       stats->tx_window_errors = mib[STATS64_TX_LATE_COL];
+       xgmac_mib_sync_end(priv);
+}
+
+static int xgmac_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       u32 step;
+
+       dev->mtu = new_mtu;
+
+       /* Configure GPSL field in XGMAC_RX_CONFIG. L2 header and FCS must
+        * be taken into account. For a MTU of 1500 bytes, this field is set
+        * to 1518. For VLAN tagged packets, the hardware adds 4 bytes
+        * (single tagged) or 8 bytes (double tagged) to the programmed value.
+        */
+       new_mtu += ETH_HLEN + ETH_FCS_LEN;
+       reg_rmw(priv, XGMAC_RX_CONFIG, XGMAC_CONFIG_GPSL,
+               FIELD_PREP(XGMAC_CONFIG_GPSL, new_mtu) | XGMAC_CONFIG_GPSLCE);
+
+       /* Configure Rx watchdog and Tx jabber threshold, with 1KB step.
+        * Unlike the GPSL field, the hardware does not count the VLAN tag
+        * overhead so it must be manually added.
+        */
+       new_mtu = min(new_mtu + VLAN_HLEN * 2, MAX_FRAME_SIZE);
+       step = DIV_ROUND_UP((u32)new_mtu, SZ_1K);
+       // The step begins at 2KB
+       step = step < 2 ? 0 : step - 2;
+       reg_write(priv, XGMAC_WD_JB_TIMEOUT, XGMAC_PJE | XGMAC_PWE |
+                 FIELD_PREP(XGMAC_JTO, step) | FIELD_PREP(XGMAC_WTO, step));
+
+       return 0;
+}
+
+static const struct net_device_ops xgmac_netdev_ops = {
+       .ndo_open               = xgmac_open,
+       .ndo_stop               = xgmac_stop,
+       .ndo_start_xmit         = xgmac_dma_xmit_fast,
+       .ndo_set_rx_mode        = xgmac_set_rx_mode,
+       .ndo_set_mac_address    = xgmac_set_mac_address,
+       .ndo_do_ioctl           = xgmac_ioctl,
+       .ndo_set_features       = xgmac_set_features,
+       .ndo_get_phys_port_id   = xgmac_get_phys_port_id,
+       .ndo_get_port_parent_id = xgmac_get_port_parent_id,
+       .ndo_neigh_destroy      = xgmac_neigh_destroy,
+       .ndo_get_stats64        = xgmac_get_stats64,
+       .ndo_change_mtu         = xgmac_change_mtu,
+};
+
+static void xgmac_validate(struct phylink_config *config,
+                          unsigned long *supported,
+                          struct phylink_link_state *state)
+{
+       __ETHTOOL_DECLARE_LINK_MODE_MASK(mac_supported) = {};
+
+       phylink_set(mac_supported, 10baseT_Half);
+       phylink_set(mac_supported, 10baseT_Full);
+       phylink_set(mac_supported, 100baseT_Half);
+       phylink_set(mac_supported, 100baseT_Full);
+       phylink_set(mac_supported, 1000baseT_Full);
+       phylink_set(mac_supported, 1000baseX_Full);
+       phylink_set(mac_supported, 1000baseKX_Full);
+       phylink_set(mac_supported, 2500baseT_Full);
+       phylink_set(mac_supported, 2500baseX_Full);
+
+       phylink_set(mac_supported, Autoneg);
+       phylink_set(mac_supported, Pause);
+       phylink_set(mac_supported, Asym_Pause);
+       phylink_set_port_modes(mac_supported);
+
+       linkmode_and(supported, supported, mac_supported);
+       linkmode_and(state->advertising, state->advertising, mac_supported);
+}
+
+static struct xgmac_priv *sfxgmac_phylink_to_port(struct phylink_config *config)
+{
+       return container_of(config, struct xgmac_priv, phylink_config);
+}
+
+static struct phylink_pcs *xgmac_mac_selct_pcs(struct phylink_config *config,
+                                           phy_interface_t interface)
+{
+       struct xgmac_priv *priv = sfxgmac_phylink_to_port(config);
+
+       return priv->pcs;
+}
+
+static void xgmac_toggle_tx_lpi(struct xgmac_priv *priv)
+{
+       if (priv->phy_supports_eee && priv->tx_lpi_enabled) {
+               reg_set(priv, XGMAC_LPI_CTRL,
+                       XGMAC_LPIATE | XGMAC_LPITXA | XGMAC_LPITXEN);
+       } else {
+               reg_clear(priv, XGMAC_LPI_CTRL,
+                         XGMAC_LPIATE | XGMAC_LPITXA | XGMAC_LPITXEN);
+       }
+}
+
+static void xgmac_mac_config(struct phylink_config *config, unsigned int mode,
+                            const struct phylink_link_state *state)
+{
+       struct xgmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+
+       /* Enable link change interrupt for RGMII */
+       if (phy_interface_mode_is_rgmii(state->interface) &&
+           phylink_autoneg_inband(mode))
+               reg_set(priv, XGMAC_INT_EN, XGMAC_LSI);
+       else
+               reg_clear(priv, XGMAC_INT_EN, XGMAC_LSI);
+}
+
+static void xgmac_mac_reset(struct xgmac_priv *priv)
+{
+       struct net_device *ndev = priv_to_netdev(priv);
+       int ret;
+
+       if (priv->id < 5) {
+               ret = regmap_clear_bits(priv->ethsys, ETHSYS_RST, BIT(priv->id));
+               if (ret)
+                       return;
+
+               ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, BIT(priv->id));
+               if (ret)
+                       return;
+       }else {
+               ret = regmap_clear_bits(priv->ethsys, ETHSYS_RST, ETHSYS_RST_MAC5);
+               if (ret)
+                       return;
+
+               /* set mac5 phy mode to rgmii, should set under mac reset */
+               ret = regmap_write(priv->ethsys, ETHSYS_MAC5_CTRL,
+                               FIELD_PREP(MAC5_PHY_INTF_SEL, 1));
+               if (ret)
+                       return;
+
+               ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, ETHSYS_RST_MAC5);
+               if (ret)
+                       return;
+       }
+
+       regmap_set_bits(priv->ethsys, ETHSYS_TX_DIS, BIT(priv->id));
+       reg_clear(priv, XGMAC_TX_CONFIG, XGMAC_CONFIG_TE);
+       reg_clear(priv, XGMAC_INT_EN, XGMAC_LSI);
+       xgmac_write_mac_addr(priv, ndev->dev_addr, 0);
+       reg_set(priv, MMC_XGMAC_CONTROL,
+               MMC_XGMAC_CONTROL_RESET | MMC_XGMAC_CONTROL_RSTONRD);
+       reg_write(priv, XGMAC_TX_CONFIG, XGMAC_CORE_INIT_TX);
+       reg_write(priv, XGMAC_RX_CONFIG, XGMAC_CORE_INIT_RX);
+       reg_write(priv, XGMAC_WD_JB_TIMEOUT, XGMAC_PJE | XGMAC_PWE);
+       reg_write(priv, XGMAC_VLAN_TAG, XGMAC_VLAN_EDVLP);
+       reg_write(priv, XGMAC_LPI_TIMER_CTRL,
+                 FIELD_PREP(XGMAC_LPI_LST, XGMAC_LPI_LST_DEFAULT) |
+                 FIELD_PREP(XGMAC_LPI_TWT, XGMAC_LPI_TWT_DEFAULT));
+       reg_write(priv, XGMAC_LPI_AUTO_EN, XGMAC_LPI_AUTO_EN_DEFAULT);
+       xgmac_mib_irq_enable(priv);
+       reg_write(priv, XGMAC_LPI_1US,
+                 clk_get_rate(priv->csr_clk) / 1000000 - 1);
+}
+
+static void wait_queue_empty(struct xgmac_priv *priv,
+               phy_interface_t interface)
+{
+       unsigned long timeout = jiffies + HZ/50;
+
+       do {
+               if (!(reg_read(priv, XGMAC_MTL_TXQ_OPMODE(0)) & XGMAC_FTQ))
+                       return;
+
+               cond_resched();
+       } while (time_after(timeout, jiffies));
+
+       xgmac_mac_reset(priv);
+       printk("wait queue empty timed out\n");
+}
+
+static void xgmac_mac_link_down(struct phylink_config *config,
+                               unsigned int mode, phy_interface_t interface)
+{
+       struct xgmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+
+       regmap_set_bits(priv->ethsys, ETHSYS_TX_DIS, BIT(priv->id));
+       reg_clear(priv, XGMAC_TX_CONFIG, XGMAC_CONFIG_TE);
+       reg_set(priv, XGMAC_MTL_TXQ_OPMODE(0), XGMAC_FTQ);
+       wait_queue_empty(priv, interface);
+       reg_clear(priv, XGMAC_LPI_CTRL, XGMAC_PLS);
+}
+
+static void xgmac_mac_link_up(struct phylink_config *config,
+                             struct phy_device *phy, unsigned int mode,
+                             phy_interface_t interface, int speed, int duplex,
+                             bool tx_pause, bool rx_pause) {
+       struct xgmac_priv *priv = netdev_priv(to_net_dev(config->dev));
+       u32 txc, rxfc, txfc;
+
+       txc = reg_read(priv, XGMAC_TX_CONFIG);
+       txc |= XGMAC_CONFIG_TE;
+       txc &= ~XGMAC_CONFIG_SS_MASK;
+
+       switch (speed) {
+       case SPEED_2500:
+               txc |= XGMAC_CONFIG_SS_2500_GMII;
+               break;
+       case SPEED_1000:
+               txc |= XGMAC_CONFIG_SS_1000_GMII;
+               break;
+       case SPEED_100:
+               txc |= XGMAC_CONFIG_SS_100_MII;
+               break;
+       case SPEED_10:
+               txc |= XGMAC_CONFIG_SS_10_MII;
+               break;
+       default:
+               return;
+       }
+
+       if (duplex == DUPLEX_FULL)
+               reg_clear(priv, XGMAC_MAC_EXT_CONFIG, XGMAC_HD);
+       else
+               reg_set(priv, XGMAC_MAC_EXT_CONFIG, XGMAC_HD);
+
+       rxfc = XGMAC_UP;
+       if (rx_pause)
+               rxfc |= XGMAC_RFE;
+
+       reg_write(priv, XGMAC_RX_FLOW_CTRL, rxfc);
+
+       txfc = 0;
+       if (tx_pause) {
+               txfc |= XGMAC_TFE;
+               if (duplex == DUPLEX_FULL)
+                       txfc |= FIELD_PREP(XGMAC_PT, 0x400);
+       }
+       reg_write(priv, XGMAC_Qx_TX_FLOW_CTRL(0), txfc);
+
+       reg_write(priv, XGMAC_TX_CONFIG, txc);
+       reg_set(priv, XGMAC_RX_CONFIG, XGMAC_CONFIG_RE);
+       reg_set(priv, XGMAC_LPI_CTRL, XGMAC_PLS);
+       regmap_clear_bits(priv->ethsys, ETHSYS_TX_DIS, BIT(priv->id));
+
+       if (phy)
+               priv->phy_supports_eee = !phy_init_eee(phy, true);
+       else
+               priv->phy_supports_eee = false;
+
+       xgmac_toggle_tx_lpi(priv);
+}
+
+static const struct phylink_mac_ops xgmac_phylink_mac_ops = {
+       .validate       = xgmac_validate,
+       .mac_select_pcs = xgmac_mac_selct_pcs,
+       .mac_config     = xgmac_mac_config,
+       .mac_link_down  = xgmac_mac_link_down,
+       .mac_link_up    = xgmac_mac_link_up,
+};
+
+static void xgmac_ethtool_get_wol(struct net_device *dev,
+                                struct ethtool_wolinfo *wol)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_get_wol(priv->phylink, wol);
+}
+
+static int xgmac_ethtool_set_wol(struct net_device *dev,
+                               struct ethtool_wolinfo *wol)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_set_wol(priv->phylink, wol);
+}
+
+static int xgmac_ethtool_nway_reset(struct net_device *dev)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_nway_reset(priv->phylink);
+}
+
+static void xgmac_ethtool_get_pauseparam(struct net_device *dev,
+                                        struct ethtool_pauseparam *pause)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       phylink_ethtool_get_pauseparam(priv->phylink, pause);
+}
+
+static int xgmac_ethtool_set_pauseparam(struct net_device *dev,
+                                       struct ethtool_pauseparam *pause)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_set_pauseparam(priv->phylink, pause);
+}
+
+
+static void xgmac_ethtool_get_strings(struct net_device *dev, u32 stringset,
+                                     u8 *data)
+{
+       int i;
+
+       if (stringset != ETH_SS_STATS)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(xgmac_mib); i++) {
+               memcpy(data, xgmac_mib[i].name, ETH_GSTRING_LEN);
+               data += ETH_GSTRING_LEN;
+       }
+}
+
+static void xgmac_ethtool_get_stats(struct net_device *dev,
+                                   struct ethtool_stats *stats, u64 *data)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       xgmac_mib_sync_begin(priv);
+       xgmac_mib_sync(priv);
+       memcpy(data, priv->mib_cache, sizeof(priv->mib_cache));
+       xgmac_mib_sync_end(priv);
+}
+
+static int xgmac_ethtool_reset(struct net_device *dev, u32 *flags)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       if (*flags & ETH_RESET_MGMT) {
+               xgmac_mib_sync_begin(priv);
+               reg_set(priv, MMC_XGMAC_CONTROL, MMC_XGMAC_CONTROL_RESET);
+               memset(priv->mib_cache, 0, sizeof(priv->mib_cache));
+               xgmac_mib_sync_end(priv);
+               *flags &= ~ETH_RESET_MGMT;
+       }
+
+       return 0;
+}
+
+static int xgmac_ethtool_get_sset_count(struct net_device *dev, int stringset)
+{
+       switch (stringset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(xgmac_mib);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int xgmac_ethtool_get_link_ksettings(struct net_device *dev,
+                                           struct ethtool_link_ksettings *cmd)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_ksettings_get(priv->phylink, cmd);
+}
+
+static int xgmac_ethtool_get_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       int ret;
+
+       ret = phylink_ethtool_get_eee(priv->phylink, e);
+       if (ret)
+               return ret;
+
+       e->tx_lpi_enabled = priv->tx_lpi_enabled;
+       e->tx_lpi_timer = reg_read(priv, XGMAC_LPI_AUTO_EN);
+
+       return 0;
+}
+
+static int xgmac_ethtool_set_eee(struct net_device *dev, struct ethtool_eee *e)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+       int ret;
+
+       if (e->tx_lpi_timer > XGMAC_LPI_AUTO_EN_MAX)
+               return -EINVAL;
+
+       ret = phylink_ethtool_set_eee(priv->phylink, e);
+       if (ret)
+               return ret;
+
+       priv->tx_lpi_enabled = e->tx_lpi_enabled;
+       xgmac_toggle_tx_lpi(priv);
+
+       reg_write(priv, XGMAC_LPI_AUTO_EN, e->tx_lpi_timer);
+
+       return 0;
+}
+
+static int xgmac_ethtool_set_link_ksettings(struct net_device *dev,
+                                           const struct ethtool_link_ksettings *cmd)
+{
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       return phylink_ethtool_ksettings_set(priv->phylink, cmd);
+}
+
+static const struct ethtool_ops xgmac_ethtool_ops = {
+       .get_wol                = xgmac_ethtool_get_wol,
+       .set_wol                = xgmac_ethtool_set_wol,
+       .nway_reset             = xgmac_ethtool_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_pauseparam         = xgmac_ethtool_get_pauseparam,
+       .set_pauseparam         = xgmac_ethtool_set_pauseparam,
+       .get_strings            = xgmac_ethtool_get_strings,
+       .get_ethtool_stats      = xgmac_ethtool_get_stats,
+       .reset                  = xgmac_ethtool_reset,
+       .get_sset_count         = xgmac_ethtool_get_sset_count,
+       .get_eee                = xgmac_ethtool_get_eee,
+       .set_eee                = xgmac_ethtool_set_eee,
+       .get_link_ksettings     = xgmac_ethtool_get_link_ksettings,
+       .set_link_ksettings     = xgmac_ethtool_set_link_ksettings,
+};
+
+static int xgmac_rgmii_delay(struct xgmac_priv *priv, phy_interface_t phy_mode)
+{
+       u32 reg = 0, rxd = MAC5_DELAY_DEFAULT, txd = MAC5_DELAY_DEFAULT;
+
+       of_property_read_u32(priv->dev->of_node, "rx-internal-delay-ps", &rxd);
+       of_property_read_u32(priv->dev->of_node, "tx-internal-delay-ps", &txd);
+
+       rxd = DIV_ROUND_CLOSEST(rxd, MAC5_DELAY_STEP);
+       txd = DIV_ROUND_CLOSEST(txd, MAC5_DELAY_STEP);
+
+       if (rxd > 256 || txd > 256)
+               return -EINVAL;
+
+       if (rxd)
+               reg |= FIELD_PREP(MAC5_RX_DELAY, rxd - 1) | MAC5_RX_DELAY_EN;
+
+       if (txd)
+               reg |= FIELD_PREP(MAC5_TX_DELAY, txd - 1) | MAC5_TX_DELAY_EN;
+
+       return regmap_update_bits(priv->ethsys, ETHSYS_MAC(5),
+                                 MAC5_DELAY_MASK, reg);
+}
+
+static int xgmac_phy_setup(struct xgmac_priv *priv)
+{
+       struct device *dev = priv->dev;
+       struct device_node *np = dev->of_node;
+       phy_interface_t phy_mode;
+       struct phylink *phylink;
+       struct platform_device *pcs_dev;
+       struct phylink_pcs *pcs = NULL;
+       int ret;
+
+       ret = of_get_phy_mode(np, &phy_mode);
+       if (ret)
+               return ret;
+
+       if (phy_interface_mode_is_rgmii(phy_mode)) {
+               ret = xgmac_rgmii_delay(priv, phy_mode);
+               if (ret)
+                       return ret;
+
+               priv->csr_clk = devm_clk_get_enabled(dev, "rgmii");
+               if (IS_ERR(priv->csr_clk))
+                       return PTR_ERR(priv->csr_clk);
+
+               if (ret)
+                       return ret;
+       } else {
+               struct of_phandle_args pcs_args;
+               ret = of_parse_phandle_with_fixed_args(np, "pcs-handle", 1, 0,
+                                                      &pcs_args);
+               if (ret)
+                       return ret;
+
+               pcs_dev = of_find_device_by_node(pcs_args.np);
+               of_node_put(pcs_args.np);
+               if (!pcs_dev)
+                       return -ENODEV;
+
+               pcs = xpcs_port_get(pcs_dev, pcs_args.args[0]);
+               if (IS_ERR(pcs))
+                       return PTR_ERR(pcs);
+
+               priv->pcs_dev = pcs_dev;
+       }
+
+       priv->phylink_config.dev = &priv_to_netdev(priv)->dev;
+       priv->phylink_config.type = PHYLINK_NETDEV;
+
+       __set_bit(phy_mode, priv->phylink_config.supported_interfaces);
+
+       priv->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
+                                               MAC_10 | MAC_100 | MAC_1000FD |
+                                               MAC_2500FD;
+
+
+       phylink = phylink_create(&priv->phylink_config, dev->fwnode, phy_mode,
+                                &xgmac_phylink_mac_ops);
+       if (IS_ERR(phylink))
+               return PTR_ERR(phylink);
+
+       if (pcs)
+               priv->pcs = pcs;
+
+       priv->phylink = phylink;
+
+       return 0;
+}
+
+static int xgmac_probe(struct platform_device *pdev)
+{
+       static bool mac_disable_tx_set;
+       struct platform_device *dma_pdev;
+       struct device_node *dma_node;
+       struct net_device *ndev;
+       struct xgmac_priv *priv;
+       struct resource *r;
+       u32 ver;
+       int ret;
+
+       dma_node = of_parse_phandle(pdev->dev.of_node, "dmas", 0);
+       if (!dma_node)
+               return -ENODEV;
+
+       dma_pdev = of_find_device_by_node(dma_node);
+       of_node_put(dma_node);
+       if (!dma_pdev)
+               return -ENODEV;
+
+       ndev = devm_alloc_etherdev_mqs(&pdev->dev, sizeof(*priv), DMA_CH_MAX,
+                                      DMA_CH_MAX);
+       if (!ndev)
+               return -ENOMEM;
+
+       SET_NETDEV_DEV(ndev, &pdev->dev);
+       platform_set_drvdata(pdev, ndev);
+       priv = netdev_priv(ndev);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->ioaddr = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(priv->ioaddr))
+               return PTR_ERR(priv->ioaddr);
+
+       priv->csr_clk = devm_clk_get_enabled(&pdev->dev, "csr");
+       if (IS_ERR(priv->csr_clk))
+               return PTR_ERR(priv->csr_clk);
+
+       priv->id = offset_to_id(r->start);
+       priv->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                      "ethsys");
+       if (IS_ERR(priv->ethsys))
+               return PTR_ERR(priv->ethsys);
+
+       if (priv->id < 5) {
+               /* mac reset and release reset*/
+               ret = regmap_clear_bits(priv->ethsys, ETHSYS_RST, BIT(priv->id));
+               if (ret)
+                       return ret;
+
+               ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, BIT(priv->id));
+               if (ret)
+                       return ret;
+
+       } else {
+               ret = regmap_clear_bits(priv->ethsys, ETHSYS_RST, ETHSYS_RST_MAC5);
+               if (ret)
+                       return ret;
+
+               /* set mac5 phy mode to rgmii, should set under mac reset */
+               ret = regmap_write(priv->ethsys, ETHSYS_MAC5_CTRL,
+                               FIELD_PREP(MAC5_PHY_INTF_SEL, 1));
+               if (ret)
+                       return ret;
+
+               ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, ETHSYS_RST_MAC5);
+               if (ret)
+                       return ret;
+       }
+
+       if (!mac_disable_tx_set) {
+               /* Disable all MAC Tx, once and only once */
+               mac_disable_tx_set = true;
+               ret = regmap_write(priv->ethsys, ETHSYS_TX_DIS, 0xff);
+               if (ret)
+                       return ret;
+       }
+
+       ver = reg_read(priv, XGMAC_VERSION);
+       if (FIELD_GET(XGMAC_VERSION_ID_MASK, ver) != XGMAC_VERSION_ID)
+               return -ENODEV;
+
+       spin_lock_init(&priv->stats_lock);
+       priv->dev = &pdev->dev;
+       priv->dma = platform_get_drvdata(dma_pdev);
+       if (!priv->dma)
+               return -EPROBE_DEFER;
+
+       ndev->base_addr = r->start;
+       ndev->netdev_ops = &xgmac_netdev_ops;
+       ndev->ethtool_ops = &xgmac_ethtool_ops;
+       ndev->features = NETIF_F_RXHASH | NETIF_F_RXCSUM | NETIF_F_GRO |
+                        NETIF_F_SG | NETIF_F_LLTX | NETIF_F_HW_TC |
+                        NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO |
+                        NETIF_F_TSO6;
+       ndev->hw_features = (ndev->features & ~NETIF_F_RXHASH) |
+                           NETIF_F_LOOPBACK | NETIF_F_RXFCS | NETIF_F_RXALL |
+                           NETIF_F_HW_L2FW_DOFFLOAD;
+       ndev->vlan_features = ndev->features;
+       ndev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE;
+       ndev->max_mtu = MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN;
+
+       /* read-clear interrupt status before registering */
+       reg_read(priv, XGMAC_MDIO_INT_STATUS);
+       reg_read(priv, XGMAC_INT_STATUS);
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               return ret;
+
+       reg_clear(priv, XGMAC_INT_EN, XGMAC_LSI);
+       snprintf(priv->irq_name, sizeof(priv->irq_name), "xgmac%u_sbd",
+                priv->id);
+       ret = devm_request_irq(&pdev->dev, ret, xgmac_irq, 0, priv->irq_name,
+                              priv);
+       if (ret)
+               return ret;
+
+       ret = xgmac_mdio_init(priv);
+       if (ret)
+               return ret;
+
+       ret = of_get_ethdev_address(pdev->dev.of_node, ndev);
+       if (ret == -EPROBE_DEFER)
+               return ret;
+
+       if (ret) {
+               eth_hw_addr_random(ndev);
+               dev_warn(&pdev->dev, "generated random MAC address %pM\n",
+                        ndev->dev_addr);
+       }
+
+       ret = xgmac_phy_setup(priv);
+       if (ret)
+               return ret;
+
+       xgmac_write_mac_addr(priv, ndev->dev_addr, 0);
+       reg_set(priv, MMC_XGMAC_CONTROL,
+               MMC_XGMAC_CONTROL_RESET | MMC_XGMAC_CONTROL_RSTONRD);
+       reg_write(priv, XGMAC_TX_CONFIG, XGMAC_CORE_INIT_TX);
+       reg_write(priv, XGMAC_RX_CONFIG, XGMAC_CORE_INIT_RX);
+       reg_write(priv, XGMAC_WD_JB_TIMEOUT, XGMAC_PJE | XGMAC_PWE);
+       reg_write(priv, XGMAC_VLAN_TAG, XGMAC_VLAN_EDVLP);
+       reg_write(priv, XGMAC_LPI_TIMER_CTRL,
+                 FIELD_PREP(XGMAC_LPI_LST, XGMAC_LPI_LST_DEFAULT) |
+                 FIELD_PREP(XGMAC_LPI_TWT, XGMAC_LPI_TWT_DEFAULT));
+       reg_write(priv, XGMAC_LPI_AUTO_EN, XGMAC_LPI_AUTO_EN_DEFAULT);
+       xgmac_mib_irq_enable(priv);
+       reg_write(priv, XGMAC_LPI_1US,
+                 clk_get_rate(priv->csr_clk) / 1000000 - 1);
+
+       ret = register_netdev(ndev);
+       if (ret)
+               goto phy_cleanup;
+
+       return 0;
+phy_cleanup:
+       phylink_destroy(priv->phylink);
+       if (priv->pcs_dev)
+               xpcs_port_put(priv->pcs_dev);
+       return ret;
+}
+
+static void xgmac_remove(struct platform_device *pdev)
+{
+       struct net_device *dev = platform_get_drvdata(pdev);
+       struct xgmac_priv *priv = netdev_priv(dev);
+
+       unregister_netdev(dev);
+       phylink_destroy(priv->phylink);
+       if (priv->pcs_dev)
+               xpcs_port_put(priv->pcs_dev);
+       regmap_clear_bits(priv->ethsys, ETHSYS_RST, BIT(priv->id));
+}
+
+static const struct of_device_id xgmac_match[] = {
+       { .compatible = "siflower,sf21-xgmac" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xgmac_match);
+
+static struct platform_driver xgmac_driver = {
+       .probe  = xgmac_probe,
+       .remove_new     = xgmac_remove,
+       .driver = {
+               .name           = "sfxgmac",
+               .of_match_table = xgmac_match,
+       },
+};
+module_platform_driver(xgmac_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Qingfang Deng <qingfang.deng@siflower.com.cn>");
+MODULE_DESCRIPTION("Ethernet XGMAC driver for SF21A6826/SF21H8898 SoC");
\ No newline at end of file
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.c b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.c
new file mode 100644 (file)
index 0000000..03c2213
--- /dev/null
@@ -0,0 +1,621 @@
+#define pr_fmt(fmt)    "xpcs: " fmt
+
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phylink.h>
+#include <linux/of_platform.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/regmap.h>
+#include <asm-generic/bug.h>
+
+#include "sfxpcs.h"
+#include "eth.h"
+
+#define DEV_MASK    GENMASK(20, 16)
+#define REG_MASK    GENMASK(15, 0)
+
+#define DW_PCS_PORTS           4
+#define DW_QSGMII_MMD1          0x1a
+#define DW_QSGMII_MMD2          0x1b
+#define DW_QSGMII_MMD3          0x1c
+#define MDIO_CTRL1                     MII_BMCR
+#define MDIO_CTRL1_RESET    BMCR_RESET
+
+static inline void *PDE_DATA(const struct inode *inode) {BUG(); return NULL;};
+
+enum {
+       XPCS_CLK_REF,
+       XPCS_CLK_EEE,
+       XPCS_CLK_CSR,
+       XPCS_NUM_CLKS
+};
+
+struct xpcs_port {
+       struct phylink_pcs pcs;
+       unsigned int index;
+};
+
+struct xpcs_priv {
+       void __iomem *ioaddr;
+       struct regmap *ethsys;
+       struct clk_bulk_data clks[XPCS_NUM_CLKS];
+       u8 power_save_count;
+       u8 port_count;
+       u8 id;
+       struct xpcs_port ports[DW_PCS_PORTS];
+};
+
+static int xpcs_qsgmii_port_to_devad(unsigned int port)
+{
+       switch (port) {
+       case 0:
+               return MDIO_MMD_VEND2;
+       case 1:
+               return DW_QSGMII_MMD1;
+       case 2:
+               return DW_QSGMII_MMD2;
+       case 3:
+               return DW_QSGMII_MMD3;
+       default:
+               BUG();
+               return -EINVAL;
+       }
+}
+
+static u16 xpcs_read(struct xpcs_priv *priv, int devad, int reg)
+{
+       ulong r;
+
+       r = FIELD_PREP(REG_MASK, reg) | FIELD_PREP(DEV_MASK, devad);
+       r <<= 2;
+
+       return readw_relaxed(priv->ioaddr + r);
+}
+
+static void xpcs_write(struct xpcs_priv *priv, int devad, int reg, u16 val)
+{
+       ulong r;
+
+       r = FIELD_PREP(REG_MASK, reg) | FIELD_PREP(DEV_MASK, devad);
+       r <<= 2;
+
+       writew_relaxed(val, priv->ioaddr + r);
+}
+
+static inline void xpcs_clear(struct xpcs_priv *priv, int devad, int reg, u16 clear)
+{
+       xpcs_write(priv, devad, reg, xpcs_read(priv, devad, reg) & ~clear);
+}
+
+static inline void xpcs_set(struct xpcs_priv *priv, int devad, int reg, u16 set)
+{
+       xpcs_write(priv, devad, reg, xpcs_read(priv, devad, reg) | set);
+}
+
+static int xpcs_poll_reset(struct xpcs_priv *priv, int devad)
+{
+       int timeout = 100000;
+
+       while (xpcs_read(priv, devad, MDIO_CTRL1) & MDIO_CTRL1_RESET) {
+               if (!--timeout) {
+                       pr_err("Timed out waiting for reset\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int xpcs_poll_pg(struct xpcs_priv *priv, int devad, u16 val)
+{
+       u32 timeout = 0;
+
+       while (FIELD_GET(PSEQ_STATE,
+                               xpcs_read(priv, devad, DW_VR_MII_DIG_STS)) != val) {
+               if (timeout >= 100) {
+                       pr_err("Timed out waiting for power state\n");
+                       return -ETIMEDOUT;
+               }
+               timeout++;
+               udelay(100);
+       }
+       return 0;
+}
+
+static int xpcs_serdes_power_down(struct xpcs_priv *priv)
+{
+       xpcs_write(priv, MDIO_MMD_VEND2, MII_BMCR, BMCR_PDOWN);
+       return xpcs_poll_pg(priv, MDIO_MMD_VEND2, PSEQ_STATE_DOWN);
+}
+
+static int xpcs_serdes_power_up(struct xpcs_priv *priv)
+{
+       /* When powered down, this register cannot be read.
+        * speed/duplex/AN will be configured in pcs_config/pcs_link_up.
+        */
+       xpcs_write(priv, MDIO_MMD_VEND2, MII_BMCR, 0);
+       return xpcs_poll_pg(priv, MDIO_MMD_VEND2, PSEQ_STATE_GOOD);
+}
+
+/* Read AN result for 1000Base-X/2500Base-X */
+static void xpcs_8023z_resolve_link(struct xpcs_priv *priv,
+                                   struct phylink_link_state *state,
+                                   int fd_bit)
+{
+       bool tx_pause, rx_pause;
+       u16 adv, lpa;
+
+       adv = xpcs_read(priv, MDIO_MMD_VEND2, MII_ADVERTISE);
+       lpa = xpcs_read(priv, MDIO_MMD_VEND2, MII_LPA);
+
+       mii_lpa_mod_linkmode_x(state->lp_advertising, lpa, fd_bit);
+
+       if (linkmode_test_bit(fd_bit, state->advertising) &&
+           linkmode_test_bit(fd_bit, state->lp_advertising)) {
+               state->duplex = DUPLEX_FULL;
+       } else {
+               /* negotiation failure */
+               state->link = false;
+       }
+
+       linkmode_resolve_pause(state->advertising, state->lp_advertising,
+                              &tx_pause, &rx_pause);
+
+       if (tx_pause)
+               state->pause |= MLO_PAUSE_TX;
+       if (rx_pause)
+               state->pause |= MLO_PAUSE_RX;
+}
+
+static void xpcs_get_state(struct phylink_pcs *pcs,
+                          struct phylink_link_state *state)
+{
+       struct xpcs_port *port;
+       struct xpcs_priv *priv;
+       u16 intrsts, bmsr;
+       int mmd;
+
+       port = container_of(pcs, struct xpcs_port, pcs);
+       priv = container_of(port, struct xpcs_priv, ports[port->index]);
+       bmsr = xpcs_read(priv, MDIO_MMD_VEND2, MII_BMSR);
+
+       state->link = !!(bmsr & BMSR_LSTATUS);
+       state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
+       if (!state->link)
+               return;
+
+       switch (state->interface) {
+       case PHY_INTERFACE_MODE_SGMII:
+       case PHY_INTERFACE_MODE_QSGMII:
+               mmd = xpcs_qsgmii_port_to_devad(port->index);
+               /* For SGMII/QSGMII, link speed and duplex can be read from
+                * DW_VR_MII_AN_INTR_STS */
+               intrsts = xpcs_read(priv, mmd, DW_VR_MII_AN_INTR_STS);
+
+               state->link = !!(intrsts & DW_VR_MII_C37_ANSGM_SP_LNKSTS);
+               if (!state->link)
+                       break;
+
+               switch (FIELD_GET(DW_VR_MII_AN_STS_C37_ANSGM_SP, intrsts)) {
+               case DW_VR_MII_C37_ANSGM_SP_10:
+                       state->speed = SPEED_10;
+                       break;
+               case DW_VR_MII_C37_ANSGM_SP_100:
+                       state->speed = SPEED_100;
+                       break;
+               case DW_VR_MII_C37_ANSGM_SP_1000:
+                       state->speed = SPEED_1000;
+                       break;
+               }
+
+               state->duplex = (intrsts & DW_VR_MII_AN_STS_C37_ANSGM_FD) ?
+                               DUPLEX_FULL : DUPLEX_HALF;
+               break;
+       case PHY_INTERFACE_MODE_1000BASEX:
+               state->speed = SPEED_1000;
+               xpcs_8023z_resolve_link(priv, state,
+                                       ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
+               break;
+       case PHY_INTERFACE_MODE_2500BASEX:
+               state->speed = SPEED_2500;
+               xpcs_8023z_resolve_link(priv, state,
+                                       ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
+               break;
+       default:
+               break;
+       }
+}
+
+static void xpcs_qsgmii_init(struct xpcs_priv *priv)
+{
+       u16 reg;
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
+       /* Already configured for QSGMII? skip. */
+       if (FIELD_GET(DW_VR_MII_PCS_MODE_MASK, reg) == DW_VR_MII_PCS_MODE_C37_QSGMII)
+               return;
+
+       reg = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, DW_VR_MII_PCS_MODE_C37_QSGMII);
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, reg);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL1, 0x28);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0);
+       reg &= ~LANE_10BIT_SEL;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0, reg);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MISC_CTRL1, 0x0);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+       reg &= ~DW_VR_MII_DIG_CTRL1_2G5_EN;
+       reg &= ~DW_VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, reg);
+
+       xpcs_serdes_power_down(priv);
+       xpcs_serdes_power_up(priv);
+}
+
+static void xpcs_1000basex_sgmii_common_init(struct xpcs_priv *priv)
+{
+       u16 reg;
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL1, 0x28);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0);
+       reg |= LANE_10BIT_SEL;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0, reg);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MISC_CTRL1, 0xa);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+       reg &= ~DW_VR_MII_DIG_CTRL1_2G5_EN;
+       reg &= ~DW_VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, reg);
+
+       xpcs_serdes_power_down(priv);
+       xpcs_serdes_power_up(priv);
+}
+
+static void xpcs_1000basex_init(struct xpcs_priv *priv)
+{
+       u16 reg;
+
+       reg = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, DW_VR_MII_PCS_MODE_C37_1000BASEX);
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, reg);
+
+       xpcs_1000basex_sgmii_common_init(priv);
+}
+
+static void xpcs_sgmii_init(struct xpcs_priv *priv)
+{
+       u16 reg;
+
+       reg = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, DW_VR_MII_PCS_MODE_C37_SGMII);
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, reg);
+
+       xpcs_1000basex_sgmii_common_init(priv);
+}
+
+static void xpcs_2500basex_init(struct xpcs_priv *priv)
+{
+       u16 reg;
+
+       reg = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK, DW_VR_MII_PCS_MODE_C37_1000BASEX);
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, reg);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL1, 0x32);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0);
+       reg |= LANE_10BIT_SEL;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MPLL_CTRL0, reg);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_RXGENCTRL0);
+       reg |= RX_ALIGN_EN_0;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_RXGENCTRL0, reg);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_MP_6G_MISC_CTRL1, 0x5);
+
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_LINK_TIMER_CTRL,
+                  DW_VR_MII_LINK_TIMER_2500BASEX);
+
+       reg = xpcs_read(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
+       reg |= DW_VR_MII_DIG_CTRL1_2G5_EN;
+       reg |= DW_VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE;
+       xpcs_write(priv, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, reg);
+
+       xpcs_serdes_power_down(priv);
+       xpcs_serdes_power_up(priv);
+}
+
+static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
+                      phy_interface_t interface,
+                      const unsigned long *advertising,
+                      bool permit_pause_to_mac)
+{
+       struct xpcs_port *port;
+       struct xpcs_priv *priv;
+       u16 val;
+       int mmd;
+
+       port = container_of(pcs, struct xpcs_port, pcs);
+       priv = container_of(port, struct xpcs_priv, ports[port->index]);
+
+       /* Port 1,2,3 only exist in QSGMII mode */
+       if (port->index && interface != PHY_INTERFACE_MODE_QSGMII)
+               return -EINVAL;
+
+       /* Disable AN */
+       mmd = xpcs_qsgmii_port_to_devad(port->index);
+       xpcs_clear(priv, mmd, MII_BMCR, BMCR_ANENABLE);
+
+       switch (interface) {
+       case PHY_INTERFACE_MODE_QSGMII:
+               xpcs_qsgmii_init(priv);
+               break;
+       case PHY_INTERFACE_MODE_SGMII:
+               xpcs_sgmii_init(priv);
+               break;
+       case PHY_INTERFACE_MODE_2500BASEX:
+               xpcs_2500basex_init(priv);
+               break;
+       case PHY_INTERFACE_MODE_1000BASEX:
+               xpcs_1000basex_init(priv);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Enable interrupt for in-band status */
+       val = xpcs_read(priv, mmd, DW_VR_MII_AN_CTRL);
+       if (phylink_autoneg_inband(mode))
+               val |= DW_VR_MII_AN_INTR_EN;
+       else
+               val &= ~DW_VR_MII_AN_INTR_EN;
+       xpcs_write(priv, mmd, DW_VR_MII_AN_CTRL, val);
+
+       if (interface != PHY_INTERFACE_MODE_2500BASEX) {
+               val = xpcs_read(priv, mmd, DW_VR_MII_DIG_CTRL1);
+               /* Enable speed auto switch for SGMII/QSGMII */
+               val |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
+               xpcs_write(priv, mmd, DW_VR_MII_DIG_CTRL1, val);
+       }
+
+       /* Configure AN ADV for 802.3z modes */
+       if (phy_interface_mode_is_8023z(interface)) {
+               int fd_bit;
+               u16 adv;
+
+               fd_bit = interface == PHY_INTERFACE_MODE_1000BASEX ?
+                        ETHTOOL_LINK_MODE_1000baseX_Full_BIT :
+                        ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
+               adv = linkmode_adv_to_mii_adv_x(advertising, fd_bit);
+
+               xpcs_write(priv, MDIO_MMD_VEND2, MII_ADVERTISE, adv);
+       }
+
+       /* Enable AN */
+       if (interface != PHY_INTERFACE_MODE_2500BASEX)
+               xpcs_write(priv, mmd, MII_BMCR, BMCR_ANENABLE);
+
+       return 0;
+}
+
+static void xpcs_an_restart(struct phylink_pcs *pcs)
+{
+       struct xpcs_port *port;
+       struct xpcs_priv *priv;
+       int mmd;
+
+       port = container_of(pcs, struct xpcs_port, pcs);
+       priv = container_of(port, struct xpcs_priv, ports[port->index]);
+
+       mmd = xpcs_qsgmii_port_to_devad(port->index);
+       xpcs_set(priv, mmd, MII_BMCR, BMCR_ANRESTART);
+}
+
+static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
+                        phy_interface_t interface, int speed, int duplex)
+{
+       struct xpcs_port *port;
+       struct xpcs_priv *priv;
+       u16 bmcr;
+       int mmd;
+
+       /* Skip speed and duplex configuration for SGMII/QSGMII in-band */
+       if (phylink_autoneg_inband(mode) &&
+           !phy_interface_mode_is_8023z(interface))
+               return;
+
+       /* 1000/2500 BaseX should only use the max speed */
+       if (phy_interface_mode_is_8023z(interface))
+               speed = SPEED_1000;
+
+       port = container_of(pcs, struct xpcs_port, pcs);
+       priv = container_of(port, struct xpcs_priv, ports[port->index]);
+
+       mmd = xpcs_qsgmii_port_to_devad(port->index);
+       bmcr = xpcs_read(priv, mmd, MII_BMCR);
+       bmcr &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_SPEED10);
+
+       switch (speed) {
+       case SPEED_2500:
+       case SPEED_1000:
+               bmcr |= BMCR_SPEED1000;
+               break;
+       case SPEED_100:
+               bmcr |= BMCR_SPEED100;
+               break;
+       case SPEED_10:
+               bmcr |= BMCR_SPEED10;
+               break;
+       }
+       if (duplex == DUPLEX_FULL)
+               bmcr |= BMCR_FULLDPLX;
+       else
+               bmcr &= ~BMCR_FULLDPLX;
+
+       xpcs_write(priv, mmd, MII_BMCR, bmcr);
+}
+
+static const struct phylink_pcs_ops xpcs_phylink_ops = {
+       .pcs_get_state  = xpcs_get_state,
+       .pcs_config     = xpcs_config,
+       .pcs_an_restart = xpcs_an_restart,
+       .pcs_link_up    = xpcs_link_up,
+};
+
+struct phylink_pcs *xpcs_port_get(struct platform_device *pdev,
+                                 unsigned int port)
+{
+       struct xpcs_priv *priv = platform_get_drvdata(pdev);
+
+       if (port >= DW_PCS_PORTS)
+               return ERR_PTR(-EINVAL);
+
+       priv->port_count++;
+       priv->power_save_count++;
+       return &priv->ports[port].pcs;
+}
+EXPORT_SYMBOL(xpcs_port_get);
+
+
+
+void xpcs_port_put(struct platform_device *pdev)
+{
+       struct xpcs_priv *priv = platform_get_drvdata(pdev);
+
+       priv->port_count--;
+       priv->power_save_count--;
+}
+EXPORT_SYMBOL(xpcs_port_put);
+
+static irqreturn_t xpcs_irq(int irq, void *dev_id)
+{
+       struct xpcs_priv *priv = dev_id;
+       irqreturn_t ret = IRQ_NONE;
+       int i;
+
+       for (i = 0; i < DW_PCS_PORTS; i++) {
+               int mmd = xpcs_qsgmii_port_to_devad(i);
+               u16 intrsts = xpcs_read(priv, mmd, DW_VR_MII_AN_INTR_STS);
+               bool up;
+
+               if (!(intrsts & DW_VR_MII_C37_ANCMPLT_INTR))
+                       continue;
+
+               xpcs_write(priv, mmd, DW_VR_MII_AN_INTR_STS, 0);
+               up = xpcs_read(priv, MDIO_MMD_VEND2, MII_BMSR) & BMSR_LSTATUS;
+               up |= intrsts & DW_VR_MII_C37_ANSGM_SP_LNKSTS;
+               phylink_pcs_change(&priv->ports[i].pcs, up);
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static int xpcs_probe(struct platform_device *pdev)
+{
+       struct xpcs_priv *priv;
+       struct resource *r;
+       int ret, i;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, priv);
+       for (i = 0; i < DW_PCS_PORTS; i++) {
+               priv->ports[i].index = i;
+               priv->ports[i].pcs.ops = &xpcs_phylink_ops;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->ioaddr = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(priv->ioaddr))
+               return PTR_ERR(priv->ioaddr);
+
+       priv->id = !!(r->start & BIT(24));
+       priv->ethsys = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                      "ethsys");
+       if (IS_ERR(priv->ethsys))
+               return PTR_ERR(priv->ethsys);
+
+       priv->clks[XPCS_CLK_REF].id = "ref";
+       priv->clks[XPCS_CLK_EEE].id = "eee";
+       priv->clks[XPCS_CLK_CSR].id = "csr";
+       ret = devm_clk_bulk_get(&pdev->dev, XPCS_NUM_CLKS, priv->clks);
+       if (ret)
+               return ret;
+
+       ret = clk_bulk_prepare_enable(XPCS_NUM_CLKS, priv->clks);
+       if (ret)
+               return ret;
+
+       ret = regmap_set_bits(priv->ethsys, ETHSYS_RST, BIT(5 + priv->id));
+       if (ret)
+               return ret;
+
+       ret = regmap_write(priv->ethsys,
+                          ETHSYS_QSG_CTRL + priv->id * sizeof(u32), 0x601);
+       if (ret)
+               return ret;
+
+       /* set ethtsuclk to 100MHz */
+       ret = clk_set_rate(priv->clks[XPCS_CLK_EEE].clk, 100000000);
+       if (ret)
+               return ret;
+
+       /* Soft reset the PCS */
+       xpcs_write(priv, MDIO_MMD_VEND2, MII_BMCR, BMCR_RESET);
+       ret = xpcs_poll_reset(priv, MDIO_MMD_VEND2);
+       if (ret)
+               return ret;
+
+       /* Enable EEE */
+       xpcs_set(priv, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0,
+                DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN);
+
+       /* Start from the power up state */
+       ret = xpcs_serdes_power_up(priv);
+       if (ret)
+               return ret;
+
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = devm_request_irq(&pdev->dev, ret, xpcs_irq, 0, KBUILD_MODNAME, priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int xpcs_remove(struct platform_device *pdev)
+{
+       struct xpcs_priv *priv = platform_get_drvdata(pdev);
+
+       clk_bulk_disable_unprepare(XPCS_NUM_CLKS, priv->clks);
+       return regmap_clear_bits(priv->ethsys, ETHSYS_RST, BIT(5 + priv->id));
+}
+
+static const struct of_device_id xpcs_match[] = {
+       { .compatible = "siflower,sf21-xpcs" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, xpcs_match);
+
+static struct platform_driver xpcs_driver = {
+       .probe  = xpcs_probe,
+       .remove = xpcs_remove,
+       .driver = {
+               .name           = "sfxpcs",
+               .of_match_table = xpcs_match,
+       },
+};
+module_platform_driver(xpcs_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Qingfang Deng <qingfang.deng@siflower.com.cn>");
+MODULE_DESCRIPTION("XPCS driver for SF21A6826/SF21H8898 SoC");
diff --git a/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.h b/target/linux/siflower/files-6.6/drivers/net/ethernet/siflower/sfxpcs.h
new file mode 100644 (file)
index 0000000..0ff9e8f
--- /dev/null
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define SYNOPSYS_XPCS_ID               0x7996ced0
+#define SYNOPSYS_XPCS_MASK             0xffffffff
+
+/* Vendor regs access */
+#define DW_VENDOR                      BIT(15)
+
+/* VR_XS_PCS */
+#define DW_USXGMII_RST                 BIT(10)
+#define DW_USXGMII_EN                  BIT(9)
+#define DW_VR_XS_PCS_DIG_STS           0x0010
+#define DW_RXFIFO_ERR                  GENMASK(6, 5)
+
+/* SR_MII */
+#define DW_USXGMII_FULL                        BIT(8)
+#define DW_USXGMII_SS_MASK             (BIT(13) | BIT(6) | BIT(5))
+#define DW_USXGMII_10000               (BIT(13) | BIT(6))
+#define DW_USXGMII_5000                        (BIT(13) | BIT(5))
+#define DW_USXGMII_2500                        (BIT(5))
+#define DW_USXGMII_1000                        (BIT(6))
+#define DW_USXGMII_100                 (BIT(13))
+#define DW_USXGMII_10                  (0)
+
+/* SR_AN */
+#define DW_SR_AN_ADV1                  0x10
+#define DW_SR_AN_ADV2                  0x11
+#define DW_SR_AN_ADV3                  0x12
+#define DW_SR_AN_LP_ABL1               0x13
+#define DW_SR_AN_LP_ABL2               0x14
+#define DW_SR_AN_LP_ABL3               0x15
+
+/* Clause 73 Defines */
+/* AN_LP_ABL1 */
+#define DW_C73_PAUSE                   BIT(10)
+#define DW_C73_ASYM_PAUSE              BIT(11)
+#define DW_C73_AN_ADV_SF               0x1
+/* AN_LP_ABL2 */
+#define DW_C73_1000KX                  BIT(5)
+#define DW_C73_10000KX4                        BIT(6)
+#define DW_C73_10000KR                 BIT(7)
+/* AN_LP_ABL3 */
+#define DW_C73_2500KX                  BIT(0)
+#define DW_C73_5000KR                  BIT(1)
+
+/* Clause 37 Defines */
+/* VR MII MMD registers offsets */
+#define DW_VR_MII_MMD_CTRL             0x0000
+#define DW_VR_MII_DIG_CTRL1            0x8000
+#define DW_VR_MII_AN_CTRL              0x8001
+#define DW_VR_MII_AN_INTR_STS          0x8002
+#define DW_VR_MII_DBG_CTRL             0x8005
+#define DW_VR_MII_LINK_TIMER_CTRL      0x800a
+#define DW_VR_MII_DIG_STS       0x8010
+#define DW_VR_MII_MP_6G_RXGENCTRL0  0x8058
+#define DW_VR_MII_MP_6G_MPLL_CTRL0  0x8078
+#define DW_VR_MII_MP_6G_MPLL_CTRL1  0x8079
+#define DW_VR_MII_MP_6G_MISC_CTRL1  0x809a
+/* Enable 2.5G Mode */
+#define DW_VR_MII_DIG_CTRL1_2G5_EN     BIT(2)
+/* EEE Mode Control Register */
+#define DW_VR_MII_EEE_MCTRL0           0x8006
+#define DW_VR_MII_EEE_MCTRL1           0x800b
+#define DW_VR_MII_DIG_CTRL2            0x80e1
+
+/* VR_MII_DIG_CTRL1 */
+#define DW_VR_MII_DIG_CTRL1_EN_25G_MODE                BIT(2)
+#define DW_VR_MII_DIG_CTRL1_CL37_TMR_OVR_RIDE  BIT(3)
+#define DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW                BIT(9)
+
+/* VR_MII_DIG_CTRL2 */
+#define DW_VR_MII_DIG_CTRL2_TX_POL_INV         BIT(4)
+#define DW_VR_MII_DIG_CTRL2_RX_POL_INV         BIT(0)
+
+/* VR_MII_AN_CTRL */
+#define DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT      3
+#define DW_VR_MII_TX_CONFIG_MASK               BIT(3)
+#define DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII     0x1
+#define DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII     0x0
+#define DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT       1
+#define DW_VR_MII_PCS_MODE_MASK                        GENMASK(2, 1)
+#define DW_VR_MII_PCS_MODE_C37_1000BASEX       0x0
+#define DW_VR_MII_PCS_MODE_C37_SGMII           0x2
+#define DW_VR_MII_PCS_MODE_C37_QSGMII          0x3
+#define DW_VR_MII_AN_INTR_EN                   BIT(0)
+
+/* VR_MII_AN_INTR_STS */
+#define DW_VR_MII_AN_STS_C37_ANSGM_FD          BIT(1)
+#define DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT    2
+#define DW_VR_MII_AN_STS_C37_ANSGM_SP          GENMASK(3, 2)
+#define DW_VR_MII_C37_ANSGM_SP_10              0x0
+#define DW_VR_MII_C37_ANSGM_SP_100             0x1
+#define DW_VR_MII_C37_ANSGM_SP_1000            0x2
+#define DW_VR_MII_C37_ANSGM_SP_LNKSTS          BIT(4)
+#define DW_VR_MII_C37_ANCMPLT_INTR             BIT(0)
+
+/* VR_MII_LINK_TIMER_CTRL */
+#define DW_VR_MII_LINK_TIMER_2500BASEX         0x2faf
+
+/* VR_MII_DIG_STS */
+#define PSEQ_STATE              GENMASK(4, 2)
+#define PSEQ_STATE_GOOD             4
+#define PSEQ_STATE_DOWN             6
+
+/* VR_MII_MP_6G_MPLL_CTRL0 */
+#define LANE_10BIT_SEL              BIT(1)
+
+/* VR_MII_MP_6G_RXGENCTRL0 */
+#define RX_ALIGN_EN_0               BIT(4)
+
+/* SR MII MMD Control defines */
+#define AN_CL37_EN                     BIT(12) /* Enable Clause 37 auto-nego */
+#define SGMII_SPEED_SS13               BIT(13) /* SGMII speed along with SS6 */
+#define SGMII_SPEED_SS6                        BIT(6)  /* SGMII speed along with SS13 */
+
+/* VR MII EEE Control 0 defines */
+#define DW_VR_MII_EEE_LTX_EN                   BIT(0)  /* LPI Tx Enable */
+#define DW_VR_MII_EEE_LRX_EN                   BIT(1)  /* LPI Rx Enable */
+#define DW_VR_MII_EEE_TX_QUIET_EN              BIT(2)  /* Tx Quiet Enable */
+#define DW_VR_MII_EEE_RX_QUIET_EN              BIT(3)  /* Rx Quiet Enable */
+#define DW_VR_MII_EEE_TX_EN_CTRL               BIT(4)  /* Tx Control Enable */
+#define DW_VR_MII_EEE_RX_EN_CTRL               BIT(7)  /* Rx Control Enable */
+
+#define DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT    8
+#define DW_VR_MII_EEE_MULT_FACT_100NS          GENMASK(11, 8)
+
+/* VR MII EEE Control 1 defines */
+#define DW_VR_MII_EEE_TRN_LPI          BIT(0)  /* Transparent Mode Enable */
+
+/* Additional MMDs for QSGMII */
+#define DW_QSGMII_MMD1                 0x1a
+#define DW_QSGMII_MMD2                 0x1b
+#define DW_QSGMII_MMD3                 0x1c
+
+/* PMA MMD registers */
+#define XS_PMA_MMD_BaseAddress 0x8020
+#define VR_XS_PMA_RX_LSTS (XS_PMA_MMD_BaseAddress + 0x0)
+#define VR_XS_PMA_RX_LSTS_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_TX_GENCTRL0 (XS_PMA_MMD_BaseAddress + 0x10)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_GENCTRL0_RegisterResetValue 0x1000
+#define VR_XS_PMA_MP_12G_16G_25G_TX_GENCTRL1 (XS_PMA_MMD_BaseAddress + 0x11)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_GENCTRL1_RegisterResetValue 0x1510
+#define VR_XS_PMA_MP_12G_16G_TX_GENCTRL2 (XS_PMA_MMD_BaseAddress + 0x12)
+#define VR_XS_PMA_MP_12G_16G_TX_GENCTRL2_RegisterResetValue 0x300
+#define VR_XS_PMA_MP_12G_16G_25G_TX_BOOST_CTRL (XS_PMA_MMD_BaseAddress + 0x13)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_BOOST_CTRL_RegisterResetValue 0xf
+#define VR_XS_PMA_MP_12G_16G_25G_TX_RATE_CTRL (XS_PMA_MMD_BaseAddress + 0x14)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_RATE_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL (XS_PMA_MMD_BaseAddress + 0x15)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_TX_EQ_CTRL0 (XS_PMA_MMD_BaseAddress + 0x16)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_EQ_CTRL0_RegisterResetValue 0x2800
+#define VR_XS_PMA_MP_12G_16G_25G_TX_EQ_CTRL1 (XS_PMA_MMD_BaseAddress + 0x17)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_EQ_CTRL1_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_TX_GENCTRL3 (XS_PMA_MMD_BaseAddress + 0x1c)
+#define VR_XS_PMA_MP_16G_25G_TX_GENCTRL3_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_TX_GENCTRL4 (XS_PMA_MMD_BaseAddress + 0x1d)
+#define VR_XS_PMA_MP_16G_25G_TX_GENCTRL4_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_TX_MISC_CTRL0 (XS_PMA_MMD_BaseAddress + 0x1e)
+#define VR_XS_PMA_MP_16G_25G_TX_MISC_CTRL0_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_TX_STS (XS_PMA_MMD_BaseAddress + 0x20)
+#define VR_XS_PMA_MP_12G_16G_25G_TX_STS_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_RX_GENCTRL0 (XS_PMA_MMD_BaseAddress + 0x30)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_GENCTRL0_RegisterResetValue 0x101
+#define VR_XS_PMA_MP_12G_16G_25G_RX_GENCTRL1 (XS_PMA_MMD_BaseAddress + 0x31)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_GENCTRL1_RegisterResetValue 0x1100
+#define VR_XS_PMA_MP_12G_16G_RX_GENCTRL2 (XS_PMA_MMD_BaseAddress + 0x32)
+#define VR_XS_PMA_MP_12G_16G_RX_GENCTRL2_RegisterResetValue 0x300
+#define VR_XS_PMA_MP_12G_16G_RX_GENCTRL3 (XS_PMA_MMD_BaseAddress + 0x33)
+#define VR_XS_PMA_MP_12G_16G_RX_GENCTRL3_RegisterResetValue 0x1
+#define VR_XS_PMA_MP_12G_16G_25G_RX_RATE_CTRL (XS_PMA_MMD_BaseAddress + 0x34)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_RATE_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL (XS_PMA_MMD_BaseAddress + 0x35)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_RX_CDR_CTRL (XS_PMA_MMD_BaseAddress + 0x36)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_CDR_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_RX_ATTN_CTRL (XS_PMA_MMD_BaseAddress + 0x37)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_ATTN_CTRL_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_RX_EQ_CTRL0 (XS_PMA_MMD_BaseAddress + 0x38)
+#define VR_XS_PMA_MP_16G_25G_RX_EQ_CTRL0_RegisterResetValue 0x5550
+#define VR_XS_PMA_MP_12G_16G_25G_RX_EQ_CTRL4 (XS_PMA_MMD_BaseAddress + 0x3c)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_EQ_CTRL4_RegisterResetValue 0x11
+#define VR_XS_PMA_MP_16G_25G_RX_EQ_CTRL5 (XS_PMA_MMD_BaseAddress + 0x3d)
+#define VR_XS_PMA_MP_16G_25G_RX_EQ_CTRL5_RegisterResetValue 0x30
+#define VR_XS_PMA_MP_12G_16G_25G_DFE_TAP_CTRL0 (XS_PMA_MMD_BaseAddress + 0x3e)
+#define VR_XS_PMA_MP_12G_16G_25G_DFE_TAP_CTRL0_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_RX_STS (XS_PMA_MMD_BaseAddress + 0x40)
+#define VR_XS_PMA_MP_12G_16G_25G_RX_STS_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_RX_PPM_STS0 (XS_PMA_MMD_BaseAddress + 0x41)
+#define VR_XS_PMA_MP_16G_25G_RX_PPM_STS0_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_RX_CDR_CTRL1 (XS_PMA_MMD_BaseAddress + 0x44)
+#define VR_XS_PMA_MP_16G_RX_CDR_CTRL1_RegisterResetValue 0x111
+#define VR_XS_PMA_MP_16G_25G_RX_PPM_CTRL0 (XS_PMA_MMD_BaseAddress + 0x45)
+#define VR_XS_PMA_MP_16G_25G_RX_PPM_CTRL0_RegisterResetValue 0x12
+#define VR_XS_PMA_MP_16G_25G_RX_GENCTRL4 (XS_PMA_MMD_BaseAddress + 0x48)
+#define VR_XS_PMA_MP_16G_25G_RX_GENCTRL4_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_25G_RX_MISC_CTRL0 (XS_PMA_MMD_BaseAddress + 0x49)
+#define VR_XS_PMA_MP_16G_25G_RX_MISC_CTRL0_RegisterResetValue 0x12
+#define VR_XS_PMA_MP_16G_25G_RX_IQ_CTRL0 (XS_PMA_MMD_BaseAddress + 0x4b)
+#define VR_XS_PMA_MP_16G_25G_RX_IQ_CTRL0_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_MPLL_CMN_CTRL (XS_PMA_MMD_BaseAddress + 0x50)
+#define VR_XS_PMA_MP_12G_16G_25G_MPLL_CMN_CTRL_RegisterResetValue 0x1
+#define VR_XS_PMA_MP_12G_16G_MPLLA_CTRL0 (XS_PMA_MMD_BaseAddress + 0x51)
+#define VR_XS_PMA_MP_12G_16G_MPLLA_CTRL0_RegisterResetValue 0x21
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL1 (XS_PMA_MMD_BaseAddress + 0x52)
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL1_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_MPLLA_CTRL2 (XS_PMA_MMD_BaseAddress + 0x53)
+#define VR_XS_PMA_MP_12G_16G_MPLLA_CTRL2_RegisterResetValue 0x600
+#define VR_XS_PMA_MP_12G_16G_MPLLB_CTRL0 (XS_PMA_MMD_BaseAddress + 0x54)
+#define VR_XS_PMA_MP_12G_16G_MPLLB_CTRL0_RegisterResetValue 0x8000
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL1 (XS_PMA_MMD_BaseAddress + 0x55)
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL1_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_MPLLB_CTRL2 (XS_PMA_MMD_BaseAddress + 0x56)
+#define VR_XS_PMA_MP_12G_16G_MPLLB_CTRL2_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL3 (XS_PMA_MMD_BaseAddress + 0x57)
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL3_RegisterResetValue 0xa016
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL3 (XS_PMA_MMD_BaseAddress + 0x58)
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL3_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL4 (XS_PMA_MMD_BaseAddress + 0x59)
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL4_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL5 (XS_PMA_MMD_BaseAddress + 0x5a)
+#define VR_XS_PMA_MP_16G_MPLLA_CTRL5_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL4 (XS_PMA_MMD_BaseAddress + 0x5b)
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL4_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL5 (XS_PMA_MMD_BaseAddress + 0x5c)
+#define VR_XS_PMA_MP_16G_MPLLB_CTRL5_RegisterResetValue 0x0
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_CTRL0 (XS_PMA_MMD_BaseAddress + 0x70)
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_CTRL0_RegisterResetValue 0x5100
+#define VR_XS_PMA_MP_12G_16G_25G_REF_CLK_CTRL (XS_PMA_MMD_BaseAddress + 0x71)
+#define VR_XS_PMA_MP_12G_16G_25G_REF_CLK_CTRL_RegisterResetValue 0x71
+#define VR_XS_PMA_MP_12G_16G_25G_REF_CLK_CTRL_REF_RPT_CLK_EN BIT(8)
+#define VR_XS_PMA_MP_12G_16G_25G_VCO_CAL_LD0 (XS_PMA_MMD_BaseAddress + 0x72)
+#define VR_XS_PMA_MP_12G_16G_25G_VCO_CAL_LD0_RegisterResetValue 0x549
+#define VR_XS_PMA_MP_16G_25G_VCO_CAL_REF0 (XS_PMA_MMD_BaseAddress + 0x76)
+#define VR_XS_PMA_MP_16G_25G_VCO_CAL_REF0_RegisterResetValue 0x29
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_STS (XS_PMA_MMD_BaseAddress + 0x78)
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_STS_RegisterResetValue 0x200
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_CTRL1 (XS_PMA_MMD_BaseAddress + 0x79)
+#define VR_XS_PMA_MP_12G_16G_25G_MISC_CTRL1_RegisterResetValue 0xffff
+#define VR_XS_PMA_MP_12G_16G_25G_EEE_CTRL (XS_PMA_MMD_BaseAddress + 0x7a)
+#define VR_XS_PMA_MP_12G_16G_25G_EEE_CTRL_RegisterResetValue 0x4f
+#define VR_XS_PMA_MP_12G_16G_25G_SRAM (XS_PMA_MMD_BaseAddress + 0x7b)
+#define VR_XS_PMA_MP_12G_16G_25G_SRAM_INIT_DN BIT(0)
+#define VR_XS_PMA_MP_12G_16G_25G_SRAM_EXT_LD_DN BIT(1)
+#define VR_XS_PMA_MP_16G_25G_MISC_CTRL2 (XS_PMA_MMD_BaseAddress + 0x7c)
+#define VR_XS_PMA_MP_16G_25G_MISC_CTRL2_RegisterResetValue 0x1
+#define VR_XS_PMA_SNPS_CR_CTRL (XS_PMA_MMD_BaseAddress + 0x80)
+#define VR_XS_PMA_SNPS_CR_CTRL_START_BUSY BIT(0)
+#define VR_XS_PMA_SNPS_CR_CTRL_WR_RDN  BIT(1)
+#define VR_XS_PMA_SNPS_CR_ADDR (XS_PMA_MMD_BaseAddress + 0x81)
+#define VR_XS_PMA_SNPS_CR_DATA (XS_PMA_MMD_BaseAddress + 0x82)
diff --git a/target/linux/siflower/files-6.6/drivers/net/phy/siflower.c b/target/linux/siflower/files-6.6/drivers/net/phy/siflower.c
new file mode 100644 (file)
index 0000000..b233354
--- /dev/null
@@ -0,0 +1,877 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * drivers/net/phy/siflower.c
+ *
+ * Driver for Siflower PHYs
+ *
+ * Copyright (c) 2023 Siflower, Inc.
+ *
+ * Support : Siflower Phys:
+ *             Giga phys: p1211f, p1240
+ */
+#include <linux/bitops.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+/* for wol feature */
+#include <linux/netdevice.h>
+
+/* WOL Enable Flag:
+ * disable by default to enable system WOL feature of phy
+ * please define this phy to 1 otherwise, define it to 0.
+ */
+#define SIFLOWER_PHY_WOL_FEATURE_ENABLE                         0
+#define SIFLOWER_PHY_WOL_PASSWD_ENABLE                          0
+
+#define SIFLOWER_PHY_MODE_SET_ENABLE                            0
+#define SIFLOWER_PHY_RXC_DELAY_SET_ENABLE                       0
+#define SIFLOWER_PHY_RXC_DELAY_VAL                              0x40
+#define SIFLOWER_PHY_TXC_DELAY_VAL                              0x40
+#define SIFLOWER_PHY_CLK_OUT_125M_ENABLE                        1
+
+#define SFPHY_GLB_DISABLE                                      0
+#define SFPHY_GLB_ENABLE                                       1
+#define SFPHY_LINK_DOWN                                        0
+#define SFPHY_LINK_UP                                          1
+/* Mask used for ID comparisons */
+#define SIFLOWER_PHY_ID_MASK                                    0xffffffff
+
+/* SF1211F PHY IDs */
+#define SF1211F_PHY_ID                                          0xADB40412
+/* SF1240 PHY IDs */
+#define SF1240_PHY_ID                                          0xADB40411
+
+/* SF1211F PHY LED */
+#define SF1211F_EXTREG_LED0                                     0x1E33   // 0
+#define SF1211F_EXTREG_LED1                                     0x1E34   // 00101111
+#define SF1211F_EXTREG_LED2                                     0x1E35   // 0x40
+/* SF1240 PHY BX LED */
+#define SF1240_EXTREG_LEDCTRL                                  0x0621
+#define SF1240_EXTREG_LED0_1                                   0x0700
+#define SF1240_EXTREG_LED0_2                                   0x0701
+#define SF1240_EXTREG_LED1_1                                   0x0702
+#define SF1240_EXTREG_LED1_2                                   0x0703
+#define SF1240_EXTREG_LED2_1                                   0x0706
+#define SF1240_EXTREG_LED2_2                                   0x0707
+#define SF1240_EXTREG_LED3_1                                   0x0708
+#define SF1240_EXTREG_LED3_2                                   0x0709
+#define SF1240_EXTREG_LED4_1                                   0x070C
+#define SF1240_EXTREG_LED4_2                                   0x070D
+#define SF1240_EXTREG_LED5_1                                   0x070E
+#define SF1240_EXTREG_LED5_2                                   0x070F
+#define SF1240_EXTREG_LED6_1                                   0x0712
+#define SF1240_EXTREG_LED6_2                                   0x0713
+#define SF1240_EXTREG_LED7_1                                   0x0714
+#define SF1240_EXTREG_LED7_2                                   0x0715
+
+/* PHY MODE OPSREG*/
+#define SF1211F_EXTREG_GET_PORT_PHY_MODE                        0x062B
+#define SF1211F_EXTREG_PHY_MODE_MASK                            0x0070
+/* Magic Packet MAC address registers */
+#define SIFLOWER_MAGIC_PACKET_MAC_ADDR                          0x0229
+/* Magic Packet MAC Passwd registers */
+#define SIFLOWER_MAGIC_PACKET_PASSWD_ADDR                       0x022F
+#define SIFLOWER_PHY_WOL_PULSE_MODE_SET                         0x062a
+
+/* Magic Packet MAC Passwd Val*/
+#define SIFLOWER_MAGIC_PACKET_PASSWD1                            0x11
+#define SIFLOWER_MAGIC_PACKET_PASSWD2                            0x22
+#define SIFLOWER_MAGIC_PACKET_PASSWD3                            0x33
+#define SIFLOWER_MAGIC_PACKET_PASSWD4                            0x44
+#define SIFLOWER_MAGIC_PACKET_PASSWD5                            0x55
+#define SIFLOWER_MAGIC_PACKET_PASSWD6                            0x66
+
+/* Siflower wol config register */
+#define SIFLOWER_WOL_CFG_REG0                                   0x0220
+#define SIFLOWER_WOL_CFG_REG1                                   0x0221
+#define SIFLOWER_WOL_CFG_REG2                                   0x0222
+#define SIFLOWER_WOL_STA_REG                                    0x0223
+/* 8 PHY MODE */
+#define SF1211F_EXTREG_PHY_MODE_UTP_TO_RGMII                    0x00
+#define SF1211F_EXTREG_PHY_MODE_FIBER_TO_RGMII                  0x10
+#define SF1211F_EXTREG_PHY_MODE_UTP_OR_FIBER_TO_RGMII           0x20
+#define SF1211F_EXTREG_PHY_MODE_UTP_TO_SGMII                    0x30
+#define SF1211F_EXTREG_PHY_MODE_SGMII_PHY_TO_RGMII_MAC          0x40
+#define SF1211F_EXTREG_PHY_MODE_SGMII_MAC_TO_RGMII_PHY          0x50
+#define SF1211F_EXTREG_PHY_MODE_UTP_TO_FIBER_AUTO               0x60
+#define SF1211F_EXTREG_PHY_MODE_UTP_TO_FIBER_FORCE              0x70
+
+/* PHY EXTRW OPSREG */
+#define SF1211F_EXTREG_ADDR                                     0x0E
+#define SF1211F_EXTREG_DATA                                     0x0D
+/* PHY PAGE SPACE */
+#define SFPHY_REG_UTP_SPACE                                    0
+#define SFPHY_REG_FIBER_SPACE                                  1
+
+/* PHY PAGE SELECT */
+#define SF1211F_EXTREG_PHY_MODE_PAGE_SELECT                     0x0016
+#define SFPHY_REG_UTP_SPACE_SETADDR                            0x0000
+#define SFPHY_REG_FIBER_SPACE_SETADDR                          0x0100
+//utp
+#define UTP_REG_PAUSE_CAP                                      0x0400    /* Can pause                   */
+#define UTP_REG_PAUSE_ASYM                                     0x0800    /* Can pause asymetrically     */
+//fiber
+#define FIBER_REG_PAUSE_CAP                                    0x0080    /* Can pause                   */
+#define FIBER_REG_PAUSE_ASYM                                   0x0100    /* Can pause asymetrically     */
+
+/* specific status register */
+#define SIFLOWER_SPEC_REG                                       0x0011
+
+/* Interrupt Enable Register */
+#define SIFLOWER_INTR_REG                                       0x0017
+/* WOL TYPE */
+#define SIFLOWER_WOL_TYPE                                       BIT(0)
+/* WOL Pulse Width */
+#define SIFLOWER_WOL_WIDTH1                                     BIT(1)
+#define SIFLOWER_WOL_WIDTH2                                     BIT(2)
+/* WOL dest addr check enable */
+#define SIFLOWER_WOL_SECURE_CHECK                               BIT(5)
+/* WOL crc check enable */
+#define SIFLOWER_WOL_CRC_CHECK                                  BIT(4)
+/* WOL dest addr check enable */
+#define SIFLOWER_WOL_DESTADDR_CHECK                             BIT(5)
+/* WOL Event Interrupt Enable */
+#define SIFLOWER_WOL_INTR_EN                                    BIT(2)
+/* WOL Enable */
+#define SIFLOWER_WOL_EN                                         BIT(7)
+
+#define SIFLOWER_WOL_RESTARTANEG                                BIT(9)
+/* GET PHY MODE */
+#define SFPHY_MODE_CURR                                        sfphy_get_port_type(phydev)
+
+enum siflower_port_type_e
+{
+       SFPHY_PORT_TYPE_UTP,
+       SFPHY_PORT_TYPE_FIBER,
+       SFPHY_PORT_TYPE_COMBO,
+       SFPHY_PORT_TYPE_EXT
+};
+enum siflower_wol_type_e
+{
+       SFPHY_WOL_TYPE_LEVEL,
+       SFPHY_WOL_TYPE_PULSE,
+       SFPHY_WOL_TYPE_EXT
+};
+
+enum siflower_wol_width_e
+{
+       SFPHY_WOL_WIDTH_84MS,
+       SFPHY_WOL_WIDTH_168MS,
+       SFPHY_WOL_WIDTH_336MS,
+       SFPHY_WOL_WIDTH_672MS,
+       SFPHY_WOL_WIDTH_EXT
+};
+
+typedef struct siflower_wol_cfg_s
+{
+       int wolen;
+       int type;
+       int width;
+       int secure;
+       int checkcrc;
+       int checkdst;
+}siflower_wol_cfg_t;
+
+static int sf1211f_phy_ext_read(struct phy_device *phydev, u32 regnum)
+{
+       int ret, val, oldpage = 0, oldval = 0;
+
+       phy_lock_mdio_bus(phydev);
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_ADDR);
+       if (ret < 0)
+               goto err_handle;
+       oldval = ret;
+
+       /* Force change to utp page */
+       ret = __phy_read(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT);//get old page
+       if (ret < 0)
+               goto err_handle;
+       oldpage = ret;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, SFPHY_REG_UTP_SPACE_SETADDR);
+       if (ret < 0)
+               goto err_handle;
+
+       /* Default utp ext rw */
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, regnum);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_DATA);
+       if (ret < 0)
+               goto err_handle;
+       val = ret;
+
+       /* Recover to old page */
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, oldpage);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, oldval);
+       if (ret < 0)
+               goto err_handle;
+       ret = val;
+
+err_handle:
+       phy_unlock_mdio_bus(phydev);
+       return ret;
+}
+
+static int sf1211f_phy_ext_write(struct phy_device *phydev, u32 regnum, u16 val)
+{
+       int ret, oldpage = 0, oldval = 0;
+
+       phy_lock_mdio_bus(phydev);
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_ADDR);
+       if (ret < 0)
+               goto err_handle;
+       oldval = ret;
+
+       /* Force change to utp page */
+       ret = __phy_read(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT); //get old page
+       if (ret < 0)
+               goto err_handle;
+       oldpage = ret;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, SFPHY_REG_UTP_SPACE_SETADDR);
+       if (ret < 0)
+               goto err_handle;
+
+       /* Default utp ext rw */
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, regnum);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_DATA, val);
+       if (ret < 0)
+               goto err_handle;
+
+       /* Recover to old page */
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, oldpage);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, oldval);
+       if (ret < 0)
+               goto err_handle;
+
+err_handle:
+       phy_unlock_mdio_bus(phydev);
+       return ret;
+
+}
+
+static int siflower_phy_select_reg_page(struct phy_device *phydev, int space)
+{
+       int ret;
+       if (space == SFPHY_REG_UTP_SPACE)
+               ret = phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, SFPHY_REG_UTP_SPACE_SETADDR);
+       else
+               ret = phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, SFPHY_REG_FIBER_SPACE_SETADDR);
+       return ret;
+}
+
+static int siflower_phy_get_reg_page(struct phy_device *phydev)
+{
+       return phy_read(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT);
+}
+
+static int siflower_phy_ext_read(struct phy_device *phydev, u32 regnum)
+{
+       return sf1211f_phy_ext_read(phydev, regnum);
+}
+
+
+static int siflower_phy_ext_write(struct phy_device *phydev, u32 regnum, u16 val)
+{
+       return sf1211f_phy_ext_write(phydev, regnum, val);
+}
+
+static int sfphy_page_read(struct phy_device *phydev, int page, u32 regnum)
+{
+       int ret, val, oldpage = 0, oldval = 0;
+
+       phy_lock_mdio_bus(phydev);
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_ADDR);
+       if (ret < 0)
+               goto err_handle;
+       oldval = ret;
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT);
+       if (ret < 0)
+               goto err_handle;
+       oldpage = ret;
+
+       //Select page
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, (page << 8));
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_read(phydev, regnum);
+       if (ret < 0)
+               goto err_handle;
+       val = ret;
+
+       /* Recover to old page */
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, oldpage);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, oldval);
+       if (ret < 0)
+               goto err_handle;
+       ret = val;
+
+err_handle:
+       phy_unlock_mdio_bus(phydev);
+       return ret;
+}
+
+static int sfphy_page_write(struct phy_device *phydev, int page, u32 regnum, u16 value)
+{
+       int ret, oldpage = 0, oldval = 0;
+
+       phy_lock_mdio_bus(phydev);
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_ADDR);
+       if (ret < 0)
+               goto err_handle;
+       oldval = ret;
+
+       ret = __phy_read(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT);
+       if (ret < 0)
+               goto err_handle;
+       oldpage = ret;
+
+       //Select page
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, (page << 8));
+       if(ret<0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, regnum, value);
+       if(ret<0)
+               goto err_handle;
+
+       /* Recover to old page */
+       ret = __phy_write(phydev, SF1211F_EXTREG_PHY_MODE_PAGE_SELECT, oldpage);
+       if (ret < 0)
+               goto err_handle;
+
+       ret = __phy_write(phydev, SF1211F_EXTREG_ADDR, oldval);
+       if (ret < 0)
+               goto err_handle;
+
+err_handle:
+       phy_unlock_mdio_bus(phydev);
+       return ret;
+}
+
+//get port type
+static int sfphy_get_port_type(struct phy_device *phydev)
+{
+       int ret, mode;
+
+       ret = siflower_phy_ext_read(phydev, SF1211F_EXTREG_GET_PORT_PHY_MODE);
+       if (ret < 0)
+               return ret;
+       ret &= SF1211F_EXTREG_PHY_MODE_MASK;
+
+       if (ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_RGMII ||
+               ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_SGMII) {
+               mode = SFPHY_PORT_TYPE_UTP;
+       } else if (ret == SF1211F_EXTREG_PHY_MODE_FIBER_TO_RGMII ||
+               ret == SF1211F_EXTREG_PHY_MODE_SGMII_PHY_TO_RGMII_MAC ||
+               ret == SF1211F_EXTREG_PHY_MODE_SGMII_MAC_TO_RGMII_PHY) {
+               mode = SFPHY_PORT_TYPE_FIBER;
+       } else {
+               mode = SFPHY_PORT_TYPE_COMBO;
+       }
+
+       return mode;
+}
+
+static int sfphy_restart_aneg(struct phy_device *phydev)
+{
+       int ret, ctl;
+
+       ctl = sfphy_page_read(phydev, SFPHY_REG_FIBER_SPACE, MII_BMCR);
+       if (ctl < 0)
+               return ctl;
+       ctl |= BMCR_ANENABLE;
+       ret = sfphy_page_write(phydev, SFPHY_REG_FIBER_SPACE, MII_BMCR, ctl);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+int sf1211f_config_aneg(struct phy_device *phydev)
+{
+       int ret, phymode, oldpage = 0;
+
+       phymode = SFPHY_MODE_CURR;
+
+       if (phymode == SFPHY_PORT_TYPE_UTP || phymode == SFPHY_PORT_TYPE_COMBO) {
+               oldpage = siflower_phy_get_reg_page(phydev);
+               if (oldpage < 0)
+                       return oldpage;
+               ret = siflower_phy_select_reg_page(phydev, SFPHY_REG_UTP_SPACE);
+               if (ret < 0)
+                       return ret;
+               ret = genphy_config_aneg(phydev);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_select_reg_page(phydev, oldpage);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (phymode == SFPHY_PORT_TYPE_FIBER || phymode == SFPHY_PORT_TYPE_COMBO) {
+               oldpage = siflower_phy_get_reg_page(phydev);
+               if (oldpage < 0)
+                       return oldpage;
+               ret = siflower_phy_select_reg_page(phydev, SFPHY_REG_FIBER_SPACE);
+               if (ret < 0)
+                       return ret;
+               if (AUTONEG_ENABLE != phydev->autoneg)
+                       return genphy_setup_forced(phydev);
+               ret = sfphy_restart_aneg(phydev);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_select_reg_page(phydev, oldpage);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+int sf1211f_aneg_done(struct phy_device *phydev)
+{
+       int val = 0;
+
+       val = phy_read(phydev, 0x16);
+
+       if (val == SFPHY_REG_FIBER_SPACE_SETADDR) {
+               val = phy_read(phydev, 0x1);
+               val = phy_read(phydev, 0x1);
+               return (val < 0) ? val : (val & BMSR_LSTATUS);
+       }
+
+       return genphy_aneg_done(phydev);
+}
+
+#if (SIFLOWER_PHY_WOL_FEATURE_ENABLE)
+static void siflower_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+       int val = 0;
+       wol->supported = WAKE_MAGIC;
+       wol->wolopts = 0;
+
+       val = siflower_phy_ext_read(phydev, SIFLOWER_WOL_CFG_REG1);
+       if (val < 0)
+               return;
+
+       if (val & SIFLOWER_WOL_EN)
+               wol->wolopts |= WAKE_MAGIC;
+
+       return;
+}
+
+static int siflower_wol_en_cfg(struct phy_device *phydev, siflower_wol_cfg_t wol_cfg)
+{
+       int ret, val0,val1;
+
+       val0 = siflower_phy_ext_read(phydev, SIFLOWER_WOL_CFG_REG0);
+       if (val0 < 0)
+               return val0;
+       val1 = siflower_phy_ext_read(phydev, SIFLOWER_WOL_CFG_REG1);
+       if (val1 < 0)
+               return val1;
+       if (wol_cfg.wolen) {
+               val1 |= SIFLOWER_WOL_EN;
+               if (wol_cfg.type == SFPHY_WOL_TYPE_LEVEL) {
+                       val0 |= SIFLOWER_WOL_TYPE;
+               } else if (wol_cfg.type == SFPHY_WOL_TYPE_PULSE) {
+                       ret = siflower_phy_ext_write(phydev, SIFLOWER_PHY_WOL_PULSE_MODE_SET, 0x04);//set int pin pulse
+                       if (ret < 0)
+                               return ret;
+                       val0 &= ~SIFLOWER_WOL_TYPE;
+                       if (wol_cfg.width == SFPHY_WOL_WIDTH_84MS) {
+                               val0 &= ~SIFLOWER_WOL_WIDTH1;
+                               val0 &= ~SIFLOWER_WOL_WIDTH2;
+                       } else if (wol_cfg.width == SFPHY_WOL_WIDTH_168MS) {
+                               val0 |= SIFLOWER_WOL_WIDTH1;
+                               val0 &= ~SIFLOWER_WOL_WIDTH2;
+                       } else if (wol_cfg.width == SFPHY_WOL_WIDTH_336MS) {
+                               val0 &= ~SIFLOWER_WOL_WIDTH1;
+                               val0 |= SIFLOWER_WOL_WIDTH2;
+                       } else if (wol_cfg.width == SFPHY_WOL_WIDTH_672MS) {
+                               val0 |= SIFLOWER_WOL_WIDTH1;
+                               val0 |= SIFLOWER_WOL_WIDTH2;
+                       }
+               }
+               if (wol_cfg.secure == SFPHY_GLB_ENABLE)
+                       val1 |= SIFLOWER_WOL_SECURE_CHECK;
+               else
+                       val1 &= ~SIFLOWER_WOL_SECURE_CHECK;
+               if (wol_cfg.checkcrc == SFPHY_GLB_ENABLE)
+                       val0 |= SIFLOWER_WOL_CRC_CHECK;
+               else
+                       val0 &= ~SIFLOWER_WOL_CRC_CHECK;
+               if (wol_cfg.checkdst == SFPHY_GLB_ENABLE)
+                       val0 |= SIFLOWER_WOL_DESTADDR_CHECK;
+               else
+                       val0 &= ~SIFLOWER_WOL_DESTADDR_CHECK;
+       } else {
+               val1 &= ~SIFLOWER_WOL_EN;
+       }
+
+       ret = siflower_phy_ext_write(phydev, SIFLOWER_WOL_CFG_REG0, val0);
+       if (ret < 0)
+               return ret;
+       ret = siflower_phy_ext_write(phydev, SIFLOWER_WOL_CFG_REG1, val1);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int siflower_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+{
+       int ret, val, i, phymode;
+       siflower_wol_cfg_t wol_cfg;
+
+       phymode = SFPHY_MODE_CURR;
+       memset(&wol_cfg,0,sizeof(siflower_wol_cfg_t));
+
+       if (wol->wolopts & WAKE_MAGIC) {
+               if (phymode == SFPHY_PORT_TYPE_UTP || phymode == SFPHY_PORT_TYPE_COMBO) {
+               /* Enable the WOL interrupt */
+               val = sfphy_page_read(phydev, SFPHY_REG_UTP_SPACE, SIFLOWER_INTR_REG);
+               val |= SIFLOWER_WOL_INTR_EN;
+               ret = sfphy_page_write(phydev, SFPHY_REG_UTP_SPACE, SIFLOWER_INTR_REG, val);
+               if (ret < 0)
+                       return ret;
+               }
+               if (phymode == SFPHY_PORT_TYPE_FIBER || phymode == SFPHY_PORT_TYPE_COMBO) {
+                       /* Enable the WOL interrupt */
+                       val = sfphy_page_read(phydev, SFPHY_REG_FIBER_SPACE, SIFLOWER_INTR_REG);
+                       val |= SIFLOWER_WOL_INTR_EN;
+                       ret = sfphy_page_write(phydev, SFPHY_REG_FIBER_SPACE, SIFLOWER_INTR_REG, val);
+                       if (ret < 0)
+                               return ret;
+               }
+               /* Set the WOL config */
+               wol_cfg.wolen = SFPHY_GLB_ENABLE;
+               wol_cfg.type  = SFPHY_WOL_TYPE_PULSE;
+               wol_cfg.width = SFPHY_WOL_WIDTH_672MS;
+               wol_cfg.checkdst  = SFPHY_GLB_ENABLE;
+               wol_cfg.checkcrc = SFPHY_GLB_ENABLE;
+               ret = siflower_wol_en_cfg(phydev, wol_cfg);
+               if (ret < 0)
+                       return ret;
+
+               /* Store the device address for the magic packet */
+               for(i = 0; i < 6; ++i) {
+                       ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_MAC_ADDR - i,
+                               ((phydev->attached_dev->dev_addr[i])));
+                       if (ret < 0)
+                               return ret;
+               }
+#if SIFLOWER_PHY_WOL_PASSWD_ENABLE
+               /* Set passwd for the magic packet */
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR, SIFLOWER_MAGIC_PACKET_PASSWD1);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR - 1, SIFLOWER_MAGIC_PACKET_PASSWD2);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR - 2, SIFLOWER_MAGIC_PACKET_PASSWD3);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR - 3, SIFLOWER_MAGIC_PACKET_PASSWD4);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR - 4, SIFLOWER_MAGIC_PACKET_PASSWD5);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev, SIFLOWER_MAGIC_PACKET_PASSWD_ADDR - 5, SIFLOWER_MAGIC_PACKET_PASSWD6);
+               if (ret < 0)
+                       return ret;
+#endif
+       } else {
+               wol_cfg.wolen = SFPHY_GLB_DISABLE;
+               wol_cfg.type  = SFPHY_WOL_TYPE_EXT;
+               wol_cfg.width = SFPHY_WOL_WIDTH_EXT;
+               wol_cfg.checkdst  = SFPHY_GLB_DISABLE;
+               wol_cfg.checkcrc  = SFPHY_GLB_DISABLE;
+               ret = siflower_wol_en_cfg(phydev, wol_cfg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (val == SF1211F_EXTREG_PHY_MODE_UTP_TO_SGMII) {
+               val = sfphy_page_read(phydev, SFPHY_REG_UTP_SPACE, MII_BMCR);
+               val |= SIFLOWER_WOL_RESTARTANEG;
+               ret = sfphy_page_write(phydev, SFPHY_REG_UTP_SPACE, MII_BMCR, val);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+#endif
+static int sf1211f_rxc_txc_init(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = (siflower_phy_ext_read(phydev, SF1211F_EXTREG_GET_PORT_PHY_MODE) &
+               SF1211F_EXTREG_PHY_MODE_MASK);
+       if (ret < 0)
+               return ret;
+
+       if ((ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_SGMII) ||
+               (ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_FIBER_AUTO) ||
+               (ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_FIBER_FORCE))
+               return 0;
+
+       // Init rxc and enable rxc
+       if (ret == SF1211F_EXTREG_PHY_MODE_UTP_TO_RGMII) {
+               ret = phy_read(phydev, 0x11);
+               if ((ret & 0x4) == 0x0) {
+                       ret = siflower_phy_ext_write(phydev,0x1E0C, 0x17);
+                       if (ret < 0)
+                               return ret;
+                       ret = siflower_phy_ext_write(phydev,0x1E58, 0x00);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID){
+               // Init rxc delay
+               ret = siflower_phy_ext_write(phydev,0x0282, SIFLOWER_PHY_RXC_DELAY_VAL);
+               if (ret < 0)
+                       return ret;
+       }
+       else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID){
+               // Init txc delay
+               ret = siflower_phy_ext_write(phydev,0x0281, SIFLOWER_PHY_TXC_DELAY_VAL);
+               if (ret < 0)
+                       return ret;
+       }
+       else if(phydev->interface == PHY_INTERFACE_MODE_RGMII_ID){
+               ret = siflower_phy_ext_write(phydev,0x0282, SIFLOWER_PHY_RXC_DELAY_VAL);
+               if (ret < 0)
+                       return ret;
+               ret = siflower_phy_ext_write(phydev,0x0281, SIFLOWER_PHY_TXC_DELAY_VAL);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+static int sf1211f_config_opt(struct phy_device *phydev)
+{
+       int ret;
+       //100M utp optimise
+       ret = siflower_phy_ext_write(phydev, 0x0149, 0x84);
+       if (ret < 0)
+               return ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x014A, 0x86);
+       if (ret < 0)
+               return ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x023C, 0x81);
+       if (ret < 0)
+               return ret;
+
+       //1000M utp optimise
+       ret = siflower_phy_ext_write(phydev, 0x0184, 0x85);
+       if (ret < 0)
+               return ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x0185, 0x86);
+       if (ret < 0)
+               return ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x0186, 0x85);
+       if (ret < 0)
+               return ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x0187, 0x86);
+       if (ret < 0)
+               return ret;
+       return ret;
+}
+#if SIFLOWER_PHY_CLK_OUT_125M_ENABLE
+static int sf1211f_clkout_init(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = siflower_phy_ext_write(phydev, 0x0272 , 0x09);
+
+       return ret;
+}
+#endif
+
+#if SIFLOWER_PHY_MODE_SET_ENABLE
+//set mode
+static int phy_mode_set(struct phy_device *phydev, u16 phyMode)
+{
+       int ret, num = 0;
+
+       ret = siflower_phy_ext_read(phydev, 0xC417);
+       if (ret < 0)
+               return ret;
+
+       ret = (ret & 0xF0) | (0x8 | phyMode);
+
+       ret = siflower_phy_ext_write(phydev, 0xC417, ret);
+       if (ret < 0)
+               return ret;
+
+       while ((siflower_phy_ext_read(phydev, 0xC415) & 0x07) != phyMode) {
+               msleep(10);
+               if(++num == 5) {
+                       printk("Phy Mode Set Time Out!\r\n");
+                       break;
+               }
+       }
+
+       while (siflower_phy_ext_read(phydev, 0xC413) != 0) {
+               msleep(10);
+               if(++num == 10) {
+                       printk("Phy Mode Set Time Out!\r\n");
+                       break;
+               }
+       }
+
+       return 0;
+}
+#endif
+
+int sf1240_config_init(struct phy_device *phydev)
+{
+       int ret;
+               ret = genphy_read_abilities(phydev);
+       if (ret < 0)
+               return ret;
+
+       linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                       phydev->supported, ESTATUS_1000_TFULL);
+       linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                       phydev->advertising, ESTATUS_1000_TFULL);
+       return 0;
+}
+
+int sf1211f_config_init(struct phy_device *phydev)
+{
+       int ret, phymode;
+
+#if SIFLOWER_PHY_WOL_FEATURE_ENABLE
+       struct ethtool_wolinfo wol;
+#endif
+
+#if SIFLOWER_PHY_MODE_SET_ENABLE
+       ret = phy_mode_set(phydev, 0x0);
+       if (ret < 0)
+               return ret;
+#endif
+       phymode = SFPHY_MODE_CURR;
+
+       if (phymode == SFPHY_PORT_TYPE_UTP || phymode == SFPHY_PORT_TYPE_COMBO) {
+               siflower_phy_select_reg_page(phydev, SFPHY_REG_UTP_SPACE);
+               ret = genphy_read_abilities(phydev);
+               if (ret < 0)
+                       return ret;
+       } else {
+               siflower_phy_select_reg_page(phydev, SFPHY_REG_FIBER_SPACE);
+               ret = genphy_read_abilities(phydev);
+               if (ret < 0)
+                       return ret;
+
+               linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                               phydev->supported, ESTATUS_1000_TFULL);
+               linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+                               phydev->advertising, ESTATUS_1000_TFULL);
+       }
+
+       ret = sf1211f_rxc_txc_init(phydev);
+       if (ret < 0)
+               return ret;
+
+       ret = sf1211f_config_opt(phydev);
+       if (ret < 0)
+               return ret;
+
+#if SIFLOWER_PHY_CLK_OUT_125M_ENABLE
+       ret = sf1211f_clkout_init(phydev);
+       if (ret < 0)
+               return ret;
+#endif
+
+#if SIFLOWER_PHY_WOL_FEATURE_ENABLE
+       wol.wolopts = 0;
+       wol.supported = WAKE_MAGIC;
+       wol.wolopts |= WAKE_MAGIC;
+       siflower_set_wol(phydev, &wol);
+#endif
+
+       return 0;
+}
+
+static struct phy_driver sf_phy_drivers[] = {
+       {
+               .phy_id             = SF1211F_PHY_ID,
+               .phy_id_mask        = SIFLOWER_PHY_ID_MASK,
+               .name               = "SF1211F Gigabit Ethernet",
+               .features           = PHY_GBIT_FEATURES,
+               .flags              = PHY_POLL,
+               .config_init        = sf1211f_config_init,
+               .config_aneg        = sf1211f_config_aneg,
+               .aneg_done          = sf1211f_aneg_done,
+               .write_mmd          = genphy_write_mmd_unsupported,
+               .read_mmd           = genphy_read_mmd_unsupported,
+               .suspend            = genphy_suspend,
+               .resume             = genphy_resume,
+#if SIFLOWER_PHY_WOL_FEATURE_ENABLE
+               .get_wol            = &siflower_get_wol,
+               .set_wol            = &siflower_set_wol,
+#endif
+       },
+
+       {
+               .phy_id             = SF1240_PHY_ID,
+               .phy_id_mask        = SIFLOWER_PHY_ID_MASK,
+               .name               = "SF1240 Gigabit Ethernet",
+               .features           = PHY_GBIT_FEATURES,
+               .flags              = PHY_POLL,
+               .config_init        = sf1240_config_init,
+               .config_aneg        = genphy_config_aneg,
+               .write_mmd          = genphy_write_mmd_unsupported,
+               .read_mmd           = genphy_read_mmd_unsupported,
+               .suspend            = genphy_suspend,
+               .resume             = genphy_resume,
+       },
+};
+
+/* for linux 4.x */
+module_phy_driver(sf_phy_drivers);
+
+static struct mdio_device_id __maybe_unused siflower_phy_tbl[] = {
+       { SF1211F_PHY_ID, SIFLOWER_PHY_ID_MASK },
+       { SF1240_PHY_ID, SIFLOWER_PHY_ID_MASK },
+       {},
+};
+
+MODULE_DEVICE_TABLE(mdio, siflower_phy_tbl);
+
+MODULE_DESCRIPTION("Siflower PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/siflower/files-6.6/drivers/pci/controller/dwc/pcie-sf21.c b/target/linux/siflower/files-6.6/drivers/pci/controller/dwc/pcie-sf21.c
new file mode 100644 (file)
index 0000000..50be505
--- /dev/null
@@ -0,0 +1,364 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siflower SF21A6826/SF21H8898 PCIE driver
+ *
+ * Author: Chuanhong Guo <gch981213@gmail.com>
+ */
+
+#include <linux/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/resource.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/reset.h>
+
+#include "pcie-designware.h"
+
+#define SF_PCIE_MAX_TIMEOUT    10000
+
+#define ELBI_REG0              0x0
+#define  APP_LTSSM_ENABLE      BIT(23)
+
+#define to_sf_pcie(x)  dev_get_drvdata((x)->dev)
+
+#define SYSM_PCIE_SET          0x0
+#define  PCIE_DEVTYPE_EP       0
+#define  PCIE_DEVTYPE_RC       4
+
+#define SYSM_PCIE_INIT         0x4
+#define SYSM_PCIE_CLK_EN       0x9c
+
+enum sf_pcie_regfield_ids {
+       DEVICE_TYPE,
+       PERST_N_OUT,
+       PERST_N,
+       BUTTON_RSTN,
+       POWER_UP_RSTN,
+       ACLK_M_EN,
+       ACLK_S_EN,
+       ACLK_C_EN,
+       HCLK_EN,
+       SYSM_REGFIELD_MAX,
+};
+
+static const struct reg_field pcie0_sysm_regs[SYSM_REGFIELD_MAX] = {
+       [DEVICE_TYPE] = REG_FIELD(SYSM_PCIE_SET, 0, 3),
+       [PERST_N_OUT] = REG_FIELD(SYSM_PCIE_INIT, 15, 15),
+       [PERST_N] = REG_FIELD(SYSM_PCIE_INIT, 5, 5),
+       [BUTTON_RSTN] = REG_FIELD(SYSM_PCIE_INIT, 4, 4),
+       [POWER_UP_RSTN] = REG_FIELD(SYSM_PCIE_INIT, 3, 3),
+       [ACLK_M_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 3, 3),
+       [ACLK_S_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 2, 2),
+       [ACLK_C_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 1, 1),
+       [HCLK_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 0, 0),
+};
+
+static const struct reg_field pcie1_sysm_regs[SYSM_REGFIELD_MAX] = {
+       [DEVICE_TYPE] = REG_FIELD(SYSM_PCIE_SET, 4, 7),
+       [PERST_N_OUT] = REG_FIELD(SYSM_PCIE_INIT, 16, 16),
+       [PERST_N] = REG_FIELD(SYSM_PCIE_INIT, 8, 8),
+       [BUTTON_RSTN] = REG_FIELD(SYSM_PCIE_INIT, 7, 7),
+       [POWER_UP_RSTN] = REG_FIELD(SYSM_PCIE_INIT, 6, 6),
+       [ACLK_M_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 8, 8),
+       [ACLK_S_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 7, 7),
+       [ACLK_C_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 6, 6),
+       [HCLK_EN] = REG_FIELD(SYSM_PCIE_CLK_EN, 5, 5),
+};
+
+struct sf_pcie {
+       struct dw_pcie                  pci;
+       void __iomem                    *elbi;
+       struct clk                      *csr_clk;
+       struct clk                      *ref_clk;
+       struct phy                      *phy;
+       struct regmap                   *pciesys;
+       struct regmap_field             *pciesys_reg[SYSM_REGFIELD_MAX];
+       struct gpio_desc                *reset_gpio;
+};
+
+static void sf_pcie_enable_part_lanes_rxei_exit(struct sf_pcie *sf_pcie)
+{
+       u32 val;
+       val = readl(sf_pcie->pci.dbi_base + 0x708);
+       val = val | 0x1 << 22;
+       writel(val, sf_pcie->pci.dbi_base + 0x708);
+       val = readl(sf_pcie->pci.dbi_base + 0x708);
+       msleep(20);
+}
+
+static void sf_pcie_enable_speed_change(struct sf_pcie *sf_pcie)
+{
+       u32 val;
+       val = readl(sf_pcie->pci.dbi_base + 0x80c);
+       val = val | 0x1 << 17;
+       writel(val, sf_pcie->pci.dbi_base + 0x80c);
+       val = readl(sf_pcie->pci.dbi_base + 0x80c);
+       msleep(20);
+}
+
+static int sf_pcie_clk_enable(struct sf_pcie *sf_pcie)
+{
+       int ret;
+       ret = clk_prepare_enable(sf_pcie->csr_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(sf_pcie->ref_clk);
+       if (ret)
+               return ret;
+
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_M_EN], 1);
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_S_EN], 1);
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_C_EN], 1);
+       regmap_field_write(sf_pcie->pciesys_reg[HCLK_EN], 1);
+       return 0;
+}
+
+static void sf_pcie_clk_disable(struct sf_pcie *sf_pcie)
+{
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_M_EN], 0);
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_S_EN], 0);
+       regmap_field_write(sf_pcie->pciesys_reg[ACLK_C_EN], 0);
+       regmap_field_write(sf_pcie->pciesys_reg[HCLK_EN], 0);
+       clk_disable_unprepare(sf_pcie->csr_clk);
+       clk_disable_unprepare(sf_pcie->ref_clk);
+}
+
+static int sf_pcie_phy_enable(struct sf_pcie *pcie)
+{
+       int ret;
+
+       ret = phy_init(pcie->phy);
+       if (ret)
+               return ret;
+       return phy_power_on(pcie->phy);
+}
+
+static int sf_pcie_phy_disable(struct sf_pcie *pcie)
+{
+       int ret;
+
+       ret = phy_power_off(pcie->phy);
+       if (ret)
+               return ret;
+       return phy_exit(pcie->phy);
+}
+
+static void sf_pcie_ltssm_set_en(struct sf_pcie *pcie, bool enable)
+{
+       u32 val;
+
+       val = readl(pcie->elbi + ELBI_REG0);
+       if (enable)
+               val |= APP_LTSSM_ENABLE;
+       else
+               val &= ~APP_LTSSM_ENABLE;
+       writel(val, pcie->elbi + ELBI_REG0);
+}
+
+static void sf_pcie_set_reset(struct sf_pcie *pcie, bool assert) {
+       regmap_field_write(pcie->pciesys_reg[PERST_N], !assert);
+       regmap_field_write(pcie->pciesys_reg[BUTTON_RSTN], !assert);
+       regmap_field_write(pcie->pciesys_reg[POWER_UP_RSTN], !assert);
+}
+
+/*
+ * The bus interconnect subtracts address offset from the request
+ * before sending it to PCIE slave port. Since DT puts config space
+ * at the beginning, we can obtain the address offset from there and
+ * subtract it.
+ */
+static u64 sf_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 cpu_addr)
+{
+       struct dw_pcie_rp *pp = &pci->pp;
+
+       return cpu_addr - pp->cfg0_base;
+}
+
+static int sf_pcie_host_init(struct dw_pcie_rp *pp)
+{
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct sf_pcie *sf_pcie = to_sf_pcie(pci);
+       int ret;
+
+       ret = sf_pcie_clk_enable(sf_pcie);
+       if (ret)
+               return dev_err_probe(sf_pcie->pci.dev, ret,
+                                    "failed to enable pcie clocks.\n");
+
+       sf_pcie_set_reset(sf_pcie, true);
+
+       ret = regmap_field_write(sf_pcie->pciesys_reg[DEVICE_TYPE], PCIE_DEVTYPE_RC);
+       if (ret)
+               return ret;
+
+       gpiod_set_value_cansleep(sf_pcie->reset_gpio, 1);
+
+       ret = sf_pcie_phy_enable(sf_pcie);
+       if (ret)
+               return ret;
+
+       /* TODO: release power-down */
+       msleep(100);
+
+       sf_pcie_set_reset(sf_pcie, false);
+
+       dw_pcie_dbi_ro_wr_en(pci);
+       sf_pcie_enable_part_lanes_rxei_exit(sf_pcie);
+
+       gpiod_set_value_cansleep(sf_pcie->reset_gpio, 0);
+       return 0;
+}
+
+void sf_pcie_host_deinit(struct dw_pcie_rp *pp) {
+       struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
+       struct sf_pcie *sf_pcie = to_sf_pcie(pci);
+
+       sf_pcie_set_reset(sf_pcie, true);
+
+       sf_pcie_phy_disable(sf_pcie);
+
+       gpiod_set_value_cansleep(sf_pcie->reset_gpio, 1);
+
+       sf_pcie_clk_disable(sf_pcie);
+}
+
+static const struct dw_pcie_host_ops sf_pcie_host_ops = {
+       .host_init = sf_pcie_host_init,
+       .host_deinit = sf_pcie_host_deinit,
+};
+
+static int sf_pcie_start_link(struct dw_pcie *pci)
+{
+       struct sf_pcie *pcie = to_sf_pcie(pci);
+       /*
+        * before link up with GEN1, we should config the field
+        * DIRECTION_SPEED_CHANGE of GEN2_CTRL_OFF register to insure
+        * the LTSSM to initiate a speed change to Gen2 or Gen3 after
+        * the link is initialized at Gen1 speed.
+        */
+       sf_pcie_enable_speed_change(pcie);
+
+       sf_pcie_ltssm_set_en(pcie, true);
+       return 0;
+}
+
+static void sf_pcie_stop_link(struct dw_pcie *pci) {
+       struct sf_pcie *pcie = to_sf_pcie(pci);
+
+       sf_pcie_ltssm_set_en(pcie, false);
+}
+
+static const struct dw_pcie_ops dw_pcie_ops = {
+       .cpu_addr_fixup = sf_pcie_cpu_addr_fixup,
+       .start_link = sf_pcie_start_link,
+       .stop_link = sf_pcie_stop_link,
+};
+
+static int sf_pcie_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct sf_pcie *sf_pcie;
+       int ret;
+       u32 ctlr_id;
+
+       sf_pcie = devm_kzalloc(dev, sizeof(*sf_pcie), GFP_KERNEL);
+       if (!sf_pcie)
+               return -ENOMEM;
+
+       sf_pcie->pci.dev = dev;
+       sf_pcie->pci.ops = &dw_pcie_ops;
+       sf_pcie->pci.pp.ops = &sf_pcie_host_ops;
+
+       platform_set_drvdata(pdev, sf_pcie);
+
+       sf_pcie->csr_clk = devm_clk_get(dev, "csr");
+       if (IS_ERR(sf_pcie->csr_clk))
+               return PTR_ERR(sf_pcie->csr_clk);
+
+       sf_pcie->ref_clk = devm_clk_get(dev, "ref");
+       if (IS_ERR(sf_pcie->ref_clk))
+               return PTR_ERR(sf_pcie->ref_clk);
+
+       sf_pcie->reset_gpio =
+               devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(sf_pcie->reset_gpio)) {
+               return dev_err_probe(dev, PTR_ERR(sf_pcie->reset_gpio),
+                                    "unable to get reset gpio\n");
+       }
+
+       sf_pcie->pciesys = syscon_regmap_lookup_by_phandle(
+               pdev->dev.of_node, "siflower,pcie-sysm");
+       if (IS_ERR(sf_pcie->pciesys))
+               return PTR_ERR(sf_pcie->pciesys);
+
+       sf_pcie->phy = devm_phy_get(dev, NULL);
+       if (IS_ERR(sf_pcie->phy))
+               return PTR_ERR(sf_pcie->phy);
+
+       sf_pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
+       if (IS_ERR(sf_pcie->elbi)) {
+               return PTR_ERR(sf_pcie->elbi);
+       }
+
+       ret = of_property_read_u32(node, "siflower,ctlr-idx", &ctlr_id);
+       if (ret) {
+               ctlr_id = 0;
+       }
+
+       ret = devm_regmap_field_bulk_alloc(
+               dev, sf_pcie->pciesys, sf_pcie->pciesys_reg,
+               ctlr_id ? pcie1_sysm_regs : pcie0_sysm_regs, SYSM_REGFIELD_MAX);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "failed to alloc regmap fields.\n");
+
+       ret = dw_pcie_host_init(&sf_pcie->pci.pp);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to initialize host\n");
+
+       return 0;
+}
+
+static int sf_pcie_remove(struct platform_device *pdev)
+{
+       struct sf_pcie *pcie = platform_get_drvdata(pdev);
+
+       dw_pcie_host_deinit(&pcie->pci.pp);
+       return 0;
+
+}
+
+static const struct of_device_id sf_pcie_of_match[] = {
+       { .compatible = "siflower,sf21-pcie", },
+       {},
+};
+
+static struct platform_driver sf_pcie_driver = {
+       .driver = {
+               .name   = "sf21-pcie",
+               .of_match_table = sf_pcie_of_match,
+               .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+       },
+       .probe    = sf_pcie_probe,
+       .remove   = sf_pcie_remove,
+};
+
+module_platform_driver(sf_pcie_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
+MODULE_DESCRIPTION("PCIe Controller driver for SF21A6826/SF21H8898 SoC");
index 000d1864e99b2d396826d15faf20e8d5afe70620..5124c81f7953d07ad674737435da2abfae3f0bc8 100644 (file)
@@ -4,3 +4,20 @@ config PHY_SF19A2890_USB
        select GENERIC_PHY
        help
          Enable this to support the USB2.0 PHY on the SIFLOWER SF19A2890.
+
+config PHY_SF21_PCIE
+       tristate "Siflower SF21A6826/SF21H8898 PCIE PHY driver"
+       default n
+       depends on HAS_IOMEM
+       select GENERIC_PHY
+       help
+         Enable this to support the PCIE PHY on the Siflower SF21A6826 SoC.
+
+
+config PHY_SF21_USB
+       tristate "Siflower SF21A6826/SF21H8898 USB2.0 PHY driver"
+       default n
+       depends on HAS_IOMEM
+       select GENERIC_PHY
+       help
+         Enable this to support the USB2.0 PHY on the Siflower SF21A6826/SF21H8898 SoC.
index 0c65e8c8663226983417515c4431fd9bceb192d3..ddef17fe7f4bf610124c8bc7c52211396f7c08fb 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PHY_SF19A2890_USB) += phy-sf19a2890-usb.o
-
+obj-$(CONFIG_PHY_SF21_PCIE) += phy-sf21-pcie.o
+obj-$(CONFIG_PHY_SF21_USB) += phy-sf21-usb.o
diff --git a/target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-pcie.c b/target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-pcie.c
new file mode 100644 (file)
index 0000000..856efa1
--- /dev/null
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/mfd/syscon.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#define SF_PCIE_PHY_NLANES     2
+
+#define TOPCRM_LVDS0_CFG       0xe8
+#define TOPCRM_LVDS1_CFG       0x120
+#define  LVDS_BIAS_EN          BIT(20)
+#define  LVDS_PULLDN           BIT(19)
+#define  LVDS_SCHMITT_EN       BIT(18)
+#define  LVDS_TX_CM            BIT(17)
+#define  LVDS_RXCM_EN          BIT(16)
+#define  LVDS_RTERM_VAL                GENMASK(15, 13)
+#define  LVDS_TXDRV            GENMASK(12, 9)
+#define  LVDS_IEN_N            BIT(8)
+#define  LVDS_IEN_P            BIT(7)
+#define  LVDS_OEN_N            BIT(6)
+#define  LVDS_OEN_P            BIT(5)
+#define  LVDS_RTERM_EN         BIT(4)
+#define  LVDS_RXEN             BIT(3)
+#define  LVDS_TXEN             BIT(2)
+#define  LVDS_VBIAS_SEL                BIT(0)
+
+#define PCIE_SYSM_SET          0x0
+#define  PCIE_LANE_MUX         GENMASK(9, 8)
+#define  PHY0_L0_PHY1_L1       (0 << 8)
+#define  PHY0_L0L1             (1 << 8)
+#define  PHY0_L1_PHY1_L0       (2 << 8)
+#define  PHY1_L0L1             (3 << 8)
+
+#define PCIE_SYSM_INIT         0x4
+#define  PCIE_L1_REPEAT_CLK_EN BIT(10)
+#define  PCIE_L0_REPEAT_CLK_EN BIT(9)
+#define  PCIE_L1_RSTN          BIT(2)
+#define  PCIE_L0_RSTN          BIT(1)
+#define  PCIE_PHY_RSTN         BIT(0)
+
+
+struct sf21_pcie_phy_inst {
+       struct phy *phy;
+       u8 idx;
+       u8 num_lanes;
+       u8 lvds_idx;
+};
+
+struct sf21_pcie_phy {
+       struct device *dev;
+       struct clk *refclk;
+       struct clk *csrclk;
+       struct regmap *pcie_regmap;
+       struct regmap *topcrm_regmap;
+       struct mutex lock;
+       int nlanes_enabled;
+       struct sf21_pcie_phy_inst insts[2];
+};
+
+static struct sf21_pcie_phy_inst *phy_to_instance(struct phy *phy)
+{
+       return phy_get_drvdata(phy);
+}
+
+static struct sf21_pcie_phy *
+instance_to_priv(struct sf21_pcie_phy_inst *inst)
+{
+       return container_of(inst, struct sf21_pcie_phy, insts[inst->idx]);
+}
+
+static int sf_pcie_phy_lvds_on(struct sf21_pcie_phy *priv, int idx)
+{
+       return regmap_set_bits(priv->topcrm_regmap,
+                              idx ? TOPCRM_LVDS1_CFG : TOPCRM_LVDS0_CFG,
+                              LVDS_TXEN | LVDS_BIAS_EN);
+}
+
+static int sf_pcie_phy_lvds_off(struct sf21_pcie_phy *priv, int idx)
+{
+       return regmap_clear_bits(priv->topcrm_regmap,
+                                idx ? TOPCRM_LVDS1_CFG : TOPCRM_LVDS0_CFG,
+                                LVDS_TXEN | LVDS_BIAS_EN);
+}
+
+static int sf_pcie_lane_on(struct sf21_pcie_phy *priv, int idx)
+{
+       return regmap_set_bits(priv->pcie_regmap, PCIE_SYSM_INIT,
+                                idx ? PCIE_L1_RSTN : PCIE_L0_RSTN);
+}
+
+static int sf_pcie_lane_off(struct sf21_pcie_phy *priv, int idx)
+{
+       return regmap_clear_bits(priv->pcie_regmap, PCIE_SYSM_INIT,
+                              idx ? PCIE_L1_RSTN : PCIE_L0_RSTN);
+}
+
+static int sf21_pcie_phy_power_on(struct phy *phy)
+{
+       struct sf21_pcie_phy_inst *inst = phy_to_instance(phy);
+       struct sf21_pcie_phy *priv = instance_to_priv(inst);
+       int ret;
+       mutex_lock(&priv->lock);
+       if (SF_PCIE_PHY_NLANES - priv->nlanes_enabled < inst->num_lanes) {
+               dev_err(priv->dev, "too many lanes requested for PHY %u\n",
+                       inst->idx);
+               ret = -EBUSY;
+               goto out;
+       }
+
+       if (inst->num_lanes == 2) {
+               regmap_update_bits(priv->pcie_regmap, PCIE_SYSM_SET,
+                                  PCIE_LANE_MUX,
+                                  inst->idx ? PHY1_L0L1 : PHY0_L0L1);
+       } else {
+               regmap_update_bits(priv->pcie_regmap, PCIE_SYSM_SET,
+                                  PCIE_LANE_MUX, PHY0_L0_PHY1_L1);
+       }
+
+       /*
+        * The PCIE clock goes like:
+        *  internal refclk -- serdes0 -- serdes1 -- LVDS0
+        *                                        \- LVDS1
+        * Both clock repeaters must be enabled at PHY power-on,
+        * otherwise there's no PCIE reference clock output.
+        */
+
+       if (!priv->nlanes_enabled) {
+               ret = clk_prepare_enable(priv->refclk);
+               if (ret)
+                       goto out;
+
+               ret = regmap_set_bits(priv->pcie_regmap, PCIE_SYSM_INIT, PCIE_PHY_RSTN);
+               if (ret)
+                       goto out;
+
+               ret = regmap_set_bits(priv->pcie_regmap, PCIE_SYSM_INIT,
+                                     PCIE_L0_REPEAT_CLK_EN |
+                                             PCIE_L1_REPEAT_CLK_EN);
+               if (ret)
+                       goto out;
+       }
+
+       priv->nlanes_enabled += inst->num_lanes;
+
+       ret = sf_pcie_phy_lvds_on(priv, inst->lvds_idx);
+       if (ret)
+               goto out;
+
+       ret = sf_pcie_lane_on(priv, inst->idx);
+       if (ret)
+               goto out;
+       if (inst->num_lanes == 2)
+               ret = sf_pcie_lane_on(priv, !inst->idx);
+out:
+       mutex_unlock(&priv->lock);
+       return ret;
+}
+
+static int sf21_pcie_phy_power_off(struct phy *phy)
+{
+       struct sf21_pcie_phy_inst *inst = phy_to_instance(phy);
+       struct sf21_pcie_phy *priv = instance_to_priv(inst);
+       int ret;
+       mutex_lock(&priv->lock);
+
+       if (inst->num_lanes == 2) {
+               ret = sf_pcie_lane_off(priv, !inst->idx);
+               if (ret)
+                       goto out;
+       }
+
+       ret = sf_pcie_lane_off(priv, inst->idx);
+       if (ret)
+               goto out;
+
+       ret = sf_pcie_phy_lvds_off(priv, inst->lvds_idx);
+       if (ret)
+               goto out;
+       priv->nlanes_enabled -= inst->num_lanes;
+
+       if (!priv->nlanes_enabled) {
+               ret = regmap_clear_bits(priv->pcie_regmap, PCIE_SYSM_INIT, PCIE_PHY_RSTN);
+               if (ret)
+                       goto out;
+
+               ret = regmap_clear_bits(priv->pcie_regmap, PCIE_SYSM_INIT,
+                                       PCIE_L0_REPEAT_CLK_EN |
+                                               PCIE_L1_REPEAT_CLK_EN);
+               if (ret)
+                       goto out;
+               clk_disable_unprepare(priv->refclk);
+       }
+out:
+       mutex_unlock(&priv->lock);
+       return ret;
+}
+
+static const struct phy_ops sf21_pcie_phy_ops = {
+       .power_on = sf21_pcie_phy_power_on,
+       .power_off = sf21_pcie_phy_power_off,
+       .owner = THIS_MODULE,
+};
+
+static int sf21_pcie_phy_probe(struct platform_device *pdev)
+{
+       struct sf21_pcie_phy *p_phy;
+       struct phy_provider *provider;
+       struct phy *phy;
+       struct device_node *child;
+       int num_insts = 0;
+       u32 reg_idx, num_lanes, lvds_idx;
+       int ret;
+
+       p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
+       if (!p_phy)
+               return -ENOMEM;
+
+       p_phy->dev = &pdev->dev;
+       platform_set_drvdata(pdev, p_phy);
+
+       p_phy->refclk = devm_clk_get(p_phy->dev, "ref");
+       if (IS_ERR(p_phy->refclk))
+               return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->refclk),
+                                    "Failed to get phy reference clock.\n");
+
+       p_phy->csrclk = devm_clk_get_enabled(p_phy->dev, "csr");
+       if (IS_ERR(p_phy->csrclk))
+               return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->csrclk),
+                                    "Failed to get enabled phy csr clock.\n");
+
+       p_phy->pcie_regmap = syscon_node_to_regmap(pdev->dev.of_node);
+       if (IS_ERR(p_phy->pcie_regmap))
+               return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->pcie_regmap),
+                                    "Failed to get regmap.\n");
+
+       p_phy->topcrm_regmap = syscon_regmap_lookup_by_phandle(
+               pdev->dev.of_node, "siflower,topcrm");
+       if (IS_ERR(p_phy->topcrm_regmap))
+               return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->topcrm_regmap),
+                                    "Failed to get regmap for topcrm.\n");
+
+       p_phy->nlanes_enabled = 0;
+       mutex_init(&p_phy->lock);
+
+       regmap_clear_bits(p_phy->pcie_regmap, PCIE_SYSM_INIT,
+                       PCIE_L1_RSTN | PCIE_L0_RSTN | PCIE_PHY_RSTN);
+
+       for_each_available_child_of_node(pdev->dev.of_node, child) {
+               ret = of_property_read_u32(child, "reg", &reg_idx);
+               if (ret)
+                       return dev_err_probe(
+                               p_phy->dev, ret,
+                               "failed to read reg of child node %d.\n",
+                               num_insts);
+
+               if (reg_idx > 1) {
+                       dev_err(p_phy->dev, "PHY reg should be 0 or 1.\n");
+                       return -EINVAL;
+               }
+
+               p_phy->insts[reg_idx].idx = reg_idx;
+
+               ret = of_property_read_u32(child, "siflower,num-lanes",
+                                          &num_lanes);
+               if (ret)
+                       return dev_err_probe(
+                               p_phy->dev, ret,
+                               "failed to read num-lanes of phy@%u.\n",
+                               reg_idx);
+
+               if (num_lanes != 1 && num_lanes != 2) {
+                       dev_err(p_phy->dev,
+                               "One PHY can only request 1 or 2 serdes lanes.\n");
+                       return -EINVAL;
+               }
+
+               p_phy->insts[reg_idx].num_lanes = num_lanes;
+
+               /* LVDS provides PCIE reference clock and is a separated block. */
+               ret = of_property_read_u32(child, "siflower,lvds-idx",
+                                          &lvds_idx);
+               if (ret)
+                       p_phy->insts[reg_idx].lvds_idx = reg_idx;
+               else
+                       p_phy->insts[reg_idx].lvds_idx = lvds_idx;
+
+               phy = devm_phy_create(p_phy->dev, child,
+                                     &sf21_pcie_phy_ops);
+               if (IS_ERR(phy))
+                       return dev_err_probe(p_phy->dev, PTR_ERR(phy),
+                                            "failed to register phy@%d.\n",
+                                            reg_idx);
+
+               phy_set_drvdata(phy, &p_phy->insts[reg_idx]);
+               p_phy->insts[reg_idx].phy = phy;
+
+               num_insts++;
+               if (num_insts >= 2)
+                       break;
+       }
+
+       provider = devm_of_phy_provider_register(p_phy->dev, of_phy_simple_xlate);
+       if (IS_ERR(provider))
+               return dev_err_probe(p_phy->dev, PTR_ERR(provider),
+                                    "Failed to register PHY provider.\n");
+
+       return 0;
+}
+
+static const struct of_device_id sf21_pcie_phy_of_match[] = {
+       { .compatible = "siflower,sf21-pcie-phy" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sf21_pcie_phy_of_match);
+
+static struct platform_driver sf21_pcie_phy_driver = {
+       .probe          = sf21_pcie_phy_probe,
+       .driver         = {
+               .name   = "sf21-pcie-phy",
+               .of_match_table = sf21_pcie_phy_of_match,
+       },
+};
+module_platform_driver(sf21_pcie_phy_driver);
+
+MODULE_AUTHOR("Chuanhong Guo <gch981213@gmail.com>");
+MODULE_DESCRIPTION("Siflower SF21A6826/SF21H8898 PCIE PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-usb.c b/target/linux/siflower/files-6.6/drivers/phy/siflower/phy-sf21-usb.c
new file mode 100644 (file)
index 0000000..fbb19b5
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#define SF21_USB_PHY_RESET_OFFSET              0xC
+#define  RST_PRST                              BIT(0)
+#define  RST_PHY_POR                           BIT(1)
+#define  RST_PHY_PORT                          BIT(2)
+
+struct sf21_usb_phy {
+       struct device *dev;
+       struct clk *phy_clk;
+       struct clk *bus_clk;
+       void __iomem *base;
+};
+
+static int sf21_usb_phy_power_on(struct phy *phy)
+{
+       struct sf21_usb_phy *p_phy = phy_get_drvdata(phy);
+       int ret;
+
+       writel(RST_PRST | RST_PHY_POR | RST_PHY_PORT,
+              p_phy->base + SF21_USB_PHY_RESET_OFFSET);
+
+       ret = clk_prepare_enable(p_phy->phy_clk);
+       if (ret < 0) {
+               dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret);
+               return ret;
+       }
+
+       writel(RST_PRST, p_phy->base + SF21_USB_PHY_RESET_OFFSET);
+       usleep_range(50, 1000);
+       writel(0, p_phy->base + SF21_USB_PHY_RESET_OFFSET);
+       udelay(5);
+
+       return ret;
+}
+
+static int sf21_usb_phy_power_off(struct phy *phy)
+{
+       struct sf21_usb_phy *p_phy = phy_get_drvdata(phy);
+
+       writel(RST_PRST | RST_PHY_POR | RST_PHY_PORT,
+              p_phy->base + SF21_USB_PHY_RESET_OFFSET);
+       clk_disable_unprepare(p_phy->phy_clk);
+       return 0;
+}
+
+static const struct phy_ops sf21_usb_phy_ops = {
+       .power_on = sf21_usb_phy_power_on,
+       .power_off = sf21_usb_phy_power_off,
+       .owner = THIS_MODULE,
+};
+
+static int sf21_usb_phy_probe(struct platform_device *pdev)
+{
+       struct sf21_usb_phy *p_phy;
+       struct phy_provider *provider;
+       struct phy *phy;
+
+       p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL);
+       if (!p_phy)
+               return -ENOMEM;
+
+       p_phy->dev = &pdev->dev;
+       platform_set_drvdata(pdev, p_phy);
+
+       p_phy->phy_clk = devm_clk_get(p_phy->dev, "usb_phy_clk");
+       if (IS_ERR(p_phy->phy_clk))
+               return dev_err_probe(p_phy->dev, PTR_ERR(p_phy->phy_clk),
+                                    "Failed to get usb_phy clock.\n");
+
+       p_phy->base = devm_platform_ioremap_resource(pdev, 0);
+
+       phy = devm_phy_create(p_phy->dev, NULL, &sf21_usb_phy_ops);
+       if (IS_ERR(phy))
+               return dev_err_probe(p_phy->dev, PTR_ERR(phy),
+                                    "Failed to create PHY.\n");
+
+       phy_set_drvdata(phy, p_phy);
+
+       provider = devm_of_phy_provider_register(p_phy->dev, of_phy_simple_xlate);
+       if (IS_ERR(provider))
+               return dev_err_probe(p_phy->dev, PTR_ERR(provider),
+                                    "Failed to register PHY provider.\n");
+
+       return 0;
+}
+
+static const struct of_device_id sf21_usb_phy_of_match[] = {
+       { .compatible = "siflower,sf21-usb-phy", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sf21_usb_phy_of_match);
+
+static struct platform_driver sf21_usb_phy_driver = {
+       .probe          = sf21_usb_phy_probe,
+       .driver         = {
+               .name   = "sf21-usb-phy",
+               .of_match_table = sf21_usb_phy_of_match,
+       },
+};
+module_platform_driver(sf21_usb_phy_driver);
+
+MODULE_AUTHOR("Ziying Wu <ziying.wu@siflower.com.cn>");
+MODULE_DESCRIPTION("Siflower SF21A6826/SF21H8898 USB2.0 PHY driver");
+MODULE_LICENSE("GPL");
diff --git a/target/linux/siflower/files-6.6/drivers/reset/reset-sf21.c b/target/linux/siflower/files-6.6/drivers/reset/reset-sf21.c
new file mode 100644 (file)
index 0000000..7f67071
--- /dev/null
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <dt-bindings/reset/siflower,sf21-reset.h>
+
+#define SF21_SOFT_RESET 0xC0
+
+struct sf21_reset_data {
+       struct reset_controller_dev rcdev;
+       struct regmap *regmap;
+};
+
+static inline int sf21_reset_shift(unsigned long id)
+{
+       switch (id) {
+       case SF21_RESET_GIC:
+       case SF21_RESET_AXI:
+       case SF21_RESET_AHB:
+       case SF21_RESET_APB:
+       case SF21_RESET_IRAM:
+               return id + 1;
+       case SF21_RESET_NPU:
+       case SF21_RESET_DDR_CTL:
+       case SF21_RESET_DDR_PHY:
+       case SF21_RESET_DDR_PWR_OK_IN:
+       case SF21_RESET_DDR_CTL_APB:
+       case SF21_RESET_DDR_PHY_APB:
+               return id + 2;
+       case SF21_RESET_USB:
+               return id + 8;
+       case SF21_RESET_PVT:
+       case SF21_RESET_SERDES_CSR:
+               return id + 11;
+       case SF21_RESET_CRYPT_CSR:
+       case SF21_RESET_CRYPT_APP:
+       case SF21_RESET_NPU2DDR_ASYNCBRIDGE:
+       case SF21_RESET_IROM:
+               return id + 14;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int sf21_reset_assert(struct reset_controller_dev *rcdev,
+                                 unsigned long id)
+{
+       struct sf21_reset_data *rd;
+       int shift;
+       u32 mask;
+
+       rd = container_of(rcdev, struct sf21_reset_data, rcdev);
+
+       shift = sf21_reset_shift(id);
+       mask = BIT(shift);
+       return regmap_update_bits(rd->regmap, SF21_SOFT_RESET, mask, 0);
+}
+
+static int sf21_reset_deassert(struct reset_controller_dev *rcdev,
+                                   unsigned long id)
+{
+       struct sf21_reset_data *rd;
+       int shift;
+       u32 mask;
+
+       rd = container_of(rcdev, struct sf21_reset_data, rcdev);
+
+       shift = sf21_reset_shift(id);
+       mask = BIT(shift);
+       return regmap_update_bits(rd->regmap, SF21_SOFT_RESET, mask, mask);
+}
+
+static int sf21_reset_status(struct reset_controller_dev *rcdev,
+                                 unsigned long id)
+{
+       struct sf21_reset_data *rd;
+       int shift, ret;
+       u32 mask;
+       u32 reg;
+
+       rd = container_of(rcdev, struct sf21_reset_data, rcdev);
+       ret = regmap_read(rd->regmap, SF21_SOFT_RESET, &reg);
+       if (ret)
+               return ret;
+
+       shift = sf21_reset_shift(id);
+       mask = BIT(shift);
+       return !!(reg & mask);
+}
+
+static const struct reset_control_ops sf21_reset_ops = {
+       .assert = sf21_reset_assert,
+       .deassert = sf21_reset_deassert,
+       .status = sf21_reset_status,
+};
+
+static int sf21_reset_probe(struct platform_device *pdev)
+{
+       struct sf21_reset_data *rd;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *node;
+
+       rd = devm_kzalloc(dev, sizeof(*rd), GFP_KERNEL);
+       if (!rd)
+               return -ENOMEM;
+
+       node = of_parse_phandle(np, "siflower,crm", 0);
+       rd->regmap = syscon_node_to_regmap(node);
+
+       if (IS_ERR(rd->regmap))
+               return PTR_ERR(rd->regmap);
+
+       rd->rcdev.owner = THIS_MODULE;
+       rd->rcdev.nr_resets = SF21_RESET_MAX + 1;
+       rd->rcdev.ops = &sf21_reset_ops;
+       rd->rcdev.of_node = np;
+
+       return devm_reset_controller_register(dev, &rd->rcdev);
+}
+
+static const struct of_device_id sf21_reset_dt_ids[] = {
+       { .compatible = "siflower,sf21-reset" },
+       {},
+};
+
+static struct platform_driver sf21_reset_driver = {
+       .probe  = sf21_reset_probe,
+       .driver = {
+               .name           = "sf21-reset",
+               .of_match_table = sf21_reset_dt_ids,
+       },
+};
+builtin_platform_driver(sf21_reset_driver);
diff --git a/target/linux/siflower/files-6.6/drivers/spi/spi-sf21-qspi.c b/target/linux/siflower/files-6.6/drivers/spi/spi-sf21-qspi.c
new file mode 100644 (file)
index 0000000..da3fcdf
--- /dev/null
@@ -0,0 +1,531 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * A driver for Siflower SF21A6826/SF21H8898 QSPI controller.
+ *
+ * Based on the AMBA PL022 driver:
+ * Copyright (C) 2008-2012 ST-Ericsson AB
+ * Copyright (C) 2006 STMicroelectronics Pvt. Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sizes.h>
+
+#include <linux/spi/spi-mem.h>
+#include <linux/spi/spi.h>
+
+#define SF_SSP_FIFO_DEPTH              0x100
+
+#define SSP_CR0                                0x000
+#define SSP_CR1                                0x004
+#define SSP_DR                         0x008
+#define SSP_SR                         0x00C
+#define SSP_CPSR                       0x010
+#define SSP_IMSC                       0x014
+#define SSP_RIS                                0x018
+#define SSP_MIS                                0x01C
+#define SSP_ICR                                0x020
+#define SSP_DMACR                      0x024
+#define SSP_FIFO_LEVEL                 0x028
+#define SSP_EXSPI_CMD0                 0x02C
+#define SSP_EXSPI_CMD1                 0x030
+#define SSP_EXSPI_CMD2                 0x034
+
+/* SSP Control Register 0  - SSP_CR0 */
+#define SSP_CR0_EXSPI_FRAME    (0x3 << 4)
+#define SSP_CR0_SPO            (0x1 << 6)
+#define SSP_CR0_SPH            (0x1 << 7)
+#define SSP_CR0_BIT_MODE(x)    ((x)-1)
+#define SSP_SCR_SHFT           8
+
+/* SSP Control Register 1  - SSP_CR1 */
+#define SSP_CR1_MASK_SSE       (0x1 << 1)
+
+/* SSP Status Register - SSP_SR */
+#define SSP_SR_MASK_TFE                (0x1 << 0) /* Transmit FIFO empty */
+#define SSP_SR_MASK_TNF                (0x1 << 1) /* Transmit FIFO not full */
+#define SSP_SR_MASK_RNE                (0x1 << 2) /* Receive FIFO not empty */
+#define SSP_SR_MASK_RFF                (0x1 << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_BSY                (0x1 << 4) /* Busy Flag */
+
+/* SSP FIFO Threshold Register - SSP_FIFO_LEVEL */
+#define SSP_FIFO_LEVEL_RX      GENMASK(14, 8) /* Receive FIFO watermark */
+#define SSP_FIFO_LEVEL_TX      GENMASK(6, 0) /* Transmit FIFO watermark */
+#define DFLT_THRESH_RX         32
+#define DFLT_THRESH_TX         32
+
+/* SSP Raw Interrupt Status Register - SSP_RIS */
+#define SSP_RIS_MASK_RORRIS    (0x1 << 0) /* Receive Overrun */
+#define SSP_RIS_MASK_RTRIS     (0x1 << 1) /* Receive Timeout */
+#define SSP_RIS_MASK_RXRIS     (0x1 << 2) /* Receive FIFO Raw Interrupt status */
+#define SSP_RIS_MASK_TXRIS     (0x1 << 3) /* Transmit FIFO Raw Interrupt status */
+
+/* EXSPI command register 0 SSP_EXSPI_CMD0 */
+#define EXSPI_CMD0_CMD_COUNT   BIT(0)          /* cmd byte, must be set at last */
+#define EXSPI_CMD0_ADDR_COUNT  GENMASK(2, 1)   /* addr bytes */
+#define EXSPI_CMD0_EHC_COUNT   BIT(3)          /* Set 1 for 4-byte address mode */
+#define EXSPI_CMD0_TX_COUNT    GENMASK(14, 4)  /* TX data bytes */
+#define EXSPI_CMD0_VALID       BIT(15)         /* Set 1 to make the cmd to be run */
+
+/* EXSPI command register 1 SSP_EXSPI_CMD1 */
+#define EXSPI_CMD1_DUMMY_COUNT GENMASK(3, 0)   /* dummy bytes */
+#define EXSPI_CMD1_RX_COUNT    GENMASK(14, 4)  /* RX data bytes */
+
+/* EXSPI command register 2 SSP_EXSPI_CMD2 */
+/* Set 1 for 1-wire, 2 for 2-wire, 3 for 4-wire */
+#define EXSPI_CMD2_CMD_IO_MODE GENMASK(1, 0)   /* cmd IO mode */
+#define EXSPI_CMD2_ADDR_IO_MODE        GENMASK(3, 2)   /* addr IO mode */
+#define EXSPI_CMD2_DATA_IO_MODE        GENMASK(5, 4)   /* data IO mode */
+
+/* SSP Clock Defaults */
+#define SSP_DEFAULT_CLKRATE 0x2
+#define SSP_DEFAULT_PRESCALE 0x40
+
+/* SSP Clock Parameter ranges */
+#define CPSDVR_MIN 0x02
+#define CPSDVR_MAX 0xFE
+#define SCR_MIN 0x00
+#define SCR_MAX 0xFF
+
+#define SF_READ_TIMEOUT                (10 * HZ)
+#define MAX_S_BUF                      100
+
+struct sf_qspi {
+       void __iomem *base;
+       struct clk *clk, *apbclk;
+       struct device *dev;
+};
+
+struct ssp_clock_params {
+       u32 freq;
+       u8 cpsdvsr; /* value from 2 to 254 (even only!) */
+       u8 scr;     /* value from 0 to 255 */
+};
+
+struct chip_data {
+       u32 freq;
+       u32 cr0;
+       u16 cpsr;
+};
+
+static void sf_qspi_flush_rxfifo(struct sf_qspi *s)
+{
+       while (readw(s->base + SSP_SR) & SSP_SR_MASK_RNE)
+               readw(s->base + SSP_DR);
+}
+
+static int sf_qspi_wait_not_busy(struct sf_qspi *s)
+{
+       unsigned long timeout = jiffies + SF_READ_TIMEOUT;
+
+       do {
+               if (!(readw(s->base + SSP_SR) & SSP_SR_MASK_BSY))
+                       return 0;
+
+               cond_resched();
+       } while (time_after(timeout, jiffies));
+
+       dev_err(s->dev, "I/O timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int sf_qspi_wait_rx_not_empty(struct sf_qspi *s)
+{
+       unsigned long timeout = jiffies + SF_READ_TIMEOUT;
+
+       do {
+               if (readw(s->base + SSP_SR) & SSP_SR_MASK_RNE)
+                       return 0;
+
+               cond_resched();
+       } while (time_after(timeout, jiffies));
+
+       dev_err(s->dev, "read timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int sf_qspi_wait_rxfifo(struct sf_qspi *s)
+{
+       unsigned long timeout = jiffies + SF_READ_TIMEOUT;
+
+       do {
+               if (readw(s->base + SSP_RIS) & SSP_RIS_MASK_RXRIS)
+                       return 0;
+
+               cond_resched();
+       } while (time_after(timeout, jiffies));
+
+       dev_err(s->dev, "read timed out\n");
+       return -ETIMEDOUT;
+}
+
+static void sf_qspi_enable(struct sf_qspi *s)
+{
+       /* Enable the SPI hardware */
+       writew(SSP_CR1_MASK_SSE, s->base + SSP_CR1);
+}
+
+static void sf_qspi_disable(struct sf_qspi *s)
+{
+       /* Disable the SPI hardware */
+       writew(0, s->base + SSP_CR1);
+}
+
+static void sf_qspi_xmit(struct sf_qspi *s, unsigned int nbytes, const u8 *out)
+{
+       while (nbytes--)
+               writew(*out++, s->base + SSP_DR);
+}
+
+static int sf_qspi_rcv(struct sf_qspi *s, unsigned int nbytes, u8 *in)
+{
+       int ret, i;
+
+       while (nbytes >= DFLT_THRESH_RX) {
+               /* wait for RX FIFO to reach the threshold */
+               ret = sf_qspi_wait_rxfifo(s);
+               if (ret)
+                       return ret;
+
+               for (i = 0; i < DFLT_THRESH_RX; i++)
+                       *in++ = readw(s->base + SSP_DR);
+
+               nbytes -= DFLT_THRESH_RX;
+       }
+
+       /* read the remaining data */
+       while (nbytes) {
+               ret = sf_qspi_wait_rx_not_empty(s);
+               if (ret)
+                       return ret;
+
+               *in++ = readw(s->base + SSP_DR);
+               nbytes--;
+       }
+
+       return 0;
+}
+
+static void sf_qspi_set_param(struct sf_qspi *s, const struct spi_mem_op *op)
+{
+       unsigned int tx_count = 0, rx_count = 0;
+       u8 cmd_io, addr_io, data_io;
+       u8 cmd_count, addr_count, ehc_count;
+
+       cmd_io = op->cmd.buswidth == 4 ? 3 : op->cmd.buswidth;
+       addr_io = op->addr.buswidth == 4 ? 3 : op->addr.buswidth;
+       data_io = op->data.buswidth == 4 ? 3 : op->data.buswidth;
+
+       if (op->data.nbytes) {
+               if (op->data.dir == SPI_MEM_DATA_IN)
+                       rx_count = op->data.nbytes;
+               else
+                       tx_count = op->data.nbytes;
+       }
+       if (op->addr.nbytes > 3) {
+               addr_count = 3;
+               ehc_count = 1;
+       } else {
+               addr_count = op->addr.nbytes;
+               ehc_count = 0;
+       }
+       cmd_count = op->cmd.nbytes;
+
+       writew(FIELD_PREP(EXSPI_CMD2_CMD_IO_MODE, cmd_io) |
+                      FIELD_PREP(EXSPI_CMD2_ADDR_IO_MODE, addr_io) |
+                      FIELD_PREP(EXSPI_CMD2_DATA_IO_MODE, data_io),
+              s->base + SSP_EXSPI_CMD2);
+       writew(FIELD_PREP(EXSPI_CMD1_DUMMY_COUNT, op->dummy.nbytes) |
+                      FIELD_PREP(EXSPI_CMD1_RX_COUNT, rx_count),
+              s->base + SSP_EXSPI_CMD1);
+       writew(EXSPI_CMD0_VALID |
+                      FIELD_PREP(EXSPI_CMD0_CMD_COUNT, op->cmd.nbytes) |
+                      FIELD_PREP(EXSPI_CMD0_ADDR_COUNT, addr_count) |
+                      FIELD_PREP(EXSPI_CMD0_EHC_COUNT, ehc_count) |
+                      FIELD_PREP(EXSPI_CMD0_TX_COUNT, tx_count),
+              s->base + SSP_EXSPI_CMD0);
+}
+
+static int sf_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+       struct sf_qspi *s = spi_controller_get_devdata(mem->spi->master);
+       struct chip_data *chip = spi_get_ctldata(mem->spi);
+       unsigned int pops = 0;
+       int ret, i, op_len;
+       const u8 *tx_buf = NULL;
+       u8 *rx_buf = NULL, op_buf[MAX_S_BUF];
+
+       writew(chip->cr0, s->base + SSP_CR0);
+       writew(chip->cpsr, s->base + SSP_CPSR);
+
+       if (op->data.nbytes) {
+               if (op->data.dir == SPI_MEM_DATA_IN)
+                       rx_buf = op->data.buf.in;
+               else
+                       tx_buf = op->data.buf.out;
+       }
+       op_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+       sf_qspi_set_param(s, op);
+
+       op_buf[pops++] = op->cmd.opcode;
+       if (op->addr.nbytes) {
+               for (i = 0; i < op->addr.nbytes; i++)
+                       op_buf[pops + i] = op->addr.val >>
+                                          (8 * (op->addr.nbytes - i - 1));
+               pops += op->addr.nbytes;
+       }
+
+       sf_qspi_flush_rxfifo(s);
+       memset(op_buf + pops, 0xff, op->dummy.nbytes);
+       sf_qspi_xmit(s, op_len, op_buf);
+       if (tx_buf) {
+               sf_qspi_xmit(s, op->data.nbytes, tx_buf);
+       }
+       sf_qspi_enable(s);
+       if (rx_buf)
+               ret = sf_qspi_rcv(s, op->data.nbytes, rx_buf);
+       else
+               ret = sf_qspi_wait_not_busy(s);
+
+       sf_qspi_disable(s);
+
+       return ret;
+}
+
+static int sf_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+       u32 nbytes;
+
+       nbytes = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+       if (nbytes >= SF_SSP_FIFO_DEPTH)
+               return -ENOTSUPP;
+
+       if (op->data.dir == SPI_MEM_DATA_IN)
+               op->data.nbytes =
+                       min_t(unsigned int, op->data.nbytes, SF_SSP_FIFO_DEPTH);
+       else
+               op->data.nbytes = min_t(unsigned int, op->data.nbytes,
+                                       SF_SSP_FIFO_DEPTH - nbytes);
+
+       return 0;
+}
+
+static bool sf_qspi_supports_op(struct spi_mem *mem,
+                               const struct spi_mem_op *op)
+{
+       if (!spi_mem_default_supports_op(mem, op))
+               return false;
+
+       /* dummy buswidth must be the same as addr */
+       if (op->addr.nbytes && op->dummy.nbytes &&
+           op->addr.buswidth != op->dummy.buswidth)
+               return false;
+
+       return true;
+}
+
+static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
+{
+       return rate / (cpsdvsr * (1 + scr));
+}
+
+static int calculate_effective_freq(struct sf_qspi *s, int freq,
+                                   struct ssp_clock_params *clk_freq)
+{
+       /* Lets calculate the frequency parameters */
+       u16 cpsdvsr = CPSDVR_MIN;
+       u32 rate, rate_scaled, max_tclk, min_tclk, scr;
+       u32 best_freq = 0, best_cpsdvsr = 0, best_scr = 0, tmp, found = 0;
+
+       rate = clk_get_rate(s->clk);
+       /* cpsdvscr = 2 & scr 0 */
+       max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN);
+       if (freq > max_tclk) {
+               dev_warn(
+                       s->dev,
+                       "Requested SPI frequency %d Hz is more than maximum: %d Hz\n",
+                       freq, max_tclk);
+               clk_freq->freq = max_tclk;
+               clk_freq->cpsdvsr = CPSDVR_MIN;
+               clk_freq->scr = SCR_MIN;
+               return 0;
+       }
+
+       /* cpsdvsr = 254 & scr = 255 */
+       min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
+       if (freq < min_tclk) {
+               dev_err(s->dev,
+                       "Requested SPI frequency %d Hz is less than minimum: %d Hz\n",
+                       freq, min_tclk);
+               return -EINVAL;
+       }
+
+       /*
+        * best_freq will give closest possible available rate (<= requested
+        * freq) for all values of scr & cpsdvsr.
+        */
+       while ((cpsdvsr <= CPSDVR_MAX) && !found) {
+               rate_scaled = rate / cpsdvsr;
+
+               if (rate_scaled < freq)
+                       break;
+
+               scr = DIV_ROUND_UP(rate_scaled, freq) - 1;
+               if (scr > SCR_MAX)
+                       continue;
+
+               tmp = spi_rate(rate, cpsdvsr, scr);
+
+               /*
+                * If found exact value, mark found and break.
+                * If found more closer value, update and break.
+                */
+               if (tmp > best_freq) {
+                       best_freq = tmp;
+                       best_cpsdvsr = cpsdvsr;
+                       best_scr = scr;
+
+                       if (tmp == freq)
+                               found = 1;
+               }
+
+               cpsdvsr += 2;
+       }
+
+       clk_freq->freq = best_freq;
+       clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
+       clk_freq->scr = (u8) (best_scr & 0xFF);
+       dev_dbg(s->dev,
+               "SSP Target Frequency is: %u, Effective Frequency is %u\n",
+               freq, best_freq);
+       dev_dbg(s->dev, "SSP cpsdvsr = %d, scr = %d\n",
+               clk_freq->cpsdvsr, clk_freq->scr);
+
+       return 0;
+}
+
+static int sf_qspi_setup(struct spi_device *spi)
+{
+       struct sf_qspi *s = spi_controller_get_devdata(spi->controller);
+       struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0 };
+       struct chip_data *chip;
+       int ret = 0;
+       u16 cr0 = 0;
+
+       if (!spi->max_speed_hz)
+               return -EINVAL;
+
+       ret = calculate_effective_freq(s, spi->max_speed_hz, &clk_freq);
+       if (ret < 0)
+               return ret;
+
+       chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       cr0 = SSP_CR0_BIT_MODE(8);
+       cr0 |= clk_freq.scr << 8;
+       /*set module*/
+       cr0 &= ~(SSP_CR0_SPH | SSP_CR0_SPO);
+       if (spi->mode & SPI_CPHA)
+               cr0 |= SSP_CR0_SPH;
+       if (spi->mode & SPI_CPOL)
+               cr0 |= SSP_CR0_SPO;
+       cr0 |= SSP_CR0_EXSPI_FRAME;
+
+       chip->freq = clk_freq.freq;
+       chip->cr0 = cr0;
+       chip->cpsr = clk_freq.cpsdvsr;
+
+       spi_set_ctldata(spi, chip);
+       return 0;
+}
+
+static void sf_qspi_cleanup(struct spi_device *spi)
+{
+       struct chip_data *chip = spi_get_ctldata(spi);
+
+       spi_set_ctldata(spi, NULL);
+       kfree(chip);
+}
+
+static const struct spi_controller_mem_ops sf_qspi_mem_ops = {
+       .supports_op = sf_qspi_supports_op,
+       .adjust_op_size = sf_qspi_adjust_op_size,
+       .exec_op = sf_qspi_exec_op,
+};
+
+static int sf_qspi_probe(struct platform_device *pdev)
+{
+       struct spi_controller *master;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct sf_qspi *s;
+       int ret;
+
+       master = devm_spi_alloc_master(&pdev->dev, sizeof(*s));
+       if (!master)
+               return -ENOMEM;
+       master->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD | SPI_TX_DUAL |
+                           SPI_TX_QUAD;
+       s = spi_controller_get_devdata(master);
+       s->dev = dev;
+       platform_set_drvdata(pdev, s);
+
+       s->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(s->base))
+               return dev_err_probe(dev, PTR_ERR(s->base),
+                                    "failed to remap memory resources.\n");
+
+       s->clk = devm_clk_get_enabled(dev, "sspclk");
+       if (IS_ERR(s->clk))
+               return dev_err_probe(dev, PTR_ERR(s->clk),
+                                    "failed to get and enable sspclk.\n");
+
+       s->apbclk = devm_clk_get_enabled(dev, "apb_pclk");
+       if (IS_ERR(s->apbclk))
+               return dev_err_probe(dev, PTR_ERR(s->apbclk),
+                                    "failed to get and enable apb_pclk.\n");
+
+       master->cleanup = sf_qspi_cleanup;
+       master->setup = sf_qspi_setup;
+       master->use_gpio_descriptors = true;
+       master->mem_ops = &sf_qspi_mem_ops;
+       master->dev.of_node = np;
+
+       writew(FIELD_PREP(SSP_FIFO_LEVEL_RX, DFLT_THRESH_RX) |
+              FIELD_PREP(SSP_FIFO_LEVEL_TX, DFLT_THRESH_TX),
+              s->base + SSP_FIFO_LEVEL);
+
+       ret = devm_spi_register_controller(dev, master);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "failed to register controller.\n");
+
+       return 0;
+}
+
+static const struct of_device_id sf_qspi_ids[] = {
+       {.compatible = "siflower,sf21-qspi"},
+       {},
+};
+MODULE_DEVICE_TABLE(of, sf_qspi_ids);
+
+static struct platform_driver sf_qspi_driver = {
+       .driver = {
+               .name = "sf21_qspi",
+               .of_match_table = sf_qspi_ids,
+       },
+       .probe = sf_qspi_probe,
+};
+module_platform_driver(sf_qspi_driver);
diff --git a/target/linux/siflower/files-6.6/include/dt-bindings/clock/siflower,sf21-topcrm.h b/target/linux/siflower/files-6.6/include/dt-bindings/clock/siflower,sf21-topcrm.h
new file mode 100644 (file)
index 0000000..598e755
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+
+#define CLK_CMNPLL_VCO         0
+#define CLK_CMNPLL_POSTDIV     1
+
+#define CLK_DDRPLL_POSTDIV     2
+
+#define CLK_PCIEPLL_VCO                3
+#define CLK_PCIEPLL_FOUT0      4
+#define CLK_PCIEPLL_FOUT1      5
+#define CLK_PCIEPLL_FOUT2      6
+#define CLK_ETH_REF_P          CLK_PCIEPLL_FOUT2
+#define CLK_PCIEPLL_FOUT3      7
+
+#define CLK_CPU                        8
+#define CLK_PIC                        9
+#define CLK_AXI                        10
+#define CLK_AHB                        11
+#define CLK_APB                        12
+#define CLK_UART               13
+#define CLK_IRAM               14
+#define CLK_NPU                        15
+#define CLK_DDRPHY_REF         16
+#define CLK_DDR_BYPASS         17
+#define CLK_ETHTSU             18
+#define CLK_GMAC_BYP_REF       19
+
+#define CLK_USB                        20
+#define CLK_USBPHY             21
+#define CLK_SERDES_CSR         22
+#define CLK_CRYPT_CSR          23
+#define CLK_CRYPT_APP          24
+#define CLK_IROM               25
+
+#define CLK_BOOT               26
+
+#define CLK_PVT                        27
+#define CLK_PLL_TEST           28
+
+#define CLK_PCIE_REFN          29
+#define CLK_PCIE_REFP          30
+
+#define CLK_MAX                        31
diff --git a/target/linux/siflower/files-6.6/include/dt-bindings/pinctrl/siflower,sf21-iomux.h b/target/linux/siflower/files-6.6/include/dt-bindings/pinctrl/siflower,sf21-iomux.h
new file mode 100644 (file)
index 0000000..8ab3a28
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __DT_BINDINGS_SF21_IOMUX_H__
+#define __DT_BINDINGS_SF21_IOMUX_H__
+
+#define SW_DS          0xf             /* Drive strength */
+#define SW_ST          (1 << 4)        /* Schmitt enable */
+#define SW_PD          (1 << 5)        /* Pull-down enable */
+#define SW_PU          (1 << 6)        /* Pull-up enable */
+#define SW_OEN         (1 << 7)        /* Output disable [sic] */
+#define SW_IE          (1 << 8)        /* Input enable */
+#define MODE_BIT0      (1 << 9)        /* Function mode LSB */
+#define MODE_BIT1      (1 << 10)       /* Function mode MSB */
+#define FMUX_SEL       (1 << 11)       /* GPIO mode enable */
+#define FUNC_SW_SEL    (1 << 12)       /* Function mode enable */
+
+#define FUNC_MODE_MASK 0x1f80
+#define FUNC_MODE0     (FUNC_SW_SEL | SW_IE)
+#define FUNC_MODE1     (FUNC_MODE0 | MODE_BIT0)
+#define FUNC_MODE2     (FUNC_MODE0 | MODE_BIT1)
+#define FUNC_MODE3     (FUNC_MODE0 | MODE_BIT0 | MODE_BIT1)
+#define GPIO_MODE      (FUNC_MODE0 | FMUX_SEL)
+
+#define EXT_CLK_IN     0x00
+#define CLK_OUT                0x04
+#define SPI0_TXD       0x08
+#define SPI0_RXD       0x0c
+#define SPI0_CLK       0x10
+#define SPI0_CSN       0x14
+#define SPI0_HOLD      0x18
+#define SPI0_WP                0x1c
+#define JTAG_TDO       0x20
+#define JTAG_TDI       0x24
+#define JTAG_TMS       0x28
+#define JTAG_TCK       0x2c
+#define JTAG_RST       0x30
+#define UART1_TX       0x34
+#define UART1_RX       0x38
+#define I2C0_DAT       0x3c
+#define I2C0_CLK       0x40
+#define I2C1_DAT       0x44
+#define I2C1_CLK       0x48
+#define PWM0           0x4c
+#define PWM1           0x50
+#define RGMII_GTX_CLK  0x54
+#define RGMII_TXCLK    0x58
+#define RGMII_TXD0     0x5c
+#define RGMII_TXD1     0x60
+#define RGMII_TXD2     0x64
+#define RGMII_TXD3     0x68
+#define RGMII_TXCTL    0x6c
+#define RGMII_RXCLK    0x70
+#define RGMII_RXD0     0x74
+#define RGMII_RXD1     0x78
+#define RGMII_RXD2     0x7c
+#define RGMII_RXD3     0x80
+#define RGMII_RXCTL    0x84
+#define QSGMII_MDIO    0x88
+#define QSGMII_MDC     0x8c
+#define SXGMII_MDIO    0x90
+#define SXGMII_MDC     0x94
+#define DGS_INT                0x98
+#define PHY_RSTN       0x9c
+#define PHY_INT                0xa0
+#endif
diff --git a/target/linux/siflower/files-6.6/include/dt-bindings/reset/siflower,sf21-reset.h b/target/linux/siflower/files-6.6/include/dt-bindings/reset/siflower,sf21-reset.h
new file mode 100644 (file)
index 0000000..d31ed04
--- /dev/null
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _SF21_RESETS_H
+#define _SF21_RESETS_H
+
+#define SF21_RESET_GIC                 0
+#define SF21_RESET_AXI                 1
+#define SF21_RESET_AHB                 2
+#define SF21_RESET_APB                 3
+#define SF21_RESET_IRAM                        4
+
+#define SF21_RESET_NPU                 5
+#define SF21_RESET_DDR_CTL             6
+#define SF21_RESET_DDR_PHY             7
+#define SF21_RESET_DDR_PWR_OK_IN       8
+#define SF21_RESET_DDR_CTL_APB         9
+#define SF21_RESET_DDR_PHY_APB         10
+
+#define SF21_RESET_USB                 11
+
+#define SF21_RESET_PVT                 12
+#define SF21_RESET_SERDES_CSR          13
+
+#define SF21_RESET_CRYPT_CSR           14
+#define SF21_RESET_CRYPT_APP           15
+#define SF21_RESET_NPU2DDR_ASYNCBRIDGE 16
+#define SF21_RESET_IROM                        17
+#define SF21_RESET_MAX                 17
+#endif
diff --git a/target/linux/siflower/image/sf21.mk b/target/linux/siflower/image/sf21.mk
new file mode 100644 (file)
index 0000000..6812303
--- /dev/null
@@ -0,0 +1,20 @@
+
+define Device/Default
+  PROFILES = Default $$(DEVICE_NAME)
+  BLOCKSIZE := 64k
+  KERNEL = kernel-bin | lzma
+  KERNEL_INITRAMFS = kernel-bin | lzma | \
+       fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd | pad-to 128k
+  KERNEL_LOADADDR := 0x20000000
+  FILESYSTEMS := squashfs
+  DEVICE_DTS_DIR := ../dts
+  IMAGES := sysupgrade.bin
+  IMAGE/sysupgrade.bin = append-kernel | fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb external-static-with-rootfs | pad-rootfs | append-metadata
+endef
+
+define Device/NAND
+  KERNEL := kernel-bin | gzip
+  KERNEL_INITRAMFS = kernel-bin | lzma | \
+       fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb with-initrd | pad-to 128k
+  IMAGE/sysupgrade.bin = append-kernel | fit gzip $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtb external-static-with-rootfs | append-metadata
+endef
index e8aaf768e4325c826f55c3c297577a2437aa745c..db1e3be058257db614b6947467acb219f11f93af 100644 (file)
@@ -13,3 +13,19 @@ define KernelPackage/phy-sf19a2890-usb/description
 endef
 
 $(eval $(call KernelPackage,phy-sf19a2890-usb))
+
+define KernelPackage/phy-sf21-usb
+  TITLE:=Siflower SF21 USB 2.0 PHY Driver
+  KCONFIG:=CONFIG_PHY_SF21_USB
+  DEPENDS:=@TARGET_siflower_sf21
+  SUBMENU:=$(USB_MENU)
+  FILES:=$(LINUX_DIR)/drivers/phy/siflower/phy-sf21-usb.ko
+  AUTOLOAD:=$(call AutoLoad,45,phy-sf21-usb,1)
+endef
+
+define KernelPackage/phy-sf21-usb/description
+  Support for Siflower SF21 USB 2.0 PHY connected to the USB
+  controller.
+endef
+
+$(eval $(call KernelPackage,phy-sf21-usb))
diff --git a/target/linux/siflower/patches-6.6/001-mips-add-support-for-Siflower-SF19A2890.patch b/target/linux/siflower/patches-6.6/001-mips-add-support-for-Siflower-SF19A2890.patch
deleted file mode 100644 (file)
index 69bd0b8..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-From c2ec4604afb39904c01dfe38ca8289c446b898bb Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:32:17 +0800
-Subject: [PATCH 1/9] mips: add support for Siflower SF19A2890
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- arch/mips/Kconfig          | 29 +++++++++++++++++++++++++++++
- arch/mips/generic/Platform |  1 +
- 2 files changed, 30 insertions(+)
-
---- a/arch/mips/Kconfig
-+++ b/arch/mips/Kconfig
-@@ -861,6 +861,35 @@ config SIBYTE_BIGSUR
-       select ZONE_DMA32 if 64BIT
-       select SWIOTLB if ARCH_DMA_ADDR_T_64BIT && PCI
-+config MACH_SIFLOWER_MIPS
-+      bool "Siflower MIPS SoCs"
-+      select MIPS_GENERIC
-+      select ARM_AMBA
-+      select BOOT_RAW
-+      select CEVT_R4K
-+      select CLKSRC_MIPS_GIC
-+      select COMMON_CLK
-+      select CPU_MIPSR2_IRQ_EI
-+      select CPU_MIPSR2_IRQ_VI
-+      select CSRC_R4K
-+      select DMA_NONCOHERENT
-+      select IRQ_MIPS_CPU
-+      select MIPS_CPU_SCACHE
-+      select MIPS_GIC
-+      select MIPS_L1_CACHE_SHIFT_5
-+      select NO_EXCEPT_FILL
-+      select SMP_UP if SMP
-+      select SYS_HAS_CPU_MIPS32_R2
-+      select SYS_SUPPORTS_32BIT_KERNEL
-+      select SYS_SUPPORTS_LITTLE_ENDIAN
-+      select SYS_SUPPORTS_MIPS16
-+      select SYS_SUPPORTS_MIPS_CPS
-+      select SYS_SUPPORTS_MULTITHREADING
-+      select USE_OF
-+      help
-+        Select this to build a kernel which supports SoCs from Siflower
-+        with MIPS InterAptiv cores, like Siflower SF19A2890.
-+
- config SNI_RM
-       bool "SNI RM200/300/400"
-       select ARC_MEMORY
---- a/arch/mips/generic/Platform
-+++ b/arch/mips/generic/Platform
-@@ -10,6 +10,7 @@
- # Note: order matters, keep the asm/mach-generic include last.
- cflags-$(CONFIG_MACH_INGENIC_SOC)     += -I$(srctree)/arch/mips/include/asm/mach-ingenic
-+cflags-$(CONFIG_MACH_SIFLOWER_MIPS)   += -I$(srctree)/arch/mips/include/asm/mach-siflower
- cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic
- load-$(CONFIG_MIPS_GENERIC)   += 0xffffffff80100000
diff --git a/target/linux/siflower/patches-6.6/001-net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch b/target/linux/siflower/patches-6.6/001-net-phy-c45-add-genphy_c45_pma_read_ext_abilities-fu.patch
new file mode 100644 (file)
index 0000000..37c7f15
--- /dev/null
@@ -0,0 +1,180 @@
+From: Oleksij Rempel <o.rempel@pengutronix.de>
+Date: Tue, 12 Dec 2023 06:41:43 +0100
+Subject: [PATCH 01/20] net: phy: c45: add genphy_c45_pma_read_ext_abilities()
+ function
+
+Move part of the genphy_c45_pma_read_abilities() code to a separate
+function.
+
+Some PHYs do not implement PMA/PMD status 2 register (Register 1.8) but
+do implement PMA/PMD extended ability register (Register 1.11). To make
+use of it, we need to be able to access this part of code separately.
+
+Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Link: https://lore.kernel.org/r/20231212054144.87527-2-o.rempel@pengutronix.de
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+(cherry picked from commit 0c476157085fe2ad13b9bec70ea672e86647fa1a)
+---
+ drivers/net/phy/phy-c45.c | 129 ++++++++++++++++++++++----------------
+ include/linux/phy.h       |   1 +
+ 2 files changed, 75 insertions(+), 55 deletions(-)
+
+--- a/drivers/net/phy/phy-c45.c
++++ b/drivers/net/phy/phy-c45.c
+@@ -920,6 +920,79 @@ int genphy_c45_pma_baset1_read_abilities
+ EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
+ /**
++ * genphy_c45_pma_read_ext_abilities - read supported link modes from PMA
++ * @phydev: target phy_device struct
++ *
++ * Read the supported link modes from the PMA/PMD extended ability register
++ * (Register 1.11).
++ */
++int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev)
++{
++      int val;
++
++      val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
++      if (val < 0)
++              return val;
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10GBLRM);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10GBT);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10GBKX4);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10GBKR);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_1000BT);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_1000BKX);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_100BTX);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_100BTX);
++
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10BT);
++      linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
++                       phydev->supported,
++                       val & MDIO_PMA_EXTABLE_10BT);
++
++      if (val & MDIO_PMA_EXTABLE_NBT) {
++              val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
++                                 MDIO_PMA_NG_EXTABLE);
++              if (val < 0)
++                      return val;
++
++              linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
++                               phydev->supported,
++                               val & MDIO_PMA_NG_EXTABLE_2_5GBT);
++
++              linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
++                               phydev->supported,
++                               val & MDIO_PMA_NG_EXTABLE_5GBT);
++      }
++
++      if (val & MDIO_PMA_EXTABLE_BT1) {
++              val = genphy_c45_pma_baset1_read_abilities(phydev);
++              if (val < 0)
++                      return val;
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(genphy_c45_pma_read_ext_abilities);
++
++/**
+  * genphy_c45_pma_read_abilities - read supported link modes from PMA
+  * @phydev: target phy_device struct
+  *
+@@ -962,63 +1035,9 @@ int genphy_c45_pma_read_abilities(struct
+                        val & MDIO_PMA_STAT2_10GBER);
+       if (val & MDIO_PMA_STAT2_EXTABLE) {
+-              val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
++              val = genphy_c45_pma_read_ext_abilities(phydev);
+               if (val < 0)
+                       return val;
+-
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10GBLRM);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10GBT);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10GBKX4);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10GBKR);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_1000BT);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_1000BKX);
+-
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_100BTX);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_100BTX);
+-
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10BT);
+-              linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+-                               phydev->supported,
+-                               val & MDIO_PMA_EXTABLE_10BT);
+-
+-              if (val & MDIO_PMA_EXTABLE_NBT) {
+-                      val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
+-                                         MDIO_PMA_NG_EXTABLE);
+-                      if (val < 0)
+-                              return val;
+-
+-                      linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+-                                       phydev->supported,
+-                                       val & MDIO_PMA_NG_EXTABLE_2_5GBT);
+-
+-                      linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+-                                       phydev->supported,
+-                                       val & MDIO_PMA_NG_EXTABLE_5GBT);
+-              }
+-
+-              if (val & MDIO_PMA_EXTABLE_BT1) {
+-                      val = genphy_c45_pma_baset1_read_abilities(phydev);
+-                      if (val < 0)
+-                              return val;
+-              }
+       }
+       /* This is optional functionality. If not supported, we may get an error
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1896,6 +1896,7 @@ int genphy_c45_an_config_aneg(struct phy
+ int genphy_c45_an_disable_aneg(struct phy_device *phydev);
+ int genphy_c45_read_mdix(struct phy_device *phydev);
+ int genphy_c45_pma_read_abilities(struct phy_device *phydev);
++int genphy_c45_pma_read_ext_abilities(struct phy_device *phydev);
+ int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev);
+ int genphy_c45_read_eee_abilities(struct phy_device *phydev);
+ int genphy_c45_pma_baset1_read_master_slave(struct phy_device *phydev);
diff --git a/target/linux/siflower/patches-6.6/002-clk-add-drivers-for-sf19a2890.patch b/target/linux/siflower/patches-6.6/002-clk-add-drivers-for-sf19a2890.patch
deleted file mode 100644 (file)
index 620e432..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From fcb96cb774abf14375326c41cedd237d6c8f6e94 Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:33:01 +0800
-Subject: [PATCH 2/9] clk: add drivers for sf19a2890
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- drivers/clk/Kconfig  | 1 +
- drivers/clk/Makefile | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/clk/Kconfig
-+++ b/drivers/clk/Kconfig
-@@ -489,6 +489,7 @@ source "drivers/clk/renesas/Kconfig"
- source "drivers/clk/rockchip/Kconfig"
- source "drivers/clk/samsung/Kconfig"
- source "drivers/clk/sifive/Kconfig"
-+source "drivers/clk/siflower/Kconfig"
- source "drivers/clk/socfpga/Kconfig"
- source "drivers/clk/sprd/Kconfig"
- source "drivers/clk/starfive/Kconfig"
---- a/drivers/clk/Makefile
-+++ b/drivers/clk/Makefile
-@@ -116,6 +116,7 @@ obj-y                                      += renesas/
- obj-$(CONFIG_ARCH_ROCKCHIP)           += rockchip/
- obj-$(CONFIG_COMMON_CLK_SAMSUNG)      += samsung/
- obj-$(CONFIG_CLK_SIFIVE)              += sifive/
-+obj-$(CONFIG_CLK_SIFLOWER)            += siflower/
- obj-y                                 += socfpga/
- obj-$(CONFIG_PLAT_SPEAR)              += spear/
- obj-y                                 += sprd/
diff --git a/target/linux/siflower/patches-6.6/002-net-phy-Optimize-phy-speed-mask-to-be-compatible-to-.patch b/target/linux/siflower/patches-6.6/002-net-phy-Optimize-phy-speed-mask-to-be-compatible-to-.patch
new file mode 100644 (file)
index 0000000..68368b1
--- /dev/null
@@ -0,0 +1,49 @@
+From: Frank Sae <Frank.Sae@motor-comm.com>
+Date: Sun, 1 Sep 2024 01:35:25 -0700
+Subject: [PATCH 02/20] net: phy: Optimize phy speed mask to be compatible to
+ yt8821
+
+yt8521 and yt8531s as Gigabit transceiver use bit15:14(bit9 reserved
+default 0) as phy speed mask, yt8821 as 2.5G transceiver uses bit9 bit15:14
+as phy speed mask.
+
+Be compatible to yt8821, reform phy speed mask and phy speed macro.
+
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+
+(cherry picked from commit 8d878c87b5c45ae64b0aecd4aac71e210d19173f)
+---
+ drivers/net/phy/motorcomm.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/phy/motorcomm.c
++++ b/drivers/net/phy/motorcomm.c
+@@ -47,12 +47,10 @@
+ /* Specific Status Register */
+ #define YTPHY_SPECIFIC_STATUS_REG             0x11
+-#define YTPHY_SSR_SPEED_MODE_OFFSET           14
+-
+-#define YTPHY_SSR_SPEED_MODE_MASK             (BIT(15) | BIT(14))
+-#define YTPHY_SSR_SPEED_10M                   0x0
+-#define YTPHY_SSR_SPEED_100M                  0x1
+-#define YTPHY_SSR_SPEED_1000M                 0x2
++#define YTPHY_SSR_SPEED_MASK                  ((0x3 << 14) | BIT(9))
++#define YTPHY_SSR_SPEED_10M                   ((0x0 << 14))
++#define YTPHY_SSR_SPEED_100M                  ((0x1 << 14))
++#define YTPHY_SSR_SPEED_1000M                 ((0x2 << 14))
+ #define YTPHY_SSR_DUPLEX_OFFSET                       13
+ #define YTPHY_SSR_DUPLEX                      BIT(13)
+ #define YTPHY_SSR_PAGE_RECEIVED                       BIT(12)
+@@ -1188,8 +1186,7 @@ static int yt8521_adjust_status(struct p
+       else
+               duplex = DUPLEX_FULL;   /* for fiber, it always DUPLEX_FULL */
+-      speed_mode = (status & YTPHY_SSR_SPEED_MODE_MASK) >>
+-                   YTPHY_SSR_SPEED_MODE_OFFSET;
++      speed_mode = status & YTPHY_SSR_SPEED_MASK;
+       switch (speed_mode) {
+       case YTPHY_SSR_SPEED_10M:
diff --git a/target/linux/siflower/patches-6.6/003-net-phy-Add-driver-for-Motorcomm-yt8821-2.5G-etherne.patch b/target/linux/siflower/patches-6.6/003-net-phy-Add-driver-for-Motorcomm-yt8821-2.5G-etherne.patch
new file mode 100644 (file)
index 0000000..6778f00
--- /dev/null
@@ -0,0 +1,753 @@
+From: Frank Sae <Frank.Sae@motor-comm.com>
+Date: Sun, 1 Sep 2024 01:35:26 -0700
+Subject: [PATCH 03/20] net: phy: Add driver for Motorcomm yt8821 2.5G ethernet
+ phy
+
+Add a driver for the motorcomm yt8821 2.5G ethernet phy. Verified the
+driver on BPI-R3(with MediaTek MT7986(Filogic 830) SoC) development board,
+which is developed by Guangdong Bipai Technology Co., Ltd..
+
+yt8821 2.5G ethernet phy works in AUTO_BX2500_SGMII or FORCE_BX2500
+interface, supports 2.5G/1000M/100M/10M speeds, and wol(magic package).
+
+Signed-off-by: Frank Sae <Frank.Sae@motor-comm.com>
+Reviewed-by: Sai Krishna <saikrishnag@marvell.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+
+(cherry picked from commit b671105b88c3bb9acc1fb61a3ee2ca0ece60cb8d)
+---
+ drivers/net/phy/motorcomm.c | 671 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 667 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/phy/motorcomm.c
++++ b/drivers/net/phy/motorcomm.c
+@@ -1,6 +1,6 @@
+ // SPDX-License-Identifier: GPL-2.0+
+ /*
+- * Motorcomm 8511/8521/8531/8531S PHY driver.
++ * Motorcomm 8511/8521/8531/8531S/8821 PHY driver.
+  *
+  * Author: Peter Geis <pgwipeout@gmail.com>
+  * Author: Frank <Frank.Sae@motor-comm.com>
+@@ -17,8 +17,8 @@
+ #define PHY_ID_YT8521         0x0000011a
+ #define PHY_ID_YT8531         0x4f51e91b
+ #define PHY_ID_YT8531S                0x4f51e91a
+-
+-/* YT8521/YT8531S Register Overview
++#define PHY_ID_YT8821         0x4f51ea19
++/* YT8521/YT8531S/YT8821 Register Overview
+  *    UTP Register space      |       FIBER Register space
+  *  ------------------------------------------------------------
+  * |  UTP MII                 |       FIBER MII               |
+@@ -51,6 +51,8 @@
+ #define YTPHY_SSR_SPEED_10M                   ((0x0 << 14))
+ #define YTPHY_SSR_SPEED_100M                  ((0x1 << 14))
+ #define YTPHY_SSR_SPEED_1000M                 ((0x2 << 14))
++#define YTPHY_SSR_SPEED_10G                   ((0x3 << 14))
++#define YTPHY_SSR_SPEED_2500M                 ((0x0 << 14) | BIT(9))
+ #define YTPHY_SSR_DUPLEX_OFFSET                       13
+ #define YTPHY_SSR_DUPLEX                      BIT(13)
+ #define YTPHY_SSR_PAGE_RECEIVED                       BIT(12)
+@@ -269,12 +271,89 @@
+ #define YT8531_SCR_CLK_SRC_REF_25M            4
+ #define YT8531_SCR_CLK_SRC_SSC_25M            5
++#define YT8821_SDS_EXT_CSR_CTRL_REG                   0x23
++#define YT8821_SDS_EXT_CSR_VCO_LDO_EN                 BIT(15)
++#define YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN            BIT(8)
++
++#define YT8821_UTP_EXT_PI_CTRL_REG                    0x56
++#define YT8821_UTP_EXT_PI_RST_N_FIFO                  BIT(5)
++#define YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE              BIT(4)
++#define YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE            BIT(3)
++#define YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE            BIT(2)
++#define YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE            BIT(1)
++#define YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE            BIT(0)
++
++#define YT8821_UTP_EXT_VCT_CFG6_CTRL_REG              0x97
++#define YT8821_UTP_EXT_FECHO_AMP_TH_HUGE              GENMASK(15, 8)
++
++#define YT8821_UTP_EXT_ECHO_CTRL_REG                  0x336
++#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000                GENMASK(14, 8)
++
++#define YT8821_UTP_EXT_GAIN_CTRL_REG                  0x340
++#define YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000                GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_RPDN_CTRL_REG                  0x34E
++#define YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500           BIT(15)
++#define YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500           BIT(7)
++#define YT8821_UTP_EXT_RPDN_IPR_SHT_2500              GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG          0x36A
++#define YT8821_UTP_EXT_TH_20DB_2500                   GENMASK(15, 0)
++
++#define YT8821_UTP_EXT_TRACE_CTRL_REG                 0x372
++#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500                GENMASK(14, 8)
++#define YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500                GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG             0x374
++#define YT8821_UTP_EXT_ALPHA_SHT_2500                 GENMASK(14, 8)
++#define YT8821_UTP_EXT_IPR_LNG_2500                   GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_PLL_CTRL_REG                   0x450
++#define YT8821_UTP_EXT_PLL_SPARE_CFG                  GENMASK(7, 0)
++
++#define YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG               0x466
++#define YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG           GENMASK(14, 8)
++#define YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG           GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG               0x467
++#define YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG           GENMASK(14, 8)
++#define YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG           GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG               0x468
++#define YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG           GENMASK(14, 8)
++#define YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG           GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG               0x469
++#define YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG           GENMASK(14, 8)
++#define YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG           GENMASK(6, 0)
++
++#define YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG          0x4B3
++#define YT8821_UTP_EXT_MU_COARSE_FR_F_FFE             GENMASK(14, 12)
++#define YT8821_UTP_EXT_MU_COARSE_FR_F_FBE             GENMASK(10, 8)
++
++#define YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG            0x4B5
++#define YT8821_UTP_EXT_MU_FINE_FR_F_FFE                       GENMASK(14, 12)
++#define YT8821_UTP_EXT_MU_FINE_FR_F_FBE                       GENMASK(10, 8)
++
++#define YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG          0x4D2
++#define YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER             GENMASK(7, 4)
++#define YT8821_UTP_EXT_VGA_LPF1_CAP_2500              GENMASK(3, 0)
++
++#define YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG          0x4D3
++#define YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER             GENMASK(7, 4)
++#define YT8821_UTP_EXT_VGA_LPF2_CAP_2500              GENMASK(3, 0)
++
++#define YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG               0x660
++#define YT8821_UTP_EXT_NFR_TX_ABILITY                 BIT(3)
+ /* Extended Register  end */
+ #define YTPHY_DTS_OUTPUT_CLK_DIS              0
+ #define YTPHY_DTS_OUTPUT_CLK_25M              25000000
+ #define YTPHY_DTS_OUTPUT_CLK_125M             125000000
++#define YT8821_CHIP_MODE_AUTO_BX2500_SGMII    0
++#define YT8821_CHIP_MODE_FORCE_BX2500         1
++
+ struct yt8521_priv {
+       /* combo_advertising is used for case of YT8521 in combo mode,
+        * this means that yt8521 may work in utp or fiber mode which depends
+@@ -2250,6 +2329,572 @@ static int yt8521_get_features(struct ph
+       return ret;
+ }
++/**
++ * yt8821_get_features - read mmd register to get 2.5G capability
++ * @phydev: target phy_device struct
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_get_features(struct phy_device *phydev)
++{
++      int ret;
++
++      ret = genphy_c45_pma_read_ext_abilities(phydev);
++      if (ret < 0)
++              return ret;
++
++      return genphy_read_abilities(phydev);
++}
++
++/**
++ * yt8821_get_rate_matching - read register to get phy chip mode
++ * @phydev: target phy_device struct
++ * @iface: PHY data interface type
++ *
++ * Returns: rate matching type or negative errno code
++ */
++static int yt8821_get_rate_matching(struct phy_device *phydev,
++                                  phy_interface_t iface)
++{
++      int val;
++
++      val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
++      if (val < 0)
++              return val;
++
++      if (FIELD_GET(YT8521_CCR_MODE_SEL_MASK, val) ==
++          YT8821_CHIP_MODE_FORCE_BX2500)
++              return RATE_MATCH_PAUSE;
++
++      return RATE_MATCH_NONE;
++}
++
++/**
++ * yt8821_aneg_done() - determines the auto negotiation result
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0(no link)or 1(utp link) or negative errno code
++ */
++static int yt8821_aneg_done(struct phy_device *phydev)
++{
++      return yt8521_aneg_done_paged(phydev, YT8521_RSSR_UTP_SPACE);
++}
++
++/**
++ * yt8821_serdes_init() - serdes init
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_serdes_init(struct phy_device *phydev)
++{
++      int old_page;
++      int ret = 0;
++      u16 mask;
++      u16 set;
++
++      old_page = phy_select_page(phydev, YT8521_RSSR_FIBER_SPACE);
++      if (old_page < 0) {
++              phydev_err(phydev, "Failed to select page: %d\n",
++                         old_page);
++              goto err_restore_page;
++      }
++
++      ret = __phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_SDS_EXT_CSR_VCO_LDO_EN |
++              YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN;
++      set = YT8821_SDS_EXT_CSR_VCO_LDO_EN;
++      ret = ytphy_modify_ext(phydev, YT8821_SDS_EXT_CSR_CTRL_REG, mask,
++                             set);
++
++err_restore_page:
++      return phy_restore_page(phydev, old_page, ret);
++}
++
++/**
++ * yt8821_utp_init() - utp init
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_utp_init(struct phy_device *phydev)
++{
++      int old_page;
++      int ret = 0;
++      u16 mask;
++      u16 save;
++      u16 set;
++
++      old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
++      if (old_page < 0) {
++              phydev_err(phydev, "Failed to select page: %d\n",
++                         old_page);
++              goto err_restore_page;
++      }
++
++      mask = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
++              YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 |
++              YT8821_UTP_EXT_RPDN_IPR_SHT_2500;
++      set = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
++              YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500;
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_RPDN_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER |
++              YT8821_UTP_EXT_VGA_LPF1_CAP_2500;
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG,
++                             mask, 0);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER |
++              YT8821_UTP_EXT_VGA_LPF2_CAP_2500;
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG,
++                             mask, 0);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 |
++              YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500;
++      set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500, 0x5a) |
++              FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500, 0x3c);
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_TRACE_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_IPR_LNG_2500;
++      set = FIELD_PREP(YT8821_UTP_EXT_IPR_LNG_2500, 0x6c);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000;
++      set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000, 0x2a);
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_ECHO_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000;
++      set = FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000, 0x22);
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_GAIN_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_TH_20DB_2500;
++      set = FIELD_PREP(YT8821_UTP_EXT_TH_20DB_2500, 0x8000);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_MU_COARSE_FR_F_FFE |
++              YT8821_UTP_EXT_MU_COARSE_FR_F_FBE;
++      set = FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FFE, 0x7) |
++              FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FBE, 0x7);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_MU_FINE_FR_F_FFE |
++              YT8821_UTP_EXT_MU_FINE_FR_F_FBE;
++      set = FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FFE, 0x2) |
++              FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FBE, 0x2);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      /* save YT8821_UTP_EXT_PI_CTRL_REG's val for use later */
++      ret = ytphy_read_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG);
++      if (ret < 0)
++              goto err_restore_page;
++
++      save = ret;
++
++      mask = YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE |
++              YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE |
++              YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE |
++              YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE |
++              YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE;
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG,
++                             mask, 0);
++      if (ret < 0)
++              goto err_restore_page;
++
++      /* restore YT8821_UTP_EXT_PI_CTRL_REG's val */
++      ret = ytphy_write_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG, save);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_FECHO_AMP_TH_HUGE;
++      set = FIELD_PREP(YT8821_UTP_EXT_FECHO_AMP_TH_HUGE, 0x38);
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_VCT_CFG6_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_NFR_TX_ABILITY;
++      set = YT8821_UTP_EXT_NFR_TX_ABILITY;
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_PLL_SPARE_CFG;
++      set = FIELD_PREP(YT8821_UTP_EXT_PLL_SPARE_CFG, 0xe9);
++      ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PLL_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG |
++              YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG;
++      set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG, 0x64) |
++              FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG, 0x64);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG |
++              YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG;
++      set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG, 0x64) |
++              FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG, 0x64);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG |
++              YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG;
++      set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG, 0x64) |
++              FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG, 0x64);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG,
++                             mask, set);
++      if (ret < 0)
++              goto err_restore_page;
++
++      mask = YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG |
++              YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG;
++      set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG, 0x64) |
++              FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG, 0x64);
++      ret = ytphy_modify_ext(phydev,
++                             YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG,
++                             mask, set);
++
++err_restore_page:
++      return phy_restore_page(phydev, old_page, ret);
++}
++
++/**
++ * yt8821_auto_sleep_config() - phy auto sleep config
++ * @phydev: a pointer to a &struct phy_device
++ * @enable: true enable auto sleep, false disable auto sleep
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_auto_sleep_config(struct phy_device *phydev,
++                                  bool enable)
++{
++      int old_page;
++      int ret = 0;
++
++      old_page = phy_select_page(phydev, YT8521_RSSR_UTP_SPACE);
++      if (old_page < 0) {
++              phydev_err(phydev, "Failed to select page: %d\n",
++                         old_page);
++              goto err_restore_page;
++      }
++
++      ret = ytphy_modify_ext(phydev,
++                             YT8521_EXTREG_SLEEP_CONTROL1_REG,
++                             YT8521_ESC1R_SLEEP_SW,
++                             enable ? 1 : 0);
++
++err_restore_page:
++      return phy_restore_page(phydev, old_page, ret);
++}
++
++/**
++ * yt8821_soft_reset() - soft reset utp and serdes
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_soft_reset(struct phy_device *phydev)
++{
++      return ytphy_modify_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG,
++                                        YT8521_CCR_SW_RST, 0);
++}
++
++/**
++ * yt8821_config_init() - phy initializatioin
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_config_init(struct phy_device *phydev)
++{
++      u8 mode = YT8821_CHIP_MODE_AUTO_BX2500_SGMII;
++      int ret;
++      u16 set;
++
++      if (phydev->interface == PHY_INTERFACE_MODE_2500BASEX)
++              mode = YT8821_CHIP_MODE_FORCE_BX2500;
++
++      set = FIELD_PREP(YT8521_CCR_MODE_SEL_MASK, mode);
++      ret = ytphy_modify_ext_with_lock(phydev,
++                                       YT8521_CHIP_CONFIG_REG,
++                                       YT8521_CCR_MODE_SEL_MASK,
++                                       set);
++      if (ret < 0)
++              return ret;
++
++      __set_bit(PHY_INTERFACE_MODE_2500BASEX,
++                phydev->possible_interfaces);
++
++      if (mode == YT8821_CHIP_MODE_AUTO_BX2500_SGMII) {
++              __set_bit(PHY_INTERFACE_MODE_SGMII,
++                        phydev->possible_interfaces);
++
++              phydev->rate_matching = RATE_MATCH_NONE;
++      } else if (mode == YT8821_CHIP_MODE_FORCE_BX2500) {
++              phydev->rate_matching = RATE_MATCH_PAUSE;
++      }
++
++      ret = yt8821_serdes_init(phydev);
++      if (ret < 0)
++              return ret;
++
++      ret = yt8821_utp_init(phydev);
++      if (ret < 0)
++              return ret;
++
++      /* disable auto sleep */
++      ret = yt8821_auto_sleep_config(phydev, false);
++      if (ret < 0)
++              return ret;
++
++      /* soft reset */
++      return yt8821_soft_reset(phydev);
++}
++
++/**
++ * yt8821_adjust_status() - update speed and duplex to phydev
++ * @phydev: a pointer to a &struct phy_device
++ * @val: read from YTPHY_SPECIFIC_STATUS_REG
++ */
++static void yt8821_adjust_status(struct phy_device *phydev, int val)
++{
++      int speed, duplex;
++      int speed_mode;
++
++      duplex = FIELD_GET(YTPHY_SSR_DUPLEX, val);
++      speed_mode = val & YTPHY_SSR_SPEED_MASK;
++      switch (speed_mode) {
++      case YTPHY_SSR_SPEED_10M:
++              speed = SPEED_10;
++              break;
++      case YTPHY_SSR_SPEED_100M:
++              speed = SPEED_100;
++              break;
++      case YTPHY_SSR_SPEED_1000M:
++              speed = SPEED_1000;
++              break;
++      case YTPHY_SSR_SPEED_2500M:
++              speed = SPEED_2500;
++              break;
++      default:
++              speed = SPEED_UNKNOWN;
++              break;
++      }
++
++      phydev->speed = speed;
++      phydev->duplex = duplex;
++}
++
++/**
++ * yt8821_update_interface() - update interface per current speed
++ * @phydev: a pointer to a &struct phy_device
++ */
++static void yt8821_update_interface(struct phy_device *phydev)
++{
++      if (!phydev->link)
++              return;
++
++      switch (phydev->speed) {
++      case SPEED_2500:
++              phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
++              break;
++      case SPEED_1000:
++      case SPEED_100:
++      case SPEED_10:
++              phydev->interface = PHY_INTERFACE_MODE_SGMII;
++              break;
++      default:
++              phydev_warn(phydev, "phy speed err :%d\n", phydev->speed);
++              break;
++      }
++}
++
++/**
++ * yt8821_read_status() -  determines the negotiated speed and duplex
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_read_status(struct phy_device *phydev)
++{
++      int link;
++      int ret;
++      int val;
++
++      ret = ytphy_write_ext_with_lock(phydev,
++                                      YT8521_REG_SPACE_SELECT_REG,
++                                      YT8521_RSSR_UTP_SPACE);
++      if (ret < 0)
++              return ret;
++
++      ret = genphy_read_status(phydev);
++      if (ret < 0)
++              return ret;
++
++      if (phydev->autoneg_complete) {
++              ret = genphy_c45_read_lpa(phydev);
++              if (ret < 0)
++                      return ret;
++      }
++
++      ret = phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
++      if (ret < 0)
++              return ret;
++
++      val = ret;
++
++      link = val & YTPHY_SSR_LINK;
++      if (link)
++              yt8821_adjust_status(phydev, val);
++
++      if (link) {
++              if (phydev->link == 0)
++                      phydev_dbg(phydev,
++                                 "%s, phy addr: %d, link up\n",
++                                 __func__, phydev->mdio.addr);
++              phydev->link = 1;
++      } else {
++              if (phydev->link == 1)
++                      phydev_dbg(phydev,
++                                 "%s, phy addr: %d, link down\n",
++                                 __func__, phydev->mdio.addr);
++              phydev->link = 0;
++      }
++
++      val = ytphy_read_ext_with_lock(phydev, YT8521_CHIP_CONFIG_REG);
++      if (val < 0)
++              return val;
++
++      if (FIELD_GET(YT8521_CCR_MODE_SEL_MASK, val) ==
++          YT8821_CHIP_MODE_AUTO_BX2500_SGMII)
++              yt8821_update_interface(phydev);
++
++      return 0;
++}
++
++/**
++ * yt8821_modify_utp_fiber_bmcr - bits modify a PHY's BMCR register
++ * @phydev: the phy_device struct
++ * @mask: bit mask of bits to clear
++ * @set: bit mask of bits to set
++ *
++ * NOTE: Convenience function which allows a PHY's BMCR register to be
++ * modified as new register value = (old register value & ~mask) | set.
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_modify_utp_fiber_bmcr(struct phy_device *phydev,
++                                      u16 mask, u16 set)
++{
++      int ret;
++
++      ret = yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_UTP_SPACE,
++                                     mask, set);
++      if (ret < 0)
++              return ret;
++
++      return yt8521_modify_bmcr_paged(phydev, YT8521_RSSR_FIBER_SPACE,
++                                      mask, set);
++}
++
++/**
++ * yt8821_suspend() - suspend the hardware
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_suspend(struct phy_device *phydev)
++{
++      int wol_config;
++
++      wol_config = ytphy_read_ext_with_lock(phydev,
++                                            YTPHY_WOL_CONFIG_REG);
++      if (wol_config < 0)
++              return wol_config;
++
++      /* if wol enable, do nothing */
++      if (wol_config & YTPHY_WCR_ENABLE)
++              return 0;
++
++      return yt8821_modify_utp_fiber_bmcr(phydev, 0, BMCR_PDOWN);
++}
++
++/**
++ * yt8821_resume() - resume the hardware
++ * @phydev: a pointer to a &struct phy_device
++ *
++ * Returns: 0 or negative errno code
++ */
++static int yt8821_resume(struct phy_device *phydev)
++{
++      int wol_config;
++      int ret;
++
++      /* disable auto sleep */
++      ret = yt8821_auto_sleep_config(phydev, false);
++      if (ret < 0)
++              return ret;
++
++      wol_config = ytphy_read_ext_with_lock(phydev,
++                                            YTPHY_WOL_CONFIG_REG);
++      if (wol_config < 0)
++              return wol_config;
++
++      /* if wol enable, do nothing */
++      if (wol_config & YTPHY_WCR_ENABLE)
++              return 0;
++
++      return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
++}
++
+ static struct phy_driver motorcomm_phy_drvs[] = {
+       {
+               PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
+@@ -2305,11 +2950,28 @@ static struct phy_driver motorcomm_phy_d
+               .suspend        = yt8521_suspend,
+               .resume         = yt8521_resume,
+       },
++      {
++              PHY_ID_MATCH_EXACT(PHY_ID_YT8821),
++              .name                   = "YT8821 2.5Gbps PHY",
++              .get_features           = yt8821_get_features,
++              .read_page              = yt8521_read_page,
++              .write_page             = yt8521_write_page,
++              .get_wol                = ytphy_get_wol,
++              .set_wol                = ytphy_set_wol,
++              .config_aneg            = genphy_config_aneg,
++              .aneg_done              = yt8821_aneg_done,
++              .config_init            = yt8821_config_init,
++              .get_rate_matching      = yt8821_get_rate_matching,
++              .read_status            = yt8821_read_status,
++              .soft_reset             = yt8821_soft_reset,
++              .suspend                = yt8821_suspend,
++              .resume                 = yt8821_resume,
++      },
+ };
+ module_phy_driver(motorcomm_phy_drvs);
+-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S PHY driver");
++MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821 PHY driver");
+ MODULE_AUTHOR("Peter Geis");
+ MODULE_AUTHOR("Frank");
+ MODULE_LICENSE("GPL");
+@@ -2319,6 +2981,7 @@ static const struct mdio_device_id __may
+       { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
+       { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
+       { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
++      { PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },
+       { /* sentinel */ }
+ };
diff --git a/target/linux/siflower/patches-6.6/003-reset-add-support-for-sf19a2890.patch b/target/linux/siflower/patches-6.6/003-reset-add-support-for-sf19a2890.patch
deleted file mode 100644 (file)
index 52992ac..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From 819d2a48d45f3734c876186e651917bae69be9ba Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:33:43 +0800
-Subject: [PATCH 3/9] reset: add support for sf19a2890
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- drivers/reset/Kconfig  | 8 ++++++++
- drivers/reset/Makefile | 1 +
- 2 files changed, 9 insertions(+)
-
---- a/drivers/reset/Kconfig
-+++ b/drivers/reset/Kconfig
-@@ -211,6 +211,14 @@ config RESET_SCMI
-         This driver uses SCMI Message Protocol to interact with the
-         firmware controlling all the reset signals.
-+config RESET_SF19A2890_PERIPH
-+      bool "Siflower SF19A2890 Peripheral Reset Controller Driver"
-+      default MACH_SIFLOWER_MIPS
-+      depends on HAS_IOMEM
-+      help
-+        This enables reset controller driver for peripheral reset blocks
-+        found on Siflower SF19A2890 SoC.
-+
- config RESET_SIMPLE
-       bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
-       default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
---- a/drivers/reset/Makefile
-+++ b/drivers/reset/Makefile
-@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qc
- obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
- obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
- obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
-+obj-$(CONFIG_RESET_SF19A2890_PERIPH) += reset-sf19a2890-periph.o
- obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
- obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
- obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
diff --git a/target/linux/siflower/patches-6.6/004-gpio-add-support-for-siflower-socs.patch b/target/linux/siflower/patches-6.6/004-gpio-add-support-for-siflower-socs.patch
deleted file mode 100644 (file)
index c381b86..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-From 1d37455eacb1d0c262ae6aaecadf27964cbf97d8 Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:33:57 +0800
-Subject: [PATCH 4/9] gpio: add support for siflower socs
-
----
- drivers/gpio/Kconfig  | 8 ++++++++
- drivers/gpio/Makefile | 1 +
- 2 files changed, 9 insertions(+)
-
---- a/drivers/gpio/Kconfig
-+++ b/drivers/gpio/Kconfig
-@@ -576,6 +576,14 @@ config GPIO_SIFIVE
-       help
-         Say yes here to support the GPIO device on SiFive SoCs.
-+config GPIO_SIFLOWER
-+      tristate "SiFlower GPIO support"
-+      depends on OF_GPIO
-+      depends on MACH_SIFLOWER_MIPS || COMPILE_TEST
-+      select GPIOLIB_IRQCHIP
-+      help
-+        GPIO controller driver for SiFlower SoCs.
-+
- config GPIO_SIOX
-       tristate "SIOX GPIO support"
-       depends on SIOX
---- a/drivers/gpio/Makefile
-+++ b/drivers/gpio/Makefile
-@@ -143,6 +143,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)   += gpio
- obj-$(CONFIG_GPIO_SCH311X)            += gpio-sch311x.o
- obj-$(CONFIG_GPIO_SCH)                        += gpio-sch.o
- obj-$(CONFIG_GPIO_SIFIVE)             += gpio-sifive.o
-+obj-$(CONFIG_GPIO_SIFLOWER)           += gpio-siflower.o
- obj-$(CONFIG_GPIO_SIM)                        += gpio-sim.o
- obj-$(CONFIG_GPIO_SIOX)                       += gpio-siox.o
- obj-$(CONFIG_GPIO_SL28CPLD)           += gpio-sl28cpld.o
diff --git a/target/linux/siflower/patches-6.6/004-mips-add-support-for-Siflower-SF19A2890.patch b/target/linux/siflower/patches-6.6/004-mips-add-support-for-Siflower-SF19A2890.patch
new file mode 100644 (file)
index 0000000..b0f3c1a
--- /dev/null
@@ -0,0 +1,58 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:32:17 +0800
+Subject: [PATCH 04/20] mips: add support for Siflower SF19A2890
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/mips/Kconfig          | 29 +++++++++++++++++++++++++++++
+ arch/mips/generic/Platform |  1 +
+ 2 files changed, 30 insertions(+)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -861,6 +861,35 @@ config SIBYTE_BIGSUR
+       select ZONE_DMA32 if 64BIT
+       select SWIOTLB if ARCH_DMA_ADDR_T_64BIT && PCI
++config MACH_SIFLOWER_MIPS
++      bool "Siflower MIPS SoCs"
++      select MIPS_GENERIC
++      select ARM_AMBA
++      select BOOT_RAW
++      select CEVT_R4K
++      select CLKSRC_MIPS_GIC
++      select COMMON_CLK
++      select CPU_MIPSR2_IRQ_EI
++      select CPU_MIPSR2_IRQ_VI
++      select CSRC_R4K
++      select DMA_NONCOHERENT
++      select IRQ_MIPS_CPU
++      select MIPS_CPU_SCACHE
++      select MIPS_GIC
++      select MIPS_L1_CACHE_SHIFT_5
++      select NO_EXCEPT_FILL
++      select SMP_UP if SMP
++      select SYS_HAS_CPU_MIPS32_R2
++      select SYS_SUPPORTS_32BIT_KERNEL
++      select SYS_SUPPORTS_LITTLE_ENDIAN
++      select SYS_SUPPORTS_MIPS16
++      select SYS_SUPPORTS_MIPS_CPS
++      select SYS_SUPPORTS_MULTITHREADING
++      select USE_OF
++      help
++        Select this to build a kernel which supports SoCs from Siflower
++        with MIPS InterAptiv cores, like Siflower SF19A2890.
++
+ config SNI_RM
+       bool "SNI RM200/300/400"
+       select ARC_MEMORY
+--- a/arch/mips/generic/Platform
++++ b/arch/mips/generic/Platform
+@@ -10,6 +10,7 @@
+ # Note: order matters, keep the asm/mach-generic include last.
+ cflags-$(CONFIG_MACH_INGENIC_SOC)     += -I$(srctree)/arch/mips/include/asm/mach-ingenic
++cflags-$(CONFIG_MACH_SIFLOWER_MIPS)   += -I$(srctree)/arch/mips/include/asm/mach-siflower
+ cflags-$(CONFIG_MIPS_GENERIC) += -I$(srctree)/arch/mips/include/asm/mach-generic
+ load-$(CONFIG_MIPS_GENERIC)   += 0xffffffff80100000
diff --git a/target/linux/siflower/patches-6.6/005-clk-add-drivers-for-siflower-socs.patch b/target/linux/siflower/patches-6.6/005-clk-add-drivers-for-siflower-socs.patch
new file mode 100644 (file)
index 0000000..53539d9
--- /dev/null
@@ -0,0 +1,30 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:33:01 +0800
+Subject: [PATCH 05/20] clk: add drivers for siflower socs
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/clk/Kconfig  | 1 +
+ drivers/clk/Makefile | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/clk/Kconfig
++++ b/drivers/clk/Kconfig
+@@ -489,6 +489,7 @@ source "drivers/clk/renesas/Kconfig"
+ source "drivers/clk/rockchip/Kconfig"
+ source "drivers/clk/samsung/Kconfig"
+ source "drivers/clk/sifive/Kconfig"
++source "drivers/clk/siflower/Kconfig"
+ source "drivers/clk/socfpga/Kconfig"
+ source "drivers/clk/sprd/Kconfig"
+ source "drivers/clk/starfive/Kconfig"
+--- a/drivers/clk/Makefile
++++ b/drivers/clk/Makefile
+@@ -116,6 +116,7 @@ obj-y                                      += renesas/
+ obj-$(CONFIG_ARCH_ROCKCHIP)           += rockchip/
+ obj-$(CONFIG_COMMON_CLK_SAMSUNG)      += samsung/
+ obj-$(CONFIG_CLK_SIFIVE)              += sifive/
++obj-$(CONFIG_CLK_SIFLOWER)            += siflower/
+ obj-y                                 += socfpga/
+ obj-$(CONFIG_PLAT_SPEAR)              += spear/
+ obj-y                                 += sprd/
diff --git a/target/linux/siflower/patches-6.6/005-pinctrl-add-driver-for-siflower-sf19a2890.patch b/target/linux/siflower/patches-6.6/005-pinctrl-add-driver-for-siflower-sf19a2890.patch
deleted file mode 100644 (file)
index e902647..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-From 59c6a4972b584d986f72fe8d7c55930fdf799bc8 Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:34:20 +0800
-Subject: [PATCH 5/9] pinctrl: add driver for siflower sf19a2890
-
----
- drivers/pinctrl/Kconfig  | 10 ++++++++++
- drivers/pinctrl/Makefile |  1 +
- 2 files changed, 11 insertions(+)
-
---- a/drivers/pinctrl/Kconfig
-+++ b/drivers/pinctrl/Kconfig
-@@ -417,6 +417,16 @@ config PINCTRL_ROCKCHIP
-       help
-           This support pinctrl and GPIO driver for Rockchip SoCs.
-+config PINCTRL_SF19A2890
-+      tristate "Siflower SF19A2890 pinctrl driver"
-+      depends on OF && (MACH_SIFLOWER_MIPS || COMPILE_TEST)
-+      select PINMUX
-+      select PINCONF
-+      select GENERIC_PINCONF
-+      default MACH_SIFLOWER_MIPS
-+      help
-+         Say Y here to enable the Siflower SF19A2890 pinctrl driver.
-+
- config PINCTRL_SINGLE
-       tristate "One-register-per-pin type device tree based pinctrl driver"
-       depends on OF
---- a/drivers/pinctrl/Makefile
-+++ b/drivers/pinctrl/Makefile
-@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_PIC32)  += pinctrl-p
- obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
- obj-$(CONFIG_PINCTRL_RK805)   += pinctrl-rk805.o
- obj-$(CONFIG_PINCTRL_ROCKCHIP)        += pinctrl-rockchip.o
-+obj-$(CONFIG_PINCTRL_SF19A2890)       += pinctrl-sf19a2890.o
- obj-$(CONFIG_PINCTRL_SINGLE)  += pinctrl-single.o
- obj-$(CONFIG_PINCTRL_ST)      += pinctrl-st.o
- obj-$(CONFIG_PINCTRL_STMFX)   += pinctrl-stmfx.o
diff --git a/target/linux/siflower/patches-6.6/006-reset-add-support-for-sf19a2890.patch b/target/linux/siflower/patches-6.6/006-reset-add-support-for-sf19a2890.patch
new file mode 100644 (file)
index 0000000..2701478
--- /dev/null
@@ -0,0 +1,37 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:33:43 +0800
+Subject: [PATCH 06/20] reset: add support for sf19a2890
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/reset/Kconfig  | 8 ++++++++
+ drivers/reset/Makefile | 1 +
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/reset/Kconfig
++++ b/drivers/reset/Kconfig
+@@ -211,6 +211,14 @@ config RESET_SCMI
+         This driver uses SCMI Message Protocol to interact with the
+         firmware controlling all the reset signals.
++config RESET_SF19A2890_PERIPH
++      bool "Siflower SF19A2890 Peripheral Reset Controller Driver"
++      default MACH_SIFLOWER_MIPS
++      depends on HAS_IOMEM
++      help
++        This enables reset controller driver for peripheral reset blocks
++        found on Siflower SF19A2890 SoC.
++
+ config RESET_SIMPLE
+       bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
+       default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
+--- a/drivers/reset/Makefile
++++ b/drivers/reset/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qc
+ obj-$(CONFIG_RESET_RASPBERRYPI) += reset-raspberrypi.o
+ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
+ obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
++obj-$(CONFIG_RESET_SF19A2890_PERIPH) += reset-sf19a2890-periph.o
+ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
+ obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+ obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
diff --git a/target/linux/siflower/patches-6.6/006-stmmac-add-support-for-sf19a2890.patch b/target/linux/siflower/patches-6.6/006-stmmac-add-support-for-sf19a2890.patch
deleted file mode 100644 (file)
index b65cd3e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-From baa6c00f7a88b28f6838a9743f66c9f7f4716e25 Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 20 Aug 2024 08:34:42 +0800
-Subject: [PATCH 6/9] stmmac: add support for sf19a2890
-
----
- drivers/net/ethernet/stmicro/stmmac/Kconfig  | 9 +++++++++
- drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
- 2 files changed, 10 insertions(+)
-
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -142,6 +142,15 @@ config DWMAC_ROCKCHIP
-         This selects the Rockchip RK3288 SoC glue layer support for
-         the stmmac device driver.
-+config DWMAC_SF19A2890
-+      tristate "Siflower SF19A2890 GMAC support"
-+      default MACH_SIFLOWER_MIPS
-+      help
-+        Support for GMAC on Siflower SF19A2890 SoC.
-+
-+        This selects the Siflower SF19A2890 SoC glue layer support for
-+        the stmmac device driver.
-+
- config DWMAC_SOCFPGA
-       tristate "SOCFPGA dwmac support"
-       default ARCH_INTEL_SOCFPGA
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -21,6 +21,7 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-me
- obj-$(CONFIG_DWMAC_MESON)     += dwmac-meson.o dwmac-meson8b.o
- obj-$(CONFIG_DWMAC_QCOM_ETHQOS)       += dwmac-qcom-ethqos.o
- obj-$(CONFIG_DWMAC_ROCKCHIP)  += dwmac-rk.o
-+obj-$(CONFIG_DWMAC_SF19A2890) += dwmac-sf19a2890.o
- obj-$(CONFIG_DWMAC_SOCFPGA)   += dwmac-altr-socfpga.o
- obj-$(CONFIG_DWMAC_STARFIVE)  += dwmac-starfive.o
- obj-$(CONFIG_DWMAC_STI)               += dwmac-sti.o
diff --git a/target/linux/siflower/patches-6.6/007-gpio-add-support-for-siflower-socs.patch b/target/linux/siflower/patches-6.6/007-gpio-add-support-for-siflower-socs.patch
new file mode 100644 (file)
index 0000000..4d0b287
--- /dev/null
@@ -0,0 +1,42 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:33:57 +0800
+Subject: [PATCH 07/20] gpio: add support for siflower socs
+
+Add support for the GPIO controller on Siflower SoCs.
+This controller is found on Siflower SF19A2890 (MIPS) and SF21A6826
+(RISC-V)
+
+Signed-off-by: Qingfang Deng <qingfang.deng@siflower.com.cn>
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/gpio/Kconfig  | 8 ++++++++
+ drivers/gpio/Makefile | 1 +
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -576,6 +576,14 @@ config GPIO_SIFIVE
+       help
+         Say yes here to support the GPIO device on SiFive SoCs.
++config GPIO_SIFLOWER
++      tristate "SiFlower GPIO support"
++      depends on OF_GPIO
++      depends on MACH_SIFLOWER_MIPS || RISCV || COMPILE_TEST
++      select GPIOLIB_IRQCHIP
++      help
++        GPIO controller driver for SiFlower SoCs.
++
+ config GPIO_SIOX
+       tristate "SIOX GPIO support"
+       depends on SIOX
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -143,6 +143,7 @@ obj-$(CONFIG_GPIO_SAMA5D2_PIOBU)   += gpio
+ obj-$(CONFIG_GPIO_SCH311X)            += gpio-sch311x.o
+ obj-$(CONFIG_GPIO_SCH)                        += gpio-sch.o
+ obj-$(CONFIG_GPIO_SIFIVE)             += gpio-sifive.o
++obj-$(CONFIG_GPIO_SIFLOWER)           += gpio-siflower.o
+ obj-$(CONFIG_GPIO_SIM)                        += gpio-sim.o
+ obj-$(CONFIG_GPIO_SIOX)                       += gpio-siox.o
+ obj-$(CONFIG_GPIO_SL28CPLD)           += gpio-sl28cpld.o
diff --git a/target/linux/siflower/patches-6.6/007-phy-add-support-for-SF19A2890-USB-PHY.patch b/target/linux/siflower/patches-6.6/007-phy-add-support-for-SF19A2890-USB-PHY.patch
deleted file mode 100644 (file)
index 97b7126..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-From 68817a14ae9dff587cee8515e68c67cba89b39ab Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Mon, 9 Sep 2024 10:18:33 +0800
-Subject: [PATCH 7/9] phy: add support for SF19A2890 USB PHY
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- drivers/phy/Kconfig  | 1 +
- drivers/phy/Makefile | 1 +
- 2 files changed, 2 insertions(+)
-
---- a/drivers/phy/Kconfig
-+++ b/drivers/phy/Kconfig
-@@ -90,6 +90,7 @@ source "drivers/phy/ralink/Kconfig"
- source "drivers/phy/renesas/Kconfig"
- source "drivers/phy/rockchip/Kconfig"
- source "drivers/phy/samsung/Kconfig"
-+source "drivers/phy/siflower/Kconfig"
- source "drivers/phy/socionext/Kconfig"
- source "drivers/phy/st/Kconfig"
- source "drivers/phy/starfive/Kconfig"
---- a/drivers/phy/Makefile
-+++ b/drivers/phy/Makefile
-@@ -29,6 +29,7 @@ obj-y                                        += allwinner/   \
-                                          renesas/     \
-                                          rockchip/    \
-                                          samsung/     \
-+                                         siflower/    \
-                                          socionext/   \
-                                          st/          \
-                                          starfive/    \
diff --git a/target/linux/siflower/patches-6.6/008-pinctrl-add-driver-for-siflower-sf19a2890.patch b/target/linux/siflower/patches-6.6/008-pinctrl-add-driver-for-siflower-sf19a2890.patch
new file mode 100644 (file)
index 0000000..7475602
--- /dev/null
@@ -0,0 +1,38 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:34:20 +0800
+Subject: [PATCH 08/20] pinctrl: add driver for siflower sf19a2890
+
+---
+ drivers/pinctrl/Kconfig  | 10 ++++++++++
+ drivers/pinctrl/Makefile |  1 +
+ 2 files changed, 11 insertions(+)
+
+--- a/drivers/pinctrl/Kconfig
++++ b/drivers/pinctrl/Kconfig
+@@ -417,6 +417,16 @@ config PINCTRL_ROCKCHIP
+       help
+           This support pinctrl and GPIO driver for Rockchip SoCs.
++config PINCTRL_SF19A2890
++      tristate "Siflower SF19A2890 pinctrl driver"
++      depends on OF && (MACH_SIFLOWER_MIPS || COMPILE_TEST)
++      select PINMUX
++      select PINCONF
++      select GENERIC_PINCONF
++      default MACH_SIFLOWER_MIPS
++      help
++         Say Y here to enable the Siflower SF19A2890 pinctrl driver.
++
+ config PINCTRL_SINGLE
+       tristate "One-register-per-pin type device tree based pinctrl driver"
+       depends on OF
+--- a/drivers/pinctrl/Makefile
++++ b/drivers/pinctrl/Makefile
+@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_PIC32)  += pinctrl-p
+ obj-$(CONFIG_PINCTRL_PISTACHIO)       += pinctrl-pistachio.o
+ obj-$(CONFIG_PINCTRL_RK805)   += pinctrl-rk805.o
+ obj-$(CONFIG_PINCTRL_ROCKCHIP)        += pinctrl-rockchip.o
++obj-$(CONFIG_PINCTRL_SF19A2890)       += pinctrl-sf19a2890.o
+ obj-$(CONFIG_PINCTRL_SINGLE)  += pinctrl-single.o
+ obj-$(CONFIG_PINCTRL_ST)      += pinctrl-st.o
+ obj-$(CONFIG_PINCTRL_STMFX)   += pinctrl-stmfx.o
diff --git a/target/linux/siflower/patches-6.6/008-usb-dwc2-add-support-for-Siflower-SF19A2890.patch b/target/linux/siflower/patches-6.6/008-usb-dwc2-add-support-for-Siflower-SF19A2890.patch
deleted file mode 100644 (file)
index b551e4f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-From 29282086f215ae723e6d2c139d23094e699ba5bb Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Mon, 9 Sep 2024 16:46:53 +0800
-Subject: [PATCH 8/9] usb: dwc2: add support for Siflower SF19A2890
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- drivers/usb/dwc2/params.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/usb/dwc2/params.c
-+++ b/drivers/usb/dwc2/params.c
-@@ -200,6 +200,14 @@ static void dwc2_set_amcc_params(struct
-       p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
- }
-+static void dwc2_set_sf19a2890_params(struct dwc2_hsotg *hsotg)
-+{
-+      struct dwc2_core_params *p = &hsotg->params;
-+
-+      p->max_transfer_size = 65535;
-+      p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
-+}
-+
- static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
- {
-       struct dwc2_core_params *p = &hsotg->params;
-@@ -294,6 +302,8 @@ const struct of_device_id dwc2_of_match_
-         .data = dwc2_set_amlogic_a1_params },
-       { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
-       { .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
-+      { .compatible = "siflower,sf19a2890-usb",
-+        .data = dwc2_set_sf19a2890_params },
-       { .compatible = "st,stm32f4x9-fsotg",
-         .data = dwc2_set_stm32f4x9_fsotg_params },
-       { .compatible = "st,stm32f4x9-hsotg" },
diff --git a/target/linux/siflower/patches-6.6/009-stmmac-add-support-for-sf19a2890.patch b/target/linux/siflower/patches-6.6/009-stmmac-add-support-for-sf19a2890.patch
new file mode 100644 (file)
index 0000000..85d17be
--- /dev/null
@@ -0,0 +1,37 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 20 Aug 2024 08:34:42 +0800
+Subject: [PATCH 09/20] stmmac: add support for sf19a2890
+
+---
+ drivers/net/ethernet/stmicro/stmmac/Kconfig  | 9 +++++++++
+ drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -142,6 +142,15 @@ config DWMAC_ROCKCHIP
+         This selects the Rockchip RK3288 SoC glue layer support for
+         the stmmac device driver.
++config DWMAC_SF19A2890
++      tristate "Siflower SF19A2890 GMAC support"
++      default MACH_SIFLOWER_MIPS
++      help
++        Support for GMAC on Siflower SF19A2890 SoC.
++
++        This selects the Siflower SF19A2890 SoC glue layer support for
++        the stmmac device driver.
++
+ config DWMAC_SOCFPGA
+       tristate "SOCFPGA dwmac support"
+       default ARCH_INTEL_SOCFPGA
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-me
+ obj-$(CONFIG_DWMAC_MESON)     += dwmac-meson.o dwmac-meson8b.o
+ obj-$(CONFIG_DWMAC_QCOM_ETHQOS)       += dwmac-qcom-ethqos.o
+ obj-$(CONFIG_DWMAC_ROCKCHIP)  += dwmac-rk.o
++obj-$(CONFIG_DWMAC_SF19A2890) += dwmac-sf19a2890.o
+ obj-$(CONFIG_DWMAC_SOCFPGA)   += dwmac-altr-socfpga.o
+ obj-$(CONFIG_DWMAC_STARFIVE)  += dwmac-starfive.o
+ obj-$(CONFIG_DWMAC_STI)               += dwmac-sti.o
diff --git a/target/linux/siflower/patches-6.6/009-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch b/target/linux/siflower/patches-6.6/009-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch
deleted file mode 100644 (file)
index 03fb168..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-From 0b04c37a1aae523025195c29a6477cf26234d26c Mon Sep 17 00:00:00 2001
-From: Chuanhong Guo <gch981213@gmail.com>
-Date: Tue, 10 Sep 2024 09:10:27 +0800
-Subject: [PATCH 9/9] usb: dwc2: handle OTG interrupt regardless of GINTSTS
-
-The DWC OTG 3.30a found on Siflower SF19A2890 has battery charger
-support enabled. It triggers MultVallpChng interrupt (bit 20 of
-GOTGINT) but doesn't set OTGInt in GINTSTS. As a result, this
-interrupt is never handled, and linux disables USB interrupt
-because "nobody cares".
-
-Handle OTG interrupt in IRQ handler regardless of whether the
-OTGInt bit in GINTSTS is set or not.
-
-Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
----
- drivers/usb/dwc2/core_intr.c | 11 ++++++++---
- 1 file changed, 8 insertions(+), 3 deletions(-)
-
---- a/drivers/usb/dwc2/core_intr.c
-+++ b/drivers/usb/dwc2/core_intr.c
-@@ -79,7 +79,7 @@ static void dwc2_handle_mode_mismatch_in
-  *
-  * @hsotg: Programming view of DWC_otg controller
-  */
--static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
-+static irqreturn_t dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
- {
-       u32 gotgint;
-       u32 gotgctl;
-@@ -87,6 +87,10 @@ static void dwc2_handle_otg_intr(struct
-       gotgint = dwc2_readl(hsotg, GOTGINT);
-       gotgctl = dwc2_readl(hsotg, GOTGCTL);
-+
-+      if (!gotgint)
-+              return IRQ_NONE;
-+
-       dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
-               dwc2_op_state_str(hsotg));
-@@ -229,6 +233,7 @@ static void dwc2_handle_otg_intr(struct
-       /* Clear GOTGINT */
-       dwc2_writel(hsotg, gotgint, GOTGINT);
-+      return IRQ_HANDLED;
- }
- /**
-@@ -842,6 +847,8 @@ irqreturn_t dwc2_handle_common_intr(int
-               hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
-                                      & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
-+      retval = dwc2_handle_otg_intr(hsotg);
-+
-       gintsts = dwc2_read_common_intr(hsotg);
-       if (gintsts & ~GINTSTS_PRTINT)
-               retval = IRQ_HANDLED;
-@@ -855,8 +862,6 @@ irqreturn_t dwc2_handle_common_intr(int
-       if (gintsts & GINTSTS_MODEMIS)
-               dwc2_handle_mode_mismatch_intr(hsotg);
--      if (gintsts & GINTSTS_OTGINT)
--              dwc2_handle_otg_intr(hsotg);
-       if (gintsts & GINTSTS_CONIDSTSCHNG)
-               dwc2_handle_conn_id_status_change_intr(hsotg);
-       if (gintsts & GINTSTS_DISCONNINT)
diff --git a/target/linux/siflower/patches-6.6/010-phy-add-support-for-Siflower-USB-PHYs.patch b/target/linux/siflower/patches-6.6/010-phy-add-support-for-Siflower-USB-PHYs.patch
new file mode 100644 (file)
index 0000000..dc30ace
--- /dev/null
@@ -0,0 +1,30 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Mon, 9 Sep 2024 10:18:33 +0800
+Subject: [PATCH 10/20] phy: add support for Siflower USB PHYs
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/phy/Kconfig  | 1 +
+ drivers/phy/Makefile | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -90,6 +90,7 @@ source "drivers/phy/ralink/Kconfig"
+ source "drivers/phy/renesas/Kconfig"
+ source "drivers/phy/rockchip/Kconfig"
+ source "drivers/phy/samsung/Kconfig"
++source "drivers/phy/siflower/Kconfig"
+ source "drivers/phy/socionext/Kconfig"
+ source "drivers/phy/st/Kconfig"
+ source "drivers/phy/starfive/Kconfig"
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -29,6 +29,7 @@ obj-y                                        += allwinner/   \
+                                          renesas/     \
+                                          rockchip/    \
+                                          samsung/     \
++                                         siflower/    \
+                                          socionext/   \
+                                          st/          \
+                                          starfive/    \
diff --git a/target/linux/siflower/patches-6.6/011-usb-dwc2-add-support-for-Siflower-SF19A2890.patch b/target/linux/siflower/patches-6.6/011-usb-dwc2-add-support-for-Siflower-SF19A2890.patch
new file mode 100644 (file)
index 0000000..6d9d5c8
--- /dev/null
@@ -0,0 +1,35 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Mon, 9 Sep 2024 16:46:53 +0800
+Subject: [PATCH 11/20] usb: dwc2: add support for Siflower SF19A2890
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/usb/dwc2/params.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+--- a/drivers/usb/dwc2/params.c
++++ b/drivers/usb/dwc2/params.c
+@@ -200,6 +200,14 @@ static void dwc2_set_amcc_params(struct
+       p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
+ }
++static void dwc2_set_sf19a2890_params(struct dwc2_hsotg *hsotg)
++{
++      struct dwc2_core_params *p = &hsotg->params;
++
++      p->max_transfer_size = 65535;
++      p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT;
++}
++
+ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
+ {
+       struct dwc2_core_params *p = &hsotg->params;
+@@ -294,6 +302,8 @@ const struct of_device_id dwc2_of_match_
+         .data = dwc2_set_amlogic_a1_params },
+       { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
+       { .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
++      { .compatible = "siflower,sf19a2890-usb",
++        .data = dwc2_set_sf19a2890_params },
+       { .compatible = "st,stm32f4x9-fsotg",
+         .data = dwc2_set_stm32f4x9_fsotg_params },
+       { .compatible = "st,stm32f4x9-hsotg" },
diff --git a/target/linux/siflower/patches-6.6/012-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch b/target/linux/siflower/patches-6.6/012-usb-dwc2-handle-OTG-interrupt-regardless-of-GINTSTS.patch
new file mode 100644 (file)
index 0000000..eafd3ba
--- /dev/null
@@ -0,0 +1,66 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Tue, 10 Sep 2024 09:10:27 +0800
+Subject: [PATCH 12/20] usb: dwc2: handle OTG interrupt regardless of GINTSTS
+
+The DWC OTG 3.30a found on Siflower SF19A2890 has battery charger
+support enabled. It triggers MultVallpChng interrupt (bit 20 of
+GOTGINT) but doesn't set OTGInt in GINTSTS. As a result, this
+interrupt is never handled, and linux disables USB interrupt
+because "nobody cares".
+
+Handle OTG interrupt in IRQ handler regardless of whether the
+OTGInt bit in GINTSTS is set or not.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/usb/dwc2/core_intr.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/dwc2/core_intr.c
++++ b/drivers/usb/dwc2/core_intr.c
+@@ -79,7 +79,7 @@ static void dwc2_handle_mode_mismatch_in
+  *
+  * @hsotg: Programming view of DWC_otg controller
+  */
+-static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
++static irqreturn_t dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
+ {
+       u32 gotgint;
+       u32 gotgctl;
+@@ -87,6 +87,10 @@ static void dwc2_handle_otg_intr(struct
+       gotgint = dwc2_readl(hsotg, GOTGINT);
+       gotgctl = dwc2_readl(hsotg, GOTGCTL);
++
++      if (!gotgint)
++              return IRQ_NONE;
++
+       dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
+               dwc2_op_state_str(hsotg));
+@@ -229,6 +233,7 @@ static void dwc2_handle_otg_intr(struct
+       /* Clear GOTGINT */
+       dwc2_writel(hsotg, gotgint, GOTGINT);
++      return IRQ_HANDLED;
+ }
+ /**
+@@ -842,6 +847,8 @@ irqreturn_t dwc2_handle_common_intr(int
+               hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
+                                      & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
++      retval = dwc2_handle_otg_intr(hsotg);
++
+       gintsts = dwc2_read_common_intr(hsotg);
+       if (gintsts & ~GINTSTS_PRTINT)
+               retval = IRQ_HANDLED;
+@@ -855,8 +862,6 @@ irqreturn_t dwc2_handle_common_intr(int
+       if (gintsts & GINTSTS_MODEMIS)
+               dwc2_handle_mode_mismatch_intr(hsotg);
+-      if (gintsts & GINTSTS_OTGINT)
+-              dwc2_handle_otg_intr(hsotg);
+       if (gintsts & GINTSTS_CONIDSTSCHNG)
+               dwc2_handle_conn_id_status_change_intr(hsotg);
+       if (gintsts & GINTSTS_DISCONNINT)
diff --git a/target/linux/siflower/patches-6.6/013-riscv-add-Siflower-RISC-V-SoC-family-Kconfig-support.patch b/target/linux/siflower/patches-6.6/013-riscv-add-Siflower-RISC-V-SoC-family-Kconfig-support.patch
new file mode 100644 (file)
index 0000000..7e99db1
--- /dev/null
@@ -0,0 +1,31 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Sat, 14 Sep 2024 11:57:35 +0800
+Subject: [PATCH 13/20] riscv: add Siflower RISC-V SoC family Kconfig support
+
+Siflower RISC-V SoCs, including SF21A6826, SF21H8898 and some other
+upcomping chips, are RISC-V chips with T-Head C908 cores for home
+routers and gateways. Add a Kconfig entry named ARCH_SIFLOWER for
+them.
+Notably these chips uses ARM PL011 for UART. ARM_AMBA is selected
+for its driver.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/riscv/Kconfig.socs | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/riscv/Kconfig.socs
++++ b/arch/riscv/Kconfig.socs
+@@ -22,6 +22,12 @@ config SOC_SIFIVE
+       help
+         This enables support for SiFive SoC platform hardware.
++config ARCH_SIFLOWER
++      bool "Siflower RISC-V SoCs"
++      select ARM_AMBA if TTY
++      help
++        This enables support for Siflower RISC-V SoC platform hardware.
++
+ config ARCH_STARFIVE
+       def_bool SOC_STARFIVE
diff --git a/target/linux/siflower/patches-6.6/014-riscv-add-an-option-for-efficient-unaligned-access.patch b/target/linux/siflower/patches-6.6/014-riscv-add-an-option-for-efficient-unaligned-access.patch
new file mode 100644 (file)
index 0000000..df11d02
--- /dev/null
@@ -0,0 +1,46 @@
+From: Qingfang Deng <qingfang.deng@siflower.com.cn>
+Date: Sat, 14 Sep 2024 12:00:59 +0800
+Subject: [PATCH 14/20] riscv: add an option for efficient unaligned access
+
+Some riscv cpus like T-Head C908 allows unaligned memory access,
+and we don't need to force an alignment on compiler level.
+Add an option for that.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ arch/riscv/Kconfig  | 11 +++++++++++
+ arch/riscv/Makefile |  2 ++
+ 2 files changed, 13 insertions(+)
+
+--- a/arch/riscv/Kconfig
++++ b/arch/riscv/Kconfig
+@@ -639,6 +639,17 @@ config THREAD_SIZE_ORDER
+         Specify the Pages of thread stack size (from 4KB to 64KB), which also
+         affects irq stack size, which is equal to thread stack size.
++config RISCV_EFFICIENT_UNALIGNED_ACCESS
++      bool "Assume the system supports fast unaligned memory accesses"
++      depends on NONPORTABLE
++      select HAVE_EFFICIENT_UNALIGNED_ACCESS
++      help
++        Assume that the system supports fast unaligned memory accesses. When
++        enabled, this option improves the performance of the kernel on such
++        systems. However, the kernel and userspace programs will run much more
++        slowly, or will not be able to run at all, on systems that do not
++        support efficient unaligned memory accesses.
++
+ endmenu # "Platform type"
+ menu "Kernel features"
+--- a/arch/riscv/Makefile
++++ b/arch/riscv/Makefile
+@@ -104,7 +104,9 @@ KBUILD_AFLAGS_MODULE += $(call as-option
+ # unaligned accesses.  While unaligned accesses are explicitly allowed in the
+ # RISC-V ISA, they're emulated by machine mode traps on all extant
+ # architectures.  It's faster to have GCC emit only aligned accesses.
++ifneq ($(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS),y)
+ KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
++endif
+ ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
+ prepare: stack_protector_prepare
diff --git a/target/linux/siflower/patches-6.6/015-reset-add-support-for-sf21a6826-sf21h8898.patch b/target/linux/siflower/patches-6.6/015-reset-add-support-for-sf21a6826-sf21h8898.patch
new file mode 100644 (file)
index 0000000..060180f
--- /dev/null
@@ -0,0 +1,33 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Sat, 14 Sep 2024 16:51:36 +0800
+Subject: [PATCH 15/20] reset: add support for sf21a6826/sf21h8898
+
+---
+ drivers/reset/Kconfig  | 5 +++++
+ drivers/reset/Makefile | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/reset/Kconfig
++++ b/drivers/reset/Kconfig
+@@ -219,6 +219,11 @@ config RESET_SF19A2890_PERIPH
+         This enables reset controller driver for peripheral reset blocks
+         found on Siflower SF19A2890 SoC.
++config RESET_SF21
++      tristate "Siflower SF21A6826/SF21H8898 Reset Controller Driver"
++      help
++        This enables the reset controller driver for Siflower SF21A6826/SF21H8898.
++
+ config RESET_SIMPLE
+       bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT
+       default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC
+--- a/drivers/reset/Makefile
++++ b/drivers/reset/Makefile
+@@ -30,6 +30,7 @@ obj-$(CONFIG_RESET_RASPBERRYPI) += reset
+ obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o
+ obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
+ obj-$(CONFIG_RESET_SF19A2890_PERIPH) += reset-sf19a2890-periph.o
++obj-$(CONFIG_RESET_SF21) += reset-sf21.o
+ obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
+ obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
+ obj-$(CONFIG_RESET_SUNPLUS) += reset-sunplus.o
diff --git a/target/linux/siflower/patches-6.6/016-spi-spi-mem-allow-gpio-cs-in-spi_mem_exec_op.patch b/target/linux/siflower/patches-6.6/016-spi-spi-mem-allow-gpio-cs-in-spi_mem_exec_op.patch
new file mode 100644 (file)
index 0000000..6b71fad
--- /dev/null
@@ -0,0 +1,41 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Thu, 19 Sep 2024 09:23:27 +0800
+Subject: [PATCH 16/20] spi: spi-mem: allow gpio cs in spi_mem_exec_op
+
+spi_mem_exec_op can use gpio cs, either by not asserting the native
+cs or switching the native cs pin to GPIO mode with pinctrl.
+
+Allow calling exec_op when GPIO CS present and control GPIO CS
+before and after calling exec_op.
+If exec_op decided to return -EOPNOTSUPP, the code will assert and
+deassert GPIO CS without clock pulsing, which should be fine on most
+SPI slaves.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/spi/spi-mem.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/spi/spi-mem.c
++++ b/drivers/spi/spi-mem.c
+@@ -325,13 +325,19 @@ int spi_mem_exec_op(struct spi_mem *mem,
+       if (!spi_mem_internal_supports_op(mem, op))
+               return -ENOTSUPP;
+-      if (ctlr->mem_ops && ctlr->mem_ops->exec_op && !spi_get_csgpiod(mem->spi, 0)) {
++      if (ctlr->mem_ops && ctlr->mem_ops->exec_op) {
+               ret = spi_mem_access_start(mem);
+               if (ret)
+                       return ret;
++              if (spi_get_csgpiod(mem->spi, 0))
++                      gpiod_set_value_cansleep(spi_get_csgpiod(mem->spi, 0), 1);
++
+               ret = ctlr->mem_ops->exec_op(mem, op);
++              if (spi_get_csgpiod(mem->spi, 0))
++                      gpiod_set_value_cansleep(spi_get_csgpiod(mem->spi, 0), 0);
++
+               spi_mem_access_end(mem);
+               /*
diff --git a/target/linux/siflower/patches-6.6/017-spi-add-support-for-sf21-qspi.patch b/target/linux/siflower/patches-6.6/017-spi-add-support-for-sf21-qspi.patch
new file mode 100644 (file)
index 0000000..5337477
--- /dev/null
@@ -0,0 +1,46 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Thu, 19 Sep 2024 10:02:16 +0800
+Subject: [PATCH 17/20] spi: add support for sf21-qspi
+
+Add support for the QSPI controller found on Siflower SF21A6826
+and SF21H8898.
+It is based on ARM PL022, with custom modifications to support
+Dual/Quad SPI modes.
+A new driver is created because this modified controller is
+supported under the SPI-MEM framework. While the setup procedure
+is a bit similar to the spi-pl022.c, there aren't much code
+shared between them.
+
+Signed-off-by: Qingfang Deng <qingfang.deng@siflower.com.cn>
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/spi/Kconfig  | 7 +++++++
+ drivers/spi/Makefile | 1 +
+ 2 files changed, 8 insertions(+)
+
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -940,6 +940,13 @@ config SPI_SIFIVE
+       help
+         This exposes the SPI controller IP from SiFive.
++config SPI_SF21_QSPI
++      tristate "Siflower SF21A6826/SF21H8898 QSPI controller"
++      depends on ARCH_SIFLOWER || COMPILE_TEST
++      help
++        This enables support for the SPI controller present on the
++        Siflower SF21A6826/SF21H8898 SoCs.
++
+ config SPI_SLAVE_MT27XX
+       tristate "MediaTek SPI slave device"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -125,6 +125,7 @@ obj-$(CONFIG_SPI_SH_HSPI)          += spi-sh-hsp
+ obj-$(CONFIG_SPI_SH_MSIOF)            += spi-sh-msiof.o
+ obj-$(CONFIG_SPI_SH_SCI)              += spi-sh-sci.o
+ obj-$(CONFIG_SPI_SIFIVE)              += spi-sifive.o
++obj-$(CONFIG_SPI_SF21_QSPI)           += spi-sf21-qspi.o
+ obj-$(CONFIG_SPI_SLAVE_MT27XX)          += spi-slave-mt27xx.o
+ obj-$(CONFIG_SPI_SN_F_OSPI)           += spi-sn-f-ospi.o
+ obj-$(CONFIG_SPI_SPRD)                        += spi-sprd.o
diff --git a/target/linux/siflower/patches-6.6/018-pci-dw-pcie-add-support-for-sf21-pcie.patch b/target/linux/siflower/patches-6.6/018-pci-dw-pcie-add-support-for-sf21-pcie.patch
new file mode 100644 (file)
index 0000000..dea74da
--- /dev/null
@@ -0,0 +1,41 @@
+From: Chuanhong Guo <gch981213@gmail.com>
+Date: Fri, 29 Nov 2024 16:34:49 +0800
+Subject: [PATCH 18/20] pci: dw-pcie add support for sf21 pcie
+
+Add support for the PCIE controller found on Siflower SF21A6826
+and SF21H8898.
+
+Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
+---
+ drivers/pci/controller/dwc/Kconfig  | 9 +++++++++
+ drivers/pci/controller/dwc/Makefile | 1 +
+ 2 files changed, 10 insertions(+)
+
+--- a/drivers/pci/controller/dwc/Kconfig
++++ b/drivers/pci/controller/dwc/Kconfig
+@@ -317,6 +317,15 @@ config PCIE_FU740
+         Say Y here if you want PCIe controller support for the SiFive
+         FU740.
++config PCIE_SF21
++      bool "Siflower SF21A6826/SF21H8898 PCIe controller"
++      depends on ARCH_SIFLOWER || COMPILE_TEST
++      depends on PCI_MSI
++      select PCIE_DW_HOST
++      help
++        Say Y here to enable support of the Siflower SF21A6826/SF21H8898
++        PCIe controller.
++
+ config PCIE_UNIPHIER
+       bool "Socionext UniPhier PCIe controller (host mode)"
+       depends on ARCH_UNIPHIER || COMPILE_TEST
+--- a/drivers/pci/controller/dwc/Makefile
++++ b/drivers/pci/controller/dwc/Makefile
+@@ -22,6 +22,7 @@ obj-$(CONFIG_PCIE_KEEMBAY) += pcie-keemb
+ obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
+ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
+ obj-$(CONFIG_PCI_MESON) += pci-meson.o
++obj-$(CONFIG_PCIE_SF21) += pcie-sf21.o
+ obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
+ obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
+ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
diff --git a/target/linux/siflower/patches-6.6/019-net-phy-add-support-for-Siflower-SF23P1211-SF23P1240.patch b/target/linux/siflower/patches-6.6/019-net-phy-add-support-for-Siflower-SF23P1211-SF23P1240.patch
new file mode 100644 (file)
index 0000000..70c60ad
--- /dev/null
@@ -0,0 +1,30 @@
+From: "haoming.chen" <haoming.chen@siflower.com.cn>
+Date: Thu, 7 Nov 2024 20:18:59 +0800
+Subject: [PATCH 19/20] net: phy: add support for Siflower SF23P1211 &
+ SF23P1240
+
+Signed-off-by: haoming.chen <haoming.chen@siflower.com.cn>
+---
+ drivers/net/phy/Kconfig  | 5 +++++
+ drivers/net/phy/Makefile | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- a/drivers/net/phy/Kconfig
++++ b/drivers/net/phy/Kconfig
+@@ -482,3 +482,8 @@ endif # PHYLIB
+ config MICREL_KS8995MA
+       tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch"
+       depends on SPI
++
++config SIFLOWER_PHY
++      tristate "Siflower PHYs"
++      help
++        Currently supports the SF1211F, SF1240 gigabit PHY.
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -107,3 +107,4 @@ obj-$(CONFIG_STE10XP)              += ste10Xp.o
+ obj-$(CONFIG_TERANETICS_PHY)  += teranetics.o
+ obj-$(CONFIG_VITESSE_PHY)     += vitesse.o
+ obj-$(CONFIG_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
++obj-$(CONFIG_SIFLOWER_PHY)    += siflower.o
+\ No newline at end of file
diff --git a/target/linux/siflower/patches-6.6/020-net-ethernet-add-support-for-Siflower-DPNS.patch b/target/linux/siflower/patches-6.6/020-net-ethernet-add-support-for-Siflower-DPNS.patch
new file mode 100644 (file)
index 0000000..acbff1f
--- /dev/null
@@ -0,0 +1,27 @@
+From: "haoming.chen" <haoming.chen@siflower.com.cn>
+Date: Tue, 26 Nov 2024 16:38:13 +0800
+Subject: [PATCH 20/20] net: ethernet: add support for Siflower DPNS
+
+Change-Id: Ie8fc30e4714eaa666563b1a85e22d0eb8ee778b5
+Signed-off-by: haoming.chen <haoming.chen@siflower.com.cn>
+---
+ drivers/net/ethernet/Kconfig  | 1 +
+ drivers/net/ethernet/Makefile | 1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/net/ethernet/Kconfig
++++ b/drivers/net/ethernet/Kconfig
+@@ -192,5 +192,6 @@ source "drivers/net/ethernet/wangxun/Kco
+ source "drivers/net/ethernet/wiznet/Kconfig"
+ source "drivers/net/ethernet/xilinx/Kconfig"
+ source "drivers/net/ethernet/xircom/Kconfig"
++source "drivers/net/ethernet/siflower/Kconfig"
+ endif # ETHERNET
+--- a/drivers/net/ethernet/Makefile
++++ b/drivers/net/ethernet/Makefile
+@@ -104,3 +104,4 @@ obj-$(CONFIG_NET_VENDOR_XILINX) += xilin
+ obj-$(CONFIG_NET_VENDOR_XIRCOM) += xircom/
+ obj-$(CONFIG_NET_VENDOR_SYNOPSYS) += synopsys/
+ obj-$(CONFIG_NET_VENDOR_PENSANDO) += pensando/
++obj-$(CONFIG_NET_VENDOR_SIFLOWER) += siflower/
diff --git a/target/linux/siflower/sf21/base-files/etc/board.d/02_network b/target/linux/siflower/sf21/base-files/etc/board.d/02_network
new file mode 100644 (file)
index 0000000..572dba0
--- /dev/null
@@ -0,0 +1,22 @@
+
+. /lib/functions.sh
+. /lib/functions/uci-defaults.sh
+. /lib/functions/system.sh
+
+siflower_setup_interfaces()
+{
+       local board="$1"
+
+       case $board in
+       *)
+               ucidef_set_interfaces_lan_wan 'eth0 eth1 eth2' 'eth3'
+               ;;
+       esac
+}
+
+board_config_update
+board=$(board_name)
+siflower_setup_interfaces $board
+board_config_flush
+
+exit 0
diff --git a/target/linux/siflower/sf21/base-files/lib/upgrade/platform.sh b/target/linux/siflower/sf21/base-files/lib/upgrade/platform.sh
new file mode 100644 (file)
index 0000000..ab62c84
--- /dev/null
@@ -0,0 +1,33 @@
+REQUIRE_IMAGE_METADATA=1
+RAMFS_COPY_BIN='fitblk'
+
+platform_do_upgrade() {
+       local board=$(board_name)
+
+       case "$board" in
+       *)
+               default_do_upgrade "$1"
+               ;;
+       esac
+}
+
+PART_NAME=firmware
+
+platform_check_image() {
+       local board=$(board_name)
+       local magic="$(get_magic_long "$1")"
+
+       [ "$#" -gt 1 ] && return 1
+
+       case "$board" in
+       *)
+               [ "$magic" != "d00dfeed" ] && {
+                       echo "Invalid image type."
+                       return 1
+               }
+               return 0
+               ;;
+       esac
+
+       return 0
+}
diff --git a/target/linux/siflower/sf21/config-6.6 b/target/linux/siflower/sf21/config-6.6
new file mode 100644 (file)
index 0000000..b66f377
--- /dev/null
@@ -0,0 +1,287 @@
+CONFIG_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_DEFAULT_COHERENT=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MMAP_RND_BITS=18
+CONFIG_ARCH_MMAP_RND_BITS_MAX=24
+CONFIG_ARCH_MMAP_RND_BITS_MIN=18
+CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
+# CONFIG_ARCH_RV32I is not set
+CONFIG_ARCH_RV64I=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SIFLOWER=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_STACKWALK=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ARCH_THEAD is not set
+CONFIG_ARCH_WANTS_THP_SWAP=y
+CONFIG_ARM_AMBA=y
+# CONFIG_AX45MP_L2_CACHE is not set
+CONFIG_BLK_MQ_PCI=y
+CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y
+CONFIG_CLK_SF19A2890_PERIPH=y
+CONFIG_CLK_SF21_TOPCRM=y
+CONFIG_CLK_SIFLOWER=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="root=/dev/fit0"
+CONFIG_CMDLINE_FALLBACK=y
+CONFIG_CMODEL_MEDANY=y
+# CONFIG_CMODEL_MEDLOW is not set
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
+# CONFIG_COMPAT_32BIT_TIME is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONTEXT_TRACKING=y
+CONFIG_CONTEXT_TRACKING_IDLE=y
+CONFIG_CPU_MITIGATIONS=y
+CONFIG_CPU_RMAP=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_HASH_INFO=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
+CONFIG_CRYPTO_LIB_GF128MUL=y
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1
+CONFIG_CRYPTO_LIB_SHA1=y
+CONFIG_CRYPTO_LIB_UTILS=y
+# CONFIG_CRYPTO_PCRYPT is not set
+CONFIG_CRYPTO_ZSTD=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEVPORT is not set
+CONFIG_DMA_BOUNCE_UNALIGNED_KMALLOC=y
+CONFIG_DMA_DIRECT_REMAP=y
+CONFIG_DTC=y
+CONFIG_DW_WATCHDOG=y
+CONFIG_EDAC_SUPPORT=y
+# CONFIG_ERRATA_ANDES is not set
+# CONFIG_ERRATA_SIFIVE is not set
+# CONFIG_ERRATA_THEAD is not set
+CONFIG_EXCLUSIVE_SYSTEM_RAM=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FPU=y
+CONFIG_FS_IOMAP=y
+CONFIG_FUNCTION_ALIGNMENT=0
+CONFIG_FWNODE_MDIO=y
+CONFIG_FW_LOADER_PAGED_BUF=y
+CONFIG_FW_LOADER_SYSFS=y
+CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_ARCH_TOPOLOGY=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_EARLY_IOREMAP=y
+CONFIG_GENERIC_ENTRY=y
+CONFIG_GENERIC_GETTIMEOFDAY=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IOREMAP=y
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
+CONFIG_GENERIC_IRQ_IPI_MUX=y
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
+CONFIG_GENERIC_MSI_IRQ=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_PINCTRL_GROUPS=y
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_CDEV=y
+CONFIG_GPIO_SIFLOWER=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_STACKS=y
+CONFIG_IRQ_WORK=y
+CONFIG_JUMP_LABEL=y
+CONFIG_KCMP=y
+CONFIG_LED_TRIGGER_PHY=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_MARVELL_PHY=y
+CONFIG_MDIO_BUS=y
+CONFIG_MDIO_DEVICE=y
+CONFIG_MDIO_DEVRES=y
+CONFIG_MFD_SYSCON=y
+CONFIG_MIGRATION=y
+CONFIG_MMIOWB=y
+CONFIG_MMU_LAZY_TLB_REFCOUNT=y
+CONFIG_MODULES_USE_ELF_RELA=y
+CONFIG_MODULE_SECTIONS=y
+CONFIG_MOTORCOMM_PHY=y
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_NAND_CORE=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
+CONFIG_MTD_SPLIT_FIT_FW=y
+# CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+CONFIG_MTD_UBI_NVMEM=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_EGRESS=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_INGRESS=y
+CONFIG_NET_SELFTESTS=y
+CONFIG_NET_SIFLOWER_ETH_DMA=y
+CONFIG_NET_SIFLOWER_ETH_DPNS=y
+CONFIG_NET_SIFLOWER_ETH_USE_INTERNAL_SRAM=y
+CONFIG_NET_SIFLOWER_ETH_XGMAC=y
+CONFIG_NET_SIFLOWER_ETH_XPCS=y
+CONFIG_NET_SWITCHDEV=y
+CONFIG_NET_VENDOR_SIFLOWER=y
+CONFIG_NET_XGRESS=y
+CONFIG_NONPORTABLE=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_NVMEM=y
+CONFIG_NVMEM_LAYOUTS=y
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_KOBJ=y
+CONFIG_OF_MDIO=y
+CONFIG_PAGE_OFFSET=0xff60000000000000
+CONFIG_PAGE_POOL=y
+CONFIG_PAGE_POOL_STATS=y
+CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
+CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
+CONFIG_PCI=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIE_DW=y
+CONFIG_PCIE_DW_HOST=y
+CONFIG_PCIE_SF21=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PCI_MSI=y
+CONFIG_PER_VMA_LOCK=y
+CONFIG_PGTABLE_LEVELS=5
+CONFIG_PHYLIB=y
+CONFIG_PHYLIB_LEDS=y
+CONFIG_PHYLINK=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+# CONFIG_PHYS_RAM_BASE_FIXED is not set
+# CONFIG_PHY_SF19A2890_USB is not set
+CONFIG_PHY_SF21_PCIE=y
+# CONFIG_PHY_SF21_USB is not set
+CONFIG_PINCTRL=y
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PREEMPT_NONE_BUILD=y
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
+CONFIG_QUEUED_RWLOCKS=y
+CONFIG_RANDSTRUCT_NONE=y
+CONFIG_RAS=y
+CONFIG_RATIONAL=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_MMIO=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESET_SF19A2890_PERIPH=y
+CONFIG_RESET_SF21=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RISCV=y
+CONFIG_RISCV_ALTERNATIVE=y
+# CONFIG_RISCV_BOOT_SPINWAIT is not set
+CONFIG_RISCV_DMA_NONCOHERENT=y
+CONFIG_RISCV_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_RISCV_INTC=y
+CONFIG_RISCV_ISA_C=y
+# CONFIG_RISCV_ISA_FALLBACK is not set
+CONFIG_RISCV_ISA_SVNAPOT=y
+CONFIG_RISCV_ISA_SVPBMT=y
+# CONFIG_RISCV_ISA_V is not set
+CONFIG_RISCV_ISA_ZBB=y
+CONFIG_RISCV_ISA_ZICBOM=y
+CONFIG_RISCV_ISA_ZICBOZ=y
+CONFIG_RISCV_SBI=y
+# CONFIG_RISCV_SBI_V01 is not set
+CONFIG_RISCV_TIMER=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SGL_ALLOC=y
+CONFIG_SIFIVE_PLIC=y
+CONFIG_SIFLOWER_PHY=y
+CONFIG_SMP=y
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
+# CONFIG_SOC_MICROCHIP_POLARFIRE is not set
+# CONFIG_SOC_SIFIVE is not set
+# CONFIG_SOC_STARFIVE is not set
+# CONFIG_SOC_VIRT is not set
+CONFIG_SOFTIRQ_ON_OWN_STACK=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_MEM=y
+CONFIG_SPI_SF21_QSPI=y
+# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
+CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
+CONFIG_SQUASHFS_DECOMP_SINGLE=y
+CONFIG_SRAM=y
+CONFIG_SWIOTLB=y
+CONFIG_SWPHY=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_THREAD_INFO_IN_TASK=y
+CONFIG_THREAD_SIZE_ORDER=2
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TIMER_OF=y
+CONFIG_TIMER_PROBE=y
+CONFIG_TOOLCHAIN_HAS_V=y
+CONFIG_TOOLCHAIN_HAS_ZBB=y
+CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y
+CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y
+CONFIG_TREE_RCU=y
+CONFIG_TREE_SRCU=y
+CONFIG_TUNE_GENERIC=y
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+# CONFIG_UBIFS_FS_LZO is not set
+# CONFIG_UBIFS_FS_ZLIB is not set
+CONFIG_UIMAGE_FIT_BLK=y
+CONFIG_USB_SUPPORT=y
+CONFIG_VMAP_STACK=y
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XXHASH=y
+CONFIG_ZONE_DMA32=y
+CONFIG_ZSTD_COMMON=y
+CONFIG_ZSTD_COMPRESS=y
+CONFIG_ZSTD_DECOMPRESS=y
diff --git a/target/linux/siflower/sf21/target.mk b/target/linux/siflower/sf21/target.mk
new file mode 100644 (file)
index 0000000..2c1f54e
--- /dev/null
@@ -0,0 +1,10 @@
+ARCH:=riscv64
+SUBTARGET:=sf21
+BOARDNAME:=Siflower SF21A6826/SF21H8898 based boards
+FEATURES+=fpu nand separate_ramdisk
+DEFAULT_PACKAGES += fitblk
+KERNELNAME:=Image
+
+define Target/Description
+       Build firmware images for Siflower SF21A6826/SF21H8898 based boards.
+endef