I.MX6UL/ULL 内部有个以太网 MAC 外设,也就是 ENET,需要外接一个 PHY 芯片来实现网络通信功能,也就是内部MAC+外部 PHY 芯片的方案。
I.MX6UL/ULL 有两个网络接口 ENET1 和 ENET2,I.MX6U-ALPHA 开发板提供了这两个网络接口,其中 ENET1 和 ENET2 都使用 LAN8720A 作为 PHY 芯片。
NXP 官方的I.MX6ULL EVK 开发板使用 KSZ8081 这颗 PHY 芯片,LAN8720A 相比 KSZ8081 具有体积小、外围器件少、价格便宜等优点。
直接使用 KSZ8081 固然可以,但是我们在实际的产品中不一定会使用 KSZ8081,有时候为了降低成本会选择其他的 PHY 芯片。
这个时候就有个问题:换了PHY 芯片以后网络驱动怎么办?为此,I.MX6U-ALPHA 开发板将 ENET1 和 ENET2的 PHY 换成了LAN8720A,这样就可以给大家讲解更换 PHY 芯片以后如何调整网络驱动,使网络工作正常。
I.MX6U-ALPHA 开发板的 ENET1 引脚与 NXP 官方的 I.MX6ULL EVK 开发板基本一样,唯独复位引脚不同。从图可以看出,I.MX6U-ALPHA 开发板的 ENET1 复位引脚ENET1_RST 接到了 I.M6ULL 的SNVS_TAMPER7 这个引脚上。
LAN8720A 内部是有寄存器的,I.MX6ULL 会读取 LAN8720 内部寄存器来判断当前的物理链接状态、 连接速度(10M 还是 100M)和双工状态(半双工还是全双工)。 I.MX6ULL 通过 MDIO接口来读取 PHY 芯片的内部寄存器,MDIO 接口有两个引脚,ENET_MDC 和 ENET_MDIO, ENET_MDC 提供时钟,ENET_MDIO 进行数据传输。一个 MIDO 接口可以管理 32 个 PHY 芯片,同一个 MDIO 接口下的这些 PHY 使用不同的器件地址来做区分,MIDO 接口通过不同的器件地址即可访问到相应的 PHY 芯片。I.MX6U-ALPHA 开发板 ENET1 上连接的 LAN8720A器件地址为 0X0,
所以我们要修改 ENET1 网络驱动的话重点就三点:
①、ENET1 复位引脚初始化。 ENET1_RST -->SNVS_TAMPER7
②、LAN8720A 的器件 ID。0x0
③、LAN8720 驱动
修改 ENET2网络驱动的话重点就三点:
①、ENET1 复位引脚初始化。 ENET1_RST -->SNVS_TAMPER8
②、LAN8720A 的器件 ID。0x1
③、LAN8720 驱动
终端输入:gedit board/freescale/mx6ull_mybsp_emmc/mx6ull_mybsp_emmc.c
修改前:
#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)
修改后:
#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)
static iomux_v3_cfg_t const iox_pads[] = {
/* IOX_SDI */
MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_SHCP */
MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_STCP */
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
/* IOX_nOE */
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};
board_init 会调用 imx_iomux_v3_setup_multiple_pads 和 iox74lv_init 这两个函数来初始化
74lv595 的 GPIO,将这两行删除掉。至此,mx6ull_mybsp_emmc.c 中关于 74LV595 芯片的驱
动代码都删除掉了。
在 mx6ull_mybsp_emmc.c 中找到关键词:
①static iomux_v3_cfg_t const fec1_pads[]
②static iomux_v3_cfg_t const fec2_pads[]
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),/* 初始化ETH1 RESET引脚 */
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),/* 初始化ETH2 RESET引脚 */
继续在文件 mx6ull_mybsp_emmc.c 中找到函数 setup_iomux_fec。将这两个 IO 设置为输出并且硬件复位一下 LAN8720A,这个硬件复位很重要!否则可能导致 uboot 无法识别 LAN8720A。
追加内容如下:
static void setup_iomux_fec(int fec_id)
{
if (fec_id == 0)
{
imx_iomux_v3_setup_multiple_pads(fec1_pads,
ARRAY_SIZE(fec1_pads));
gpio_direction_output(ENET1_RESET, 1);
gpio_set_value(ENET1_RESET, 0);
mdelay(100);
gpio_set_value(ENET1_RESET, 1);
}
else
{
imx_iomux_v3_setup_multiple_pads(fec2_pads,
ARRAY_SIZE(fec2_pads));
gpio_direction_output(ENET2_RESET, 1);
gpio_set_value(ENET2_RESET, 0);
mdelay(100);
gpio_set_value(ENET2_RESET, 1);
}
}
uboot 中的 LAN8720A 驱动有点问题,打开文件drivers/net/phy/phy.c,找到函数 genphy_update_link,这是个通用 PHY 驱动函数,此函数用于更新 PHY 的连接状态和速度。
终端输入:gedit drivers/net/phy/phy.c
搜索关键字:genphy_update_link
修改如下:
/* LAN8720 must software*/
#ifdef CONFIG_PHY_SMSC
static int lan8720_flag = 0;
int bmcr_reg = 0;
if (lan8720_flag == 0) {
bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); /* 读取寄存器BMCR默认值 */
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); /* 软件复位,自动清零 */
while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & BMCR_RESET) {
udelay(100);
}
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg); /* BMCR写入原来的值 */
lan8720_flag = 1;
}
#endif
./mx6ull_mybsp_emmc.sh
或
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_mybsp_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
chmod 777 imxdownload
//给予 imxdownload 可执行权限
./imxdownload u-boot.bin /dev/sdg
//烧写 u-boot.bin 到 SD 卡中
烧写完成以后将 SD 卡插入 I.MX6U-ALPHA 开发板的 TF 卡槽中,最后设置开发板从 SD卡启动。打开 SecureCRT,设置好开发板所使用的串口并打开,复位开发板。
setenv ipaddr 192.168.1.55
//开发板 IP 地址
setenv ethaddr 00:04:9f:04:d2:35
//开发板网卡 MAC 地址
setenv gatewayip 192.168.1.1
//开发板默认网关
setenv netmask 255.255.255.0
//开发板子网掩码
setenv serverip 192.168.1.250
//服务器地址,也就是 Ubuntu 地址
saveenv
//保存环境变量
SecureCRT的uboot中使用ping命令。
ping 192.168.1.250