基于335X平台Linux交换芯片驱动开发
一、软硬件平台资料
1、开发板:创龙AM3359核心板,网口采用RMII形式。
2、Kernel版本:4.4.12,采用FDT
3、交换芯片MARVELL的88E6321.
二、移植准备工作
1、熟悉88E6321的datasheet及Functional_Specification_Rev.0.05
2、熟悉设备树相关理论和用法
3、熟悉Linux网络驱动MDIO、PHY部分的软件流程
三、DTS文件修改
本工程的DTS文件以am335x-icev2.dts为基础进行修改
1、修改网络接口MODE
我们板子上使用的是335X的RMII接口与SW相连,使用SW的RMII接口提供的50M时钟信号。根据硬件连接关系,335X的RMII接口与SW的PORT5相连,根据SW使用单芯片模式,根据SW的访问机制,这里设置phy_id为0x15.所以对设备树相关接口模式部分做如下修改
- &cpsw_emac0 {
- phy_id = <&davinci_mdio>, <0>;
- phy-mode = "rgmii";
- };
+ &cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0x15>;
+ phy-mode = "rmii";
+ };
2、修改网络接口pinmux
将原有cpsw_default、cpsw_sleep部分的pinmux改为RMII模式相对应的pinmux配置,如下:
cpsw_default: cpsw_default {
pinctrl-single,pins = <
/* Slave 1, RMII mode */
AM33XX_IOPAD(0x914, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txen.rmii1_txen */
AM33XX_IOPAD(0x924, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd1.rmii1_td1 */
AM33XX_IOPAD(0x928, PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* mii1_txd0.rmii1_td0 */
AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd1.rmii1_rd1 */
AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE1) /* mii1_rxd0.rmii1_rd0 */
AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE0) /* RMII1_REF_CLK.rmii1_refclk*/
AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE1) /* MII1_RX_ER. rmii1_rxerr*/
AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE1) /* MII1_CRS. rmii1_crs_dv*/
>;
};
cpsw_sleep: cpsw_sleep {
pinctrl-single,pins = <
/* Slave 1 reset value */
AM33XX_IOPAD(0x914, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x924, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x928, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x93c, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x940, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x944, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x910, PIN_INPUT_PULLDOWN | MUX_MODE7)
AM33XX_IOPAD(0x90c, PIN_INPUT_PULLDOWN | MUX_MODE7)
>;
};
四、网口驱动架构及流程分析
网口驱动架构见文档:基于335X的Linux网口驱动分析
4.1.网口底层驱动启动及加载过程大致如下:
1 |
--> kernel相关启动及初始化 |
4.2.网口底层驱动关键过程分析
4.2.1.phy_driver初始化
在phy_device.c中,函数phy_init进行相关phy设备驱动的加载注册,具体过程为:
phy_init()
->mdio_bus_init
->phy_drivers_register
phy_init函数主要完成了mdio_bus的初始化工作,注册了mdio_bus_class,注册了mdio_bus_type,其中mdio_bus_type中的mdio_bus_match成员函数规定了phy_device和phy_driver的匹配方式。
4.2.2. davinci_mdio设备及驱动
在davinci_mdio.c文件中会进行davinci_mdio_driver的注册,davinci_mdio_driver中的davinci_mdio_of_mtable有compatible字符。
在系统启动时,会进行设备树文件的解析,将设备树中的设备节点转换为设备结构体,会转换出davinci_mdio相关的设备。davinci_mdio设备及驱动都属于platform_bus。通过比较设备树文件中davinci_mdio节点的compatible属性以及davinci_mdio_driver中的davinci_mdio_of_mtable包含的compatible内容。如果匹配,就会执行davinci_mdio_probe函数。
4.2.3 davinci_mdio_probe函数分析
最主要的工作是进行mdio_bus的相关对象内容的填充及mdio_bus_class总线类型的设置。主要是完成MDIO读、写、复位函数的关联。之后通过__mdiobus_register函数中的bus->reset(bus)对CPSW的alive寄存器进行读取,其值标识这MDIO总线检测到“活着”的phy设备。再通过mdiobus_scan对检测到的phy设备进行通过phydev->bus->phy_map[phydev->addr]对其进行管理。并对其分别注册。
在注册PHY设备时,就会进行与4.2.1小节中进行注册的phy_driver进行匹配,若匹配成功,则执行phy_probe函数。注意,这里可能会检测到多个PHY,也可能会有多个PHY和多个phy_driver的匹配,最终具体使用哪个PHY及phy_driver。在cpsw_probe中连接PHY设备时才会选择,这里只是对“活着”的PHY设备进行驱动的匹配。
4.2.4 cpsw设备及驱动的匹配
与davinci_mdio设备类似,cpsw设备及驱动也是属于platform_bus,系统启动时将设备树中的设备节点转换为设备结构体,会转换出cpsw相关的设备。也是使用compatible属性和cpsw_driver进行匹配,匹配成功后就会执行cpsw_probe函数。
4.2.5 cpsw_probe函数分