arch/arm/boot/dts/am33xx.dtsi
/ {
ocp {
mac: ethernet@4a100000 {
compatible = "ti,cpsw"; //属性,与驱动函数的匹配字符串是一致的
ti,hwmods = "cpgmac0"; //可选属性:对硬件模块配置,为了跟驱动匹配
//指定时钟,定义在am33xx-clocks.dtsi文件中
clocks = <&cpsw_125mhz_gclk>, <&cpsw_cpts_rft_clk>;
clock-names = "fck", "cpts";
//cpma(common platformdma)的通道数
cpdma_channels = <8>;
//指定ale条目
ale_entries = <1024>;
bd_ram_size = <0x2000>;
//设置HW descriptor是否在内部bd ram 0 or 1
no_bd_ram = <0>;
//指定RX描述符个数
rx_descs = <64>;
//mac 控制器
mac_control = <0x20>;
//从站数量
slaves = <2>;
//默认是从站0
active_slave = <0>;
cpts_clock_mult = <0x80000000>;
cpts_clock_shift = <29>;
//cpsw寄存器映射地址
reg = <0x4a100000 0x800
0x4a101200 0x100>;
#address-cells = <1>;
#size-cells = <1>;
//父中断控制器
interrupt-parent = <&intc>;
/*
* c0_rx_thresh_pend
* c0_rx_pend
* c0_tx_pend
* c0_misc_pend
*/
//中断号
interrupts = <40 41 42 43>;
ranges;
davinci_mdio: mdio@4a101000 {
compatible = "ti,davinci_mdio";
#address-cells = <1>;
#size-cells = <0>;
ti,hwmods = "davinci_mdio";
bus_freq = <1000000>;
reg = <0x4a101000 0x100>;
};
//以太网控制器
cpsw_emac0: slave@4a100200 {
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
cpsw_emac1: slave@4a100300 {
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
//phy寄存器基地址和寄存器的值
phy_sel: cpsw-phy-sel@44e10650 {
compatible = "ti,am3352-cpsw-phy-sel";
reg= <0x44e10650 0x3a>; //见TRM第9章gmii_sel Register的内容
reg-names = "gmii-sel";
};
};
};
};
drivers/net/ethernet/ti/cpsw.c
static const struct of_device_id cpsw_of_mtable[] = {
{ .compatible = "ti,cpsw", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static struct platform_driver cpsw_driver = {
.driver = {
.name = "cpsw",
.owner = THIS_MODULE,
.pm = &cpsw_pm_ops,
.of_match_table = cpsw_of_mtable,
},
.probe = cpsw_probe,
.remove = cpsw_remove,
};
当cpsw_of_mtable与设备树中的匹配,就执行probe函数。如果在设备树中找不到,就判断平台设备中是否存在"cpsw",存在就执行probe函数
static int cpsw_probe(struct platform_device *pdev)
{
//分配网络设备空间
ndev = alloc_etherdev(sizeof(struct cpsw_priv));
一些平台数据、资源、DMA初始化、赋值netdev_ops、ethtool_ops
//获取设备树中的信息
if (cpsw_probe_dt(&priv->data, pdev)) {
........
//注册net_device_ops结构体
ndev->netdev_ops = &cpsw_netdev_ops;
//注册网络设备
ret = register_netdev(ndev);
//注册第2个从设备
if (priv->data.dual_emac) {
ret = cpsw_probe_dual_emac(pdev, priv);
}
static const struct net_device_ops cpsw_netdev_ops = {
.ndo_open = cpsw_ndo_open,
.ndo_stop = cpsw_ndo_stop,
.ndo_start_xmit = cpsw_ndo_start_xmit,
.ndo_set_mac_address = cpsw_ndo_set_mac_address,
.ndo_do_ioctl = cpsw_ndo_ioctl,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_tx_timeout = cpsw_ndo_tx_timeout,
.ndo_set_rx_mode = cpsw_ndo_set_rx_mode,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cpsw_ndo_poll_controller,
#endif
.ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid,
};
static int cpsw_ndo_open(struct net_device *ndev)
{
//初始化,执行ifconfig up会打印这个信息
dev_info(priv->dev, "initializing cpsw version %d.%d (%d)\n",
CPSW_MAJOR_VERSION(reg), CPSW_MINOR_VERSION(reg),
CPSW_RTL_VERSION(reg));
for_each_slave(priv, cpsw_slave_open, priv);
}
static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
slave->phy = phy_connect(priv->ndev, slave->data->phy_id,
&cpsw_adjust_link, slave->data->phy_if);
if (IS_ERR(slave->phy)) {
dev_err(priv->dev, "phy %s not found on slave %d\n",
slave->data->phy_id, slave->slave_num); //检测到网络从设备
slave->phy = NULL;
} else {
dev_info(priv->dev, "phy found : id is : 0x%x\n",
slave->phy->phy_id); //检测到phy_id
phy_start(slave->phy); //PHY_READY变为PHY_UP
/* Configure GMII_SEL register */
cpsw_phy_sel(&priv->pdev->dev, slave->phy->interface,
slave->slave_num);
}
}
struct phy_device *phy_connect(struct net_device *dev, const char *bus_id,
void (*handler)(struct net_device *),
phy_interface_t interface)
{
rc = phy_connect_direct(dev, phydev, handler, interface);
}
int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
void (*handler)(struct net_device *),
phy_interface_t interface)
{
rc = phy_attach_direct(dev, phydev, phydev->dev_flags, interface);
phy_prepare_link(phydev, handler);
//启动phy状态机
phy_start_machine(phydev);
if (phydev->irq > 0)
phy_start_interrupts(phydev);
return 0;
}
int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
u32 flags, phy_interface_t interface)
{
if (NULL == d->driver) {
if (phydev->is_c45)
//通用驱动赋值,支持1G、10G
d->driver = &genphy_driver[GENPHY_DRV_10G].driver;
else
d->driver = &genphy_driver[GENPHY_DRV_1G].driver;
//调用到genphy_driver的检测函数
err = d->driver->probe(d);
if (err >= 0)
//绑定驱动到设备
err = device_bind_driver(d);
if (err)
return err;
}
//指向dev
phydev->attached_dev = dev;
dev->phydev = phydev;
phydev->dev_flags = flags;
phydev->interface = interface;
//将phy的状态标记为PHY_READY
phydev->state = PHY_READY;
//硬件级的初始化,最后会调用config_init
err = phy_init_hw(phydev);
if (err)
phy_detach(phydev);
else
phy_resume(phydev);
}
drivers/net/phy/phy_device.c
static int __init phy_init(void)
rc = phy_drivers_register(genphy_driver,ARRAY_SIZE(genphy_driver));
for (i = 0; i < n; i++) {
ret = phy_driver_register(new_driver + i);
new_driver->driver.name = new_driver->name;
new_driver->driver.bus = &mdio_bus_type;
new_driver->driver.probe = phy_probe;
new_driver->driver.remove = phy_remove;
static int phy_probe(struct device *dev)
{
//从device结构体得到phy_device指针
struct phy_device *phydev = to_phy_device(dev);
//赋值device_driver指针
struct device_driver *drv = phydev->dev.driver;
//从drv得到phy_driver指针
struct phy_driver *phydrv = to_phy_driver(drv);
phydev->supported = phydrv->features;
phydev->advertising = phydrv->features;
phydev->state = PHY_READY;
if (phydev->drv->probe)
err = phydev->drv->probe(phydev);
}
上电过程中调用的主要函数,默认是自动协商的
--> tixxx_cpsw_init
--> phy_init
--> mdio_bus_init
--> phy_drivers_register
-->phy_driver_register
--> davinci_mdio_probe
--> cpsw_probe
--> cpsw_ndo_open
--> cpsw_slave_open
--> phy_probe
--> PHY_READY->PHY_UP
--> phy_state_machine状态机函数
--> phy_start_aneg
--> genphy_config_aneg
--> genphy_config_advert
--> genphy_restart_aneg
--> PHY_AN
--> PHY_AN->HY_RUNNING
--> _cpsw_adjust_link
--> phy_print_status
--> "Link is Up - xxxx"
--> PHY_RUNNING->PHY_CHANGELINK->PHY_RUNNING(循环)