Linux驱动之系统移植----uboot移植_修改网络驱动(uboot无设备树版本)

uboot版本:uboot.2016.03
开发板:100ask_imx6ull_pro

修改网络驱动

须知
I.MX6UL/ULL内部有个以太网 MAC外设,也就是 ENET,需要外接一个 PHY芯片来实现网络通信功能,也就是内部 MAC+外部 PHY芯片的方案。(一个MAC可对应N个PHY芯片, PHY有地址索引)
也有些芯片没有内部以太网MAC如三星的 2440,4412, 因而采用 DM9000来实现联网功能。DM9000提供了一个类似 SRAM的访问接口,主控 CPU通过这个接口即可与DM9000进行通信,DM9000就是一个 MAC+PHY芯片。
内部 MAC+PHY芯片与 DM9000方案相比, 通信效率和速度上前者是碾压之势

通过开发板的原理图, 已知晓, 手头上的开发板采用了 ENET2使用 LAN8720A作为 PHY芯片.

LAN8720A有个管理接口, MDIO,两个线, MDIO和MDC, 时钟和数据线, 一个MDIO接口可以管理32个PHY芯片, MDIO通过PHY ADDR来确定访问哪个PHY芯片.

LAN8720A有复位引脚.

LAN8720驱动, 因为所有的PHY, 前16个寄存器一模一样是个phy的标准,在前16个寄存器的配置必须能够驱动phy芯片, 因此uboot里面会有已经写好了通用的PHY驱动, 所以理论上不需要修改.

原厂的网络模块原理图
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

开发板的网络模块原理图

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

在这里插入图片描述

通过和公板对比 我们发现网络通信接口都是使用的 RMII 接口 其中命令接口使用为 MDIO 接口,引脚 pin number 一致,只有 ENET2 RST 引脚不同,公板用74lv扩展出RST 引脚, 此时我们只需要修改 ENET2 RST 引脚即可 由于网卡时通过 PHY 地址来进行区分查找的 我们也要查看 PHY 芯片手册来知道如何确认 PHY 地址。

① ENET2的复位引脚,从图 33.2.7.2可以看出,ENET2的复位引脚 ENET2_RST接到了I.MX6ULL的 SNVS_TAMPER6
② ENET2所使用的 PHY芯片器件地址,从图 33.2.7.2可以看出,PHY器件地址为 0X1。

明确目的

  • 对ENET2添加复位引脚.
  • 对ENET2驱动添加复位功能.
  • 对驱动指定PHY ADDR.
  • 移除原有的74lv的相关驱动代码

修改PHY地址 指定PHY ADDR

打开include/configs/mx6ull_jzy_emmc.h
搜索到CONFIG_FEC_ENET_DEV

#define CONFIG_FEC_ENET_DEV		1

宏 CONFIG_FEC_ENET_DEV用于选择使用哪个网口,默认为 1,也就是选择ENET2。
搜索 CONFIG_FEC_MXC_PHYADDR

#if (CONFIG_FEC_ENET_DEV == 0) 
#define IMX_FEC_BASE              ENET_BASE_ADDR 
#define CONFIG_FEC_MXC_PHYADDR     0x2 
#define CONFIG_FEC_XCV_TYPE         RMII 
#elif (CONFIG_FEC_ENET_DEV == 1) 
#define IMX_FEC_BASE              ENET2_BASE_ADDR 
#define CONFIG_FEC_MXC_PHYADDR    0x1

前面根据原理图分析了, 使用的是enet2, 并且地址是0x1. 所以这里不需要做修改.

修改PHY初始化的选择
打开drivers/net/phy/phy.c
搜索函数 phy_init

int phy_init(void)
{
#ifdef CONFIG_PHY_AQUANTIA
	phy_aquantia_init();
#endif
#ifdef CONFIG_PHY_ATHEROS
	phy_atheros_init();
#endif
#ifdef CONFIG_PHY_BROADCOM
	phy_broadcom_init();
#endif
#ifdef CONFIG_PHY_CORTINA
	phy_cortina_init();
#endif
#ifdef CONFIG_PHY_DAVICOM
	phy_davicom_init();
#endif
#ifdef CONFIG_PHY_ET1011C
	phy_et1011c_init();
#endif
#ifdef CONFIG_PHY_LXT
	phy_lxt_init();
#endif
#ifdef CONFIG_PHY_MARVELL
	phy_marvell_init();
#endif
#ifdef CONFIG_PHY_MICREL
	phy_micrel_init();
#endif
#ifdef CONFIG_PHY_NATSEMI
	phy_natsemi_init();
#endif
#ifdef CONFIG_PHY_REALTEK
	phy_realtek_init();
#endif
#ifdef CONFIG_PHY_SMSC
	phy_smsc_init();
#endif
#ifdef CONFIG_PHY_TERANETICS
	phy_teranetics_init();
#endif
#ifdef CONFIG_PHY_TI
	phy_ti_init();
#endif
#ifdef CONFIG_PHY_VITESSE
	phy_vitesse_init();
#endif

	return 0;
}

其中phy_smsc_init定义了LAN8720的初始化

static struct phy_driver lan8710_driver = {
	.name = "SMSC LAN8710/LAN8720",
	.uid = 0x0007c0f0,
	.mask = 0xffff0,
	.features = PHY_BASIC_FEATURES,
	.config = &genphy_config_aneg,
	.startup = &genphy_startup,
	.shutdown = &genphy_shutdown,
};
......
int phy_smsc_init(void)
{
	phy_register(&lan8710_driver);
	phy_register(&lan911x_driver);
	phy_register(&lan8700_driver);
	phy_register(&lan8740_driver);

	return 0;
}

所以需要选择CONFIG_PHY_SMSC
回到mx6ull_jzy_emmc.h文件查找发现默认选择的是CONFIG_PHY_MICREL

#define CONFIG_PHY_MICREL

将其修改为CONFIG_PHY_SMSC

#define CONFIG_PHY_SMSC

屏蔽74LV595驱动代码
进入board/freescale/mx6ull_jzy_emmc/mx6ull_jzy_emmc.c文件
模仿74LV595定义一个gpio5_6

#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 ENET2_RESET IMX_GPIO_NR(5, 6) 

找到int board_init(void)初始化函数

int board_init(void) 
{ 
 ...... 
	imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads)); 
    iox74lv_init(); 
    ......
}

将iox74lv_init();初始化函数删除

添加复位引脚的驱动

static iomux_v3_cfg_t const fec2_pads[]数组定义了引脚复用
添加gpio5_6的引脚

static iomux_v3_cfg_t const fec2_pads[] = {
	MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
	MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
	MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_SNVS_TAMPER6__GPIO5_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

setup_iomux_fec(int fec_id)是根据fec2_pads和fec1_pads网络IO配置数组来初始化网络IO, 需要在其中添加网络复位IO的初始化代码, 通过GPIO硬复位

static void setup_iomux_fec(int fec_id)
{
	if (fec_id == 0)
		imx_iomux_v3_setup_multiple_pads(fec1_pads,
						 ARRAY_SIZE(fec1_pads));
	else
		imx_iomux_v3_setup_multiple_pads(fec2_pads,
						 ARRAY_SIZE(fec2_pads));
}
||                                             ||
||*********************************************||
||                                             || 
static void setup_iomux_fec(int fec_id)
{
	if (fec_id == 0)
	{
		imx_iomux_v3_setup_multiple_pads(fec1_pads,
						 ARRAY_SIZE(fec1_pads));
	}
	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(20);
		gpio_set_value(ENET2_RESET, 1);
	}
}

这是通过LAN8720A芯片手册读到的信息, 将复位引脚拉低至少20ms复位.
这个硬件复位很重要!
否则可能导致 uboot无法识别 LAN8720A。

修改 drivers/net/phy/phy.c文件中的函数 genphy_update_link
uboot中的LAN8720A驱动依然有些问题,
打开文件
drivers/net/phy/phy.c,找到函数 genphy_update_link,这是个通用 PHY驱动函数,此函数用于更
新 PHY的连接状态和速度。
使用 LAN8720A的时候要使其复位一下, 这是软复位

 int genphy_update_link(struct phy_device *phydev) 
 { 
     unsigned int mii_reg; 
  
 #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);     
         phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);    
         while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) { 
             udelay(100);             
         } 
         phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);     
         lan8720_flag = 1; 
     } 
 #endif 
  
     /* 
      * Wait if the link is up, and autonegotiation is in progress 
      * (ie - we're capable and it's not done) 
      */ 
     mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); 
... 
  
     return 0; 
 }

phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);读取MII_BMCR寄存器的值
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);往寄存器MII_BMCR写入BMCR_RESET值,
#define BMCR_RESET 0x8000 /* Reset the DP83840 */
MII_BMCR寄存器的0x8000功能是复位
等待复位结束, 将之前存的默认值写回去.

编译后移植, 启动uboot 测试网络
设置网卡信息

=> setenv eth1addr 00:01:3f:2d:3e:4d
=> setenv ipaddr 192.168.31.178
=> setenv gatewayip 192.168.31.1
=> setenv netmask 255.255.255.0
=> setenv serverip 192.168.31.158
=> saveenv
=> ping 192.168.31.139
Using FEC1 device
host 192.168.31.139 is alive

成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值