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 BOARD:=siflower
BOARDNAME:=Siflower SoCs BOARDNAME:=Siflower SoCs
FEATURES:=squashfs usb usbgadget source-only FEATURES:=squashfs usb usbgadget source-only
SUBTARGETS:=sf19a2890 SUBTARGETS:=sf19a2890 sf21
KERNEL_PATCHVER:=6.6 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 menuconfig CLK_SIFLOWER
bool "Siflower SoC driver support" bool "Siflower SoC driver support"
depends on MIPS || COMPILE_TEST depends on MIPS || RISCV || COMPILE_TEST
help help
SoC drivers for Siflower Linux-capable SoCs. SoC drivers for Siflower Linux-capable SoCs.
@ -18,10 +18,18 @@ config CLK_SF19A2890
config CLK_SF19A2890_PERIPH config CLK_SF19A2890_PERIPH
bool "Clock driver for Siflower SF19A2890 peripheral clock gates" bool "Clock driver for Siflower SF19A2890 peripheral clock gates"
depends on MIPS || COMPILE_TEST depends on MIPS || RISCV || COMPILE_TEST
help help
Supports the clock gates for various peripherals in SF19A2890. Supports the clock gates for various peripherals in SF19A2890.
If this kernel is meant to run on a Siflower SF19A2890 SoC, If this kernel is meant to run on a Siflower SF19A2890 SoC,
enable this driver. 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 endif

View File

@ -1,2 +1,3 @@
obj-$(CONFIG_CLK_SF19A2890) += clk-sf19a2890.o obj-$(CONFIG_CLK_SF19A2890) += clk-sf19a2890.o
obj-$(CONFIG_CLK_SF19A2890_PERIPH) += clk-sf19a2890-periph.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/kernel.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/slab.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, .remove = sf_gpio_remove,
.driver = { .driver = {
.name = "siflower_gpio", .name = "siflower_gpio",
.owner = THIS_MODULE,
.of_match_table = sf_gpio_ids, .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 select GENERIC_PHY
help help
Enable this to support the USB2.0 PHY on the SIFLOWER SF19A2890. 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_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 endef
$(eval $(call KernelPackage,phy-sf19a2890-usb)) $(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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:32:17 +0800 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> 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:01 +0800 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> 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:43 +0800 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> 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:33:57 +0800 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/Kconfig | 8 ++++++++
drivers/gpio/Makefile | 1 + drivers/gpio/Makefile | 1 +
@ -17,7 +22,7 @@ Subject: [PATCH 4/9] gpio: add support for siflower socs
+config GPIO_SIFLOWER +config GPIO_SIFLOWER
+ tristate "SiFlower GPIO support" + tristate "SiFlower GPIO support"
+ depends on OF_GPIO + depends on OF_GPIO
+ depends on MACH_SIFLOWER_MIPS || COMPILE_TEST + depends on MACH_SIFLOWER_MIPS || RISCV || COMPILE_TEST
+ select GPIOLIB_IRQCHIP + select GPIOLIB_IRQCHIP
+ help + help
+ GPIO controller driver for SiFlower SoCs. + 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:34:20 +0800 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 ++++++++++ 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 20 Aug 2024 08:34:42 +0800 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 +++++++++ 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Mon, 9 Sep 2024 10:18:33 +0800 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> 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Mon, 9 Sep 2024 16:46:53 +0800 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> 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> From: Chuanhong Guo <gch981213@gmail.com>
Date: Tue, 10 Sep 2024 09:10:27 +0800 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 The DWC OTG 3.30a found on Siflower SF19A2890 has battery charger
support enabled. It triggers MultVallpChng interrupt (bit 20 of 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