siflower: sf21: new subtarget for sf21a6826/sf21h8898

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>
This commit is contained in:
Chuanhong Guo 2024-10-08 14:18:27 +08:00
parent 274df8eedb
commit c057db94f8
62 changed files with 12043 additions and 23 deletions

View 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

View File

@ -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>;
};
};
};

View File

@ -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>;
};

View File

@ -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>;
};

View 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

View 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

View File

@ -1,3 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/kernel.h>
#include <linux/of_address.h>
#include <linux/slab.h>

View File

@ -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);

View 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,
},
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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

View File

@ -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");

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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__ */

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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)

View File

@ -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");

View File

@ -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");

View 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.

View 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

View File

@ -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");

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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))

View File

@ -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);

View File

@ -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:

View File

@ -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 */ }
};

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 04/20] mips: add support for Siflower SF19A2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 05/20] clk: add drivers for siflower socs
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 06/20] reset: add support for sf19a2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---

View File

@ -1,8 +1,13 @@
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
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 +
@ -17,7 +22,7 @@ Subject: [PATCH 4/9] gpio: add support for siflower socs
+config GPIO_SIFLOWER
+ tristate "SiFlower GPIO support"
+ depends on OF_GPIO
+ depends on MACH_SIFLOWER_MIPS || COMPILE_TEST
+ depends on MACH_SIFLOWER_MIPS || RISCV || COMPILE_TEST
+ select GPIOLIB_IRQCHIP
+ help
+ GPIO controller driver for SiFlower SoCs.

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 08/20] pinctrl: add driver for siflower sf19a2890
---
drivers/pinctrl/Kconfig | 10 ++++++++++

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 09/20] stmmac: add support for sf19a2890
---
drivers/net/ethernet/stmicro/stmmac/Kconfig | 9 +++++++++

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 10/20] phy: add support for Siflower USB PHYs
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---

View File

@ -1,7 +1,6 @@
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
Subject: [PATCH 11/20] usb: dwc2: add support for Siflower SF19A2890
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
---

View File

@ -1,7 +1,6 @@
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
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
/*

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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