ZYNQ Linux 双网口,MDIO共用,RESET-GPIO不共用

news/2024/11/18 0:29:14/

目录

  • 前言
  • 一、硬件方案
  • 二、第一种方法:只配置设备树
  • 二、第二种方法:修改内核驱动和设备树
    • 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 = <0x0 0x40000000>;};
};&gem0 {compatible = "cdns,zynq-gem";status = "okay";phy-mode = "rgmii-id";phy-handle = <&phy0>;local-mac-address = [00 0a 35 11 22 34];phy0: phy@0 {device_type = "ethernet-phy";reg = <0>;reset-gpios = <&gpio0 54 1>;/* 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 = <0x3 0x10 0xff00 0x40>;/* kernel/drivers/net/phy/marvell.c* marvell,reg-init = <reg-page reg mask value>,...;* There may be one or more sets of <reg-page reg mask value>:* 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 = <1>;reset-gpios = <&gpio0 55 1>;marvell,reg-init = <0x3 0x10 0xff00 0x40>;};
};&gem1 {compatible = "cdns,zynq-gem";status = "okay";phy-mode = "rgmii-id";phy-handle = <&phy1>;local-mac-address = [00 0a 35 11 22 35];};&qspi {u-boot,dm-pre-reloc;is-dual = <0>;num-cs = <1>;status = "okay";flash@0 {compatible = "s25fl512s";reg = <0x0>;spi-tx-bus-width = <1>;spi-rx-bus-width = <4>;spi-max-frequency = <50000000>;};
};&uart0 {device_type = "serial";port-number = <0>;status = "okay";
};&uart1 {device_type = "serial";port-number = <1>;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 = <0x0 0x40000000>;};
};&gem0 {compatible = "cdns,zynq-gem";status = "okay";phy-mode = "rgmii-id";phy-handle = <&phy0>;reset-gpios = <&gpio0 54 1>; //GPIO_ACTIVE_HIGH 0 GPIO_ACTIVE_LOW 1reset-1-gpios = <&gpio0 55 1>; //GPIO_ACTIVE_HIGH 0 GPIO_ACTIVE_LOW 1phy0: phy@0 {device_type = "ethernet-phy";reg = <0>;};phy1: phy@1 {device_type = "ethernet-phy";reg = <1>;};
};&gem1 {compatible = "cdns,zynq-gem";status = "okay";phy-mode = "rgmii-id";phy-handle = <&phy1>;
};&gpio0 {emio-gpio-width = <10>;gpio-mask-high = <0x0>;gpio-mask-low = <0x5600>;
};

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 20210510gpiod = 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.cvoid 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 Link0100 = Blink - Activity, Off - No Activity
LED[0] 0000 = On - Link, Off - No Link0010 = 3 blinks - 1000 Mbps2 blinks - 100 Mbps1 blink - 10 Mbps0 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 eth0auto 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.1auto 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

  1. 设备树修改(目前只测试了一个PHY芯片)
/ {model = "ZYNQ Board";compatible = "xlnx,zynq-7000";aliases {ethernet0 = &gem0;//ethernet1 = &gem1;serial0 = &uart0;spi0 = &qspi;mmc0 = &sdhci0;};
};&gpio0 {emio-gpio-width = <8>;gpio-mask-high = <0x0>;gpio-mask-low = <0x5600>;
};&gem0 {status = "okay";phy-mode = "rgmii-id";phy-handle = <&ethernet_phy_0>;reset-gpios = <&gpio0 54 0>; //GPIO_ACTIVE_HIGH 0//reset-1-gpios = <&gpio0 55 0>; //GPIO_ACTIVE_HIGH 0ethernet_phy_0: ethernet_phy@0 {device_type = "ethernet-phy";reg = <0>;};/*ethernet_phy_1: ethernet_phy@1 {device_type = "ethernet-phy";reg = <1>;};*/
};/*gem1 {status = "okay";phy-mode = "rgmii-id";phy-handle = <&ethernet_phy_1>;
};*/
  1. 添加GPIO复位程序

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

添加 头文件:

 #include <asm/gpio.h>

添加 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-gpiosreset-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 20210514zynq_phy_reset(dev);//phy resetpdata->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.cint 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),可参考下面连接,暂未测试。

  1. petalinux在zynq平台移植和双网口实现
  2. ZYNQ petalinux双网口88E1512设计
  3. 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 = <0xe000b000 0x1000>;clocks = <&clkc 30>, <&clkc 30>, <&clkc 13>;clock-names = "pclk", "hclk", "tx_clk";#address-cells = <1>;#size-cells = <0>;ethernet_phy0: ethernet-phy@0 {compatible = "marvell,88e1510";device_type = "ethernet-phy";reg = <0>;};ethernet_phy1: ethernet-phy@1 {compatible = "marvell,88e1510";device_type = "ethernet-phy";reg = <1>;};};
};
&gem0 {status = "okay";phy-mode = "rgmii-id";local-mac-address = [00 0a 35 00 1e 53];phy-handle = <&ethernet_phy0>;phy-reset-gpio = <&gpio0 54 1>;phy-reset-duration = <20>;phy-reset-active-low;	     	
};
&gem1 {status = "okay";phy-mode = "rgmii-id";local-mac-address = [00 0a 35 00 1e 54];phy-handle = <&ethernet_phy1>;	   phy-reset-gpio = <&gpio0 55 1>;phy-reset-duration = <20>;phy-reset-active-low;	 
};

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


http://www.ppmy.cn/news/271986.html

相关文章

supersocket client 固定端口_西门子CPU控制器1512P-1PN端口交换机附件200KB

西门子CPU控制器1512P-1PN端口交换机附件200KB 浔之漫智控技术(上海)有限公司 上海诗慕自动化设备有限公司本公司销售西门子自动化产品&#xff0c;全新原装&#xff0c;质量保证&#xff0c;价格优势西门子PLC,西门子触摸屏&#xff0c;西门子数控系统&#xff0c;西门子…

【HDOJ】1512 Monkey King

左偏树并查集。左偏树就是可合并二叉堆。 1 /* 1512 */2 #include <iostream>3 #include <string>4 #include <map>5 #include <queue>6 #include <set>7 #include <stack>8 #include <vector>9 #include <deque>10 #include …

力扣1748,387,1941,448,1512,1711题解

文章目录 1748. 唯一元素的和计数法哈希表&#xff08;STL&#xff09; 387. 字符串中的第一个唯一字符计数法统计出现次数&#xff0c;然后一次循环返回索引哈希表存次数 1941. 检查是否所有字符出现次数相同统计每一个字符出现的次数&#xff0c;然后都和第一个次数比较相等与…

CF1512E Permutation by Sum(思维)

题目传送门 这道题是我灵光一闪突然想到的做法。 首先叙述一下题意&#xff1a; 这道题的意思就是说&#xff1a;给你四个数n,a,b,s让你构造一个长度为n的数字序列&#xff0c;这个序列的要求是数字必须是在1~n中的&#xff0c;而且不能有重复的数字&#xff0c;并且在下标a ~ …

1512 好数对的数目

题目描述&#xff1a; 给你一个整数数组 nums 。 如果一组数字 (i,j) 满足 nums[i] nums[j] 且 i < j &#xff0c;就可以认为这是一组 好数对 。 返回好数对的数目。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3,1,1,3] 输出&#xff1a;4 解释&#xff1a;有 4 组…

大数据基础-Hadoop MP开发

1. MAPREDUCE原理篇&#xff08;1&#xff09; Mapreduce是一个分布式运算程序的编程框架&#xff0c;是用户开发“基于hadoop的数据分析应用”的核心框架&#xff1b; Mapreduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序&#xff0c…

ZYNQMP_XAZU3EG_LINUX 默认启动项修改

默认启动项为 ZynqMP> print default_bootcmd default_bootcmdrun uenvboot; run cp_kernel2ram && bootm ${netstart} 由于启动vx7改动&#xff0c;需要恢复&#xff0c;做如下改动&#xff0c;恢复正常 ZynqMP> setenv bootcmd $default_bootcmd ZynqMP>…

Xilinx zynq zynqmp Macb Gem千兆网使用

作者 QQ群&#xff1a;852283276 微信&#xff1a;arm80x86 微信公众号&#xff1a;青儿创客基地 B站&#xff1a;主页 https://space.bilibili.com/208826118 参考 zynqMP GEM 如何配置GT lane Zynq MPsoc的GEM Ethernet DTS问题 2017.1-2018.3 Zynq UltraScale MPSoC: Linu…