NanoPC-T2 以太网分析(2)

在linux kerneldriver/net/ethernet/nxpmac目录下的代码是对S5P4418 SOC中的MAC进行初始化,该目录下仍然存在大量的stmmac

其中在nxpmac_main.c中是这个驱动的入口,在这个源文件中存在

module_init(stmmac_init);
module_exit(stmmac_exit);

在stmmac_init函数中调用stmmac_register_platform向kernel注册驱动程序。而stmmac_register_platform函数存在于nxpmac.h,函数实体如下:

extern struct platform_driver stmmac_pltfr_driver;
static inline int stmmac_register_platform(void)
{
int err;
err = platform_driver_register(&stmmac_pltfr_driver);
if (err)
pr_err("stmmac: failed to register the platform driver\n");
return err;
}

static inline void stmmac_unregister_platform(void)
{
platform_driver_unregister(&stmmac_pltfr_driver);
}

进一步追踪stmmac_pltfr_driver变量,在nxpmac_platform.c中发现该变量的定义

struct platform_driver stmmac_pltfr_driver = {
.probe = stmmac_pltfr_probe,
.remove = stmmac_pltfr_remove,
.driver = {
  .name = NXPMAC_RESOURCE_NAME,
  .owner = THIS_MODULE,
#if CFG_ETHER_LOOPBACK_MODE == 1
#else
  .pm = &stmmac_pltfr_pm_ops,
#endif
  .of_match_table = of_match_ptr(stmmac_dt_ids),
  },
};

对stmmac_pltfr_probe进行分析:首先是获取MAC I/O内存的起始地址和大小(MAC和PHY寄存器的地址资源)res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

然后在内核IO内存request_mem_region(res->start, resource_size(res), pdev->name),申请成功后使用addr = ioremap(res->start, resource_size(res));获取物理地址对应的虚拟地址。

紧接着,驱动程序获取之前注册设备的时候注册的数据plat_dat = dev_get_platdata(&pdev->dev);如果注册设备的时候没有注册platdata,那么驱动程序会为platdata申请内存
if (!plat_dat)
plat_dat = devm_kzalloc(&pdev->dev,
sizeof(struct plat_stmmacenet_data),
GFP_KERNEL);

接下来会调用ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);这个函数的作用是获取注册设备的时候注册的一些配置。但是在NanoPC-T2中,这个函数是空的,不会做任何的事情。

驱动会调用注册设备时候添加的一个init函数

if (plat_dat->init) {
ret = plat_dat->init(pdev);
if (unlikely(ret))
goto out_unmap;
}

static struct plat_stmmacenet_data nxpmac_plat_data = {
#if defined (CONFIG_REALTEK_PHY_RTL8201)
.phy_addr = 3,  // 7 for 8211 3 for 8201
    .clk_csr = 0xe,
    .speed = SPEED_100,
#else
    .phy_addr = 7,
    .clk_csr = 0x4, // PCLK 150~250 Mhz
    .speed = SPEED_1000, // SPEED_1000
#endif
    .interface = PHY_INTERFACE_MODE_RGMII,
.autoneg = AUTONEG_ENABLE, //AUTONEG_ENABLE or AUTONEG_DISABLE
.duplex = DUPLEX_FULL,
.pbl = 16,          /* burst 16 */
.has_gmac = 1,      /* GMAC ethernet    */
.enh_desc = 0,
.mdio_bus_data = &nxpmac0_mdio_bus,
.init = &nxpmac_init,
};

在nxpmac_init函数中做如下的配置:

一、时钟设置

1、在S5P4418 SOC中存在一个Clok Generator模块,在这个模块中控制各个IP时钟产生,在nxpmac_init会获取控制GMAC始终控制寄存器的地址

addr = NX_CLKGEN_GetPhysicalAddress(CLOCKINDEX_OF_DWC_GMAC_MODULE);

2、设置GMACCLKGEN0L寄存器的CLKSRCSEL0=4,意味着RX的时钟来自外部。在NanoPC-T2中,RX时钟来自PHY芯片

NX_CLKGEN_SetClockSource( CLOCKINDEX_OF_DWC_GMAC_MODULE, 0, 4); 

3、设置GMACCLKGEN0L寄存器的CLKDIV0=0

NX_CLKGEN_SetClockDivisor( CLOCKINDEX_OF_DWC_GMAC_MODULE, 0, 1);

4、设置GMACCLK寄存器的OUTCLKINV0=0(Normal:Falling Edge)

NX_CLKGEN_SetClockOutInv( CLOCKINDEX_OF_DWC_GMAC_MODULE, 0, CFALSE); 

5、设置GMACCLKENB寄存器的CLKGENENB=1

NX_CLKGEN_SetClockDivisorEnable( CLOCKINDEX_OF_DWC_GMAC_MODULE, CTRUE);

二、复位控制设置

1、获取复位控制寄存器的物理地址,开始地址在0xC001_2000

2、让MAC IP核复位一下

NX_RSTCON_SetnRST(RESETINDEX_OF_DWC_GMAC_MODULE_aresetn_i, RSTCON_ENABLE);
udelay(100);
NX_RSTCON_SetnRST(RESETINDEX_OF_DWC_GMAC_MODULE_aresetn_i, RSTCON_DISABLE);
udelay(100);
NX_RSTCON_SetnRST(RESETINDEX_OF_DWC_GMAC_MODULE_aresetn_i, RSTCON_ENABLE);
udelay(100);

三、让PHY芯片复位

1、外部的PHY芯片的RESET与S5P4418的一个引脚相连,驱动程序通过让此引脚输出低电平来达到让PHY复位的功能

gpio_request(CFG_ETHER_GMAC_PHY_RST_NUM,"Ethernet Rst pin");
gpio_direction_output(CFG_ETHER_GMAC_PHY_RST_NUM, 1 );
udelay( 100 );
gpio_set_value(CFG_ETHER_GMAC_PHY_RST_NUM, 0 );
udelay( 100 );
gpio_set_value(CFG_ETHER_GMAC_PHY_RST_NUM, 1 );


以上步骤执行完毕后,返回stmmac_pltfr_probe函数执行priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);

下一章介绍stmmac_dvr_probe函数的过程。






















你可能感兴趣的:(NanoPC-T2 以太网分析(2))