ZYNQ Linux 双网口,MDIO共用,RESET

您所在的位置:网站首页 linux网卡灯不亮 ZYNQ Linux 双网口,MDIO共用,RESET

ZYNQ Linux 双网口,MDIO共用,RESET

2023-12-26 21:31| 来源: 网络整理| 查看: 265

目录 前言一、硬件方案二、第一种方法:只配置设备树二、第二种方法:修改内核驱动和设备树1. 修改设备树2. 修改设备树kernel中 PHY GPIO 复位程序修改3. kernel中 PHY LED指示灯配置修改 三、文件系统中 网络配置文件修改四、U-Boot 中添加PHY GPIO Reset五、其他方案

前言

本文硬件方案:ZYNQ上两个PHY芯片共用一个MDIO,两个PHY芯片GPIO Reset相互独立。 本文解决问题:两个PHY芯片的设备树配置,两个PHY芯片的GPIO复位,两个PHY芯片LED灯配置

一、硬件方案

ZYNQ使用PS的两个网口,两个PHY芯片共用ENET0的MDIO,PHY芯片的复位管脚使用PL端的引脚。 使用的是88E1512 PHY芯片,根据硬件设计方案在使用前需要GPIO复位PHY芯片。 将PHY芯片复位管脚使用EMIO映射到PS端。

在这里插入图片描述 在这里插入图片描述

在这里插入图片描述

二、第一种方法:只配置设备树 /* * CAUTION: This file is automatically generated by Xilinx. * Version: * Today is: Tue Sep 15 13:54:36 2020 */ /include/ "system-top.dts" / { model = "Zynq Board"; compatible = "xlnx,zynq-MZ7X", "xlnx,zynq-7000"; chosen { bootargs = "earlycon"; stdout-path = "serial0:115200n8"; }; aliases { ethernet0 = &gem0; ethernet1 = &gem1; serial0 = &uart0; serial1 = &uart1; spi0 = &qspi; }; memory { device_type = "memory"; reg = ; }; }; &gem0 { compatible = "cdns,zynq-gem"; status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; local-mac-address = [00 0a 35 11 22 34]; phy0: phy@0 { device_type = "ethernet-phy"; reg = ; reset-gpios = ; /* kernel/drivers/net/phy/mdio_bus.c * mdiobus_register_gpiod / __mdiobus_register * gpiod = fwnode_get_named_gpiod(&mdiodev->dev.of_node->fwnode, * "reset-gpios", 0, GPIOD_OUT_LOW, * "PHY reset"); */ marvell,reg-init = ; /* kernel/drivers/net/phy/marvell.c * marvell,reg-init = ,...; * There may be one or more sets of : * reg-page: which register bank to use. * reg: the register. * mask: if non-zero, ANDed with existing register value. * value: ORed with the masked value and written to the regiser. */ }; phy1: phy@1 { device_type = "ethernet-phy"; reg = ; reset-gpios = ; marvell,reg-init = ; }; }; &gem1 { compatible = "cdns,zynq-gem"; status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; local-mac-address = [00 0a 35 11 22 35]; }; &qspi { u-boot,dm-pre-reloc; is-dual = ; num-cs = ; status = "okay"; flash@0 { compatible = "s25fl512s"; reg = ; spi-tx-bus-width = ; spi-rx-bus-width = ; spi-max-frequency = ; }; }; &uart0 { device_type = "serial"; port-number = ; status = "okay"; }; &uart1 { device_type = "serial"; port-number = ; status = "okay"; }; 二、第二种方法:修改内核驱动和设备树 1. 修改设备树

将两个PHY节点都添加到GEM0中,MDIO设备初始化时,会读取两个PHY芯片信息。 将两个PHY芯片复位管脚添加到GEM0中, MIDIO设备初始化前复位两个PHY芯片。

system-user.dtsi:

/include/ "system-top.dts" / { model = "Zynq Board"; compatible = "xlnx,zynq-MZ7X", "xlnx,zynq-7000"; chosen { bootargs = "earlycon"; stdout-path = "serial0:115200n8"; }; aliases { ethernet0 = &gem0; ethernet1 = &gem1; serial0 = &uart0; serial1 = &uart1; spi0 = &qspi; spi1 = &spi0; }; memory { device_type = "memory"; reg = ; }; }; &gem0 { compatible = "cdns,zynq-gem"; status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; reset-gpios = ; //GPIO_ACTIVE_HIGH 0 GPIO_ACTIVE_LOW 1 reset-1-gpios = ; //GPIO_ACTIVE_HIGH 0 GPIO_ACTIVE_LOW 1 phy0: phy@0 { device_type = "ethernet-phy"; reg = ; }; phy1: phy@1 { device_type = "ethernet-phy"; reg = ; }; }; &gem1 { compatible = "cdns,zynq-gem"; status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; }; &gpio0 { emio-gpio-width = ; gpio-mask-high = ; gpio-mask-low = ; }; 2. 修改设备树kernel中 PHY GPIO 复位程序修改

内核版本:4.19,其他版本可能程序不一样

MDIO总线程序中默认只有一个复位管脚,我们要复位两个PHY芯片,所以要添加复位程序。

(1)在 /kernel/driver/net/phy/mdio_bus.c: __mdiobus_register 中 修改 gpio复位程序: - 添加一个读取设备树中 reset-1 GPIO信息并复位的程序。 - 添加复位打印信息。

/* de-assert bus level PHY GPIO reset */ gpiod = devm_gpiod_get_optional(&bus->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(gpiod)) { dev_err(&bus->dev, "mii_bus %s couldn't get reset GPIO\n", bus->id); return PTR_ERR(gpiod); } else if (gpiod) { bus->reset_gpiod = gpiod; dev_info(&bus->dev, "%s: reset-gpio = %d, gpio_offset = %d\n", __func__, desc_to_gpio(gpiod), \ desc_to_gpio(gpiod)-gpiod_to_chip(gpiod)->base); gpiod_set_value_cansleep(gpiod, 1); udelay(bus->reset_delay_us); gpiod_set_value_cansleep(gpiod, 0); } //add 20210510 gpiod = devm_gpiod_get_optional(&bus->dev, "reset-1", GPIOD_OUT_LOW); if (IS_ERR(gpiod)) { dev_err(&bus->dev, "mii_bus %s couldn't get reset-1 GPIO\n", bus->id); //return PTR_ERR(gpiod); } else if (gpiod) { //bus->reset_gpiod = gpiod; dev_info(&bus->dev, "%s: reset-1-gpio = %d, gpio_offset = %d\n", __func__, desc_to_gpio(gpiod), \ desc_to_gpio(gpiod)-gpiod_to_chip(gpiod)->base); gpiod_set_value_cansleep(gpiod, 1); udelay(bus->reset_delay_us); gpiod_set_value_cansleep(gpiod, 0); }

程序会根据 reset-1 到设备树中读取复位管脚信息,然后复位。

(2)添加GPIO复位打印信息 在 kernel/drivers/gpio/gpiolib.c 的 void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) 函数中添加打印 :

static void gpiod_set_raw_value_commit(struct gpio_desc *desc, bool value) { struct gpio_chip *chip; int offset = gpio_chip_hwgpio(desc); chip = desc->gdev->chip; trace_gpio_value(desc_to_gpio(desc), 0, value); chip->set(chip, offset, value); gpiod_info(desc,"%s: base = %d, offset = %d, value = %d\n", __func__, chip->base, offset, value); } 3. kernel中 PHY LED指示灯配置修改

88E1512 PHY芯片使用的是88E1510驱动,LED灯定义可能不一样,导致LED灯可能不亮或者状态不对。

在 /kernel/driver/net/phy/marvell.c: 中修改 MII_88E1510_PHY_LED_DEF 定义:

原来定义为

#define MII_88E1510_PHY_LED_DEF 0x1177

修改为:

/* 88E1512 LED 设置 LED[1] 0001 = On - Link, Blink - Activity, Off - No Link 0100 = Blink - Activity, Off - No Activity LED[0] 0000 = On - Link, Off - No Link 0010 = 3 blinks - 1000 Mbps 2 blinks - 100 Mbps 1 blink - 10 Mbps 0 blink - No Link */ #define MII_88E1510_PHY_LED_DEF 0x1040

修改后LED0表示Link状态,LED1表示Activity状态。

三、文件系统中 网络配置文件修改

修改/etc/network/interface文件: 设置MAC和IP:eht0和eth1只能设置一个网关,修改MAC地址要在网卡启动前(使用pre-up)

auto lo iface lo inet loopback # A. For DHCP on eth0 # auto eth0 # iface eth0 inet dhcp # B. For static on eth0 auto eth0 iface eth0 inet static pre-up ifconfig $IFACE down pre-up ifconfig $IFACE hw ether 00:0A:35:00:02:11 pre-up ifconfig $IFACE up address 192.168.0.210 netmask 255.255.255.0 gateway 192.168.0.1 auto eth1 iface eth1 inet static pre-up ifconfig $IFACE down pre-up ifconfig $IFACE hw ether 00:0A:35:00:02:12 pre-up ifconfig $IFACE up address 192.168.1.210 netmask 255.255.255.0 #gateway 192.168.1.1 四、U-Boot 中添加PHY GPIO Reset 设备树修改(目前只测试了一个PHY芯片) / { model = "ZYNQ Board"; compatible = "xlnx,zynq-7000"; aliases { ethernet0 = &gem0; //ethernet1 = &gem1; serial0 = &uart0; spi0 = &qspi; mmc0 = &sdhci0; }; }; &gpio0 { emio-gpio-width = ; gpio-mask-high = ; gpio-mask-low = ; }; &gem0 { status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; reset-gpios = ; //GPIO_ACTIVE_HIGH 0 //reset-1-gpios = ; //GPIO_ACTIVE_HIGH 0 ethernet_phy_0: ethernet_phy@0 { device_type = "ethernet-phy"; reg = ; }; /*ethernet_phy_1: ethernet_phy@1 { device_type = "ethernet-phy"; reg = ; };*/ }; /*gem1 { status = "okay"; phy-mode = "rgmii-id"; phy-handle = ; };*/ 添加GPIO复位程序

(1) 在 u-boot/drivers/net/zynq_gem.c 中:

添加 头文件:

#include

添加 gpio_desc 定义:在结构体 zynq_gem_priv 中添加

/* Initialized, rxbd_current, rx_first_buf must be 0 after init */ struct zynq_gem_priv { struct emac_bd *tx_bd; struct emac_bd *rx_bd; char *rxbuffers; u32 rxbd_current; u32 rx_first_buf; int phyaddr; int init; struct zynq_gem_regs *iobase; phy_interface_t interface; struct phy_device *phydev; int phy_of_handle; struct mii_dev *bus; struct clk clk; u32 max_speed; bool int_pcs; struct gpio_desc reset_gpio; };

(2) 在 u-boot/drivers/net/zynq_gem.c 中添加 zynq_phy_reset(struct udevice *dev) 函数

函数功能:读取设备树中 reset-gpios 和 reset-1-gpios 的GPIO信息,如果GPIO信息有效就先将GPIO置0,延时10ms后再置1

/* * phy gpio reset * add 20210514 */ static void zynq_phy_reset(struct udevice *dev) { struct zynq_gem_priv *priv = dev_get_priv(dev); gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio, GPIOD_IS_OUT); if (dm_gpio_is_valid(&priv->reset_gpio)) { printf("%s: reset-gpios = %d\n", __func__, priv->reset_gpio.offset); dm_gpio_set_value(&priv->reset_gpio, 0); udelay(10000); dm_gpio_set_value(&priv->reset_gpio, 1); } gpio_request_by_name(dev, "reset-1-gpios", 0, &priv->reset_gpio, GPIOD_IS_OUT); if (dm_gpio_is_valid(&priv->reset_gpio)) { printf("%s: reset-1-gpios = %d\n", __func__, priv->reset_gpio.offset); dm_gpio_set_value(&priv->reset_gpio, 0); udelay(10000); dm_gpio_set_value(&priv->reset_gpio, 1); } }

(3) 在 int zynq_gem_ofdata_to_platdata(struct udevice *dev) 函数中调用 zynq_phy_reset(struct udevice *dev) 函数

static int zynq_gem_ofdata_to_platdata(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); struct zynq_gem_priv *priv = dev_get_priv(dev); int node = dev_of_offset(dev); const char *phy_mode; //add 20210514 zynq_phy_reset(dev);//phy reset pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); priv->iobase = (struct zynq_gem_regs *)pdata->iobase; /* Hardcode for now */ priv->phyaddr = -1; priv->phy_of_handle = fdtdec_lookup_phandle(gd->fdt_blob, node, "phy-handle"); if (priv->phy_of_handle > 0) priv->phyaddr = fdtdec_get_int(gd->fdt_blob, priv->phy_of_handle, "reg", -1); phy_mode = fdt_getprop(gd->fdt_blob, node, "phy-mode", NULL); if (phy_mode) pdata->phy_interface = phy_get_interface_by_name(phy_mode); if (pdata->phy_interface == -1) { debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode); return -EINVAL; } priv->interface = pdata->phy_interface; priv->max_speed = fdtdec_get_uint(gd->fdt_blob, priv->phy_of_handle, "max-speed", SPEED_1000); priv->int_pcs = fdtdec_get_bool(gd->fdt_blob, node, "is-internal-pcspma"); printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase, priv->phyaddr, phy_string_for_interface(priv->interface)); return 0; }

(4) 添加GPIO复位打印信息 在 u-boot/drivers/gpio/gpio-uclass.c 的 int dm_gpio_set_value(const struct gpio_desc *desc, int value) 函数中添加打印 :

int dm_gpio_set_value(const struct gpio_desc *desc, int value) { int ret; ret = check_reserved(desc, "set_value"); if (ret) return ret; if (desc->flags & GPIOD_ACTIVE_LOW) value = !value; gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value); printf("%s: gpio offset = %d, value = %d\n", __func__, desc->offset, value); return 0; } 五、其他方案

需要给内核打补丁(0001-net-macb-Add-MDIO-driver-for-accessing-multiple-PHY-.patch),可参考下面连接,暂未测试。

petalinux在zynq平台移植和双网口实现ZYNQ petalinux双网口88E1512设计Dual Ethernet over MII/MDIO not working in Petalinux SDK 2018.2

Kernel补丁(Petalinux 2018.2): 0001-net-macb-Add-MDIO-driver-for-accessing-multiple-PHY-.zip Uboot补丁(Petalinux 2018.2): 0001_u-boot_multiple_phy_on_mdio.zip

设备树(system-user.dtsi):

/include/ "system-conf.dtsi" / { mdio { compatible = "cdns,macb-mdio"; reg = ; clocks = , , ; clock-names = "pclk", "hclk", "tx_clk"; #address-cells = ; #size-cells = ; ethernet_phy0: ethernet-phy@0 { compatible = "marvell,88e1510"; device_type = "ethernet-phy"; reg = ; }; ethernet_phy1: ethernet-phy@1 { compatible = "marvell,88e1510"; device_type = "ethernet-phy"; reg = ; }; }; }; &gem0 { status = "okay"; phy-mode = "rgmii-id"; local-mac-address = [00 0a 35 00 1e 53]; phy-handle = ; phy-reset-gpio = ; phy-reset-duration = ; phy-reset-active-low; }; &gem1 { status = "okay"; phy-mode = "rgmii-id"; local-mac-address = [00 0a 35 00 1e 54]; phy-handle = ; phy-reset-gpio = ; phy-reset-duration = ; phy-reset-active-low; };

注:内核版本为:4.14 可使用该设备树,4.19不可用



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3