如何配置STM32MP257的RMII Switch

前言

STM32MP257系列是一款双核A35的MPU,同时带有一个千兆switch功能的芯片,switch分别支持RMII/RGMII接口的PHY,STM32官方已经提供了STM32MP257-EV参考设计板,支持是RGMII,同时wiki也有关于switch配置RGMII PHY设备参考。这篇文章主要关于switch接RMII百兆PHY的硬件设计,设备配置和TSN switch软件功能使能。

1. 概括
STM32MP257系列的MPU都带有两个独立的网口ETH1和ETH2,同时带有switch功能,ETH1既可以配置为普通网口,也可以使能switch功能,当使能switch功能后ETH3可以接PHY,switch及可以支持RMII接口的百兆PHY,也可以支持RGMII接口的千兆PHY如下图框:

1.png

STM32MP257系列的硬件的switch设计和不带switch的硬件设计大致相同,可以参考硬件设计文档AN5489。ETH1 Switch硬件支持的功能有两部分组成,分别是DeIP标准的802.1功能和ACM模块,如下图:

2.png

因此软件kernel驱动大概有三部分:

  • STM32 deip glue:用来配置rcc时钟;

  • Switch driver(edge-lkm):用来配置switch DeIP和TSN应用支持;

  • ACM driver:控制ACM寄存器;

Switch使能后默认的网络配置如下:

3.png

end0,ETH2口,是独立的GMAC接口。

end1,ETH1口,既可以做独立的GMAC接口,也可以使能switch。

Switch使能后如下描述几个口的含义:

Sw0p1是对内的GMAC接口,不需要配置IP;

Sw0p2和sw0p3是对外的GMAC接口,分别接ETH3和ETH1口,不需要分配IP;

Sw0ep是终端接口,也是MP2内外通讯的端口,IP要配置到这个口。

2. Developer开发包使能RMII Switch
Developer使能RMII Switch的步骤:

2.1 kernel的配置,如上面图示,switch框架需要使能bridge,所以需要使能如下的配置:

CONFIG_BRIDGE=m
CONFIG_BRIDGE_NETFILTER=m
CONFIG_BRIDGE_VLAN_FILTERING=y
CONFIG_VLAN_8021Q=m

2.2 switch是千兆以太网接口,需要提供125Mhz内部时钟,所以需要修改OPTEE时钟如下:

&rcc 
{ 
    <...> 
    st,flexgen = < 
        <...> 
        FLEXGEN_CFG(54, XBAR_SRC_PLL6, 0, 3) /* 125 Mhz */ 
        <...> 
    >; 
    <...> 
}

2.3 kernel设备树配置,配置ETH1内部GMAC口和使能switch,如下:

&eth1 
{
    status = "okay"; 
    pinctrl-0 = <&eth1_mdio_pins_a>;
    pinctrl-names = "default";
    phy-mode="rgmii";
    phy-handle=<&phy1_eth1>;
    st,ext-phyclk;
    
    fixed_link: fixed-link 
    {
        speed=<1000>;
        full-duplex;
    };
    mdio1{
        #address-cells=<1>;
        #size-cells=<0>;
        compatible="snps,dwmac-mdio";
        phy1_eth1: ethernet-phy@1 {
            compatible="ethernet-phy-id001c.c816";
            reset-gpios=  <&gpioj 9 GPIO_ACTIVE_LOW>;
            max-speed = <100>;
            reset-assert-us = <10000>;
            reset-deassert-us = <80000>;
            reg = <1>;
        };
        phy2_eth1:ethernet-phy@2 {
            compatible = "ethernet-phy-id001c.c816",  
            "ethernet-phy-ieee802.3-c22";
            max-speed = <100>;
            reg = <2>;
        };
    };
};
&switch0 {
    status = "okay";
    pinctrl-0 = <ð1_rmii_pins_a>;
    pinctrl-names = "default"; 
    phy-mode = "rmii"; 
    st,ethsw-internal-125; 
};

2.4 编译以太网switch驱动模块

> *需要先source MP2开发的SDK* 
> 
> PC > git clone https://github.com/STMicroelectronics/tttech-tsn-swchcontent.git -b 1.6.8 
> PC > cd st,stm32-deip 
> PC > INSTALL_MOD_PATH=./install_artifact KDIR=/build platform=st sched=fsc sid=sid make 
> PC > INSTALL_MOD_PATH=./install_artifact KDIR=/build platform=st sched=fsc sid=sid make modules_install > 

> PC > cd ../tsn_sw_base.edge-lkm 
> PC > INSTALL_MOD_PATH=./install_artifact KDIR=/build platform=st sched=fsc sid=sid make 
> PC > INSTALL_MOD_PATH=./install_artifact KDIR=/build platform=st sched=fsc sid=sid make modules 
> PC > INSTALL_MOD_PATH=./install_artifact KDIR=/build platform=st sched=fsc sid=sid make modules_install

2.5 运行脚本

./switch_init.sh: 
modprobe 8021q 
modprobe bridge 
modprobe sch_prio 
modprobe sch_mqprio 
modprobe stm32_deip
modprobe edgx_pfm_lkm netif="eth0:0" //这个是以太网ETH1的网络名,如果不一样,需要修改

2.6 ttt-ip-init.sh start:这个脚本可以通过distribution编译带有个TSN-SWITH的文件系统copy出来。

#!/bin/sh  
REF_ETH_INTERFACE=eth0 
IP_REF_NAME=42080000.bus/42080000.bus:ttt-sw@4c000000/4c000000.deip-sw  
# read mac address  
get_mac() { 
    read MAC </sys/class/net/$REF_ETH_INTERFACE/address 
    echo "[INFO]: Mac Address of $REF_ETH_INTERFACE: $MAC" 
}
 
get_soc_path() { 
    devicetree_path=$(ls -1 -d /sys/devices/platform/* | grep "/soc" | head -n 1) 
    if [ -d "$devicetree_path" ]; 
    then 
    SOC_PATH=$devicetree_path 
    else 
    echo "[ERROR]: /sys/devices/platform/soc* is not available" 
    echo ""
    exit 1 
    fi
} 

wait_sysfs() {
    path=$1
    for i in $(seq 0 5)
    do
    if [ ! -e "$path" ]; then
    break;
    else
    sleep 0.5s 
    fi 
    done  
}

st_configure() { 
    get_soc_path 
    wait_sysfs $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus 
    if [ -e $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus ]; then 
    echo -n stmmac-1:01 > $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus 
    echo -n stmmac-1:02 > $SOC_PATH/$IP_REF_NAME/net/sw0p2/phy/mdiobus 
    else 
    echo "[ERROR]: $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus not available" 
    echo "" 
    exit 1 
    fi 
    
echo 170 > /sys/class/net/sw0p2/phy/delay1000tx_min 
echo 200 > /sys/class/net/sw0p2/phy/delay1000tx_max 
echo 170 > /sys/class/net/sw0p3/phy/delay1000tx_min 
echo 200 > /sys/class/net/sw0p3/phy/delay1000tx_max 
echo 520 > /sys/class/net/sw0p2/phy/delay1000rx_min 
echo 570 > /sys/class/net/sw0p2/phy/delay1000rx_max 
echo 520 > /sys/class/net/sw0p3/phy/delay1000rx_min 
echo 570 > /sys/class/net/sw0p3/phy/delay1000rx_max } 

# Set the interfaces up like in the interfaces files 
# Usage: set_interfaces_up 
set_interfaces_up() 
{ 
    get_mac 
    ip link set dev sw0ep address $MAC 
    ip link set dev sw0ep up 
    # ask to network to put an ip address on this interface 
    # udhcpc -i sw0ep > /dev/null 2>&1 & 
    ip addr add 192.168.0.10 dev sw0ep 
    ip route add 192.168.0.0/24 dev sw0ep 
    
    sleep 1 
    
    ip link add name br0 type bridge
    ip link set dev br0 up 
    ip link set dev sw0p1 master br0 up 
    ip link set dev sw0p2 master br0 up 
    ip link set dev sw0p3 master br0 up 
    ip link set dev sw0ep up 
    echo "[INFO]: ST interfaces are up" 
} 

# Set the interfaces down like in the interfaces files 
# Usage: set_interfaces_down 
set_interfaces_down() 
{ 
    ip link set dev br0 down 
    ip link delete dev br0 
    ip link set dev sw0ep down 
} 

# Start the deamons as they would do at start 
# Usage: start_daemons 
start_daemons() 
{ 
    # stop NTP service 
    systemctl stop systemd-timesyncd 
    systemctl stop ntpd 
    
    ip link set br0 type bridge stp_state 1 

    mstpctl addbridge br0 
    mstpctl setforcevers br0 mstp 
    mstpctl setvid2fid br0 0:1 

    systemctl start lldpd & 
    
    systemctl start deptp & 
    
    #systemctl start snmpd & 
    
    /usr/share/netopeer2-server/netopeer2-server-service start &
}

# Stop the daemons 
# Usage: 
stop_daemons stop_daemons() 
{ 
    mstpctl delbridge br0 
    #systemctl stop snmpd &
    systemctl stop lldpd & 
    systemctl stop deptp & 
    /usr/share/netopeer2-server/netopeer2-server-service stop 
} 

start() 
{ 
    echo "[INFO]: ST configuration of IP" 
    st_configure 
    echo "[INFO]: ST set brigde interface" 
    set_interfaces_up 
    # echo "[INFO]: start service" 
    # start_daemons 
} 
    
stop() { 
    # stop_daemons 
    set_interfaces_down 
} 
    
case "$1" in     
start)     
start 
;; 
stop) 
stop 
;; 
restart) 
stop  
start  
;; 
restore)  
/usr/share/netopeer2-server/netopeer2-server-service restore  
;;  
esac  
exit 0

其中st_configure这个函数里面的stmmac-1根据硬件设计的PHY地址来修改。

echo -n stmmac-1:01 > $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus 
echo -n stmmac-1:02 > $SOC_PATH/$IP_REF_NAME/net/sw0p2/phy/mdiobus

3. 基于distribution开发包使能RMII Switch

具体步骤:

3.1 编译带有TSN Switch功能的distribution package,具体可以参考这个wiki。bitbake-layers add-layer../layers/meta-st/meta-st-stm32mp-tsn-swch 主要是通过这个指令把tsn-switch的layer添加到yocto的待编译的工程layer中。

3.2 switch是千兆以太网接口,需要提供125Mhz内部时钟,所以需要修改OPTEE时钟如下:

&rcc { 
    <...> 
    st,flexgen = < 
        <...> 
        FLEXGEN_CFG(54, XBAR_SRC_PLL6, 0, 3) /* 125 Mhz */  
        <...>  
    >;  
    <...>  
}

3.3 kernel设备树配置,配置ETH1内部GMAC口和使能switch,如下:

&eth1 {
    status = "okay";
    pinctrl-0 = <ð1_mdio_pins_a>; 
    pinctrl-names = "default";
    phy-mode = "rgmii"; 
    phy-handle = <&phy1_eth1>; 
    st,ext-phyclk; 
    
    fixed_link: fixed-link { 
        speed = <1000>; 
        full-duplex; 
    }; 
    mdio1 {
        #address-cells = <1>; 
        #size-cells = <0>; 
        compatible = "snps,dwmac-mdio"; 
        phy1_eth1: ethernet-phy@1 { 
            compatible = "ethernet-phy-id001c.c816"; 
            reset-gpios = <&gpioj 9 GPIO_ACTIVE_LOW>; 
            max-speed = <100>; 
            reset-assert-us = <10000>; 
            reset-deassert-us = <80000>; 
            reg = <1>; 
        }; 
        phy2_eth1: ethernet-phy@2 { 
            compatible = "ethernet-phy-id001c.c816", 
            "ethernet-phy-ieee802.3-c22"; 
            max-speed = <100>; 
            reg = <2>; 
        }; 
    }; 
}; 

&switch0 { 
    status = "okay"; 
    pinctrl-0 = <ð1_rmii_pins_a>;pinctrl-names = "default"; 
    phy-mode = "rmii"; 
    st,ethsw-internal-125; 
};  
&switch0 {  
    status = "okay";  
    pinctrl-0 = <ð1_rmii_pins_a>;  
    pinctrl-names = "default";  
    phy-mode = "rmii";  
    st,ethsw-internal-125;  
};

3.4 修改启动脚本(需要注意默认的eth0,eth1已经被重新命名为end0,end1,脚本都是按这个名字修改的),修改文件系统中的/usr/sbin/ttt-ip-init-systemd.sh,如下:

REF_ETH_INTERFACE=eth0 
…… 
st_configure() { 
    get_soc_path 
    wait_sysfs $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus 
    if [ -e $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus ]; 
    then 
    echo -n stmmac-1:01 > 
    $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus /*这个 01 是 RMII 接口 PHY 的物理地址*/ 
    #
    #echo 
    -n stmmac-1:05 > $SOC_PATH/$IP_REF_NAME/net/sw0p2/phy/mdiobus /*因为 MP23x 只设计了两个 口,如果这个口没有引出来,可以注释掉*/ 
    else 
    echo "[ERROR]: $SOC_PATH/$IP_REF_NAME/net/sw0p3/phy/mdiobus not available" 
    echo "" 
    exit 1 
    fi
};

4. 常见问题和注意事情

4.1 因为Switch千兆的RGMII,如果外部接的是RMII百兆的PHY,收发数据的时候内部switch还是按照千兆的网络来收发,所以使用iperf3来测试的时候需要指定带宽参数-b 100M。也可以使用tc指令来系统设置:

tc qdisc replace dev sw0ep root handle 1: htb default 1 r2q 1 
tc class replace dev sw0ep parent 1: classid 1:1 htb rate 95Mbit

4.2 如何客人使用的是ST提供的文件系统,有可能自己重新配置了以太网的名字,因此需要修改以下几个脚本的默认名字:

/usr/sbin/ttt-ip-init-systemd.sh //switch驱动使能的以太网名字
/etc/modprobe.d/edgx_sw_core.conf //驱动加载的以太网名字
/usr/lib/systemd/network/80-wired.network //网络ip配置的以太网名字

来源:STM32

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。