SOC可以对PHY 进行配置或者读取PHY 相关状态,这个就需要 PHY 内部寄存器去实现了。PHY 芯片寄存器地址空间为 5位(支持访问32个寄存器).IEEE 定义了0~15这 16个寄存器的功能。而 16~31这16 个寄存器由厂商自行实现。
就是说不管你用的哪个厂家的 PHY 芯片,其中 0~15 这 16 个寄存器是一模一样的。仅靠这16个寄存器是完全可以驱动起 PHY 芯片的,至少能保证基本的网络数据通信,因此 Linux 内核有通用 PHY 驱动。所以 一般情况下,如果不需要使用PHY厂家提供的自定义的寄存器配置实现一些个性化的功能,那么PHY驱动就基本不需要修改。
如 寄存器0是PHY控制寄存器,通过Control Register可以对PHY的主要工作状态进行设置。 寄存器1是PHY状态寄存器,主要包含PHY的状态信息。等等 具体可以去找具体的寄存器信息,这里不做详细叙述。
如:
MAC控制器通过MDIO总线来管理phy设备,mdio总线与i2c总线类似,可以一个主机对应多个从设备,每个从设备都有地址。mdio最多接32个phy设备。
对应的目录是/sys/mdio,在/sys/mdio/devices目录中会有挂载在mdio的phy设备,在/sys/mdio/drivers中会有phy设备的驱动。
如:
/sys/bus/mdio_bus/devices/stmmac-0:00
其中 stmmac-0:00 表示 PHY 地址是 0。
该命令会读取 0~31 的所有寄存器,所以可以查看对应的寄存器值
cat /sys/bus/mdio_bus/devices/stmmac-0:00/phy_registers
root@OpenSDT:/sys/devices/platform/fe300000.ethernet/mdio_bus/stmmac-0/stmmac-0:00# cat phy_registers
0: 0x1140
1: 0x7989
2: 0x1c
3: 0xc982
4: 0x1e1
5: 0x0
6: 0x64
7: 0x2001
8: 0x0
9: 0xe00
10: 0x0
11: 0x0
12: 0x0
13: 0x0
14: 0x0
15: 0x2000
16: 0x23
17: 0x0
18: 0xffff
19: 0x0
20: 0x0
21: 0x0
22: 0xf00
23: 0xf00
24: 0x19c
25: 0x40
26: 0x5000
27: 0x802a
28: 0x0
29: 0x220
30: 0x0
31: 0x0
root@OpenSDT:/sys/devices/platform/fe300000.ethernet/mdio_bus/stmmac-0/stmmac-0:00#
drivers\net\phy\phy_device.c
static struct phy_driver genphy_driver = {
.phy_id = 0xffffffff,
.phy_id_mask = 0xffffffff,
.name = "Generic PHY",
.soft_reset = genphy_no_soft_reset,
.config_init = genphy_config_init,
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
SUPPORTED_AUI | SUPPORTED_FIBRE |
SUPPORTED_BNC,
.aneg_done = genphy_aneg_done,
.suspend = genphy_suspend,
.resume = genphy_resume,
.set_loopback = genphy_loopback,
};
static int __init phy_init(void)
{
int rc;
//mdio 总线初始化注册:
/*
注册:
/sys/class/mdio_bus
/sys/bus/mdio_bus
*/
rc = mdio_bus_init();
if (rc)
return rc;
//注册 名为 "Generic 10G PHY" phy驱动 到 mdio 总线
rc = phy_driver_register(&genphy_10g_driver, THIS_MODULE);
if (rc)
goto err_10g;
//注册 名为 "Generic PHY" phy驱动 到 mdio 总线
rc = phy_driver_register(&genphy_driver, THIS_MODULE);
if (rc) {
phy_driver_unregister(&genphy_10g_driver);
err_10g:
mdio_bus_exit();
}
return rc;
}
static void __exit phy_exit(void)
{
phy_driver_unregister(&genphy_10g_driver);
phy_driver_unregister(&genphy_driver);
mdio_bus_exit();
}
subsys_initcall(phy_init);
module_exit(phy_exit);
\drivers\net\phy\mdio_bus.c
// sys/class/mdio_bus
static struct class mdio_bus_class = {
.name = "mdio_bus",
.dev_release = mdiobus_release,
};
// /sys/bus/mdio_bus
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
.uevent = mdio_uevent,
};
EXPORT_SYMBOL(mdio_bus_type);
int __init mdio_bus_init(void)
{
int ret;
// 即 /sys/class/mdio_bus
ret = class_register(&mdio_bus_class);
if (!ret) {
//即 /sys/bus/mdio_bus
ret = bus_register(&mdio_bus_type);
if (ret)
class_unregister(&mdio_bus_class);
}
return ret;
}
EXPORT_SYMBOL_GPL(mdio_bus_init);
int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
{
int retval;
/*
//phy 驱动
struct phy_driver
.name = "Generic PHY",
//MDIO 驱动通用部分
struct mdio_driver_common mdiodrv;-----+
|
|
+---struct mdio_driver_common mdiodrv;
int flags |= MDIO_DEVICE_IS_PHY
struct device_driver driver;
.name = "Generic PHY",
//总线 //mdio 总线
struct bus_type *bus;-------------------------------struct bus_type mdio_bus_type = {
int (*probe) (struct device *dev); = phy_probe .name = "mdio_bus",
... .match = mdio_bus_match,
.uevent = mdio_uevent,
struct subsys_private *p;
//相关的驱动程序列表
struct kset *drivers_kset;
*/
new_driver->mdiodrv.flags |= MDIO_DEVICE_IS_PHY;
new_driver->mdiodrv.driver.name = new_driver->name;
new_driver->mdiodrv.driver.bus = &mdio_bus_type;
new_driver->mdiodrv.driver.probe = phy_probe;
new_driver->mdiodrv.driver.remove = phy_remove;
new_driver->mdiodrv.driver.owner = owner;
new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
retval = driver_register(&new_driver->mdiodrv.driver);
if (retval) {
pr_err("%s: Error %d in registering driver\n",
new_driver->name, retval);
return retval;
}
pr_debug("%s: Registered new driver\n", new_driver->name);
return 0;
}
EXPORT_SYMBOL(phy_driver_register);
所以 phy 驱动注册部分主要做了如下工作:
1 创建 初始化 struct phy_driver
2 设置struct phy_driver ,
如所在的名为“mdio_bus” 的mdio_bus_type 总线
如 匹配成功后的 probe()函数
…
3 注册 phy_driver
至此
phy_driver注册成功了,那就差phy_device的注册。看代码就知道 phy_device的注册不依靠设备树,而是在GMAC控制器注册时候 在其中的mdiobus_register中会注册phy_device 。