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

成功

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Rockchip RK3566是一款由Rockchip推出的高性能应用处理器,其集成了四核ARM Cortex-A55 CPU和ARM Mali-G52 GPU。在移植U-Boot 2023.04时,我们需要考虑以下几个方面的工作: 1. 了解RK3566芯片的硬件架构和技术规格,包括处理器核心、内存控制器、外设接口等。这将有助于理解U-Boot如何与硬件交互,并进行相应的配置。 2. 下载并准备U-Boot 2023.04的源代码。在Rockchip官方网站或开源社区中可以找到最新的U-Boot源代码。将其下载并解压到开发机上。 3. 设置交叉编译环境。因为U-Boot是一个跨平台的项目,所以需要配置适合RK3566的交叉编译器,确保能够正确编译U-Boot源代码。 4. 配置U-Boot。根据RK3566的硬件架构和技术规格,需要进行相应的配置,包括处理器、内存、外设等设置。这些设置在U-Boot的配置文件中进行,可以根据需求进行修改。 5. 编译U-Boot。在配置好U-Boot后,使用交叉编译器编译U-Boot源代码。编译完成后,将生成的U-Boot二进制文件烧录到RK3566的启动设备上,如eMMC或SD卡。 6. 测试U-Boot。将准备好的启动设备插入RK3566开发板中,根据开发板的启动方式,进入U-Boot命令行界面。在命令行界面中可以进行各种操作和调试,如加载内核、启动操作系统等。 7. 调试和优化。在移植和测试U-Boot过程中,可能会出现一些问题和不稳定的情况。需要通过调试和优化来解决这些问题,确保U-Boot的正常运行和稳定性。 总之,移植U-Boot 2023.04到Rockchip RK3566需要了解芯片的硬件架构和技术规格,配置和编译U-Boot源代码,进行测试和调试。这样可以确保U-Boot能够与RK3566正常交互,并为后续的操作系统加载和启动提供基础支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值